Fix #104016: Resolve Metal LineLoop emulation. #105142

Merged
Clément Foucault merged 2 commits from Jason-Fielder/blender:Fix_104016 into blender-v3.5-release 2023-02-26 15:22:05 +01:00
66 changed files with 886 additions and 434 deletions
Showing only changes of commit d8679ed931 - Show all commits

View File

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

View File

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

View File

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

View File

@ -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)",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

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

View File

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

View File

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

View File

@ -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. */

View File

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

View File

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

View File

@ -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. */

View File

@ -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");

View File

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

View File

@ -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_;
}

View File

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

View File

@ -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);
}

View File

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

View File

@ -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*/)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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());

View File

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

View File

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

View File

@ -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();
}

View File

@ -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());
}

View File

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

View File

@ -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. */

View File

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

View File

@ -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);
}
}
}
}

View File

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

View File

@ -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. */

View File

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

View File

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

View File

@ -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");
}

View File

@ -0,0 +1,5 @@
void main()
{
fragColor = texture(image_texture, texCoord_interp);
}

View File

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

View File

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

View File

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

View File

@ -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. */

View File

@ -1,5 +0,0 @@
void main()
{
fragColor = texture(image, texCoord_interp) * finalColor;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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));
}
}
}

View File

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

View File

@ -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");

View File

@ -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();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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