Replace Default OCIO config with AgX (Filmic v2) #106355

Closed
Zijun Zhou wants to merge 112 commits from (deleted):main into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
21 changed files with 706 additions and 289 deletions
Showing only changes of commit 95fe126d14 - Show all commits

View File

@ -4410,6 +4410,8 @@ def km_face_mask(params):
{"properties": [("deselect", False)]}),
("paint.face_select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True},
{"properties": [("deselect", True)]}),
("paint.face_select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None),
("paint.face_select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None),
])
return keymap
@ -4437,6 +4439,8 @@ def km_weight_paint_vertex_selection(params):
{"properties": [("select", True)]}),
("paint.vert_select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True},
{"properties": [("select", False)]}),
("paint.vert_select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None),
("paint.vert_select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None),
])
return keymap

View File

@ -2011,6 +2011,9 @@ class VIEW3D_MT_select_paint_mask(Menu):
layout.operator("paint.face_select_all", text="None").action = 'DESELECT'
layout.operator("paint.face_select_all", text="Invert").action = 'INVERT'
layout.operator("paint.face_select_more")
layout.operator("paint.face_select_less")
layout.separator()
layout.operator("view3d.select_box")
@ -2032,6 +2035,9 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu):
layout.operator("paint.vert_select_all", text="None").action = 'DESELECT'
layout.operator("paint.vert_select_all", text="Invert").action = 'INVERT'
layout.operator("paint.vert_select_more"),
layout.operator("paint.vert_select_less"),
layout.separator()
layout.operator("view3d.select_box")
@ -7047,13 +7053,16 @@ class VIEW3D_PT_snapping(Panel):
col.prop(tool_settings, "use_snap_backface_culling")
if 'FACE' in snap_elements:
col.prop(tool_settings, "use_snap_project")
is_face_nearest_enabled = 'FACE_NEAREST' in snap_elements
if is_face_nearest_enabled or 'FACE' in snap_elements:
sub = col.column()
sub.active = not is_face_nearest_enabled
sub.prop(tool_settings, "use_snap_project")
if 'FACE_NEAREST' in snap_elements:
col.prop(tool_settings, "use_snap_to_same_target")
if object_mode == 'EDIT':
col.prop(tool_settings, "snap_face_nearest_steps")
if is_face_nearest_enabled:
col.prop(tool_settings, "use_snap_to_same_target")
if object_mode == 'EDIT':
col.prop(tool_settings, "snap_face_nearest_steps")
if 'VOLUME' in snap_elements:
col.prop(tool_settings, "use_snap_peel_object")

View File

@ -196,11 +196,14 @@ class AttributeFieldInput : public GeometryFieldInput {
category_ = Category::NamedAttribute;
}
static fn::GField Create(std::string name, const CPPType &type)
{
auto field_input = std::make_shared<AttributeFieldInput>(std::move(name), type);
return fn::GField(field_input);
}
template<typename T> static fn::Field<T> Create(std::string name)
{
const CPPType &type = CPPType::get<T>();
auto field_input = std::make_shared<AttributeFieldInput>(std::move(name), type);
return fn::Field<T>{field_input};
return fn::Field<T>(Create(std::move(name), CPPType::get<T>()));
}
StringRefNull attribute_name() const

View File

@ -21,7 +21,7 @@ void ModifierComputeContext::print_current_in_line(std::ostream &stream) const
NodeGroupComputeContext::NodeGroupComputeContext(
const ComputeContext *parent,
const int node_id,
const int32_t node_id,
const std::optional<ComputeContextHash> &cached_hash)
: ComputeContext(s_static_type, parent), node_id_(node_id)
{

View File

@ -1101,8 +1101,8 @@ double determinant_m3_array_db(const double m[3][3])
bool invert_m2_m2(float inverse[2][2], const float mat[2][2])
{
const float det = determinant_m2(mat[0][0], mat[1][0], mat[0][1], mat[1][1]);
adjoint_m2_m2(inverse, mat);
float det = determinant_m2(mat[0][0], mat[1][0], mat[0][1], mat[1][1]);
bool success = (det != 0.0f);
if (success) {
@ -1957,11 +1957,15 @@ void normalize_m4_m4(float rmat[4][4], const float mat[4][4])
void adjoint_m2_m2(float R[2][2], const float M[2][2])
{
BLI_assert(R != M);
R[0][0] = M[1][1];
R[0][1] = -M[0][1];
R[1][0] = -M[1][0];
R[1][1] = M[0][0];
const float r00 = M[1][1];
const float r01 = -M[0][1];
const float r10 = -M[1][0];
const float r11 = M[0][0];
R[0][0] = r00;
R[0][1] = r01;
R[1][0] = r10;
R[1][1] = r11;
}
void adjoint_m3_m3(float R[3][3], const float M[3][3])
@ -2026,9 +2030,8 @@ void adjoint_m4_m4(float R[4][4], const float M[4][4]) /* out = ADJ(in) */
R[3][3] = determinant_m3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
}
float determinant_m2(float a, float b, float c, float d)
float determinant_m2(const float a, const float b, const float c, const float d)
{
return a * d - b * c;
}

View File

@ -419,6 +419,11 @@ void paintface_select_linked(struct bContext *C,
struct Object *ob,
const int mval[2],
bool select);
/** Grow the selection of faces.
* \param face_step If true will also select faces that only touch on the corner.
*/
void paintface_select_more(struct Mesh *mesh, bool face_step);
void paintface_select_less(struct Mesh *mesh, bool face_step);
bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]);
void paintface_hide(struct bContext *C, struct Object *ob, bool unselected);
@ -444,6 +449,8 @@ void paintvert_select_linked_pick(struct bContext *C,
struct Object *ob,
const int region_coordinates[2],
bool select);
void paintvert_select_more(struct Mesh *mesh, bool face_step);
void paintvert_select_less(struct Mesh *mesh, bool face_step);
void paintvert_hide(struct bContext *C, struct Object *ob, bool unselected);
void paintvert_reveal(struct bContext *C, struct Object *ob, bool select);

View File

@ -24,6 +24,7 @@
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_mesh.hh"
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
#include "ED_mesh.h"
@ -350,6 +351,131 @@ void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const b
paintface_flush_flags(C, ob, true, false);
}
static bool poly_has_selected_neighbor(blender::Span<int> poly_edges,
blender::Span<MEdge> edges,
blender::Span<bool> select_vert,
const bool face_step)
{
for (const int edge_index : poly_edges) {
const MEdge &edge = edges[edge_index];
/* If a poly is selected, all of its verts are selected too, meaning that neighboring faces
* will have some vertices selected. */
if (face_step) {
if (select_vert[edge.v1] || select_vert[edge.v2]) {
return true;
}
}
else {
if (select_vert[edge.v1] && select_vert[edge.v2]) {
return true;
}
}
}
return false;
}
void paintface_select_more(Mesh *mesh, const bool face_step)
{
using namespace blender;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", ATTR_DOMAIN_FACE);
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", ATTR_DOMAIN_POINT);
const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
".hide_poly", ATTR_DOMAIN_FACE, false);
const Span<MPoly> polys = mesh->polys();
const Span<int> corner_edges = mesh->corner_edges();
const Span<MEdge> edges = mesh->edges();
threading::parallel_for(select_poly.span.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
if (select_poly.span[i] || hide_poly[i]) {
continue;
}
const MPoly &poly = polys[i];
if (poly_has_selected_neighbor(corner_edges.slice(poly.loopstart, poly.totloop),
edges,
select_vert.span,
face_step)) {
select_poly.span[i] = true;
}
}
});
select_poly.finish();
select_vert.finish();
}
static bool poly_has_unselected_neighbor(blender::Span<int> poly_edges,
blender::Span<MEdge> edges,
blender::BitSpan verts_of_unselected_faces,
const bool face_step)
{
for (const int edge_index : poly_edges) {
const MEdge &edge = edges[edge_index];
if (face_step) {
if (verts_of_unselected_faces[edge.v1] || verts_of_unselected_faces[edge.v2]) {
return true;
}
}
else {
if (verts_of_unselected_faces[edge.v1] && verts_of_unselected_faces[edge.v2]) {
return true;
}
}
}
return false;
}
void paintface_select_less(Mesh *mesh, const bool face_step)
{
using namespace blender;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", ATTR_DOMAIN_FACE);
const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
".hide_poly", ATTR_DOMAIN_FACE, false);
const Span<MPoly> polys = mesh->polys();
const Span<int> corner_verts = mesh->corner_verts();
const Span<int> corner_edges = mesh->corner_edges();
const Span<MEdge> edges = mesh->edges();
BitVector<> verts_of_unselected_faces(mesh->totvert);
/* Find all vertices of unselected faces to help find neighboring faces after. */
for (const int i : polys.index_range()) {
if (select_poly.span[i]) {
continue;
}
const MPoly &poly = polys[i];
for (const int vert : corner_verts.slice(poly.loopstart, poly.totloop)) {
verts_of_unselected_faces[vert].set(true);
}
}
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
if (!select_poly.span[i] || hide_poly[i]) {
continue;
}
const MPoly &poly = polys[i];
if (poly_has_unselected_neighbor(corner_edges.slice(poly.loopstart, poly.totloop),
edges,
verts_of_unselected_faces,
face_step)) {
select_poly.span[i] = false;
}
}
});
select_poly.finish();
}
bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags)
{
using namespace blender;
@ -660,6 +786,126 @@ void paintvert_select_linked(bContext *C, Object *ob)
paintvert_select_linked_vertices(C, ob, indices, true);
}
void paintvert_select_more(Mesh *mesh, const bool face_step)
{
using namespace blender;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", ATTR_DOMAIN_POINT);
const VArray<bool> hide_edge = attributes.lookup_or_default<bool>(
".hide_edge", ATTR_DOMAIN_EDGE, false);
const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
".hide_poly", ATTR_DOMAIN_FACE, false);
const Span<MPoly> polys = mesh->polys();
const Span<int> corner_edges = mesh->corner_edges();
const Span<int> corner_verts = mesh->corner_verts();
const Span<MEdge> edges = mesh->edges();
Array<Vector<int, 2>> edge_to_face_map;
if (face_step) {
edge_to_face_map = bke::mesh_topology::build_edge_to_poly_map(
polys, corner_edges, mesh->totedge);
}
/* Need a copy of the selected verts that we can read from and is not modified. */
BitVector<> select_vert_original(mesh->totvert, false);
for (int i = 0; i < mesh->totvert; i++) {
select_vert_original[i].set(select_vert.span[i]);
}
/* If we iterated over polys we wouldn't extend the selection through edges that have no face
* attached to them. */
for (const int i : edges.index_range()) {
const MEdge &edge = edges[i];
if ((!select_vert_original[edge.v1] && !select_vert_original[edge.v2]) || hide_edge[i]) {
continue;
}
select_vert.span[edge.v1] = true;
select_vert.span[edge.v2] = true;
if (!face_step) {
continue;
}
const Span<int> neighbor_polys = edge_to_face_map[i];
for (const int poly_i : neighbor_polys) {
if (hide_poly[poly_i]) {
continue;
}
const MPoly &poly = polys[poly_i];
for (const int vert : corner_verts.slice(poly.loopstart, poly.totloop)) {
select_vert.span[vert] = true;
}
}
}
select_vert.finish();
}
void paintvert_select_less(Mesh *mesh, const bool face_step)
{
using namespace blender;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", ATTR_DOMAIN_POINT);
const VArray<bool> hide_edge = attributes.lookup_or_default<bool>(
".hide_edge", ATTR_DOMAIN_EDGE, false);
const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
".hide_poly", ATTR_DOMAIN_FACE, false);
const Span<MPoly> polys = mesh->polys();
const Span<int> corner_edges = mesh->corner_edges();
const Span<int> corner_verts = mesh->corner_verts();
const Span<MEdge> edges = mesh->edges();
MeshElemMap *edge_poly_map;
int *edge_poly_mem = nullptr;
if (face_step) {
BKE_mesh_edge_poly_map_create(&edge_poly_map,
&edge_poly_mem,
edges.size(),
polys.data(),
polys.size(),
corner_edges.data(),
corner_edges.size());
}
/* Need a copy of the selected verts that we can read from and is not modified. */
BitVector<> select_vert_original(mesh->totvert);
for (int i = 0; i < mesh->totvert; i++) {
select_vert_original[i].set(select_vert.span[i]);
}
for (const int i : edges.index_range()) {
const MEdge &edge = edges[i];
if ((select_vert_original[edge.v1] && select_vert_original[edge.v2]) && !hide_edge[i]) {
continue;
}
select_vert.span[edge.v1] = false;
select_vert.span[edge.v2] = false;
if (!face_step) {
continue;
}
const Span<int> neighbor_polys(edge_poly_map[i].indices, edge_poly_map[i].count);
for (const int poly_i : neighbor_polys) {
if (hide_poly[poly_i]) {
continue;
}
const MPoly &poly = polys[poly_i];
for (const int vert : corner_verts.slice(poly.loopstart, poly.totloop)) {
select_vert.span[vert] = false;
}
}
}
if (edge_poly_mem) {
MEM_freeN(edge_poly_map);
MEM_freeN(edge_poly_mem);
}
select_vert.finish();
}
void paintvert_tag_select_update(bContext *C, Object *ob)
{
DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);

View File

@ -4043,6 +4043,10 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
CustomData_MeshMasks cddata_masks = scene_eval->customdata_mask;
cddata_masks.fmask |= CD_MASK_MTFACE;
cddata_masks.lmask |= CD_MASK_PROP_FLOAT2;
cddata_masks.vmask |= CD_MASK_PROP_ALL | CD_MASK_CREASE;
cddata_masks.emask |= CD_MASK_PROP_ALL | CD_MASK_CREASE;
cddata_masks.pmask |= CD_MASK_PROP_ALL | CD_MASK_CREASE;
cddata_masks.lmask |= CD_MASK_PROP_ALL | CD_MASK_CREASE;
if (ps->do_face_sel) {
cddata_masks.vmask |= CD_MASK_ORIGINDEX;
cddata_masks.emask |= CD_MASK_ORIGINDEX;

View File

@ -378,6 +378,8 @@ void BRUSH_OT_sculpt_curves_falloff_preset(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked_pick(struct wmOperatorType *ot);
void PAINT_OT_face_select_all(struct wmOperatorType *ot);
void PAINT_OT_face_select_more(struct wmOperatorType *ot);
void PAINT_OT_face_select_less(struct wmOperatorType *ot);
void PAINT_OT_face_select_hide(struct wmOperatorType *ot);
void PAINT_OT_face_vert_reveal(struct wmOperatorType *ot);
@ -387,6 +389,8 @@ void PAINT_OT_vert_select_ungrouped(struct wmOperatorType *ot);
void PAINT_OT_vert_select_hide(struct wmOperatorType *ot);
void PAINT_OT_vert_select_linked(struct wmOperatorType *ot);
void PAINT_OT_vert_select_linked_pick(struct wmOperatorType *ot);
void PAINT_OT_vert_select_more(struct wmOperatorType *ot);
void PAINT_OT_vert_select_less(struct wmOperatorType *ot);
bool vert_paint_poll(struct bContext *C);
bool mask_paint_poll(struct bContext *C);

View File

@ -1501,6 +1501,8 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_vert_select_hide);
WM_operatortype_append(PAINT_OT_vert_select_linked);
WM_operatortype_append(PAINT_OT_vert_select_linked_pick);
WM_operatortype_append(PAINT_OT_vert_select_more);
WM_operatortype_append(PAINT_OT_vert_select_less);
/* vertex */
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
@ -1518,6 +1520,8 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_face_select_linked);
WM_operatortype_append(PAINT_OT_face_select_linked_pick);
WM_operatortype_append(PAINT_OT_face_select_all);
WM_operatortype_append(PAINT_OT_face_select_more);
WM_operatortype_append(PAINT_OT_face_select_less);
WM_operatortype_append(PAINT_OT_face_select_hide);
WM_operatortype_append(PAINT_OT_face_vert_reveal);

View File

@ -693,6 +693,68 @@ void PAINT_OT_face_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
static int paint_select_more_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == NULL || mesh->totpoly == 0) {
return OPERATOR_CANCELLED;
}
const bool face_step = RNA_boolean_get(op->ptr, "face_step");
paintface_select_more(mesh, face_step);
paintface_flush_flags(C, ob, true, false);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
void PAINT_OT_face_select_more(wmOperatorType *ot)
{
ot->name = "Select More";
ot->description = "Select Faces connected to existing selection";
ot->idname = "PAINT_OT_face_select_more";
ot->exec = paint_select_more_exec;
ot->poll = facemask_paint_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(
ot->srna, "face_step", true, "Face Step", "Also select faces that only touch on a corner");
}
static int paint_select_less_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == NULL || mesh->totpoly == 0) {
return OPERATOR_CANCELLED;
}
const bool face_step = RNA_boolean_get(op->ptr, "face_step");
paintface_select_less(mesh, face_step);
paintface_flush_flags(C, ob, true, false);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
void PAINT_OT_face_select_less(wmOperatorType *ot)
{
ot->name = "Select Less";
ot->description = "Deselect Faces connected to existing selection";
ot->idname = "PAINT_OT_face_select_less";
ot->exec = paint_select_less_exec;
ot->poll = facemask_paint_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(
ot->srna, "face_step", true, "Face Step", "Also deselect faces that only touch on a corner");
}
static int vert_select_all_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
@ -796,6 +858,72 @@ void PAINT_OT_vert_select_linked_pick(wmOperatorType *ot)
"Whether to select or deselect linked vertices under the cursor");
}
static int paintvert_select_more_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == NULL || mesh->totpoly == 0) {
return OPERATOR_CANCELLED;
}
const bool face_step = RNA_boolean_get(op->ptr, "face_step");
paintvert_select_more(mesh, face_step);
paintvert_flush_flags(ob);
paintvert_tag_select_update(C, ob);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
void PAINT_OT_vert_select_more(wmOperatorType *ot)
{
ot->name = "Select More";
ot->description = "Select Vertices connected to existing selection";
ot->idname = "PAINT_OT_vert_select_more";
ot->exec = paintvert_select_more_exec;
ot->poll = vert_paint_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(
ot->srna, "face_step", true, "Face Step", "Also select faces that only touch on a corner");
}
static int paintvert_select_less_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == NULL || mesh->totpoly == 0) {
return OPERATOR_CANCELLED;
}
const bool face_step = RNA_boolean_get(op->ptr, "face_step");
paintvert_select_less(mesh, face_step);
paintvert_flush_flags(ob);
paintvert_tag_select_update(C, ob);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
void PAINT_OT_vert_select_less(wmOperatorType *ot)
{
ot->name = "Select Less";
ot->description = "Deselect Vertices connected to existing selection";
ot->idname = "PAINT_OT_vert_select_less";
ot->exec = paintvert_select_less_exec;
ot->poll = vert_paint_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(
ot->srna, "face_step", true, "Face Step", "Also deselect faces that only touch on a corner");
}
static int face_select_hide_exec(bContext *C, wmOperator *op)
{
const bool unselected = RNA_boolean_get(op->ptr, "unselected");

View File

@ -182,6 +182,28 @@ static void graph_main_region_init(wmWindowManager *wm, ARegion *region)
WM_event_add_keymap_handler(&region->handlers, keymap);
}
/* Draw a darker area above 1 and below -1. */
static void draw_normalization_borders(Scene *scene, View2D *v2d)
{
GPU_blend(GPU_BLEND_ALPHA);
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShadeAlpha(TH_BACK, -25, -180);
if (v2d->cur.ymax >= 1) {
immRectf(pos, scene->r.sfra, 1, scene->r.efra, v2d->cur.ymax);
}
if (v2d->cur.ymin <= -1) {
immRectf(pos, scene->r.sfra, v2d->cur.ymin, scene->r.efra, -1);
}
GPU_blend(GPU_BLEND_NONE);
immUnbindProgram();
}
static void graph_main_region_draw(const bContext *C, ARegion *region)
{
/* draw entirely, view changes should be handled here */
@ -207,6 +229,10 @@ static void graph_main_region_draw(const bContext *C, ARegion *region)
ANIM_draw_framerange(scene, v2d);
}
if (sipo->mode == SIPO_MODE_ANIMATION && (sipo->flag & SIPO_NORMALIZE)) {
draw_normalization_borders(scene, v2d);
}
/* draw data */
if (ANIM_animdata_get_context(C, &ac)) {
/* draw ghost curves */

View File

@ -433,8 +433,9 @@ static void nla_draw_strip(SpaceNla *snla,
float yminc,
float ymaxc)
{
const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) &&
(nlt->flag & NLATRACK_SOLO) == 0);
const bool solo = !((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) &&
(nlt->flag & NLATRACK_SOLO) == 0);
const bool muted = ((nlt->flag & NLATRACK_MUTED) || (strip->flag & NLASTRIP_FLAG_MUTED));
float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
uint shdr_pos;
@ -448,7 +449,7 @@ static void nla_draw_strip(SpaceNla *snla,
/* draw extrapolation info first (as backdrop)
* - but this should only be drawn if track has some contribution
*/
if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && (non_solo == 0)) {
if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && solo) {
/* enable transparency... */
GPU_blend(GPU_BLEND_ALPHA);
@ -486,7 +487,7 @@ static void nla_draw_strip(SpaceNla *snla,
}
/* draw 'inside' of strip itself */
if (non_solo == 0 && is_nlastrip_enabled(adt, nlt, strip)) {
if (solo && is_nlastrip_enabled(adt, nlt, strip)) {
immUnbindProgram();
/* strip is in normal track */
@ -629,8 +630,9 @@ static void nla_draw_strip_text(AnimData *adt,
float yminc,
float ymaxc)
{
const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) &&
(nlt->flag & NLATRACK_SOLO) == 0);
const bool solo = !((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) &&
(nlt->flag & NLATRACK_SOLO) == 0);
char str[256];
size_t str_len;
uchar col[4];
@ -650,12 +652,12 @@ static void nla_draw_strip_text(AnimData *adt,
else {
col[0] = col[1] = col[2] = 255;
}
// Default strip to 100% opacity.
col[3] = 255;
/* text opacity depends on whether if there's a solo'd track, this isn't it */
if (non_solo == 0) {
col[3] = 255;
}
else {
/* Reduce text opacity if a track is soloed,
* and if target track isn't the soloed track. */
if (!solo) {
col[3] = 128;
}

View File

@ -731,16 +731,27 @@ static eSnapTargetOP snap_target_select_from_spacetype(TransInfo *t)
static void initSnappingMode(TransInfo *t)
{
if (!transformModeUseSnap(t)) {
/* In this case, snapping is always disabled by default. */
t->modifiers &= ~MOD_SNAP;
}
if (doForceIncrementSnap(t)) {
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
if ((t->spacetype != SPACE_VIEW3D) || !(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST) ||
(t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST) || (t->flag & T_NO_PROJECT)) {
if ((t->spacetype != SPACE_VIEW3D) ||
!(t->tsnap.mode & (SCE_SNAP_MODE_FACE_RAYCAST | SCE_SNAP_MODE_FACE_NEAREST)) ||
(t->flag & T_NO_PROJECT)) {
/* Force project off when not supported. */
t->tsnap.flag &= ~SCE_SNAP_PROJECT;
}
if (t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST) {
/* This mode only works with individual projection. */
t->tsnap.flag |= SCE_SNAP_PROJECT;
}
setSnappingCallback(t);
if (t->spacetype == SPACE_VIEW3D) {
@ -881,9 +892,9 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->tsnap.source_operation = snap_source;
transform_snap_flag_from_modifiers_set(t);
initSnappingMode(t);
transform_snap_flag_from_modifiers_set(t);
}
void freeSnapping(TransInfo *t)

View File

@ -1457,12 +1457,7 @@ static void uvedit_pack_islands_multi(const Scene *scene,
for (int64_t i : pack_island_vector.index_range()) {
blender::geometry::PackIsland *pack_island = pack_island_vector[i];
FaceIsland *island = island_vector[pack_island->caller_index];
const float cos_angle = cosf(pack_island->angle);
const float sin_angle = sinf(pack_island->angle);
matrix[0][0] = cos_angle * scale[0];
matrix[0][1] = -sin_angle * scale[0] * pack_island->aspect_y;
matrix[1][0] = sin_angle * scale[1] / pack_island->aspect_y;
matrix[1][1] = cos_angle * scale[1];
pack_island->build_transformation(scale[0], pack_island->angle, matrix);
invert_m2_m2(matrix_inverse, matrix);
/* Add base_offset, post transform. */

View File

@ -72,8 +72,6 @@ class UVPackIsland_Params {
class PackIsland {
public:
/** Calculated automatically. */
rctf bounds_rect;
/** Aspect ratio, required for rotation. */
float aspect_y;
/** Output pre-translation. */
@ -87,8 +85,16 @@ class PackIsland {
void add_polygon(const blender::Span<float2> uvs, MemArena *arena, Heap *heap);
void finalize_geometry(const UVPackIsland_Params &params, MemArena *arena, Heap *heap);
void build_transformation(const float scale, const float angle, float r_matrix[2][2]);
void build_inverse_transformation(const float scale, const float angle, float r_matrix[2][2]);
/** Center of AABB and inside-or-touching the convex hull. */
float2 pivot_;
/** Half of the diagonal of the AABB. */
float2 half_diagonal_;
private:
void calculate_pivot(); /* Choose a pivot based on triangles. */
void calculate_pivot(); /* Calculate `pivot_` and `half_diagonal_` based on added triangles. */
blender::Vector<float2> triangle_vertices_;
friend class Occupancy;
};

View File

@ -163,15 +163,8 @@ void PackIsland::finalize_geometry(const UVPackIsland_Params &params, MemArena *
void PackIsland::calculate_pivot()
{
Bounds<float2> triangle_bounds = *bounds::min_max(triangle_vertices_.as_span());
float2 aabb_min = triangle_bounds.min;
float2 aabb_max = triangle_bounds.max;
float2 pivot = (aabb_min + aabb_max) * 0.5f;
float2 half_diagonal = (aabb_max - aabb_min) * 0.5f;
bounds_rect.xmin = pivot.x - half_diagonal.x;
bounds_rect.ymin = pivot.y - half_diagonal.y;
bounds_rect.xmax = pivot.x + half_diagonal.x;
bounds_rect.ymax = pivot.y + half_diagonal.y;
pivot_ = (triangle_bounds.min + triangle_bounds.max) * 0.5f;
half_diagonal_ = (triangle_bounds.max - triangle_bounds.min) * 0.5f;
}
UVPackIsland_Params::UVPackIsland_Params()
@ -243,8 +236,8 @@ static void pack_islands_alpaca_turbo(const Span<UVAABBIsland *> islands,
}
/* Place the island. */
island->uv_placement.x = u0;
island->uv_placement.y = v0;
island->uv_placement.x = u0 + dsm_u * 0.5f;
island->uv_placement.y = v0 + dsm_v * 0.5f;
if (zigzag) {
/* Move upwards. */
v0 += dsm_v;
@ -277,11 +270,11 @@ static void pack_island_box_pack_2d(const Span<UVAABBIsland *> aabbs,
MEM_mallocN(sizeof(*box_array) * islands.size(), __func__));
/* Prepare for box_pack_2d. */
for (const int64_t i : islands.index_range()) {
for (const int64_t i : aabbs.index_range()) {
PackIsland *island = islands[aabbs[i]->index];
BoxPack *box = box_array + i;
box->w = BLI_rctf_size_x(&island->bounds_rect) * scale + 2 * margin;
box->h = BLI_rctf_size_y(&island->bounds_rect) * scale + 2 * margin;
box->w = island->half_diagonal_.x * 2 * scale + 2 * margin;
box->h = island->half_diagonal_.y * 2 * scale + 2 * margin;
}
const bool sort_boxes = false; /* Use existing ordering from `aabbs`. */
@ -290,12 +283,12 @@ static void pack_island_box_pack_2d(const Span<UVAABBIsland *> aabbs,
BLI_box_pack_2d(box_array, int(islands.size()), sort_boxes, r_max_u, r_max_v);
/* Write back box_pack UVs. */
for (const int64_t i : islands.index_range()) {
for (const int64_t i : aabbs.index_range()) {
PackIsland *island = islands[aabbs[i]->index];
BoxPack *box = box_array + i;
island->angle = 0.0f; /* #BLI_box_pack_2d never rotates. */
island->pre_translate.x = (box->x + margin) / scale - island->bounds_rect.xmin;
island->pre_translate.y = (box->y + margin) / scale - island->bounds_rect.ymin;
island->pre_translate.x = (box->x + box->w * 0.5f) / scale - island->pivot_.x;
island->pre_translate.y = (box->y + box->h * 0.5f) / scale - island->pivot_.y;
}
/* Housekeeping. */
@ -448,13 +441,13 @@ float Occupancy::trace_island(PackIsland *island,
{
if (!write) {
if (uv.x <= 0.0f || uv.y <= 0.0f) {
if (uv.x < island->half_diagonal_.x * scale + margin ||
uv.y < island->half_diagonal_.y * scale + margin) {
return terminal; /* Occupied. */
}
}
const float2 origin(island->bounds_rect.xmin, island->bounds_rect.ymin);
const float2 delta = uv - origin * scale;
uint vert_count = uint(island->triangle_vertices_.size());
const float2 delta = uv - island->pivot_ * scale;
uint vert_count = uint(island->triangle_vertices_.size()); /* `uint` is faster than `int`. */
for (uint i = 0; i < vert_count; i += 3) {
uint j = (i + triangle_hint_) % vert_count;
float extent = trace_triangle(delta + island->triangle_vertices_[j] * scale,
@ -474,36 +467,33 @@ float Occupancy::trace_island(PackIsland *island,
static float2 find_best_fit_for_island(
PackIsland *island, int scan_line, Occupancy &occupancy, const float scale, const float margin)
{
const float scan_line_bscaled = scan_line / occupancy.bitmap_scale_reciprocal;
const float size_x_scaled = BLI_rctf_size_x(&island->bounds_rect) * scale;
const float size_y_scaled = BLI_rctf_size_y(&island->bounds_rect) * scale;
const float bitmap_scale = 1.0f / occupancy.bitmap_scale_reciprocal;
const float half_x_scaled = island->half_diagonal_.x * scale;
const float half_y_scaled = island->half_diagonal_.y * scale;
/* Scan using an "Alpaca"-style search, first horizontally using "less-than". */
int t = int(ceilf(size_x_scaled * occupancy.bitmap_scale_reciprocal));
int t = int(ceilf((2 * half_x_scaled + margin) * occupancy.bitmap_scale_reciprocal));
while (t < scan_line) {
const float t_bscaled = t / occupancy.bitmap_scale_reciprocal;
const float2 probe(t_bscaled - size_x_scaled, scan_line_bscaled - size_y_scaled);
const float2 probe(t * bitmap_scale - half_x_scaled, scan_line * bitmap_scale - half_y_scaled);
const float extent = occupancy.trace_island(island, scale, margin, probe, false);
if (extent < 0.0f) {
return probe;
return probe; /* Success. */
}
t = t + std::max(1, int(extent));
}
/* Then scan vertically using "less-than-or-equal" */
t = int(ceilf(size_y_scaled * occupancy.bitmap_scale_reciprocal));
t = int(ceilf((2 * half_y_scaled + margin) * occupancy.bitmap_scale_reciprocal));
while (t <= scan_line) {
const float t_bscaled = t / occupancy.bitmap_scale_reciprocal;
const float2 probe(scan_line_bscaled - size_x_scaled, t_bscaled - size_y_scaled);
const float2 probe(scan_line * bitmap_scale - half_x_scaled, t * bitmap_scale - half_y_scaled);
const float extent = occupancy.trace_island(island, scale, margin, probe, false);
if (extent < 0.0f) {
return probe;
return probe; /* Success. */
}
t = t + std::max(1, int(extent));
}
return float2(-1, -1);
return float2(-1, -1); /* Unable to find a place to fit. */
}
static float guess_initial_scale(const Span<PackIsland *> islands,
@ -513,8 +503,8 @@ static float guess_initial_scale(const Span<PackIsland *> islands,
float sum = 1e-40f;
for (int64_t i : islands.index_range()) {
PackIsland *island = islands[i];
sum += BLI_rctf_size_x(&island->bounds_rect) * scale + 2 * margin;
sum += BLI_rctf_size_y(&island->bounds_rect) * scale + 2 * margin;
sum += island->half_diagonal_.x * 2 * scale + 2 * margin;
sum += island->half_diagonal_.y * 2 * scale + 2 * margin;
}
return sqrtf(sum) / 6.0f;
}
@ -583,8 +573,7 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
/* Redraw already placed islands. (Greedy.) */
for (int j = 0; j < i; j++) {
PackIsland *other = islands[island_indices[j]->index];
float2 where(other->bounds_rect.xmin * scale - margin,
other->bounds_rect.ymin * scale - margin);
float2 where = (other->pre_translate + other->pivot_) * scale;
occupancy.trace_island(islands[island_indices[j]->index], scale, margin, where, true);
}
continue;
@ -592,13 +581,12 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
/* Place island. */
island->angle = 0.0f;
island->pre_translate.x = (best.x + margin) / scale - island->bounds_rect.xmin;
island->pre_translate.y = (best.y + margin) / scale - island->bounds_rect.ymin;
island->pre_translate = best / scale - island->pivot_;
occupancy.trace_island(island, scale, margin, best, true);
i++; /* Next island. */
max_u = std::max(best.x + BLI_rctf_size_x(&island->bounds_rect) * scale + 2 * margin, max_u);
max_v = std::max(best.y + BLI_rctf_size_y(&island->bounds_rect) * scale + 2 * margin, max_v);
max_u = std::max(best.x + island->half_diagonal_.x * scale + margin, max_u);
max_v = std::max(best.y + island->half_diagonal_.y * scale + margin, max_v);
if (i < 128 || (i & 31) == 16) {
scan_line = 0; /* Restart completely. */
@ -693,9 +681,13 @@ static void pack_islands_alpaca_rotate(const Span<UVAABBIsland *> islands,
island->uv_placement.y = hole[1];
if (hole_rotate == (min_dsm == island->uv_diagonal.x)) {
island->angle = DEG2RADF(90.0f);
island->uv_placement.x += max_dsm * 0.5f;
island->uv_placement.y += min_dsm * 0.5f;
}
else {
island->angle = 0.0f;
island->uv_placement.x += min_dsm * 0.5f;
island->uv_placement.y += max_dsm * 0.5f;
}
/* Update space left in the hole. */
@ -730,14 +722,18 @@ static void pack_islands_alpaca_rotate(const Span<UVAABBIsland *> islands,
}
/* Place the island. */
island->uv_placement.x = u0;
island->uv_placement.y = v0;
if (zigzag == (min_dsm == island->uv_diagonal.x)) {
island->angle = DEG2RADF(90.0f);
island->uv_placement.x += max_dsm * 0.5f;
island->uv_placement.y += min_dsm * 0.5f;
}
else {
island->angle = 0.0f;
island->uv_placement.x += min_dsm * 0.5f;
island->uv_placement.y += max_dsm * 0.5f;
}
island->uv_placement.x = u0;
island->uv_placement.y = v0;
/* Move according to the "Alpaca rules", with rotation. */
if (zigzag) {
@ -797,8 +793,8 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
PackIsland *pack_island = islands[i];
UVAABBIsland *aabb = new UVAABBIsland();
aabb->index = i;
aabb->uv_diagonal.x = BLI_rctf_size_x(&pack_island->bounds_rect) * scale + 2 * margin;
aabb->uv_diagonal.y = BLI_rctf_size_y(&pack_island->bounds_rect) * scale + 2 * margin;
aabb->uv_diagonal.x = pack_island->half_diagonal_.x * 2 * scale + 2 * margin;
aabb->uv_diagonal.y = pack_island->half_diagonal_.y * 2 * scale + 2 * margin;
aabbs[i] = aabb;
if (pack_island->aspect_y != 1.0f) {
contains_non_square_islands = true;
@ -846,6 +842,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
alpaca_cutoff = alpaca_cutoff_fast;
}
}
const int64_t max_box_pack = std::min(alpaca_cutoff, islands.size());
/* Call box_pack_2d (slow for large N.) */
@ -878,20 +875,10 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
UVAABBIsland *aabb = aabbs[i];
PackIsland *pack_island = islands[aabb->index];
pack_island->angle = aabb->angle;
if (aabb->angle) {
pack_island->pre_translate.x = (aabb->uv_placement.y + margin) / scale /
-pack_island->aspect_y -
pack_island->bounds_rect.xmax;
pack_island->pre_translate.y = (aabb->uv_placement.x + margin) / scale *
pack_island->aspect_y -
pack_island->bounds_rect.ymin;
}
else {
pack_island->pre_translate.x = (aabb->uv_placement.x + margin) / scale -
pack_island->bounds_rect.xmin;
pack_island->pre_translate.y = (aabb->uv_placement.y + margin) / scale -
pack_island->bounds_rect.ymin;
}
float matrix_inverse[2][2];
pack_island->build_inverse_transformation(scale, pack_island->angle, matrix_inverse);
mul_v2_m2v2(pack_island->pre_translate, matrix_inverse, aabb->uv_placement);
pack_island->pre_translate -= pack_island->pivot_;
}
/* Memory management. */
@ -1018,8 +1005,8 @@ static float calc_margin_from_aabb_length_sum(const Span<PackIsland *> &island_v
* `aabb_length_sum` (was "`area`") to multiply the margin by the length (was "area"). */
double aabb_length_sum = 0.0f;
for (PackIsland *island : island_vector) {
float w = BLI_rctf_size_x(&island->bounds_rect);
float h = BLI_rctf_size_y(&island->bounds_rect);
float w = island->half_diagonal_.x * 2.0f;
float h = island->half_diagonal_.y * 2.0f;
aabb_length_sum += sqrtf(w * h);
}
return params.margin * aabb_length_sum * 0.1f;
@ -1071,4 +1058,23 @@ void pack_islands(const Span<PackIsland *> &islands,
/** \} */
void PackIsland::build_transformation(const float scale, const float angle, float (*r_matrix)[2])
{
const float cos_angle = cosf(angle);
const float sin_angle = sinf(angle);
r_matrix[0][0] = cos_angle * scale;
r_matrix[0][1] = -sin_angle * scale * aspect_y;
r_matrix[1][0] = sin_angle * scale / aspect_y;
r_matrix[1][1] = cos_angle * scale;
}
void PackIsland::build_inverse_transformation(const float scale,
const float angle,
float (*r_matrix)[2])
{
/* TODO: Generate inverse transform directly. */
build_transformation(scale, angle, r_matrix);
invert_m2_m2(r_matrix, r_matrix);
}
} // namespace blender::geometry

View File

@ -4146,15 +4146,11 @@ void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, boo
MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
Heap *heap = BLI_heap_new();
int unpacked = 0;
for (int i = 0; i < handle->ncharts; i++) {
PChart *chart = handle->charts[i];
if (ignore_pinned && chart->has_pins) {
unpacked++;
continue;
}
(void)unpacked; /* Quiet set-but-unused warning (may be removed). */
geometry::PackIsland *pack_island = new geometry::PackIsland();
pack_island->caller_index = i;
@ -4182,17 +4178,9 @@ void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, boo
PChart *chart = handle->charts[pack_island->caller_index];
float matrix[2][2];
float b[2];
const float cos_angle = cosf(pack_island->angle);
const float sin_angle = sinf(pack_island->angle);
matrix[0][0] = cos_angle * scale[0];
matrix[0][1] = -sin_angle * scale[0] * pack_island->aspect_y;
matrix[1][0] = sin_angle * scale[1] / pack_island->aspect_y;
matrix[1][1] = cos_angle * scale[1];
b[0] = pack_island->pre_translate.x;
b[1] = pack_island->pre_translate.y;
pack_island->build_transformation(scale[0], pack_island->angle, matrix);
for (PVert *v = chart->verts; v; v = v->nextlink) {
blender::geometry::mul_v2_m2_add_v2v2(v->uv, matrix, v->uv, b);
blender::geometry::mul_v2_m2_add_v2v2(v->uv, matrix, v->uv, pack_island->pre_translate);
}
pack_island_vector[i] = nullptr;

View File

@ -2307,7 +2307,7 @@ typedef enum eSnapMode {
/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
/* TODO: move this macro to a more general place. */
#ifdef ENUM_OPERATORS
ENUM_OPERATORS(eSnapMode, SCE_SNAP_MODE_GRID)
ENUM_OPERATORS(eSnapMode, SCE_SNAP_MODE_FACE_NEAREST)
#endif
#define SCE_SNAP_MODE_GEOM \

View File

@ -3414,7 +3414,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_PROJECT);
RNA_def_property_ui_text(prop,
"Project Individual Elements",
"Project individual elements on the surface of other objects");
"Project individual elements on the surface of other objects (Always "
"enabled with Face Nearest)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_backface_culling", PROP_BOOLEAN, PROP_NONE);

View File

@ -94,47 +94,9 @@
#include "FN_multi_function.hh"
namespace lf = blender::fn::lazy_function;
namespace geo_log = blender::nodes::geo_eval_log;
using blender::Array;
using blender::ColorGeometry4f;
using blender::CPPType;
using blender::destruct_ptr;
using blender::float3;
using blender::FunctionRef;
using blender::GMutablePointer;
using blender::GMutableSpan;
using blender::GPointer;
using blender::GVArray;
using blender::IndexRange;
using blender::Map;
using blender::MultiValueMap;
using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::Stack;
using blender::StringRef;
using blender::StringRefNull;
using blender::Vector;
using blender::bke::AttributeMetaData;
using blender::bke::AttributeValidator;
using blender::fn::Field;
using blender::fn::FieldOperation;
using blender::fn::GField;
using blender::fn::ValueOrField;
using blender::fn::ValueOrFieldCPPType;
using blender::nodes::FieldInferencingInterface;
using blender::nodes::GeoNodeExecParams;
using blender::nodes::InputSocketFieldType;
using blender::nodes::geo_eval_log::GeometryAttributeInfo;
using blender::nodes::geo_eval_log::GeometryInfoLog;
using blender::nodes::geo_eval_log::GeoModifierLog;
using blender::nodes::geo_eval_log::GeoNodeLog;
using blender::nodes::geo_eval_log::GeoTreeLog;
using blender::nodes::geo_eval_log::NamedAttributeUsage;
using blender::nodes::geo_eval_log::NodeWarning;
using blender::nodes::geo_eval_log::NodeWarningType;
using blender::nodes::geo_eval_log::ValueLog;
using blender::threading::EnumerableThreadSpecific;
namespace blender {
static void initData(ModifierData *md)
{
@ -430,15 +392,14 @@ static bool socket_type_has_attribute_toggle(const bNodeSocket &socket)
static bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
{
BLI_assert(node_tree.runtime->field_inferencing_interface);
const FieldInferencingInterface &field_interface =
const nodes::FieldInferencingInterface &field_interface =
*node_tree.runtime->field_inferencing_interface;
return field_interface.inputs[socket_index] != InputSocketFieldType::None;
return field_interface.inputs[socket_index] != nodes::InputSocketFieldType::None;
}
static std::unique_ptr<IDProperty, blender::bke::idprop::IDPropertyDeleter>
id_property_create_from_socket(const bNodeSocket &socket)
static std::unique_ptr<IDProperty, bke::idprop::IDPropertyDeleter> id_property_create_from_socket(
const bNodeSocket &socket)
{
using namespace blender;
switch (socket.type) {
case SOCK_FLOAT: {
const bNodeSocketValueFloat *value = static_cast<const bNodeSocketValueFloat *>(
@ -585,34 +546,34 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
else if (property.type == IDP_DOUBLE) {
value = float(IDP_Double(&property));
}
new (r_value) ValueOrField<float>(value);
new (r_value) fn::ValueOrField<float>(value);
break;
}
case SOCK_INT: {
int value = IDP_Int(&property);
new (r_value) ValueOrField<int>(value);
new (r_value) fn::ValueOrField<int>(value);
break;
}
case SOCK_VECTOR: {
float3 value;
copy_v3_v3(value, (const float *)IDP_Array(&property));
new (r_value) ValueOrField<float3>(value);
new (r_value) fn::ValueOrField<float3>(value);
break;
}
case SOCK_RGBA: {
blender::ColorGeometry4f value;
ColorGeometry4f value;
copy_v4_v4((float *)value, (const float *)IDP_Array(&property));
new (r_value) ValueOrField<ColorGeometry4f>(value);
new (r_value) fn::ValueOrField<ColorGeometry4f>(value);
break;
}
case SOCK_BOOLEAN: {
const bool value = IDP_Bool(&property);
new (r_value) ValueOrField<bool>(value);
new (r_value) fn::ValueOrField<bool>(value);
break;
}
case SOCK_STRING: {
std::string value = IDP_String(&property);
new (r_value) ValueOrField<std::string>(std::move(value));
new (r_value) fn::ValueOrField<std::string>(std::move(value));
break;
}
case SOCK_OBJECT: {
@ -773,8 +734,11 @@ static void update_output_properties_from_node_tree(const bNodeTree &tree,
}
}
} // namespace blender
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
{
using namespace blender;
if (nmd->node_group == nullptr) {
if (nmd->settings.properties) {
IDP_FreeProperty(nmd->settings.properties);
@ -800,38 +764,39 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
}
static void initialize_group_input(NodesModifierData &nmd,
const bNodeSocket &interface_socket,
namespace blender {
static void initialize_group_input(const bNodeTree &tree,
const IDProperty *properties,
const int input_index,
void *r_value)
{
const bNodeSocketType &socket_type = *interface_socket.typeinfo;
const eNodeSocketDatatype socket_data_type = static_cast<eNodeSocketDatatype>(
interface_socket.type);
if (nmd.settings.properties == nullptr) {
socket_type.get_geometry_nodes_cpp_value(interface_socket, r_value);
const bNodeSocket &io_input = *tree.interface_inputs()[input_index];
const bNodeSocketType &socket_type = *io_input.typeinfo;
const eNodeSocketDatatype socket_data_type = static_cast<eNodeSocketDatatype>(io_input.type);
if (properties == nullptr) {
socket_type.get_geometry_nodes_cpp_value(io_input, r_value);
return;
}
const IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties,
interface_socket.identifier);
const IDProperty *property = IDP_GetPropertyFromGroup(properties, io_input.identifier);
if (property == nullptr) {
socket_type.get_geometry_nodes_cpp_value(interface_socket, r_value);
socket_type.get_geometry_nodes_cpp_value(io_input, r_value);
return;
}
if (!id_property_type_matches_socket(interface_socket, *property)) {
socket_type.get_geometry_nodes_cpp_value(interface_socket, r_value);
if (!id_property_type_matches_socket(io_input, *property)) {
socket_type.get_geometry_nodes_cpp_value(io_input, r_value);
return;
}
if (!input_has_attribute_toggle(*nmd.node_group, input_index)) {
if (!input_has_attribute_toggle(tree, input_index)) {
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
return;
}
const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup(
nmd.settings.properties, (interface_socket.identifier + use_attribute_suffix).c_str());
properties, (io_input.identifier + use_attribute_suffix).c_str());
const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
nmd.settings.properties, (interface_socket.identifier + attribute_name_suffix).c_str());
properties, (io_input.identifier + attribute_name_suffix).c_str());
if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
return;
@ -840,14 +805,13 @@ static void initialize_group_input(NodesModifierData &nmd,
const bool use_attribute = IDP_Int(property_use_attribute) != 0;
if (use_attribute) {
const StringRef attribute_name{IDP_String(property_attribute_name)};
if (!blender::bke::allow_procedural_attribute_access(attribute_name)) {
if (!bke::allow_procedural_attribute_access(attribute_name)) {
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
return;
}
auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
attribute_name, *socket_type.base_cpp_type);
GField attribute_field{std::move(attribute_input), 0};
const auto *value_or_field_cpp_type = ValueOrFieldCPPType::get_from_self(
fn::GField attribute_field = bke::AttributeFieldInput::Create(attribute_name,
*socket_type.base_cpp_type);
const auto *value_or_field_cpp_type = fn::ValueOrFieldCPPType::get_from_self(
*socket_type.geometry_nodes_cpp_type);
BLI_assert(value_or_field_cpp_type != nullptr);
value_or_field_cpp_type->construct_from_field(r_value, std::move(attribute_field));
@ -859,16 +823,16 @@ static void initialize_group_input(NodesModifierData &nmd,
static const lf::FunctionNode *find_viewer_lf_node(const bNode &viewer_bnode)
{
if (const blender::nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
blender::nodes::ensure_geometry_nodes_lazy_function_graph(viewer_bnode.owner_tree())) {
if (const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
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)
{
if (const blender::nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
blender::nodes::ensure_geometry_nodes_lazy_function_graph(group_bnode.owner_tree())) {
if (const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
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;
@ -878,10 +842,10 @@ static void find_side_effect_nodes_for_viewer_path(
const ViewerPath &viewer_path,
const NodesModifierData &nmd,
const ModifierEvalContext &ctx,
MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
{
const std::optional<blender::ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
blender::ed::viewer_path::parse_geometry_nodes_viewer(viewer_path);
const std::optional<ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
ed::viewer_path::parse_geometry_nodes_viewer(viewer_path);
if (!parsed_path.has_value()) {
return;
}
@ -892,8 +856,8 @@ static void find_side_effect_nodes_for_viewer_path(
return;
}
blender::ComputeContextBuilder compute_context_builder;
compute_context_builder.push<blender::bke::ModifierComputeContext>(parsed_path->modifier_name);
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
const bNodeTree *group = nmd.node_group;
Stack<const bNode *> group_node_stack;
@ -910,7 +874,7 @@ static void find_side_effect_nodes_for_viewer_path(
}
group_node_stack.push(found_node);
group = reinterpret_cast<bNodeTree *>(found_node->id);
compute_context_builder.push<blender::bke::NodeGroupComputeContext>(*found_node);
compute_context_builder.push<bke::NodeGroupComputeContext>(*found_node);
}
const bNode *found_viewer_node = group->node_by_id(parsed_path->viewer_node_id);
@ -940,7 +904,7 @@ static void find_side_effect_nodes_for_viewer_path(
static void find_side_effect_nodes(
const NodesModifierData &nmd,
const ModifierEvalContext &ctx,
MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
{
Main *bmain = DEG_get_bmain(ctx.depsgraph);
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
@ -968,7 +932,7 @@ static void find_side_effect_nodes(
static void find_socket_log_contexts(const NodesModifierData &nmd,
const ModifierEvalContext &ctx,
Set<blender::ComputeContextHash> &r_socket_log_contexts)
Set<ComputeContextHash> &r_socket_log_contexts)
{
Main *bmain = DEG_get_bmain(ctx.depsgraph);
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
@ -981,9 +945,9 @@ static void find_socket_log_contexts(const NodesModifierData &nmd,
const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
if (sl->spacetype == SPACE_NODE) {
const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
if (const std::optional<blender::ComputeContextHash> hash = blender::nodes::geo_eval_log::
GeoModifierLog::get_compute_context_hash_for_node_editor(snode,
nmd.modifier.name)) {
if (const std::optional<ComputeContextHash> hash =
geo_log::GeoModifierLog::get_compute_context_hash_for_node_editor(
snode, nmd.modifier.name)) {
r_socket_log_contexts.add(*hash);
}
}
@ -994,13 +958,13 @@ static void find_socket_log_contexts(const NodesModifierData &nmd,
static void clear_runtime_data(NodesModifierData *nmd)
{
if (nmd->runtime_eval_log != nullptr) {
delete static_cast<GeoModifierLog *>(nmd->runtime_eval_log);
delete static_cast<geo_log::GeoModifierLog *>(nmd->runtime_eval_log);
nmd->runtime_eval_log = nullptr;
}
}
struct OutputAttributeInfo {
GField field;
fn::GField field;
StringRefNull name;
};
@ -1016,7 +980,10 @@ struct OutputAttributeToStore {
* can be evaluated together.
*/
static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to_store(
const NodesModifierData &nmd, const bNode &output_node, Span<GMutablePointer> output_values)
const bNodeTree &tree,
const IDProperty *properties,
const bNode &output_node,
Span<GMutablePointer> output_values)
{
MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain;
for (const bNodeSocket *socket : output_node.input_sockets().drop_front(1).drop_back(1)) {
@ -1025,7 +992,7 @@ static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to
}
const std::string prop_name = socket->identifier + attribute_name_suffix;
const IDProperty *prop = IDP_GetPropertyFromGroup(nmd.settings.properties, prop_name.c_str());
const IDProperty *prop = IDP_GetPropertyFromGroup(properties, prop_name.c_str());
if (prop == nullptr) {
continue;
}
@ -1033,18 +1000,17 @@ static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to
if (attribute_name.is_empty()) {
continue;
}
if (!blender::bke::allow_procedural_attribute_access(attribute_name)) {
if (!bke::allow_procedural_attribute_access(attribute_name)) {
continue;
}
const int index = socket->index();
const GPointer value = output_values[index];
const auto *value_or_field_type = ValueOrFieldCPPType::get_from_self(*value.type());
const auto *value_or_field_type = fn::ValueOrFieldCPPType::get_from_self(*value.type());
BLI_assert(value_or_field_type != nullptr);
const GField field = value_or_field_type->as_field(value.get());
const fn::GField field = value_or_field_type->as_field(value.get());
const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink(
&nmd.node_group->outputs, index);
const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink(&tree.outputs, index);
const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain;
OutputAttributeInfo output_info;
output_info.field = std::move(field);
@ -1071,7 +1037,7 @@ static Vector<OutputAttributeToStore> compute_attributes_to_store(
continue;
}
const GeometryComponent &component = *geometry.get_component_for_read(component_type);
const blender::bke::AttributeAccessor attributes = *component.attributes();
const bke::AttributeAccessor attributes = *component.attributes();
for (const auto item : outputs_by_domain.items()) {
const eAttrDomain domain = item.key;
const Span<OutputAttributeInfo> outputs_info = item.value;
@ -1079,18 +1045,18 @@ static Vector<OutputAttributeToStore> compute_attributes_to_store(
continue;
}
const int domain_size = attributes.domain_size(domain);
blender::bke::GeometryFieldContext field_context{component, domain};
blender::fn::FieldEvaluator field_evaluator{field_context, domain_size};
bke::GeometryFieldContext field_context{component, domain};
fn::FieldEvaluator field_evaluator{field_context, domain_size};
for (const OutputAttributeInfo &output_info : outputs_info) {
const CPPType &type = output_info.field.cpp_type();
const AttributeValidator validator = attributes.lookup_validator(output_info.name);
const bke::AttributeValidator validator = attributes.lookup_validator(output_info.name);
OutputAttributeToStore store{
component_type,
domain,
output_info.name,
GMutableSpan{
type, MEM_malloc_arrayN(domain_size, type.size(), __func__), domain_size}};
GField field = validator.validate_field_if_necessary(output_info.field);
fn::GField field = validator.validate_field_if_necessary(output_info.field);
field_evaluator.add_with_destination(std::move(field), store.data);
attributes_to_store.append(store);
}
@ -1105,11 +1071,11 @@ static void store_computed_output_attributes(
{
for (const OutputAttributeToStore &store : attributes_to_store) {
GeometryComponent &component = geometry.get_component_for_write(store.component_type);
blender::bke::MutableAttributeAccessor attributes = *component.attributes_for_write();
bke::MutableAttributeAccessor attributes = *component.attributes_for_write();
const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(
store.data.type());
const std::optional<AttributeMetaData> meta_data = attributes.lookup_meta_data(store.name);
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(store.data.type());
const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(
store.name);
/* Attempt to remove the attribute if it already exists but the domain and type don't match.
* Removing the attribute won't succeed if it is built in and non-removable. */
@ -1122,12 +1088,12 @@ static void store_computed_output_attributes(
* attribute didn't exist before, or if it existed but was removed above. */
if (attributes.add(store.name,
store.domain,
blender::bke::cpp_type_to_custom_data_type(store.data.type()),
blender::bke::AttributeInitMoveArray(store.data.data()))) {
bke::cpp_type_to_custom_data_type(store.data.type()),
bke::AttributeInitMoveArray(store.data.data()))) {
continue;
}
blender::bke::GAttributeWriter attribute = attributes.lookup_or_add_for_write(
bke::GAttributeWriter attribute = attributes.lookup_or_add_for_write(
store.name, store.domain, data_type);
if (attribute) {
attribute.varray.set_all(store.data.data());
@ -1141,14 +1107,15 @@ static void store_computed_output_attributes(
}
static void store_output_attributes(GeometrySet &geometry,
const NodesModifierData &nmd,
const bNodeTree &tree,
const IDProperty *properties,
const bNode &output_node,
Span<GMutablePointer> output_values)
{
/* All new attribute values have to be computed before the geometry is actually changed. This is
* necessary because some fields might depend on attributes that are overwritten. */
MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain =
find_output_attributes_to_store(nmd, output_node, output_values);
find_output_attributes_to_store(tree, properties, output_node, output_values);
Vector<OutputAttributeToStore> attributes_to_store = compute_attributes_to_store(
geometry, outputs_by_domain);
store_computed_output_attributes(geometry, attributes_to_store);
@ -1157,15 +1124,14 @@ static void store_output_attributes(GeometrySet &geometry,
/**
* Evaluate a node group to compute the output geometry.
*/
static GeometrySet compute_geometry(
const bNodeTree &btree,
const blender::nodes::GeometryNodesLazyFunctionGraphInfo &lf_graph_info,
const bNode &output_node,
GeometrySet input_geometry_set,
NodesModifierData *nmd,
const ModifierEvalContext *ctx)
static GeometrySet compute_geometry(const bNodeTree &btree,
const nodes::GeometryNodesLazyFunctionGraphInfo &lf_graph_info,
const bNode &output_node,
GeometrySet input_geometry_set,
NodesModifierData *nmd,
const ModifierEvalContext *ctx)
{
const blender::nodes::GeometryNodeLazyFunctionGraphMapping &mapping = lf_graph_info.mapping;
const nodes::GeometryNodeLazyFunctionGraphMapping &mapping = lf_graph_info.mapping;
Vector<const lf::OutputSocket *> graph_inputs = mapping.group_input_sockets;
graph_inputs.extend(mapping.group_output_used_sockets);
@ -1179,35 +1145,36 @@ static GeometrySet compute_geometry(
Array<lf::ValueUsage> param_output_usages(graph_outputs.size(), lf::ValueUsage::Used);
Array<bool> param_set_outputs(graph_outputs.size(), false);
blender::nodes::GeometryNodesLazyFunctionLogger lf_logger(lf_graph_info);
blender::nodes::GeometryNodesLazyFunctionSideEffectProvider lf_side_effect_provider;
nodes::GeometryNodesLazyFunctionLogger lf_logger(lf_graph_info);
nodes::GeometryNodesLazyFunctionSideEffectProvider lf_side_effect_provider;
lf::GraphExecutor graph_executor{
lf_graph_info.graph, graph_inputs, graph_outputs, &lf_logger, &lf_side_effect_provider};
blender::nodes::GeoNodesModifierData geo_nodes_modifier_data;
nodes::GeoNodesModifierData geo_nodes_modifier_data;
geo_nodes_modifier_data.depsgraph = ctx->depsgraph;
geo_nodes_modifier_data.self_object = ctx->object;
auto eval_log = std::make_unique<GeoModifierLog>();
auto eval_log = std::make_unique<geo_log::GeoModifierLog>();
Set<blender::ComputeContextHash> socket_log_contexts;
Set<ComputeContextHash> socket_log_contexts;
if (logging_enabled(ctx)) {
geo_nodes_modifier_data.eval_log = eval_log.get();
find_socket_log_contexts(*nmd, *ctx, socket_log_contexts);
geo_nodes_modifier_data.socket_log_contexts = &socket_log_contexts;
}
MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> r_side_effect_nodes;
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> r_side_effect_nodes;
find_side_effect_nodes(*nmd, *ctx, r_side_effect_nodes);
geo_nodes_modifier_data.side_effect_nodes = &r_side_effect_nodes;
blender::nodes::GeoNodesLFUserData user_data;
nodes::GeoNodesLFUserData user_data;
user_data.modifier_data = &geo_nodes_modifier_data;
blender::bke::ModifierComputeContext modifier_compute_context{nullptr, nmd->modifier.name};
bke::ModifierComputeContext modifier_compute_context{nullptr, nmd->modifier.name};
user_data.compute_context = &modifier_compute_context;
blender::LinearAllocator<> allocator;
LinearAllocator<> allocator;
Vector<GMutablePointer> inputs_to_destruct;
const IDProperty *properties = nmd->settings.properties;
int input_index = -1;
for (const int i : btree.interface_inputs().index_range()) {
input_index++;
@ -1220,7 +1187,7 @@ static GeometrySet compute_geometry(
const CPPType *type = interface_socket.typeinfo->geometry_nodes_cpp_type;
BLI_assert(type != nullptr);
void *value = allocator.allocate(type->size(), type->alignment());
initialize_group_input(*nmd, interface_socket, i, value);
initialize_group_input(btree, properties, i, value);
param_inputs[input_index] = {type, value};
inputs_to_destruct.append({type, value});
}
@ -1231,7 +1198,7 @@ static GeometrySet compute_geometry(
param_inputs[input_index] = &output_used_inputs[i];
}
Array<blender::bke::AnonymousAttributeSet> attributes_to_propagate(
Array<bke::AnonymousAttributeSet> attributes_to_propagate(
mapping.attribute_set_by_geometry_output.size());
for (const int i : attributes_to_propagate.index_range()) {
input_index++;
@ -1262,7 +1229,7 @@ static GeometrySet compute_geometry(
}
GeometrySet output_geometry_set = std::move(*static_cast<GeometrySet *>(param_outputs[0].get()));
store_output_attributes(output_geometry_set, *nmd, output_node, param_outputs);
store_output_attributes(output_geometry_set, btree, properties, output_node, param_outputs);
for (GMutablePointer &ptr : param_outputs) {
ptr.destruct();
@ -1271,7 +1238,7 @@ static GeometrySet compute_geometry(
if (logging_enabled(ctx)) {
NodesModifierData *nmd_orig = reinterpret_cast<NodesModifierData *>(
BKE_modifier_get_original(ctx->object, &nmd->modifier));
delete static_cast<GeoModifierLog *>(nmd_orig->runtime_eval_log);
delete static_cast<geo_log::GeoModifierLog *>(nmd_orig->runtime_eval_log);
nmd_orig->runtime_eval_log = eval_log.release();
}
@ -1325,6 +1292,7 @@ static void modifyGeometry(ModifierData *md,
const ModifierEvalContext *ctx,
GeometrySet &geometry_set)
{
using namespace blender;
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
if (nmd->node_group == nullptr) {
return;
@ -1355,8 +1323,8 @@ static void modifyGeometry(ModifierData *md,
return;
}
const blender::nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
blender::nodes::ensure_geometry_nodes_lazy_function_graph(tree);
const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
nodes::ensure_geometry_nodes_lazy_function_graph(tree);
if (lf_graph_info == nullptr) {
BKE_modifier_set_error(ctx->object, md, "Cannot evaluate node group");
geometry_set.clear();
@ -1446,13 +1414,13 @@ static NodesModifierData *get_modifier_data(Main &bmain,
return reinterpret_cast<NodesModifierData *>(md);
}
static GeoTreeLog *get_root_tree_log(const NodesModifierData &nmd)
static geo_log::GeoTreeLog *get_root_tree_log(const NodesModifierData &nmd)
{
if (nmd.runtime_eval_log == nullptr) {
return nullptr;
}
GeoModifierLog &modifier_log = *static_cast<GeoModifierLog *>(nmd.runtime_eval_log);
blender::bke::ModifierComputeContext compute_context{nullptr, nmd.modifier.name};
auto &modifier_log = *static_cast<geo_log::GeoModifierLog *>(nmd.runtime_eval_log);
bke::ModifierComputeContext compute_context{nullptr, nmd.modifier.name};
return &modifier_log.get_tree_log(compute_context.hash());
}
@ -1467,7 +1435,7 @@ static void attribute_search_update_fn(
if (nmd->node_group == nullptr) {
return;
}
GeoTreeLog *tree_log = get_root_tree_log(*nmd);
geo_log::GeoTreeLog *tree_log = get_root_tree_log(*nmd);
if (tree_log == nullptr) {
return;
}
@ -1494,22 +1462,21 @@ static void attribute_search_update_fn(
}
}
Set<StringRef> names;
Vector<const GeometryAttributeInfo *> attributes;
Vector<const geo_log::GeometryAttributeInfo *> attributes;
for (const bNodeSocket *socket : sockets_to_check) {
const ValueLog *value_log = tree_log->find_socket_value_log(*socket);
const geo_log::ValueLog *value_log = tree_log->find_socket_value_log(*socket);
if (value_log == nullptr) {
continue;
}
if (const GeometryInfoLog *geo_log = dynamic_cast<const GeometryInfoLog *>(value_log)) {
for (const GeometryAttributeInfo &attribute : geo_log->attributes) {
if (const auto *geo_log = dynamic_cast<const geo_log::GeometryInfoLog *>(value_log)) {
for (const geo_log::GeometryAttributeInfo &attribute : geo_log->attributes) {
if (names.add(attribute.name)) {
attributes.append(&attribute);
}
}
}
}
blender::ui::attribute_search_add_items(
str, data.is_output, attributes.as_span(), items, is_first);
ui::attribute_search_add_items(str, data.is_output, attributes.as_span(), items, is_first);
}
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
@ -1518,7 +1485,7 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
return;
}
AttributeSearchData &data = *static_cast<AttributeSearchData *>(data_v);
const GeometryAttributeInfo &item = *static_cast<const GeometryAttributeInfo *>(item_v);
const auto &item = *static_cast<const geo_log::GeometryAttributeInfo *>(item_v);
const NodesModifierData *nmd = get_modifier_data(*CTX_data_main(C), *CTX_wm_manager(C), data);
if (nmd == nullptr) {
return;
@ -1589,7 +1556,7 @@ static void add_attribute_search_button(const bContext &C,
char *attribute_name = RNA_string_get_alloc(
md_ptr, rna_path_attribute_name.c_str(), nullptr, 0, nullptr);
const bool access_allowed = blender::bke::allow_procedural_attribute_access(attribute_name);
const bool access_allowed = bke::allow_procedural_attribute_access(attribute_name);
MEM_freeN(attribute_name);
if (!access_allowed) {
UI_but_flag_enable(but, UI_BUT_REDALERT);
@ -1779,11 +1746,11 @@ static void panel_draw(const bContext *C, Panel *panel)
}
/* Draw node warnings. */
GeoTreeLog *tree_log = get_root_tree_log(*nmd);
geo_log::GeoTreeLog *tree_log = get_root_tree_log(*nmd);
if (tree_log != nullptr) {
tree_log->ensure_node_warnings();
for (const NodeWarning &warning : tree_log->all_warnings) {
if (warning.type != NodeWarningType::Info) {
for (const geo_log::NodeWarning &warning : tree_log->all_warnings) {
if (warning.type != geo_log::NodeWarningType::Info) {
uiItemL(layout, warning.message.c_str(), ICON_ERROR);
}
}
@ -1823,13 +1790,13 @@ static void internal_dependencies_panel_draw(const bContext * /*C*/, Panel *pane
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
GeoTreeLog *tree_log = get_root_tree_log(*nmd);
geo_log::GeoTreeLog *tree_log = get_root_tree_log(*nmd);
if (tree_log == nullptr) {
return;
}
tree_log->ensure_used_named_attributes();
const Map<StringRefNull, NamedAttributeUsage> &usage_by_attribute =
const Map<StringRefNull, geo_log::NamedAttributeUsage> &usage_by_attribute =
tree_log->used_named_attributes;
if (usage_by_attribute.is_empty()) {
@ -1839,7 +1806,7 @@ static void internal_dependencies_panel_draw(const bContext * /*C*/, Panel *pane
struct NameWithUsage {
StringRefNull name;
NamedAttributeUsage usage;
geo_log::NamedAttributeUsage usage;
};
Vector<NameWithUsage> sorted_used_attribute;
@ -1854,20 +1821,20 @@ static void internal_dependencies_panel_draw(const bContext * /*C*/, Panel *pane
for (const NameWithUsage &attribute : sorted_used_attribute) {
const StringRefNull attribute_name = attribute.name;
const NamedAttributeUsage usage = attribute.usage;
const geo_log::NamedAttributeUsage usage = attribute.usage;
/* #uiLayoutRowWithHeading doesn't seem to work in this case. */
uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
std::stringstream ss;
Vector<std::string> usages;
if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) {
if ((usage & geo_log::NamedAttributeUsage::Read) != geo_log::NamedAttributeUsage::None) {
usages.append(TIP_("Read"));
}
if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) {
if ((usage & geo_log::NamedAttributeUsage::Write) != geo_log::NamedAttributeUsage::None) {
usages.append(TIP_("Write"));
}
if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) {
if ((usage & geo_log::NamedAttributeUsage::Remove) != geo_log::NamedAttributeUsage::None) {
usages.append(TIP_("Remove"));
}
for (const int i : usages.index_range()) {
@ -1889,6 +1856,7 @@ static void internal_dependencies_panel_draw(const bContext * /*C*/, Panel *pane
static void panelRegister(ARegionType *region_type)
{
using namespace blender;
PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
modifier_subpanel_register(region_type,
"output_attributes",
@ -1991,6 +1959,8 @@ static void requiredDataMask(ModifierData * /*md*/, CustomData_MeshMasks *r_cdda
r_cddata_masks->vmask |= CD_MASK_PROP_ALL;
}
} // namespace blender
ModifierTypeInfo modifierType_Nodes = {
/*name*/ N_("GeometryNodes"),
/*structName*/ "NodesModifierData",
@ -2004,26 +1974,26 @@ ModifierTypeInfo modifierType_Nodes = {
eModifierTypeFlag_SupportsMapping),
/*icon*/ ICON_GEOMETRY_NODES,
/*copyData*/ copyData,
/*copyData*/ blender::copyData,
/*deformVerts*/ nullptr,
/*deformMatrices*/ nullptr,
/*deformVertsEM*/ nullptr,
/*deformMatricesEM*/ nullptr,
/*modifyMesh*/ modifyMesh,
/*modifyGeometrySet*/ modifyGeometrySet,
/*modifyMesh*/ blender::modifyMesh,
/*modifyGeometrySet*/ blender::modifyGeometrySet,
/*initData*/ initData,
/*requiredDataMask*/ requiredDataMask,
/*freeData*/ freeData,
/*isDisabled*/ isDisabled,
/*updateDepsgraph*/ updateDepsgraph,
/*dependsOnTime*/ dependsOnTime,
/*initData*/ blender::initData,
/*requiredDataMask*/ blender::requiredDataMask,
/*freeData*/ blender::freeData,
/*isDisabled*/ blender::isDisabled,
/*updateDepsgraph*/ blender::updateDepsgraph,
/*dependsOnTime*/ blender::dependsOnTime,
/*dependsOnNormals*/ nullptr,
/*foreachIDLink*/ foreachIDLink,
/*foreachTexLink*/ foreachTexLink,
/*foreachIDLink*/ blender::foreachIDLink,
/*foreachTexLink*/ blender::foreachTexLink,
/*freeRuntimeData*/ nullptr,
/*panelRegister*/ panelRegister,
/*blendWrite*/ blendWrite,
/*blendRead*/ blendRead,
/*panelRegister*/ blender::panelRegister,
/*blendWrite*/ blender::blendWrite,
/*blendRead*/ blender::blendRead,
};