|
4 | 4 | import gpu
|
5 | 5 | from bpy.props import IntProperty, StringProperty, BoolProperty
|
6 | 6 | from bpy.types import Context
|
| 7 | +from gpu_extras.batch import batch_for_shader |
7 | 8 |
|
8 | 9 | from .. import global_data
|
9 | 10 | from ..utilities import preferences
|
|
13 | 14 | from ..utilities.index import index_to_rgb, breakdown_index
|
14 | 15 | from ..utilities.view import update_cb
|
15 | 16 | from ..utilities.solver import update_system_cb
|
| 17 | +from ..utilities.draw import ThickRenderer, RenderMode |
16 | 18 |
|
17 | 19 | logger = logging.getLogger(__name__)
|
18 | 20 |
|
19 | 21 |
|
20 |
| -class SlvsGenericEntity: |
| 22 | +class ThickRenderingMixin: |
| 23 | + """Mixin class providing thick rendering functionality with error handling.""" |
| 24 | + |
| 25 | + def create_thick_batch(self, coords, indices, shader_type="TRIS"): |
| 26 | + """Create a GPU batch from thick rendering coordinates and indices. |
| 27 | +
|
| 28 | + Args: |
| 29 | + coords: List of coordinate tuples |
| 30 | + indices: List of triangle indices |
| 31 | + shader_type: Shader type (default: "TRIS") |
| 32 | +
|
| 33 | + Returns: |
| 34 | + GPU batch object or None if creation fails |
| 35 | + """ |
| 36 | + if not coords: |
| 37 | + logger.warning(f"No coordinates provided for thick rendering batch in {self}") |
| 38 | + return None |
| 39 | + |
| 40 | + try: |
| 41 | + kwargs = {"pos": coords} |
| 42 | + batch = batch_for_shader(self._shader, shader_type, kwargs, indices=indices) |
| 43 | + return batch |
| 44 | + except Exception as e: |
| 45 | + logger.error(f"Failed to create thick rendering batch for {self}: {e}") |
| 46 | + return None |
| 47 | + |
| 48 | + def update_thick_point(self, center, size): |
| 49 | + """Update entity with thick point rendering. |
| 50 | +
|
| 51 | + Args: |
| 52 | + center: Point center coordinates |
| 53 | + size: Point size |
| 54 | + """ |
| 55 | + if self._should_skip_update(): |
| 56 | + return |
| 57 | + |
| 58 | + try: |
| 59 | + coords, indices = ThickRenderer.render_point(center, size) |
| 60 | + batch = self.create_thick_batch(coords, indices) |
| 61 | + if batch: |
| 62 | + self._batch = batch |
| 63 | + self.is_dirty = False |
| 64 | + except Exception as e: |
| 65 | + logger.error(f"Error updating thick point {self}: {e}") |
| 66 | + self.is_dirty = False # Prevent infinite update loops |
| 67 | + |
| 68 | + def update_thick_line(self, start, end, width, is_dashed=False): |
| 69 | + """Update entity with thick line rendering. |
| 70 | +
|
| 71 | + Args: |
| 72 | + start: Line start point |
| 73 | + end: Line end point |
| 74 | + width: Line width |
| 75 | + is_dashed: Whether line should be dashed |
| 76 | + """ |
| 77 | + if self._should_skip_update(): |
| 78 | + return |
| 79 | + |
| 80 | + try: |
| 81 | + mode = RenderMode.DASHED if is_dashed else RenderMode.SOLID |
| 82 | + coords, indices = ThickRenderer.render_line(start, end, width, mode) |
| 83 | + batch = self.create_thick_batch(coords, indices) |
| 84 | + if batch: |
| 85 | + self._batch = batch |
| 86 | + self.is_dirty = False |
| 87 | + except Exception as e: |
| 88 | + logger.error(f"Error updating thick line {self}: {e}") |
| 89 | + self.is_dirty = False |
| 90 | + |
| 91 | + def update_thick_line_strip(self, coords, width, is_dashed=False): |
| 92 | + """Update entity with thick line strip rendering. |
| 93 | +
|
| 94 | + Args: |
| 95 | + coords: List of points forming the line strip |
| 96 | + width: Line width |
| 97 | + is_dashed: Whether line should be dashed |
| 98 | + """ |
| 99 | + if self._should_skip_update(): |
| 100 | + return |
| 101 | + |
| 102 | + try: |
| 103 | + mode = RenderMode.DASHED if is_dashed else RenderMode.SOLID |
| 104 | + thick_coords, indices = ThickRenderer.render_line_strip(coords, width, mode) |
| 105 | + batch = self.create_thick_batch(thick_coords, indices) |
| 106 | + if batch: |
| 107 | + self._batch = batch |
| 108 | + self.is_dirty = False |
| 109 | + except Exception as e: |
| 110 | + logger.error(f"Error updating thick line strip {self}: {e}") |
| 111 | + self.is_dirty = False |
| 112 | + |
| 113 | + def _should_skip_update(self): |
| 114 | + """Check if update should be skipped (e.g., in background mode).""" |
| 115 | + import bpy |
| 116 | + return bpy.app.background |
| 117 | + |
| 118 | + |
| 119 | +class SlvsGenericEntity(ThickRenderingMixin): |
21 | 120 | def entity_name_getter(self):
|
22 | 121 | return self.get("name", str(self))
|
23 | 122 |
|
|
0 commit comments