Files
test/tests/python/bl_pyapi_grease_pencil.py
Falk David ed3c16624b GPv3: High level python API
This extends the `GreasePencilDrawing` rna type using python.
The goal is to add an API that allows developers to transition to
the new grease pencil API a bit more smoothly.

Adds the following endpoints to the `GreasePencilDrawing`:
* `drawing.strokes`: Returns a list/slice of `GreasePencilStroke`s in the drawing.

Adds a python class `GreasePencilStroke`:
* `stroke.points`: Returns a list/slice of `GreasePencilStrokePoint`s.
* Getters/Setters of attributes for this stroke:
   * `stroke.cyclic`
   * `stroke.material_index`
   * `stroke.select`
   * `stroke.softness` (used to be `hardness`)
   * `stroke.start_cap`
   * `stroke.end_cap`
   * `stroke.curve_type`: The type of curve: `POLY`,`BEZIER`,`CATMULL_ROM`,`NURBS`.
   * `stroke.aspect_ratio`
   * `stroke.fill_opacity`
   * `stroke.fill_color`
   * `stroke.time_start`
* High-level functions:
   * `stroke.add_points(count)`: Adds `count` points at the end of the stroke.
  * `stroke.remove_points(count)`: Removes `count` points from the end of the stroke. Note that this will not remove the stroke if the count is greater than the number of points in the stroke. A stroke has at least 1 point. Removing strokes can be done from the drawing.

Adds a python class `GreasePencilStrokePoint`:
* Getters/Setters of attributes for this point:
   * `position`
   * `radius`
   * `opacity`
   * `select`
   * `vertex_color`
   * `rotation`
   * `delta_time`

Note that `GreasePencilStroke` and `GreasePencilStrokePoint` are not stored in the file and don't have an RNA API. This means that they are not compatible with e.g. `layout.prop`.

This API should not be used for performance critical code. It's likely
even slower than the python API from 4.2.

There will be migration documentation for addon developers here:
https://developer.blender.org/docs/release_notes/4.3/grease_pencil/#python-api-changes

Pull Request: https://projects.blender.org/blender/blender/pulls/125599
2024-08-15 10:58:21 +02:00

180 lines
6.9 KiB
Python

# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: Apache-2.0
# ./blender.bin --background --python tests/python/bl_pyapi_grease_pencil.py -- --verbose
import bpy
import unittest
# -----------------------------------------------------------------------------
# Tests
class TestGreasePencil(unittest.TestCase):
def setUp(self):
self.gp = bpy.data.grease_pencils_v3.new("test_grease_pencil")
def tearDown(self):
bpy.data.grease_pencils_v3.remove(self.gp)
del self.gp
def test_grease_pencil_new(self):
self.assertEqual(self.gp.name, "test_grease_pencil")
self.assertEqual(len(self.gp.layers), 0)
class TestGreasePencilLayers(unittest.TestCase):
def setUp(self):
self.gp = bpy.data.grease_pencils_v3.new("test_grease_pencil")
self.gp.layers.new("test_layer01")
self.gp.layers.new("test_layer02")
self.gp.layers.new("test_layer03")
def tearDown(self):
bpy.data.grease_pencils_v3.remove(self.gp)
del self.gp
def test_grease_pencil_layers_new(self):
self.assertEqual(len(self.gp.layers), 3)
# Test empty name
self.gp.layers.new("")
self.assertEqual(self.gp.layers[-1].name, "Layer")
self.gp.layers.new("")
self.assertEqual(self.gp.layers[-1].name, "Layer.001")
def test_grease_pencil_layers_rename(self):
self.gp.layers[0].name = "test"
self.assertEqual(self.gp.layers[0].name, "test")
self.gp.layers[0].name = ""
self.assertEqual(self.gp.layers[0].name, "Layer")
self.gp.layers[0].name = "test_layer02"
self.assertEqual(self.gp.layers[0].name, "test_layer02.001")
def test_grease_pencil_layers_remove(self):
self.gp.layers.remove(self.gp.layers[-1])
self.assertEqual(len(self.gp.layers), 2)
self.assertEqual(self.gp.layers[-1].name, "test_layer02")
def test_grease_pencil_layers_move_down(self):
# Move the top most layer down
self.gp.layers.move(self.gp.layers[-1], 'DOWN')
self.assertEqual(self.gp.layers[0].name, "test_layer01")
self.assertEqual(self.gp.layers[1].name, "test_layer03")
self.assertEqual(self.gp.layers[2].name, "test_layer02")
def test_grease_pencil_layers_move_up(self):
# Move the bottom most layer up
self.gp.layers.move(self.gp.layers[0], 'UP')
self.assertEqual(self.gp.layers[0].name, "test_layer02")
self.assertEqual(self.gp.layers[1].name, "test_layer01")
self.assertEqual(self.gp.layers[2].name, "test_layer03")
class TestGreasePencilDrawing(unittest.TestCase):
def setUp(self):
self.gp = bpy.data.grease_pencils_v3.new("test_grease_pencil")
layer = self.gp.layers.new("test_layer01")
frame = layer.frames.new(0)
self.drawing = frame.drawing
stroke_sizes = [3, 5, 7, 11]
self.drawing.add_strokes(stroke_sizes)
def tearDown(self):
bpy.data.grease_pencils_v3.remove(self.gp)
del self.gp
def test_grease_pencil_drawing_add_strokes(self):
self.assertEqual(len(self.drawing.strokes), 4)
self.assertEqual(len(self.drawing.strokes[0].points), 3)
self.assertEqual(len(self.drawing.strokes[1].points), 5)
self.assertEqual(len(self.drawing.strokes[2].points), 7)
self.assertEqual(len(self.drawing.strokes[3].points), 11)
def test_grease_pencil_drawing_remove_all_strokes(self):
self.drawing.remove_strokes()
self.assertIsNone(self.drawing.strokes)
def test_grease_pencil_drawing_remove_strokes(self):
self.drawing.remove_strokes(indices=[0, 2])
self.assertEqual(len(self.drawing.strokes), 2)
self.assertEqual(len(self.drawing.strokes[0].points), 5)
self.assertEqual(len(self.drawing.strokes[1].points), 11)
def test_grease_pencil_drawing_resize_strokes(self):
self.drawing.resize_strokes([20, 25, 15, 30])
self.assertEqual(len(self.drawing.strokes), 4)
self.assertEqual(len(self.drawing.strokes[0].points), 20)
self.assertEqual(len(self.drawing.strokes[1].points), 25)
self.assertEqual(len(self.drawing.strokes[2].points), 15)
self.assertEqual(len(self.drawing.strokes[3].points), 30)
self.drawing.resize_strokes([1, 2], indices=[0, 2])
self.assertEqual(len(self.drawing.strokes), 4)
self.assertEqual(len(self.drawing.strokes[0].points), 1)
self.assertEqual(len(self.drawing.strokes[1].points), 25)
self.assertEqual(len(self.drawing.strokes[2].points), 2)
self.assertEqual(len(self.drawing.strokes[3].points), 30)
def test_grease_pencil_drawing_strokes_slice(self):
self.assertEqual(len(self.drawing.strokes[:]), 4)
self.assertEqual(len(self.drawing.strokes[0:]), 4)
self.assertEqual(len(self.drawing.strokes[:4]), 4)
self.assertEqual(len(self.drawing.strokes[-4:]), 4)
self.assertEqual(len(self.drawing.strokes[:5]), 4)
self.assertEqual(len(self.drawing.strokes[-5:]), 4)
self.assertEqual(len(self.drawing.strokes[4:]), 0)
self.assertEqual(len(self.drawing.strokes[:0]), 0)
self.assertEqual(len(self.drawing.strokes[:-4]), 0)
strokes = self.drawing.strokes[1:]
self.assertEqual(len(strokes), 3)
self.assertEqual(len(strokes[0].points), 5)
self.assertEqual(len(strokes[1].points), 7)
self.assertEqual(len(strokes[2].points), 11)
strokes = self.drawing.strokes[:-1]
self.assertEqual(len(strokes), 3)
self.assertEqual(len(strokes[0].points), 3)
self.assertEqual(len(strokes[1].points), 5)
self.assertEqual(len(strokes[2].points), 7)
strokes = self.drawing.strokes[:1]
self.assertEqual(len(strokes), 1)
self.assertEqual(len(strokes[0].points), 3)
strokes = self.drawing.strokes[-1:]
self.assertEqual(len(strokes), 1)
self.assertEqual(len(strokes[0].points), 11)
strokes = self.drawing.strokes[1:-1]
self.assertEqual(len(strokes), 2)
self.assertEqual(len(strokes[0].points), 5)
self.assertEqual(len(strokes[1].points), 7)
strokes = self.drawing.strokes[1:][1:]
self.assertEqual(len(strokes), 2)
self.assertEqual(len(strokes[0].points), 7)
self.assertEqual(len(strokes[1].points), 11)
strokes = self.drawing.strokes[:-1][1:]
self.assertEqual(len(strokes), 2)
self.assertEqual(len(strokes[0].points), 5)
self.assertEqual(len(strokes[1].points), 7)
strokes = self.drawing.strokes[1:-1][1:]
self.assertEqual(len(strokes), 1)
self.assertEqual(len(strokes[0].points), 7)
strokes = self.drawing.strokes[1:-1][:-1]
self.assertEqual(len(strokes), 1)
self.assertEqual(len(strokes[0].points), 5)
if __name__ == '__main__':
import sys
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
unittest.main()