GPv3: Curve Fill node #113614
|
@ -231,30 +231,23 @@ class GHOST_DeviceVK {
|
|||
device_features.drawIndirectFirstInstance = VK_TRUE;
|
||||
device_features.fragmentStoresAndAtomics = VK_TRUE;
|
||||
|
||||
VkPhysicalDeviceVulkan12Features device_12_features = {};
|
||||
device_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
|
||||
device_12_features.shaderOutputLayer = VK_TRUE;
|
||||
device_12_features.shaderOutputViewportIndex = VK_TRUE;
|
||||
/* Enable shader draw parameters on logical device when supported on physical device. */
|
||||
VkPhysicalDeviceShaderDrawParametersFeatures shader_draw_parameters = {};
|
||||
shader_draw_parameters.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
|
||||
shader_draw_parameters.shaderDrawParameters = features_11.shaderDrawParameters;
|
||||
|
||||
VkPhysicalDeviceMaintenance4FeaturesKHR maintenance_4 = {};
|
||||
maintenance_4.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR;
|
||||
maintenance_4.maintenance4 = VK_TRUE;
|
||||
/* Mainenance4 is core in Vulkan 1.3 so we need to query for availability. */
|
||||
if (has_extensions({VK_KHR_MAINTENANCE_4_EXTENSION_NAME})) {
|
||||
maintenance_4.pNext = device_12_features.pNext;
|
||||
device_12_features.pNext = &maintenance_4;
|
||||
maintenance_4.pNext = shader_draw_parameters.pNext;
|
||||
shader_draw_parameters.pNext = &maintenance_4;
|
||||
}
|
||||
|
||||
/* Enable shader draw parameters on logical device when supported on physical device. */
|
||||
VkPhysicalDeviceShaderDrawParametersFeatures shader_draw_parameters = {};
|
||||
shader_draw_parameters.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
|
||||
shader_draw_parameters.shaderDrawParameters = features_11.shaderDrawParameters;
|
||||
shader_draw_parameters.pNext = device_12_features.pNext;
|
||||
device_12_features.pNext = &shader_draw_parameters;
|
||||
|
||||
VkDeviceCreateInfo device_create_info = {};
|
||||
device_create_info.pNext = &device_12_features;
|
||||
device_create_info.pNext = &shader_draw_parameters;
|
||||
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
device_create_info.queueCreateInfoCount = uint32_t(queue_create_infos.size());
|
||||
device_create_info.pQueueCreateInfos = queue_create_infos.data();
|
||||
|
@ -980,8 +973,6 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
|
|||
if (m_debug) {
|
||||
enableLayer(layers_available, layers_enabled, VkLayer::KHRONOS_validation, m_debug);
|
||||
requireExtension(extensions_available, extensions_enabled, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
requireExtension(
|
||||
extensions_available, extensions_enabled, VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
if (use_window_surface) {
|
||||
|
|
|
@ -2376,6 +2376,17 @@ static void data_device_handle_data_offer(void * /*data*/,
|
|||
{
|
||||
CLOG_INFO(LOG, 2, "data_offer");
|
||||
|
||||
/* The ownership of data-offer isn't so obvious:
|
||||
* At this point it's not known if this will be used for drag & drop or selection.
|
||||
*
|
||||
* The API docs state that the following callbacks run immediately after this callback:
|
||||
* - #wl_data_device_listener::enter (for drag & drop).
|
||||
* - #wl_data_device_listener::selection (for copy & paste).
|
||||
*
|
||||
* In the case of GHOST, this means they will be assigned to either:
|
||||
* - #GWL_Seat::data_offer_dnd
|
||||
* - #GWL_Seat::data_offer_copy_paste
|
||||
*/
|
||||
GWL_DataOffer *data_offer = new GWL_DataOffer;
|
||||
data_offer->wl.id = id;
|
||||
wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
|
||||
|
@ -2389,18 +2400,28 @@ static void data_device_handle_enter(void *data,
|
|||
const wl_fixed_t y,
|
||||
wl_data_offer *id)
|
||||
{
|
||||
/* Always clear the current data-offer no matter what else happens. */
|
||||
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
|
||||
std::lock_guard lock{seat->data_offer_dnd_mutex};
|
||||
if (seat->data_offer_dnd) {
|
||||
wl_data_offer_destroy(seat->data_offer_dnd->wl.id);
|
||||
delete seat->data_offer_dnd;
|
||||
seat->data_offer_dnd = nullptr;
|
||||
}
|
||||
/* Clearing complete. */
|
||||
|
||||
/* Handle the new offer. */
|
||||
GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id));
|
||||
if (!ghost_wl_surface_own_with_null_check(wl_surface)) {
|
||||
CLOG_INFO(LOG, 2, "enter (skipped)");
|
||||
wl_data_offer_destroy(data_offer->wl.id);
|
||||
delete data_offer;
|
||||
return;
|
||||
}
|
||||
CLOG_INFO(LOG, 2, "enter");
|
||||
|
||||
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
|
||||
std::lock_guard lock{seat->data_offer_dnd_mutex};
|
||||
|
||||
delete seat->data_offer_dnd;
|
||||
seat->data_offer_dnd = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id));
|
||||
GWL_DataOffer *data_offer = seat->data_offer_dnd;
|
||||
/* Transfer ownership of the `data_offer`. */
|
||||
seat->data_offer_dnd = data_offer;
|
||||
|
||||
data_offer->dnd.in_use = true;
|
||||
data_offer->dnd.xy[0] = x;
|
||||
|
@ -2427,7 +2448,10 @@ static void data_device_handle_leave(void *data, wl_data_device * /*wl_data_devi
|
|||
{
|
||||
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
|
||||
std::lock_guard lock{seat->data_offer_dnd_mutex};
|
||||
|
||||
/* The user may have only dragged over the window decorations. */
|
||||
if (seat->data_offer_dnd == nullptr) {
|
||||
return;
|
||||
}
|
||||
CLOG_INFO(LOG, 2, "leave");
|
||||
|
||||
dnd_events(seat, GHOST_kEventDraggingExited);
|
||||
|
@ -2448,6 +2472,10 @@ static void data_device_handle_motion(void *data,
|
|||
{
|
||||
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
|
||||
std::lock_guard lock{seat->data_offer_dnd_mutex};
|
||||
/* The user may have only dragged over the window decorations. */
|
||||
if (seat->data_offer_dnd == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
CLOG_INFO(LOG, 2, "motion");
|
||||
|
||||
|
@ -2462,6 +2490,8 @@ static void data_device_handle_drop(void *data, wl_data_device * /*wl_data_devic
|
|||
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
|
||||
std::lock_guard lock{seat->data_offer_dnd_mutex};
|
||||
|
||||
/* No need to check this for null (as other callbacks do).
|
||||
* because the the data-offer has not been accepted (actions set... etc). */
|
||||
GWL_DataOffer *data_offer = seat->data_offer_dnd;
|
||||
|
||||
/* Use a blank string for `mime_receive` to prevent crashes, although could also be `nullptr`.
|
||||
|
@ -2573,27 +2603,25 @@ static void data_device_handle_selection(void *data,
|
|||
wl_data_device * /*wl_data_device*/,
|
||||
wl_data_offer *id)
|
||||
{
|
||||
/* Always clear the current data-offer no matter what else happens. */
|
||||
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
|
||||
|
||||
std::lock_guard lock{seat->data_offer_copy_paste_mutex};
|
||||
|
||||
GWL_DataOffer *data_offer = seat->data_offer_copy_paste;
|
||||
|
||||
/* Delete old data offer. */
|
||||
if (data_offer != nullptr) {
|
||||
wl_data_offer_destroy(data_offer->wl.id);
|
||||
delete data_offer;
|
||||
data_offer = nullptr;
|
||||
if (seat->data_offer_copy_paste) {
|
||||
wl_data_offer_destroy(seat->data_offer_copy_paste->wl.id);
|
||||
delete seat->data_offer_copy_paste;
|
||||
seat->data_offer_copy_paste = nullptr;
|
||||
}
|
||||
/* Clearing complete. */
|
||||
|
||||
/* Handle the new offer. */
|
||||
if (id == nullptr) {
|
||||
CLOG_INFO(LOG, 2, "selection: (skipped)");
|
||||
return;
|
||||
}
|
||||
|
||||
CLOG_INFO(LOG, 2, "selection");
|
||||
/* Get new data offer. */
|
||||
data_offer = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id));
|
||||
GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id));
|
||||
/* Transfer ownership of the `data_offer`. */
|
||||
seat->data_offer_copy_paste = data_offer;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,18 @@
|
|||
/* Logging, use `ghost.wl.*` prefix. */
|
||||
#include "CLG_log.h"
|
||||
|
||||
/**
|
||||
* NOTE(@ideasman42): Workaround a bug with fractional scaling with LIBDECOR.
|
||||
* When fractional scaling is used the GHOST window uses a buffer-scale of 1
|
||||
* with the actual scale compensated for by a #wp_viewport.
|
||||
*
|
||||
* This causes various glitches between the GHOST window and LIBDECOR.
|
||||
* While this hack doesn't resolve all of them it does fix the problem where a new windows
|
||||
* decorations don't match the window, sometimes causing a delayed decrease in the windows size.
|
||||
* See #109194 for related issues.
|
||||
*/
|
||||
#define USE_LIBDECOR_FRACTIONAL_SCALE_HACK
|
||||
|
||||
static const xdg_activation_token_v1_listener *xdg_activation_listener_get();
|
||||
|
||||
static constexpr size_t base_dpi = 96;
|
||||
|
@ -519,6 +531,20 @@ static bool gwl_window_viewport_set(GWL_Window *win,
|
|||
else {
|
||||
wl_surface_commit(win->wl.surface);
|
||||
}
|
||||
|
||||
#if defined(WITH_GHOST_WAYLAND_LIBDECOR) && defined(USE_LIBDECOR_FRACTIONAL_SCALE_HACK)
|
||||
/* NOTE(@ideasman42): it's important this only runs when enabling the viewport
|
||||
* since there is a bug with LIBDECOR not supporting the switch from non-fractional
|
||||
* to fractional scaled surfaces. */
|
||||
if (use_libdecor) {
|
||||
WGL_LibDecor_Window &decor = *win->libdecor;
|
||||
libdecor_state *state = libdecor_state_new(
|
||||
gwl_window_fractional_from_viewport_round(win->frame, win->frame.size[0]),
|
||||
gwl_window_fractional_from_viewport_round(win->frame, win->frame.size[1]));
|
||||
libdecor_frame_commit(decor.frame, state, nullptr);
|
||||
libdecor_state_free(state);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1215,9 +1241,9 @@ static void libdecor_frame_handle_commit(libdecor_frame * /*frame*/, void *data)
|
|||
|
||||
/* NOTE: cannot be `const` because of the LIBDECOR API. */
|
||||
static libdecor_frame_interface libdecor_frame_iface = {
|
||||
libdecor_frame_handle_configure,
|
||||
libdecor_frame_handle_close,
|
||||
libdecor_frame_handle_commit,
|
||||
/*configure*/ libdecor_frame_handle_configure,
|
||||
/*close*/ libdecor_frame_handle_close,
|
||||
/*commit*/ libdecor_frame_handle_commit,
|
||||
};
|
||||
|
||||
# undef LOG
|
||||
|
@ -1390,14 +1416,18 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
|
|||
* known once #surface_enter callback runs (which isn't guaranteed to run at all).
|
||||
*
|
||||
* Using the maximum scale is best as it results in the window first being smaller,
|
||||
* avoiding a large window flashing before it's made smaller. */
|
||||
int fractional_scale = 0;
|
||||
* avoiding a large window flashing before it's made smaller.
|
||||
*
|
||||
* For fractional scaling the buffer will eventually be 1. Setting it to 1 now
|
||||
* (to avoid window size rounding and buffer size switching) has some down-sides.
|
||||
* It means the window will be drawn larger for a moment then smaller once fractional scaling
|
||||
* is detected and enabled. Unfortunately, it doesn't seem possible to receive the
|
||||
* #wp_fractional_scale_v1_listener::preferred_scale information before the window is created
|
||||
* So leave the buffer scaled up because there is no *guarantee* the fractional scaling support
|
||||
* will run which could result in an incorrect buffer scale.
|
||||
* Leaving the buffer scale is necessary for #USE_LIBDECOR_FRACTIONAL_SCALE_HACK to work too. */
|
||||
window_->frame.buffer_scale = outputs_uniform_scale_or_default(
|
||||
system_->outputs_get(), 1, &fractional_scale);
|
||||
|
||||
if (fractional_scale / FRACTIONAL_DENOMINATOR != window_->frame.buffer_scale) {
|
||||
window_->frame.buffer_scale = 1;
|
||||
}
|
||||
system_->outputs_get(), 1, nullptr);
|
||||
window_->frame_pending.buffer_scale = window_->frame.buffer_scale;
|
||||
|
||||
window_->frame.size[0] = int32_t(width);
|
||||
|
|
|
@ -588,6 +588,7 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
|
|||
),
|
||||
"message": (),
|
||||
"heading": (),
|
||||
"placeholder": ((("text_ctxt",), _ctxt_to_ctxt),),
|
||||
}
|
||||
|
||||
context_kw_set = {}
|
||||
|
@ -621,7 +622,8 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
|
|||
for arg_pos, (arg_kw, arg) in enumerate(func.parameters.items()):
|
||||
if (not arg.is_output) and (arg.type == 'STRING'):
|
||||
for msgid, msgctxts in context_kw_set.items():
|
||||
if arg_kw in msgctxts:
|
||||
# The msgid can be missing if it is used in only some UILayout functions but not all
|
||||
if arg_kw in msgctxts and msgid in func_translate_args[func_id]:
|
||||
func_translate_args[func_id][msgid][1][arg_kw] = arg_pos
|
||||
# The report() func of operators.
|
||||
for func_id, func in bpy.types.Operator.bl_rna.functions.items():
|
||||
|
|
|
@ -273,7 +273,17 @@ PYGETTEXT_KEYWORDS = (() +
|
|||
tuple((r"\.{}\(\s*" + _msg_re + r"\s*\)").format(it)
|
||||
for it in ("description", "error_message_add")) +
|
||||
|
||||
# Node socket labels
|
||||
# Node socket labels from declarations: context-less names
|
||||
tuple((r"\.{}\(\s*" + _msg_re +
|
||||
r"\s*\)(?![^;]*\.translation_context\()[^;]*;").format(it)
|
||||
for it in ("short_label",)) +
|
||||
|
||||
# Node socket labels from declarations: names with contexts
|
||||
tuple((r"\.{}\(\s*" + _msg_re + r"[^;]*\.translation_context\(\s*" +
|
||||
_ctxt_re + r"\s*\)").format(it)
|
||||
for it in ("short_label",)) +
|
||||
|
||||
# Dynamic node socket labels
|
||||
tuple((r"{}\(\s*[^,]+,\s*" + _msg_re + r"\s*\)").format(it)
|
||||
for it in ("node_sock_label",)) +
|
||||
|
||||
|
|
|
@ -292,7 +292,7 @@ def load_scripts(*, reload_scripts=False, refresh_scripts=False, extensions=True
|
|||
# however reloading scripts re-enable all add-ons immediately (which may inspect key-maps).
|
||||
# For this reason it's important to update key-maps which will have been tagged to update.
|
||||
# Without this, add-on register functions accessing key-map properties can crash, see: #111702.
|
||||
_bpy.context.window_manager.keyconfigs.update()
|
||||
_bpy.context.window_manager.keyconfigs.update(keep_properties=True)
|
||||
|
||||
from bpy_restrict_state import RestrictBlend
|
||||
|
||||
|
@ -308,6 +308,11 @@ def load_scripts(*, reload_scripts=False, refresh_scripts=False, extensions=True
|
|||
for mod in modules_from_path(path, loaded_modules):
|
||||
test_register(mod)
|
||||
|
||||
if reload_scripts:
|
||||
# Update key-maps for key-map items referencing operators defined in "startup".
|
||||
# Without this, key-map items wont be set properly, see: #113309.
|
||||
_bpy.context.window_manager.keyconfigs.update()
|
||||
|
||||
if extensions:
|
||||
load_scripts_extensions(reload_scripts=reload_scripts)
|
||||
|
||||
|
|
|
@ -7,6 +7,46 @@ __all__ = (
|
|||
)
|
||||
|
||||
|
||||
def find_base_socket_type(socket):
|
||||
"""
|
||||
Find the base class of the socket.
|
||||
|
||||
Sockets can have a subtype such as NodeSocketFloatFactor,
|
||||
but only the base type is allowed, e. g. NodeSocketFloat
|
||||
"""
|
||||
if socket.type == 'CUSTOM':
|
||||
# Custom socket types are used directly
|
||||
return socket.bl_idname
|
||||
if socket.type == 'VALUE':
|
||||
return 'NodeSocketFloat'
|
||||
if socket.type == 'INT':
|
||||
return 'NodeSocketInt'
|
||||
if socket.type == 'BOOLEAN':
|
||||
return 'NodeSocketBoolean'
|
||||
if socket.type == 'VECTOR':
|
||||
return 'NodeSocketVector'
|
||||
if socket.type == 'ROTATION':
|
||||
return 'NodeSocketRotation'
|
||||
if socket.type == 'STRING':
|
||||
return 'NodeSocketString'
|
||||
if socket.type == 'RGBA':
|
||||
return 'NodeSocketColor'
|
||||
if socket.type == 'SHADER':
|
||||
return 'NodeSocketShader'
|
||||
if socket.type == 'OBJECT':
|
||||
return 'NodeSocketObject'
|
||||
if socket.type == 'IMAGE':
|
||||
return 'NodeSocketImage'
|
||||
if socket.type == 'GEOMETRY':
|
||||
return 'NodeSocketGeometry'
|
||||
if socket.type == 'COLLECTION':
|
||||
return 'NodeSocketCollection'
|
||||
if socket.type == 'TEXTURE':
|
||||
return 'NodeSocketTexture'
|
||||
if socket.type == 'MATERIAL':
|
||||
return 'NodeSocketMaterial'
|
||||
|
||||
|
||||
def connect_sockets(input, output):
|
||||
"""
|
||||
Connect sockets in a node tree.
|
||||
|
@ -35,14 +75,16 @@ def connect_sockets(input, output):
|
|||
return
|
||||
|
||||
if output_node.type == 'GROUP_OUTPUT' and type(input) == bpy.types.NodeSocketVirtual:
|
||||
output_node.id_data.interface.new_socket(
|
||||
name=output.name, socket_type=type(output).__name__, in_out='OUTPUT'
|
||||
output_type = find_base_socket_type(output)
|
||||
socket_interface = output_node.id_data.interface.new_socket(
|
||||
name=output.name, socket_type=output_type, in_out='OUTPUT'
|
||||
)
|
||||
input = output_node.inputs[-2]
|
||||
|
||||
if input_node.type == 'GROUP_INPUT' and type(output) == bpy.types.NodeSocketVirtual:
|
||||
input_node.id_data.interface.new_socket(
|
||||
name=input.name, socket_type=type(input).__name__, in_out='INPUT'
|
||||
input_type = find_base_socket_type(input)
|
||||
socket_interface = input_node.id_data.interface.new_socket(
|
||||
name=input.name, socket_type=input_type, in_out='INPUT'
|
||||
)
|
||||
output = input_node.outputs[-2]
|
||||
|
||||
|
|
|
@ -4608,6 +4608,8 @@ def km_grease_pencil_edit(params):
|
|||
# Delete all active frames
|
||||
("grease_pencil.delete_frame", {"type": 'DEL', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("type", "ALL_FRAMES")]}),
|
||||
# Keyframe Menu
|
||||
op_menu("VIEW3D_MT_edit_greasepencil_animation", {"type": 'I', "value": 'PRESS'}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
|
|
@ -45,7 +45,7 @@ class NODE_MT_category_compositor_input_constant(Menu):
|
|||
node_add_menu.add_node_type(layout, "CompositorNodeRGB")
|
||||
node_add_menu.add_node_type(layout, "CompositorNodeValue")
|
||||
|
||||
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
||||
node_add_menu.draw_assets_for_catalog(layout, "Input/Constant")
|
||||
|
||||
|
||||
class NODE_MT_category_compositor_input_scene(Menu):
|
||||
|
@ -58,7 +58,7 @@ class NODE_MT_category_compositor_input_scene(Menu):
|
|||
node_add_menu.add_node_type(layout, "CompositorNodeSceneTime")
|
||||
node_add_menu.add_node_type(layout, "CompositorNodeTime")
|
||||
|
||||
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
||||
node_add_menu.draw_assets_for_catalog(layout, "Input/Scene")
|
||||
|
||||
|
||||
class NODE_MT_category_compositor_output(Menu):
|
||||
|
@ -120,7 +120,7 @@ class NODE_MT_category_compositor_color_adjust(Menu):
|
|||
node_add_menu.add_node_type(layout, "CompositorNodeCurveRGB")
|
||||
node_add_menu.add_node_type(layout, "CompositorNodeTonemap")
|
||||
|
||||
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
||||
node_add_menu.draw_assets_for_catalog(layout, "Color/Adjust")
|
||||
|
||||
|
||||
class NODE_MT_category_compositor_color_mix(Menu):
|
||||
|
@ -138,7 +138,7 @@ class NODE_MT_category_compositor_color_mix(Menu):
|
|||
layout, "CompositorNodeMixRGB",
|
||||
label=iface_("Mix Color"))
|
||||
node_add_menu.add_node_type(layout, "CompositorNodeZcombine")
|
||||
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
||||
node_add_menu.draw_assets_for_catalog(layout, "Color/Mix")
|
||||
|
||||
|
||||
class NODE_MT_category_compositor_filter(Menu):
|
||||
|
@ -179,7 +179,7 @@ class NODE_MT_category_compositor_filter_blur(Menu):
|
|||
node_add_menu.add_node_type(layout, "CompositorNodeDBlur")
|
||||
node_add_menu.add_node_type(layout, "CompositorNodeVecBlur")
|
||||
|
||||
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
||||
node_add_menu.draw_assets_for_catalog(layout, "Filter/Blur")
|
||||
|
||||
|
||||
class NODE_MT_category_compositor_group(Menu):
|
||||
|
|
|
@ -52,12 +52,22 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
|||
|
||||
class OBJECT_MT_modifier_add(ModifierAddMenu, Menu):
|
||||
bl_label = "Add Modifier"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
ob_type = context.object.type
|
||||
geometry_nodes_supported = ob_type in {'MESH', 'CURVE', 'CURVES',
|
||||
'FONT', 'SURFACE', 'VOLUME', 'POINTCLOUD', 'GREASEPENCIL'}
|
||||
'FONT', 'VOLUME', 'POINTCLOUD', 'GREASEPENCIL'}
|
||||
|
||||
if layout.operator_context == 'EXEC_REGION_WIN':
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("WM_OT_search_single_menu", text="Search...",
|
||||
icon='VIEWZOOM').menu_idname = "OBJECT_MT_modifier_add"
|
||||
layout.separator()
|
||||
|
||||
layout.operator_context = 'EXEC_REGION_WIN'
|
||||
|
||||
if geometry_nodes_supported:
|
||||
self.operator_modifier_add(layout, 'NODES')
|
||||
layout.separator()
|
||||
|
@ -76,6 +86,7 @@ class OBJECT_MT_modifier_add(ModifierAddMenu, Menu):
|
|||
|
||||
class OBJECT_MT_modifier_add_edit(ModifierAddMenu, Menu):
|
||||
bl_label = "Edit"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -99,6 +110,7 @@ class OBJECT_MT_modifier_add_edit(ModifierAddMenu, Menu):
|
|||
|
||||
class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu):
|
||||
bl_label = "Generate"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -140,6 +152,7 @@ class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu):
|
|||
|
||||
class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu):
|
||||
bl_label = "Deform"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -175,6 +188,7 @@ class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu):
|
|||
|
||||
class OBJECT_MT_modifier_add_physics(ModifierAddMenu, Menu):
|
||||
bl_label = "Physics"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
|
|
@ -870,7 +870,7 @@ class RENDER_PT_eevee_next_sampling_viewport(RenderButtonsPanel, Panel):
|
|||
col.prop(props, "taa_samples", text="Samples")
|
||||
col.prop(props, "use_taa_reprojection", text="Temporal Reprojection")
|
||||
|
||||
# Add sss sample count here
|
||||
# Add SSS sample count here.
|
||||
|
||||
|
||||
class RENDER_PT_eevee_next_sampling_render(RenderButtonsPanel, Panel):
|
||||
|
@ -893,7 +893,7 @@ class RENDER_PT_eevee_next_sampling_render(RenderButtonsPanel, Panel):
|
|||
col = layout.column(align=True)
|
||||
col.prop(props, "taa_render_samples", text="Samples")
|
||||
|
||||
# Add sss sample count here
|
||||
# Add SSS sample count here.
|
||||
|
||||
|
||||
class RENDER_PT_eevee_indirect_lighting(RenderButtonsPanel, Panel):
|
||||
|
|
|
@ -226,11 +226,18 @@ class NODE_MT_add(bpy.types.Menu):
|
|||
bl_space_type = 'NODE_EDITOR'
|
||||
bl_label = "Add"
|
||||
bl_translation_context = i18n_contexts.operator_default
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
import nodeitems_utils
|
||||
|
||||
layout = self.layout
|
||||
|
||||
if layout.operator_context == 'EXEC_REGION_WIN':
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("WM_OT_search_single_menu", text="Search...", icon='VIEWZOOM').menu_idname = "NODE_MT_add"
|
||||
layout.separator()
|
||||
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
|
||||
snode = context.space_data
|
||||
|
|
|
@ -2331,6 +2331,7 @@ class VIEW3D_MT_select_sculpt_curves(Menu):
|
|||
class VIEW3D_MT_mesh_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_mesh_add"
|
||||
bl_label = "Mesh"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -2357,6 +2358,7 @@ class VIEW3D_MT_mesh_add(Menu):
|
|||
class VIEW3D_MT_curve_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_curve_add"
|
||||
bl_label = "Curve"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -2385,6 +2387,7 @@ class VIEW3D_MT_curve_add(Menu):
|
|||
class VIEW3D_MT_surface_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_surface_add"
|
||||
bl_label = "Surface"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -2427,6 +2430,7 @@ class VIEW3D_MT_edit_metaball_context_menu(Menu):
|
|||
class VIEW3D_MT_metaball_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_metaball_add"
|
||||
bl_label = "Metaball"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -2439,6 +2443,7 @@ class TOPBAR_MT_edit_curve_add(Menu):
|
|||
bl_idname = "TOPBAR_MT_edit_curve_add"
|
||||
bl_label = "Add"
|
||||
bl_translation_context = i18n_contexts.operator_default
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -2456,6 +2461,7 @@ class TOPBAR_MT_edit_curve_add(Menu):
|
|||
class TOPBAR_MT_edit_armature_add(Menu):
|
||||
bl_idname = "TOPBAR_MT_edit_armature_add"
|
||||
bl_label = "Armature"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -2467,6 +2473,7 @@ class TOPBAR_MT_edit_armature_add(Menu):
|
|||
class VIEW3D_MT_armature_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_armature_add"
|
||||
bl_label = "Armature"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -2479,6 +2486,7 @@ class VIEW3D_MT_light_add(Menu):
|
|||
bl_idname = "VIEW3D_MT_light_add"
|
||||
bl_context = i18n_contexts.id_light
|
||||
bl_label = "Light"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -2490,6 +2498,7 @@ class VIEW3D_MT_light_add(Menu):
|
|||
class VIEW3D_MT_lightprobe_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_lightprobe_add"
|
||||
bl_label = "Light Probe"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -2501,6 +2510,7 @@ class VIEW3D_MT_lightprobe_add(Menu):
|
|||
class VIEW3D_MT_camera_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_camera_add"
|
||||
bl_label = "Camera"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -2512,6 +2522,7 @@ class VIEW3D_MT_volume_add(Menu):
|
|||
bl_idname = "VIEW3D_MT_volume_add"
|
||||
bl_label = "Volume"
|
||||
bl_translation_context = i18n_contexts.id_id
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -2524,6 +2535,7 @@ class VIEW3D_MT_volume_add(Menu):
|
|||
class VIEW3D_MT_grease_pencil_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_grease_pencil_add"
|
||||
bl_label = "Grease Pencil"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -2535,10 +2547,16 @@ class VIEW3D_MT_grease_pencil_add(Menu):
|
|||
class VIEW3D_MT_add(Menu):
|
||||
bl_label = "Add"
|
||||
bl_translation_context = i18n_contexts.operator_default
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
if layout.operator_context == 'EXEC_REGION_WIN':
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("WM_OT_search_single_menu", text="Search...", icon='VIEWZOOM').menu_idname = "VIEW3D_MT_add"
|
||||
layout.separator()
|
||||
|
||||
# NOTE: don't use 'EXEC_SCREEN' or operators won't get the `v3d` context.
|
||||
|
||||
# NOTE: was `EXEC_AREA`, but this context does not have the `rv3d`, which prevents
|
||||
|
@ -2626,6 +2644,7 @@ class VIEW3D_MT_add(Menu):
|
|||
|
||||
class VIEW3D_MT_image_add(Menu):
|
||||
bl_label = "Add Image"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
@ -5734,6 +5753,15 @@ class VIEW3D_MT_gpencil_animation(Menu):
|
|||
layout.operator("gpencil.active_frames_delete_all", text="Delete Active Keyframes (All Layers)")
|
||||
|
||||
|
||||
class VIEW3D_MT_edit_greasepencil_animation(Menu):
|
||||
bl_label = "Animation"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("grease_pencil.insert_blank_frame", text="Insert Blank Keyframe (Active Layer)")
|
||||
layout.operator("grease_pencil.insert_blank_frame", text="Insert Blank Keyframe (All Layer)").all_layers = True
|
||||
|
||||
|
||||
class VIEW3D_MT_edit_gpencil_transform(Menu):
|
||||
bl_label = "Transform"
|
||||
|
||||
|
@ -8684,6 +8712,7 @@ classes = (
|
|||
VIEW3D_MT_edit_greasepencil,
|
||||
VIEW3D_MT_edit_greasepencil_delete,
|
||||
VIEW3D_MT_edit_greasepencil_stroke,
|
||||
VIEW3D_MT_edit_greasepencil_animation,
|
||||
VIEW3D_MT_edit_curve,
|
||||
VIEW3D_MT_edit_curve_ctrlpoints,
|
||||
VIEW3D_MT_edit_curve_segments,
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "ED_transform.hh"
|
||||
#include "RNA_types.hh"
|
||||
|
||||
struct ID;
|
||||
struct ListBase;
|
||||
struct Main;
|
||||
struct Scene;
|
||||
struct ViewLayer;
|
||||
|
||||
struct AnimationEvalContext;
|
||||
struct NlaKeyframingContext;
|
||||
|
@ -101,4 +103,49 @@ int clear_keyframe(Main *bmain,
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Auto keyframing
|
||||
* Notes:
|
||||
* - All the defines for this (User-Pref settings and Per-Scene settings)
|
||||
* are defined in DNA_userdef_types.h
|
||||
* - Scene settings take precedence over those for user-preferences, with old files
|
||||
* inheriting user-preferences settings for the scene settings
|
||||
* - "On/Off + Mode" are stored per Scene, but "settings" are currently stored as user-preferences.
|
||||
* \{ */
|
||||
|
||||
/** Check if auto-key-framing is enabled (per scene takes precedence). */
|
||||
bool is_autokey_on(const Scene *scene);
|
||||
|
||||
/** Check the mode for auto-keyframing (per scene takes precedence). */
|
||||
bool is_autokey_mode(const Scene *scene, eAutokey_Mode mode);
|
||||
|
||||
/** Check if a flag is set for auto-key-framing (per scene takes precedence). */
|
||||
bool is_autokey_flag(const Scene *scene, eAutokey_Flag flag);
|
||||
|
||||
/**
|
||||
* Auto-keyframing feature - checks for whether anything should be done for the current frame.
|
||||
*/
|
||||
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id);
|
||||
|
||||
void autokeyframe_object(
|
||||
bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, eTfmMode tmode);
|
||||
bool autokeyframe_object(bContext *C, Scene *scene, Object *ob, KeyingSet *ks);
|
||||
bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks);
|
||||
|
||||
/**
|
||||
* Use for auto-key-framing.
|
||||
* \param only_if_property_keyed: if true, auto-key-framing only creates keyframes on already keyed
|
||||
* properties. This is by design when using buttons. For other callers such as gizmos or sequencer
|
||||
* preview transform, creating new animation/keyframes also on non-keyed properties is desired.
|
||||
*/
|
||||
bool autokeyframe_property(bContext *C,
|
||||
Scene *scene,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
int rnaindex,
|
||||
float cfra,
|
||||
bool only_if_property_keyed);
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::animrig
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
/** \file
|
||||
* \ingroup animrig
|
||||
*
|
||||
* \brief Functions to work with the visal keying system.
|
||||
* \brief Functions to work with the visual keying system.
|
||||
*/
|
||||
|
||||
struct PointerRNA;
|
||||
|
|
|
@ -23,6 +23,7 @@ set(SRC
|
|||
intern/bone_collections.cc
|
||||
intern/bonecolor.cc
|
||||
intern/keyframing.cc
|
||||
intern/keyframing_auto.cc
|
||||
intern/visualkey.cc
|
||||
intern/fcurve.cc
|
||||
|
||||
|
|
|
@ -0,0 +1,347 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup animrig
|
||||
*/
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "RNA_path.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "ED_keyframing.hh"
|
||||
#include "ED_scene.hh"
|
||||
#include "ED_transform.hh"
|
||||
|
||||
#include "ANIM_keyframing.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
namespace blender::animrig {
|
||||
|
||||
bool is_autokey_on(const Scene *scene)
|
||||
{
|
||||
if (scene) {
|
||||
return scene->toolsettings->autokey_mode & AUTOKEY_ON;
|
||||
}
|
||||
return U.autokey_mode & AUTOKEY_ON;
|
||||
}
|
||||
|
||||
bool is_autokey_mode(const Scene *scene, const eAutokey_Mode mode)
|
||||
{
|
||||
if (scene) {
|
||||
return scene->toolsettings->autokey_mode == mode;
|
||||
}
|
||||
return U.autokey_mode == mode;
|
||||
}
|
||||
|
||||
bool is_autokey_flag(const Scene *scene, const eAutokey_Flag flag)
|
||||
{
|
||||
if (scene) {
|
||||
return (scene->toolsettings->autokey_flag & flag) || (U.autokey_flag & flag);
|
||||
}
|
||||
return U.autokey_flag & flag;
|
||||
}
|
||||
|
||||
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
|
||||
{
|
||||
/* only filter if auto-key mode requires this */
|
||||
if (!is_autokey_on(scene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_autokey_mode(scene, AUTOKEY_MODE_EDITKEYS)) {
|
||||
/* Replace Mode:
|
||||
* For whole block, only key if there's a keyframe on that frame already
|
||||
* This is a valid assumption when we're blocking + tweaking
|
||||
*/
|
||||
const float cfra = BKE_scene_frame_get(scene);
|
||||
return id_frame_has_keyframe(id, cfra);
|
||||
}
|
||||
|
||||
/* Normal Mode (or treat as being normal mode):
|
||||
*
|
||||
* Just in case the flags aren't set properly (i.e. only on/off is set, without a mode)
|
||||
* let's set the "normal" flag too, so that it will all be sane everywhere...
|
||||
*/
|
||||
scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL;
|
||||
|
||||
/* Can insert anytime we like... */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-keyframing feature - for objects
|
||||
*
|
||||
* \param tmode: A transform mode.
|
||||
*
|
||||
* \note Context may not always be available,
|
||||
* so must check before using it as it's a luxury for a few cases.
|
||||
*/
|
||||
void autokeyframe_object(
|
||||
bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, const eTfmMode tmode)
|
||||
{
|
||||
/* TODO: this should probably be done per channel instead. */
|
||||
ID *id = &ob->id;
|
||||
if (!autokeyframe_cfra_can_key(scene, id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReportList *reports = CTX_wm_reports(C);
|
||||
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
|
||||
depsgraph, BKE_scene_frame_get(scene));
|
||||
eInsertKeyFlags flag = eInsertKeyFlags(0);
|
||||
|
||||
/* Get flags used for inserting keyframes. */
|
||||
flag = ANIM_get_keyframing_flags(scene, true);
|
||||
|
||||
/* Add data-source override for the object. */
|
||||
blender::Vector<PointerRNA> sources;
|
||||
ANIM_relative_keyingset_add_source(sources, id);
|
||||
|
||||
if (is_autokey_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && (active_ks)) {
|
||||
/* Only insert into active keyingset
|
||||
* NOTE: we assume here that the active Keying Set
|
||||
* does not need to have its iterator overridden.
|
||||
*/
|
||||
ANIM_apply_keyingset(
|
||||
C, &sources, active_ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
|
||||
}
|
||||
else if (is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAIL)) {
|
||||
AnimData *adt = ob->adt;
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
/* only key on available channels */
|
||||
if (adt && adt->action) {
|
||||
ListBase nla_cache = {nullptr, nullptr};
|
||||
LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
|
||||
insert_keyframe(bmain,
|
||||
reports,
|
||||
id,
|
||||
adt->action,
|
||||
(fcu->grp ? fcu->grp->name : nullptr),
|
||||
fcu->rna_path,
|
||||
fcu->array_index,
|
||||
&anim_eval_context,
|
||||
eBezTriple_KeyframeType(ts->keyframe_type),
|
||||
&nla_cache,
|
||||
flag);
|
||||
}
|
||||
|
||||
BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
|
||||
}
|
||||
}
|
||||
else if (is_autokey_flag(scene, AUTOKEY_FLAG_INSERTNEEDED)) {
|
||||
bool do_loc = false, do_rot = false, do_scale = false;
|
||||
|
||||
/* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
|
||||
if (tmode == TFM_TRANSLATION) {
|
||||
do_loc = true;
|
||||
}
|
||||
else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
|
||||
if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
if (ob != BKE_view_layer_active_object_get(view_layer)) {
|
||||
do_loc = true;
|
||||
}
|
||||
}
|
||||
else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
|
||||
do_loc = true;
|
||||
}
|
||||
|
||||
if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
|
||||
do_rot = true;
|
||||
}
|
||||
}
|
||||
else if (tmode == TFM_RESIZE) {
|
||||
if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
if (ob != BKE_view_layer_active_object_get(view_layer)) {
|
||||
do_loc = true;
|
||||
}
|
||||
}
|
||||
else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
|
||||
do_loc = true;
|
||||
}
|
||||
|
||||
if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
|
||||
do_scale = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert keyframes for the affected sets of channels using the builtin KeyingSets found */
|
||||
if (do_loc) {
|
||||
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_LOCATION_ID);
|
||||
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
|
||||
}
|
||||
if (do_rot) {
|
||||
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_ROTATION_ID);
|
||||
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
|
||||
}
|
||||
if (do_scale) {
|
||||
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_SCALING_ID);
|
||||
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
|
||||
}
|
||||
}
|
||||
/* insert keyframe in all (transform) channels */
|
||||
else {
|
||||
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_LOC_ROT_SCALE_ID);
|
||||
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
|
||||
}
|
||||
}
|
||||
|
||||
bool autokeyframe_object(bContext *C, Scene *scene, Object *ob, KeyingSet *ks)
|
||||
{
|
||||
/* auto keyframing */
|
||||
if (!autokeyframe_cfra_can_key(scene, &ob->id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Now insert the key-frame(s) using the Keying Set:
|
||||
* 1) Add data-source override for the Object.
|
||||
* 2) Insert key-frames.
|
||||
* 3) Free the extra info.
|
||||
*/
|
||||
blender::Vector<PointerRNA> sources;
|
||||
ANIM_relative_keyingset_add_source(sources, &ob->id);
|
||||
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, BKE_scene_frame_get(scene));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks)
|
||||
{
|
||||
if (autokeyframe_cfra_can_key(scene, &ob->id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Now insert the keyframe(s) using the Keying Set:
|
||||
* 1) Add data-source override for the pose-channel.
|
||||
* 2) Insert key-frames.
|
||||
* 3) Free the extra info.
|
||||
*/
|
||||
blender::Vector<PointerRNA> sources;
|
||||
ANIM_relative_keyingset_add_source(sources, &ob->id, &RNA_PoseBone, pchan);
|
||||
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, BKE_scene_frame_get(scene));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool autokeyframe_property(bContext *C,
|
||||
Scene *scene,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
const int rnaindex,
|
||||
const float cfra,
|
||||
const bool only_if_property_keyed)
|
||||
{
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
|
||||
cfra);
|
||||
bAction *action;
|
||||
bool driven;
|
||||
bool special;
|
||||
bool changed = false;
|
||||
|
||||
/* for entire array buttons we check the first component, it's not perfect
|
||||
* but works well enough in typical cases */
|
||||
const int rnaindex_check = (rnaindex == -1) ? 0 : rnaindex;
|
||||
FCurve *fcu = BKE_fcurve_find_by_rna_context_ui(
|
||||
C, ptr, prop, rnaindex_check, nullptr, &action, &driven, &special);
|
||||
|
||||
/* Only early out when we actually want an existing F-curve already
|
||||
* (e.g. auto-keyframing from buttons). */
|
||||
if (fcu == nullptr && (driven || special || only_if_property_keyed)) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
if (special) {
|
||||
/* NLA Strip property */
|
||||
if (is_autokey_on(scene)) {
|
||||
ReportList *reports = CTX_wm_reports(C);
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
|
||||
changed = insert_keyframe_direct(reports,
|
||||
*ptr,
|
||||
prop,
|
||||
fcu,
|
||||
&anim_eval_context,
|
||||
eBezTriple_KeyframeType(ts->keyframe_type),
|
||||
nullptr,
|
||||
eInsertKeyFlags(0));
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, nullptr);
|
||||
}
|
||||
}
|
||||
else if (driven) {
|
||||
/* Driver - Try to insert keyframe using the driver's input as the frame,
|
||||
* making it easier to set up corrective drivers
|
||||
*/
|
||||
if (is_autokey_on(scene)) {
|
||||
ReportList *reports = CTX_wm_reports(C);
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
|
||||
changed = insert_keyframe_direct(reports,
|
||||
*ptr,
|
||||
prop,
|
||||
fcu,
|
||||
&anim_eval_context,
|
||||
eBezTriple_KeyframeType(ts->keyframe_type),
|
||||
nullptr,
|
||||
INSERTKEY_DRIVER);
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, nullptr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ID *id = ptr->owner_id;
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
/* TODO: this should probably respect the keyingset only option for anim */
|
||||
if (autokeyframe_cfra_can_key(scene, id)) {
|
||||
ReportList *reports = CTX_wm_reports(C);
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
const eInsertKeyFlags flag = ANIM_get_keyframing_flags(scene, true);
|
||||
char *path = RNA_path_from_ID_to_property(ptr, prop);
|
||||
|
||||
if (only_if_property_keyed) {
|
||||
/* NOTE: We use rnaindex instead of fcu->array_index,
|
||||
* because a button may control all items of an array at once.
|
||||
* E.g., color wheels (see #42567). */
|
||||
BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
|
||||
}
|
||||
changed = insert_keyframe(bmain,
|
||||
reports,
|
||||
id,
|
||||
action,
|
||||
(fcu && fcu->grp) ? fcu->grp->name : nullptr,
|
||||
fcu ? fcu->rna_path : path,
|
||||
rnaindex,
|
||||
&anim_eval_context,
|
||||
eBezTriple_KeyframeType(ts->keyframe_type),
|
||||
nullptr,
|
||||
flag) != 0;
|
||||
if (path) {
|
||||
MEM_freeN(path);
|
||||
}
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, nullptr);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace blender::animrig
|
|
@ -122,7 +122,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk(eAssetLibraryType l
|
|||
std::string normalized_root_path = utils::normalize_directory_path(root_path);
|
||||
|
||||
std::unique_ptr<AssetLibrary> *lib_uptr_ptr = on_disk_libraries_.lookup_ptr(
|
||||
normalized_root_path);
|
||||
{library_type, normalized_root_path});
|
||||
if (lib_uptr_ptr != nullptr) {
|
||||
CLOG_INFO(&LOG, 2, "get \"%s\" (cached)", normalized_root_path.c_str());
|
||||
AssetLibrary *lib = lib_uptr_ptr->get();
|
||||
|
@ -139,7 +139,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk(eAssetLibraryType l
|
|||
/* Reload catalogs on refresh. */
|
||||
lib->on_refresh_ = [](AssetLibrary &self) { self.catalog_service->reload_catalogs(); };
|
||||
|
||||
on_disk_libraries_.add_new(normalized_root_path, std::move(lib_uptr));
|
||||
on_disk_libraries_.add_new({library_type, normalized_root_path}, std::move(lib_uptr));
|
||||
CLOG_INFO(&LOG, 2, "get \"%s\" (loaded)", normalized_root_path.c_str());
|
||||
return lib;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "AS_asset_library.hh"
|
||||
|
||||
|
@ -38,9 +39,12 @@ namespace blender::asset_system {
|
|||
class AssetLibraryService {
|
||||
static std::unique_ptr<AssetLibraryService> instance_;
|
||||
|
||||
/* Mapping absolute path of the library's root path (normalize with #normalize_directory_path()!)
|
||||
* the AssetLibrary instance. */
|
||||
Map<std::string, std::unique_ptr<AssetLibrary>> on_disk_libraries_;
|
||||
/** Identify libraries with the library type, and the absolute path of the library's root path
|
||||
* (normalize with #normalize_directory_path()!). The type is relevant since the current file
|
||||
* library may point to the same path as a custom library. */
|
||||
using OnDiskLibraryIdentifier = std::pair<eAssetLibraryType, std::string>;
|
||||
/* Mapping of a (type, root path) pair to the AssetLibrary instance. */
|
||||
Map<OnDiskLibraryIdentifier, std::unique_ptr<AssetLibrary>> on_disk_libraries_;
|
||||
/** Library without a known path, i.e. the "Current File" library if the file isn't saved yet. If
|
||||
* the file was saved, a valid path for the library can be determined and #on_disk_libraries_
|
||||
* above should be used. */
|
||||
|
|
|
@ -406,9 +406,15 @@ BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step(FontBLF *font,
|
|||
GlyphBLF *g = blf_glyph_ensure(font, gc, charcode);
|
||||
if (g && pen_x && !(font->flags & BLF_MONOSPACED)) {
|
||||
*pen_x += blf_kerning(font, g_prev, g);
|
||||
#ifndef BLF_SUBPIXEL_POSITION
|
||||
|
||||
#ifdef BLF_SUBPIXEL_POSITION
|
||||
if (!(font->flags & BLF_RENDER_SUBPIXELAA)) {
|
||||
*pen_x = FT_PIX_ROUND(*pen_x);
|
||||
}
|
||||
#else
|
||||
*pen_x = FT_PIX_ROUND(*pen_x);
|
||||
#endif
|
||||
|
||||
#ifdef BLF_SUBPIXEL_AA
|
||||
g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x);
|
||||
#endif
|
||||
|
@ -666,13 +672,34 @@ void blf_font_draw_buffer(FontBLF *font, const char *str, const size_t str_len,
|
|||
* - #BLF_width_to_rstrlen
|
||||
* \{ */
|
||||
|
||||
static bool blf_font_width_to_strlen_glyph_process(
|
||||
FontBLF *font, GlyphBLF *g_prev, GlyphBLF *g, ft_pix *pen_x, const int width_i)
|
||||
static bool blf_font_width_to_strlen_glyph_process(FontBLF *font,
|
||||
GlyphCacheBLF *gc,
|
||||
GlyphBLF *g_prev,
|
||||
GlyphBLF *g,
|
||||
ft_pix *pen_x,
|
||||
const int width_i)
|
||||
{
|
||||
if (UNLIKELY(g == nullptr)) {
|
||||
return false; /* continue the calling loop. */
|
||||
}
|
||||
*pen_x += blf_kerning(font, g_prev, g) + g->advance_x;
|
||||
|
||||
if (g && pen_x && !(font->flags & BLF_MONOSPACED)) {
|
||||
*pen_x += blf_kerning(font, g_prev, g);
|
||||
|
||||
#ifdef BLF_SUBPIXEL_POSITION
|
||||
if (!(font->flags & BLF_RENDER_SUBPIXELAA)) {
|
||||
*pen_x = FT_PIX_ROUND(*pen_x);
|
||||
}
|
||||
#else
|
||||
*pen_x = FT_PIX_ROUND(*pen_x);
|
||||
#endif
|
||||
|
||||
#ifdef BLF_SUBPIXEL_AA
|
||||
g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x);
|
||||
#endif
|
||||
}
|
||||
|
||||
*pen_x += g->advance_x;
|
||||
|
||||
/* When true, break the calling loop. */
|
||||
return (ft_pix_to_int(*pen_x) >= width_i);
|
||||
|
@ -693,7 +720,7 @@ size_t blf_font_width_to_strlen(
|
|||
i_prev = i, width_new = pen_x, g_prev = g)
|
||||
{
|
||||
g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i, nullptr);
|
||||
if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width_i)) {
|
||||
if (blf_font_width_to_strlen_glyph_process(font, gc, g_prev, g, &pen_x, width_i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -736,7 +763,7 @@ size_t blf_font_width_to_rstrlen(
|
|||
BLI_assert(i_tmp == i);
|
||||
}
|
||||
|
||||
if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width)) {
|
||||
if (blf_font_width_to_strlen_glyph_process(font, gc, g_prev, g, &pen_x, width)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1338,6 +1365,176 @@ static void blf_font_fill(FontBLF *font)
|
|||
font->buf_info.col_init[3] = 0;
|
||||
}
|
||||
|
||||
/* Note that the data the following function creates is not yet used.
|
||||
* But do not remove it as it will be used in the near future - Harley */
|
||||
static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
|
||||
{
|
||||
/* Members with non-zero defaults. */
|
||||
metrics->weight = 400;
|
||||
metrics->width = 1.0f;
|
||||
metrics->spacing = 1.0f;
|
||||
|
||||
TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
|
||||
if (os2_table) {
|
||||
/* The default (resting) font weight. */
|
||||
if (os2_table->usWeightClass >= 1 && os2_table->usWeightClass <= 1000) {
|
||||
metrics->weight = short(os2_table->usWeightClass);
|
||||
}
|
||||
|
||||
/* Width value is one of integers 1-9 with known values. */
|
||||
if (os2_table->usWidthClass >= 1 && os2_table->usWidthClass <= 9) {
|
||||
switch (os2_table->usWidthClass) {
|
||||
case 1:
|
||||
metrics->width = 0.5f;
|
||||
break;
|
||||
case 2:
|
||||
metrics->width = 0.625f;
|
||||
break;
|
||||
case 3:
|
||||
metrics->width = 0.75f;
|
||||
break;
|
||||
case 4:
|
||||
metrics->width = 0.875f;
|
||||
break;
|
||||
case 5:
|
||||
metrics->width = 1.0f;
|
||||
break;
|
||||
case 6:
|
||||
metrics->width = 1.125f;
|
||||
break;
|
||||
case 7:
|
||||
metrics->width = 1.25f;
|
||||
break;
|
||||
case 8:
|
||||
metrics->width = 1.5f;
|
||||
break;
|
||||
case 9:
|
||||
metrics->width = 2.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
metrics->strikeout_position = short(os2_table->yStrikeoutPosition);
|
||||
metrics->strikeout_thickness = short(os2_table->yStrikeoutSize);
|
||||
metrics->subscript_size = short(os2_table->ySubscriptYSize);
|
||||
metrics->subscript_xoffset = short(os2_table->ySubscriptXOffset);
|
||||
metrics->subscript_yoffset = short(os2_table->ySubscriptYOffset);
|
||||
metrics->superscript_size = short(os2_table->ySuperscriptYSize);
|
||||
metrics->superscript_xoffset = short(os2_table->ySuperscriptXOffset);
|
||||
metrics->superscript_yoffset = short(os2_table->ySuperscriptYOffset);
|
||||
metrics->family_class = short(os2_table->sFamilyClass);
|
||||
metrics->selection_flags = short(os2_table->fsSelection);
|
||||
metrics->first_charindex = short(os2_table->usFirstCharIndex);
|
||||
metrics->last_charindex = short(os2_table->usLastCharIndex);
|
||||
if (os2_table->version > 1) {
|
||||
metrics->cap_height = short(os2_table->sCapHeight);
|
||||
metrics->x_height = short(os2_table->sxHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/* The Post table usually contains a slant value, but in counter-clockwise degrees. */
|
||||
TT_Postscript *post_table = (TT_Postscript *)FT_Get_Sfnt_Table(face, FT_SFNT_POST);
|
||||
if (post_table) {
|
||||
if (post_table->italicAngle != 0) {
|
||||
metrics->slant = float(post_table->italicAngle) / -65536.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* Metrics copied from those gathered by FreeType. */
|
||||
metrics->units_per_EM = short(face->units_per_EM);
|
||||
metrics->ascender = short(face->ascender);
|
||||
metrics->descender = short(face->descender);
|
||||
metrics->line_height = short(face->height);
|
||||
metrics->max_advance_width = short(face->max_advance_width);
|
||||
metrics->max_advance_height = short(face->max_advance_height);
|
||||
metrics->underline_position = short(face->underline_position);
|
||||
metrics->underline_thickness = short(face->underline_thickness);
|
||||
metrics->num_glyphs = int(face->num_glyphs);
|
||||
metrics->bounding_box.xmin = int(face->bbox.xMin);
|
||||
metrics->bounding_box.xmax = int(face->bbox.xMax);
|
||||
metrics->bounding_box.ymin = int(face->bbox.yMin);
|
||||
metrics->bounding_box.ymax = int(face->bbox.yMax);
|
||||
|
||||
if (metrics->cap_height == 0) {
|
||||
/* Calculate or guess cap height if it is not set in the font. */
|
||||
FT_UInt gi = FT_Get_Char_Index(face, uint('H'));
|
||||
if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
|
||||
metrics->cap_height = short(face->glyph->metrics.height);
|
||||
}
|
||||
else {
|
||||
metrics->cap_height = short(float(metrics->units_per_EM) * 0.7f);
|
||||
}
|
||||
}
|
||||
|
||||
if (metrics->x_height == 0) {
|
||||
/* Calculate or guess x-height if it is not set in the font. */
|
||||
FT_UInt gi = FT_Get_Char_Index(face, uint('x'));
|
||||
if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
|
||||
metrics->x_height = short(face->glyph->metrics.height);
|
||||
}
|
||||
else {
|
||||
metrics->x_height = short(float(metrics->units_per_EM) * 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
FT_UInt gi = FT_Get_Char_Index(face, uint('o'));
|
||||
if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
|
||||
metrics->o_proportion = float(face->glyph->metrics.width) / float(face->glyph->metrics.height);
|
||||
}
|
||||
|
||||
if (metrics->ascender == 0) {
|
||||
/* Set a sane value for ascender if not set in the font. */
|
||||
metrics->ascender = short(float(metrics->units_per_EM) * 0.8f);
|
||||
}
|
||||
|
||||
if (metrics->descender == 0) {
|
||||
/* Set a sane value for descender if not set in the font. */
|
||||
metrics->descender = metrics->ascender - metrics->units_per_EM;
|
||||
}
|
||||
|
||||
if (metrics->weight == 400 && face->style_flags & FT_STYLE_FLAG_BOLD) {
|
||||
/* Normal weight yet this is an bold font, so set a sane weight value. */
|
||||
metrics->weight = 700;
|
||||
}
|
||||
|
||||
if (metrics->slant == 0.0f && face->style_flags & FT_STYLE_FLAG_ITALIC) {
|
||||
/* No slant yet this is an italic font, so set a sane slant value. */
|
||||
metrics->slant = 8.0f;
|
||||
}
|
||||
|
||||
if (metrics->underline_position == 0) {
|
||||
metrics->underline_position = short(float(metrics->units_per_EM) * -0.2f);
|
||||
}
|
||||
|
||||
if (metrics->underline_thickness == 0) {
|
||||
metrics->underline_thickness = short(float(metrics->units_per_EM) * 0.07f);
|
||||
}
|
||||
|
||||
if (metrics->strikeout_position == 0) {
|
||||
metrics->strikeout_position = short(float(metrics->x_height) * 0.6f);
|
||||
}
|
||||
|
||||
if (metrics->strikeout_thickness == 0) {
|
||||
metrics->strikeout_thickness = metrics->underline_thickness;
|
||||
}
|
||||
|
||||
if (metrics->subscript_size == 0) {
|
||||
metrics->subscript_size = short(float(metrics->units_per_EM) * 0.6f);
|
||||
}
|
||||
|
||||
if (metrics->subscript_yoffset == 0) {
|
||||
metrics->subscript_yoffset = short(float(metrics->units_per_EM) * 0.075f);
|
||||
}
|
||||
|
||||
if (metrics->superscript_size == 0) {
|
||||
metrics->superscript_size = short(float(metrics->units_per_EM) * 0.6f);
|
||||
}
|
||||
|
||||
if (metrics->superscript_yoffset == 0) {
|
||||
metrics->superscript_yoffset = short(float(metrics->units_per_EM) * 0.35f);
|
||||
}
|
||||
}
|
||||
|
||||
bool blf_ensure_face(FontBLF *font)
|
||||
{
|
||||
if (font->face) {
|
||||
|
@ -1425,6 +1622,9 @@ bool blf_ensure_face(FontBLF *font)
|
|||
FT_Get_MM_Var(font->face, &(font->variations));
|
||||
}
|
||||
|
||||
blf_ensure_size(font);
|
||||
blf_font_metrics(font->face, &font->metrics);
|
||||
|
||||
/* Save TrueType table with bits to quickly test most unicode block coverage. */
|
||||
TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
|
||||
if (os2_table) {
|
||||
|
|
|
@ -209,6 +209,75 @@ typedef struct FontBufInfoBLF {
|
|||
|
||||
} FontBufInfoBLF;
|
||||
|
||||
typedef struct FontMetrics {
|
||||
/** This font's default weight, 100-900, 400 is normal. */
|
||||
short weight;
|
||||
/** This font's default width, 1 is normal, 2 is twice as wide. */
|
||||
float width;
|
||||
/** This font's slant in clockwise degrees, 0 being upright. */
|
||||
float slant;
|
||||
/** This font's default spacing, 1 is normal. */
|
||||
float spacing;
|
||||
|
||||
/** Number of font units in an EM square. 2048, 1024, 1000 are typical. */
|
||||
short units_per_EM; /* */
|
||||
/** Design classification from OS/2 sFamilyClass. */
|
||||
short family_class;
|
||||
/** Style classification from OS/2 fsSelection. */
|
||||
short selection_flags;
|
||||
/** Total number of glyphs in the font. */
|
||||
int num_glyphs;
|
||||
/** Minimum Unicode index, typically 0x0020. */
|
||||
short first_charindex;
|
||||
/** Maximum Unicode index, or 0xFFFF if greater than. */
|
||||
short last_charindex;
|
||||
|
||||
/**
|
||||
* Bounds that can contain every glyph in the font when in default positions. Can be used for
|
||||
* maximum ascender, minimum descender. Can be out by a pixel when hinting. Does not change with
|
||||
* variation axis changes. */
|
||||
rcti bounding_box;
|
||||
/**
|
||||
* Positive number of font units from baseline to top of typical capitals. Can be slightly more
|
||||
* than cap height when head serifs, terminals, or apexes extend above cap line. */
|
||||
short ascender;
|
||||
/** Negative (!) number of font units from baseline to bottom of letters like `gjpqy`. */
|
||||
short descender;
|
||||
/** Positive number of font units between consecutive baselines. */
|
||||
short line_height;
|
||||
/** Font units from baseline to lowercase mean line, typically to top of "x". */
|
||||
short x_height;
|
||||
/** Font units from baseline to top of capital letters, specifically "H". */
|
||||
short cap_height;
|
||||
/** Ratio width to height of lowercase "O". Reliable indication of font proportion. */
|
||||
float o_proportion;
|
||||
/** Font unit maximum horizontal advance for all glyphs in font. Can help with wrapping. */
|
||||
short max_advance_width;
|
||||
/** As above but only for vertical layout fonts, otherwise is set to line_height value. */
|
||||
short max_advance_height;
|
||||
|
||||
/** Negative (!) number of font units below baseline to center (!) of underlining stem. */
|
||||
short underline_position;
|
||||
/** thickness of the underline in font units. */
|
||||
short underline_thickness;
|
||||
/** Positive number of font units above baseline to the top (!) of strikeout stroke. */
|
||||
short strikeout_position;
|
||||
/** thickness of the strikeout line in font units. */
|
||||
short strikeout_thickness;
|
||||
/** EM size font units of recommended subscript letters. */
|
||||
short subscript_size;
|
||||
/** Horizontal offset before first subscript character, typically 0. */
|
||||
short subscript_xoffset;
|
||||
/** Positive number of font units above baseline for subscript characters. */
|
||||
short subscript_yoffset;
|
||||
/** EM size font units of recommended superscript letters. */
|
||||
short superscript_size;
|
||||
/** Horizontal offset before first superscript character, typically 0. */
|
||||
short superscript_xoffset;
|
||||
/** Positive (!) number of font units below baseline for subscript characters. */
|
||||
short superscript_yoffset;
|
||||
} FontMetrics;
|
||||
|
||||
typedef struct FontBLF {
|
||||
/** Full path to font file or NULL if from memory. */
|
||||
char *filepath;
|
||||
|
@ -307,6 +376,9 @@ typedef struct FontBLF {
|
|||
/** Copy of the font->face->face_flags, in case we don't have a face loaded. */
|
||||
FT_Long face_flags;
|
||||
|
||||
/** Details about the font's design and style and sizes (in un-sized font units). */
|
||||
FontMetrics metrics;
|
||||
|
||||
/** Data for buffer usage (drawing into a texture buffer) */
|
||||
FontBufInfoBLF buf_info;
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ void BKE_keyingsets_foreach_id(struct LibraryForeachIDData *data,
|
|||
void BKE_keyingset_free_path(struct KeyingSet *ks, struct KS_Path *ksp);
|
||||
|
||||
/* Free data for KeyingSet but not set itself */
|
||||
void BKE_keyingset_free(struct KeyingSet *ks);
|
||||
void BKE_keyingset_free_paths(struct KeyingSet *ks);
|
||||
|
||||
/* Free all the KeyingSets in the given list */
|
||||
void BKE_keyingsets_free(struct ListBase *list);
|
||||
|
|
|
@ -29,6 +29,7 @@ class ComponentAttributeProviders;
|
|||
class CurvesEditHints;
|
||||
class Instances;
|
||||
class GeometryComponent;
|
||||
class GreasePencilEditHints;
|
||||
} // namespace blender::bke
|
||||
|
||||
namespace blender::bke {
|
||||
|
@ -228,6 +229,11 @@ struct GeometrySet {
|
|||
bool include_instances,
|
||||
AttributeForeachCallback callback) const;
|
||||
|
||||
static void propagate_attributes_from_layer_to_instances(
|
||||
const AttributeAccessor src_attributes,
|
||||
MutableAttributeAccessor dst_attributes,
|
||||
const AnonymousAttributePropagationInfo &propagation_info);
|
||||
|
||||
void gather_attributes_for_propagation(Span<GeometryComponent::Type> component_types,
|
||||
GeometryComponent::Type dst_component_type,
|
||||
bool include_instances,
|
||||
|
@ -668,6 +674,10 @@ class GeometryComponentEditData final : public GeometryComponent {
|
|||
* example, when the curves have been converted to a mesh.
|
||||
*/
|
||||
std::unique_ptr<CurvesEditHints> curves_edit_hints_;
|
||||
/**
|
||||
* Information about how drawings on the grease pencil layers are manipulated during evaluation.
|
||||
*/
|
||||
std::unique_ptr<GreasePencilEditHints> grease_pencil_edit_hints_;
|
||||
|
||||
GeometryComponentEditData();
|
||||
|
||||
|
@ -683,7 +693,7 @@ class GeometryComponentEditData final : public GeometryComponent {
|
|||
* lost, which would make curves sculpt mode fall back to using original curve positions instead
|
||||
* of deformed ones.
|
||||
*/
|
||||
static void remember_deformed_curve_positions_if_necessary(GeometrySet &geometry);
|
||||
static void remember_deformed_positions_if_necessary(GeometrySet &geometry);
|
||||
|
||||
static constexpr inline GeometryComponent::Type static_type = GeometryComponent::Type::Edit;
|
||||
};
|
||||
|
|
|
@ -666,6 +666,33 @@ class GreasePencilRuntime {
|
|||
~GreasePencilRuntime() {}
|
||||
};
|
||||
|
||||
class GreasePencilDrawingEditHints {
|
||||
public:
|
||||
std::optional<Array<float3>> positions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to propagate deformation data through modifier evaluation.
|
||||
*/
|
||||
class GreasePencilEditHints {
|
||||
public:
|
||||
/**
|
||||
* Original data that the edit hints below are meant to be used for.
|
||||
*/
|
||||
const GreasePencil &grease_pencil_id_orig;
|
||||
|
||||
GreasePencilEditHints(const GreasePencil &grease_pencil_id_orig)
|
||||
: grease_pencil_id_orig(grease_pencil_id_orig)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of #GreasePencilDrawingEditHints. There is one edit hint for each evaluated drawing.
|
||||
* Note: The index for each element is the layer index.
|
||||
*/
|
||||
std::optional<Array<GreasePencilDrawingEditHints>> drawing_hints;
|
||||
};
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
inline blender::bke::greasepencil::Drawing &GreasePencilDrawing::wrap()
|
||||
|
|
|
@ -362,17 +362,22 @@ typedef struct bNodeType {
|
|||
/* Execute a geometry node. */
|
||||
NodeGeometryExecFunction geometry_node_execute;
|
||||
|
||||
/* Declares which sockets the node has. */
|
||||
NodeDeclareFunction declare;
|
||||
/**
|
||||
* Declare which sockets the node has for declarations that aren't static per node type.
|
||||
* In other words, defining this callback means that different nodes of this type can have
|
||||
* different declarations and different sockets.
|
||||
* Declares which sockets and panels the node has. It has to be able to generate a declaration
|
||||
* with and without a specific node context. If the declaration depends on the node, but the node
|
||||
* is not provided, then the declaration should be generated as much as possible and everything
|
||||
* that depends on the node context should be skipped.
|
||||
*/
|
||||
NodeDeclareDynamicFunction declare_dynamic;
|
||||
NodeDeclareFunction declare;
|
||||
|
||||
/* Declaration to be used when it is not dynamic. */
|
||||
NodeDeclarationHandle *fixed_declaration;
|
||||
/**
|
||||
* Declaration of the node outside of any context. If the node declaration is never dependent on
|
||||
* the node context, this declaration is also shared with the corresponding node instances.
|
||||
* Otherwise, it mainly allows checking what sockets a node will have, without having to create
|
||||
* the node. In this case, the static declaration is mostly just a hint, and does not have to
|
||||
* match with the final node.
|
||||
*/
|
||||
NodeDeclarationHandle *static_declaration;
|
||||
|
||||
/**
|
||||
* Add to the list of search names and operations gathered by node link drag searching.
|
||||
|
|
|
@ -286,6 +286,12 @@ void nodeLabel(const bNodeTree *ntree, const bNode *node, char *label, int maxle
|
|||
*/
|
||||
const char *nodeSocketLabel(const bNodeSocket *sock);
|
||||
|
||||
/**
|
||||
* Get node socket short label if it is set.
|
||||
* It is used when grouping sockets under panels, to avoid redundancy in the label.
|
||||
*/
|
||||
const char *nodeSocketShortLabel(const bNodeSocket *sock);
|
||||
|
||||
/**
|
||||
* Initialize a new node type struct with default values and callbacks.
|
||||
*/
|
||||
|
|
|
@ -296,6 +296,9 @@ class bNodeRuntime : NonCopyable, NonMovable {
|
|||
/** Eagerly maintained cache of the node's index in the tree. */
|
||||
int index_in_tree = -1;
|
||||
|
||||
/** Used to avoid running forward compatibility code more often than necessary. */
|
||||
bool forward_compatible_versioning_done = false;
|
||||
|
||||
/** Only valid if #topology_cache_is_dirty is false. */
|
||||
Vector<bNodeSocket *> inputs;
|
||||
Vector<bNodeSocket *> outputs;
|
||||
|
|
|
@ -403,8 +403,12 @@ void BKE_pbvh_node_get_grids(PBVH *pbvh,
|
|||
int *maxgrid,
|
||||
int *gridsize,
|
||||
CCGElem ***r_griddata);
|
||||
void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int *r_totvert);
|
||||
blender::Span<int> BKE_pbvh_node_get_vert_indices(PBVHNode *node);
|
||||
void BKE_pbvh_node_num_verts(const PBVH *pbvh,
|
||||
const PBVHNode *node,
|
||||
int *r_uniquevert,
|
||||
int *r_totvert);
|
||||
blender::Span<int> BKE_pbvh_node_get_vert_indices(const PBVHNode *node);
|
||||
blender::Span<int> BKE_pbvh_node_get_unique_vert_indices(const PBVHNode *node);
|
||||
void BKE_pbvh_node_get_loops(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
const int **r_loop_indices,
|
||||
|
@ -691,22 +695,19 @@ bool BKE_pbvh_get_color_layer(Mesh *me, CustomDataLayer **r_layer, eAttrDomain *
|
|||
/* Swaps colors at each element in indices (of domain pbvh->vcol_domain)
|
||||
* with values in colors. */
|
||||
void BKE_pbvh_swap_colors(PBVH *pbvh,
|
||||
const int *indices,
|
||||
const int indices_num,
|
||||
float (*colors)[4]);
|
||||
blender::Span<int> indices,
|
||||
blender::MutableSpan<blender::float4> r_colors);
|
||||
|
||||
/* Stores colors from the elements in indices (of domain pbvh->vcol_domain)
|
||||
* into colors. */
|
||||
void BKE_pbvh_store_colors(PBVH *pbvh,
|
||||
const int *indices,
|
||||
const int indices_num,
|
||||
float (*colors)[4]);
|
||||
blender::Span<int> indices,
|
||||
blender::MutableSpan<blender::float4> r_colors);
|
||||
|
||||
/* Like BKE_pbvh_store_colors but handles loop->vert conversion */
|
||||
void BKE_pbvh_store_colors_vertex(PBVH *pbvh,
|
||||
const int *indices,
|
||||
const int indices_num,
|
||||
float (*colors)[4]);
|
||||
blender::Span<int> indices,
|
||||
blender::MutableSpan<blender::float4> r_colors);
|
||||
|
||||
bool BKE_pbvh_is_drawing(const PBVH *pbvh);
|
||||
|
||||
|
|
|
@ -18,21 +18,47 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Reporting Information and Errors
|
||||
/** Reporting Information and Errors.
|
||||
*
|
||||
* These functions also accept NULL in case no error reporting
|
||||
* is needed. */
|
||||
* These functions are thread-safe, unless otherwise specified.
|
||||
*
|
||||
* These functions also accept nullptr in case no error reporting is needed. The message are only
|
||||
* printed to the console then. */
|
||||
|
||||
/* Report structures are stored in DNA. */
|
||||
|
||||
/** Initialize a #ReportList struct.
|
||||
*
|
||||
* \note: Not thread-safe, should only be called from the 'owner' thread of the report list.
|
||||
*/
|
||||
void BKE_reports_init(ReportList *reports, int flag);
|
||||
/**
|
||||
* Only frees the list \a reports.
|
||||
* Fully release any internal resources used by this #ReportList, as acquired by #BKE_reports_init.
|
||||
*
|
||||
* Also calls #BKE_reports_clear. The given `reports` should not be used anymore unless it is
|
||||
* re-initialized first.
|
||||
*
|
||||
* \note: Not thread-safe, should only be called from the current owner of the report list, once
|
||||
* no other concurrent access is possible.
|
||||
*/
|
||||
void BKE_reports_free(ReportList *reports);
|
||||
|
||||
/**
|
||||
* Only frees the list of reports in given \a reports. Use #BKE_reports_free to fully cleanup all
|
||||
* allocated resources.
|
||||
*
|
||||
* To make displayed reports disappear, either remove window-manager reports
|
||||
* (#wmWindowManager.reports, or #CTX_wm_reports()), or use #WM_report_banners_cancel().
|
||||
*/
|
||||
void BKE_reports_clear(ReportList *reports);
|
||||
|
||||
/** Moves all reports from `reports_src` to `reports_dst`. */
|
||||
void BKE_reports_move_to_reports(ReportList *reports_dst, ReportList *reports_src);
|
||||
|
||||
/** (Un)lock given `reports`, in case external code needs to access its data. */
|
||||
void BKE_reports_lock(ReportList *reports);
|
||||
void BKE_reports_unlock(ReportList *reports);
|
||||
|
||||
void BKE_report(ReportList *reports, eReportType type, const char *message);
|
||||
void BKE_reportf(ReportList *reports, eReportType type, const char *format, ...)
|
||||
ATTR_PRINTF_FORMAT(3, 4);
|
||||
|
|
|
@ -433,6 +433,10 @@ enum class MenuTypeFlag {
|
|||
* dependent, menu search has to scan it in different contexts.
|
||||
*/
|
||||
ContextDependent = (1 << 0),
|
||||
/**
|
||||
* Automatically start searching in the menu when pressing a key.
|
||||
*/
|
||||
SearchOnKeyPress = (1 << 1),
|
||||
};
|
||||
ENUM_OPERATORS(MenuTypeFlag, MenuTypeFlag::ContextDependent)
|
||||
|
||||
|
|
|
@ -706,6 +706,15 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
|
||||
ASSERT_IS_VALID_MESH(mesh_final);
|
||||
}
|
||||
|
||||
if (mti->required_data_mask) {
|
||||
CustomData_MeshMasks mask{};
|
||||
mti->required_data_mask(md, &mask);
|
||||
if (mask.vmask & CD_MASK_ORCO) {
|
||||
add_orco_mesh(ob, nullptr, mesh_final, nullptr, CD_ORCO);
|
||||
}
|
||||
}
|
||||
|
||||
BKE_modifier_deform_verts(
|
||||
md,
|
||||
&mectx,
|
||||
|
|
|
@ -255,7 +255,7 @@ void BKE_keyingsets_foreach_id(LibraryForeachIDData *data, const ListBase *keyin
|
|||
|
||||
/* Freeing Tools --------------------------- */
|
||||
|
||||
void BKE_keyingset_free(KeyingSet *ks)
|
||||
void BKE_keyingset_free_paths(KeyingSet *ks)
|
||||
{
|
||||
KS_Path *ksp, *kspn;
|
||||
|
||||
|
@ -281,11 +281,11 @@ void BKE_keyingsets_free(ListBase *list)
|
|||
}
|
||||
|
||||
/* loop over KeyingSets freeing them
|
||||
* - BKE_keyingset_free() doesn't free the set itself, but it frees its sub-data
|
||||
* - BKE_keyingset_free_paths() doesn't free the set itself, but it frees its sub-data
|
||||
*/
|
||||
for (ks = static_cast<KeyingSet *>(list->first); ks; ks = ksn) {
|
||||
ksn = ks->next;
|
||||
BKE_keyingset_free(ks);
|
||||
BKE_keyingset_free_paths(ks);
|
||||
BLI_freelinkN(list, ks);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -670,34 +670,73 @@ GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
|||
|
||||
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval,
|
||||
const Object &ob_orig,
|
||||
const int drawing_index)
|
||||
const int layer_index)
|
||||
{
|
||||
BLI_assert(ob_orig.type == OB_GREASE_PENCIL);
|
||||
const GreasePencil &grease_pencil = *static_cast<const GreasePencil *>(ob_eval->data);
|
||||
const GreasePencil &grease_pencil_orig = *static_cast<const GreasePencil *>(ob_orig.data);
|
||||
|
||||
const int eval_frame = grease_pencil.runtime->eval_frame;
|
||||
const int drawing_index = grease_pencil_orig.layers()[layer_index]->drawing_index_at(eval_frame);
|
||||
if (drawing_index == -1) {
|
||||
return {};
|
||||
}
|
||||
const GreasePencilDrawingBase *drawing_base = grease_pencil_orig.drawing(drawing_index);
|
||||
if (drawing_base->type != GP_DRAWING) {
|
||||
return {};
|
||||
}
|
||||
const bke::greasepencil::Drawing &drawing_orig =
|
||||
reinterpret_cast<const GreasePencilDrawing *>(drawing_base)->wrap();
|
||||
|
||||
GeometryDeformation deformation;
|
||||
if (drawing_base->type == GP_DRAWING) {
|
||||
const auto *drawing = reinterpret_cast<const GreasePencilDrawing *>(drawing_base);
|
||||
/* Use the undeformed positions by default. */
|
||||
deformation.positions = drawing->wrap().strokes().positions();
|
||||
}
|
||||
else if (drawing_base->type == GP_DRAWING_REFERENCE) {
|
||||
/* TODO */
|
||||
}
|
||||
/* Use the undeformed positions by default. */
|
||||
deformation.positions = drawing_orig.strokes().positions();
|
||||
|
||||
if (ob_eval == nullptr) {
|
||||
return deformation;
|
||||
}
|
||||
const GeometrySet *geometry_eval = ob_eval->runtime.geometry_set_eval;
|
||||
if (geometry_eval == nullptr) {
|
||||
if (geometry_eval == nullptr || !geometry_eval->has<GeometryComponentEditData>()) {
|
||||
return deformation;
|
||||
}
|
||||
|
||||
/* TODO: Read `GeometryComponentEditData` from `geometry_eval` and populate deformation with it.
|
||||
*/
|
||||
/* If there are edit hints, use the positions of those. */
|
||||
const GeometryComponentEditData &edit_component_eval =
|
||||
*geometry_eval->get_component<GeometryComponentEditData>();
|
||||
const GreasePencilEditHints *edit_hints = edit_component_eval.grease_pencil_edit_hints_.get();
|
||||
if (edit_hints != nullptr && &edit_hints->grease_pencil_id_orig == &grease_pencil_orig &&
|
||||
edit_hints->drawing_hints.has_value())
|
||||
{
|
||||
BLI_assert(edit_hints->drawing_hints->size() == grease_pencil_orig.layers().size());
|
||||
const GreasePencilDrawingEditHints &drawing_hints =
|
||||
edit_hints->drawing_hints.value()[layer_index];
|
||||
if (drawing_hints.positions.has_value()) {
|
||||
deformation.positions = *drawing_hints.positions;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise use the positions of the evaluated drawing if the number of points match. */
|
||||
if (const GreasePencilComponent *grease_pencil_component_eval =
|
||||
geometry_eval->get_component<GreasePencilComponent>())
|
||||
{
|
||||
if (const GreasePencil *grease_pencil_eval = grease_pencil_component_eval->get()) {
|
||||
Span<const bke::greasepencil::Layer *> layers_eval = grease_pencil_eval->layers();
|
||||
const bke::greasepencil::Layer *layer_eval = layers_eval[layer_index];
|
||||
const int drawing_index_eval = layer_eval->drawing_index_at(eval_frame);
|
||||
if (drawing_index_eval != -1) {
|
||||
const GreasePencilDrawingBase *drawing_base_eval = grease_pencil_eval->drawing(
|
||||
drawing_index_eval);
|
||||
if (drawing_base_eval->type != GP_DRAWING) {
|
||||
return {};
|
||||
}
|
||||
const bke::greasepencil::Drawing &drawing_eval =
|
||||
reinterpret_cast<const GreasePencilDrawing *>(drawing_base_eval)->wrap();
|
||||
if (drawing_eval.strokes().points_num() == drawing_orig.strokes().points_num()) {
|
||||
deformation.positions = drawing_eval.strokes().positions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return deformation;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
|
@ -15,6 +16,10 @@ GeometryComponent *GeometryComponentEditData::copy() const
|
|||
if (curves_edit_hints_) {
|
||||
new_component->curves_edit_hints_ = std::make_unique<CurvesEditHints>(*curves_edit_hints_);
|
||||
}
|
||||
if (grease_pencil_edit_hints_) {
|
||||
new_component->grease_pencil_edit_hints_ = std::make_unique<GreasePencilEditHints>(
|
||||
*grease_pencil_edit_hints_);
|
||||
}
|
||||
return new_component;
|
||||
}
|
||||
|
||||
|
@ -32,24 +37,18 @@ void GeometryComponentEditData::clear()
|
|||
{
|
||||
BLI_assert(this->is_mutable() || this->is_expired());
|
||||
curves_edit_hints_.reset();
|
||||
grease_pencil_edit_hints_.reset();
|
||||
}
|
||||
|
||||
void GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(
|
||||
GeometrySet &geometry)
|
||||
static void remember_deformed_curve_positions_if_necessary(
|
||||
const Curves *curves_id, GeometryComponentEditData &edit_component)
|
||||
{
|
||||
/* This component should be created at the start of object evaluation if it's necessary. */
|
||||
if (!geometry.has<GeometryComponentEditData>()) {
|
||||
return;
|
||||
}
|
||||
GeometryComponentEditData &edit_component =
|
||||
geometry.get_component_for_write<GeometryComponentEditData>();
|
||||
if (!edit_component.curves_edit_hints_) {
|
||||
return;
|
||||
}
|
||||
if (edit_component.curves_edit_hints_->positions.has_value()) {
|
||||
return;
|
||||
}
|
||||
const Curves *curves_id = geometry.get_curves();
|
||||
if (curves_id == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
@ -62,4 +61,57 @@ void GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(
|
|||
edit_component.curves_edit_hints_->positions->as_mutable_span().copy_from(curves.positions());
|
||||
}
|
||||
|
||||
static void remember_deformed_grease_pencil_if_necessary(const GreasePencil *grease_pencil,
|
||||
GeometryComponentEditData &edit_component)
|
||||
{
|
||||
if (!edit_component.grease_pencil_edit_hints_) {
|
||||
return;
|
||||
}
|
||||
if (edit_component.grease_pencil_edit_hints_->drawing_hints.has_value()) {
|
||||
return;
|
||||
}
|
||||
if (grease_pencil == nullptr) {
|
||||
return;
|
||||
}
|
||||
const GreasePencil &orig_grease_pencil =
|
||||
edit_component.grease_pencil_edit_hints_->grease_pencil_id_orig;
|
||||
const Span<const bke::greasepencil::Layer *> layers = grease_pencil->layers();
|
||||
const Span<const bke::greasepencil::Layer *> orig_layers = orig_grease_pencil.layers();
|
||||
const int layers_num = layers.size();
|
||||
if (layers_num != orig_layers.size()) {
|
||||
return;
|
||||
}
|
||||
edit_component.grease_pencil_edit_hints_->drawing_hints.emplace(layers_num);
|
||||
MutableSpan<GreasePencilDrawingEditHints> all_hints =
|
||||
*edit_component.grease_pencil_edit_hints_->drawing_hints;
|
||||
for (const int layer_index : layers.index_range()) {
|
||||
const bke::greasepencil::Drawing *drawing = greasepencil::get_eval_grease_pencil_layer_drawing(
|
||||
*grease_pencil, layer_index);
|
||||
const bke::greasepencil::Layer &orig_layer = *orig_layers[layer_index];
|
||||
const bke::greasepencil::Drawing *orig_drawing = orig_grease_pencil.get_drawing_at(
|
||||
&orig_layer, grease_pencil->runtime->eval_frame);
|
||||
GreasePencilDrawingEditHints &drawing_hints = all_hints[layer_index];
|
||||
|
||||
if (!drawing || !orig_drawing) {
|
||||
continue;
|
||||
}
|
||||
if (drawing->strokes().points_num() != orig_drawing->strokes().points_num()) {
|
||||
continue;
|
||||
}
|
||||
drawing_hints.positions->as_mutable_span().copy_from(drawing->strokes().positions());
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryComponentEditData::remember_deformed_positions_if_necessary(GeometrySet &geometry)
|
||||
{
|
||||
/* This component should be created at the start of object evaluation if it's necessary. */
|
||||
if (!geometry.has<GeometryComponentEditData>()) {
|
||||
return;
|
||||
}
|
||||
GeometryComponentEditData &edit_component =
|
||||
geometry.get_component_for_write<GeometryComponentEditData>();
|
||||
remember_deformed_curve_positions_if_necessary(geometry.get_curves(), edit_component);
|
||||
remember_deformed_grease_pencil_if_necessary(geometry.get_grease_pencil(), edit_component);
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
|
|
@ -303,7 +303,7 @@ GVArray CurvesFieldInput::get_varray_for_context(const fn::FieldContext &context
|
|||
if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
|
||||
&context))
|
||||
{
|
||||
if (const CurvesGeometry *curves = geometry_context->curves()) {
|
||||
if (const CurvesGeometry *curves = geometry_context->curves_or_strokes()) {
|
||||
return this->get_varray_for_context(*curves, geometry_context->domain(), mask);
|
||||
}
|
||||
}
|
||||
|
@ -529,7 +529,7 @@ GVArray NormalFieldInput::get_varray_for_context(const GeometryFieldContext &con
|
|||
if (const Mesh *mesh = context.mesh()) {
|
||||
return mesh_normals_varray(*mesh, mask, context.domain());
|
||||
}
|
||||
if (const CurvesGeometry *curves = context.curves()) {
|
||||
if (const CurvesGeometry *curves = context.curves_or_strokes()) {
|
||||
return curve_normals_varray(*curves, context.domain());
|
||||
}
|
||||
return {};
|
||||
|
|
|
@ -605,6 +605,33 @@ void GeometrySet::attribute_foreach(const Span<GeometryComponent::Type> componen
|
|||
}
|
||||
}
|
||||
|
||||
void GeometrySet::propagate_attributes_from_layer_to_instances(
|
||||
const AttributeAccessor src_attributes,
|
||||
MutableAttributeAccessor dst_attributes,
|
||||
const AnonymousAttributePropagationInfo &propagation_info)
|
||||
{
|
||||
src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
||||
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
|
||||
return true;
|
||||
}
|
||||
const GAttributeReader src = src_attributes.lookup(id, ATTR_DOMAIN_LAYER);
|
||||
if (src.sharing_info && src.varray.is_span()) {
|
||||
const AttributeInitShared init(src.varray.get_internal_span().data(), *src.sharing_info);
|
||||
if (dst_attributes.add(id, ATTR_DOMAIN_INSTANCE, meta_data.data_type, init)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
id, ATTR_DOMAIN_INSTANCE, meta_data.data_type);
|
||||
if (!dst) {
|
||||
return true;
|
||||
}
|
||||
array_utils::copy(src.varray, dst.span);
|
||||
dst.finish();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void GeometrySet::gather_attributes_for_propagation(
|
||||
const Span<GeometryComponent::Type> component_types,
|
||||
const GeometryComponent::Type dst_component_type,
|
||||
|
|
|
@ -1183,6 +1183,14 @@ void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
|
|||
grease_pencil->runtime->eval_frame = int(DEG_get_ctime(depsgraph));
|
||||
GeometrySet geometry_set = GeometrySet::from_grease_pencil(grease_pencil,
|
||||
GeometryOwnershipType::ReadOnly);
|
||||
/* Only add the edit hint component in edit mode for now so users can properly select deformed
|
||||
* drawings. */
|
||||
if (object->mode == OB_MODE_EDIT) {
|
||||
GeometryComponentEditData &edit_component =
|
||||
geometry_set.get_component_for_write<GeometryComponentEditData>();
|
||||
edit_component.grease_pencil_edit_hints_ = std::make_unique<GreasePencilEditHints>(
|
||||
*static_cast<const GreasePencil *>(DEG_get_original_object(object)->data));
|
||||
}
|
||||
grease_pencil_evaluate_modifiers(depsgraph, scene, object, geometry_set);
|
||||
|
||||
if (!geometry_set.has_grease_pencil()) {
|
||||
|
@ -1760,57 +1768,18 @@ enum ForeachDrawingMode {
|
|||
EDITABLE,
|
||||
};
|
||||
|
||||
static void foreach_drawing_ex(
|
||||
GreasePencil &grease_pencil,
|
||||
const int frame,
|
||||
const ForeachDrawingMode mode,
|
||||
blender::FunctionRef<void(int, blender::bke::greasepencil::Drawing &)> function)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
blender::Span<GreasePencilDrawingBase *> drawings = grease_pencil.drawings();
|
||||
for (const Layer *layer : grease_pencil.layers()) {
|
||||
switch (mode) {
|
||||
case VISIBLE: {
|
||||
if (!layer->is_visible()) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EDITABLE: {
|
||||
if (!layer->is_editable()) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int index = layer->drawing_index_at(frame);
|
||||
if (index == -1) {
|
||||
continue;
|
||||
}
|
||||
GreasePencilDrawingBase *drawing_base = drawings[index];
|
||||
if (drawing_base->type == GP_DRAWING) {
|
||||
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
|
||||
function(index, drawing->wrap());
|
||||
}
|
||||
else if (drawing_base->type == GP_DRAWING_REFERENCE) {
|
||||
/* TODO: Drawing references are not implemented yet. */
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void foreach_drawing_ex(
|
||||
const GreasePencil &grease_pencil,
|
||||
const int frame,
|
||||
const ForeachDrawingMode mode,
|
||||
blender::FunctionRef<void(int, const blender::bke::greasepencil::Drawing &)> function)
|
||||
blender::FunctionRef<void(const int, const blender::bke::greasepencil::Drawing &)> function)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
blender::Span<const GreasePencilDrawingBase *> drawings = grease_pencil.drawings();
|
||||
for (const Layer *layer : grease_pencil.layers()) {
|
||||
blender::Span<const Layer *> layers = grease_pencil.layers();
|
||||
for (const int layer_i : layers.index_range()) {
|
||||
const Layer *layer = layers[layer_i];
|
||||
switch (mode) {
|
||||
case VISIBLE: {
|
||||
if (!layer->is_visible()) {
|
||||
|
@ -1834,7 +1803,7 @@ static void foreach_drawing_ex(
|
|||
if (drawing_base->type == GP_DRAWING) {
|
||||
const GreasePencilDrawing *drawing = reinterpret_cast<const GreasePencilDrawing *>(
|
||||
drawing_base);
|
||||
function(index, drawing->wrap());
|
||||
function(layer_i, drawing->wrap());
|
||||
}
|
||||
else if (drawing_base->type == GP_DRAWING_REFERENCE) {
|
||||
/* TODO: Drawing references are not implemented yet. */
|
||||
|
@ -1845,23 +1814,38 @@ static void foreach_drawing_ex(
|
|||
|
||||
void GreasePencil::foreach_visible_drawing(
|
||||
const int frame,
|
||||
blender::FunctionRef<void(int, blender::bke::greasepencil::Drawing &)> function)
|
||||
blender::FunctionRef<void(const int, blender::bke::greasepencil::Drawing &)> function)
|
||||
{
|
||||
foreach_drawing_ex(*this, frame, VISIBLE, function);
|
||||
foreach_drawing_ex(
|
||||
*this,
|
||||
frame,
|
||||
VISIBLE,
|
||||
[&](const int layer_index, const blender::bke::greasepencil::Drawing &drawing) {
|
||||
/* We const_cast here to be able to implement `foreach_drawing_ex` only once. */
|
||||
function(layer_index, const_cast<blender::bke::greasepencil::Drawing &>(drawing));
|
||||
});
|
||||
}
|
||||
|
||||
void GreasePencil::foreach_visible_drawing(
|
||||
const int frame,
|
||||
blender::FunctionRef<void(int, const blender::bke::greasepencil::Drawing &)> function) const
|
||||
blender::FunctionRef<void(const int, const blender::bke::greasepencil::Drawing &)> function)
|
||||
const
|
||||
{
|
||||
foreach_drawing_ex(*this, frame, VISIBLE, function);
|
||||
}
|
||||
|
||||
void GreasePencil::foreach_editable_drawing(
|
||||
const int frame,
|
||||
blender::FunctionRef<void(int, blender::bke::greasepencil::Drawing &)> function)
|
||||
blender::FunctionRef<void(const int, blender::bke::greasepencil::Drawing &)> function)
|
||||
{
|
||||
foreach_drawing_ex(*this, frame, EDITABLE, function);
|
||||
foreach_drawing_ex(
|
||||
*this,
|
||||
frame,
|
||||
EDITABLE,
|
||||
[&](const int layer_index, const blender::bke::greasepencil::Drawing &drawing) {
|
||||
/* We const_cast here to be able to implement `foreach_drawing_ex` only once. */
|
||||
function(layer_index, const_cast<blender::bke::greasepencil::Drawing &>(drawing));
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<blender::Bounds<blender::float3>> GreasePencil::bounds_min_max() const
|
||||
|
@ -1870,7 +1854,7 @@ std::optional<blender::Bounds<blender::float3>> GreasePencil::bounds_min_max() c
|
|||
std::optional<Bounds<float3>> bounds;
|
||||
this->foreach_visible_drawing(
|
||||
this->runtime->eval_frame,
|
||||
[&](int /*drawing_index*/, const bke::greasepencil::Drawing &drawing) {
|
||||
[&](const int /*layer_index*/, const bke::greasepencil::Drawing &drawing) {
|
||||
const bke::CurvesGeometry &curves = drawing.strokes();
|
||||
bounds = bounds::merge(bounds, curves.bounds_min_max());
|
||||
});
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "NOD_common.h"
|
||||
#include "NOD_composite.h"
|
||||
#include "NOD_composite.hh"
|
||||
#include "NOD_geometry.hh"
|
||||
#include "NOD_geometry_nodes_lazy_function.hh"
|
||||
#include "NOD_node_declaration.hh"
|
||||
|
@ -1153,7 +1153,7 @@ namespace blender::bke {
|
|||
|
||||
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
|
||||
{
|
||||
if (ntype->declare || ntype->declare_dynamic) {
|
||||
if (ntype->declare) {
|
||||
node_verify_sockets(ntree, node, true);
|
||||
return;
|
||||
}
|
||||
|
@ -1455,8 +1455,8 @@ static void node_free_type(void *nodetype_v)
|
|||
* or we'd want to update *all* active Mains, which we cannot do anyway currently. */
|
||||
blender::bke::update_typeinfo(G_MAIN, nullptr, nullptr, nodetype, nullptr, true);
|
||||
|
||||
delete nodetype->fixed_declaration;
|
||||
nodetype->fixed_declaration = nullptr;
|
||||
delete nodetype->static_declaration;
|
||||
nodetype->static_declaration = nullptr;
|
||||
|
||||
/* Can be null when the type is not dynamically allocated. */
|
||||
if (nodetype->free_self) {
|
||||
|
@ -1470,11 +1470,9 @@ void nodeRegisterType(bNodeType *nt)
|
|||
BLI_assert(nt->idname[0] != '\0');
|
||||
BLI_assert(nt->poll != nullptr);
|
||||
|
||||
if (nt->declare && !nt->declare_dynamic) {
|
||||
if (nt->fixed_declaration == nullptr) {
|
||||
nt->fixed_declaration = new blender::nodes::NodeDeclaration();
|
||||
blender::nodes::build_node_declaration(*nt, *nt->fixed_declaration);
|
||||
}
|
||||
if (nt->declare) {
|
||||
nt->static_declaration = new blender::nodes::NodeDeclaration();
|
||||
blender::nodes::build_node_declaration(*nt, *nt->static_declaration, nullptr, nullptr);
|
||||
}
|
||||
|
||||
BLI_ghash_insert(blender::bke::nodetypes_hash, nt->idname, nt);
|
||||
|
@ -3268,8 +3266,12 @@ void node_free_node(bNodeTree *ntree, bNode *node)
|
|||
MEM_freeN(node->prop);
|
||||
}
|
||||
|
||||
if (node->typeinfo->declare_dynamic) {
|
||||
delete node->runtime->declaration;
|
||||
if (node->runtime->declaration) {
|
||||
/* Only free if this declaration is not shared with the node type, which can happen if it does
|
||||
* not depend on any context. */
|
||||
if (node->runtime->declaration != node->typeinfo->static_declaration) {
|
||||
delete node->runtime->declaration;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_delete(node->runtime);
|
||||
|
@ -3734,18 +3736,20 @@ bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *ntree, bNode *node)
|
|||
if (node->runtime->declaration != nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (node->typeinfo->declare_dynamic) {
|
||||
if (node->typeinfo->declare) {
|
||||
if (node->typeinfo->static_declaration) {
|
||||
if (!node->typeinfo->static_declaration->is_context_dependent) {
|
||||
node->runtime->declaration = node->typeinfo->static_declaration;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node->typeinfo->declare) {
|
||||
BLI_assert(ntree != nullptr);
|
||||
BLI_assert(node != nullptr);
|
||||
blender::nodes::update_node_declaration_and_sockets(*ntree, *node);
|
||||
return true;
|
||||
}
|
||||
if (node->typeinfo->declare) {
|
||||
/* Declaration should have been created in #nodeRegisterType. */
|
||||
BLI_assert(node->typeinfo->fixed_declaration != nullptr);
|
||||
node->runtime->declaration = node->typeinfo->fixed_declaration;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4002,6 +4006,17 @@ void nodeLabel(const bNodeTree *ntree, const bNode *node, char *label, const int
|
|||
BLI_strncpy(label, IFACE_(node->typeinfo->ui_name), label_maxncpy);
|
||||
}
|
||||
|
||||
const char *nodeSocketShortLabel(const bNodeSocket *sock)
|
||||
{
|
||||
if (sock->runtime->declaration != nullptr) {
|
||||
blender::StringRefNull short_label = sock->runtime->declaration->short_label;
|
||||
if (!short_label.is_empty()) {
|
||||
return sock->runtime->declaration->short_label.data();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *nodeSocketLabel(const bNodeSocket *sock)
|
||||
{
|
||||
return (sock->label[0] != '\0') ? sock->label : sock->name;
|
||||
|
|
|
@ -563,8 +563,12 @@ class NodeTreeMainUpdater {
|
|||
if (ntype.updatefunc) {
|
||||
ntype.updatefunc(&ntree, node);
|
||||
}
|
||||
if (ntype.declare_dynamic) {
|
||||
nodes::update_node_declaration_and_sockets(ntree, *node);
|
||||
if (ntype.declare) {
|
||||
/* Should have been created when the node was registered. */
|
||||
BLI_assert(ntype.static_declaration != nullptr);
|
||||
if (ntype.static_declaration->is_context_dependent) {
|
||||
nodes::update_node_declaration_and_sockets(ntree, *node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1958,12 +1958,20 @@ int BKE_pbvh_num_faces(const PBVH *pbvh)
|
|||
return 0;
|
||||
}
|
||||
|
||||
blender::Span<int> BKE_pbvh_node_get_vert_indices(PBVHNode *node)
|
||||
blender::Span<int> BKE_pbvh_node_get_vert_indices(const PBVHNode *node)
|
||||
{
|
||||
return node->vert_indices;
|
||||
}
|
||||
|
||||
void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int *r_totvert)
|
||||
blender::Span<int> BKE_pbvh_node_get_unique_vert_indices(const PBVHNode *node)
|
||||
{
|
||||
return node->vert_indices.as_span().take_front(node->uniq_verts);
|
||||
}
|
||||
|
||||
void BKE_pbvh_node_num_verts(const PBVH *pbvh,
|
||||
const PBVHNode *node,
|
||||
int *r_uniquevert,
|
||||
int *r_totvert)
|
||||
{
|
||||
int tot;
|
||||
|
||||
|
|
|
@ -161,14 +161,13 @@ void BKE_pbvh_vertex_color_set(PBVH *pbvh, PBVHVertRef vertex, const float color
|
|||
}
|
||||
|
||||
void BKE_pbvh_swap_colors(PBVH *pbvh,
|
||||
const int *indices,
|
||||
const int indices_num,
|
||||
float (*r_colors)[4])
|
||||
const blender::Span<int> indices,
|
||||
blender::MutableSpan<blender::float4> r_colors)
|
||||
{
|
||||
blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
T *pbvh_colors = static_cast<T *>(pbvh->color_layer->data);
|
||||
for (const int i : IndexRange(indices_num)) {
|
||||
for (const int i : indices.index_range()) {
|
||||
T temp = pbvh_colors[indices[i]];
|
||||
blender::bke::from_float(r_colors[i], pbvh_colors[indices[i]]);
|
||||
blender::bke::to_float(temp, r_colors[i]);
|
||||
|
@ -177,31 +176,29 @@ void BKE_pbvh_swap_colors(PBVH *pbvh,
|
|||
}
|
||||
|
||||
void BKE_pbvh_store_colors(PBVH *pbvh,
|
||||
const int *indices,
|
||||
const int indices_num,
|
||||
float (*r_colors)[4])
|
||||
const blender::Span<int> indices,
|
||||
blender::MutableSpan<blender::float4> r_colors)
|
||||
{
|
||||
blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
T *pbvh_colors = static_cast<T *>(pbvh->color_layer->data);
|
||||
for (const int i : IndexRange(indices_num)) {
|
||||
for (const int i : indices.index_range()) {
|
||||
blender::bke::to_float(pbvh_colors[indices[i]], r_colors[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BKE_pbvh_store_colors_vertex(PBVH *pbvh,
|
||||
const int *indices,
|
||||
const int indices_num,
|
||||
float (*r_colors)[4])
|
||||
const blender::Span<int> indices,
|
||||
blender::MutableSpan<blender::float4> r_colors)
|
||||
{
|
||||
if (pbvh->color_domain == ATTR_DOMAIN_POINT) {
|
||||
BKE_pbvh_store_colors(pbvh, indices, indices_num, r_colors);
|
||||
BKE_pbvh_store_colors(pbvh, indices, r_colors);
|
||||
}
|
||||
else {
|
||||
blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
for (const int i : IndexRange(indices_num)) {
|
||||
for (const int i : indices.index_range()) {
|
||||
blender::bke::pbvh_vertex_color_get<T>(*pbvh, BKE_pbvh_make_vref(indices[i]), r_colors[i]);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_dynstr.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string_utils.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
|
@ -60,6 +62,20 @@ void BKE_reports_init(ReportList *reports, int flag)
|
|||
reports->storelevel = RPT_INFO;
|
||||
reports->printlevel = RPT_ERROR;
|
||||
reports->flag = flag;
|
||||
|
||||
reports->lock = MEM_new<std::mutex>(__func__);
|
||||
}
|
||||
|
||||
void BKE_reports_free(ReportList *reports)
|
||||
{
|
||||
if (!reports) {
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_reports_clear(reports);
|
||||
|
||||
MEM_delete(reports->lock);
|
||||
reports->lock = nullptr;
|
||||
}
|
||||
|
||||
void BKE_reports_clear(ReportList *reports)
|
||||
|
@ -70,6 +86,8 @@ void BKE_reports_clear(ReportList *reports)
|
|||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(*reports->lock);
|
||||
|
||||
report = static_cast<Report *>(reports->list.first);
|
||||
|
||||
while (report) {
|
||||
|
@ -82,6 +100,28 @@ void BKE_reports_clear(ReportList *reports)
|
|||
BLI_listbase_clear(&reports->list);
|
||||
}
|
||||
|
||||
void BKE_reports_lock(ReportList *reports)
|
||||
{
|
||||
reports->lock->lock();
|
||||
}
|
||||
|
||||
void BKE_reports_unlock(ReportList *reports)
|
||||
{
|
||||
reports->lock->unlock();
|
||||
}
|
||||
|
||||
void BKE_reports_move_to_reports(ReportList *reports_dst, ReportList *reports_src)
|
||||
{
|
||||
BLI_assert(reports_dst);
|
||||
if (!reports_src) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(*reports_src->lock, *reports_dst->lock);
|
||||
|
||||
BLI_movelisttolist(&reports_dst->list, &reports_src->list);
|
||||
}
|
||||
|
||||
void BKE_report(ReportList *reports, eReportType type, const char *_message)
|
||||
{
|
||||
Report *report;
|
||||
|
@ -94,6 +134,8 @@ void BKE_report(ReportList *reports, eReportType type, const char *_message)
|
|||
}
|
||||
|
||||
if (reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) {
|
||||
std::scoped_lock lock(*reports->lock);
|
||||
|
||||
char *message_alloc;
|
||||
report = static_cast<Report *>(MEM_callocN(sizeof(Report), "Report"));
|
||||
report->type = type;
|
||||
|
@ -124,6 +166,8 @@ void BKE_reportf(ReportList *reports, eReportType type, const char *_format, ...
|
|||
}
|
||||
|
||||
if (reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) {
|
||||
std::scoped_lock lock(*reports->lock);
|
||||
|
||||
report = static_cast<Report *>(MEM_callocN(sizeof(Report), "Report"));
|
||||
|
||||
va_start(args, _format);
|
||||
|
@ -145,6 +189,9 @@ static void reports_prepend_impl(ReportList *reports, const char *prepend)
|
|||
{
|
||||
/* Caller must ensure. */
|
||||
BLI_assert(reports && reports->list.first);
|
||||
|
||||
std::scoped_lock lock(*reports->lock);
|
||||
|
||||
const size_t prefix_len = strlen(prepend);
|
||||
LISTBASE_FOREACH (Report *, report, &reports->list) {
|
||||
char *message = BLI_string_joinN(prepend, report->message);
|
||||
|
@ -193,6 +240,8 @@ void BKE_report_print_level_set(ReportList *reports, eReportType level)
|
|||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(*reports->lock);
|
||||
|
||||
reports->printlevel = level;
|
||||
}
|
||||
|
||||
|
@ -211,6 +260,8 @@ void BKE_report_store_level_set(ReportList *reports, eReportType level)
|
|||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(*reports->lock);
|
||||
|
||||
reports->storelevel = level;
|
||||
}
|
||||
|
||||
|
@ -223,6 +274,8 @@ char *BKE_reports_string(ReportList *reports, eReportType level)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(*reports->lock);
|
||||
|
||||
ds = BLI_dynstr_new();
|
||||
LISTBASE_FOREACH (Report *, report, &reports->list) {
|
||||
if (report->type >= level) {
|
||||
|
@ -274,6 +327,8 @@ void BKE_reports_print(ReportList *reports, eReportType level)
|
|||
|
||||
Report *BKE_reports_last_displayable(ReportList *reports)
|
||||
{
|
||||
std::scoped_lock lock(*reports->lock);
|
||||
|
||||
LISTBASE_FOREACH_BACKWARD (Report *, report, &reports->list) {
|
||||
if (ELEM(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO)) {
|
||||
return report;
|
||||
|
@ -286,6 +341,8 @@ Report *BKE_reports_last_displayable(ReportList *reports)
|
|||
bool BKE_reports_contain(ReportList *reports, eReportType level)
|
||||
{
|
||||
if (reports != nullptr) {
|
||||
std::scoped_lock lock(*reports->lock);
|
||||
|
||||
LISTBASE_FOREACH (Report *, report, &reports->list) {
|
||||
if (report->type >= level) {
|
||||
return true;
|
||||
|
@ -301,6 +358,8 @@ bool BKE_report_write_file_fp(FILE *fp, ReportList *reports, const char *header)
|
|||
fputs(header, fp);
|
||||
}
|
||||
|
||||
std::scoped_lock lock(*reports->lock);
|
||||
|
||||
LISTBASE_FOREACH (Report *, report, &reports->list) {
|
||||
fprintf((FILE *)fp, "%s # %s\n", report->message, report->typestr);
|
||||
}
|
||||
|
|
|
@ -632,6 +632,54 @@ template<typename T> [[nodiscard]] inline int dominant_axis(const VecBase<T, 3>
|
|||
return ((b.x > b.y) ? ((b.x > b.z) ? 0 : 2) : ((b.y > b.z) ? 1 : 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* \return the maximum component of a vector.
|
||||
*/
|
||||
template<typename T, int Size> [[nodiscard]] inline T reduce_max(const VecBase<T, Size> &a)
|
||||
{
|
||||
T result = a[0];
|
||||
for (int i = 1; i < Size; i++) {
|
||||
if (a[i] > result) {
|
||||
result = a[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return the minimum component of a vector.
|
||||
*/
|
||||
template<typename T, int Size> [[nodiscard]] inline T reduce_min(const VecBase<T, Size> &a)
|
||||
{
|
||||
T result = a[0];
|
||||
for (int i = 1; i < Size; i++) {
|
||||
if (a[i] < result) {
|
||||
result = a[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return the sum of the components of a vector.
|
||||
*/
|
||||
template<typename T, int Size> [[nodiscard]] inline T reduce_add(const VecBase<T, Size> &a)
|
||||
{
|
||||
T result = a[0];
|
||||
for (int i = 1; i < Size; i++) {
|
||||
result += a[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return the average of the components of a vector.
|
||||
*/
|
||||
template<typename T, int Size> [[nodiscard]] inline T average(const VecBase<T, Size> &a)
|
||||
{
|
||||
return reduce_add(a) * (T(1) / T(Size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a perpendicular vector to \a v.
|
||||
* \note Returned vector can be in any perpendicular direction.
|
||||
|
|
|
@ -26,7 +26,8 @@ struct SearchItem {
|
|||
* given higher weight.
|
||||
*/
|
||||
int main_group_id;
|
||||
int length;
|
||||
int main_group_length;
|
||||
int total_length;
|
||||
int weight;
|
||||
/**
|
||||
* This is a logical time stamp, i.e. the greater it is, the more recent the item was used. The
|
||||
|
|
|
@ -415,15 +415,24 @@ void extract_normalized_words(StringRef str,
|
|||
Vector<int, 64> &r_word_group_ids)
|
||||
{
|
||||
const uint32_t unicode_space = uint32_t(' ');
|
||||
const uint32_t unicode_dash = uint32_t('-');
|
||||
const uint32_t unicode_underscore = uint32_t('_');
|
||||
const uint32_t unicode_slash = uint32_t('/');
|
||||
const uint32_t unicode_right_triangle = UI_MENU_ARROW_SEP_UNICODE;
|
||||
|
||||
BLI_assert(unicode_space == BLI_str_utf8_as_unicode_safe(" "));
|
||||
BLI_assert(unicode_dash == BLI_str_utf8_as_unicode_safe("-"));
|
||||
BLI_assert(unicode_underscore == BLI_str_utf8_as_unicode_safe("_"));
|
||||
BLI_assert(unicode_slash == BLI_str_utf8_as_unicode_safe("/"));
|
||||
BLI_assert(unicode_right_triangle == BLI_str_utf8_as_unicode_safe(UI_MENU_ARROW_SEP));
|
||||
|
||||
auto is_separator = [&](uint32_t unicode) {
|
||||
return ELEM(unicode, unicode_space, unicode_slash, unicode_right_triangle);
|
||||
return ELEM(unicode,
|
||||
unicode_space,
|
||||
unicode_dash,
|
||||
unicode_underscore,
|
||||
unicode_slash,
|
||||
unicode_right_triangle);
|
||||
};
|
||||
|
||||
Vector<int, 64> section_indices;
|
||||
|
@ -479,10 +488,19 @@ void StringSearchBase::add_impl(const StringRef str, void *user_data, const int
|
|||
recent_cache_->logical_time_by_str.lookup_default(str, -1) :
|
||||
-1;
|
||||
const int main_group_id = word_group_ids.is_empty() ? 0 : word_group_ids.last();
|
||||
|
||||
int main_group_length = 0;
|
||||
for (const int i : words.index_range()) {
|
||||
if (word_group_ids[i] == main_group_id) {
|
||||
main_group_length += int(words[i].size());
|
||||
}
|
||||
}
|
||||
|
||||
items_.append({user_data,
|
||||
allocator_.construct_array_copy(words.as_span()),
|
||||
allocator_.construct_array_copy(word_group_ids.as_span()),
|
||||
main_group_id,
|
||||
main_group_length,
|
||||
int(str.size()),
|
||||
weight,
|
||||
recent_time});
|
||||
|
@ -531,7 +549,12 @@ Vector<void *> StringSearchBase::query_impl(const StringRef query) const
|
|||
* looking for. This also ensures that exact matches will be at the top, even if the query
|
||||
* is a sub-string of another item. */
|
||||
std::sort(indices.begin(), indices.end(), [&](int a, int b) {
|
||||
return items_[a].length < items_[b].length;
|
||||
const SearchItem &item_a = items_[a];
|
||||
const SearchItem &item_b = items_[b];
|
||||
/* The length of the main group has priority over the total length. */
|
||||
return item_a.main_group_length < item_b.main_group_length ||
|
||||
(item_a.main_group_length == item_b.main_group_length &&
|
||||
item_a.total_length < item_b.total_length);
|
||||
});
|
||||
/* Prefer items with larger weights. Use `stable_sort` so that if the weights are the same,
|
||||
* the order won't be changed. */
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
#include "IMB_imbuf.h" /* for proxy / time-code versioning stuff. */
|
||||
|
||||
#include "NOD_common.h"
|
||||
#include "NOD_composite.h"
|
||||
#include "NOD_composite.hh"
|
||||
#include "NOD_texture.h"
|
||||
|
||||
#include "BLO_readfile.h"
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
#include "BLO_readfile.h"
|
||||
|
||||
#include "NOD_common.h"
|
||||
#include "NOD_composite.h"
|
||||
#include "NOD_composite.hh"
|
||||
#include "NOD_socket.hh"
|
||||
|
||||
#include "readfile.hh"
|
||||
|
|
|
@ -619,7 +619,13 @@ static void version_principled_bsdf_subsurface(bNodeTree *ntree)
|
|||
|
||||
bNodeSocket *subsurf = nodeFindSocket(node, SOCK_IN, "Subsurface");
|
||||
float *subsurf_val = version_cycles_node_socket_float_value(subsurf);
|
||||
*version_cycles_node_socket_float_value(scale_in) = *subsurf_val;
|
||||
|
||||
if (!subsurf->link && *subsurf_val == 0.0f) {
|
||||
*version_cycles_node_socket_float_value(scale_in) = 0.05f;
|
||||
}
|
||||
else {
|
||||
*version_cycles_node_socket_float_value(scale_in) = *subsurf_val;
|
||||
}
|
||||
|
||||
if (subsurf->link == nullptr && *subsurf_val == 0.0f) {
|
||||
/* Node doesn't use Subsurf, we're done here. */
|
||||
|
|
|
@ -120,7 +120,7 @@ bool BlendfileLoadingBaseTest::blendfile_load(const char *filepath)
|
|||
char abspath[FILE_MAX];
|
||||
BLI_path_join(abspath, sizeof(abspath), test_assets_dir.c_str(), filepath);
|
||||
|
||||
BlendFileReadReport bf_reports = {nullptr};
|
||||
BlendFileReadReport bf_reports = {};
|
||||
bfile = BLO_read_from_file(abspath, BLO_READ_SKIP_NONE, &bf_reports);
|
||||
if (bfile == nullptr) {
|
||||
ADD_FAILURE() << "Unable to load file '" << filepath << "' from test assets dir '"
|
||||
|
@ -143,10 +143,6 @@ void BlendfileLoadingBaseTest::blendfile_free()
|
|||
return;
|
||||
}
|
||||
|
||||
wmWindowManager *wm = static_cast<wmWindowManager *>(bfile->main->wm.first);
|
||||
if (wm != nullptr) {
|
||||
wm_close_and_free(nullptr, wm);
|
||||
}
|
||||
BLO_blendfiledata_free(bfile);
|
||||
bfile = nullptr;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ if(WITH_COMPOSITOR_CPU)
|
|||
)
|
||||
|
||||
set(SRC
|
||||
COM_compositor.h
|
||||
COM_compositor.hh
|
||||
COM_defines.h
|
||||
|
||||
intern/COM_BufferArea.h
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
#include "DNA_color_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Render;
|
||||
|
||||
/* Keep ascii art. */
|
||||
|
@ -349,7 +345,3 @@ void COM_deinitialize(void);
|
|||
* To deinitialize the compositor use the COM_deinitialize method.
|
||||
*/
|
||||
// void COM_clear_caches(void); // NOT YET WRITTEN
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include "COM_ExecutionSystem.h"
|
||||
#include "COM_WorkScheduler.h"
|
||||
#include "COM_compositor.h"
|
||||
#include "COM_compositor.hh"
|
||||
|
||||
#include "RE_compositor.hh"
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "BKE_node.hh"
|
||||
|
||||
#include "NOD_composite.h"
|
||||
#include "NOD_composite.hh"
|
||||
|
||||
#include "COM_ConvertOperation.h"
|
||||
#include "COM_CryptomatteNode.h"
|
||||
|
|
|
@ -24,7 +24,7 @@ void main()
|
|||
/* Note that the first row of sums is the result of summing the prologues of a virtual block
|
||||
* that is before the first row of blocks and we assume that those prologues are all zeros,
|
||||
* so we set the sum to zero in that case. This is implemented by setting the sums of the
|
||||
* first vertical work-group to zero, white latter work-groups are summed as as usual and
|
||||
* first vertical work-group to zero, white latter work-groups are summed as usual and
|
||||
* stored starting from the second row. */
|
||||
imageStore(complete_x_prologues_sum_img, ivec2(y, 0), vec4(0.0));
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ ivec2 get_diagonal_direction()
|
|||
|
||||
/* Computes the number of values in the anti diagonal of the given index in the matrix with the
|
||||
* given size, where the anti diagonals are indexed from the lower left corner to the upper right
|
||||
* corner such that that their start is at the bottom and right edges of the matrix as shown in the
|
||||
* corner such that their start is at the bottom and right edges of the matrix as shown in the
|
||||
* diagram below. The numbers in the diagram denote the index of the anti diagonal and its length.
|
||||
*
|
||||
* Width = 6
|
||||
|
|
|
@ -669,8 +669,13 @@ set(GLSL_SRC
|
|||
intern/shaders/draw_debug_info.hh
|
||||
intern/shaders/draw_debug_print_display_frag.glsl
|
||||
intern/shaders/draw_debug_print_display_vert.glsl
|
||||
intern/shaders/draw_intersect_lib.glsl
|
||||
intern/shaders/draw_math_geom_lib.glsl
|
||||
intern/shaders/draw_model_lib.glsl
|
||||
intern/shaders/draw_resource_finalize_comp.glsl
|
||||
intern/shaders/draw_view_finalize_comp.glsl
|
||||
intern/shaders/draw_view_lib.glsl
|
||||
intern/shaders/draw_view_reconstruction_lib.glsl
|
||||
intern/shaders/draw_visibility_comp.glsl
|
||||
|
||||
intern/draw_command_shared.hh
|
||||
|
|
|
@ -111,7 +111,7 @@ void main()
|
|||
FragColor = vec4(sh, 1.0);
|
||||
#else
|
||||
# if defined(IRRADIANCE_HL2)
|
||||
/* Downside: very very low resolution (6 texels), bleed lighting because of interpolation */
|
||||
/* Downside: extremely low resolution (6 texels), bleed lighting because of interpolation */
|
||||
int x = int(gl_FragCoord.x) % 3;
|
||||
int y = int(gl_FragCoord.y) % 2;
|
||||
|
||||
|
|
|
@ -331,7 +331,7 @@ static inline float film_filter_weight(float filter_radius, float sample_distanc
|
|||
float weight = expf(fac * r);
|
||||
#else
|
||||
/* Blackman-Harris filter. */
|
||||
float r = M_2PI * saturate(0.5 + sqrtf(sample_distance_sqr) / (2.0 * filter_radius));
|
||||
float r = M_TAU * saturate(0.5 + sqrtf(sample_distance_sqr) / (2.0 * filter_radius));
|
||||
float weight = 0.35875 - 0.48829 * cosf(r) + 0.14128 * cosf(2.0 * r) - 0.01168 * cosf(3.0 * r);
|
||||
#endif
|
||||
return weight;
|
||||
|
@ -520,12 +520,12 @@ static inline float view_z_to_volume_z(
|
|||
}
|
||||
}
|
||||
|
||||
static inline float3 ndc_to_volume(float4x4 projection_matrix,
|
||||
float near,
|
||||
float far,
|
||||
float distribution,
|
||||
float2 coord_scale,
|
||||
float3 coord)
|
||||
static inline float3 screen_to_volume(float4x4 projection_matrix,
|
||||
float near,
|
||||
float far,
|
||||
float distribution,
|
||||
float2 coord_scale,
|
||||
float3 coord)
|
||||
{
|
||||
bool is_persp = projection_matrix[3][3] == 0.0;
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
|
||||
namespace blender::eevee {
|
||||
|
||||
bool VolumeModule::GridAABB::init(Object *ob, const Camera &camera, const VolumesInfoData &data)
|
||||
VolumeModule::GridAABB::GridAABB(Object *ob, const Camera &camera, const VolumesInfoData &data)
|
||||
{
|
||||
/* Returns the unified volume grid cell index of a world space coordinate. */
|
||||
/* Returns the unified volume grid cell corner of a world space coordinate. */
|
||||
auto to_global_grid_coords = [&](float3 wP) -> int3 {
|
||||
const float4x4 &view_matrix = camera.data_get().viewmat;
|
||||
const float4x4 &projection_matrix = camera.data_get().winmat;
|
||||
|
@ -32,47 +32,38 @@ bool VolumeModule::GridAABB::init(Object *ob, const Camera &camera, const Volume
|
|||
float3 ndc_coords = math::project_point(projection_matrix * view_matrix, wP);
|
||||
ndc_coords = (ndc_coords * 0.5f) + float3(0.5f);
|
||||
|
||||
float3 grid_coords = ndc_to_volume(projection_matrix,
|
||||
data.depth_near,
|
||||
data.depth_far,
|
||||
data.depth_distribution,
|
||||
data.coord_scale,
|
||||
ndc_coords);
|
||||
|
||||
return int3(grid_coords * float3(data.tex_size));
|
||||
float3 grid_coords = screen_to_volume(projection_matrix,
|
||||
data.depth_near,
|
||||
data.depth_far,
|
||||
data.depth_distribution,
|
||||
data.coord_scale,
|
||||
ndc_coords);
|
||||
/* Round to nearest grid corner. */
|
||||
return int3(grid_coords * float3(data.tex_size) + 0.5);
|
||||
};
|
||||
|
||||
const BoundBox &bbox = *BKE_object_boundbox_get(ob);
|
||||
min = int3(INT32_MAX);
|
||||
max = int3(INT32_MIN);
|
||||
|
||||
for (float3 corner : bbox.vec) {
|
||||
corner = math::transform_point(float4x4(ob->object_to_world), corner);
|
||||
int3 grid_coord = to_global_grid_coords(corner);
|
||||
min = math::min(min, grid_coord);
|
||||
max = math::max(max, grid_coord);
|
||||
for (float3 l_corner : bbox.vec) {
|
||||
float3 w_corner = math::transform_point(float4x4(ob->object_to_world), l_corner);
|
||||
/* Note that this returns the nearest cell corner coordinate.
|
||||
* So sub-froxel AABB will effectively return the same coordinate
|
||||
* for each corner (making it empty and skipped) unless it
|
||||
* cover the center of the froxel. */
|
||||
math::min_max(to_global_grid_coords(w_corner), min, max);
|
||||
}
|
||||
|
||||
bool is_visible = false;
|
||||
for (int i : IndexRange(3)) {
|
||||
is_visible = is_visible || (min[i] >= 0 && min[i] < data.tex_size[i]);
|
||||
is_visible = is_visible || (max[i] >= 0 && max[i] < data.tex_size[i]);
|
||||
}
|
||||
|
||||
min = math::clamp(min, int3(0), data.tex_size);
|
||||
max = math::clamp(max, int3(0), data.tex_size);
|
||||
|
||||
return is_visible;
|
||||
}
|
||||
|
||||
bool VolumeModule::GridAABB::overlaps(const GridAABB &aabb)
|
||||
bool VolumeModule::GridAABB::is_empty() const
|
||||
{
|
||||
for (int i : IndexRange(3)) {
|
||||
if (min[i] > aabb.max[i] || max[i] < aabb.min[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return math::reduce_min(max - min) <= 0;
|
||||
}
|
||||
|
||||
VolumeModule::GridAABB VolumeModule::GridAABB::intersect(const GridAABB &other) const
|
||||
{
|
||||
return {math::min(this->max, other.max), math::max(this->min, other.min)};
|
||||
}
|
||||
|
||||
void VolumeModule::init()
|
||||
|
@ -180,8 +171,11 @@ void VolumeModule::sync_object(Object *ob,
|
|||
return;
|
||||
}
|
||||
|
||||
GridAABB aabb;
|
||||
if (!aabb.init(ob, inst_.camera, data_)) {
|
||||
GridAABB object_aabb(ob, inst_.camera, data_);
|
||||
/* Remember that these are cells corners, so this extents to `tex_size`. */
|
||||
GridAABB view_aabb(int3(0), data_.tex_size);
|
||||
if (object_aabb.intersect(view_aabb).is_empty()) {
|
||||
/* Skip invisible object with respect to raster grid and bounds density. */
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -191,27 +185,25 @@ void VolumeModule::sync_object(Object *ob,
|
|||
enabled_ = true;
|
||||
|
||||
/* Add a barrier at the start of a subpass or when 2 volumes overlaps. */
|
||||
if (!subpass_aabbs_.contains_as(shader)) {
|
||||
if (!subpass_aabbs_.contains_as(shader) == false) {
|
||||
object_pass->barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
subpass_aabbs_.add(shader, {aabb});
|
||||
subpass_aabbs_.add(shader, {object_aabb});
|
||||
}
|
||||
else {
|
||||
Vector<GridAABB> &aabbs = subpass_aabbs_.lookup(shader);
|
||||
for (GridAABB &_aabb : aabbs) {
|
||||
if (aabb.overlaps(_aabb)) {
|
||||
for (GridAABB &other_aabb : aabbs) {
|
||||
if (object_aabb.intersect(other_aabb).is_empty() == false) {
|
||||
object_pass->barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
aabbs.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
aabbs.append(aabb);
|
||||
aabbs.append(object_aabb);
|
||||
}
|
||||
|
||||
int3 grid_size = aabb.max - aabb.min + int3(1);
|
||||
|
||||
object_pass->push_constant("drw_ResourceID", int(res_handle.resource_index()));
|
||||
object_pass->push_constant("grid_coords_min", aabb.min);
|
||||
object_pass->dispatch(math::divide_ceil(grid_size, int3(VOLUME_GROUP_SIZE)));
|
||||
object_pass->push_constant("grid_coords_min", object_aabb.min);
|
||||
object_pass->dispatch(math::divide_ceil(object_aabb.extent(), int3(VOLUME_GROUP_SIZE)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,12 +79,25 @@ class VolumeModule {
|
|||
/* Axis aligned bounding box in the volume grid.
|
||||
* Used for frustum culling and volumes overlapping detection. */
|
||||
struct GridAABB {
|
||||
/* Represent min and max grid corners covered by a volume.
|
||||
* So a volume covering the first froxel will have min={0,0,0} and max={1,1,1}.
|
||||
* A volume with min={0,0,0} and max={0,0,0} covers nothing. */
|
||||
int3 min, max;
|
||||
|
||||
/* Returns true if visible. */
|
||||
bool init(Object *ob, const Camera &camera, const VolumesInfoData &data);
|
||||
GridAABB(int3 min_, int3 max_) : min(min_), max(max_){};
|
||||
GridAABB(Object *ob, const Camera &camera, const VolumesInfoData &data);
|
||||
|
||||
bool overlaps(const GridAABB &aabb);
|
||||
/** Returns the intersection between this AABB and the \a other AABB. */
|
||||
GridAABB intersect(const GridAABB &other) const;
|
||||
|
||||
/** Returns true if volume covers no froxel. */
|
||||
bool is_empty() const;
|
||||
|
||||
/** Returns the extent of the volume. */
|
||||
int3 extent() const
|
||||
{
|
||||
return max - min;
|
||||
}
|
||||
};
|
||||
/* Stores a vector of volume AABBs for each material pass,
|
||||
* so we can detect overlapping volumes and place GPU barriers where needed
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_fast_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_ray_types_lib.glsl)
|
||||
|
||||
|
@ -93,14 +96,14 @@ float ambient_ambient_occlusion_search_horizon(vec3 vI,
|
|||
|
||||
if (ssray.max_time <= 2.0) {
|
||||
/* Produces self shadowing under this threshold. */
|
||||
return fast_acos(h);
|
||||
return acos_fast(h);
|
||||
}
|
||||
|
||||
float prev_time, time = 0.0;
|
||||
for (float iter = 0.0; time < ssray.max_time && iter < sample_count; iter++) {
|
||||
prev_time = time;
|
||||
/* Gives us good precision at center and ensure we cross at least one pixel per iteration. */
|
||||
time = 1.0 + iter + sqr((iter + noise) / sample_count) * ssray.max_time;
|
||||
time = 1.0 + iter + square((iter + noise) / sample_count) * ssray.max_time;
|
||||
float stride = time - prev_time;
|
||||
float lod = (log2(stride) - noise) / (1.0 + uniform_buf.ao.quality);
|
||||
|
||||
|
@ -116,7 +119,7 @@ float ambient_ambient_occlusion_search_horizon(vec3 vI,
|
|||
const float bias = 2.0 * 2.4e-7;
|
||||
depth += (inverted != 0.0) ? -bias : bias;
|
||||
|
||||
vec3 s = get_view_space_from_depth(uv, depth);
|
||||
vec3 s = drw_point_screen_to_view(vec3(uv, depth));
|
||||
vec3 omega_s = s - vP;
|
||||
float len = length(omega_s);
|
||||
/* Sample's horizon angle cosine. */
|
||||
|
@ -124,7 +127,7 @@ float ambient_ambient_occlusion_search_horizon(vec3 vI,
|
|||
/* Blend weight to fade artifacts. */
|
||||
float dist_ratio = abs(len) / radius;
|
||||
/* Sphere falloff. */
|
||||
float dist_fac = sqr(saturate(dist_ratio));
|
||||
float dist_fac = square(saturate(dist_ratio));
|
||||
/* Unbiased, gives too much hard cut behind objects */
|
||||
// float dist_fac = step(0.999, dist_ratio);
|
||||
|
||||
|
@ -135,7 +138,7 @@ float ambient_ambient_occlusion_search_horizon(vec3 vI,
|
|||
h = mix(max(h, s_h), h, dist_fac);
|
||||
}
|
||||
}
|
||||
return fast_acos(h);
|
||||
return acos_fast(h);
|
||||
}
|
||||
|
||||
OcclusionData ambient_occlusion_search(vec3 vP,
|
||||
|
@ -147,8 +150,8 @@ OcclusionData ambient_occlusion_search(vec3 vP,
|
|||
{
|
||||
vec2 noise = ambient_occlusion_get_noise(texel);
|
||||
vec2 dir = ambient_occlusion_get_dir(noise.x);
|
||||
vec2 uv = get_uvs_from_view(vP);
|
||||
vec3 vI = ((ProjectionMatrix[3][3] == 0.0) ? normalize(-vP) : vec3(0.0, 0.0, 1.0));
|
||||
vec2 uv = drw_point_view_to_screen(vP).xy;
|
||||
vec3 vI = (drw_view_is_perspective() ? normalize(-vP) : vec3(0.0, 0.0, 1.0));
|
||||
vec3 avg_dir = vec3(0.0);
|
||||
float avg_apperture = 0.0;
|
||||
|
||||
|
@ -211,8 +214,8 @@ void ambient_occlusion_eval(OcclusionData data,
|
|||
/* No error by default. */
|
||||
visibility_error = 1.0;
|
||||
|
||||
bool early_out = (inverted != 0.0) ? (max_v4(abs(data.horizons)) == 0.0) :
|
||||
(min_v4(abs(data.horizons)) == M_PI);
|
||||
bool early_out = (inverted != 0.0) ? (reduce_max(abs(data.horizons)) == 0.0) :
|
||||
(reduce_min(abs(data.horizons)) == M_PI);
|
||||
if (early_out) {
|
||||
visibility = saturate(dot(N, Ng) * 0.5 + 0.5);
|
||||
visibility = min(visibility, data.custom_occlusion);
|
||||
|
@ -234,13 +237,13 @@ void ambient_occlusion_eval(OcclusionData data,
|
|||
bent_normal = N * 0.001;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
vec3 T = transform_direction(ViewMatrixInverse, vec3(dir, 0.0));
|
||||
vec3 T = drw_normal_view_to_world(vec3(dir, 0.0));
|
||||
/* Setup integration domain around V. */
|
||||
vec3 B = normalize(cross(V, T));
|
||||
T = normalize(cross(B, V));
|
||||
|
||||
float proj_N_len;
|
||||
vec3 proj_N = normalize_len(N - B * dot(N, B), proj_N_len);
|
||||
vec3 proj_N = normalize_and_get_length(N - B * dot(N, B), proj_N_len);
|
||||
vec3 proj_Ng = normalize(Ng - B * dot(Ng, B));
|
||||
|
||||
vec2 h = (i == 0) ? data.horizons.xy : data.horizons.zw;
|
||||
|
@ -250,8 +253,8 @@ void ambient_occlusion_eval(OcclusionData data,
|
|||
float N_cos = saturate(dot(proj_N, V));
|
||||
float Ng_cos = saturate(dot(proj_Ng, V));
|
||||
/* Gamma, angle between normalized projected normal and view vector. */
|
||||
float angle_Ng = sign(Ng_sin) * fast_acos(Ng_cos);
|
||||
float angle_N = sign(N_sin) * fast_acos(N_cos);
|
||||
float angle_Ng = sign(Ng_sin) * acos_fast(Ng_cos);
|
||||
float angle_N = sign(N_sin) * acos_fast(N_cos);
|
||||
/* Clamp horizons to hemisphere around shading normal. */
|
||||
h = ambient_occlusion_clamp_horizons_to_hemisphere(h, angle_N, inverted);
|
||||
|
||||
|
@ -285,7 +288,7 @@ void ambient_occlusion_eval(OcclusionData data,
|
|||
|
||||
if (AO_BENT_NORMALS) {
|
||||
/* NOTE: using pow(visibility, 6.0) produces NaN (see #87369). */
|
||||
float tmp = saturate(pow6(visibility));
|
||||
float tmp = saturate(pow6f(visibility));
|
||||
bent_normal = normalize(mix(bent_normal, N, tmp));
|
||||
}
|
||||
else {
|
||||
|
@ -379,14 +382,14 @@ float ambient_occlusion_specular(
|
|||
specular_dir = normalize(mix(specular_dir, visibility_dir, roughness * (1.0 - visibility)));
|
||||
|
||||
/* Visibility to cone angle (eq. 18). */
|
||||
float vis_angle = fast_acos(sqrt(1 - visibility));
|
||||
float vis_angle = acos_fast(sqrt(1 - visibility));
|
||||
/* Roughness to cone angle (eq. 26). */
|
||||
/* A 0.001 min_angle can generate NaNs on Intel GPUs. See D12508. */
|
||||
const float min_angle = 0.00990998744964599609375;
|
||||
float spec_angle = max(min_angle, fast_acos(ambient_occlusion_cone_cosine(roughness)));
|
||||
float spec_angle = max(min_angle, acos_fast(ambient_occlusion_cone_cosine(roughness)));
|
||||
/* Angle between cone axes. */
|
||||
float cone_cone_dist = fast_acos(saturate(dot(visibility_dir, specular_dir)));
|
||||
float cone_nor_dist = fast_acos(saturate(dot(N, specular_dir)));
|
||||
float cone_cone_dist = acos_fast(saturate(dot(visibility_dir, specular_dir)));
|
||||
float cone_nor_dist = acos_fast(saturate(dot(N, specular_dir)));
|
||||
|
||||
float isect_solid_angle = ambient_occlusion_spherical_cap_intersection(
|
||||
vis_angle, spec_angle, cone_cone_dist);
|
||||
|
@ -394,7 +397,7 @@ float ambient_occlusion_specular(
|
|||
M_PI_2, spec_angle, cone_nor_dist);
|
||||
float specular_occlusion = isect_solid_angle / specular_solid_angle;
|
||||
/* Mix because it is unstable in unoccluded areas. */
|
||||
float tmp = saturate(pow8(visibility));
|
||||
float tmp = saturate(pow8f(visibility));
|
||||
visibility = mix(specular_occlusion, 1.0, tmp);
|
||||
|
||||
return saturate(visibility);
|
||||
|
|
|
@ -2,64 +2,10 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_reconstruction_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_ambient_occlusion_lib.glsl)
|
||||
|
||||
/* Similar to https://atyuwen.github.io/posts/normal-reconstruction/.
|
||||
* This samples the depth buffer 4 time for each direction to get the most correct
|
||||
* implicit normal reconstruction out of the depth buffer. */
|
||||
vec3 view_position_derivative_from_depth(
|
||||
sampler2D depth_tx, ivec2 extent, vec2 uv, ivec2 offset, vec3 vP, float depth_center)
|
||||
{
|
||||
vec4 H;
|
||||
H.x = texelFetch(depth_tx, ivec2(uv * vec2(extent)) - offset * 2, 0).r;
|
||||
H.y = texelFetch(depth_tx, ivec2(uv * vec2(extent)) - offset, 0).r;
|
||||
H.z = texelFetch(depth_tx, ivec2(uv * vec2(extent)) + offset, 0).r;
|
||||
H.w = texelFetch(depth_tx, ivec2(uv * vec2(extent)) + offset * 2, 0).r;
|
||||
|
||||
vec2 uv_offset = vec2(offset) / vec2(extent);
|
||||
vec2 uv1 = uv - uv_offset * 2.0;
|
||||
vec2 uv2 = uv - uv_offset;
|
||||
vec2 uv3 = uv + uv_offset;
|
||||
vec2 uv4 = uv + uv_offset * 2.0;
|
||||
|
||||
/* Fix issue with depth precision. Take even larger diff. */
|
||||
vec4 diff = abs(vec4(depth_center, H.yzw) - H.x);
|
||||
if (max_v4(diff) < 2.4e-7 && all(lessThan(diff.xyz, diff.www))) {
|
||||
return 0.25 * (get_view_space_from_depth(uv3, H.w) - get_view_space_from_depth(uv1, H.x));
|
||||
}
|
||||
/* Simplified (H.xw + 2.0 * (H.yz - H.xw)) - depth_center */
|
||||
vec2 deltas = abs((2.0 * H.yz - H.xw) - depth_center);
|
||||
if (deltas.x < deltas.y) {
|
||||
return vP - get_view_space_from_depth(uv2, H.y);
|
||||
}
|
||||
else {
|
||||
return get_view_space_from_depth(uv3, H.z) - vP;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO(Miguel Pozo): This should be in common_view_lib,
|
||||
* but moving it there results in dependency hell. */
|
||||
bool reconstruct_view_position_and_normal_from_depth(
|
||||
sampler2D depth_tx, ivec2 extent, vec2 uv, out vec3 vP, out vec3 vNg)
|
||||
{
|
||||
float depth_center = texelFetch(depth_tx, ivec2(uv * vec2(extent)), 0).r;
|
||||
|
||||
vP = get_view_space_from_depth(uv, depth_center);
|
||||
|
||||
vec3 dPdx = view_position_derivative_from_depth(
|
||||
depth_tx, extent, uv, ivec2(1, 0), vP, depth_center);
|
||||
vec3 dPdy = view_position_derivative_from_depth(
|
||||
depth_tx, extent, uv, ivec2(0, 1), vP, depth_center);
|
||||
|
||||
vNg = safe_normalize(cross(dPdx, dPdy));
|
||||
|
||||
/* Background case. */
|
||||
return depth_center != 1.0;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
@ -68,29 +14,26 @@ void main()
|
|||
return;
|
||||
}
|
||||
|
||||
vec2 uv = (vec2(texel) + vec2(0.5)) / vec2(extent);
|
||||
vec3 vP, vNg;
|
||||
if (!reconstruct_view_position_and_normal_from_depth(hiz_tx, extent, uv, vP, vNg)) {
|
||||
SurfaceReconstructResult surf = view_reconstruct_from_depth(hiz_tx, extent, texel);
|
||||
if (surf.is_background) {
|
||||
/* Do not trace for background */
|
||||
imageStore(out_ao_img, ivec3(texel, out_ao_img_layer_index), vec4(0.0));
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 P = transform_point(ViewMatrixInverse, vP);
|
||||
vec3 V = cameraVec(P);
|
||||
vec3 Ng = transform_direction(ViewMatrixInverse, vNg);
|
||||
vec3 P = drw_point_view_to_world(surf.vP);
|
||||
vec3 V = drw_world_incident_vector(P);
|
||||
vec3 Ng = drw_normal_view_to_world(surf.vNg);
|
||||
vec3 N = imageLoad(in_normal_img, ivec3(texel, in_normal_img_layer_index)).xyz;
|
||||
|
||||
OcclusionData data = ambient_occlusion_search(
|
||||
vP, hiz_tx, texel, uniform_buf.ao.distance, 0.0, 8.0);
|
||||
surf.vP, hiz_tx, texel, uniform_buf.ao.distance, 0.0, 8.0);
|
||||
|
||||
float visibility;
|
||||
float visibility_error_out;
|
||||
vec3 bent_normal_out;
|
||||
float unused_visibility_error_out;
|
||||
vec3 unused_bent_normal_out;
|
||||
ambient_occlusion_eval(
|
||||
data, texel, V, N, Ng, 0.0, visibility, visibility_error_out, bent_normal_out);
|
||||
/* Scale by user factor */
|
||||
visibility = saturate(visibility);
|
||||
data, texel, V, N, Ng, 0.0, visibility, unused_visibility_error_out, unused_bent_normal_out);
|
||||
|
||||
imageStore(out_ao_img, ivec3(texel, out_ao_img_layer_index), vec4(visibility));
|
||||
imageStore(out_ao_img, ivec3(texel, out_ao_img_layer_index), vec4(saturate(visibility)));
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_model_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl)
|
||||
|
||||
#define EEVEE_ATTRIBUTE_LIB
|
||||
|
@ -33,7 +33,7 @@ vec3 attr_load_orco(vec4 orco)
|
|||
# endif
|
||||
vec4 attr_load_tangent(vec4 tangent)
|
||||
{
|
||||
tangent.xyz = safe_normalize(normal_object_to_world(tangent.xyz));
|
||||
tangent.xyz = safe_normalize(drw_normal_object_to_world(tangent.xyz));
|
||||
return tangent;
|
||||
}
|
||||
vec4 attr_load_vec4(vec4 attr)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* BxDF evaluation functions.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(eevee_bxdf_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_math_geom_lib.glsl)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Microfacet GGX distribution
|
||||
|
@ -17,7 +17,7 @@
|
|||
|
||||
float sample_pdf_ggx_reflect(float NH, float NV, float VH, float G1_V, float alpha)
|
||||
{
|
||||
float a2 = sqr(alpha);
|
||||
float a2 = square(alpha);
|
||||
#if GGX_USE_VISIBLE_NORMAL
|
||||
return 0.25 * bxdf_ggx_D(NH, a2) * G1_V / NV;
|
||||
#else
|
||||
|
@ -28,10 +28,10 @@ float sample_pdf_ggx_reflect(float NH, float NV, float VH, float G1_V, float alp
|
|||
float sample_pdf_ggx_refract(
|
||||
float NH, float NV, float VH, float LH, float G1_V, float alpha, float eta)
|
||||
{
|
||||
float a2 = sqr(alpha);
|
||||
float a2 = square(alpha);
|
||||
float D = bxdf_ggx_D(NH, a2);
|
||||
float Ht2 = sqr(eta * LH + VH);
|
||||
return (D * G1_V * abs(VH * LH) * sqr(eta)) / (NV * Ht2);
|
||||
float Ht2 = square(eta * LH + VH);
|
||||
return (D * G1_V * abs(VH * LH) * square(eta)) / (NV * Ht2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,8 +70,8 @@ vec3 sample_ggx(vec3 rand, float alpha, vec3 Vt, out float G1_V)
|
|||
return Ht;
|
||||
#else
|
||||
/* Theta is the cone angle. */
|
||||
float z = sqrt((1.0 - rand.x) / (1.0 + sqr(alpha) * rand.x - rand.x)); /* cos theta */
|
||||
float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */
|
||||
float z = sqrt((1.0 - rand.x) / (1.0 + square(alpha) * rand.x - rand.x)); /* cos theta */
|
||||
float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */
|
||||
float x = r * rand.y;
|
||||
float y = r * rand.z;
|
||||
/* Microfacet Normal */
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Camera projection / uv functions and utils.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Panoramic Projections
|
||||
|
@ -68,10 +68,10 @@ vec3 camera_mirror_ball_to_direction(CameraData cam, vec2 uv)
|
|||
uv = uv * cam.uv_scale + cam.uv_bias;
|
||||
vec3 dir;
|
||||
dir.xy = uv * 2.0 - 1.0;
|
||||
if (len_squared(dir.xy) > 1.0) {
|
||||
if (length_squared(dir.xy) > 1.0) {
|
||||
return vec3(0.0);
|
||||
}
|
||||
dir.z = -safe_sqrt(1.0 - sqr(dir.x) - sqr(dir.y));
|
||||
dir.z = -safe_sqrt(1.0 - square(dir.x) - square(dir.y));
|
||||
const vec3 I = vec3(0.0, 0.0, 1.0);
|
||||
return reflect(I, dir);
|
||||
}
|
||||
|
|
|
@ -38,3 +38,16 @@ vec4 colorspace_scene_linear_from_YCoCg(vec4 ycocg_color)
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/**
|
||||
* Clamp components to avoid black square artifacts if a pixel goes NaN or negative.
|
||||
* Threshold is arbitrary.
|
||||
*/
|
||||
vec4 colorspace_safe_color(vec4 c)
|
||||
{
|
||||
return clamp(c, vec4(0.0), vec4(1e20));
|
||||
}
|
||||
vec3 colorspace_safe_color(vec3 c)
|
||||
{
|
||||
return clamp(c, vec3(0.0), vec3(1e20));
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ void main()
|
|||
}
|
||||
}
|
||||
|
||||
gl_Position = point_world_to_ndc(P);
|
||||
gl_Position = drw_point_world_to_homogenous(P);
|
||||
gl_Position.z -= 2.5e-5;
|
||||
gl_PointSize = 3.0;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_debug_gradients_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
|
||||
vec3 debug_random_color(int v)
|
||||
{
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_matrix_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -37,17 +37,15 @@ void main()
|
|||
break;
|
||||
}
|
||||
|
||||
vec3 N = surfel.normal;
|
||||
vec3 T, B;
|
||||
make_orthonormal_basis(N, T, B);
|
||||
mat3x3 TBN = from_up_axis(surfel.normal);
|
||||
|
||||
mat4 model_matrix = mat4(vec4(T * debug_surfel_radius, 0),
|
||||
vec4(B * debug_surfel_radius, 0),
|
||||
vec4(N * debug_surfel_radius, 0),
|
||||
mat4 model_matrix = mat4(vec4(TBN[0] * debug_surfel_radius, 0),
|
||||
vec4(TBN[1] * debug_surfel_radius, 0),
|
||||
vec4(TBN[2] * debug_surfel_radius, 0),
|
||||
vec4(surfel.position, 1));
|
||||
|
||||
P = (model_matrix * vec4(lP, 1)).xyz;
|
||||
|
||||
gl_Position = point_world_to_ndc(P);
|
||||
gl_Position = drw_point_world_to_homogenous(P);
|
||||
gl_Position.z -= 2.5e-5;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
* Compute light objects lighting contribution using captured Gbuffer data.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl)
|
||||
|
||||
|
@ -24,10 +24,10 @@ void main()
|
|||
stack.cl[0].ltc_mat = LTC_LAMBERT_MAT;
|
||||
stack.cl[0].type = LIGHT_DIFFUSE;
|
||||
|
||||
vec3 P = get_world_space_from_depth(uvcoordsvar.xy, depth);
|
||||
vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth));
|
||||
vec3 Ng = stack.cl[0].N;
|
||||
vec3 V = cameraVec(P);
|
||||
float vPz = dot(cameraForward, P) - dot(cameraForward, cameraPos);
|
||||
vec3 V = drw_world_incident_vector(P);
|
||||
float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
|
||||
|
||||
/* Direct light. */
|
||||
light_eval(stack, P, Ng, V, vPz, gbuf.thickness);
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
* Compute light objects lighting contribution using Gbuffer data.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_renderpass_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_thickness_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_subsurface_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -20,8 +20,12 @@ void main()
|
|||
float depth = texelFetch(hiz_tx, texel, 0).r;
|
||||
GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel);
|
||||
|
||||
vec3 P = get_world_space_from_depth(uvcoordsvar.xy, depth);
|
||||
vec3 V = cameraVec(P);
|
||||
vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth));
|
||||
/* Assume reflection closure normal is always somewhat representative of the geometric normal.
|
||||
* Ng is only used for shadow biases and subsurface check in this case. */
|
||||
vec3 Ng = gbuf.has_reflection ? gbuf.reflection.N : gbuf.diffuse.N;
|
||||
vec3 V = drw_world_incident_vector(P);
|
||||
float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
|
||||
|
||||
ClosureLightStack stack;
|
||||
|
||||
|
@ -45,11 +49,6 @@ void main()
|
|||
stack.cl[2] = cl_sss;
|
||||
#endif
|
||||
|
||||
/* Assume reflection closure normal is always somewhat representative of the geometric normal.
|
||||
* Ng is only used for shadow biases and subsurface check in this case. */
|
||||
vec3 Ng = gbuf.has_reflection ? gbuf.reflection.N : gbuf.diffuse.N;
|
||||
float vPz = dot(cameraForward, P) - dot(cameraForward, cameraPos);
|
||||
|
||||
#ifdef SSS_TRANSMITTANCE
|
||||
float shadow_thickness = thickness_from_shadow(P, Ng, vPz);
|
||||
float thickness = (shadow_thickness != THICKNESS_NO_VALUE) ?
|
||||
|
@ -90,7 +89,7 @@ void main()
|
|||
|
||||
/* TODO(fclem): Change shadow pass to be colored. */
|
||||
vec3 shadows = radiance_shadowed * safe_rcp(radiance_unshadowed);
|
||||
output_renderpass_value(uniform_buf.render_pass.shadow_id, avg(shadows));
|
||||
output_renderpass_value(uniform_buf.render_pass.shadow_id, average(shadows));
|
||||
|
||||
imageStore(direct_diffuse_img, texel, vec4(radiance_diffuse, 1.0));
|
||||
imageStore(direct_reflect_img, texel, vec4(radiance_specular, 1.0));
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
* Compute light objects lighting contribution using captured Gbuffer data.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl)
|
||||
|
||||
|
@ -19,10 +19,10 @@ void main()
|
|||
|
||||
GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel);
|
||||
|
||||
vec3 P = get_world_space_from_depth(uvcoordsvar.xy, depth);
|
||||
vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth));
|
||||
vec3 Ng = gbuf.diffuse.N;
|
||||
vec3 V = cameraVec(P);
|
||||
float vPz = dot(cameraForward, P) - dot(cameraForward, cameraPos);
|
||||
vec3 V = drw_world_incident_vector(P);
|
||||
float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
|
||||
|
||||
ClosureLightStack stack;
|
||||
stack.cl[0].N = gbuf.diffuse.N;
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
* One is for the half-resolution gather passes and the other one for slight in focus regions.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_debug_gradients_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_matrix_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Options.
|
||||
|
@ -316,7 +318,7 @@ void dof_gather_accumulate_center_sample(DofGatherData center_data,
|
|||
|
||||
if (is_foreground && !is_resolve) {
|
||||
/* Reduce issue with closer foreground over distant foreground. */
|
||||
float ring_area = sqr(bordering_radius);
|
||||
float ring_area = square(bordering_radius);
|
||||
dof_gather_ammend_weight(center_data, ring_area);
|
||||
}
|
||||
|
||||
|
@ -468,7 +470,7 @@ void dof_gather_accumulator(sampler2D color_tx,
|
|||
int sample_pair_count = gather_ring_density * ring;
|
||||
|
||||
float step_rot = M_PI / float(sample_pair_count);
|
||||
mat2 step_rot_mat = rot2_from_angle(step_rot);
|
||||
mat2 step_rot_mat = from_rotation(Angle(step_rot));
|
||||
|
||||
float angle_offset = noise.y * step_rot;
|
||||
vec2 offset = vec2(cos(angle_offset), sin(angle_offset));
|
||||
|
@ -516,9 +518,9 @@ void dof_gather_accumulator(sampler2D color_tx,
|
|||
if (is_foreground) {
|
||||
/* Reduce issue with closer foreground over distant foreground. */
|
||||
/* TODO(fclem) this seems to not be completely correct as the issue remains. */
|
||||
float ring_area = (sqr(float(ring) + 0.5 + coc_radius_error) -
|
||||
sqr(float(ring) - 0.5 + coc_radius_error)) *
|
||||
sqr(base_radius * unit_sample_radius);
|
||||
float ring_area = (square(float(ring) + 0.5 + coc_radius_error) -
|
||||
square(float(ring) - 0.5 + coc_radius_error)) *
|
||||
square(base_radius * unit_sample_radius);
|
||||
dof_gather_ammend_weight(ring_data, ring_area);
|
||||
}
|
||||
|
||||
|
@ -574,13 +576,13 @@ void dof_gather_accumulator(sampler2D color_tx,
|
|||
|
||||
if (debug_gather_perf && density_change > 0) {
|
||||
float fac = saturate(float(density_change) / float(10.0));
|
||||
out_color.rgb = avg(out_color.rgb) * neon_gradient(fac);
|
||||
out_color.rgb = average(out_color.rgb) * neon_gradient(fac);
|
||||
}
|
||||
if (debug_gather_perf && do_fast_gather) {
|
||||
out_color.rgb = avg(out_color.rgb) * vec3(0.0, 1.0, 0.0);
|
||||
out_color.rgb = average(out_color.rgb) * vec3(0.0, 1.0, 0.0);
|
||||
}
|
||||
if (debug_scatter_perf) {
|
||||
out_color.rgb = avg(out_color.rgb) * vec3(0.0, 1.0, 0.0);
|
||||
out_color.rgb = average(out_color.rgb) * vec3(0.0, 1.0, 0.0);
|
||||
}
|
||||
|
||||
/* Output premultiplied color so we can use bilinear sampler in resolve pass. */
|
||||
|
@ -616,7 +618,7 @@ void dof_slight_focus_gather(depth2D depth_tx,
|
|||
|
||||
const float sample_count_max = float(DOF_SLIGHT_FOCUS_SAMPLE_MAX);
|
||||
/* Scale by search area. */
|
||||
float sample_count = sample_count_max * saturate(sqr(radius) / sqr(dof_layer_threshold));
|
||||
float sample_count = sample_count_max * saturate(square(radius) / square(dof_layer_threshold));
|
||||
|
||||
bool first_ring = true;
|
||||
|
||||
|
@ -632,7 +634,7 @@ void dof_slight_focus_gather(depth2D depth_tx,
|
|||
vec2 sample_uv = (frag_coord + sample_offset) / vec2(textureSize(depth_tx, 0));
|
||||
float depth = textureLod(depth_tx, sample_uv, 0.0).r;
|
||||
pair_data[i].coc = dof_coc_from_depth(dof_buf, sample_uv, depth);
|
||||
pair_data[i].color = safe_color(textureLod(color_tx, sample_uv, 0.0));
|
||||
pair_data[i].color = colorspace_safe_color(textureLod(color_tx, sample_uv, 0.0));
|
||||
pair_data[i].dist = ring_dist;
|
||||
if (DOF_BOKEH_TEXTURE) {
|
||||
/* Contains sub-pixel distance to bokeh shape. */
|
||||
|
@ -668,7 +670,7 @@ void dof_slight_focus_gather(depth2D depth_tx,
|
|||
/* Center sample. */
|
||||
vec2 sample_uv = frag_coord / vec2(textureSize(depth_tx, 0));
|
||||
DofGatherData center_data;
|
||||
center_data.color = safe_color(textureLod(color_tx, sample_uv, 0.0));
|
||||
center_data.color = colorspace_safe_color(textureLod(color_tx, sample_uv, 0.0));
|
||||
center_data.coc = dof_coc_from_depth(dof_buf, sample_uv, textureLod(depth_tx, sample_uv, 0.0).r);
|
||||
center_data.coc = clamp(center_data.coc, -dof_buf.coc_abs_max, dof_buf.coc_abs_max);
|
||||
center_data.dist = 0.0;
|
||||
|
|
|
@ -24,7 +24,7 @@ void main()
|
|||
|
||||
if (dof_buf.bokeh_blades > 0.0) {
|
||||
/* NOTE: atan(y,x) has output range [-M_PI..M_PI], so add 2pi to avoid negative angles. */
|
||||
float theta = atan(gather_uv.y, gather_uv.x) + M_2PI;
|
||||
float theta = atan(gather_uv.y, gather_uv.x) + M_TAU;
|
||||
float r = length(gather_uv);
|
||||
|
||||
radius /= circle_to_polygon_radius(dof_buf.bokeh_blades, theta - dof_buf.bokeh_rotation);
|
||||
|
@ -39,7 +39,7 @@ void main()
|
|||
{
|
||||
/* Slight focus distance */
|
||||
slight_focus_texel *= dof_buf.bokeh_anisotropic_scale_inv;
|
||||
float theta = atan(slight_focus_texel.y, -slight_focus_texel.x) + M_2PI;
|
||||
float theta = atan(slight_focus_texel.y, -slight_focus_texel.x) + M_TAU;
|
||||
slight_focus_texel /= circle_to_polygon_radius(dof_buf.bokeh_blades,
|
||||
theta + dof_buf.bokeh_rotation);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* Also does not weight luma for the bilateral weights.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl)
|
||||
|
||||
void main()
|
||||
|
@ -27,7 +28,7 @@ void main()
|
|||
|
||||
vec4 weights = dof_bilateral_coc_weights(cocs);
|
||||
/* Normalize so that the sum is 1. */
|
||||
weights *= safe_rcp(sum(weights));
|
||||
weights *= safe_rcp(reduce_add(weights));
|
||||
|
||||
vec4 out_color = weighted_sum_array(colors, weights);
|
||||
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
* Depth of Field utils.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Constants.
|
||||
|
@ -114,10 +115,10 @@ float dof_coc_from_depth(DepthOfFieldData dof_data, vec2 uv, float depth)
|
|||
{
|
||||
if (is_panoramic(dof_data.camera_type)) {
|
||||
/* Use radial depth. */
|
||||
depth = -length(get_view_space_from_depth(uv, depth));
|
||||
depth = -length(drw_point_screen_to_view(vec3(uv, depth)));
|
||||
}
|
||||
else {
|
||||
depth = get_view_z_from_depth(depth);
|
||||
depth = drw_depth_screen_to_view(depth);
|
||||
}
|
||||
return coc_radius_from_camera_depth(dof_data, depth);
|
||||
}
|
||||
|
@ -153,7 +154,7 @@ vec4 dof_layer_weight(vec4 coc)
|
|||
float dof_sample_weight(float coc)
|
||||
{
|
||||
#if 1 /* Optimized */
|
||||
return min(1.0, 1.0 / sqr(coc));
|
||||
return min(1.0, 1.0 / square(coc));
|
||||
#else
|
||||
/* Full intensity if CoC radius is below the pixel footprint. */
|
||||
const float min_coc = 1.0;
|
||||
|
@ -164,7 +165,7 @@ float dof_sample_weight(float coc)
|
|||
vec4 dof_sample_weight(vec4 coc)
|
||||
{
|
||||
#if 1 /* Optimized */
|
||||
return min(vec4(1.0), 1.0 / sqr(coc));
|
||||
return min(vec4(1.0), 1.0 / square(coc));
|
||||
#else
|
||||
/* Full intensity if CoC radius is below the pixel footprint. */
|
||||
const float min_coc = 1.0;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||
|
||||
/* NOTE: Do not compare alpha as it is not scattered by the scatter pass. */
|
||||
float dof_scatter_neighborhood_rejection(vec3 color)
|
||||
|
@ -34,7 +35,7 @@ float dof_scatter_neighborhood_rejection(vec3 color)
|
|||
vec3 ref = textureLod(downsample_tx, sample_uv, 0.0).rgb;
|
||||
|
||||
ref = min(vec3(dof_buf.scatter_neighbor_max_color), ref);
|
||||
float diff = max_v3(max(vec3(0.0), abs(ref - color)));
|
||||
float diff = reduce_max(max(vec3(0.0), abs(ref - color)));
|
||||
|
||||
const float rejection_threshold = 0.7;
|
||||
diff = saturate(diff / rejection_threshold - 1.0);
|
||||
|
@ -51,7 +52,7 @@ float dof_scatter_screen_border_rejection(float coc, ivec2 texel)
|
|||
vec2 screen_size = vec2(imageSize(inout_color_lod0_img));
|
||||
vec2 uv = (vec2(texel) + 0.5) / screen_size;
|
||||
vec2 screen_pos = uv * screen_size;
|
||||
float min_screen_border_distance = min_v2(min(screen_pos, screen_size - screen_pos));
|
||||
float min_screen_border_distance = reduce_min(min(screen_pos, screen_size - screen_pos));
|
||||
/* Full-resolution to half-resolution CoC. */
|
||||
coc *= 0.5;
|
||||
/* Allow 10px transition. */
|
||||
|
@ -62,7 +63,7 @@ float dof_scatter_screen_border_rejection(float coc, ivec2 texel)
|
|||
float dof_scatter_luminosity_rejection(vec3 color)
|
||||
{
|
||||
const float rejection_hardness = 1.0;
|
||||
return saturate(max_v3(color - dof_buf.scatter_color_threshold) * rejection_hardness);
|
||||
return saturate(reduce_max(color - dof_buf.scatter_color_threshold) * rejection_hardness);
|
||||
}
|
||||
|
||||
float dof_scatter_coc_radius_rejection(float coc)
|
||||
|
@ -118,7 +119,7 @@ void main()
|
|||
do_scatter4.w = do_scatter[LOCAL_OFFSET(0, 0)];
|
||||
if (any(greaterThan(do_scatter4, vec4(0.0)))) {
|
||||
/* Apply energy conservation to anamorphic scattered bokeh. */
|
||||
do_scatter4 *= max_v2(dof_buf.bokeh_anisotropic_scale_inv);
|
||||
do_scatter4 *= reduce_max(dof_buf.bokeh_anisotropic_scale_inv);
|
||||
|
||||
/* Circle of Confusion. */
|
||||
vec4 coc4;
|
||||
|
@ -132,7 +133,7 @@ void main()
|
|||
vec2 offset = vec2(gl_GlobalInvocationID.xy) + 1;
|
||||
/* Add 2.5 to max_coc because the max_coc may not be centered on the sprite origin
|
||||
* and because we smooth the bokeh shape a bit in the pixel shader. */
|
||||
vec2 half_extent = max_v4(abs(coc4)) * dof_buf.bokeh_anisotropic_scale + 2.5;
|
||||
vec2 half_extent = reduce_max(abs(coc4)) * dof_buf.bokeh_anisotropic_scale + 2.5;
|
||||
/* Issue a sprite for each field if any CoC matches. */
|
||||
if (any(lessThan(do_scatter4 * sign(coc4), vec4(0.0)))) {
|
||||
/* Same value for all threads. Not an issue if we don't sync access to it. */
|
||||
|
@ -226,7 +227,7 @@ void main()
|
|||
vec4 weights = dof_bilateral_coc_weights(coc4);
|
||||
weights *= dof_bilateral_color_weights(colors);
|
||||
/* Normalize so that the sum is 1. */
|
||||
weights *= safe_rcp(sum(weights));
|
||||
weights *= safe_rcp(reduce_add(weights));
|
||||
|
||||
color_cache[LOCAL_INDEX] = weighted_sum_array(colors, weights);
|
||||
coc_cache[LOCAL_INDEX] = dot(coc4, weights);
|
||||
|
|
|
@ -72,11 +72,11 @@ vec3 dof_neighborhood_clamp(vec2 frag_coord, vec3 color, float center_coc, float
|
|||
neighbor_max = (i == 0) ? ycocg_sample : max(neighbor_max, ycocg_sample);
|
||||
}
|
||||
/* Pad the bounds in the near in focus region to get back a bit of detail. */
|
||||
float padding = 0.125 * saturate(1.0 - sqr(center_coc) / sqr(8.0));
|
||||
float padding = 0.125 * saturate(1.0 - square(center_coc) / square(8.0));
|
||||
neighbor_max += abs(neighbor_min) * padding;
|
||||
neighbor_min -= abs(neighbor_min) * padding;
|
||||
/* Progressively apply the clamp to avoid harsh transition. Also mask by weight. */
|
||||
float fac = saturate(sqr(center_coc) * 4.0) * weight;
|
||||
float fac = saturate(square(center_coc) * 4.0) * weight;
|
||||
/* Clamp in YCoCg space to avoid too much color drift. */
|
||||
color = colorspace_YCoCg_from_scene_linear(color);
|
||||
color = mix(color, clamp(color, neighbor_min, neighbor_max), fac);
|
||||
|
@ -154,7 +154,7 @@ void main()
|
|||
}
|
||||
|
||||
if (!no_focus_pass && prediction.do_focus) {
|
||||
layer_color = safe_color(textureLod(color_tx, uv, 0.0));
|
||||
layer_color = colorspace_safe_color(textureLod(color_tx, uv, 0.0));
|
||||
layer_weight = 1.0;
|
||||
/* Composite in focus. */
|
||||
out_color = out_color * (1.0 - layer_weight) + layer_color;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||
|
||||
#define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0))
|
||||
|
||||
|
@ -38,7 +39,7 @@ void main()
|
|||
/* Smooth the edges a bit to fade out the undersampling artifacts. */
|
||||
shapes = saturate(1.0 - linearstep(-0.8, 0.8, shapes));
|
||||
/* Outside of bokeh shape. Try to avoid overloading ROPs. */
|
||||
if (max_v4(shapes) == 0.0) {
|
||||
if (reduce_max(shapes) == 0.0) {
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
@ -52,7 +53,7 @@ void main()
|
|||
/* Occlude the sprite with geometry from the same field using a chebychev test (slide 85). */
|
||||
float mean = occlusion_data.x;
|
||||
float variance = occlusion_data.y;
|
||||
shapes *= variance * safe_rcp(variance + sqr(max(coc4 * correction_fac - mean, 0.0)));
|
||||
shapes *= variance * safe_rcp(variance + square(max(coc4 * correction_fac - mean, 0.0)));
|
||||
}
|
||||
|
||||
out_color = (interp_flat.color_and_coc1 * shapes[0] + interp_flat.color_and_coc2 * shapes[1] +
|
||||
|
@ -61,6 +62,6 @@ void main()
|
|||
out_color.a = 0.0;
|
||||
|
||||
if (debug_scatter_perf) {
|
||||
out_color.rgb = avg(out_color.rgb) * vec3(1.0, 0.0, 0.0);
|
||||
out_color.rgb = average(out_color.rgb) * vec3(1.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -36,7 +37,7 @@ void main()
|
|||
interp_noperspective.rect_uv3 = ((uv + quad_offsets[2]) * uv_div) * 0.5 + 0.5;
|
||||
interp_noperspective.rect_uv4 = ((uv + quad_offsets[3]) * uv_div) * 0.5 + 0.5;
|
||||
/* Only for sampling. */
|
||||
interp_flat.distance_scale *= max_v2(abs(rect.half_extent));
|
||||
interp_flat.distance_scale *= reduce_max(abs(rect.half_extent));
|
||||
}
|
||||
else {
|
||||
interp_flat.distance_scale = 1.0;
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
* Half-resolution Color, signed CoC (out_coc.x), and max slight focus abs CoC (out_coc.y).
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -29,7 +30,7 @@ void main()
|
|||
for (int i = 0; i < 4; i++) {
|
||||
vec2 sample_uv = quad_center + quad_offsets[i] * fullres_texel_size;
|
||||
/* NOTE: We use samplers without filtering. */
|
||||
colors[i] = safe_color(textureLod(color_tx, sample_uv, 0.0));
|
||||
colors[i] = colorspace_safe_color(textureLod(color_tx, sample_uv, 0.0));
|
||||
cocs[i] = dof_coc_from_depth(dof_buf, sample_uv, textureLod(depth_tx, sample_uv, 0.0).r);
|
||||
}
|
||||
|
||||
|
@ -38,7 +39,7 @@ void main()
|
|||
vec4 weights = dof_bilateral_coc_weights(cocs);
|
||||
weights *= dof_bilateral_color_weights(colors);
|
||||
/* Normalize so that the sum is 1. */
|
||||
weights *= safe_rcp(sum(weights));
|
||||
weights *= safe_rcp(reduce_add(weights));
|
||||
|
||||
ivec2 out_texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
vec4 out_color = weighted_sum_array(colors, weights);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* - Stabilized Color and CoC (half-resolution).
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
|
||||
|
@ -263,7 +262,7 @@ DofSample dof_sample_history(vec2 input_texel)
|
|||
color += textureLod(in_history_tx, vec2(uv_3.x, uv_12.y), 0.0) * weight_cross.z;
|
||||
color += textureLod(in_history_tx, vec2(uv_12.x, uv_3.y), 0.0) * weight_cross.w;
|
||||
/* Re-normalize for the removed corners. */
|
||||
color /= (weight_center + sum(weight_cross));
|
||||
color /= (weight_center + reduce_add(weight_cross));
|
||||
#endif
|
||||
/* NOTE(fclem): Opacity is wrong on purpose. Final Opacity does not rely on history. */
|
||||
return DofSample(color.xyzz, color.w);
|
||||
|
@ -306,7 +305,7 @@ float dof_history_blend_factor(
|
|||
* "High Quality Temporal Supersampling" by Brian Karis at Siggraph 2014 (Slide 43)
|
||||
* Bias towards history if incoming pixel is near clamping. Reduces flicker.
|
||||
*/
|
||||
float distance_to_luma_clip = min_v2(vec2(luma_history - luma_min, luma_max - luma_history));
|
||||
float distance_to_luma_clip = reduce_min(vec2(luma_history - luma_min, luma_max - luma_history));
|
||||
/* Divide by bbox size to get a factor. 2 factor to compensate the line above. */
|
||||
distance_to_luma_clip *= 2.0 * safe_rcp(luma_max - luma_min);
|
||||
/* Linearly blend when history gets below to 25% of the bbox size. */
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(eevee_spherical_harmonics_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_matrix_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -24,7 +24,7 @@ void main()
|
|||
float validity = texelFetch(validity_tx, cell, 0).r;
|
||||
|
||||
vec3 vN = vec3(lP, sqrt(max(0.0, 1.0 - dist_sqr)));
|
||||
vec3 N = normal_view_to_world(vN);
|
||||
vec3 N = drw_normal_view_to_world(vN);
|
||||
vec3 lN = transform_direction(world_to_grid, N);
|
||||
|
||||
vec3 irradiance = spherical_harmonics_evaluate_lambert(lN, sh);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_lightprobe_lib.glsl)
|
||||
|
||||
void main()
|
||||
|
@ -35,9 +35,9 @@ void main()
|
|||
}
|
||||
|
||||
vec3 vs_offset = vec3(lP, 0.0) * sphere_radius_final;
|
||||
vec3 vP = (ViewMatrix * vec4(ws_cell_pos, 1.0)).xyz + vs_offset;
|
||||
vec3 vP = drw_point_world_to_view(ws_cell_pos) + vs_offset;
|
||||
|
||||
gl_Position = ProjectionMatrix * vec4(vP, 1.0);
|
||||
gl_Position = drw_point_view_to_homogenous(vP);
|
||||
/* Small bias to let the icon draw without Z-fighting. */
|
||||
gl_Position.z += 0.0001;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_film_lib.glsl)
|
||||
|
||||
void main()
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
|
||||
#define CRYPTOMATTE_LEVELS_MAX 16
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_film_lib.glsl)
|
||||
|
||||
void main()
|
||||
|
@ -33,7 +32,7 @@ void main()
|
|||
film_process_data(texel_film, out_color, out_depth);
|
||||
}
|
||||
|
||||
gl_FragDepth = get_depth_from_view_z(-out_depth);
|
||||
gl_FragDepth = drw_depth_view_to_screen(-out_depth);
|
||||
|
||||
gl_FragDepth = film_display_depth_ammend(texel_film, gl_FragDepth);
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
* Film accumulation utils functions.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_camera_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_cryptomatte_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
|
||||
|
||||
/* Return scene linear Z depth from the camera or radial depth for panoramic cameras. */
|
||||
float film_depth_convert_to_scene(float depth)
|
||||
|
@ -20,7 +20,7 @@ float film_depth_convert_to_scene(float depth)
|
|||
/* TODO */
|
||||
return 1.0;
|
||||
}
|
||||
return abs(get_view_z_from_depth(depth));
|
||||
return abs(drw_depth_screen_to_view(depth));
|
||||
}
|
||||
|
||||
/* Load a texture sample in a specific format. Combined pass needs to use this. */
|
||||
|
@ -70,7 +70,7 @@ FilmSample film_sample_get(int sample_n, ivec2 texel_film)
|
|||
* can be used by many final pixel. */
|
||||
vec2 offset = uniform_buf.film.subpixel_offset -
|
||||
vec2(texel_film % uniform_buf.film.scaling_factor);
|
||||
film_sample.weight = film_filter_weight(uniform_buf.film.filter_size, len_squared(offset));
|
||||
film_sample.weight = film_filter_weight(uniform_buf.film.filter_size, length_squared(offset));
|
||||
# endif
|
||||
|
||||
#endif /* PANORAMIC */
|
||||
|
@ -119,7 +119,7 @@ void film_sample_accum_mist(FilmSample samp, inout float accum)
|
|||
}
|
||||
float depth = texelFetch(depth_tx, samp.texel, 0).x;
|
||||
vec2 uv = (vec2(samp.texel) + 0.5) / vec2(textureSize(depth_tx, 0).xy);
|
||||
vec3 vP = get_view_space_from_depth(uv, depth);
|
||||
vec3 vP = drw_point_screen_to_view(vec3(uv, depth));
|
||||
bool is_persp = ProjectionMatrix[3][3] == 0.0;
|
||||
float mist = (is_persp) ? length(vP) : abs(vP.z);
|
||||
/* Remap to 0..1 range. */
|
||||
|
@ -312,7 +312,7 @@ vec4 film_sample_catmull_rom(sampler2D color_tx, vec2 input_texel)
|
|||
color += textureLod(color_tx, vec2(uv_3.x, uv_12.y), 0.0) * weight_cross.z;
|
||||
color += textureLod(color_tx, vec2(uv_12.x, uv_3.y), 0.0) * weight_cross.w;
|
||||
/* Re-normalize for the removed corners. */
|
||||
return color / (weight_center + sum(weight_cross));
|
||||
return color / (weight_center + reduce_add(weight_cross));
|
||||
|
||||
#else /* Nearest interpolation for debugging. 1 Tap. */
|
||||
ivec2 texel = ivec2(center_texel) + ivec2(greaterThan(inter_texel, vec2(0.5)));
|
||||
|
@ -343,7 +343,7 @@ void film_combined_neighbor_boundbox(ivec2 texel, out vec4 min_c, out vec4 max_c
|
|||
for (int i = 0; i < 5; i++) {
|
||||
vec4 color = film_texelfetch_as_YCoCg_opacity(combined_tx, texel + plus_offsets[i]);
|
||||
mu1 += color;
|
||||
mu2 += sqr(color);
|
||||
mu2 += square(color);
|
||||
}
|
||||
mu1 *= (1.0 / 5.0);
|
||||
mu2 *= (1.0 / 5.0);
|
||||
|
@ -352,7 +352,7 @@ void film_combined_neighbor_boundbox(ivec2 texel, out vec4 min_c, out vec4 max_c
|
|||
* Balance between more flickering (0.75) or more ghosting (1.25). */
|
||||
const float gamma = 1.25;
|
||||
/* Standard deviation. */
|
||||
vec4 sigma = sqrt(abs(mu2 - sqr(mu1)));
|
||||
vec4 sigma = sqrt(abs(mu2 - square(mu1)));
|
||||
/* eq. 6 in "A Survey of Temporal Anti-aliasing Techniques". */
|
||||
min_c = mu1 - gamma * sigma;
|
||||
max_c = mu1 + gamma * sigma;
|
||||
|
@ -425,7 +425,7 @@ float film_history_blend_factor(float velocity,
|
|||
* "High Quality Temporal Supersampling" by Brian Karis at Siggraph 2014 (Slide 43)
|
||||
* Bias towards history if incoming pixel is near clamping. Reduces flicker.
|
||||
*/
|
||||
float distance_to_luma_clip = min_v2(vec2(luma_history - luma_min, luma_max - luma_history));
|
||||
float distance_to_luma_clip = reduce_min(vec2(luma_history - luma_min, luma_max - luma_history));
|
||||
/* Divide by bbox size to get a factor. 2 factor to compensate the line above. */
|
||||
distance_to_luma_clip *= 2.0 * safe_rcp(luma_max - luma_min);
|
||||
/* Linearly blend when history gets below to 25% of the bbox size. */
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_hair_lib.glsl) /* TODO rename to curve. */
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_model_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_hair_lib.glsl) /* TODO rename to curve. */
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -58,5 +57,5 @@ void main()
|
|||
clip_interp.clip_distance = dot(clip_plane.plane, vec4(interp.P, 1.0));
|
||||
#endif
|
||||
|
||||
gl_Position = point_world_to_ndc(interp.P);
|
||||
gl_Position = drw_point_world_to_homogenous(interp.P);
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_gpencil_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_model_lib.glsl)
|
||||
/* Grease pencil includes commmon_view_lib. */
|
||||
// #pragma BLENDER_REQUIRE(common_gpencil_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
|
||||
|
@ -38,7 +39,7 @@ void main()
|
|||
hardness);
|
||||
#ifdef MAT_VELOCITY
|
||||
/* GPencil do not support deformation motion blur. */
|
||||
vec3 lP_curr = transform_point(ModelMatrixInverse, interp.P);
|
||||
vec3 lP_curr = drw_point_world_to_object(interp.P);
|
||||
/* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
|
||||
* ignores motion from animated displacement. Supporting animated displacement motion vectors
|
||||
* would require evaluating the node-tree multiple time with different node-tree UBOs evaluated
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_model_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
|
||||
|
@ -17,8 +17,8 @@ void main()
|
|||
|
||||
init_interface();
|
||||
|
||||
interp.P = point_object_to_world(pos);
|
||||
interp.N = normal_object_to_world(nor);
|
||||
interp.P = drw_point_object_to_world(pos);
|
||||
interp.N = drw_normal_object_to_world(nor);
|
||||
#ifdef MAT_VELOCITY
|
||||
vec3 prv, nxt;
|
||||
velocity_local_pos_get(pos, gl_VertexID, prv, nxt);
|
||||
|
@ -39,5 +39,5 @@ void main()
|
|||
clip_interp.clip_distance = dot(clip_plane.plane, vec4(interp.P, 1.0));
|
||||
#endif
|
||||
|
||||
gl_Position = point_world_to_ndc(interp.P);
|
||||
gl_Position = drw_point_world_to_homogenous(interp.P);
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(draw_model_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_rotation_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -27,11 +27,11 @@ void main()
|
|||
* Apply a bias to avoid self-shadow issues. */
|
||||
/* TODO(fclem): remove multiplication here. Here only for keeping the size correct for now. */
|
||||
float actual_radius = point_cloud_interp.radius * 0.01;
|
||||
interp.P -= cameraVec(interp.P) * actual_radius;
|
||||
interp.P -= drw_world_incident_vector(interp.P) * actual_radius;
|
||||
#endif
|
||||
|
||||
#ifdef MAT_VELOCITY
|
||||
vec3 lP = point_world_to_object(point_cloud_interp.position);
|
||||
vec3 lP = drw_point_world_to_object(point_cloud_interp.position);
|
||||
vec3 prv, nxt;
|
||||
velocity_local_pos_get(lP, point_cloud_interp_flat.id, prv, nxt);
|
||||
/* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
|
||||
|
@ -51,5 +51,5 @@ void main()
|
|||
clip_interp.clip_distance = dot(clip_plane.plane, vec4(interp.P, 1.0));
|
||||
#endif
|
||||
|
||||
gl_Position = point_world_to_ndc(interp.P);
|
||||
gl_Position = drw_point_world_to_homogenous(interp.P);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Custom full-screen triangle with placeholders varyings.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
|
||||
|
||||
|
@ -19,6 +19,6 @@ void main()
|
|||
gl_Position = vec4(x, y, 1.0, 1.0);
|
||||
|
||||
/* Pass view position to keep accuracy. */
|
||||
interp.P = project_point(ProjectionMatrixInverse, gl_Position.xyz);
|
||||
interp.P = drw_point_ndc_to_view(gl_Position.xyz);
|
||||
interp.N = vec3(1);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* downsample to max level.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||
|
||||
shared float local_depths[gl_WorkGroupSize.y][gl_WorkGroupSize.x];
|
||||
|
||||
|
@ -59,7 +59,7 @@ void main()
|
|||
}
|
||||
|
||||
/* Level 1. (No load) */
|
||||
float max_depth = max_v4(samp);
|
||||
float max_depth = reduce_max(samp);
|
||||
ivec2 dst_px = ivec2(kernel_origin + local_px);
|
||||
imageStore(out_mip_1, dst_px, vec4(max_depth));
|
||||
store_local_depth(local_px, max_depth);
|
||||
|
@ -72,7 +72,7 @@ void main()
|
|||
active_thread = all(lessThan(uvec2(local_px), gl_WorkGroupSize.xy >> uint(mask_shift))); \
|
||||
barrier(); /* Wait for previous writes to finish. */ \
|
||||
if (active_thread) { \
|
||||
max_depth = max_v4(load_local_depths(local_px)); \
|
||||
max_depth = reduce_max(load_local_depths(local_px)); \
|
||||
dst_px = ivec2((kernel_origin >> mask_shift) + local_px); \
|
||||
imageStore(out_mip__, dst_px, vec4(max_depth)); \
|
||||
} \
|
||||
|
@ -109,7 +109,7 @@ void main()
|
|||
samp.z = imageLoad(out_mip_5, min(src_px + ivec2(1, 0), image_border)).x;
|
||||
samp.w = imageLoad(out_mip_5, min(src_px + ivec2(0, 0), image_border)).x;
|
||||
/* Level 6. */
|
||||
float max_depth = max_v4(samp);
|
||||
float max_depth = reduce_max(samp);
|
||||
ivec2 dst_px = ivec2(kernel_origin + local_px);
|
||||
imageStore(out_mip_6, dst_px, vec4(max_depth));
|
||||
store_local_depth(local_px, max_depth);
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
* pass is not conservative enough).
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_debug_gradients_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_light_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_light_iter_lib.glsl)
|
||||
|
||||
|
@ -18,8 +18,8 @@ void main()
|
|||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
|
||||
float depth = texelFetch(hiz_tx, texel, 0).r;
|
||||
float vP_z = get_view_z_from_depth(depth);
|
||||
vec3 P = get_world_space_from_depth(uvcoordsvar.xy, depth);
|
||||
float vP_z = drw_depth_screen_to_view(depth);
|
||||
vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth));
|
||||
|
||||
float light_count = 0.0;
|
||||
uint light_cull = 0u;
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* Select the visible items inside the active view and put them inside the sorting buffer.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_intersect_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_intersect_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -62,7 +62,9 @@ void main()
|
|||
if (intersect_view(sphere)) {
|
||||
uint index = atomicAdd(light_cull_buf.visible_count, 1u);
|
||||
|
||||
out_zdist_buf[index] = dot(cameraForward, light._position) - dot(cameraForward, cameraPos);
|
||||
float z_dist = dot(drw_view_forward(), light._position) -
|
||||
dot(drw_view_forward(), drw_view_position());
|
||||
out_zdist_buf[index] = z_dist;
|
||||
out_key_buf[index] = l_idx;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* One thread processes one Light entity.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
|
||||
shared float zdists_cache[gl_WorkGroupSize.x];
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Dispatch one thread per word.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_intersect_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_light_iter_lib.glsl)
|
||||
|
||||
|
@ -148,10 +148,10 @@ void main()
|
|||
LightData light = light_buf[l_idx];
|
||||
|
||||
/* Culling in view space for precision and simplicity. */
|
||||
vec3 vP = transform_point(ViewMatrix, light._position);
|
||||
vec3 v_right = transform_direction(ViewMatrix, light._right);
|
||||
vec3 v_up = transform_direction(ViewMatrix, light._up);
|
||||
vec3 v_back = transform_direction(ViewMatrix, light._back);
|
||||
vec3 vP = drw_point_world_to_view(light._position);
|
||||
vec3 v_right = drw_normal_world_to_view(light._right);
|
||||
vec3 v_up = drw_normal_world_to_view(light._up);
|
||||
vec3 v_back = drw_normal_world_to_view(light._back);
|
||||
float radius = light.influence_radius_max;
|
||||
|
||||
Sphere sphere = shape_sphere(vP, radius);
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
* For this reason, we only dispatch 1 thread group.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_light_iter_lib.glsl)
|
||||
|
||||
/* Fits the limit of 32KB. */
|
||||
|
@ -37,7 +38,7 @@ void main()
|
|||
vec3 P = light_buf[index]._position;
|
||||
/* TODO(fclem): Could have better bounds for spot and area lights. */
|
||||
float radius = light_buf[index].influence_radius_max;
|
||||
float z_dist = dot(cameraForward, P) - dot(cameraForward, cameraPos);
|
||||
float z_dist = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
|
||||
int z_min = culling_z_to_zbin(
|
||||
light_cull_buf.zbin_scale, light_cull_buf.zbin_bias, z_dist + radius);
|
||||
int z_max = culling_z_to_zbin(
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue