WIP: Brush assets project #106303
|
@ -162,6 +162,7 @@ class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu):
|
||||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_MIRROR')
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_MIRROR')
|
||||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_MULTIPLY')
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_MULTIPLY')
|
||||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_OUTLINE')
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_OUTLINE')
|
||||||
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_SIMPLIFY')
|
||||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_SUBDIV')
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_SUBDIV')
|
||||||
self.operator_modifier_add(layout, 'LINEART')
|
self.operator_modifier_add(layout, 'LINEART')
|
||||||
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
||||||
|
|
|
@ -203,58 +203,41 @@ static void get_keyframe_values_create_reports(ReportList *reports,
|
||||||
MEM_freeN(str_failed_indices);
|
MEM_freeN(str_failed_indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static Vector<float> get_keyframe_values(PointerRNA *ptr, PropertyRNA *prop, const bool visual_key)
|
||||||
* Retrieve current property values to keyframe,
|
|
||||||
* possibly applying NLA correction when necessary.
|
|
||||||
*
|
|
||||||
* \param r_successful_remaps: Enables bits for indices which are both intended to be remapped and
|
|
||||||
* were successfully remapped. Bitmap allocated so it must be freed afterward.
|
|
||||||
*/
|
|
||||||
static Vector<float> get_keyframe_values(ReportList *reports,
|
|
||||||
PointerRNA ptr,
|
|
||||||
PropertyRNA *prop,
|
|
||||||
int index,
|
|
||||||
NlaKeyframingContext *nla_context,
|
|
||||||
eInsertKeyFlags flag,
|
|
||||||
const AnimationEvalContext *anim_eval_context,
|
|
||||||
bool *r_force_all,
|
|
||||||
blender::BitVector<> &r_successful_remaps)
|
|
||||||
{
|
{
|
||||||
Vector<float> values;
|
Vector<float> values;
|
||||||
|
|
||||||
if ((flag & INSERTKEY_MATRIX) && visualkey_can_use(&ptr, prop)) {
|
if (visual_key && visualkey_can_use(ptr, prop)) {
|
||||||
/* Visual-keying is only available for object and pchan datablocks, as
|
/* Visual-keying is only available for object and pchan datablocks, as
|
||||||
* it works by keyframing using a value extracted from the final matrix
|
* it works by keyframing using a value extracted from the final matrix
|
||||||
* instead of using the kt system to extract a value.
|
* instead of using the kt system to extract a value.
|
||||||
*/
|
*/
|
||||||
values = visualkey_get_values(&ptr, prop);
|
values = visualkey_get_values(ptr, prop);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
values = get_rna_values(&ptr, prop);
|
values = get_rna_values(ptr, prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
r_successful_remaps.resize(values.size());
|
|
||||||
|
|
||||||
/* adjust the value for NLA factors */
|
|
||||||
BKE_animsys_nla_remap_keyframe_values(nla_context,
|
|
||||||
&ptr,
|
|
||||||
prop,
|
|
||||||
values.as_mutable_span(),
|
|
||||||
index,
|
|
||||||
anim_eval_context,
|
|
||||||
r_force_all,
|
|
||||||
r_successful_remaps);
|
|
||||||
get_keyframe_values_create_reports(reports,
|
|
||||||
ptr,
|
|
||||||
prop,
|
|
||||||
index,
|
|
||||||
values.size(),
|
|
||||||
r_force_all ? *r_force_all : false,
|
|
||||||
r_successful_remaps);
|
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BitVector<> nla_map_keyframe_values_and_generate_reports(
|
||||||
|
const MutableSpan<float> values,
|
||||||
|
const int index,
|
||||||
|
PointerRNA &ptr,
|
||||||
|
PropertyRNA &prop,
|
||||||
|
NlaKeyframingContext *nla_context,
|
||||||
|
const AnimationEvalContext *anim_eval_context,
|
||||||
|
ReportList *reports,
|
||||||
|
bool *force_all)
|
||||||
|
{
|
||||||
|
BitVector<> successful_remaps(values.size(), false);
|
||||||
|
BKE_animsys_nla_remap_keyframe_values(
|
||||||
|
nla_context, &ptr, &prop, values, index, anim_eval_context, force_all, successful_remaps);
|
||||||
|
get_keyframe_values_create_reports(
|
||||||
|
reports, ptr, &prop, index, values.size(), false, successful_remaps);
|
||||||
|
return successful_remaps;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move the point where a key is about to be inserted to be inside the main cycle range.
|
* Move the point where a key is about to be inserted to be inside the main cycle range.
|
||||||
* Returns the type of the cycle if it is enabled and valid.
|
* Returns the type of the cycle if it is enabled and valid.
|
||||||
|
@ -429,9 +412,18 @@ bool insert_keyframe_direct(ReportList *reports,
|
||||||
update_autoflags_fcurve_direct(fcu, prop);
|
update_autoflags_fcurve_direct(fcu, prop);
|
||||||
|
|
||||||
const int index = fcu->array_index;
|
const int index = fcu->array_index;
|
||||||
BitVector<> successful_remaps;
|
const bool visual_keyframing = flag & INSERTKEY_MATRIX;
|
||||||
Vector<float> values = get_keyframe_values(
|
Vector<float> values = get_keyframe_values(&ptr, prop, visual_keyframing);
|
||||||
reports, ptr, prop, index, nla_context, flag, anim_eval_context, nullptr, successful_remaps);
|
|
||||||
|
BitVector<> successful_remaps = nla_map_keyframe_values_and_generate_reports(
|
||||||
|
values.as_mutable_span(),
|
||||||
|
index,
|
||||||
|
ptr,
|
||||||
|
*prop,
|
||||||
|
nla_context,
|
||||||
|
anim_eval_context,
|
||||||
|
reports,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
float current_value = 0.0f;
|
float current_value = 0.0f;
|
||||||
if (index >= 0 && index < values.size()) {
|
if (index >= 0 && index < values.size()) {
|
||||||
|
@ -594,17 +586,19 @@ int insert_keyframe(Main *bmain,
|
||||||
const float nla_mapped_frame = nla_time_remap(
|
const float nla_mapped_frame = nla_time_remap(
|
||||||
anim_eval_context, &id_ptr, adt, act, &nla_cache, &nla_context);
|
anim_eval_context, &id_ptr, adt, act, &nla_cache, &nla_context);
|
||||||
|
|
||||||
|
const bool visual_keyframing = flag & INSERTKEY_MATRIX;
|
||||||
|
Vector<float> values = get_keyframe_values(&ptr, prop, visual_keyframing);
|
||||||
|
|
||||||
bool force_all;
|
bool force_all;
|
||||||
BitVector successful_remaps;
|
BitVector<> successful_remaps = nla_map_keyframe_values_and_generate_reports(
|
||||||
Vector<float> values = get_keyframe_values(reports,
|
values.as_mutable_span(),
|
||||||
ptr,
|
array_index,
|
||||||
prop,
|
ptr,
|
||||||
array_index,
|
*prop,
|
||||||
nla_context,
|
nla_context,
|
||||||
flag,
|
anim_eval_context,
|
||||||
anim_eval_context,
|
reports,
|
||||||
&force_all,
|
&force_all);
|
||||||
successful_remaps);
|
|
||||||
|
|
||||||
CombinedKeyingResult combined_result;
|
CombinedKeyingResult combined_result;
|
||||||
|
|
||||||
|
@ -971,25 +965,6 @@ int insert_key_action(Main *bmain,
|
||||||
return inserted_keys;
|
return inserted_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
static blender::Vector<float> get_keyframe_values(PointerRNA *ptr,
|
|
||||||
PropertyRNA *prop,
|
|
||||||
const bool visual_key)
|
|
||||||
{
|
|
||||||
Vector<float> values;
|
|
||||||
|
|
||||||
if (visual_key && visualkey_can_use(ptr, prop)) {
|
|
||||||
/* Visual-keying is only available for object and pchan datablocks, as
|
|
||||||
* it works by keyframing using a value extracted from the final matrix
|
|
||||||
* instead of using the kt system to extract a value.
|
|
||||||
*/
|
|
||||||
values = visualkey_get_values(ptr, prop);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
values = get_rna_values(ptr, prop);
|
|
||||||
}
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
void insert_key_rna(PointerRNA *rna_pointer,
|
void insert_key_rna(PointerRNA *rna_pointer,
|
||||||
const blender::Span<std::string> rna_paths,
|
const blender::Span<std::string> rna_paths,
|
||||||
const float scene_frame,
|
const float scene_frame,
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "BLI_string_ref.hh"
|
#include "BLI_string_ref.hh"
|
||||||
|
#include "BLI_utility_mixins.hh"
|
||||||
|
|
||||||
#include "DNA_ID_enums.h"
|
#include "DNA_ID_enums.h"
|
||||||
#include "DNA_asset_types.h"
|
#include "DNA_asset_types.h"
|
||||||
|
@ -31,7 +32,7 @@ namespace blender::asset_system {
|
||||||
|
|
||||||
class AssetLibrary;
|
class AssetLibrary;
|
||||||
|
|
||||||
class AssetRepresentation {
|
class AssetRepresentation : NonCopyable, NonMovable {
|
||||||
AssetIdentifier identifier_;
|
AssetIdentifier identifier_;
|
||||||
/**
|
/**
|
||||||
* Indicate if this is a local or external asset, and as such, which of the union members below
|
* Indicate if this is a local or external asset, and as such, which of the union members below
|
||||||
|
@ -69,11 +70,6 @@ class AssetRepresentation {
|
||||||
const AssetLibrary &owner_asset_library);
|
const AssetLibrary &owner_asset_library);
|
||||||
~AssetRepresentation();
|
~AssetRepresentation();
|
||||||
|
|
||||||
AssetRepresentation(const AssetRepresentation &) = delete;
|
|
||||||
AssetRepresentation(AssetRepresentation &&) = delete;
|
|
||||||
AssetRepresentation &operator=(AssetRepresentation &&) = delete;
|
|
||||||
AssetRepresentation &operator=(const AssetRepresentation &) = delete;
|
|
||||||
|
|
||||||
const AssetIdentifier &get_identifier() const;
|
const AssetIdentifier &get_identifier() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "BLI_math_vector_types.hh"
|
#include "BLI_math_vector_types.hh"
|
||||||
#include "BLI_offset_indices.hh"
|
#include "BLI_offset_indices.hh"
|
||||||
#include "BLI_span.hh"
|
#include "BLI_span.hh"
|
||||||
|
#include "BLI_virtual_array.hh"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shrinkwrap is composed by a set of functions and options that define the type of shrink.
|
* Shrinkwrap is composed by a set of functions and options that define the type of shrink.
|
||||||
|
@ -79,7 +80,7 @@ struct ShrinkwrapTreeData {
|
||||||
blender::Span<blender::float3> face_normals;
|
blender::Span<blender::float3> face_normals;
|
||||||
blender::Span<blender::float3> vert_normals;
|
blender::Span<blender::float3> vert_normals;
|
||||||
blender::Span<blender::float3> corner_normals;
|
blender::Span<blender::float3> corner_normals;
|
||||||
const bool *sharp_faces;
|
blender::VArraySpan<bool> sharp_faces;
|
||||||
const ShrinkwrapBoundaryData *boundary;
|
const ShrinkwrapBoundaryData *boundary;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2181,6 +2181,49 @@ static void legacy_object_modifier_build(Object &object, GpencilModifierData &le
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void legacy_object_modifier_simplify(Object &object, GpencilModifierData &legacy_md)
|
||||||
|
{
|
||||||
|
ModifierData &md = legacy_object_modifier_common(
|
||||||
|
object, eModifierType_GreasePencilSimplify, legacy_md);
|
||||||
|
auto &md_simplify = reinterpret_cast<GreasePencilSimplifyModifierData &>(md);
|
||||||
|
auto &legacy_md_simplify = reinterpret_cast<SimplifyGpencilModifierData &>(legacy_md);
|
||||||
|
|
||||||
|
switch (legacy_md_simplify.mode) {
|
||||||
|
case GP_SIMPLIFY_FIXED:
|
||||||
|
md_simplify.mode = MOD_GREASE_PENCIL_SIMPLIFY_FIXED;
|
||||||
|
break;
|
||||||
|
case GP_SIMPLIFY_ADAPTIVE:
|
||||||
|
md_simplify.mode = MOD_GREASE_PENCIL_SIMPLIFY_ADAPTIVE;
|
||||||
|
break;
|
||||||
|
case GP_SIMPLIFY_SAMPLE:
|
||||||
|
md_simplify.mode = MOD_GREASE_PENCIL_SIMPLIFY_SAMPLE;
|
||||||
|
break;
|
||||||
|
case GP_SIMPLIFY_MERGE:
|
||||||
|
md_simplify.mode = MOD_GREASE_PENCIL_SIMPLIFY_MERGE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
md_simplify.step = legacy_md_simplify.step;
|
||||||
|
md_simplify.factor = legacy_md_simplify.factor;
|
||||||
|
md_simplify.length = legacy_md_simplify.length;
|
||||||
|
md_simplify.sharp_threshold = legacy_md_simplify.sharp_threshold;
|
||||||
|
md_simplify.distance = legacy_md_simplify.distance;
|
||||||
|
|
||||||
|
legacy_object_modifier_influence(md_simplify.influence,
|
||||||
|
legacy_md_simplify.layername,
|
||||||
|
legacy_md_simplify.layer_pass,
|
||||||
|
legacy_md_simplify.flag & GP_SIMPLIFY_INVERT_LAYER,
|
||||||
|
legacy_md_simplify.flag & GP_SIMPLIFY_INVERT_LAYERPASS,
|
||||||
|
&legacy_md_simplify.material,
|
||||||
|
legacy_md_simplify.pass_index,
|
||||||
|
legacy_md_simplify.flag & GP_SIMPLIFY_INVERT_MATERIAL,
|
||||||
|
legacy_md_simplify.flag & GP_SIMPLIFY_INVERT_PASS,
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
nullptr,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
static void legacy_object_modifiers(Main & /*bmain*/, Object &object)
|
static void legacy_object_modifiers(Main & /*bmain*/, Object &object)
|
||||||
{
|
{
|
||||||
BLI_assert(BLI_listbase_is_empty(&object.modifiers));
|
BLI_assert(BLI_listbase_is_empty(&object.modifiers));
|
||||||
|
@ -2265,6 +2308,8 @@ static void legacy_object_modifiers(Main & /*bmain*/, Object &object)
|
||||||
legacy_object_modifier_build(object, *gpd_md);
|
legacy_object_modifier_build(object, *gpd_md);
|
||||||
break;
|
break;
|
||||||
case eGpencilModifierType_Simplify:
|
case eGpencilModifierType_Simplify:
|
||||||
|
legacy_object_modifier_simplify(object, *gpd_md);
|
||||||
|
break;
|
||||||
case eGpencilModifierType_Texture:
|
case eGpencilModifierType_Texture:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1281,6 +1281,9 @@ void update_normals(PBVH &pbvh, SubdivCCG *subdiv_ccg)
|
||||||
{
|
{
|
||||||
Vector<PBVHNode *> nodes = search_gather(
|
Vector<PBVHNode *> nodes = search_gather(
|
||||||
&pbvh, [&](PBVHNode &node) { return update_search(&node, PBVH_UpdateNormals); });
|
&pbvh, [&](PBVHNode &node) { return update_search(&node, PBVH_UpdateNormals); });
|
||||||
|
if (nodes.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (pbvh.header.type == PBVH_BMESH) {
|
if (pbvh.header.type == PBVH_BMESH) {
|
||||||
bmesh_normals_update(nodes);
|
bmesh_normals_update(nodes);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
#include "BKE_DerivedMesh.hh"
|
#include "BKE_DerivedMesh.hh"
|
||||||
|
#include "BKE_attribute.hh"
|
||||||
#include "BKE_cdderivedmesh.h"
|
#include "BKE_cdderivedmesh.h"
|
||||||
#include "BKE_modifier.hh"
|
#include "BKE_modifier.hh"
|
||||||
#include "BKE_shrinkwrap.hh"
|
#include "BKE_shrinkwrap.hh"
|
||||||
|
@ -96,6 +97,7 @@ bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
|
||||||
bool BKE_shrinkwrap_init_tree(
|
bool BKE_shrinkwrap_init_tree(
|
||||||
ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
|
ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
|
||||||
{
|
{
|
||||||
|
using namespace blender::bke;
|
||||||
*data = {};
|
*data = {};
|
||||||
|
|
||||||
if (mesh == nullptr) {
|
if (mesh == nullptr) {
|
||||||
|
@ -115,8 +117,8 @@ bool BKE_shrinkwrap_init_tree(
|
||||||
data->faces = mesh->faces();
|
data->faces = mesh->faces();
|
||||||
data->corner_edges = mesh->corner_edges();
|
data->corner_edges = mesh->corner_edges();
|
||||||
data->vert_normals = mesh->vert_normals();
|
data->vert_normals = mesh->vert_normals();
|
||||||
data->sharp_faces = static_cast<const bool *>(
|
const AttributeAccessor attributes = mesh->attributes();
|
||||||
CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face"));
|
data->sharp_faces = *attributes.lookup<bool>("sharp_face", AttrDomain::Face);
|
||||||
|
|
||||||
if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) {
|
if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) {
|
||||||
data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2);
|
data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2);
|
||||||
|
@ -1160,7 +1162,7 @@ void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree,
|
||||||
const int face_i = tree->mesh->corner_tri_faces()[corner_tri_idx];
|
const int face_i = tree->mesh->corner_tri_faces()[corner_tri_idx];
|
||||||
|
|
||||||
/* Interpolate smooth normals if enabled. */
|
/* Interpolate smooth normals if enabled. */
|
||||||
if (!(tree->sharp_faces && tree->sharp_faces[face_i])) {
|
if (tree->sharp_faces.is_empty() || tree->sharp_faces[face_i]) {
|
||||||
const int vert_indices[3] = {treeData->corner_verts[tri[0]],
|
const int vert_indices[3] = {treeData->corner_verts[tri[0]],
|
||||||
treeData->corner_verts[tri[1]],
|
treeData->corner_verts[tri[1]],
|
||||||
treeData->corner_verts[tri[2]]};
|
treeData->corner_verts[tri[2]]};
|
||||||
|
@ -1205,6 +1207,9 @@ void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree,
|
||||||
/* Use the face normal if flat. */
|
/* Use the face normal if flat. */
|
||||||
else if (!tree->face_normals.is_empty()) {
|
else if (!tree->face_normals.is_empty()) {
|
||||||
copy_v3_v3(r_no, tree->face_normals[face_i]);
|
copy_v3_v3(r_no, tree->face_normals[face_i]);
|
||||||
|
if (transform) {
|
||||||
|
BLI_space_transform_invert_normal(transform, r_no);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Finally fallback to the corner_tris normal. */
|
/* Finally fallback to the corner_tris normal. */
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -470,21 +470,22 @@ struct alignas(Alignment) MatBase : public vec_struct_base<VecBase<T, NumRow>, N
|
||||||
friend std::ostream &operator<<(std::ostream &stream, const MatBase &mat)
|
friend std::ostream &operator<<(std::ostream &stream, const MatBase &mat)
|
||||||
{
|
{
|
||||||
stream << "(\n";
|
stream << "(\n";
|
||||||
unroll<NumRow>([&](auto i) {
|
for (int i = 0; i < NumRow; i++) {
|
||||||
stream << "(";
|
stream << "(";
|
||||||
unroll<NumCol>([&](auto j) {
|
for (int j = 0; j < NumCol; j++) {
|
||||||
/** NOTE: j and i are swapped to follow mathematical convention. */
|
/** NOTE: j and i are swapped to follow mathematical convention. */
|
||||||
stream << mat[j][i];
|
stream << mat[j][i];
|
||||||
if (j < NumCol - 1) {
|
if (j < NumCol - 1) {
|
||||||
stream << ", ";
|
stream << ", ";
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
stream << ")";
|
stream << ")";
|
||||||
if (i < NumRow - 1) {
|
if (i < NumRow - 1) {
|
||||||
stream << ",";
|
stream << ",";
|
||||||
}
|
}
|
||||||
stream << "\n";
|
stream << "\n";
|
||||||
});
|
}
|
||||||
|
|
||||||
stream << ")\n";
|
stream << ")\n";
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index)
|
||||||
MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_VIEWER_ATTRIBUTE_OVERLAY |
|
MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_VIEWER_ATTRIBUTE_OVERLAY |
|
||||||
MBC_SURFACE_PER_MAT;
|
MBC_SURFACE_PER_MAT;
|
||||||
case BUFFER_INDEX(vbo.nor):
|
case BUFFER_INDEX(vbo.nor):
|
||||||
return MBC_SURFACE | MBC_EDIT_LNOR | MBC_WIRE_LOOPS | MBC_SURFACE_PER_MAT;
|
return MBC_SURFACE | MBC_EDIT_LNOR | MBC_WIRE_LOOPS | MBC_SURFACE_PER_MAT | MBC_ALL_VERTS;
|
||||||
case BUFFER_INDEX(vbo.edge_fac):
|
case BUFFER_INDEX(vbo.edge_fac):
|
||||||
return MBC_WIRE_EDGES;
|
return MBC_WIRE_EDGES;
|
||||||
case BUFFER_INDEX(vbo.weights):
|
case BUFFER_INDEX(vbo.weights):
|
||||||
|
@ -1555,9 +1555,10 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
|
||||||
}
|
}
|
||||||
drw_add_attributes_vbo(cache.batch.surface, mbuflist, &cache.attr_used);
|
drw_add_attributes_vbo(cache.batch.surface, mbuflist, &cache.attr_used);
|
||||||
}
|
}
|
||||||
assert_deps_valid(MBC_ALL_VERTS, {BUFFER_INDEX(vbo.pos)});
|
assert_deps_valid(MBC_ALL_VERTS, {BUFFER_INDEX(vbo.pos), BUFFER_INDEX(vbo.nor)});
|
||||||
if (DRW_batch_requested(cache.batch.all_verts, GPU_PRIM_POINTS)) {
|
if (DRW_batch_requested(cache.batch.all_verts, GPU_PRIM_POINTS)) {
|
||||||
DRW_vbo_request(cache.batch.all_verts, &mbuflist->vbo.pos);
|
DRW_vbo_request(cache.batch.all_verts, &mbuflist->vbo.pos);
|
||||||
|
DRW_vbo_request(cache.batch.all_verts, &mbuflist->vbo.nor);
|
||||||
}
|
}
|
||||||
assert_deps_valid(
|
assert_deps_valid(
|
||||||
MBC_SCULPT_OVERLAYS,
|
MBC_SCULPT_OVERLAYS,
|
||||||
|
|
|
@ -103,6 +103,7 @@ static const asset_system::AssetRepresentation *find_asset_from_weak_ref(
|
||||||
asset_system::all_library_reference());
|
asset_system::all_library_reference());
|
||||||
if (!all_library) {
|
if (!all_library) {
|
||||||
BKE_report(reports, RPT_WARNING, "Asset loading is unfinished");
|
BKE_report(reports, RPT_WARNING, "Asset loading is unfinished");
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string full_path = all_library->resolve_asset_weak_reference_to_full_path(weak_ref);
|
const std::string full_path = all_library->resolve_asset_weak_reference_to_full_path(weak_ref);
|
||||||
|
|
|
@ -138,7 +138,7 @@ void AssetView::build_items()
|
||||||
return handle_get_preview_or_type_icon_id(&asset_handle);
|
return handle_get_preview_or_type_icon_id(&asset_handle);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
AssetViewItem &item = add_item<AssetViewItem>(
|
AssetViewItem &item = this->add_item<AssetViewItem>(
|
||||||
asset_handle, identifier, asset->get_name(), preview_id);
|
asset_handle, identifier, asset->get_name(), preview_id);
|
||||||
if (!show_names) {
|
if (!show_names) {
|
||||||
item.hide_label();
|
item.hide_label();
|
||||||
|
@ -222,7 +222,7 @@ void AssetViewItem::build_grid_tile(uiLayout &layout) const
|
||||||
|
|
||||||
void AssetViewItem::build_context_menu(bContext &C, uiLayout &column) const
|
void AssetViewItem::build_context_menu(bContext &C, uiLayout &column) const
|
||||||
{
|
{
|
||||||
const AssetView &asset_view = dynamic_cast<const AssetView &>(get_view());
|
const AssetView &asset_view = dynamic_cast<const AssetView &>(this->get_view());
|
||||||
const AssetShelfType &shelf_type = *asset_view.shelf_.type;
|
const AssetShelfType &shelf_type = *asset_view.shelf_.type;
|
||||||
if (shelf_type.draw_context_menu) {
|
if (shelf_type.draw_context_menu) {
|
||||||
asset_system::AssetRepresentation *asset = handle_get_representation(&asset_);
|
asset_system::AssetRepresentation *asset = handle_get_representation(&asset_);
|
||||||
|
@ -245,7 +245,7 @@ std::optional<bool> AssetViewItem::should_be_active() const
|
||||||
|
|
||||||
bool AssetViewItem::is_filtered_visible() const
|
bool AssetViewItem::is_filtered_visible() const
|
||||||
{
|
{
|
||||||
const AssetView &asset_view = dynamic_cast<const AssetView &>(get_view());
|
const AssetView &asset_view = dynamic_cast<const AssetView &>(this->get_view());
|
||||||
if (asset_view.search_string[0] == '\0') {
|
if (asset_view.search_string[0] == '\0') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,7 @@ std::unique_ptr<ui::AbstractViewItemDragController> AssetViewItem::create_drag_c
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
asset_system::AssetRepresentation *asset = handle_get_representation(&asset_);
|
asset_system::AssetRepresentation *asset = handle_get_representation(&asset_);
|
||||||
return std::make_unique<AssetDragController>(get_view(), *asset);
|
return std::make_unique<AssetDragController>(this->get_view(), *asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
|
@ -1108,7 +1108,7 @@ static bool gpencil_vertexpaint_brush_do_frame(bContext *C,
|
||||||
static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpaintData *gso)
|
static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpaintData *gso)
|
||||||
{
|
{
|
||||||
ToolSettings *ts = CTX_data_tool_settings(C);
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
||||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||||
Object *obact = gso->object;
|
Object *obact = gso->object;
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
|
|
|
@ -1154,15 +1154,15 @@ void ED_mesh_split_faces(Mesh *mesh)
|
||||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||||
const VArray<bool> mesh_sharp_edges = *attributes.lookup_or_default<bool>(
|
const VArray<bool> mesh_sharp_edges = *attributes.lookup_or_default<bool>(
|
||||||
"sharp_edge", bke::AttrDomain::Edge, false);
|
"sharp_edge", bke::AttrDomain::Edge, false);
|
||||||
const bool *sharp_faces = static_cast<const bool *>(
|
const VArraySpan<bool> sharp_faces = *attributes.lookup<bool>("sharp_face",
|
||||||
CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face"));
|
bke::AttrDomain::Face);
|
||||||
|
|
||||||
Array<bool> sharp_edges(mesh->edges_num);
|
Array<bool> sharp_edges(mesh->edges_num);
|
||||||
mesh_sharp_edges.materialize(sharp_edges);
|
mesh_sharp_edges.materialize(sharp_edges);
|
||||||
|
|
||||||
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
|
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
|
||||||
for (const int face_i : range) {
|
for (const int face_i : range) {
|
||||||
if (sharp_faces && sharp_faces[face_i]) {
|
if (!sharp_faces.is_empty() && sharp_faces[face_i]) {
|
||||||
for (const int edge : corner_edges.slice(polys[face_i])) {
|
for (const int edge : corner_edges.slice(polys[face_i])) {
|
||||||
sharp_edges[edge] = true;
|
sharp_edges[edge] = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1010,6 +1010,8 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
|
||||||
vwpaint::update_cache_invariants(C, vp, ss, op, mouse);
|
vwpaint::update_cache_invariants(C, vp, ss, op, mouse);
|
||||||
vwpaint::init_session_data(ts, ob);
|
vwpaint::init_session_data(ts, ob);
|
||||||
|
|
||||||
|
/* Brush may have changed after initialization. */
|
||||||
|
brush = BKE_paint_brush(&vp->paint);
|
||||||
if (ELEM(brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
|
if (ELEM(brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
|
||||||
wpd->precomputed_weight = (float *)MEM_mallocN(sizeof(float) * mesh->verts_num, __func__);
|
wpd->precomputed_weight = (float *)MEM_mallocN(sizeof(float) * mesh->verts_num, __func__);
|
||||||
}
|
}
|
||||||
|
|
|
@ -622,13 +622,8 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh,
|
||||||
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||||
bke::SpanAttributeWriter material_indices = attributes.lookup_or_add_for_write_span<int>(
|
bke::SpanAttributeWriter material_indices = attributes.lookup_or_add_for_write_span<int>(
|
||||||
"material_index", bke::AttrDomain::Face);
|
"material_index", bke::AttrDomain::Face);
|
||||||
|
bke::SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_span<bool>(
|
||||||
bool *sharp_faces = static_cast<bool *>(CustomData_get_layer_named_for_write(
|
"sharp_face", bke::AttrDomain::Face);
|
||||||
&mesh->face_data, CD_PROP_BOOL, "sharp_face", mesh->faces_num));
|
|
||||||
if (!sharp_faces) {
|
|
||||||
sharp_faces = static_cast<bool *>(CustomData_add_layer_named(
|
|
||||||
&mesh->face_data, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->faces_num, "sharp_face"));
|
|
||||||
}
|
|
||||||
|
|
||||||
COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
|
COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
|
||||||
COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals();
|
COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals();
|
||||||
|
@ -673,7 +668,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh,
|
||||||
if (mp_has_normals) { /* vertex normals, same implementation as for the triangles */
|
if (mp_has_normals) { /* vertex normals, same implementation as for the triangles */
|
||||||
/* The same for vertices normals. */
|
/* The same for vertices normals. */
|
||||||
uint vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]};
|
uint vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]};
|
||||||
sharp_faces[face_index] = is_flat_face(vertex_normal_indices, nor, 3);
|
sharp_faces.span[face_index] = is_flat_face(vertex_normal_indices, nor, 3);
|
||||||
normal_indices++;
|
normal_indices++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,7 +738,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh,
|
||||||
if (mp_has_normals) {
|
if (mp_has_normals) {
|
||||||
/* If it turns out that we have complete custom normals for each poly
|
/* If it turns out that we have complete custom normals for each poly
|
||||||
* and we want to use custom normals, this will be overridden. */
|
* and we want to use custom normals, this will be overridden. */
|
||||||
sharp_faces[face_index] = is_flat_face(normal_indices, nor, vcount);
|
sharp_faces.span[face_index] = is_flat_face(normal_indices, nor, vcount);
|
||||||
|
|
||||||
if (use_custom_normals) {
|
if (use_custom_normals) {
|
||||||
/* Store the custom normals for later application. */
|
/* Store the custom normals for later application. */
|
||||||
|
|
|
@ -1062,4 +1062,14 @@
|
||||||
.percentage_fac = 0.0f, \
|
.percentage_fac = 0.0f, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define _DNA_DEFAULT_GreasePencilSimplifyModifierData \
|
||||||
|
{ \
|
||||||
|
.factor = 0.0f, \
|
||||||
|
.mode = MOD_GREASE_PENCIL_SIMPLIFY_FIXED, \
|
||||||
|
.step = 1, \
|
||||||
|
.length = 0.1f, \
|
||||||
|
.distance = 0.1f, \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
|
@ -119,6 +119,7 @@ typedef enum ModifierType {
|
||||||
eModifierType_GreasePencilOutline = 82,
|
eModifierType_GreasePencilOutline = 82,
|
||||||
eModifierType_GreasePencilShrinkwrap = 83,
|
eModifierType_GreasePencilShrinkwrap = 83,
|
||||||
eModifierType_GreasePencilBuild = 84,
|
eModifierType_GreasePencilBuild = 84,
|
||||||
|
eModifierType_GreasePencilSimplify = 85,
|
||||||
NUM_MODIFIER_TYPES,
|
NUM_MODIFIER_TYPES,
|
||||||
} ModifierType;
|
} ModifierType;
|
||||||
|
|
||||||
|
@ -3404,3 +3405,28 @@ typedef enum GreasePencilBuildFlag {
|
||||||
MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME = (1 << 0),
|
MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME = (1 << 0),
|
||||||
MOD_GREASE_PENCIL_BUILD_USE_FADING = (1 << 14),
|
MOD_GREASE_PENCIL_BUILD_USE_FADING = (1 << 14),
|
||||||
} GreasePencilBuildFlag;
|
} GreasePencilBuildFlag;
|
||||||
|
|
||||||
|
typedef struct GreasePencilSimplifyModifierData {
|
||||||
|
ModifierData modifier;
|
||||||
|
GreasePencilModifierInfluenceData influence;
|
||||||
|
|
||||||
|
/** #GreasePencilSimplifyModifierMode. */
|
||||||
|
short mode;
|
||||||
|
char _pad[4];
|
||||||
|
/** Every n vertex to keep. */
|
||||||
|
short step;
|
||||||
|
float factor;
|
||||||
|
/** For sampling. */
|
||||||
|
float length;
|
||||||
|
float sharp_threshold;
|
||||||
|
|
||||||
|
/** Merge distance */
|
||||||
|
float distance;
|
||||||
|
} GreasePencilSimplifyModifierData;
|
||||||
|
|
||||||
|
typedef enum GreasePencilSimplifyModifierMode {
|
||||||
|
MOD_GREASE_PENCIL_SIMPLIFY_FIXED = 0,
|
||||||
|
MOD_GREASE_PENCIL_SIMPLIFY_ADAPTIVE = 1,
|
||||||
|
MOD_GREASE_PENCIL_SIMPLIFY_SAMPLE = 2,
|
||||||
|
MOD_GREASE_PENCIL_SIMPLIFY_MERGE = 3,
|
||||||
|
} GreasePencilSimplifyModifierMode;
|
||||||
|
|
|
@ -357,6 +357,7 @@ SDNA_DEFAULT_DECL_STRUCT(GreasePencilHookModifierData);
|
||||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilArmatureModifierData);
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilArmatureModifierData);
|
||||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilTimeModifierSegment);
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilTimeModifierSegment);
|
||||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilTimeModifierData);
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilTimeModifierData);
|
||||||
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilSimplifyModifierData);
|
||||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilEnvelopeModifierData);
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilEnvelopeModifierData);
|
||||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilOutlineModifierData);
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilOutlineModifierData);
|
||||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilShrinkwrapModifierData);
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilShrinkwrapModifierData);
|
||||||
|
@ -634,6 +635,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
|
||||||
SDNA_DEFAULT_DECL(GreasePencilArmatureModifierData),
|
SDNA_DEFAULT_DECL(GreasePencilArmatureModifierData),
|
||||||
SDNA_DEFAULT_DECL(GreasePencilTimeModifierSegment),
|
SDNA_DEFAULT_DECL(GreasePencilTimeModifierSegment),
|
||||||
SDNA_DEFAULT_DECL(GreasePencilTimeModifierData),
|
SDNA_DEFAULT_DECL(GreasePencilTimeModifierData),
|
||||||
|
SDNA_DEFAULT_DECL(GreasePencilSimplifyModifierData),
|
||||||
SDNA_DEFAULT_DECL(GreasePencilEnvelopeModifierData),
|
SDNA_DEFAULT_DECL(GreasePencilEnvelopeModifierData),
|
||||||
SDNA_DEFAULT_DECL(GreasePencilOutlineModifierData),
|
SDNA_DEFAULT_DECL(GreasePencilOutlineModifierData),
|
||||||
SDNA_DEFAULT_DECL(GreasePencilShrinkwrapModifierData),
|
SDNA_DEFAULT_DECL(GreasePencilShrinkwrapModifierData),
|
||||||
|
|
|
@ -259,6 +259,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
|
||||||
ICON_GP_MULTIFRAME_EDITING,
|
ICON_GP_MULTIFRAME_EDITING,
|
||||||
"Multiple Strokes",
|
"Multiple Strokes",
|
||||||
"Generate multiple strokes around original strokes"},
|
"Generate multiple strokes around original strokes"},
|
||||||
|
{eModifierType_GreasePencilSimplify,
|
||||||
|
"GREASE_PENCIL_SIMPLIFY",
|
||||||
|
ICON_MOD_SIMPLIFY,
|
||||||
|
"Simplify",
|
||||||
|
"Simplify stroke reducing number of points"},
|
||||||
{eModifierType_GreasePencilSubdiv,
|
{eModifierType_GreasePencilSubdiv,
|
||||||
"GREASE_PENCIL_SUBDIV",
|
"GREASE_PENCIL_SUBDIV",
|
||||||
ICON_MOD_SUBSURF,
|
ICON_MOD_SUBSURF,
|
||||||
|
@ -1992,6 +1997,7 @@ RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilWeightAngle);
|
||||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilArray);
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilArray);
|
||||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilWeightProximity);
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilWeightProximity);
|
||||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilHook);
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilHook);
|
||||||
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilSimplify);
|
||||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilEnvelope);
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilEnvelope);
|
||||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilOutline);
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilOutline);
|
||||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilShrinkwrap);
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilShrinkwrap);
|
||||||
|
@ -2008,6 +2014,7 @@ RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilWeightAngle);
|
||||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilWeightProximity);
|
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilWeightProximity);
|
||||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilHook);
|
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilHook);
|
||||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilArmature);
|
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilArmature);
|
||||||
|
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilSimplify);
|
||||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilEnvelope);
|
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilEnvelope);
|
||||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilShrinkwrap);
|
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilShrinkwrap);
|
||||||
|
|
||||||
|
@ -9995,6 +10002,89 @@ static void rna_def_modifier_grease_pencil_weight_proximity(BlenderRNA *brna)
|
||||||
RNA_define_lib_overridable(false);
|
RNA_define_lib_overridable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rna_def_modifier_grease_pencil_simplify(BlenderRNA *brna)
|
||||||
|
{
|
||||||
|
StructRNA *srna;
|
||||||
|
PropertyRNA *prop;
|
||||||
|
|
||||||
|
static EnumPropertyItem prop_gpencil_simplify_mode_items[] = {
|
||||||
|
{MOD_GREASE_PENCIL_SIMPLIFY_FIXED,
|
||||||
|
"FIXED",
|
||||||
|
ICON_IPO_CONSTANT,
|
||||||
|
"Fixed",
|
||||||
|
"Delete alternating vertices in the stroke, except extremes"},
|
||||||
|
{MOD_GREASE_PENCIL_SIMPLIFY_ADAPTIVE,
|
||||||
|
"ADAPTIVE",
|
||||||
|
ICON_IPO_EASE_IN_OUT,
|
||||||
|
"Adaptive",
|
||||||
|
"Use a Ramer-Douglas-Peucker algorithm to simplify the stroke preserving main shape"},
|
||||||
|
{MOD_GREASE_PENCIL_SIMPLIFY_SAMPLE,
|
||||||
|
"SAMPLE",
|
||||||
|
ICON_IPO_EASE_IN_OUT,
|
||||||
|
"Sample",
|
||||||
|
"Re-sample the stroke with segments of the specified length"},
|
||||||
|
{MOD_GREASE_PENCIL_SIMPLIFY_MERGE,
|
||||||
|
"MERGE",
|
||||||
|
ICON_IPO_EASE_IN_OUT,
|
||||||
|
"Merge",
|
||||||
|
"Simplify the stroke by merging vertices closer than a given distance"},
|
||||||
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
|
};
|
||||||
|
|
||||||
|
srna = RNA_def_struct(brna, "GreasePencilSimplifyModifier", "Modifier");
|
||||||
|
RNA_def_struct_ui_text(srna, "Simplify Modifier", "Simplify Stroke modifier");
|
||||||
|
RNA_def_struct_sdna(srna, "GreasePencilSimplifyModifierData");
|
||||||
|
RNA_def_struct_ui_icon(srna, ICON_MOD_SIMPLIFY);
|
||||||
|
|
||||||
|
rna_def_modifier_grease_pencil_layer_filter(srna);
|
||||||
|
rna_def_modifier_grease_pencil_material_filter(
|
||||||
|
srna, "rna_GreasePencilSimplifyModifier_material_filter_set");
|
||||||
|
rna_def_modifier_grease_pencil_vertex_group(
|
||||||
|
srna, "rna_GreasePencilSimplifyModifier_vertex_group_name_set");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "factor");
|
||||||
|
RNA_def_property_range(prop, 0, 100.0);
|
||||||
|
RNA_def_property_ui_range(prop, 0, 5.0f, 1.0f, 3);
|
||||||
|
RNA_def_property_ui_text(prop, "Factor", "Factor of Simplify");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_items(prop, prop_gpencil_simplify_mode_items);
|
||||||
|
RNA_def_property_ui_text(prop, "Mode", "How to simplify the stroke");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
|
||||||
|
RNA_def_property_int_sdna(prop, nullptr, "step");
|
||||||
|
RNA_def_property_range(prop, 1, 50);
|
||||||
|
RNA_def_property_ui_text(prop, "Iterations", "Number of times to apply simplify");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "length");
|
||||||
|
RNA_def_property_range(prop, 0, FLT_MAX);
|
||||||
|
RNA_def_property_ui_range(prop, 0.005, 1.0, 0.05, 3);
|
||||||
|
RNA_def_property_ui_text(prop, "Length", "Length of each segment");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "sharp_threshold", PROP_FLOAT, PROP_ANGLE);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "sharp_threshold");
|
||||||
|
RNA_def_property_range(prop, 0, M_PI);
|
||||||
|
RNA_def_property_ui_range(prop, 0, M_PI, 1.0, 1);
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Sharp Threshold", "Preserve corners that have sharper angle than this threshold");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "distance");
|
||||||
|
RNA_def_property_range(prop, 0, FLT_MAX);
|
||||||
|
RNA_def_property_ui_range(prop, 0, 1.0, 0.01, 3);
|
||||||
|
RNA_def_property_ui_text(prop, "Distance", "Distance between points");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
RNA_define_lib_overridable(false);
|
||||||
|
}
|
||||||
|
|
||||||
static void rna_def_modifier_grease_pencil_armature(BlenderRNA *brna)
|
static void rna_def_modifier_grease_pencil_armature(BlenderRNA *brna)
|
||||||
{
|
{
|
||||||
StructRNA *srna;
|
StructRNA *srna;
|
||||||
|
@ -10904,6 +10994,7 @@ void RNA_def_modifier(BlenderRNA *brna)
|
||||||
rna_def_modifier_grease_pencil_armature(brna);
|
rna_def_modifier_grease_pencil_armature(brna);
|
||||||
rna_def_modifier_grease_pencil_time_segment(brna);
|
rna_def_modifier_grease_pencil_time_segment(brna);
|
||||||
rna_def_modifier_grease_pencil_time(brna);
|
rna_def_modifier_grease_pencil_time(brna);
|
||||||
|
rna_def_modifier_grease_pencil_simplify(brna);
|
||||||
rna_def_modifier_grease_pencil_envelope(brna);
|
rna_def_modifier_grease_pencil_envelope(brna);
|
||||||
rna_def_modifier_grease_pencil_outline(brna);
|
rna_def_modifier_grease_pencil_outline(brna);
|
||||||
rna_def_modifier_grease_pencil_shrinkwrap(brna);
|
rna_def_modifier_grease_pencil_shrinkwrap(brna);
|
||||||
|
|
|
@ -63,6 +63,7 @@ set(SRC
|
||||||
intern/MOD_grease_pencil_noise.cc
|
intern/MOD_grease_pencil_noise.cc
|
||||||
intern/MOD_grease_pencil_offset.cc
|
intern/MOD_grease_pencil_offset.cc
|
||||||
intern/MOD_grease_pencil_opacity.cc
|
intern/MOD_grease_pencil_opacity.cc
|
||||||
|
intern/MOD_grease_pencil_simplify.cc
|
||||||
intern/MOD_grease_pencil_outline.cc
|
intern/MOD_grease_pencil_outline.cc
|
||||||
intern/MOD_grease_pencil_shrinkwrap.cc
|
intern/MOD_grease_pencil_shrinkwrap.cc
|
||||||
intern/MOD_grease_pencil_smooth.cc
|
intern/MOD_grease_pencil_smooth.cc
|
||||||
|
|
|
@ -93,6 +93,7 @@ extern ModifierTypeInfo modifierType_GreasePencilHook;
|
||||||
extern ModifierTypeInfo modifierType_GreasePencilLineart;
|
extern ModifierTypeInfo modifierType_GreasePencilLineart;
|
||||||
extern ModifierTypeInfo modifierType_GreasePencilArmature;
|
extern ModifierTypeInfo modifierType_GreasePencilArmature;
|
||||||
extern ModifierTypeInfo modifierType_GreasePencilTime;
|
extern ModifierTypeInfo modifierType_GreasePencilTime;
|
||||||
|
extern ModifierTypeInfo modifierType_GreasePencilSimplify;
|
||||||
extern ModifierTypeInfo modifierType_GreasePencilEnvelope;
|
extern ModifierTypeInfo modifierType_GreasePencilEnvelope;
|
||||||
extern ModifierTypeInfo modifierType_GreasePencilOutline;
|
extern ModifierTypeInfo modifierType_GreasePencilOutline;
|
||||||
extern ModifierTypeInfo modifierType_GreasePencilShrinkwrap;
|
extern ModifierTypeInfo modifierType_GreasePencilShrinkwrap;
|
||||||
|
|
|
@ -0,0 +1,427 @@
|
||||||
|
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup modifiers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BLI_index_mask.hh"
|
||||||
|
#include "BLI_kdtree.h"
|
||||||
|
|
||||||
|
#include "BLT_translation.hh"
|
||||||
|
|
||||||
|
#include "BLO_read_write.hh"
|
||||||
|
|
||||||
|
#include "DNA_defaults.h"
|
||||||
|
#include "DNA_modifier_types.h"
|
||||||
|
#include "DNA_screen_types.h"
|
||||||
|
|
||||||
|
#include "BKE_curves_utils.hh"
|
||||||
|
#include "BKE_geometry_fields.hh"
|
||||||
|
#include "BKE_geometry_set.hh"
|
||||||
|
#include "BKE_grease_pencil.hh"
|
||||||
|
#include "BKE_modifier.hh"
|
||||||
|
|
||||||
|
#include "GEO_resample_curves.hh"
|
||||||
|
#include "GEO_simplify_curves.hh"
|
||||||
|
|
||||||
|
#include "UI_interface.hh"
|
||||||
|
#include "UI_resources.hh"
|
||||||
|
|
||||||
|
#include "MOD_grease_pencil_util.hh"
|
||||||
|
#include "MOD_ui_common.hh"
|
||||||
|
|
||||||
|
#include "RNA_access.hh"
|
||||||
|
#include "RNA_prototypes.h"
|
||||||
|
|
||||||
|
namespace blender {
|
||||||
|
|
||||||
|
static void init_data(ModifierData *md)
|
||||||
|
{
|
||||||
|
auto *gpmd = reinterpret_cast<GreasePencilSimplifyModifierData *>(md);
|
||||||
|
|
||||||
|
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
|
||||||
|
|
||||||
|
MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(GreasePencilSimplifyModifierData), modifier);
|
||||||
|
modifier::greasepencil::init_influence_data(&gpmd->influence, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_data(ModifierData *md)
|
||||||
|
{
|
||||||
|
auto *mmd = reinterpret_cast<GreasePencilSimplifyModifierData *>(md);
|
||||||
|
|
||||||
|
modifier::greasepencil::free_influence_data(&mmd->influence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_data(const ModifierData *md, ModifierData *target, int flag)
|
||||||
|
{
|
||||||
|
const auto *gmd = reinterpret_cast<const GreasePencilSimplifyModifierData *>(md);
|
||||||
|
auto *tgmd = reinterpret_cast<GreasePencilSimplifyModifierData *>(target);
|
||||||
|
|
||||||
|
BKE_modifier_copydata_generic(md, target, flag);
|
||||||
|
modifier::greasepencil::copy_influence_data(&gmd->influence, &tgmd->influence, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
|
||||||
|
{
|
||||||
|
const auto *mmd = reinterpret_cast<const GreasePencilSimplifyModifierData *>(md);
|
||||||
|
|
||||||
|
BLO_write_struct(writer, GreasePencilSimplifyModifierData, mmd);
|
||||||
|
modifier::greasepencil::write_influence_data(writer, &mmd->influence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||||
|
{
|
||||||
|
auto *mmd = reinterpret_cast<GreasePencilSimplifyModifierData *>(md);
|
||||||
|
|
||||||
|
modifier::greasepencil::read_influence_data(reader, &mmd->influence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static IndexMask simplify_fixed(const bke::CurvesGeometry &curves,
|
||||||
|
const int step,
|
||||||
|
IndexMaskMemory &memory)
|
||||||
|
{
|
||||||
|
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||||
|
const Array<int> point_to_curve_map = curves.point_to_curve_map();
|
||||||
|
return IndexMask::from_predicate(
|
||||||
|
curves.points_range(), GrainSize(2048), memory, [&](const int64_t i) {
|
||||||
|
const int curve_i = point_to_curve_map[i];
|
||||||
|
const IndexRange points = points_by_curve[curve_i];
|
||||||
|
if (points.drop_front(1).drop_back(1).contains(i)) {
|
||||||
|
const int local_i = i - points.start();
|
||||||
|
return local_i % int(math::pow(2.0f, float(step - 1))) == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static int curve_merge_by_distance(const IndexRange points,
|
||||||
|
const Span<float> distances,
|
||||||
|
const IndexMask &selection,
|
||||||
|
const float merge_distance,
|
||||||
|
MutableSpan<int> r_merge_indices)
|
||||||
|
{
|
||||||
|
/* We use a KDTree_1d here, because we can only merge neighboring points in the curves. */
|
||||||
|
KDTree_1d *tree = BLI_kdtree_1d_new(selection.size());
|
||||||
|
/* The selection is an IndexMask of the points just in this curve. */
|
||||||
|
selection.foreach_index_optimized<int64_t>([&](const int64_t i, const int64_t pos) {
|
||||||
|
BLI_kdtree_1d_insert(tree, pos, &distances[i - points.first()]);
|
||||||
|
});
|
||||||
|
BLI_kdtree_1d_balance(tree);
|
||||||
|
|
||||||
|
Array<int> selection_merge_indices(selection.size(), -1);
|
||||||
|
const int duplicate_count = BLI_kdtree_1d_calc_duplicates_fast(
|
||||||
|
tree, merge_distance, false, selection_merge_indices.data());
|
||||||
|
BLI_kdtree_1d_free(tree);
|
||||||
|
|
||||||
|
array_utils::fill_index_range<int>(r_merge_indices);
|
||||||
|
|
||||||
|
selection.foreach_index([&](const int src_index, const int pos) {
|
||||||
|
const int merge_index = selection_merge_indices[pos];
|
||||||
|
if (merge_index != -1) {
|
||||||
|
const int src_merge_index = selection[merge_index] - points.first();
|
||||||
|
r_merge_indices[src_index - points.first()] = src_merge_index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return duplicate_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: The code here is an adapted version of #blender::geometry::point_merge_by_distance. */
|
||||||
|
static bke::CurvesGeometry curves_merge_by_distance(
|
||||||
|
const bke::CurvesGeometry &src_curves,
|
||||||
|
const float merge_distance,
|
||||||
|
const IndexMask &selection,
|
||||||
|
const bke::AnonymousAttributePropagationInfo &propagation_info)
|
||||||
|
{
|
||||||
|
const int src_point_size = src_curves.points_num();
|
||||||
|
if (src_point_size == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const OffsetIndices<int> points_by_curve = src_curves.points_by_curve();
|
||||||
|
const VArray<bool> cyclic = src_curves.cyclic();
|
||||||
|
src_curves.ensure_evaluated_lengths();
|
||||||
|
|
||||||
|
bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
|
||||||
|
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||||
|
|
||||||
|
std::atomic<int> total_duplicate_count = 0;
|
||||||
|
Array<Array<int>> merge_indices_per_curve(src_curves.curves_num());
|
||||||
|
threading::parallel_for(src_curves.curves_range(), 512, [&](const IndexRange range) {
|
||||||
|
for (const int curve_i : range) {
|
||||||
|
const IndexRange points = points_by_curve[curve_i];
|
||||||
|
merge_indices_per_curve[curve_i].reinitialize(points.size());
|
||||||
|
|
||||||
|
Array<float> distances_along_curve(points.size());
|
||||||
|
distances_along_curve.first() = 0.0f;
|
||||||
|
const Span<float> lengths = src_curves.evaluated_lengths_for_curve(curve_i, cyclic[curve_i]);
|
||||||
|
distances_along_curve.as_mutable_span().drop_front(1).copy_from(lengths);
|
||||||
|
|
||||||
|
MutableSpan<int> merge_indices = merge_indices_per_curve[curve_i].as_mutable_span();
|
||||||
|
array_utils::fill_index_range<int>(merge_indices);
|
||||||
|
|
||||||
|
const int duplicate_count = curve_merge_by_distance(points,
|
||||||
|
distances_along_curve,
|
||||||
|
selection.slice_content(points),
|
||||||
|
merge_distance,
|
||||||
|
merge_indices);
|
||||||
|
/* Write the curve size. The counts will be accumulated to offsets below. */
|
||||||
|
dst_offsets[curve_i] = points.size() - duplicate_count;
|
||||||
|
total_duplicate_count += duplicate_count;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const int dst_point_size = src_point_size - total_duplicate_count;
|
||||||
|
dst_curves.resize(dst_point_size, src_curves.curves_num());
|
||||||
|
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||||
|
|
||||||
|
int merged_points = 0;
|
||||||
|
Array<int> src_to_dst_indices(src_point_size);
|
||||||
|
for (const int curve_i : src_curves.curves_range()) {
|
||||||
|
const IndexRange points = points_by_curve[curve_i];
|
||||||
|
const Span<int> merge_indices = merge_indices_per_curve[curve_i].as_span();
|
||||||
|
for (const int i : points.index_range()) {
|
||||||
|
const int point_i = points.start() + i;
|
||||||
|
src_to_dst_indices[point_i] = point_i - merged_points;
|
||||||
|
if (merge_indices[i] != i) {
|
||||||
|
merged_points++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<int> point_merge_counts(dst_point_size, 0);
|
||||||
|
for (const int curve_i : src_curves.curves_range()) {
|
||||||
|
const IndexRange points = points_by_curve[curve_i];
|
||||||
|
const Span<int> merge_indices = merge_indices_per_curve[curve_i].as_span();
|
||||||
|
for (const int i : points.index_range()) {
|
||||||
|
const int merge_index = merge_indices[i];
|
||||||
|
const int point_src = points.start() + merge_index;
|
||||||
|
const int dst_index = src_to_dst_indices[point_src];
|
||||||
|
point_merge_counts[dst_index]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<int> map_offsets_data(dst_point_size + 1);
|
||||||
|
map_offsets_data.as_mutable_span().drop_back(1).copy_from(point_merge_counts);
|
||||||
|
OffsetIndices<int> map_offsets = offset_indices::accumulate_counts_to_offsets(map_offsets_data);
|
||||||
|
|
||||||
|
point_merge_counts.fill(0);
|
||||||
|
|
||||||
|
Array<int> merge_map_indices(src_point_size);
|
||||||
|
for (const int curve_i : src_curves.curves_range()) {
|
||||||
|
const IndexRange points = points_by_curve[curve_i];
|
||||||
|
const Span<int> merge_indices = merge_indices_per_curve[curve_i].as_span();
|
||||||
|
for (const int i : points.index_range()) {
|
||||||
|
const int point_i = points.start() + i;
|
||||||
|
const int merge_index = merge_indices[i];
|
||||||
|
const int dst_index = src_to_dst_indices[points.start() + merge_index];
|
||||||
|
merge_map_indices[map_offsets[dst_index].first() + point_merge_counts[dst_index]] = point_i;
|
||||||
|
point_merge_counts[dst_index]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bke::AttributeAccessor src_attributes = src_curves.attributes();
|
||||||
|
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||||
|
src_attributes.for_all([&](const bke::AttributeIDRef &id,
|
||||||
|
const bke::AttributeMetaData &meta_data) {
|
||||||
|
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (meta_data.domain != bke::AttrDomain::Point) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bke::GAttributeReader src_attribute = src_attributes.lookup(id);
|
||||||
|
bke::attribute_math::convert_to_static_type(src_attribute.varray.type(), [&](auto dummy) {
|
||||||
|
using T = decltype(dummy);
|
||||||
|
if constexpr (!std::is_void_v<bke::attribute_math::DefaultMixer<T>>) {
|
||||||
|
bke::SpanAttributeWriter<T> dst_attribute =
|
||||||
|
dst_attributes.lookup_or_add_for_write_only_span<T>(id, bke::AttrDomain::Point);
|
||||||
|
VArraySpan<T> src = src_attribute.varray.typed<T>();
|
||||||
|
|
||||||
|
threading::parallel_for(dst_curves.points_range(), 1024, [&](IndexRange range) {
|
||||||
|
for (const int dst_point_i : range) {
|
||||||
|
/* Create a separate mixer for every point to avoid allocating temporary buffers
|
||||||
|
* in the mixer the size of the result curves and to improve memory locality. */
|
||||||
|
bke::attribute_math::DefaultMixer<T> mixer{dst_attribute.span.slice(dst_point_i, 1)};
|
||||||
|
|
||||||
|
Span<int> src_merge_indices = merge_map_indices.as_span().slice(
|
||||||
|
map_offsets[dst_point_i]);
|
||||||
|
for (const int src_point_i : src_merge_indices) {
|
||||||
|
mixer.mix_in(0, src[src_point_i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mixer.finalize();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dst_attribute.finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return dst_curves;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void simplify_drawing(const GreasePencilSimplifyModifierData &mmd,
|
||||||
|
const Object &ob,
|
||||||
|
bke::greasepencil::Drawing &drawing)
|
||||||
|
{
|
||||||
|
IndexMaskMemory memory;
|
||||||
|
const bke::CurvesGeometry &curves = drawing.strokes();
|
||||||
|
const IndexMask strokes = modifier::greasepencil::get_filtered_stroke_mask(
|
||||||
|
&ob, curves, mmd.influence, memory);
|
||||||
|
if (strokes.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mmd.mode) {
|
||||||
|
case MOD_GREASE_PENCIL_SIMPLIFY_FIXED: {
|
||||||
|
const IndexMask points_to_keep = simplify_fixed(curves, mmd.step, memory);
|
||||||
|
drawing.strokes_for_write() = bke::curves_copy_point_selection(curves, points_to_keep, {});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MOD_GREASE_PENCIL_SIMPLIFY_ADAPTIVE: {
|
||||||
|
const IndexMask points_to_delete = geometry::simplify_curve_attribute(
|
||||||
|
curves.positions(),
|
||||||
|
strokes,
|
||||||
|
curves.points_by_curve(),
|
||||||
|
curves.cyclic(),
|
||||||
|
mmd.factor,
|
||||||
|
curves.positions(),
|
||||||
|
memory);
|
||||||
|
drawing.strokes_for_write().remove_points(points_to_delete, {});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MOD_GREASE_PENCIL_SIMPLIFY_SAMPLE: {
|
||||||
|
drawing.strokes_for_write() = geometry::resample_to_length(
|
||||||
|
curves, strokes, VArray<float>::ForSingle(mmd.length, curves.curves_num()), {});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MOD_GREASE_PENCIL_SIMPLIFY_MERGE: {
|
||||||
|
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||||
|
const Array<int> point_to_curve_map = curves.point_to_curve_map();
|
||||||
|
const IndexMask points = IndexMask::from_predicate(
|
||||||
|
curves.points_range(), GrainSize(2048), memory, [&](const int64_t i) {
|
||||||
|
const int curve_i = point_to_curve_map[i];
|
||||||
|
const IndexRange points = points_by_curve[curve_i];
|
||||||
|
if (points.drop_front(1).drop_back(1).contains(i)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
drawing.strokes_for_write() = curves_merge_by_distance(curves, mmd.distance, points, {});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawing.tag_topology_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void modify_geometry_set(ModifierData *md,
|
||||||
|
const ModifierEvalContext *ctx,
|
||||||
|
bke::GeometrySet *geometry_set)
|
||||||
|
{
|
||||||
|
const auto *mmd = reinterpret_cast<GreasePencilSimplifyModifierData *>(md);
|
||||||
|
|
||||||
|
if (!geometry_set->has_grease_pencil()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
|
||||||
|
const int current_frame = grease_pencil.runtime->eval_frame;
|
||||||
|
|
||||||
|
IndexMaskMemory mask_memory;
|
||||||
|
const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask(
|
||||||
|
grease_pencil, mmd->influence, mask_memory);
|
||||||
|
const Vector<bke::greasepencil::Drawing *> drawings =
|
||||||
|
modifier::greasepencil::get_drawings_for_write(grease_pencil, layer_mask, current_frame);
|
||||||
|
|
||||||
|
threading::parallel_for_each(drawings, [&](bke::greasepencil::Drawing *drawing) {
|
||||||
|
simplify_drawing(*mmd, *ctx->object, *drawing);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
|
||||||
|
{
|
||||||
|
auto *mmd = reinterpret_cast<GreasePencilSimplifyModifierData *>(md);
|
||||||
|
|
||||||
|
modifier::greasepencil::foreach_influence_ID_link(&mmd->influence, ob, walk, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void panel_draw(const bContext * /*C*/, Panel *panel)
|
||||||
|
{
|
||||||
|
uiLayout *layout = panel->layout;
|
||||||
|
|
||||||
|
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
|
||||||
|
|
||||||
|
int mode = RNA_enum_get(ptr, "mode");
|
||||||
|
|
||||||
|
uiLayoutSetPropSep(layout, true);
|
||||||
|
|
||||||
|
uiItemR(layout, ptr, "mode", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
|
||||||
|
if (mode == MOD_GREASE_PENCIL_SIMPLIFY_FIXED) {
|
||||||
|
uiItemR(layout, ptr, "step", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
}
|
||||||
|
else if (mode == MOD_GREASE_PENCIL_SIMPLIFY_ADAPTIVE) {
|
||||||
|
uiItemR(layout, ptr, "factor", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
}
|
||||||
|
else if (mode == MOD_GREASE_PENCIL_SIMPLIFY_SAMPLE) {
|
||||||
|
uiItemR(layout, ptr, "length", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
uiItemR(layout, ptr, "sharp_threshold", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
}
|
||||||
|
else if (mode == MOD_GREASE_PENCIL_SIMPLIFY_MERGE) {
|
||||||
|
uiItemR(layout, ptr, "distance", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier_panel_end(layout, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void panel_register(ARegionType *region_type)
|
||||||
|
{
|
||||||
|
modifier_panel_register(region_type, eModifierType_GreasePencilSimplify, panel_draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace blender
|
||||||
|
|
||||||
|
ModifierTypeInfo modifierType_GreasePencilSimplify = {
|
||||||
|
/*idname*/ "GreasePencilSimplifyModifier",
|
||||||
|
/*name*/ N_("Simplify"),
|
||||||
|
/*struct_name*/ "GreasePencilSimplifyModifierData",
|
||||||
|
/*struct_size*/ sizeof(GreasePencilSimplifyModifierData),
|
||||||
|
/*srna*/ &RNA_GreasePencilSimplifyModifier,
|
||||||
|
/*type*/ ModifierTypeType::Nonconstructive,
|
||||||
|
/*flags*/
|
||||||
|
eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_SupportsEditmode |
|
||||||
|
eModifierTypeFlag_EnableInEditmode,
|
||||||
|
/*icon*/ ICON_MOD_SIMPLIFY,
|
||||||
|
|
||||||
|
/*copy_data*/ blender::copy_data,
|
||||||
|
|
||||||
|
/*deform_verts*/ nullptr,
|
||||||
|
/*deform_matrices*/ nullptr,
|
||||||
|
/*deform_verts_EM*/ nullptr,
|
||||||
|
/*deform_matrices_EM*/ nullptr,
|
||||||
|
/*modify_mesh*/ nullptr,
|
||||||
|
/*modify_geometry_set*/ blender::modify_geometry_set,
|
||||||
|
|
||||||
|
/*init_data*/ blender::init_data,
|
||||||
|
/*required_data_mask*/ nullptr,
|
||||||
|
/*free_data*/ blender::free_data,
|
||||||
|
/*is_disabled*/ nullptr,
|
||||||
|
/*update_depsgraph*/ nullptr,
|
||||||
|
/*depends_on_time*/ nullptr,
|
||||||
|
/*depends_on_normals*/ nullptr,
|
||||||
|
/*foreach_ID_link*/ blender::foreach_ID_link,
|
||||||
|
/*foreach_tex_link*/ nullptr,
|
||||||
|
/*free_runtime_data*/ nullptr,
|
||||||
|
/*panel_register*/ blender::panel_register,
|
||||||
|
/*blend_write*/ blender::blend_write,
|
||||||
|
/*blend_read*/ blender::blend_read,
|
||||||
|
/*foreach_cache*/ nullptr,
|
||||||
|
};
|
|
@ -284,6 +284,7 @@ void modifier_type_init(ModifierTypeInfo *types[])
|
||||||
INIT_TYPE(GreasePencilLineart);
|
INIT_TYPE(GreasePencilLineart);
|
||||||
INIT_TYPE(GreasePencilArmature);
|
INIT_TYPE(GreasePencilArmature);
|
||||||
INIT_TYPE(GreasePencilTime);
|
INIT_TYPE(GreasePencilTime);
|
||||||
|
INIT_TYPE(GreasePencilSimplify);
|
||||||
INIT_TYPE(GreasePencilEnvelope);
|
INIT_TYPE(GreasePencilEnvelope);
|
||||||
INIT_TYPE(GreasePencilOutline);
|
INIT_TYPE(GreasePencilOutline);
|
||||||
INIT_TYPE(GreasePencilShrinkwrap);
|
INIT_TYPE(GreasePencilShrinkwrap);
|
||||||
|
|
|
@ -848,6 +848,28 @@ static void engine_render_view_layer(Render *re,
|
||||||
if (use_gpu_context) {
|
if (use_gpu_context) {
|
||||||
DRW_render_context_enable(engine->re);
|
DRW_render_context_enable(engine->re);
|
||||||
}
|
}
|
||||||
|
else if (engine->has_grease_pencil && use_grease_pencil && G.background) {
|
||||||
|
/* Workaround for specific NVidia drivers which crash on Linux when OptiX context is
|
||||||
|
* initialized prior to OpenGL context. This affects driver versions 545.29.06, 550.54.14,
|
||||||
|
* and 550.67 running on kernel 6.8.
|
||||||
|
*
|
||||||
|
* The idea here is to initialize GPU context before giving control to the render engine in
|
||||||
|
* cases when we know that the GPU context will definitely be needed later on.
|
||||||
|
*
|
||||||
|
* Only do it for background renders to avoid possible extra global locking during the
|
||||||
|
* context initialization. For the non-background renders the GPU context is already
|
||||||
|
* initialized for the Blender interface and no workaround is needed.
|
||||||
|
*
|
||||||
|
* Technically it is enough to only call WM_init_gpu() here, but it expects to only be called
|
||||||
|
* once, and from here it is not possible to know whether GPU sub-system is initialized or
|
||||||
|
* not. So instead temporarily enable the render context, which will take care of the GPU
|
||||||
|
* context initialization.
|
||||||
|
*
|
||||||
|
* For demo file and tracking progress of possible fixes on driver side refer to #120007. */
|
||||||
|
DRW_render_context_enable(engine->re);
|
||||||
|
DRW_render_context_disable(engine->re);
|
||||||
|
}
|
||||||
|
|
||||||
if (engine->type->update) {
|
if (engine->type->update) {
|
||||||
engine->type->update(engine, re->main, engine->depsgraph);
|
engine->type->update(engine, re->main, engine->depsgraph);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue