WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 352 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
88 changed files with 1314 additions and 782 deletions
Showing only changes of commit eb041d185c - Show all commits

View File

@ -120,24 +120,24 @@ enable_testing()
if(CMAKE_COMPILER_IS_GNUCC)
if("${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "11.0.0")
message(FATAL_ERROR "\
The minimum supported version of GCC is 11.0.0, found ${CMAKE_C_COMPILER_VERSION}"
The minimum supported version of GCC is 11.0.0, found C compiler: ${CMAKE_C_COMPILER_VERSION}"
)
endif()
if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "11.0.0")
message(FATAL_ERROR "\
The minimum supported version of GCC is 11.0.0, found ${CMAKE_CXX_COMPILER_VERSION}"
The minimum supported version of GCC is 11.0.0, found C++ compiler${CMAKE_CXX_COMPILER_VERSION}"
)
endif()
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
if(CMAKE_COMPILER_IS_GNUCC)
if("${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "8.0")
message(FATAL_ERROR "\
The minimum supported version of CLANG is 8.0, found ${CMAKE_C_COMPILER_VERSION}"
The minimum supported version of CLANG is 8.0, found C compiler ${CMAKE_C_COMPILER_VERSION}"
)
endif()
if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "8.0")
message(FATAL_ERROR "\
The minimum supported version of CLANG is 8.0, found ${CMAKE_CXX_COMPILER_VERSION}"
The minimum supported version of CLANG is 8.0, found C++ compiler ${CMAKE_CXX_COMPILER_VERSION}"
)
endif()
endif()

View File

@ -21,3 +21,20 @@ diff -Naur orig/src/cmake/compiler.cmake external_openimageio/src/cmake/compiler
endif (MSVC)
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD"
diff --git a/src/libOpenImageIO/imageioplugin.cpp b/src/libOpenImageIO/imageioplugin.cpp
index 9ad45042e..d2a0210ff 100644
--- a/src/libOpenImageIO/imageioplugin.cpp
+++ b/src/libOpenImageIO/imageioplugin.cpp
@@ -469,12 +469,6 @@ pvt::catalog_all_plugins(std::string searchpath)
std::unique_lock<std::recursive_mutex> lock(imageio_mutex);
append_if_env_exists(searchpath, "OIIO_LIBRARY_PATH", true);
-#ifdef __APPLE__
- append_if_env_exists(searchpath, "DYLD_LIBRARY_PATH");
-#endif
-#if defined(__linux__) || defined(__FreeBSD__)
- append_if_env_exists(searchpath, "LD_LIBRARY_PATH");
-#endif
size_t patlen = pattern.length();
std::vector<std::string> dirs;

View File

@ -477,17 +477,17 @@ ccl_device
/* compute roughness */
float anisotropy = clamp(param2, -0.99f, 0.99f);
if (data_node.y == SVM_STACK_INVALID || fabsf(anisotropy) <= 1e-4f) {
if (data_node.w == SVM_STACK_INVALID || fabsf(anisotropy) <= 1e-4f) {
/* Isotropic case. */
bsdf->T = zero_float3();
bsdf->alpha_x = roughness;
bsdf->alpha_y = roughness;
}
else {
bsdf->T = stack_load_float3(stack, data_node.y);
bsdf->T = stack_load_float3(stack, data_node.w);
/* rotate tangent */
float rotation = stack_load_float(stack, data_node.z);
float rotation = stack_load_float(stack, data_node.y);
if (rotation != 0.0f) {
bsdf->T = rotate_around_axis(bsdf->T, bsdf->N, rotation * M_2PI_F);
}
@ -512,8 +512,8 @@ ccl_device
else {
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
kernel_assert(stack_valid(data_node.w));
const Spectrum color = rgb_to_spectrum(stack_load_float3(stack, data_node.w));
kernel_assert(stack_valid(data_node.z));
const Spectrum color = rgb_to_spectrum(stack_load_float3(stack, data_node.z));
bsdf_microfacet_setup_fresnel_constant(kg, bsdf, sd, color);
}
}
@ -585,7 +585,7 @@ ccl_device
fresnel->f0 = make_float3(F0_from_ior(ior));
fresnel->f90 = one_spectrum();
fresnel->exponent = -ior;
const float3 color = stack_load_float3(stack, data_node.z);
const float3 color = stack_load_float3(stack, data_node.y);
fresnel->reflection_tint = reflective_caustics ? rgb_to_spectrum(color) : zero_spectrum();
fresnel->transmission_tint = refractive_caustics ? rgb_to_spectrum(color) :
zero_spectrum();
@ -834,10 +834,10 @@ ccl_device
bsdf->N = maybe_ensure_valid_specular_reflection(sd, N);
bsdf->roughness1 = param1;
bsdf->roughness2 = param2;
bsdf->offset = -stack_load_float(stack, data_node.z);
bsdf->offset = -stack_load_float(stack, data_node.y);
if (stack_valid(data_node.y)) {
bsdf->T = normalize(stack_load_float3(stack, data_node.y));
if (stack_valid(data_node.w)) {
bsdf->T = normalize(stack_load_float3(stack, data_node.w));
}
else if (!(sd->type & PRIMITIVE_CURVE)) {
bsdf->T = normalize(sd->dPdv);
@ -866,12 +866,12 @@ ccl_device
ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd, weight);
if (bssrdf) {
bssrdf->radius = rgb_to_spectrum(stack_load_float3(stack, data_node.z) * param1);
bssrdf->radius = rgb_to_spectrum(stack_load_float3(stack, data_node.y) * param1);
bssrdf->albedo = closure_weight;
bssrdf->N = maybe_ensure_valid_specular_reflection(sd, N);
bssrdf->ior = param2;
bssrdf->alpha = 1.0f;
bssrdf->anisotropy = stack_load_float(stack, data_node.w);
bssrdf->anisotropy = stack_load_float(stack, data_node.z);
sd->flag |= bssrdf_setup(sd, bssrdf, path_flag, (ClosureType)type);
}

View File

@ -2283,14 +2283,14 @@ bool BsdfBaseNode::has_bump()
BsdfNode::BsdfNode(const NodeType *node_type) : BsdfBaseNode(node_type) {}
void BsdfNode::compile(SVMCompiler &compiler,
ShaderInput *param1,
ShaderInput *param2,
ShaderInput *param3,
ShaderInput *param4)
ShaderInput *bsdf_y,
ShaderInput *bsdf_z,
ShaderInput *data_y,
ShaderInput *data_z,
ShaderInput *data_w)
{
ShaderInput *color_in = input("Color");
ShaderInput *normal_in = input("Normal");
ShaderInput *tangent_in = input("Tangent");
if (color_in->link) {
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
@ -2300,21 +2300,20 @@ void BsdfNode::compile(SVMCompiler &compiler,
}
int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID;
int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) :
SVM_STACK_INVALID;
int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID;
int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID;
int data_y_offset = (data_y) ? compiler.stack_assign(data_y) : SVM_STACK_INVALID;
int data_z_offset = (data_z) ? compiler.stack_assign(data_z) : SVM_STACK_INVALID;
int data_w_offset = (data_w) ? compiler.stack_assign(data_w) : SVM_STACK_INVALID;
compiler.add_node(
NODE_CLOSURE_BSDF,
compiler.encode_uchar4(closure,
(param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID,
(param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID,
(bsdf_y) ? compiler.stack_assign(bsdf_y) : SVM_STACK_INVALID,
(bsdf_z) ? compiler.stack_assign(bsdf_z) : SVM_STACK_INVALID,
compiler.closure_mix_weight_offset()),
__float_as_int((param1) ? get_float(param1->socket_type) : 0.0f),
__float_as_int((param2) ? get_float(param2->socket_type) : 0.0f));
__float_as_int((bsdf_y) ? get_float(bsdf_y->socket_type) : 0.0f),
__float_as_int((bsdf_z) ? get_float(bsdf_z->socket_type) : 0.0f));
compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset);
compiler.add_node(normal_offset, data_y_offset, data_z_offset, data_w_offset);
}
void BsdfNode::compile(SVMCompiler &compiler)
@ -2392,13 +2391,21 @@ void GlossyBsdfNode::compile(SVMCompiler &compiler)
{
closure = distribution;
ShaderInput *tangent = input("Tangent");
tangent = compiler.is_linked(tangent) ? tangent : nullptr;
/* TODO: Just use weight for legacy MultiGGX? Would also simplify OSL. */
if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
BsdfNode::compile(
compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
BsdfNode::compile(compiler,
input("Roughness"),
input("Anisotropy"),
input("Rotation"),
input("Color"),
tangent);
}
else {
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
BsdfNode::compile(
compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), nullptr, tangent);
}
}
@ -3535,7 +3542,11 @@ void HairBsdfNode::compile(SVMCompiler &compiler)
{
closure = component;
BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
ShaderInput *tangent = input("Tangent");
tangent = compiler.is_linked(tangent) ? tangent : nullptr;
BsdfNode::compile(
compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"), nullptr, tangent);
}
void HairBsdfNode::compile(OSLCompiler &compiler)

View File

@ -479,10 +479,11 @@ class BsdfNode : public BsdfBaseNode {
SHADER_NODE_BASE_CLASS(BsdfNode)
void compile(SVMCompiler &compiler,
ShaderInput *param1,
ShaderInput *param2,
ShaderInput *param3 = NULL,
ShaderInput *param4 = NULL);
ShaderInput *bsdf_y,
ShaderInput *bsdf_z,
ShaderInput *data_y = nullptr,
ShaderInput *data_z = nullptr,
ShaderInput *data_w = nullptr);
NODE_SOCKET_API(float3, color)
NODE_SOCKET_API(float3, normal)

View File

@ -294,9 +294,14 @@ int SVMCompiler::stack_assign(ShaderOutput *output)
return output->stack_offset;
}
bool SVMCompiler::is_linked(ShaderInput *input)
{
return (input->link || input->constant_folded_in);
}
int SVMCompiler::stack_assign_if_linked(ShaderInput *input)
{
if (input->link || input->constant_folded_in) {
if (is_linked(input)) {
return stack_assign(input);
}

View File

@ -87,6 +87,7 @@ class SVMCompiler {
int stack_assign(ShaderOutput *output);
int stack_assign(ShaderInput *input);
bool is_linked(ShaderInput *input);
int stack_assign_if_linked(ShaderInput *input);
int stack_assign_if_linked(ShaderOutput *output);
int stack_find_offset(int size);

View File

@ -123,6 +123,10 @@ typedef enum {
* Supports IME text input methods (when `WITH_INPUT_IME` is defined).
*/
GHOST_kCapabilityInputIME = (1 << 6),
/**
* Support detecting the physical trackpad direction.
*/
GHOST_kCapabilityTrackpadPhysicalDirection = (1 << 7),
} GHOST_TCapabilityFlag;
/**
@ -132,7 +136,8 @@ typedef enum {
#define GHOST_CAPABILITY_FLAG_ALL \
(GHOST_kCapabilityCursorWarp | GHOST_kCapabilityWindowPosition | \
GHOST_kCapabilityPrimaryClipboard | GHOST_kCapabilityGPUReadFrontBuffer | \
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityDesktopSample | GHOST_kCapabilityInputIME)
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityDesktopSample | \
GHOST_kCapabilityInputIME | GHOST_kCapabilityTrackpadPhysicalDirection)
/* Xtilt and Ytilt represent how much the pen is tilted away from
* vertically upright in either the X or Y direction, with X and Y the

View File

@ -108,6 +108,8 @@ static bool has_libdecor = true;
# endif
#endif
static signed char has_wl_trackpad_physical_direction = -1;
#include "IMB_imbuf.hh"
#include "IMB_imbuf_types.hh"
@ -6410,6 +6412,8 @@ static void gwl_registry_wl_seat_add(GWL_Display *display, const GWL_RegisteryAd
display->seats.push_back(seat);
wl_seat_add_listener(seat->wl.seat, &seat_listener, seat);
gwl_registry_entry_add(display, params, static_cast<void *>(seat));
has_wl_trackpad_physical_direction = version >= 9;
}
static void gwl_registry_wl_seat_update(GWL_Display *display,
const GWL_RegisteryUpdate_Params &params)
@ -8367,6 +8371,9 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_visibility_set(const bool visible)
GHOST_TCapabilityFlag GHOST_SystemWayland::getCapabilities() const
{
GHOST_ASSERT(has_wl_trackpad_physical_direction != -1,
"The trackpad direction was expected to be initialized");
return GHOST_TCapabilityFlag(
GHOST_CAPABILITY_FLAG_ALL &
~(
@ -8388,7 +8395,9 @@ GHOST_TCapabilityFlag GHOST_SystemWayland::getCapabilities() const
* is negligible. */
GHOST_kCapabilityGPUReadFrontBuffer |
/* This WAYLAND back-end has not yet implemented desktop color sample. */
GHOST_kCapabilityDesktopSample));
GHOST_kCapabilityDesktopSample |
/* This flag will eventually be removed. */
(has_wl_trackpad_physical_direction ? 0 : GHOST_kCapabilityTrackpadPhysicalDirection)));
}
bool GHOST_SystemWayland::cursor_grab_use_software_display_get(const GHOST_TGrabCursorMode mode)

View File

@ -7154,21 +7154,53 @@ def km_image_editor_tool_uv_rip_region(params):
)
def km_image_editor_tool_uv_sculpt_stroke(params):
def km_image_editor_tool_uv_grab(params):
return (
"Image Editor Tool: Uv, Sculpt Stroke",
"Image Editor Tool: Uv, Grab",
{"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
{"items": [
("sculpt.uv_sculpt_stroke", {"type": params.tool_mouse, "value": 'PRESS'}, None),
("sculpt.uv_sculpt_stroke", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
{"properties": [("mode", 'INVERT')]}),
("sculpt.uv_sculpt_stroke", {"type": params.tool_mouse, "value": 'PRESS', "shift": True},
{"properties": [("mode", 'RELAX')]}),
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 0.9)]}),
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
*_template_paint_radial_control("uv_sculpt"),
("sculpt.uv_sculpt_grab", {"type": params.tool_mouse, "value": 'PRESS'}, None),
("sculpt.uv_sculpt_grab", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
{"properties": [("use_invert", True)]}),
("sculpt.uv_sculpt_relax", {"type": params.tool_mouse, "value": 'PRESS', "shift": True}, None),
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.size"), ], }),
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.strength"), ], }),
]},
)
def km_image_editor_tool_uv_relax(params):
return (
"Image Editor Tool: Uv, Relax",
{"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
{"items": [
("sculpt.uv_sculpt_relax", {"type": params.tool_mouse, "value": 'PRESS'}, None),
("sculpt.uv_sculpt_relax", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
{"properties": [("use_invert", True)]}),
("sculpt.uv_sculpt_relax", {"type": params.tool_mouse, "value": 'PRESS', "shift": True}, None),
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.size"), ], }),
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.strength"), ], }),
]},
)
def km_image_editor_tool_uv_pinch(params):
return (
"Image Editor Tool: Uv, Pinch",
{"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
{"items": [
("sculpt.uv_sculpt_pinch", {"type": params.tool_mouse, "value": 'PRESS'}, None),
("sculpt.uv_sculpt_pinch", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
{"properties": [("use_invert", True)]}),
("sculpt.uv_sculpt_relax", {"type": params.tool_mouse, "value": 'PRESS', "shift": True}, None),
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.size"), ], }),
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.strength"), ], }),
]},
)
@ -8930,7 +8962,9 @@ def generate_keymaps(params=None):
*(km_image_editor_tool_uv_select_circle(params, fallback=fallback) for fallback in (False, True)),
*(km_image_editor_tool_uv_select_lasso(params, fallback=fallback) for fallback in (False, True)),
km_image_editor_tool_uv_rip_region(params),
km_image_editor_tool_uv_sculpt_stroke(params),
km_image_editor_tool_uv_grab(params),
km_image_editor_tool_uv_relax(params),
km_image_editor_tool_uv_pinch(params),
km_image_editor_tool_uv_move(params),
km_image_editor_tool_uv_rotate(params),
km_image_editor_tool_uv_scale(params),

View File

@ -6,6 +6,7 @@ from __future__ import annotations
import bpy
from bpy.types import (
FileHandler,
Operator,
PropertyGroup,
)
@ -441,9 +442,27 @@ class NODE_OT_enum_definition_item_move(Operator):
return {'FINISHED'}
class NODE_FH_image_node(FileHandler):
bl_idname = "NODE_FH_image_node"
bl_label = "Image node"
bl_import_operator = "node.add_file"
bl_file_extensions = ";".join((*bpy.path.extensions_image, *bpy.path.extensions_movie))
@classmethod
def poll_drop(cls, context):
return (
(context.area is not None) and
(context.area.type == 'NODE_EDITOR') and
(context.region is not None) and
(context.region.type == 'WINDOW')
)
classes = (
NodeSetting,
NODE_FH_image_node,
NODE_OT_add_node,
NODE_OT_add_simulation_zone,
NODE_OT_add_repeat_zone,

View File

@ -718,10 +718,6 @@ class IMAGE_HT_tool_header(Header):
layout.popover("IMAGE_PT_tools_brush_display")
layout.popover("IMAGE_PT_tools_brush_texture")
layout.popover("IMAGE_PT_tools_mask_texture")
elif tool_mode == 'UV':
if (tool is not None) and tool.has_datablock:
layout.popover("IMAGE_PT_uv_sculpt_curve")
layout.popover("IMAGE_PT_uv_sculpt_options")
def draw_mode_settings(self, context):
layout = self.layout
@ -1348,50 +1344,21 @@ class IMAGE_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel):
row.prop(ipaint, "tile_y", text="Y", toggle=True)
class UVSculptPanel(UnifiedPaintPanel):
@classmethod
def poll(cls, context):
return cls.get_brush_mode(context) == 'UV_SCULPT'
class IMAGE_PT_uv_sculpt_brush_select(Panel, BrushSelectPanel, ImagePaintPanel, UVSculptPanel):
bl_context = ".uv_sculpt"
bl_category = "Tool"
bl_label = "Brushes"
class IMAGE_PT_uv_sculpt_brush_settings(Panel, ImagePaintPanel, UVSculptPanel):
bl_context = ".uv_sculpt"
bl_category = "Tool"
bl_label = "Brush Settings"
def draw(self, context):
layout = self.layout
tool_settings = context.tool_settings
uvsculpt = tool_settings.uv_sculpt
brush = uvsculpt.brush
brush_settings(layout.column(), context, brush)
if brush:
if brush.uv_sculpt_tool == 'RELAX':
# Although this settings is stored in the scene,
# it is only used by a single tool,
# so it doesn't make sense from a user perspective to move it to the Options panel.
layout.prop(tool_settings, "uv_relax_method")
class IMAGE_PT_uv_sculpt_curve(Panel, FalloffPanel, ImagePaintPanel, UVSculptPanel):
class IMAGE_PT_uv_sculpt_curve(Panel, ImagePaintPanel):
bl_context = ".uv_sculpt" # Dot on purpose (access from top-bar).
bl_parent_id = "IMAGE_PT_uv_sculpt_brush_settings"
bl_category = "Tool"
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
props = context.scene.tool_settings.uv_sculpt
layout.prop(props, "curve_preset", text="")
if props.curve_preset == 'CUSTOM':
layout.template_curve_mapping(props, "strength_curve")
class IMAGE_PT_uv_sculpt_options(Panel, ImagePaintPanel, UVSculptPanel):
class IMAGE_PT_uv_sculpt_options(Panel, ImagePaintPanel):
bl_context = ".uv_sculpt" # Dot on purpose (access from top-bar).
bl_category = "Tool"
bl_label = "Options"
@ -1400,12 +1367,10 @@ class IMAGE_PT_uv_sculpt_options(Panel, ImagePaintPanel, UVSculptPanel):
layout = self.layout
tool_settings = context.tool_settings
uvsculpt = tool_settings.uv_sculpt
col = layout.column()
col.prop(tool_settings, "uv_sculpt_lock_borders")
col.prop(tool_settings, "uv_sculpt_all_islands")
col.prop(uvsculpt, "show_brush", text="Display Cursor")
class ImageScopesPanel:
@ -1789,8 +1754,6 @@ classes = (
IMAGE_PT_paint_curve,
IMAGE_PT_tools_brush_display,
IMAGE_PT_tools_imagepaint_symmetry,
IMAGE_PT_uv_sculpt_brush_select,
IMAGE_PT_uv_sculpt_brush_settings,
IMAGE_PT_uv_sculpt_options,
IMAGE_PT_uv_sculpt_curve,
IMAGE_PT_view_histogram,

View File

@ -2207,36 +2207,82 @@ class _defs_image_uv_edit:
class _defs_image_uv_sculpt:
@staticmethod
def generate_from_brushes(context):
def draw_cursor(context, _tool, xy):
@ToolDef.from_fn
def grab():
def draw_settings(context, layout, tool):
uv_sculpt = context.scene.tool_settings.uv_sculpt
layout.prop(uv_sculpt, "size")
layout.prop(uv_sculpt, "strength")
layout.popover("IMAGE_PT_uv_sculpt_curve")
layout.popover("IMAGE_PT_uv_sculpt_options")
def draw_cursor(context, tool, xy):
from gpu_extras.presets import draw_circle_2d
tool_settings = context.tool_settings
uv_sculpt = tool_settings.uv_sculpt
if not uv_sculpt.show_brush:
return
ups = tool_settings.unified_paint_settings
if ups.use_unified_size:
radius = ups.size
else:
brush = tool_settings.uv_sculpt.brush
if brush is None:
return
radius = brush.size
uv_sculpt = context.scene.tool_settings.uv_sculpt
radius = uv_sculpt.size
draw_circle_2d(xy, (1.0,) * 4, radius)
return generate_from_enum_ex(
context,
idname_prefix="builtin_brush.",
icon_prefix="brush.uv_sculpt.",
type=bpy.types.Brush,
attr="uv_sculpt_tool",
tooldef_keywords=dict(
operator="sculpt.uv_sculpt_stroke",
keymap="Image Editor Tool: Uv, Sculpt Stroke",
draw_cursor=draw_cursor,
options={'KEYMAP_FALLBACK'},
),
return dict(
idname="sculpt.uv_sculpt_grab",
label="Grab",
icon="brush.uv_sculpt.grab",
keymap=(),
draw_cursor=draw_cursor,
draw_settings=draw_settings,
options={'KEYMAP_FALLBACK'},
)
@ToolDef.from_fn
def relax():
def draw_settings(context, layout, tool):
uv_sculpt = context.scene.tool_settings.uv_sculpt
layout.prop(uv_sculpt, "size")
layout.prop(uv_sculpt, "strength")
layout.popover("IMAGE_PT_uv_sculpt_curve")
layout.popover("IMAGE_PT_uv_sculpt_options")
props = tool.operator_properties("sculpt.uv_sculpt_relax")
layout.prop(props, "relax_method", text="Method")
def draw_cursor(context, tool, xy):
from gpu_extras.presets import draw_circle_2d
uv_sculpt = context.scene.tool_settings.uv_sculpt
radius = uv_sculpt.size
draw_circle_2d(xy, (1.0,) * 4, radius)
return dict(
idname="sculpt.uv_sculpt_relax",
label="Relax",
icon="brush.uv_sculpt.relax",
keymap=(),
draw_cursor=draw_cursor,
draw_settings=draw_settings,
options={'KEYMAP_FALLBACK'},
)
@ToolDef.from_fn
def pinch():
def draw_settings(context, layout, tool):
uv_sculpt = context.scene.tool_settings.uv_sculpt
layout.prop(uv_sculpt, "size")
layout.prop(uv_sculpt, "strength")
layout.popover("IMAGE_PT_uv_sculpt_curve")
layout.popover("IMAGE_PT_uv_sculpt_options")
def draw_cursor(context, tool, xy):
from gpu_extras.presets import draw_circle_2d
uv_sculpt = context.scene.tool_settings.uv_sculpt
radius = uv_sculpt.size
draw_circle_2d(xy, (1.0,) * 4, radius)
return dict(
idname="sculpt.uv_sculpt_pinch",
label="Pinch",
icon="brush.uv_sculpt.pinch",
keymap=(),
draw_cursor=draw_cursor,
draw_settings=draw_settings,
options={'KEYMAP_FALLBACK'},
)
@ -3078,11 +3124,9 @@ class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
_defs_image_uv_edit.rip_region,
None,
lambda context: (
_defs_image_uv_sculpt.generate_from_brushes(context)
if _defs_image_generic.poll_uvedit(context)
else ()
),
_defs_image_uv_sculpt.grab,
_defs_image_uv_sculpt.relax,
_defs_image_uv_sculpt.pinch,
],
'MASK': [
None,

View File

@ -1795,6 +1795,13 @@ class USERPREF_PT_input_touchpad(InputPanel, CenterAlignMixIn, Panel):
col = layout.column()
col.prop(inputs, "use_multitouch_gestures")
from _bpy import _wm_capabilities
capabilities = _wm_capabilities()
if not capabilities['TRACKPAD_PHYSICAL_DIRECTION']:
row = col.row()
row.active = inputs.use_multitouch_gestures
row.prop(inputs, "touchpad_scroll_direction", text="Scroll Direction")
class USERPREF_PT_input_tablet(InputPanel, CenterAlignMixIn, Panel):
bl_label = "Tablet"

View File

@ -155,6 +155,14 @@ int clear_keyframe(Main *bmain,
int array_index,
eInsertKeyFlags /*flag*/);
/** Check if a flag is set for keyframing (per scene takes precedence). */
bool is_keying_flag(const Scene *scene, eKeying_Flag flag);
/**
* Get the settings for key-framing from the given scene.
*/
eInsertKeyFlags get_keyframing_flags(Scene *scene);
/** \} */
/* -------------------------------------------------------------------- */
@ -173,9 +181,6 @@ bool is_autokey_on(const Scene *scene);
/** Check the mode for auto-keyframing (per scene takes precedence). */
bool is_autokey_mode(const Scene *scene, eAutokey_Mode mode);
/** Check if a flag is set for keyframing (per scene takes precedence). */
bool is_keying_flag(const Scene *scene, eKeying_Flag flag);
/**
* Auto-keyframing feature - checks for whether anything should be done for the current frame.
*/

View File

@ -208,6 +208,27 @@ bool is_keying_flag(const Scene *scene, const eKeying_Flag flag)
return U.keying_flag & flag;
}
eInsertKeyFlags get_keyframing_flags(Scene *scene)
{
eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
/* Visual keying. */
if (is_keying_flag(scene, KEYING_FLAG_VISUALKEY)) {
flag |= INSERTKEY_MATRIX;
}
/* Cycle-aware keyframe insertion - preserve cycle period and flow. */
if (is_keying_flag(scene, KEYING_FLAG_CYCLEAWARE)) {
flag |= INSERTKEY_CYCLE_AWARE;
}
if (is_keying_flag(scene, MANUALKEY_FLAG_INSERTNEEDED)) {
flag |= INSERTKEY_NEEDED;
}
return flag;
}
/** Used to make curves newly added to a cyclic Action cycle with the correct period. */
static void make_new_fcurve_cyclic(FCurve *fcu, const blender::float2 &action_range)
{

View File

@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 23
#define BLENDER_FILE_SUBVERSION 24
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@ -10,6 +10,7 @@
* General operations for brushes.
*/
#include "DNA_brush_enums.h"
#include "DNA_color_types.h"
#include "DNA_object_enums.h"
@ -93,6 +94,10 @@ float BKE_brush_curve_strength_clamped(const Brush *br, float p, float len);
/**
* Uses the brush curve control to find a strength value.
*/
float BKE_brush_curve_strength(eBrushCurvePreset preset,
const CurveMapping *cumap,
float distance,
float brush_radius);
float BKE_brush_curve_strength(const Brush *br, float p, float len);
/* Sampling. */

View File

@ -35,6 +35,16 @@ namespace blender::bke {
namespace greasepencil {
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px`
* was the brush size which would be stored in the stroke thickness and then scaled by the
* point pressure factor. Finally, the render engine would divide this thickness value by
* 2000 (we're going from a thickness to a radius, hence the factor of two) to convert back
* into blender units. With Grease Pencil 3, the radius is no longer stored in `px` space,
* but in blender units (world space) directly. Also note that there is no longer a stroke
* "thickness" attribute, the radii are directly stored on the points.
* For compatibility, legacy thickness values have to be multiplied by this factor. */
constexpr float LEGACY_RADIUS_CONVERSION_FACTOR = 1.0f / 2000.0f;
class DrawingRuntime {
public:
/**

View File

@ -99,7 +99,6 @@ enum class PaintMode : int8_t {
Texture3D = 3,
/** Image space (2D painting). */
Texture2D = 4,
SculptUV = 5,
GPencil = 6,
/* Grease Pencil Vertex Paint */
VertexGPencil = 7,
@ -114,8 +113,6 @@ enum class PaintMode : int8_t {
Invalid = 12,
};
#define PAINT_MODE_HAS_BRUSH(mode) !ELEM(mode, PaintMode::SculptUV)
/* overlay invalidation */
enum ePaintOverlayControlFlags {
PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY = 1,

View File

@ -2546,20 +2546,24 @@ void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask)
}
}
float BKE_brush_curve_strength(const Brush *br, float p, const float len)
float BKE_brush_curve_strength(const eBrushCurvePreset preset,
const CurveMapping *cumap,
const float distance,
const float brush_radius)
{
float p = distance;
float strength = 1.0f;
if (p >= len) {
if (p >= brush_radius) {
return 0;
}
p = p / len;
p = p / brush_radius;
p = 1.0f - p;
switch (br->curve_preset) {
switch (preset) {
case BRUSH_CURVE_CUSTOM:
strength = BKE_curvemapping_evaluateF(br->curve, 0, 1.0f - p);
strength = BKE_curvemapping_evaluateF(cumap, 0, 1.0f - p);
break;
case BRUSH_CURVE_SHARP:
strength = p * p;
@ -2593,6 +2597,11 @@ float BKE_brush_curve_strength(const Brush *br, float p, const float len)
return strength;
}
float BKE_brush_curve_strength(const Brush *br, float p, const float len)
{
return BKE_brush_curve_strength(eBrushCurvePreset(br->curve_preset), br->curve, p, len);
}
float BKE_brush_curve_strength_clamped(const Brush *br, float p, const float len)
{
float strength = BKE_brush_curve_strength(br, p, len);

View File

@ -813,13 +813,7 @@ static void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
BLI_assert(points.size() == gps->totpoints);
const Span<bGPDspoint> src_points{gps->points, gps->totpoints};
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px`
* was the brush size which would be stored in the stroke thickness and then scaled by the
* point pressure factor. Finally, the render engine would divide this thickness value by
* 2000 (we're going from a thickness to a radius, hence the factor of two) to convert back
* into blender units. Store the radius now directly in blender units. This makes it
* consistent with how hair curves handle the radius. */
const float stroke_thickness = float(gps->thickness) / 2000.0f;
const float stroke_thickness = float(gps->thickness) * LEGACY_RADIUS_CONVERSION_FACTOR;
MutableSpan<float3> dst_positions = positions.slice(points);
MutableSpan<float3> dst_handle_positions_left = has_bezier_stroke ?
handle_positions_left.slice(points) :
@ -1213,6 +1207,61 @@ static void thickness_factor_to_modifier(ConversionData &conversion_data,
animdata_thickness_transfer.fcurves_convert_finalize();
}
static void fcurve_convert_thickness_cb(FCurve &fcurve)
{
if (fcurve.bezt) {
for (uint i = 0; i < fcurve.totvert; i++) {
BezTriple &bezier_triple = fcurve.bezt[i];
bezier_triple.vec[0][1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
bezier_triple.vec[1][1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
bezier_triple.vec[2][1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
}
}
if (fcurve.fpt) {
for (uint i = 0; i < fcurve.totvert; i++) {
FPoint &fpoint = fcurve.fpt[i];
fpoint.vec[1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
}
}
fcurve.flag &= ~FCURVE_INT_VALUES;
BKE_fcurve_handles_recalc(&fcurve);
}
static void legacy_object_thickness_modifier_thickness_anim(ConversionData &conversion_data,
Object &object)
{
if (BKE_animdata_from_id(&object.id) == nullptr) {
return;
}
/* Note: At this point, the animation was already transferred to the destination object. Now we
* just need to convert the fcurve data to be in the right space. */
AnimDataConvertor animdata_convert_thickness(
conversion_data,
object.id,
object.id,
{{".thickness", ".thickness", fcurve_convert_thickness_cb}});
LISTBASE_FOREACH (ModifierData *, tmd, &object.modifiers) {
if (ModifierType(tmd->type) != eModifierType_GreasePencilThickness) {
continue;
}
char modifier_name[MAX_NAME * 2];
BLI_str_escape(modifier_name, tmd->name, sizeof(modifier_name));
animdata_convert_thickness.root_path_src = fmt::format("modifiers[\"{}\"]", modifier_name);
animdata_convert_thickness.root_path_dst = fmt::format("modifiers[\"{}\"]", modifier_name);
if (!animdata_convert_thickness.source_has_animation_to_convert()) {
continue;
}
animdata_convert_thickness.fcurves_convert();
}
animdata_convert_thickness.fcurves_convert_finalize();
DEG_relations_tag_update(&conversion_data.bmain);
}
static void layer_adjustments_to_modifiers(ConversionData &conversion_data,
bGPdata &src_object_data,
Object &dst_object)
@ -1225,26 +1274,6 @@ static void layer_adjustments_to_modifiers(ConversionData &conversion_data,
src_object_data.id,
{{".tint_color", ".color"}, {".tint_factor", ".factor"}});
/* Ensure values are divided by 2k, to match conversion done for non-animated value. */
constexpr float thickness_adjustement_factor = 1.0f / 2000.0f;
auto fcurve_convert_thickness_cb = [&](FCurve &fcurve) {
if (fcurve.bezt) {
for (uint i = 0; i < fcurve.totvert; i++) {
BezTriple &bezier_triple = fcurve.bezt[i];
bezier_triple.vec[0][1] *= thickness_adjustement_factor;
bezier_triple.vec[1][1] *= thickness_adjustement_factor;
bezier_triple.vec[2][1] *= thickness_adjustement_factor;
}
}
if (fcurve.fpt) {
for (uint i = 0; i < fcurve.totvert; i++) {
FPoint &fpoint = fcurve.fpt[i];
fpoint.vec[1] *= thickness_adjustement_factor;
}
}
fcurve.flag &= ~FCURVE_INT_VALUES;
BKE_fcurve_handles_recalc(&fcurve);
};
AnimDataConvertor animdata_thickness_transfer(
conversion_data,
dst_object.id,
@ -1301,7 +1330,7 @@ static void layer_adjustments_to_modifiers(ConversionData &conversion_data,
/* Convert the "pixel" offset value into a radius value.
* GPv2 used a conversion of 1 "px" = 0.001. */
/* Note: this offset may be negative. */
const float radius_offset = float(thickness_px) * thickness_adjustement_factor;
const float radius_offset = float(thickness_px) * LEGACY_RADIUS_CONVERSION_FACTOR;
const auto offset_radius_ntree_ensure = [&](Library *owner_library) {
if (bNodeTree **ntree = conversion_data.offset_radius_ntree_by_library.lookup_ptr(
@ -2252,7 +2281,7 @@ static void legacy_object_modifier_thickness(ConversionData &conversion_data,
md_thickness.flag |= MOD_GREASE_PENCIL_THICK_WEIGHT_FACTOR;
}
md_thickness.thickness_fac = legacy_md_thickness.thickness_fac;
md_thickness.thickness = legacy_md_thickness.thickness;
md_thickness.thickness = legacy_md_thickness.thickness * LEGACY_RADIUS_CONVERSION_FACTOR;
legacy_object_modifier_influence(md_thickness.influence,
legacy_md_thickness.layername,
@ -2914,6 +2943,8 @@ static void legacy_gpencil_object_ex(ConversionData &conversion_data, Object &ob
}
legacy_object_modifiers(conversion_data, object);
/* Convert the animation of the "uniform thickness" setting of the thickness modifier. */
legacy_object_thickness_modifier_thickness_anim(conversion_data, object);
/* Layer adjustments should be added after all other modifiers. */
layer_adjustments_to_modifiers(conversion_data, *gpd, object);
@ -2975,95 +3006,87 @@ void legacy_main(Main &bmain, BlendFileReadReport & /*reports*/)
void lineart_wrap_v3(const LineartGpencilModifierData *lmd_legacy,
GreasePencilLineartModifierData *lmd)
{
#define LMD_WRAP(var) lmd->var = lmd_legacy->var
LMD_WRAP(edge_types);
LMD_WRAP(source_type);
LMD_WRAP(use_multiple_levels);
LMD_WRAP(level_start);
LMD_WRAP(level_end);
LMD_WRAP(source_camera);
LMD_WRAP(light_contour_object);
LMD_WRAP(source_object);
LMD_WRAP(source_collection);
LMD_WRAP(target_material);
lmd->edge_types = lmd_legacy->edge_types;
lmd->source_type = lmd_legacy->source_type;
lmd->use_multiple_levels = lmd_legacy->use_multiple_levels;
lmd->level_start = lmd_legacy->level_start;
lmd->level_end = lmd_legacy->level_end;
lmd->source_camera = lmd_legacy->source_camera;
lmd->light_contour_object = lmd_legacy->light_contour_object;
lmd->source_object = lmd_legacy->source_object;
lmd->source_collection = lmd_legacy->source_collection;
lmd->target_material = lmd_legacy->target_material;
STRNCPY(lmd->source_vertex_group, lmd_legacy->source_vertex_group);
STRNCPY(lmd->vgname, lmd_legacy->vgname);
LMD_WRAP(overscan);
LMD_WRAP(shadow_camera_fov);
LMD_WRAP(shadow_camera_size);
LMD_WRAP(shadow_camera_near);
LMD_WRAP(shadow_camera_far);
LMD_WRAP(opacity);
lmd->overscan = lmd_legacy->overscan;
lmd->shadow_camera_fov = lmd_legacy->shadow_camera_fov;
lmd->shadow_camera_size = lmd_legacy->shadow_camera_size;
lmd->shadow_camera_near = lmd_legacy->shadow_camera_near;
lmd->shadow_camera_far = lmd_legacy->shadow_camera_far;
lmd->opacity = lmd_legacy->opacity;
lmd->thickness = lmd_legacy->thickness / 2;
LMD_WRAP(mask_switches);
LMD_WRAP(material_mask_bits);
LMD_WRAP(intersection_mask);
LMD_WRAP(shadow_selection);
LMD_WRAP(silhouette_selection);
LMD_WRAP(crease_threshold);
LMD_WRAP(angle_splitting_threshold);
LMD_WRAP(chain_smooth_tolerance);
LMD_WRAP(chaining_image_threshold);
LMD_WRAP(calculation_flags);
LMD_WRAP(flags);
LMD_WRAP(stroke_depth_offset);
LMD_WRAP(level_start_override);
LMD_WRAP(level_end_override);
LMD_WRAP(edge_types_override);
LMD_WRAP(shadow_selection_override);
LMD_WRAP(shadow_use_silhouette_override);
LMD_WRAP(cache);
LMD_WRAP(la_data_ptr);
#undef LMD_WRAP
lmd->mask_switches = lmd_legacy->mask_switches;
lmd->material_mask_bits = lmd_legacy->material_mask_bits;
lmd->intersection_mask = lmd_legacy->intersection_mask;
lmd->shadow_selection = lmd_legacy->shadow_selection;
lmd->silhouette_selection = lmd_legacy->silhouette_selection;
lmd->crease_threshold = lmd_legacy->crease_threshold;
lmd->angle_splitting_threshold = lmd_legacy->angle_splitting_threshold;
lmd->chain_smooth_tolerance = lmd_legacy->chain_smooth_tolerance;
lmd->chaining_image_threshold = lmd_legacy->chaining_image_threshold;
lmd->calculation_flags = lmd_legacy->calculation_flags;
lmd->flags = lmd_legacy->flags;
lmd->stroke_depth_offset = lmd_legacy->stroke_depth_offset;
lmd->level_start_override = lmd_legacy->level_start_override;
lmd->level_end_override = lmd_legacy->level_end_override;
lmd->edge_types_override = lmd_legacy->edge_types_override;
lmd->shadow_selection_override = lmd_legacy->shadow_selection_override;
lmd->shadow_use_silhouette_override = lmd_legacy->shadow_use_silhouette_override;
lmd->cache = lmd_legacy->cache;
lmd->la_data_ptr = lmd_legacy->la_data_ptr;
}
void lineart_unwrap_v3(LineartGpencilModifierData *lmd_legacy,
const GreasePencilLineartModifierData *lmd)
{
#define LMD_UNWRAP(var) lmd_legacy->var = lmd->var
LMD_UNWRAP(edge_types);
LMD_UNWRAP(source_type);
LMD_UNWRAP(use_multiple_levels);
LMD_UNWRAP(level_start);
LMD_UNWRAP(level_end);
LMD_UNWRAP(source_camera);
LMD_UNWRAP(light_contour_object);
LMD_UNWRAP(source_object);
LMD_UNWRAP(source_collection);
LMD_UNWRAP(target_material);
lmd_legacy->edge_types = lmd->edge_types;
lmd_legacy->source_type = lmd->source_type;
lmd_legacy->use_multiple_levels = lmd->use_multiple_levels;
lmd_legacy->level_start = lmd->level_start;
lmd_legacy->level_end = lmd->level_end;
lmd_legacy->source_camera = lmd->source_camera;
lmd_legacy->light_contour_object = lmd->light_contour_object;
lmd_legacy->source_object = lmd->source_object;
lmd_legacy->source_collection = lmd->source_collection;
lmd_legacy->target_material = lmd->target_material;
STRNCPY(lmd_legacy->source_vertex_group, lmd->source_vertex_group);
STRNCPY(lmd_legacy->vgname, lmd->vgname);
LMD_UNWRAP(overscan);
LMD_UNWRAP(shadow_camera_fov);
LMD_UNWRAP(shadow_camera_size);
LMD_UNWRAP(shadow_camera_near);
LMD_UNWRAP(shadow_camera_far);
LMD_UNWRAP(opacity);
lmd_legacy->overscan = lmd->overscan;
lmd_legacy->shadow_camera_fov = lmd->shadow_camera_fov;
lmd_legacy->shadow_camera_size = lmd->shadow_camera_size;
lmd_legacy->shadow_camera_near = lmd->shadow_camera_near;
lmd_legacy->shadow_camera_far = lmd->shadow_camera_far;
lmd_legacy->opacity = lmd->opacity;
lmd_legacy->thickness = lmd->thickness * 2;
LMD_UNWRAP(mask_switches);
LMD_UNWRAP(material_mask_bits);
LMD_UNWRAP(intersection_mask);
LMD_UNWRAP(shadow_selection);
LMD_UNWRAP(silhouette_selection);
LMD_UNWRAP(crease_threshold);
LMD_UNWRAP(angle_splitting_threshold);
LMD_UNWRAP(chain_smooth_tolerance);
LMD_UNWRAP(chaining_image_threshold);
LMD_UNWRAP(calculation_flags);
LMD_UNWRAP(flags);
LMD_UNWRAP(stroke_depth_offset);
LMD_UNWRAP(level_start_override);
LMD_UNWRAP(level_end_override);
LMD_UNWRAP(edge_types_override);
LMD_UNWRAP(shadow_selection_override);
LMD_UNWRAP(shadow_use_silhouette_override);
LMD_UNWRAP(cache);
LMD_UNWRAP(la_data_ptr);
#undef LMD_UNWRAP
lmd_legacy->mask_switches = lmd->mask_switches;
lmd_legacy->material_mask_bits = lmd->material_mask_bits;
lmd_legacy->intersection_mask = lmd->intersection_mask;
lmd_legacy->shadow_selection = lmd->shadow_selection;
lmd_legacy->silhouette_selection = lmd->silhouette_selection;
lmd_legacy->crease_threshold = lmd->crease_threshold;
lmd_legacy->angle_splitting_threshold = lmd->angle_splitting_threshold;
lmd_legacy->chain_smooth_tolerance = lmd->chain_smooth_tolerance;
lmd_legacy->chaining_image_threshold = lmd->chaining_image_threshold;
lmd_legacy->calculation_flags = lmd->calculation_flags;
lmd_legacy->flags = lmd->flags;
lmd_legacy->stroke_depth_offset = lmd->stroke_depth_offset;
lmd_legacy->level_start_override = lmd->level_start_override;
lmd_legacy->level_end_override = lmd->level_end_override;
lmd_legacy->edge_types_override = lmd->edge_types_override;
lmd_legacy->shadow_selection_override = lmd->shadow_selection_override;
lmd_legacy->shadow_use_silhouette_override = lmd->shadow_use_silhouette_override;
lmd_legacy->cache = lmd->cache;
lmd_legacy->la_data_ptr = lmd->la_data_ptr;
}
} // namespace blender::bke::greasepencil::convert

View File

@ -350,9 +350,6 @@ bool BKE_paint_ensure_from_paintmode(Main *bmain, Scene *sce, PaintMode mode)
paint_tmp = (Paint *)&ts->imapaint;
paint_ptr = &paint_tmp;
break;
case PaintMode::SculptUV:
paint_ptr = (Paint **)&ts->uvsculpt;
break;
case PaintMode::GPencil:
paint_ptr = (Paint **)&ts->gp_paint;
break;
@ -396,8 +393,6 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode)
case PaintMode::Texture2D:
case PaintMode::Texture3D:
return &ts->imapaint.paint;
case PaintMode::SculptUV:
return &ts->uvsculpt->paint;
case PaintMode::GPencil:
return &ts->gp_paint->paint;
case PaintMode::VertexGPencil:
@ -432,8 +427,6 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(const PaintMode m
case PaintMode::Texture2D:
case PaintMode::Texture3D:
return rna_enum_brush_image_tool_items;
case PaintMode::SculptUV:
return rna_enum_brush_uv_sculpt_tool_items;
case PaintMode::GPencil:
return rna_enum_brush_gpencil_types_items;
case PaintMode::VertexGPencil:
@ -479,8 +472,6 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
return &ts->gp_weightpaint->paint;
case OB_MODE_SCULPT_CURVES:
return &ts->curves_sculpt->paint;
case OB_MODE_EDIT:
return ts->uvsculpt ? &ts->uvsculpt->paint : nullptr;
default:
break;
}
@ -509,9 +500,6 @@ Paint *BKE_paint_get_active_from_context(const bContext *C)
if (sima->mode == SI_MODE_PAINT) {
return &ts->imapaint.paint;
}
if (sima->mode == SI_MODE_UV) {
return &ts->uvsculpt->paint;
}
}
else {
return &ts->imapaint.paint;
@ -540,9 +528,6 @@ PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
if (sima->mode == SI_MODE_PAINT) {
return PaintMode::Texture2D;
}
if (sima->mode == SI_MODE_UV) {
return PaintMode::SculptUV;
}
}
else {
return PaintMode::Texture2D;
@ -570,8 +555,6 @@ PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
return PaintMode::Weight;
case OB_MODE_TEXTURE_PAINT:
return PaintMode::Texture3D;
case OB_MODE_EDIT:
return PaintMode::SculptUV;
case OB_MODE_SCULPT_CURVES:
return PaintMode::SculptCurves;
default:
@ -620,8 +603,6 @@ PaintMode BKE_paintmode_get_from_tool(const bToolRef *tref)
switch (tref->mode) {
case SI_MODE_PAINT:
return PaintMode::Texture2D;
case SI_MODE_UV:
return PaintMode::SculptUV;
}
}
@ -779,9 +760,6 @@ void BKE_paint_brush_set_default_references(ToolSettings *ts)
if (ts->vpaint) {
paint_brush_set_default_reference(&ts->vpaint->paint);
}
if (ts->uvsculpt) {
paint_brush_set_default_reference(&ts->uvsculpt->paint);
}
if (ts->gp_paint) {
paint_brush_set_default_reference(&ts->gp_paint->paint);
}
@ -834,9 +812,6 @@ static void paint_runtime_init(const ToolSettings *ts, Paint *paint)
else if (ts->wpaint && paint == &ts->wpaint->paint) {
paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT;
}
else if (ts->uvsculpt && paint == &ts->uvsculpt->paint) {
paint->runtime.ob_mode = OB_MODE_EDIT;
}
else if (ts->gp_paint && paint == &ts->gp_paint->paint) {
paint->runtime.ob_mode = OB_MODE_PAINT_GPENCIL_LEGACY;
}
@ -871,8 +846,6 @@ uint BKE_paint_get_brush_tool_offset_from_paintmode(const PaintMode mode)
return offsetof(Brush, vertexpaint_tool);
case PaintMode::Weight:
return offsetof(Brush, weightpaint_tool);
case PaintMode::SculptUV:
return offsetof(Brush, uv_sculpt_tool);
case PaintMode::GPencil:
return offsetof(Brush, gpencil_tool);
case PaintMode::VertexGPencil:
@ -1213,8 +1186,6 @@ eObjectMode BKE_paint_object_mode_from_paintmode(const PaintMode mode)
case PaintMode::Texture2D:
case PaintMode::Texture3D:
return OB_MODE_TEXTURE_PAINT;
case PaintMode::SculptUV:
return OB_MODE_EDIT;
case PaintMode::SculptCurves:
return OB_MODE_SCULPT_CURVES;
case PaintMode::GPencil:
@ -1247,7 +1218,6 @@ bool BKE_paint_ensure(Main *bmain, ToolSettings *ts, Paint **r_paint)
(Paint *)ts->sculpt,
(Paint *)ts->vpaint,
(Paint *)ts->wpaint,
(Paint *)ts->uvsculpt,
(Paint *)ts->curves_sculpt,
(Paint *)&ts->imapaint));
#ifndef NDEBUG
@ -1289,10 +1259,6 @@ bool BKE_paint_ensure(Main *bmain, ToolSettings *ts, Paint **r_paint)
GpWeightPaint *data = MEM_cnew<GpWeightPaint>(__func__);
paint = &data->paint;
}
else if ((UvSculpt **)r_paint == &ts->uvsculpt) {
UvSculpt *data = MEM_cnew<UvSculpt>(__func__);
paint = &data->paint;
}
else if ((CurvesSculpt **)r_paint == &ts->curves_sculpt) {
CurvesSculpt *data = MEM_cnew<CurvesSculpt>(__func__);
paint = &data->paint;

View File

@ -705,14 +705,6 @@ static void scene_foreach_toolsettings(LibraryForeachIDData *data,
}
toolsett_old->sculpt->gravity_object = gravity_object_old;
}
if (toolsett_old->uvsculpt) {
paint = toolsett->uvsculpt ? &toolsett->uvsculpt->paint : nullptr;
paint_old = &toolsett_old->uvsculpt->paint;
BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
data,
do_undo_restore,
scene_foreach_paint(data, paint, do_undo_restore, reader, paint_old));
}
if (toolsett_old->gp_paint) {
paint = toolsett->gp_paint ? &toolsett->gp_paint->paint : nullptr;
paint_old = &toolsett_old->gp_paint->paint;
@ -1038,9 +1030,8 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres
BKE_paint_blend_write(writer, &tos->sculpt->paint);
}
if (tos->uvsculpt) {
BLO_write_struct(writer, UvSculpt, tos->uvsculpt);
BKE_paint_blend_write(writer, &tos->uvsculpt->paint);
if (tos->uvsculpt.strength_curve) {
BKE_curvemapping_blend_write(writer, tos->uvsculpt.strength_curve);
}
if (tos->gp_paint) {
BLO_write_struct(writer, GpPaint, tos->gp_paint);
@ -1242,7 +1233,6 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->sculpt);
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->vpaint);
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->wpaint);
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->uvsculpt);
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->gp_paint);
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->gp_vertexpaint);
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->gp_sculptpaint);
@ -1255,6 +1245,11 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
sce->toolsettings->particle.scene = nullptr;
sce->toolsettings->particle.object = nullptr;
sce->toolsettings->gp_sculpt.paintcursor = nullptr;
if (sce->toolsettings->uvsculpt.strength_curve) {
BLO_read_struct(reader, CurveMapping, &sce->toolsettings->uvsculpt.strength_curve);
BKE_curvemapping_blend_read(reader, sce->toolsettings->uvsculpt.strength_curve);
BKE_curvemapping_init(sce->toolsettings->uvsculpt.strength_curve);
}
if (sce->toolsettings->sculpt) {
BLO_read_struct(reader, CurveMapping, &sce->toolsettings->sculpt->automasking_cavity_curve);
@ -1654,9 +1649,9 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
BKE_curvemapping_init(ts->sculpt->automasking_cavity_curve_op);
}
}
if (ts->uvsculpt) {
ts->uvsculpt = static_cast<UvSculpt *>(MEM_dupallocN(ts->uvsculpt));
BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag);
if (ts->uvsculpt.strength_curve) {
ts->uvsculpt.strength_curve = BKE_curvemapping_copy(ts->uvsculpt.strength_curve);
BKE_curvemapping_init(ts->uvsculpt.strength_curve);
}
if (ts->gp_paint) {
ts->gp_paint = static_cast<GpPaint *>(MEM_dupallocN(ts->gp_paint));
@ -1720,9 +1715,8 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
BKE_paint_free(&toolsettings->sculpt->paint);
MEM_freeN(toolsettings->sculpt);
}
if (toolsettings->uvsculpt) {
BKE_paint_free(&toolsettings->uvsculpt->paint);
MEM_freeN(toolsettings->uvsculpt);
if (toolsettings->uvsculpt.strength_curve) {
BKE_curvemapping_free(toolsettings->uvsculpt.strength_curve);
}
if (toolsettings->gp_paint) {
BKE_paint_free(&toolsettings->gp_paint->paint);

View File

@ -797,9 +797,6 @@ static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMa
if (ts->sculpt) {
callback(ts->sculpt->paint.cavity_curve);
}
if (ts->uvsculpt) {
callback(ts->uvsculpt->paint.cavity_curve);
}
if (ts->gp_paint) {
callback(ts->gp_paint->paint.cavity_curve);
}

View File

@ -3491,12 +3491,6 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 302, 6)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
ToolSettings *ts = scene->toolsettings;
if (ts->uv_relax_method == 0) {
ts->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN;
}
}
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
ToolSettings *tool_settings = scene->toolsettings;
tool_settings->snap_flag_seq = tool_settings->snap_flag &

View File

@ -1966,13 +1966,6 @@ static void versioning_nodes_dynamic_sockets_2(bNodeTree &ntree)
static void versioning_grease_pencil_stroke_radii_scaling(GreasePencil *grease_pencil)
{
using namespace blender;
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px` was
* the brush size which would be stored in the stroke thickness and then scaled by the point
* pressure factor. Finally, the render engine would divide this thickness value by 2000 (we're
* going from a thickness to a radius, hence the factor of two) to convert back into blender
* units.
* Store the radius now directly in blender units. This makes it consistent with how hair curves
* handle the radius. */
for (GreasePencilDrawingBase *base : grease_pencil->drawings()) {
if (base->type != GP_DRAWING) {
continue;
@ -1981,7 +1974,7 @@ static void versioning_grease_pencil_stroke_radii_scaling(GreasePencil *grease_p
MutableSpan<float> radii = drawing.radii_for_write();
threading::parallel_for(radii.index_range(), 8192, [&](const IndexRange range) {
for (const int i : range) {
radii[i] /= 2000.0f;
radii[i] *= bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR;
}
});
}
@ -2983,9 +2976,6 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
input_sample_values[2] = ts->curves_sculpt != nullptr ?
ts->curves_sculpt->paint.num_input_samples_deprecated :
1;
input_sample_values[3] = ts->uvsculpt != nullptr ?
ts->uvsculpt->paint.num_input_samples_deprecated :
1;
input_sample_values[4] = ts->gp_paint != nullptr ?
ts->gp_paint->paint.num_input_samples_deprecated :
@ -3265,6 +3255,18 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 23)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
ToolSettings *ts = scene->toolsettings;
if (!ts->uvsculpt.strength_curve) {
ts->uvsculpt.size = 50;
ts->uvsculpt.strength = 1.0f;
ts->uvsculpt.curve_preset = BRUSH_CURVE_SMOOTH;
ts->uvsculpt.strength_curve = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 24)) {
update_paint_modes_for_brush_assets(*bmain);
}

View File

@ -59,15 +59,17 @@ void Light::sync(ShadowModule &shadows, const Object *ob, float threshold)
this->color = float3(&la->r) * la->energy;
float3 scale;
this->object_mat = ob->object_to_world();
this->object_mat.view<3, 3>() = normalize_and_get_size(this->object_mat.view<3, 3>(), scale);
float4x4 object_to_world = ob->object_to_world();
object_to_world.view<3, 3>() = normalize_and_get_size(object_to_world.view<3, 3>(), scale);
/* Make sure we have consistent handedness (in case of negatively scaled Z axis). */
float3 back = cross(float3(this->_right), float3(this->_up));
if (dot(back, float3(this->_back)) < 0.0f) {
negate_v3(this->_up);
float3 back = cross(float3(object_to_world.x_axis()), float3(object_to_world.y_axis()));
if (dot(back, float3(object_to_world.z_axis())) < 0.0f) {
negate_v3(object_to_world.y_axis());
}
this->object_to_world = object_to_world;
shape_parameters_set(la, scale, threshold);
const bool diffuse_visibility = (ob->visibility_flag & OB_HIDE_DIFFUSE) == 0;
@ -93,7 +95,7 @@ void Light::sync(ShadowModule &shadows, const Object *ob, float threshold)
if (la->mode & LA_SHADOW) {
shadow_ensure(shadows);
if (is_sun_light(this->type)) {
this->directional->sync(this->object_mat,
this->directional->sync(object_to_world,
1.0f,
la->sun_angle * la->shadow_softness_factor,
la->shadow_trace_distance);
@ -113,7 +115,7 @@ void Light::sync(ShadowModule &shadows, const Object *ob, float threshold)
shadow_radius = la->shadow_softness_factor * la->radius;
}
this->punctual->sync(this->type,
this->object_mat,
object_to_world,
la->spotsize,
radius,
this->local.influence_radius_max,
@ -293,7 +295,9 @@ float Light::point_radiance_get()
void Light::debug_draw()
{
#ifndef NDEBUG
drw_debug_sphere(float3(_position), local.influence_radius_max, float4(0.8f, 0.3f, 0.0f, 1.0f));
drw_debug_sphere(transform_location(this->object_to_world),
local.influence_radius_max,
float4(0.8f, 0.3f, 0.0f, 1.0f));
#endif
}

View File

@ -43,6 +43,80 @@ constexpr GPUSamplerState with_filter = {GPU_SAMPLER_FILTERING_LINEAR};
#define UBO_MIN_MAX_SUPPORTED_SIZE 1 << 14
/* -------------------------------------------------------------------- */
/** \name Transform
* \{ */
struct Transform {
/* The transform is stored transposed for compactness. */
float4 x, y, z;
#if IS_CPP
Transform() = default;
Transform(const float4x4 &tx)
: x(tx[0][0], tx[1][0], tx[2][0], tx[3][0]),
y(tx[0][1], tx[1][1], tx[2][1], tx[3][1]),
z(tx[0][2], tx[1][2], tx[2][2], tx[3][2])
{
}
operator float4x4() const
{
return float4x4(float4(x.x, y.x, z.x, 0.0f),
float4(x.y, y.y, z.y, 0.0f),
float4(x.z, y.z, z.z, 0.0f),
float4(x.w, y.w, z.w, 1.0f));
}
#endif
};
static inline float3 transform_x_axis(Transform t)
{
return float3(t.x.x, t.y.x, t.z.x);
}
static inline float3 transform_y_axis(Transform t)
{
return float3(t.x.y, t.y.y, t.z.y);
}
static inline float3 transform_z_axis(Transform t)
{
return float3(t.x.z, t.y.z, t.z.z);
}
static inline float3 transform_location(Transform t)
{
return float3(t.x.w, t.y.w, t.z.w);
}
static inline float3 transform_point(Transform t, float3 point)
{
return float4(point, 1.0f) * float3x4(t.x, t.y, t.z);
}
static inline float3 transform_direction(Transform t, float3 direction)
{
return direction * float3x3(float3(t.x.x, t.x.y, t.x.z),
float3(t.y.x, t.y.y, t.y.z),
float3(t.z.x, t.z.y, t.z.z));
}
static inline float3 transform_direction_transposed(Transform t, float3 direction)
{
return float3x3(float3(t.x.x, t.x.y, t.x.z),
float3(t.y.x, t.y.y, t.y.z),
float3(t.z.x, t.z.y, t.z.z)) *
direction;
}
/* Assumes the transform has unit scale. */
static inline float3 transform_point_inversed(Transform t, float3 point)
{
return float3x3(float3(t.x.x, t.x.y, t.x.z),
float3(t.y.x, t.y.y, t.y.z),
float3(t.z.x, t.z.y, t.z.z)) *
(point - transform_location(t));
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Debug Mode
* \{ */
@ -870,21 +944,8 @@ BLI_STATIC_ASSERT(sizeof(LightSunData) == sizeof(LightLocalData), "Data size mus
#endif
struct LightData {
/** Normalized object to world matrix. */
/* TODO(fclem): Use float4x3. */
float4x4 object_mat;
/** Aliases for axes. */
#ifndef USE_GPU_SHADER_CREATE_INFO
# define _right object_mat[0]
# define _up object_mat[1]
# define _back object_mat[2]
# define _position object_mat[3]
#else
# define _right object_mat[0].xyz
# define _up object_mat[1].xyz
# define _back object_mat[2].xyz
# define _position object_mat[3].xyz
#endif
/** Normalized object to world matrix. Stored transposed for compactness. */
Transform object_to_world;
/** Power depending on shader type. Referenced by LightingType. */
float4 power;
@ -922,6 +983,23 @@ struct LightData {
};
BLI_STATIC_ASSERT_ALIGN(LightData, 16)
static inline float3 light_x_axis(LightData light)
{
return transform_x_axis(light.object_to_world);
}
static inline float3 light_y_axis(LightData light)
{
return transform_y_axis(light.object_to_world);
}
static inline float3 light_z_axis(LightData light)
{
return transform_z_axis(light.object_to_world);
}
static inline float3 light_position_get(LightData light)
{
return transform_location(light.object_to_world);
}
#ifdef GPU_SHADER
# define CHECK_TYPE_PAIR(a, b)
# define CHECK_TYPE(a, b)

View File

@ -370,11 +370,7 @@ void ShadowPunctual::end_sync(Light &light, float lod_bias)
compute_projection_boundaries(
light.type, light_radius_, shadow_radius_, max_distance_, near, far, side, shift);
float4x4 obmat_tmp = light.object_mat;
/* Clear embedded custom data. */
obmat_tmp[0][3] = obmat_tmp[1][3] = obmat_tmp[2][3] = 0.0f;
obmat_tmp[3][3] = 1.0f;
float4x4 obmat_tmp = light.object_to_world;
/* Acquire missing tile-maps. */
while (tilemaps_.size() < tilemaps_needed_) {
@ -519,7 +515,9 @@ void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera
float2 farthest_tilemap_center = local_view_direction * half_size * (levels_range.size() - 1);
/* Offset for smooth level transitions. */
light.object_mat.location() = near_point;
light.object_to_world.x.w = near_point.x;
light.object_to_world.y.w = near_point.y;
light.object_to_world.z.w = near_point.z;
/* Offset in tiles from the scene origin to the center of the first tile-maps. */
int2 origin_offset = int2(round(float2(near_point) / tile_size));
@ -637,7 +635,10 @@ void ShadowDirectional::clipmap_tilemaps_distribution(Light &light,
light.type = LIGHT_SUN;
/* Used for selecting the clipmap level. */
light.object_mat.location() = camera.position() * float3x3(object_mat_.view<3, 3>());
float3 location = camera.position() * float3x3(object_mat_.view<3, 3>());
light.object_to_world.x.w = location.x;
light.object_to_world.y.w = location.y;
light.object_to_world.z.w = location.z;
/* Used as origin for the clipmap_base_offset trick. */
light.sun.clipmap_origin = float2(level_offset_max * tile_size_max);

View File

@ -117,10 +117,8 @@ void SyncModule::sync_mesh(Object *ob,
return;
}
if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) {
/** NOTE:
* EEVEE doesn't render meshes with bounds or wire display type in the viewport,
* but Cycles does. */
if ((ob->dt < OB_SOLID) && ((inst_.is_viewport() && inst_.v3d->shading.type != OB_RENDER))) {
/** Do not render objects with display type lower than solid when in material preview mode. */
return;
}

View File

@ -38,11 +38,14 @@ void main()
LightSpotData spot = light_spot_data_get(light);
/* Only for < ~170 degree Cone due to plane extraction precision. */
if (spot.spot_tan < 10.0) {
vec3 x_axis = light_x_axis(light);
vec3 y_axis = light_y_axis(light);
vec3 z_axis = light_z_axis(light);
Pyramid pyramid = shape_pyramid_non_oblique(
light._position,
light._position - light._back * spot.influence_radius_max,
light._right * spot.influence_radius_max * spot.spot_tan / spot.spot_size_inv.x,
light._up * spot.influence_radius_max * spot.spot_tan / spot.spot_size_inv.y);
light_position_get(light),
light_position_get(light) - z_axis * spot.influence_radius_max,
x_axis * spot.influence_radius_max * spot.spot_tan / spot.spot_size_inv.x,
y_axis * spot.influence_radius_max * spot.spot_tan / spot.spot_size_inv.y);
if (!intersect_view(pyramid)) {
return;
}
@ -52,7 +55,7 @@ void main()
case LIGHT_ELLIPSE:
case LIGHT_OMNI_SPHERE:
case LIGHT_OMNI_DISK:
sphere.center = light._position;
sphere.center = light_position_get(light);
sphere.radius = light_local_data_get(light).influence_radius_max;
break;
default:
@ -66,7 +69,7 @@ void main()
if (intersect_view(sphere)) {
uint index = atomicAdd(light_cull_buf.visible_count, 1u);
float z_dist = dot(drw_view_forward(), light._position) -
float z_dist = dot(drw_view_forward(), light_position_get(light)) -
dot(drw_view_forward(), drw_view_position());
out_zdist_buf[index] = z_dist;
out_key_buf[index] = l_idx;

View File

@ -148,10 +148,10 @@ void main()
LightData light = light_buf[l_idx];
/* Culling in view space for precision and simplicity. */
vec3 vP = drw_point_world_to_view(light._position);
vec3 v_right = drw_normal_world_to_view(light._right);
vec3 v_up = drw_normal_world_to_view(light._up);
vec3 v_back = drw_normal_world_to_view(light._back);
vec3 vP = drw_point_world_to_view(light_position_get(light));
vec3 v_right = drw_normal_world_to_view(light_x_axis(light));
vec3 v_up = drw_normal_world_to_view(light_y_axis(light));
vec3 v_back = drw_normal_world_to_view(light_z_axis(light));
float radius = light_local_data_get(light).influence_radius_max;
Sphere sphere = shape_sphere(vP, radius);

View File

@ -36,7 +36,7 @@ void main()
continue;
}
LightData light = light_buf[index];
vec3 P = light._position;
vec3 P = light_position_get(light);
/* TODO(fclem): Could have better bounds for spot and area lights. */
float radius = light_local_data_get(light).influence_radius_max;
float z_dist = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());

View File

@ -24,11 +24,11 @@ LightVector light_vector_get(LightData light, const bool is_directional, vec3 P)
{
LightVector lv;
if (is_directional) {
lv.L = light._back;
lv.L = light_z_axis(light);
lv.dist = 1.0;
}
else {
lv.L = light._position - P;
lv.L = light_position_get(light) - P;
float inv_distance = inversesqrt(length_squared(lv.L));
lv.L *= inv_distance;
lv.dist = 1.0 / inv_distance;
@ -42,21 +42,17 @@ LightVector light_shape_vector_get(LightData light, const bool is_directional, v
if (!is_directional && is_area_light(light.type)) {
LightAreaData area = light_area_data_get(light);
vec3 L = P - light._position;
vec2 closest_point = vec2(dot(light._right, L), dot(light._up, L));
closest_point /= area.size;
vec3 lP = transform_point_inversed(light.object_to_world, P);
vec2 ls_closest_point = lP.xy;
if (light.type == LIGHT_ELLIPSE) {
closest_point /= max(1.0, length(closest_point));
ls_closest_point /= max(1.0, length(ls_closest_point / area.size));
}
else {
closest_point = clamp(closest_point, -1.0, 1.0);
ls_closest_point = clamp(ls_closest_point, -area.size, area.size);
}
closest_point *= area.size;
vec3 ws_closest_point = transform_point(light.object_to_world, vec3(ls_closest_point, 0.0));
vec3 L_prime = light._right * closest_point.x + light._up * closest_point.y;
L = L_prime - L;
vec3 L = ws_closest_point - P;
float inv_distance = inversesqrt(length_squared(L));
LightVector lv;
lv.L = L * inv_distance;
@ -70,19 +66,7 @@ LightVector light_shape_vector_get(LightData light, const bool is_directional, v
/* Rotate vector to light's local space. Does not translate. */
vec3 light_world_to_local(LightData light, vec3 L)
{
/* Avoid relying on compiler to optimize this.
* vec3 lL = transpose(mat3(light.object_mat)) * L; */
vec3 lL;
lL.x = dot(light.object_mat[0].xyz, L);
lL.y = dot(light.object_mat[1].xyz, L);
lL.z = dot(light.object_mat[2].xyz, L);
return lL;
}
/* Transform position from light's local space to world space. Does translation. */
vec3 light_local_position_to_world(LightData light, vec3 lP)
{
return mat3(light.object_mat) * lP + light._position;
return transform_direction_transposed(light.object_to_world, L);
}
/* From Frostbite PBR Course
@ -101,7 +85,7 @@ float light_spot_attenuation(LightData light, vec3 L)
vec3 lL = light_world_to_local(light, L);
float ellipse = inversesqrt(1.0 + length_squared(lL.xy * spot.spot_size_inv / lL.z));
float spotmask = smoothstep(0.0, 1.0, ellipse * spot.spot_mul + spot.spot_bias);
return spotmask * step(0.0, -dot(L, -light._back));
return (lL.z > 0.0) ? spotmask : 0.0;
}
float light_attenuation_common(LightData light, const bool is_directional, vec3 L)
@ -113,7 +97,7 @@ float light_attenuation_common(LightData light, const bool is_directional, vec3
return light_spot_attenuation(light, L);
}
if (is_area_light(light.type)) {
return step(0.0, -dot(L, -light._back));
return float(dot(L, light_z_axis(light)) > 0.0);
}
return 1.0;
}
@ -202,7 +186,7 @@ float light_point_light(LightData light, const bool is_directional, LightVector
if (is_area_light(light.type)) {
/* Modulate by light plane orientation / solid angle. */
power *= saturate(dot(light._back, lv.L));
power *= saturate(dot(light_z_axis(light), lv.L));
}
return power;
}
@ -227,12 +211,15 @@ float light_ltc(
return 1.0;
}
vec3 Px = light_x_axis(light);
vec3 Py = light_y_axis(light);
if (light.type == LIGHT_RECT) {
LightAreaData area = light_area_data_get(light);
vec3 corners[4];
corners[0] = light._right * area.size.x + light._up * -area.size.y;
corners[1] = light._right * area.size.x + light._up * area.size.y;
corners[0] = Px * area.size.x + Py * -area.size.y;
corners[1] = Px * area.size.x + Py * area.size.y;
corners[2] = -corners[0];
corners[3] = -corners[1];
@ -247,9 +234,6 @@ float light_ltc(
return ltc_evaluate_quad(utility_tx, corners, vec3(0.0, 0.0, 1.0));
}
else {
vec3 Px = light._right;
vec3 Py = light._up;
if (!is_area_light(light.type)) {
make_orthonormal_basis(lv.L, Px, Py);
}

View File

@ -124,11 +124,6 @@ bool debug_tilemaps(vec3 P, LightData light)
out_color_add = vec4(debug_tile_state_color(light.type, tile), 0.0);
out_color_mul = vec4(0.0);
# ifdef DRW_DEBUG_PRINT
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
drw_print(light.object_mat);
}
# endif
return true;
}
#else
@ -144,11 +139,6 @@ bool debug_tilemaps(vec3 P, LightData light)
out_color_add = vec4(debug_tile_state_color(tile), 0.0);
out_color_mul = vec4(0.0);
# ifdef DRW_DEBUG_PRINT
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
drw_print(light.object_mat);
}
# endif
return true;
}
#endif
@ -186,7 +176,7 @@ void debug_random_tilemap_color(vec3 P, LightData light)
coord = shadow_directional_coordinates(light, lP);
}
else {
vec3 lP = light_world_to_local(light, P - light._position);
vec3 lP = light_world_to_local(light, P - light_position_get(light));
int face_id = shadow_punctual_face_index_get(lP);
lP = shadow_punctual_local_position_to_face_local(face_id, lP);
coord = shadow_punctual_coordinates(light, lP, face_id);

View File

@ -152,12 +152,12 @@ vec3 shadow_punctual_reconstruct_position(ShadowSampleParams params,
vec3 lP = project_point(wininv, clip_P);
int face_id = params.tilemap_index - light.tilemap_index;
lP = shadow_punctual_face_local_to_local_position(face_id, lP);
return mat3(light.object_mat) * lP + light._position;
return transform_point(light.object_to_world, lP);
}
ShadowSampleParams shadow_punctual_sample_params_get(LightData light, vec3 P)
{
vec3 lP = (P - light._position) * mat3(light.object_mat);
vec3 lP = transform_point_inversed(light.object_to_world, P);
int face_id = shadow_punctual_face_index_get(lP);
/* Local Light Space > Face Local (View) Space. */
@ -205,7 +205,7 @@ ShadowDirectionalSampleInfo shadow_directional_sample_info_get(LightData light,
info.clip_near = orderedIntBitsToFloat(light.clip_near);
info.clip_far = orderedIntBitsToFloat(light.clip_far);
int level = shadow_directional_level(light, lP - light._position);
int level = shadow_directional_level(light, lP - light_position_get(light));
/* This difference needs to be less than 32 for the later shift to be valid.
* This is ensured by ShadowDirectional::clipmap_level_range(). */
info.level_relative = level - light_sun_data_get(light).clipmap_lod_min;
@ -234,14 +234,14 @@ vec3 shadow_directional_reconstruct_position(ShadowSampleParams params, LightDat
lP.xy = clipmap_pos + info.clipmap_origin;
lP.z = (params.uv.z + info.clip_near) * -1.0;
return mat3(light.object_mat) * lP;
return transform_direction_transposed(light.object_to_world, lP);
}
ShadowSampleParams shadow_directional_sample_params_get(usampler2D tilemaps_tx,
LightData light,
vec3 P)
{
vec3 lP = P * mat3(light.object_mat);
vec3 lP = transform_direction(light.object_to_world, P);
ShadowDirectionalSampleInfo info = shadow_directional_sample_info_get(light, lP);
ShadowCoordinates coord = shadow_directional_coordinates(light, lP);

View File

@ -55,15 +55,15 @@ void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radi
/* TODO(Miguel Pozo): Implement lod_bias support. */
if (radius == 0.0) {
int level = shadow_directional_level(light, lP - light._position);
int level = shadow_directional_level(light, lP - light_position_get(light));
ShadowCoordinates coord = shadow_directional_coordinates_at_level(light, lP, level);
shadow_tag_usage_tile(light, coord.tile_coord, 0, coord.tilemap_index);
}
else {
vec3 start_lP = light_world_to_local(light, P - V * radius);
vec3 end_lP = light_world_to_local(light, P + V * radius);
int min_level = shadow_directional_level(light, start_lP - light._position);
int max_level = shadow_directional_level(light, end_lP - light._position);
int min_level = shadow_directional_level(light, start_lP - light_position_get(light));
int max_level = shadow_directional_level(light, end_lP - light_position_get(light));
for (int level = min_level; level <= max_level; level++) {
ShadowCoordinates coord_min = shadow_directional_coordinates_at_level(
@ -89,7 +89,7 @@ void shadow_tag_usage_tilemap_punctual(
return;
}
vec3 lP = light_world_to_local(light, P - light._position);
vec3 lP = light_world_to_local(light, P - light_position_get(light));
float dist_to_light = max(length(lP) - radius, 1e-5);
if (dist_to_light > light_local_data_get(light).influence_radius_max) {
return;

View File

@ -111,7 +111,9 @@ void main()
set_clipmap_data(light, 0, 2, 0.0, 0.0);
light.tilemap_index = light_sun_data_get(light).clipmap_lod_min;
light._position = vec3(0.0);
light.object_to_world.x = float4(1.0, 0.0, 0.0, 0.0);
light.object_to_world.y = float4(0.0, 1.0, 0.0, 0.0);
light.object_to_world.z = float4(0.0, 0.0, 1.0, 0.0);
light.lod_bias = 0;
float lod_min_tile_size = exp2(float(light_sun_data_get(light).clipmap_lod_min)) /
@ -226,7 +228,9 @@ void main()
// clipmap_lod_max = 2; /* 3 tile-maps. */
set_clipmap_data(light, 0, 2, 0.0, 0.0);
light.tilemap_index = 1;
light._position = vec3(0.0);
light.object_to_world.x = float4(1.0, 0.0, 0.0, 0.0);
light.object_to_world.y = float4(0.0, 1.0, 0.0, 0.0);
light.object_to_world.z = float4(0.0, 0.0, 1.0, 0.0);
light.lod_bias = light_sun_data_get(light).clipmap_lod_min - 1;
float lod_tile_size = exp2(float(light_sun_data_get(light).clipmap_lod_min)) /
float(SHADOW_TILEMAP_RES);

View File

@ -53,7 +53,7 @@ void main()
float local_min = FLT_MAX;
float local_max = -FLT_MAX;
for (int i = 0; i < 8; i++) {
float z = dot(box.corners[i].xyz, -light._back);
float z = dot(box.corners[i].xyz, -light_z_axis(light));
local_min = min(local_min, z);
local_max = max(local_max, z);
}

View File

@ -105,7 +105,7 @@ ShadowSamplingTile shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int t
* This function should be the inverse of ShadowDirectional::coverage_get().
*
* \a lP shading point position in light space, relative to the to camera position snapped to
* the smallest clip-map level (`shadow_world_to_local(light, P) - light._position`).
* the smallest clip-map level (`shadow_world_to_local(light, P) - light_position_get(light)`).
*/
float shadow_directional_level_fractional(LightData light, vec3 lP)
@ -149,7 +149,7 @@ float shadow_punctual_footprint_ratio(LightData light,
* This gives a good approximation of what LOD to select to get a somewhat uniform shadow map
* resolution in screen space. */
float dist_to_light = distance(P, light._position);
float dist_to_light = distance(P, light_position_get(light));
float footprint_ratio = dist_to_light;
/* Project the radius to the screen. 1 unit away from the camera the same way
* pixel_world_radius_inv was computed. Not needed in orthographic mode. */
@ -225,7 +225,7 @@ ShadowCoordinates shadow_directional_coordinates_at_level(LightData light, vec3
*/
ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP)
{
int level = shadow_directional_level(light, lP - light._position);
int level = shadow_directional_level(light, lP - light_position_get(light));
return shadow_directional_coordinates_at_level(light, lP, level);
}

View File

@ -247,7 +247,7 @@ ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state,
/* Ray position is ray local position with origin at light origin. */
vec4 ray_pos = ray.origin + ray.direction * state.ray_time;
int level = shadow_directional_level(ray.light, ray_pos.xyz - ray.light._position);
int level = shadow_directional_level(ray.light, ray_pos.xyz - light_position_get(ray.light));
/* This difference needs to be less than 32 for the later shift to be valid.
* This is ensured by ShadowDirectional::clipmap_level_range(). */
int level_relative = level - light_sun_data_get(ray.light).clipmap_lod_min;
@ -460,7 +460,7 @@ vec3 shadow_pcf_offset(LightData light, const bool is_directional, vec3 P, vec3
/* Scale the offset based on shadow LOD. */
if (is_directional) {
vec3 lP = light_world_to_local(light, P);
float level = shadow_directional_level_fractional(light, lP - light._position);
float level = shadow_directional_level_fractional(light, lP - light_position_get(light));
float pcf_scale = mix(0.5, 1.0, fract(level));
pcf_offset *= pcf_scale;
}
@ -550,7 +550,7 @@ ShadowEvalResult shadow_eval(LightData light,
P += N_bias * normal_offset;
vec3 lP = is_directional ? light_world_to_local(light, P) :
light_world_to_local(light, P - light._position);
light_world_to_local(light, P - light_position_get(light));
vec3 lNg = light_world_to_local(light, Ng);
/* Invert horizon clipping. */
lNg = (is_transmission) ? -lNg : lNg;

View File

@ -199,7 +199,7 @@ vec3 volume_light(LightData light, const bool is_directional, LightVector lv)
if (light.type == LIGHT_RECT || light.type == LIGHT_ELLIPSE) {
/* Modulate by light plane orientation / solid angle. */
power *= saturate(dot(light._back, lv.L));
power *= saturate(dot(light_z_axis(light), lv.L));
}
}
return light.color * light.power[LIGHT_VOLUME] * power;

View File

@ -525,8 +525,7 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_PrivateData *pd,
const GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
const bool is_in_front = (ob->dtx & OB_DRAW_IN_FRONT);
/* Grease Pencil 3 doesn't have this. */
const bool is_screenspace = false;
const bool override_vertcol = (pd->v3d_color_type != -1);
const bool is_vert_col_mode = (pd->v3d_color_type == V3D_SHADING_VERTEX_COLOR) ||
(ob->mode == OB_MODE_VERTEX_PAINT) || pd->is_render;
@ -541,9 +540,9 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_PrivateData *pd,
const float vert_col_opacity = (override_vertcol) ?
(is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) :
(pd->is_render ? 1.0f : pd->vertex_paint_opacity);
/* Negate thickness sign to tag that strokes are in screen space.
* Convert to world units (by default, 1 meter = 1000 pixels). */
const float thickness_scale = (is_screenspace) ? -1.0f : 1.0f / 1000.0f;
/* Negate thickness sign to tag that strokes are in screen space (this is no longer used in
* GPv3). Convert to world units (by default, 1 meter = 1000 pixels). */
const float thickness_scale = blender::bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR;
/* If the layer is used as a mask (but is otherwise not visible in the render), render it with a
* opacity of 0 so that it can still mask other layers. */
const float layer_opacity = !is_used_as_mask ? grease_pencil_layer_final_opacity_get(

View File

@ -750,9 +750,9 @@ static void grease_pencil_geom_batch_ensure(Object &object,
const float3 pos = math::transform_point(layer_space_to_object_space, positions[point_i]);
copy_v3_v3(s_vert.pos, pos);
s_vert.radius = radii[point_i] * ((end_cap == GP_STROKE_CAP_TYPE_ROUND) ? 1.0f : -1.0f);
/* Convert to legacy "pixel" space. The shader expects the values to be in this space.
* Otherwise the values will get clamped. */
s_vert.radius *= 1000.0f;
/* Convert to legacy "pixel" space. We divide here, because the shader expects the values to
* be in the `px` space rather than world space. Otherwise the values will get clamped. */
s_vert.radius /= bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR;
s_vert.opacity = opacities[point_i] *
((start_cap == GP_STROKE_CAP_TYPE_ROUND) ? 1.0f : -1.0f);
s_vert.point_id = verts_range[idx];

View File

@ -383,7 +383,7 @@ PassType *drw_volume_object_mesh_init(PassType &ps,
volume_infos.grids_xform[grid_id++] = float4x4::identity();
}
}
else if (!fds->fluid) {
else if (fds->fluid) {
/* Smoke Simulation. */
DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE);

View File

@ -5142,7 +5142,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
cfra = BKE_nla_tweakedit_remap(adt, float(scene->r.cfra), NLATIME_CONVERT_UNMAP);
/* Get flags for keyframing. */
flag = ANIM_get_keyframing_flags(scene);
flag = blender::animrig::get_keyframing_flags(scene);
/* try to resolve the path stored in the F-Curve */
if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
@ -5205,7 +5205,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
key->adt, anim_eval_context.eval_time, NLATIME_CONVERT_UNMAP);
/* get flags for keyframing */
flag = ANIM_get_keyframing_flags(scene);
flag = blender::animrig::get_keyframing_flags(scene);
/* try to resolve the path stored in the F-Curve */
if (RNA_path_resolve_property(&id_ptr, rna_path ? rna_path->c_str() : nullptr, &ptr, &prop)) {
@ -5261,7 +5261,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C, void * /*id_poin*/
cfra = float(scene->r.cfra);
/* get flags for keyframing */
flag = ANIM_get_keyframing_flags(scene);
flag = blender::animrig::get_keyframing_flags(scene);
/* Get pointer and property from the slider -
* this should all match up with the NlaStrip required. */

View File

@ -70,31 +70,6 @@ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op,
static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *ks);
/* ************************************************** */
/* Keyframing Setting Wrangling */
eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene)
{
using namespace blender::animrig;
eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
/* Visual keying. */
if (is_keying_flag(scene, KEYING_FLAG_VISUALKEY)) {
flag |= INSERTKEY_MATRIX;
}
/* Cycle-aware keyframe insertion - preserve cycle period and flow. */
if (is_keying_flag(scene, KEYING_FLAG_CYCLEAWARE)) {
flag |= INSERTKEY_CYCLE_AWARE;
}
if (is_keying_flag(scene, MANUALKEY_FLAG_INSERTNEEDED)) {
flag |= INSERTKEY_NEEDED;
}
return flag;
}
/* ******************************************* */
/* Animation Data Validation */
@ -389,7 +364,7 @@ static int insert_key(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
const float scene_frame = BKE_scene_frame_get(scene);
const eInsertKeyFlags insert_key_flags = ANIM_get_keyframing_flags(scene);
const eInsertKeyFlags insert_key_flags = animrig::get_keyframing_flags(scene);
const eBezTriple_KeyframeType key_type = eBezTriple_KeyframeType(
scene->toolsettings->keyframe_type);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@ -976,7 +951,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
const bool all = RNA_boolean_get(op->ptr, "all");
eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
flag = ANIM_get_keyframing_flags(scene);
flag = get_keyframing_flags(scene);
if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) {
/* pass event on if no active button found */

View File

@ -101,7 +101,7 @@ static int add_default_keyingset_exec(bContext *C, wmOperator * /*op*/)
*/
const eKS_Settings flag = KEYINGSET_ABSOLUTE;
const eInsertKeyFlags keyingflag = ANIM_get_keyframing_flags(scene);
const eInsertKeyFlags keyingflag = blender::animrig::get_keyframing_flags(scene);
/* Call the API func, and set the active keyingset index. */
BKE_keyingset_add(&scene->keyingsets, nullptr, nullptr, flag, keyingflag);
@ -285,7 +285,7 @@ static int add_keyingset_button_exec(bContext *C, wmOperator *op)
*/
const eKS_Settings flag = KEYINGSET_ABSOLUTE;
const eInsertKeyFlags keyingflag = ANIM_get_keyframing_flags(scene);
const eInsertKeyFlags keyingflag = blender::animrig::get_keyframing_flags(scene);
/* Call the API func, and set the active keyingset index. */
keyingset = BKE_keyingset_add(
@ -1136,7 +1136,7 @@ int ANIM_apply_keyingset(bContext *C,
}
Scene *scene = CTX_data_scene(C);
const eInsertKeyFlags base_kflags = ANIM_get_keyframing_flags(scene);
const eInsertKeyFlags base_kflags = blender::animrig::get_keyframing_flags(scene);
eInsertKeyFlags kflag = INSERTKEY_NOFLAGS;
if (mode == MODIFYKEY_MODE_INSERT) {
/* use context settings as base */

View File

@ -261,16 +261,12 @@ static int grease_pencil_stroke_simplify_exec(bContext *C, wmOperator *op)
[positions, radii](int64_t first_index, int64_t last_index, int64_t index) {
const float dist_position = dist_to_line_v3(
positions[index], positions[first_index], positions[last_index]);
/* We divide the distance by 2000.0f to convert from "pixels" to an actual
* distance. For some reason, grease pencil strokes the thickness of strokes in
* pixels rather than object space distance. */
const float dist_radii = dist_to_interpolated(positions[index],
positions[first_index],
positions[last_index],
radii[index],
radii[first_index],
radii[last_index]) /
2000.0f;
radii[last_index]);
return math::max(dist_position, dist_radii);
};
@ -2231,7 +2227,8 @@ static int grease_pencil_paste_strokes_exec(bContext *C, wmOperator *op)
}
/* Ensure active keyframe. */
if (!ensure_active_keyframe(scene, grease_pencil)) {
bool inserted_keyframe = false;
if (!ensure_active_keyframe(scene, grease_pencil, inserted_keyframe)) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
return OPERATOR_CANCELLED;
}
@ -2256,6 +2253,10 @@ static int grease_pencil_paste_strokes_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
if (inserted_keyframe) {
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr);
}
return OPERATOR_FINISHED;
}

View File

@ -335,7 +335,9 @@ void create_keyframe_edit_data_selected_frames_list(KeyframeEditData *ked,
}
}
bool ensure_active_keyframe(const Scene &scene, GreasePencil &grease_pencil)
bool ensure_active_keyframe(const Scene &scene,
GreasePencil &grease_pencil,
bool &r_inserted_keyframe)
{
const int current_frame = scene.r.cfra;
bke::greasepencil::Layer &active_layer = *grease_pencil.get_active_layer();
@ -366,6 +368,7 @@ bool ensure_active_keyframe(const Scene &scene, GreasePencil &grease_pencil)
/* Otherwise we just insert a blank keyframe at the current frame. */
grease_pencil.insert_blank_frame(active_layer, current_frame, 0, BEZT_KEYTYPE_KEYFRAME);
}
r_inserted_keyframe = true;
}
/* There should now always be a drawing at the current frame. */
BLI_assert(active_layer.has_drawing_at(current_frame));

View File

@ -1172,11 +1172,14 @@ int grease_pencil_draw_operator_invoke(bContext *C, wmOperator *op)
}
/* Ensure a drawing at the current keyframe. */
if (!ed::greasepencil::ensure_active_keyframe(*scene, grease_pencil)) {
bool inserted_keyframe = false;
if (!ed::greasepencil::ensure_active_keyframe(*scene, grease_pencil, inserted_keyframe)) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
return OPERATOR_CANCELLED;
}
if (inserted_keyframe) {
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr);
}
return OPERATOR_RUNNING_MODAL;
}

View File

@ -209,7 +209,9 @@ bool has_any_frame_selected(const bke::greasepencil::Layer &layer);
* create one when auto-key is on (taking additive drawing setting into account).
* \return false when no keyframe could be found or created.
*/
bool ensure_active_keyframe(const Scene &scene, GreasePencil &grease_pencil);
bool ensure_active_keyframe(const Scene &scene,
GreasePencil &grease_pencil,
bool &r_inserted_keyframe);
void create_keyframe_edit_data_selected_frames_list(KeyframeEditData *ked,
const bke::greasepencil::Layer &layer);

View File

@ -39,15 +39,6 @@ struct NlaKeyframingContext;
/** \name Key-Framing Management
* \{ */
/**
* Get the active settings for key-framing settings from context (specifically the given scene)
* \param use_autokey_mode: include settings from key-framing mode in the result
* (i.e. replace only).
*/
eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene);
/* -------- */
/**
* \brief Lesser Key-framing API call.
*

View File

@ -68,7 +68,9 @@ bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool
if (but->type == UI_BTYPE_LABEL) {
if (for_tooltip) {
/* It's important labels are considered interactive for the purpose of showing tooltip. */
if (!ui_but_drag_is_draggable(but) && but->tip_func == nullptr) {
if (!ui_but_drag_is_draggable(but) && but->tip_func == nullptr &&
(but->tip == nullptr || but->tip[0] == '\0'))
{
return false;
}
}

View File

@ -279,10 +279,14 @@ static int grease_pencil_sculpt_paint_invoke(bContext *C, wmOperator *op, const
}
/* Ensure a drawing at the current keyframe. */
if (!ed::greasepencil::ensure_active_keyframe(*scene, grease_pencil)) {
bool inserted_keyframe = false;
if (!ed::greasepencil::ensure_active_keyframe(*scene, grease_pencil, inserted_keyframe)) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
return OPERATOR_CANCELLED;
}
if (inserted_keyframe) {
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr);
}
op->customdata = paint_stroke_new(C,
op,

View File

@ -709,7 +709,7 @@ void PaintOperation::on_stroke_done(const bContext &C)
drawing.tag_topology_changed();
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &grease_pencil.id);
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil.id);
}
std::unique_ptr<GreasePencilStrokeOperation> new_paint_operation()

View File

@ -1215,7 +1215,6 @@ static bool paint_use_2d_cursor(PaintMode mode)
return false;
case PaintMode::Texture3D:
case PaintMode::Texture2D:
case PaintMode::SculptUV:
case PaintMode::VertexGPencil:
case PaintMode::SculptGPencil:
case PaintMode::WeightGPencil:

View File

@ -320,7 +320,9 @@ void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache,
/* `sculpt_uv.cc` */
void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot);
void SCULPT_OT_uv_sculpt_grab(wmOperatorType *ot);
void SCULPT_OT_uv_sculpt_relax(wmOperatorType *ot);
void SCULPT_OT_uv_sculpt_pinch(wmOperatorType *ot);
/* paint_utils.cc */

View File

@ -1902,7 +1902,9 @@ void ED_operatortypes_paint()
WM_operatortype_append(PAINT_OT_weight_sample_group);
/* uv */
WM_operatortype_append(SCULPT_OT_uv_sculpt_stroke);
WM_operatortype_append(SCULPT_OT_uv_sculpt_grab);
WM_operatortype_append(SCULPT_OT_uv_sculpt_relax);
WM_operatortype_append(SCULPT_OT_uv_sculpt_pinch);
/* vertex selection */
WM_operatortype_append(PAINT_OT_vert_select_all);

View File

@ -40,12 +40,25 @@
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_enum_types.hh"
#include "paint_intern.hh"
#include "uvedit_intern.hh"
#include "UI_view2d.hh"
typedef enum eBrushUVSculptTool {
UV_SCULPT_TOOL_GRAB = 0,
UV_SCULPT_TOOL_RELAX = 1,
UV_SCULPT_TOOL_PINCH = 2,
} eBrushUVSculptTool;
enum {
UV_SCULPT_TOOL_RELAX_LAPLACIAN = 0,
UV_SCULPT_TOOL_RELAX_HC = 1,
UV_SCULPT_TOOL_RELAX_COTAN = 2,
};
/* When set, the UV element is on the boundary of the graph.
* i.e. Instead of a 2-dimensional laplace operator, use a 1-dimensional version.
* Visually, UV elements on the graph boundary appear as borders of the UV Island. */
@ -73,7 +86,7 @@ struct UVInitialStrokeElement {
/** index to unique UV. */
int uv;
/** Strength of brush on initial position. */
/** Strength on initial position. */
float strength;
/** initial UV position. */
@ -91,7 +104,7 @@ struct UVInitialStroke {
float init_coord[2];
};
/** Custom data for UV smoothing brush. */
/** Custom data for UV smoothing. */
struct UvSculptData {
/**
* Contains the first of each set of coincident UVs.
@ -111,14 +124,14 @@ struct UvSculptData {
/** data for initial stroke, used by tools like grab */
UVInitialStroke *initial_stroke;
/** Timer to be used for airbrush-type brush. */
/** Timer to be used for airbrush-type. */
wmTimer *timer;
/** To determine quickly adjacent UVs. */
UvElementMap *elementMap;
/** UV-smooth Paint for fast reference. */
Paint *uvsculpt;
/** UV-smooth for fast reference. */
UvSculpt *uvsculpt;
/** Tool to use. duplicating here to change if modifier keys are pressed. */
char tool;
@ -144,6 +157,18 @@ static void apply_sculpt_data_constraints(UvSculptData *sculptdata, float uv[2])
uv[1] = clamp_f(uv[1], v, v + 1.0f);
}
static float calc_strength(const UvSculptData *sculptdata, float p, const float len)
{
float strength = BKE_brush_curve_strength(eBrushCurvePreset(sculptdata->uvsculpt->curve_preset),
sculptdata->uvsculpt->strength_curve,
p,
len);
CLAMP(strength, 0.0f, 1.0f);
return strength;
}
/*********** Improved Laplacian Relaxation Operator ************************/
/* original code by Raul Fernandez Hernandez "farsthary" *
* adapted to uv smoothing by Antony Riakiatakis *
@ -164,7 +189,6 @@ static void HC_relaxation_iteration_uv(UvSculptData *sculptdata,
float diff[2];
int i;
const float radius = sqrtf(radius_sq);
Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
Temp_UVData *tmp_uvdata = (Temp_UVData *)MEM_callocN(
sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
@ -205,7 +229,7 @@ static void HC_relaxation_iteration_uv(UvSculptData *sculptdata,
if (dist <= radius_sq) {
UvElement *element;
float strength;
strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius);
strength = alpha * calc_strength(sculptdata, sqrtf(dist), radius);
sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] +
strength *
@ -250,7 +274,6 @@ static void laplacian_relaxation_iteration_uv(UvSculptData *sculptdata,
float diff[2];
int i;
const float radius = sqrtf(radius_sq);
Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
Temp_UVData *tmp_uvdata = (Temp_UVData *)MEM_callocN(
sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
@ -288,7 +311,7 @@ static void laplacian_relaxation_iteration_uv(UvSculptData *sculptdata,
if (dist <= radius_sq) {
UvElement *element;
float strength;
strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius);
strength = alpha * calc_strength(sculptdata, sqrtf(dist), radius);
sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] +
strength * tmp_uvdata[i].p[0];
@ -412,14 +435,13 @@ static void relaxation_iteration_uv(UvSculptData *sculptdata,
add_weighted_edge(delta_buf, storage, head_prev, head_curr, *luv_prev, *luv_curr, weight_next);
}
Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
for (int i = 0; i < sculptdata->totalUniqueUvs; i++) {
UvAdjacencyElement *adj_el = &sculptdata->uv[i];
if (adj_el->is_locked) {
continue; /* Locked UVs can't move. */
}
/* Is UV within brush's influence? */
/* Is UV within influence? */
float diff[2];
sub_v2_v2v2(diff, adj_el->uv, mouse_coord);
diff[1] /= aspect_ratio;
@ -427,8 +449,7 @@ static void relaxation_iteration_uv(UvSculptData *sculptdata,
if (dist_sq > radius_sq) {
continue;
}
const float strength = alpha * BKE_brush_curve_strength_clamped(
brush, sqrtf(dist_sq), sqrtf(radius_sq));
const float strength = alpha * calc_strength(sculptdata, sqrtf(dist_sq), sqrtf(radius_sq));
const float *delta_sum = delta_buf[adj_el->element - storage];
@ -460,15 +481,12 @@ static void uv_sculpt_stroke_apply(bContext *C,
const wmEvent *event,
Object *obedit)
{
Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
UvSculptData *sculptdata = (UvSculptData *)op->customdata;
Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
ToolSettings *toolsettings = CTX_data_tool_settings(C);
eBrushUVSculptTool tool = eBrushUVSculptTool(sculptdata->tool);
int invert = sculptdata->invert ? -1 : 1;
float alpha = BKE_brush_alpha_get(scene, brush);
float alpha = sculptdata->uvsculpt->strength;
float co[2];
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
@ -481,7 +499,7 @@ static void uv_sculpt_stroke_apply(bContext *C,
float zoomx, zoomy;
ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
const float radius = BKE_brush_size_get(scene, brush) / (width * zoomx);
const float radius = sculptdata->uvsculpt->size / (width * zoomx);
float aspectRatio = width / float(height);
/* We will compare squares to save some computation */
@ -505,7 +523,7 @@ static void uv_sculpt_stroke_apply(bContext *C,
if (dist <= radius_sq) {
UvElement *element;
float strength;
strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius);
strength = alpha * calc_strength(sculptdata, sqrtf(dist), radius);
normalize_v2(diff);
sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f;
@ -531,7 +549,7 @@ static void uv_sculpt_stroke_apply(bContext *C,
alpha,
radius_sq,
aspectRatio,
toolsettings->uv_relax_method);
RNA_enum_get(op->ptr, "relax_method"));
break;
}
case UV_SCULPT_TOOL_GRAB: {
@ -637,11 +655,10 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
UvSculptData *data = MEM_cnew<UvSculptData>(__func__);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
Brush *brush = BKE_paint_brush(&ts->uvsculpt->paint);
op->customdata = data;
BKE_curvemapping_init(brush->curve);
BKE_curvemapping_init(ts->uvsculpt.strength_curve);
if (!data) {
return nullptr;
@ -658,12 +675,18 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
int island_index = 0;
data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH) ?
UV_SCULPT_TOOL_RELAX :
eBrushUVSculptTool(brush->uv_sculpt_tool);
data->invert = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT) ? 1 : 0;
if (STREQ(op->type->idname, "SCULPT_OT_uv_sculpt_relax")) {
data->tool = UV_SCULPT_TOOL_RELAX;
}
else if (STREQ(op->type->idname, "SCULPT_OT_uv_sculpt_grab")) {
data->tool = UV_SCULPT_TOOL_GRAB;
}
else {
data->tool = UV_SCULPT_TOOL_PINCH;
}
data->invert = RNA_boolean_get(op->ptr, "use_invert");
data->uvsculpt = &ts->uvsculpt->paint;
data->uvsculpt = &ts->uvsculpt;
/* Winding was added to island detection in 5197aa04c6bd
* However the sculpt tools can flip faces, potentially creating orphaned islands.
@ -834,12 +857,8 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
/* Allocate initial selection for grab tool */
if (data->tool == UV_SCULPT_TOOL_GRAB) {
UvSculptData *sculptdata = (UvSculptData *)op->customdata;
Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
float alpha = BKE_brush_alpha_get(scene, brush);
float radius = BKE_brush_size_get(scene, brush);
float alpha = data->uvsculpt->strength;
float radius = data->uvsculpt->size;
int width, height;
ED_space_image_get_size(sima, &width, &height);
float zoomx, zoomy;
@ -875,7 +894,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
float dist = dot_v2v2(diff, diff);
if (dist <= radius_sq) {
float strength;
strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius);
strength = alpha * calc_strength(data, sqrtf(dist), radius);
data->initial_stroke->initialSelection[counter].uv = i;
data->initial_stroke->initialSelection[counter].strength = strength;
@ -946,57 +965,78 @@ static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_RUNNING_MODAL;
}
static bool uv_sculpt_stroke_poll(bContext *C)
static void register_common_props(wmOperatorType *ot)
{
if (ED_operator_uvedit_space_image(C)) {
/* While these values could be initialized on demand,
* the only case this would be useful is running from the operator search popup.
* This is such a corner case that it's simpler to check a brush has already been created
* (something the tool system ensures). */
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
Brush *brush = BKE_paint_brush(&ts->uvsculpt->paint);
if (brush != nullptr) {
return true;
}
}
return false;
}
void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot)
{
static const EnumPropertyItem stroke_mode_items[] = {
{BRUSH_STROKE_NORMAL, "NORMAL", 0, "Regular", "Apply brush normally"},
{BRUSH_STROKE_INVERT,
"INVERT",
0,
"Invert",
"Invert action of brush for duration of stroke"},
{BRUSH_STROKE_SMOOTH,
"RELAX",
0,
"Relax",
"Switch brush to relax mode for duration of stroke"},
{0},
};
/* identifiers */
ot->name = "Sculpt UVs";
ot->description = "Sculpt UVs using a brush";
ot->idname = "SCULPT_OT_uv_sculpt_stroke";
/* api callbacks */
ot->invoke = uv_sculpt_stroke_invoke;
ot->modal = uv_sculpt_stroke_modal;
ot->poll = uv_sculpt_stroke_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
PropertyRNA *prop;
prop = RNA_def_enum(
ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, "Mode", "Stroke Mode");
prop = RNA_def_boolean(
ot->srna, "use_invert", false, "Invert", "Invert action for the duration of the stroke");
RNA_def_property_flag(prop, PropertyFlag(PROP_SKIP_SAVE));
}
void SCULPT_OT_uv_sculpt_grab(wmOperatorType *ot)
{
ot->name = "Grab UVs";
ot->description = "Grab UVs";
ot->idname = "SCULPT_OT_uv_sculpt_grab";
ot->invoke = uv_sculpt_stroke_invoke;
ot->modal = uv_sculpt_stroke_modal;
ot->poll = ED_operator_uvedit_space_image;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
register_common_props(ot);
}
void SCULPT_OT_uv_sculpt_relax(wmOperatorType *ot)
{
ot->name = "Relax UVs";
ot->description = "Relax UVs";
ot->idname = "SCULPT_OT_uv_sculpt_relax";
ot->invoke = uv_sculpt_stroke_invoke;
ot->modal = uv_sculpt_stroke_modal;
ot->poll = ED_operator_uvedit_space_image;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
register_common_props(ot);
static const EnumPropertyItem relax_method_items[] = {
{UV_SCULPT_TOOL_RELAX_LAPLACIAN,
"LAPLACIAN",
0,
"Laplacian",
"Use Laplacian method for relaxation"},
{UV_SCULPT_TOOL_RELAX_HC, "HC", 0, "HC", "Use HC method for relaxation"},
{UV_SCULPT_TOOL_RELAX_COTAN,
"COTAN",
0,
"Geometry",
"Use Geometry (cotangent) relaxation, making UVs follow the underlying 3D geometry"},
{0, nullptr, 0, nullptr, nullptr},
};
RNA_def_enum(ot->srna,
"relax_method",
relax_method_items,
CURVE_PRESET_SMOOTH,
"Relax Method",
"Algorithm used for UV relaxation");
}
void SCULPT_OT_uv_sculpt_pinch(wmOperatorType *ot)
{
ot->name = "Pinch UVs";
ot->description = "Pinch UVs";
ot->idname = "SCULPT_OT_uv_sculpt_pinch";
ot->invoke = uv_sculpt_stroke_invoke;
ot->modal = uv_sculpt_stroke_modal;
ot->poll = ED_operator_uvedit_space_image;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
register_common_props(ot);
}

View File

@ -909,7 +909,7 @@ static void insert_action_keys(bAnimContext *ac, short mode)
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
/* Init keyframing flag. */
flag = ANIM_get_keyframing_flags(scene);
flag = blender::animrig::get_keyframing_flags(scene);
/* GPLayers specific flags */
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {

View File

@ -145,7 +145,7 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
}
/* Init key-framing flag. */
eInsertKeyFlags flag = ANIM_get_keyframing_flags(scene);
eInsertKeyFlags flag = blender::animrig::get_keyframing_flags(scene);
KeyframeSettings settings = get_keyframe_settings(true);
settings.keyframe_type = eBezTriple_KeyframeType(ts->keyframe_type);

View File

@ -331,10 +331,8 @@ bool space_image_main_region_poll(bContext *C)
static bool space_image_main_area_not_uv_brush_poll(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *toolsettings = scene->toolsettings;
if (sima && !toolsettings->uvsculpt && (CTX_data_edit_object(C) == nullptr)) {
if (sima && (CTX_data_edit_object(C) == nullptr)) {
return true;
}

View File

@ -4,6 +4,7 @@
set(INC
../include
../io
../../asset_system
../../blenkernel
../../blenloader

View File

@ -16,6 +16,7 @@
#include "DNA_node_types.h"
#include "DNA_texture_types.h"
#include "BLI_easing.h"
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
@ -50,6 +51,9 @@
#include "UI_view2d.hh"
#include "io_utils.hh"
#include <fmt/format.h>
#include "node_intern.hh" /* own include */
namespace blender::ed::space_node {
@ -683,17 +687,58 @@ static bool node_add_file_poll(bContext *C)
ELEM(snode->nodetree->type, NTREE_SHADER, NTREE_TEXTURE, NTREE_COMPOSIT, NTREE_GEOMETRY);
}
/** Node stack animation data, sorts nodes so each node is placed on top of each other. */
struct NodeStackAnimationData {
Vector<bNode *> nodes;
wmTimer *anim_timer;
};
static int node_add_file_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
NodeStackAnimationData *data = static_cast<NodeStackAnimationData *>(op->customdata);
if (event->type != TIMER || data == nullptr || data->anim_timer != event->customdata) {
return OPERATOR_PASS_THROUGH;
}
const float node_stack_anim_duration = 0.25f;
const float duration = float(data->anim_timer->time_duration);
const float prev_duration = duration - float(data->anim_timer->time_delta);
const float clamped_duration = math::min(duration, node_stack_anim_duration);
const float delta_factor =
BLI_easing_cubic_ease_in_out(clamped_duration, 0.0f, 1.0f, node_stack_anim_duration) -
BLI_easing_cubic_ease_in_out(prev_duration, 0.0f, 1.0f, node_stack_anim_duration);
bool redraw = false;
/* Each node is pushed by all previous nodes in the stack. */
float stack_offset = 0.0f;
for (bNode *node : data->nodes) {
node->locy -= stack_offset;
stack_offset += (node->runtime->totr.ymax - node->runtime->totr.ymin) * delta_factor;
redraw = true;
}
if (redraw) {
ED_region_tag_redraw(CTX_wm_region(C));
}
/* End stack animation. */
if (duration > node_stack_anim_duration) {
WM_event_timer_remove(CTX_wm_manager(C), nullptr, data->anim_timer);
MEM_delete(data);
op->customdata = nullptr;
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
}
return OPERATOR_RUNNING_MODAL;
}
static int node_add_file_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
int type = 0;
Image *ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
if (!ima) {
return OPERATOR_CANCELLED;
}
switch (snode.nodetree->type) {
case NTREE_SHADER:
type = SH_NODE_TEX_IMAGE;
@ -710,36 +755,82 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
default:
return OPERATOR_CANCELLED;
}
Vector<Image *> images;
/* Load all paths as ID Images. */
const Vector<std::string> paths = ed::io::paths_from_operator_properties(op->ptr);
for (const std::string &path : paths) {
RNA_string_set(op->ptr, "filepath", path.c_str());
Image *image = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
if (!image) {
BKE_report(op->reports, RPT_WARNING, fmt::format("Could not load {}", path).c_str());
continue;
}
images.append(image);
/* When adding new image file via drag-drop we need to load #ImBuf in order
* to get proper image source. */
BKE_image_signal(bmain, image, nullptr, IMA_SIGNAL_RELOAD);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, image);
}
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
/* If not path is provided, try to get a ID Image from operator. */
if (paths.is_empty()) {
Image *image = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
if (image) {
images.append(image);
}
}
bNode *node = add_static_node(*C, type, snode.runtime->cursor);
float2 position = snode.runtime->cursor;
Vector<bNode *> nodes;
/* Add a node for each image. */
for (Image *image : images) {
bNode *node = add_static_node(*C, type, position);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
continue;
}
if (type == GEO_NODE_IMAGE_TEXTURE) {
bNodeSocket *image_socket = (bNodeSocket *)node->inputs.first;
bNodeSocketValueImage *socket_value = (bNodeSocketValueImage *)image_socket->default_value;
socket_value->value = image;
}
else {
node->id = (ID *)image;
}
nodes.append(node);
/* Initial offset between nodes. */
position[1] -= 20.0f;
}
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
if (nodes.is_empty()) {
return OPERATOR_CANCELLED;
}
if (type == GEO_NODE_IMAGE_TEXTURE) {
bNodeSocket *image_socket = (bNodeSocket *)node->inputs.first;
bNodeSocketValueImage *socket_value = (bNodeSocketValueImage *)image_socket->default_value;
socket_value->value = ima;
}
else {
node->id = (ID *)ima;
/* Set new nodes as selected. */
bNodeTree &node_tree = *snode.edittree;
node_deselect_all(node_tree);
for (bNode *node : nodes) {
nodeSetSelected(node, true);
}
ED_node_set_active(bmain, &snode, &node_tree, nodes[0], nullptr);
/* When adding new image file via drag-drop we need to load #ImBuf in order
* to get proper image source. */
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
BKE_image_signal(bmain, ima, nullptr, IMA_SIGNAL_RELOAD);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
ED_node_tree_propagate_change(C, bmain, snode.edittree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
if (nodes.size() == 1) {
return OPERATOR_FINISHED;
}
/* Start the stack animation, so each node is placed on top of each other. */
NodeStackAnimationData *data = MEM_new<NodeStackAnimationData>(__func__);
data->nodes = std::move(nodes);
data->anim_timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.02);
op->customdata = data;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int node_add_file_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@ -774,6 +865,7 @@ void NODE_OT_add_file(wmOperatorType *ot)
/* callbacks */
ot->exec = node_add_file_exec;
ot->modal = node_add_file_modal;
ot->invoke = node_add_file_invoke;
ot->poll = node_add_file_poll;
@ -784,7 +876,8 @@ void NODE_OT_add_file(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_DIRECTORY |
WM_FILESEL_FILES,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
WM_operator_properties_id_lookup(ot, true);

View File

@ -3424,7 +3424,8 @@ static void node_draw_basis(const bContext &C,
nullptr,
0,
0,
"");
TIP_(node.typeinfo->ui_description));
if (node.flag & NODE_MUTED) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
@ -3661,7 +3662,7 @@ static void node_draw_hidden(const bContext &C,
nullptr,
0,
0,
"");
TIP_(node.typeinfo->ui_description));
/* Outline. */
{

View File

@ -879,13 +879,8 @@ static bool node_collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *
return WM_drag_is_ID_type(drag, ID_GR) && !UI_but_active_drop_name(C);
}
static bool node_ima_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
static bool node_id_im_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
{
if (drag->type == WM_DRAG_PATH) {
const eFileSel_File_Types file_type = static_cast<eFileSel_File_Types>(
WM_drag_get_path_file_type(drag));
return ELEM(file_type, FILE_TYPE_IMAGE, FILE_TYPE_MOVIE);
}
return WM_drag_is_ID_type(drag, ID_IM);
}
@ -915,22 +910,14 @@ static void node_id_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
RNA_int_set(drop->ptr, "session_uid", int(id->session_uid));
}
static void node_id_path_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
static void node_id_im_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(C, drag, 0);
if (id) {
RNA_int_set(drop->ptr, "session_uid", int(id->session_uid));
RNA_struct_property_unset(drop->ptr, "filepath");
return;
}
const char *path = WM_drag_get_single_path(drag);
if (path) {
RNA_string_set(drop->ptr, "filepath", path);
RNA_struct_property_unset(drop->ptr, "name");
return;
}
}
/* this region dropbox definition */
@ -958,8 +945,8 @@ static void node_dropboxes()
nullptr);
WM_dropbox_add(lb,
"NODE_OT_add_file",
node_ima_drop_poll,
node_id_path_drop_copy,
node_id_im_drop_poll,
node_id_im_drop_copy,
WM_drag_free_imported_drag_ID,
nullptr);
WM_dropbox_add(lb,

View File

@ -784,7 +784,9 @@ static void sort_time_beztmaps(const blender::MutableSpan<BeztMap> bezms)
}
/* This function firstly adjusts the pointers that the transdata has to each BezTriple. */
static void beztmap_to_data(TransInfo *t, FCurve *fcu, const blender::Span<BeztMap> bezms)
static void update_transdata_bezt_pointers(TransInfo *t,
FCurve *fcu,
const blender::Span<BeztMap> bezms)
{
TransData2D *td2d;
TransData *td;
@ -882,7 +884,7 @@ static void remake_graph_transdata(TransInfo *t, const blender::Span<FCurve *> f
/* NOTE: none of these functions use 'use_handle', it could be removed. */
blender::Vector<BeztMap> bezms = bezt_to_beztmaps(fcu->bezt, fcu->totvert);
sort_time_beztmaps(bezms);
beztmap_to_data(t, fcu, bezms);
update_transdata_bezt_pointers(t, fcu, bezms);
/* Re-sort actual beztriples
* (perhaps this could be done using the beztmaps to save time?). */

View File

@ -2430,6 +2430,25 @@ mat4 MAT4x4(mat3x4 m)
{
return mat4(m[0], m[1], m[2], vec4(0.0, 0.0, 0.0, 1.0));
}
mat4 MAT4x4(mat4x3 m)
{
return mat4(m[0][0],
m[0][1],
m[0][2],
0.0,
m[1][0],
m[1][1],
m[1][2],
0.0,
m[2][0],
m[2][1],
m[2][2],
0.0,
m[3][0],
m[3][1],
m[3][2],
0.0);
}
mat4 MAT4x4(mat2 m)
{
return mat4(vec4(m[0].xy, 0.0, 0.0),

View File

@ -35,43 +35,32 @@ class CommandBufferLog : public VKCommandBufferInterface {
void begin_recording() override
{
BLI_assert_msg(!is_recording_,
"`CommandBufferLog::begin_recording` is called, when the command buffer is "
"already recording.");
EXPECT_FALSE(is_recording_);
is_recording_ = true;
}
void end_recording() override
{
BLI_assert_msg(is_recording_,
"`CommandBufferLog::end_recording` is called, when the command buffer is "
"not recording.");
EXPECT_TRUE(is_recording_);
is_recording_ = false;
}
void submit_with_cpu_synchronization() override
{
BLI_assert_msg(!is_recording_, "`CommandBufferLog` is submitted when still recording.");
BLI_assert_msg(!is_cpu_synchronizing_,
"`CommandBufferLog::submit_with_cpu_synchronization` is called, when the "
"command buffer is "
"still synchronizing.");
EXPECT_FALSE(is_recording_);
EXPECT_FALSE(is_cpu_synchronizing_);
is_cpu_synchronizing_ = true;
};
void wait_for_cpu_synchronization() override
{
BLI_assert_msg(!is_recording_, "`CommandBufferLog` is synchronizing when still recording.");
BLI_assert_msg(
is_cpu_synchronizing_,
"`CommandBufferLog::wait_for_cpu_synchronization` is called, when the command buffer is "
"not synchronizing.");
EXPECT_FALSE(is_recording_);
EXPECT_TRUE(is_cpu_synchronizing_);
is_cpu_synchronizing_ = false;
};
void bind_pipeline(VkPipelineBindPoint pipeline_bind_point, VkPipeline pipeline) override
{
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "bind_pipeline(";
ss << "pipeline_bind_point=" << to_string(pipeline_bind_point);
@ -95,8 +84,7 @@ class CommandBufferLog : public VKCommandBufferInterface {
p_descriptor_sets,
dynamic_offset_count,
p_dynamic_offsets);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "bind_descriptor_sets(";
ss << "pipeline_bind_point=" << to_string(pipeline_bind_point);
@ -109,9 +97,8 @@ class CommandBufferLog : public VKCommandBufferInterface {
void bind_index_buffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType index_type) override
{
UNUSED_VARS(buffer, offset, index_type);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
void bind_vertex_buffers(uint32_t first_binding,
@ -120,9 +107,8 @@ class CommandBufferLog : public VKCommandBufferInterface {
const VkDeviceSize *p_offsets) override
{
UNUSED_VARS(first_binding, binding_count, p_buffers, p_offsets);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
void draw(uint32_t vertex_count,
@ -131,9 +117,8 @@ class CommandBufferLog : public VKCommandBufferInterface {
uint32_t first_instance) override
{
UNUSED_VARS(vertex_count, instance_count, first_vertex, first_instance);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
void draw_indexed(uint32_t index_count,
@ -143,9 +128,8 @@ class CommandBufferLog : public VKCommandBufferInterface {
uint32_t first_instance) override
{
UNUSED_VARS(index_count, instance_count, first_index, vertex_offset, first_instance);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
void draw_indirect(VkBuffer buffer,
@ -154,9 +138,8 @@ class CommandBufferLog : public VKCommandBufferInterface {
uint32_t stride) override
{
UNUSED_VARS(buffer, offset, draw_count, stride);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
void draw_indexed_indirect(VkBuffer buffer,
@ -165,16 +148,14 @@ class CommandBufferLog : public VKCommandBufferInterface {
uint32_t stride) override
{
UNUSED_VARS(buffer, offset, draw_count, stride);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
void dispatch(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) override
{
UNUSED_VARS(group_count_x, group_count_y, group_count_z);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "dispatch(";
ss << "group_count_x=" << group_count_x;
@ -186,8 +167,7 @@ class CommandBufferLog : public VKCommandBufferInterface {
void dispatch_indirect(VkBuffer buffer, VkDeviceSize offset) override
{
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "dispatch_indirect(";
ss << "buffer=" << to_string(buffer);
@ -201,8 +181,7 @@ class CommandBufferLog : public VKCommandBufferInterface {
uint32_t region_count,
const VkBufferCopy *p_regions) override
{
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "copy_buffer(";
ss << "src_buffer=" << to_string(src_buffer);
@ -222,8 +201,7 @@ class CommandBufferLog : public VKCommandBufferInterface {
uint32_t region_count,
const VkImageCopy *p_regions) override
{
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "copy_image(";
ss << "src_image=" << to_string(src_image);
@ -246,8 +224,7 @@ class CommandBufferLog : public VKCommandBufferInterface {
const VkImageBlit *p_regions,
VkFilter filter) override
{
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "blit_image(";
ss << "src_image=" << to_string(src_image);
@ -269,8 +246,7 @@ class CommandBufferLog : public VKCommandBufferInterface {
uint32_t region_count,
const VkBufferImageCopy *p_regions) override
{
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "copy_buffer_to_image(";
ss << "src_buffer=" << to_string(src_buffer);
@ -291,8 +267,7 @@ class CommandBufferLog : public VKCommandBufferInterface {
uint32_t region_count,
const VkBufferImageCopy *p_regions) override
{
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "copy_image_to_buffer(";
ss << "src_image=" << to_string(src_image);
@ -312,8 +287,7 @@ class CommandBufferLog : public VKCommandBufferInterface {
VkDeviceSize size,
uint32_t data) override
{
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "fill_buffer(";
ss << "dst_buffer=" << to_string(dst_buffer);
@ -331,8 +305,7 @@ class CommandBufferLog : public VKCommandBufferInterface {
const VkImageSubresourceRange *p_ranges) override
{
UNUSED_VARS(p_color, range_count, p_ranges);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "clear_color_image(";
ss << "image=" << to_string(image);
@ -348,9 +321,8 @@ class CommandBufferLog : public VKCommandBufferInterface {
const VkImageSubresourceRange *p_ranges) override
{
UNUSED_VARS(image, image_layout, p_depth_stencil, range_count, p_ranges);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
void clear_attachments(uint32_t attachment_count,
@ -359,9 +331,8 @@ class CommandBufferLog : public VKCommandBufferInterface {
const VkClearRect *p_rects) override
{
UNUSED_VARS(attachment_count, p_attachments, rect_count, p_rects);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
void pipeline_barrier(VkPipelineStageFlags src_stage_mask,
@ -375,8 +346,7 @@ class CommandBufferLog : public VKCommandBufferInterface {
const VkImageMemoryBarrier *p_image_memory_barriers) override
{
UNUSED_VARS(dependency_flags, memory_barrier_count, p_memory_barriers);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
EXPECT_TRUE(is_recording_);
std::stringstream ss;
ss << "pipeline_barrier(";
ss << "src_stage_mask=" << to_string_vk_pipeline_stage_flags(src_stage_mask);
@ -404,25 +374,22 @@ class CommandBufferLog : public VKCommandBufferInterface {
const void *p_values) override
{
UNUSED_VARS(layout, stage_flags, offset, size, p_values);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
void begin_render_pass(const VkRenderPassBeginInfo *p_render_pass_begin,
VkSubpassContents contents) override
{
UNUSED_VARS(p_render_pass_begin, contents);
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
void end_render_pass() override
{
BLI_assert_msg(is_recording_,
"Command is added to command buffer, which isn't in recording state.");
BLI_assert_unreachable();
EXPECT_TRUE(is_recording_);
GTEST_FAIL() << __func__ << " not implemented!";
}
};

View File

@ -55,6 +55,43 @@ std::string to_string(VkDescriptorSet vk_handle)
return to_string_handle(uint64_t(vk_handle));
}
const char *to_string(const VkAttachmentLoadOp vk_attachment_load_op)
{
switch (vk_attachment_load_op) {
case VK_ATTACHMENT_LOAD_OP_LOAD:
return STRINGIFY(VK_ATTACHMENT_LOAD_OP_LOAD);
case VK_ATTACHMENT_LOAD_OP_CLEAR:
return STRINGIFY(VK_ATTACHMENT_LOAD_OP_CLEAR);
case VK_ATTACHMENT_LOAD_OP_DONT_CARE:
return STRINGIFY(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
default:
break;
}
return STRINGIFY_ARG(vk_attachment_load_op);
}
const char *to_string(const VkAttachmentStoreOp vk_attachment_store_op)
{
switch (vk_attachment_store_op) {
case VK_ATTACHMENT_STORE_OP_STORE:
return STRINGIFY(VK_ATTACHMENT_STORE_OP_STORE);
case VK_ATTACHMENT_STORE_OP_DONT_CARE:
return STRINGIFY(VK_ATTACHMENT_STORE_OP_DONT_CARE);
/* Extensions for VK_KHR_dynamic_rendering. */
case VK_ATTACHMENT_STORE_OP_NONE_KHR:
return STRINGIFY(VK_ATTACHMENT_STORE_OP_NONE_KHR);
default:
break;
}
return STRINGIFY_ARG(vk_attachment_store_op);
}
const char *to_string(const VkFilter vk_filter)
{
switch (vk_filter) {
@ -258,6 +295,30 @@ const char *to_string(const VkPipelineBindPoint vk_pipeline_bind_point)
return STRINGIFY_ARG(vk_pipeline_bind_point);
}
const char *to_string(const VkResolveModeFlagBits vk_resolve_mode_flag_bits)
{
switch (vk_resolve_mode_flag_bits) {
case VK_RESOLVE_MODE_NONE:
return STRINGIFY(VK_RESOLVE_MODE_NONE);
case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT:
return STRINGIFY(VK_RESOLVE_MODE_SAMPLE_ZERO_BIT);
case VK_RESOLVE_MODE_AVERAGE_BIT:
return STRINGIFY(VK_RESOLVE_MODE_AVERAGE_BIT);
case VK_RESOLVE_MODE_MIN_BIT:
return STRINGIFY(VK_RESOLVE_MODE_MIN_BIT);
case VK_RESOLVE_MODE_MAX_BIT:
return STRINGIFY(VK_RESOLVE_MODE_MAX_BIT);
default:
break;
}
return STRINGIFY_ARG(vk_resolve_mode_flag_bits);
}
const char *to_string(const VkSubpassContents vk_subpass_contents)
{
switch (vk_subpass_contents) {
@ -455,6 +516,36 @@ std::string to_string_vk_pipeline_stage_flags(const VkPipelineStageFlags vk_pipe
return result;
}
std::string to_string_vk_rendering_flags(const VkRenderingFlags vk_rendering_flags)
{
std::stringstream ss;
if (vk_rendering_flags & VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT) {
ss << STRINGIFY(VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT) << ", ";
}
if (vk_rendering_flags & VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR) {
ss << STRINGIFY(VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR) << ", ";
}
if (vk_rendering_flags & VK_RENDERING_SUSPENDING_BIT) {
ss << STRINGIFY(VK_RENDERING_SUSPENDING_BIT) << ", ";
}
if (vk_rendering_flags & VK_RENDERING_SUSPENDING_BIT_KHR) {
ss << STRINGIFY(VK_RENDERING_SUSPENDING_BIT_KHR) << ", ";
}
if (vk_rendering_flags & VK_RENDERING_RESUMING_BIT) {
ss << STRINGIFY(VK_RENDERING_RESUMING_BIT) << ", ";
}
if (vk_rendering_flags & VK_RENDERING_RESUMING_BIT_KHR) {
ss << STRINGIFY(VK_RENDERING_RESUMING_BIT_KHR) << ", ";
}
std::string result = ss.str();
if (result.size() >= 2) {
result.erase(result.size() - 2, 2);
}
return result;
}
std::string to_string_vk_shader_stage_flags(const VkShaderStageFlags vk_shader_stage_flags)
{
std::stringstream ss;
@ -739,4 +830,56 @@ std::string to_string(const VkRenderPassBeginInfo &vk_render_pass_begin_info,
return ss.str();
}
std::string to_string(const VkRenderingAttachmentInfo &vk_rendering_attachment_info,
int indentation_level)
{
UNUSED_VARS(indentation_level);
std::stringstream ss;
ss << "image_view=" << vk_rendering_attachment_info.imageView;
ss << ", image_layout=" << to_string(vk_rendering_attachment_info.imageLayout);
ss << ", resolve_mode=" << to_string(vk_rendering_attachment_info.resolveMode);
ss << ", resolve_image_view=" << vk_rendering_attachment_info.resolveImageView;
ss << ", resolve_image_layout=" << to_string(vk_rendering_attachment_info.resolveImageLayout);
ss << ", load_op=" << to_string(vk_rendering_attachment_info.loadOp);
ss << ", store_op=" << to_string(vk_rendering_attachment_info.storeOp);
return ss.str();
}
std::string to_string(const VkRenderingInfo &vk_rendering_info, int indentation_level)
{
std::stringstream ss;
ss << "flags=" << to_string_vk_rendering_flags(vk_rendering_info.flags);
ss << ", render_area=" << std::endl;
ss << std::string(indentation_level * 2 + 2, ' ')
<< to_string(vk_rendering_info.renderArea, indentation_level + 1);
ss << std::string(indentation_level * 2, ' ');
ss << ", layer_count=" << vk_rendering_info.layerCount;
ss << ", view_mask=" << vk_rendering_info.viewMask;
ss << ", color_attachment_count=" << vk_rendering_info.colorAttachmentCount;
ss << ", p_color_attachments=" << std::endl;
for (const VkRenderingAttachmentInfo &vk_rendering_attachment : Span<VkRenderingAttachmentInfo>(
vk_rendering_info.pColorAttachments, vk_rendering_info.colorAttachmentCount))
{
ss << std::string(indentation_level * 2 + 2, ' ')
<< to_string(vk_rendering_attachment, indentation_level + 1) << std::endl;
}
if (vk_rendering_info.pDepthAttachment != nullptr) {
ss << std::string(indentation_level * 2, ' ');
ss << ", p_depth_attachment=" << std::endl;
ss << std::string(indentation_level * 2 + 2, ' ')
<< to_string(*vk_rendering_info.pDepthAttachment, indentation_level + 1);
ss << std::endl;
}
if (vk_rendering_info.pStencilAttachment != nullptr) {
ss << std::string(indentation_level * 2, ' ');
ss << ", p_stencil_attachment=" << std::endl;
ss << std::string(indentation_level * 2 + 2, ' ')
<< to_string(*vk_rendering_info.pStencilAttachment, indentation_level + 1);
ss << std::endl;
}
return ss.str();
}
} // namespace blender::gpu

View File

@ -19,16 +19,20 @@ std::string to_string(VkPipelineLayout vk_handle);
std::string to_string(VkRenderPass vk_handle);
std::string to_string(VkFramebuffer vk_handle);
const char *to_string(VkAttachmentLoadOp vk_attachment_load_op);
const char *to_string(VkAttachmentStoreOp vk_attachment_store_op);
const char *to_string(VkFilter vk_filter);
const char *to_string(VkImageLayout vk_image_layout);
const char *to_string(VkIndexType vk_index_type);
const char *to_string(VkObjectType vk_object_type);
const char *to_string(VkPipelineBindPoint vk_pipeline_bind_point);
const char *to_string(VkResolveModeFlagBits vk_resolve_mode_flag_bits);
const char *to_string(VkSubpassContents vk_subpass_contents);
std::string to_string_vk_access_flags(VkAccessFlags vk_access_flags);
std::string to_string_vk_dependency_flags(VkDependencyFlags vk_dependency_flags);
std::string to_string_vk_image_aspect_flags(VkImageAspectFlags vk_image_aspect_flags);
std::string to_string_vk_pipeline_stage_flags(VkPipelineStageFlags vk_pipeline_stage_flags);
std::string to_string_vk_rendering_flags(VkRenderingFlags vk_rendering_flags);
std::string to_string_vk_shader_stage_flags(VkShaderStageFlags vk_shader_stage_flags);
std::string to_string(const VkBufferCopy &vk_buffer_copy, int indentation_level = 0);
std::string to_string(const VkBufferImageCopy &vk_buffer_image_copy, int indentation_level = 0);
@ -54,4 +58,8 @@ std::string to_string(const VkOffset3D &vk_offset3_d, int indentation_level = 0)
std::string to_string(const VkRect2D &vk_rect2_d, int indentation_level = 0);
std::string to_string(const VkRenderPassBeginInfo &vk_render_pass_begin_info,
int indentation_level = 0);
std::string to_string(const VkRenderingAttachmentInfo &vk_rendering_attachment_info,
int indentation_level = 0);
std::string to_string(const VkRenderingInfo &vk_rendering_info, int indentation_level = 0);
} // namespace blender::gpu

View File

@ -36,6 +36,7 @@ FEATURES = [
# List of extensions blender uses. These can extend enum flags.
EXTENSIONS = [
"VK_KHR_swapchain",
"VK_KHR_dynamic_rendering",
]
# List of vkCmd commands blender uses.
@ -58,8 +59,8 @@ COMMANDS_TO_GEN = [
"vkCmdBindVertexBuffers",
"vkCmdBindPipeline",
"vkCmdBeginRenderPass",
"vkCmdEndRenderPass",
"vkCmdBeginRendering",
"vkCmdEndRendering",
"vkCmdDraw",
"vkCmdDrawIndexed",
"vkCmdDrawIndirect",

View File

@ -483,13 +483,6 @@ typedef enum eBrushSculptTool {
SCULPT_TOOL_DISPLACEMENT_SMEAR = 32,
} eBrushSculptTool;
/** #Brush.uv_sculpt_tool */
typedef enum eBrushUVSculptTool {
UV_SCULPT_TOOL_GRAB = 0,
UV_SCULPT_TOOL_RELAX = 1,
UV_SCULPT_TOOL_PINCH = 2,
} eBrushUVSculptTool;
/* Brush.curves_sculpt_tool. */
typedef enum eBrushCurvesSculptTool {
CURVES_SCULPT_TOOL_COMB = 0,

View File

@ -273,8 +273,6 @@ typedef struct Brush {
/** Active sculpt tool. */
char sculpt_tool;
/** Active sculpt tool. */
char uv_sculpt_tool;
/** Active vertex paint. */
char vertexpaint_tool;
/** Active weight paint. */
@ -293,7 +291,7 @@ typedef struct Brush {
char gpencil_weight_tool;
/** Active curves sculpt tool (#eBrushCurvesSculptTool). */
char curves_sculpt_tool;
char _pad1[5];
char _pad1[6];
float autosmooth_factor;

View File

@ -408,8 +408,7 @@
\
/* UV painting */ \
.uv_sculpt_settings = 0, \
.uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN, \
\
\
/* Placement */ \
.snap_mode_tools = SCE_SNAP_TO_GEOM,\
.plane_axis = 2,\

View File

@ -860,13 +860,6 @@ enum {
UV_SCULPT_ALL_ISLANDS = 2,
};
/** #ToolSettings::uv_relax_method */
enum {
UV_SCULPT_TOOL_RELAX_LAPLACIAN = 1,
UV_SCULPT_TOOL_RELAX_HC = 2,
UV_SCULPT_TOOL_RELAX_COTAN = 3,
};
/* Stereo Flags. */
#define STEREO_RIGHT_NAME "right"
#define STEREO_LEFT_NAME "left"
@ -1099,7 +1092,11 @@ typedef struct CurvesSculpt {
} CurvesSculpt;
typedef struct UvSculpt {
Paint paint;
struct CurveMapping *strength_curve;
int size;
float strength;
int8_t curve_preset; /* #eBrushCurvePreset. */
char _pad[7];
} UvSculpt;
/** Grease pencil drawing brushes. */
@ -1512,7 +1509,7 @@ typedef struct ToolSettings {
VPaint *wpaint;
Sculpt *sculpt;
/** UV smooth. */
UvSculpt *uvsculpt;
UvSculpt uvsculpt;
/** Gpencil paint. */
GpPaint *gp_paint;
/** Gpencil vertex paint. */
@ -1664,10 +1661,11 @@ typedef struct ToolSettings {
/* UV painting. */
char uv_sculpt_settings;
char uv_relax_method;
char workspace_tool_type;
char _pad5[1];
/**
* XXX: these `sculpt_paint_*` fields are deprecated, use the
* unified_paint_settings field instead!

View File

@ -788,7 +788,12 @@ typedef struct UserDef {
char pref_flag;
char savetime;
char mouse_emulate_3_button_modifier;
char _pad4[1];
/**
* Workaround for WAYLAND (at time of writing compositors don't support this info).
* #eUserpref_TrackpadScrollDir type
* TODO: Remove this once this API is better supported by Wayland compositors, see #107676.
*/
char trackpad_scroll_direction;
/** FILE_MAXDIR length. */
char tempdir[768];
char fontdir[768];
@ -1533,6 +1538,11 @@ typedef enum eUserpref_EmulateMMBMod {
USER_EMU_MMB_MOD_OSKEY = 1,
} eUserpref_EmulateMMBMod;
typedef enum eUserpref_TrackpadScrollDir {
USER_TRACKPAD_SCROLL_DIR_TRADITIONAL = 0,
USER_TRACKPAD_SCROLL_DIR_NATURAL = 1,
} eUserpref_TrackpadScrollDir;
typedef enum eUserpref_DiskCacheCompression {
USER_SEQ_DISK_CACHE_COMPRESSION_NONE = 0,
USER_SEQ_DISK_CACHE_COMPRESSION_LOW = 1,

View File

@ -109,7 +109,6 @@ DEF_ENUM(rna_enum_operator_property_tag_items)
DEF_ENUM(rna_enum_brush_automasking_flag_items)
DEF_ENUM(rna_enum_brush_sculpt_tool_items)
DEF_ENUM(rna_enum_brush_uv_sculpt_tool_items)
DEF_ENUM(rna_enum_brush_vertex_tool_items)
DEF_ENUM(rna_enum_brush_weight_tool_items)
DEF_ENUM(rna_enum_brush_gpencil_types_items)
@ -118,6 +117,7 @@ DEF_ENUM(rna_enum_brush_gpencil_sculpt_types_items)
DEF_ENUM(rna_enum_brush_gpencil_weight_types_items)
DEF_ENUM(rna_enum_brush_curves_sculpt_tool_items)
DEF_ENUM(rna_enum_brush_image_tool_items)
DEF_ENUM(rna_enum_brush_curve_preset_items)
DEF_ENUM(rna_enum_grease_pencil_selectmode_items)

View File

@ -94,6 +94,20 @@ static const EnumPropertyItem rna_enum_brush_texture_slot_map_texture_mode_items
};
#endif
const EnumPropertyItem rna_enum_brush_curve_preset_items[] = {
{BRUSH_CURVE_CUSTOM, "CUSTOM", ICON_RNDCURVE, "Custom", ""},
{BRUSH_CURVE_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
{BRUSH_CURVE_SMOOTHER, "SMOOTHER", ICON_SMOOTHCURVE, "Smoother", ""},
{BRUSH_CURVE_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
{BRUSH_CURVE_ROOT, "ROOT", ICON_ROOTCURVE, "Root", ""},
{BRUSH_CURVE_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
{BRUSH_CURVE_LIN, "LIN", ICON_LINCURVE, "Linear", ""},
{BRUSH_CURVE_POW4, "POW4", ICON_SHARPCURVE, "Sharper", ""},
{BRUSH_CURVE_INVSQUARE, "INVSQUARE", ICON_INVERSESQUARECURVE, "Inverse Square", ""},
{BRUSH_CURVE_CONSTANT, "CONSTANT", ICON_NOCURVE, "Constant", ""},
{0, nullptr, 0, nullptr, nullptr},
};
/* Note: we don't actually turn these into a single enum bit-mask property,
* instead we construct individual boolean properties. */
const EnumPropertyItem rna_enum_brush_automasking_flag_items[] = {
@ -185,13 +199,6 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
const EnumPropertyItem rna_enum_brush_uv_sculpt_tool_items[] = {
{UV_SCULPT_TOOL_GRAB, "GRAB", 0, "Grab", "Grab UVs"},
{UV_SCULPT_TOOL_RELAX, "RELAX", 0, "Relax", "Relax UVs"},
{UV_SCULPT_TOOL_PINCH, "PINCH", 0, "Pinch", "Pinch UVs"},
{0, nullptr, 0, nullptr, nullptr},
};
const EnumPropertyItem rna_enum_brush_vertex_tool_items[] = {
{VPAINT_TOOL_DRAW, "DRAW", ICON_BRUSH_MIX, "Draw", ""},
{VPAINT_TOOL_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", ""},
@ -2419,20 +2426,6 @@ static void rna_def_brush(BlenderRNA *brna)
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem brush_curve_preset_items[] = {
{BRUSH_CURVE_CUSTOM, "CUSTOM", ICON_RNDCURVE, "Custom", ""},
{BRUSH_CURVE_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
{BRUSH_CURVE_SMOOTHER, "SMOOTHER", ICON_SMOOTHCURVE, "Smoother", ""},
{BRUSH_CURVE_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
{BRUSH_CURVE_ROOT, "ROOT", ICON_ROOTCURVE, "Root", ""},
{BRUSH_CURVE_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
{BRUSH_CURVE_LIN, "LIN", ICON_LINCURVE, "Linear", ""},
{BRUSH_CURVE_POW4, "POW4", ICON_SHARPCURVE, "Sharper", ""},
{BRUSH_CURVE_INVSQUARE, "INVSQUARE", ICON_INVERSESQUARECURVE, "Inverse Square", ""},
{BRUSH_CURVE_CONSTANT, "CONSTANT", ICON_NOCURVE, "Constant", ""},
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem brush_deformation_target_items[] = {
{BRUSH_DEFORM_TARGET_GEOMETRY,
"GEOMETRY",
@ -2619,11 +2612,6 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_BRUSH);
RNA_def_property_update(prop, 0, "rna_Brush_update_and_reset_icon");
prop = RNA_def_property(srna, "uv_sculpt_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_brush_uv_sculpt_tool_items);
RNA_def_property_ui_text(prop, "UV Sculpt Tool", "");
RNA_def_property_update(prop, 0, "rna_Brush_update_and_reset_icon");
prop = RNA_def_property(srna, "vertex_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "vertexpaint_tool");
RNA_def_property_enum_items(prop, rna_enum_brush_vertex_tool_items);
@ -2703,7 +2691,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "curve_preset", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, brush_curve_preset_items);
RNA_def_property_enum_items(prop, rna_enum_brush_curve_preset_items);
RNA_def_property_ui_text(prop, "Curve Preset", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVES); /* Abusing id_curves :/ */
RNA_def_property_update(prop, 0, "rna_Brush_update");

View File

@ -85,23 +85,6 @@ const EnumPropertyItem rna_enum_exr_codec_items[] = {
};
#endif
#ifndef RNA_RUNTIME
static const EnumPropertyItem uv_sculpt_relaxation_items[] = {
{UV_SCULPT_TOOL_RELAX_LAPLACIAN,
"LAPLACIAN",
0,
"Laplacian",
"Use Laplacian method for relaxation"},
{UV_SCULPT_TOOL_RELAX_HC, "HC", 0, "HC", "Use HC method for relaxation"},
{UV_SCULPT_TOOL_RELAX_COTAN,
"COTAN",
0,
"Geometry",
"Use Geometry (cotangent) relaxation, making UVs follow the underlying 3D geometry"},
{0, nullptr, 0, nullptr, nullptr},
};
#endif
const EnumPropertyItem rna_enum_snap_source_items[] = {
{SCE_SNAP_SOURCE_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"},
{SCE_SNAP_SOURCE_CENTER, "CENTER", 0, "Center", "Snap transformation center onto target"},
@ -3331,12 +3314,6 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_DEG_SYNC_ONLY);
RNA_def_property_ui_text(prop, "Sculpt All Islands", "Brush operates on all islands");
prop = RNA_def_property(srna, "uv_relax_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "uv_relax_method");
RNA_def_property_flag(prop, PROP_DEG_SYNC_ONLY);
RNA_def_property_enum_items(prop, uv_sculpt_relaxation_items);
RNA_def_property_ui_text(prop, "Relaxation Method", "Algorithm used for UV relaxation");
prop = RNA_def_property(srna, "lock_object_mode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "object_flag", SCE_OBJECT_MODE_LOCK);
RNA_def_property_flag(prop, PROP_DEG_SYNC_ONLY);

View File

@ -110,6 +110,7 @@ const EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
# include "MEM_guardedalloc.h"
# include "BKE_collection.hh"
# include "BKE_colortools.hh"
# include "BKE_context.hh"
# include "BKE_gpencil_legacy.h"
# include "BKE_object.hh"
@ -429,6 +430,18 @@ static void rna_ImaPaint_canvas_update(bContext *C, PointerRNA * /*ptr*/)
}
}
static void rna_UvSculpt_curve_preset_set(PointerRNA *ptr, int value)
{
Scene *scene = reinterpret_cast<Scene *>(ptr->owner_id);
if (value == BRUSH_CURVE_CUSTOM) {
if (!scene->toolsettings->uvsculpt.strength_curve) {
scene->toolsettings->uvsculpt.strength_curve = BKE_curvemapping_add(
1, 0.0f, 0.0f, 1.0f, 1.0f);
}
}
scene->toolsettings->uvsculpt.curve_preset = int8_t(value);
}
/** \name Paint mode settings
* \{ */
@ -886,10 +899,34 @@ static void rna_def_sculpt(BlenderRNA *brna)
static void rna_def_uv_sculpt(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "UvSculpt", "Paint");
RNA_def_struct_path_func(srna, "rna_UvSculpt_path");
RNA_def_struct_ui_text(srna, "UV Sculpting", "");
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
RNA_def_property_ui_range(prop, 1, 500, 1, 1);
RNA_def_property_range(prop, 1, 5000);
RNA_def_property_ui_text(prop, "Size", "");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Strength", "");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
prop = RNA_def_property(srna, "strength_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "CurveMapping");
RNA_def_property_pointer_funcs(prop, nullptr, nullptr, nullptr, nullptr);
RNA_def_property_ui_text(prop, "Strength Curve", "");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
prop = RNA_def_property(srna, "curve_preset", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_brush_curve_preset_items);
RNA_def_property_ui_text(prop, "Strength Curve Preset", "");
RNA_def_property_enum_funcs(prop, nullptr, "rna_UvSculpt_curve_preset_set", nullptr);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
static void rna_def_gp_paint(BlenderRNA *brna)

View File

@ -6570,6 +6570,20 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "invert_zoom_wheel", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "uiflag", USER_WHEELZOOMDIR);
RNA_def_property_ui_text(prop, "Wheel Invert Zoom", "Swap the Mouse Wheel zoom direction");
static const EnumPropertyItem touchpad_scroll_direction_items[] = {
{USER_TRACKPAD_SCROLL_DIR_TRADITIONAL,
"TRADITIONAL",
0,
"Traditional",
"Traditional scroll direction"},
{USER_TRACKPAD_SCROLL_DIR_NATURAL, "NATURAL", 0, "Natural", "Natural scroll direction"},
{0, nullptr, 0, nullptr, nullptr},
};
prop = RNA_def_property(srna, "touchpad_scroll_direction", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "trackpad_scroll_direction");
RNA_def_property_enum_items(prop, touchpad_scroll_direction_items);
RNA_def_property_ui_text(prop, "Touchpad Scroll Direction", "Scroll direction (Wayland only)");
}
static void rna_def_userdef_keymap(BlenderRNA *brna)

View File

@ -593,6 +593,57 @@ static PyObject *bpy_ghost_backend(PyObject * /*self*/)
return PyUnicode_FromString(WM_ghost_backend());
}
/* NOTE(@ideasman42): This is a private function because the keys in the returned dictionary,
* are not considered stable. Sometimes a function is temporarily only supported by one platform.
* Once all platforms support the functionality there is no need for the flag
* and it can be removed. This is at odds with a public API that has values which are
* intended to be kept between releases.
* If this were to be made public we would have to document that this is subject to change. */
PyDoc_STRVAR(
/* Wrap. */
bpy_wm_capabilities_doc,
".. function:: _wm_capabilities()\n"
"\n"
" :return: A dictionary of capabilities (string keys, boolean values).\n"
" :rtype: dict\n");
static PyObject *bpy_wm_capabilities(PyObject *self)
{
static _Py_Identifier PyId_capabilities = {"_wm_capabilities_", -1};
PyObject *result = nullptr;
switch (_PyObject_LookupAttrId(self, &PyId_capabilities, &result)) {
case 1:
return result;
case 0:
break;
default:
/* Unlikely, but there may be an error, forward it. */
return nullptr;
}
result = PyDict_New();
const eWM_CapabilitiesFlag flag = WM_capabilities_flag();
#define SetFlagItem(x) \
PyDict_SetItemString(result, STRINGIFY(x), PyBool_FromLong((WM_CAPABILITY_##x) & flag));
SetFlagItem(CURSOR_WARP);
SetFlagItem(WINDOW_POSITION);
SetFlagItem(PRIMARY_CLIPBOARD);
SetFlagItem(GPU_FRONT_BUFFER_READ);
SetFlagItem(CLIPBOARD_IMAGES);
SetFlagItem(DESKTOP_SAMPLE);
SetFlagItem(INPUT_IME);
SetFlagItem(TRACKPAD_PHYSICAL_DIRECTION);
#undef SetFlagItem
_PyObject_SetAttrId(self, &PyId_capabilities, result);
return result;
}
#if (defined(__GNUC__) && !defined(__clang__))
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-function-type"
@ -631,6 +682,7 @@ static PyMethodDef bpy_methods[] = {
METH_VARARGS | METH_KEYWORDS,
bpy_driver_secure_code_test_doc},
{"_ghost_backend", (PyCFunction)bpy_ghost_backend, METH_NOARGS, bpy_ghost_backend_doc},
{"_wm_capabilities", (PyCFunction)bpy_wm_capabilities, METH_NOARGS, bpy_wm_capabilities_doc},
{nullptr, nullptr, 0, nullptr},
};
@ -719,7 +771,7 @@ void BPy_init_modules(bContext *C)
BPY_rna_types_extend_capi();
#define PYMODULE_ADD_METHOD(mod, meth) \
PyModule_AddObject(mod, (meth)->ml_name, (PyObject *)PyCFunction_New(meth, nullptr))
PyModule_AddObject(mod, (meth)->ml_name, (PyObject *)PyCFunction_New(meth, mod))
for (int i = 0; bpy_methods[i].ml_name; i++) {
PyMethodDef *m = &bpy_methods[i];

View File

@ -186,10 +186,12 @@ enum eWM_CapabilitiesFlag {
WM_CAPABILITY_DESKTOP_SAMPLE = (1 << 5),
/** Support for IME input methods. */
WM_CAPABILITY_INPUT_IME = (1 << 6),
/** Trackpad physical scroll detection. */
WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION = (1 << 7),
/** The initial value, indicates the value needs to be set by inspecting GHOST. */
WM_CAPABILITY_INITIALIZED = (1u << 31),
};
ENUM_OPERATORS(eWM_CapabilitiesFlag, WM_CAPABILITY_CLIPBOARD_IMAGES)
ENUM_OPERATORS(eWM_CapabilitiesFlag, WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION)
eWM_CapabilitiesFlag WM_capabilities_flag();

View File

@ -5632,6 +5632,23 @@ void wm_event_add_ghostevent(wmWindowManager *wm,
event.flag |= WM_EVENT_SCROLL_INVERT;
}
#if !defined(WIN32) && !defined(__APPLE__)
/* Ensure "auto" is used when supported. */
char trackpad_scroll_direction = U.trackpad_scroll_direction;
if ((WM_capabilities_flag() & WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION) == 0) {
switch (eUserpref_TrackpadScrollDir(trackpad_scroll_direction)) {
case USER_TRACKPAD_SCROLL_DIR_TRADITIONAL: {
event.flag &= ~WM_EVENT_SCROLL_INVERT;
break;
}
case USER_TRACKPAD_SCROLL_DIR_NATURAL: {
event.flag |= WM_EVENT_SCROLL_INVERT;
break;
}
}
}
#endif
wm_event_add_trackpad(win, &event, delta[0], delta[1]);
break;
}

View File

@ -2077,6 +2077,9 @@ eWM_CapabilitiesFlag WM_capabilities_flag()
if (ghost_flag & GHOST_kCapabilityInputIME) {
flag |= WM_CAPABILITY_INPUT_IME;
}
if (ghost_flag & GHOST_kCapabilityTrackpadPhysicalDirection) {
flag |= WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION;
}
return flag;
}