GPv3: Python API #116043

Open
opened 2023-12-11 16:01:32 +01:00 by Falk David · 1 comment
Member

The python API for grease pencil needs to be ported to the new data-structure.

We're expecting to break compatibility with the current API.

Instead of trying to replicate the old API exactly, we should focus on covering all the functionality. This means that some endpoints might change the way they are named, the way they are used, etc. but generally the same functionality should be archivable (with a bit of translation).

Changes to the data-structure

  • object.data.layers can stay exactly the same. We define a collection that lists the layers from bottom-most to top-most
  • layer.frames can also stay the same, but...
  • A GreasePencilFrame should have a property drawing that points to the GreasePencilDrawing. A frame no longer contains a list of strokes.
  • A GreasePencilDrawing has a type ('DRAWING' or 'REFERENCE'?) . This is the struct that cointains the geometry.
  • Iterating over the strokes should be replaced by a CurveSlice iterator similar to what is done in rna_def_curves_curve.
  • We can do something similar for points.
  • Iterating over the strokes is done using a collection property strokes of type Stroke
    • This Stroke property has two int properties: start and end. They are the offset indices into the data arrays.
    • Example:
    # Print the positions by strokes
    drawing_positions = drawing.positions
    for i, stroke in enumerate(drawing.strokes):
        stroke_positions = drawing_positions[stroke.start:stroke.end]
        print(i, stroke_positions)
    
  • It might be good to have properties for num_points and num_strokes since calling len(...) is a bit expensive.
  • Generally, functions should do their work over all elements rather than just affecting a single element. E.g. strokes.new currently creates one stroke at a time.
  • Issue of getting access to a Drawing in rna functions:
    • Sometimes it is necessary to get access to a parent struct to query some data. In RNA this is currently not possible. A PointerRNA only knows about the data it points to and the ID that the data is owned by. This means that in practice we have to do a search to find the parent.
    • In case of the Drawing and some substructure inside it, this may look something like this:
    static Drawing* find_drawing_from_pointer(PointerRNA *ptr)
    {
      GreasePencil *grease_pencil = rna_grease_pencil(ptr);
      for (GreasePencilDrawingBase *base : grease_pencil->drawings()) {
        if (base->type != GP_DRAWING) {
          continue;
        }
        Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
        if (find_data_in_drawing(drawing, ptr->data)) {
          return &drawing;
        }
      }
      return nullptr;
    }
    
    • Note that for e.g. reading/writing attribute data on a drawing, it should be possible to only do the search once, e.g. to retrieve the attribure as a python object. Then the user can iterate and manipulate elements inside the attribute, without triggering the search above again.

Tasks

Complete list of Grease Pencil Python API endpoints

Object data API:

Status Name Type Parameters Description Notes
after_color prop
before_color prop
clear function
curve_edit_corner_angle prop
curve_edit_threshold prop
edit_curve_resolution prop
edit_line_color prop
ghost_after_range prop
ghost_before_range prop
grid prop
is_annotation prop
is_stroke_paint_mode prop
is_stroke_sculpt_mode prop
is_stroke_vertex_mode prop
is_stroke_weight_mode prop
layers collection A collection of layers. The first element in the collection is the bottom-most layer in the layer stack.
materials collection
onion_factor prop
onion_keyframe_type prop
onion_mode prop
pixel_factor prop
stroke_depth_order prop
stroke_thickness_space prop
use_adaptive_curve_resolution prop
use_autolock_layers prop
use_curve_edit prop
use_ghost_custom_colors prop
use_ghosts_always prop
use_multiedit prop
use_onion_fade prop
use_onion_loop prop
use_onion_skinning prop
use_stroke_edit_mode prop
zdepth_offset prop

Grid API:

Status Name Type Parameters Description Notes
color prop The Grid API should be moved to the overlay settings.
lines prop "
offset prop "
scale prop "

Layers (Collection) API:

Status Name Type Parameters Description Notes
active_index prop
active_note prop
active prop The active layer. None if there is no active layer.
move function
new function
remove function

Layer API:

Status Name Type Parameters Description Notes
active_frame prop
annotation_hide prop
annotation_onion_after_color prop
annotation_onion_after_range prop
annotation_onion_before_color prop
annotation_onion_before_range prop
annotation_opacity prop
blend_mode prop
channel_color prop
clear function
color prop
frames collection
hide prop
info prop
is_parented prop
is_ruler prop
line_change prop
location prop
lock prop
lock_frame prop
lock_material prop
mask_layers collection
matrix_inverse prop
matrix_inverse_layer prop
matrix_layer prop
opacity prop
parent prop
parent_bone prop
parent_type prop
pass_index prop
rna_type prop
rotation prop
scale prop
select prop
show_in_front prop
show_points prop
thickness prop
tint_color prop
tint_factor prop
use_annotation_onion_skinning prop
use_lights prop
use_mask_layer prop
use_onion_skinning prop
use_solo_mode prop
use_viewlayer_masks prop
vertex_paint_opacity prop
viewlayer_render prop

Frames (Collection) API:

Status Name Type Parameters Description Notes
active prop
copy function
new function
remove function

Masks (Collection) API:

Status Name Type Parameters Description Notes
active_mask_index prop
add function
remove function

Frame API:

Status Name Type Parameters Description Notes
clear function
frame_number prop
is_edited prop
keyframe_type prop
select prop
strokes collection This needs to be replaced by a GreasePencilDrawing

Mask API:

Status Name Type Parameters Description Notes
hide prop
invert prop
name prop

Strokes (Collection) API:

Status Name Type Parameters Description Notes
close function
new function
remove function

Stroke API:

Status Name Type Parameters Description Notes
aspect prop
bound_box_max prop
bound_box_min prop
display_mode prop
edit_curve prop
end_cap_mode prop
hardness prop
has_edit_curve prop
is_nofill_stroke prop
line_width prop
material_index prop
points collection
select_index prop
select prop
start_cap_mode prop
time_start prop
triangles collection
use_cyclic prop
uv_rotation prop
uv_scale prop
uv_translation prop
vertex_color_fill prop

Points (Collection) API:

Status Name Type Parameters Description Notes
add function
pop function
update function
weight_get function
weight_set function

Triangle API:

Status Name Type Parameters Description Notes
v1 prop
v2 prop
v3 prop

Point API:

Status Name Type Parameters Description Notes
co prop
pressure prop
select prop
strength prop
time prop
uv_factor prop
uv_fill prop
uv_rotation prop
vertex_color prop

Edit Curve API:

Status Name Type Parameters Description Notes
curve_points collection
select prop

Edit Curve Point API:

Status Name Type Parameters Description Notes
co prop
handle_left prop
handle_right prop
hide prop
point_index prop
pressure prop
select_control_point prop
select_left_handle prop
select_right_handle prop
strength prop
uv_factor prop
uv_rotation prop
vertex_color prop
The python API for grease pencil needs to be ported to the new data-structure. We're expecting to **break compatibility** with the current API. Instead of trying to replicate the old API exactly, we should focus on covering all the functionality. This means that some endpoints might change the way they are named, the way they are used, etc. but generally the same functionality should be archivable (with a bit of translation). ## Changes to the data-structure * `object.data.layers` can stay exactly the same. We define a collection that lists the layers from bottom-most to top-most * `layer.frames` can also stay the same, but... * A `GreasePencilFrame` should have a property `drawing` that points to the `GreasePencilDrawing`. A frame no longer contains a list of `strokes`. * A `GreasePencilDrawing` has a type (`'DRAWING'` or `'REFERENCE'`?) . This is the struct that cointains the geometry. * ~~Iterating over the strokes should be replaced by a `CurveSlice` iterator similar to what is done in `rna_def_curves_curve`.~~ * ~~We can do something similar for `points`.~~ * Iterating over the strokes is done using a collection property `strokes` of type `Stroke` * This `Stroke` property has two `int` properties: `start` and `end`. They are the offset indices into the data arrays. * Example: ```py # Print the positions by strokes drawing_positions = drawing.positions for i, stroke in enumerate(drawing.strokes): stroke_positions = drawing_positions[stroke.start:stroke.end] print(i, stroke_positions) ``` * It might be good to have properties for `num_points` and `num_strokes` since calling `len(...)` is a bit expensive. * Generally, functions should do their work over all elements rather than just affecting a single element. E.g. `strokes.new` currently creates one stroke at a time. * Issue of getting access to a `Drawing` in rna functions: * Sometimes it is necessary to get access to a parent struct to query some data. In RNA this is currently not possible. A `PointerRNA` only knows about the `data` it points to and the `ID` that the `data` is owned by. This means that in practice we have to do a search to find the `parent`. * In case of the `Drawing` and some substructure inside it, this may look something like this: ```cpp static Drawing* find_drawing_from_pointer(PointerRNA *ptr) { GreasePencil *grease_pencil = rna_grease_pencil(ptr); for (GreasePencilDrawingBase *base : grease_pencil->drawings()) { if (base->type != GP_DRAWING) { continue; } Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap(); if (find_data_in_drawing(drawing, ptr->data)) { return &drawing; } } return nullptr; } ``` * Note that for e.g. reading/writing attribute data on a drawing, it should be possible to only do the search once, e.g. to retrieve the attribure as a python object. Then the user can iterate and manipulate elements inside the attribute, without triggering the search above again. ## Tasks - [ ] [#116045: GPv3: Python API: GreasePencilFrame](https://projects.blender.org/blender/blender/issues/116045) ## Complete list of Grease Pencil Python API endpoints ### Object data API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `after_color` | `prop` | | | | | <input type="checkbox" /> | `before_color` | `prop` | | | | | <input type="checkbox" /> | `clear` | `function` | | | | | <input type="checkbox" /> | `curve_edit_corner_angle` | `prop` | | | | | <input type="checkbox" /> | `curve_edit_threshold` | `prop` | | | | | <input type="checkbox" /> | `edit_curve_resolution` | `prop` | | | | | <input type="checkbox" /> | `edit_line_color` | `prop` | | | | | <input type="checkbox" /> | `ghost_after_range` | `prop` | | | | | <input type="checkbox" /> | `ghost_before_range` | `prop` | | | | | <input type="checkbox" /> | `grid` | `prop` | | | | | <input type="checkbox" /> | `is_annotation` | `prop` | | | | | <input type="checkbox" /> | `is_stroke_paint_mode` | `prop` | | | | | <input type="checkbox" /> | `is_stroke_sculpt_mode` | `prop` | | | | | <input type="checkbox" /> | `is_stroke_vertex_mode` | `prop` | | | | | <input type="checkbox" /> | `is_stroke_weight_mode` | `prop` | | | | | <input type="checkbox" checked/> | `layers` | `collection` | | A collection of layers. The first element in the collection is the bottom-most layer in the layer stack. | | | <input type="checkbox" /> | `materials` | `collection` | | | | | <input type="checkbox" /> | `onion_factor` | `prop` | | | | | <input type="checkbox" /> | `onion_keyframe_type` | `prop` | | | | | <input type="checkbox" /> | `onion_mode` | `prop` | | | | | <input type="checkbox" /> | `pixel_factor` | `prop` | | | | | <input type="checkbox" /> | `stroke_depth_order` | `prop` | | | | | <input type="checkbox" /> | `stroke_thickness_space` | `prop` | | | | | <input type="checkbox" /> | `use_adaptive_curve_resolution` | `prop` | | | | | <input type="checkbox" /> | `use_autolock_layers` | `prop` | | | | | <input type="checkbox" /> | `use_curve_edit` | `prop` | | | | | <input type="checkbox" /> | `use_ghost_custom_colors` | `prop` | | | | | <input type="checkbox" /> | `use_ghosts_always` | `prop` | | | | | <input type="checkbox" /> | `use_multiedit` | `prop` | | | | | <input type="checkbox" /> | `use_onion_fade` | `prop` | | | | | <input type="checkbox" /> | `use_onion_loop` | `prop` | | | | | <input type="checkbox" /> | `use_onion_skinning` | `prop` | | | | | <input type="checkbox" /> | `use_stroke_edit_mode` | `prop` | | | | | <input type="checkbox" /> | `zdepth_offset` | `prop` | | | | ### Grid API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `color` | `prop` | | | The `Grid` API should be moved to the overlay settings. | | <input type="checkbox" /> | `lines` | `prop` | | |" | | <input type="checkbox" /> | `offset` | `prop` | | | "| | <input type="checkbox" /> | `scale` | `prop` | | |" | ### Layers (Collection) API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `active_index` | `prop` | | | | | <input type="checkbox" /> | `active_note` | `prop` | | | | | <input type="checkbox" checked/> | `active` | `prop` | | The active layer. `None` if there is no active layer. | | | <input type="checkbox" /> | `move` | `function` | | | | | <input type="checkbox" /> | `new` | `function` | | | | | <input type="checkbox" /> | `remove` | `function` | | | | ### Layer API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `active_frame` | `prop` | | | | | <input type="checkbox" /> | `annotation_hide` | `prop` | | | | | <input type="checkbox" /> | `annotation_onion_after_color` | `prop` | | | | | <input type="checkbox" /> | `annotation_onion_after_range` | `prop` | | | | | <input type="checkbox" /> | `annotation_onion_before_color` | `prop` | | | | | <input type="checkbox" /> | `annotation_onion_before_range` | `prop` | | | | | <input type="checkbox" /> | `annotation_opacity` | `prop` | | | | | <input type="checkbox" /> | `blend_mode` | `prop` | | | | | <input type="checkbox" /> | `channel_color` | `prop` | | | | | <input type="checkbox" /> | `clear` | `function` | | | | | <input type="checkbox" /> | `color` | `prop` | | | | | <input type="checkbox" /> | `frames` | `collection` | | | | | <input type="checkbox" /> | `hide` | `prop` | | | | | <input type="checkbox" /> | `info` | `prop` | | | | | <input type="checkbox" /> | `is_parented` | `prop` | | | | | <input type="checkbox" /> | `is_ruler` | `prop` | | | | | <input type="checkbox" /> | `line_change` | `prop` | | | | | <input type="checkbox" /> | `location` | `prop` | | | | | <input type="checkbox" /> | `lock` | `prop` | | | | | <input type="checkbox" /> | `lock_frame` | `prop` | | | | | <input type="checkbox" /> | `lock_material` | `prop` | | | | | <input type="checkbox" /> | `mask_layers` | `collection` | | | | | <input type="checkbox" /> | `matrix_inverse` | `prop` | | | | | <input type="checkbox" /> | `matrix_inverse_layer` | `prop` | | | | | <input type="checkbox" /> | `matrix_layer` | `prop` | | | | | <input type="checkbox" /> | `opacity` | `prop` | | | | | <input type="checkbox" /> | `parent` | `prop` | | | | | <input type="checkbox" /> | `parent_bone` | `prop` | | | | | <input type="checkbox" /> | `parent_type` | `prop` | | | | | <input type="checkbox" /> | `pass_index` | `prop` | | | | | <input type="checkbox" /> | `rna_type` | `prop` | | | | | <input type="checkbox" /> | `rotation` | `prop` | | | | | <input type="checkbox" /> | `scale` | `prop` | | | | | <input type="checkbox" /> | `select` | `prop` | | | | | <input type="checkbox" /> | `show_in_front` | `prop` | | | | | <input type="checkbox" /> | `show_points` | `prop` | | | | | <input type="checkbox" /> | `thickness` | `prop` | | | | | <input type="checkbox" /> | `tint_color` | `prop` | | | | | <input type="checkbox" /> | `tint_factor` | `prop` | | | | | <input type="checkbox" /> | `use_annotation_onion_skinning` | `prop` | | | | | <input type="checkbox" /> | `use_lights` | `prop` | | | | | <input type="checkbox" /> | `use_mask_layer` | `prop` | | | | | <input type="checkbox" /> | `use_onion_skinning` | `prop` | | | | | <input type="checkbox" /> | `use_solo_mode` | `prop` | | | | | <input type="checkbox" /> | `use_viewlayer_masks` | `prop` | | | | | <input type="checkbox" /> | `vertex_paint_opacity` | `prop` | | | | | <input type="checkbox" /> | `viewlayer_render` | `prop` | | | | ### Frames (Collection) API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `active` | `prop` | | | | | <input type="checkbox" /> | `copy` | `function` | | | | | <input type="checkbox" /> | `new` | `function` | | | | | <input type="checkbox" /> | `remove` | `function` | | | | ### Masks (Collection) API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `active_mask_index` | `prop` | | | | | <input type="checkbox" /> | `add` | `function` | | | | | <input type="checkbox" /> | `remove` | `function` | | | | ### Frame API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `clear` | `function` | | | | | <input type="checkbox" /> | `frame_number` | `prop` | | | | | <input type="checkbox" /> | `is_edited` | `prop` | | | | | <input type="checkbox" /> | `keyframe_type` | `prop` | | | | | <input type="checkbox" /> | `select` | `prop` | | | | | <input type="checkbox" /> | `strokes` | `collection` | | | This needs to be replaced by a `GreasePencilDrawing` | ### Mask API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `hide` | `prop` | | | | | <input type="checkbox" /> | `invert` | `prop` | | | | | <input type="checkbox" /> | `name` | `prop` | | | | ### Strokes (Collection) API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `close` | `function` | | | | | <input type="checkbox" /> | `new` | `function` | | | | | <input type="checkbox" /> | `remove` | `function` | | | | ### Stroke API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `aspect` | `prop` | | | | | <input type="checkbox" /> | `bound_box_max` | `prop` | | | | | <input type="checkbox" /> | `bound_box_min` | `prop` | | | | | <input type="checkbox" /> | `display_mode` | `prop` | | | | | <input type="checkbox" /> | `edit_curve` | `prop` | | | | | <input type="checkbox" /> | `end_cap_mode` | `prop` | | | | | <input type="checkbox" /> | `hardness` | `prop` | | | | | <input type="checkbox" /> | `has_edit_curve` | `prop` | | | | | <input type="checkbox" /> | `is_nofill_stroke` | `prop` | | | | | <input type="checkbox" /> | `line_width` | `prop` | | | | | <input type="checkbox" /> | `material_index` | `prop` | | | | | <input type="checkbox" /> | `points` | `collection` | | | | | <input type="checkbox" /> | `select_index` | `prop` | | | | | <input type="checkbox" /> | `select` | `prop` | | | | | <input type="checkbox" /> | `start_cap_mode` | `prop` | | | | | <input type="checkbox" /> | `time_start` | `prop` | | | | | <input type="checkbox" /> | `triangles` | `collection` | | | | | <input type="checkbox" /> | `use_cyclic` | `prop` | | | | | <input type="checkbox" /> | `uv_rotation` | `prop` | | | | | <input type="checkbox" /> | `uv_scale` | `prop` | | | | | <input type="checkbox" /> | `uv_translation` | `prop` | | | | | <input type="checkbox" /> | `vertex_color_fill` | `prop` | | | | ### Points (Collection) API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `add` | `function` | | | | | <input type="checkbox" /> | `pop` | `function` | | | | | <input type="checkbox" /> | `update` | `function` | | | | | <input type="checkbox" /> | `weight_get` | `function` | | | | | <input type="checkbox" /> | `weight_set` | `function` | | | | ### Triangle API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `v1` | `prop` | | | | | <input type="checkbox" /> | `v2` | `prop` | | | | | <input type="checkbox" /> | `v3` | `prop` | | | | ### Point API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `co` | `prop` | | | | | <input type="checkbox" /> | `pressure` | `prop` | | | | | <input type="checkbox" /> | `select` | `prop` | | | | | <input type="checkbox" /> | `strength` | `prop` | | | | | <input type="checkbox" /> | `time` | `prop` | | | | | <input type="checkbox" /> | `uv_factor` | `prop` | | | | | <input type="checkbox" /> | `uv_fill` | `prop` | | | | | <input type="checkbox" /> | `uv_rotation` | `prop` | | | | | <input type="checkbox" /> | `vertex_color` | `prop` | | | | ### Edit Curve API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `curve_points` | `collection` | | | | | <input type="checkbox" /> | `select` | `prop` | | | | ### Edit Curve Point API: | Status | Name | Type | Parameters | Description | Notes | |---|---|---|---|---|---| | <input type="checkbox" /> | `co` | `prop` | | | | | <input type="checkbox" /> | `handle_left` | `prop` | | | | | <input type="checkbox" /> | `handle_right` | `prop` | | | | | <input type="checkbox" /> | `hide` | `prop` | | | | | <input type="checkbox" /> | `point_index` | `prop` | | | | | <input type="checkbox" /> | `pressure` | `prop` | | | | | <input type="checkbox" /> | `select_control_point` | `prop` | | | | | <input type="checkbox" /> | `select_left_handle` | `prop` | | | | | <input type="checkbox" /> | `select_right_handle` | `prop` | | | | | <input type="checkbox" /> | `strength` | `prop` | | | | | <input type="checkbox" /> | `uv_factor` | `prop` | | | | | <input type="checkbox" /> | `uv_rotation` | `prop` | | | | | <input type="checkbox" /> | `vertex_color` | `prop` | | | |
Falk David added the
Type
To Do
label 2023-12-11 16:01:32 +01:00
Falk David added this to the Grease Pencil project 2023-12-11 16:01:34 +01:00
Member

