diff --git a/plugins/PaintTool/PaintTool.py b/plugins/PaintTool/PaintTool.py index a2d8e2abce..abc802148e 100644 --- a/plugins/PaintTool/PaintTool.py +++ b/plugins/PaintTool/PaintTool.py @@ -355,10 +355,23 @@ class PaintTool(Tool): is_moved = event.type == Event.MouseMoveEvent is_pressed = event.type == Event.MousePressEvent if (is_moved or is_pressed) and self._controller.getToolsEnabled(): - if is_moved and not self._mouse_held: - return False - mouse_evt = cast(MouseEvent, event) + + if not self._picking_pass: + self._picking_pass = CuraApplication.getInstance().getRenderer().getRenderPass("picking_selected") + if not self._picking_pass: + return False + + brush_color = self._brush_color if self.getPaintType() != "extruder" else str(self._brush_extruder) + + world_coords_vec = None + if is_moved: + world_coords_vec = self._picking_pass.getPickedPosition(mouse_evt.x, mouse_evt.y) + self._view.setCursor(world_coords_vec, self._brush_size / 128.0, brush_color) + if not self._mouse_held: + self._updateScene(node) + return False + if is_pressed: if MouseEvent.LeftButton not in mouse_evt.buttons: return False @@ -370,11 +383,6 @@ class PaintTool(Tool): if not self._faces_selection_pass: return False - if not self._picking_pass: - self._picking_pass = CuraApplication.getInstance().getRenderer().getRenderPass("picking_selected") - if not self._picking_pass: - return False - if self._camera is None: self._updateCamera() if self._camera is None: @@ -395,8 +403,10 @@ class PaintTool(Tool): face_id = self._faces_selection_pass.getFaceIdAtPosition(mouse_evt.x, mouse_evt.y) if face_id < 0 or face_id >= self._mesh_transformed_cache.getFaceCount(): return False - world_coords = self._picking_pass.getPickedPosition(mouse_evt.x, mouse_evt.y).getData() + if world_coords_vec is None: + world_coords_vec = self._picking_pass.getPickedPosition(mouse_evt.x, mouse_evt.y) + world_coords = world_coords_vec.getData() if self._last_world_coords is None: self._last_world_coords = world_coords self._last_face_id = face_id @@ -405,7 +415,6 @@ class PaintTool(Tool): if len(uv_areas) == 0: return False stroke_img, (start_x, start_y) = self._createStrokeImage(uv_areas) - brush_color = self._brush_color if self.getPaintType() != "extruder" else str(self._brush_extruder) self._view.addStroke(stroke_img, start_x, start_y, brush_color, is_moved) self._last_world_coords = world_coords diff --git a/plugins/PaintTool/PaintView.py b/plugins/PaintTool/PaintView.py index cf29ca71b6..17013f6c62 100644 --- a/plugins/PaintTool/PaintView.py +++ b/plugins/PaintTool/PaintView.py @@ -2,11 +2,12 @@ # Cura is released under the terms of the LGPLv3 or higher. import os -from PyQt6.QtCore import QRect, pyqtSignal -from typing import Optional, Dict +from typing import Optional, List, Dict +from PyQt6.QtCore import QRect, pyqtSignal from PyQt6.QtGui import QImage, QUndoStack, QColor +from UM.Math.Vector import Vector from cura.CuraApplication import CuraApplication from cura.BuildVolume import BuildVolume from cura.CuraView import CuraView @@ -46,6 +47,10 @@ class PaintView(CuraView): self._paint_undo_stack.canUndoChanged.connect(self.canUndoChanged) self._paint_undo_stack.canRedoChanged.connect(self.canRedoChanged) + self._cursor_position: Vector = Vector(0.0, 0.0, 0.0) + self._cursor_size: float = 0.0 + self._cursor_color: List[float] = [0.0, 0.0, 0.0, 1.0] + application = CuraApplication.getInstance() application.engineCreatedSignal.connect(self._makePaintModes) self._scene = application.getController().getScene() @@ -114,6 +119,11 @@ class PaintView(CuraView): shader_filename = os.path.join(PluginRegistry.getInstance().getPluginPath("PaintTool"), "paint.shader") self._paint_shader = OpenGL.getInstance().createShaderProgram(shader_filename) + def setCursor(self, position: Optional[Vector] = None, size: float = -1, color: Optional[str] = None) -> None: + self._cursor_position = position if position is not None else self._cursor_position + self._cursor_size = size if size >= 0 else self._cursor_size + self._cursor_color = self._paint_modes[self._current_paint_type][color].display_color if color is not None else self._cursor_color + def addStroke(self, stroke_mask: QImage, start_x: int, start_y: int, brush_color: str, merge_with_previous: bool) -> None: if self._current_paint_texture is None or self._current_paint_texture.getImage() is None: return @@ -208,6 +218,10 @@ class PaintView(CuraView): self._paint_shader.setUniformValue("u_bitsRangesStart", self._current_bits_ranges[0]) self._paint_shader.setUniformValue("u_bitsRangesEnd", self._current_bits_ranges[1]) + self._paint_shader.setUniformValue("u_cursorPos", self._cursor_position) + self._paint_shader.setUniformValue("u_cursorSize", self._cursor_size) + self._paint_shader.setUniformValue("u_cursorColor", self._cursor_color) + colors = [paint_type_obj.display_color for paint_type_obj in self._paint_modes[self._current_paint_type].values()] colors_values = [[int(color_part * 255) for color_part in [color.r, color.g, color.b]] for color in colors] self._paint_shader.setUniformValueArray("u_renderColors", colors_values) diff --git a/plugins/PaintTool/paint.shader b/plugins/PaintTool/paint.shader index 1982724910..1bfec2b9fe 100644 --- a/plugins/PaintTool/paint.shader +++ b/plugins/PaintTool/paint.shader @@ -33,6 +33,9 @@ fragment = uniform mediump int u_bitsRangesStart; uniform mediump int u_bitsRangesEnd; uniform mediump vec3 u_renderColors[16]; + uniform highp vec3 u_cursorPos; + uniform highp float u_cursorSize; + uniform lowp vec4 u_cursorColor; varying highp vec3 v_vertex; varying highp vec3 v_normal; @@ -57,8 +60,16 @@ fragment = highp float n_dot_l = mix(0.3, 0.7, dot(normal, light_dir)); final_color += (n_dot_l * diffuse_color); - final_color.a = 1.0; + /* Cursor */ + vec3 diff = v_vertex - u_cursorPos; + float squared_dist = dot(diff, diff); + if (squared_dist <= (u_cursorSize * u_cursorSize)) + { + final_color.rgb = mix(final_color.rgb / 2.0, u_cursorColor.rgb, u_cursorColor.a); + } + /* Output */ + final_color.a = 1.0; frag_color = final_color; } @@ -98,6 +109,9 @@ fragment41core = uniform mediump int u_bitsRangesStart; uniform mediump int u_bitsRangesEnd; uniform mediump vec3 u_renderColors[16]; + uniform highp vec3 u_cursorPos; + uniform highp float u_cursorSize; + uniform lowp vec4 u_cursorColor; in highp vec3 v_vertex; in highp vec3 v_normal; @@ -123,14 +137,24 @@ fragment41core = highp float n_dot_l = mix(0.3, 0.7, dot(normal, light_dir)); final_color += (n_dot_l * diffuse_color); - final_color.a = 1.0; + /* Cursor */ + vec3 diff = v_vertex - u_cursorPos; + float squared_dist = dot(diff, diff); + if (squared_dist <= (u_cursorSize * u_cursorSize)) + { + final_color.rgb = mix(final_color.rgb / 2.0, u_cursorColor.rgb, u_cursorColor.a); + } + /* Output */ + final_color.a = 1.0; frag_color = final_color; } [defaults] u_ambientColor = [0.3, 0.3, 0.3, 1.0] u_texture = 0 +u_cursorSize = 0.0 +u_cursorColor = [0.0, 0.0, 0.0, 0.0] [bindings] u_modelMatrix = model_matrix