Refactored paint-view into its own thing.

part of CURA-12543
This commit is contained in:
Remco Burema 2025-05-21 21:50:17 +02:00
parent c5592eea83
commit 3ae85e3e2a
5 changed files with 65 additions and 22 deletions

View File

@ -27,7 +27,7 @@ class PaintTool(Tool):
self._cache_dirty = True self._cache_dirty = True
@staticmethod @staticmethod
def _get_intersect_ratio_via_pt(a, pt, b, c): def _get_intersect_ratio_via_pt(a, pt, b, c) -> float:
# compute the intersection of (param) A - pt with (param) B - (param) C # compute the intersection of (param) A - pt with (param) B - (param) C
# compute unit vectors of directions of lines A and B # compute unit vectors of directions of lines A and B
@ -61,12 +61,18 @@ class PaintTool(Tool):
""" """
super().event(event) super().event(event)
controller = Application.getInstance().getController()
# Make sure the displayed values are updated if the bounding box of the selected mesh(es) changes # Make sure the displayed values are updated if the bounding box of the selected mesh(es) changes
if event.type == Event.ToolActivateEvent: if event.type == Event.ToolActivateEvent:
return False controller.setActiveStage("PrepareStage")
controller.setActiveView("PaintTool") # Because that's the plugin-name, and the view is registered to it.
return True
if event.type == Event.ToolDeactivateEvent: if event.type == Event.ToolDeactivateEvent:
return False controller.setActiveStage("PrepareStage")
controller.setActiveView("SolidView")
return True
if event.type == Event.KeyPressEvent and cast(KeyEvent, event).key == KeyEvent.ShiftKey: if event.type == Event.KeyPressEvent and cast(KeyEvent, event).key == KeyEvent.ShiftKey:
return False return False
@ -121,10 +127,10 @@ class PaintTool(Tool):
wc /= wt wc /= wt
texcoords = wa * ta + wb * tb + wc * tc texcoords = wa * ta + wb * tb + wc * tc
solidview = Application.getInstance().getController().getActiveView() paintview = controller.getActiveView()
if solidview.getPluginId() != "SolidView": if paintview.getPluginId() != "PaintTool":
return False return False
solidview.setUvPixel(texcoords[0], texcoords[1], [255, 128, 0, 255]) paintview.setUvPixel(texcoords[0], texcoords[1], [255, 128, 0, 255])
return True return True

View File

@ -0,0 +1,42 @@
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import os
from UM.PluginRegistry import PluginRegistry
from UM.View.View import View
from UM.Scene.Selection import Selection
from UM.View.GL.OpenGL import OpenGL
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
class PaintView(View):
"""View for model-painting."""
def __init__(self) -> None:
super().__init__()
self._paint_shader = None
self._paint_texture = None
def _checkSetup(self):
if not self._paint_shader:
shader_filename = os.path.join(PluginRegistry.getInstance().getPluginPath("PaintTool"), "paint.shader")
self._paint_shader = OpenGL.getInstance().createShaderProgram(shader_filename)
if not self._paint_texture:
self._paint_texture = OpenGL.getInstance().createTexture(256, 256)
self._paint_shader.setTexture(0, self._paint_texture)
def setUvPixel(self, x, y, color) -> None:
self._paint_texture.setPixel(x, y, color)
def beginRendering(self) -> None:
renderer = self.getRenderer()
self._checkSetup()
paint_batch = renderer.createRenderBatch(shader=self._paint_shader)
renderer.addRenderBatch(paint_batch)
node = Selection.getAllSelectedObjects()[0]
if node is None:
return
paint_batch.addItem(node.getWorldTransformation(copy=False), node.getMeshData(), normal_transformation=node.getCachedNormalMatrix())

View File

@ -2,6 +2,7 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from . import PaintTool from . import PaintTool
from . import PaintView
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura") i18n_catalog = i18nCatalog("cura")
@ -14,8 +15,16 @@ def getMetaData():
"icon": "Visual", "icon": "Visual",
"tool_panel": "PaintTool.qml", "tool_panel": "PaintTool.qml",
"weight": 0 "weight": 0
},
"view": {
"name": i18n_catalog.i18nc("@item:inmenu", "Paint view"),
"weight": 0,
"visible": False
} }
} }
def register(app): def register(app):
return { "tool": PaintTool.PaintTool() } return {
"tool": PaintTool.PaintTool(),
"view": PaintView.PaintView()
}

View File

@ -42,13 +42,11 @@ class SolidView(View):
super().__init__() super().__init__()
application = Application.getInstance() application = Application.getInstance()
application.getPreferences().addPreference(self._show_overhang_preference, True) application.getPreferences().addPreference(self._show_overhang_preference, True)
application.getPreferences().addPreference(self._paint_active_preference, False)
application.globalContainerStackChanged.connect(self._onGlobalContainerChanged) application.globalContainerStackChanged.connect(self._onGlobalContainerChanged)
self._enabled_shader = None self._enabled_shader = None
self._disabled_shader = None self._disabled_shader = None
self._non_printing_shader = None self._non_printing_shader = None
self._support_mesh_shader = None self._support_mesh_shader = None
self._paint_shader = None
self._xray_shader = None self._xray_shader = None
self._xray_pass = None self._xray_pass = None
@ -142,11 +140,6 @@ class SolidView(View):
min_height = max(min_height, init_layer_height) min_height = max(min_height, init_layer_height)
return min_height return min_height
def _setPaintTexture(self):
self._paint_texture = OpenGL.getInstance().createTexture(256, 256)
if self._paint_shader:
self._paint_shader.setTexture(0, self._paint_texture)
def _checkSetup(self): def _checkSetup(self):
if not self._extruders_model: if not self._extruders_model:
self._extruders_model = Application.getInstance().getExtrudersModel() self._extruders_model = Application.getInstance().getExtrudersModel()
@ -175,10 +168,6 @@ class SolidView(View):
self._support_mesh_shader.setUniformValue("u_vertical_stripes", True) self._support_mesh_shader.setUniformValue("u_vertical_stripes", True)
self._support_mesh_shader.setUniformValue("u_width", 5.0) self._support_mesh_shader.setUniformValue("u_width", 5.0)
if not self._paint_shader:
self._paint_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "paint.shader"))
self._setPaintTexture()
if not Application.getInstance().getPreferences().getValue(self._show_xray_warning_preference): if not Application.getInstance().getPreferences().getValue(self._show_xray_warning_preference):
self._xray_shader = None self._xray_shader = None
self._xray_composite_shader = None self._xray_composite_shader = None
@ -216,9 +205,6 @@ class SolidView(View):
self._old_composite_shader = self._composite_pass.getCompositeShader() self._old_composite_shader = self._composite_pass.getCompositeShader()
self._composite_pass.setCompositeShader(self._xray_composite_shader) self._composite_pass.setCompositeShader(self._xray_composite_shader)
def setUvPixel(self, x, y, color):
self._paint_texture.setPixel(x, y, color)
def beginRendering(self): def beginRendering(self):
scene = self.getController().getScene() scene = self.getController().getScene()
renderer = self.getRenderer() renderer = self.getRenderer()
@ -236,7 +222,7 @@ class SolidView(View):
else: else:
self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0)))
self._enabled_shader.setUniformValue("u_lowestPrintableHeight", self._lowest_printable_height) self._enabled_shader.setUniformValue("u_lowestPrintableHeight", self._lowest_printable_height)
disabled_batch = renderer.createRenderBatch(shader = self._paint_shader) #### TODO: put back to 'self._disabled_shader' disabled_batch = renderer.createRenderBatch(shader = self._disabled_shader)
normal_object_batch = renderer.createRenderBatch(shader = self._enabled_shader) normal_object_batch = renderer.createRenderBatch(shader = self._enabled_shader)
renderer.addRenderBatch(disabled_batch) renderer.addRenderBatch(disabled_batch)
renderer.addRenderBatch(normal_object_batch) renderer.addRenderBatch(normal_object_batch)