I worked on a first draft for the Frame and Drawing API: #121407: WIP: GPv3: RNA for frame, drawing, stroke and point.
We have to decide how we expose the curves geometry data in the API. As I see it, there are two options.


Proposal: Keep close to GPv2, define drawing.strokes and drawing.strokes[].points

Python object structure:

  • frame = layer.frames[index]
  • drawing = frame.drawing
  • stroke = drawing.strokes[index]
  • point = stroke.points[index]

Properties of stroke:
index, num_points, use_cyclic, select, start_cap_mode, end_cap_mode, hardness, aspect_ratio, fill_color, material_index, init_time

Properties of point:
position, radius, opacity, vertex_color, rotation, select, delta_time

Properties of stroke and point can be get/set in bulk: e.g. drawing.strokes.foreach_get("material_index", array) or drawing.strokes[0].points.foreach_set("opacity", array).

Pros:

  • Data structure is easy comprehensible for addon developers, since it resembles the structure in GPv2.
  • Existing addons have to be adapted, but not rewritten from scratch due to a different data structure.
  • The concepts are pythonic: a stroke is a stroke, not secretly an index, a point.radius is a float value, not an attribute object in a radii collection.
  • Developers don't have to juggle with things like OffsetIndices and IndexMask.

Cons:

  • Batch operations on all points in a drawing are not possible.
  • Always traversing strokes to be able to access points might be slower for some use cases.
  • Needs a little workaround in RNA, with a small memory cost.

Alternative: Define all attributes on drawing, use stroke and point indices

Python object structure:

  • frame = layer.frames[index]
  • drawing = frame.drawing
  • drawing.strokes[stroke_index] or drawing.stroke_points[stroke_index]: gives the start and end point index per stroke
  • drawing.fill_colors[stroke_index] for the fill color of strokes
  • drawing.vertex_colors[point_index] for the vertex color of stroke points
  • drawing.radii[index]
  • etc...
  • drawing.positions[point_index].vector for getting a point position
  • drawing.radii[point_index].value for getting a point radius

Stroke and point attributes can be get/set in bulk: e.g. drawing.positions.foreach_get("vector", array) or drawing.hardnesses.foreach_set("value", array).

Pros:

  • Resembles the internal C++ data structure, so fast and easy to maintain.
  • Direct access to point attributes.

Cons:

  • Data structure is quite different from GPv2, massive rewrites of addons are necessary.
  • The concept is less pythonic: working with indices pointing to a member of an attribute collection is less direct than accessing the attribute itself.
  • Developers must know the attribute domain by heart. fill_colors is in the curve domain, vertex_colors is in the point domain. Or the domain can be part of the attribute name, stroke_fill_colors, but that's pretty verbose.
  • A RNA limitation: collection properties, like drawing.radii[], always return an object, not a straight value. So you have to write drawing.radii[0].value = ... instead of drawing.radii[0] = .... Which becomes annoying pretty quickly.

