mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 22:47:29 -06:00
CURA-4526 Delete LayerView plugin because it will be replaced with the
SimulationView. This commit also adapts the code in order to accept the messages coming from the engine, with information about feedrates and line thicknesses. Add also some changes in the GCodeReader that reads feedrates and line thickness from the gcode file.
This commit is contained in:
parent
43f339f927
commit
b6e997c88d
22 changed files with 116 additions and 2209 deletions
|
@ -218,7 +218,7 @@ class CuraApplication(QtApplication):
|
||||||
"CuraEngineBackend",
|
"CuraEngineBackend",
|
||||||
"UserAgreement",
|
"UserAgreement",
|
||||||
"SolidView",
|
"SolidView",
|
||||||
"LayerView",
|
"SimulationView",
|
||||||
"STLReader",
|
"STLReader",
|
||||||
"SelectionTool",
|
"SelectionTool",
|
||||||
"CameraTool",
|
"CameraTool",
|
||||||
|
@ -1386,7 +1386,7 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
extension = os.path.splitext(filename)[1]
|
extension = os.path.splitext(filename)[1]
|
||||||
if extension.lower() in self._non_sliceable_extensions:
|
if extension.lower() in self._non_sliceable_extensions:
|
||||||
self.getController().setActiveView("LayerView")
|
self.getController().setActiveView("SimulationView")
|
||||||
view = self.getController().getActiveView()
|
view = self.getController().getActiveView()
|
||||||
view.resetLayerData()
|
view.resetLayerData()
|
||||||
view.setLayer(9999999)
|
view.setLayer(9999999)
|
||||||
|
|
|
@ -47,12 +47,12 @@ class Layer:
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def build(self, vertex_offset, index_offset, vertices, colors, line_dimensions, extruders, line_types, indices):
|
def build(self, vertex_offset, index_offset, vertices, colors, line_dimensions, feedrates, extruders, line_types, indices):
|
||||||
result_vertex_offset = vertex_offset
|
result_vertex_offset = vertex_offset
|
||||||
result_index_offset = index_offset
|
result_index_offset = index_offset
|
||||||
self._element_count = 0
|
self._element_count = 0
|
||||||
for polygon in self._polygons:
|
for polygon in self._polygons:
|
||||||
polygon.build(result_vertex_offset, result_index_offset, vertices, colors, line_dimensions, extruders, line_types, indices)
|
polygon.build(result_vertex_offset, result_index_offset, vertices, colors, line_dimensions, feedrates, extruders, line_types, indices)
|
||||||
result_vertex_offset += polygon.lineMeshVertexCount()
|
result_vertex_offset += polygon.lineMeshVertexCount()
|
||||||
result_index_offset += polygon.lineMeshElementCount()
|
result_index_offset += polygon.lineMeshElementCount()
|
||||||
self._element_count += polygon.elementCount
|
self._element_count += polygon.elementCount
|
||||||
|
|
|
@ -20,11 +20,11 @@ class LayerDataBuilder(MeshBuilder):
|
||||||
if layer not in self._layers:
|
if layer not in self._layers:
|
||||||
self._layers[layer] = Layer(layer)
|
self._layers[layer] = Layer(layer)
|
||||||
|
|
||||||
def addPolygon(self, layer, polygon_type, data, line_width):
|
def addPolygon(self, layer, polygon_type, data, line_width, line_thickness, line_feedrate):
|
||||||
if layer not in self._layers:
|
if layer not in self._layers:
|
||||||
self.addLayer(layer)
|
self.addLayer(layer)
|
||||||
|
|
||||||
p = LayerPolygon(self, polygon_type, data, line_width)
|
p = LayerPolygon(self, polygon_type, data, line_width, line_thickness, line_feedrate)
|
||||||
self._layers[layer].polygons.append(p)
|
self._layers[layer].polygons.append(p)
|
||||||
|
|
||||||
def getLayer(self, layer):
|
def getLayer(self, layer):
|
||||||
|
@ -64,13 +64,14 @@ class LayerDataBuilder(MeshBuilder):
|
||||||
line_dimensions = numpy.empty((vertex_count, 2), numpy.float32)
|
line_dimensions = numpy.empty((vertex_count, 2), numpy.float32)
|
||||||
colors = numpy.empty((vertex_count, 4), numpy.float32)
|
colors = numpy.empty((vertex_count, 4), numpy.float32)
|
||||||
indices = numpy.empty((index_count, 2), numpy.int32)
|
indices = numpy.empty((index_count, 2), numpy.int32)
|
||||||
|
feedrates = numpy.empty((vertex_count), numpy.float32)
|
||||||
extruders = numpy.empty((vertex_count), numpy.float32)
|
extruders = numpy.empty((vertex_count), numpy.float32)
|
||||||
line_types = numpy.empty((vertex_count), numpy.float32)
|
line_types = numpy.empty((vertex_count), numpy.float32)
|
||||||
|
|
||||||
vertex_offset = 0
|
vertex_offset = 0
|
||||||
index_offset = 0
|
index_offset = 0
|
||||||
for layer, data in sorted(self._layers.items()):
|
for layer, data in sorted(self._layers.items()):
|
||||||
( vertex_offset, index_offset ) = data.build( vertex_offset, index_offset, vertices, colors, line_dimensions, extruders, line_types, indices)
|
( vertex_offset, index_offset ) = data.build( vertex_offset, index_offset, vertices, colors, line_dimensions, feedrates, extruders, line_types, indices)
|
||||||
self._element_counts[layer] = data.elementCount
|
self._element_counts[layer] = data.elementCount
|
||||||
|
|
||||||
self.addVertices(vertices)
|
self.addVertices(vertices)
|
||||||
|
@ -107,6 +108,11 @@ class LayerDataBuilder(MeshBuilder):
|
||||||
"value": line_types,
|
"value": line_types,
|
||||||
"opengl_name": "a_line_type",
|
"opengl_name": "a_line_type",
|
||||||
"opengl_type": "float"
|
"opengl_type": "float"
|
||||||
|
},
|
||||||
|
"feedrates": {
|
||||||
|
"value": feedrates,
|
||||||
|
"opengl_name": "a_feedrate",
|
||||||
|
"opengl_type": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ class LayerPolygon:
|
||||||
# \param data new_points
|
# \param data new_points
|
||||||
# \param line_widths array with line widths
|
# \param line_widths array with line widths
|
||||||
# \param line_thicknesses: array with type as index and thickness as value
|
# \param line_thicknesses: array with type as index and thickness as value
|
||||||
def __init__(self, extruder, line_types, data, line_widths, line_thicknesses):
|
# \param line_feedrates array with line feedrates
|
||||||
|
def __init__(self, extruder, line_types, data, line_widths, line_thicknesses, line_feedrates):
|
||||||
self._extruder = extruder
|
self._extruder = extruder
|
||||||
self._types = line_types
|
self._types = line_types
|
||||||
for i in range(len(self._types)):
|
for i in range(len(self._types)):
|
||||||
|
@ -37,6 +38,7 @@ class LayerPolygon:
|
||||||
self._data = data
|
self._data = data
|
||||||
self._line_widths = line_widths
|
self._line_widths = line_widths
|
||||||
self._line_thicknesses = line_thicknesses
|
self._line_thicknesses = line_thicknesses
|
||||||
|
self._line_feedrates = line_feedrates
|
||||||
|
|
||||||
self._vertex_begin = 0
|
self._vertex_begin = 0
|
||||||
self._vertex_end = 0
|
self._vertex_end = 0
|
||||||
|
@ -84,10 +86,11 @@ class LayerPolygon:
|
||||||
# \param vertices : vertex numpy array to be filled
|
# \param vertices : vertex numpy array to be filled
|
||||||
# \param colors : vertex numpy array to be filled
|
# \param colors : vertex numpy array to be filled
|
||||||
# \param line_dimensions : vertex numpy array to be filled
|
# \param line_dimensions : vertex numpy array to be filled
|
||||||
|
# \param feedrates : vertex numpy array to be filled
|
||||||
# \param extruders : vertex numpy array to be filled
|
# \param extruders : vertex numpy array to be filled
|
||||||
# \param line_types : vertex numpy array to be filled
|
# \param line_types : vertex numpy array to be filled
|
||||||
# \param indices : index numpy array to be filled
|
# \param indices : index numpy array to be filled
|
||||||
def build(self, vertex_offset, index_offset, vertices, colors, line_dimensions, extruders, line_types, indices):
|
def build(self, vertex_offset, index_offset, vertices, colors, line_dimensions, feedrates, extruders, line_types, indices):
|
||||||
if self._build_cache_line_mesh_mask is None or self._build_cache_needed_points is None:
|
if self._build_cache_line_mesh_mask is None or self._build_cache_needed_points is None:
|
||||||
self.buildCache()
|
self.buildCache()
|
||||||
|
|
||||||
|
@ -109,10 +112,13 @@ class LayerPolygon:
|
||||||
# Create an array with colors for each vertex and remove the color data for the points that has been thrown away.
|
# Create an array with colors for each vertex and remove the color data for the points that has been thrown away.
|
||||||
colors[self._vertex_begin:self._vertex_end, :] = numpy.tile(self._colors, (1, 2)).reshape((-1, 4))[needed_points_list.ravel()]
|
colors[self._vertex_begin:self._vertex_end, :] = numpy.tile(self._colors, (1, 2)).reshape((-1, 4))[needed_points_list.ravel()]
|
||||||
|
|
||||||
# Create an array with line widths for each vertex.
|
# Create an array with line widths and thicknesses for each vertex.
|
||||||
line_dimensions[self._vertex_begin:self._vertex_end, 0] = numpy.tile(self._line_widths, (1, 2)).reshape((-1, 1))[needed_points_list.ravel()][:, 0]
|
line_dimensions[self._vertex_begin:self._vertex_end, 0] = numpy.tile(self._line_widths, (1, 2)).reshape((-1, 1))[needed_points_list.ravel()][:, 0]
|
||||||
line_dimensions[self._vertex_begin:self._vertex_end, 1] = numpy.tile(self._line_thicknesses, (1, 2)).reshape((-1, 1))[needed_points_list.ravel()][:, 0]
|
line_dimensions[self._vertex_begin:self._vertex_end, 1] = numpy.tile(self._line_thicknesses, (1, 2)).reshape((-1, 1))[needed_points_list.ravel()][:, 0]
|
||||||
|
|
||||||
|
# Create an array with feedrates for each line
|
||||||
|
feedrates[self._vertex_begin:self._vertex_end] = numpy.tile(self._line_feedrates, (1, 2)).reshape((-1, 1))[needed_points_list.ravel()][:, 0]
|
||||||
|
|
||||||
extruders[self._vertex_begin:self._vertex_end] = self._extruder
|
extruders[self._vertex_begin:self._vertex_end] = self._extruder
|
||||||
|
|
||||||
# Convert type per vertex to type per line
|
# Convert type per vertex to type per line
|
||||||
|
@ -166,6 +172,14 @@ class LayerPolygon:
|
||||||
@property
|
@property
|
||||||
def lineWidths(self):
|
def lineWidths(self):
|
||||||
return self._line_widths
|
return self._line_widths
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lineThicknesses(self):
|
||||||
|
return self._line_thicknesses
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lineFeedrates(self):
|
||||||
|
return self._line_feedrates
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def jumpMask(self):
|
def jumpMask(self):
|
||||||
|
|
|
@ -61,6 +61,8 @@ message Polygon {
|
||||||
Type type = 1; // Type of move
|
Type type = 1; // Type of move
|
||||||
bytes points = 2; // The points of the polygon, or two points if only a line segment (Currently only line segments are used)
|
bytes points = 2; // The points of the polygon, or two points if only a line segment (Currently only line segments are used)
|
||||||
float line_width = 3; // The width of the line being laid down
|
float line_width = 3; // The width of the line being laid down
|
||||||
|
float line_thickness = 4; // The thickness of the line being laid down
|
||||||
|
float line_feedrate = 5; // The feedrate of the line being laid down
|
||||||
}
|
}
|
||||||
|
|
||||||
message LayerOptimized {
|
message LayerOptimized {
|
||||||
|
@ -82,6 +84,8 @@ message PathSegment {
|
||||||
bytes points = 3; // The points defining the line segments, bytes of float[2/3] array of length N+1
|
bytes points = 3; // The points defining the line segments, bytes of float[2/3] array of length N+1
|
||||||
bytes line_type = 4; // Type of line segment as an unsigned char array of length 1 or N, where N is the number of line segments in this path
|
bytes line_type = 4; // Type of line segment as an unsigned char array of length 1 or N, where N is the number of line segments in this path
|
||||||
bytes line_width = 5; // The widths of the line segments as bytes of a float array of length 1 or N
|
bytes line_width = 5; // The widths of the line segments as bytes of a float array of length 1 or N
|
||||||
|
bytes line_thickness = 6; // The thickness of the line segments as bytes of a float array of length 1 or N
|
||||||
|
bytes line_feedrate = 7; // The feedrate of the line segments as bytes of a float array of length 1 or N
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -608,7 +608,7 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
def _onActiveViewChanged(self):
|
def _onActiveViewChanged(self):
|
||||||
if Application.getInstance().getController().getActiveView():
|
if Application.getInstance().getController().getActiveView():
|
||||||
view = Application.getInstance().getController().getActiveView()
|
view = Application.getInstance().getController().getActiveView()
|
||||||
if view.getPluginId() == "LayerView": # If switching to layer view, we should process the layers if that hasn't been done yet.
|
if view.getPluginId() == "SimulationView": # If switching to layer view, we should process the layers if that hasn't been done yet.
|
||||||
self._layer_view_active = True
|
self._layer_view_active = True
|
||||||
# There is data and we're not slicing at the moment
|
# There is data and we're not slicing at the moment
|
||||||
# if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment.
|
# if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment.
|
||||||
|
|
|
@ -61,7 +61,7 @@ class ProcessSlicedLayersJob(Job):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
start_time = time()
|
start_time = time()
|
||||||
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
|
if Application.getInstance().getController().getActiveView().getPluginId() == "SimulationView":
|
||||||
self._progress_message.show()
|
self._progress_message.show()
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
if self._abort_requested:
|
if self._abort_requested:
|
||||||
|
@ -109,6 +109,7 @@ class ProcessSlicedLayersJob(Job):
|
||||||
layer_data.addLayer(abs_layer_number)
|
layer_data.addLayer(abs_layer_number)
|
||||||
this_layer = layer_data.getLayer(abs_layer_number)
|
this_layer = layer_data.getLayer(abs_layer_number)
|
||||||
layer_data.setLayerHeight(abs_layer_number, layer.height)
|
layer_data.setLayerHeight(abs_layer_number, layer.height)
|
||||||
|
layer_data.setLayerThickness(abs_layer_number, layer.thickness)
|
||||||
|
|
||||||
for p in range(layer.repeatedMessageCount("path_segment")):
|
for p in range(layer.repeatedMessageCount("path_segment")):
|
||||||
polygon = layer.getRepeatedMessage("path_segment", p)
|
polygon = layer.getRepeatedMessage("path_segment", p)
|
||||||
|
@ -127,10 +128,11 @@ class ProcessSlicedLayersJob(Job):
|
||||||
line_widths = numpy.fromstring(polygon.line_width, dtype="f4") # Convert bytearray to numpy array
|
line_widths = numpy.fromstring(polygon.line_width, dtype="f4") # Convert bytearray to numpy array
|
||||||
line_widths = line_widths.reshape((-1,1)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
|
line_widths = line_widths.reshape((-1,1)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
|
||||||
|
|
||||||
# In the future, line_thicknesses should be given by CuraEngine as well.
|
line_thicknesses = numpy.fromstring(polygon.line_thickness, dtype="f4") # Convert bytearray to numpy array
|
||||||
# Currently the infill layer thickness also translates to line width
|
line_thicknesses = line_thicknesses.reshape((-1,1)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
|
||||||
line_thicknesses = numpy.zeros(line_widths.shape, dtype="f4")
|
|
||||||
line_thicknesses[:] = layer.thickness / 1000 # from micrometer to millimeter
|
line_feedrates = numpy.fromstring(polygon.line_feedrate, dtype="f4") # Convert bytearray to numpy array
|
||||||
|
line_feedrates = line_feedrates.reshape((-1,1)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
|
||||||
|
|
||||||
# Create a new 3D-array, copy the 2D points over and insert the right height.
|
# Create a new 3D-array, copy the 2D points over and insert the right height.
|
||||||
# This uses manual array creation + copy rather than numpy.insert since this is
|
# This uses manual array creation + copy rather than numpy.insert since this is
|
||||||
|
@ -145,7 +147,7 @@ class ProcessSlicedLayersJob(Job):
|
||||||
new_points[:, 1] = points[:, 2]
|
new_points[:, 1] = points[:, 2]
|
||||||
new_points[:, 2] = -points[:, 1]
|
new_points[:, 2] = -points[:, 1]
|
||||||
|
|
||||||
this_poly = LayerPolygon.LayerPolygon(extruder, line_types, new_points, line_widths, line_thicknesses)
|
this_poly = LayerPolygon.LayerPolygon(extruder, line_types, new_points, line_widths, line_thicknesses, line_feedrates)
|
||||||
this_poly.buildCache()
|
this_poly.buildCache()
|
||||||
|
|
||||||
this_layer.polygons.append(this_poly)
|
this_layer.polygons.append(this_poly)
|
||||||
|
@ -219,7 +221,7 @@ class ProcessSlicedLayersJob(Job):
|
||||||
self._progress_message.setProgress(100)
|
self._progress_message.setProgress(100)
|
||||||
|
|
||||||
view = Application.getInstance().getController().getActiveView()
|
view = Application.getInstance().getController().getActiveView()
|
||||||
if view.getPluginId() == "LayerView":
|
if view.getPluginId() == "SimulationView":
|
||||||
view.resetLayerData()
|
view.resetLayerData()
|
||||||
|
|
||||||
if self._progress_message:
|
if self._progress_message:
|
||||||
|
@ -232,7 +234,7 @@ class ProcessSlicedLayersJob(Job):
|
||||||
|
|
||||||
def _onActiveViewChanged(self):
|
def _onActiveViewChanged(self):
|
||||||
if self.isRunning():
|
if self.isRunning():
|
||||||
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
|
if Application.getInstance().getController().getActiveView().getPluginId() == "SimulationView":
|
||||||
if not self._progress_message:
|
if not self._progress_message:
|
||||||
self._progress_message = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, 0, catalog.i18nc("@info:title", "Information"))
|
self._progress_message = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, 0, catalog.i18nc("@info:title", "Information"))
|
||||||
if self._progress_message.getProgress() != 100:
|
if self._progress_message.getProgress() != 100:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2016 Aleph Objects, Inc.
|
# Copyright (c) 2017 Aleph Objects, Inc.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
|
@ -40,7 +40,8 @@ class GCodeReader(MeshReader):
|
||||||
self._extruder_number = 0
|
self._extruder_number = 0
|
||||||
self._clearValues()
|
self._clearValues()
|
||||||
self._scene_node = None
|
self._scene_node = None
|
||||||
self._position = namedtuple('Position', ['x', 'y', 'z', 'e'])
|
# X, Y, Z position, F feedrate and E extruder values are stored
|
||||||
|
self._position = namedtuple('Position', ['x', 'y', 'z', 'f', 'e'])
|
||||||
self._is_layers_in_file = False # Does the Gcode have the layers comment?
|
self._is_layers_in_file = False # Does the Gcode have the layers comment?
|
||||||
self._extruder_offsets = {} # Offsets for multi extruders. key is index, value is [x-offset, y-offset]
|
self._extruder_offsets = {} # Offsets for multi extruders. key is index, value is [x-offset, y-offset]
|
||||||
self._current_layer_thickness = 0.2 # default
|
self._current_layer_thickness = 0.2 # default
|
||||||
|
@ -48,7 +49,9 @@ class GCodeReader(MeshReader):
|
||||||
Preferences.getInstance().addPreference("gcodereader/show_caution", True)
|
Preferences.getInstance().addPreference("gcodereader/show_caution", True)
|
||||||
|
|
||||||
def _clearValues(self):
|
def _clearValues(self):
|
||||||
|
self._filament_diameter = 2.85
|
||||||
self._extruder_number = 0
|
self._extruder_number = 0
|
||||||
|
self._extrusion_length_offset = [0]
|
||||||
self._layer_type = LayerPolygon.Inset0Type
|
self._layer_type = LayerPolygon.Inset0Type
|
||||||
self._layer_number = 0
|
self._layer_number = 0
|
||||||
self._previous_z = 0
|
self._previous_z = 0
|
||||||
|
@ -97,7 +100,7 @@ class GCodeReader(MeshReader):
|
||||||
def _createPolygon(self, layer_thickness, path, extruder_offsets):
|
def _createPolygon(self, layer_thickness, path, extruder_offsets):
|
||||||
countvalid = 0
|
countvalid = 0
|
||||||
for point in path:
|
for point in path:
|
||||||
if point[3] > 0:
|
if point[5] > 0:
|
||||||
countvalid += 1
|
countvalid += 1
|
||||||
if countvalid >= 2:
|
if countvalid >= 2:
|
||||||
# we know what to do now, no need to count further
|
# we know what to do now, no need to count further
|
||||||
|
@ -115,27 +118,56 @@ class GCodeReader(MeshReader):
|
||||||
line_types = numpy.empty((count - 1, 1), numpy.int32)
|
line_types = numpy.empty((count - 1, 1), numpy.int32)
|
||||||
line_widths = numpy.empty((count - 1, 1), numpy.float32)
|
line_widths = numpy.empty((count - 1, 1), numpy.float32)
|
||||||
line_thicknesses = numpy.empty((count - 1, 1), numpy.float32)
|
line_thicknesses = numpy.empty((count - 1, 1), numpy.float32)
|
||||||
# TODO: need to calculate actual line width based on E values
|
line_feedrates = numpy.empty((count - 1, 1), numpy.float32)
|
||||||
line_widths[:, 0] = 0.35 # Just a guess
|
line_widths[:, 0] = 0.35 # Just a guess
|
||||||
line_thicknesses[:, 0] = layer_thickness
|
line_thicknesses[:, 0] = layer_thickness
|
||||||
points = numpy.empty((count, 3), numpy.float32)
|
points = numpy.empty((count, 3), numpy.float32)
|
||||||
|
extrusion_values = numpy.empty((count, 1), numpy.float32)
|
||||||
i = 0
|
i = 0
|
||||||
for point in path:
|
for point in path:
|
||||||
points[i, :] = [point[0] + extruder_offsets[0], point[2], -point[1] - extruder_offsets[1]]
|
points[i, :] = [point[0] + extruder_offsets[0], point[2], -point[1] - extruder_offsets[1]]
|
||||||
|
extrusion_values[i] = point[4]
|
||||||
if i > 0:
|
if i > 0:
|
||||||
line_types[i - 1] = point[3]
|
line_feedrates[i - 1] = point[3]
|
||||||
if point[3] in [LayerPolygon.MoveCombingType, LayerPolygon.MoveRetractionType]:
|
line_types[i - 1] = point[5]
|
||||||
|
if point[5] in [LayerPolygon.MoveCombingType, LayerPolygon.MoveRetractionType]:
|
||||||
line_widths[i - 1] = 0.1
|
line_widths[i - 1] = 0.1
|
||||||
|
line_thicknesses[i - 1] = 0.0 # Travels are set as zero thickness lines
|
||||||
|
else:
|
||||||
|
line_widths[i - 1] = self._calculateLineWidth(points[i], points[i-1], extrusion_values[i], extrusion_values[i-1], layer_thickness)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
this_poly = LayerPolygon(self._extruder_number, line_types, points, line_widths, line_thicknesses)
|
this_poly = LayerPolygon(self._extruder_number, line_types, points, line_widths, line_thicknesses, line_feedrates)
|
||||||
this_poly.buildCache()
|
this_poly.buildCache()
|
||||||
|
|
||||||
this_layer.polygons.append(this_poly)
|
this_layer.polygons.append(this_poly)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _calculateLineWidth(self, current_point, previous_point, current_extrusion, previous_extrusion, layer_thickness):
|
||||||
|
# Area of the filament
|
||||||
|
Af = (self._filament_diameter / 2) ** 2 * numpy.pi
|
||||||
|
# Length of the extruded filament
|
||||||
|
de = current_extrusion - previous_extrusion
|
||||||
|
# Volumne of the extruded filament
|
||||||
|
dVe = de * Af
|
||||||
|
# Length of the printed line
|
||||||
|
dX = numpy.sqrt((current_point[0] - previous_point[0])**2 + (current_point[2] - previous_point[2])**2)
|
||||||
|
# When the extruder recovers from a retraction, we get zero distance
|
||||||
|
if dX == 0:
|
||||||
|
return 0.1
|
||||||
|
# Area of the printed line. This area is a rectangle
|
||||||
|
Ae = dVe / dX
|
||||||
|
# This area is a rectangle with area equal to layer_thickness * layer_width
|
||||||
|
line_width = Ae / layer_thickness
|
||||||
|
|
||||||
|
# A threshold is set to avoid weird paths in the GCode
|
||||||
|
if line_width > 1.2:
|
||||||
|
return 0.35
|
||||||
|
return line_width
|
||||||
|
|
||||||
def _gCode0(self, position, params, path):
|
def _gCode0(self, position, params, path):
|
||||||
x, y, z, e = position
|
x, y, z, f, e = position
|
||||||
|
|
||||||
if self._is_absolute_positioning:
|
if self._is_absolute_positioning:
|
||||||
x = params.x if params.x is not None else x
|
x = params.x if params.x is not None else x
|
||||||
y = params.y if params.y is not None else y
|
y = params.y if params.y is not None else y
|
||||||
|
@ -145,22 +177,24 @@ class GCodeReader(MeshReader):
|
||||||
y += params.y if params.y is not None else 0
|
y += params.y if params.y is not None else 0
|
||||||
z += params.z if params.z is not None else 0
|
z += params.z if params.z is not None else 0
|
||||||
|
|
||||||
|
f = params.f if params.f is not None else f
|
||||||
|
|
||||||
if params.e is not None:
|
if params.e is not None:
|
||||||
new_extrusion_value = params.e if self._is_absolute_positioning else e[self._extruder_number] + params.e
|
new_extrusion_value = params.e if self._is_absolute_positioning else e[self._extruder_number] + params.e
|
||||||
if new_extrusion_value > e[self._extruder_number]:
|
if new_extrusion_value > e[self._extruder_number]:
|
||||||
path.append([x, y, z, self._layer_type]) # extrusion
|
path.append([x, y, z, f, params.e + self._extrusion_length_offset[self._extruder_number], self._layer_type]) # extrusion
|
||||||
else:
|
else:
|
||||||
path.append([x, y, z, LayerPolygon.MoveRetractionType]) # retraction
|
path.append([x, y, z, f, params.e + self._extrusion_length_offset[self._extruder_number], LayerPolygon.MoveRetractionType]) # retraction
|
||||||
e[self._extruder_number] = new_extrusion_value
|
e[self._extruder_number] = new_extrusion_value
|
||||||
|
|
||||||
# Only when extruding we can determine the latest known "layer height" which is the difference in height between extrusions
|
# Only when extruding we can determine the latest known "layer height" which is the difference in height between extrusions
|
||||||
# Also, 1.5 is a heuristic for any priming or whatsoever, we skip those.
|
# Also, 1.5 is a heuristic for any priming or whatsoever, we skip those.
|
||||||
if z > self._previous_z and (z - self._previous_z < 1.5):
|
if z > self._previous_z and (z - self._previous_z < 1.5):
|
||||||
self._current_layer_thickness = z - self._previous_z + 0.05 # allow a tiny overlap
|
self._current_layer_thickness = z - self._previous_z # allow a tiny overlap
|
||||||
self._previous_z = z
|
self._previous_z = z
|
||||||
else:
|
else:
|
||||||
path.append([x, y, z, LayerPolygon.MoveCombingType])
|
path.append([x, y, z, f, e[self._extruder_number] + self._extrusion_length_offset[self._extruder_number], LayerPolygon.MoveCombingType])
|
||||||
return self._position(x, y, z, e)
|
return self._position(x, y, z, f, e)
|
||||||
|
|
||||||
# G0 and G1 should be handled exactly the same.
|
# G0 and G1 should be handled exactly the same.
|
||||||
_gCode1 = _gCode0
|
_gCode1 = _gCode0
|
||||||
|
@ -171,6 +205,7 @@ class GCodeReader(MeshReader):
|
||||||
params.x if params.x is not None else position.x,
|
params.x if params.x is not None else position.x,
|
||||||
params.y if params.y is not None else position.y,
|
params.y if params.y is not None else position.y,
|
||||||
0,
|
0,
|
||||||
|
position.f,
|
||||||
position.e)
|
position.e)
|
||||||
|
|
||||||
## Set the absolute positioning
|
## Set the absolute positioning
|
||||||
|
@ -187,11 +222,14 @@ class GCodeReader(MeshReader):
|
||||||
# For example: G92 X10 will set the X to 10 without any physical motion.
|
# For example: G92 X10 will set the X to 10 without any physical motion.
|
||||||
def _gCode92(self, position, params, path):
|
def _gCode92(self, position, params, path):
|
||||||
if params.e is not None:
|
if params.e is not None:
|
||||||
|
# Sometimes a G92 E0 is introduced in the middle of the GCode so we need to keep those offsets for calculate the line_width
|
||||||
|
self._extrusion_length_offset[self._extruder_number] += position.e[self._extruder_number] - params.e
|
||||||
position.e[self._extruder_number] = params.e
|
position.e[self._extruder_number] = params.e
|
||||||
return self._position(
|
return self._position(
|
||||||
params.x if params.x is not None else position.x,
|
params.x if params.x is not None else position.x,
|
||||||
params.y if params.y is not None else position.y,
|
params.y if params.y is not None else position.y,
|
||||||
params.z if params.z is not None else position.z,
|
params.z if params.z is not None else position.z,
|
||||||
|
params.f if params.f is not None else position.f,
|
||||||
position.e)
|
position.e)
|
||||||
|
|
||||||
def _processGCode(self, G, line, position, path):
|
def _processGCode(self, G, line, position, path):
|
||||||
|
@ -199,7 +237,7 @@ class GCodeReader(MeshReader):
|
||||||
line = line.split(";", 1)[0] # Remove comments (if any)
|
line = line.split(";", 1)[0] # Remove comments (if any)
|
||||||
if func is not None:
|
if func is not None:
|
||||||
s = line.upper().split(" ")
|
s = line.upper().split(" ")
|
||||||
x, y, z, e = None, None, None, None
|
x, y, z, f, e = None, None, None, None, None
|
||||||
for item in s[1:]:
|
for item in s[1:]:
|
||||||
if len(item) <= 1:
|
if len(item) <= 1:
|
||||||
continue
|
continue
|
||||||
|
@ -211,17 +249,20 @@ class GCodeReader(MeshReader):
|
||||||
y = float(item[1:])
|
y = float(item[1:])
|
||||||
if item[0] == "Z":
|
if item[0] == "Z":
|
||||||
z = float(item[1:])
|
z = float(item[1:])
|
||||||
|
if item[0] == "F":
|
||||||
|
f = float(item[1:]) / 60
|
||||||
if item[0] == "E":
|
if item[0] == "E":
|
||||||
e = float(item[1:])
|
e = float(item[1:])
|
||||||
if self._is_absolute_positioning and ((x is not None and x < 0) or (y is not None and y < 0)):
|
if self._is_absolute_positioning and ((x is not None and x < 0) or (y is not None and y < 0)):
|
||||||
self._center_is_zero = True
|
self._center_is_zero = True
|
||||||
params = self._position(x, y, z, e)
|
params = self._position(x, y, z, f, e)
|
||||||
return func(position, params, path)
|
return func(position, params, path)
|
||||||
return position
|
return position
|
||||||
|
|
||||||
def _processTCode(self, T, line, position, path):
|
def _processTCode(self, T, line, position, path):
|
||||||
self._extruder_number = T
|
self._extruder_number = T
|
||||||
if self._extruder_number + 1 > len(position.e):
|
if self._extruder_number + 1 > len(position.e):
|
||||||
|
self._extrusion_length_offset.extend([0] * (self._extruder_number - len(position.e) + 1))
|
||||||
position.e.extend([0] * (self._extruder_number - len(position.e) + 1))
|
position.e.extend([0] * (self._extruder_number - len(position.e) + 1))
|
||||||
return position
|
return position
|
||||||
|
|
||||||
|
@ -240,6 +281,8 @@ class GCodeReader(MeshReader):
|
||||||
def read(self, file_name):
|
def read(self, file_name):
|
||||||
Logger.log("d", "Preparing to load %s" % file_name)
|
Logger.log("d", "Preparing to load %s" % file_name)
|
||||||
self._cancelled = False
|
self._cancelled = False
|
||||||
|
# We obtain the filament diameter from the selected printer to calculate line widths
|
||||||
|
self._filament_diameter = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value")
|
||||||
|
|
||||||
scene_node = SceneNode()
|
scene_node = SceneNode()
|
||||||
# Override getBoundingBox function of the sceneNode, as this node should return a bounding box, but there is no
|
# Override getBoundingBox function of the sceneNode, as this node should return a bounding box, but there is no
|
||||||
|
@ -277,7 +320,7 @@ class GCodeReader(MeshReader):
|
||||||
|
|
||||||
Logger.log("d", "Parsing %s..." % file_name)
|
Logger.log("d", "Parsing %s..." % file_name)
|
||||||
|
|
||||||
current_position = self._position(0, 0, 0, [0])
|
current_position = self._position(0, 0, 0, 0, [0])
|
||||||
current_path = []
|
current_path = []
|
||||||
|
|
||||||
for line in file:
|
for line in file:
|
||||||
|
@ -310,6 +353,7 @@ class GCodeReader(MeshReader):
|
||||||
else:
|
else:
|
||||||
Logger.log("w", "Encountered a unknown type (%s) while parsing g-code.", type)
|
Logger.log("w", "Encountered a unknown type (%s) while parsing g-code.", type)
|
||||||
|
|
||||||
|
# When the layer change is reached, the polygon is computed so we have just one layer per layer per extruder
|
||||||
if self._is_layers_in_file and line[:len(self._layer_keyword)] == self._layer_keyword:
|
if self._is_layers_in_file and line[:len(self._layer_keyword)] == self._layer_keyword:
|
||||||
try:
|
try:
|
||||||
layer_number = int(line[len(self._layer_keyword):])
|
layer_number = int(line[len(self._layer_keyword):])
|
||||||
|
@ -325,17 +369,12 @@ class GCodeReader(MeshReader):
|
||||||
|
|
||||||
G = self._getInt(line, "G")
|
G = self._getInt(line, "G")
|
||||||
if G is not None:
|
if G is not None:
|
||||||
|
# When find a movement, the new posistion is calculated and added to the current_path, but
|
||||||
|
# don't need to create a polygon until the end of the layer
|
||||||
current_position = self._processGCode(G, line, current_position, current_path)
|
current_position = self._processGCode(G, line, current_position, current_path)
|
||||||
|
|
||||||
# < 2 is a heuristic for a movement only, that should not be counted as a layer
|
|
||||||
if current_position.z > last_z and abs(current_position.z - last_z) < 2:
|
|
||||||
if self._createPolygon(self._current_layer_thickness, current_path, self._extruder_offsets.get(self._extruder_number, [0, 0])):
|
|
||||||
current_path.clear()
|
|
||||||
if not self._is_layers_in_file:
|
|
||||||
self._layer_number += 1
|
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# When changing the extruder, the polygon with the stored paths is computed
|
||||||
if line.startswith("T"):
|
if line.startswith("T"):
|
||||||
T = self._getInt(line, "T")
|
T = self._getInt(line, "T")
|
||||||
if T is not None:
|
if T is not None:
|
||||||
|
@ -344,8 +383,8 @@ class GCodeReader(MeshReader):
|
||||||
|
|
||||||
current_position = self._processTCode(T, line, current_position, current_path)
|
current_position = self._processTCode(T, line, current_position, current_path)
|
||||||
|
|
||||||
# "Flush" leftovers
|
# "Flush" leftovers. Last layer paths are still stored
|
||||||
if not self._is_layers_in_file and len(current_path) > 1:
|
if len(current_path) > 1:
|
||||||
if self._createPolygon(self._current_layer_thickness, current_path, self._extruder_offsets.get(self._extruder_number, [0, 0])):
|
if self._createPolygon(self._current_layer_thickness, current_path, self._extruder_offsets.get(self._extruder_number, [0, 0])):
|
||||||
self._layer_number += 1
|
self._layer_number += 1
|
||||||
current_path.clear()
|
current_path.clear()
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
# Copyright (c) 2016 Ultimaker B.V.
|
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
|
||||||
|
|
||||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
|
||||||
from UM.Resources import Resources
|
|
||||||
from UM.Scene.SceneNode import SceneNode
|
|
||||||
from UM.Scene.ToolHandle import ToolHandle
|
|
||||||
from UM.Application import Application
|
|
||||||
from UM.PluginRegistry import PluginRegistry
|
|
||||||
|
|
||||||
from UM.View.RenderPass import RenderPass
|
|
||||||
from UM.View.RenderBatch import RenderBatch
|
|
||||||
from UM.View.GL.OpenGL import OpenGL
|
|
||||||
|
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
## RenderPass used to display g-code paths.
|
|
||||||
class LayerPass(RenderPass):
|
|
||||||
def __init__(self, width, height):
|
|
||||||
super().__init__("layerview", width, height)
|
|
||||||
|
|
||||||
self._layer_shader = None
|
|
||||||
self._tool_handle_shader = None
|
|
||||||
self._gl = OpenGL.getInstance().getBindingsObject()
|
|
||||||
self._scene = Application.getInstance().getController().getScene()
|
|
||||||
self._extruder_manager = ExtruderManager.getInstance()
|
|
||||||
|
|
||||||
self._layer_view = None
|
|
||||||
self._compatibility_mode = None
|
|
||||||
|
|
||||||
def setLayerView(self, layerview):
|
|
||||||
self._layer_view = layerview
|
|
||||||
self._compatibility_mode = layerview.getCompatibilityMode()
|
|
||||||
|
|
||||||
def render(self):
|
|
||||||
if not self._layer_shader:
|
|
||||||
if self._compatibility_mode:
|
|
||||||
shader_filename = "layers.shader"
|
|
||||||
else:
|
|
||||||
shader_filename = "layers3d.shader"
|
|
||||||
self._layer_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("LayerView"), shader_filename))
|
|
||||||
# Use extruder 0 if the extruder manager reports extruder index -1 (for single extrusion printers)
|
|
||||||
self._layer_shader.setUniformValue("u_active_extruder", float(max(0, self._extruder_manager.activeExtruderIndex)))
|
|
||||||
if self._layer_view:
|
|
||||||
self._layer_shader.setUniformValue("u_layer_view_type", self._layer_view.getLayerViewType())
|
|
||||||
self._layer_shader.setUniformValue("u_extruder_opacity", self._layer_view.getExtruderOpacities())
|
|
||||||
self._layer_shader.setUniformValue("u_show_travel_moves", self._layer_view.getShowTravelMoves())
|
|
||||||
self._layer_shader.setUniformValue("u_show_helpers", self._layer_view.getShowHelpers())
|
|
||||||
self._layer_shader.setUniformValue("u_show_skin", self._layer_view.getShowSkin())
|
|
||||||
self._layer_shader.setUniformValue("u_show_infill", self._layer_view.getShowInfill())
|
|
||||||
else:
|
|
||||||
#defaults
|
|
||||||
self._layer_shader.setUniformValue("u_layer_view_type", 1)
|
|
||||||
self._layer_shader.setUniformValue("u_extruder_opacity", [1, 1, 1, 1])
|
|
||||||
self._layer_shader.setUniformValue("u_show_travel_moves", 0)
|
|
||||||
self._layer_shader.setUniformValue("u_show_helpers", 1)
|
|
||||||
self._layer_shader.setUniformValue("u_show_skin", 1)
|
|
||||||
self._layer_shader.setUniformValue("u_show_infill", 1)
|
|
||||||
|
|
||||||
if not self._tool_handle_shader:
|
|
||||||
self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "toolhandle.shader"))
|
|
||||||
|
|
||||||
self.bind()
|
|
||||||
|
|
||||||
tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Overlay)
|
|
||||||
|
|
||||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
|
||||||
|
|
||||||
if isinstance(node, ToolHandle):
|
|
||||||
tool_handle_batch.addItem(node.getWorldTransformation(), mesh = node.getSolidMesh())
|
|
||||||
|
|
||||||
elif isinstance(node, SceneNode) and (node.getMeshData() or node.callDecoration("isBlockSlicing")) and node.isVisible():
|
|
||||||
layer_data = node.callDecoration("getLayerData")
|
|
||||||
if not layer_data:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Render all layers below a certain number as line mesh instead of vertices.
|
|
||||||
if self._layer_view._current_layer_num > -1 and ((not self._layer_view._only_show_top_layers) or (not self._layer_view.getCompatibilityMode())):
|
|
||||||
start = 0
|
|
||||||
end = 0
|
|
||||||
element_counts = layer_data.getElementCounts()
|
|
||||||
for layer in sorted(element_counts.keys()):
|
|
||||||
if layer > self._layer_view._current_layer_num:
|
|
||||||
break
|
|
||||||
if self._layer_view._minimum_layer_num > layer:
|
|
||||||
start += element_counts[layer]
|
|
||||||
end += element_counts[layer]
|
|
||||||
|
|
||||||
# This uses glDrawRangeElements internally to only draw a certain range of lines.
|
|
||||||
batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (start, end))
|
|
||||||
batch.addItem(node.getWorldTransformation(), layer_data)
|
|
||||||
batch.render(self._scene.getActiveCamera())
|
|
||||||
|
|
||||||
# Create a new batch that is not range-limited
|
|
||||||
batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid)
|
|
||||||
|
|
||||||
if self._layer_view.getCurrentLayerMesh():
|
|
||||||
batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerMesh())
|
|
||||||
|
|
||||||
if self._layer_view.getCurrentLayerJumps():
|
|
||||||
batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerJumps())
|
|
||||||
|
|
||||||
if len(batch.items) > 0:
|
|
||||||
batch.render(self._scene.getActiveCamera())
|
|
||||||
|
|
||||||
# Render toolhandles on top of the layerview
|
|
||||||
if len(tool_handle_batch.items) > 0:
|
|
||||||
tool_handle_batch.render(self._scene.getActiveCamera())
|
|
||||||
|
|
||||||
self.release()
|
|
|
@ -1,312 +0,0 @@
|
||||||
// Copyright (c) 2017 Ultimaker B.V.
|
|
||||||
// Cura is released under the terms of the LGPLv3 or higher.
|
|
||||||
|
|
||||||
import QtQuick 2.2
|
|
||||||
import QtQuick.Controls 1.2
|
|
||||||
import QtQuick.Layouts 1.1
|
|
||||||
import QtQuick.Controls.Styles 1.1
|
|
||||||
|
|
||||||
import UM 1.0 as UM
|
|
||||||
import Cura 1.0 as Cura
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: sliderRoot
|
|
||||||
|
|
||||||
// handle properties
|
|
||||||
property real handleSize: 10
|
|
||||||
property real handleRadius: handleSize / 2
|
|
||||||
property real minimumRangeHandleSize: handleSize / 2
|
|
||||||
property color upperHandleColor: "black"
|
|
||||||
property color lowerHandleColor: "black"
|
|
||||||
property color rangeHandleColor: "black"
|
|
||||||
property real handleLabelWidth: width
|
|
||||||
property var activeHandle: upperHandle
|
|
||||||
|
|
||||||
// track properties
|
|
||||||
property real trackThickness: 4 // width of the slider track
|
|
||||||
property real trackRadius: trackThickness / 2
|
|
||||||
property color trackColor: "white"
|
|
||||||
property real trackBorderWidth: 1 // width of the slider track border
|
|
||||||
property color trackBorderColor: "black"
|
|
||||||
|
|
||||||
// value properties
|
|
||||||
property real maximumValue: 100
|
|
||||||
property real minimumValue: 0
|
|
||||||
property real minimumRange: 0 // minimum range allowed between min and max values
|
|
||||||
property bool roundValues: true
|
|
||||||
property real upperValue: maximumValue
|
|
||||||
property real lowerValue: minimumValue
|
|
||||||
|
|
||||||
property bool layersVisible: true
|
|
||||||
|
|
||||||
function getUpperValueFromSliderHandle () {
|
|
||||||
return upperHandle.getValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
function setUpperValue (value) {
|
|
||||||
upperHandle.setValue(value)
|
|
||||||
updateRangeHandle()
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLowerValueFromSliderHandle () {
|
|
||||||
return lowerHandle.getValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLowerValue (value) {
|
|
||||||
lowerHandle.setValue(value)
|
|
||||||
updateRangeHandle()
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateRangeHandle () {
|
|
||||||
rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the active handle to show only one label at a time
|
|
||||||
function setActiveHandle (handle) {
|
|
||||||
activeHandle = handle
|
|
||||||
}
|
|
||||||
|
|
||||||
// slider track
|
|
||||||
Rectangle {
|
|
||||||
id: track
|
|
||||||
|
|
||||||
width: sliderRoot.trackThickness
|
|
||||||
height: sliderRoot.height - sliderRoot.handleSize
|
|
||||||
radius: sliderRoot.trackRadius
|
|
||||||
anchors.centerIn: sliderRoot
|
|
||||||
color: sliderRoot.trackColor
|
|
||||||
border.width: sliderRoot.trackBorderWidth
|
|
||||||
border.color: sliderRoot.trackBorderColor
|
|
||||||
visible: sliderRoot.layersVisible
|
|
||||||
}
|
|
||||||
|
|
||||||
// Range handle
|
|
||||||
Item {
|
|
||||||
id: rangeHandle
|
|
||||||
|
|
||||||
y: upperHandle.y + upperHandle.height
|
|
||||||
width: sliderRoot.handleSize
|
|
||||||
height: sliderRoot.minimumRangeHandleSize
|
|
||||||
anchors.horizontalCenter: sliderRoot.horizontalCenter
|
|
||||||
visible: sliderRoot.layersVisible
|
|
||||||
|
|
||||||
// set the new value when dragging
|
|
||||||
function onHandleDragged () {
|
|
||||||
|
|
||||||
upperHandle.y = y - upperHandle.height
|
|
||||||
lowerHandle.y = y + height
|
|
||||||
|
|
||||||
var upperValue = sliderRoot.getUpperValueFromSliderHandle()
|
|
||||||
var lowerValue = sliderRoot.getLowerValueFromSliderHandle()
|
|
||||||
|
|
||||||
// set both values after moving the handle position
|
|
||||||
UM.LayerView.setCurrentLayer(upperValue)
|
|
||||||
UM.LayerView.setMinimumLayer(lowerValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
function setValue (value) {
|
|
||||||
var range = sliderRoot.upperValue - sliderRoot.lowerValue
|
|
||||||
value = Math.min(value, sliderRoot.maximumValue)
|
|
||||||
value = Math.max(value, sliderRoot.minimumValue + range)
|
|
||||||
|
|
||||||
UM.LayerView.setCurrentLayer(value)
|
|
||||||
UM.LayerView.setMinimumLayer(value - range)
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth
|
|
||||||
height: parent.height + sliderRoot.handleSize
|
|
||||||
anchors.centerIn: parent
|
|
||||||
color: sliderRoot.rangeHandleColor
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
drag {
|
|
||||||
target: parent
|
|
||||||
axis: Drag.YAxis
|
|
||||||
minimumY: upperHandle.height
|
|
||||||
maximumY: sliderRoot.height - (rangeHandle.height + lowerHandle.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
onPositionChanged: parent.onHandleDragged()
|
|
||||||
onPressed: sliderRoot.setActiveHandle(rangeHandle)
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerSliderLabel {
|
|
||||||
id: rangleHandleLabel
|
|
||||||
|
|
||||||
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
|
|
||||||
x: parent.x - width - UM.Theme.getSize("default_margin").width
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
target: Qt.point(sliderRoot.width, y + height / 2)
|
|
||||||
visible: sliderRoot.activeHandle == parent
|
|
||||||
|
|
||||||
// custom properties
|
|
||||||
maximumValue: sliderRoot.maximumValue
|
|
||||||
value: sliderRoot.upperValue
|
|
||||||
busy: UM.LayerView.busy
|
|
||||||
setValue: rangeHandle.setValue // connect callback functions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upper handle
|
|
||||||
Rectangle {
|
|
||||||
id: upperHandle
|
|
||||||
|
|
||||||
y: sliderRoot.height - (sliderRoot.minimumRangeHandleSize + 2 * sliderRoot.handleSize)
|
|
||||||
width: sliderRoot.handleSize
|
|
||||||
height: sliderRoot.handleSize
|
|
||||||
anchors.horizontalCenter: sliderRoot.horizontalCenter
|
|
||||||
radius: sliderRoot.handleRadius
|
|
||||||
color: sliderRoot.upperHandleColor
|
|
||||||
visible: sliderRoot.layersVisible
|
|
||||||
|
|
||||||
function onHandleDragged () {
|
|
||||||
|
|
||||||
// don't allow the lower handle to be heigher than the upper handle
|
|
||||||
if (lowerHandle.y - (y + height) < sliderRoot.minimumRangeHandleSize) {
|
|
||||||
lowerHandle.y = y + height + sliderRoot.minimumRangeHandleSize
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the range handle
|
|
||||||
sliderRoot.updateRangeHandle()
|
|
||||||
|
|
||||||
// set the new value after moving the handle position
|
|
||||||
UM.LayerView.setCurrentLayer(getValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the upper value based on the slider position
|
|
||||||
function getValue () {
|
|
||||||
var result = y / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize))
|
|
||||||
result = sliderRoot.maximumValue + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumValue))
|
|
||||||
result = sliderRoot.roundValues ? Math.round(result) : result
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the slider position based on the upper value
|
|
||||||
function setValue (value) {
|
|
||||||
|
|
||||||
UM.LayerView.setCurrentLayer(value)
|
|
||||||
|
|
||||||
var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
|
|
||||||
var newUpperYPosition = Math.round(diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
|
|
||||||
y = newUpperYPosition
|
|
||||||
|
|
||||||
// update the range handle
|
|
||||||
sliderRoot.updateRangeHandle()
|
|
||||||
}
|
|
||||||
|
|
||||||
// dragging
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
drag {
|
|
||||||
target: parent
|
|
||||||
axis: Drag.YAxis
|
|
||||||
minimumY: 0
|
|
||||||
maximumY: sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
onPositionChanged: parent.onHandleDragged()
|
|
||||||
onPressed: sliderRoot.setActiveHandle(upperHandle)
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerSliderLabel {
|
|
||||||
id: upperHandleLabel
|
|
||||||
|
|
||||||
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
|
|
||||||
x: parent.x - width - UM.Theme.getSize("default_margin").width
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
target: Qt.point(sliderRoot.width, y + height / 2)
|
|
||||||
visible: sliderRoot.activeHandle == parent
|
|
||||||
|
|
||||||
// custom properties
|
|
||||||
maximumValue: sliderRoot.maximumValue
|
|
||||||
value: sliderRoot.upperValue
|
|
||||||
busy: UM.LayerView.busy
|
|
||||||
setValue: upperHandle.setValue // connect callback functions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lower handle
|
|
||||||
Rectangle {
|
|
||||||
id: lowerHandle
|
|
||||||
|
|
||||||
y: sliderRoot.height - sliderRoot.handleSize
|
|
||||||
width: parent.handleSize
|
|
||||||
height: parent.handleSize
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
radius: sliderRoot.handleRadius
|
|
||||||
color: sliderRoot.lowerHandleColor
|
|
||||||
|
|
||||||
visible: slider.layersVisible
|
|
||||||
|
|
||||||
function onHandleDragged () {
|
|
||||||
|
|
||||||
// don't allow the upper handle to be lower than the lower handle
|
|
||||||
if (y - (upperHandle.y + upperHandle.height) < sliderRoot.minimumRangeHandleSize) {
|
|
||||||
upperHandle.y = y - (upperHandle.heigth + sliderRoot.minimumRangeHandleSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the range handle
|
|
||||||
sliderRoot.updateRangeHandle()
|
|
||||||
|
|
||||||
// set the new value after moving the handle position
|
|
||||||
UM.LayerView.setMinimumLayer(getValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the lower value from the current slider position
|
|
||||||
function getValue () {
|
|
||||||
var result = (y - (sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)) / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize));
|
|
||||||
result = sliderRoot.maximumValue - sliderRoot.minimumRange + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumRange))
|
|
||||||
result = sliderRoot.roundValues ? Math.round(result) : result
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the slider position based on the lower value
|
|
||||||
function setValue (value) {
|
|
||||||
|
|
||||||
UM.LayerView.setMinimumLayer(value)
|
|
||||||
|
|
||||||
var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
|
|
||||||
var newLowerYPosition = Math.round((sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize) + diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
|
|
||||||
y = newLowerYPosition
|
|
||||||
|
|
||||||
// update the range handle
|
|
||||||
sliderRoot.updateRangeHandle()
|
|
||||||
}
|
|
||||||
|
|
||||||
// dragging
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
drag {
|
|
||||||
target: parent
|
|
||||||
axis: Drag.YAxis
|
|
||||||
minimumY: upperHandle.height + sliderRoot.minimumRangeHandleSize
|
|
||||||
maximumY: sliderRoot.height - parent.height
|
|
||||||
}
|
|
||||||
|
|
||||||
onPositionChanged: parent.onHandleDragged()
|
|
||||||
onPressed: sliderRoot.setActiveHandle(lowerHandle)
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerSliderLabel {
|
|
||||||
id: lowerHandleLabel
|
|
||||||
|
|
||||||
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
|
|
||||||
x: parent.x - width - UM.Theme.getSize("default_margin").width
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
target: Qt.point(sliderRoot.width, y + height / 2)
|
|
||||||
visible: sliderRoot.activeHandle == parent
|
|
||||||
|
|
||||||
// custom properties
|
|
||||||
maximumValue: sliderRoot.maximumValue
|
|
||||||
value: sliderRoot.lowerValue
|
|
||||||
busy: UM.LayerView.busy
|
|
||||||
setValue: lowerHandle.setValue // connect callback functions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
// Copyright (c) 2017 Ultimaker B.V.
|
|
||||||
// Cura is released under the terms of the LGPLv3 or higher.
|
|
||||||
|
|
||||||
import QtQuick 2.2
|
|
||||||
import QtQuick.Controls 1.2
|
|
||||||
import QtQuick.Layouts 1.1
|
|
||||||
import QtQuick.Controls.Styles 1.1
|
|
||||||
|
|
||||||
import UM 1.0 as UM
|
|
||||||
import Cura 1.0 as Cura
|
|
||||||
|
|
||||||
UM.PointingRectangle {
|
|
||||||
id: sliderLabelRoot
|
|
||||||
|
|
||||||
// custom properties
|
|
||||||
property real maximumValue: 100
|
|
||||||
property real value: 0
|
|
||||||
property var setValue // Function
|
|
||||||
property bool busy: false
|
|
||||||
|
|
||||||
target: Qt.point(parent.width, y + height / 2)
|
|
||||||
arrowSize: UM.Theme.getSize("default_arrow").width
|
|
||||||
height: parent.height
|
|
||||||
width: valueLabel.width + UM.Theme.getSize("default_margin").width
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
// make sure the text field is focussed when pressing the parent handle
|
|
||||||
// needed to connect the key bindings when switching active handle
|
|
||||||
onVisibleChanged: if (visible) valueLabel.forceActiveFocus()
|
|
||||||
|
|
||||||
color: UM.Theme.getColor("tool_panel_background")
|
|
||||||
borderColor: UM.Theme.getColor("lining")
|
|
||||||
borderWidth: UM.Theme.getSize("default_lining").width
|
|
||||||
|
|
||||||
Behavior on height {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 50
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// catch all mouse events so they're not handled by underlying 3D scene
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
}
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: valueLabel
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2)
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
width: 40 * screenScaleFactor
|
|
||||||
text: sliderLabelRoot.value + 1 // the current handle value, add 1 because layers is an array
|
|
||||||
horizontalAlignment: TextInput.AlignRight
|
|
||||||
|
|
||||||
// key bindings, work when label is currenctly focused (active handle in LayerSlider)
|
|
||||||
Keys.onUpPressed: sliderLabelRoot.setValue(sliderLabelRoot.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
|
|
||||||
Keys.onDownPressed: sliderLabelRoot.setValue(sliderLabelRoot.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
|
|
||||||
|
|
||||||
style: TextFieldStyle {
|
|
||||||
textColor: UM.Theme.getColor("setting_control_text")
|
|
||||||
font: UM.Theme.getFont("default")
|
|
||||||
background: Item { }
|
|
||||||
}
|
|
||||||
|
|
||||||
onEditingFinished: {
|
|
||||||
|
|
||||||
// Ensure that the cursor is at the first position. On some systems the text isn't fully visible
|
|
||||||
// Seems to have to do something with different dpi densities that QML doesn't quite handle.
|
|
||||||
// Another option would be to increase the size even further, but that gives pretty ugly results.
|
|
||||||
cursorPosition = 0
|
|
||||||
|
|
||||||
if (valueLabel.text != "") {
|
|
||||||
// -1 because we need to convert back to an array structure
|
|
||||||
sliderLabelRoot.setValue(parseInt(valueLabel.text) - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
validator: IntValidator {
|
|
||||||
bottom: 1
|
|
||||||
top: sliderLabelRoot.maximumValue + 1 // +1 because actual layers is an array
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BusyIndicator {
|
|
||||||
id: busyIndicator
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
left: parent.right
|
|
||||||
leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2)
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
width: sliderLabelRoot.height
|
|
||||||
height: width
|
|
||||||
|
|
||||||
visible: sliderLabelRoot.busy
|
|
||||||
running: sliderLabelRoot.busy
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,495 +0,0 @@
|
||||||
# Copyright (c) 2015 Ultimaker B.V.
|
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from UM.PluginRegistry import PluginRegistry
|
|
||||||
from UM.View.View import View
|
|
||||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
|
||||||
from UM.Resources import Resources
|
|
||||||
from UM.Event import Event, KeyEvent
|
|
||||||
from UM.Signal import Signal
|
|
||||||
from UM.Scene.Selection import Selection
|
|
||||||
from UM.Math.Color import Color
|
|
||||||
from UM.Mesh.MeshBuilder import MeshBuilder
|
|
||||||
from UM.Job import Job
|
|
||||||
from UM.Preferences import Preferences
|
|
||||||
from UM.Logger import Logger
|
|
||||||
from UM.View.GL.OpenGL import OpenGL
|
|
||||||
from UM.Message import Message
|
|
||||||
from UM.Application import Application
|
|
||||||
from UM.View.GL.OpenGLContext import OpenGLContext
|
|
||||||
|
|
||||||
from cura.ConvexHullNode import ConvexHullNode
|
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
from PyQt5.QtWidgets import QApplication
|
|
||||||
|
|
||||||
from . import LayerViewProxy
|
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
|
||||||
catalog = i18nCatalog("cura")
|
|
||||||
|
|
||||||
from . import LayerPass
|
|
||||||
|
|
||||||
import numpy
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
## View used to display g-code paths.
|
|
||||||
class LayerView(View):
|
|
||||||
# Must match LayerView.qml
|
|
||||||
LAYER_VIEW_TYPE_MATERIAL_TYPE = 0
|
|
||||||
LAYER_VIEW_TYPE_LINE_TYPE = 1
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
self._max_layers = 0
|
|
||||||
self._current_layer_num = 0
|
|
||||||
self._minimum_layer_num = 0
|
|
||||||
self._current_layer_mesh = None
|
|
||||||
self._current_layer_jumps = None
|
|
||||||
self._top_layers_job = None
|
|
||||||
self._activity = False
|
|
||||||
self._old_max_layers = 0
|
|
||||||
|
|
||||||
self._busy = False
|
|
||||||
|
|
||||||
self._ghost_shader = None
|
|
||||||
self._layer_pass = None
|
|
||||||
self._composite_pass = None
|
|
||||||
self._old_layer_bindings = None
|
|
||||||
self._layerview_composite_shader = None
|
|
||||||
self._old_composite_shader = None
|
|
||||||
|
|
||||||
self._global_container_stack = None
|
|
||||||
self._proxy = LayerViewProxy.LayerViewProxy()
|
|
||||||
self._controller.getScene().getRoot().childrenChanged.connect(self._onSceneChanged)
|
|
||||||
|
|
||||||
self._resetSettings()
|
|
||||||
self._legend_items = None
|
|
||||||
self._show_travel_moves = False
|
|
||||||
|
|
||||||
Preferences.getInstance().addPreference("view/top_layer_count", 5)
|
|
||||||
Preferences.getInstance().addPreference("view/only_show_top_layers", False)
|
|
||||||
Preferences.getInstance().addPreference("view/force_layer_view_compatibility_mode", False)
|
|
||||||
|
|
||||||
Preferences.getInstance().addPreference("layerview/layer_view_type", 0)
|
|
||||||
Preferences.getInstance().addPreference("layerview/extruder_opacities", "")
|
|
||||||
|
|
||||||
Preferences.getInstance().addPreference("layerview/show_travel_moves", False)
|
|
||||||
Preferences.getInstance().addPreference("layerview/show_helpers", True)
|
|
||||||
Preferences.getInstance().addPreference("layerview/show_skin", True)
|
|
||||||
Preferences.getInstance().addPreference("layerview/show_infill", True)
|
|
||||||
|
|
||||||
Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
|
|
||||||
self._updateWithPreferences()
|
|
||||||
|
|
||||||
self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count"))
|
|
||||||
self._only_show_top_layers = bool(Preferences.getInstance().getValue("view/only_show_top_layers"))
|
|
||||||
self._compatibility_mode = True # for safety
|
|
||||||
|
|
||||||
self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled"),
|
|
||||||
title = catalog.i18nc("@info:title", "Layer View"))
|
|
||||||
|
|
||||||
def _resetSettings(self):
|
|
||||||
self._layer_view_type = 0 # 0 is material color, 1 is color by linetype, 2 is speed
|
|
||||||
self._extruder_count = 0
|
|
||||||
self._extruder_opacity = [1.0, 1.0, 1.0, 1.0]
|
|
||||||
self._show_travel_moves = 0
|
|
||||||
self._show_helpers = 1
|
|
||||||
self._show_skin = 1
|
|
||||||
self._show_infill = 1
|
|
||||||
|
|
||||||
def getActivity(self):
|
|
||||||
return self._activity
|
|
||||||
|
|
||||||
def getLayerPass(self):
|
|
||||||
if not self._layer_pass:
|
|
||||||
# Currently the RenderPass constructor requires a size > 0
|
|
||||||
# This should be fixed in RenderPass's constructor.
|
|
||||||
self._layer_pass = LayerPass.LayerPass(1, 1)
|
|
||||||
self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode"))
|
|
||||||
self._layer_pass.setLayerView(self)
|
|
||||||
return self._layer_pass
|
|
||||||
|
|
||||||
def getCurrentLayer(self):
|
|
||||||
return self._current_layer_num
|
|
||||||
|
|
||||||
def getMinimumLayer(self):
|
|
||||||
return self._minimum_layer_num
|
|
||||||
|
|
||||||
def _onSceneChanged(self, node):
|
|
||||||
self.calculateMaxLayers()
|
|
||||||
|
|
||||||
def getMaxLayers(self):
|
|
||||||
return self._max_layers
|
|
||||||
|
|
||||||
busyChanged = Signal()
|
|
||||||
|
|
||||||
def isBusy(self):
|
|
||||||
return self._busy
|
|
||||||
|
|
||||||
def setBusy(self, busy):
|
|
||||||
if busy != self._busy:
|
|
||||||
self._busy = busy
|
|
||||||
self.busyChanged.emit()
|
|
||||||
|
|
||||||
def resetLayerData(self):
|
|
||||||
self._current_layer_mesh = None
|
|
||||||
self._current_layer_jumps = None
|
|
||||||
|
|
||||||
def beginRendering(self):
|
|
||||||
scene = self.getController().getScene()
|
|
||||||
renderer = self.getRenderer()
|
|
||||||
|
|
||||||
if not self._ghost_shader:
|
|
||||||
self._ghost_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader"))
|
|
||||||
self._ghost_shader.setUniformValue("u_color", Color(*Application.getInstance().getTheme().getColor("layerview_ghost").getRgb()))
|
|
||||||
|
|
||||||
for node in DepthFirstIterator(scene.getRoot()):
|
|
||||||
# We do not want to render ConvexHullNode as it conflicts with the bottom layers.
|
|
||||||
# However, it is somewhat relevant when the node is selected, so do render it then.
|
|
||||||
if type(node) is ConvexHullNode and not Selection.isSelected(node.getWatchedNode()):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not node.render(renderer):
|
|
||||||
if (node.getMeshData()) and node.isVisible():
|
|
||||||
renderer.queueNode(node, transparent = True, shader = self._ghost_shader)
|
|
||||||
|
|
||||||
def setLayer(self, value):
|
|
||||||
if self._current_layer_num != value:
|
|
||||||
self._current_layer_num = value
|
|
||||||
if self._current_layer_num < 0:
|
|
||||||
self._current_layer_num = 0
|
|
||||||
if self._current_layer_num > self._max_layers:
|
|
||||||
self._current_layer_num = self._max_layers
|
|
||||||
if self._current_layer_num < self._minimum_layer_num:
|
|
||||||
self._minimum_layer_num = self._current_layer_num
|
|
||||||
|
|
||||||
self._startUpdateTopLayers()
|
|
||||||
|
|
||||||
self.currentLayerNumChanged.emit()
|
|
||||||
|
|
||||||
def setMinimumLayer(self, value):
|
|
||||||
if self._minimum_layer_num != value:
|
|
||||||
self._minimum_layer_num = value
|
|
||||||
if self._minimum_layer_num < 0:
|
|
||||||
self._minimum_layer_num = 0
|
|
||||||
if self._minimum_layer_num > self._max_layers:
|
|
||||||
self._minimum_layer_num = self._max_layers
|
|
||||||
if self._minimum_layer_num > self._current_layer_num:
|
|
||||||
self._current_layer_num = self._minimum_layer_num
|
|
||||||
|
|
||||||
self._startUpdateTopLayers()
|
|
||||||
|
|
||||||
self.currentLayerNumChanged.emit()
|
|
||||||
|
|
||||||
## Set the layer view type
|
|
||||||
#
|
|
||||||
# \param layer_view_type integer as in LayerView.qml and this class
|
|
||||||
def setLayerViewType(self, layer_view_type):
|
|
||||||
self._layer_view_type = layer_view_type
|
|
||||||
self.currentLayerNumChanged.emit()
|
|
||||||
|
|
||||||
## Return the layer view type, integer as in LayerView.qml and this class
|
|
||||||
def getLayerViewType(self):
|
|
||||||
return self._layer_view_type
|
|
||||||
|
|
||||||
## Set the extruder opacity
|
|
||||||
#
|
|
||||||
# \param extruder_nr 0..3
|
|
||||||
# \param opacity 0.0 .. 1.0
|
|
||||||
def setExtruderOpacity(self, extruder_nr, opacity):
|
|
||||||
if 0 <= extruder_nr <= 3:
|
|
||||||
self._extruder_opacity[extruder_nr] = opacity
|
|
||||||
self.currentLayerNumChanged.emit()
|
|
||||||
|
|
||||||
def getExtruderOpacities(self):
|
|
||||||
return self._extruder_opacity
|
|
||||||
|
|
||||||
def setShowTravelMoves(self, show):
|
|
||||||
self._show_travel_moves = show
|
|
||||||
self.currentLayerNumChanged.emit()
|
|
||||||
|
|
||||||
def getShowTravelMoves(self):
|
|
||||||
return self._show_travel_moves
|
|
||||||
|
|
||||||
def setShowHelpers(self, show):
|
|
||||||
self._show_helpers = show
|
|
||||||
self.currentLayerNumChanged.emit()
|
|
||||||
|
|
||||||
def getShowHelpers(self):
|
|
||||||
return self._show_helpers
|
|
||||||
|
|
||||||
def setShowSkin(self, show):
|
|
||||||
self._show_skin = show
|
|
||||||
self.currentLayerNumChanged.emit()
|
|
||||||
|
|
||||||
def getShowSkin(self):
|
|
||||||
return self._show_skin
|
|
||||||
|
|
||||||
def setShowInfill(self, show):
|
|
||||||
self._show_infill = show
|
|
||||||
self.currentLayerNumChanged.emit()
|
|
||||||
|
|
||||||
def getShowInfill(self):
|
|
||||||
return self._show_infill
|
|
||||||
|
|
||||||
def getCompatibilityMode(self):
|
|
||||||
return self._compatibility_mode
|
|
||||||
|
|
||||||
def getExtruderCount(self):
|
|
||||||
return self._extruder_count
|
|
||||||
|
|
||||||
def calculateMaxLayers(self):
|
|
||||||
scene = self.getController().getScene()
|
|
||||||
self._activity = True
|
|
||||||
|
|
||||||
self._old_max_layers = self._max_layers
|
|
||||||
## Recalculate num max layers
|
|
||||||
new_max_layers = 0
|
|
||||||
for node in DepthFirstIterator(scene.getRoot()):
|
|
||||||
layer_data = node.callDecoration("getLayerData")
|
|
||||||
if not layer_data:
|
|
||||||
continue
|
|
||||||
|
|
||||||
min_layer_number = sys.maxsize
|
|
||||||
max_layer_number = -sys.maxsize
|
|
||||||
for layer_id in layer_data.getLayers():
|
|
||||||
if max_layer_number < layer_id:
|
|
||||||
max_layer_number = layer_id
|
|
||||||
if min_layer_number > layer_id:
|
|
||||||
min_layer_number = layer_id
|
|
||||||
layer_count = max_layer_number - min_layer_number
|
|
||||||
|
|
||||||
if new_max_layers < layer_count:
|
|
||||||
new_max_layers = layer_count
|
|
||||||
|
|
||||||
if new_max_layers > 0 and new_max_layers != self._old_max_layers:
|
|
||||||
self._max_layers = new_max_layers
|
|
||||||
|
|
||||||
# The qt slider has a bit of weird behavior that if the maxvalue needs to be changed first
|
|
||||||
# if it's the largest value. If we don't do this, we can have a slider block outside of the
|
|
||||||
# slider.
|
|
||||||
if new_max_layers > self._current_layer_num:
|
|
||||||
self.maxLayersChanged.emit()
|
|
||||||
self.setLayer(int(self._max_layers))
|
|
||||||
else:
|
|
||||||
self.setLayer(int(self._max_layers))
|
|
||||||
self.maxLayersChanged.emit()
|
|
||||||
self._startUpdateTopLayers()
|
|
||||||
|
|
||||||
maxLayersChanged = Signal()
|
|
||||||
currentLayerNumChanged = Signal()
|
|
||||||
globalStackChanged = Signal()
|
|
||||||
preferencesChanged = Signal()
|
|
||||||
|
|
||||||
## Hackish way to ensure the proxy is already created, which ensures that the layerview.qml is already created
|
|
||||||
# as this caused some issues.
|
|
||||||
def getProxy(self, engine, script_engine):
|
|
||||||
return self._proxy
|
|
||||||
|
|
||||||
def endRendering(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def event(self, event):
|
|
||||||
modifiers = QApplication.keyboardModifiers()
|
|
||||||
ctrl_is_active = modifiers & Qt.ControlModifier
|
|
||||||
shift_is_active = modifiers & Qt.ShiftModifier
|
|
||||||
if event.type == Event.KeyPressEvent and ctrl_is_active:
|
|
||||||
amount = 10 if shift_is_active else 1
|
|
||||||
if event.key == KeyEvent.UpKey:
|
|
||||||
self.setLayer(self._current_layer_num + amount)
|
|
||||||
return True
|
|
||||||
if event.key == KeyEvent.DownKey:
|
|
||||||
self.setLayer(self._current_layer_num - amount)
|
|
||||||
return True
|
|
||||||
|
|
||||||
if event.type == Event.ViewActivateEvent:
|
|
||||||
# Make sure the LayerPass is created
|
|
||||||
layer_pass = self.getLayerPass()
|
|
||||||
self.getRenderer().addRenderPass(layer_pass)
|
|
||||||
|
|
||||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
|
||||||
self._onGlobalStackChanged()
|
|
||||||
|
|
||||||
if not self._layerview_composite_shader:
|
|
||||||
self._layerview_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("LayerView"), "layerview_composite.shader"))
|
|
||||||
theme = Application.getInstance().getTheme()
|
|
||||||
self._layerview_composite_shader.setUniformValue("u_background_color", Color(*theme.getColor("viewport_background").getRgb()))
|
|
||||||
self._layerview_composite_shader.setUniformValue("u_outline_color", Color(*theme.getColor("model_selection_outline").getRgb()))
|
|
||||||
|
|
||||||
if not self._composite_pass:
|
|
||||||
self._composite_pass = self.getRenderer().getRenderPass("composite")
|
|
||||||
|
|
||||||
self._old_layer_bindings = self._composite_pass.getLayerBindings()[:] # make a copy so we can restore to it later
|
|
||||||
self._composite_pass.getLayerBindings().append("layerview")
|
|
||||||
self._old_composite_shader = self._composite_pass.getCompositeShader()
|
|
||||||
self._composite_pass.setCompositeShader(self._layerview_composite_shader)
|
|
||||||
|
|
||||||
elif event.type == Event.ViewDeactivateEvent:
|
|
||||||
self._wireprint_warning_message.hide()
|
|
||||||
Application.getInstance().globalContainerStackChanged.disconnect(self._onGlobalStackChanged)
|
|
||||||
if self._global_container_stack:
|
|
||||||
self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
|
|
||||||
|
|
||||||
self.getRenderer().removeRenderPass(self._layer_pass)
|
|
||||||
self._composite_pass.setLayerBindings(self._old_layer_bindings)
|
|
||||||
self._composite_pass.setCompositeShader(self._old_composite_shader)
|
|
||||||
|
|
||||||
def getCurrentLayerMesh(self):
|
|
||||||
return self._current_layer_mesh
|
|
||||||
|
|
||||||
def getCurrentLayerJumps(self):
|
|
||||||
return self._current_layer_jumps
|
|
||||||
|
|
||||||
def _onGlobalStackChanged(self):
|
|
||||||
if self._global_container_stack:
|
|
||||||
self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
|
|
||||||
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
|
|
||||||
if self._global_container_stack:
|
|
||||||
self._global_container_stack.propertyChanged.connect(self._onPropertyChanged)
|
|
||||||
self._extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value")
|
|
||||||
self._onPropertyChanged("wireframe_enabled", "value")
|
|
||||||
self.globalStackChanged.emit()
|
|
||||||
else:
|
|
||||||
self._wireprint_warning_message.hide()
|
|
||||||
|
|
||||||
def _onPropertyChanged(self, key, property_name):
|
|
||||||
if key == "wireframe_enabled" and property_name == "value":
|
|
||||||
if self._global_container_stack.getProperty("wireframe_enabled", "value"):
|
|
||||||
self._wireprint_warning_message.show()
|
|
||||||
else:
|
|
||||||
self._wireprint_warning_message.hide()
|
|
||||||
|
|
||||||
def _startUpdateTopLayers(self):
|
|
||||||
if not self._compatibility_mode:
|
|
||||||
return
|
|
||||||
|
|
||||||
if self._top_layers_job:
|
|
||||||
self._top_layers_job.finished.disconnect(self._updateCurrentLayerMesh)
|
|
||||||
self._top_layers_job.cancel()
|
|
||||||
|
|
||||||
self.setBusy(True)
|
|
||||||
|
|
||||||
self._top_layers_job = _CreateTopLayersJob(self._controller.getScene(), self._current_layer_num, self._solid_layers)
|
|
||||||
self._top_layers_job.finished.connect(self._updateCurrentLayerMesh)
|
|
||||||
self._top_layers_job.start()
|
|
||||||
|
|
||||||
def _updateCurrentLayerMesh(self, job):
|
|
||||||
self.setBusy(False)
|
|
||||||
|
|
||||||
if not job.getResult():
|
|
||||||
return
|
|
||||||
self.resetLayerData() # Reset the layer data only when job is done. Doing it now prevents "blinking" data.
|
|
||||||
self._current_layer_mesh = job.getResult().get("layers")
|
|
||||||
if self._show_travel_moves:
|
|
||||||
self._current_layer_jumps = job.getResult().get("jumps")
|
|
||||||
self._controller.getScene().sceneChanged.emit(self._controller.getScene().getRoot())
|
|
||||||
|
|
||||||
self._top_layers_job = None
|
|
||||||
|
|
||||||
def _updateWithPreferences(self):
|
|
||||||
self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count"))
|
|
||||||
self._only_show_top_layers = bool(Preferences.getInstance().getValue("view/only_show_top_layers"))
|
|
||||||
self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(
|
|
||||||
Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode"))
|
|
||||||
|
|
||||||
self.setLayerViewType(int(float(Preferences.getInstance().getValue("layerview/layer_view_type"))));
|
|
||||||
|
|
||||||
for extruder_nr, extruder_opacity in enumerate(Preferences.getInstance().getValue("layerview/extruder_opacities").split("|")):
|
|
||||||
try:
|
|
||||||
opacity = float(extruder_opacity)
|
|
||||||
except ValueError:
|
|
||||||
opacity = 1.0
|
|
||||||
self.setExtruderOpacity(extruder_nr, opacity)
|
|
||||||
|
|
||||||
self.setShowTravelMoves(bool(Preferences.getInstance().getValue("layerview/show_travel_moves")))
|
|
||||||
self.setShowHelpers(bool(Preferences.getInstance().getValue("layerview/show_helpers")))
|
|
||||||
self.setShowSkin(bool(Preferences.getInstance().getValue("layerview/show_skin")))
|
|
||||||
self.setShowInfill(bool(Preferences.getInstance().getValue("layerview/show_infill")))
|
|
||||||
|
|
||||||
self._startUpdateTopLayers()
|
|
||||||
self.preferencesChanged.emit()
|
|
||||||
|
|
||||||
def _onPreferencesChanged(self, preference):
|
|
||||||
if preference not in {
|
|
||||||
"view/top_layer_count",
|
|
||||||
"view/only_show_top_layers",
|
|
||||||
"view/force_layer_view_compatibility_mode",
|
|
||||||
"layerview/layer_view_type",
|
|
||||||
"layerview/extruder_opacities",
|
|
||||||
"layerview/show_travel_moves",
|
|
||||||
"layerview/show_helpers",
|
|
||||||
"layerview/show_skin",
|
|
||||||
"layerview/show_infill",
|
|
||||||
}:
|
|
||||||
return
|
|
||||||
|
|
||||||
self._updateWithPreferences()
|
|
||||||
|
|
||||||
|
|
||||||
class _CreateTopLayersJob(Job):
|
|
||||||
def __init__(self, scene, layer_number, solid_layers):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
self._scene = scene
|
|
||||||
self._layer_number = layer_number
|
|
||||||
self._solid_layers = solid_layers
|
|
||||||
self._cancel = False
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
layer_data = None
|
|
||||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
|
||||||
layer_data = node.callDecoration("getLayerData")
|
|
||||||
if layer_data:
|
|
||||||
break
|
|
||||||
|
|
||||||
if self._cancel or not layer_data:
|
|
||||||
return
|
|
||||||
|
|
||||||
layer_mesh = MeshBuilder()
|
|
||||||
for i in range(self._solid_layers):
|
|
||||||
layer_number = self._layer_number - i
|
|
||||||
if layer_number < 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
layer = layer_data.getLayer(layer_number).createMesh()
|
|
||||||
except Exception:
|
|
||||||
Logger.logException("w", "An exception occurred while creating layer mesh.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if not layer or layer.getVertices() is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
layer_mesh.addIndices(layer_mesh.getVertexCount() + layer.getIndices())
|
|
||||||
layer_mesh.addVertices(layer.getVertices())
|
|
||||||
|
|
||||||
# Scale layer color by a brightness factor based on the current layer number
|
|
||||||
# This will result in a range of 0.5 - 1.0 to multiply colors by.
|
|
||||||
brightness = numpy.ones((1, 4), dtype=numpy.float32) * (2.0 - (i / self._solid_layers)) / 2.0
|
|
||||||
brightness[0, 3] = 1.0
|
|
||||||
layer_mesh.addColors(layer.getColors() * brightness)
|
|
||||||
|
|
||||||
if self._cancel:
|
|
||||||
return
|
|
||||||
|
|
||||||
Job.yieldThread()
|
|
||||||
|
|
||||||
if self._cancel:
|
|
||||||
return
|
|
||||||
|
|
||||||
Job.yieldThread()
|
|
||||||
jump_mesh = layer_data.getLayer(self._layer_number).createJumps()
|
|
||||||
if not jump_mesh or jump_mesh.getVertices() is None:
|
|
||||||
jump_mesh = None
|
|
||||||
|
|
||||||
self.setResult({"layers": layer_mesh.build(), "jumps": jump_mesh})
|
|
||||||
|
|
||||||
def cancel(self):
|
|
||||||
self._cancel = True
|
|
||||||
super().cancel()
|
|
||||||
|
|
|
@ -1,388 +0,0 @@
|
||||||
// Copyright (c) 2017 Ultimaker B.V.
|
|
||||||
// Cura is released under the terms of the LGPLv3 or higher.
|
|
||||||
|
|
||||||
import QtQuick 2.4
|
|
||||||
import QtQuick.Controls 1.2
|
|
||||||
import QtQuick.Layouts 1.1
|
|
||||||
import QtQuick.Controls.Styles 1.1
|
|
||||||
|
|
||||||
import UM 1.0 as UM
|
|
||||||
import Cura 1.0 as Cura
|
|
||||||
|
|
||||||
Item
|
|
||||||
{
|
|
||||||
id: base
|
|
||||||
width: {
|
|
||||||
if (UM.LayerView.compatibilityMode) {
|
|
||||||
return UM.Theme.getSize("layerview_menu_size_compatibility").width;
|
|
||||||
} else {
|
|
||||||
return UM.Theme.getSize("layerview_menu_size").width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
height: {
|
|
||||||
if (UM.LayerView.compatibilityMode) {
|
|
||||||
return UM.Theme.getSize("layerview_menu_size_compatibility").height;
|
|
||||||
} else if (UM.Preferences.getValue("layerview/layer_view_type") == 0) {
|
|
||||||
return UM.Theme.getSize("layerview_menu_size_material_color_mode").height + UM.LayerView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height)
|
|
||||||
} else {
|
|
||||||
return UM.Theme.getSize("layerview_menu_size").height + UM.LayerView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property var buttonTarget: {
|
|
||||||
if(parent != null)
|
|
||||||
{
|
|
||||||
var force_binding = parent.y; // ensure this gets reevaluated when the panel moves
|
|
||||||
return base.mapFromItem(parent.parent, parent.buttonTarget.x, parent.buttonTarget.y)
|
|
||||||
}
|
|
||||||
return Qt.point(0,0)
|
|
||||||
}
|
|
||||||
|
|
||||||
visible: parent != null ? !parent.parent.monitoringPrint: true
|
|
||||||
|
|
||||||
UM.PointingRectangle {
|
|
||||||
id: layerViewMenu
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
z: slider.z - 1
|
|
||||||
color: UM.Theme.getColor("tool_panel_background")
|
|
||||||
borderWidth: UM.Theme.getSize("default_lining").width
|
|
||||||
borderColor: UM.Theme.getColor("lining")
|
|
||||||
arrowSize: 0 // hide arrow until weird issue with first time rendering is fixed
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: view_settings
|
|
||||||
|
|
||||||
property var extruder_opacities: UM.Preferences.getValue("layerview/extruder_opacities").split("|")
|
|
||||||
property bool show_travel_moves: UM.Preferences.getValue("layerview/show_travel_moves")
|
|
||||||
property bool show_helpers: UM.Preferences.getValue("layerview/show_helpers")
|
|
||||||
property bool show_skin: UM.Preferences.getValue("layerview/show_skin")
|
|
||||||
property bool show_infill: UM.Preferences.getValue("layerview/show_infill")
|
|
||||||
// if we are in compatibility mode, we only show the "line type"
|
|
||||||
property bool show_legend: UM.LayerView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type") == 1
|
|
||||||
property bool only_show_top_layers: UM.Preferences.getValue("view/only_show_top_layers")
|
|
||||||
property int top_layer_count: UM.Preferences.getValue("view/top_layer_count")
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
|
||||||
spacing: UM.Theme.getSize("layerview_row_spacing").height
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
|
||||||
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
id: layerViewTypesLabel
|
|
||||||
anchors.left: parent.left
|
|
||||||
text: catalog.i18nc("@label","Color scheme")
|
|
||||||
font: UM.Theme.getFont("default");
|
|
||||||
visible: !UM.LayerView.compatibilityMode
|
|
||||||
Layout.fillWidth: true
|
|
||||||
color: UM.Theme.getColor("setting_control_text")
|
|
||||||
}
|
|
||||||
|
|
||||||
ListModel // matches LayerView.py
|
|
||||||
{
|
|
||||||
id: layerViewTypes
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted:
|
|
||||||
{
|
|
||||||
layerViewTypes.append({
|
|
||||||
text: catalog.i18nc("@label:listbox", "Material Color"),
|
|
||||||
type_id: 0
|
|
||||||
})
|
|
||||||
layerViewTypes.append({
|
|
||||||
text: catalog.i18nc("@label:listbox", "Line Type"),
|
|
||||||
type_id: 1 // these ids match the switching in the shader
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
ComboBox
|
|
||||||
{
|
|
||||||
id: layerTypeCombobox
|
|
||||||
anchors.left: parent.left
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
|
|
||||||
model: layerViewTypes
|
|
||||||
visible: !UM.LayerView.compatibilityMode
|
|
||||||
style: UM.Theme.styles.combobox
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 10 * screenScaleFactor
|
|
||||||
|
|
||||||
onActivated:
|
|
||||||
{
|
|
||||||
UM.Preferences.setValue("layerview/layer_view_type", index);
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted:
|
|
||||||
{
|
|
||||||
currentIndex = UM.LayerView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type");
|
|
||||||
updateLegends(currentIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLegends(type_id)
|
|
||||||
{
|
|
||||||
// update visibility of legends
|
|
||||||
view_settings.show_legend = UM.LayerView.compatibilityMode || (type_id == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
id: compatibilityModeLabel
|
|
||||||
anchors.left: parent.left
|
|
||||||
text: catalog.i18nc("@label","Compatibility Mode")
|
|
||||||
font: UM.Theme.getFont("default")
|
|
||||||
color: UM.Theme.getColor("text")
|
|
||||||
visible: UM.LayerView.compatibilityMode
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
|
|
||||||
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
|
|
||||||
}
|
|
||||||
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
id: space2Label
|
|
||||||
anchors.left: parent.left
|
|
||||||
text: " "
|
|
||||||
font.pointSize: 0.5
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: UM.Preferences
|
|
||||||
onPreferenceChanged:
|
|
||||||
{
|
|
||||||
layerTypeCombobox.currentIndex = UM.LayerView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type");
|
|
||||||
layerTypeCombobox.updateLegends(layerTypeCombobox.currentIndex);
|
|
||||||
view_settings.extruder_opacities = UM.Preferences.getValue("layerview/extruder_opacities").split("|");
|
|
||||||
view_settings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves");
|
|
||||||
view_settings.show_helpers = UM.Preferences.getValue("layerview/show_helpers");
|
|
||||||
view_settings.show_skin = UM.Preferences.getValue("layerview/show_skin");
|
|
||||||
view_settings.show_infill = UM.Preferences.getValue("layerview/show_infill");
|
|
||||||
view_settings.only_show_top_layers = UM.Preferences.getValue("view/only_show_top_layers");
|
|
||||||
view_settings.top_layer_count = UM.Preferences.getValue("view/top_layer_count");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: Cura.ExtrudersModel{}
|
|
||||||
CheckBox {
|
|
||||||
id: extrudersModelCheckBox
|
|
||||||
checked: view_settings.extruder_opacities[index] > 0.5 || view_settings.extruder_opacities[index] == undefined || view_settings.extruder_opacities[index] == ""
|
|
||||||
onClicked: {
|
|
||||||
view_settings.extruder_opacities[index] = checked ? 1.0 : 0.0
|
|
||||||
UM.Preferences.setValue("layerview/extruder_opacities", view_settings.extruder_opacities.join("|"));
|
|
||||||
}
|
|
||||||
visible: !UM.LayerView.compatibilityMode
|
|
||||||
enabled: index + 1 <= 4
|
|
||||||
Rectangle {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.right: extrudersModelCheckBox.right
|
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
|
||||||
width: UM.Theme.getSize("layerview_legend_size").width
|
|
||||||
height: UM.Theme.getSize("layerview_legend_size").height
|
|
||||||
color: model.color
|
|
||||||
radius: width / 2
|
|
||||||
border.width: UM.Theme.getSize("default_lining").width
|
|
||||||
border.color: UM.Theme.getColor("lining")
|
|
||||||
visible: !view_settings.show_legend
|
|
||||||
}
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
|
|
||||||
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
|
|
||||||
style: UM.Theme.styles.checkbox
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
text: model.name
|
|
||||||
elide: Text.ElideRight
|
|
||||||
color: UM.Theme.getColor("setting_control_text")
|
|
||||||
font: UM.Theme.getFont("default")
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: extrudersModelCheckBox.left;
|
|
||||||
anchors.right: extrudersModelCheckBox.right;
|
|
||||||
anchors.leftMargin: UM.Theme.getSize("checkbox").width + UM.Theme.getSize("default_margin").width /2
|
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: ListModel {
|
|
||||||
id: typesLegenModel
|
|
||||||
Component.onCompleted:
|
|
||||||
{
|
|
||||||
typesLegenModel.append({
|
|
||||||
label: catalog.i18nc("@label", "Show Travels"),
|
|
||||||
initialValue: view_settings.show_travel_moves,
|
|
||||||
preference: "layerview/show_travel_moves",
|
|
||||||
colorId: "layerview_move_combing"
|
|
||||||
});
|
|
||||||
typesLegenModel.append({
|
|
||||||
label: catalog.i18nc("@label", "Show Helpers"),
|
|
||||||
initialValue: view_settings.show_helpers,
|
|
||||||
preference: "layerview/show_helpers",
|
|
||||||
colorId: "layerview_support"
|
|
||||||
});
|
|
||||||
typesLegenModel.append({
|
|
||||||
label: catalog.i18nc("@label", "Show Shell"),
|
|
||||||
initialValue: view_settings.show_skin,
|
|
||||||
preference: "layerview/show_skin",
|
|
||||||
colorId: "layerview_inset_0"
|
|
||||||
});
|
|
||||||
typesLegenModel.append({
|
|
||||||
label: catalog.i18nc("@label", "Show Infill"),
|
|
||||||
initialValue: view_settings.show_infill,
|
|
||||||
preference: "layerview/show_infill",
|
|
||||||
colorId: "layerview_infill"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckBox {
|
|
||||||
id: legendModelCheckBox
|
|
||||||
checked: model.initialValue
|
|
||||||
onClicked: {
|
|
||||||
UM.Preferences.setValue(model.preference, checked);
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.right: legendModelCheckBox.right
|
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
|
||||||
width: UM.Theme.getSize("layerview_legend_size").width
|
|
||||||
height: UM.Theme.getSize("layerview_legend_size").height
|
|
||||||
color: UM.Theme.getColor(model.colorId)
|
|
||||||
border.width: UM.Theme.getSize("default_lining").width
|
|
||||||
border.color: UM.Theme.getColor("lining")
|
|
||||||
visible: view_settings.show_legend
|
|
||||||
}
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
|
|
||||||
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
|
|
||||||
style: UM.Theme.styles.checkbox
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
text: label
|
|
||||||
font: UM.Theme.getFont("default")
|
|
||||||
elide: Text.ElideRight
|
|
||||||
color: UM.Theme.getColor("setting_control_text")
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: legendModelCheckBox.left;
|
|
||||||
anchors.right: legendModelCheckBox.right;
|
|
||||||
anchors.leftMargin: UM.Theme.getSize("checkbox").width + UM.Theme.getSize("default_margin").width /2
|
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckBox {
|
|
||||||
checked: view_settings.only_show_top_layers
|
|
||||||
onClicked: {
|
|
||||||
UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0);
|
|
||||||
}
|
|
||||||
text: catalog.i18nc("@label", "Only Show Top Layers")
|
|
||||||
visible: UM.LayerView.compatibilityMode
|
|
||||||
style: UM.Theme.styles.checkbox
|
|
||||||
}
|
|
||||||
CheckBox {
|
|
||||||
checked: view_settings.top_layer_count == 5
|
|
||||||
onClicked: {
|
|
||||||
UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1);
|
|
||||||
}
|
|
||||||
text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top")
|
|
||||||
visible: UM.LayerView.compatibilityMode
|
|
||||||
style: UM.Theme.styles.checkbox
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: ListModel {
|
|
||||||
id: typesLegenModelNoCheck
|
|
||||||
Component.onCompleted:
|
|
||||||
{
|
|
||||||
typesLegenModelNoCheck.append({
|
|
||||||
label: catalog.i18nc("@label", "Top / Bottom"),
|
|
||||||
colorId: "layerview_skin",
|
|
||||||
});
|
|
||||||
typesLegenModelNoCheck.append({
|
|
||||||
label: catalog.i18nc("@label", "Inner Wall"),
|
|
||||||
colorId: "layerview_inset_x",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
text: label
|
|
||||||
visible: view_settings.show_legend
|
|
||||||
id: typesLegendModelLabel
|
|
||||||
Rectangle {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.right: typesLegendModelLabel.right
|
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
|
||||||
width: UM.Theme.getSize("layerview_legend_size").width
|
|
||||||
height: UM.Theme.getSize("layerview_legend_size").height
|
|
||||||
color: UM.Theme.getColor(model.colorId)
|
|
||||||
border.width: UM.Theme.getSize("default_lining").width
|
|
||||||
border.color: UM.Theme.getColor("lining")
|
|
||||||
visible: view_settings.show_legend
|
|
||||||
}
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
|
|
||||||
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
|
|
||||||
color: UM.Theme.getColor("setting_control_text")
|
|
||||||
font: UM.Theme.getFont("default")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerSlider {
|
|
||||||
id: slider
|
|
||||||
|
|
||||||
width: UM.Theme.getSize("slider_handle").width
|
|
||||||
height: UM.Theme.getSize("layerview_menu_size").height
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: parent.bottom
|
|
||||||
topMargin: UM.Theme.getSize("slider_layerview_margin").height
|
|
||||||
right: layerViewMenu.right
|
|
||||||
rightMargin: UM.Theme.getSize("slider_layerview_margin").width
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom properties
|
|
||||||
upperValue: UM.LayerView.currentLayer
|
|
||||||
lowerValue: UM.LayerView.minimumLayer
|
|
||||||
maximumValue: UM.LayerView.numLayers
|
|
||||||
handleSize: UM.Theme.getSize("slider_handle").width
|
|
||||||
trackThickness: UM.Theme.getSize("slider_groove").width
|
|
||||||
trackColor: UM.Theme.getColor("slider_groove")
|
|
||||||
trackBorderColor: UM.Theme.getColor("slider_groove_border")
|
|
||||||
upperHandleColor: UM.Theme.getColor("slider_handle")
|
|
||||||
lowerHandleColor: UM.Theme.getColor("slider_handle")
|
|
||||||
rangeHandleColor: UM.Theme.getColor("slider_groove_fill")
|
|
||||||
handleLabelWidth: UM.Theme.getSize("slider_layerview_background").width
|
|
||||||
layersVisible: UM.LayerView.layerActivity && CuraApplication.platformActivity ? true : false
|
|
||||||
|
|
||||||
// update values when layer data changes
|
|
||||||
Connections {
|
|
||||||
target: UM.LayerView
|
|
||||||
onMaxLayersChanged: slider.setUpperValue(UM.LayerView.currentLayer)
|
|
||||||
onMinimumLayerChanged: slider.setLowerValue(UM.LayerView.minimumLayer)
|
|
||||||
onCurrentLayerChanged: slider.setUpperValue(UM.LayerView.currentLayer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure the slider handlers show the correct value after switching views
|
|
||||||
Component.onCompleted: {
|
|
||||||
slider.setLowerValue(UM.LayerView.minimumLayer)
|
|
||||||
slider.setUpperValue(UM.LayerView.currentLayer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FontMetrics {
|
|
||||||
id: fontMetrics
|
|
||||||
font: UM.Theme.getFont("default")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
|
|
||||||
from UM.FlameProfiler import pyqtSlot
|
|
||||||
from UM.Application import Application
|
|
||||||
|
|
||||||
import LayerView
|
|
||||||
|
|
||||||
|
|
||||||
class LayerViewProxy(QObject):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self._current_layer = 0
|
|
||||||
self._controller = Application.getInstance().getController()
|
|
||||||
self._controller.activeViewChanged.connect(self._onActiveViewChanged)
|
|
||||||
self._onActiveViewChanged()
|
|
||||||
|
|
||||||
currentLayerChanged = pyqtSignal()
|
|
||||||
maxLayersChanged = pyqtSignal()
|
|
||||||
activityChanged = pyqtSignal()
|
|
||||||
globalStackChanged = pyqtSignal()
|
|
||||||
preferencesChanged = pyqtSignal()
|
|
||||||
busyChanged = pyqtSignal()
|
|
||||||
|
|
||||||
@pyqtProperty(bool, notify=activityChanged)
|
|
||||||
def layerActivity(self):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
return active_view.getActivity()
|
|
||||||
|
|
||||||
@pyqtProperty(int, notify=maxLayersChanged)
|
|
||||||
def numLayers(self):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
return active_view.getMaxLayers()
|
|
||||||
|
|
||||||
@pyqtProperty(int, notify=currentLayerChanged)
|
|
||||||
def currentLayer(self):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
return active_view.getCurrentLayer()
|
|
||||||
|
|
||||||
@pyqtProperty(int, notify=currentLayerChanged)
|
|
||||||
def minimumLayer(self):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
return active_view.getMinimumLayer()
|
|
||||||
|
|
||||||
@pyqtProperty(bool, notify=busyChanged)
|
|
||||||
def busy(self):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
return active_view.isBusy()
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
@pyqtProperty(bool, notify=preferencesChanged)
|
|
||||||
def compatibilityMode(self):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
return active_view.getCompatibilityMode()
|
|
||||||
return False
|
|
||||||
|
|
||||||
@pyqtSlot(int)
|
|
||||||
def setCurrentLayer(self, layer_num):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
active_view.setLayer(layer_num)
|
|
||||||
|
|
||||||
@pyqtSlot(int)
|
|
||||||
def setMinimumLayer(self, layer_num):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
active_view.setMinimumLayer(layer_num)
|
|
||||||
|
|
||||||
@pyqtSlot(int)
|
|
||||||
def setLayerViewType(self, layer_view_type):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
active_view.setLayerViewType(layer_view_type)
|
|
||||||
|
|
||||||
@pyqtSlot(result=int)
|
|
||||||
def getLayerViewType(self):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
return active_view.getLayerViewType()
|
|
||||||
return 0
|
|
||||||
|
|
||||||
# Opacity 0..1
|
|
||||||
@pyqtSlot(int, float)
|
|
||||||
def setExtruderOpacity(self, extruder_nr, opacity):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
active_view.setExtruderOpacity(extruder_nr, opacity)
|
|
||||||
|
|
||||||
@pyqtSlot(int)
|
|
||||||
def setShowTravelMoves(self, show):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
active_view.setShowTravelMoves(show)
|
|
||||||
|
|
||||||
@pyqtSlot(int)
|
|
||||||
def setShowHelpers(self, show):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
active_view.setShowHelpers(show)
|
|
||||||
|
|
||||||
@pyqtSlot(int)
|
|
||||||
def setShowSkin(self, show):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
active_view.setShowSkin(show)
|
|
||||||
|
|
||||||
@pyqtSlot(int)
|
|
||||||
def setShowInfill(self, show):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
active_view.setShowInfill(show)
|
|
||||||
|
|
||||||
@pyqtProperty(int, notify=globalStackChanged)
|
|
||||||
def extruderCount(self):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
return active_view.getExtruderCount()
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def _layerActivityChanged(self):
|
|
||||||
self.activityChanged.emit()
|
|
||||||
|
|
||||||
def _onLayerChanged(self):
|
|
||||||
self.currentLayerChanged.emit()
|
|
||||||
self._layerActivityChanged()
|
|
||||||
|
|
||||||
def _onMaxLayersChanged(self):
|
|
||||||
self.maxLayersChanged.emit()
|
|
||||||
|
|
||||||
def _onBusyChanged(self):
|
|
||||||
self.busyChanged.emit()
|
|
||||||
|
|
||||||
def _onGlobalStackChanged(self):
|
|
||||||
self.globalStackChanged.emit()
|
|
||||||
|
|
||||||
def _onPreferencesChanged(self):
|
|
||||||
self.preferencesChanged.emit()
|
|
||||||
|
|
||||||
def _onActiveViewChanged(self):
|
|
||||||
active_view = self._controller.getActiveView()
|
|
||||||
if type(active_view) == LayerView.LayerView.LayerView:
|
|
||||||
active_view.currentLayerNumChanged.connect(self._onLayerChanged)
|
|
||||||
active_view.maxLayersChanged.connect(self._onMaxLayersChanged)
|
|
||||||
active_view.busyChanged.connect(self._onBusyChanged)
|
|
||||||
active_view.globalStackChanged.connect(self._onGlobalStackChanged)
|
|
||||||
active_view.preferencesChanged.connect(self._onPreferencesChanged)
|
|
|
@ -1,25 +0,0 @@
|
||||||
# Copyright (c) 2015 Ultimaker B.V.
|
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
|
||||||
|
|
||||||
from . import LayerView, LayerViewProxy
|
|
||||||
from PyQt5.QtQml import qmlRegisterType, qmlRegisterSingletonType
|
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
|
||||||
catalog = i18nCatalog("cura")
|
|
||||||
|
|
||||||
def getMetaData():
|
|
||||||
return {
|
|
||||||
"view": {
|
|
||||||
"name": catalog.i18nc("@item:inlistbox", "Layer view"),
|
|
||||||
"view_panel": "LayerView.qml",
|
|
||||||
"weight": 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def createLayerViewProxy(engine, script_engine):
|
|
||||||
return LayerViewProxy.LayerViewProxy()
|
|
||||||
|
|
||||||
def register(app):
|
|
||||||
layer_view = LayerView.LayerView()
|
|
||||||
qmlRegisterSingletonType(LayerViewProxy.LayerViewProxy, "UM", 1, 0, "LayerView", layer_view.getProxy)
|
|
||||||
return { "view": LayerView.LayerView() }
|
|
|
@ -1,156 +0,0 @@
|
||||||
[shaders]
|
|
||||||
vertex =
|
|
||||||
uniform highp mat4 u_modelViewProjectionMatrix;
|
|
||||||
uniform lowp float u_active_extruder;
|
|
||||||
uniform lowp float u_shade_factor;
|
|
||||||
uniform highp int u_layer_view_type;
|
|
||||||
|
|
||||||
attribute highp float a_extruder;
|
|
||||||
attribute highp float a_line_type;
|
|
||||||
attribute highp vec4 a_vertex;
|
|
||||||
attribute lowp vec4 a_color;
|
|
||||||
attribute lowp vec4 a_material_color;
|
|
||||||
|
|
||||||
varying lowp vec4 v_color;
|
|
||||||
varying float v_line_type;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = u_modelViewProjectionMatrix * a_vertex;
|
|
||||||
// shade the color depending on the extruder index
|
|
||||||
v_color = a_color;
|
|
||||||
// 8 and 9 are travel moves
|
|
||||||
if ((a_line_type != 8.0) && (a_line_type != 9.0)) {
|
|
||||||
v_color = (a_extruder == u_active_extruder) ? v_color : vec4(u_shade_factor * v_color.rgb, v_color.a);
|
|
||||||
}
|
|
||||||
|
|
||||||
v_line_type = a_line_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment =
|
|
||||||
varying lowp vec4 v_color;
|
|
||||||
varying float v_line_type;
|
|
||||||
|
|
||||||
uniform int u_show_travel_moves;
|
|
||||||
uniform int u_show_helpers;
|
|
||||||
uniform int u_show_skin;
|
|
||||||
uniform int u_show_infill;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
if ((u_show_travel_moves == 0) && (v_line_type >= 7.5) && (v_line_type <= 9.5)) { // actually, 8 and 9
|
|
||||||
// discard movements
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
// support: 4, 5, 7, 10
|
|
||||||
if ((u_show_helpers == 0) && (
|
|
||||||
((v_line_type >= 3.5) && (v_line_type <= 4.5)) ||
|
|
||||||
((v_line_type >= 6.5) && (v_line_type <= 7.5)) ||
|
|
||||||
((v_line_type >= 9.5) && (v_line_type <= 10.5)) ||
|
|
||||||
((v_line_type >= 4.5) && (v_line_type <= 5.5))
|
|
||||||
)) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
// skin: 1, 2, 3
|
|
||||||
if ((u_show_skin == 0) && (
|
|
||||||
(v_line_type >= 0.5) && (v_line_type <= 3.5)
|
|
||||||
)) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
// infill:
|
|
||||||
if ((u_show_infill == 0) && (v_line_type >= 5.5) && (v_line_type <= 6.5)) {
|
|
||||||
// discard movements
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
gl_FragColor = v_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
vertex41core =
|
|
||||||
#version 410
|
|
||||||
uniform highp mat4 u_modelViewProjectionMatrix;
|
|
||||||
uniform lowp float u_active_extruder;
|
|
||||||
uniform lowp float u_shade_factor;
|
|
||||||
uniform highp int u_layer_view_type;
|
|
||||||
|
|
||||||
in highp float a_extruder;
|
|
||||||
in highp float a_line_type;
|
|
||||||
in highp vec4 a_vertex;
|
|
||||||
in lowp vec4 a_color;
|
|
||||||
in lowp vec4 a_material_color;
|
|
||||||
|
|
||||||
out lowp vec4 v_color;
|
|
||||||
out float v_line_type;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = u_modelViewProjectionMatrix * a_vertex;
|
|
||||||
v_color = a_color;
|
|
||||||
if ((a_line_type != 8) && (a_line_type != 9)) {
|
|
||||||
v_color = (a_extruder == u_active_extruder) ? v_color : vec4(u_shade_factor * v_color.rgb, v_color.a);
|
|
||||||
}
|
|
||||||
|
|
||||||
v_line_type = a_line_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment41core =
|
|
||||||
#version 410
|
|
||||||
in lowp vec4 v_color;
|
|
||||||
in float v_line_type;
|
|
||||||
out vec4 frag_color;
|
|
||||||
|
|
||||||
uniform int u_show_travel_moves;
|
|
||||||
uniform int u_show_helpers;
|
|
||||||
uniform int u_show_skin;
|
|
||||||
uniform int u_show_infill;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
if ((u_show_travel_moves == 0) && (v_line_type >= 7.5) && (v_line_type <= 9.5)) { // actually, 8 and 9
|
|
||||||
// discard movements
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
// helpers: 4, 5, 7, 10
|
|
||||||
if ((u_show_helpers == 0) && (
|
|
||||||
((v_line_type >= 3.5) && (v_line_type <= 4.5)) ||
|
|
||||||
((v_line_type >= 6.5) && (v_line_type <= 7.5)) ||
|
|
||||||
((v_line_type >= 9.5) && (v_line_type <= 10.5)) ||
|
|
||||||
((v_line_type >= 4.5) && (v_line_type <= 5.5))
|
|
||||||
)) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
// skin: 1, 2, 3
|
|
||||||
if ((u_show_skin == 0) && (
|
|
||||||
(v_line_type >= 0.5) && (v_line_type <= 3.5)
|
|
||||||
)) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
// infill:
|
|
||||||
if ((u_show_infill == 0) && (v_line_type >= 5.5) && (v_line_type <= 6.5)) {
|
|
||||||
// discard movements
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
frag_color = v_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
[defaults]
|
|
||||||
u_active_extruder = 0.0
|
|
||||||
u_shade_factor = 0.60
|
|
||||||
u_layer_view_type = 0
|
|
||||||
u_extruder_opacity = [1.0, 1.0, 1.0, 1.0]
|
|
||||||
|
|
||||||
u_show_travel_moves = 0
|
|
||||||
u_show_helpers = 1
|
|
||||||
u_show_skin = 1
|
|
||||||
u_show_infill = 1
|
|
||||||
|
|
||||||
[bindings]
|
|
||||||
u_modelViewProjectionMatrix = model_view_projection_matrix
|
|
||||||
|
|
||||||
[attributes]
|
|
||||||
a_vertex = vertex
|
|
||||||
a_color = color
|
|
||||||
a_extruder = extruder
|
|
||||||
a_line_type = line_type
|
|
||||||
a_material_color = material_color
|
|
|
@ -1,264 +0,0 @@
|
||||||
[shaders]
|
|
||||||
vertex41core =
|
|
||||||
#version 410
|
|
||||||
uniform highp mat4 u_modelViewProjectionMatrix;
|
|
||||||
|
|
||||||
uniform highp mat4 u_modelMatrix;
|
|
||||||
uniform highp mat4 u_viewProjectionMatrix;
|
|
||||||
uniform lowp float u_active_extruder;
|
|
||||||
uniform lowp int u_layer_view_type;
|
|
||||||
uniform lowp vec4 u_extruder_opacity; // currently only for max 4 extruders, others always visible
|
|
||||||
|
|
||||||
uniform highp mat4 u_normalMatrix;
|
|
||||||
|
|
||||||
in highp vec4 a_vertex;
|
|
||||||
in lowp vec4 a_color;
|
|
||||||
in lowp vec4 a_material_color;
|
|
||||||
in highp vec4 a_normal;
|
|
||||||
in highp vec2 a_line_dim; // line width and thickness
|
|
||||||
in highp float a_extruder;
|
|
||||||
in highp float a_line_type;
|
|
||||||
|
|
||||||
out lowp vec4 v_color;
|
|
||||||
|
|
||||||
out highp vec3 v_vertex;
|
|
||||||
out highp vec3 v_normal;
|
|
||||||
out lowp vec2 v_line_dim;
|
|
||||||
out highp int v_extruder;
|
|
||||||
out highp vec4 v_extruder_opacity;
|
|
||||||
out float v_line_type;
|
|
||||||
|
|
||||||
out lowp vec4 f_color;
|
|
||||||
out highp vec3 f_vertex;
|
|
||||||
out highp vec3 f_normal;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec4 v1_vertex = a_vertex;
|
|
||||||
v1_vertex.y -= a_line_dim.y / 2; // half layer down
|
|
||||||
|
|
||||||
vec4 world_space_vert = u_modelMatrix * v1_vertex;
|
|
||||||
gl_Position = world_space_vert;
|
|
||||||
// shade the color depending on the extruder index stored in the alpha component of the color
|
|
||||||
|
|
||||||
switch (u_layer_view_type) {
|
|
||||||
case 0: // "Material color"
|
|
||||||
v_color = a_material_color;
|
|
||||||
break;
|
|
||||||
case 1: // "Line type"
|
|
||||||
v_color = a_color;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
v_vertex = world_space_vert.xyz;
|
|
||||||
v_normal = (u_normalMatrix * normalize(a_normal)).xyz;
|
|
||||||
v_line_dim = a_line_dim;
|
|
||||||
v_extruder = int(a_extruder);
|
|
||||||
v_line_type = a_line_type;
|
|
||||||
v_extruder_opacity = u_extruder_opacity;
|
|
||||||
|
|
||||||
// for testing without geometry shader
|
|
||||||
f_color = v_color;
|
|
||||||
f_vertex = v_vertex;
|
|
||||||
f_normal = v_normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
geometry41core =
|
|
||||||
#version 410
|
|
||||||
|
|
||||||
uniform highp mat4 u_viewProjectionMatrix;
|
|
||||||
uniform int u_show_travel_moves;
|
|
||||||
uniform int u_show_helpers;
|
|
||||||
uniform int u_show_skin;
|
|
||||||
uniform int u_show_infill;
|
|
||||||
|
|
||||||
layout(lines) in;
|
|
||||||
layout(triangle_strip, max_vertices = 26) out;
|
|
||||||
|
|
||||||
in vec4 v_color[];
|
|
||||||
in vec3 v_vertex[];
|
|
||||||
in vec3 v_normal[];
|
|
||||||
in vec2 v_line_dim[];
|
|
||||||
in int v_extruder[];
|
|
||||||
in vec4 v_extruder_opacity[];
|
|
||||||
in float v_line_type[];
|
|
||||||
|
|
||||||
out vec4 f_color;
|
|
||||||
out vec3 f_normal;
|
|
||||||
out vec3 f_vertex;
|
|
||||||
|
|
||||||
// Set the set of variables and EmitVertex
|
|
||||||
void myEmitVertex(vec3 vertex, vec4 color, vec3 normal, vec4 pos) {
|
|
||||||
f_vertex = vertex;
|
|
||||||
f_color = color;
|
|
||||||
f_normal = normal;
|
|
||||||
gl_Position = pos;
|
|
||||||
EmitVertex();
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec4 g_vertex_delta;
|
|
||||||
vec3 g_vertex_normal_horz; // horizontal and vertical in respect to layers
|
|
||||||
vec4 g_vertex_offset_horz; // vec4 to match gl_in[x].gl_Position
|
|
||||||
vec3 g_vertex_normal_vert;
|
|
||||||
vec4 g_vertex_offset_vert;
|
|
||||||
vec3 g_vertex_normal_horz_head;
|
|
||||||
vec4 g_vertex_offset_horz_head;
|
|
||||||
|
|
||||||
float size_x;
|
|
||||||
float size_y;
|
|
||||||
|
|
||||||
if ((v_extruder_opacity[0][v_extruder[0]] == 0.0) && (v_line_type[0] != 8) && (v_line_type[0] != 9)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// See LayerPolygon; 8 is MoveCombingType, 9 is RetractionType
|
|
||||||
if ((u_show_travel_moves == 0) && ((v_line_type[0] == 8) || (v_line_type[0] == 9))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((u_show_helpers == 0) && ((v_line_type[0] == 4) || (v_line_type[0] == 5) || (v_line_type[0] == 7) || (v_line_type[0] == 10))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((u_show_skin == 0) && ((v_line_type[0] == 1) || (v_line_type[0] == 2) || (v_line_type[0] == 3))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((u_show_infill == 0) && (v_line_type[0] == 6)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((v_line_type[0] == 8) || (v_line_type[0] == 9)) {
|
|
||||||
// fixed size for movements
|
|
||||||
size_x = 0.05;
|
|
||||||
} else {
|
|
||||||
size_x = v_line_dim[1].x / 2 + 0.01; // radius, and make it nicely overlapping
|
|
||||||
}
|
|
||||||
size_y = v_line_dim[1].y / 2 + 0.01;
|
|
||||||
|
|
||||||
g_vertex_delta = gl_in[1].gl_Position - gl_in[0].gl_Position;
|
|
||||||
g_vertex_normal_horz_head = normalize(vec3(-g_vertex_delta.x, -g_vertex_delta.y, -g_vertex_delta.z));
|
|
||||||
g_vertex_offset_horz_head = vec4(g_vertex_normal_horz_head * size_x, 0.0);
|
|
||||||
|
|
||||||
g_vertex_normal_horz = normalize(vec3(g_vertex_delta.z, g_vertex_delta.y, -g_vertex_delta.x));
|
|
||||||
|
|
||||||
g_vertex_offset_horz = vec4(g_vertex_normal_horz * size_x, 0.0); //size * g_vertex_normal_horz;
|
|
||||||
g_vertex_normal_vert = vec3(0.0, 1.0, 0.0);
|
|
||||||
g_vertex_offset_vert = vec4(g_vertex_normal_vert * size_y, 0.0);
|
|
||||||
|
|
||||||
if ((v_line_type[0] == 8) || (v_line_type[0] == 9)) {
|
|
||||||
// Travels: flat plane with pointy ends
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head + g_vertex_offset_vert));
|
|
||||||
|
|
||||||
EndPrimitive();
|
|
||||||
} else {
|
|
||||||
// All normal lines are rendered as 3d tubes.
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
|
|
||||||
|
|
||||||
EndPrimitive();
|
|
||||||
|
|
||||||
// left side
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
|
|
||||||
|
|
||||||
EndPrimitive();
|
|
||||||
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
|
|
||||||
|
|
||||||
EndPrimitive();
|
|
||||||
|
|
||||||
// right side
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
|
|
||||||
|
|
||||||
EndPrimitive();
|
|
||||||
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
|
|
||||||
|
|
||||||
EndPrimitive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment41core =
|
|
||||||
#version 410
|
|
||||||
in lowp vec4 f_color;
|
|
||||||
in lowp vec3 f_normal;
|
|
||||||
in lowp vec3 f_vertex;
|
|
||||||
|
|
||||||
out vec4 frag_color;
|
|
||||||
|
|
||||||
uniform mediump vec4 u_ambientColor;
|
|
||||||
uniform highp vec3 u_lightPosition;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
mediump vec4 finalColor = vec4(0.0);
|
|
||||||
float alpha = f_color.a;
|
|
||||||
|
|
||||||
finalColor.rgb += f_color.rgb * 0.3;
|
|
||||||
|
|
||||||
highp vec3 normal = normalize(f_normal);
|
|
||||||
highp vec3 light_dir = normalize(u_lightPosition - f_vertex);
|
|
||||||
|
|
||||||
// Diffuse Component
|
|
||||||
highp float NdotL = clamp(dot(normal, light_dir), 0.0, 1.0);
|
|
||||||
finalColor += (NdotL * f_color);
|
|
||||||
finalColor.a = alpha; // Do not change alpha in any way
|
|
||||||
|
|
||||||
frag_color = finalColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[defaults]
|
|
||||||
u_active_extruder = 0.0
|
|
||||||
u_layer_view_type = 0
|
|
||||||
u_extruder_opacity = [1.0, 1.0, 1.0, 1.0]
|
|
||||||
|
|
||||||
u_specularColor = [0.4, 0.4, 0.4, 1.0]
|
|
||||||
u_ambientColor = [0.3, 0.3, 0.3, 0.0]
|
|
||||||
u_diffuseColor = [1.0, 0.79, 0.14, 1.0]
|
|
||||||
u_shininess = 20.0
|
|
||||||
|
|
||||||
u_show_travel_moves = 0
|
|
||||||
u_show_helpers = 1
|
|
||||||
u_show_skin = 1
|
|
||||||
u_show_infill = 1
|
|
||||||
|
|
||||||
[bindings]
|
|
||||||
u_modelViewProjectionMatrix = model_view_projection_matrix
|
|
||||||
u_modelMatrix = model_matrix
|
|
||||||
u_viewProjectionMatrix = view_projection_matrix
|
|
||||||
u_normalMatrix = normal_matrix
|
|
||||||
u_lightPosition = light_0_position
|
|
||||||
|
|
||||||
[attributes]
|
|
||||||
a_vertex = vertex
|
|
||||||
a_color = color
|
|
||||||
a_normal = normal
|
|
||||||
a_line_dim = line_dim
|
|
||||||
a_extruder = extruder
|
|
||||||
a_material_color = material_color
|
|
||||||
a_line_type = line_type
|
|
|
@ -1,148 +0,0 @@
|
||||||
[shaders]
|
|
||||||
vertex =
|
|
||||||
uniform highp mat4 u_modelViewProjectionMatrix;
|
|
||||||
attribute highp vec4 a_vertex;
|
|
||||||
attribute highp vec2 a_uvs;
|
|
||||||
|
|
||||||
varying highp vec2 v_uvs;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = u_modelViewProjectionMatrix * a_vertex;
|
|
||||||
v_uvs = a_uvs;
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment =
|
|
||||||
uniform sampler2D u_layer0;
|
|
||||||
uniform sampler2D u_layer1;
|
|
||||||
uniform sampler2D u_layer2;
|
|
||||||
|
|
||||||
uniform vec2 u_offset[9];
|
|
||||||
|
|
||||||
uniform vec4 u_background_color;
|
|
||||||
uniform float u_outline_strength;
|
|
||||||
uniform vec4 u_outline_color;
|
|
||||||
|
|
||||||
varying vec2 v_uvs;
|
|
||||||
|
|
||||||
float kernel[9];
|
|
||||||
|
|
||||||
const vec3 x_axis = vec3(1.0, 0.0, 0.0);
|
|
||||||
const vec3 y_axis = vec3(0.0, 1.0, 0.0);
|
|
||||||
const vec3 z_axis = vec3(0.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// blur kernel
|
|
||||||
kernel[0] = 0.0; kernel[1] = 1.0; kernel[2] = 0.0;
|
|
||||||
kernel[3] = 1.0; kernel[4] = -4.0; kernel[5] = 1.0;
|
|
||||||
kernel[6] = 0.0; kernel[7] = 1.0; kernel[8] = 0.0;
|
|
||||||
|
|
||||||
vec4 result = u_background_color;
|
|
||||||
|
|
||||||
vec4 main_layer = texture2D(u_layer0, v_uvs);
|
|
||||||
vec4 selection_layer = texture2D(u_layer1, v_uvs);
|
|
||||||
vec4 layerview_layer = texture2D(u_layer2, v_uvs);
|
|
||||||
|
|
||||||
result = main_layer * main_layer.a + result * (1.0 - main_layer.a);
|
|
||||||
result = layerview_layer * layerview_layer.a + result * (1.0 - layerview_layer.a);
|
|
||||||
|
|
||||||
vec4 sum = vec4(0.0);
|
|
||||||
for (int i = 0; i < 9; i++)
|
|
||||||
{
|
|
||||||
vec4 color = vec4(texture2D(u_layer1, v_uvs.xy + u_offset[i]).a);
|
|
||||||
sum += color * (kernel[i] / u_outline_strength);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((selection_layer.rgb == x_axis || selection_layer.rgb == y_axis || selection_layer.rgb == z_axis))
|
|
||||||
{
|
|
||||||
gl_FragColor = result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gl_FragColor = mix(result, u_outline_color, abs(sum.a));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vertex41core =
|
|
||||||
#version 410
|
|
||||||
uniform highp mat4 u_modelViewProjectionMatrix;
|
|
||||||
in highp vec4 a_vertex;
|
|
||||||
in highp vec2 a_uvs;
|
|
||||||
|
|
||||||
out highp vec2 v_uvs;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = u_modelViewProjectionMatrix * a_vertex;
|
|
||||||
v_uvs = a_uvs;
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment41core =
|
|
||||||
#version 410
|
|
||||||
uniform sampler2D u_layer0;
|
|
||||||
uniform sampler2D u_layer1;
|
|
||||||
uniform sampler2D u_layer2;
|
|
||||||
|
|
||||||
uniform vec2 u_offset[9];
|
|
||||||
|
|
||||||
uniform vec4 u_background_color;
|
|
||||||
uniform float u_outline_strength;
|
|
||||||
uniform vec4 u_outline_color;
|
|
||||||
|
|
||||||
in vec2 v_uvs;
|
|
||||||
|
|
||||||
float kernel[9];
|
|
||||||
|
|
||||||
const vec3 x_axis = vec3(1.0, 0.0, 0.0);
|
|
||||||
const vec3 y_axis = vec3(0.0, 1.0, 0.0);
|
|
||||||
const vec3 z_axis = vec3(0.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
out vec4 frag_color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// blur kernel
|
|
||||||
kernel[0] = 0.0; kernel[1] = 1.0; kernel[2] = 0.0;
|
|
||||||
kernel[3] = 1.0; kernel[4] = -4.0; kernel[5] = 1.0;
|
|
||||||
kernel[6] = 0.0; kernel[7] = 1.0; kernel[8] = 0.0;
|
|
||||||
|
|
||||||
vec4 result = u_background_color;
|
|
||||||
|
|
||||||
vec4 main_layer = texture(u_layer0, v_uvs);
|
|
||||||
vec4 selection_layer = texture(u_layer1, v_uvs);
|
|
||||||
vec4 layerview_layer = texture(u_layer2, v_uvs);
|
|
||||||
|
|
||||||
result = main_layer * main_layer.a + result * (1.0 - main_layer.a);
|
|
||||||
result = layerview_layer * layerview_layer.a + result * (1.0 - layerview_layer.a);
|
|
||||||
|
|
||||||
vec4 sum = vec4(0.0);
|
|
||||||
for (int i = 0; i < 9; i++)
|
|
||||||
{
|
|
||||||
vec4 color = vec4(texture(u_layer1, v_uvs.xy + u_offset[i]).a);
|
|
||||||
sum += color * (kernel[i] / u_outline_strength);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((selection_layer.rgb == x_axis || selection_layer.rgb == y_axis || selection_layer.rgb == z_axis))
|
|
||||||
{
|
|
||||||
frag_color = result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
frag_color = mix(result, u_outline_color, abs(sum.a));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[defaults]
|
|
||||||
u_layer0 = 0
|
|
||||||
u_layer1 = 1
|
|
||||||
u_layer2 = 2
|
|
||||||
u_background_color = [0.965, 0.965, 0.965, 1.0]
|
|
||||||
u_outline_strength = 1.0
|
|
||||||
u_outline_color = [0.05, 0.66, 0.89, 1.0]
|
|
||||||
|
|
||||||
[bindings]
|
|
||||||
|
|
||||||
[attributes]
|
|
||||||
a_vertex = vertex
|
|
||||||
a_uvs = uv
|
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"name": "Layer View",
|
|
||||||
"author": "Ultimaker B.V.",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Provides the Layer view.",
|
|
||||||
"api": 4,
|
|
||||||
"i18n-catalog": "cura"
|
|
||||||
}
|
|
|
@ -133,6 +133,7 @@
|
||||||
"slider_groove_fill": [245, 245, 245, 255],
|
"slider_groove_fill": [245, 245, 245, 255],
|
||||||
"slider_handle": [255, 255, 255, 255],
|
"slider_handle": [255, 255, 255, 255],
|
||||||
"slider_handle_hover": [77, 182, 226, 255],
|
"slider_handle_hover": [77, 182, 226, 255],
|
||||||
|
"slider_handle_active": [68, 192, 255, 255],
|
||||||
"slider_handle_border": [39, 44, 48, 255],
|
"slider_handle_border": [39, 44, 48, 255],
|
||||||
"slider_text_background": [255, 255, 255, 255],
|
"slider_text_background": [255, 255, 255, 255],
|
||||||
|
|
||||||
|
@ -194,6 +195,7 @@
|
||||||
"layerview_move_combing": [0, 0, 255, 255],
|
"layerview_move_combing": [0, 0, 255, 255],
|
||||||
"layerview_move_retraction": [128, 128, 255, 255],
|
"layerview_move_retraction": [128, 128, 255, 255],
|
||||||
"layerview_support_interface": [64, 192, 255, 255],
|
"layerview_support_interface": [64, 192, 255, 255],
|
||||||
|
"layerview_nozzle": [181, 166, 66, 120],
|
||||||
|
|
||||||
"material_compatibility_warning": [255, 255, 255, 255],
|
"material_compatibility_warning": [255, 255, 255, 255],
|
||||||
|
|
||||||
|
|
|
@ -269,6 +269,7 @@ QtObject {
|
||||||
arrowSize: Theme.getSize("button_tooltip_arrow").width
|
arrowSize: Theme.getSize("button_tooltip_arrow").width
|
||||||
color: Theme.getColor("button_tooltip")
|
color: Theme.getColor("button_tooltip")
|
||||||
opacity: control.hovered ? 1.0 : 0.0;
|
opacity: control.hovered ? 1.0 : 0.0;
|
||||||
|
visible: control.text != ""
|
||||||
|
|
||||||
width: control.hovered ? button_tip.width + Theme.getSize("button_tooltip").width : 0
|
width: control.hovered ? button_tip.width + Theme.getSize("button_tooltip").width : 0
|
||||||
height: Theme.getSize("button_tooltip").height
|
height: Theme.getSize("button_tooltip").height
|
||||||
|
|
|
@ -183,6 +183,7 @@
|
||||||
"slider_groove_fill": [127, 127, 127, 255],
|
"slider_groove_fill": [127, 127, 127, 255],
|
||||||
"slider_handle": [0, 0, 0, 255],
|
"slider_handle": [0, 0, 0, 255],
|
||||||
"slider_handle_hover": [77, 182, 226, 255],
|
"slider_handle_hover": [77, 182, 226, 255],
|
||||||
|
"slider_handle_active": [68, 192, 255, 255],
|
||||||
"slider_handle_border": [39, 44, 48, 255],
|
"slider_handle_border": [39, 44, 48, 255],
|
||||||
"slider_text_background": [255, 255, 255, 255],
|
"slider_text_background": [255, 255, 255, 255],
|
||||||
|
|
||||||
|
@ -271,7 +272,8 @@
|
||||||
"layerview_support_infill": [0, 255, 255, 255],
|
"layerview_support_infill": [0, 255, 255, 255],
|
||||||
"layerview_move_combing": [0, 0, 255, 255],
|
"layerview_move_combing": [0, 0, 255, 255],
|
||||||
"layerview_move_retraction": [128, 128, 255, 255],
|
"layerview_move_retraction": [128, 128, 255, 255],
|
||||||
"layerview_support_interface": [64, 192, 255, 255]
|
"layerview_support_interface": [64, 192, 255, 255],
|
||||||
|
"layerview_nozzle": [181, 166, 66, 50]
|
||||||
},
|
},
|
||||||
|
|
||||||
"sizes": {
|
"sizes": {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue