Curves: Add edit mode operator to set attribute values #105076

Merged
Hans Goudey merged 9 commits from HooglyBoogly/blender:curves-attribute-set into main 2023-10-17 12:35:50 +02:00
41 changed files with 589 additions and 275 deletions
Showing only changes of commit 3c14f2c675 - Show all commits

View File

@ -1826,7 +1826,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam,
if (!window->m_mousePresent) {
WINTAB_PRINTF("HWND %p mouse enter\n", window->getHWND());
TRACKMOUSEEVENT tme = {sizeof(tme)};
tme.dwFlags = TME_LEAVE;
/* Request WM_MOUSELEAVE message when the cursor leaves the client area, and
* WM_MOUSEHOVER message after 50ms when in the client area. */
tme.dwFlags = TME_LEAVE | TME_HOVER;
tme.dwHoverTime = 50;
tme.hwndTrack = hwnd;
TrackMouseEvent(&tme);
window->m_mousePresent = true;
@ -1843,6 +1846,35 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam,
break;
}
case WM_MOUSEHOVER: {
/* Mouse Tracking is now off. TrackMouseEvent restarts in MouseMove. */
window->m_mousePresent = false;
/* Auto-focus only occurs within Blender windows, not with _other_ applications. */
HWND old_hwnd = ::GetFocus();
if (hwnd != old_hwnd) {
HWND new_parent = ::GetParent(hwnd);
HWND old_parent = ::GetParent(old_hwnd);
if (hwnd == old_parent || old_hwnd == new_parent) {
/* Child to its parent, parent to its child. */
::SetFocus(hwnd);
}
else if (new_parent != HWND_DESKTOP && new_parent == old_parent) {
/* Between siblings of same parent. */
::SetFocus(hwnd);
}
else if (!new_parent && !old_parent) {
/* Between main windows that don't overlap. */
RECT new_rect, old_rect, dest_rect;
::GetWindowRect(hwnd, &new_rect);
::GetWindowRect(old_hwnd, &old_rect);
if (!IntersectRect(&dest_rect, &new_rect, &old_rect)) {
::SetFocus(hwnd);
}
}
}
break;
}
case WM_MOUSEWHEEL: {
/* The WM_MOUSEWHEEL message is sent to the focus window
* when the mouse wheel is rotated. The DefWindowProc

View File

@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Panel, Menu
from bpy.types import Panel, Menu, UIList
from rna_prop_ui import PropertyPanel
from bl_ui.properties_animviz import (
@ -91,6 +91,16 @@ class DATA_MT_bone_group_context_menu(Menu):
layout.operator("pose.group_sort", icon='SORTALPHA')
class DATA_UL_bone_groups(UIList):
def draw_item(self, _context, layout, _data, item, _icon, _active_data, _active_propname, _index):
layout.prop(item, "name", text="", emboss=False, icon='GROUP_BONE')
if item.is_custom_color_set or item.color_set == 'DEFAULT':
layout.prop(item, "color_set", icon_only=True, icon="COLOR")
else:
layout.prop(item, "color_set", icon_only=True)
class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
bl_label = "Bone Groups"
bl_options = {'DEFAULT_CLOSED'}
@ -111,8 +121,9 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
rows = 1
if group:
rows = 4
row.template_list(
"UI_UL_list",
"DATA_UL_bone_groups",
"bone_groups",
pose,
"bone_groups",
@ -121,6 +132,7 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
rows=rows,
)
col = row.column(align=True)
col.operator("pose.group_add", icon='ADD', text="")
col.operator("pose.group_remove", icon='REMOVE', text="")
@ -130,17 +142,20 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
col.operator("pose.group_move", icon='TRIA_UP', text="").direction = 'UP'
col.operator("pose.group_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
split = layout.split()
if group.is_custom_color_set:
col = layout.column()
split = col.split(factor=0.4)
col = split.column()
col.prop(group, "color_set")
if group.color_set:
col = split.column()
sub = col.row(align=True)
sub.enabled = group.is_custom_color_set # only custom colors are editable
sub.prop(group.colors, "normal", text="")
sub.prop(group.colors, "select", text="")
sub.prop(group.colors, "active", text="")
row = col.row()
row.alignment = 'RIGHT'
row.label(text="Custom Colors")
col = split.column(align=True)
row = col.row(align=True)
row.prop(group.colors, "normal", text="")
row.prop(group.colors, "select", text="")
row.prop(group.colors, "active", text="")
row = layout.row()
@ -258,6 +273,7 @@ classes = (
DATA_PT_skeleton,
DATA_MT_bone_group_context_menu,
DATA_PT_bone_groups,
DATA_UL_bone_groups,
DATA_PT_motion_paths,
DATA_PT_motion_paths_display,
DATA_PT_display,

View File

@ -1091,17 +1091,6 @@ static void blf_glyph_calc_rect(rcti *rect, GlyphBLF *g, const int x, const int
rect->ymax = rect->ymin - g->dims[1];
}
static void blf_glyph_calc_rect_test(rcti *rect, GlyphBLF *g, const int x, const int y)
{
/* Intentionally check with `g->advance`, because this is the
* width used by BLF_width. This allows that the text slightly
* overlaps the clipping border to achieve better alignment. */
rect->xmin = x;
rect->xmax = rect->xmin + MIN2(ft_pix_to_int(g->advance_x), g->dims[0]);
rect->ymin = y;
rect->ymax = rect->ymin - g->dims[1];
}
static void blf_glyph_calc_rect_shadow(
rcti *rect, GlyphBLF *g, const int x, const int y, FontBLF *font)
{
@ -1213,9 +1202,10 @@ void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x,
if (font->flags & BLF_CLIPPING) {
rcti rect_test;
blf_glyph_calc_rect_test(&rect_test, g, x, y);
BLI_rcti_translate(&rect_test, font->pos[0], font->pos[1]);
rect_test.xmin = x + font->pos[0] + g->pos[0] + 1;
rect_test.xmax = rect_test.xmin + g->dims[0] - 2;
rect_test.ymin = y + font->pos[1];
rect_test.ymax = rect_test.ymin + g->pos[1];
if (!BLI_rcti_inside_rcti(&font->clip_rec, &rect_test)) {
return;
}

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

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

@ -6532,6 +6532,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;
@ -6610,10 +6612,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)) {
@ -6696,7 +6701,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

@ -970,9 +970,9 @@ 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);
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 +990,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

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

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

@ -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. */
@ -1159,6 +1166,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");
@ -1220,20 +1228,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();
@ -1255,6 +1263,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;
@ -1285,14 +1294,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) {
@ -1385,13 +1400,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",
@ -1412,6 +1429,7 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
handle_left.span,
handle_right.span,
radius.span,
nurbs_weight.span,
resolution.span);
}
});
@ -1432,6 +1450,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

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

@ -225,7 +225,7 @@ static void test_gpu_shader_compute_ssbo()
EXPECT_NE(shader, nullptr);
GPU_shader_bind(shader);
/* Construct IBO. */
/* Construct SSBO. */
GPUStorageBuf *ssbo = GPU_storagebuf_create_ex(
SIZE * sizeof(uint32_t), nullptr, GPU_USAGE_DEVICE_ONLY, __func__);
GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out"));

View File

@ -119,6 +119,10 @@ void VKDescriptorSet::update(VkDevice vk_device)
descriptor_writes.append(write_descriptor);
}
BLI_assert_msg(image_infos.size() + buffer_infos.size() == descriptor_writes.size(),
"Not all changes have been converted to a write descriptor. Check "
"`Binding::is_buffer` and `Binding::is_image`.");
vkUpdateDescriptorSets(
vk_device, descriptor_writes.size(), descriptor_writes.data(), 0, nullptr);

View File

@ -15,10 +15,11 @@
#include "vk_common.hh"
namespace blender::gpu {
class VKStorageBuffer;
class VKVertexBuffer;
class VKIndexBuffer;
class VKShaderInterface;
class VKStorageBuffer;
class VKTexture;
class VKVertexBuffer;
/**
* In vulkan shader resources (images and buffers) are grouped in descriptor sets.
@ -26,7 +27,7 @@ class VKTexture;
* The resources inside a descriptor set can be updated and bound per set.
*
* Currently Blender only supports a single descriptor set per shader, but it is planned to be able
* to use 2 descriptor sets per shader. Only for each #blender::gpu::shader::Frequency.
* to use 2 descriptor sets per shader. One for each #blender::gpu::shader::Frequency.
*/
class VKDescriptorSet : NonCopyable {
struct Binding;
@ -50,9 +51,12 @@ class VKDescriptorSet : NonCopyable {
*/
uint32_t binding;
Location() = default;
Location(uint32_t binding) : binding(binding)
{
}
public:
Location() = default;
Location(const ShaderInput *shader_input) : binding(shader_input->location)
{
}
@ -68,6 +72,7 @@ class VKDescriptorSet : NonCopyable {
}
friend struct Binding;
friend class VKShaderInterface;
};
private:

View File

@ -24,9 +24,9 @@ void VKIndexBuffer::bind_as_ssbo(uint binding)
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const ShaderInput *shader_input = shader_interface.shader_input_get(
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding);
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, shader_input);
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, location);
}
void VKIndexBuffer::read(uint32_t *data) const

View File

@ -326,10 +326,10 @@ static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifie
}
static void print_resource(std::ostream &os,
const ShaderInput &shader_input,
const VKDescriptorSet::Location location,
const ShaderCreateInfo::Resource &res)
{
os << "layout(binding = " << shader_input.location;
os << "layout(binding = " << static_cast<uint32_t>(location);
if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
os << ", " << to_string(res.image.format);
}
@ -379,12 +379,8 @@ static void print_resource(std::ostream &os,
const VKShaderInterface &shader_interface,
const ShaderCreateInfo::Resource &res)
{
const ShaderInput *shader_input = shader_interface.shader_input_get(res);
if (shader_input == nullptr) {
BLI_assert_msg(shader_input, "Cannot find shader input for resource");
return;
}
print_resource(os, *shader_input, res);
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(res);
print_resource(os, location, res);
}
static void print_resource_alias(std::ostream &os, const ShaderCreateInfo::Resource &res)
@ -860,10 +856,10 @@ static VkDescriptorType descriptor_type(const shader::ShaderCreateInfo::Resource
}
static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding(
const ShaderInput &shader_input, const shader::ShaderCreateInfo::Resource &resource)
const VKDescriptorSet::Location location, const shader::ShaderCreateInfo::Resource &resource)
{
VkDescriptorSetLayoutBinding binding = {};
binding.binding = shader_input.location;
binding.binding = location;
binding.descriptorType = descriptor_type(resource);
binding.descriptorCount = 1;
binding.stageFlags = VK_SHADER_STAGE_ALL;
@ -878,13 +874,8 @@ static void add_descriptor_set_layout_bindings(
Vector<VkDescriptorSetLayoutBinding> &r_bindings)
{
for (const shader::ShaderCreateInfo::Resource &resource : resources) {
const ShaderInput *shader_input = interface.shader_input_get(resource);
if (shader_input == nullptr) {
BLI_assert_msg(shader_input, "Cannot find shader input for resource.");
continue;
}
r_bindings.append(create_descriptor_set_layout_binding(*shader_input, resource));
const VKDescriptorSet::Location location = interface.descriptor_set_location(resource);
r_bindings.append(create_descriptor_set_layout_binding(location, resource));
}
}
@ -1033,12 +1024,6 @@ std::string VKShader::vertex_interface_declare(const shader::ShaderCreateInfo &i
ss << "layout(location = " << attr.index << ") ";
ss << "in " << to_string(attr.type) << " " << attr.name << ";\n";
}
/* NOTE(D4490): Fix a bug where shader without any vertex attributes do not behave correctly.
*/
if (GPU_type_matches_ex(GPU_DEVICE_APPLE, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL) &&
info.vertex_inputs_.is_empty()) {
ss << "in float gpu_dummy_workaround;\n";
}
ss << "\n/* Interfaces. */\n";
int location = 0;
for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {

View File

@ -41,7 +41,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
}
}
/* Make sure that the image slots don't overlap with the sampler slots.*/
image_offset_ += 1;
image_offset_++;
int32_t input_tot_len = ubo_len_ + uniform_len_ + ssbo_len_;
inputs_ = static_cast<ShaderInput *>(
@ -51,14 +51,11 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer");
uint32_t name_buffer_offset = 0;
int location = 0;
/* Uniform blocks */
for (const ShaderCreateInfo::Resource &res : all_resources) {
if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset);
input->location = location++;
input->binding = res.slot;
input->location = input->binding = res.slot;
input++;
}
}
@ -67,14 +64,12 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
for (const ShaderCreateInfo::Resource &res : all_resources) {
if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) {
copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset);
input->location = location++;
input->binding = res.slot;
input->location = input->binding = res.slot;
input++;
}
else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset);
input->location = location++;
input->binding = res.slot + image_offset_;
input->location = input->binding = res.slot + image_offset_;
input++;
}
}
@ -83,13 +78,57 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
for (const ShaderCreateInfo::Resource &res : all_resources) {
if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) {
copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset);
input->location = location++;
input->binding = res.slot;
input->location = input->binding = res.slot;
input++;
}
}
sort_inputs();
/* Determine the descriptor set locations after the inputs have been sorted.*/
descriptor_set_locations_ = Array<VKDescriptorSet::Location>(input_tot_len);
uint32_t descriptor_set_location = 0;
for (ShaderCreateInfo::Resource &res : all_resources) {
const ShaderInput *input = shader_input_get(res);
descriptor_set_location_update(input, descriptor_set_location++);
}
}
static int32_t shader_input_index(const ShaderInput *shader_inputs,
const ShaderInput *shader_input)
{
int32_t index = (shader_input - shader_inputs);
return index;
}
void VKShaderInterface::descriptor_set_location_update(const ShaderInput *shader_input,
const VKDescriptorSet::Location location)
{
int32_t index = shader_input_index(inputs_, shader_input);
descriptor_set_locations_[index] = location;
}
const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
const ShaderInput *shader_input) const
{
int32_t index = shader_input_index(inputs_, shader_input);
return descriptor_set_locations_[index];
}
const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
const shader::ShaderCreateInfo::Resource &resource) const
{
const ShaderInput *shader_input = shader_input_get(resource);
BLI_assert(shader_input);
return descriptor_set_location(shader_input);
}
const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const
{
const ShaderInput *shader_input = shader_input_get(bind_type, binding);
BLI_assert(shader_input);
return descriptor_set_location(shader_input);
}
const ShaderInput *VKShaderInterface::shader_input_get(

View File

@ -7,9 +7,13 @@
#pragma once
#include "BLI_array.hh"
#include "gpu_shader_create_info.hh"
#include "gpu_shader_interface.hh"
#include "vk_descriptor_set.hh"
namespace blender::gpu {
class VKShaderInterface : public ShaderInterface {
private:
@ -21,11 +25,19 @@ class VKShaderInterface : public ShaderInterface {
* overlapping.
*/
uint32_t image_offset_ = 0;
Array<VKDescriptorSet::Location> descriptor_set_locations_;
public:
VKShaderInterface() = default;
void init(const shader::ShaderCreateInfo &info);
const VKDescriptorSet::Location descriptor_set_location(
const shader::ShaderCreateInfo::Resource &resource) const;
const VKDescriptorSet::Location descriptor_set_location(
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const;
private:
/**
* Retrieve the shader input for the given resource.
*
@ -35,5 +47,9 @@ class VKShaderInterface : public ShaderInterface {
const ShaderInput *shader_input_get(const shader::ShaderCreateInfo::Resource &resource) const;
const ShaderInput *shader_input_get(
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const;
const VKDescriptorSet::Location descriptor_set_location(const ShaderInput *shader_input) const;
void descriptor_set_location_update(const ShaderInput *shader_input,
const VKDescriptorSet::Location location);
};
} // namespace blender::gpu

View File

@ -34,9 +34,9 @@ void VKStorageBuffer::bind(int slot)
}
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const ShaderInput *shader_input = shader_interface.shader_input_get(
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, slot);
shader->pipeline_get().descriptor_set_get().bind(*this, shader_input);
shader->pipeline_get().descriptor_set_get().bind(*this, location);
}
void VKStorageBuffer::unbind()

View File

@ -227,8 +227,9 @@ void VKTexture::image_bind(int binding)
}
VKContext &context = *VKContext::get();
VKShader *shader = static_cast<VKShader *>(context.shader);
VKDescriptorSet::Location location(shader->interface_get().shader_input_get(
shader::ShaderCreateInfo::Resource::BindType::IMAGE, binding));
const VKShaderInterface &shader_interface = shader->interface_get();
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::IMAGE, binding);
shader->pipeline_get().descriptor_set_get().image_bind(*this, location);
}

View File

@ -27,9 +27,9 @@ void VKVertexBuffer::bind_as_ssbo(uint binding)
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const ShaderInput *shader_input = shader_interface.shader_input_get(
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding);
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, shader_input);
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, location);
}
void VKVertexBuffer::bind_as_texture(uint /*binding*/)

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

@ -475,12 +475,19 @@ static USDPrimReader *get_usd_reader(CacheReader *reader,
return usd_reader;
}
USDMeshReadParams create_mesh_read_params(const double motion_sample_time, const int read_flags)
{
USDMeshReadParams params = {};
params.motion_sample_time = motion_sample_time;
params.read_flags = read_flags;
return params;
}
struct Mesh *USD_read_mesh(struct CacheReader *reader,
struct Object *ob,
struct Mesh *existing_mesh,
const double time,
const char **err_str,
const int read_flag)
const USDMeshReadParams params,
const char **err_str)
{
USDGeomReader *usd_reader = dynamic_cast<USDGeomReader *>(get_usd_reader(reader, ob, err_str));
@ -488,7 +495,7 @@ struct Mesh *USD_read_mesh(struct CacheReader *reader,
return nullptr;
}
return usd_reader->read_mesh(existing_mesh, time, read_flag, err_str);
return usd_reader->read_mesh(existing_mesh, params, err_str);
}
bool USD_mesh_topology_changed(CacheReader *reader,

View File

@ -162,8 +162,7 @@ void USDCurvesReader::read_curve_sample(Curve *cu, const double motionSampleTime
}
Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh,
const double motionSampleTime,
const int /* read_flag */,
const USDMeshReadParams params,
const char ** /* err_str */)
{
if (!curve_prim_) {
@ -176,11 +175,11 @@ Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh,
pxr::VtIntArray usdCounts;
vertexAttr.Get(&usdCounts, motionSampleTime);
vertexAttr.Get(&usdCounts, params.motion_sample_time);
int num_subcurves = usdCounts.size();
pxr::VtVec3fArray usdPoints;
pointsAttr.Get(&usdPoints, motionSampleTime);
pointsAttr.Get(&usdPoints, params.motion_sample_time);
int vertex_idx = 0;
int curve_idx;
@ -204,7 +203,7 @@ Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh,
if (!same_topology) {
BKE_nurbList_free(&curve->nurb);
read_curve_sample(curve, motionSampleTime);
read_curve_sample(curve, params.motion_sample_time);
}
else {
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);

View File

@ -36,8 +36,7 @@ class USDCurvesReader : public USDGeomReader {
void read_curve_sample(Curve *cu, double motionSampleTime);
Mesh *read_mesh(struct Mesh *existing_mesh,
double motionSampleTime,
int read_flag,
USDMeshReadParams params,
const char **err_str) override;
};

View File

@ -20,8 +20,7 @@ class USDGeomReader : public USDXformReader {
}
virtual Mesh *read_mesh(struct Mesh *existing_mesh,
double motionSampleTime,
int read_flag,
USDMeshReadParams params,
const char **err_str) = 0;
virtual bool topology_changed(const Mesh * /* existing_mesh */, double /* motionSampleTime */)

View File

@ -194,8 +194,9 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime)
Mesh *mesh = (Mesh *)object_->data;
is_initial_load_ = true;
Mesh *read_mesh = this->read_mesh(
mesh, motionSampleTime, import_params_.mesh_read_flag, nullptr);
const USDMeshReadParams params = create_mesh_read_params(motionSampleTime, import_params_.mesh_read_flag);
Mesh *read_mesh = this->read_mesh(mesh, params, nullptr);
is_initial_load_ = false;
if (read_mesh != mesh) {
@ -222,7 +223,7 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime)
}
USDXformReader::read_object_data(bmain, motionSampleTime);
}
} // namespace blender::io::usd
bool USDMeshReader::valid() const
{
@ -767,8 +768,7 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot
}
Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
const double motionSampleTime,
const int read_flag,
const USDMeshReadParams params,
const char ** /* err_str */)
{
if (!mesh_prim_) {
@ -785,7 +785,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
std::vector<pxr::TfToken> uv_tokens;
/* Currently we only handle UV primvars. */
if (read_flag & MOD_MESHSEQ_READ_UV) {
if (params.read_flags & MOD_MESHSEQ_READ_UV) {
std::vector<pxr::UsdGeomPrimvar> primvars = primvarsAPI.GetPrimvars();
@ -838,9 +838,9 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
* the topology is consistent, as in the Alembic importer. */
ImportSettings settings;
settings.read_flag |= read_flag;
settings.read_flag |= params.read_flags;
if (topology_changed(existing_mesh, motionSampleTime)) {
if (topology_changed(existing_mesh, params.motion_sample_time)) {
new_mesh = true;
active_mesh = BKE_mesh_new_nomain_from_template(
existing_mesh, positions_.size(), 0, 0, face_indices_.size(), face_counts_.size());
@ -850,7 +850,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
}
}
read_mesh_sample(&settings, active_mesh, motionSampleTime, new_mesh || is_initial_load_);
read_mesh_sample(&settings, active_mesh, params.motion_sample_time, new_mesh || is_initial_load_);
if (new_mesh) {
/* Here we assume that the number of materials doesn't change, i.e. that
@ -862,7 +862,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
bke::MutableAttributeAccessor attributes = active_mesh->attributes_for_write();
bke::SpanAttributeWriter<int> material_indices =
attributes.lookup_or_add_for_write_span<int>("material_index", ATTR_DOMAIN_FACE);
assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map);
assign_facesets_to_material_indices(params.motion_sample_time, material_indices.span, &mat_map);
material_indices.finish();
}
}

View File

@ -49,8 +49,7 @@ class USDMeshReader : public USDGeomReader {
void read_object_data(Main *bmain, double motionSampleTime) override;
struct Mesh *read_mesh(struct Mesh *existing_mesh,
double motionSampleTime,
int read_flag,
USDMeshReadParams params,
const char **err_str) override;
bool topology_changed(const Mesh *existing_mesh, double motionSampleTime) override;

View File

@ -165,8 +165,7 @@ void USDNurbsReader::read_curve_sample(Curve *cu, const double motionSampleTime)
}
Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */,
const double motionSampleTime,
const int /* read_flag */,
const USDMeshReadParams params,
const char ** /* err_str */)
{
pxr::UsdGeomCurves curve_prim_(prim_);
@ -177,11 +176,11 @@ Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */,
pxr::VtIntArray usdCounts;
vertexAttr.Get(&usdCounts, motionSampleTime);
vertexAttr.Get(&usdCounts, params.motion_sample_time);
int num_subcurves = usdCounts.size();
pxr::VtVec3fArray usdPoints;
pointsAttr.Get(&usdPoints, motionSampleTime);
pointsAttr.Get(&usdPoints, params.motion_sample_time);
int vertex_idx = 0;
int curve_idx;
@ -205,7 +204,7 @@ Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */,
if (!same_topology) {
BKE_nurbList_free(&curve->nurb);
read_curve_sample(curve, motionSampleTime);
read_curve_sample(curve, params.motion_sample_time);
}
else {
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);

View File

@ -36,8 +36,7 @@ class USDNurbsReader : public USDGeomReader {
void read_curve_sample(Curve *cu, double motionSampleTime);
Mesh *read_mesh(struct Mesh *existing_mesh,
double motionSampleTime,
int read_flag,
USDMeshReadParams params,
const char **err_str) override;
};

View File

@ -45,9 +45,10 @@ void USDShapeReader::create_object(Main *bmain, double /*motionSampleTime*/)
void USDShapeReader::read_object_data(Main *bmain, double motionSampleTime)
{
const USDMeshReadParams params = create_mesh_read_params(motionSampleTime,
import_params_.mesh_read_flag);
Mesh *mesh = (Mesh *)object_->data;
Mesh *read_mesh = this->read_mesh(
mesh, motionSampleTime, import_params_.mesh_read_flag, nullptr);
Mesh *read_mesh = this->read_mesh(mesh, params, nullptr);
if (read_mesh != mesh) {
BKE_mesh_nomain_to_mesh(read_mesh, mesh, object_);
@ -124,8 +125,7 @@ bool USDShapeReader::read_mesh_values(double motionSampleTime,
}
Mesh *USDShapeReader::read_mesh(struct Mesh *existing_mesh,
double motionSampleTime,
int /*read_flag*/,
const USDMeshReadParams params,
const char ** /*err_str*/)
{
pxr::VtIntArray face_indices;
@ -136,7 +136,8 @@ Mesh *USDShapeReader::read_mesh(struct Mesh *existing_mesh,
}
/* Should have a good set of data by this point-- copy over. */
Mesh *active_mesh = mesh_from_prim(existing_mesh, motionSampleTime, face_indices, face_counts);
Mesh *active_mesh = mesh_from_prim(
existing_mesh, params.motion_sample_time, face_indices, face_counts);
if (active_mesh == existing_mesh) {
return existing_mesh;
}

View File

@ -48,8 +48,7 @@ class USDShapeReader : public USDGeomReader {
void create_object(Main *bmain, double /*motionSampleTime*/) override;
void read_object_data(Main *bmain, double motionSampleTime) override;
Mesh *read_mesh(Mesh *existing_mesh,
double motionSampleTime,
int /*read_flag*/,
USDMeshReadParams params,
const char ** /*err_str*/) override;
bool is_time_varying();

View File

@ -86,6 +86,16 @@ struct USDImportParams {
bool import_all_materials;
};
/* This struct is in place to store the mesh sequence parameters needed when reading a data from a
* usd file for the mesh sequence cache.
*/
typedef struct USDMeshReadParams {
double motion_sample_time; /* USD TimeCode in frames. */
int read_flags; /* MOD_MESHSEQ_xxx value that is set from MeshSeqCacheModifierData.read_flag. */
} USDMeshReadParams;
USDMeshReadParams create_mesh_read_params(double motion_sample_time, int read_flags);
/* The USD_export takes a as_background_job parameter, and returns a boolean.
*
* When as_background_job=true, returns false immediately after scheduling
@ -121,9 +131,8 @@ void USD_get_transform(struct CacheReader *reader, float r_mat[4][4], float time
struct Mesh *USD_read_mesh(struct CacheReader *reader,
struct Object *ob,
struct Mesh *existing_mesh,
double time,
const char **err_str,
int read_flag);
USDMeshReadParams params,
const char **err_str);
bool USD_mesh_topology_changed(struct CacheReader *reader,
const struct Object *ob,

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

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

View File

@ -245,12 +245,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
# endif
break;
}
case CACHEFILE_TYPE_USD:
case CACHEFILE_TYPE_USD: {
# ifdef WITH_USD
result = USD_read_mesh(
mcmd->reader, ctx->object, mesh, time * FPS, &err_str, mcmd->read_flag);
const USDMeshReadParams params = create_mesh_read_params(time * FPS, mcmd->read_flag);
result = USD_read_mesh(mcmd->reader, ctx->object, mesh, params, &err_str);
# endif
break;
}
case CACHE_FILE_TYPE_INVALID:
break;
}

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,31 @@ 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;
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 = evaluated_lengths.last();
break;
}
case CURVE_TYPE_POLY:
lengths.drop_front(1).copy_from(evaluated_lengths.take_front(lengths.size() - 1));
total = evaluated_lengths.last();
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 = evaluated_lengths.last();
break;
}
case CURVE_TYPE_NURBS: {
@ -98,115 +130,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 +179,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 +213,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 +247,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

@ -3669,22 +3669,26 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
}
}
static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
static eHandlerActionFlag wm_event_drag_and_drop_test(wmWindowManager *wm,
wmWindow *win,
wmEvent *event)
{
bScreen *screen = WM_window_get_active_screen(win);
if (BLI_listbase_is_empty(&wm->drags)) {
return;
return WM_HANDLER_CONTINUE;
}
if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) {
screen->do_draw_drag = true;
}
else if (event->type == EVT_ESCKEY) {
else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
wm_drags_exit(wm, win);
WM_drag_free_list(&wm->drags);
screen->do_draw_drag = true;
return WM_HANDLER_BREAK;
}
else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
event->type = EVT_DROP;
@ -3703,6 +3707,8 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv
/* Restore cursor (disabled, see `wm_dragdrop.cc`) */
// WM_cursor_modal_restore(win);
}
return WM_HANDLER_CONTINUE;
}
/**
@ -4025,7 +4031,7 @@ void wm_event_do_handlers(bContext *C)
}
/* Check dragging, creates new event or frees, adds draw tag. */
wm_event_drag_and_drop_test(wm, win, event);
action |= wm_event_drag_and_drop_test(wm, win, event);
if ((action & WM_HANDLER_BREAK) == 0) {
/* NOTE: setting sub-window active should be done here,