GPv3: Layer Parenting/Transforms #117247
|
@ -15,6 +15,17 @@ class DataButtonsPanel:
|
|||
return hasattr(context, "grease_pencil") and context.grease_pencil
|
||||
|
||||
|
||||
class LayerDataButtonsPanel:
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "data"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
grease_pencil = context.grease_pencil
|
||||
return grease_pencil and grease_pencil.layers.active
|
||||
|
||||
|
||||
class DATA_PT_context_grease_pencil(DataButtonsPanel, Panel):
|
||||
bl_label = ""
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
|
@ -67,13 +78,59 @@ class DATA_PT_grease_pencil_layers(DataButtonsPanel, Panel):
|
|||
layout.use_property_decorate = True
|
||||
col = layout.column(align=True)
|
||||
|
||||
col = layout.row(align=True)
|
||||
col.prop(layer, "opacity", text="Opacity", slider=True)
|
||||
row = layout.row(align=True)
|
||||
row.prop(layer, "opacity", text="Opacity", slider=True)
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_layer_transform(LayerDataButtonsPanel, Panel):
|
||||
bl_label = "Transform"
|
||||
bl_parent_id = "DATA_PT_grease_pencil_layers"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
grease_pencil = context.grease_pencil
|
||||
layer = grease_pencil.layers.active
|
||||
layout.active = not layer.lock
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(layer, "translation")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(layer, "rotation")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(layer, "scale")
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_layer_relations(LayerDataButtonsPanel, Panel):
|
||||
bl_label = "Relations"
|
||||
bl_parent_id = "DATA_PT_grease_pencil_layers"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
grease_pencil = context.grease_pencil
|
||||
layer = grease_pencil.layers.active
|
||||
layout.active = not layer.lock
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(layer, "parent", text="Parent")
|
||||
|
||||
if layer.parent and layer.parent.type == 'ARMATURE':
|
||||
row = layout.row(align=True)
|
||||
row.prop_search(layer, "parent_bone", layer.parent.data, "bones", text="Bone")
|
||||
|
||||
|
||||
classes = (
|
||||
DATA_PT_context_grease_pencil,
|
||||
DATA_PT_grease_pencil_layers,
|
||||
DATA_PT_grease_pencil_layer_transform,
|
||||
DATA_PT_grease_pencil_layer_relations,
|
||||
GREASE_PENCIL_MT_grease_pencil_add_layer_extra,
|
||||
)
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 0
|
||||
#define BLENDER_FILE_SUBVERSION 1
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
|
|
@ -34,14 +34,6 @@ namespace blender::bke {
|
|||
|
||||
namespace greasepencil {
|
||||
|
||||
struct DrawingTransforms {
|
||||
float4x4 world_space_to_layer_space;
|
||||
float4x4 layer_space_to_world_space;
|
||||
|
||||
DrawingTransforms() = default;
|
||||
DrawingTransforms(const Object &grease_pencil_ob);
|
||||
};
|
||||
|
||||
class DrawingRuntime {
|
||||
public:
|
||||
/**
|
||||
|
@ -447,6 +439,23 @@ class Layer : public ::GreasePencilLayer {
|
|||
*/
|
||||
void update_from_dna_read();
|
||||
|
||||
/**
|
||||
* Returns the transformation from layer space to object space.
|
||||
*/
|
||||
float4x4 to_object_space(const Object &object) const;
|
||||
|
||||
/**
|
||||
* Returns the transformation from layer space to world space.
|
||||
*/
|
||||
float4x4 to_world_space(const Object &object) const;
|
||||
|
||||
/**
|
||||
* Returns the name of the parent bone. Should only be used in case the parent object is an
|
||||
* armature.
|
||||
*/
|
||||
StringRefNull parent_bone_name() const;
|
||||
void set_parent_bone_name(const char *new_name);
|
||||
|
||||
private:
|
||||
using SortedKeysIterator = const int *;
|
||||
|
||||
|
@ -460,6 +469,16 @@ class Layer : public ::GreasePencilLayer {
|
|||
*/
|
||||
SortedKeysIterator remove_leading_null_frames_in_range(SortedKeysIterator begin,
|
||||
SortedKeysIterator end);
|
||||
|
||||
/**
|
||||
* The local transform of the layer (in layer space, not object space).
|
||||
*/
|
||||
float4x4 local_transform() const;
|
||||
|
||||
/**
|
||||
* Get the parent to world marix for this layer.
|
||||
*/
|
||||
float4x4 parent_to_world(const Object &parent) const;
|
||||
};
|
||||
|
||||
class LayerGroupRuntime {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_anim_data.h"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_customdata.hh"
|
||||
|
@ -25,8 +26,10 @@
|
|||
|
||||
#include "BLI_bounds.hh"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_euler_types.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_memory_utils.hh"
|
||||
|
@ -240,14 +243,6 @@ IDTypeInfo IDType_ID_GP = {
|
|||
|
||||
namespace blender::bke::greasepencil {
|
||||
|
||||
filedescriptor marked this conversation as resolved
Outdated
|
||||
DrawingTransforms::DrawingTransforms(const Object &grease_pencil_ob)
|
||||
{
|
||||
/* TODO: For now layer space = object space. This needs to change once the layers have a
|
||||
* transform. */
|
||||
this->layer_space_to_world_space = float4x4_view(grease_pencil_ob.object_to_world);
|
||||
this->world_space_to_layer_space = math::invert(this->layer_space_to_world_space);
|
||||
}
|
||||
|
||||
static const std::string ATTR_RADIUS = "radius";
|
||||
static const std::string ATTR_OPACITY = "opacity";
|
||||
static const std::string ATTR_VERTEX_COLOR = "vertex_color";
|
||||
|
@ -664,6 +659,13 @@ Layer::Layer()
|
|||
|
||||
this->opacity = 1.0f;
|
||||
|
||||
this->parent = nullptr;
|
||||
this->parsubstr = nullptr;
|
||||
|
||||
zero_v3(this->translation);
|
||||
zero_v3(this->rotation);
|
||||
copy_v3_fl(this->scale, 1.0f);
|
||||
|
||||
BLI_listbase_clear(&this->masks);
|
||||
|
||||
this->runtime = MEM_new<LayerRuntime>(__func__);
|
||||
|
@ -680,11 +682,18 @@ Layer::Layer(const Layer &other) : Layer()
|
|||
|
||||
/* TODO: duplicate masks. */
|
||||
|
||||
/* Note: We do not duplicate the frame storage since it is only needed for writing. */
|
||||
/* Note: We do not duplicate the frame storage since it is only needed for writing to file. */
|
||||
|
||||
this->blend_mode = other.blend_mode;
|
||||
this->opacity = other.opacity;
|
||||
|
||||
this->parent = other.parent;
|
||||
this->set_parent_bone_name(other.parsubstr);
|
||||
|
||||
copy_v3_v3(this->translation, other.translation);
|
||||
copy_v3_v3(this->rotation, other.rotation);
|
||||
copy_v3_v3(this->scale, other.scale);
|
||||
|
||||
this->runtime->frames_ = other.runtime->frames_;
|
||||
this->runtime->sorted_keys_cache_ = other.runtime->sorted_keys_cache_;
|
||||
/* TODO: what about masks cache? */
|
||||
|
@ -702,6 +711,8 @@ Layer::~Layer()
|
|||
MEM_freeN(mask);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(this->parsubstr);
|
||||
|
||||
MEM_delete(this->runtime);
|
||||
this->runtime = nullptr;
|
||||
}
|
||||
|
@ -946,6 +957,57 @@ void Layer::update_from_dna_read()
|
|||
}
|
||||
}
|
||||
|
||||
float4x4 Layer::to_world_space(const Object &object) const
|
||||
{
|
||||
if (this->parent == nullptr) {
|
||||
return float4x4(object.object_to_world) * this->local_transform();
|
||||
}
|
||||
const Object &parent = *this->parent;
|
||||
return this->parent_to_world(parent) * this->local_transform();
|
||||
}
|
||||
|
||||
float4x4 Layer::to_object_space(const Object &object) const
|
||||
{
|
||||
if (this->parent == nullptr) {
|
||||
return this->local_transform();
|
||||
}
|
||||
const Object &parent = *this->parent;
|
||||
return float4x4(object.world_to_object) * this->parent_to_world(parent) *
|
||||
this->local_transform();
|
||||
}
|
||||
|
||||
StringRefNull Layer::parent_bone_name() const
|
||||
{
|
||||
return (this->parsubstr != nullptr) ? StringRefNull(this->parsubstr) : StringRefNull();
|
||||
}
|
||||
|
||||
void Layer::set_parent_bone_name(const char *new_name)
|
||||
{
|
||||
if (this->parsubstr != nullptr) {
|
||||
MEM_freeN(this->parsubstr);
|
||||
}
|
||||
this->parsubstr = BLI_strdup_null(new_name);
|
||||
}
|
||||
|
||||
float4x4 Layer::parent_to_world(const Object &parent) const
|
||||
{
|
||||
const float4x4 parent_object_to_world(parent.object_to_world);
|
||||
if (parent.type == OB_ARMATURE && !this->parent_bone_name().is_empty()) {
|
||||
if (bPoseChannel *channel = BKE_pose_channel_find_name(parent.pose,
|
||||
this->parent_bone_name().c_str()))
|
||||
{
|
||||
return parent_object_to_world * float4x4_view(channel->pose_mat);
|
||||
}
|
||||
}
|
||||
return parent_object_to_world;
|
||||
}
|
||||
|
||||
float4x4 Layer::local_transform() const
|
||||
{
|
||||
return math::from_loc_rot_scale<float4x4, math::EulerXYZ>(
|
||||
float3(this->translation), float3(this->rotation), float3(this->scale));
|
||||
}
|
||||
|
||||
LayerGroup::LayerGroup()
|
||||
{
|
||||
new (&this->base) TreeNode(GP_LAYER_TREE_GROUP);
|
||||
|
|
|
@ -282,6 +282,13 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
|||
|
||||
new_layer.blend_mode = int8_t(gpl->blend_mode);
|
||||
|
||||
new_layer.parent = gpl->parent;
|
||||
new_layer.set_parent_bone_name(gpl->parsubstr);
|
||||
|
||||
copy_v3_v3(new_layer.translation, gpl->location);
|
||||
copy_v3_v3(new_layer.rotation, gpl->rotation);
|
||||
copy_v3_v3(new_layer.scale, gpl->scale);
|
||||
|
||||
/* Convert the layer masks. */
|
||||
LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
|
||||
LayerMask *new_mask = new LayerMask(mask->name);
|
||||
|
|
|
@ -2887,6 +2887,16 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 1)) {
|
||||
using namespace blender::bke::greasepencil;
|
||||
/* Initialize newly added scale layer transform to one. */
|
||||
LISTBASE_FOREACH (GreasePencil *, grease_pencil, &bmain->grease_pencils) {
|
||||
for (Layer *layer : grease_pencil->layers_for_write()) {
|
||||
copy_v3_fl(layer->scale, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
|
|
@ -973,9 +973,11 @@ void DepsgraphNodeBuilder::build_object_data(Object *object)
|
|||
case OB_CURVES:
|
||||
case OB_POINTCLOUD:
|
||||
case OB_VOLUME:
|
||||
case OB_GREASE_PENCIL:
|
||||
build_object_data_geometry(object);
|
||||
break;
|
||||
case OB_GREASE_PENCIL:
|
||||
build_object_data_grease_pencil(object);
|
||||
break;
|
||||
case OB_ARMATURE:
|
||||
build_rig(object);
|
||||
break;
|
||||
|
@ -1026,6 +1028,20 @@ void DepsgraphNodeBuilder::build_object_data_lightprobe(Object *object)
|
|||
add_operation_node(&object->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL);
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_object_data_grease_pencil(Object *object)
|
||||
{
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
/* Build the layer parents. */
|
||||
for (const bke::greasepencil::Layer *layer : grease_pencil.layers()) {
|
||||
Object *parent = layer->parent;
|
||||
if (parent == nullptr) {
|
||||
continue;
|
||||
}
|
||||
build_object(-1, parent, DEG_ID_LINKED_INDIRECTLY, false);
|
||||
}
|
||||
build_object_data_geometry(object);
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_object_data_speaker(Object *object)
|
||||
{
|
||||
Speaker *speaker = (Speaker *)object->data;
|
||||
|
|
|
@ -194,6 +194,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
|
|||
virtual void build_object_data_light(Object *object);
|
||||
virtual void build_object_data_lightprobe(Object *object);
|
||||
virtual void build_object_data_speaker(Object *object);
|
||||
virtual void build_object_data_grease_pencil(Object *object);
|
||||
virtual void build_object_transform(Object *object);
|
||||
virtual void build_object_constraints(Object *object);
|
||||
virtual void build_object_pointcache(Object *object);
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "BKE_effect.h"
|
||||
#include "BKE_fcurve_driver.h"
|
||||
#include "BKE_gpencil_modifier_legacy.h"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_key.hh"
|
||||
|
@ -2728,9 +2729,32 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
|
|||
break;
|
||||
}
|
||||
case ID_GP: {
|
||||
GreasePencil &grease_pencil = *reinterpret_cast<GreasePencil *>(obdata);
|
||||
|
||||
/* Update geometry when time is changed. */
|
||||
TimeSourceKey time_key;
|
||||
ComponentKey geometry_key(obdata, NodeType::GEOMETRY);
|
||||
ComponentKey geometry_key(&grease_pencil.id, NodeType::GEOMETRY);
|
||||
add_relation(time_key, geometry_key, "Grease Pencil Frame Change");
|
||||
|
||||
/* Add relations for layer parents. */
|
||||
for (const bke::greasepencil::Layer *layer : grease_pencil.layers()) {
|
||||
Object *parent = layer->parent;
|
||||
if (parent == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (parent->type == OB_ARMATURE && !layer->parent_bone_name().is_empty()) {
|
||||
ComponentKey bone_key(&parent->id, NodeType::BONE, layer->parent_bone_name().c_str());
|
||||
OperationKey armature_key(
|
||||
&parent->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL);
|
||||
|
||||
add_relation(bone_key, geometry_key, "Grease Pencil Layer Bone Parent");
|
||||
add_relation(armature_key, geometry_key, "Grease Pencil Layer Armature Parent");
|
||||
}
|
||||
else {
|
||||
ComponentKey transform_key(&parent->id, NodeType::TRANSFORM);
|
||||
add_relation(transform_key, geometry_key, "Grease Pencil Layer Object Parent");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -199,6 +199,16 @@ BLI_INLINE int32_t pack_rotation_aspect_hardness(float rot, float asp, float har
|
|||
return packed;
|
||||
}
|
||||
|
||||
static void copy_transformed_positions(const Span<float3> src_positions,
|
||||
const IndexRange range,
|
||||
const float4x4 &transform,
|
||||
MutableSpan<float3> dst_positions)
|
||||
{
|
||||
for (const int point_i : range) {
|
||||
dst_positions[point_i] = math::transform_point(transform, src_positions[point_i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void grease_pencil_edit_batch_ensure(Object &object,
|
||||
const GreasePencil &grease_pencil,
|
||||
const Scene &scene)
|
||||
|
@ -259,7 +269,8 @@ static void grease_pencil_edit_batch_ensure(Object &object,
|
|||
int total_line_ids_num = 0;
|
||||
int drawing_start_offset = 0;
|
||||
for (const ed::greasepencil::DrawingInfo &info : drawings) {
|
||||
const Layer *layer = layers[info.layer_index];
|
||||
const Layer &layer = *layers[info.layer_index];
|
||||
const float4x4 layer_space_to_object_space = layer.to_object_space(object);
|
||||
const bke::CurvesGeometry &curves = info.drawing.strokes();
|
||||
const bke::AttributeAccessor attributes = curves.attributes();
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
|
@ -272,11 +283,15 @@ static void grease_pencil_edit_batch_ensure(Object &object,
|
|||
const VArray<float> selection_float = *attributes.lookup_or_default<float>(
|
||||
".selection", bke::AttrDomain::Point, true);
|
||||
|
||||
edit_points.slice(drawing_start_offset, curves.points_num()).copy_from(curves.positions());
|
||||
MutableSpan<float> selection_slice = edit_points_selection.slice(drawing_start_offset,
|
||||
curves.points_num());
|
||||
const IndexRange points(drawing_start_offset, curves.points_num());
|
||||
const Span<float3> positions = curves.positions();
|
||||
MutableSpan<float3> positions_slice = edit_points.slice(points);
|
||||
threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange range) {
|
||||
copy_transformed_positions(positions, range, layer_space_to_object_space, positions_slice);
|
||||
});
|
||||
MutableSpan<float> selection_slice = edit_points_selection.slice(points);
|
||||
/* Do not show selection for locked layers. */
|
||||
if (layer->is_locked()) {
|
||||
if (layer.is_locked()) {
|
||||
selection_slice.fill(0.0f);
|
||||
}
|
||||
else {
|
||||
|
@ -296,7 +311,7 @@ static void grease_pencil_edit_batch_ensure(Object &object,
|
|||
total_line_ids_num += array_utils::count_booleans(curves.cyclic(), editable_strokes);
|
||||
|
||||
/* Do not show points for locked layers. */
|
||||
if (layer->is_locked()) {
|
||||
if (layer.is_locked()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -493,6 +508,8 @@ static void grease_pencil_geom_batch_ensure(Object &object,
|
|||
/* Fill buffers with data. */
|
||||
for (const int drawing_i : drawings.index_range()) {
|
||||
const ed::greasepencil::DrawingInfo &info = drawings[drawing_i];
|
||||
const Layer &layer = *grease_pencil.layers()[info.layer_index];
|
||||
const float4x4 layer_space_to_object_space = layer.to_object_space(object);
|
||||
const bke::CurvesGeometry &curves = info.drawing.strokes();
|
||||
const bke::AttributeAccessor attributes = curves.attributes();
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
|
@ -538,7 +555,8 @@ static void grease_pencil_geom_batch_ensure(Object &object,
|
|||
float length,
|
||||
GreasePencilStrokeVert &s_vert,
|
||||
GreasePencilColorVert &c_vert) {
|
||||
copy_v3_v3(s_vert.pos, positions[point_i]);
|
||||
copy_v3_v3(s_vert.pos,
|
||||
math::transform_point(layer_space_to_object_space, positions[point_i]));
|
||||
s_vert.radius = radii[point_i] * ((end_cap == GP_STROKE_CAP_TYPE_ROUND) ? 1.0f : -1.0f);
|
||||
s_vert.opacity = opacities[point_i] *
|
||||
((start_cap == GP_STROKE_CAP_TYPE_ROUND) ? 1.0f : -1.0f);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "BKE_context.hh"
|
||||
#include "BKE_deform.hh"
|
||||
#include "BKE_gpencil_modifier_legacy.h"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_modifier.hh"
|
||||
|
@ -336,6 +337,22 @@ void ED_armature_bone_rename(Main *bmain,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ob->type == OB_GREASE_PENCIL) {
|
||||
using namespace blender;
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
|
||||
for (bke::greasepencil::Layer *layer : grease_pencil.layers_for_write()) {
|
||||
Object *parent = layer->parent;
|
||||
if (parent == nullptr) {
|
||||
continue;
|
||||
}
|
||||
StringRefNull bone_name = layer->parent_bone_name();
|
||||
if (!bone_name.is_empty() && bone_name == StringRef(oldname)) {
|
||||
layer->set_parent_bone_name(newname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
|
||||
}
|
||||
|
||||
|
|
|
@ -525,16 +525,13 @@ void apply_selection_operation_at_index(GMutableSpan selection,
|
|||
|
||||
static std::optional<FindClosestData> find_closest_point_to_screen_co(
|
||||
const ARegion *region,
|
||||
const RegionView3D *rv3d,
|
||||
const Object &object,
|
||||
const Span<float3> positions,
|
||||
const float4x4 &projection,
|
||||
const IndexMask &points_mask,
|
||||
const float2 mouse_pos,
|
||||
float radius,
|
||||
const FindClosestData &initial_closest)
|
||||
{
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get(rv3d, &object);
|
||||
|
||||
const float radius_sq = pow2f(radius);
|
||||
const FindClosestData new_closest_data = threading::parallel_reduce(
|
||||
points_mask.index_range(),
|
||||
|
@ -581,17 +578,14 @@ static std::optional<FindClosestData> find_closest_point_to_screen_co(
|
|||
|
||||
static std::optional<FindClosestData> find_closest_curve_to_screen_co(
|
||||
const ARegion *region,
|
||||
const RegionView3D *rv3d,
|
||||
const Object &object,
|
||||
const OffsetIndices<int> points_by_curve,
|
||||
const Span<float3> positions,
|
||||
const float4x4 &projection,
|
||||
const IndexMask &curves_mask,
|
||||
const float2 mouse_pos,
|
||||
float radius,
|
||||
const FindClosestData &initial_closest)
|
||||
{
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get(rv3d, &object);
|
||||
|
||||
const float radius_sq = pow2f(radius);
|
||||
|
||||
const FindClosestData new_closest_data = threading::parallel_reduce(
|
||||
|
@ -667,9 +661,9 @@ static std::optional<FindClosestData> find_closest_curve_to_screen_co(
|
|||
|
||||
std::optional<FindClosestData> closest_elem_find_screen_space(
|
||||
const ViewContext &vc,
|
||||
const Object &object,
|
||||
const OffsetIndices<int> points_by_curve,
|
||||
const Span<float3> positions,
|
||||
const float4x4 &projection,
|
||||
const IndexMask &mask,
|
||||
const bke::AttrDomain domain,
|
||||
const int2 coord,
|
||||
|
@ -678,19 +672,17 @@ std::optional<FindClosestData> closest_elem_find_screen_space(
|
|||
switch (domain) {
|
||||
case bke::AttrDomain::Point:
|
||||
return find_closest_point_to_screen_co(vc.region,
|
||||
vc.rv3d,
|
||||
object,
|
||||
positions,
|
||||
projection,
|
||||
mask,
|
||||
float2(coord),
|
||||
ED_view3d_select_dist_px(),
|
||||
initial_closest);
|
||||
case bke::AttrDomain::Curve:
|
||||
return find_closest_curve_to_screen_co(vc.region,
|
||||
vc.rv3d,
|
||||
object,
|
||||
points_by_curve,
|
||||
positions,
|
||||
projection,
|
||||
mask,
|
||||
float2(coord),
|
||||
ED_view3d_select_dist_px(),
|
||||
|
@ -704,6 +696,7 @@ std::optional<FindClosestData> closest_elem_find_screen_space(
|
|||
bool select_box(const ViewContext &vc,
|
||||
bke::CurvesGeometry &curves,
|
||||
const Span<float3> positions,
|
||||
const float4x4 &projection,
|
||||
const IndexMask &mask,
|
||||
const bke::AttrDomain selection_domain,
|
||||
const rcti &rect,
|
||||
|
@ -718,8 +711,6 @@ bool select_box(const ViewContext &vc,
|
|||
changed = true;
|
||||
}
|
||||
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get(vc.rv3d, vc.obact);
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
if (selection_domain == bke::AttrDomain::Point) {
|
||||
mask.foreach_index(GrainSize(1024), [&](const int point_i) {
|
||||
|
@ -766,6 +757,7 @@ bool select_box(const ViewContext &vc,
|
|||
bool select_lasso(const ViewContext &vc,
|
||||
bke::CurvesGeometry &curves,
|
||||
const Span<float3> positions,
|
||||
const float4x4 &projection_matrix,
|
||||
const IndexMask &mask,
|
||||
const bke::AttrDomain selection_domain,
|
||||
const Span<int2> lasso_coords,
|
||||
filedescriptor marked this conversation as resolved
Hans Goudey
commented
Commit this name change separately too maybe? Commit this name change separately too maybe?
Falk David
commented
Sure :) Sure :)
|
||||
|
@ -784,13 +776,11 @@ bool select_lasso(const ViewContext &vc,
|
|||
changed = true;
|
||||
}
|
||||
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get(vc.rv3d, vc.obact);
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
if (selection_domain == bke::AttrDomain::Point) {
|
||||
mask.foreach_index(GrainSize(1024), [&](const int point_i) {
|
||||
const float2 pos_proj = ED_view3d_project_float_v2_m4(
|
||||
vc.region, positions[point_i], projection);
|
||||
vc.region, positions[point_i], projection_matrix);
|
||||
/* Check the lasso bounding box first as an optimization. */
|
||||
if (BLI_rcti_isect_pt_v(&bbox, int2(pos_proj)) &&
|
||||
BLI_lasso_is_point_inside(
|
||||
|
@ -806,7 +796,7 @@ bool select_lasso(const ViewContext &vc,
|
|||
const IndexRange points = points_by_curve[curve_i];
|
||||
if (points.size() == 1) {
|
||||
const float2 pos_proj = ED_view3d_project_float_v2_m4(
|
||||
vc.region, positions[points.first()], projection);
|
||||
vc.region, positions[points.first()], projection_matrix);
|
||||
/* Check the lasso bounding box first as an optimization. */
|
||||
if (BLI_rcti_isect_pt_v(&bbox, int2(pos_proj)) &&
|
||||
BLI_lasso_is_point_inside(
|
||||
|
@ -821,8 +811,8 @@ bool select_lasso(const ViewContext &vc,
|
|||
const float3 pos1 = positions[segment_i];
|
||||
const float3 pos2 = positions[segment_i + 1];
|
||||
|
||||
const float2 pos1_proj = ED_view3d_project_float_v2_m4(vc.region, pos1, projection);
|
||||
const float2 pos2_proj = ED_view3d_project_float_v2_m4(vc.region, pos2, projection);
|
||||
const float2 pos1_proj = ED_view3d_project_float_v2_m4(vc.region, pos1, projection_matrix);
|
||||
const float2 pos2_proj = ED_view3d_project_float_v2_m4(vc.region, pos2, projection_matrix);
|
||||
|
||||
/* Check the lasso bounding box first as an optimization. */
|
||||
if (BLI_rcti_isect_segment(&bbox, int2(pos1_proj), int2(pos2_proj)) &&
|
||||
|
@ -849,6 +839,7 @@ bool select_lasso(const ViewContext &vc,
|
|||
bool select_circle(const ViewContext &vc,
|
||||
bke::CurvesGeometry &curves,
|
||||
const Span<float3> positions,
|
||||
const float4x4 &projection,
|
||||
const IndexMask &mask,
|
||||
const bke::AttrDomain selection_domain,
|
||||
const int2 coord,
|
||||
|
@ -865,8 +856,6 @@ bool select_circle(const ViewContext &vc,
|
|||
changed = true;
|
||||
}
|
||||
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get(vc.rv3d, vc.obact);
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
if (selection_domain == bke::AttrDomain::Point) {
|
||||
mask.foreach_index(GrainSize(1024), [&](const int point_i) {
|
||||
|
|
|
@ -34,9 +34,12 @@ namespace blender::ed::greasepencil {
|
|||
DrawingPlacement::DrawingPlacement(const Scene &scene,
|
||||
const ARegion ®ion,
|
||||
const View3D &view3d,
|
||||
const Object &object)
|
||||
: region_(®ion), view3d_(&view3d), transforms_(object)
|
||||
const Object &eval_object,
|
||||
const bke::greasepencil::Layer &layer)
|
||||
: region_(®ion), view3d_(&view3d)
|
||||
{
|
||||
layer_space_to_world_space_ = layer.to_world_space(eval_object);
|
||||
world_space_to_layer_space_ = math::invert(layer_space_to_world_space_);
|
||||
/* Initialize DrawingPlacementPlane from toolsettings. */
|
||||
switch (scene.toolsettings->gp_sculpt.lock_axis) {
|
||||
case GP_LOCKAXIS_VIEW:
|
||||
|
@ -66,7 +69,7 @@ DrawingPlacement::DrawingPlacement(const Scene &scene,
|
|||
switch (scene.toolsettings->gpencil_v3d_align) {
|
||||
case GP_PROJECT_VIEWSPACE:
|
||||
depth_ = DrawingPlacementDepth::ObjectOrigin;
|
||||
placement_loc_ = transforms_.layer_space_to_world_space.location();
|
||||
placement_loc_ = layer_space_to_world_space_.location();
|
||||
break;
|
||||
case (GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR):
|
||||
depth_ = DrawingPlacementDepth::Cursor;
|
||||
|
@ -76,12 +79,12 @@ DrawingPlacement::DrawingPlacement(const Scene &scene,
|
|||
depth_ = DrawingPlacementDepth::Surface;
|
||||
surface_offset_ = scene.toolsettings->gpencil_surface_offset;
|
||||
/* Default to view placement with the object origin if we don't hit a surface. */
|
||||
placement_loc_ = transforms_.layer_space_to_world_space.location();
|
||||
placement_loc_ = layer_space_to_world_space_.location();
|
||||
break;
|
||||
case (GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_STROKE):
|
||||
depth_ = DrawingPlacementDepth::NearestStroke;
|
||||
/* Default to view placement with the object origin if we don't hit a stroke. */
|
||||
placement_loc_ = transforms_.layer_space_to_world_space.location();
|
||||
placement_loc_ = layer_space_to_world_space_.location();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -133,7 +136,7 @@ void DrawingPlacement::set_origin_to_nearest_stroke(const float2 co)
|
|||
}
|
||||
else {
|
||||
/* If nothing was hit, use origin. */
|
||||
placement_loc_ = transforms_.layer_space_to_world_space.location();
|
||||
placement_loc_ = layer_space_to_world_space_.location();
|
||||
}
|
||||
plane_from_point_normal_v3(placement_plane_, placement_loc_, placement_normal_);
|
||||
}
|
||||
|
@ -169,7 +172,7 @@ float3 DrawingPlacement::project(const float2 co) const
|
|||
ED_view3d_win_to_3d(view3d_, region_, placement_loc_, co, proj_point);
|
||||
}
|
||||
}
|
||||
return math::transform_point(transforms_.world_space_to_layer_space, proj_point);
|
||||
return math::transform_point(world_space_to_layer_space_, proj_point);
|
||||
}
|
||||
|
||||
void DrawingPlacement::project(const Span<float2> src, MutableSpan<float3> dst) const
|
||||
|
|
|
@ -239,9 +239,9 @@ struct FindClosestData {
|
|||
* \return A new point or curve closer than the \a initial input, if one exists.
|
||||
*/
|
||||
std::optional<FindClosestData> closest_elem_find_screen_space(const ViewContext &vc,
|
||||
const Object &object,
|
||||
OffsetIndices<int> points_by_curve,
|
||||
Span<float3> deformed_positions,
|
||||
const float4x4 &projection,
|
||||
const IndexMask &mask,
|
||||
bke::AttrDomain domain,
|
||||
int2 coord,
|
||||
|
@ -253,6 +253,7 @@ std::optional<FindClosestData> closest_elem_find_screen_space(const ViewContext
|
|||
bool select_box(const ViewContext &vc,
|
||||
bke::CurvesGeometry &curves,
|
||||
Span<float3> deformed_positions,
|
||||
const float4x4 &projection,
|
||||
const IndexMask &mask,
|
||||
bke::AttrDomain selection_domain,
|
||||
const rcti &rect,
|
||||
|
@ -264,9 +265,10 @@ bool select_box(const ViewContext &vc,
|
|||
bool select_lasso(const ViewContext &vc,
|
||||
bke::CurvesGeometry &curves,
|
||||
Span<float3> deformed_positions,
|
||||
const float4x4 &projection_matrix,
|
||||
filedescriptor marked this conversation as resolved
Outdated
Hans Goudey
commented
const reference (applies elsewhere in the PR too, I won't write it everywhere though) const reference (applies elsewhere in the PR too, I won't write it everywhere though)
|
||||
const IndexMask &mask,
|
||||
bke::AttrDomain selection_domain,
|
||||
Span<int2> coords,
|
||||
Span<int2> lasso_coords,
|
||||
eSelectOp sel_op);
|
||||
|
||||
/**
|
||||
|
@ -275,6 +277,7 @@ bool select_lasso(const ViewContext &vc,
|
|||
bool select_circle(const ViewContext &vc,
|
||||
bke::CurvesGeometry &curves,
|
||||
Span<float3> deformed_positions,
|
||||
const float4x4 &projection,
|
||||
const IndexMask &mask,
|
||||
bke::AttrDomain selection_domain,
|
||||
int2 coord,
|
||||
|
|
|
@ -70,7 +70,6 @@ class DrawingPlacement {
|
|||
|
||||
DrawingPlacementDepth depth_;
|
||||
DrawingPlacementPlane plane_;
|
||||
bke::greasepencil::DrawingTransforms transforms_;
|
||||
ViewDepths *depth_cache_ = nullptr;
|
||||
float surface_offset_;
|
||||
|
||||
|
@ -78,12 +77,16 @@ class DrawingPlacement {
|
|||
float3 placement_normal_;
|
||||
float4 placement_plane_;
|
||||
|
||||
float4x4 layer_space_to_world_space_;
|
||||
float4x4 world_space_to_layer_space_;
|
||||
|
||||
public:
|
||||
DrawingPlacement() = default;
|
||||
DrawingPlacement(const Scene &scene,
|
||||
const ARegion ®ion,
|
||||
const View3D &view3d,
|
||||
const Object &object);
|
||||
const Object &eval_object,
|
||||
const bke::greasepencil::Layer &layer);
|
||||
~DrawingPlacement();
|
||||
|
||||
public:
|
||||
|
|
|
@ -61,13 +61,7 @@ struct EraseOperationExecutor {
|
|||
int2 mouse_position_pixels{};
|
||||
int64_t eraser_squared_radius_pixels{};
|
||||
|
||||
bke::greasepencil::DrawingTransforms transforms_;
|
||||
|
||||
EraseOperationExecutor(const bContext &C)
|
||||
{
|
||||
Object *object = CTX_data_active_object(&C);
|
||||
transforms_ = bke::greasepencil::DrawingTransforms(*object);
|
||||
}
|
||||
EraseOperationExecutor(const bContext & /*C*/) {}
|
||||
|
||||
/**
|
||||
* Computes the intersections between a 2D line segment and a circle with integer values.
|
||||
|
@ -759,50 +753,51 @@ struct EraseOperationExecutor {
|
|||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(obact->data);
|
||||
|
||||
bool changed = false;
|
||||
const auto execute_eraser_on_drawing =
|
||||
[&](const int layer_index, const int frame_number, Drawing &drawing) {
|
||||
const bke::CurvesGeometry &src = drawing.strokes();
|
||||
const auto execute_eraser_on_drawing = [&](const int layer_index,
|
||||
const int frame_number,
|
||||
Drawing &drawing) {
|
||||
const Layer &layer = *grease_pencil.layers()[layer_index];
|
||||
const bke::CurvesGeometry &src = drawing.strokes();
|
||||
|
||||
/* Evaluated geometry. */
|
||||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
|
||||
ob_eval, *obact, layer_index, frame_number);
|
||||
/* Evaluated geometry. */
|
||||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
|
||||
ob_eval, *obact, layer_index, frame_number);
|
||||
|
||||
/* Compute screen space positions. */
|
||||
Array<float2> screen_space_positions(src.points_num());
|
||||
threading::parallel_for(src.points_range(), 4096, [&](const IndexRange src_points) {
|
||||
for (const int src_point : src_points) {
|
||||
ED_view3d_project_float_global(
|
||||
region,
|
||||
math::transform_point(transforms_.layer_space_to_world_space,
|
||||
deformation.positions[src_point]),
|
||||
screen_space_positions[src_point],
|
||||
V3D_PROJ_TEST_NOP);
|
||||
}
|
||||
});
|
||||
/* Compute screen space positions. */
|
||||
Array<float2> screen_space_positions(src.points_num());
|
||||
threading::parallel_for(src.points_range(), 4096, [&](const IndexRange src_points) {
|
||||
for (const int src_point : src_points) {
|
||||
ED_view3d_project_float_global(region,
|
||||
math::transform_point(layer.to_world_space(*ob_eval),
|
||||
deformation.positions[src_point]),
|
||||
screen_space_positions[src_point],
|
||||
V3D_PROJ_TEST_NOP);
|
||||
}
|
||||
});
|
||||
|
||||
/* Erasing operator. */
|
||||
bke::CurvesGeometry dst;
|
||||
bool erased = false;
|
||||
switch (self.eraser_mode) {
|
||||
case GP_BRUSH_ERASER_STROKE:
|
||||
erased = stroke_eraser(src, screen_space_positions, dst);
|
||||
break;
|
||||
case GP_BRUSH_ERASER_HARD:
|
||||
erased = hard_eraser(src, screen_space_positions, dst, self.keep_caps);
|
||||
break;
|
||||
case GP_BRUSH_ERASER_SOFT:
|
||||
// To be implemented
|
||||
return;
|
||||
}
|
||||
/* Erasing operator. */
|
||||
bke::CurvesGeometry dst;
|
||||
bool erased = false;
|
||||
switch (self.eraser_mode) {
|
||||
case GP_BRUSH_ERASER_STROKE:
|
||||
erased = stroke_eraser(src, screen_space_positions, dst);
|
||||
break;
|
||||
case GP_BRUSH_ERASER_HARD:
|
||||
erased = hard_eraser(src, screen_space_positions, dst, self.keep_caps);
|
||||
break;
|
||||
case GP_BRUSH_ERASER_SOFT:
|
||||
// To be implemented
|
||||
return;
|
||||
}
|
||||
|
||||
if (erased) {
|
||||
/* Set the new geometry. */
|
||||
drawing.geometry.wrap() = std::move(dst);
|
||||
drawing.tag_topology_changed();
|
||||
changed = true;
|
||||
}
|
||||
};
|
||||
if (erased) {
|
||||
/* Set the new geometry. */
|
||||
drawing.geometry.wrap() = std::move(dst);
|
||||
drawing.tag_topology_changed();
|
||||
changed = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (self.active_layer_only) {
|
||||
/* Erase only on the drawing at the current frame of the active layer. */
|
||||
|
|
|
@ -424,10 +424,12 @@ struct PaintOperationExecutor {
|
|||
|
||||
void PaintOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(&C);
|
||||
ARegion *region = CTX_wm_region(&C);
|
||||
View3D *view3d = CTX_wm_view3d(&C);
|
||||
Scene *scene = CTX_data_scene(&C);
|
||||
Object *object = CTX_data_active_object(&C);
|
||||
Object *eval_object = DEG_get_evaluated_object(depsgraph, object);
|
||||
GreasePencil *grease_pencil = static_cast<GreasePencil *>(object->data);
|
||||
|
||||
Paint *paint = &scene->toolsettings->gp_paint->paint;
|
||||
|
@ -444,7 +446,8 @@ void PaintOperation::on_stroke_begin(const bContext &C, const InputSample &start
|
|||
BKE_curvemapping_init(brush->gpencil_settings->curve_rand_value);
|
||||
|
||||
/* Initialize helper class for projecting screen space coordinates. */
|
||||
placement_ = ed::greasepencil::DrawingPlacement(*scene, *region, *view3d, *object);
|
||||
placement_ = ed::greasepencil::DrawingPlacement(
|
||||
*scene, *region, *view3d, *eval_object, *grease_pencil->get_active_layer());
|
||||
if (placement_.use_project_to_surface()) {
|
||||
placement_.cache_viewport_depths(CTX_data_depsgraph_pointer(&C), region, view3d);
|
||||
}
|
||||
|
|
|
@ -1197,6 +1197,7 @@ static bool do_lasso_select_grease_pencil(ViewContext *vc,
|
|||
const Array<ed::greasepencil::MutableDrawingInfo> drawings =
|
||||
ed::greasepencil::retrieve_editable_drawings(*vc->scene, grease_pencil);
|
||||
for (const ed::greasepencil::MutableDrawingInfo info : drawings) {
|
||||
const bke::greasepencil::Layer &layer = *grease_pencil.layers()[info.layer_index];
|
||||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
|
||||
ob_eval, *vc->obedit, info.layer_index, info.frame_number);
|
||||
|
@ -1207,10 +1208,13 @@ static bool do_lasso_select_grease_pencil(ViewContext *vc,
|
|||
if (elements.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
const float4x4 layer_to_world = layer.to_world_space(*ob_eval);
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get_from_obmat(vc->rv3d, layer_to_world);
|
||||
changed = ed::curves::select_lasso(
|
||||
*vc,
|
||||
info.drawing.strokes_for_write(),
|
||||
deformation.positions,
|
||||
projection,
|
||||
elements,
|
||||
selection_domain,
|
||||
Span<int2>(reinterpret_cast<const int2 *>(mcoords), mcoords_len),
|
||||
|
@ -1432,10 +1436,12 @@ static bool view3d_lasso_select(bContext *C,
|
|||
bke::crazyspace::get_evaluated_curves_deformation(*vc->depsgraph, *vc->obedit);
|
||||
const bke::AttrDomain selection_domain = bke::AttrDomain(curves_id.selection_domain);
|
||||
const IndexRange elements(curves.attributes().domain_size(selection_domain));
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get(vc->rv3d, vc->obedit);
|
||||
changed = ed::curves::select_lasso(
|
||||
*vc,
|
||||
curves,
|
||||
deformation.positions,
|
||||
projection,
|
||||
elements,
|
||||
selection_domain,
|
||||
Span<int2>(reinterpret_cast<const int2 *>(mcoords), mcoords_len),
|
||||
|
@ -3109,12 +3115,13 @@ static bool ed_curves_select_pick(bContext &C, const int mval[2], const SelectPi
|
|||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*vc.depsgraph, *vc.obedit);
|
||||
const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get(vc.rv3d, &curves_ob);
|
||||
const IndexRange elements(curves.attributes().domain_size(selection_domain));
|
||||
std::optional<ed::curves::FindClosestData> new_closest_elem =
|
||||
ed::curves::closest_elem_find_screen_space(vc,
|
||||
curves_ob,
|
||||
curves.points_by_curve(),
|
||||
deformation.positions,
|
||||
projection,
|
||||
elements,
|
||||
selection_domain,
|
||||
mval,
|
||||
|
@ -3208,6 +3215,7 @@ static bool ed_grease_pencil_select_pick(bContext *C,
|
|||
ClosestGreasePencilDrawing new_closest = init;
|
||||
for (const int i : range) {
|
||||
ed::greasepencil::MutableDrawingInfo info = drawings[i];
|
||||
const bke::greasepencil::Layer &layer = *grease_pencil.layers()[info.layer_index];
|
||||
/* Get deformation by modifiers. */
|
||||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
|
||||
|
@ -3219,11 +3227,14 @@ static bool ed_grease_pencil_select_pick(bContext *C,
|
|||
if (elements.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
const float4x4 layer_to_world = layer.to_world_space(*ob_eval);
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get_from_obmat(vc.rv3d,
|
||||
layer_to_world);
|
||||
std::optional<ed::curves::FindClosestData> new_closest_elem =
|
||||
ed::curves::closest_elem_find_screen_space(vc,
|
||||
*vc.obedit,
|
||||
info.drawing.strokes().points_by_curve(),
|
||||
deformation.positions,
|
||||
projection,
|
||||
elements,
|
||||
selection_domain,
|
||||
mval,
|
||||
|
@ -4216,6 +4227,7 @@ static bool do_grease_pencil_box_select(ViewContext *vc, const rcti *rect, const
|
|||
const Array<ed::greasepencil::MutableDrawingInfo> drawings =
|
||||
ed::greasepencil::retrieve_editable_drawings(*scene, grease_pencil);
|
||||
for (const ed::greasepencil::MutableDrawingInfo info : drawings) {
|
||||
const bke::greasepencil::Layer &layer = *grease_pencil.layers()[info.layer_index];
|
||||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
|
||||
ob_eval, *vc->obedit, info.layer_index, info.frame_number);
|
||||
|
@ -4225,9 +4237,12 @@ static bool do_grease_pencil_box_select(ViewContext *vc, const rcti *rect, const
|
|||
if (elements.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
const float4x4 layer_to_world = layer.to_world_space(*ob_eval);
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get_from_obmat(vc->rv3d, layer_to_world);
|
||||
changed |= ed::curves::select_box(*vc,
|
||||
info.drawing.strokes_for_write(),
|
||||
deformation.positions,
|
||||
projection,
|
||||
elements,
|
||||
selection_domain,
|
||||
*rect,
|
||||
|
@ -4313,9 +4328,16 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
|
|||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*vc.depsgraph, *vc.obedit);
|
||||
const bke::AttrDomain selection_domain = bke::AttrDomain(curves_id.selection_domain);
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get(vc.rv3d, vc.obedit);
|
||||
const IndexRange elements(curves.attributes().domain_size(selection_domain));
|
||||
changed = ed::curves::select_box(
|
||||
vc, curves, deformation.positions, elements, selection_domain, rect, sel_op);
|
||||
changed = ed::curves::select_box(vc,
|
||||
curves,
|
||||
deformation.positions,
|
||||
projection,
|
||||
elements,
|
||||
selection_domain,
|
||||
rect,
|
||||
sel_op);
|
||||
if (changed) {
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
|
||||
* generic attribute for now. */
|
||||
|
@ -5070,6 +5092,7 @@ static bool grease_pencil_circle_select(ViewContext *vc,
|
|||
const Array<ed::greasepencil::MutableDrawingInfo> drawings =
|
||||
ed::greasepencil::retrieve_editable_drawings(*vc->scene, grease_pencil);
|
||||
for (const ed::greasepencil::MutableDrawingInfo info : drawings) {
|
||||
const bke::greasepencil::Layer &layer = *grease_pencil.layers()[info.layer_index];
|
||||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
|
||||
ob_eval, *vc->obedit, info.layer_index, info.frame_number);
|
||||
|
@ -5079,9 +5102,12 @@ static bool grease_pencil_circle_select(ViewContext *vc,
|
|||
if (elements.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
const float4x4 layer_to_world = layer.to_world_space(*ob_eval);
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get_from_obmat(vc->rv3d, layer_to_world);
|
||||
changed = ed::curves::select_circle(*vc,
|
||||
info.drawing.strokes_for_write(),
|
||||
deformation.positions,
|
||||
projection,
|
||||
elements,
|
||||
selection_domain,
|
||||
int2(mval),
|
||||
|
@ -5138,9 +5164,17 @@ static bool obedit_circle_select(bContext *C,
|
|||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*vc->depsgraph, *vc->obedit);
|
||||
const bke::AttrDomain selection_domain = bke::AttrDomain(curves_id.selection_domain);
|
||||
const float4x4 projection = ED_view3d_ob_project_mat_get(vc->rv3d, vc->obedit);
|
||||
const IndexRange elements(curves.attributes().domain_size(selection_domain));
|
||||
changed = ed::curves::select_circle(
|
||||
*vc, curves, deformation.positions, elements, selection_domain, mval, rad, sel_op);
|
||||
changed = ed::curves::select_circle(*vc,
|
||||
curves,
|
||||
deformation.positions,
|
||||
projection,
|
||||
elements,
|
||||
selection_domain,
|
||||
mval,
|
||||
rad,
|
||||
sel_op);
|
||||
if (changed) {
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
|
||||
* generic attribute for now. */
|
||||
|
|
|
@ -117,6 +117,7 @@ void animrecord_check_state(TransInfo *t, ID *id);
|
|||
*/
|
||||
void curve_populate_trans_data_structs(TransDataContainer &tc,
|
||||
blender::bke::CurvesGeometry &curves,
|
||||
const blender::float4x4 &matrix,
|
||||
std::optional<blender::MutableSpan<float>> value_attribute,
|
||||
const blender::IndexMask &selected_indices,
|
||||
bool use_proportional_edit,
|
||||
|
|
|
@ -95,7 +95,8 @@ static void createTransCurvesVerts(bContext * /*C*/, TransInfo *t)
|
|||
if (tc.data_len == 0) {
|
||||
continue;
|
||||
}
|
||||
Curves *curves_id = static_cast<Curves *>(tc.obedit->data);
|
||||
Object *object = tc.obedit;
|
||||
Curves *curves_id = static_cast<Curves *>(object->data);
|
||||
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
|
||||
std::optional<MutableSpan<float>> value_attribute;
|
||||
|
@ -117,6 +118,7 @@ static void createTransCurvesVerts(bContext * /*C*/, TransInfo *t)
|
|||
|
||||
curve_populate_trans_data_structs(tc,
|
||||
curves,
|
||||
float4x4(object->object_to_world),
|
||||
value_attribute,
|
||||
selection_per_object[i],
|
||||
use_proportional_edit,
|
||||
|
@ -153,9 +155,10 @@ static void recalcData_curves(TransInfo *t)
|
|||
|
||||
void curve_populate_trans_data_structs(TransDataContainer &tc,
|
||||
blender::bke::CurvesGeometry &curves,
|
||||
const blender::float4x4 &transform,
|
||||
filedescriptor marked this conversation as resolved
Outdated
Hans Goudey
commented
`matrix` -> `transform`
|
||||
std::optional<blender::MutableSpan<float>> value_attribute,
|
||||
const blender::IndexMask &selected_indices,
|
||||
bool use_proportional_edit,
|
||||
const bool use_proportional_edit,
|
||||
const blender::IndexMask &affected_curves,
|
||||
bool use_connected_only,
|
||||
int trans_data_offset)
|
||||
|
@ -163,7 +166,7 @@ void curve_populate_trans_data_structs(TransDataContainer &tc,
|
|||
using namespace blender;
|
||||
|
||||
float mtx[3][3], smtx[3][3];
|
||||
copy_m3_m4(mtx, tc.obedit->object_to_world);
|
||||
copy_m3_m4(mtx, transform.ptr());
|
||||
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
|
||||
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include "BKE_context.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "ED_curves.hh"
|
||||
#include "ED_grease_pencil.hh"
|
||||
|
||||
|
@ -24,6 +26,7 @@ namespace blender::ed::transform::greasepencil {
|
|||
|
||||
static void createTransGreasePencilVerts(bContext *C, TransInfo *t)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *object = CTX_data_active_object(C);
|
||||
MutableSpan<TransDataContainer> trans_data_contrainers(t->data_container, t->data_container_len);
|
||||
|
@ -81,15 +84,15 @@ static void createTransGreasePencilVerts(bContext *C, TransInfo *t)
|
|||
if (tc.data_len == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float mtx[3][3], smtx[3][3];
|
||||
copy_m3_m4(mtx, tc.obedit->object_to_world);
|
||||
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
|
||||
Object *object_eval = DEG_get_evaluated_object(depsgraph, tc.obedit);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object_eval->data);
|
||||
Span<const bke::greasepencil::Layer *> layers = grease_pencil.layers();
|
||||
|
||||
int layer_points_offset = 0;
|
||||
|
||||
const Array<ed::greasepencil::MutableDrawingInfo> drawings = all_drawings[i];
|
||||
for (ed::greasepencil::MutableDrawingInfo info : drawings) {
|
||||
const bke::greasepencil::Layer &layer = *layers[info.layer_index];
|
||||
const float4x4 layer_space_to_world_space = layer.to_world_space(*object_eval);
|
||||
bke::CurvesGeometry &curves = info.drawing.strokes_for_write();
|
||||
const IndexMask points = points_per_layer_per_object[layer_offset];
|
||||
|
||||
|
@ -108,6 +111,7 @@ static void createTransGreasePencilVerts(bContext *C, TransInfo *t)
|
|||
*object, info.drawing, memory);
|
||||
curve_populate_trans_data_structs(tc,
|
||||
curves,
|
||||
layer_space_to_world_space,
|
||||
value_attribute,
|
||||
points,
|
||||
true,
|
||||
|
@ -118,6 +122,7 @@ static void createTransGreasePencilVerts(bContext *C, TransInfo *t)
|
|||
else {
|
||||
curve_populate_trans_data_structs(tc,
|
||||
curves,
|
||||
layer_space_to_world_space,
|
||||
value_attribute,
|
||||
points,
|
||||
false,
|
||||
|
|
|
@ -292,6 +292,17 @@ typedef struct GreasePencilLayer {
|
|||
* List of `GreasePencilLayerMask`.
|
||||
*/
|
||||
ListBase masks;
|
||||
/**
|
||||
* Layer parent object. Can be an armature in which case the `parsubstr` is the bone name.
|
||||
*/
|
||||
struct Object *parent;
|
||||
char *parsubstr;
|
||||
filedescriptor marked this conversation as resolved
Outdated
Hans Goudey
commented
How about using How about using `char *` to take up less space when it isn't used? (and to simplify assignment, etc.)
|
||||
/**
|
||||
* Layer transform UI settings. These should *not* be used to do any computation.
|
||||
* Use the functions is the `bke::greasepencil::Layer` class instead.
|
||||
*/
|
||||
float translation[3], rotation[3], scale[3];
|
||||
char _pad2[4];
|
||||
/**
|
||||
* Runtime struct pointer.
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
# include "BLI_span.hh"
|
||||
|
||||
# include "DEG_depsgraph.hh"
|
||||
# include "DEG_depsgraph_build.hh"
|
||||
|
||||
static GreasePencil *rna_grease_pencil(const PointerRNA *ptr)
|
||||
{
|
||||
|
@ -36,7 +37,14 @@ static GreasePencil *rna_grease_pencil(const PointerRNA *ptr)
|
|||
static void rna_grease_pencil_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr)
|
||||
{
|
||||
DEG_id_tag_update(&rna_grease_pencil(ptr)->id, ID_RECALC_GEOMETRY);
|
||||
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, nullptr);
|
||||
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, rna_grease_pencil(ptr));
|
||||
}
|
||||
|
||||
static void rna_grease_pencil_dependency_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr)
|
||||
filedescriptor marked this conversation as resolved
Brecht Van Lommel
commented
This should be This should be `ID_RECALC_GEOMETRY`, since here the transform is getting applied to the geometry. `ID_RECALC_TRANSFORM` is for when the object matrix is affected.
|
||||
{
|
||||
DEG_id_tag_update(&rna_grease_pencil(ptr)->id, ID_RECALC_GEOMETRY);
|
||||
filedescriptor marked this conversation as resolved
Outdated
Brecht Van Lommel
commented
Same here, this doesn't seem like the appropriate modifier if the mechanism is different. Probably Same here, this doesn't seem like the appropriate modifier if the mechanism is different. Probably `NC_GPENCIL | NA_EDITED` is better.
|
||||
DEG_relations_tag_update(bmain);
|
||||
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, rna_grease_pencil(ptr));
|
||||
}
|
||||
|
||||
static void rna_iterator_grease_pencil_layers_begin(CollectionPropertyIterator *iter,
|
||||
|
@ -181,6 +189,8 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
|||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
const float scale_defaults[3] = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
srna = RNA_def_struct(brna, "GreasePencilLayer", nullptr);
|
||||
RNA_def_struct_sdna(srna, "GreasePencilLayer");
|
||||
RNA_def_struct_ui_text(srna, "Grease Pencil Layer", "Collection of related drawings");
|
||||
|
@ -226,6 +236,41 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(
|
||||
prop, "Onion Skinning", "Display onion skins before and after the current frame");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Object");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
|
||||
RNA_def_property_ui_text(prop, "Parent", "Parent object");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_dependency_update");
|
||||
|
||||
prop = RNA_def_property(srna, "parent_bone", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, nullptr, "parsubstr");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Parent Bone", "Name of parent bone. Only used when the parent object is an armature");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_dependency_update");
|
||||
|
||||
prop = RNA_def_property(srna, "translation", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "translation");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_ui_text(prop, "Translation", "Translation of the layer");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "rotation");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_ui_text(prop, "Rotation", "Euler rotation of the layer");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "scale");
|
||||
RNA_def_property_float_array_default(prop, scale_defaults);
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
|
||||
RNA_def_property_ui_text(prop, "Scale", "Scale of the layer");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
|
|
Loading…
Reference in New Issue
Are these changes still necessary? Seems this isn't used