WIP: Brush assets project #106303

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

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
105 changed files with 1318 additions and 846 deletions
Showing only changes of commit 2fdd7c6a56 - 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
@ -8609,38 +8628,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
@ -914,6 +916,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
@ -1064,6 +1071,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'}:
layout.prop(brush, "image_tool")

View File

@ -2506,6 +2506,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
@ -3213,6 +3244,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:
@ -1183,7 +1244,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")

View File

@ -619,8 +619,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
@ -637,7 +640,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")
)
@ -678,7 +681,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 13
#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

@ -87,6 +87,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,
@ -105,9 +106,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

@ -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_asset_types.h"
@ -254,6 +255,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;
@ -365,6 +367,9 @@ bool BKE_paint_ensure_from_paintmode(Main *bmain, 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;
}
@ -402,6 +407,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:
@ -436,6 +443,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;
}
@ -545,7 +554,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:
@ -597,6 +612,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) {
@ -872,6 +889,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. */
}
@ -1206,6 +1225,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

@ -3145,7 +3145,7 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 13)) {
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 14)) {
update_paint_modes_for_brush_assets(*bmain);
}

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

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

@ -353,10 +353,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

@ -1365,6 +1365,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);
}

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

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

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

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

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

View File

@ -339,7 +339,7 @@ void exporter_main(bContext *C, const OBJExportParams &export_params)
if (!collection) {
BKE_reportf(export_params.reports,
RPT_ERROR,
"OBJ Export: Unable to find collection %s",
"OBJ Export: Unable to find collection '%s'",
export_params.collection);
return;
}

View File

@ -853,21 +853,6 @@ enum {
/** \name Render Conversion/Simplification Settings
* \{ */
/** Control render convert and shading engine. */
typedef struct RenderProfile {
struct RenderProfile *next, *prev;
char name[32];
short particle_perc;
short subsurf_max;
short shadbufsample_max;
char _pad1[2];
float ao_error;
char _pad2[4];
} RenderProfile;
/* UV Paint. */
/** #ToolSettings::uv_sculpt_settings */
enum {

View File

@ -483,12 +483,15 @@ typedef struct ThemeStripColor {
/**
* A theme.
*
* \note Currently only a single theme is ever used at once.
* \note Currently only the first theme is used at once.
* Different theme presets are stored as external files now.
*/
typedef struct bTheme {
struct bTheme *next, *prev;
char name[32];
/** #MAX_NAME. */
char name[64];
/* NOTE: Values after `name` are copied when resetting the default theme. */
ThemeUI tui;
@ -854,6 +857,10 @@ typedef struct UserDef {
/** Startup application template. */
char app_template[64];
/**
* A list of themes (#bTheme), the first is only used currently.
* But there may be multiple themes in the list.
*/
struct ListBase themes;
struct ListBase uifonts;
struct ListBase uistyles;

View File

@ -765,7 +765,7 @@ StructRNA *ID_code_to_RNA_type(short idcode);
#if defined __GNUC__
# define RNA_warning(format, args...) _RNA_warning("%s: " format "\n", __func__, ##args)
#elif defined(_MSVC_TRADITIONAL) && \
!_MSVC_TRADITIONAL // The "new preprocessor" is enabled via /Zc:preprocessor
!_MSVC_TRADITIONAL /* The "new preprocessor" is enabled via `/Zc:preprocessor`. */
# define RNA_warning(format, ...) _RNA_warning("%s: " format "\n", __FUNCTION__, ##__VA_ARGS__)
#else
# define RNA_warning(format, ...) _RNA_warning("%s: " format "\n", __FUNCTION__, __VA_ARGS__)

View File

@ -498,7 +498,7 @@ static bool rna_property_override_operation_store(Main *bmain,
}
}
if (ptr_storage != nullptr && prop_storage->magic == RNA_MAGIC &&
if ((prop_storage->magic == RNA_MAGIC) &&
!ELEM(prop_storage->override_store, nullptr, override_store))
{
override_store = nullptr;

View File

@ -46,6 +46,7 @@ const EnumPropertyItem rna_enum_context_mode_items[] = {
{CTX_MODE_VERTEX_GPENCIL_LEGACY, "VERTEX_GPENCIL", 0, "Grease Pencil Vertex Paint", ""},
{CTX_MODE_SCULPT_CURVES, "SCULPT_CURVES", 0, "Curves Sculpt", ""},
{CTX_MODE_PAINT_GREASE_PENCIL, "PAINT_GREASE_PENCIL", 0, "Grease Pencil Paint", ""},
{CTX_MODE_SCULPT_GREASE_PENCIL, "SCULPT_GREASE_PENCIL", 0, "Grease Pencil Sculpt", ""},
{0, nullptr, 0, nullptr, nullptr},
};

View File

@ -1021,6 +1021,13 @@ static int rna_lang_enum_properties_get_no_international(PointerRNA * /*ptr*/)
}
# endif
static void rna_Theme_name_set(PointerRNA *ptr, const char *value)
{
bTheme *btheme = static_cast<bTheme *>(ptr->data);
STRNCPY_UTF8(btheme->name, value);
BLI_uniquename(&U.themes, btheme, "Theme", '.', offsetof(bTheme, name), sizeof(btheme->name));
}
static void rna_Addon_module_set(PointerRNA *ptr, const char *value)
{
bAddon *addon = (bAddon *)ptr->data;
@ -2168,7 +2175,7 @@ static void rna_def_userdef_theme_spaces_asset_shelf_main(StructRNA *srna)
RNA_def_property_ui_text(prop, "Asset Shelf", "Settings for asset shelf");
}
static void rna_def_userdef_theme_spaces_vertex(StructRNA *srna)
static void rna_def_userdef_theme_spaces_vertex(StructRNA *srna, const bool has_vertex_active)
{
PropertyRNA *prop;
@ -2182,10 +2189,12 @@ static void rna_def_userdef_theme_spaces_vertex(StructRNA *srna)
RNA_def_property_ui_text(prop, "Vertex Select", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "vertex_active", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Active Vertex", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
if (has_vertex_active) {
prop = RNA_def_property(srna, "vertex_active", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Active Vertex", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
}
prop = RNA_def_property(srna, "vertex_size", PROP_INT, PROP_PIXEL);
RNA_def_property_range(prop, 1, 32);
@ -2561,7 +2570,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
/* Mesh Object specific */
rna_def_userdef_theme_spaces_vertex(srna);
rna_def_userdef_theme_spaces_vertex(srna, false);
rna_def_userdef_theme_spaces_edge(srna);
rna_def_userdef_theme_spaces_face(srna);
@ -2773,7 +2782,7 @@ static void rna_def_userdef_theme_space_graph(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Preview Range", "Color of preview range overlay");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
rna_def_userdef_theme_spaces_vertex(srna);
rna_def_userdef_theme_spaces_vertex(srna, true);
rna_def_userdef_theme_spaces_curves(srna, false, true, true, true);
}
@ -3339,7 +3348,7 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grid", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
rna_def_userdef_theme_spaces_vertex(srna);
rna_def_userdef_theme_spaces_vertex(srna, false);
rna_def_userdef_theme_spaces_face(srna);
prop = RNA_def_property(srna, "editmesh_active", PROP_FLOAT, PROP_COLOR_GAMMA);
@ -4287,6 +4296,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "Name of the theme");
RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_Theme_name_set");
RNA_def_struct_name_property(srna, prop);
/* XXX: for now putting this in presets is silly - its just Default */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);

View File

@ -62,18 +62,17 @@ static PyObject *pygpu_compute_dispatch(PyObject * /*self*/, PyObject *args, PyO
if (_PyArg_ParseTupleAndKeywordsFast(
args, kwds, &_parser, &py_shader, &groups_x_len, &groups_y_len, &groups_z_len))
{
if (!BPyGPUShader_Check(py_shader)) {
PyErr_Format(PyExc_TypeError, "Expected a GPUShader, got %s", Py_TYPE(py_shader)->tp_name);
return nullptr;
}
// Check that groups do not exceed GPU_max_work_group_count()
/* Check that groups do not exceed #GPU_max_work_group_count(). */
const int max_work_group_count_x = GPU_max_work_group_count(0);
const int max_work_group_count_y = GPU_max_work_group_count(1);
const int max_work_group_count_z = GPU_max_work_group_count(2);
// Report back to the user both the requested and the maximum supported value
/* Report back to the user both the requested and the maximum supported value. */
if (groups_x_len > GPU_max_work_group_count(0)) {
PyErr_Format(PyExc_ValueError,
"groups_x_len (%d) exceeds maximum supported value (max work group count: %d)",

View File

@ -45,7 +45,7 @@ void SEQ_for_each_callback(ListBase *seqbase, SeqForEachFunc callback, void *use
seq_for_each_recursive(seqbase, callback, user_data);
}
VectorSet<Sequence *> SEQ_query_by_reference(Sequence *reference_strip,
VectorSet<Sequence *> SEQ_query_by_reference(Sequence *seq_reference,
const Scene *scene,
ListBase *seqbase,
void seq_query_func(const Scene *scene,
@ -54,7 +54,7 @@ VectorSet<Sequence *> SEQ_query_by_reference(Sequence *reference_strip,
VectorSet<Sequence *> &strips))
{
VectorSet<Sequence *> strips;
seq_query_func(scene, reference_strip, seqbase, strips);
seq_query_func(scene, seq_reference, seqbase, strips);
return strips;
}

View File

@ -272,7 +272,7 @@ void *SEQ_sound_equalizermodifier_recreator(Sequence *seq, SequenceModifierData
SoundEqualizerModifierData *semd = (SoundEqualizerModifierData *)smd;
// No Equalizer definition
/* No equalizer definition. */
if (BLI_listbase_is_empty(&semd->graphics)) {
return sound;
}
@ -286,7 +286,7 @@ void *SEQ_sound_equalizermodifier_recreator(Sequence *seq, SequenceModifierData
float maxX;
float interval = SOUND_EQUALIZER_DEFAULT_MAX_FREQ / float(SOUND_EQUALIZER_SIZE_DEFINITION);
// Visit all equalizer definitions
/* Visit all equalizer definitions. */
LISTBASE_FOREACH (EQCurveMappingData *, mapping, &semd->graphics) {
eq_mapping = &mapping->curve_mapping;
BKE_curvemapping_init(eq_mapping);

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