From 8da7a82b5e226be0bb9fc5cae79206b28fd78eb5 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 12 Jun 2020 18:24:10 +0100 Subject: [PATCH] Added highlighting of the selected faces --- .../opengl/mesh/selection/__init__.py | 1 + .../opengl/mesh/selection/render_selection.py | 2 +- .../selection/render_selection_editable.py | 21 +++++- .../render_selection_group_editable.py | 24 ++++++- .../render_selection_highlightable.py | 68 +++++++++++++++++++ .../edit/canvas/controllable_edit_canvas.py | 2 +- 6 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 amulet_map_editor/opengl/mesh/selection/render_selection_highlightable.py diff --git a/amulet_map_editor/opengl/mesh/selection/__init__.py b/amulet_map_editor/opengl/mesh/selection/__init__.py index f48cc060..e485605d 100644 --- a/amulet_map_editor/opengl/mesh/selection/__init__.py +++ b/amulet_map_editor/opengl/mesh/selection/__init__.py @@ -1,4 +1,5 @@ from .render_selection import RenderSelection +from .render_selection_highlightable import RenderSelectionHighlightable from .render_selection_editable import RenderSelectionEditable from .render_selection_group import RenderSelectionGroup from .render_selection_group_editable import RenderSelectionGroupEditable diff --git a/amulet_map_editor/opengl/mesh/selection/render_selection.py b/amulet_map_editor/opengl/mesh/selection/render_selection.py index 5cd68110..1e071b87 100644 --- a/amulet_map_editor/opengl/mesh/selection/render_selection.py +++ b/amulet_map_editor/opengl/mesh/selection/render_selection.py @@ -26,7 +26,7 @@ def __init__(self, self._draw_mode = GL_TRIANGLES @property - def box_tint(self) -> Tuple[int, int, int]: + def box_tint(self) -> Tuple[float, float, float]: return 1, 1, 1 def _init_verts(self, texture_bounds: Dict[Any, Tuple[float, float, float, float]]): diff --git a/amulet_map_editor/opengl/mesh/selection/render_selection_editable.py b/amulet_map_editor/opengl/mesh/selection/render_selection_editable.py index d6eaeec1..61deb20c 100644 --- a/amulet_map_editor/opengl/mesh/selection/render_selection_editable.py +++ b/amulet_map_editor/opengl/mesh/selection/render_selection_editable.py @@ -3,10 +3,10 @@ from typing import Tuple, Dict, Any from amulet.api.data_types import BlockCoordinatesAny, PointCoordinatesAny -from .render_selection import RenderSelection +from .render_selection_highlightable import RenderSelectionHighlightable -class RenderSelectionEditable(RenderSelection): +class RenderSelectionEditable(RenderSelectionHighlightable): """A drawable selection box with additional editing controls""" def __init__(self, context_identifier: str, @@ -29,6 +29,13 @@ def _init_verts(self, texture_bounds: Dict[Any, Tuple[float, float, float, float self.verts[72:, 5:9] = texture_bounds.get(('amulet', 'ui/selection_blue'), missing_no) self.verts[:, 9:12] = self.box_tint + @property + def highlight_colour(self) -> Tuple[float, float, float]: + if self.is_dynamic: + return 1.0, 0.7, 0.3 + else: + return 1.2, 1.2, 1.2 + @property def is_static(self) -> bool: return not self.is_dynamic @@ -73,7 +80,15 @@ def _mark_recreate(self): self._rebuild = True def set_active_point(self, position: BlockCoordinatesAny): - self._points[self._free_edges] = numpy.array([position, position])[self._free_edges] + if self.is_dynamic: + self._points[self._free_edges] = numpy.array([position, position])[self._free_edges] + self._highlight_edges[:] = self._free_edges + elif position in self: + self._highlight_edges[:] = position == self._points + self._highlight_edges[1, self._highlight_edges[0]] = False + else: + self._highlight_edges[:] = False + self._mark_recreate() def _create_geometry_(self): diff --git a/amulet_map_editor/opengl/mesh/selection/render_selection_group_editable.py b/amulet_map_editor/opengl/mesh/selection/render_selection_group_editable.py index b916b35c..c02a726c 100644 --- a/amulet_map_editor/opengl/mesh/selection/render_selection_group_editable.py +++ b/amulet_map_editor/opengl/mesh/selection/render_selection_group_editable.py @@ -1,9 +1,10 @@ import numpy -from typing import Tuple, Dict, Any, Optional +from typing import Tuple, Dict, Any, Optional, List from amulet.api.data_types import BlockCoordinatesAny, BlockCoordinatesNDArray, PointCoordinatesAny, BlockCoordinates from .render_selection_group import RenderSelectionGroup from .render_selection import RenderSelection +from .render_selection_highlightable import RenderSelectionHighlightable from .render_selection_editable import RenderSelectionEditable @@ -20,6 +21,8 @@ def __init__(self, self._active_box_index: Optional[int] = None self._last_active_box_index: Optional[int] = None self._hover_box_index: Optional[int] = None + self._boxes: List[RenderSelectionHighlightable] = [] + self._last_highlighted_box_index: Optional[int] = None self._cursor = RenderSelection(context_identifier, texture_bounds, texture) self._cursor_position = numpy.array([0, 0, 0], dtype=numpy.int) @@ -43,6 +46,9 @@ def active_selection_corners(self, box_corners: Tuple[BlockCoordinates, BlockCoo box = self._boxes[self._active_box_index] box.point1, box.point2 = box_corners + def _new_render_selection(self): + return RenderSelectionHighlightable(self._context_identifier, self._texture_bounds, self._texture) + def _new_editable_render_selection(self): return RenderSelectionEditable(self._context_identifier, self._texture_bounds, self._texture) @@ -109,7 +115,7 @@ def deselect_all(self): box = self._boxes.pop() box.unload() self._active_box: Optional[RenderSelectionEditable] = None - self._active_box_index = self._last_active_box_index = None + self._active_box_index = self._last_active_box_index = self._last_highlighted_box_index = None self._post_box_disable_inputs_event() def deselect_active(self): @@ -118,8 +124,12 @@ def deselect_active(self): box = self._boxes.pop(self._active_box_index) box.unload() if self._boxes: + if self._last_active_box_index is not None and self._last_active_box_index > self._active_box_index: + self._last_active_box_index -= 1 if self._active_box_index >= 1: self._active_box_index -= 1 + if self._last_highlighted_box_index is not None and self._last_highlighted_box_index >= 1: + self._last_highlighted_box_index -= 1 self._create_active_box_from_existing() else: self._active_box = None @@ -135,9 +145,17 @@ def deselect_active(self): self._post_box_disable_inputs_event() def update_cursor_position(self, position: BlockCoordinatesAny, box_index: Optional[int]): + print(self._last_active_box_index, self._active_box_index) self._cursor_position[:] = position self._hover_box_index = box_index self._cursor.point1 = self._cursor.point2 = position + if self._last_highlighted_box_index is not None and self._last_highlighted_box_index != box_index: + self._boxes[self._last_highlighted_box_index].set_highlight_edges(False) + self._last_highlighted_box_index = None + if box_index is not None and self._active_box_index != box_index: + self._boxes[box_index].set_active_point(position) + self._last_highlighted_box_index = box_index + if self._active_box: self._active_box.set_active_point(position) self._post_box_change_event() @@ -206,7 +224,7 @@ def draw( if draw_cursor and not self.editing: self._cursor.draw(transformation_matrix) - def closest_intersection(self, origin: PointCoordinatesAny, vector: PointCoordinatesAny) -> Tuple[Optional[int], Optional["RenderSelection"]]: + def closest_intersection(self, origin: PointCoordinatesAny, vector: PointCoordinatesAny) -> Tuple[Optional[int], Optional["RenderSelectionHighlightable"]]: """ Returns the index for the closest box in the look vector :param origin: diff --git a/amulet_map_editor/opengl/mesh/selection/render_selection_highlightable.py b/amulet_map_editor/opengl/mesh/selection/render_selection_highlightable.py new file mode 100644 index 00000000..994cff61 --- /dev/null +++ b/amulet_map_editor/opengl/mesh/selection/render_selection_highlightable.py @@ -0,0 +1,68 @@ +from typing import Dict, Any, Tuple +import numpy + +from amulet.api.data_types import BlockCoordinatesAny +from .render_selection import RenderSelection + + +class RenderSelectionHighlightable(RenderSelection): + """A drawable selection box with edges that can be highlighted""" + def __init__(self, + context_identifier: str, + texture_bounds: Dict[Any, Tuple[float, float, float, float]], + texture: int + ): + super().__init__(context_identifier, texture_bounds, texture) + self._highlight_edges = numpy.array([[False, False, False], [False, False, False]], dtype=numpy.bool) # which edges are highlighted + + @property + def highlight_colour(self) -> Tuple[float, float, float]: + return 1.2, 1.2, 1.2 + + def set_active_point(self, position: BlockCoordinatesAny): + if position in self: + self._highlight_edges[:] = position == self._points + self._highlight_edges[1, self._highlight_edges[0]] = False + else: + self._highlight_edges[:] = False + self._mark_recreate() + + def set_highlight_edges(self, highlight_edges): + self._highlight_edges[:] = highlight_edges + self._mark_recreate() + + def _create_geometry_(self): + super()._create_geometry_() + self.verts[:36, 9:12] = self.box_tint + + indexes = numpy.zeros(6, numpy.uint8) + if self.point2[0] > self.point1[0]: + indexes[[1, 3]] = 0, 3 + else: + indexes[[1, 3]] = 3, 0 + + if self.point2[1] > self.point1[1]: + indexes[[0, 5]] = 1, 4 + else: + indexes[[0, 5]] = 4, 1 + + if self.point2[2] > self.point1[2]: + indexes[[2, 4]] = 2, 5 + else: + indexes[[2, 4]] = 5, 2 + + # [1, 0, 2, 3, 5, 4] + + # 0 down 1 + # 1 west 0 + # 2 north 2 + # 3 east 3 + # 4 south 5 + # 5 up 4 + + self.verts[:36][ + numpy.repeat( + self._highlight_edges.ravel()[indexes], 6 + ), + 9:12 + ] = self.highlight_colour diff --git a/amulet_map_editor/programs/edit/canvas/controllable_edit_canvas.py b/amulet_map_editor/programs/edit/canvas/controllable_edit_canvas.py index 830037c1..10555be5 100644 --- a/amulet_map_editor/programs/edit/canvas/controllable_edit_canvas.py +++ b/amulet_map_editor/programs/edit/canvas/controllable_edit_canvas.py @@ -111,7 +111,7 @@ def _process_action(self, evt, press: bool): self._box_select_time = time.time() else: # run once on button press and frequently until released if action == "box click": - if self.selection_editable and time.time() - self._box_select_time > 0.3: + if self.selection_editable and time.time() - self._box_select_time > 0.1: self._selection_group.box_select_disable() elif action == "toggle mouse mode": self._toggle_mouse_lock()