mirror of
https://github.com/Ultimaker/Cura.git
synced 2026-01-28 11:50:43 -07:00
Painting: Set color, brush-size, brush-shape.
part of CURA-12543
This commit is contained in:
parent
3ae85e3e2a
commit
a176957fa7
3 changed files with 219 additions and 4 deletions
|
|
@ -5,9 +5,11 @@ from typing import cast, Optional
|
|||
|
||||
import numpy
|
||||
from PyQt6.QtCore import Qt
|
||||
from typing import List, Tuple
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Event import Event, MouseEvent, KeyEvent
|
||||
from UM.Logger import Logger
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Tool import Tool
|
||||
from cura.PickingPass import PickingPass
|
||||
|
|
@ -26,6 +28,31 @@ class PaintTool(Tool):
|
|||
self._mesh_transformed_cache = None
|
||||
self._cache_dirty = True
|
||||
|
||||
self._color_str_to_rgba = {
|
||||
"A": [192, 0, 192, 255],
|
||||
"B": [232, 128, 0, 255],
|
||||
"C": [0, 255, 0, 255],
|
||||
"D": [255, 255, 255, 255],
|
||||
}
|
||||
|
||||
self._brush_size = 10
|
||||
self._brush_color = "A"
|
||||
self._brush_shape = "A"
|
||||
|
||||
def setPaintType(self, paint_type: str) -> None:
|
||||
Logger.warning(f"TODO: Implement paint-types ({paint_type}).")
|
||||
pass
|
||||
|
||||
def setBrushSize(self, brush_size: float) -> None:
|
||||
self._brush_size = int(brush_size)
|
||||
print(self._brush_size)
|
||||
|
||||
def setBrushColor(self, brush_color: str) -> None:
|
||||
self._brush_color = brush_color
|
||||
|
||||
def setBrushShape(self, brush_shape: str) -> None:
|
||||
self._brush_shape = brush_shape
|
||||
|
||||
@staticmethod
|
||||
def _get_intersect_ratio_via_pt(a, pt, b, c) -> float:
|
||||
# compute the intersection of (param) A - pt with (param) B - (param) C
|
||||
|
|
@ -52,6 +79,20 @@ class PaintTool(Tool):
|
|||
def _nodeTransformChanged(self, *args) -> None:
|
||||
self._cache_dirty = True
|
||||
|
||||
def _getBrushPixels(self, mid_x: float, mid_y: float, w: float, h: float) -> List[Tuple[float, float]]:
|
||||
res = []
|
||||
include = False
|
||||
for y in range(-self._brush_size, self._brush_size + 1):
|
||||
for x in range(-self._brush_size, self._brush_size + 1):
|
||||
match self._brush_shape:
|
||||
case "A":
|
||||
include = True
|
||||
case "B":
|
||||
include = x * x + y * y <= self._brush_size * self._brush_size
|
||||
if include:
|
||||
res.append((mid_x + (x / w), mid_y + (y / h)))
|
||||
return res
|
||||
|
||||
def event(self, event: Event) -> bool:
|
||||
"""Handle mouse and keyboard events.
|
||||
|
||||
|
|
@ -128,9 +169,12 @@ class PaintTool(Tool):
|
|||
texcoords = wa * ta + wb * tb + wc * tc
|
||||
|
||||
paintview = controller.getActiveView()
|
||||
if paintview.getPluginId() != "PaintTool":
|
||||
if paintview is None or paintview.getPluginId() != "PaintTool":
|
||||
return False
|
||||
paintview.setUvPixel(texcoords[0], texcoords[1], [255, 128, 0, 255])
|
||||
color = self._color_str_to_rgba[self._brush_color]
|
||||
w, h = paintview.getUvTexDimensions()
|
||||
for (x, y) in self._getBrushPixels(texcoords[0], texcoords[1], float(w), float(h)):
|
||||
paintview.setUvPixel(x, y, color)
|
||||
|
||||
return True
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// Copyright (c) 2025 UltiMaker
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import UM 1.7 as UM
|
||||
|
||||
|
|
@ -11,4 +12,169 @@ Item
|
|||
width: childrenRect.width
|
||||
height: childrenRect.height
|
||||
UM.I18nCatalog { id: catalog; name: "cura"}
|
||||
|
||||
ColumnLayout
|
||||
{
|
||||
RowLayout
|
||||
{
|
||||
UM.ToolbarButton
|
||||
{
|
||||
id: paintTypeA
|
||||
|
||||
text: catalog.i18nc("@action:button", "Paint Type A")
|
||||
toolItem: UM.ColorImage
|
||||
{
|
||||
source: UM.Theme.getIcon("Buildplate")
|
||||
color: UM.Theme.getColor("icon")
|
||||
}
|
||||
property bool needBorder: true
|
||||
|
||||
z: 2
|
||||
|
||||
onClicked: UM.Controller.triggerActionWithData("setPaintType", "A")
|
||||
}
|
||||
|
||||
UM.ToolbarButton
|
||||
{
|
||||
id: paintTypeB
|
||||
|
||||
text: catalog.i18nc("@action:button", "Paint Type B")
|
||||
toolItem: UM.ColorImage
|
||||
{
|
||||
source: UM.Theme.getIcon("BlackMagic")
|
||||
color: UM.Theme.getColor("icon")
|
||||
}
|
||||
property bool needBorder: true
|
||||
|
||||
z: 2
|
||||
|
||||
onClicked: UM.Controller.triggerActionWithData("setPaintType", "B")
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout
|
||||
{
|
||||
UM.ToolbarButton
|
||||
{
|
||||
id: colorButtonA
|
||||
|
||||
text: catalog.i18nc("@action:button", "Color A")
|
||||
toolItem: UM.ColorImage
|
||||
{
|
||||
source: UM.Theme.getIcon("Eye")
|
||||
color: "purple"
|
||||
}
|
||||
property bool needBorder: true
|
||||
|
||||
z: 2
|
||||
|
||||
onClicked: UM.Controller.triggerActionWithData("setBrushColor", "A")
|
||||
}
|
||||
|
||||
UM.ToolbarButton
|
||||
{
|
||||
id: colorButtonB
|
||||
|
||||
text: catalog.i18nc("@action:button", "Color B")
|
||||
toolItem: UM.ColorImage
|
||||
{
|
||||
source: UM.Theme.getIcon("Eye")
|
||||
color: "orange"
|
||||
}
|
||||
property bool needBorder: true
|
||||
|
||||
z: 2
|
||||
|
||||
onClicked: UM.Controller.triggerActionWithData("setBrushColor", "B")
|
||||
}
|
||||
|
||||
UM.ToolbarButton
|
||||
{
|
||||
id: colorButtonC
|
||||
|
||||
text: catalog.i18nc("@action:button", "Color C")
|
||||
toolItem: UM.ColorImage
|
||||
{
|
||||
source: UM.Theme.getIcon("Eye")
|
||||
color: "green"
|
||||
}
|
||||
property bool needBorder: true
|
||||
|
||||
z: 2
|
||||
|
||||
onClicked: UM.Controller.triggerActionWithData("setBrushColor", "C")
|
||||
}
|
||||
|
||||
UM.ToolbarButton
|
||||
{
|
||||
id: colorButtonD
|
||||
|
||||
text: catalog.i18nc("@action:button", "Color D")
|
||||
toolItem: UM.ColorImage
|
||||
{
|
||||
source: UM.Theme.getIcon("Eye")
|
||||
color: "ghostwhite"
|
||||
}
|
||||
property bool needBorder: true
|
||||
|
||||
z: 2
|
||||
|
||||
onClicked: UM.Controller.triggerActionWithData("setBrushColor", "D")
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout
|
||||
{
|
||||
UM.ToolbarButton
|
||||
{
|
||||
id: shapeSquareButton
|
||||
|
||||
text: catalog.i18nc("@action:button", "Square Brush")
|
||||
toolItem: UM.ColorImage
|
||||
{
|
||||
source: UM.Theme.getIcon("MeshTypeNormal")
|
||||
color: UM.Theme.getColor("icon")
|
||||
}
|
||||
property bool needBorder: true
|
||||
|
||||
z: 2
|
||||
|
||||
onClicked: UM.Controller.triggerActionWithData("setBrushShape", "A")
|
||||
}
|
||||
|
||||
UM.ToolbarButton
|
||||
{
|
||||
id: shapeCircleButton
|
||||
|
||||
text: catalog.i18nc("@action:button", "Round Brush")
|
||||
toolItem: UM.ColorImage
|
||||
{
|
||||
source: UM.Theme.getIcon("CircleOutline")
|
||||
color: UM.Theme.getColor("icon")
|
||||
}
|
||||
property bool needBorder: true
|
||||
|
||||
z: 2
|
||||
|
||||
onClicked: UM.Controller.triggerActionWithData("setBrushShape", "B")
|
||||
}
|
||||
|
||||
UM.Slider
|
||||
{
|
||||
id: shapeSizeSlider
|
||||
|
||||
from: 1
|
||||
to: 50
|
||||
value: 10
|
||||
|
||||
onPressedChanged: function(pressed)
|
||||
{
|
||||
if(! pressed)
|
||||
{
|
||||
UM.Controller.triggerActionWithData("setBrushSize", shapeSizeSlider.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,18 +18,23 @@ class PaintView(View):
|
|||
super().__init__()
|
||||
self._paint_shader = None
|
||||
self._paint_texture = None
|
||||
self._tex_width = 256
|
||||
self._tex_height = 256
|
||||
|
||||
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_texture = OpenGL.getInstance().createTexture(self._tex_width, self._tex_height)
|
||||
self._paint_shader.setTexture(0, self._paint_texture)
|
||||
|
||||
def setUvPixel(self, x, y, color) -> None:
|
||||
self._paint_texture.setPixel(x, y, color)
|
||||
|
||||
def getUvTexDimensions(self):
|
||||
return self._tex_width, self._tex_height
|
||||
|
||||
def beginRendering(self) -> None:
|
||||
renderer = self.getRenderer()
|
||||
self._checkSetup()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue