Fix #104016: Resolve Metal LineLoop emulation. #105142
|
@ -432,7 +432,10 @@ def external_scripts_update(args: argparse.Namespace,
|
|||
# Switch to branch and pull.
|
||||
if submodule_branch:
|
||||
if make_utils.git_branch(args.git_command) != submodule_branch:
|
||||
call([args.git_command, "checkout", submodule_branch])
|
||||
if make_utils.git_remote_exist(args.git_command, "origin"):
|
||||
call([args.git_command, "checkout", "-t", f"origin/{submodule_branch}"])
|
||||
elif make_utils.git_remote_exist(args.git_command, "upstream"):
|
||||
call([args.git_command, "checkout", "-t", f"upstream/{submodule_branch}"])
|
||||
# Don't use extra fetch since all remotes of interest have been already fetched
|
||||
# some lines above.
|
||||
skip_msg += work_tree_update(args, use_fetch=False)
|
||||
|
|
|
@ -54,44 +54,10 @@ int BlenderDisplayShader::get_tex_coord_attrib_location()
|
|||
/* --------------------------------------------------------------------
|
||||
* BlenderFallbackDisplayShader.
|
||||
*/
|
||||
|
||||
/* TODO move shaders to standalone .glsl file. */
|
||||
static const char *FALLBACK_VERTEX_SHADER =
|
||||
"uniform vec2 fullscreen;\n"
|
||||
"in vec2 texCoord;\n"
|
||||
"in vec2 pos;\n"
|
||||
"out vec2 texCoord_interp;\n"
|
||||
"\n"
|
||||
"vec2 normalize_coordinates()\n"
|
||||
"{\n"
|
||||
" return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n"
|
||||
" texCoord_interp = texCoord;\n"
|
||||
"}\n\0";
|
||||
|
||||
static const char *FALLBACK_FRAGMENT_SHADER =
|
||||
"uniform sampler2D image_texture;\n"
|
||||
"in vec2 texCoord_interp;\n"
|
||||
"out vec4 fragColor;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" fragColor = texture(image_texture, texCoord_interp);\n"
|
||||
"}\n\0";
|
||||
|
||||
static GPUShader *compile_fallback_shader(void)
|
||||
{
|
||||
/* NOTE: Compilation errors are logged to console. */
|
||||
GPUShader *shader = GPU_shader_create(FALLBACK_VERTEX_SHADER,
|
||||
FALLBACK_FRAGMENT_SHADER,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"FallbackCyclesBlitShader");
|
||||
GPUShader *shader = GPU_shader_create_from_info_name("gpu_shader_cycles_display_fallback");
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ class MetalDevice : public Device {
|
|||
id<MTLArgumentEncoder> mtlAncillaryArgEncoder =
|
||||
nil; /* encoder used for fetching device pointers from MTLBuffers */
|
||||
string source[PSO_NUM];
|
||||
string source_md5[PSO_NUM];
|
||||
string kernels_md5[PSO_NUM];
|
||||
string global_defines_md5[PSO_NUM];
|
||||
|
||||
bool capture_enabled = false;
|
||||
|
||||
|
@ -112,6 +113,8 @@ class MetalDevice : public Device {
|
|||
|
||||
bool use_local_atomic_sort() const;
|
||||
|
||||
string preprocess_source(MetalPipelineType pso_type, const uint kernel_features, string* source = nullptr);
|
||||
|
||||
bool make_source_and_check_if_compile_needed(MetalPipelineType pso_type);
|
||||
|
||||
void make_source(MetalPipelineType pso_type, const uint kernel_features);
|
||||
|
|
|
@ -299,7 +299,7 @@ bool MetalDevice::use_local_atomic_sort() const
|
|||
return DebugFlags().metal.use_local_atomic_sort;
|
||||
}
|
||||
|
||||
void MetalDevice::make_source(MetalPipelineType pso_type, const uint kernel_features)
|
||||
string MetalDevice::preprocess_source(MetalPipelineType pso_type, const uint kernel_features, string* source)
|
||||
{
|
||||
string global_defines;
|
||||
if (use_adaptive_compilation()) {
|
||||
|
@ -339,70 +339,70 @@ void MetalDevice::make_source(MetalPipelineType pso_type, const uint kernel_feat
|
|||
NSOperatingSystemVersion macos_ver = [processInfo operatingSystemVersion];
|
||||
global_defines += "#define __KERNEL_METAL_MACOS__ " + to_string(macos_ver.majorVersion) + "\n";
|
||||
|
||||
string &source = this->source[pso_type];
|
||||
source = "\n#include \"kernel/device/metal/kernel.metal\"\n";
|
||||
source = path_source_replace_includes(source, path_get("source"));
|
||||
|
||||
/* Perform any required specialization on the source.
|
||||
* With Metal function constants we can generate a single variant of the kernel source which can
|
||||
* be repeatedly respecialized.
|
||||
*/
|
||||
string baked_constants;
|
||||
|
||||
/* Replace specific KernelData "dot" dereferences with a Metal function_constant identifier of
|
||||
* the same character length. Build a string of all active constant values which is then hashed
|
||||
* in order to identify the PSO.
|
||||
*/
|
||||
if (pso_type != PSO_GENERIC) {
|
||||
const double starttime = time_dt();
|
||||
if (source) {
|
||||
const double starttime = time_dt();
|
||||
|
||||
# define KERNEL_STRUCT_BEGIN(name, parent) \
|
||||
string_replace_same_length(source, "kernel_data." #parent ".", "kernel_data_" #parent "_");
|
||||
string_replace_same_length(*source, "kernel_data." #parent ".", "kernel_data_" #parent "_");
|
||||
|
||||
bool next_member_is_specialized = true;
|
||||
bool next_member_is_specialized = true;
|
||||
|
||||
# define KERNEL_STRUCT_MEMBER_DONT_SPECIALIZE next_member_is_specialized = false;
|
||||
|
||||
/* Add constants to md5 so that 'get_best_pipeline' is able to return a suitable match. */
|
||||
# define KERNEL_STRUCT_MEMBER(parent, _type, name) \
|
||||
if (next_member_is_specialized) { \
|
||||
baked_constants += string(#parent "." #name "=") + \
|
||||
to_string(_type(launch_params.data.parent.name)) + "\n"; \
|
||||
} \
|
||||
else { \
|
||||
string_replace( \
|
||||
source, "kernel_data_" #parent "_" #name, "kernel_data." #parent ".__unused_" #name); \
|
||||
next_member_is_specialized = true; \
|
||||
}
|
||||
if (!next_member_is_specialized) { \
|
||||
string_replace( \
|
||||
*source, "kernel_data_" #parent "_" #name, "kernel_data." #parent ".__unused_" #name); \
|
||||
next_member_is_specialized = true; \
|
||||
}
|
||||
|
||||
# include "kernel/data_template.h"
|
||||
|
||||
# undef KERNEL_STRUCT_MEMBER
|
||||
# undef KERNEL_STRUCT_MEMBER_DONT_SPECIALIZE
|
||||
# undef KERNEL_STRUCT_BEGIN
|
||||
|
||||
metal_printf("KernelData patching took %.1f ms\n", (time_dt() - starttime) * 1000.0);
|
||||
}
|
||||
|
||||
/* Opt in to all of available specializations. This can be made more granular for the
|
||||
* PSO_SPECIALIZED_INTERSECT case in order to minimize the number of specialization requests,
|
||||
* but the overhead should be negligible as these are very quick to (re)build and aren't
|
||||
* serialized to disk via MTLBinaryArchives.
|
||||
*/
|
||||
global_defines += "#define __KERNEL_USE_DATA_CONSTANTS__\n";
|
||||
|
||||
metal_printf("KernelData patching took %.1f ms\n", (time_dt() - starttime) * 1000.0);
|
||||
}
|
||||
|
||||
source = global_defines + source;
|
||||
# if 0
|
||||
metal_printf("================\n%s================\n\%s================\n",
|
||||
global_defines.c_str(),
|
||||
baked_constants.c_str());
|
||||
metal_printf("================\n%s================\n",
|
||||
global_defines.c_str());
|
||||
# endif
|
||||
|
||||
/* Generate an MD5 from the source and include any baked constants. This is used when caching
|
||||
* PSOs. */
|
||||
MD5Hash md5;
|
||||
md5.append(baked_constants);
|
||||
md5.append(source);
|
||||
if (use_metalrt) {
|
||||
md5.append(std::to_string(kernel_features & METALRT_FEATURE_MASK));
|
||||
if (source) {
|
||||
*source = global_defines + *source;
|
||||
}
|
||||
source_md5[pso_type] = md5.get_hex();
|
||||
|
||||
MD5Hash md5;
|
||||
md5.append(global_defines);
|
||||
return md5.get_hex();
|
||||
}
|
||||
|
||||
void MetalDevice::make_source(MetalPipelineType pso_type, const uint kernel_features)
|
||||
{
|
||||
string &source = this->source[pso_type];
|
||||
source = "\n#include \"kernel/device/metal/kernel.metal\"\n";
|
||||
source = path_source_replace_includes(source, path_get("source"));
|
||||
|
||||
/* Perform any required specialization on the source.
|
||||
* With Metal function constants we can generate a single variant of the kernel source which can
|
||||
* be repeatedly respecialized.
|
||||
*/
|
||||
global_defines_md5[pso_type] = preprocess_source(pso_type, kernel_features, &source);
|
||||
}
|
||||
|
||||
bool MetalDevice::load_kernels(const uint _kernel_features)
|
||||
|
@ -436,9 +436,45 @@ bool MetalDevice::load_kernels(const uint _kernel_features)
|
|||
|
||||
bool MetalDevice::make_source_and_check_if_compile_needed(MetalPipelineType pso_type)
|
||||
{
|
||||
if (this->source[pso_type].empty()) {
|
||||
string defines_md5 = preprocess_source(pso_type, kernel_features);
|
||||
|
||||
/* Rebuild the source string if the injected block of #defines has changed. */
|
||||
if (global_defines_md5[pso_type] != defines_md5) {
|
||||
make_source(pso_type, kernel_features);
|
||||
}
|
||||
|
||||
string constant_values;
|
||||
if (pso_type != PSO_GENERIC) {
|
||||
bool next_member_is_specialized = true;
|
||||
|
||||
# define KERNEL_STRUCT_MEMBER_DONT_SPECIALIZE next_member_is_specialized = false;
|
||||
|
||||
/* Add specialization constants to md5 so that 'get_best_pipeline' is able to return a suitable match. */
|
||||
# define KERNEL_STRUCT_MEMBER(parent, _type, name) \
|
||||
if (next_member_is_specialized) { \
|
||||
constant_values += string(#parent "." #name "=") + \
|
||||
to_string(_type(launch_params.data.parent.name)) + "\n"; \
|
||||
} \
|
||||
else { \
|
||||
next_member_is_specialized = true; \
|
||||
}
|
||||
|
||||
# include "kernel/data_template.h"
|
||||
|
||||
# undef KERNEL_STRUCT_MEMBER
|
||||
# undef KERNEL_STRUCT_MEMBER_DONT_SPECIALIZE
|
||||
|
||||
# if 0
|
||||
metal_printf("================\n%s================\n",
|
||||
constant_values.c_str());
|
||||
# endif
|
||||
}
|
||||
|
||||
MD5Hash md5;
|
||||
md5.append(constant_values);
|
||||
md5.append(source[pso_type]);
|
||||
kernels_md5[pso_type] = md5.get_hex();
|
||||
|
||||
return MetalDeviceKernels::should_load_kernels(this, pso_type);
|
||||
}
|
||||
|
||||
|
@ -866,6 +902,11 @@ void MetalDevice::cancel()
|
|||
|
||||
bool MetalDevice::is_ready(string &status) const
|
||||
{
|
||||
if (!error_msg.empty()) {
|
||||
/* Avoid hanging if we had an error. */
|
||||
return true;
|
||||
}
|
||||
|
||||
int num_loaded = MetalDeviceKernels::get_loaded_kernel_count(this, PSO_GENERIC);
|
||||
if (num_loaded < DEVICE_KERNEL_NUM) {
|
||||
status = string_printf("%d / %d render kernels loaded (may take a few minutes the first time)",
|
||||
|
|
|
@ -76,7 +76,7 @@ struct MetalKernelPipeline {
|
|||
|
||||
id<MTLLibrary> mtlLibrary = nil;
|
||||
MetalPipelineType pso_type;
|
||||
string source_md5;
|
||||
string kernels_md5;
|
||||
size_t usage_count = 0;
|
||||
|
||||
KernelData kernel_data_;
|
||||
|
|
|
@ -292,7 +292,7 @@ bool ShaderCache::should_load_kernel(DeviceKernel device_kernel,
|
|||
/* check whether the kernel has already been requested / cached */
|
||||
thread_scoped_lock lock(cache_mutex);
|
||||
for (auto &pipeline : pipelines[device_kernel]) {
|
||||
if (pipeline->source_md5 == device->source_md5[pso_type]) {
|
||||
if (pipeline->kernels_md5 == device->kernels_md5[pso_type]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ void ShaderCache::load_kernel(DeviceKernel device_kernel,
|
|||
memcpy(&pipeline->kernel_data_, &device->launch_params.data, sizeof(pipeline->kernel_data_));
|
||||
pipeline->pso_type = pso_type;
|
||||
pipeline->mtlDevice = mtlDevice;
|
||||
pipeline->source_md5 = device->source_md5[pso_type];
|
||||
pipeline->kernels_md5 = device->kernels_md5[pso_type];
|
||||
pipeline->mtlLibrary = device->mtlLibrary[pso_type];
|
||||
pipeline->device_kernel = device_kernel;
|
||||
pipeline->threads_per_threadgroup = device->max_threads_per_threadgroup;
|
||||
|
@ -392,8 +392,8 @@ MetalKernelPipeline *ShaderCache::get_best_pipeline(DeviceKernel kernel, const M
|
|||
}
|
||||
|
||||
if (pipeline->pso_type != PSO_GENERIC) {
|
||||
if (pipeline->source_md5 == device->source_md5[PSO_SPECIALIZED_INTERSECT] ||
|
||||
pipeline->source_md5 == device->source_md5[PSO_SPECIALIZED_SHADE]) {
|
||||
if (pipeline->kernels_md5 == device->kernels_md5[PSO_SPECIALIZED_INTERSECT] ||
|
||||
pipeline->kernels_md5 == device->kernels_md5[PSO_SPECIALIZED_SHADE]) {
|
||||
best_pipeline = pipeline.get();
|
||||
}
|
||||
}
|
||||
|
@ -428,11 +428,12 @@ bool MetalKernelPipeline::should_use_binary_archive() const
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Workaround for Intel GPU having issue using Binary Archives */
|
||||
MetalGPUVendor gpu_vendor = MetalInfo::get_device_vendor(mtlDevice);
|
||||
if (gpu_vendor == METAL_GPU_INTEL) {
|
||||
return false;
|
||||
else {
|
||||
/* Workaround for issues using Binary Archives on non-Apple Silicon systems. */
|
||||
MetalGPUVendor gpu_vendor = MetalInfo::get_device_vendor(mtlDevice);
|
||||
if (gpu_vendor != METAL_GPU_APPLE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pso_type == PSO_GENERIC) {
|
||||
|
@ -440,8 +441,10 @@ bool MetalKernelPipeline::should_use_binary_archive() const
|
|||
return true;
|
||||
}
|
||||
|
||||
if (device_kernel >= DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND &&
|
||||
device_kernel <= DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW) {
|
||||
if ((device_kernel >= DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND &&
|
||||
device_kernel <= DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW) ||
|
||||
(device_kernel >= DEVICE_KERNEL_SHADER_EVAL_DISPLACE &&
|
||||
device_kernel <= DEVICE_KERNEL_SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY)) {
|
||||
/* Archive all shade kernels - they take a long time to compile. */
|
||||
return true;
|
||||
}
|
||||
|
@ -674,7 +677,7 @@ void MetalKernelPipeline::compile()
|
|||
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
|
||||
string osVersion = [[processInfo operatingSystemVersionString] UTF8String];
|
||||
MD5Hash local_md5;
|
||||
local_md5.append(source_md5);
|
||||
local_md5.append(kernels_md5);
|
||||
local_md5.append(osVersion);
|
||||
local_md5.append((uint8_t *)&this->threads_per_threadgroup,
|
||||
sizeof(this->threads_per_threadgroup));
|
||||
|
|
|
@ -997,6 +997,7 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
|
|||
import os
|
||||
import re
|
||||
import bpy.utils
|
||||
from bpy.app.translations import pgettext_iface as iface_
|
||||
|
||||
layout = self.layout
|
||||
|
||||
|
@ -1031,7 +1032,7 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
|
|||
name = display_name(filepath) if display_name else bpy.path.display_name(f)
|
||||
props = row.operator(
|
||||
operator,
|
||||
text=name,
|
||||
text=iface_(name),
|
||||
translate=False,
|
||||
)
|
||||
|
||||
|
@ -1073,7 +1074,6 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
|
|||
- preset_operator_defaults (dict of keyword args)
|
||||
"""
|
||||
import bpy
|
||||
from bpy.app.translations import pgettext_iface as iface_
|
||||
ext_valid = getattr(self, "preset_extensions", {".py", ".xml"})
|
||||
props_default = getattr(self, "preset_operator_defaults", None)
|
||||
add_operator = getattr(self, "preset_add_operator", None)
|
||||
|
@ -1083,8 +1083,7 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
|
|||
props_default=props_default,
|
||||
filter_ext=lambda ext: ext.lower() in ext_valid,
|
||||
add_operator=add_operator,
|
||||
display_name=lambda name: iface_(
|
||||
bpy.path.display_name(name, title_case=False))
|
||||
display_name=lambda name: bpy.path.display_name(name, title_case=False)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -5631,6 +5631,8 @@ def km_curves(params):
|
|||
("curves.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||
("curves.delete", {"type": 'X', "value": 'PRESS'}, None),
|
||||
("curves.delete", {"type": 'DEL', "value": 'PRESS'}, None),
|
||||
*_template_items_proportional_editing(
|
||||
params, connected=True, toggle_data_path='tool_settings.use_proportional_edit'),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
from bpy.types import Panel
|
||||
from bpy.app.translations import contexts as i18n_contexts
|
||||
|
||||
|
||||
class ObjectConstraintPanel:
|
||||
|
|
|
@ -1408,6 +1408,7 @@ class _defs_sculpt:
|
|||
def draw_settings(_context, layout, tool):
|
||||
props = tool.operator_properties("sculpt.trim_box_gesture")
|
||||
layout.prop(props, "trim_mode", expand=False)
|
||||
layout.prop(props, "trim_orientation", expand=False)
|
||||
layout.prop(props, "trim_extrude_mode", expand=False)
|
||||
layout.prop(props, "use_cursor_depth", expand=False)
|
||||
return dict(
|
||||
|
|
|
@ -1067,10 +1067,10 @@ class VIEW3D_MT_transform(VIEW3D_MT_transform_base, Menu):
|
|||
elif context.mode == 'EDIT_CURVE':
|
||||
layout.operator("transform.transform", text="Radius").mode = 'CURVE_SHRINKFATTEN'
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("transform.translate", text="Move Texture Space").texture_space = True
|
||||
layout.operator("transform.resize", text="Scale Texture Space").texture_space = True
|
||||
if context.mode != 'EDIT_CURVES':
|
||||
layout.separator()
|
||||
layout.operator("transform.translate", text="Move Texture Space").texture_space = True
|
||||
layout.operator("transform.resize", text="Scale Texture Space").texture_space = True
|
||||
|
||||
|
||||
# Object-specific extensions to Transform menu
|
||||
|
@ -6195,6 +6195,7 @@ class VIEW3D_PT_shading_compositor(Panel):
|
|||
bl_region_type = 'HEADER'
|
||||
bl_label = "Compositor"
|
||||
bl_parent_id = 'VIEW3D_PT_shading'
|
||||
bl_order = 10
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
|
|
@ -1337,8 +1337,6 @@ static void layerCopyValue_propcol(const void *source,
|
|||
memcpy(tmp_col, m1->color, sizeof(tmp_col));
|
||||
}
|
||||
blend_color_interpolate_float(m2->color, m2->color, tmp_col, mixfactor);
|
||||
|
||||
copy_v4_v4(m2->color, m1->color);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -250,6 +250,88 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
|
|||
|
||||
/* ********** */
|
||||
|
||||
/**
|
||||
* When transfering color attributes, also transfer the active color attribute string.
|
||||
* If a match can't be found, use the first color layer that can be found (to ensure a valid string
|
||||
* is set).
|
||||
*/
|
||||
static void data_transfer_mesh_attributes_transfer_active_color_string(
|
||||
Mesh *mesh_dst, Mesh *mesh_src, const eAttrDomainMask mask_domain, const int data_type)
|
||||
{
|
||||
if (mesh_dst->active_color_attribute) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *active_color_src = BKE_id_attributes_active_color_name(&mesh_src->id);
|
||||
|
||||
if ((data_type == CD_PROP_COLOR) &&
|
||||
!BKE_id_attribute_search(&mesh_src->id, active_color_src, CD_MASK_PROP_COLOR, ATTR_DOMAIN_MASK_COLOR)) {
|
||||
return;
|
||||
}
|
||||
else if ((data_type == CD_PROP_BYTE_COLOR) &&
|
||||
!BKE_id_attribute_search(&mesh_src->id, active_color_src, CD_MASK_PROP_BYTE_COLOR, ATTR_DOMAIN_MASK_COLOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((data_type == CD_PROP_COLOR) &&
|
||||
BKE_id_attribute_search(&mesh_dst->id, active_color_src, CD_MASK_PROP_COLOR, ATTR_DOMAIN_MASK_COLOR)) {
|
||||
mesh_dst->active_color_attribute = BLI_strdup(active_color_src);
|
||||
}
|
||||
else if ((data_type == CD_PROP_BYTE_COLOR) &&
|
||||
BKE_id_attribute_search(&mesh_dst->id, active_color_src, CD_MASK_PROP_BYTE_COLOR, ATTR_DOMAIN_MASK_COLOR)) {
|
||||
mesh_dst->active_color_attribute = BLI_strdup(active_color_src);
|
||||
}
|
||||
else {
|
||||
CustomDataLayer *first_color_layer = BKE_id_attribute_from_index(
|
||||
&mesh_dst->id, 0, mask_domain, CD_MASK_COLOR_ALL);
|
||||
if (first_color_layer != nullptr) {
|
||||
mesh_dst->active_color_attribute = BLI_strdup(first_color_layer->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When transfering color attributes, also transfer the default color attribute string.
|
||||
* If a match cant be found, use the first color layer that can be found (to ensure a valid string
|
||||
* is set).
|
||||
*/
|
||||
static void data_transfer_mesh_attributes_transfer_default_color_string(
|
||||
Mesh *mesh_dst, Mesh *mesh_src, const eAttrDomainMask mask_domain, const int data_type)
|
||||
{
|
||||
if (mesh_dst->default_color_attribute) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *default_color_src = BKE_id_attributes_default_color_name(&mesh_src->id);
|
||||
|
||||
if ((data_type == CD_PROP_COLOR) &&
|
||||
!BKE_id_attribute_search(&mesh_src->id, default_color_src, CD_MASK_PROP_COLOR, ATTR_DOMAIN_MASK_COLOR)) {
|
||||
return;
|
||||
}
|
||||
else if ((data_type == CD_PROP_BYTE_COLOR) &&
|
||||
!BKE_id_attribute_search(&mesh_src->id, default_color_src, CD_MASK_PROP_BYTE_COLOR, ATTR_DOMAIN_MASK_COLOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((data_type == CD_PROP_COLOR) &&
|
||||
BKE_id_attribute_search(&mesh_dst->id, default_color_src, CD_MASK_PROP_COLOR, ATTR_DOMAIN_MASK_COLOR)) {
|
||||
mesh_dst->default_color_attribute = BLI_strdup(default_color_src);
|
||||
}
|
||||
else if ((data_type == CD_PROP_BYTE_COLOR) &&
|
||||
BKE_id_attribute_search(&mesh_dst->id, default_color_src, CD_MASK_PROP_BYTE_COLOR, ATTR_DOMAIN_MASK_COLOR)) {
|
||||
mesh_dst->default_color_attribute = BLI_strdup(default_color_src);
|
||||
}
|
||||
else {
|
||||
CustomDataLayer *first_color_layer = BKE_id_attribute_from_index(
|
||||
&mesh_dst->id, 0, mask_domain, CD_MASK_COLOR_ALL);
|
||||
if (first_color_layer != nullptr) {
|
||||
mesh_dst->default_color_attribute = BLI_strdup(first_color_layer->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ********** */
|
||||
|
||||
/* Generic pre/post processing, only used by custom loop normals currently. */
|
||||
|
||||
static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
|
||||
|
@ -1124,6 +1206,14 @@ void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
|
|||
fromlayers,
|
||||
tolayers,
|
||||
nullptr);
|
||||
/* Make sure we have active/defaut color layers if none existed before.
|
||||
* Use the active/defaut from src (if it was transferred), otherwise the first. */
|
||||
if (ELEM(cddata_type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) {
|
||||
data_transfer_mesh_attributes_transfer_active_color_string(
|
||||
me_dst, me_src, ATTR_DOMAIN_MASK_POINT, cddata_type);
|
||||
data_transfer_mesh_attributes_transfer_default_color_string(
|
||||
me_dst, me_src, ATTR_DOMAIN_MASK_POINT, cddata_type);
|
||||
}
|
||||
}
|
||||
if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
|
||||
const int num_elem_dst = me_dst->totedge;
|
||||
|
@ -1164,6 +1254,14 @@ void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
|
|||
fromlayers,
|
||||
tolayers,
|
||||
nullptr);
|
||||
/* Make sure we have active/defaut color layers if none existed before.
|
||||
* Use the active/defaut from src (if it was transferred), otherwise the first. */
|
||||
if (ELEM(cddata_type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) {
|
||||
data_transfer_mesh_attributes_transfer_active_color_string(
|
||||
me_dst, me_src, ATTR_DOMAIN_MASK_CORNER, cddata_type);
|
||||
data_transfer_mesh_attributes_transfer_default_color_string(
|
||||
me_dst, me_src, ATTR_DOMAIN_MASK_CORNER, cddata_type);
|
||||
}
|
||||
}
|
||||
if (DT_DATATYPE_IS_POLY(dtdata_type)) {
|
||||
const int num_elem_dst = me_dst->totpoly;
|
||||
|
|
|
@ -2267,6 +2267,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
|
|||
return pbvh;
|
||||
}
|
||||
|
||||
ob->sculpt->islands_valid = false;
|
||||
|
||||
if (ob->sculpt->bm != nullptr) {
|
||||
/* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
|
||||
pbvh = build_pbvh_for_dynamic_topology(ob);
|
||||
|
@ -2717,6 +2719,11 @@ static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob,
|
|||
if (attr) {
|
||||
sculpt_attr_update(ob, attr);
|
||||
|
||||
/* Since "stroke_only" is not a CustomData flag we have
|
||||
* to sync its parameter setting manually. Fixes #104618.
|
||||
*/
|
||||
attr->params.stroke_only = params->stroke_only;
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,8 +91,6 @@ struct SampleSegmentHint {
|
|||
* \param sample_length: The position to sample at.
|
||||
* \param r_segment_index: Returns the index of the segment that #sample_length is in.
|
||||
* \param r_factor: Returns the position within the segment.
|
||||
*
|
||||
* \note #sample_length must not be outside of any segment.
|
||||
*/
|
||||
inline void sample_at_length(const Span<float> accumulated_segment_lengths,
|
||||
const float sample_length,
|
||||
|
@ -105,7 +103,6 @@ inline void sample_at_length(const Span<float> accumulated_segment_lengths,
|
|||
|
||||
BLI_assert(lengths.size() > 0);
|
||||
BLI_assert(sample_length >= 0.0f);
|
||||
BLI_assert(sample_length <= lengths.last() + 0.00001f);
|
||||
|
||||
if (hint != nullptr && hint->segment_index >= 0) {
|
||||
const float length_in_segment = sample_length - hint->segment_start;
|
||||
|
|
|
@ -102,7 +102,7 @@ Closure closure_eval(ClosureTranslucent translucent)
|
|||
}
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(GlossyBSDF, Glossy)
|
||||
Closure closure_eval(ClosureReflection reflection)
|
||||
Closure closure_eval(ClosureReflection reflection, const bool do_output_ssr)
|
||||
{
|
||||
/* Glue with the old system. */
|
||||
CLOSURE_VARS_DECLARE_1(Glossy);
|
||||
|
@ -113,12 +113,22 @@ Closure closure_eval(ClosureReflection reflection)
|
|||
CLOSURE_EVAL_FUNCTION_1(GlossyBSDF, Glossy);
|
||||
|
||||
Closure closure = CLOSURE_DEFAULT;
|
||||
if (!output_ssr(reflection)) {
|
||||
|
||||
bool output_radiance = true;
|
||||
if (do_output_ssr) {
|
||||
output_radiance = !output_ssr(reflection);
|
||||
}
|
||||
if (output_radiance) {
|
||||
closure.radiance += out_Glossy_0.radiance * reflection.color * reflection.weight;
|
||||
}
|
||||
return closure;
|
||||
}
|
||||
|
||||
Closure closure_eval(ClosureReflection reflection)
|
||||
{
|
||||
return closure_eval(reflection, true);
|
||||
}
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(RefractionBSDF, Refraction)
|
||||
Closure closure_eval(ClosureRefraction refraction)
|
||||
{
|
||||
|
@ -155,6 +165,13 @@ Closure closure_eval(ClosureTransparency transparency)
|
|||
CLOSURE_EVAL_FUNCTION_DECLARE_2(GlassBSDF, Glossy, Refraction)
|
||||
Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction)
|
||||
{
|
||||
|
||||
#if defined(DO_SPLIT_CLOSURE_EVAL)
|
||||
Closure closure = closure_eval(refraction);
|
||||
Closure closure_reflection = closure_eval(reflection);
|
||||
closure.radiance += closure_reflection.radiance;
|
||||
return closure;
|
||||
#else
|
||||
/* Glue with the old system. */
|
||||
CLOSURE_VARS_DECLARE_2(Glossy, Refraction);
|
||||
|
||||
|
@ -172,12 +189,19 @@ Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction)
|
|||
closure.radiance += out_Glossy_0.radiance * reflection.color * reflection.weight;
|
||||
}
|
||||
return closure;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Dielectric BSDF */
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_2(DielectricBSDF, Diffuse, Glossy)
|
||||
Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection)
|
||||
{
|
||||
#if defined(DO_SPLIT_CLOSURE_EVAL)
|
||||
Closure closure = closure_eval(diffuse);
|
||||
Closure closure_reflection = closure_eval(reflection);
|
||||
closure.radiance += closure_reflection.radiance;
|
||||
return closure;
|
||||
#else
|
||||
/* Glue with the old system. */
|
||||
CLOSURE_VARS_DECLARE_2(Diffuse, Glossy);
|
||||
|
||||
|
@ -198,6 +222,7 @@ Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection)
|
|||
closure.radiance += out_Glossy_1.radiance * reflection.color * reflection.weight;
|
||||
}
|
||||
return closure;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Specular BSDF */
|
||||
|
@ -206,6 +231,13 @@ Closure closure_eval(ClosureDiffuse diffuse,
|
|||
ClosureReflection reflection,
|
||||
ClosureReflection clearcoat)
|
||||
{
|
||||
#if defined(DO_SPLIT_CLOSURE_EVAL)
|
||||
Closure closure = closure_eval(diffuse);
|
||||
Closure closure_reflection = closure_eval(reflection);
|
||||
Closure closure_clearcoat = closure_eval(clearcoat, false);
|
||||
closure.radiance += closure_reflection.radiance + closure_clearcoat.radiance;
|
||||
return closure;
|
||||
#else
|
||||
/* Glue with the old system. */
|
||||
CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy);
|
||||
|
||||
|
@ -229,6 +261,7 @@ Closure closure_eval(ClosureDiffuse diffuse,
|
|||
closure.radiance += out_Glossy_1.radiance * reflection.color * reflection.weight;
|
||||
}
|
||||
return closure;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Principled BSDF */
|
||||
|
@ -238,6 +271,15 @@ Closure closure_eval(ClosureDiffuse diffuse,
|
|||
ClosureReflection clearcoat,
|
||||
ClosureRefraction refraction)
|
||||
{
|
||||
#if defined(DO_SPLIT_CLOSURE_EVAL)
|
||||
Closure closure = closure_eval(diffuse);
|
||||
Closure closure_reflection = closure_eval(reflection);
|
||||
Closure closure_clearcoat = closure_eval(clearcoat, false);
|
||||
Closure closure_refraction = closure_eval(refraction);
|
||||
closure.radiance += closure_reflection.radiance + closure_clearcoat.radiance +
|
||||
closure_refraction.radiance;
|
||||
return closure;
|
||||
#else
|
||||
/* Glue with the old system. */
|
||||
CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction);
|
||||
|
||||
|
@ -263,11 +305,18 @@ Closure closure_eval(ClosureDiffuse diffuse,
|
|||
closure.radiance += out_Glossy_1.radiance * reflection.color * reflection.weight;
|
||||
}
|
||||
return closure;
|
||||
#endif
|
||||
}
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_2(PrincipledBSDFMetalClearCoat, Glossy, Glossy)
|
||||
Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat)
|
||||
{
|
||||
#if defined(DO_SPLIT_CLOSURE_EVAL)
|
||||
Closure closure = closure_eval(clearcoat);
|
||||
Closure closure_reflection = closure_eval(reflection);
|
||||
closure.radiance += closure_reflection.radiance;
|
||||
return closure;
|
||||
#else
|
||||
/* Glue with the old system. */
|
||||
CLOSURE_VARS_DECLARE_2(Glossy, Glossy);
|
||||
|
||||
|
@ -284,6 +333,7 @@ Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat)
|
|||
closure.radiance += out_Glossy_0.radiance * reflection.color * reflection.weight;
|
||||
}
|
||||
return closure;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Not supported for surface shaders. */
|
||||
|
|
|
@ -16,6 +16,14 @@ typedef struct CommonUniformBlock CommonUniformBlock;
|
|||
# endif
|
||||
#endif
|
||||
|
||||
/* NOTE: AMD-based macOS platforms experience performance and correctness issues with EEVEE
|
||||
* material closure evaluation. Using singular closure evaluation, rather than the compound
|
||||
* function calls reduces register overflow, by limiting the simultaneous number of live
|
||||
* registers used by the virtual GPU function stack. */
|
||||
#if (defined(GPU_METAL) && defined(GPU_ATI))
|
||||
# define DO_SPLIT_CLOSURE_EVAL 1
|
||||
#endif
|
||||
|
||||
struct CommonUniformBlock {
|
||||
mat4 pastViewProjectionMatrix;
|
||||
vec4 hizUvScale; /* To correct mip level texel misalignment */
|
||||
|
|
|
@ -4483,7 +4483,8 @@ void ANIM_channel_draw(
|
|||
if (ac->sl) {
|
||||
if (ELEM(ac->spacetype, SPACE_ACTION, SPACE_GRAPH) &&
|
||||
(acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) ||
|
||||
acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE))) {
|
||||
acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) &&
|
||||
!ELEM(ale->type, ANIMTYPE_GPLAYER, ANIMTYPE_DSGPENCIL)) {
|
||||
/* for F-Curves, draw color-preview of curve left to the visibility icon */
|
||||
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
|
||||
FCurve *fcu = (FCurve *)ale->data;
|
||||
|
@ -5227,7 +5228,8 @@ void ANIM_channel_draw_widgets(const bContext *C,
|
|||
if (ac->sl) {
|
||||
if (ELEM(ac->spacetype, SPACE_ACTION, SPACE_GRAPH) &&
|
||||
(acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) ||
|
||||
acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE))) {
|
||||
acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) &&
|
||||
(ale->type != ANIMTYPE_GPLAYER)) {
|
||||
/* Pin toggle. */
|
||||
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) {
|
||||
draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_ALWAYS_VISIBLE);
|
||||
|
|
|
@ -6515,6 +6515,8 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
|||
va_list args;
|
||||
uiStringInfo *si;
|
||||
|
||||
PointerRNA *opptr = UI_but_operator_ptr_get(but);
|
||||
|
||||
const EnumPropertyItem *items = nullptr, *item = nullptr;
|
||||
int totitems;
|
||||
bool free_items = false;
|
||||
|
@ -6593,10 +6595,13 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
|||
}
|
||||
else if (but->optype) {
|
||||
if (type == BUT_GET_RNA_LABEL) {
|
||||
tmp = BLI_strdup(WM_operatortype_name(but->optype, but->opptr));
|
||||
tmp = BLI_strdup(WM_operatortype_name(but->optype, opptr));
|
||||
}
|
||||
else {
|
||||
tmp = WM_operatortype_description(C, but->optype, but->opptr);
|
||||
bContextStore *previous_ctx = CTX_store_get(C);
|
||||
CTX_store_set(C, but->context);
|
||||
tmp = WM_operatortype_description(C, but->optype, opptr);
|
||||
CTX_store_set(C, previous_ctx);
|
||||
}
|
||||
}
|
||||
else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) {
|
||||
|
@ -6679,7 +6684,6 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
|||
int(ui_but_value_get(but));
|
||||
}
|
||||
else if (but->optype) {
|
||||
PointerRNA *opptr = UI_but_operator_ptr_get(but);
|
||||
wmOperatorType *ot = but->optype;
|
||||
|
||||
/* So the context is passed to `itemf` functions. */
|
||||
|
|
|
@ -1617,12 +1617,12 @@ static void icon_draw_cache_texture_flush_ex(GPUTexture *texture,
|
|||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR);
|
||||
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_ICON_MULTI);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const int data_binding = GPU_shader_get_ubo_binding(shader, "multi_rect_data");
|
||||
const int data_binding = GPU_shader_get_ubo_binding(shader, "multi_icon_data");
|
||||
GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
|
||||
sizeof(MultiRectCallData), texture_draw_calls->drawcall_cache, __func__);
|
||||
sizeof(MultiIconCallData), texture_draw_calls->drawcall_cache, __func__);
|
||||
GPU_uniformbuf_bind(ubo, data_binding);
|
||||
|
||||
const int img_binding = GPU_shader_get_sampler_binding(shader, "image");
|
||||
|
@ -1798,7 +1798,7 @@ static void icon_draw_texture(float x,
|
|||
GPU_shader_bind(shader);
|
||||
|
||||
const int img_binding = GPU_shader_get_sampler_binding(shader, "image");
|
||||
const int color_loc = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR);
|
||||
const int color_loc = GPU_shader_get_uniform(shader, "finalColor");
|
||||
const int rect_tex_loc = GPU_shader_get_uniform(shader, "rect_icon");
|
||||
const int rect_geom_loc = GPU_shader_get_uniform(shader, "rect_geom");
|
||||
|
||||
|
|
|
@ -465,13 +465,6 @@ int ED_mesh_color_add(
|
|||
name = "Col";
|
||||
}
|
||||
|
||||
if (const CustomDataLayer *layer = BKE_id_attribute_find(
|
||||
&me->id, me->active_color_attribute, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER)) {
|
||||
int dummy;
|
||||
const CustomData *data = mesh_customdata_get_type(me, BM_LOOP, &dummy);
|
||||
return CustomData_get_named_layer(data, CD_PROP_BYTE_COLOR, layer->name);
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = BKE_id_attribute_new(
|
||||
&me->id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER, reports);
|
||||
|
||||
|
@ -518,6 +511,7 @@ bool ED_mesh_color_ensure(Mesh *me, const char *name)
|
|||
}
|
||||
|
||||
BKE_id_attributes_active_color_set(&me->id, unique_name);
|
||||
BKE_id_attributes_default_color_set(&me->id, unique_name);
|
||||
BKE_mesh_tessface_clear(me);
|
||||
DEG_id_tag_update(&me->id, 0);
|
||||
|
||||
|
|
|
@ -225,6 +225,7 @@ struct AddOperationExecutor {
|
|||
BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
|
||||
add_inputs.interpolate_point_count = brush_settings_->flag &
|
||||
BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
|
||||
add_inputs.interpolate_resolution = curves_orig_->attributes().contains("resolution");
|
||||
add_inputs.fallback_curve_length = brush_settings_->curve_length;
|
||||
add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve);
|
||||
add_inputs.transforms = &transforms_;
|
||||
|
@ -234,7 +235,7 @@ struct AddOperationExecutor {
|
|||
add_inputs.corner_normals_su = corner_normals_su;
|
||||
|
||||
if (add_inputs.interpolate_length || add_inputs.interpolate_shape ||
|
||||
add_inputs.interpolate_point_count) {
|
||||
add_inputs.interpolate_point_count || add_inputs.interpolate_resolution) {
|
||||
this->ensure_curve_roots_kdtree();
|
||||
add_inputs.old_roots_kdtree = self_->curve_roots_kdtree_;
|
||||
}
|
||||
|
|
|
@ -275,6 +275,7 @@ struct DensityAddOperationExecutor {
|
|||
BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
|
||||
add_inputs.interpolate_point_count = brush_settings_->flag &
|
||||
BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
|
||||
add_inputs.interpolate_resolution = curves_orig_->attributes().contains("resolution");
|
||||
add_inputs.fallback_curve_length = brush_settings_->curve_length;
|
||||
add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve);
|
||||
add_inputs.transforms = &transforms_;
|
||||
|
|
|
@ -970,9 +970,10 @@ static void min_distance_edit_draw(bContext *C, int /*x*/, int /*y*/, void *cust
|
|||
|
||||
const uint pos3d = GPU_vertformat_attr_add(format3d, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
const uint col3d = GPU_vertformat_attr_add(format3d, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
const uint siz3d = GPU_vertformat_attr_add(format3d, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
||||
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
|
||||
immUniform1f("size", 4.0f);
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
|
||||
GPU_program_point_size(true);
|
||||
immBegin(GPU_PRIM_POINTS, points_wo.size());
|
||||
|
||||
float3 brush_origin_wo = math::transform_point(op_data.curves_to_world_mat, op_data.pos_cu);
|
||||
|
@ -990,6 +991,7 @@ static void min_distance_edit_draw(bContext *C, int /*x*/, int /*y*/, void *cust
|
|||
const float dist_to_point_re = math::distance(pos_re, brush_origin_re);
|
||||
const float alpha = 1.0f - ((dist_to_point_re - dist_to_inner_border_re) / alpha_border_re);
|
||||
|
||||
immAttr1f(siz3d, 3.0f);
|
||||
immAttr4f(col3d, 0.9f, 0.9f, 0.9f, alpha);
|
||||
immVertex3fv(pos3d, pos_wo);
|
||||
}
|
||||
|
|
|
@ -1033,8 +1033,10 @@ static void sculpt_gesture_trim_shape_origin_normal_get(SculptGestureContext *sg
|
|||
*/
|
||||
switch (trim_operation->orientation) {
|
||||
case SCULPT_GESTURE_TRIM_ORIENTATION_VIEW:
|
||||
copy_v3_v3(r_origin, sgcontext->world_space_view_origin);
|
||||
mul_v3_m4v3(
|
||||
r_origin, sgcontext->vc.obact->object_to_world, sgcontext->ss->gesture_initial_location);
|
||||
copy_v3_v3(r_normal, sgcontext->world_space_view_normal);
|
||||
negate_v3(r_normal);
|
||||
break;
|
||||
case SCULPT_GESTURE_TRIM_ORIENTATION_SURFACE:
|
||||
mul_v3_m4v3(
|
||||
|
@ -1168,14 +1170,30 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
|
|||
|
||||
const float(*ob_imat)[4] = vc->obact->world_to_object;
|
||||
|
||||
/* Write vertices coordinates for the front face. */
|
||||
/* Write vertices coordinatesSCULPT_GESTURE_TRIM_DIFFERENCE for the front face. */
|
||||
float(*positions)[3] = BKE_mesh_vert_positions_for_write(trim_operation->mesh);
|
||||
float depth_point[3];
|
||||
madd_v3_v3v3fl(depth_point, shape_origin, shape_normal, depth_front);
|
||||
|
||||
/* Get origin point for SCULPT_GESTURE_TRIM_ORIENTATION_VIEW.
|
||||
* Note: for projection extrusion we add depth_front here
|
||||
* instead of in the loop.
|
||||
*/
|
||||
if (trim_operation->extrude_mode == SCULPT_GESTURE_TRIM_EXTRUDE_FIXED) {
|
||||
copy_v3_v3(depth_point, shape_origin);
|
||||
}
|
||||
else {
|
||||
madd_v3_v3v3fl(depth_point, shape_origin, shape_normal, depth_front);
|
||||
}
|
||||
|
||||
for (int i = 0; i < tot_screen_points; i++) {
|
||||
float new_point[3];
|
||||
if (trim_operation->orientation == SCULPT_GESTURE_TRIM_ORIENTATION_VIEW) {
|
||||
ED_view3d_win_to_3d(vc->v3d, region, depth_point, screen_points[i], new_point);
|
||||
|
||||
/* For fixed mode we add the shape normal here to avoid projection errors. */
|
||||
if (trim_operation->extrude_mode == SCULPT_GESTURE_TRIM_EXTRUDE_FIXED) {
|
||||
madd_v3_v3fl(new_point, shape_normal, depth_front);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ED_view3d_win_to_3d_on_plane(region, shape_plane, screen_points[i], false, new_point);
|
||||
|
|
|
@ -81,6 +81,19 @@ using blender::MutableSpan;
|
|||
using blender::Set;
|
||||
using blender::Vector;
|
||||
|
||||
static float sculpt_calc_radius(ViewContext *vc,
|
||||
const Brush *brush,
|
||||
const Scene *scene,
|
||||
const float3 location)
|
||||
{
|
||||
if (!BKE_brush_use_locked_size(scene, brush)) {
|
||||
return paint_calc_object_space_radius(vc, location, BKE_brush_size_get(scene, brush));
|
||||
}
|
||||
else {
|
||||
return BKE_brush_unprojected_radius_get(scene, brush);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Sculpt PBVH Abstraction API
|
||||
*
|
||||
|
@ -4925,14 +4938,11 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
|
|||
|
||||
/* Truly temporary data that isn't stored in properties. */
|
||||
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
|
||||
cache->initial_radius = sculpt_calc_radius(cache->vc, brush, scene, cache->true_location);
|
||||
|
||||
if (!BKE_brush_use_locked_size(scene, brush)) {
|
||||
cache->initial_radius = paint_calc_object_space_radius(
|
||||
cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
|
||||
BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
|
||||
}
|
||||
else {
|
||||
cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clay stabilized pressure. */
|
||||
|
@ -5280,6 +5290,19 @@ bool SCULPT_stroke_get_location(bContext *C,
|
|||
float out[3],
|
||||
const float mval[2],
|
||||
bool force_original)
|
||||
{
|
||||
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
|
||||
bool check_closest = brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE;
|
||||
|
||||
return SCULPT_stroke_get_location_ex(C, out, mval, force_original, check_closest, true);
|
||||
}
|
||||
|
||||
bool SCULPT_stroke_get_location_ex(bContext *C,
|
||||
float out[3],
|
||||
const float mval[2],
|
||||
bool force_original,
|
||||
bool check_closest,
|
||||
bool limit_closest_radius)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
Object *ob;
|
||||
|
@ -5329,11 +5352,7 @@ bool SCULPT_stroke_get_location(bContext *C,
|
|||
}
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
return hit;
|
||||
}
|
||||
|
||||
if (!ELEM(brush->falloff_shape, PAINT_FALLOFF_SHAPE_TUBE)) {
|
||||
if (hit || !check_closest) {
|
||||
return hit;
|
||||
}
|
||||
|
||||
|
@ -5348,14 +5367,20 @@ bool SCULPT_stroke_get_location(bContext *C,
|
|||
|
||||
BKE_pbvh_find_nearest_to_ray(
|
||||
ss->pbvh, sculpt_find_nearest_to_ray_cb, &srd, ray_start, ray_normal, srd.original);
|
||||
if (srd.hit) {
|
||||
if (srd.hit && srd.dist_sq_to_ray) {
|
||||
hit = true;
|
||||
copy_v3_v3(out, ray_normal);
|
||||
mul_v3_fl(out, srd.depth);
|
||||
add_v3_v3(out, ray_start);
|
||||
}
|
||||
|
||||
return hit;
|
||||
float closest_radius_sq = FLT_MAX;
|
||||
if (limit_closest_radius) {
|
||||
closest_radius_sq = sculpt_calc_radius(&vc, brush, CTX_data_scene(C), out);
|
||||
closest_radius_sq *= closest_radius_sq;
|
||||
}
|
||||
|
||||
return hit && srd.dist_sq_to_ray < closest_radius_sq;
|
||||
}
|
||||
|
||||
static void sculpt_brush_init_tex(Sculpt *sd, SculptSession *ss)
|
||||
|
@ -5620,7 +5645,12 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
|
|||
static bool over_mesh(bContext *C, wmOperator * /*op*/, const float mval[2])
|
||||
{
|
||||
float co_dummy[3];
|
||||
return SCULPT_stroke_get_location(C, co_dummy, mval, false);
|
||||
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
|
||||
bool check_closest = brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE;
|
||||
|
||||
return SCULPT_stroke_get_location_ex(C, co_dummy, mval, false, check_closest, true);
|
||||
}
|
||||
|
||||
static void sculpt_stroke_undo_begin(const bContext *C, wmOperator *op)
|
||||
|
@ -5974,29 +6004,7 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
|
|||
|
||||
static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
bool started = op->customdata && paint_stroke_started((PaintStroke *)op->customdata);
|
||||
|
||||
int retval = paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
|
||||
|
||||
if (!started && ELEM(retval, OPERATOR_FINISHED, OPERATOR_CANCELLED)) {
|
||||
/* Did the stroke never start? If so push a blank sculpt undo
|
||||
* step to prevent a global undo step (which is triggered by the
|
||||
* #OPTYPE_UNDO flag in #SCULPT_OT_brush_stroke).
|
||||
*
|
||||
* Having blank global undo steps interleaved with sculpt steps
|
||||
* corrupts the DynTopo undo stack.
|
||||
* See #101430.
|
||||
*
|
||||
* NOTE: simply returning #OPERATOR_CANCELLED was not
|
||||
* sufficient to prevent this. */
|
||||
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
|
||||
sculpt_stroke_undo_begin(C, op);
|
||||
sculpt_stroke_undo_end(C, brush);
|
||||
}
|
||||
|
||||
return retval;
|
||||
return paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
|
||||
}
|
||||
|
||||
static void sculpt_redo_empty_ui(bContext * /*C*/, wmOperator * /*op*/)
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
struct AutomaskingCache;
|
||||
struct AutomaskingNodeData;
|
||||
struct Dial;
|
||||
|
@ -890,7 +892,18 @@ void SCULPT_tag_update_overlays(bContext *C);
|
|||
* Do a ray-cast in the tree to find the 3d brush location
|
||||
* (This allows us to ignore the GL depth buffer)
|
||||
* Returns 0 if the ray doesn't hit the mesh, non-zero otherwise.
|
||||
*
|
||||
* If check_closest is true and the ray test fails a point closest
|
||||
* to the ray will be found. If limit_closest_radius is true then
|
||||
* the closest point will be tested against the active brush radius.
|
||||
*/
|
||||
bool SCULPT_stroke_get_location_ex(bContext *C,
|
||||
float out[3],
|
||||
const float mval[2],
|
||||
bool force_original,
|
||||
bool check_closest,
|
||||
bool limit_closest_radius);
|
||||
|
||||
bool SCULPT_stroke_get_location(bContext *C,
|
||||
float out[3],
|
||||
const float mouse[2],
|
||||
|
|
|
@ -229,6 +229,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
SCULPT_topology_islands_invalidate(ss);
|
||||
|
||||
/* Redraw. */
|
||||
SCULPT_pbvh_clear(ob);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
||||
|
|
|
@ -942,6 +942,7 @@ static void graph_panel_drivers_header(const bContext *C, Panel *panel)
|
|||
}
|
||||
|
||||
graph_draw_driven_property_enabled_btn(panel->layout, ale->id, fcu, IFACE_("Driver"));
|
||||
MEM_freeN(ale);
|
||||
}
|
||||
|
||||
static void graph_draw_driven_property_panel(uiLayout *layout, ID *id, FCurve *fcu)
|
||||
|
|
|
@ -456,6 +456,22 @@ static int node_add_group_asset_invoke(bContext *C, wmOperator *op, const wmEven
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static char *node_add_group_asset_get_description(struct bContext *C,
|
||||
struct wmOperatorType * /*op*/,
|
||||
struct PointerRNA * /*values*/)
|
||||
{
|
||||
bool is_valid;
|
||||
const AssetHandle handle = CTX_wm_asset_handle(C, &is_valid);
|
||||
if (!is_valid) {
|
||||
return nullptr;
|
||||
}
|
||||
const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&handle);
|
||||
if (!asset_data.description) {
|
||||
return nullptr;
|
||||
}
|
||||
return BLI_strdup(asset_data.description);
|
||||
}
|
||||
|
||||
void NODE_OT_add_group_asset(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Add Node Group Asset";
|
||||
|
@ -464,6 +480,7 @@ void NODE_OT_add_group_asset(wmOperatorType *ot)
|
|||
|
||||
ot->invoke = node_add_group_asset_invoke;
|
||||
ot->poll = node_add_group_poll;
|
||||
ot->get_description = node_add_group_asset_get_description;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
|
|
@ -3268,6 +3268,11 @@ static bool outliner_data_operation_poll(bContext *C)
|
|||
}
|
||||
const SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
const TreeElement *te = get_target_element(space_outliner);
|
||||
|
||||
if (te == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
|
||||
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
return ELEM(datalevel,
|
||||
|
|
|
@ -1106,6 +1106,7 @@ static void draw_rotation_guide(const RegionView3D *rv3d)
|
|||
/* -- draw rotation center -- */
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
|
||||
immUniform1f("size", 7.0f);
|
||||
immUniform4fv("color", float4(color));
|
||||
immBegin(GPU_PRIM_POINTS, 1);
|
||||
immAttr4ubv(col, color);
|
||||
immVertex3fv(pos, o);
|
||||
|
|
|
@ -108,15 +108,12 @@ static void createTransCurvesVerts(bContext * /*C*/, TransInfo *t)
|
|||
for (const int curve_i : range) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const bool has_any_selected = ed::curves::has_anything_selected(selection, points);
|
||||
if (!has_any_selected) {
|
||||
if (!has_any_selected && use_connected_only) {
|
||||
for (const int point_i : points) {
|
||||
TransData &td = tc.data[point_i];
|
||||
td.flag |= TD_NOTCONNECTED;
|
||||
td.dist = FLT_MAX;
|
||||
}
|
||||
if (use_connected_only) {
|
||||
continue;
|
||||
td.flag |= TD_SKIP;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
closest_distances.reinitialize(points.size());
|
||||
|
|
|
@ -25,6 +25,7 @@ struct AddCurvesOnMeshInputs {
|
|||
bool interpolate_length = false;
|
||||
bool interpolate_shape = false;
|
||||
bool interpolate_point_count = false;
|
||||
bool interpolate_resolution = false;
|
||||
float fallback_curve_length = 0.0f;
|
||||
int fallback_point_count = 0;
|
||||
|
||||
|
|
|
@ -243,7 +243,7 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
|
|||
AddCurvesOnMeshOutputs outputs;
|
||||
|
||||
const bool use_interpolation = inputs.interpolate_length || inputs.interpolate_point_count ||
|
||||
inputs.interpolate_shape;
|
||||
inputs.interpolate_shape || inputs.interpolate_resolution;
|
||||
|
||||
Vector<float3> root_positions_cu;
|
||||
Vector<float3> bary_coords;
|
||||
|
@ -380,8 +380,24 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
|
|||
|
||||
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
|
||||
if (bke::SpanAttributeWriter<int> resolution = attributes.lookup_for_write_span<int>(
|
||||
"resolution")) {
|
||||
if (inputs.interpolate_resolution) {
|
||||
interpolate_from_neighbors(
|
||||
neighbors_per_curve,
|
||||
12,
|
||||
[&](const int curve_i) { return resolution.span[curve_i]; },
|
||||
resolution.span.take_back(added_curves_num));
|
||||
resolution.finish();
|
||||
}
|
||||
else {
|
||||
resolution.span.take_back(added_curves_num).fill(12);
|
||||
}
|
||||
}
|
||||
|
||||
/* Explicitly set all other attributes besides those processed above to default values. */
|
||||
Set<std::string> attributes_to_skip{{"position", "curve_type", "surface_uv_coordinate"}};
|
||||
Set<std::string> attributes_to_skip{
|
||||
{"position", "curve_type", "surface_uv_coordinate", "resolution"}};
|
||||
attributes.for_all(
|
||||
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData /*meta_data*/) {
|
||||
if (attributes_to_skip.contains(id.name())) {
|
||||
|
|
|
@ -154,6 +154,12 @@ struct RealizeCurveInfo {
|
|||
* curves.
|
||||
*/
|
||||
VArray<int> resolution;
|
||||
|
||||
/**
|
||||
* The resolution attribute must be filled with the default value if it does not exist on some
|
||||
* curves.
|
||||
*/
|
||||
Span<float> nurbs_weight;
|
||||
};
|
||||
|
||||
/** Start indices in the final output curves data-block. */
|
||||
|
@ -208,6 +214,7 @@ struct AllCurvesInfo {
|
|||
bool create_handle_postion_attributes = false;
|
||||
bool create_radius_attribute = false;
|
||||
bool create_resolution_attribute = false;
|
||||
bool create_nurbs_weight_attribute = false;
|
||||
};
|
||||
|
||||
/** Collects all tasks that need to be executed to realize all instances. */
|
||||
|
@ -1160,6 +1167,7 @@ static OrderedAttributes gather_generic_curve_attributes_to_propagate(
|
|||
attributes_to_propagate);
|
||||
attributes_to_propagate.remove("position");
|
||||
attributes_to_propagate.remove("radius");
|
||||
attributes_to_propagate.remove("nurbs_weight");
|
||||
attributes_to_propagate.remove("resolution");
|
||||
attributes_to_propagate.remove("handle_right");
|
||||
attributes_to_propagate.remove("handle_left");
|
||||
|
@ -1221,20 +1229,20 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
|
|||
}
|
||||
}
|
||||
|
||||
/* Retrieve the radius attribute, if it exists. */
|
||||
if (attributes.contains("radius")) {
|
||||
curve_info.radius =
|
||||
attributes.lookup<float>("radius", ATTR_DOMAIN_POINT).get_internal_span();
|
||||
info.create_radius_attribute = true;
|
||||
}
|
||||
|
||||
/* Retrieve the resolution attribute, if it exists. */
|
||||
if (attributes.contains("nurbs_weight")) {
|
||||
curve_info.nurbs_weight =
|
||||
attributes.lookup<float>("nurbs_weight", ATTR_DOMAIN_POINT).get_internal_span();
|
||||
info.create_nurbs_weight_attribute = true;
|
||||
}
|
||||
curve_info.resolution = curves.resolution();
|
||||
if (attributes.contains("resolution")) {
|
||||
info.create_resolution_attribute = true;
|
||||
}
|
||||
|
||||
/* Retrieve handle position attributes, if they exist. */
|
||||
if (attributes.contains("handle_right")) {
|
||||
curve_info.handle_left =
|
||||
attributes.lookup<float3>("handle_left", ATTR_DOMAIN_POINT).get_internal_span();
|
||||
|
@ -1256,6 +1264,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
|
|||
MutableSpan<float3> all_handle_left,
|
||||
MutableSpan<float3> all_handle_right,
|
||||
MutableSpan<float> all_radii,
|
||||
MutableSpan<float> all_nurbs_weights,
|
||||
MutableSpan<int> all_resolutions)
|
||||
{
|
||||
const RealizeCurveInfo &curves_info = *task.curve_info;
|
||||
|
@ -1286,14 +1295,20 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
|
|||
}
|
||||
}
|
||||
|
||||
/* Copy radius attribute with 1.0 default if it doesn't exist. */
|
||||
auto copy_point_span_with_default =
|
||||
[&](const Span<float> src, MutableSpan<float> all_dst, const float value) {
|
||||
if (src.is_empty()) {
|
||||
all_dst.slice(dst_point_range).fill(value);
|
||||
}
|
||||
else {
|
||||
all_dst.slice(dst_point_range).copy_from(src);
|
||||
}
|
||||
};
|
||||
if (all_curves_info.create_radius_attribute) {
|
||||
if (curves_info.radius.is_empty()) {
|
||||
all_radii.slice(dst_point_range).fill(1.0f);
|
||||
}
|
||||
else {
|
||||
all_radii.slice(dst_point_range).copy_from(curves_info.radius);
|
||||
}
|
||||
copy_point_span_with_default(curves_info.radius, all_radii, 1.0f);
|
||||
}
|
||||
if (all_curves_info.create_nurbs_weight_attribute) {
|
||||
copy_point_span_with_default(curves_info.nurbs_weight, all_nurbs_weights, 1.0f);
|
||||
}
|
||||
|
||||
if (all_curves_info.create_resolution_attribute) {
|
||||
|
@ -1386,13 +1401,15 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
|
|||
ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
/* Prepare radius attribute if necessary. */
|
||||
SpanAttributeWriter<float> radius;
|
||||
if (all_curves_info.create_radius_attribute) {
|
||||
radius = dst_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
/* Prepare resolution attribute if necessary. */
|
||||
SpanAttributeWriter<float> nurbs_weight;
|
||||
if (all_curves_info.create_nurbs_weight_attribute) {
|
||||
nurbs_weight = dst_attributes.lookup_or_add_for_write_only_span<float>("nurbs_weight",
|
||||
ATTR_DOMAIN_POINT);
|
||||
}
|
||||
SpanAttributeWriter<int> resolution;
|
||||
if (all_curves_info.create_resolution_attribute) {
|
||||
resolution = dst_attributes.lookup_or_add_for_write_only_span<int>("resolution",
|
||||
|
@ -1413,6 +1430,7 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
|
|||
handle_left.span,
|
||||
handle_right.span,
|
||||
radius.span,
|
||||
nurbs_weight.span,
|
||||
resolution.span);
|
||||
}
|
||||
});
|
||||
|
@ -1433,6 +1451,7 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
|
|||
point_ids.finish();
|
||||
radius.finish();
|
||||
resolution.finish();
|
||||
nurbs_weight.finish();
|
||||
handle_left.finish();
|
||||
handle_right.finish();
|
||||
}
|
||||
|
|
|
@ -308,24 +308,23 @@ static bke::CurvesGeometry convert_curves_to_bezier(
|
|||
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
|
||||
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
|
||||
|
||||
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
|
||||
MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
|
||||
MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
|
||||
MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
|
||||
MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
|
||||
MutableSpan<float> dst_weights = dst_curves.nurbs_weights_for_write();
|
||||
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||
Set<std::string> attributes_to_skip = {
|
||||
"position", "handle_type_left", "handle_type_right", "handle_right", "handle_left"};
|
||||
if (!dst_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
|
||||
attributes_to_skip.add_new("nurbs_weight");
|
||||
}
|
||||
Vector<bke::AttributeTransferData> generic_attributes = bke::retrieve_attributes_for_transfer(
|
||||
src_attributes,
|
||||
dst_attributes,
|
||||
ATTR_DOMAIN_MASK_POINT,
|
||||
propagation_info,
|
||||
{"position",
|
||||
"handle_type_left",
|
||||
"handle_type_right",
|
||||
"handle_right",
|
||||
"handle_left",
|
||||
"nurbs_weight"});
|
||||
attributes_to_skip);
|
||||
|
||||
auto catmull_rom_to_bezier = [&](IndexMask selection) {
|
||||
bke::curves::fill_points<int8_t>(
|
||||
|
@ -396,7 +395,6 @@ static bke::CurvesGeometry convert_curves_to_bezier(
|
|||
dst_points_by_curve, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
|
||||
bke::curves::fill_points<int8_t>(
|
||||
dst_points_by_curve, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
|
||||
bke::curves::fill_points<float>(dst_points_by_curve, selection, 0.0f, dst_weights);
|
||||
|
||||
threading::parallel_for(selection.index_range(), 64, [&](IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
|
@ -513,7 +511,7 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
"nurbs_weight"});
|
||||
|
||||
auto fill_weights_if_necessary = [&](const IndexMask selection) {
|
||||
if (!src_curves.nurbs_weights().is_empty()) {
|
||||
if (src_attributes.contains("nurbs_weight")) {
|
||||
bke::curves::fill_points(
|
||||
dst_points_by_curve, selection, 1.0f, dst_curves.nurbs_weights_for_write());
|
||||
}
|
||||
|
|
|
@ -348,7 +348,7 @@ set(GLSL_SRC
|
|||
shaders/gpu_shader_2D_line_dashed_frag.glsl
|
||||
shaders/gpu_shader_2D_image_vert.glsl
|
||||
shaders/gpu_shader_2D_image_rect_vert.glsl
|
||||
shaders/gpu_shader_2D_image_multi_rect_vert.glsl
|
||||
shaders/gpu_shader_icon_multi_vert.glsl
|
||||
shaders/gpu_shader_icon_frag.glsl
|
||||
shaders/gpu_shader_icon_vert.glsl
|
||||
shaders/gpu_shader_image_frag.glsl
|
||||
|
@ -357,7 +357,6 @@ set(GLSL_SRC
|
|||
shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
|
||||
shaders/gpu_shader_image_shuffle_color_frag.glsl
|
||||
shaders/gpu_shader_image_color_frag.glsl
|
||||
shaders/gpu_shader_image_varying_color_frag.glsl
|
||||
shaders/gpu_shader_3D_image_vert.glsl
|
||||
shaders/gpu_shader_3D_vert.glsl
|
||||
shaders/gpu_shader_3D_normal_vert.glsl
|
||||
|
@ -498,6 +497,9 @@ set(GLSL_SRC
|
|||
shaders/gpu_shader_gpencil_stroke_frag.glsl
|
||||
shaders/gpu_shader_gpencil_stroke_geom.glsl
|
||||
|
||||
shaders/gpu_shader_display_fallback_vert.glsl
|
||||
shaders/gpu_shader_display_fallback_frag.glsl
|
||||
|
||||
shaders/gpu_shader_cfg_world_clip_lib.glsl
|
||||
shaders/gpu_shader_colorspace_lib.glsl
|
||||
|
||||
|
@ -636,7 +638,6 @@ set(SRC_SHADER_CREATE_INFOS
|
|||
shaders/infos/gpu_shader_2D_diag_stripes_info.hh
|
||||
shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh
|
||||
shaders/infos/gpu_shader_2D_image_info.hh
|
||||
shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh
|
||||
shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh
|
||||
shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
|
||||
shaders/infos/gpu_shader_2D_image_rect_color_info.hh
|
||||
|
|
|
@ -39,7 +39,7 @@ typedef enum eGPUBuiltinShader {
|
|||
/** Draw a texture with a desaturation factor. */
|
||||
GPU_SHADER_2D_IMAGE_DESATURATE_COLOR,
|
||||
/** Draw a group of texture rectangle with an associated color multiplied. */
|
||||
GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR,
|
||||
GPU_SHADER_ICON_MULTI,
|
||||
/** Draw a two color checker based on screen position (not UV coordinates). */
|
||||
GPU_SHADER_2D_CHECKER,
|
||||
/** Draw diagonal stripes with two alternating colors. */
|
||||
|
|
|
@ -82,10 +82,10 @@ BLI_STATIC_ASSERT_ALIGN(struct SimpleLightingData, 16)
|
|||
|
||||
#define MAX_CALLS 16
|
||||
|
||||
struct MultiRectCallData {
|
||||
struct MultiIconCallData {
|
||||
float4 calls_data[MAX_CALLS * 3];
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(struct MultiRectCallData, 16)
|
||||
BLI_STATIC_ASSERT_ALIGN(struct MultiIconCallData, 16)
|
||||
|
||||
enum TestStatus {
|
||||
TEST_STATUS_NONE = 0,
|
||||
|
|
|
@ -951,14 +951,16 @@ void GPU_material_compile(GPUMaterial *mat)
|
|||
* As PSOs do not always match for default shaders, we limit warming for PSO
|
||||
* configurations to ensure compile time remains fast, as these first
|
||||
* entries will be the most commonly used PSOs. As not all PSOs are necessarily
|
||||
* required immediately, this limit should remain low (1-3 at most).
|
||||
* */
|
||||
* required immediately, this limit should remain low (1-3 at most). */
|
||||
if (mat->default_mat != NULL && mat->default_mat != mat) {
|
||||
if (mat->default_mat->pass != NULL) {
|
||||
GPUShader *parent_sh = GPU_pass_shader_get(mat->default_mat->pass);
|
||||
if (parent_sh) {
|
||||
GPU_shader_set_parent(sh, parent_sh);
|
||||
GPU_shader_warm_cache(sh, 1);
|
||||
/* Skip warming if cached pass is identical to the default material. */
|
||||
if (mat->default_mat->pass != mat->pass && parent_sh != sh) {
|
||||
GPU_shader_set_parent(sh, parent_sh);
|
||||
GPU_shader_warm_cache(sh, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "GPU_capabilities.h"
|
||||
#include "GPU_shader.h"
|
||||
|
||||
/* Cache of built-in shaders (each is created on first use). */
|
||||
|
@ -41,8 +42,8 @@ static const char *builtin_shader_create_info_name(eGPUBuiltinShader shader)
|
|||
return "gpu_shader_2D_image_shuffle_color";
|
||||
case GPU_SHADER_2D_IMAGE_RECT_COLOR:
|
||||
return "gpu_shader_2D_image_rect_color";
|
||||
case GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR:
|
||||
return "gpu_shader_2D_image_multi_rect_color";
|
||||
case GPU_SHADER_ICON_MULTI:
|
||||
return "gpu_shader_icon_multi";
|
||||
case GPU_SHADER_3D_UNIFORM_COLOR:
|
||||
return "gpu_shader_3D_uniform_color";
|
||||
case GPU_SHADER_3D_FLAT_COLOR:
|
||||
|
@ -84,7 +85,8 @@ static const char *builtin_shader_create_info_name(eGPUBuiltinShader shader)
|
|||
case GPU_SHADER_2D_NODELINK_INST:
|
||||
return "gpu_shader_2D_nodelink_inst";
|
||||
case GPU_SHADER_GPENCIL_STROKE:
|
||||
return "gpu_shader_gpencil_stroke";
|
||||
return GPU_geometry_shader_support() ? "gpu_shader_gpencil_stroke_geom" :
|
||||
"gpu_shader_gpencil_stroke_nogeom";
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return "";
|
||||
|
|
|
@ -768,6 +768,7 @@ class MTLContext : public Context {
|
|||
void texture_unbind_all();
|
||||
id<MTLSamplerState> get_sampler_from_state(MTLSamplerState state);
|
||||
id<MTLSamplerState> generate_sampler_from_state(MTLSamplerState state);
|
||||
id<MTLSamplerState> generate_icon_sampler();
|
||||
id<MTLSamplerState> get_default_sampler_state();
|
||||
|
||||
/* Metal Context pipeline state. */
|
||||
|
|
|
@ -223,11 +223,13 @@ MTLContext::MTLContext(void *ghost_window, void *ghost_context)
|
|||
}
|
||||
|
||||
/* Initialize samplers. */
|
||||
for (uint i = 0; i < GPU_SAMPLER_MAX; i++) {
|
||||
for (uint i = 0; i < GPU_SAMPLER_ICON; i++) {
|
||||
MTLSamplerState state;
|
||||
state.state = static_cast<eGPUSamplerState>(i);
|
||||
sampler_state_cache_[i] = this->generate_sampler_from_state(state);
|
||||
}
|
||||
/* Special sampler for icons. */
|
||||
sampler_state_cache_[GPU_SAMPLER_ICON] = this->generate_icon_sampler();
|
||||
}
|
||||
|
||||
MTLContext::~MTLContext()
|
||||
|
@ -2024,7 +2026,6 @@ id<MTLSamplerState> MTLContext::get_sampler_from_state(MTLSamplerState sampler_s
|
|||
|
||||
id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState sampler_state)
|
||||
{
|
||||
/* Check if sampler already exists for given state. */
|
||||
MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init];
|
||||
descriptor.normalizedCoordinates = true;
|
||||
|
||||
|
@ -2067,6 +2068,21 @@ id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState samp
|
|||
return state;
|
||||
}
|
||||
|
||||
id<MTLSamplerState> MTLContext::generate_icon_sampler()
|
||||
{
|
||||
MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init];
|
||||
descriptor.minFilter = MTLSamplerMinMagFilterLinear;
|
||||
descriptor.magFilter = MTLSamplerMinMagFilterLinear;
|
||||
descriptor.mipFilter = MTLSamplerMipFilterNearest;
|
||||
descriptor.lodMinClamp = 0;
|
||||
descriptor.lodMaxClamp = 1;
|
||||
|
||||
id<MTLSamplerState> icon_state = [this->device newSamplerStateWithDescriptor:descriptor];
|
||||
BLI_assert(icon_state != nil);
|
||||
[descriptor autorelease];
|
||||
return icon_state;
|
||||
}
|
||||
|
||||
id<MTLSamplerState> MTLContext::get_default_sampler_state()
|
||||
{
|
||||
if (default_sampler_state_ == nil) {
|
||||
|
|
|
@ -529,6 +529,9 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI
|
|||
}
|
||||
}
|
||||
|
||||
this->sort_inputs();
|
||||
|
||||
/* Resolving builtins must happen after the inputs have been sorted. */
|
||||
/* Builtin Uniforms */
|
||||
for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
|
||||
GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
|
||||
|
@ -543,8 +546,6 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI
|
|||
builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
|
||||
}
|
||||
|
||||
this->sort_inputs();
|
||||
|
||||
// this->debug_print();
|
||||
|
||||
glUseProgram(last_program);
|
||||
|
|
|
@ -594,11 +594,11 @@ void GLTexture::samplers_init()
|
|||
}
|
||||
samplers_update();
|
||||
|
||||
/* Custom sampler for icons. */
|
||||
/* Custom sampler for icons.
|
||||
* NOTE: The icon texture is sampled within the shader using a -0.5f lod bias. */
|
||||
GLuint icon_sampler = samplers_[GPU_SAMPLER_ICON];
|
||||
glSamplerParameteri(icon_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
glSamplerParameteri(icon_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameterf(icon_sampler, GL_TEXTURE_LOD_BIAS, -0.5f);
|
||||
|
||||
debug::object_label(GL_SAMPLER, icon_sampler, "icons");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
void main()
|
||||
{
|
||||
fragColor = texture(image_texture, texCoord_interp);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
vec2 normalize_coordinates()
|
||||
{
|
||||
return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);
|
||||
texCoord_interp = texCoord;
|
||||
}
|
|
@ -1,12 +1,33 @@
|
|||
#ifdef USE_GEOMETRY_SHADER
|
||||
vec4 fragment_in_color()
|
||||
{
|
||||
return geometry_out.mColor;
|
||||
}
|
||||
|
||||
vec2 fragment_in_tex_coord()
|
||||
{
|
||||
return geometry_out.mTexCoord;
|
||||
}
|
||||
#else
|
||||
vec4 fragment_in_color()
|
||||
{
|
||||
return geometry_in.finalColor;
|
||||
}
|
||||
|
||||
vec2 fragment_in_tex_coord()
|
||||
{
|
||||
return vec2(0.5);
|
||||
}
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
const vec2 center = vec2(0, 0.5);
|
||||
vec4 tColor = vec4(geometry_out.mColor);
|
||||
vec4 tColor = fragment_in_color();
|
||||
/* if alpha < 0, then encap */
|
||||
if (geometry_out.mColor.a < 0) {
|
||||
if (tColor.a < 0) {
|
||||
tColor.a = tColor.a * -1.0;
|
||||
float dist = length(geometry_out.mTexCoord - center);
|
||||
float dist = length(fragment_in_tex_coord() - center);
|
||||
if (dist > 0.25) {
|
||||
discard;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
void main()
|
||||
{
|
||||
/* Sample texture with LOD BIAS. Used instead of custom lod bias in GPU_SAMPLER_ICON. */
|
||||
fragColor = texture(image, texCoord_interp, -0.5) * finalColor;
|
||||
|
||||
#ifdef DO_CORNER_MASKING
|
||||
/* Top-left rounded corner parameters. */
|
||||
const float circle_radius_outer = 0.1;
|
||||
const float circle_radius_inner = 0.075;
|
||||
|
@ -18,7 +22,6 @@ void main()
|
|||
const float mask_transparency = 0.25;
|
||||
|
||||
vec2 circle_center = vec2(circle_radius_outer - text_width, 0.5);
|
||||
fragColor = texture(image, texCoord_interp) * color;
|
||||
|
||||
/* radius in icon space (1 is the icon width). */
|
||||
float radius = length(mask_coord_interp - circle_center);
|
||||
|
@ -39,4 +42,5 @@ void main()
|
|||
}
|
||||
|
||||
fragColor = mix(vec4(0.0), fragColor, max(mask_transparency, mask));
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
void main()
|
||||
{
|
||||
vec4 rect = multi_rect_data.calls_data[gl_InstanceID * 3];
|
||||
vec4 tex = multi_rect_data.calls_data[gl_InstanceID * 3 + 1];
|
||||
finalColor = multi_rect_data.calls_data[gl_InstanceID * 3 + 2];
|
||||
vec4 rect = multi_icon_data.calls_data[gl_InstanceID * 3];
|
||||
vec4 tex = multi_icon_data.calls_data[gl_InstanceID * 3 + 1];
|
||||
finalColor = multi_icon_data.calls_data[gl_InstanceID * 3 + 2];
|
||||
|
||||
/* Use pos to select the right swizzle (instead of gl_VertexID)
|
||||
* in order to workaround an OSX driver bug. */
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
void main()
|
||||
{
|
||||
fragColor = texture(image, texCoord_interp) * finalColor;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_interface_info.hh"
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_multi_rect_color)
|
||||
.vertex_in(0, Type::VEC2, "pos")
|
||||
.vertex_out(flat_color_smooth_tex_coord_interp_iface)
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.uniform_buf(0, "MultiRectCallData", "multi_rect_data")
|
||||
.sampler(0, ImageType::FLOAT_2D, "image")
|
||||
.typedef_source("GPU_shader_shared.h")
|
||||
.vertex_source("gpu_shader_2D_image_multi_rect_vert.glsl")
|
||||
.fragment_source("gpu_shader_image_varying_color_frag.glsl")
|
||||
.do_static_compilation(true);
|
|
@ -22,3 +22,15 @@ GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_overlays_merge)
|
|||
.vertex_source("gpu_shader_2D_image_vert.glsl")
|
||||
.fragment_source("gpu_shader_image_overlays_merge_frag.glsl")
|
||||
.do_static_compilation(true);
|
||||
|
||||
/* Cycles display driver fallback shader. */
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_cycles_display_fallback)
|
||||
.vertex_in(0, Type::VEC2, "pos")
|
||||
.vertex_in(1, Type::VEC2, "texCoord")
|
||||
.vertex_out(smooth_tex_coord_interp_iface)
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.push_constant(Type::VEC2, "fullscreen")
|
||||
.sampler(0, ImageType::FLOAT_2D, "image_texture")
|
||||
.vertex_source("gpu_shader_display_fallback_vert.glsl")
|
||||
.fragment_source("gpu_shader_display_fallback_frag.glsl")
|
||||
.do_static_compilation(true);
|
||||
|
|
|
@ -14,13 +14,11 @@ GPU_SHADER_INTERFACE_INFO(gpencil_stroke_geom_iface, "geometry_out")
|
|||
.smooth(Type::VEC4, "mColor")
|
||||
.smooth(Type::VEC2, "mTexCoord");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke)
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke_base)
|
||||
.vertex_in(0, Type::VEC4, "color")
|
||||
.vertex_in(1, Type::VEC3, "pos")
|
||||
.vertex_in(2, Type::FLOAT, "thickness")
|
||||
.vertex_out(gpencil_stroke_vert_iface)
|
||||
.geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::TRIANGLE_STRIP, 13)
|
||||
.geometry_out(gpencil_stroke_geom_iface)
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
|
||||
.uniform_buf(0, "GPencilStrokeData", "gpencil_stroke_data")
|
||||
|
@ -28,7 +26,16 @@ GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke)
|
|||
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
|
||||
.push_constant(Type::MAT4, "ProjectionMatrix")
|
||||
.vertex_source("gpu_shader_gpencil_stroke_vert.glsl")
|
||||
.geometry_source("gpu_shader_gpencil_stroke_geom.glsl")
|
||||
.fragment_source("gpu_shader_gpencil_stroke_frag.glsl")
|
||||
.typedef_source("GPU_shader_shared.h")
|
||||
.typedef_source("GPU_shader_shared.h");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke_geom)
|
||||
.additional_info("gpu_shader_gpencil_stroke_base")
|
||||
.geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::TRIANGLE_STRIP, 13)
|
||||
.geometry_out(gpencil_stroke_geom_iface)
|
||||
.geometry_source("gpu_shader_gpencil_stroke_geom.glsl")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke_nogeom)
|
||||
.additional_info("gpu_shader_gpencil_stroke_base")
|
||||
.do_static_compilation(true);
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_icon)
|
||||
.define("DO_CORNER_MASKING")
|
||||
.vertex_out(smooth_icon_interp_iface)
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
|
||||
.push_constant(Type::VEC4, "color")
|
||||
.push_constant(Type::VEC4, "finalColor")
|
||||
.push_constant(Type::VEC4, "rect_icon")
|
||||
.push_constant(Type::VEC4, "rect_geom")
|
||||
.push_constant(Type::FLOAT, "text_width")
|
||||
|
@ -20,3 +21,14 @@ GPU_SHADER_CREATE_INFO(gpu_shader_icon)
|
|||
.vertex_source("gpu_shader_icon_vert.glsl")
|
||||
.fragment_source("gpu_shader_icon_frag.glsl")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_icon_multi)
|
||||
.vertex_in(0, Type::VEC2, "pos")
|
||||
.vertex_out(flat_color_smooth_tex_coord_interp_iface)
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.uniform_buf(0, "MultiIconCallData", "multi_icon_data")
|
||||
.sampler(0, ImageType::FLOAT_2D, "image")
|
||||
.typedef_source("GPU_shader_shared.h")
|
||||
.vertex_source("gpu_shader_icon_multi_vert.glsl")
|
||||
.fragment_source("gpu_shader_icon_frag.glsl")
|
||||
.do_static_compilation(true);
|
||||
|
|
|
@ -36,7 +36,7 @@ static void test_shader_builtin()
|
|||
test_compile_builtin_shader(GPU_SHADER_3D_IMAGE_COLOR, GPU_SHADER_CFG_DEFAULT);
|
||||
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_DESATURATE_COLOR, GPU_SHADER_CFG_DEFAULT);
|
||||
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR, GPU_SHADER_CFG_DEFAULT);
|
||||
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR, GPU_SHADER_CFG_DEFAULT);
|
||||
test_compile_builtin_shader(GPU_SHADER_ICON_MULTI, GPU_SHADER_CFG_DEFAULT);
|
||||
test_compile_builtin_shader(GPU_SHADER_2D_CHECKER, GPU_SHADER_CFG_DEFAULT);
|
||||
test_compile_builtin_shader(GPU_SHADER_2D_DIAG_STRIPES, GPU_SHADER_CFG_DEFAULT);
|
||||
test_compile_builtin_shader(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
|
||||
|
|
|
@ -491,6 +491,8 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
|
|||
}
|
||||
BKE_id_attributes_active_color_set(
|
||||
&me->id, CustomData_get_layer_name(&me->ldata, CD_PROP_BYTE_COLOR, 0));
|
||||
BKE_id_attributes_default_color_set(
|
||||
&me->id, CustomData_get_layer_name(&me->ldata, CD_PROP_BYTE_COLOR, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -401,6 +401,7 @@ void MeshFromGeometry::create_colors(Mesh *mesh)
|
|||
CustomDataLayer *color_layer = BKE_id_attribute_new(
|
||||
&mesh->id, "Color", CD_PROP_COLOR, ATTR_DOMAIN_POINT, nullptr);
|
||||
BKE_id_attributes_active_color_set(&mesh->id, color_layer->name);
|
||||
BKE_id_attributes_default_color_set(&mesh->id, color_layer->name);
|
||||
float4 *colors = (float4 *)color_layer->data;
|
||||
int offset = mesh_geometry_.vertex_index_min_ - block.start_vertex_index;
|
||||
for (int i = 0, n = mesh_geometry_.get_vertex_count(); i != n; ++i) {
|
||||
|
|
|
@ -1143,8 +1143,65 @@ static void rna_MeshUVLoopLayer_clone_set(PointerRNA *ptr, bool value)
|
|||
/* vertex_color_layers */
|
||||
|
||||
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_color, ldata, CD_PROP_BYTE_COLOR)
|
||||
DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(
|
||||
vertex_color, ldata, CD_PROP_BYTE_COLOR, active, MeshLoopColorLayer)
|
||||
|
||||
static PointerRNA rna_Mesh_vertex_color_active_get(PointerRNA *ptr)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ptr->data;
|
||||
|
||||
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&mesh->id);
|
||||
|
||||
if (!layer || layer->type != CD_PROP_BYTE_COLOR ||
|
||||
BKE_id_attribute_domain(&mesh->id, layer) != ATTR_DOMAIN_CORNER) {
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_MeshLoopColorLayer, layer);
|
||||
}
|
||||
|
||||
static void rna_Mesh_vertex_color_active_set(PointerRNA *ptr,
|
||||
const PointerRNA value,
|
||||
ReportList *reports)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ptr->data;
|
||||
CustomDataLayer *layer = (CustomDataLayer *)value.data;
|
||||
|
||||
if (!layer) {
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_id_attributes_active_color_set(&mesh->id, layer->name);
|
||||
}
|
||||
|
||||
static int rna_Mesh_vertex_color_active_index_get(PointerRNA *ptr)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ptr->data;
|
||||
|
||||
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&mesh->id);
|
||||
|
||||
if (!layer || layer->type != CD_PROP_BYTE_COLOR ||
|
||||
BKE_id_attribute_domain(&mesh->id, layer) != ATTR_DOMAIN_CORNER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CustomData *ldata = rna_mesh_ldata(ptr);
|
||||
return layer - ldata->layers + CustomData_get_layer_index(ldata, CD_PROP_BYTE_COLOR);
|
||||
}
|
||||
|
||||
static void rna_Mesh_vertex_color_active_index_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ptr->data;
|
||||
CustomData *ldata = rna_mesh_ldata(ptr);
|
||||
|
||||
if (value < 0 || value >= CustomData_number_of_layers(ldata, CD_PROP_BYTE_COLOR)) {
|
||||
fprintf(stderr, "Invalid loop byte attribute index %d\n", value);
|
||||
return;
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = ldata->layers + CustomData_get_layer_index(ldata, CD_PROP_BYTE_COLOR) +
|
||||
value;
|
||||
|
||||
BKE_id_attributes_active_color_set(&mesh->id, layer->name);
|
||||
}
|
||||
|
||||
static void rna_MeshLoopColorLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||
{
|
||||
|
@ -1160,35 +1217,98 @@ static int rna_MeshLoopColorLayer_data_length(PointerRNA *ptr)
|
|||
return (me->edit_mesh) ? 0 : me->totloop;
|
||||
}
|
||||
|
||||
static bool rna_MeshLoopColorLayer_active_render_get(PointerRNA *ptr)
|
||||
static bool rna_mesh_color_active_render_get(PointerRNA *ptr)
|
||||
{
|
||||
const Mesh *mesh = rna_mesh(ptr);
|
||||
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
|
||||
return mesh->default_color_attribute && STREQ(mesh->default_color_attribute, layer->name);
|
||||
}
|
||||
|
||||
static bool rna_MeshLoopColorLayer_active_get(PointerRNA *ptr)
|
||||
static bool rna_mesh_color_active_get(PointerRNA *ptr)
|
||||
{
|
||||
const Mesh *mesh = rna_mesh(ptr);
|
||||
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
|
||||
return mesh->active_color_attribute && STREQ(mesh->active_color_attribute, layer->name);
|
||||
}
|
||||
|
||||
static void rna_MeshLoopColorLayer_active_render_set(PointerRNA *ptr, bool value)
|
||||
static void rna_mesh_color_active_render_set(PointerRNA *ptr, bool value)
|
||||
{
|
||||
rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_PROP_BYTE_COLOR, 1);
|
||||
Mesh *mesh = (Mesh *)ptr->owner_id;
|
||||
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
|
||||
|
||||
BKE_id_attributes_default_color_set(&mesh->id, layer->name);
|
||||
}
|
||||
|
||||
static void rna_MeshLoopColorLayer_active_set(PointerRNA *ptr, bool value)
|
||||
static void rna_mesh_color_active_set(PointerRNA *ptr, bool value)
|
||||
{
|
||||
rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_PROP_BYTE_COLOR, 0);
|
||||
Mesh *mesh = (Mesh *)ptr->owner_id;
|
||||
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
|
||||
|
||||
BKE_id_attributes_active_color_set(&mesh->id, layer->name);
|
||||
}
|
||||
|
||||
/* sculpt_vertex_color_layers */
|
||||
|
||||
DEFINE_CUSTOMDATA_LAYER_COLLECTION(sculpt_vertex_color, vdata, CD_PROP_COLOR)
|
||||
DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(
|
||||
sculpt_vertex_color, vdata, CD_PROP_COLOR, active, MeshVertColorLayer)
|
||||
|
||||
static PointerRNA rna_Mesh_sculpt_vertex_color_active_get(PointerRNA *ptr)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ptr->data;
|
||||
|
||||
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&mesh->id);
|
||||
|
||||
if (!layer || layer->type != CD_PROP_COLOR ||
|
||||
BKE_id_attribute_domain(&mesh->id, layer) != ATTR_DOMAIN_POINT) {
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_MeshVertColorLayer, layer);
|
||||
}
|
||||
|
||||
static void rna_Mesh_sculpt_vertex_color_active_set(PointerRNA *ptr,
|
||||
const PointerRNA value,
|
||||
ReportList *reports)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ptr->data;
|
||||
CustomDataLayer *layer = (CustomDataLayer *)value.data;
|
||||
|
||||
if (!layer) {
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_id_attributes_active_color_set(&mesh->id, layer->name);
|
||||
}
|
||||
|
||||
static int rna_Mesh_sculpt_vertex_color_active_index_get(PointerRNA *ptr)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ptr->data;
|
||||
|
||||
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&mesh->id);
|
||||
CustomData *vdata = rna_mesh_vdata(ptr);
|
||||
|
||||
if (!layer || layer->type != CD_PROP_COLOR ||
|
||||
BKE_id_attribute_domain(&mesh->id, layer) != ATTR_DOMAIN_POINT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return layer - vdata->layers + CustomData_get_layer_index(vdata, CD_PROP_COLOR);
|
||||
}
|
||||
|
||||
static void rna_Mesh_sculpt_vertex_color_active_index_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ptr->data;
|
||||
CustomData *vdata = rna_mesh_vdata(ptr);
|
||||
|
||||
if (value < 0 || value >= CustomData_number_of_layers(vdata, CD_PROP_COLOR)) {
|
||||
fprintf(stderr, "Invalid loop byte attribute index %d\n", value);
|
||||
return;
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = vdata->layers + CustomData_get_layer_index(vdata, CD_PROP_COLOR) +
|
||||
value;
|
||||
|
||||
BKE_id_attributes_active_color_set(&mesh->id, layer->name);
|
||||
}
|
||||
|
||||
static void rna_MeshVertColorLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||
{
|
||||
|
@ -1204,30 +1324,6 @@ static int rna_MeshVertColorLayer_data_length(PointerRNA *ptr)
|
|||
return (me->edit_mesh) ? 0 : me->totvert;
|
||||
}
|
||||
|
||||
static bool rna_MeshVertColorLayer_active_render_get(PointerRNA *ptr)
|
||||
{
|
||||
const Mesh *mesh = rna_mesh(ptr);
|
||||
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
|
||||
return mesh->default_color_attribute && STREQ(mesh->default_color_attribute, layer->name);
|
||||
}
|
||||
|
||||
static bool rna_MeshVertColorLayer_active_get(PointerRNA *ptr)
|
||||
{
|
||||
const Mesh *mesh = rna_mesh(ptr);
|
||||
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
|
||||
return mesh->active_color_attribute && STREQ(mesh->active_color_attribute, layer->name);
|
||||
}
|
||||
|
||||
static void rna_MeshVertColorLayer_active_render_set(PointerRNA *ptr, bool value)
|
||||
{
|
||||
rna_CustomDataLayer_active_set(ptr, rna_mesh_vdata(ptr), value, CD_PROP_COLOR, 1);
|
||||
}
|
||||
|
||||
static void rna_MeshVertColorLayer_active_set(PointerRNA *ptr, bool value)
|
||||
{
|
||||
rna_CustomDataLayer_active_set(ptr, rna_mesh_vdata(ptr), value, CD_PROP_COLOR, 0);
|
||||
}
|
||||
|
||||
static int rna_float_layer_check(CollectionPropertyIterator *UNUSED(iter), void *data)
|
||||
{
|
||||
CustomDataLayer *layer = (CustomDataLayer *)data;
|
||||
|
@ -2292,6 +2388,13 @@ static PointerRNA rna_Mesh_vertex_color_new(struct Mesh *me,
|
|||
if (index != -1) {
|
||||
ldata = rna_mesh_ldata_helper(me);
|
||||
cdl = &ldata->layers[CustomData_get_layer_index_n(ldata, CD_PROP_BYTE_COLOR, index)];
|
||||
|
||||
if (!me->active_color_attribute) {
|
||||
me->active_color_attribute = BLI_strdup(cdl->name);
|
||||
}
|
||||
if (!me->default_color_attribute) {
|
||||
me->default_color_attribute = BLI_strdup(cdl->name);
|
||||
}
|
||||
}
|
||||
|
||||
RNA_pointer_create(&me->id, &RNA_MeshLoopColorLayer, cdl, &ptr);
|
||||
|
@ -3012,16 +3115,14 @@ static void rna_def_mloopcol(BlenderRNA *brna)
|
|||
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
|
||||
|
||||
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_MeshLoopColorLayer_active_get", "rna_MeshLoopColorLayer_active_set");
|
||||
RNA_def_property_boolean_funcs(prop, "rna_mesh_color_active_get", "rna_mesh_color_active_set");
|
||||
RNA_def_property_ui_text(prop, "Active", "Sets the layer as active for display and editing");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
|
||||
|
||||
prop = RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
|
||||
RNA_def_property_boolean_funcs(prop,
|
||||
"rna_MeshLoopColorLayer_active_render_get",
|
||||
"rna_MeshLoopColorLayer_active_render_set");
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_mesh_color_active_render_get", "rna_mesh_color_active_render_set");
|
||||
RNA_def_property_ui_text(prop, "Active Render", "Sets the layer as active for rendering");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
|
||||
|
||||
|
@ -3073,17 +3174,15 @@ static void rna_def_MPropCol(BlenderRNA *brna)
|
|||
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
|
||||
|
||||
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_MeshVertColorLayer_active_get", "rna_MeshVertColorLayer_active_set");
|
||||
RNA_def_property_boolean_funcs(prop, "rna_mesh_color_active_get", "rna_mesh_color_active_set");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Active", "Sets the sculpt vertex color layer as active for display and editing");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
|
||||
|
||||
prop = RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
|
||||
RNA_def_property_boolean_funcs(prop,
|
||||
"rna_MeshVertColorLayer_active_render_get",
|
||||
"rna_MeshVertColorLayer_active_render_set");
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_mesh_color_active_render_get", "rna_mesh_color_active_render_set");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Active Render", "Sets the sculpt vertex color layer as active for rendering");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
|
||||
|
|
|
@ -834,15 +834,21 @@ static void initialize_group_input(NodesModifierData &nmd,
|
|||
}
|
||||
}
|
||||
|
||||
static const lf::FunctionNode &find_viewer_lf_node(const bNode &viewer_bnode)
|
||||
static const lf::FunctionNode *find_viewer_lf_node(const bNode &viewer_bnode)
|
||||
{
|
||||
return *blender::nodes::ensure_geometry_nodes_lazy_function_graph(viewer_bnode.owner_tree())
|
||||
->mapping.viewer_node_map.lookup(&viewer_bnode);
|
||||
if (const blender::nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
|
||||
blender::nodes::ensure_geometry_nodes_lazy_function_graph(viewer_bnode.owner_tree())) {
|
||||
return lf_graph_info->mapping.viewer_node_map.lookup_default(&viewer_bnode, nullptr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static const lf::FunctionNode &find_group_lf_node(const bNode &group_bnode)
|
||||
static const lf::FunctionNode *find_group_lf_node(const bNode &group_bnode)
|
||||
{
|
||||
return *blender::nodes::ensure_geometry_nodes_lazy_function_graph(group_bnode.owner_tree())
|
||||
->mapping.group_node_map.lookup(&group_bnode);
|
||||
if (const blender::nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
|
||||
blender::nodes::ensure_geometry_nodes_lazy_function_graph(group_bnode.owner_tree())) {
|
||||
return lf_graph_info->mapping.group_node_map.lookup_default(&group_bnode, nullptr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void find_side_effect_nodes_for_viewer_path(
|
||||
|
@ -888,15 +894,22 @@ static void find_side_effect_nodes_for_viewer_path(
|
|||
if (found_viewer_node == nullptr) {
|
||||
return;
|
||||
}
|
||||
const lf::FunctionNode *lf_viewer_node = find_viewer_lf_node(*found_viewer_node);
|
||||
if (lf_viewer_node == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not only mark the viewer node as having side effects, but also all group nodes it is contained
|
||||
* in. */
|
||||
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(),
|
||||
&find_viewer_lf_node(*found_viewer_node));
|
||||
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_viewer_node);
|
||||
compute_context_builder.pop();
|
||||
while (!compute_context_builder.is_empty()) {
|
||||
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(),
|
||||
&find_group_lf_node(*group_node_stack.pop()));
|
||||
const lf::FunctionNode *lf_group_node = find_group_lf_node(*group_node_stack.pop());
|
||||
if (lf_group_node == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_group_node);
|
||||
compute_context_builder.pop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,31 @@ static Array<float> accumulated_lengths_curve_domain(const bke::CurvesGeometry &
|
|||
return lengths;
|
||||
}
|
||||
|
||||
static Array<float> calculate_curve_parameters(const bke::CurvesGeometry &curves)
|
||||
{
|
||||
const VArray<bool> cyclic = curves.cyclic();
|
||||
Array<float> lengths = accumulated_lengths_curve_domain(curves);
|
||||
|
||||
const int last_index = curves.curves_num() - 1;
|
||||
const float total_length = lengths.last() + curves.evaluated_length_total_for_curve(
|
||||
last_index, cyclic[last_index]);
|
||||
if (total_length > 0.0f) {
|
||||
const float factor = 1.0f / total_length;
|
||||
for (float &value : lengths) {
|
||||
value *= factor;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* It is arbitrary what to do in those rare cases when all the points are
|
||||
* in the same position. In this case we are just arbitrarily giving a valid
|
||||
* value in the range based on the curve index. */
|
||||
for (const int i : lengths.index_range()) {
|
||||
lengths[i] = i / (lengths.size() - 1.0f);
|
||||
}
|
||||
}
|
||||
return lengths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of each control point along each curve, starting at zero for the first point.
|
||||
* Importantly, this is different than the length at each evaluated point. The implementation is
|
||||
|
@ -55,7 +80,9 @@ static Array<float> accumulated_lengths_curve_domain(const bke::CurvesGeometry &
|
|||
* - NURBS Curves: Treat the control points as if they were a poly curve, because there
|
||||
* is no obvious mapping from each control point to a specific evaluated point.
|
||||
*/
|
||||
static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
|
||||
static Array<float> calculate_point_lengths(
|
||||
const bke::CurvesGeometry &curves,
|
||||
const FunctionRef<void(MutableSpan<float>, float)> postprocess_lengths_for_curve)
|
||||
{
|
||||
curves.ensure_evaluated_lengths();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
@ -68,26 +95,33 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
|
|||
threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
const IndexRange points = points_by_curve[i_curve];
|
||||
const Span<float> evaluated_lengths = curves.evaluated_lengths_for_curve(i_curve,
|
||||
cyclic[i_curve]);
|
||||
const bool is_cyclic = cyclic[i_curve];
|
||||
const Span<float> evaluated_lengths = curves.evaluated_lengths_for_curve(i_curve, is_cyclic);
|
||||
MutableSpan<float> lengths = result.as_mutable_span().slice(points);
|
||||
lengths.first() = 0.0f;
|
||||
const float last_evaluated_length = evaluated_lengths.is_empty() ? 0.0f :
|
||||
evaluated_lengths.last();
|
||||
|
||||
float total;
|
||||
switch (types[i_curve]) {
|
||||
case CURVE_TYPE_CATMULL_ROM: {
|
||||
const int resolution = resolutions[i_curve];
|
||||
for (const int i : IndexRange(points.size()).drop_back(1)) {
|
||||
lengths[i + 1] = evaluated_lengths[resolution * (i + 1) - 1];
|
||||
}
|
||||
total = last_evaluated_length;
|
||||
break;
|
||||
}
|
||||
case CURVE_TYPE_POLY:
|
||||
lengths.drop_front(1).copy_from(evaluated_lengths.take_front(lengths.size() - 1));
|
||||
total = last_evaluated_length;
|
||||
break;
|
||||
case CURVE_TYPE_BEZIER: {
|
||||
const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve);
|
||||
for (const int i : IndexRange(points.size()).drop_back(1)) {
|
||||
lengths[i + 1] = evaluated_lengths[offsets[i + 1] - 1];
|
||||
}
|
||||
total = last_evaluated_length;
|
||||
break;
|
||||
}
|
||||
case CURVE_TYPE_NURBS: {
|
||||
|
@ -98,115 +132,44 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
|
|||
length += math::distance(positions[i], positions[i + 1]);
|
||||
}
|
||||
lengths.last() = length;
|
||||
if (is_cyclic) {
|
||||
length += math::distance(positions.first(), positions.last());
|
||||
}
|
||||
total = length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
postprocess_lengths_for_curve(lengths, total);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry &curves,
|
||||
const IndexMask /*mask*/,
|
||||
const eAttrDomain domain)
|
||||
static void convert_lengths_to_factors(MutableSpan<float> lengths, const float total_curve_length)
|
||||
{
|
||||
const VArray<bool> cyclic = curves.cyclic();
|
||||
|
||||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
Array<float> result = curve_length_point_domain(curves);
|
||||
MutableSpan<float> lengths = result.as_mutable_span();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
MutableSpan<float> curve_lengths = lengths.slice(points_by_curve[i_curve]);
|
||||
const float total_length = curve_lengths.last();
|
||||
if (total_length > 0.0f) {
|
||||
const float factor = 1.0f / total_length;
|
||||
for (float &value : curve_lengths) {
|
||||
value *= factor;
|
||||
}
|
||||
}
|
||||
else if (curve_lengths.size() == 1) {
|
||||
/* The curve is a single point. */
|
||||
curve_lengths[0] = 0.0f;
|
||||
}
|
||||
else {
|
||||
/* It is arbitrary what to do in those rare cases when all the points are
|
||||
* in the same position. In this case we are just arbitrarily giving a valid
|
||||
* value in the range based on the point index. */
|
||||
for (const int i : curve_lengths.index_range()) {
|
||||
curve_lengths[i] = i / (curve_lengths.size() - 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return VArray<float>::ForContainer(std::move(result));
|
||||
}
|
||||
|
||||
if (domain == ATTR_DOMAIN_CURVE) {
|
||||
Array<float> lengths = accumulated_lengths_curve_domain(curves);
|
||||
|
||||
const int last_index = curves.curves_num() - 1;
|
||||
const float total_length = lengths.last() + curves.evaluated_length_total_for_curve(
|
||||
last_index, cyclic[last_index]);
|
||||
if (total_length > 0.0f) {
|
||||
const float factor = 1.0f / total_length;
|
||||
for (float &value : lengths) {
|
||||
value *= factor;
|
||||
}
|
||||
if (total_curve_length > 0.0f) {
|
||||
const float factor = 1.0f / total_curve_length;
|
||||
for (float &value : lengths.drop_front(1)) {
|
||||
value *= factor;
|
||||
}
|
||||
else {
|
||||
/* It is arbitrary what to do in those rare cases when all the points are
|
||||
* in the same position. In this case we are just arbitrarily giving a valid
|
||||
* value in the range based on the curve index. */
|
||||
for (const int i : lengths.index_range()) {
|
||||
lengths[i] = i / (lengths.size() - 1.0f);
|
||||
}
|
||||
}
|
||||
else if (lengths.size() == 1) {
|
||||
/* The curve is a single point. */
|
||||
lengths[0] = 0.0f;
|
||||
}
|
||||
else {
|
||||
/* It is arbitrary what to do in those rare cases when all the
|
||||
* points are in the same position. In this case we are just
|
||||
* arbitrarily giving a valid
|
||||
* value in the range based on the point index. */
|
||||
for (const int i : lengths.index_range()) {
|
||||
lengths[i] = i / (lengths.size() - 1.0f);
|
||||
}
|
||||
return VArray<float>::ForContainer(std::move(lengths));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGeometry &curves,
|
||||
const IndexMask /*mask*/,
|
||||
const eAttrDomain domain)
|
||||
static Array<float> calculate_point_parameters(const bke::CurvesGeometry &curves)
|
||||
{
|
||||
curves.ensure_evaluated_lengths();
|
||||
|
||||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
Array<float> lengths = curve_length_point_domain(curves);
|
||||
return VArray<float>::ForContainer(std::move(lengths));
|
||||
}
|
||||
|
||||
if (domain == ATTR_DOMAIN_CURVE) {
|
||||
Array<float> lengths = accumulated_lengths_curve_domain(curves);
|
||||
return VArray<float>::ForContainer(std::move(lengths));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static VArray<int> construct_index_on_spline_varray(const bke::CurvesGeometry &curves,
|
||||
const IndexMask /*mask*/,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
Array<int> result(curves.points_num());
|
||||
MutableSpan<int> span = result.as_mutable_span();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
MutableSpan<int> indices = span.slice(points_by_curve[i_curve]);
|
||||
for (const int i : indices.index_range()) {
|
||||
indices[i] = i;
|
||||
}
|
||||
}
|
||||
});
|
||||
return VArray<int>::ForContainer(std::move(result));
|
||||
}
|
||||
return {};
|
||||
return calculate_point_lengths(curves, convert_lengths_to_factors);
|
||||
}
|
||||
|
||||
class CurveParameterFieldInput final : public bke::CurvesFieldInput {
|
||||
|
@ -218,14 +181,21 @@ class CurveParameterFieldInput final : public bke::CurvesFieldInput {
|
|||
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const final
|
||||
const IndexMask /*mask*/) const final
|
||||
{
|
||||
return construct_curve_parameter_varray(curves, mask, domain);
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return VArray<float>::ForContainer(calculate_point_parameters(curves));
|
||||
case ATTR_DOMAIN_CURVE:
|
||||
return VArray<float>::ForContainer(calculate_curve_parameters(curves));
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
{
|
||||
/* Some random constant hash. */
|
||||
return 29837456298;
|
||||
}
|
||||
|
||||
|
@ -245,14 +215,22 @@ class CurveLengthParameterFieldInput final : public bke::CurvesFieldInput {
|
|||
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const final
|
||||
const IndexMask /*mask*/) const final
|
||||
{
|
||||
return construct_curve_length_parameter_varray(curves, mask, domain);
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return VArray<float>::ForContainer(calculate_point_lengths(
|
||||
curves, [](MutableSpan<float> /*lengths*/, const float /*total*/) {}));
|
||||
case ATTR_DOMAIN_CURVE:
|
||||
return VArray<float>::ForContainer(accumulated_lengths_curve_domain(curves));
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
{
|
||||
/* Some random constant hash. */
|
||||
return 345634563454;
|
||||
}
|
||||
|
||||
|
@ -271,14 +249,26 @@ class IndexOnSplineFieldInput final : public bke::CurvesFieldInput {
|
|||
|
||||
GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
IndexMask mask) const final
|
||||
const IndexMask /*mask*/) const final
|
||||
{
|
||||
return construct_index_on_spline_varray(curves, mask, domain);
|
||||
if (domain != ATTR_DOMAIN_POINT) {
|
||||
return {};
|
||||
}
|
||||
Array<int> result(curves.points_num());
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
MutableSpan<int> indices = result.as_mutable_span().slice(points_by_curve[i_curve]);
|
||||
for (const int i : indices.index_range()) {
|
||||
indices[i] = i;
|
||||
}
|
||||
}
|
||||
});
|
||||
return VArray<int>::ForContainer(std::move(result));
|
||||
}
|
||||
|
||||
uint64_t hash() const override
|
||||
{
|
||||
/* Some random constant hash. */
|
||||
return 4536246522;
|
||||
}
|
||||
|
||||
|
|
|
@ -218,29 +218,17 @@ class ReverseUVSampleFunction : public mf::MultiFunction {
|
|||
MutableSpan<float3> bary_weights = params.uninitialized_single_output_if_required<float3>(
|
||||
3, "Barycentric Weights");
|
||||
|
||||
Array<ReverseUVSampler::Result> results(mask.min_array_size());
|
||||
reverse_uv_sampler_->sample_many(sample_uvs, results);
|
||||
|
||||
if (!is_valid.is_empty()) {
|
||||
std::transform(results.begin(),
|
||||
results.end(),
|
||||
is_valid.begin(),
|
||||
[](const ReverseUVSampler::Result &result) {
|
||||
return result.type == ReverseUVSampler::ResultType::Ok;
|
||||
});
|
||||
}
|
||||
if (!tri_index.is_empty()) {
|
||||
std::transform(results.begin(),
|
||||
results.end(),
|
||||
tri_index.begin(),
|
||||
[](const ReverseUVSampler::Result &result) { return result.looptri_index; });
|
||||
}
|
||||
|
||||
if (!bary_weights.is_empty()) {
|
||||
std::transform(results.begin(),
|
||||
results.end(),
|
||||
bary_weights.begin(),
|
||||
[](const ReverseUVSampler::Result &result) { return result.bary_weights; });
|
||||
for (const int i : mask) {
|
||||
const ReverseUVSampler::Result result = reverse_uv_sampler_->sample(sample_uvs[i]);
|
||||
if (!is_valid.is_empty()) {
|
||||
is_valid[i] = result.type == ReverseUVSampler::ResultType::Ok;
|
||||
}
|
||||
if (!tri_index.is_empty()) {
|
||||
tri_index[i] = result.looptri_index;
|
||||
}
|
||||
if (!bary_weights.is_empty()) {
|
||||
bary_weights[i] = result.bary_weights;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -746,7 +746,13 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
|
|||
MEM_freeN(prop);
|
||||
}
|
||||
else {
|
||||
const bool overridable = prop_exist ?
|
||||
(prop_exist->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0 :
|
||||
false;
|
||||
IDP_ReplaceInGroup_ex(group, prop, prop_exist);
|
||||
if (overridable) {
|
||||
prop->flag |= IDP_FLAG_OVERRIDABLE_LIBRARY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ VERSION_MIN = (1, 6, 0)
|
|||
VERSION_MAX_RECOMMENDED = (1, 6, 0)
|
||||
AUTOPEP8_FORMAT_CMD = "autopep8"
|
||||
|
||||
BASE_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
||||
BASE_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
os.chdir(BASE_DIR)
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ VERSION_MIN = (8, 0, 0)
|
|||
VERSION_MAX_RECOMMENDED = (12, 0, 0)
|
||||
CLANG_FORMAT_CMD = "clang-format"
|
||||
|
||||
BASE_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
||||
BASE_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
os.chdir(BASE_DIR)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue