Page Menu
Home
Search
Configure Global Search
Log In
Paste
P2734
Duplicate Plan #2
Active
Public
Actions
Authored by
Johnny Matthews (guitargeek)
on Jan 13 2022, 4:42 PM.
Edit Paste
Archive Paste
View Raw File
Subscribe
Mute Notifications
Award Token
Tags
None
Subscribers
Paul Larson (GeorgiaPacific)
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include
"BLI_map.hh"
#include
"BLI_noise.hh"
#include
"BLI_span.hh"
#include
"BLI_task.hh"
#include
"DNA_mesh_types.h"
#include
"DNA_meshdata_types.h"
#include
"DNA_pointcloud_types.h"
#include
"BKE_attribute_math.hh"
#include
"BKE_mesh.h"
#include
"BKE_pointcloud.h"
#include
"BKE_spline.hh"
#include
"node_geometry_util.hh"
#include
"UI_interface.h"
#include
"UI_resources.h"
namespace
blender
::
nodes
::
node_geo_duplicate_elements_cc
{
static
void
node_declare
(
NodeDeclarationBuilder
&
b
)
{
b
.
add_input
<
decl
::
Geometry
>
(
N_
(
"Geometry"
));
b
.
add_input
<
decl
::
Bool
>
(
N_
(
"Selection"
)).
hide_value
().
default_value
(
true
).
supports_field
();
b
.
add_input
<
decl
::
Int
>
(
N_
(
"Amount"
)).
min
(
0
).
default_value
(
1
).
supports_field
();
b
.
add_output
<
decl
::
Geometry
>
(
N_
(
"Geometry"
));
b
.
add_output
<
decl
::
Int
>
(
N_
(
"Copy Index"
))
.
field_source
()
.
description
(
N_
(
"The index of the duplicate of a specific element"
));
}
static
void
node_init
(
bNodeTree
*
UNUSED
(
tree
),
bNode
*
node
)
{
NodeGeometryDuplicateElements
*
data
=
MEM_cnew
<
NodeGeometryDuplicateElements
>
(
__func__
);
data
->
domain
=
ATTR_DOMAIN_POINT
;
node
->
storage
=
data
;
}
static
void
node_layout
(
uiLayout
*
layout
,
bContext
*
UNUSED
(
C
),
PointerRNA
*
ptr
)
{
uiItemR
(
layout
,
ptr
,
"domain"
,
0
,
""
,
ICON_NONE
);
}
struct
IndexAttributes
{
StrongAnonymousAttributeID
copy_index
;
};
struct
DomainOffsets
{
Span
<
int
>
point
;
Span
<
int
>
edge
;
Span
<
int
>
face
;
Span
<
int
>
corner
;
Span
<
int
>
curve
;
Span
<
int
>
instance
;
};
static
void
gather_attributes_and_skip
(
GeometrySet
&
geometry_set
,
const
GeometryComponentType
component_type
,
Span
<
std
::
string
>
skip_attributes
,
const
bool
include_instances
,
Map
<
AttributeIDRef
,
AttributeKind
>
&
r_gathered_attributes
)
{
geometry_set
.
gather_attributes_for_propagation
(
{
component_type
},
component_type
,
include_instances
,
r_gathered_attributes
);
for
(
std
::
string
id
:
skip_attributes
)
{
r_gathered_attributes
.
remove
(
id
);
}
};
static
void
create_copy_id_attribute
(
GeometryComponent
&
component
,
const
AttributeDomain
output_domain
,
IndexAttributes
attributes
,
const
VArray
<
int
>
counts
,
const
Span
<
int
>
offsets
)
{
OutputAttribute_Typed
<
int
>
copy_attribute
=
component
.
attribute_try_get_for_output_only
<
int
>
(
attributes
.
copy_index
.
get
(),
output_domain
);
MutableSpan
<
int
>
copy_indices
=
copy_attribute
.
as_span
();
for
(
const
int
i_offset
:
offsets
.
index_range
())
{
for
(
const
int
i_duplicate
:
IndexRange
(
counts
[
i_offset
]))
{
copy_indices
[
offsets
[
i_offset
]
+
i_duplicate
]
=
i_duplicate
;
}
}
copy_attribute
.
save
();
}
static
void
copy_attributes_without_id
(
GeometrySet
&
geometry_set
,
const
GeometryComponentType
component_type
,
const
bool
include_instances
,
const
IndexMask
selection
,
const
VArray
<
int
>
counts
,
const
DomainOffsets
&
offsets
,
Vector
<
std
::
string
>
attributes_to_ignore
,
const
GeometryComponent
&
src_component
,
GeometryComponent
&
dst_component
)
{
Map
<
AttributeIDRef
,
AttributeKind
>
gathered_attributes
;
attributes_to_ignore
.
append
(
"id"
);
gather_attributes_and_skip
(
geometry_set
,
component_type
,
attributes_to_ignore
.
as_span
(),
include_instances
,
gathered_attributes
);
for
(
Map
<
AttributeIDRef
,
AttributeKind
>::
Item
entry
:
gathered_attributes
.
items
())
{
const
AttributeIDRef
attribute_id
=
entry
.
key
;
ReadAttributeLookup
src_attribute
=
src_component
.
attribute_try_get_for_read
(
attribute_id
);
if
(
!
src_attribute
)
{
continue
;
}
AttributeDomain
out_domain
=
src_attribute
.
domain
;
const
CustomDataType
data_type
=
bke
::
cpp_type_to_custom_data_type
(
src_attribute
.
varray
.
type
());
OutputAttribute
dst_attribute
=
dst_component
.
attribute_try_get_for_output_only
(
attribute_id
,
out_domain
,
data_type
);
if
(
!
dst_attribute
)
{
continue
;
}
const
int
output_size
=
dst_component
.
attribute_domain_size
(
out_domain
);
attribute_math
::
convert_to_static_type
(
data_type
,
[
&
](
auto
dummy
)
{
using
T
=
decltype
(
dummy
);
VArray_Span
<
T
>
src
{
src_attribute
.
varray
.
typed
<
T
>
()};
MutableSpan
<
T
>
dst
=
dst_attribute
.
as_span
<
T
>
();
switch
(
out_domain
)
{
case
ATTR_DOMAIN_POINT
:
BLI_assert
(
output_size
==
offsets
.
point
.
last
());
break
;
case
ATTR_DOMAIN_EDGE
:
BLI_assert
(
output_size
==
offsets
.
edge
.
last
());
break
;
case
ATTR_DOMAIN_FACE
:
BLI_assert
(
output_size
==
offsets
.
face
.
last
());
break
;
case
ATTR_DOMAIN_CORNER
:
BLI_assert
(
output_size
==
offsets
.
corner
.
last
());
break
;
case
ATTR_DOMAIN_CURVE
:
BLI_assert
(
output_size
==
offsets
.
curve
.
last
());
break
;
case
ATTR_DOMAIN_INSTANCE
:
BLI_assert
(
output_size
==
offsets
.
instance
.
last
());
for
(
const
int
i
:
IndexRange
(
offsets
.
point
.
size
()))
{
dst
.
slice
(
offsets
.
instance
[
i
],
counts
[
i
]).
fill
(
src
[
i
]);
}
break
;
default
:
break
;
}
});
dst_attribute
.
save
();
}
}
static
void
duplicate_instances
(
GeometrySet
&
geometry_set
,
const
Field
<
int
>
&
count_field
,
const
Field
<
bool
>
&
selection_field
,
IndexAttributes
&
attributes
)
{
if
(
!
geometry_set
.
has_instances
())
{
geometry_set
.
clear
();
return
;
}
const
InstancesComponent
&
src_instances
=
*
geometry_set
.
get_component_for_read
<
InstancesComponent
>
();
const
int
domain_size
=
src_instances
.
attribute_domain_size
(
ATTR_DOMAIN_INSTANCE
);
GeometryComponentFieldContext
field_context
{
src_instances
,
ATTR_DOMAIN_INSTANCE
};
FieldEvaluator
evaluator
{
field_context
,
domain_size
};
evaluator
.
add
(
count_field
);
evaluator
.
set_selection
(
selection_field
);
evaluator
.
evaluate
();
IndexMask
selection
=
evaluator
.
get_evaluated_selection_as_mask
();
const
VArray
<
int
>
counts
=
evaluator
.
get_evaluated
<
int
>
(
0
);
Array
<
int
>
offsets
(
selection
.
size
()
+
1
);
int
dst_size
=
0
;
for
(
const
int
i_selection
:
selection
.
index_range
())
{
offsets
[
i_selection
]
=
dst_size
;
dst_size
+=
std
::
max
(
0
,
counts
[
selection
[
i_selection
]]);
}
if
(
dst_size
==
0
)
{
geometry_set
.
clear
();
return
;
}
GeometrySet
instances_geometry
;
InstancesComponent
&
dst_instances
=
instances_geometry
.
get_component_for_write
<
InstancesComponent
>
();
dst_instances
.
resize
(
dst_size
);
for
(
const
int
i_selection
:
selection
.
index_range
())
{
const
int
count
=
offsets
[
i_selection
+
1
]
-
offsets
[
i_selection
];
if
(
count
==
0
)
{
continue
;
}
const
int
old_handle
=
src_instances
.
instance_reference_handles
()[
i_selection
];
const
InstanceReference
reference
=
src_instances
.
references
()[
old_handle
];
const
int
new_handle
=
dst_instances
.
add_reference
(
reference
);
const
float4x4
transform
=
src_instances
.
instance_transforms
()[
i_selection
];
dst_instances
.
instance_transforms
().
slice
(
offsets
[
i_selection
],
count
).
fill
(
transform
);
dst_instances
.
instance_reference_handles
().
slice
(
offsets
[
i_selection
],
count
).
fill
(
new_handle
);
}
DomainOffsets
offset_bundle
;
offset_bundle
.
instance
=
offsets
.
as_span
();
copy_attributes_without_id
(
geometry_set
,
GEO_COMPONENT_TYPE_INSTANCES
,
true
,
selection
,
counts
,
offset_bundle
,
{},
src_instances
,
dst_instances
);
if
(
attributes
.
copy_index
)
{
create_copy_id_attribute
(
dst_instances
,
ATTR_DOMAIN_INSTANCE
,
attributes
,
counts
,
offset_bundle
.
instance
);
}
geometry_set
.
remove
(
GEO_COMPONENT_TYPE_INSTANCES
);
geometry_set
.
add
(
dst_instances
);
}
/** \} */
static
void
node_geo_exec
(
GeoNodeExecParams
params
)
{
GeometrySet
geometry_set
=
params
.
extract_input
<
GeometrySet
>
(
"Geometry"
);
NodeGeometryDuplicateElements
*
data
=
static_cast
<
NodeGeometryDuplicateElements
*>
(
params
.
node
().
storage
);
AttributeDomain
duplicate_domain
=
AttributeDomain
(
data
->
domain
);
Field
<
int
>
count_field
=
params
.
extract_input
<
Field
<
int
>>
(
"Amount"
);
Field
<
bool
>
selection_field
=
params
.
extract_input
<
Field
<
bool
>>
(
"Selection"
);
IndexAttributes
attributes
;
if
(
params
.
output_is_required
(
"Copy Index"
))
{
attributes
.
copy_index
=
StrongAnonymousAttributeID
(
"copy_index"
);
}
if
(
duplicate_domain
==
ATTR_DOMAIN_INSTANCE
)
{
geometry_set
.
keep_only
({
GEO_COMPONENT_TYPE_INSTANCES
});
duplicate_instances
(
geometry_set
,
count_field
,
selection_field
,
attributes
);
}
if
(
geometry_set
.
is_empty
())
{
params
.
set_default_remaining_outputs
();
return
;
}
if
(
attributes
.
copy_index
)
{
params
.
set_output
(
"Copy Index"
,
AnonymousAttributeFieldInput
::
Create
<
int
>
(
std
::
move
(
attributes
.
copy_index
),
params
.
attribute_producer_name
()));
}
params
.
set_output
(
"Geometry"
,
geometry_set
);
}
}
// namespace blender::nodes::node_geo_duplicate_elements_cc
void
register_node_type_geo_duplicate_elements
()
{
namespace
file_ns
=
blender
::
nodes
::
node_geo_duplicate_elements_cc
;
static
bNodeType
ntype
;
geo_node_type_base
(
&
ntype
,
GEO_NODE_DUPLICATE_ELEMENTS
,
"Duplicate Elements"
,
NODE_CLASS_GEOMETRY
);
node_type_storage
(
&
ntype
,
"NodeGeometryDuplicateElements"
,
node_free_standard_storage
,
node_copy_standard_storage
);
node_type_init
(
&
ntype
,
file_ns
::
node_init
);
ntype
.
draw_buttons
=
file_ns
::
node_layout
;
ntype
.
geometry_node_execute
=
file_ns
::
node_geo_exec
;
ntype
.
declare
=
file_ns
::
node_declare
;
nodeRegisterType
(
&
ntype
);
}
Event Timeline
Johnny Matthews (guitargeek)
created this paste.
Jan 13 2022, 4:42 PM
Johnny Matthews (guitargeek)
edited the content of this paste.
(Show Details)
Jan 13 2022, 5:32 PM
Johnny Matthews (guitargeek)
edited the content of this paste.
(Show Details)
Paul Larson (GeorgiaPacific)
added a subscriber:
Paul Larson (GeorgiaPacific)
.
Jan 14 2022, 6:05 AM
Log In to Comment