diff --git a/src/bonsai/bonsai/bim/module/aggregate/decorator.py b/src/bonsai/bonsai/bim/module/aggregate/decorator.py index 74ab48e661..239253ec2a 100644 --- a/src/bonsai/bonsai/bim/module/aggregate/decorator.py +++ b/src/bonsai/bonsai/bim/module/aggregate/decorator.py @@ -131,6 +131,9 @@ class AggregateDecorator: return shader def draw_custom_batch(self, coords, color): + indices = None + if not tool.Blender.validate_shader_batch_data(coords, indices): + return shader = self.dotted_line_shader() arc_lengths = [0] @@ -141,6 +144,7 @@ class AggregateDecorator: shader, "LINE_STRIP", {"position": coords, "arcLength": arc_lengths}, + indices=indices, ) matrix = bpy.context.region_data.perspective_matrix @@ -150,6 +154,8 @@ class AggregateDecorator: batch.draw(shader) def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) @@ -243,6 +249,8 @@ class AggregateModeDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/boundary/decorator.py b/src/bonsai/bonsai/bim/module/boundary/decorator.py index b9243d1a24..c7875c94bf 100644 --- a/src/bonsai/bonsai/bim/module/boundary/decorator.py +++ b/src/bonsai/bonsai/bim/module/boundary/decorator.py @@ -43,6 +43,8 @@ class BoundaryDecorator: cls.installed = None def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/clash/decorator.py b/src/bonsai/bonsai/bim/module/clash/decorator.py index 764c6e5232..91ecc1fc16 100644 --- a/src/bonsai/bonsai/bim/module/clash/decorator.py +++ b/src/bonsai/bonsai/bim/module/clash/decorator.py @@ -49,6 +49,8 @@ class ClashDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/drawing/decoration.py b/src/bonsai/bonsai/bim/module/drawing/decoration.py index 19480b6a0d..a169bb46af 100644 --- a/src/bonsai/bonsai/bim/module/drawing/decoration.py +++ b/src/bonsai/bonsai/bim/module/drawing/decoration.py @@ -318,6 +318,8 @@ class BaseDecorator: color: tuple[float, float, float, float], indices: Optional[list[tuple[int, int]]] = None, ) -> None: + if not tool.Blender.validate_shader_batch_data(content_pos, indices): + return shader = self.line_shader if shader_type == "LINES" else self.base_shader batch = batch_for_shader(shader, shader_type, {"pos": content_pos}, indices=indices) shader.uniform_float("color", color) @@ -1699,6 +1701,8 @@ class CutDecorator: self.draw_batch("POINTS", selected_vertices, selected_elements_color) def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/drawing/gizmos.py b/src/bonsai/bonsai/bim/module/drawing/gizmos.py index 952ea0cb96..34458c0920 100644 --- a/src/bonsai/bonsai/bim/module/drawing/gizmos.py +++ b/src/bonsai/bonsai/bim/module/drawing/gizmos.py @@ -414,6 +414,8 @@ class ExtrusionGuidesGizmo(CustomGizmo, types.Gizmo): shader_wrapper = ExtrusionGuidesShader() verts = [Vector((0, 0, 0)), Vector((0, 0, 1))] verts, edges = shader_wrapper.process_geometry(verts) + if not tool.Blender.validate_shader_batch_data(verts, edges): + verts, edges = [], [] self.custom_shape = shader_wrapper, shader_wrapper.batch( pos=verts, indices=edges, diff --git a/src/bonsai/bonsai/bim/module/geometry/decorator.py b/src/bonsai/bonsai/bim/module/geometry/decorator.py index 5993cc4469..cf4a067f78 100644 --- a/src/bonsai/bonsai/bim/module/geometry/decorator.py +++ b/src/bonsai/bonsai/bim/module/geometry/decorator.py @@ -128,6 +128,8 @@ class ItemDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/georeference/decorator.py b/src/bonsai/bonsai/bim/module/georeference/decorator.py index afd9dfba27..55fcbc1d64 100644 --- a/src/bonsai/bonsai/bim/module/georeference/decorator.py +++ b/src/bonsai/bonsai/bim/module/georeference/decorator.py @@ -54,6 +54,8 @@ class GeoreferenceDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.Blender.validate_shader_batch_data(content_pos, indices): + return props = tool.Georeference.get_georeference_props() self.scale = props.visualization_scale content_pos = [v * self.scale for v in content_pos] diff --git a/src/bonsai/bonsai/bim/module/light/decorator.py b/src/bonsai/bonsai/bim/module/light/decorator.py index 958aca6e0f..127f636919 100644 --- a/src/bonsai/bonsai/bim/module/light/decorator.py +++ b/src/bonsai/bonsai/bim/module/light/decorator.py @@ -52,6 +52,8 @@ class SolarDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index d54551610b..6c1304f0f4 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -72,6 +72,8 @@ class ProfileDecorator: cls.installed = None def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) @@ -405,6 +407,8 @@ class PolylineDecorator: return {"verts": verts, "edges": edges, "tris": tris} def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) @@ -815,6 +819,8 @@ class ProductDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) @@ -882,6 +888,8 @@ class WallAxisDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) @@ -946,6 +954,8 @@ class SlabDirectionDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) @@ -1001,6 +1011,8 @@ class FaceAreaDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/model/opening.py b/src/bonsai/bonsai/bim/module/model/opening.py index 5cceda3bce..b00b74932d 100644 --- a/src/bonsai/bonsai/bim/module/model/opening.py +++ b/src/bonsai/bonsai/bim/module/model/opening.py @@ -896,6 +896,8 @@ class DecorationsHandler: cls.installed = None def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/nest/decorator.py b/src/bonsai/bonsai/bim/module/nest/decorator.py index e096ca24f3..64f3083b78 100644 --- a/src/bonsai/bonsai/bim/module/nest/decorator.py +++ b/src/bonsai/bonsai/bim/module/nest/decorator.py @@ -131,6 +131,10 @@ class NestDecorator: return shader def draw_custom_batch(self, coords, color): + indices = None + if not tool.Blender.validate_shader_batch_data(coords, indices): + return + shader = self.dotted_line_shader() arc_lengths = [0] @@ -141,6 +145,7 @@ class NestDecorator: shader, "LINE_STRIP", {"position": coords, "arcLength": arc_lengths}, + indices=indices, ) matrix = bpy.context.region_data.perspective_matrix @@ -150,6 +155,8 @@ class NestDecorator: batch.draw(shader) def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) @@ -243,6 +250,8 @@ class NestModeDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/project/decorator.py b/src/bonsai/bonsai/bim/module/project/decorator.py index 0adb1a4c4e..7d30a203a0 100644 --- a/src/bonsai/bonsai/bim/module/project/decorator.py +++ b/src/bonsai/bonsai/bim/module/project/decorator.py @@ -68,6 +68,8 @@ class ProjectDecorator: cls.installed = None def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) @@ -137,6 +139,8 @@ class ClippingPlaneDecorator: cls.installed = None def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) @@ -242,6 +246,8 @@ class MeasureDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/spatial/decorator.py b/src/bonsai/bonsai/bim/module/spatial/decorator.py index a7c1059fc7..b8781133b0 100644 --- a/src/bonsai/bonsai/bim/module/spatial/decorator.py +++ b/src/bonsai/bonsai/bim/module/spatial/decorator.py @@ -49,6 +49,8 @@ class GridDecorator: cls.is_installed = False def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py index d90ecd4954..be31aa0706 100644 --- a/src/bonsai/bonsai/bim/module/structural/decorator.py +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -21,6 +21,7 @@ import numpy as np import bpy import gpu import blf +import bonsai.tool as tool from bpy.types import SpaceView3D from gpu_extras.batch import batch_for_shader from typing import Iterable, Union @@ -86,6 +87,8 @@ class LoadsDecorator: shader = info["shader"] args = info["args"] indices = info["indices"] + if not tool.Blender.validate_shader_batch_data(args["coord"], indices): + continue batch = batch_for_shader(shader, "TRIS", args, indices=indices) matrix = bpy.context.region_data.perspective_matrix shader.bind() diff --git a/src/bonsai/bonsai/bim/module/system/decorator.py b/src/bonsai/bonsai/bim/module/system/decorator.py index a463aae2e9..c77b2f6879 100644 --- a/src/bonsai/bonsai/bim/module/system/decorator.py +++ b/src/bonsai/bonsai/bim/module/system/decorator.py @@ -73,6 +73,8 @@ class SystemDecorator: cls.installed = None def draw_batch(self, shader_type, content_pos, color, indices=None): + if not tool.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) diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index b7cca4f0c7..4f8c010aee 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -1668,3 +1668,21 @@ class Blender(bonsai.core.tool.Blender): unit_scale = 0.3048 return unit_scale + + @classmethod + def validate_shader_batch_data(cls, pos: Any, indices: Optional[Any]) -> bool: + """Validate shader batch data. + + If method returns ``False``, then drawing for this batch should be skipped. + Should be used always before running ``batch.draw(shader)`` + + Important because in Blender 4.4.0 on Mac passing an empty list + as ``indices`` is causing a crash. + + See https://projects.blender.org/blender/blender/issues/136831 + """ + # Checking `pos` is not critical but we keep it + # to ensure batch data is always validated to avoid crashes. + if len(pos) == 0 or (indices is not None and len(indices) == 0): + return False + return True