I have my preference, but it is clearly something to discuss thoroughly at a meeting.

I worked on a first draft for the Frame and Drawing API: [#121407: WIP: GPv3: RNA for frame, drawing, stroke and point](https://projects.blender.org/blender/blender/pulls/121407). We have to decide how we expose the curves geometry data in the API. As I see it, there are two options. --- ### Proposal: Keep close to GPv2, define `drawing.strokes` and `drawing.strokes[].points` Python object structure: - `frame = layer.frames[index]` - `drawing = frame.drawing` - `stroke = drawing.strokes[index]` - `point = stroke.points[index]` Properties of `stroke`: `index`, `num_points`, `use_cyclic`, `select`, `start_cap_mode`, `end_cap_mode`, `hardness`, `aspect_ratio`, `fill_color`, `material_index`, `init_time` Properties of `point`: `position`, `radius`, `opacity`, `vertex_color`, `rotation`, `select`, `delta_time` Properties of stroke and point can be get/set in bulk: e.g. `drawing.strokes.foreach_get("material_index", array)` or `drawing.strokes[0].points.foreach_set("opacity", array)`. **Pros:** - Data structure is easy comprehensible for addon developers, since it resembles the structure in GPv2. - Existing addons have to be adapted, but not rewritten from scratch due to a different data structure. - The concepts are _pythonic_: a `stroke` is a stroke, not secretly an index, a `point.radius` is a float value, not an attribute object in a `radii` collection. - Developers don't have to juggle with things like OffsetIndices and IndexMask. **Cons:** - Batch operations on all points in a drawing are not possible. - Always traversing strokes to be able to access points might be slower for some use cases. - Needs a little workaround in RNA, with a small memory cost. --- ### Alternative: Define all attributes on `drawing`, use stroke and point indices Python object structure: - `frame = layer.frames[index]` - `drawing = frame.drawing` - `drawing.strokes[stroke_index]` or `drawing.stroke_points[stroke_index]`: gives the `start` and `end` point _index_ per stroke - `drawing.fill_colors[stroke_index]` for the fill color of strokes - `drawing.vertex_colors[point_index]` for the vertex color of stroke points - `drawing.radii[index]` - etc... - `drawing.positions[point_index].vector` for getting a point position - `drawing.radii[point_index].value` for getting a point radius Stroke and point attributes can be get/set in bulk: e.g. `drawing.positions.foreach_get("vector", array)` or `drawing.hardnesses.foreach_set("value", array)`. **Pros:** - Resembles the internal C++ data structure, so fast and easy to maintain. - Direct access to point attributes. **Cons:** - Data structure is quite different from GPv2, massive rewrites of addons are necessary. - The concept is less _pythonic_: working with indices pointing to a member of an attribute collection is less direct than accessing the attribute itself. - Developers must know the attribute domain by heart. `fill_colors` is in the curve domain, `vertex_colors` is in the point domain. Or the domain can be part of the attribute name, `stroke_fill_colors`, but that's pretty verbose. - A RNA limitation: collection properties, like `drawing.radii[]`, always return an _object_, not a straight value. So you have to write `drawing.radii[0].value = ...` instead of `drawing.radii[0] = ...`. Which becomes annoying pretty quickly. --- I have my preference, but it is clearly something to discuss thoroughly at a meeting.
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#116043
No description provided.