mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 07:51:47 +00:00
Bonsai: add viewport decorator base helpers
Add two helpers to tool.Blender that 17+ existing viewport decorators re-implement byte-identically: - ViewportDecorator.draw_batch(shader_type, content_pos, color, indices=None) collapses the validate + batch_for_shader + uniform_float + draw cycle every shader-driven decorator needs. - Blender.transparent_color(color, alpha=0.1) is the RGBA-alpha-override helper duplicated across nest, project, aggregate, model, system module scopes plus six nested-def copies inside draw methods. Pure additions on the tool/ layer with direct unit tests covering the default-alpha, explicit-alpha, non-mutation, new-list-instance, and validation-guard branches. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -538,6 +538,19 @@ class Blender(bonsai.core.tool.Blender):
|
||||
cls.handlers.clear()
|
||||
cls.is_installed = False
|
||||
|
||||
def draw_batch(self, shader_type, content_pos, color, indices=None):
|
||||
"""Submit a GPU batch through ``self.line_shader`` (for ``"LINES"``)
|
||||
or ``self.shader`` (for any other primitive). Skips empty batches
|
||||
via ``validate_shader_batch_data`` so Blender 4.4+ doesn't crash on
|
||||
empty ``indices``. Subclasses bind both shaders in their draw method
|
||||
before calling this helper."""
|
||||
if not Blender.validate_shader_batch_data(content_pos, indices):
|
||||
return
|
||||
shader = self.line_shader if shader_type == "LINES" else self.shader
|
||||
batch = batch_for_shader(shader, shader_type, {"pos": content_pos}, indices=indices)
|
||||
shader.uniform_float("color", color)
|
||||
batch.draw(shader)
|
||||
|
||||
@staticmethod
|
||||
def _lookup_active_instance(gizmo_cls: type, context: bpy.types.Context) -> Optional[Any]:
|
||||
"""Return the live ``GizmoGroup`` instance registered under
|
||||
@@ -2391,6 +2404,13 @@ class Blender(bonsai.core.tool.Blender):
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def transparent_color(color: Iterable[float], alpha: float = 0.1) -> list[float]:
|
||||
"""Copy an RGBA color with its alpha channel overridden."""
|
||||
out = [c for c in color]
|
||||
out[3] = alpha
|
||||
return out
|
||||
|
||||
@classmethod
|
||||
def draw_bmesh_face_tris(
|
||||
cls,
|
||||
|
||||
@@ -42,6 +42,46 @@ class TestImplementsTool(NewFile):
|
||||
assert isinstance(subject(), bonsai.core.tool.Blender)
|
||||
|
||||
|
||||
class TestTransparentColor(NewFile):
|
||||
def test_default_alpha_overrides_to_zero_one(self):
|
||||
assert subject.transparent_color([1.0, 0.5, 0.25, 1.0]) == [1.0, 0.5, 0.25, 0.1]
|
||||
|
||||
def test_explicit_alpha_is_applied(self):
|
||||
assert subject.transparent_color([1.0, 0.5, 0.25, 1.0], alpha=0.5) == [1.0, 0.5, 0.25, 0.5]
|
||||
|
||||
def test_does_not_mutate_input(self):
|
||||
original = [1.0, 0.5, 0.25, 1.0]
|
||||
subject.transparent_color(original)
|
||||
assert original == [1.0, 0.5, 0.25, 1.0]
|
||||
|
||||
def test_returns_new_list_instance(self):
|
||||
original = [1.0, 0.5, 0.25, 1.0]
|
||||
result = subject.transparent_color(original)
|
||||
assert result is not original
|
||||
|
||||
|
||||
class TestViewportDecoratorDrawBatch(NewFile):
|
||||
def test_empty_content_pos_skips_shader_calls(self):
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
decorator = subject.ViewportDecorator()
|
||||
decorator.line_shader = MagicMock()
|
||||
decorator.shader = MagicMock()
|
||||
decorator.draw_batch("LINES", [], (1.0, 1.0, 1.0, 1.0))
|
||||
decorator.line_shader.uniform_float.assert_not_called()
|
||||
decorator.shader.uniform_float.assert_not_called()
|
||||
|
||||
def test_empty_indices_skips_shader_calls(self):
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
decorator = subject.ViewportDecorator()
|
||||
decorator.line_shader = MagicMock()
|
||||
decorator.shader = MagicMock()
|
||||
decorator.draw_batch("LINES", [(0.0, 0.0, 0.0), (1.0, 0.0, 0.0)], (1.0, 1.0, 1.0, 1.0), indices=[])
|
||||
decorator.line_shader.uniform_float.assert_not_called()
|
||||
decorator.shader.uniform_float.assert_not_called()
|
||||
|
||||
|
||||
class TestCopyNodeGraph(NewFile):
|
||||
def test_run(self):
|
||||
material_to = bpy.data.materials.new("material_to")
|
||||
|
||||
Reference in New Issue
Block a user