Geometry Node: Multi-input socket tooltip #104468

Merged
Jacques Lucke merged 33 commits from mod_moder/blender:multi_input_tooltip into main 2024-04-22 19:49:08 +02:00
116 changed files with 1726 additions and 921 deletions
Showing only changes of commit e545cbebb1 - Show all commits

View File

@ -870,19 +870,29 @@ else()
endif()
# Vulkan
if(NOT APPLE)
option(WITH_VULKAN_BACKEND "Enable Vulkan as graphics backend (experimental)" ON)
option(WITH_VULKAN_GUARDEDALLOC "\
Use guardedalloc for host allocations done inside Vulkan (development option)"
OFF
)
option(WITH_VULKAN_BACKEND "Enable Vulkan as graphics backend (experimental)" ON)
option(WITH_VULKAN_GUARDEDALLOC "Use guardedalloc for host allocations done inside Vulkan (development option)"
OFF
)
mark_as_advanced(
WITH_VULKAN_BACKEND
WITH_VULKAN_GUARDEDALLOC
)
if(APPLE)
option(WITH_VULKAN_MOLTENVK "Enable Vulkan over MoltenVK (development option)" OFF)
mark_as_advanced(
WITH_VULKAN_BACKEND
WITH_VULKAN_GUARDEDALLOC
WITH_VULKAN_MOLTENVK
)
if(NOT WITH_EXPERIMENTAL_FEATURES)
set(WITH_VULKAN_BACKEND OFF)
endif()
if(APPLE AND NOT WITH_VULKAN_MOLTENVK)
set(WITH_VULKAN_BACKEND OFF)
endif()
if(NOT WITH_EXPERIMENTAL_FEATURES)
if (APPLE)
set(WITH_VULKAN_MOLTENVK OFF)
endif()
set(WITH_VULKAN_BACKEND OFF)
endif()
# Metal

View File

@ -43,11 +43,11 @@ find_path(MOLTENVK_INCLUDE_DIR
find_library(MOLTENVK_LIBRARY
NAMES
MoltenVK
libMoltenVK.dylib
HINTS
${_moltenvk_SEARCH_DIRS}
PATH_SUFFIXES
dylib/macOS
dynamic/dylib/macOS
)
# handle the QUIETLY and REQUIRED arguments and set MOLTENVK_FOUND to TRUE if

View File

@ -108,6 +108,12 @@ if(WITH_OPENSUBDIV)
endif()
add_bundled_libraries(opensubdiv/lib)
if(WITH_VULKAN_BACKEND)
find_package(MoltenVK REQUIRED)
find_package(ShaderC REQUIRED)
find_package(Vulkan REQUIRED)
endif()
if(WITH_CODEC_SNDFILE)
find_package(SndFile)
find_library(_sndfile_FLAC_LIBRARY NAMES flac HINTS ${LIBDIR}/sndfile/lib)

View File

@ -945,7 +945,9 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(phase_wo);
INTEGRATOR_STATE_WRITE(state, ray, tmin) = 0.0f;
# ifdef __LIGHT_TREE__
INTEGRATOR_STATE_WRITE(state, ray, previous_dt) = ray->tmax - ray->tmin;
if (kernel_data.integrator.use_light_tree) {
INTEGRATOR_STATE_WRITE(state, ray, previous_dt) = ray->tmax - ray->tmin;
}
# endif
INTEGRATOR_STATE_WRITE(state, ray, tmax) = FLT_MAX;
# ifdef __RAY_DIFFERENTIALS__

View File

@ -75,9 +75,7 @@ KERNEL_STRUCT_MEMBER(ray, float, tmax, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(ray, float, time, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(ray, float, dD, KERNEL_FEATURE_PATH_TRACING)
#ifdef __LIGHT_TREE__
KERNEL_STRUCT_MEMBER(ray, float, previous_dt, KERNEL_FEATURE_PATH_TRACING)
#endif
KERNEL_STRUCT_MEMBER(ray, float, previous_dt, KERNEL_FEATURE_LIGHT_TREE)
KERNEL_STRUCT_END(ray)
/*************************** Intersection result ******************************/

View File

@ -1748,6 +1748,9 @@ enum KernelFeatureFlag : uint32_t {
/* Use denoising kernels and output denoising passes. */
KERNEL_FEATURE_DENOISING = (1U << 29U),
/* Light tree. */
KERNEL_FEATURE_LIGHT_TREE = (1U << 30U),
};
/* Shader node feature mask, to specialize shader evaluation for kernels. */

View File

@ -345,6 +345,10 @@ uint Integrator::get_kernel_features() const
kernel_features |= KERNEL_FEATURE_AO_ADDITIVE;
}
if (get_use_light_tree()) {
kernel_features |= KERNEL_FEATURE_LIGHT_TREE;
}
return kernel_features;
}

View File

@ -32,10 +32,6 @@
#include <sys/stat.h>
/* Set to 0 to allow devices that do not have the required features.
* This allows development on OSX until we really needs these features. */
#define STRICT_REQUIREMENTS true
/*
* Should we only select surfaces that are known to be compatible. Or should we in case no
* compatible surfaces have been found select the first one.
@ -226,14 +222,15 @@ class GHOST_DeviceVK {
queue_create_infos.push_back(graphic_queue_create_info);
VkPhysicalDeviceFeatures device_features = {};
#if STRICT_REQUIREMENTS
#ifndef __APPLE__
device_features.geometryShader = VK_TRUE;
device_features.dualSrcBlend = VK_TRUE;
/* MoltenVK supports logicOp, needs to be build with MVK_USE_METAL_PRIVATE_API. */
device_features.logicOp = VK_TRUE;
#endif
device_features.dualSrcBlend = VK_TRUE;
device_features.imageCubeArray = VK_TRUE;
device_features.multiViewport = VK_TRUE;
device_features.shaderClipDistance = VK_TRUE;
#endif
device_features.drawIndirectFirstInstance = VK_TRUE;
device_features.fragmentStoresAndAtomics = VK_TRUE;
device_features.samplerAnisotropy = features.features.samplerAnisotropy;
@ -355,7 +352,11 @@ static GHOST_TSuccess ensure_vulkan_device(VkInstance vk_instance,
}
}
#if STRICT_REQUIREMENTS
#ifdef __APPLE__
if (!device_vk.features.features.dualSrcBlend || !device_vk.features.features.imageCubeArray) {
continue;
}
#else
if (!device_vk.features.features.geometryShader || !device_vk.features.features.dualSrcBlend ||
!device_vk.features.features.logicOp || !device_vk.features.features.imageCubeArray)
{
@ -1000,8 +1001,7 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
if (use_window_surface) {
const char *native_surface_extension_name = getPlatformSpecificSurfaceExtension();
requireExtension(extensions_available, extensions_enabled, "VK_KHR_surface");
requireExtension(extensions_available, extensions_enabled, VK_KHR_SURFACE_EXTENSION_NAME);
requireExtension(extensions_available, extensions_enabled, native_surface_extension_name);
extensions_device.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
@ -1010,10 +1010,13 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
extensions_device.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
/* Enable MoltenVK required instance extensions. */
#ifdef VK_MVK_MOLTENVK_EXTENSION_NAME
#ifdef __APPLE__
requireExtension(
extensions_available, extensions_enabled, "VK_KHR_get_physical_device_properties2");
extensions_available, extensions_enabled, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
requireExtension(extensions_available,
extensions_enabled,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
VkInstance instance = VK_NULL_HANDLE;
if (!vulkan_device.has_value()) {
@ -1046,6 +1049,10 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
create_info.pNext = &validationFeatures;
}
#ifdef __APPLE__
create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
VK_CHECK(vkCreateInstance(&create_info, nullptr, &instance));
}
else {

View File

@ -56,12 +56,11 @@ size_t malloc_usable_size(void *ptr);
#endif
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
// Needed for memalign on Linux and _aligned_alloc on Windows.
/* Needed for `memalign` on Linux and _aligned_alloc on Windows. */
# include <malloc.h>
#else
// Apple's malloc is 16-byte aligned, and does not have malloc.h, so include
// stdilb instead.
/* Apple's malloc is 16-byte aligned, and does not have malloc.h, so include stdilb instead. */
# include <stdlib.h>
#endif

View File

@ -76,7 +76,7 @@ the model.
* \ingroup intern_sky_modal
*/
// Uses Sep 9 pattern / Aug 23 mean dataset
/* Uses Sep 9 pattern / Aug 23 mean dataset. */
static const double datasetXYZ1[] = {
// albedo 0, turbidity 1

View File

@ -773,7 +773,7 @@ const bTheme U_theme_default = {
.sub_back = RGBA(0x0000001f),
},
.shade2 = RGBA(0x4d4d4de6),
.hilite = RGBA(0x65a2ffff),
.hilite = RGBA(0x71a8ffff),
.grid = RGBA(0x1d1d1dff),
.vertex_size = 3,
.outline_width = 1,
@ -941,7 +941,7 @@ const bTheme U_theme_default = {
.console_input = RGBA(0xf2f2f2ff),
.console_info = RGBA(0x95d600ff),
.console_error = RGBA(0xff4d84ff),
.console_cursor = RGBA(0xff0000ff),
.console_cursor = RGBA(0x71a8ffff),
.console_select = RGBA(0xffffff30),
.vertex_size = 3,
.outline_width = 1,

View File

@ -78,7 +78,7 @@ Comment[wa]=Modelaedje 3D, animåcion, rindou eyet après-produccion
Comment[zh_HK]=3D
Comment[zh_CN]=3D
Comment[zh_TW]=3D
Keywords=3d;cg;modeling;animation;painting;sculpting;texturing;video editing;video tracking;rendering;render engine;cycles;game engine;python;
Keywords=3d;cg;modeling;animation;painting;sculpting;texturing;video editing;video tracking;rendering;render engine;cycles;python;
Exec=blender %f
Icon=blender
Terminal=false

View File

@ -369,7 +369,6 @@
speaker="#000000"
vertex="#000000"
vertex_select="#ff7a00"
vertex_active="#000000"
vertex_size="3"
vertex_bevel="#00a5ff"
vertex_unreferenced="#000000"
@ -735,7 +734,6 @@
grid="#353535ff"
vertex="#000000"
vertex_select="#ff8500"
vertex_active="#000000"
vertex_size="3"
vertex_bevel="#000000"
vertex_unreferenced="#000000"
@ -1168,7 +1166,7 @@
line_input="#f2f2f2"
line_info="#95d600"
line_error="#ff4d84"
cursor="#ff0000"
cursor="#71a8ff"
select="#ffffff30"
>
<space>

View File

@ -3656,7 +3656,7 @@ def km_animation_channels(params):
# ------------------------------------------------------------------------------
# Object Grease Pencil Modes
def km_grease_pencil(params):
def km_gpencil_legacy(params):
items = []
keymap = (
"Grease Pencil",
@ -3694,7 +3694,7 @@ def km_grease_pencil(params):
return keymap
def _grease_pencil_selection(params, *, alt_select=False):
def _gpencil_legacy_selection(params, *, alt_select=False):
return [
# Select all
*_template_items_select_actions(params, "gpencil.select_all"),
@ -3727,7 +3727,7 @@ def _grease_pencil_selection(params, *, alt_select=False):
]
def _grease_pencil_display():
def _gpencil_legacy_display():
return [
("wm.context_toggle", {"type": 'Q', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'space_data.overlay.use_gpencil_edit_lines')]}),
@ -3736,7 +3736,7 @@ def _grease_pencil_display():
]
def km_grease_pencil_stroke_edit_mode(params):
def km_gpencil_legacy_stroke_edit_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Edit Mode",
@ -3751,7 +3751,7 @@ def km_grease_pencil_stroke_edit_mode(params):
(op_tool_cycle, "builtin.interpolate"), params),
("gpencil.interpolate_sequence", {"type": 'E', "value": 'PRESS', "shift": True, "ctrl": True}, None),
# Selection
*_grease_pencil_selection(params),
*_gpencil_legacy_selection(params),
("gpencil.select_lasso", {"type": params.action_mouse, "value": 'CLICK_DRAG', "ctrl": True},
{"properties": [("mode", 'ADD')]}),
("gpencil.select_lasso", {"type": params.action_mouse, "value": 'CLICK_DRAG', "shift": True, "ctrl": True},
@ -3795,7 +3795,7 @@ def km_grease_pencil_stroke_edit_mode(params):
*_template_items_hide_reveal_actions("gpencil.hide", "gpencil.reveal"),
("gpencil.selection_opacity_toggle", {"type": 'H', "value": 'PRESS', "ctrl": True}, None),
# Display
*_grease_pencil_display(),
*_gpencil_legacy_display(),
# Isolate layer
("gpencil.layer_isolate", {"type": 'NUMPAD_ASTERIX', "value": 'PRESS'}, None),
# Move to layer
@ -3843,7 +3843,7 @@ def km_grease_pencil_stroke_edit_mode(params):
return keymap
def km_grease_pencil_stroke_curve_edit_mode(_params):
def km_gpencil_legacy_stroke_curve_edit_mode(_params):
items = []
keymap = (
"Grease Pencil Stroke Curve Edit Mode",
@ -3859,7 +3859,7 @@ def km_grease_pencil_stroke_curve_edit_mode(_params):
return keymap
def km_grease_pencil_stroke_paint_mode(params):
def km_gpencil_legacy_stroke_paint_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Paint Mode",
@ -3911,7 +3911,7 @@ def km_grease_pencil_stroke_paint_mode(params):
return keymap
def km_grease_pencil_stroke_paint_draw_brush(params):
def km_gpencil_legacy_stroke_paint_draw_brush(params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Draw brush)",
@ -3944,7 +3944,7 @@ def km_grease_pencil_stroke_paint_draw_brush(params):
return keymap
def km_grease_pencil_stroke_paint_erase(_params):
def km_gpencil_legacy_stroke_paint_erase(_params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Erase)",
@ -3963,7 +3963,7 @@ def km_grease_pencil_stroke_paint_erase(_params):
return keymap
def km_grease_pencil_stroke_paint_fill(_params):
def km_gpencil_legacy_stroke_paint_fill(_params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Fill)",
@ -3999,7 +3999,7 @@ def km_grease_pencil_stroke_paint_fill(_params):
return keymap
def km_grease_pencil_stroke_paint_tint(_params):
def km_gpencil_legacy_stroke_paint_tint(_params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Tint)",
@ -4018,7 +4018,7 @@ def km_grease_pencil_stroke_paint_tint(_params):
return keymap
def km_grease_pencil_stroke_sculpt_mode(params):
def km_gpencil_legacy_stroke_sculpt_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt Mode",
@ -4028,7 +4028,7 @@ def km_grease_pencil_stroke_sculpt_mode(params):
items.extend([
# Selection
*_grease_pencil_selection(params, alt_select=True),
*_gpencil_legacy_selection(params, alt_select=True),
*_template_items_select_lasso(params, "gpencil.select_lasso"),
# Selection mode
("wm.context_toggle", {"type": 'ONE', "value": 'PRESS'},
@ -4051,7 +4051,7 @@ def km_grease_pencil_stroke_sculpt_mode(params):
# Copy
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
# Display
*_grease_pencil_display(),
*_gpencil_legacy_display(),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Active material
@ -4077,7 +4077,7 @@ def km_grease_pencil_stroke_sculpt_mode(params):
return keymap
def km_grease_pencil_stroke_sculpt_smooth(_params):
def km_gpencil_legacy_stroke_sculpt_smooth(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Smooth)",
@ -4097,7 +4097,7 @@ def km_grease_pencil_stroke_sculpt_smooth(_params):
return keymap
def km_grease_pencil_stroke_sculpt_thickness(_params):
def km_gpencil_legacy_stroke_sculpt_thickness(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Thickness)",
@ -4117,7 +4117,7 @@ def km_grease_pencil_stroke_sculpt_thickness(_params):
return keymap
def km_grease_pencil_stroke_sculpt_strength(_params):
def km_gpencil_legacy_stroke_sculpt_strength(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Strength)",
@ -4137,7 +4137,7 @@ def km_grease_pencil_stroke_sculpt_strength(_params):
return keymap
def km_grease_pencil_stroke_sculpt_grab(_params):
def km_gpencil_legacy_stroke_sculpt_grab(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Grab)",
@ -4157,7 +4157,7 @@ def km_grease_pencil_stroke_sculpt_grab(_params):
return keymap
def km_grease_pencil_stroke_sculpt_push(_params):
def km_gpencil_legacy_stroke_sculpt_push(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Push)",
@ -4177,7 +4177,7 @@ def km_grease_pencil_stroke_sculpt_push(_params):
return keymap
def km_grease_pencil_stroke_sculpt_twist(_params):
def km_gpencil_legacy_stroke_sculpt_twist(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Twist)",
@ -4197,7 +4197,7 @@ def km_grease_pencil_stroke_sculpt_twist(_params):
return keymap
def km_grease_pencil_stroke_sculpt_pinch(_params):
def km_gpencil_legacy_stroke_sculpt_pinch(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Pinch)",
@ -4217,7 +4217,7 @@ def km_grease_pencil_stroke_sculpt_pinch(_params):
return keymap
def km_grease_pencil_stroke_sculpt_randomize(_params):
def km_gpencil_legacy_stroke_sculpt_randomize(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Randomize)",
@ -4237,7 +4237,7 @@ def km_grease_pencil_stroke_sculpt_randomize(_params):
return keymap
def km_grease_pencil_stroke_sculpt_clone(_params):
def km_gpencil_legacy_stroke_sculpt_clone(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Clone)",
@ -4257,7 +4257,7 @@ def km_grease_pencil_stroke_sculpt_clone(_params):
return keymap
def km_grease_pencil_stroke_weight_mode(params):
def km_gpencil_legacy_stroke_weight_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Weight Mode",
@ -4281,7 +4281,7 @@ def km_grease_pencil_stroke_weight_mode(params):
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
# Display
*_grease_pencil_display(),
*_gpencil_legacy_display(),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Merge Layer
@ -4310,7 +4310,7 @@ def km_grease_pencil_stroke_weight_mode(params):
return keymap
def km_grease_pencil_stroke_weight_draw(_params):
def km_gpencil_legacy_stroke_weight_draw(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight (Draw)",
@ -4327,7 +4327,7 @@ def km_grease_pencil_stroke_weight_draw(_params):
return keymap
def km_grease_pencil_stroke_weight_blur(_params):
def km_gpencil_legacy_stroke_weight_blur(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight (Blur)",
@ -4344,7 +4344,7 @@ def km_grease_pencil_stroke_weight_blur(_params):
return keymap
def km_grease_pencil_stroke_weight_average(_params):
def km_gpencil_legacy_stroke_weight_average(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight (Average)",
@ -4361,7 +4361,7 @@ def km_grease_pencil_stroke_weight_average(_params):
return keymap
def km_grease_pencil_stroke_weight_smear(_params):
def km_gpencil_legacy_stroke_weight_smear(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight (Smear)",
@ -4378,7 +4378,7 @@ def km_grease_pencil_stroke_weight_smear(_params):
return keymap
def km_grease_pencil_stroke_vertex_mode(params):
def km_gpencil_legacy_stroke_vertex_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex Mode",
@ -4388,7 +4388,7 @@ def km_grease_pencil_stroke_vertex_mode(params):
items.extend([
# Selection
*_grease_pencil_selection(params, alt_select=True),
*_gpencil_legacy_selection(params, alt_select=True),
*_template_items_select_lasso(params, "gpencil.select_lasso"),
# Selection mode
("wm.context_toggle", {"type": 'ONE', "value": 'PRESS'},
@ -4413,7 +4413,7 @@ def km_grease_pencil_stroke_vertex_mode(params):
# Color Flip
("gpencil.tint_flip", {"type": 'X', "value": 'PRESS'}, None),
# Display
*_grease_pencil_display(),
*_gpencil_legacy_display(),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Merge Layer
@ -4433,7 +4433,7 @@ def km_grease_pencil_stroke_vertex_mode(params):
return keymap
def km_grease_pencil_stroke_vertex_draw(_params):
def km_gpencil_legacy_stroke_vertex_draw(_params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Draw)",
@ -4460,7 +4460,7 @@ def km_grease_pencil_stroke_vertex_draw(_params):
return keymap
def km_grease_pencil_stroke_vertex_blur(_params):
def km_gpencil_legacy_stroke_vertex_blur(_params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Blur)",
@ -4485,7 +4485,7 @@ def km_grease_pencil_stroke_vertex_blur(_params):
return keymap
def km_grease_pencil_stroke_vertex_average(_params):
def km_gpencil_legacy_stroke_vertex_average(_params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Average)",
@ -4512,7 +4512,7 @@ def km_grease_pencil_stroke_vertex_average(_params):
return keymap
def km_grease_pencil_stroke_vertex_smear(_params):
def km_gpencil_legacy_stroke_vertex_smear(_params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Smear)",
@ -4537,7 +4537,7 @@ def km_grease_pencil_stroke_vertex_smear(_params):
return keymap
def km_grease_pencil_stroke_vertex_replace(_params):
def km_gpencil_legacy_stroke_vertex_replace(_params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Replace)",
@ -4680,6 +4680,25 @@ def km_grease_pencil_edit_mode(params):
return keymap
def km_grease_pencil_sculpt_mode(params):
items = []
keymap = (
"Grease Pencil Sculpt Mode",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items}
)
items.extend([
("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("gpencil_sculpt_paint"),
])
return keymap
# ------------------------------------------------------------------------------
# Object/Pose Modes
@ -6144,6 +6163,7 @@ def km_edit_curves(params):
{"properties": [("mode", 'CURVE_SHRINKFATTEN')]}),
("curves.cyclic_toggle", {"type": 'C', "value": 'PRESS', "alt": True}, None),
("curves.handle_type_set", {"type": 'V', "value": 'PRESS'}, None),
op_menu("VIEW3D_MT_edit_curves_add", {"type": 'A', "value": 'PRESS', "shift": True}),
])
return keymap
@ -8599,38 +8619,40 @@ def generate_keymaps(params=None):
km_animation_channels(params),
# Modes.
km_grease_pencil(params), # TODO: Rename to km_annotate
km_grease_pencil_stroke_curve_edit_mode(params),
km_grease_pencil_stroke_edit_mode(params),
km_grease_pencil_stroke_paint_mode(params),
km_grease_pencil_stroke_paint_draw_brush(params),
km_grease_pencil_stroke_paint_erase(params),
km_grease_pencil_stroke_paint_fill(params),
km_grease_pencil_stroke_paint_tint(params),
km_grease_pencil_stroke_sculpt_mode(params),
km_grease_pencil_stroke_sculpt_smooth(params),
km_grease_pencil_stroke_sculpt_thickness(params),
km_grease_pencil_stroke_sculpt_strength(params),
km_grease_pencil_stroke_sculpt_grab(params),
km_grease_pencil_stroke_sculpt_push(params),
km_grease_pencil_stroke_sculpt_twist(params),
km_grease_pencil_stroke_sculpt_pinch(params),
km_grease_pencil_stroke_sculpt_randomize(params),
km_grease_pencil_stroke_sculpt_clone(params),
km_grease_pencil_stroke_weight_mode(params),
km_grease_pencil_stroke_weight_draw(params),
km_grease_pencil_stroke_weight_blur(params),
km_grease_pencil_stroke_weight_average(params),
km_grease_pencil_stroke_weight_smear(params),
km_grease_pencil_stroke_vertex_mode(params),
km_grease_pencil_stroke_vertex_draw(params),
km_grease_pencil_stroke_vertex_blur(params),
km_grease_pencil_stroke_vertex_average(params),
km_grease_pencil_stroke_vertex_smear(params),
km_grease_pencil_stroke_vertex_replace(params),
# Grease Pencil v2
km_gpencil_legacy(params), # TODO: Rename to km_annotate
km_gpencil_legacy_stroke_curve_edit_mode(params),
km_gpencil_legacy_stroke_edit_mode(params),
km_gpencil_legacy_stroke_paint_mode(params),
km_gpencil_legacy_stroke_paint_draw_brush(params),
km_gpencil_legacy_stroke_paint_erase(params),
km_gpencil_legacy_stroke_paint_fill(params),
km_gpencil_legacy_stroke_paint_tint(params),
km_gpencil_legacy_stroke_sculpt_mode(params),
km_gpencil_legacy_stroke_sculpt_smooth(params),
km_gpencil_legacy_stroke_sculpt_thickness(params),
km_gpencil_legacy_stroke_sculpt_strength(params),
km_gpencil_legacy_stroke_sculpt_grab(params),
km_gpencil_legacy_stroke_sculpt_push(params),
km_gpencil_legacy_stroke_sculpt_twist(params),
km_gpencil_legacy_stroke_sculpt_pinch(params),
km_gpencil_legacy_stroke_sculpt_randomize(params),
km_gpencil_legacy_stroke_sculpt_clone(params),
km_gpencil_legacy_stroke_weight_mode(params),
km_gpencil_legacy_stroke_weight_draw(params),
km_gpencil_legacy_stroke_weight_blur(params),
km_gpencil_legacy_stroke_weight_average(params),
km_gpencil_legacy_stroke_weight_smear(params),
km_gpencil_legacy_stroke_vertex_mode(params),
km_gpencil_legacy_stroke_vertex_draw(params),
km_gpencil_legacy_stroke_vertex_blur(params),
km_gpencil_legacy_stroke_vertex_average(params),
km_gpencil_legacy_stroke_vertex_smear(params),
km_gpencil_legacy_stroke_vertex_replace(params),
# Grease Pencil v3
km_grease_pencil_paint_mode(params),
km_grease_pencil_edit_mode(params),
km_grease_pencil_sculpt_mode(params),
# Object mode.
km_object_mode(params),
km_object_non_modal(params),

View File

@ -2341,7 +2341,7 @@ def km_animation_channels(params):
# Modes
def km_grease_pencil(_params):
def km_gpencil_legacy(_params):
items = []
keymap = (
"Grease Pencil",
@ -2352,7 +2352,7 @@ def km_grease_pencil(_params):
return keymap
def _grease_pencil_selection(params):
def _gpencil_legacy_selection(params):
return [
# Select all
("gpencil.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
@ -2369,7 +2369,7 @@ def _grease_pencil_selection(params):
]
def _grease_pencil_display():
def _gpencil_legacy_display():
return [
("wm.context_toggle", {"type": 'Q', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'space_data.overlay.use_gpencil_edit_lines')]}),
@ -2378,7 +2378,7 @@ def _grease_pencil_display():
]
def km_grease_pencil_stroke_edit_mode(params):
def km_gpencil_legacy_stroke_edit_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Edit Mode",
@ -2393,7 +2393,7 @@ def km_grease_pencil_stroke_edit_mode(params):
("gpencil.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
{"properties": [("extend", True), ("toggle", True)]}),
# Selection
*_grease_pencil_selection(params),
*_gpencil_legacy_selection(params),
("gpencil.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
# Duplicate and move selected points
("gpencil.duplicate_move", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
@ -2453,7 +2453,7 @@ def km_grease_pencil_stroke_edit_mode(params):
return keymap
def km_grease_pencil_stroke_paint_mode(params):
def km_gpencil_legacy_stroke_paint_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Paint Mode",
@ -2509,7 +2509,7 @@ def km_grease_pencil_stroke_paint_mode(params):
return keymap
def km_grease_pencil_stroke_paint_draw_brush(params):
def km_gpencil_legacy_stroke_paint_draw_brush(params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Draw brush)",
@ -2540,7 +2540,7 @@ def km_grease_pencil_stroke_paint_draw_brush(params):
return keymap
def km_grease_pencil_stroke_paint_erase(params):
def km_gpencil_legacy_stroke_paint_erase(params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Erase)",
@ -2559,7 +2559,7 @@ def km_grease_pencil_stroke_paint_erase(params):
return keymap
def km_grease_pencil_stroke_paint_fill(params):
def km_gpencil_legacy_stroke_paint_fill(params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Fill)",
@ -2584,7 +2584,7 @@ def km_grease_pencil_stroke_paint_fill(params):
return keymap
def km_grease_pencil_stroke_paint_tint(params):
def km_gpencil_legacy_stroke_paint_tint(params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Tint)",
@ -2603,7 +2603,7 @@ def km_grease_pencil_stroke_paint_tint(params):
return keymap
def km_grease_pencil_stroke_sculpt_mode(params):
def km_gpencil_legacy_stroke_sculpt_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt Mode",
@ -2625,7 +2625,7 @@ def km_grease_pencil_stroke_sculpt_mode(params):
("gpencil.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "alt": True, "ctrl": True},
{"properties": [("use_shift_extend", True), ("toggle", True)]}),
# Selection
*_grease_pencil_selection(params),
*_gpencil_legacy_selection(params),
# Brush properties
("wm.radial_control", {"type": 'U', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt_paint.brush.strength')]}),
@ -2638,7 +2638,7 @@ def km_grease_pencil_stroke_sculpt_mode(params):
# Copy
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
# Display
*_grease_pencil_display(),
*_gpencil_legacy_display(),
# Delete
op_menu("VIEW3D_MT_edit_gpencil_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}),
op_menu("VIEW3D_MT_edit_gpencil_delete", {"type": 'DEL', "value": 'PRESS'}),
@ -2663,7 +2663,7 @@ def km_grease_pencil_stroke_sculpt_mode(params):
return keymap
def km_grease_pencil_stroke_sculpt_smooth(_params):
def km_gpencil_legacy_stroke_sculpt_smooth(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Smooth)",
@ -2683,7 +2683,7 @@ def km_grease_pencil_stroke_sculpt_smooth(_params):
return keymap
def km_grease_pencil_stroke_sculpt_thickness(_params):
def km_gpencil_legacy_stroke_sculpt_thickness(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Thickness)",
@ -2703,7 +2703,7 @@ def km_grease_pencil_stroke_sculpt_thickness(_params):
return keymap
def km_grease_pencil_stroke_sculpt_strength(_params):
def km_gpencil_legacy_stroke_sculpt_strength(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Strength)",
@ -2723,7 +2723,7 @@ def km_grease_pencil_stroke_sculpt_strength(_params):
return keymap
def km_grease_pencil_stroke_sculpt_grab(_params):
def km_gpencil_legacy_stroke_sculpt_grab(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Grab)",
@ -2743,7 +2743,7 @@ def km_grease_pencil_stroke_sculpt_grab(_params):
return keymap
def km_grease_pencil_stroke_sculpt_push(_params):
def km_gpencil_legacy_stroke_sculpt_push(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Push)",
@ -2763,7 +2763,7 @@ def km_grease_pencil_stroke_sculpt_push(_params):
return keymap
def km_grease_pencil_stroke_sculpt_twist(_params):
def km_gpencil_legacy_stroke_sculpt_twist(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Twist)",
@ -2783,7 +2783,7 @@ def km_grease_pencil_stroke_sculpt_twist(_params):
return keymap
def km_grease_pencil_stroke_sculpt_pinch(_params):
def km_gpencil_legacy_stroke_sculpt_pinch(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Pinch)",
@ -2803,7 +2803,7 @@ def km_grease_pencil_stroke_sculpt_pinch(_params):
return keymap
def km_grease_pencil_stroke_sculpt_randomize(_params):
def km_gpencil_legacy_stroke_sculpt_randomize(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Randomize)",
@ -2823,7 +2823,7 @@ def km_grease_pencil_stroke_sculpt_randomize(_params):
return keymap
def km_grease_pencil_stroke_sculpt_clone(_params):
def km_gpencil_legacy_stroke_sculpt_clone(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Clone)",
@ -2843,7 +2843,7 @@ def km_grease_pencil_stroke_sculpt_clone(_params):
return keymap
def km_grease_pencil_stroke_weight_mode(params):
def km_gpencil_legacy_stroke_weight_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Weight Mode",
@ -2888,7 +2888,7 @@ def km_grease_pencil_stroke_weight_mode(params):
return keymap
def km_grease_pencil_stroke_weight_draw(_params):
def km_gpencil_legacy_stroke_weight_draw(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight (Draw)",
@ -2906,7 +2906,7 @@ def km_grease_pencil_stroke_weight_draw(_params):
return keymap
def km_grease_pencil_stroke_weight_blur(_params):
def km_gpencil_legacy_stroke_weight_blur(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight (Blur)",
@ -2922,7 +2922,7 @@ def km_grease_pencil_stroke_weight_blur(_params):
return keymap
def km_grease_pencil_stroke_weight_average(_params):
def km_gpencil_legacy_stroke_weight_average(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight (Average)",
@ -2938,7 +2938,7 @@ def km_grease_pencil_stroke_weight_average(_params):
return keymap
def km_grease_pencil_stroke_weight_smear(_params):
def km_gpencil_legacy_stroke_weight_smear(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight (Smear)",
@ -2954,7 +2954,7 @@ def km_grease_pencil_stroke_weight_smear(_params):
return keymap
def km_grease_pencil_stroke_vertex_mode(params):
def km_gpencil_legacy_stroke_vertex_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex Mode",
@ -2976,7 +2976,7 @@ def km_grease_pencil_stroke_vertex_mode(params):
("gpencil.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "alt": True, "ctrl": True},
{"properties": [("use_shift_extend", True), ("toggle", True)]}),
# Selection
*_grease_pencil_selection(params),
*_gpencil_legacy_selection(params),
# Brush strength
("wm.radial_control", {"type": 'U', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
@ -2990,7 +2990,7 @@ def km_grease_pencil_stroke_vertex_mode(params):
# Color operators
("gpencil.tint_flip", {"type": 'X', "value": 'PRESS'}, None),
# Display
*_grease_pencil_display(),
*_gpencil_legacy_display(),
# Delete
op_menu("VIEW3D_MT_edit_gpencil_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}),
op_menu("VIEW3D_MT_edit_gpencil_delete", {"type": 'DEL', "value": 'PRESS'}),
@ -3013,7 +3013,7 @@ def km_grease_pencil_stroke_vertex_mode(params):
return keymap
def km_grease_pencil_stroke_vertex_draw(params):
def km_gpencil_legacy_stroke_vertex_draw(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Draw)",
@ -3038,7 +3038,7 @@ def km_grease_pencil_stroke_vertex_draw(params):
return keymap
def km_grease_pencil_stroke_vertex_blur(params):
def km_gpencil_legacy_stroke_vertex_blur(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Blur)",
@ -3061,7 +3061,7 @@ def km_grease_pencil_stroke_vertex_blur(params):
return keymap
def km_grease_pencil_stroke_vertex_average(params):
def km_gpencil_legacy_stroke_vertex_average(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Average)",
@ -3086,7 +3086,7 @@ def km_grease_pencil_stroke_vertex_average(params):
return keymap
def km_grease_pencil_stroke_vertex_smear(params):
def km_gpencil_legacy_stroke_vertex_smear(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Smear)",
@ -3109,7 +3109,7 @@ def km_grease_pencil_stroke_vertex_smear(params):
return keymap
def km_grease_pencil_stroke_vertex_replace(params):
def km_gpencil_legacy_stroke_vertex_replace(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Replace)",
@ -4520,34 +4520,34 @@ def generate_keymaps_impl(params=None):
km_animation_channels(params),
# Modes.
# km_grease_pencil(params), # Empty.
km_grease_pencil_stroke_edit_mode(params),
km_grease_pencil_stroke_paint_mode(params),
km_grease_pencil_stroke_paint_draw_brush(params),
km_grease_pencil_stroke_paint_erase(params),
km_grease_pencil_stroke_paint_fill(params),
km_grease_pencil_stroke_paint_tint(params),
km_grease_pencil_stroke_sculpt_mode(params),
km_grease_pencil_stroke_sculpt_smooth(params),
km_grease_pencil_stroke_sculpt_thickness(params),
km_grease_pencil_stroke_sculpt_strength(params),
km_grease_pencil_stroke_sculpt_grab(params),
km_grease_pencil_stroke_sculpt_push(params),
km_grease_pencil_stroke_sculpt_twist(params),
km_grease_pencil_stroke_sculpt_pinch(params),
km_grease_pencil_stroke_sculpt_randomize(params),
km_grease_pencil_stroke_sculpt_clone(params),
km_grease_pencil_stroke_weight_mode(params),
km_grease_pencil_stroke_weight_draw(params),
km_grease_pencil_stroke_weight_blur(params),
km_grease_pencil_stroke_weight_average(params),
km_grease_pencil_stroke_weight_smear(params),
km_grease_pencil_stroke_vertex_mode(params),
km_grease_pencil_stroke_vertex_draw(params),
km_grease_pencil_stroke_vertex_blur(params),
km_grease_pencil_stroke_vertex_average(params),
km_grease_pencil_stroke_vertex_smear(params),
km_grease_pencil_stroke_vertex_replace(params),
# km_gpencil_legacy(params), # Empty.
km_gpencil_legacy_stroke_edit_mode(params),
km_gpencil_legacy_stroke_paint_mode(params),
km_gpencil_legacy_stroke_paint_draw_brush(params),
km_gpencil_legacy_stroke_paint_erase(params),
km_gpencil_legacy_stroke_paint_fill(params),
km_gpencil_legacy_stroke_paint_tint(params),
km_gpencil_legacy_stroke_sculpt_mode(params),
km_gpencil_legacy_stroke_sculpt_smooth(params),
km_gpencil_legacy_stroke_sculpt_thickness(params),
km_gpencil_legacy_stroke_sculpt_strength(params),
km_gpencil_legacy_stroke_sculpt_grab(params),
km_gpencil_legacy_stroke_sculpt_push(params),
km_gpencil_legacy_stroke_sculpt_twist(params),
km_gpencil_legacy_stroke_sculpt_pinch(params),
km_gpencil_legacy_stroke_sculpt_randomize(params),
km_gpencil_legacy_stroke_sculpt_clone(params),
km_gpencil_legacy_stroke_weight_mode(params),
km_gpencil_legacy_stroke_weight_draw(params),
km_gpencil_legacy_stroke_weight_blur(params),
km_gpencil_legacy_stroke_weight_average(params),
km_gpencil_legacy_stroke_weight_smear(params),
km_gpencil_legacy_stroke_vertex_mode(params),
km_gpencil_legacy_stroke_vertex_draw(params),
km_gpencil_legacy_stroke_vertex_blur(params),
km_gpencil_legacy_stroke_vertex_average(params),
km_gpencil_legacy_stroke_vertex_smear(params),
km_gpencil_legacy_stroke_vertex_replace(params),
km_face_mask(params),
km_weight_paint_vertex_selection(params),
km_pose(params),

View File

@ -71,7 +71,6 @@ class ANIM_OT_keying_set_export(Operator):
f.write("ks.use_insertkey_needed = %s\n" % ks.use_insertkey_needed)
f.write("ks.use_insertkey_visual = %s\n" % ks.use_insertkey_visual)
f.write("ks.use_insertkey_xyz_to_rgb = %s\n" % ks.use_insertkey_xyz_to_rgb)
f.write("\n")
# --------------------------------------------------------

View File

@ -589,6 +589,11 @@ class RemovePresetInterfaceTheme(AddPresetBase, Operator):
def invoke(self, context, event):
return context.window_manager.invoke_confirm(self, event, title="Remove Custom Theme", confirm_text="Delete")
def post_cb(self, context):
# Without this, the name & colors are kept after removing the theme.
# Even though the theme is removed from the list, it's seems like a bug to keep it displayed after removal.
bpy.ops.preferences.reset_default_theme()
class SavePresetInterfaceTheme(AddPresetBase, Operator):
"""Save a custom theme in the preset list"""

View File

@ -70,7 +70,7 @@ class GreasePencilDisplayPanel:
def poll(cls, context):
ob = context.active_object
brush = context.tool_settings.gpencil_paint.brush
if ob and ob.type == 'GPENCIL' and brush:
if ob and ob.type in {'GPENCIL', 'GREASE_PENCIL'} and brush:
return True
return False

View File

@ -84,6 +84,8 @@ class UnifiedPaintPanel:
return tool_settings.curves_sculpt
elif mode == 'PAINT_GREASE_PENCIL':
return tool_settings.gpencil_paint
elif mode == 'SCULPT_GREASE_PENCIL':
return tool_settings.gpencil_sculpt_paint
return None
@staticmethod
@ -906,6 +908,11 @@ def brush_shared_settings(layout, context, brush, popover=False):
size = True
strength = True
# Grease Pencil #
if mode == 'SCULPT_GREASE_PENCIL':
size = True
strength = True
### Draw settings. ###
ups = context.scene.tool_settings.unified_paint_settings
@ -1053,6 +1060,17 @@ def brush_settings_advanced(layout, context, brush, popover=False):
col.prop(brush, "use_original_plane", text="Plane")
layout.separator()
elif mode == 'SCULPT_GREASE_PENCIL':
tool = brush.gpencil_sculpt_tool
gp_settings = brush.gpencil_settings
if tool in {'SMOOTH', 'RANDOMIZE'}:
col = layout.column(heading="Affect", align=True)
col.prop(gp_settings, "use_edit_position", text="Position")
col.prop(gp_settings, "use_edit_strength", text="Strength")
col.prop(gp_settings, "use_edit_thickness", text="Thickness")
col.prop(gp_settings, "use_edit_uv", text="UV")
# 3D and 2D Texture Paint.
elif mode in {'PAINT_TEXTURE', 'PAINT_2D'}:
capabilities = brush.image_paint_capabilities

View File

@ -2460,6 +2460,37 @@ class _defs_gpencil_sculpt:
)
class _defs_grease_pencil_sculpt:
@staticmethod
def poll_select_mask(context):
if context is None:
return True
ob = context.active_object
tool_settings = context.scene.tool_settings
return (
ob is not None and
ob.type in {'GPENCIL', 'GREASE_PENCIL'} and (
tool_settings.use_gpencil_select_mask_point or
tool_settings.use_gpencil_select_mask_stroke or
tool_settings.use_gpencil_select_mask_segment
)
)
@staticmethod
def generate_from_brushes(context):
return generate_from_enum_ex(
context,
idname_prefix="builtin_brush.",
icon_prefix="ops.gpencil.sculpt_",
type=bpy.types.Brush,
# Uses GPv2 tool settings
attr="gpencil_sculpt_tool",
tooldef_keywords=dict(
operator="grease_pencil.sculpt_paint",
),
)
class _defs_gpencil_weight:
@staticmethod
@ -3159,6 +3190,16 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
*_tools_annotate,
],
'SCULPT_GREASE_PENCIL': [
_defs_grease_pencil_sculpt.generate_from_brushes,
None,
*_tools_annotate,
lambda context: (
VIEW3D_PT_tools_active._tools_gpencil_select
if _defs_grease_pencil_sculpt.poll_select_mask(context)
else ()
),
],
'PAINT_TEXTURE': [
_defs_texture_paint.generate_from_brushes,
None,

View File

@ -120,6 +120,14 @@ class VIEW3D_HT_tool_header(Header):
if tool in {'SMOOTH', 'RANDOMIZE'}:
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_brush_popover")
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
elif tool_mode == 'SCULPT_GREASE_PENCIL':
if is_valid_context:
brush = context.tool_settings.gpencil_sculpt_paint.brush
if brush:
tool = brush.gpencil_sculpt_tool
if tool in {'SMOOTH', 'RANDOMIZE'}:
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_brush_popover")
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
elif tool_mode == 'WEIGHT_GPENCIL':
if is_valid_context:
layout.popover("VIEW3D_PT_tools_grease_pencil_weight_appearance")
@ -417,6 +425,59 @@ class _draw_tool_settings_context_mode:
return True
@staticmethod
def SCULPT_GREASE_PENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
return False
paint = context.tool_settings.gpencil_sculpt_paint
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
brush = paint.brush
if brush is None:
return False
tool_settings = context.tool_settings
capabilities = brush.sculpt_capabilities
ups = tool_settings.unified_paint_settings
size = "size"
size_owner = ups if ups.use_unified_size else brush
if size_owner.use_locked_size == 'SCENE':
size = "unprojected_radius"
UnifiedPaintPanel.prop_unified(
layout,
context,
brush,
size,
pressure_name="use_pressure_size",
unified_name="use_unified_size",
text="Radius",
slider=True,
header=True,
)
# strength, use_strength_pressure
pressure_name = "use_pressure_strength" if capabilities.has_strength_pressure else None
UnifiedPaintPanel.prop_unified(
layout,
context,
brush,
"strength",
pressure_name=pressure_name,
unified_name="use_unified_strength",
text="Strength",
header=True,
)
# direction
if not capabilities.has_direction:
layout.row().prop(brush, "direction", expand=True, text="")
return True
@staticmethod
def WEIGHT_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
@ -1132,7 +1193,7 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_select_paint_mask")
elif mesh.use_paint_mask_vertex and mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX'}:
layout.menu("VIEW3D_MT_select_paint_mask_vertex")
elif mode_string not in {'SCULPT', 'SCULPT_CURVES', 'PAINT_GREASE_PENCIL'}:
elif mode_string not in {'SCULPT', 'SCULPT_CURVES', 'PAINT_GREASE_PENCIL', 'SCULPT_GREASE_PENCIL'}:
layout.menu("VIEW3D_MT_select_%s" % mode_string.lower())
if gp_edit:
@ -1143,6 +1204,8 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_mesh_add", text="Add", text_ctxt=i18n_contexts.operator_default)
elif mode_string == 'EDIT_CURVE':
layout.menu("VIEW3D_MT_curve_add", text="Add", text_ctxt=i18n_contexts.operator_default)
elif mode_string == "EDIT_CURVES":
layout.menu("VIEW3D_MT_edit_curves_add", text="Add", text_ctxt=i18n_contexts.operator_default)
elif mode_string == 'EDIT_SURFACE':
layout.menu("VIEW3D_MT_surface_add", text="Add", text_ctxt=i18n_contexts.operator_default)
elif mode_string == 'EDIT_METABALL':
@ -1183,7 +1246,7 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_edit_greasepencil_point")
elif obj:
if mode_string not in {'PAINT_TEXTURE', 'SCULPT_CURVES'}:
if mode_string not in {'PAINT_TEXTURE', 'SCULPT_CURVES', 'SCULPT_GREASE_PENCIL'}:
layout.menu("VIEW3D_MT_%s" % mode_string.lower())
if mode_string == 'SCULPT':
layout.menu("VIEW3D_MT_mask")
@ -5901,6 +5964,16 @@ class VIEW3D_MT_edit_greasepencil_point(Menu):
layout.operator("grease_pencil.stroke_smooth", text="Smooth")
class VIEW3D_MT_edit_curves_add(Menu):
bl_label = "Add"
def draw(self, _context):
layout = self.layout
layout.operator("curves.add_bezier", text="Bezier", icon='CURVE_BEZCURVE')
layout.operator("curves.add_circle", text="Circle", icon='CURVE_BEZCIRCLE')
class VIEW3D_MT_edit_curves(Menu):
bl_label = "Curves"
@ -9079,6 +9152,7 @@ classes = (
VIEW3D_MT_edit_armature_delete,
VIEW3D_MT_edit_gpencil_transform,
VIEW3D_MT_edit_curves,
VIEW3D_MT_edit_curves_add,
VIEW3D_MT_edit_curves_segments,
VIEW3D_MT_edit_curves_control_points,
VIEW3D_MT_edit_pointcloud,

View File

@ -624,8 +624,11 @@ class VIEW3D_PT_slots_paint_canvas(SelectPaintSlotHelper, View3DPanel, Panel):
if mat and mat.texture_paint_images and mat.texture_paint_slots:
label = mat.texture_paint_slots[mat.paint_active_slot].name
elif paint.canvas_source == 'COLOR_ATTRIBUTE':
label = (me.color_attributes.active_color.name if me.color_attributes.active_color
else iface_("Color Attribute"))
active_color = me.color_attributes.active_color
label = (
active_color.name if active_color else
iface_("Color Attribute")
)
elif paint.canvas_image:
label = paint.canvas_image.name
@ -642,7 +645,7 @@ class VIEW3D_PT_slots_color_attributes(Panel):
me = context.object.data
active_color = me.color_attributes.active_color
self.bl_label = (
iface_(active_color.name) if active_color else
active_color.name if active_color else
iface_("Color Attributes")
)
@ -683,7 +686,7 @@ class VIEW3D_PT_slots_vertex_groups(Panel):
ob = context.object
groups = ob.vertex_groups
self.bl_label = (
iface_(groups.active.name) if groups and groups.active else
groups.active.name if groups and groups.active else
iface_("Vertex Groups")
)

View File

@ -1207,12 +1207,11 @@ bool armature_bonecoll_is_child_of(const bArmature *armature,
const int potential_child_index)
{
/* Check for roots, before we try and access collection_array[-1]. */
const bool is_root = armature_bonecoll_is_root(armature, potential_child_index);
if (is_root) {
if (armature_bonecoll_is_root(armature, potential_child_index)) {
return potential_parent_index == -1;
}
if (potential_parent_index < 0) {
return is_root;
return false;
}
const BoneCollection *potential_parent = armature->collection_array[potential_parent_index];

View File

@ -916,7 +916,7 @@ TEST_F(ArmatureBoneCollections, bcoll_move_to_parent__root_unroot)
ASSERT_EQ(6, arm.collection_array_num);
EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[1]->name);
EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[2]->name); // Became a root.
EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[2]->name); /* Became a root. */
EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[3]->name);
EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[4]->name);
EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[5]->name);
@ -941,10 +941,10 @@ TEST_F(ArmatureBoneCollections, bcoll_move_to_parent__root_unroot)
ASSERT_EQ(2, arm.collection_root_count);
ASSERT_EQ(6, arm.collection_array_num);
EXPECT_STREQ(bcoll_root_0->name, arm.collection_array[0]->name);
EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[1]->name); // Actually a root.
EXPECT_STREQ(bcoll_r0_child1->name, arm.collection_array[1]->name); /* Actually a root. */
EXPECT_STREQ(bcoll_r0_child0->name, arm.collection_array[2]->name);
EXPECT_STREQ(bcoll_r0_child2->name, arm.collection_array[3]->name);
EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[4]->name); // Became a child.
EXPECT_STREQ(bcoll_root_1->name, arm.collection_array[4]->name); /* Became a child. */
EXPECT_STREQ(bcoll_r1_child0->name, arm.collection_array[5]->name);
EXPECT_EQ(2, arm.collection_array[0]->child_index);

View File

@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 12
#define BLENDER_FILE_SUBVERSION 15
/* 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

@ -141,8 +141,9 @@ enum eContextObjectMode {
CTX_MODE_VERTEX_GPENCIL_LEGACY,
CTX_MODE_SCULPT_CURVES,
CTX_MODE_PAINT_GREASE_PENCIL,
CTX_MODE_SCULPT_GREASE_PENCIL,
};
#define CTX_MODE_NUM (CTX_MODE_PAINT_GREASE_PENCIL + 1)
#define CTX_MODE_NUM (CTX_MODE_SCULPT_GREASE_PENCIL + 1)
/* Context */

View File

@ -84,6 +84,7 @@ extern const uchar PAINT_CURSOR_VERTEX_PAINT[3];
extern const uchar PAINT_CURSOR_WEIGHT_PAINT[3];
extern const uchar PAINT_CURSOR_TEXTURE_PAINT[3];
extern const uchar PAINT_CURSOR_SCULPT_CURVES[3];
extern const uchar PAINT_CURSOR_SCULPT_GREASE_PENCIL[3];
enum class PaintMode : int8_t {
Sculpt = 0,
@ -102,9 +103,11 @@ enum class PaintMode : int8_t {
WeightGPencil = 9,
/** Curves. */
SculptCurves = 10,
/** Grease Pencil. */
SculptGreasePencil = 11,
/** Keep last. */
Invalid = 11,
Invalid = 12,
};
#define PAINT_MODE_HAS_BRUSH(mode) !ELEM(mode, PaintMode::SculptUV)

View File

@ -892,8 +892,12 @@ static bool nlastrips_path_rename_fix(ID *owner_id,
LISTBASE_FOREACH (NlaStrip *, strip, strips) {
/* fix strip's action */
if (strip->act != nullptr) {
is_changed |= fcurves_path_rename_fix(
const bool is_changed_action = fcurves_path_rename_fix(
owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths);
if (is_changed_action) {
DEG_id_tag_update(&strip->act->id, ID_RECALC_ANIMATION);
}
is_changed |= is_changed_action;
}
/* Ignore own F-Curves, since those are local. */
/* Check sub-strips (if meta-strips). */

View File

@ -1191,7 +1191,12 @@ enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit,
return CTX_MODE_EDIT_GPENCIL_LEGACY;
}
if (object_mode & OB_MODE_SCULPT_GPENCIL_LEGACY) {
return CTX_MODE_SCULPT_GPENCIL_LEGACY;
if (ob->type == OB_GPENCIL_LEGACY) {
return CTX_MODE_SCULPT_GPENCIL_LEGACY;
}
if (ob->type == OB_GREASE_PENCIL) {
return CTX_MODE_SCULPT_GREASE_PENCIL;
}
}
if (object_mode & OB_MODE_WEIGHT_GPENCIL_LEGACY) {
return CTX_MODE_WEIGHT_GPENCIL_LEGACY;
@ -1248,6 +1253,7 @@ static const char *data_mode_strings[] = {
"greasepencil_vertex",
"curves_sculpt",
"grease_pencil_paint",
"grease_pencil_sculpt",
nullptr,
};
BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1,

View File

@ -1966,8 +1966,12 @@ void BKE_fcurve_merge_duplicate_keys(FCurve *fcu, const int sel_flag, const bool
void BKE_fcurve_deduplicate_keys(FCurve *fcu)
{
if (fcu->totvert < 2) {
return;
}
BLI_assert_msg(fcu->bezt, "this function only works with regular (non-sampled) FCurves");
if (fcu->totvert < 2 || fcu->bezt == nullptr) {
if (fcu->bezt == nullptr) {
return;
}

View File

@ -643,13 +643,13 @@ static float (*mask_spline_feather_differentiated_points_with_resolution__double
/* before we transform verts */
len_base = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]);
// add_v2_v2(bezt_prev->vec[0], point_prev_n); // not needed
// add_v2_v2(bezt_prev->vec[0], point_prev_n); /* Not needed. */
add_v2_v2(bezt_prev->vec[1], point_prev_n);
add_v2_v2(bezt_prev->vec[2], point_prev_n);
add_v2_v2(bezt_curr->vec[0], point_curr_n);
add_v2_v2(bezt_curr->vec[1], point_curr_n);
// add_v2_v2(bezt_curr->vec[2], point_curr_n); // not needed
// add_v2_v2(bezt_curr->vec[2], point_curr_n); /* Not needed. */
len_feather = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]);

View File

@ -6,10 +6,11 @@
* \ingroup bke
*/
#include "BLI_map.hh"
#include "BLI_array_utils.hh"
#include "BLI_ordered_edge.hh"
#include "BLI_task.hh"
#include "BLI_threads.h"
#include "BLI_vector_set.hh"
#include "BKE_attribute.hh"
#include "BKE_customdata.hh"
@ -28,12 +29,12 @@ static uint64_t edge_hash_2(const OrderedEdge &edge)
return edge.v_low;
}
/* The map first contains an edge pointer and later an index. */
union OrigEdgeOrIndex {
const int2 *original_edge;
int index;
};
using EdgeMap = Map<OrderedEdge, OrigEdgeOrIndex>;
using EdgeMap = VectorSet<OrderedEdge,
DefaultProbingStrategy,
DefaultHash<OrderedEdge>,
DefaultEquality<OrderedEdge>,
SimpleVectorSetSlot<OrderedEdge, int>,
GuardedAllocator>;
static void reserve_hash_maps(const Mesh &mesh,
const bool keep_existing_edges,
@ -52,11 +53,11 @@ static void add_existing_edges_to_hash_maps(const Mesh &mesh,
const Span<int2> edges = mesh.edges();
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
const int task_index = &edge_map - edge_maps.data();
for (const int2 &edge : edges) {
const OrderedEdge ordered_edge(edge[0], edge[1]);
for (const int2 edge : edges) {
const OrderedEdge ordered_edge(edge);
/* Only add the edge when it belongs into this map. */
if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) {
edge_map.add_new(ordered_edge, {&edge});
edge_map.add(ordered_edge);
}
}
});
@ -76,11 +77,11 @@ static void add_face_edges_to_hash_maps(const Mesh &mesh,
const int vert = corner_verts[corner];
const int vert_prev = corner_verts[bke::mesh::face_corner_prev(face, corner)];
/* Can only be the same when the mesh data is invalid. */
if (vert_prev != vert) {
if (LIKELY(vert_prev != vert)) {
const OrderedEdge ordered_edge(vert_prev, vert);
/* Only add the edge when it belongs into this map. */
if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) {
edge_map.lookup_or_add(ordered_edge, {nullptr});
edge_map.add(ordered_edge);
}
}
}
@ -89,38 +90,17 @@ static void add_face_edges_to_hash_maps(const Mesh &mesh,
}
static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edge_maps,
const OffsetIndices<int> edge_offsets,
MutableSpan<int2> new_edges)
{
/* All edges are distributed in the hash tables now. They have to be serialized into a single
* array below. To be able to parallelize this, we have to compute edge index offsets for each
* map. */
Array<int> edge_sizes(edge_maps.size() + 1);
for (const int i : edge_maps.index_range()) {
edge_sizes[i] = edge_maps[i].size();
}
const OffsetIndices<int> edge_offsets = offset_indices::accumulate_counts_to_offsets(edge_sizes);
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
const int task_index = &edge_map - edge_maps.data();
if (edge_offsets[task_index].is_empty()) {
return;
}
int new_edge_index = edge_offsets[task_index].first();
for (EdgeMap::MutableItem item : edge_map.items()) {
int2 &new_edge = new_edges[new_edge_index];
const int2 *orig_edge = item.value.original_edge;
if (orig_edge != nullptr) {
/* Copy values from original edge. */
new_edge = *orig_edge;
}
else {
/* Initialize new edge. */
new_edge = int2(item.key.v_low, item.key.v_high);
}
item.value.index = new_edge_index;
new_edge_index++;
}
MutableSpan<int2> result_edges = new_edges.slice(edge_offsets[task_index]);
result_edges.copy_from(edge_map.as_span().cast<int2>());
});
}
@ -128,6 +108,7 @@ static void update_edge_indices_in_face_loops(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const Span<EdgeMap> edge_maps,
const uint32_t parallel_mask,
const OffsetIndices<int> edge_offsets,
MutableSpan<int> corner_edges)
{
threading::parallel_for(faces.index_range(), 100, [&](IndexRange range) {
@ -136,20 +117,19 @@ static void update_edge_indices_in_face_loops(const OffsetIndices<int> faces,
for (const int corner : face) {
const int vert = corner_verts[corner];
const int vert_prev = corner_verts[bke::mesh::face_corner_next(face, corner)];
int edge_index;
if (vert_prev != vert) {
const OrderedEdge ordered_edge(vert_prev, vert);
/* Double lookup: First find the map that contains the edge, then lookup the edge. */
const EdgeMap &edge_map = edge_maps[parallel_mask & edge_hash_2(ordered_edge)];
edge_index = edge_map.lookup(ordered_edge).index;
}
else {
if (UNLIKELY(vert == vert_prev)) {
/* This is an invalid edge; normally this does not happen in Blender,
* but it can be part of an imported mesh with invalid geometry. See
* #76514. */
edge_index = 0;
corner_edges[corner] = 0;
continue;
}
const OrderedEdge ordered_edge(vert_prev, vert);
const int task_index = parallel_mask & edge_hash_2(ordered_edge);
const EdgeMap &edge_map = edge_maps[task_index];
const int edge_i = edge_map.index_of(ordered_edge);
const int edge_index = edge_offsets[task_index][edge_i];
corner_edges[corner] = edge_index;
}
}
@ -173,6 +153,24 @@ static void clear_hash_tables(MutableSpan<EdgeMap> edge_maps)
threading::parallel_for_each(edge_maps, [](EdgeMap &edge_map) { edge_map.clear_and_shrink(); });
}
static void deselect_known_edges(const OffsetIndices<int> edge_offsets,
const Span<EdgeMap> edge_maps,
const uint32_t parallel_mask,
const Span<int2> known_edges,
MutableSpan<bool> selection)
{
threading::parallel_for(known_edges.index_range(), 2048, [&](const IndexRange range) {
for (const int2 original_edge : known_edges.slice(range)) {
const OrderedEdge ordered_edge(original_edge);
const int task_index = parallel_mask & edge_hash_2(ordered_edge);
const EdgeMap &edge_map = edge_maps[task_index];
const int edge_i = edge_map.index_of(ordered_edge);
const int edge_index = edge_offsets[task_index][edge_i];
selection[edge_index] = false;
}
});
}
} // namespace calc_edges
void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, const bool select_new_edges)
@ -191,24 +189,35 @@ void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, const bool select_new
}
calc_edges::add_face_edges_to_hash_maps(mesh, parallel_mask, edge_maps);
/* Compute total number of edges. */
int new_totedge = 0;
for (const calc_edges::EdgeMap &edge_map : edge_maps) {
new_totedge += edge_map.size();
Array<int> edge_sizes(edge_maps.size() + 1);
for (const int i : edge_maps.index_range()) {
edge_sizes[i] = edge_maps[i].size();
}
const OffsetIndices<int> edge_offsets = offset_indices::accumulate_counts_to_offsets(edge_sizes);
/* Create new edges. */
MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.add<int>(".corner_edge", AttrDomain::Corner, AttributeInitConstruct());
MutableSpan<int2> new_edges(MEM_cnew_array<int2>(new_totedge, __func__), new_totedge);
calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, new_edges);
calc_edges::update_edge_indices_in_face_loops(
mesh.faces(), mesh.corner_verts(), edge_maps, parallel_mask, mesh.corner_edges_for_write());
MutableSpan<int2> new_edges(MEM_cnew_array<int2>(edge_offsets.total_size(), __func__),
edge_offsets.total_size());
calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, edge_offsets, new_edges);
calc_edges::update_edge_indices_in_face_loops(mesh.faces(),
mesh.corner_verts(),
edge_maps,
parallel_mask,
edge_offsets,
mesh.corner_edges_for_write());
Array<int2> original_edges;
if (keep_existing_edges && select_new_edges) {
original_edges.reinitialize(mesh.edges_num);
array_utils::copy(mesh.edges(), original_edges.as_mutable_span());
}
/* Free old CustomData and assign new one. */
CustomData_free(&mesh.edge_data, mesh.edges_num);
CustomData_reset(&mesh.edge_data);
mesh.edges_num = new_totedge;
mesh.edges_num = edge_offsets.total_size();
attributes.add<int2>(".edge_verts", AttrDomain::Edge, AttributeInitMoveArray(new_edges.data()));
if (select_new_edges) {
@ -216,14 +225,10 @@ void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, const bool select_new
SpanAttributeWriter<bool> select_edge = attributes.lookup_or_add_for_write_span<bool>(
".select_edge", AttrDomain::Edge);
if (select_edge) {
int new_edge_index = 0;
for (const calc_edges::EdgeMap &edge_map : edge_maps) {
for (const calc_edges::EdgeMap::Item item : edge_map.items()) {
if (item.value.original_edge == nullptr) {
select_edge.span[new_edge_index] = true;
}
new_edge_index++;
}
select_edge.span.fill(true);
if (!original_edges.is_empty()) {
calc_edges::deselect_known_edges(
edge_offsets, edge_maps, parallel_mask, original_edges, select_edge.span);
}
select_edge.finish();
}
@ -235,7 +240,7 @@ void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, const bool select_new
}
/* Explicitly clear edge maps, because that way it can be parallelized. */
clear_hash_tables(edge_maps);
calc_edges::clear_hash_tables(edge_maps);
}
} // namespace blender::bke

View File

@ -1348,12 +1348,11 @@ OceanCache *BKE_ocean_init_cache(const char *bakepath,
void BKE_ocean_simulate_cache(OceanCache *och, int frame)
{
char filepath[FILE_MAX];
int f = frame;
/* ibufs array is zero based, but filenames are based on frame numbers */
/* still need to clamp frame numbers to valid range of images on disk though */
CLAMP(frame, och->start, och->end);
f = frame - och->start; /* shift to 0 based */
const int f = frame - och->start; /* shift to 0 based */
/* if image is already loaded in mem, return */
if (och->ibufs_disp[f] != nullptr) {

View File

@ -10,6 +10,7 @@
#include <cstring>
#include <optional>
#include "DNA_object_enums.h"
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
@ -250,6 +251,7 @@ const uchar PAINT_CURSOR_VERTEX_PAINT[3] = {255, 255, 255};
const uchar PAINT_CURSOR_WEIGHT_PAINT[3] = {200, 200, 255};
const uchar PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255};
const uchar PAINT_CURSOR_SCULPT_CURVES[3] = {255, 100, 100};
const uchar PAINT_CURSOR_SCULPT_GREASE_PENCIL[3] = {255, 100, 100};
static ePaintOverlayControlFlags overlay_flags = (ePaintOverlayControlFlags)0;
@ -361,6 +363,9 @@ bool BKE_paint_ensure_from_paintmode(Scene *sce, PaintMode mode)
case PaintMode::SculptCurves:
paint_ptr = (Paint **)&ts->curves_sculpt;
break;
case PaintMode::SculptGreasePencil:
paint_ptr = (Paint **)&ts->gp_sculptpaint;
break;
case PaintMode::Invalid:
break;
}
@ -398,6 +403,8 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode)
return &ts->gp_weightpaint->paint;
case PaintMode::SculptCurves:
return &ts->curves_sculpt->paint;
case PaintMode::SculptGreasePencil:
return &ts->gp_sculptpaint->paint;
case PaintMode::Invalid:
return nullptr;
default:
@ -432,6 +439,8 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(const PaintMode m
return rna_enum_brush_gpencil_weight_types_items;
case PaintMode::SculptCurves:
return rna_enum_brush_curves_sculpt_tool_items;
case PaintMode::SculptGreasePencil:
return rna_enum_brush_gpencil_sculpt_types_items;
case PaintMode::Invalid:
break;
}
@ -462,6 +471,8 @@ const char *BKE_paint_get_tool_prop_id_from_paintmode(const PaintMode mode)
return "gpencil_weight_tool";
case PaintMode::SculptCurves:
return "curves_sculpt_tool";
case PaintMode::SculptGreasePencil:
return "gpencil_sculpt_tool";
case PaintMode::Invalid:
break;
}
@ -485,6 +496,7 @@ const char *BKE_paint_get_tool_enum_translation_context_from_paintmode(const Pai
case PaintMode::SculptGPencil:
case PaintMode::WeightGPencil:
case PaintMode::SculptCurves:
case PaintMode::SculptGreasePencil:
case PaintMode::Invalid:
break;
}
@ -596,7 +608,13 @@ PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
case OB_MODE_SCULPT:
return PaintMode::Sculpt;
case OB_MODE_SCULPT_GPENCIL_LEGACY:
return PaintMode::SculptGPencil;
if (obact->type == OB_GPENCIL_LEGACY) {
return PaintMode::SculptGPencil;
}
if (obact->type == OB_GREASE_PENCIL) {
return PaintMode::SculptGreasePencil;
}
return PaintMode::Invalid;
case OB_MODE_WEIGHT_GPENCIL_LEGACY:
return PaintMode::WeightGPencil;
case OB_MODE_VERTEX_PAINT:
@ -648,6 +666,8 @@ PaintMode BKE_paintmode_get_from_tool(const bToolRef *tref)
return PaintMode::SculptCurves;
case CTX_MODE_PAINT_GREASE_PENCIL:
return PaintMode::GPencil;
case CTX_MODE_SCULPT_GREASE_PENCIL:
return PaintMode::SculptGreasePencil;
}
}
else if (tref->space_type == SPACE_IMAGE) {
@ -759,6 +779,8 @@ uint BKE_paint_get_brush_tool_offset_from_paintmode(const PaintMode mode)
return offsetof(Brush, gpencil_weight_tool);
case PaintMode::SculptCurves:
return offsetof(Brush, curves_sculpt_tool);
case PaintMode::SculptGreasePencil:
return offsetof(Brush, gpencil_sculpt_tool);
case PaintMode::Invalid:
break; /* We don't use these yet. */
}
@ -1093,6 +1115,8 @@ eObjectMode BKE_paint_object_mode_from_paintmode(const PaintMode mode)
return OB_MODE_SCULPT_CURVES;
case PaintMode::GPencil:
return OB_MODE_PAINT_GREASE_PENCIL;
case PaintMode::SculptGreasePencil:
return OB_MODE_SCULPT_GPENCIL_LEGACY;
case PaintMode::Invalid:
default:
return OB_MODE_OBJECT;

View File

@ -1669,7 +1669,7 @@ template<typename T>
MatBase<T, 4, 4> result = mat;
const bool is_perspective = mat[2][3] == -1.0f;
const bool is_perspective_infinite = mat[2][2] == -1.0f;
if (is_perspective | is_perspective_infinite) {
if (is_perspective || is_perspective_infinite) {
result[2][0] -= mat[0][0] * offset.x / math::length(float3(mat[0][0], mat[1][0], mat[2][0]));
result[2][1] -= mat[1][1] * offset.y / math::length(float3(mat[0][1], mat[1][1], mat[2][1]));
}

View File

@ -179,7 +179,7 @@ std::string BLI_uniquename_cb(blender::FunctionRef<bool(blender::StringRef)> uni
* \param name_offset: Offset of name within block structure
* \param name_maxncpy: Maximum length of name area
*/
void BLI_uniquename(struct ListBase *list,
void BLI_uniquename(const struct ListBase *list,
void *vlink,
const char *defname,
char delim,

View File

@ -32,7 +32,9 @@ namespace blender {
* The simplest possible vector set slot. It stores the index and state in a signed integer. If the
* value is negative, it represents empty or occupied state. Otherwise it represents the index.
*/
template<typename Key> class SimpleVectorSetSlot {
template<typename Key, typename IndexT = int64_t> class SimpleVectorSetSlot {
static_assert(std::is_integral_v<IndexT> && std::is_signed_v<IndexT>);
private:
#define s_is_empty -1
#define s_is_removed -2
@ -40,7 +42,7 @@ template<typename Key> class SimpleVectorSetSlot {
/**
* After the default constructor has run, the slot has to be in the empty state.
*/
int64_t state_ = s_is_empty;
IndexT state_ = s_is_empty;
public:
/**
@ -62,7 +64,7 @@ template<typename Key> class SimpleVectorSetSlot {
/**
* Return the stored index. It is assumed that the slot is occupied.
*/
int64_t index() const
IndexT index() const
{
BLI_assert(this->is_occupied());
return state_;
@ -88,7 +90,7 @@ template<typename Key> class SimpleVectorSetSlot {
* Change the state of this slot from empty/removed to occupied. The hash can be used by other
* slot implementations.
*/
void occupy(int64_t index, uint64_t /*hash*/)
void occupy(IndexT index, uint64_t /*hash*/)
{
BLI_assert(!this->is_occupied());
state_ = index;
@ -98,7 +100,7 @@ template<typename Key> class SimpleVectorSetSlot {
* The key has changed its position in the vector, so the index has to be updated. This method
* can assume that the slot is currently occupied.
*/
void update_index(int64_t index)
void update_index(IndexT index)
{
BLI_assert(this->is_occupied());
state_ = index;
@ -116,7 +118,7 @@ template<typename Key> class SimpleVectorSetSlot {
/**
* Return true if this slot is currently occupied and its corresponding key has the given index.
*/
bool has_index(int64_t index) const
bool has_index(IndexT index) const
{
return state_ == index;
}

View File

@ -1204,8 +1204,8 @@ static int delete_soft(const char *file, const char **error_message)
const char *args[5];
const char *process_failed;
char *xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP");
char *xdg_session_desktop = getenv("XDG_SESSION_DESKTOP");
const char *xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP");
const char *xdg_session_desktop = getenv("XDG_SESSION_DESKTOP");
if ((xdg_current_desktop != nullptr && STREQ(xdg_current_desktop, "KDE")) ||
(xdg_session_desktop != nullptr && STREQ(xdg_session_desktop, "KDE")))

View File

@ -53,11 +53,10 @@ bool BLI_tridiagonal_solve(
size_t bytes = sizeof(double) * (uint)count;
double *c1 = (double *)MEM_mallocN(bytes * 2, "tridiagonal_c1d1");
double *d1 = c1 + count;
if (!c1) {
return false;
}
double *d1 = c1 + count;
int i;
double c_prev, d_prev, x_prev;
@ -120,11 +119,10 @@ bool BLI_tridiagonal_solve_cyclic(
size_t bytes = sizeof(float) * (uint)count;
float *tmp = (float *)MEM_mallocN(bytes * 2, "tridiagonal_ex");
float *b2 = tmp + count;
if (!tmp) {
return false;
}
float *b2 = tmp + count;
/* Prepare the non-cyclic system; relies on tridiagonal_solve ignoring values. */
memcpy(b2, b, bytes);

View File

@ -1397,7 +1397,7 @@ static bool is_pwn(const IMesh &tm, const TriMeshTopology &tmtopo)
* the dummy triangle lies, then finding which cell is between
* the two triangles on either side of the dummy.
*/
static int find_cell_for_point_near_edge(mpq3 p,
static int find_cell_for_point_near_edge(const mpq3 &p,
const Edge &e,
const IMesh &tm,
const TriMeshTopology &tmtopo,
@ -3254,7 +3254,7 @@ static void do_dissolve(FaceMergeState *fms)
* \note it is possible that some of the triangles in \a tris have reversed orientation
* to the rest, so we have to handle the two cases separately.
*/
static Vector<Face *> merge_tris_for_face(Vector<int> tris,
static Vector<Face *> merge_tris_for_face(const Vector<int> &tris,
const IMesh &tm,
const IMesh &imesh_in,
IMeshArena *arena)

View File

@ -468,7 +468,10 @@ std::string BLI_uniquename_cb(blender::FunctionRef<bool(blender::StringRef)> uni
* \param name_offset: should be calculated using `offsetof(structname, membername)`
* macro from `stddef.h`
*/
static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offset)
static bool uniquename_find_dupe(const ListBase *list,
void *vlink,
const char *name,
int name_offset)
{
for (Link *link = static_cast<Link *>(list->first); link; link = link->next) {
if (link != vlink) {
@ -483,7 +486,7 @@ static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name,
}
struct UniqueNameCheckData {
ListBase *lb;
const ListBase *lb;
void *vlink;
int name_offset;
};
@ -495,7 +498,7 @@ static bool uniquename_unique_check(void *arg, const char *name)
return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offset);
}
void BLI_uniquename(ListBase *list,
void BLI_uniquename(const ListBase *list,
void *vlink,
const char *defname,
char delim,

View File

@ -140,7 +140,7 @@ char *BLI_cpu_brand_string(void)
return brand;
}
#else
// No CPUID on ARM64, so we pull from the registry (on Windows) instead
/* No CPUID on ARM64, so we pull from the registry (on Windows) instead. */
DWORD vendorIdentifierLength = 255;
char vendorIdentifier[255];
if (RegGetValueA(HKEY_LOCAL_MACHINE,

View File

@ -245,6 +245,23 @@ static void version_bonegroups_to_bonecollections(Main *bmain)
}
}
/**
* Change animation/drivers from "collections[..." to "collections_all[..." so
* they remain stable when the bone collection hierarchy structure changes.
*/
static void version_bonecollection_anim(FCurve *fcurve)
{
const blender::StringRef rna_path(fcurve->rna_path);
constexpr char const *rna_path_prefix = "collections[";
if (!rna_path.startswith(rna_path_prefix)) {
return;
}
const std::string path_remainder(rna_path.drop_known_prefix(rna_path_prefix));
MEM_freeN(fcurve->rna_path);
fcurve->rna_path = BLI_sprintfN("collections_all[%s", path_remainder.c_str());
}
static void version_principled_bsdf_update_animdata(ID *owner_id, bNodeTree *ntree)
{
ID *id = &ntree->id;
@ -495,6 +512,27 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain)
version_nla_tweakmode_incomplete(bmain);
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 15)) {
/* Change drivers and animation on "armature.collections" to
* ".collections_all", so that they are drawn correctly in the tree view,
* and keep working when the collection is moved around in the hierarchy. */
LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
AnimData *adt = BKE_animdata_from_id(&arm->id);
if (!adt) {
continue;
}
LISTBASE_FOREACH (FCurve *, fcurve, &adt->drivers) {
version_bonecollection_anim(fcurve);
}
if (adt->action) {
LISTBASE_FOREACH (FCurve *, fcurve, &adt->action->curves) {
version_bonecollection_anim(fcurve);
}
}
}
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.

View File

@ -140,6 +140,16 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_view3d.face_mode_select);
}
if (!USER_VERSION_ATLEAST(402, 13)) {
FROM_DEFAULT_V4_UCHAR(space_text.hilite);
FROM_DEFAULT_V4_UCHAR(space_console.console_cursor);
}
if (!USER_VERSION_ATLEAST(402, 14)) {
BLI_uniquename(
&userdef->themes, btheme, "Theme", '.', offsetof(bTheme, name), sizeof(btheme->name));
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a USER_VERSION_ATLEAST check.

View File

@ -691,13 +691,13 @@ static void SMAABlendingWeightCalculationVS(float2 texcoord,
{
pixcoord = texcoord * float2(size);
// We will use these offsets for the searches later on (see @PSEUDO_GATHER4):
/* We will use these offsets for the searches later on (see @PSEUDO_GATHER4): */
offset[0] = float4(texcoord.xy(), texcoord.xy()) +
float4(-0.25f, -0.125f, 1.25f, -0.125f) / float4(size, size);
offset[1] = float4(texcoord.xy(), texcoord.xy()) +
float4(-0.125f, -0.25f, -0.125f, 1.25f) / float4(size, size);
// And these for the searches, they indicate the ends of the loops:
/* And these for the searches, they indicate the ends of the loops: */
offset[2] = float4(offset[0].x, offset[0].z, offset[1].y, offset[1].w) +
(float4(-2.0f, 2.0f, -2.0f, 2.0f) * float(SMAA_MAX_SEARCH_STEPS)) /
float4(float2(size.x), float2(size.y));
@ -710,7 +710,7 @@ static void SMAANeighborhoodBlendingVS(float2 texcoord, int2 size, float4 &offse
{
offset = float4(texcoord, texcoord) + float4(1.0f, 0.0f, 0.0f, 1.0f) / float4(size, size);
}
#endif // SMAA_INCLUDE_VS
#endif /* SMAA_INCLUDE_VS */
/**
* Luma Edge Detection
@ -732,11 +732,11 @@ static float2 SMAALumaEdgeDetectionPS(float2 texcoord,
float2 threshold = SMAACalculatePredicatedThreshold(
texcoord, offset, SMAATexturePass2D(predicationTex));
#else
// Calculate the threshold:
/* Calculate the threshold: */
float2 threshold = float2(edge_threshold, edge_threshold);
#endif
// Calculate lumas:
/* Calculate lumas: */
// float4 weights = float4(0.2126, 0.7152, 0.0722, 0.0);
float4 weights = float4(luminance_coefficients, 0.0f);
float L = math::dot(SMAASamplePoint(colorTex, texcoord), weights);
@ -744,40 +744,40 @@ static float2 SMAALumaEdgeDetectionPS(float2 texcoord,
float Lleft = math::dot(SMAASamplePoint(colorTex, offset[0].xy()), weights);
float Ltop = math::dot(SMAASamplePoint(colorTex, offset[0].zw()), weights);
// We do the usual threshold:
/* We do the usual threshold: */
float4 delta;
float2 delta_left_top = math::abs(L - float2(Lleft, Ltop));
delta.x = delta_left_top.x;
delta.y = delta_left_top.y;
float2 edges = math::step(threshold, delta.xy());
// Then return early if there is no edge:
/* Then return early if there is no edge: */
if (math::dot(edges, float2(1.0f, 1.0f)) == 0.0f) {
return float2(0.0f);
}
// Calculate right and bottom deltas:
/* Calculate right and bottom deltas: */
float Lright = math::dot(SMAASamplePoint(colorTex, offset[1].xy()), weights);
float Lbottom = math::dot(SMAASamplePoint(colorTex, offset[1].zw()), weights);
float2 delta_right_bottom = math::abs(L - float2(Lright, Lbottom));
delta.z = delta_right_bottom.x;
delta.w = delta_right_bottom.y;
// Calculate the maximum delta in the direct neighborhood:
/* Calculate the maximum delta in the direct neighborhood: */
float2 maxDelta = math::max(delta.xy(), delta.zw());
// Calculate left-left and top-top deltas:
/* Calculate left-left and top-top deltas: */
float Lleftleft = math::dot(SMAASamplePoint(colorTex, offset[2].xy()), weights);
float Ltoptop = math::dot(SMAASamplePoint(colorTex, offset[2].zw()), weights);
float2 delta_left_left_top_top = math::abs(float2(Lleft, Ltop) - float2(Lleftleft, Ltoptop));
delta.z = delta_left_left_top_top.x;
delta.w = delta_left_left_top_top.y;
// Calculate the final maximum delta:
/* Calculate the final maximum delta: */
maxDelta = math::max(maxDelta.xy(), delta.zw());
float finalDelta = math::max(maxDelta.x, maxDelta.y);
// Local contrast adaptation:
/* Local contrast adaptation: */
edges *= math::step(finalDelta, local_contrast_adaptation_factor * delta.xy());
return edges;
@ -793,19 +793,20 @@ static float2 SMAALumaEdgeDetectionPS(float2 texcoord,
*/
static float2 SMAADecodeDiagBilinearAccess(float2 e)
{
// Bilinear access for fetching 'e' have a 0.25 offset, and we are
// interested in the R and G edges:
//
// +---G---+-------+
// | x o R x |
// +-------+-------+
//
// Then, if one of these edge is enabled:
// Red: (0.75 * X + 0.25 * 1) => 0.25 or 1.0
// Green: (0.75 * 1 + 0.25 * X) => 0.75 or 1.0
//
// This function will unpack the values (mad + mul + round):
// wolframalpha.com: round(x * abs(5 * x - 5 * 0.75)) plot 0 to 1
/* Bilinear access for fetching 'e' have a 0.25 offset, and we are
* interested in the R and G edges:
*
* +---G---+-------+
* | x o R x |
* +-------+-------+
*
* Then, if one of these edge is enabled:
* Red: `(0.75 * X + 0.25 * 1) => 0.25 or 1.0`
* Green: `(0.75 * 1 + 0.25 * X) => 0.75 or 1.0`
*
* This function will unpack the values `(mad + mul + round)`:
* wolframalpha.com: `round(x * abs(5 * x - 5 * 0.75))` plot 0 to 1
*/
e.x = e.x * math::abs(5.0f * e.x - 5.0f * 0.75f);
return math::round(e);
}
@ -840,7 +841,7 @@ static float2 SMAASearchDiag2(
SMAATexture2D(edgesTex), float2 texcoord, float2 dir, int2 size, float2 &e)
{
float4 coord = float4(texcoord, -1.0f, 1.0f);
coord.x += 0.25f / size.x; // See @SearchDiag2Optimization
coord.x += 0.25f / size.x; /* See @SearchDiag2Optimization */
float3 t = float3(1.0f / float2(size), 1.0f);
while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) && coord.w > 0.9f) {
float3 increment = mad(t, float3(dir, 1.0f), coord.xyz());
@ -848,12 +849,12 @@ static float2 SMAASearchDiag2(
coord.y = increment.y;
coord.z = increment.z;
// @SearchDiag2Optimization
// Fetch both edges at once using bilinear filtering:
/* @SearchDiag2Optimization */
/* Fetch both edges at once using bilinear filtering: */
e = SMAASampleLevelZero(edgesTex, coord.xy()).xy();
e = SMAADecodeDiagBilinearAccess(e);
// Non-optimized version:
/* Non-optimized version: */
// e.g = SMAASampleLevelZero(edgesTex, coord.xy).g;
// e.r = SMAASampleLevelZeroOffset(edgesTex, coord.xy, int2(1, 0), size).r;
@ -871,16 +872,16 @@ static float2 SMAAAreaDiag(SMAATexture2D(areaTex), float2 dist, float2 e, float
float2 texcoord = mad(
float2(SMAA_AREATEX_MAX_DISTANCE_DIAG, SMAA_AREATEX_MAX_DISTANCE_DIAG), e, dist);
// We do a scale and bias for mapping to texel space:
/* We do a scale and bias for mapping to texel space: */
texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5f * SMAA_AREATEX_PIXEL_SIZE);
// Diagonal areas are on the second half of the texture:
/* Diagonal areas are on the second half of the texture: */
texcoord.x += 0.5f;
// Move to proper place, according to the subpixel offset:
/* Move to proper place, according to the subpixel offset: */
texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;
// Do it!
/* Do it! */
return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord));
}
@ -896,7 +897,7 @@ static float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex),
{
float2 weights = float2(0.0f, 0.0f);
// Search for the line ends:
/* Search for the line ends: */
float4 d;
float2 end;
if (e.x > 0.0f) {
@ -916,8 +917,8 @@ static float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex),
d.w = positive_diagonal.y;
SMAA_BRANCH
if (d.x + d.y > 2.0f) { // d.x + d.y + 1 > 3
// Fetch the crossing edges:
if (d.x + d.y > 2.0f) { /* `d.x + d.y + 1 > 3`. */
/* Fetch the crossing edges: */
float4 coords = float4(texcoord, texcoord) +
float4(-d.x + 0.25f, d.x, d.y, -d.y - 0.25f) / float4(size, size);
float4 c;
@ -933,7 +934,7 @@ static float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex),
c.w = decoded_access.z;
c.z = decoded_access.w;
// Non-optimized version:
/* Non-optimized version: */
// float4 coords = mad(float4(-d.x, d.x, d.y, -d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
// float4 c;
// c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0), size).g;
@ -941,17 +942,17 @@ static float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex),
// c.z = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0), size).g;
// c.w = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, -1), size).r;
// Merge crossing edges at each side into a single value:
/* Merge crossing edges at each side into a single value: */
float2 cc = mad(float2(2.0f, 2.0f), float2(c.x, c.z), float2(c.y, c.w));
// Remove the crossing edge if we didn't found the end of the line:
/* Remove the crossing edge if we didn't found the end of the line: */
SMAAMovc(math::step(0.9f, d.zw()), cc, float2(0.0f, 0.0f));
// Fetch the areas for this line:
/* Fetch the areas for this line: */
weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy(), cc, subsampleIndices.z);
}
// Search for the line ends:
/* Search for the line ends: */
float2 negative_diagonal = SMAASearchDiag2(
SMAATexturePass2D(edgesTex), texcoord, float2(-1.0f, -1.0f), size, end);
d.x = negative_diagonal.x;
@ -969,8 +970,8 @@ static float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex),
}
SMAA_BRANCH
if (d.x + d.y > 2.0f) { // d.x + d.y + 1 > 3
// Fetch the crossing edges:
if (d.x + d.y > 2.0f) { /* `d.x + d.y + 1 > 3` */
/* Fetch the crossing edges: */
float4 coords = float4(texcoord, texcoord) + float4(-d.x, -d.x, d.y, d.y) / float4(size, size);
float4 c;
c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy(), int2(-1, 0), size).y;
@ -980,10 +981,10 @@ static float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex),
c.w = left_edge.x;
float2 cc = mad(float2(2.0f, 2.0f), float2(c.x, c.z), float2(c.y, c.w));
// Remove the crossing edge if we didn't found the end of the line:
/* Remove the crossing edge if we didn't found the end of the line: */
SMAAMovc(math::step(0.9f, d.zw()), cc, float2(0.0f, 0.0f));
// Fetch the areas for this line:
/* Fetch the areas for this line: */
float2 area = SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy(), cc, subsampleIndices.w).xy();
weights.x += area.y;
weights.y += area.x;
@ -1004,21 +1005,21 @@ static float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex),
*/
static float SMAASearchLength(SMAATexture2D(searchTex), float2 e, float offset)
{
// The texture is flipped vertically, with left and right cases taking half
// of the space horizontally:
/* The texture is flipped vertically, with left and right cases taking half
* of the space horizontally: */
float2 scale = SMAA_SEARCHTEX_SIZE * float2(0.5f, -1.0f);
float2 bias = SMAA_SEARCHTEX_SIZE * float2(offset, 1.0f);
// Scale and bias to access texel centers:
/* Scale and bias to access texel centers: */
scale += float2(-1.0f, 1.0f);
bias += float2(0.5f, -0.5f);
// Convert from pixel coordinates to texcoords:
// (We use SMAA_SEARCHTEX_PACKED_SIZE because the texture is cropped)
/* Convert from pixel coordinates to texcoords:
* (We use SMAA_SEARCHTEX_PACKED_SIZE because the texture is cropped). */
scale *= 1.0f / SMAA_SEARCHTEX_PACKED_SIZE;
bias *= 1.0f / SMAA_SEARCHTEX_PACKED_SIZE;
// Lookup the search texture:
/* Lookup the search texture: */
return SMAA_SEARCHTEX_SELECT(SMAASampleLevelZero(searchTex, mad(scale, e, bias)));
}
@ -1036,8 +1037,8 @@ static float SMAASearchXLeft(
* which edges are active from the four fetched ones.
*/
float2 e = float2(0.0f, 1.0f);
while (texcoord.x > end && e.y > 0.8281f && // Is there some edge not activated?
e.x == 0.0f) // Or is there a crossing edge that breaks the line?
while (texcoord.x > end && e.y > 0.8281f && /* Is there some edge not activated? */
e.x == 0.0f) /* Or is there a crossing edge that breaks the line? */
{
e = SMAASampleLevelZero(edgesTex, texcoord).xy();
texcoord = texcoord - float2(2.0f, 0.0f) / float2(size);
@ -1047,26 +1048,26 @@ static float SMAASearchXLeft(
-(255.0f / 127.0f), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0f), 3.25f);
return texcoord.x + offset / size.x;
// Non-optimized version:
// We correct the previous (-0.25, -0.125) offset we applied:
/* Non-optimized version:
* We correct the previous (-0.25, -0.125) offset we applied: */
// texcoord.x += 0.25 * SMAA_RT_METRICS.x;
// The searches are bias by 1, so adjust the coords accordingly:
/* The searches are bias by 1, so adjust the coords accordingly: */
// texcoord.x += SMAA_RT_METRICS.x;
// Disambiguate the length added by the last step:
// texcoord.x += 2.0 * SMAA_RT_METRICS.x; // Undo last step
/* Disambiguate the length added by the last step: */
// texcoord.x += 2.0 * SMAA_RT_METRICS.x; /* Undo last step. */
// texcoord.x -= SMAA_RT_METRICS.x * (255.0 / 127.0) *
// SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0); return mad(SMAA_RT_METRICS.x, offset,
// texcoord.x);
// SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0);
// return mad(SMAA_RT_METRICS.x, offset, texcoord.x);
}
static float SMAASearchXRight(
SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end, int2 size)
{
float2 e = float2(0.0f, 1.0f);
while (texcoord.x < end && e.y > 0.8281f && // Is there some edge not activated?
e.x == 0.0f) // Or is there a crossing edge that breaks the line?
while (texcoord.x < end && e.y > 0.8281f && /* Is there some edge not activated? */
e.x == 0.0f) /* Or is there a crossing edge that breaks the line? */
{
e = SMAASampleLevelZero(edgesTex, texcoord).xy();
texcoord = texcoord + float2(2.0f, 0.0f) / float2(size);
@ -1080,8 +1081,8 @@ static float SMAASearchYUp(
SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end, int2 size)
{
float2 e = float2(1.0f, 0.0f);
while (texcoord.y > end && e.x > 0.8281f && // Is there some edge not activated?
e.y == 0.0f) // Or is there a crossing edge that breaks the line?
while (texcoord.y > end && e.x > 0.8281f && /* Is there some edge not activated? */
e.y == 0.0f) /* Or is there a crossing edge that breaks the line? */
{
e = SMAASampleLevelZero(edgesTex, texcoord).xy();
texcoord = texcoord - float2(0.0f, 2.0f) / float2(size);
@ -1097,8 +1098,8 @@ static float SMAASearchYDown(
SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end, int2 size)
{
float2 e = float2(1.0f, 0.0f);
while (texcoord.y < end && e.x > 0.8281f && // Is there some edge not activated?
e.y == 0.0f) // Or is there a crossing edge that breaks the line?
while (texcoord.y < end && e.x > 0.8281f && /* Is there some edge not activated? */
e.y == 0.0f) /* Or is there a crossing edge that breaks the line? */
{
e = SMAASampleLevelZero(edgesTex, texcoord).xy();
texcoord = texcoord + float2(0.0f, 2.0f) / float2(size);
@ -1116,18 +1117,18 @@ static float SMAASearchYDown(
*/
static float2 SMAAArea(SMAATexture2D(areaTex), float2 dist, float e1, float e2, float offset)
{
// Rounding prevents precision errors of bilinear filtering:
/* Rounding prevents precision errors of bilinear filtering: */
float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE, SMAA_AREATEX_MAX_DISTANCE),
math::round(4.0f * float2(e1, e2)),
dist);
// We do a scale and bias for mapping to texel space:
/* We do a scale and bias for mapping to texel space: */
texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5f * SMAA_AREATEX_PIXEL_SIZE);
// Move to proper place, according to the subpixel offset:
/* Move to proper place, according to the subpixel offset: */
texcoord.y = mad(SMAA_AREATEX_SUBTEX_SIZE, offset, texcoord.y);
// Do it!
/* Do it! */
return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord));
}
@ -1145,7 +1146,7 @@ static void SMAADetectHorizontalCornerPattern(SMAATexture2D(edgesTex),
float2 leftRight = math::step(d, float2(d.y, d.x));
float2 rounding = (1.0f - corner_rounding / 100.0f) * leftRight;
rounding /= leftRight.x + leftRight.y; // Reduce blending for pixels in the center of a line.
rounding /= leftRight.x + leftRight.y; /* Reduce blending for pixels in the center of a line. */
float2 factor = float2(1.0f, 1.0f);
factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy(), int2(0, 1), size).x;
@ -1192,16 +1193,17 @@ static float4 SMAABlendingWeightCalculationPS(float2 texcoord,
float4 subsampleIndices,
int2 size,
int corner_rounding)
{ // Just pass zero for SMAA 1x, see @SUBSAMPLE_INDICES.
{
/* Just pass zero for SMAA 1x, see @SUBSAMPLE_INDICES. */
float4 weights = float4(0.0f, 0.0f, 0.0f, 0.0f);
float2 e = SMAASamplePoint(edgesTex, texcoord).xy();
SMAA_BRANCH
if (e.y > 0.0f) { // Edge at north
if (e.y > 0.0f) { /* Edge at north. */
#if !defined(SMAA_DISABLE_DIAG_DETECTION)
// Diagonals have both north and west edges, so searching for them in
// one of the boundaries is enough.
/* Diagonals have both north and west edges, so searching for them in
* one of the boundaries is enough. */
float2 diagonal_weights = SMAACalculateDiagWeights(SMAATexturePass2D(edgesTex),
SMAATexturePass2D(areaTex),
texcoord,
@ -1212,15 +1214,15 @@ static float4 SMAABlendingWeightCalculationPS(float2 texcoord,
weights.x = diagonal_weights.x;
weights.y = diagonal_weights.y;
// We give priority to diagonals, so if we find a diagonal we skip
// horizontal/vertical processing.
/* We give priority to diagonals, so if we find a diagonal we skip
* horizontal/vertical processing. */
SMAA_BRANCH
if (weights.x == -weights.y) { // weights.x + weights.y == 0.0
if (weights.x == -weights.y) { /* `weights.x + weights.y == 0.0` */
#endif
float2 d;
// Find the distance to the left:
/* Find the distance to the left: */
float3 coords;
coords.x = SMAASearchXLeft(SMAATexturePass2D(edgesTex),
SMAATexturePass2D(searchTex),
@ -1231,12 +1233,12 @@ static float4 SMAABlendingWeightCalculationPS(float2 texcoord,
offset[1].y; // offset[1].y = texcoord.y - 0.25 * SMAA_RT_METRICS.y (@CROSSING_OFFSET)
d.x = coords.x;
// Now fetch the left crossing edges, two at a time using bilinear
// filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to
// discern what value each edge has:
/* Now fetch the left crossing edges, two at a time using bilinear
* filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to
* discern what value each edge has: */
float e1 = SMAASampleLevelZero(edgesTex, coords.xy()).x;
// Find the distance to the right:
/* Find the distance to the right: */
coords.z = SMAASearchXRight(SMAATexturePass2D(edgesTex),
SMAATexturePass2D(searchTex),
offset[0].zw(),
@ -1244,25 +1246,23 @@ static float4 SMAABlendingWeightCalculationPS(float2 texcoord,
size);
d.y = coords.z;
// We want the distances to be in pixel units (doing this here allows
// better interleaving of arithmetic and memory accesses):
/* We want the distances to be in pixel units (doing this here allows
* better interleaving of arithmetic and memory accesses): */
d = math::abs(math::round(mad(float2(size.x), d, -float2(pixcoord.x))));
// SMAAArea below needs a sqrt, as the areas texture is compressed
// quadratically:
/* SMAAArea below needs a sqrt, as the areas texture is compressed quadratically: */
float2 sqrt_d = math::sqrt(d);
// Fetch the right crossing edges:
/* Fetch the right crossing edges: */
float e2 =
SMAASampleLevelZeroOffset(edgesTex, float2(coords.z, coords.y), int2(1, 0), size).x;
// Ok, we know how this pattern looks like, now it is time for getting
// the actual area:
/* Ok, we know how this pattern looks like, now it is time for getting the actual area: */
float2 area = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.y);
weights.x = area.x;
weights.y = area.y;
// Fix corners:
/* Fix corners: */
coords.y = texcoord.y;
float2 corner_weight = weights.xy();
@ -1278,15 +1278,15 @@ static float4 SMAABlendingWeightCalculationPS(float2 texcoord,
#if !defined(SMAA_DISABLE_DIAG_DETECTION)
}
else
e.x = 0.0f; // Skip vertical processing.
e.x = 0.0f; /* Skip vertical processing. */
#endif
}
SMAA_BRANCH
if (e.x > 0.0f) { // Edge at west
if (e.x > 0.0f) { /* Edge at west. */
float2 d;
// Find the distance to the top:
/* Find the distance to the top: */
float3 coords;
coords.y = SMAASearchYUp(SMAATexturePass2D(edgesTex),
SMAATexturePass2D(searchTex),
@ -1296,10 +1296,10 @@ static float4 SMAABlendingWeightCalculationPS(float2 texcoord,
coords.x = offset[0].x; // offset[1].x = texcoord.x - 0.25 * SMAA_RT_METRICS.x;
d.x = coords.y;
// Fetch the top crossing edges:
/* Fetch the top crossing edges: */
float e1 = SMAASampleLevelZero(edgesTex, coords.xy()).y;
// Find the distance to the bottom:
/* Find the distance to the bottom: */
coords.z = SMAASearchYDown(SMAATexturePass2D(edgesTex),
SMAATexturePass2D(searchTex),
offset[1].zw(),
@ -1307,22 +1307,21 @@ static float4 SMAABlendingWeightCalculationPS(float2 texcoord,
size);
d.y = coords.z;
// We want the distances to be in pixel units:
/* We want the distances to be in pixel units: */
d = math::abs(math::round(mad(float2(size.y), d, -float2(pixcoord.y))));
// SMAAArea below needs a sqrt, as the areas texture is compressed
// quadratically:
/* SMAAArea below needs a sqrt, as the areas texture is compressed quadratically: */
float2 sqrt_d = math::sqrt(d);
// Fetch the bottom crossing edges:
/* Fetch the bottom crossing edges: */
float e2 = SMAASampleLevelZeroOffset(edgesTex, float2(coords.x, coords.z), int2(0, 1), size).y;
// Get the area for this direction:
/* Get the area for this direction: */
float2 area = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.x);
weights.z = area.x;
weights.w = area.y;
// Fix corners:
/* Fix corners: */
coords.x = texcoord.x;
float2 corner_weight = weights.zw();
@ -1351,14 +1350,14 @@ static float4 SMAANeighborhoodBlendingPS(float2 texcoord,
#endif
int2 size)
{
// Fetch the blending weights for current pixel:
/* Fetch the blending weights for current pixel: */
float4 a;
a.x = SMAASample(blendTex, offset.xy()).w; // Right
a.y = SMAASample(blendTex, offset.zw()).y; // Top
a.z = SMAASample(blendTex, texcoord).z; // Left
a.w = SMAASample(blendTex, texcoord).x; // Bottom
// Is there any blending weight with a value greater than 0.0?
/* Is there any blending weight with a value greater than 0.0? */
SMAA_BRANCH
if (math::dot(a, float4(1.0f, 1.0f, 1.0f, 1.0f)) < 1e-5f) {
float4 color = SMAASampleLevelZero(colorTex, texcoord);
@ -1366,38 +1365,37 @@ static float4 SMAANeighborhoodBlendingPS(float2 texcoord,
#if SMAA_REPROJECTION
float2 velocity = SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, texcoord));
// Pack velocity into the alpha channel:
/* Pack velocity into the alpha channel: */
color.a = math::sqrt(5.0f * math::length(velocity));
#endif
return color;
}
else {
bool h = math::max(a.x, a.z) > math::max(a.y, a.w); // max(horizontal) > max(vertical)
bool h = math::max(a.x, a.z) > math::max(a.y, a.w); /* `max(horizontal) > max(vertical)`. */
// Calculate the blending offsets:
/* Calculate the blending offsets: */
float4 blendingOffset = float4(0.0f, a.y, 0.0f, a.w);
float2 blendingWeight = float2(a.y, a.w);
SMAAMovc(float4(h), blendingOffset, float4(a.x, 0.0f, a.z, 0.0f));
SMAAMovc(float2(h), blendingWeight, float2(a.x, a.z));
blendingWeight /= math::dot(blendingWeight, float2(1.0f, 1.0f));
// Calculate the texture coordinates:
/* Calculate the texture coordinates: */
float4 blendingCoord = float4(texcoord, texcoord) + blendingOffset / float4(size, -size);
// We exploit bilinear filtering to mix current pixel with the chosen
// neighbor:
/* We exploit bilinear filtering to mix current pixel with the chosen neighbor: */
float4 color = blendingWeight.x * SMAASampleLevelZero(colorTex, blendingCoord.xy());
color += blendingWeight.y * SMAASampleLevelZero(colorTex, blendingCoord.zw());
#if SMAA_REPROJECTION
// Antialias velocity for proper reprojection in a later stage:
/* Antialias velocity for proper reprojection in a later stage: */
float2 velocity = blendingWeight.x *
SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.xy()));
velocity += blendingWeight.y *
SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.zw()));
// Pack velocity into the alpha channel:
/* Pack velocity into the alpha channel: */
color.a = math::sqrt(5.0f * math::length(velocity));
#endif

View File

@ -968,7 +968,13 @@ void DepsgraphNodeBuilder::build_object_modifiers(Object *object)
BuilderWalkUserData data;
data.builder = this;
/* Temporarily set the collection visibility to false, relying on the visibility flushing code
* to flush the visibility from a modifier into collections it depends on. */
const bool is_current_parent_collection_visible = is_parent_collection_visible_;
is_parent_collection_visible_ = false;
BKE_modifiers_foreach_ID_link(object, modifier_walk, &data);
is_parent_collection_visible_ = is_current_parent_collection_visible;
}
void DepsgraphNodeBuilder::build_object_data(Object *object)

View File

@ -458,6 +458,9 @@ void Film::sync()
accumulate_ps_.specialize_constant(sh, "samples_len", &data_.samples_len);
accumulate_ps_.specialize_constant(sh, "use_reprojection", &use_reprojection_);
accumulate_ps_.specialize_constant(sh, "scaling_factor", data_.scaling_factor);
accumulate_ps_.specialize_constant(sh, "combined_id", &data_.combined_id);
accumulate_ps_.specialize_constant(sh, "display_id", &data_.display_id);
accumulate_ps_.specialize_constant(sh, "normal_id", &data_.normal_id);
accumulate_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
accumulate_ps_.shader_set(sh);
accumulate_ps_.bind_resources(inst_.uniform_data);

View File

@ -278,8 +278,8 @@ class DeferredLayer : DeferredLayerBase {
void render(View &main_view,
View &render_view,
Framebuffer &prepass_fb,
Framebuffer &gbuffer_fb,
Framebuffer &combined_fb,
Framebuffer &gbuffer_fb,
int2 extent,
RayTraceBuffer &rt_buffer,
bool is_first_pass);

View File

@ -53,6 +53,7 @@ void VolumeModule::init()
data_.shadow_steps = (shadow_enabled) ? scene_eval->eevee.volumetric_shadow_samples : 0;
data_.light_clamp = scene_eval->eevee.volumetric_light_clamp;
data_.light_clamp = (data_.light_clamp > 0.0) ? data_.light_clamp : 1e20;
use_reprojection_ = (scene_eval->eevee.flag & SCE_EEVEE_TAA_REPROJECTION) != 0;
}

View File

@ -2,6 +2,9 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
/* -------------------------------------------------------------------- */
/** \name YCoCg
* \{ */
@ -55,15 +58,11 @@ vec3 colorspace_safe_color(vec3 c)
/**
* Clamp all components to the specified maximum and avoid color shifting.
*/
vec3 colorspace_brightness_clamp_max(vec3 color, float max_value)
vec3 colorspace_brightness_clamp_max(vec3 color, float limit)
{
float luma = max(1e-8, max(max(color.r, color.g), color.b));
if (luma < 1e-8) {
return color;
}
return color * (1.0 - max(0.0, luma - max_value) / luma);
return color * saturate(limit / max(1e-8, reduce_max(abs(color))));
}
vec4 colorspace_brightness_clamp_max(vec4 color, float max_value)
vec4 colorspace_brightness_clamp_max(vec4 color, float limit)
{
return vec4(colorspace_brightness_clamp_max(color.rgb, max_value), color.a);
return vec4(colorspace_brightness_clamp_max(color.rgb, limit), color.a);
}

View File

@ -12,20 +12,19 @@ void main()
if (uniform_buf.film.display_only) {
out_depth = imageLoad(depth_img, texel_film).r;
if (uniform_buf.film.display_id == -1) {
if (display_id == -1) {
out_color = texelFetch(in_combined_tx, texel_film, 0);
}
else if (uniform_buf.film.display_storage_type == PASS_STORAGE_VALUE) {
out_color.rgb =
imageLoad(value_accum_img, ivec3(texel_film, uniform_buf.film.display_id)).rrr;
out_color.rgb = imageLoad(value_accum_img, ivec3(texel_film, display_id)).rrr;
out_color.a = 1.0;
}
else if (uniform_buf.film.display_storage_type == PASS_STORAGE_COLOR) {
out_color = imageLoad(color_accum_img, ivec3(texel_film, uniform_buf.film.display_id));
out_color = imageLoad(color_accum_img, ivec3(texel_film, display_id));
}
else /* PASS_STORAGE_CRYPTOMATTE */ {
out_color = cryptomatte_false_color(
imageLoad(cryptomatte_img, ivec3(texel_film, uniform_buf.film.display_id)).r);
imageLoad(cryptomatte_img, ivec3(texel_film, display_id)).r);
}
}
else {

View File

@ -87,7 +87,7 @@ float film_weight_accumulation(ivec2 texel_film)
/* TODO(fclem): Reference implementation, also needed for panoramic cameras. */
if (scaling_factor > 1) {
float weight = 0.0;
for (int i = 0; i < uniform_buf.film.samples_len; i++) {
for (int i = 0; i < samples_len; i++) {
weight += film_sample_get(i, texel_film).weight;
}
return weight;
@ -132,7 +132,7 @@ void film_sample_accum_mist(FilmSample samp, inout float accum)
void film_sample_accum_combined(FilmSample samp, inout vec4 accum, inout float weight_accum)
{
if (uniform_buf.film.combined_id == -1) {
if (combined_id == -1) {
return;
}
vec4 color = film_texelfetch_as_YCoCg_opacity(combined_tx, samp.texel);
@ -436,7 +436,7 @@ float film_history_blend_factor(float velocity,
void film_store_combined(
FilmSample dst, ivec2 src_texel, vec4 color, float color_weight, inout vec4 display)
{
if (uniform_buf.film.combined_id == -1) {
if (combined_id == -1) {
return;
}
@ -499,7 +499,7 @@ void film_store_combined(
color = vec4(0.0, 0.0, 0.0, 1.0);
}
if (uniform_buf.film.display_id == -1) {
if (display_id == -1) {
display = color;
}
imageStore(out_combined_img, dst.texel, color);
@ -520,7 +520,7 @@ void film_store_color(FilmSample dst, int pass_id, vec4 color, inout vec4 displa
color = vec4(0.0, 0.0, 0.0, 1.0);
}
if (uniform_buf.film.display_id == pass_id) {
if (display_id == pass_id) {
display = color;
}
imageStore(color_accum_img, ivec3(dst.texel, pass_id), color);
@ -541,7 +541,7 @@ void film_store_value(FilmSample dst, int pass_id, float value, inout vec4 displ
value = 0.0;
}
if (uniform_buf.film.display_id == pass_id) {
if (display_id == pass_id) {
display = vec4(value, value, value, 1.0);
}
imageStore(value_accum_img, ivec3(dst.texel, pass_id), vec4(value));
@ -554,7 +554,7 @@ void film_store_data(ivec2 texel_film, int pass_id, vec4 data_sample, inout vec4
return;
}
if (uniform_buf.film.display_id == pass_id) {
if (display_id == pass_id) {
display = data_sample;
}
imageStore(color_accum_img, ivec3(texel_film, pass_id), data_sample);
@ -616,7 +616,7 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth
/* NOTE: We split the accumulations into separate loops to avoid using too much registers and
* maximize occupancy. */
if (uniform_buf.film.combined_id != -1) {
if (combined_id != -1) {
/* NOTE: Do weight accumulation again since we use custom weights. */
float weight_accum = 0.0;
vec4 combined_accum = vec4(0.0);
@ -643,10 +643,10 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth
vector *= vec4(vec2(uniform_buf.film.render_extent), vec2(uniform_buf.film.render_extent));
film_store_depth(texel_film, depth, out_depth);
if (uniform_buf.film.normal_id != -1) {
if (normal_id != -1) {
vec4 normal = texelFetch(
rp_color_tx, ivec3(film_sample.texel, uniform_buf.render_pass.normal_id), 0);
film_store_data(texel_film, uniform_buf.film.normal_id, normal, out_color);
film_store_data(texel_film, normal_id, normal, out_color);
}
if (uniform_buf.film.position_id != -1) {
vec4 position = texelFetch(
@ -658,10 +658,8 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth
}
else {
out_depth = imageLoad(depth_img, texel_film).r;
if (uniform_buf.film.display_id != -1 &&
uniform_buf.film.display_id == uniform_buf.film.normal_id)
{
out_color = imageLoad(color_accum_img, ivec3(texel_film, uniform_buf.film.display_id));
if (display_id != -1 && display_id == normal_id) {
out_color = imageLoad(color_accum_img, ivec3(texel_film, display_id));
}
}
}

View File

@ -185,20 +185,6 @@ vec3 volume_light(LightData light, const bool is_directional, LightVector lv)
float power = 1.0;
if (!is_directional) {
float volume_radius_squared = light_local_data_get(light).radius_squared;
float light_clamp = uniform_buf.volumes.light_clamp;
if (light_clamp != 0.0) {
/* 0.0 light clamp means it's disabled. */
float max_power = reduce_max(light.color) * light.power[LIGHT_VOLUME];
if (max_power > 0.0) {
/* The limit of the power attenuation function when the distance to the light goes to 0 is
* `2 / r^2` where r is the light radius. We need to find the right radius that emits at
* most the volume light upper bound. Inverting the function we get: */
float min_radius_squared = 1.0 / (0.5 * light_clamp / max_power);
/* Square it here to avoid a multiplication inside the shader. */
volume_radius_squared = max(volume_radius_squared, min_radius_squared);
}
}
/**
* Using "Point Light Attenuation Without Singularity" from Cem Yuksel
* http://www.cemyuksel.com/research/pointlightattenuation/pointlightattenuation.pdf

View File

@ -14,6 +14,7 @@
#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_volume_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_volume_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
@ -25,6 +26,7 @@ vec3 volume_scatter_light_eval(
{
LightData light = light_buf[l_idx];
/* TODO(fclem): Own light list for volume without lights that have 0 volume influence. */
if (light.power[LIGHT_VOLUME] == 0.0) {
return vec3(0);
}
@ -41,14 +43,15 @@ vec3 volume_scatter_light_eval(
visibility *= shadow_sample(is_directional, shadow_atlas_tx, shadow_tilemaps_tx, light, P)
.light_visibilty;
}
visibility *= volume_phase_function(-V, lv.L, s_anisotropy);
if (visibility < LIGHT_ATTENUATION_THRESHOLD) {
return vec3(0);
}
vec3 Li = volume_light(light, is_directional, lv) *
vec3 Li = volume_light(light, is_directional, lv) * visibility *
volume_shadow(light, is_directional, P, lv, extinction_tx);
return Li * visibility * volume_phase_function(-V, lv.L, s_anisotropy);
return colorspace_brightness_clamp_max(Li, uniform_buf.volumes.light_clamp);
}
#endif

View File

@ -27,6 +27,9 @@ GPU_SHADER_CREATE_INFO(eevee_film)
.specialization_constant(Type::INT, "samples_len", 0)
.specialization_constant(Type::BOOL, "use_reprojection", false)
.specialization_constant(Type::INT, "scaling_factor", 1)
.specialization_constant(Type::INT, "combined_id", 0)
.specialization_constant(Type::INT, "display_id", -1)
.specialization_constant(Type::INT, "normal_id", -1)
.additional_info("eevee_shared")
.additional_info("eevee_global_ubo")
.additional_info("eevee_velocity_camera")

View File

@ -182,6 +182,7 @@ static void OVERLAY_cache_init(void *vedata)
OVERLAY_edit_lattice_cache_init(data);
break;
case CTX_MODE_PAINT_GREASE_PENCIL:
case CTX_MODE_SCULPT_GREASE_PENCIL:
case CTX_MODE_EDIT_GREASE_PENCIL:
OVERLAY_edit_grease_pencil_cache_init(data);
break;

View File

@ -225,8 +225,9 @@ struct SortedFaceData {
Array<int> tris_num_by_material;
/**
* The first triangle index for each face, sorted into slices by material.
* May be empty if the mesh only has a single material.
*/
Array<int> face_tri_offsets;
std::optional<Array<int>> face_tri_offsets;
};
/**

View File

@ -611,7 +611,6 @@ void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
*/
const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
GPU_use_hq_normals_workaround();
const bool override_single_mat = mesh_render_mat_len_get(object, mesh) <= 1;
/* Create an array containing all the extractors that needs to be executed. */
ExtractorRunDatas extractors;
@ -621,8 +620,7 @@ void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
#define EXTRACT_ADD_REQUESTED(type, name) \
do { \
if (DRW_##type##_requested(mbuflist->type.name)) { \
const MeshExtract *extractor = mesh_extract_override_get( \
&extract_##name, do_hq_normals, override_single_mat); \
const MeshExtract *extractor = mesh_extract_override_get(&extract_##name, do_hq_normals); \
extractors.append(extractor); \
} \
} while (0)

View File

@ -189,9 +189,10 @@ static void accumululate_material_counts_mesh(
const MeshRenderData &mr, threading::EnumerableThreadSpecific<Array<int>> &all_tri_counts)
{
const OffsetIndices faces = mr.faces;
if (mr.material_indices.is_empty()) {
if (mr.use_hide && !mr.hide_poly.is_empty()) {
const Span hide_poly = mr.hide_poly;
const Span<bool> hide_poly = mr.hide_poly;
const Span material_indices = mr.material_indices;
if (material_indices.is_empty()) {
if (!hide_poly.is_empty()) {
all_tri_counts.local().first() = threading::parallel_reduce(
faces.index_range(),
4096,
@ -212,13 +213,12 @@ static void accumululate_material_counts_mesh(
return;
}
const Span material_indices = mr.material_indices;
threading::parallel_for(material_indices.index_range(), 1024, [&](const IndexRange range) {
Array<int> &tri_counts = all_tri_counts.local();
const int last_index = tri_counts.size() - 1;
if (mr.use_hide && !mr.hide_poly.is_empty()) {
if (!hide_poly.is_empty()) {
for (const int i : range) {
if (!mr.hide_poly[i]) {
if (!hide_poly[i]) {
const int mat = std::clamp(material_indices[i], 0, last_index);
tri_counts[mat] += bke::mesh::face_triangles_num(faces[i].size());
}
@ -257,64 +257,109 @@ static Array<int> mesh_render_data_mat_tri_len_build(const MeshRenderData &mr)
return std::move(tris_num_by_material);
}
static void mesh_render_data_faces_sorted_build(MeshRenderData &mr, MeshBufferCache &cache)
static Array<int> calc_face_tri_starts_bmesh(const MeshRenderData &mr,
MutableSpan<int> material_tri_starts)
{
cache.face_sorted.tris_num_by_material = mesh_render_data_mat_tri_len_build(mr);
const Span<int> tris_num_by_material = cache.face_sorted.tris_num_by_material;
BMesh &bm = *mr.bm;
Array<int> face_tri_offsets(bm.totface);
#ifndef NDEBUG
face_tri_offsets.fill(-1);
#endif
/* Apply offset. */
int visible_tris_num = 0;
Array<int, 32> mat_tri_offs(mr.materials_num);
{
for (int i = 0; i < mr.materials_num; i++) {
mat_tri_offs[i] = visible_tris_num;
visible_tris_num += tris_num_by_material[i];
const int mat_last = mr.materials_num - 1;
BMIter iter;
BMFace *face;
int i;
BM_ITER_MESH_INDEX (face, &iter, &bm, BM_FACES_OF_MESH, i) {
if (BM_elem_flag_test(face, BM_ELEM_HIDDEN)) {
continue;
}
const int mat = std::clamp(int(face->mat_nr), 0, mat_last);
face_tri_offsets[i] = material_tri_starts[mat];
material_tri_starts[mat] += face->len - 2;
}
cache.face_sorted.visible_tris_num = visible_tris_num;
cache.face_sorted.face_tri_offsets.reinitialize(mr.faces_num);
MutableSpan<int> face_tri_offsets = cache.face_sorted.face_tri_offsets;
return face_tri_offsets;
}
static bool mesh_is_single_material(const OffsetIndices<int> material_tri_starts)
{
const int used_materials = std::count_if(
material_tri_starts.index_range().begin(),
material_tri_starts.index_range().end(),
[&](const int i) { return material_tri_starts[i].size() > 0; });
return used_materials == 1;
}
static std::optional<Array<int>> calc_face_tri_starts_mesh(const MeshRenderData &mr,
MutableSpan<int> material_tri_starts)
{
const bool single_material = mesh_is_single_material(material_tri_starts.as_span());
if (single_material && mr.hide_poly.is_empty()) {
return std::nullopt;
}
const OffsetIndices faces = mr.faces;
const Span<bool> hide_poly = mr.hide_poly;
Array<int> face_tri_offsets(faces.size());
#ifndef NDEBUG
face_tri_offsets.fill(-1);
#endif
if (single_material) {
int offset = 0;
for (const int face : faces.index_range()) {
if (hide_poly[face]) {
continue;
}
face_tri_offsets[face] = offset;
offset += bke::mesh::face_triangles_num(faces[face].size());
}
return face_tri_offsets;
}
const Span<int> material_indices = mr.material_indices;
const int mat_last = mr.materials_num - 1;
for (const int face : faces.index_range()) {
if (!hide_poly.is_empty() && hide_poly[face]) {
continue;
}
const int mat = std::clamp(material_indices[face], 0, mat_last);
face_tri_offsets[face] = material_tri_starts[mat];
material_tri_starts[mat] += bke::mesh::face_triangles_num(faces[face].size());
}
return face_tri_offsets;
}
static SortedFaceData mesh_render_data_faces_sorted_build(const MeshRenderData &mr)
{
SortedFaceData cache;
cache.tris_num_by_material = mesh_render_data_mat_tri_len_build(mr);
const Span<int> tris_num_by_material = cache.tris_num_by_material;
Array<int, 32> material_tri_starts(mr.materials_num + 1);
material_tri_starts.as_mutable_span().drop_back(1).copy_from(tris_num_by_material);
offset_indices::accumulate_counts_to_offsets(material_tri_starts);
cache.visible_tris_num = material_tri_starts.last();
/* Sort per material. */
int mat_last = mr.materials_num - 1;
if (mr.extract_type == MR_EXTRACT_BMESH) {
BMIter iter;
BMFace *f;
int i;
BM_ITER_MESH_INDEX (f, &iter, mr.bm, BM_FACES_OF_MESH, i) {
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
const int mat = clamp_i(f->mat_nr, 0, mat_last);
face_tri_offsets[i] = mat_tri_offs[mat];
mat_tri_offs[mat] += f->len - 2;
}
else {
face_tri_offsets[i] = -1;
}
}
cache.face_tri_offsets = calc_face_tri_starts_bmesh(mr, material_tri_starts);
}
else {
for (int i = 0; i < mr.faces_num; i++) {
if (!(mr.use_hide && !mr.hide_poly.is_empty() && mr.hide_poly[i])) {
const int mat = mr.material_indices.is_empty() ?
0 :
clamp_i(mr.material_indices[i], 0, mat_last);
face_tri_offsets[i] = mat_tri_offs[mat];
mat_tri_offs[mat] += mr.faces[i].size() - 2;
}
else {
face_tri_offsets[i] = -1;
}
}
cache.face_tri_offsets = calc_face_tri_starts_mesh(mr, material_tri_starts);
}
return cache;
}
static void mesh_render_data_faces_sorted_ensure(MeshRenderData &mr, MeshBufferCache &cache)
{
if (!cache.face_sorted.face_tri_offsets.is_empty()) {
if (cache.face_sorted.visible_tris_num > 0) {
return;
}
mesh_render_data_faces_sorted_build(mr, cache);
cache.face_sorted = mesh_render_data_faces_sorted_build(mr);
}
void mesh_render_data_update_faces_sorted(MeshRenderData &mr,

View File

@ -64,26 +64,13 @@ static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *ex
return extractor;
}
static const MeshExtract *mesh_extract_override_single_material(const MeshExtract *extractor)
{
if (extractor == &extract_tris) {
return &extract_tris_single_mat;
}
return extractor;
}
const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
const bool do_hq_normals,
const bool do_single_mat)
const bool do_hq_normals)
{
if (do_hq_normals) {
extractor = mesh_extract_override_hq_normals(extractor);
}
if (do_single_mat) {
extractor = mesh_extract_override_single_material(extractor);
}
return extractor;
}

View File

@ -320,9 +320,7 @@ struct EditLoopData {
void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist);
eMRIterType mesh_extract_iter_type(const MeshExtract *ext);
const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
bool do_hq_normals,
bool do_single_mat);
const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, bool do_hq_normals);
void mesh_render_data_face_flag(const MeshRenderData &mr,
const BMFace *efa,
BMUVOffsets offsets,
@ -340,7 +338,6 @@ template<typename GPUType>
void extract_vert_normals(const MeshRenderData &mr, MutableSpan<GPUType> normals);
extern const MeshExtract extract_tris;
extern const MeshExtract extract_tris_single_mat;
extern const MeshExtract extract_lines;
extern const MeshExtract extract_lines_with_lines_loose;
extern const MeshExtract extract_lines_loose_only;

View File

@ -16,83 +16,84 @@
namespace blender::draw {
static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_from)
{
GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
GPU_indexbuf_join(elb_to, elb_from);
}
/* ---------------------------------------------------------------------- */
/** \name Extract Triangles Indices (multi material)
* \{ */
static void extract_tris_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void * /*ibo*/,
void *tls_data)
static void extract_tris_mesh(const MeshRenderData &mr, gpu::IndexBuf &ibo)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr.face_sorted->visible_tris_num, mr.corners_num);
}
static void extract_tris_iter_face_bm(const MeshRenderData &mr,
const BMFace *f,
const int f_index,
void *_data)
{
int tri_offset = mr.face_sorted->face_tri_offsets[f_index];
if (tri_offset == -1) {
const Span<int3> corner_tris = mr.corner_tris;
if (!mr.face_sorted->face_tri_offsets) {
/* There are no hidden faces and no reordering is necessary to group triangles with the same
* material. The corner indices from #Mesh::corner_tris() can be copied directly to the GPU. */
BLI_assert(mr.face_sorted->visible_tris_num == corner_tris.size());
GPU_indexbuf_build_in_place_from_memory(&ibo,
GPU_PRIM_TRIS,
corner_tris.cast<uint32_t>().data(),
corner_tris.size(),
0,
mr.corners_num,
false);
return;
}
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
int tri_first_index_real = poly_to_tri_count(f_index, BM_elem_index_get(f->l_first));
const OffsetIndices faces = mr.faces;
const Span<bool> hide_poly = mr.hide_poly;
Span<std::array<BMLoop *, 3>> looptris = mr.edit_bmesh->looptris;
int tri_len = f->len - 2;
for (int offs = 0; offs < tri_len; offs++) {
const std::array<BMLoop *, 3> &elt = looptris[tri_first_index_real + offs];
int tri_index = tri_offset + offs;
GPU_indexbuf_set_tri_verts(elb,
tri_index,
BM_elem_index_get(elt[0]),
BM_elem_index_get(elt[1]),
BM_elem_index_get(elt[2]));
}
GPUIndexBufBuilder builder;
GPU_indexbuf_init(&builder, GPU_PRIM_TRIS, mr.face_sorted->visible_tris_num, mr.corners_num);
MutableSpan<uint3> data = GPU_indexbuf_get_data(&builder).cast<uint3>();
const Span<int> face_tri_offsets = mr.face_sorted->face_tri_offsets->as_span();
threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
for (const int face : range) {
if (!hide_poly.is_empty() && hide_poly[face]) {
continue;
}
const IndexRange mesh_range = bke::mesh::face_triangles_range(faces, face);
const Span<uint3> mesh_tris = corner_tris.slice(mesh_range).cast<uint3>();
MutableSpan<uint3> ibo_tris = data.slice(face_tri_offsets[face], mesh_tris.size());
ibo_tris.copy_from(mesh_tris);
}
});
GPU_indexbuf_build_in_place_ex(&builder, 0, mr.face_sorted->visible_tris_num, false, &ibo);
}
static void extract_tris_iter_face_mesh(const MeshRenderData &mr,
const int face_index,
void *_data)
static void extract_tris_bmesh(const MeshRenderData &mr, gpu::IndexBuf &ibo)
{
int tri_offset = mr.face_sorted->face_tri_offsets[face_index];
if (tri_offset == -1) {
return;
}
GPUIndexBufBuilder builder;
GPU_indexbuf_init(&builder, GPU_PRIM_TRIS, mr.face_sorted->visible_tris_num, mr.corners_num);
MutableSpan<uint3> data = GPU_indexbuf_get_data(&builder).cast<uint3>();
const IndexRange face = mr.faces[face_index];
BMesh &bm = *mr.bm;
const Span<std::array<BMLoop *, 3>> looptris = mr.edit_bmesh->looptris;
const Span<int> face_tri_offsets = *mr.face_sorted->face_tri_offsets;
threading::parallel_for(IndexRange(bm.totface), 1024, [&](const IndexRange range) {
for (const int face_index : range) {
const BMFace &face = *BM_face_at_index(&bm, face_index);
if (BM_elem_flag_test(&face, BM_ELEM_HIDDEN)) {
continue;
}
const int loop_index = BM_elem_index_get(BM_FACE_FIRST_LOOP(&face));
const IndexRange bm_tris(poly_to_tri_count(face_index, loop_index),
bke::mesh::face_triangles_num(face.len));
const IndexRange ibo_tris(face_tri_offsets[face_index], bm_tris.size());
for (const int i : bm_tris.index_range()) {
data[ibo_tris[i]] = uint3(BM_elem_index_get(looptris[bm_tris[i]][0]),
BM_elem_index_get(looptris[bm_tris[i]][1]),
BM_elem_index_get(looptris[bm_tris[i]][2]));
}
}
});
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
int tri_first_index_real = poly_to_tri_count(face_index, face.start());
int tri_len = face.size() - 2;
for (int offs = 0; offs < tri_len; offs++) {
const int3 &tri = mr.corner_tris[tri_first_index_real + offs];
int tri_index = tri_offset + offs;
GPU_indexbuf_set_tri_verts(elb, tri_index, tri[0], tri[1], tri[2]);
}
GPU_indexbuf_build_in_place_ex(&builder, 0, mr.face_sorted->visible_tris_num, false, &ibo);
}
static void extract_tris_finish(const MeshRenderData &mr,
MeshBatchCache &cache,
void *buf,
void *_data)
gpu::IndexBuf &ibo)
{
gpu::IndexBuf *ibo = static_cast<gpu::IndexBuf *>(buf);
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
GPU_indexbuf_build_in_place(elb, ibo);
/* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch
* is created before the surfaces-per-material. */
if (mr.use_final_mesh && cache.tris_per_mat) {
@ -107,12 +108,29 @@ static void extract_tris_finish(const MeshRenderData &mr,
/* Multiply by 3 because these are triangle indices. */
const int start = mat_start * 3;
const int len = mat_tri_len * 3;
GPU_indexbuf_create_subrange_in_place(cache.tris_per_mat[i], ibo, start, len);
GPU_indexbuf_create_subrange_in_place(cache.tris_per_mat[i], &ibo, start, len);
mat_start += mat_tri_len;
}
}
}
static void extract_tris_init(const MeshRenderData &mr,
MeshBatchCache &cache,
void *ibo_v,
void * /*tls_data*/)
{
gpu::IndexBuf &ibo = *static_cast<gpu::IndexBuf *>(ibo_v);
if (mr.extract_type == MR_EXTRACT_MESH) {
extract_tris_mesh(mr, ibo);
}
else {
extract_tris_bmesh(mr, ibo);
}
extract_tris_finish(mr, cache, ibo);
}
static void extract_tris_init_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData & /*mr*/,
MeshBatchCache &cache,
@ -144,101 +162,7 @@ constexpr MeshExtract create_extractor_tris()
MeshExtract extractor = {nullptr};
extractor.init = extract_tris_init;
extractor.init_subdiv = extract_tris_init_subdiv;
extractor.iter_face_bm = extract_tris_iter_face_bm;
extractor.iter_face_mesh = extract_tris_iter_face_mesh;
extractor.task_reduce = extract_tris_mat_task_reduce;
extractor.finish = extract_tris_finish;
extractor.data_type = MR_DATA_CORNER_TRI | MR_DATA_POLYS_SORTED;
extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.tris);
return extractor;
}
/** \} */
/** \name Extract Triangles Indices (single material)
* \{ */
static void extract_tris_single_mat_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void * /*ibo*/,
void *tls_data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr.corner_tris_num, mr.corners_num);
}
static void extract_tris_single_mat_iter_looptri_bm(const MeshRenderData & /*mr*/,
BMLoop **elt,
const int elt_index,
void *_data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
GPU_indexbuf_set_tri_verts(elb,
elt_index,
BM_elem_index_get(elt[0]),
BM_elem_index_get(elt[1]),
BM_elem_index_get(elt[2]));
}
else {
GPU_indexbuf_set_tri_restart(elb, elt_index);
}
}
static void extract_tris_single_mat_iter_corner_tri_mesh(const MeshRenderData &mr,
const int3 &tri,
const int tri_index,
void *_data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
const int face_i = mr.corner_tri_faces[tri_index];
const bool hidden = mr.use_hide && !mr.hide_poly.is_empty() && mr.hide_poly[face_i];
if (hidden) {
GPU_indexbuf_set_tri_restart(elb, tri_index);
}
else {
GPU_indexbuf_set_tri_verts(elb, tri_index, tri[0], tri[1], tri[2]);
}
}
static void extract_tris_single_mat_finish(const MeshRenderData &mr,
MeshBatchCache &cache,
void *buf,
void *_data)
{
gpu::IndexBuf *ibo = static_cast<gpu::IndexBuf *>(buf);
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
GPU_indexbuf_build_in_place(elb, ibo);
/* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch
* is created before the surfaces-per-material. */
if (mr.use_final_mesh && cache.tris_per_mat) {
for (int i = 0; i < mr.materials_num; i++) {
/* These IBOs have not been queried yet but we create them just in case they are needed
* later since they are not tracked by mesh_buffer_cache_create_requested(). */
if (cache.tris_per_mat[i] == nullptr) {
cache.tris_per_mat[i] = GPU_indexbuf_calloc();
}
/* Multiply by 3 because these are triangle indices. */
const int len = mr.corner_tris_num * 3;
GPU_indexbuf_create_subrange_in_place(cache.tris_per_mat[i], ibo, 0, len);
}
}
}
constexpr MeshExtract create_extractor_tris_single_mat()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_tris_single_mat_init;
extractor.init_subdiv = extract_tris_init_subdiv;
extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm;
extractor.iter_corner_tri_mesh = extract_tris_single_mat_iter_corner_tri_mesh;
extractor.task_reduce = extract_tris_mat_task_reduce;
extractor.finish = extract_tris_single_mat_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.tris);
return extractor;
@ -247,6 +171,5 @@ constexpr MeshExtract create_extractor_tris_single_mat()
/** \} */
const MeshExtract extract_tris = create_extractor_tris();
const MeshExtract extract_tris_single_mat = create_extractor_tris_single_mat();
} // namespace blender::draw

View File

@ -352,10 +352,10 @@ void storage_tag_main_data_dirty()
}
}
void storage_id_remap(ID *id_new, ID *id_old)
void storage_id_remap(ID *id_old, ID *id_new)
{
for (AssetList &list : global_storage().values()) {
list.remap_id(id_new, id_old);
list.remap_id(id_old, id_new);
}
}

View File

@ -63,9 +63,11 @@
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "GEO_join_geometries.hh"
#include "GEO_reverse_uv_sampler.hh"
#include "GEO_set_curve_type.hh"
#include "GEO_subdivide_curves.hh"
#include "GEO_transform.hh"
/**
* The code below uses a suffix naming convention to indicate the coordinate space:
@ -1365,6 +1367,8 @@ static int exec(bContext *C, wmOperator * /*op*/)
attributes.remove("cyclic");
}
curves.calculate_bezier_auto_handles();
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
}
@ -1525,6 +1529,169 @@ static void CURVES_OT_subdivide(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** Add new curves primitive to an existing curves object in edit mode. */
static void append_primitive_curve(bContext *C,
Curves &curves_id,
CurvesGeometry new_curves,
wmOperator &op)
{
const int new_points_num = new_curves.points_num();
const int new_curves_num = new_curves.curves_num();
/* Create geometry sets so that generic join code can be used. */
bke::GeometrySet old_geometry = bke::GeometrySet::from_curves(
&curves_id, bke::GeometryOwnershipType::ReadOnly);
bke::GeometrySet new_geometry = bke::GeometrySet::from_curves(
bke::curves_new_nomain(std::move(new_curves)));
/* Transform primitive according to settings. */
float3 location;
float3 rotation;
float3 scale;
object::add_generic_get_opts(C, &op, 'Z', location, rotation, scale, nullptr, nullptr, nullptr);
const float4x4 transform = math::from_loc_rot_scale<float4x4>(
location, math::EulerXYZ(rotation), scale);
geometry::transform_geometry(new_geometry, transform);
bke::GeometrySet joined_geometry = geometry::join_geometries({old_geometry, new_geometry}, {});
Curves *joined_curves_id = joined_geometry.get_curves_for_write();
CurvesGeometry &dst_curves = curves_id.geometry.wrap();
dst_curves = std::move(joined_curves_id->geometry.wrap());
/* Only select the new curves. */
const bke::AttrDomain selection_domain = bke::AttrDomain(curves_id.selection_domain);
const int new_element_num = selection_domain == bke::AttrDomain::Point ? new_points_num :
new_curves_num;
foreach_selection_attribute_writer(
dst_curves, selection_domain, [&](bke::GSpanAttributeWriter &selection) {
fill_selection_false(selection.span.drop_back(new_element_num));
fill_selection_true(selection.span.take_back(new_element_num));
});
dst_curves.tag_topology_changed();
}
namespace add_circle {
static CurvesGeometry generate_circle_primitive(const float radius)
{
CurvesGeometry curves{4, 1};
MutableSpan<int> offsets = curves.offsets_for_write();
offsets[0] = 0;
offsets[1] = 4;
curves.fill_curve_types(CURVE_TYPE_BEZIER);
curves.cyclic_for_write().fill(true);
curves.handle_types_left_for_write().fill(BEZIER_HANDLE_AUTO);
curves.handle_types_right_for_write().fill(BEZIER_HANDLE_AUTO);
curves.resolution_for_write().fill(12);
MutableSpan<float3> positions = curves.positions_for_write();
positions[0] = float3(-radius, 0, 0);
positions[1] = float3(0, radius, 0);
positions[2] = float3(radius, 0, 0);
positions[3] = float3(0, -radius, 0);
/* Ensure these attributes exist. */
curves.handle_positions_left_for_write();
curves.handle_positions_right_for_write();
curves.calculate_bezier_auto_handles();
return curves;
}
static int exec(bContext *C, wmOperator *op)
{
Object *object = CTX_data_edit_object(C);
Curves *active_curves_id = static_cast<Curves *>(object->data);
const float radius = RNA_float_get(op->ptr, "radius");
append_primitive_curve(C, *active_curves_id, generate_circle_primitive(radius), *op);
DEG_id_tag_update(&active_curves_id->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, active_curves_id);
return OPERATOR_FINISHED;
}
} // namespace add_circle
static void CURVES_OT_add_circle(wmOperatorType *ot)
{
ot->name = "Add Circle";
ot->idname = __func__;
ot->description = "Add new circle curve";
ot->exec = add_circle::exec;
ot->poll = editable_curves_in_edit_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
object::add_unit_props_radius(ot);
object::add_generic_props(ot, true);
}
namespace add_bezier {
static CurvesGeometry generate_bezier_primitive(const float radius)
{
CurvesGeometry curves{2, 1};
MutableSpan<int> offsets = curves.offsets_for_write();
offsets[0] = 0;
offsets[1] = 2;
curves.fill_curve_types(CURVE_TYPE_BEZIER);
curves.handle_types_left_for_write().fill(BEZIER_HANDLE_ALIGN);
curves.handle_types_right_for_write().fill(BEZIER_HANDLE_ALIGN);
curves.resolution_for_write().fill(12);
MutableSpan<float3> positions = curves.positions_for_write();
MutableSpan<float3> left_handles = curves.handle_positions_left_for_write();
MutableSpan<float3> right_handles = curves.handle_positions_right_for_write();
left_handles[0] = float3(-1.5f, -0.5, 0) * radius;
positions[0] = float3(-1.0f, 0, 0) * radius;
right_handles[0] = float3(-0.5f, 0.5f, 0) * radius;
left_handles[1] = float3(0, 0, 0) * radius;
positions[1] = float3(1.0f, 0, 0) * radius;
right_handles[1] = float3(2.0f, 0, 0) * radius;
return curves;
}
static int exec(bContext *C, wmOperator *op)
{
Object *object = CTX_data_edit_object(C);
Curves *active_curves_id = static_cast<Curves *>(object->data);
const float radius = RNA_float_get(op->ptr, "radius");
append_primitive_curve(C, *active_curves_id, generate_bezier_primitive(radius), *op);
DEG_id_tag_update(&active_curves_id->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, active_curves_id);
return OPERATOR_FINISHED;
}
} // namespace add_bezier
static void CURVES_OT_add_bezier(wmOperatorType *ot)
{
ot->name = "Add Bezier";
ot->idname = __func__;
ot->description = "Add new bezier curve";
ot->exec = add_bezier::exec;
ot->poll = editable_curves_in_edit_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
object::add_unit_props_radius(ot);
object::add_generic_props(ot, true);
}
namespace set_handle_type {
static int exec(bContext *C, wmOperator *op)
@ -1606,6 +1773,8 @@ void operatortypes_curves()
WM_operatortype_append(CURVES_OT_curve_type_set);
WM_operatortype_append(CURVES_OT_switch_direction);
WM_operatortype_append(CURVES_OT_subdivide);
WM_operatortype_append(CURVES_OT_add_circle);
WM_operatortype_append(CURVES_OT_add_bezier);
WM_operatortype_append(CURVES_OT_handle_type_set);
}

View File

@ -13,6 +13,7 @@
#include <cstdlib>
#include <cstring>
#include "DNA_object_enums.h"
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
@ -25,6 +26,7 @@
#include "BLT_translation.hh"
#include "DNA_gpencil_legacy_types.h"
#include "DNA_grease_pencil_types.h"
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@ -61,6 +63,7 @@
#include "UI_view2d.hh"
#include "ED_gpencil_legacy.hh"
#include "ED_image.hh"
#include "ED_object.hh"
#include "ED_outliner.hh"
#include "ED_screen.hh"
@ -453,10 +456,25 @@ static bool gpencil_sculptmode_toggle_poll(bContext *C)
{
/* if using gpencil object, use this gpd */
Object *ob = CTX_data_active_object(C);
if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) {
if (ob == nullptr) {
return false;
}
if (ELEM(ob->type, OB_GPENCIL_LEGACY, OB_GREASE_PENCIL)) {
return ob->data != nullptr;
}
return ED_gpencil_data_get_active(C) != nullptr;
return false;
}
static bool gpencil_sculpt_poll_view3d(bContext *C)
{
const Object *ob = CTX_data_active_object(C);
if (ob == nullptr || (ob->mode & OB_MODE_SCULPT_GPENCIL_LEGACY) == 0) {
return false;
}
if (CTX_wm_region_view3d(C) == nullptr) {
return false;
}
return true;
}
static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
@ -467,35 +485,49 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
const bool back = RNA_boolean_get(op->ptr, "back");
wmMsgBus *mbus = CTX_wm_message_bus(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
bool is_object = false;
short mode;
/* if using a gpencil object, use this datablock */
Object *ob = CTX_data_active_object(C);
if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) {
gpd = static_cast<bGPdata *>(ob->data);
bGPdata *gpd = ED_gpencil_data_get_active(C);
if (gpd == nullptr) {
return OPERATOR_CANCELLED;
}
/* Just toggle sculptmode flag... */
gpd->flag ^= GP_DATA_STROKE_SCULPTMODE;
/* set mode */
if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) {
mode = OB_MODE_SCULPT_GPENCIL_LEGACY;
}
else {
/* try to back previous mode */
if ((ob->restore_mode) && (back == 1)) {
mode = ob->restore_mode;
}
else {
mode = OB_MODE_OBJECT;
}
}
is_object = true;
}
if ((ob) && (ob->type == OB_GREASE_PENCIL)) {
const bool is_mode_set = (ob->mode & OB_MODE_SCULPT_GPENCIL_LEGACY) != 0;
if (is_mode_set) {
mode = OB_MODE_OBJECT;
}
else {
Scene *scene = CTX_data_scene(C);
BKE_paint_init(
bmain, scene, PaintMode::SculptGreasePencil, PAINT_CURSOR_SCULPT_GREASE_PENCIL);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, PaintMode::SculptGreasePencil);
ED_paint_cursor_start(paint, gpencil_sculpt_poll_view3d);
mode = OB_MODE_SCULPT_GPENCIL_LEGACY;
}
is_object = true;
}
if (gpd == nullptr) {
return OPERATOR_CANCELLED;
}
/* Just toggle sculptmode flag... */
gpd->flag ^= GP_DATA_STROKE_SCULPTMODE;
/* set mode */
if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) {
mode = OB_MODE_SCULPT_GPENCIL_LEGACY;
}
else {
mode = OB_MODE_OBJECT;
}
if (is_object) {
/* try to back previous mode */
if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_SCULPTMODE) == 0) && (back == 1)) {
mode = ob->restore_mode;
}
ob->restore_mode = ob->mode;
ob->mode = mode;
}
@ -511,9 +543,16 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
}
/* setup other modes */
ED_gpencil_setup_modes(C, gpd, mode);
/* set cache as dirty */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
if (ob->type == OB_GPENCIL_LEGACY) {
bGPdata *gpd = ED_gpencil_data_get_active(C);
ED_gpencil_setup_modes(C, gpd, mode);
/* set cache as dirty */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
if (ob->type == OB_GREASE_PENCIL) {
GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
DEG_id_tag_update(&grease_pencil->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);

View File

@ -8,6 +8,7 @@
#include "BKE_context.hh"
#include "DNA_object_enums.h"
#include "DNA_scene_types.h"
#include "ED_grease_pencil.hh"
@ -81,6 +82,22 @@ bool grease_pencil_painting_poll(bContext *C)
return true;
}
bool grease_pencil_sculpting_poll(bContext *C)
{
if (!active_grease_pencil_poll(C)) {
return false;
}
Object *object = CTX_data_active_object(C);
if ((object->mode & OB_MODE_SCULPT_GPENCIL_LEGACY) == 0) {
return false;
}
ToolSettings *ts = CTX_data_tool_settings(C);
if (!ts || !ts->gp_sculptpaint) {
return false;
}
return true;
}
static void keymap_grease_pencil_edit_mode(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_ensure(

View File

@ -175,6 +175,7 @@ bool editable_grease_pencil_poll(bContext *C);
bool active_grease_pencil_layer_poll(bContext *C);
bool editable_grease_pencil_point_selection_poll(bContext *C);
bool grease_pencil_painting_poll(bContext *C);
bool grease_pencil_sculpting_poll(bContext *C);
struct DrawingInfo {
const bke::greasepencil::Drawing &drawing;

View File

@ -1066,18 +1066,21 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
void UI_theme_init_default()
{
/* we search for the theme with name Default */
/* We search for the theme with the default name. */
bTheme *btheme = static_cast<bTheme *>(
BLI_findstring(&U.themes, "Default", offsetof(bTheme, name)));
BLI_findstring(&U.themes, U_theme_default.name, offsetof(bTheme, name)));
if (btheme == nullptr) {
btheme = MEM_cnew<bTheme>(__func__);
BLI_addtail(&U.themes, btheme);
BLI_addhead(&U.themes, btheme);
}
/* Must be first, see `U.themes` doc-string. */
BLI_listbase_rotate_first(&U.themes, btheme);
UI_SetTheme(0, 0); /* make sure the global used in this file is set */
const int active_theme_area = btheme->active_theme_area;
memcpy(btheme, &U_theme_default, sizeof(*btheme));
MEMCPY_STRUCT_AFTER(btheme, &U_theme_default, name);
btheme->active_theme_area = active_theme_area;
}

View File

@ -115,7 +115,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
static void ui_obj_export_settings(const bContext *C, uiLayout *layout, PointerRNA *imfptr)
{
const bool export_animation = RNA_boolean_get(imfptr, "export_animation");
const bool export_smooth_groups = RNA_boolean_get(imfptr, "export_smooth_groups");
@ -129,9 +129,16 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
/* Object Transform options. */
box = uiLayoutBox(layout);
col = uiLayoutColumn(box, false);
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Limit to"));
uiItemR(
sub, imfptr, "export_selected_objects", UI_ITEM_NONE, IFACE_("Selected Only"), ICON_NONE);
if (CTX_wm_space_file(C)) {
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Limit to"));
uiItemR(
sub, imfptr, "export_selected_objects", UI_ITEM_NONE, IFACE_("Selected Only"), ICON_NONE);
}
else {
sub = uiLayoutColumn(col, false);
}
uiItemR(sub, imfptr, "global_scale", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(sub, imfptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
uiItemR(sub, imfptr, "up_axis", UI_ITEM_NONE, IFACE_("Up Axis"), ICON_NONE);
@ -197,9 +204,9 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(sub, imfptr, "end_frame", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
}
static void wm_obj_export_draw(bContext * /*C*/, wmOperator *op)
static void wm_obj_export_draw(bContext *C, wmOperator *op)
{
ui_obj_export_settings(op->layout, op->ptr);
ui_obj_export_settings(C, op->layout, op->ptr);
}
/**

View File

@ -222,7 +222,7 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static void wm_usd_export_draw(bContext * /*C*/, wmOperator *op)
static void wm_usd_export_draw(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
uiLayout *col;
@ -232,9 +232,11 @@ static void wm_usd_export_draw(bContext * /*C*/, wmOperator *op)
uiLayout *box = uiLayoutBox(layout);
col = uiLayoutColumn(box, true);
uiItemR(col, ptr, "selected_objects_only", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(col, ptr, "visible_objects_only", UI_ITEM_NONE, nullptr, ICON_NONE);
if (CTX_wm_space_file(C)) {
col = uiLayoutColumn(box, true);
uiItemR(col, ptr, "selected_objects_only", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(col, ptr, "visible_objects_only", UI_ITEM_NONE, nullptr, ICON_NONE);
}
col = uiLayoutColumn(box, true);
uiItemR(col, ptr, "export_animation", UI_ITEM_NONE, nullptr, ICON_NONE);

View File

@ -9,6 +9,7 @@
* actual mode switching logic is per-object type.
*/
#include "DNA_object_enums.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@ -147,7 +148,9 @@ bool mode_compat_test(const Object *ob, eObjectMode mode)
}
break;
case OB_GREASE_PENCIL:
if (mode & (OB_MODE_EDIT | OB_MODE_PAINT_GREASE_PENCIL | OB_MODE_WEIGHT_PAINT)) {
if (mode & (OB_MODE_EDIT | OB_MODE_PAINT_GREASE_PENCIL | OB_MODE_WEIGHT_PAINT |
OB_MODE_SCULPT_GPENCIL_LEGACY))
{
return true;
}
break;

View File

@ -11,6 +11,7 @@
#include "DNA_brush_types.h"
#include "DNA_grease_pencil_types.h"
#include "DNA_scene_types.h"
#include "ED_grease_pencil.hh"
#include "ED_image.hh"
#include "ED_object.hh"
@ -30,41 +31,9 @@
namespace blender::ed::sculpt_paint {
/* -------------------------------------------------------------------- */
/** \name Brush Stroke Operator
/** \name Common Paint Operator Functions
* \{ */
static bool start_brush_operation(bContext &C,
wmOperator & /*op*/,
PaintStroke *paint_stroke,
const InputSample &start_sample)
{
// const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op.ptr, "mode"));
const Scene &scene = *CTX_data_scene(&C);
const GpPaint &gp_paint = *scene.toolsettings->gp_paint;
const Brush &brush = *BKE_paint_brush_for_read(&gp_paint.paint);
GreasePencilStrokeOperation *operation = nullptr;
switch (brush.gpencil_tool) {
case GPAINT_TOOL_DRAW:
/* FIXME: Somehow store the unique_ptr in the PaintStroke. */
operation = greasepencil::new_paint_operation().release();
break;
case GPAINT_TOOL_ERASE:
operation = greasepencil::new_erase_operation().release();
break;
case GPAINT_TOOL_TINT:
operation = greasepencil::new_tint_operation().release();
break;
}
if (operation) {
paint_stroke_set_mode_data(paint_stroke, operation);
operation->on_stroke_begin(C, start_sample);
return true;
}
return false;
}
static bool stroke_get_location(bContext * /*C*/,
float out[3],
const float mouse[2],
@ -76,19 +45,19 @@ static bool stroke_get_location(bContext * /*C*/,
return true;
}
static bool stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
static void stroke_start(bContext &C,
wmOperator &op,
const float2 &mouse,
GreasePencilStrokeOperation &operation)
{
PaintStroke *paint_stroke = static_cast<PaintStroke *>(op->customdata);
PaintStroke *paint_stroke = static_cast<PaintStroke *>(op.customdata);
InputSample start_sample;
start_sample.mouse_position = float2(mouse);
start_sample.pressure = 0.0f;
if (!start_brush_operation(*C, *op, paint_stroke, start_sample)) {
return false;
}
return true;
paint_stroke_set_mode_data(paint_stroke, &operation);
operation.on_stroke_begin(C, start_sample);
}
static void stroke_update_step(bContext *C,
@ -121,6 +90,12 @@ static void stroke_done(const bContext *C, PaintStroke *stroke)
operation->~GreasePencilStrokeOperation();
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Brush Stroke Operator
* \{ */
static bool grease_pencil_brush_stroke_poll(bContext *C)
{
if (!ed::greasepencil::grease_pencil_painting_poll(C)) {
@ -132,6 +107,37 @@ static bool grease_pencil_brush_stroke_poll(bContext *C)
return true;
}
static GreasePencilStrokeOperation *grease_pencil_brush_stroke_operation(bContext &C)
{
const Scene &scene = *CTX_data_scene(&C);
const GpPaint &gp_paint = *scene.toolsettings->gp_paint;
const Brush &brush = *BKE_paint_brush_for_read(&gp_paint.paint);
switch (eBrushGPaintTool(brush.gpencil_tool)) {
case GPAINT_TOOL_DRAW:
/* FIXME: Somehow store the unique_ptr in the PaintStroke. */
return greasepencil::new_paint_operation().release();
case GPAINT_TOOL_ERASE:
return greasepencil::new_erase_operation().release();
case GPAINT_TOOL_FILL:
return nullptr;
case GPAINT_TOOL_TINT:
return greasepencil::new_tint_operation().release();
}
return nullptr;
}
static bool grease_pencil_brush_stroke_test_start(bContext *C,
wmOperator *op,
const float mouse[2])
{
GreasePencilStrokeOperation *operation = grease_pencil_brush_stroke_operation(*C);
if (operation) {
stroke_start(*C, *op, float2(mouse), *operation);
return true;
}
return false;
}
static int grease_pencil_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const Scene *scene = CTX_data_scene(C);
@ -168,7 +174,7 @@ static int grease_pencil_brush_stroke_invoke(bContext *C, wmOperator *op, const
op->customdata = paint_stroke_new(C,
op,
stroke_get_location,
stroke_test_start,
grease_pencil_brush_stroke_test_start,
stroke_update_step,
stroke_redraw,
stroke_done,
@ -211,6 +217,140 @@ static void GREASE_PENCIL_OT_brush_stroke(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Sculpt Operator
* \{ */
static bool grease_pencil_sculpt_paint_poll(bContext *C)
{
if (!ed::greasepencil::grease_pencil_sculpting_poll(C)) {
return false;
}
if (!WM_toolsystem_active_tool_is_brush(C)) {
return false;
}
return true;
}
static GreasePencilStrokeOperation *grease_pencil_sculpt_paint_operation(bContext &C)
{
const Scene &scene = *CTX_data_scene(&C);
const GpSculptPaint &gp_sculptpaint = *scene.toolsettings->gp_sculptpaint;
const Brush &brush = *BKE_paint_brush_for_read(&gp_sculptpaint.paint);
switch (eBrushGPSculptTool(brush.gpencil_sculpt_tool)) {
case GPSCULPT_TOOL_SMOOTH:
return nullptr;
case GPSCULPT_TOOL_THICKNESS:
return nullptr;
case GPSCULPT_TOOL_STRENGTH:
return nullptr;
case GPSCULPT_TOOL_GRAB:
return nullptr;
case GPSCULPT_TOOL_PUSH:
return nullptr;
case GPSCULPT_TOOL_TWIST:
return nullptr;
case GPSCULPT_TOOL_PINCH:
return nullptr;
case GPSCULPT_TOOL_RANDOMIZE:
return nullptr;
case GPSCULPT_TOOL_CLONE:
return nullptr;
}
return nullptr;
}
static bool grease_pencil_sculpt_paint_test_start(bContext *C,
wmOperator *op,
const float mouse[2])
{
GreasePencilStrokeOperation *operation = grease_pencil_sculpt_paint_operation(*C);
if (operation) {
stroke_start(*C, *op, float2(mouse), *operation);
return true;
}
return false;
}
static int grease_pencil_sculpt_paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const Scene *scene = CTX_data_scene(C);
const Object *object = CTX_data_active_object(C);
if (!object || object->type != OB_GREASE_PENCIL) {
return OPERATOR_CANCELLED;
}
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
if (!grease_pencil.has_active_layer()) {
BKE_report(op->reports, RPT_ERROR, "No active Grease Pencil layer");
return OPERATOR_CANCELLED;
}
const Paint *paint = BKE_paint_get_active_from_context(C);
const Brush *brush = BKE_paint_brush_for_read(paint);
if (brush == nullptr) {
return OPERATOR_CANCELLED;
}
bke::greasepencil::Layer &active_layer = *grease_pencil.get_active_layer();
if (!active_layer.is_editable()) {
BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hidden");
return OPERATOR_CANCELLED;
}
/* Ensure a drawing at the current keyframe. */
if (!ed::greasepencil::ensure_active_keyframe(*scene, grease_pencil)) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
return OPERATOR_CANCELLED;
}
op->customdata = paint_stroke_new(C,
op,
stroke_get_location,
grease_pencil_sculpt_paint_test_start,
stroke_update_step,
stroke_redraw,
stroke_done,
event->type);
const int return_value = op->type->modal(C, op, event);
if (return_value == OPERATOR_FINISHED) {
return OPERATOR_FINISHED;
}
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int grease_pencil_sculpt_paint_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
return paint_stroke_modal(C, op, event, reinterpret_cast<PaintStroke **>(&op->customdata));
}
static void grease_pencil_sculpt_paint_cancel(bContext *C, wmOperator *op)
{
paint_stroke_cancel(C, op, static_cast<PaintStroke *>(op->customdata));
}
static void GREASE_PENCIL_OT_sculpt_paint(wmOperatorType *ot)
{
ot->name = "Grease Pencil Draw";
ot->idname = "GREASE_PENCIL_OT_sculpt_paint";
ot->description = "Draw a new stroke in the active Grease Pencil object";
ot->poll = grease_pencil_sculpt_paint_poll;
ot->invoke = grease_pencil_sculpt_paint_invoke;
ot->modal = grease_pencil_sculpt_paint_modal;
ot->cancel = grease_pencil_sculpt_paint_cancel;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
paint_stroke_operator_properties(ot);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Toggle Draw Mode
* \{ */
@ -306,6 +446,7 @@ void ED_operatortypes_grease_pencil_draw()
{
using namespace blender::ed::sculpt_paint;
WM_operatortype_append(GREASE_PENCIL_OT_brush_stroke);
WM_operatortype_append(GREASE_PENCIL_OT_sculpt_paint);
WM_operatortype_append(GREASE_PENCIL_OT_draw_mode_toggle);
}

View File

@ -793,7 +793,7 @@ struct EraseOperationExecutor {
erased = hard_eraser(src, screen_space_positions, dst, self.keep_caps);
break;
case GP_BRUSH_ERASER_SOFT:
// To be implemented
/* To be implemented. */
return;
}

View File

@ -1220,6 +1220,7 @@ static bool paint_use_2d_cursor(PaintMode mode)
case PaintMode::SculptGPencil:
case PaintMode::WeightGPencil:
case PaintMode::SculptCurves:
case PaintMode::SculptGreasePencil:
case PaintMode::GPencil:
return true;
case PaintMode::Invalid:

View File

@ -689,6 +689,9 @@ static int paintcurve_draw_exec(bContext *C, wmOperator * /*op*/)
case PaintMode::GPencil:
name = "GREASE_PENCIL_OT_brush_stroke";
break;
case PaintMode::SculptGreasePencil:
name = "GREASE_PENCIL_OT_sculpt_paint";
break;
default:
return OPERATOR_PASS_THROUGH;
}

View File

@ -943,6 +943,7 @@ static const PaintMode brush_select_paint_modes[] = {
PaintMode::SculptGPencil,
PaintMode::WeightGPencil,
PaintMode::SculptCurves,
PaintMode::SculptGreasePencil,
};
static int brush_select_exec(bContext *C, wmOperator *op)

View File

@ -1041,7 +1041,7 @@ bool paint_space_stroke_enabled(Brush *br, PaintMode mode)
return false;
}
if (mode == PaintMode::GPencil) {
if (ELEM(mode, PaintMode::GPencil, PaintMode::SculptGreasePencil)) {
/* No spacing needed for now. */
return false;
}

View File

@ -636,7 +636,7 @@ static void nla_draw_strip_text(AnimData *adt,
else {
col[0] = col[1] = col[2] = 255;
}
// Default strip to 100% opacity.
/* Default strip to 100% opacity. */
col[3] = 255;
/* Reduce text opacity if a track is soloed,

View File

@ -1378,8 +1378,8 @@ static void create_inspection_string_for_field_info(const bNodeSocket &socket,
ss << "\n";
for (const int i : input_tooltips.index_range()) {
const blender::StringRef tooltip = input_tooltips[i];
ss << fmt::format(TIP_("\u2022 {}"), TIP_(tooltip.data()));
const blender::StringRefNull tooltip = input_tooltips[i];
ss << fmt::format(TIP_("\u2022 {}"), TIP_(tooltip.c_str()));
if (i < input_tooltips.size() - 1) {
ss << ".\n";
}
@ -1461,15 +1461,16 @@ static void create_inspection_string_for_geometry_info(const geo_log::GeometryIn
break;
}
case bke::GeometryComponent::Type::GreasePencil: {
const geo_log::GeometryInfoLog::GreasePencilInfo &grease_pencil_info =
*value_log.grease_pencil_info;
char line[256];
SNPRINTF(line,
TIP_("\u2022 Grease Pencil: %s layers"),
to_string(grease_pencil_info.layers_num).c_str());
ss << line;
break;
break;
if (U.experimental.use_grease_pencil_version3) {
const geo_log::GeometryInfoLog::GreasePencilInfo &grease_pencil_info =
*value_log.grease_pencil_info;
char line[256];
SNPRINTF(line,
TIP_("\u2022 Grease Pencil: %s layers"),
to_string(grease_pencil_info.layers_num).c_str());
ss << line;
break;
}
}
}
if (type != component_types.last()) {
@ -1536,12 +1537,12 @@ static std::optional<std::string> create_description_inspection_string(const bNo
return std::nullopt;
}
const blender::nodes::SocketDeclaration &socket_decl = *socket.runtime->declaration;
blender::StringRef description = socket_decl.description;
blender::StringRefNull description = socket_decl.description;
if (description.is_empty()) {
return std::nullopt;
}
return TIP_(description.data());
return TIP_(description.c_str());
}
static std::optional<std::string> create_log_inspection_string(geo_log::GeoTreeLog *geo_tree_log,

View File

@ -1403,6 +1403,10 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
ptr = RNA_pointer_create(tselem->id, &RNA_BoneCollection, te->directdata);
context = BCONTEXT_DATA;
break;
case TSE_LAYER_COLLECTION:
ptr = RNA_pointer_create(tselem->id, &RNA_Collection, te->directdata);
context = BCONTEXT_COLLECTION;
break;
}
}

View File

@ -409,6 +409,10 @@ static void view3d_main_region_init(wmWindowManager *wm, ARegion *region)
wm->defaultconf, "Grease Pencil Paint Mode", SPACE_EMPTY, RGN_TYPE_WINDOW);
WM_event_add_keymap_handler(&region->handlers, keymap);
keymap = WM_keymap_ensure(
wm->defaultconf, "Grease Pencil Sculpt Mode", SPACE_EMPTY, RGN_TYPE_WINDOW);
WM_event_add_keymap_handler(&region->handlers, keymap);
/* Edit-font key-map swallows almost all (because of text input). */
keymap = WM_keymap_ensure(wm->defaultconf, "Font", SPACE_EMPTY, RGN_TYPE_WINDOW);
WM_event_add_keymap_handler(&region->handlers, keymap);
@ -1707,6 +1711,9 @@ void ED_view3d_buttons_region_layout_ex(const bContext *C,
case CTX_MODE_PAINT_GREASE_PENCIL:
ARRAY_SET_ITEMS(contexts, ".grease_pencil_paint");
break;
case CTX_MODE_SCULPT_GREASE_PENCIL:
ARRAY_SET_ITEMS(contexts, ".paint_common", ".grease_pencil_sculpt");
break;
case CTX_MODE_EDIT_POINT_CLOUD:
ARRAY_SET_ITEMS(contexts, ".point_cloud_edit");
break;

View File

@ -291,6 +291,7 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup,
}
}
}
UNUSED_VARS(dist_best);
*r_co_index = co_index_best;
return found;

View File

@ -733,53 +733,50 @@ struct BeztMap {
};
/**
* This function converts an FCurve's BezTriple array to a BeztMap array
* NOTE: this allocates memory that will need to get freed later.
* Converts an FCurve's BezTriple array to a BeztMap vector.
*/
static BeztMap *bezt_to_beztmaps(BezTriple *bezts, int totvert)
static blender::Vector<BeztMap> bezt_to_beztmaps(BezTriple *bezts, const int totvert)
{
BezTriple *bezt = bezts;
BezTriple *prevbezt = nullptr;
BeztMap *bezm, *bezms;
int i;
/* Allocate memory for this array. */
if (totvert == 0 || bezts == nullptr) {
return nullptr;
return {};
}
bezm = bezms = static_cast<BeztMap *>(MEM_callocN(sizeof(BeztMap) * totvert, "BeztMaps"));
/* Assign beztriples to beztmaps. */
for (i = 0; i < totvert; i++, bezm++, prevbezt = bezt, bezt++) {
bezm->bezt = bezt;
blender::Vector<BeztMap> bezms = blender::Vector<BeztMap>(totvert);
bezm->oldIndex = i;
BezTriple *prevbezt = nullptr;
for (const int i : bezms.index_range()) {
BezTriple *bezt = &bezts[i];
BeztMap &bezm = bezms[i];
bezm.bezt = bezt;
bezm->prev_ipo = (prevbezt) ? prevbezt->ipo : bezt->ipo;
bezm->current_ipo = bezt->ipo;
bezm.oldIndex = i;
bezm.prev_ipo = (prevbezt) ? prevbezt->ipo : bezt->ipo;
bezm.current_ipo = bezt->ipo;
prevbezt = bezt;
}
return bezms;
}
/* This function copies the code of sort_time_ipocurve, but acts on BeztMap structs instead. */
static void sort_time_beztmaps(BeztMap *bezms, int totvert)
static void sort_time_beztmaps(const blender::MutableSpan<BeztMap> bezms)
{
BeztMap *bezm;
int i, ok = 1;
bool ok = true;
/* Keep repeating the process until nothing is out of place anymore. */
while (ok) {
ok = 0;
ok = false;
bezm = bezms;
i = totvert;
while (i--) {
for (const int i : bezms.index_range()) {
bezm = &bezms[i];
/* Is current bezm out of order (i.e. occurs later than next)? */
if (i > 0) {
if (i < bezms.size() - 1) {
if (bezm->bezt->vec[1][0] > (bezm + 1)->bezt->vec[1][0]) {
std::swap(*bezm, *(bezm + 1));
ok = 1;
ok = true;
}
}
@ -797,34 +794,33 @@ static void sort_time_beztmaps(BeztMap *bezms, int totvert)
bezm->swap_handles = -1;
}
}
bezm++;
}
}
}
/* This function firstly adjusts the pointers that the transdata has to each BezTriple. */
static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totvert)
static void beztmap_to_data(TransInfo *t, FCurve *fcu, const blender::Span<BeztMap> bezms)
{
TransData2D *td2d;
TransData *td;
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* Dynamically allocate an array of chars to mark whether an TransData's
* pointers have been fixed already, so that we don't override ones that are already done. */
char *adjusted = static_cast<char *>(MEM_callocN(tc->data_len, "beztmap_adjusted_map"));
/* Used to mark whether an TransData's pointers have been fixed already, so that we don't
* override ones that are already done. */
blender::Vector<bool> adjusted(tc->data_len, false);
/* For each beztmap item, find if it is used anywhere. */
BeztMap *bezm = bezms;
for (int i = 0; i < totvert; i++, bezm++) {
const BeztMap *bezm;
for (const int i : bezms.index_range()) {
bezm = &bezms[i];
/* Loop through transdata, testing if we have a hit
* for the handles (vec[0]/vec[2]), we must also check if they need to be swapped. */
td2d = tc->data_2d;
td = tc->data;
for (int j = 0; j < tc->data_len; j++, td2d++, td++) {
/* Skip item if already marked. */
if (adjusted[j] != 0) {
if (adjusted[j]) {
continue;
}
@ -837,7 +833,7 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
else {
td2d->loc2d = fcu->bezt[i].vec[0];
}
adjusted[j] = 1;
adjusted[j] = true;
}
else if (td2d->loc2d == bezm->bezt->vec[2]) {
if (bezm->swap_handles == 1) {
@ -846,7 +842,7 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
else {
td2d->loc2d = fcu->bezt[i].vec[2];
}
adjusted[j] = 1;
adjusted[j] = true;
}
else if (td2d->loc2d == bezm->bezt->vec[1]) {
td2d->loc2d = fcu->bezt[i].vec[1];
@ -859,7 +855,7 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
td2d->h2 = fcu->bezt[i].vec[2];
}
adjusted[j] = 1;
adjusted[j] = true;
}
/* The handle type pointer has to be updated too. */
@ -875,9 +871,6 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
}
}
}
/* Free temp memory used for 'adjusted' array. */
MEM_freeN(adjusted);
}
/* This function is called by recalc_data during the Transform loop to recalculate
@ -900,16 +893,11 @@ static void remake_graph_transdata(TransInfo *t, const blender::Span<FCurve *> f
continue;
}
BeztMap *bezm;
/* Adjust transform-data pointers. */
/* NOTE: none of these functions use 'use_handle', it could be removed. */
bezm = bezt_to_beztmaps(fcu->bezt, fcu->totvert);
sort_time_beztmaps(bezm, fcu->totvert);
beztmap_to_data(t, fcu, bezm, fcu->totvert);
/* Free mapping stuff. */
MEM_freeN(bezm);
blender::Vector<BeztMap> bezms = bezt_to_beztmaps(fcu->bezt, fcu->totvert);
sort_time_beztmaps(bezms);
beztmap_to_data(t, fcu, bezms);
/* Re-sort actual beztriples
* (perhaps this could be done using the beztmaps to save time?). */

View File

@ -10,6 +10,8 @@
#pragma once
#include "BLI_span.hh"
#include "GPU_primitive.hh"
#define GPU_TRACK_INDEX_RANGE 1
@ -154,6 +156,8 @@ blender::gpu::IndexBuf *GPU_indexbuf_build_on_device(uint index_len);
void GPU_indexbuf_init_build_on_device(blender::gpu::IndexBuf *elem, uint index_len);
blender::MutableSpan<uint32_t> GPU_indexbuf_get_data(GPUIndexBufBuilder *);
/*
* Thread safe.
*
@ -180,6 +184,26 @@ void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem);
blender::gpu::IndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *);
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, blender::gpu::IndexBuf *);
void GPU_indexbuf_build_in_place_ex(GPUIndexBufBuilder *builder,
uint index_min,
uint index_max,
bool uses_restart_indices,
blender::gpu::IndexBuf *elem);
/**
* Fill an IBO by uploading the referenced data directly to the GPU, bypassing the separate storage
* in the IBO. This should be used whenever the equivalent indices already exist in a contiguous
* array on the CPU.
*
* \todo The optimization to avoid the local copy currently isn't implemented.
*/
void GPU_indexbuf_build_in_place_from_memory(blender::gpu::IndexBuf *ibo,
GPUPrimType prim_type,
const uint32_t *data,
int32_t data_len,
int32_t index_min,
int32_t index_max,
bool uses_restart_indices);
void GPU_indexbuf_bind_as_ssbo(blender::gpu::IndexBuf *elem, int binding);

View File

@ -10,6 +10,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_array_utils.hh"
#include "BLI_math_base.h"
#include "BLI_utildefines.h"
@ -96,6 +97,11 @@ void GPU_indexbuf_init_build_on_device(IndexBuf *elem, uint index_len)
elem_->init_build_on_device(index_len);
}
blender::MutableSpan<uint32_t> GPU_indexbuf_get_data(GPUIndexBufBuilder *builder)
{
return {builder->data, builder->max_index_len};
}
void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from)
{
BLI_assert(builder_to->data == builder_from->data);
@ -492,6 +498,43 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, IndexBuf *elem)
builder->data = nullptr;
}
void GPU_indexbuf_build_in_place_ex(GPUIndexBufBuilder *builder,
const uint index_min,
const uint index_max,
const bool uses_restart_indices,
IndexBuf *elem)
{
BLI_assert(builder->data != nullptr);
/* Transfer data ownership to IndexBuf.
* It will be uploaded upon first use. */
elem->init(builder->max_index_len,
builder->data,
index_min,
index_max,
builder->prim_type,
uses_restart_indices);
builder->data = nullptr;
}
void GPU_indexbuf_build_in_place_from_memory(IndexBuf *ibo,
const GPUPrimType prim_type,
const uint32_t *data,
const int32_t data_len,
const int32_t index_min,
const int32_t index_max,
const bool uses_restart_indices)
{
const uint32_t indices_num = data_len * indices_per_primitive(prim_type);
/* TODO: The need for this copy is meant to be temporary. The data should be uploaded directly to
* the GPU here rather than copied to an array owned by the IBO first. */
uint32_t *copy = static_cast<uint32_t *>(
MEM_malloc_arrayN(indices_num, sizeof(uint32_t), __func__));
threading::memory_bandwidth_bound_task(sizeof(uint32_t) * indices_num * 2, [&]() {
array_utils::copy(Span(data, indices_num), MutableSpan(copy, indices_num));
});
ibo->init(indices_num, copy, index_min, index_max, prim_type, uses_restart_indices);
}
void GPU_indexbuf_create_subrange_in_place(IndexBuf *elem,
IndexBuf *elem_src,
uint start,

View File

@ -74,6 +74,62 @@ enum class Type {
SHORT4
};
BLI_INLINE int to_component_count(const Type &type)
{
switch (type) {
case Type::FLOAT:
case Type::UINT:
case Type::INT:
case Type::BOOL:
return 1;
case Type::VEC2:
case Type::UVEC2:
case Type::IVEC2:
return 2;
case Type::VEC3:
case Type::UVEC3:
case Type::IVEC3:
return 3;
case Type::VEC4:
case Type::UVEC4:
case Type::IVEC4:
return 4;
case Type::MAT3:
return 9;
case Type::MAT4:
return 16;
/* Alias special types. */
case Type::UCHAR:
case Type::USHORT:
return 1;
case Type::UCHAR2:
case Type::USHORT2:
return 2;
case Type::UCHAR3:
case Type::USHORT3:
return 3;
case Type::UCHAR4:
case Type::USHORT4:
return 4;
case Type::CHAR:
case Type::SHORT:
return 1;
case Type::CHAR2:
case Type::SHORT2:
return 2;
case Type::CHAR3:
case Type::SHORT3:
return 3;
case Type::CHAR4:
case Type::SHORT4:
return 4;
case Type::VEC3_101010I2:
return 3;
}
BLI_assert_unreachable();
return -1;
}
/* All of these functions is a bit out of place */
static inline Type to_type(const eGPUType type)
{

View File

@ -155,7 +155,7 @@ class MTLFrameBuffer : public FrameBuffer {
protected:
void subpass_transition_impl(const GPUAttachmentState /*depth_attachment_state*/,
Span<GPUAttachmentState> /*color_attachment_states*/) override{};
Span<GPUAttachmentState> color_attachment_states) override;
public:
void apply_state();

View File

@ -472,6 +472,27 @@ void MTLFrameBuffer::clear_attachment(GPUAttachmentType type,
this->force_clear();
}
}
void MTLFrameBuffer::subpass_transition_impl(const GPUAttachmentState /*depth_attachment_state*/,
Span<GPUAttachmentState> color_attachment_states)
{
const bool is_tile_based_arch = (GPU_platform_architecture() == GPU_ARCHITECTURE_TBDR);
if (!is_tile_based_arch) {
/* Break renderpass if tile memory is unsupported to ensure current framebuffer results are
* stored. */
context_->main_command_buffer.end_active_command_encoder();
/* Bind framebuffer attachments as textures.
* NOTE: Follows behaviour of gl_framebuffer. However, shaders utilising subpass_in will
* need to avoid bindpoint collisions for image/texture resources. */
for (int i : color_attachment_states.index_range()) {
GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0 + i;
GPUTexture *attach_tex = this->attachments_[type].tex;
if (color_attachment_states[i] == GPU_ATTACHEMENT_READ) {
GPU_texture_image_bind(attach_tex, i);
}
}
}
}
void MTLFrameBuffer::read(eGPUFrameBufferBits planes,
eGPUDataFormat format,

View File

@ -414,6 +414,7 @@ class MSLGeneratorInterface {
blender::Vector<MSLConstant> constants;
/* Fragment tile inputs. */
blender::Vector<MSLFragmentTileInputAttribute> fragment_tile_inputs;
bool supports_native_tile_inputs;
/* Should match vertex outputs, but defined separately as
* some shader permutations will not utilize all inputs/outputs.
* Final shader uses the intersection between the two sets. */

View File

@ -2089,6 +2089,16 @@ void MSLGeneratorInterface::prepare_from_createinfo(const shader::ShaderCreateIn
fragment_outputs.append(mtl_frag_out);
}
/** Identify support for tile inputs. */
const bool is_tile_based_arch = (GPU_platform_architecture() == GPU_ARCHITECTURE_TBDR);
if (is_tile_based_arch) {
supports_native_tile_inputs = true;
}
else {
/* NOTE: If emulating tile input reads, we must ensure we also expose position data. */
supports_native_tile_inputs = false;
}
/* Fragment tile inputs. */
for (const shader::ShaderCreateInfo::SubpassIn &frag_tile_in : create_info_->subpass_inputs_) {
@ -2107,6 +2117,51 @@ void MSLGeneratorInterface::prepare_from_createinfo(const shader::ShaderCreateIn
mtl_frag_in.raster_order_group = frag_tile_in.raster_order_group;
fragment_tile_inputs.append(mtl_frag_in);
/* If we do not support native tile inputs, generate an image-binding per input. */
if (!supports_native_tile_inputs) {
/* Determine type: */
bool is_layered_fb = bool(create_info_->builtins_ & BuiltinBits::LAYER);
/* Start with invalid value to detect failure cases. */
ImageType image_type = ImageType::FLOAT_BUFFER;
switch (frag_tile_in.type) {
case Type::FLOAT:
image_type = is_layered_fb ? ImageType::FLOAT_2D_ARRAY : ImageType::FLOAT_2D;
break;
case Type::INT:
image_type = is_layered_fb ? ImageType::INT_2D_ARRAY : ImageType::INT_2D;
break;
case Type::UINT:
image_type = is_layered_fb ? ImageType::UINT_2D_ARRAY : ImageType::UINT_2D;
break;
default:
break;
}
BLI_assert(image_type != ImageType::FLOAT_BUFFER);
/* Generate texture binding resource. */
MSLTextureResource msl_image;
msl_image.stage = ShaderStage::FRAGMENT;
msl_image.type = image_type;
msl_image.name = frag_tile_in.name + "_subpass_img";
msl_image.access = MSLTextureSamplerAccess::TEXTURE_ACCESS_READ;
msl_image.slot = texture_slot_id++;
/* WATCH: We don't have a great place to generate the image bindings.
* So we will use the subpass binding index and check if it collides with an existing
* binding. */
msl_image.location = frag_tile_in.index;
msl_image.is_texture_sampler = false;
BLI_assert(msl_image.slot < MTL_MAX_TEXTURE_SLOTS);
BLI_assert(msl_image.location < MTL_MAX_TEXTURE_SLOTS);
/* Check existing samplers. */
for (const auto &tex : texture_samplers) {
BLI_assert(tex.location != msl_image.location);
}
texture_samplers.append(msl_image);
max_tex_bind_index = max_ii(max_tex_bind_index, msl_image.slot);
}
}
/* Transform feedback. */
@ -3043,10 +3098,31 @@ std::string MSLGeneratorInterface::generate_msl_global_uniform_population(Shader
std::string MSLGeneratorInterface::generate_msl_fragment_tile_input_population()
{
std::stringstream out;
for (const MSLFragmentTileInputAttribute &tile_input : this->fragment_tile_inputs) {
out << "\t" << get_shader_stage_instance_name(ShaderStage::FRAGMENT) << "." << tile_input.name
<< " = "
<< "fragment_tile_in." << tile_input.name << ";" << std::endl;
/* Native tile read is supported on tile-based architectures (Apple Silicon). */
if (supports_native_tile_inputs) {
for (const MSLFragmentTileInputAttribute &tile_input : this->fragment_tile_inputs) {
out << "\t" << get_shader_stage_instance_name(ShaderStage::FRAGMENT) << "."
<< tile_input.name << " = "
<< "fragment_tile_in." << tile_input.name << ";" << std::endl;
}
}
else {
for (const MSLFragmentTileInputAttribute &tile_input : this->fragment_tile_inputs) {
/* Get read swizzle mask. */
char swizzle[] = "xyzw";
swizzle[to_component_count(tile_input.type)] = '\0';
bool is_layered_fb = bool(create_info_->builtins_ & BuiltinBits::LAYER);
std::string texel_co = (is_layered_fb) ?
"ivec3(ivec2(v_in._default_position_.xy), int(v_in.gpu_Layer))" :
"ivec2(v_in._default_position_.xy)";
out << "\t" << get_shader_stage_instance_name(ShaderStage::FRAGMENT) << "."
<< tile_input.name << " = texelFetch("
<< get_shader_stage_instance_name(ShaderStage::FRAGMENT) << "." << tile_input.name
<< "_subpass_img, " << texel_co << ", 0)." << swizzle << ";\n";
}
}
return out.str();
}

View File

@ -2215,8 +2215,14 @@ void gpu::MTLTexture::prepare_internal()
* bandwidth implications for lossless compression and is considered best-practice.
*
* Attachment usage also required for depth-stencil attachment targets, for depth-update support.
* NOTE: Emulated atomic textures cannot support render-target usage. For clearing, the backing
* buffer is cleared instead.
*/
gpu_image_usage_flags_ |= GPU_TEXTURE_USAGE_ATTACHMENT;
if (!((gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_ATOMIC) &&
!MTLBackend::get_capabilities().supports_texture_atomics))
{
gpu_image_usage_flags_ |= GPU_TEXTURE_USAGE_ATTACHMENT;
}
/* Derive maximum number of mip levels by default.
* TODO(Metal): This can be removed if max mip counts are specified upfront. */

View File

@ -144,62 +144,6 @@ static const char *to_string(const Type &type)
return "unknown";
}
static int to_component_count(const Type &type)
{
switch (type) {
case Type::FLOAT:
case Type::UINT:
case Type::INT:
case Type::BOOL:
return 1;
case Type::VEC2:
case Type::UVEC2:
case Type::IVEC2:
return 2;
case Type::VEC3:
case Type::UVEC3:
case Type::IVEC3:
return 3;
case Type::VEC4:
case Type::UVEC4:
case Type::IVEC4:
return 4;
case Type::MAT3:
return 9;
case Type::MAT4:
return 16;
/* Alias special types. */
case Type::UCHAR:
case Type::USHORT:
return 1;
case Type::UCHAR2:
case Type::USHORT2:
return 2;
case Type::UCHAR3:
case Type::USHORT3:
return 3;
case Type::UCHAR4:
case Type::USHORT4:
return 4;
case Type::CHAR:
case Type::SHORT:
return 1;
case Type::CHAR2:
case Type::SHORT2:
return 2;
case Type::CHAR3:
case Type::SHORT3:
return 3;
case Type::CHAR4:
case Type::SHORT4:
return 4;
case Type::VEC3_101010I2:
return 3;
}
BLI_assert_unreachable();
return -1;
}
static Type to_component_type(const Type &type)
{
switch (type) {

View File

@ -103,7 +103,9 @@ void VKBackend::detect_workarounds(VKDevice &device)
!device.physical_device_vulkan_12_features_get().shaderOutputViewportIndex;
/* AMD GPUs don't support texture formats that use are aligned to 24 or 48 bits. */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) ||
GPU_type_matches(GPU_DEVICE_APPLE, GPU_OS_MAC, GPU_DRIVER_ANY))
{
workarounds.not_aligned_pixel_formats = true;
}

View File

@ -41,7 +41,7 @@ class VKVertexAttributeObject {
void bind(VKContext &context);
// Copy assignment operator.
/** Copy assignment operator. */
VKVertexAttributeObject &operator=(const VKVertexAttributeObject &other);
void update_bindings(const VKContext &context, VKBatch &batch);

View File

@ -48,13 +48,13 @@ void ArmatureExporter::add_bone_collections(Object *ob_arm, COLLADASW::Node &nod
std::string collection_names = collection_stream.str();
if (collection_names.length() > 1) {
collection_names.pop_back(); // Pop off the last \n.
collection_names.pop_back(); /* Pop off the last `\n`. */
node.addExtraTechniqueParameter("blender", "collections", collection_names);
}
std::string visible_names = visible_stream.str();
if (visible_names.length() > 1) {
visible_names.pop_back(); // Pop off the last \n.
visible_names.pop_back(); /* Pop off the last `\n`. */
node.addExtraTechniqueParameter("blender", "visible_collections", visible_names);
}
@ -195,7 +195,7 @@ void ArmatureExporter::add_bone_node(Bone *bone,
collection_names += std::string(bcoll_ref->bcoll->name) + "\n";
}
if (collection_names.length() > 1) {
collection_names.pop_back(); // Pop off the last \n.
collection_names.pop_back(); /* Pop off the last `\n`. */
node.addExtraTechniqueParameter("blender", "", collection_names, "", "collections");
}

View File

@ -77,10 +77,14 @@ void export_frame(Depsgraph *depsgraph,
std::replace(object_name.begin(), object_name.end(), ' ', '_');
/* Include object name in the exported file name. */
std::string suffix = object_name + ".stl";
char filepath[FILE_MAX];
STRNCPY(filepath, export_params.filepath);
BLI_path_extension_replace(filepath, FILE_MAX, suffix.c_str());
BLI_path_suffix(filepath, FILE_MAX, object_name.c_str(), "");
/* Make sure we have .stl extension (case insensitive). */
if (!BLI_path_extension_check(filepath, ".stl")) {
BLI_path_extension_ensure(filepath, FILE_MAX, ".stl");
}
try {
writer = std::make_unique<FileWriter>(filepath, export_params.ascii_format);
}

View File

@ -70,7 +70,7 @@ std::string add_unique_name(blender::Set<std::string> &names, const std::string
return unique_name;
}
} // End anonymous namespace.
} // namespace
namespace blender::io::usd {

View File

@ -491,7 +491,7 @@ bool USD_export(bContext *C,
if (!collection) {
BKE_reportf(job->params.worker_status->reports,
RPT_ERROR,
"USD Export: Unable to find collection %s",
"USD Export: Unable to find collection '%s'",
job->params.collection);
return false;
}

View File

@ -765,4 +765,4 @@ UsdPathSet USDStageReader::collect_point_instancer_proto_paths() const
return result;
}
} // Namespace blender::io::usd
} // namespace blender::io::usd

View File

@ -372,7 +372,7 @@ void add_skinned_mesh_bindings(const pxr::UsdSkelSkeleton &skel,
}
}
} // End anonymous namespace.
} // namespace
namespace blender::io::usd {

Some files were not shown because too many files have changed in this diff Show More