mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 11:06:00 +08:00
Merge branch 'master' into fs_mouse
This commit is contained in:
commit
0d48cf5ab9
@ -506,6 +506,12 @@ endif ()
|
|||||||
|
|
||||||
# Find the Cereal serialization library
|
# Find the Cereal serialization library
|
||||||
find_package(cereal REQUIRED)
|
find_package(cereal REQUIRED)
|
||||||
|
add_library(libcereal INTERFACE)
|
||||||
|
if (NOT TARGET cereal::cereal)
|
||||||
|
target_link_libraries(libcereal INTERFACE cereal)
|
||||||
|
else()
|
||||||
|
target_link_libraries(libcereal INTERFACE cereal::cereal)
|
||||||
|
endif()
|
||||||
|
|
||||||
# l10n
|
# l10n
|
||||||
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization")
|
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization")
|
||||||
|
4
deps/wxWidgets/wxWidgets.cmake
vendored
4
deps/wxWidgets/wxWidgets.cmake
vendored
@ -12,8 +12,8 @@ endif()
|
|||||||
prusaslicer_add_cmake_project(wxWidgets
|
prusaslicer_add_cmake_project(wxWidgets
|
||||||
# GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
|
# GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
|
||||||
# GIT_TAG tm_cross_compile #${_wx_git_tag}
|
# GIT_TAG tm_cross_compile #${_wx_git_tag}
|
||||||
URL https://github.com/prusa3d/wxWidgets/archive/73f029adfcc82fb3aa4b01220a013f716e57d110.zip
|
URL https://github.com/prusa3d/wxWidgets/archive/489f6118256853cf5b299d595868641938566cdb.zip
|
||||||
URL_HASH SHA256=c35fe0187db497b6a3f477e24ed5e307028657ff0c2554385810b6e7961ad2e4
|
URL_HASH SHA256=5b22d465377cedd8044bba69bea958b248953fd3628c1de4913a84d4e6f6175b
|
||||||
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG
|
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG
|
||||||
CMAKE_ARGS
|
CMAKE_ARGS
|
||||||
-DwxBUILD_PRECOMP=ON
|
-DwxBUILD_PRECOMP=ON
|
||||||
|
@ -64,6 +64,13 @@ technology = FFF
|
|||||||
family = PREDATOR
|
family = PREDATOR
|
||||||
default_materials = Generic PLA @PREDATOR; Generic PETG @PREDATOR; Generic ABS @PREDATOR
|
default_materials = Generic PLA @PREDATOR; Generic PETG @PREDATOR; Generic ABS @PREDATOR
|
||||||
|
|
||||||
|
[printer_model:PHOTON MONO X]
|
||||||
|
name = Photon Mono X
|
||||||
|
variants = default
|
||||||
|
technology = SLA
|
||||||
|
family = PHOTON MONO
|
||||||
|
default_materials = Generic Blue Resin @MONO 0.05
|
||||||
|
|
||||||
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
||||||
# not make it into the user interface.
|
# not make it into the user interface.
|
||||||
|
|
||||||
@ -1898,3 +1905,94 @@ default_print_profile = 0.24mm 0.8 nozzle DETAILED QUALITY @PREDATOR
|
|||||||
#########################################
|
#########################################
|
||||||
########## end printer presets ##########
|
########## end printer presets ##########
|
||||||
#########################################
|
#########################################
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
########## SLA printer presets ##########
|
||||||
|
#########################################
|
||||||
|
|
||||||
|
|
||||||
|
[sla_print:*common print ANYCUBIC SLA*]
|
||||||
|
compatible_printers_condition = family=="PHOTON MONO"
|
||||||
|
layer_height = 0.05
|
||||||
|
output_filename_format = [input_filename_base].pwmx
|
||||||
|
pad_edge_radius = 0.5
|
||||||
|
pad_enable = 0
|
||||||
|
pad_max_merge_distance = 50
|
||||||
|
pad_wall_height = 0
|
||||||
|
pad_wall_thickness = 1
|
||||||
|
pad_wall_slope = 45
|
||||||
|
faded_layers = 8
|
||||||
|
slice_closing_radius = 0.005
|
||||||
|
support_base_diameter = 3
|
||||||
|
support_base_height = 1
|
||||||
|
support_critical_angle = 45
|
||||||
|
support_density_at_45 = 250
|
||||||
|
support_density_at_horizontal = 500
|
||||||
|
support_head_front_diameter = 0.4
|
||||||
|
support_head_penetration = 0.4
|
||||||
|
support_head_width = 3
|
||||||
|
support_max_bridge_length = 10
|
||||||
|
support_minimal_z = 0
|
||||||
|
support_object_elevation = 5
|
||||||
|
support_pillar_diameter = 1
|
||||||
|
support_pillar_connection_mode = zigzag
|
||||||
|
support_pillar_widening_factor = 0
|
||||||
|
supports_enable = 1
|
||||||
|
support_small_pillar_diameter_percent = 60%
|
||||||
|
|
||||||
|
[sla_print:0.05 Normal @ANYCUBIC]
|
||||||
|
inherits = *common print ANYCUBIC SLA*
|
||||||
|
layer_height = 0.05
|
||||||
|
|
||||||
|
########### Materials
|
||||||
|
|
||||||
|
[sla_material:*common ANYCUBIC SLA*]
|
||||||
|
compatible_printers_condition = printer_notes=~/.*PHOTONMONOX.*/
|
||||||
|
compatible_prints_condition = layer_height == 0.05
|
||||||
|
exposure_time = 7
|
||||||
|
initial_exposure_time = 40
|
||||||
|
initial_layer_height = 0.05
|
||||||
|
material_correction = 1,1,1
|
||||||
|
material_notes = LIFT_DISTANCE=8.0\nLIFT_SPEED=2.5\nRETRACT_SPEED=3.0\nBOTTOM_LIFT_SPEED=2.0\nBOTTOM_LIFT_DISTANCE=9.0\nDELAY_BEFORE_EXPOSURE=0.5
|
||||||
|
|
||||||
|
[sla_material:*common 0.05 ANYCUBIC SLA*]
|
||||||
|
inherits = *common ANYCUBIC SLA*
|
||||||
|
|
||||||
|
[sla_material:Generic Blue Resin @MONO 0.05]
|
||||||
|
inherits = *common 0.05 ANYCUBIC SLA*
|
||||||
|
exposure_time = 2.5
|
||||||
|
initial_exposure_time = 40
|
||||||
|
material_type = Tough
|
||||||
|
material_vendor = Generic
|
||||||
|
material_colour = #6080EC
|
||||||
|
compatible_printers_condition = printer_notes=~/.*PHOTONMONOX.*/
|
||||||
|
|
||||||
|
########## Printers
|
||||||
|
|
||||||
|
[printer:Anycubic Photon Mono X]
|
||||||
|
printer_technology = SLA
|
||||||
|
printer_model = PHOTON MONO X
|
||||||
|
printer_variant = default
|
||||||
|
default_sla_material_profile = Generic Blue Resin @MONO 0.05
|
||||||
|
default_sla_print_profile = 0.05 Normal @ANYCUBIC
|
||||||
|
thumbnails = 224x168
|
||||||
|
sla_archive_format = pwmx
|
||||||
|
bed_shape = 1.48x1.02,193.48x1.02,193.48x121.02,1.48x121.02
|
||||||
|
display_height = 120
|
||||||
|
display_orientation = landscape
|
||||||
|
display_mirror_x = 1
|
||||||
|
display_mirror_y = 0
|
||||||
|
display_pixels_x = 3840
|
||||||
|
display_pixels_y = 2400
|
||||||
|
display_width = 192
|
||||||
|
max_print_height = 245
|
||||||
|
elefant_foot_compensation = 0.2
|
||||||
|
elefant_foot_min_width = 0.2
|
||||||
|
min_exposure_time = 1
|
||||||
|
max_exposure_time = 120
|
||||||
|
min_initial_exposure_time = 1
|
||||||
|
max_initial_exposure_time = 300
|
||||||
|
printer_correction = 1,1,1
|
||||||
|
gamma_correction = 1
|
||||||
|
area_fill = 45
|
||||||
|
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.'\nPRINTER_VENDOR_ANYCUBIC\nPRINTER_MODEL_PHOTONMONOX\n
|
||||||
|
BIN
resources/profiles/Anycubic/PHOTON MONO X_thumbnail.png
Normal file
BIN
resources/profiles/Anycubic/PHOTON MONO X_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
@ -126,7 +126,7 @@ if (NOT WIN32 AND NOT APPLE)
|
|||||||
set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer")
|
set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
target_link_libraries(PrusaSlicer libslic3r cereal)
|
target_link_libraries(PrusaSlicer libslic3r libcereal)
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
# add_compile_options(-stdlib=libc++)
|
# add_compile_options(-stdlib=libc++)
|
||||||
# add_definitions(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE)
|
# add_definitions(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE)
|
||||||
|
@ -94,6 +94,12 @@ public:
|
|||||||
// Called on initial G-code preview on OpenGL vertex buffer interleaved normals and vertices.
|
// Called on initial G-code preview on OpenGL vertex buffer interleaved normals and vertices.
|
||||||
bool all_paths_inside_vertices_and_normals_interleaved(const std::vector<float>& paths, const Eigen::AlignedBox<float, 3>& bbox, bool ignore_bottom = true) const;
|
bool all_paths_inside_vertices_and_normals_interleaved(const std::vector<float>& paths, const Eigen::AlignedBox<float, 3>& bbox, bool ignore_bottom = true) const;
|
||||||
|
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
const std::pair<std::vector<Vec2d>, std::vector<Vec2d>>& top_bottom_convex_hull_decomposition_scene() const { return m_top_bottom_convex_hull_decomposition_scene; }
|
||||||
|
const std::pair<std::vector<Vec2d>, std::vector<Vec2d>>& top_bottom_convex_hull_decomposition_bed() const { return m_top_bottom_convex_hull_decomposition_bed; }
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Source definition of the print bed geometry (PrintConfig::bed_shape)
|
// Source definition of the print bed geometry (PrintConfig::bed_shape)
|
||||||
std::vector<Vec2d> m_bed_shape;
|
std::vector<Vec2d> m_bed_shape;
|
||||||
|
@ -94,10 +94,14 @@ set(SLIC3R_SOURCES
|
|||||||
Format/objparser.hpp
|
Format/objparser.hpp
|
||||||
Format/STL.cpp
|
Format/STL.cpp
|
||||||
Format/STL.hpp
|
Format/STL.hpp
|
||||||
|
Format/SLAArchive.hpp
|
||||||
|
Format/SLAArchive.cpp
|
||||||
Format/SL1.hpp
|
Format/SL1.hpp
|
||||||
Format/SL1.cpp
|
Format/SL1.cpp
|
||||||
Format/SL1_SVG.hpp
|
Format/SL1_SVG.hpp
|
||||||
Format/SL1_SVG.cpp
|
Format/SL1_SVG.cpp
|
||||||
|
Format/pwmx.hpp
|
||||||
|
Format/pwmx.cpp
|
||||||
GCode/ThumbnailData.cpp
|
GCode/ThumbnailData.cpp
|
||||||
GCode/ThumbnailData.hpp
|
GCode/ThumbnailData.hpp
|
||||||
GCode/Thumbnails.cpp
|
GCode/Thumbnails.cpp
|
||||||
@ -354,7 +358,7 @@ find_package(JPEG REQUIRED)
|
|||||||
target_link_libraries(libslic3r
|
target_link_libraries(libslic3r
|
||||||
libnest2d
|
libnest2d
|
||||||
admesh
|
admesh
|
||||||
cereal
|
libcereal
|
||||||
libigl
|
libigl
|
||||||
miniz
|
miniz
|
||||||
boost_libs
|
boost_libs
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
@ -44,7 +45,8 @@ size_t max_concurrency(const EP &ep)
|
|||||||
template<class EP, class It, class Fn, class = ExecutionPolicyOnly<EP>>
|
template<class EP, class It, class Fn, class = ExecutionPolicyOnly<EP>>
|
||||||
void for_each(const EP &ep, It from, It to, Fn &&fn, size_t granularity = 1)
|
void for_each(const EP &ep, It from, It to, Fn &&fn, size_t granularity = 1)
|
||||||
{
|
{
|
||||||
AsTraits<EP>::for_each(ep, from, to, std::forward<Fn>(fn), granularity);
|
AsTraits<EP>::for_each(ep, from, to, std::forward<Fn>(fn),
|
||||||
|
std::max(granularity, size_t(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A reduce operation with the execution policy passed as argument.
|
// A reduce operation with the execution policy passed as argument.
|
||||||
@ -68,7 +70,7 @@ T reduce(const EP & ep,
|
|||||||
return AsTraits<EP>::reduce(ep, from, to, init,
|
return AsTraits<EP>::reduce(ep, from, to, init,
|
||||||
std::forward<MergeFn>(mergefn),
|
std::forward<MergeFn>(mergefn),
|
||||||
std::forward<AccessFn>(accessfn),
|
std::forward<AccessFn>(accessfn),
|
||||||
granularity);
|
std::max(granularity, size_t(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// An overload of reduce method to be used with iterators as 'from' and 'to'
|
// An overload of reduce method to be used with iterators as 'from' and 'to'
|
||||||
@ -87,7 +89,7 @@ T reduce(const EP &ep,
|
|||||||
{
|
{
|
||||||
return reduce(
|
return reduce(
|
||||||
ep, from, to, init, std::forward<MergeFn>(mergefn),
|
ep, from, to, init, std::forward<MergeFn>(mergefn),
|
||||||
[](const auto &i) { return i; }, granularity);
|
[](const auto &i) { return i; }, std::max(granularity, size_t(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class EP,
|
template<class EP,
|
||||||
@ -103,7 +105,8 @@ T accumulate(const EP & ep,
|
|||||||
size_t granularity = 1)
|
size_t granularity = 1)
|
||||||
{
|
{
|
||||||
return reduce(ep, from, to, init, std::plus<T>{},
|
return reduce(ep, from, to, init, std::plus<T>{},
|
||||||
std::forward<AccessFn>(accessfn), granularity);
|
std::forward<AccessFn>(accessfn),
|
||||||
|
std::max(granularity, size_t(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -119,7 +122,7 @@ T accumulate(const EP &ep,
|
|||||||
{
|
{
|
||||||
return reduce(
|
return reduce(
|
||||||
ep, from, to, init, std::plus<T>{}, [](const auto &i) { return i; },
|
ep, from, to, init, std::plus<T>{}, [](const auto &i) { return i; },
|
||||||
granularity);
|
std::max(granularity, size_t(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace execution_policy
|
} // namespace execution_policy
|
||||||
|
@ -20,11 +20,14 @@
|
|||||||
#include "libslic3r/miniz_extension.hpp"
|
#include "libslic3r/miniz_extension.hpp"
|
||||||
#include "libslic3r/PNGReadWrite.hpp"
|
#include "libslic3r/PNGReadWrite.hpp"
|
||||||
#include "libslic3r/LocalesUtils.hpp"
|
#include "libslic3r/LocalesUtils.hpp"
|
||||||
|
#include "libslic3r/GCode/ThumbnailData.hpp"
|
||||||
|
|
||||||
#include <boost/property_tree/ini_parser.hpp>
|
#include <boost/property_tree/ini_parser.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
|
#include <miniz.h>
|
||||||
|
|
||||||
namespace marchsq {
|
namespace marchsq {
|
||||||
|
|
||||||
template<> struct _RasterTraits<Slic3r::png::ImageGreyscale> {
|
template<> struct _RasterTraits<Slic3r::png::ImageGreyscale> {
|
||||||
@ -482,10 +485,31 @@ sla::RasterEncoder SL1Archive::get_encoder() const
|
|||||||
return sla::PNGRasterEncoder{};
|
return sla::PNGRasterEncoder{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SL1Archive::export_print(Zipper& zipper,
|
static void write_thumbnail(Zipper &zipper, const ThumbnailData &data)
|
||||||
const SLAPrint &print,
|
|
||||||
const std::string &prjname)
|
|
||||||
{
|
{
|
||||||
|
size_t png_size = 0;
|
||||||
|
|
||||||
|
void *png_data = tdefl_write_image_to_png_file_in_memory_ex(
|
||||||
|
(const void *) data.pixels.data(), data.width, data.height, 4,
|
||||||
|
&png_size, MZ_DEFAULT_LEVEL, 1);
|
||||||
|
|
||||||
|
if (png_data != nullptr) {
|
||||||
|
zipper.add_entry("thumbnail/thumbnail" + std::to_string(data.width) +
|
||||||
|
"x" + std::to_string(data.height) + ".png",
|
||||||
|
static_cast<const std::uint8_t *>(png_data),
|
||||||
|
png_size);
|
||||||
|
|
||||||
|
mz_free(png_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SL1Archive::export_print(const std::string fname,
|
||||||
|
const SLAPrint &print,
|
||||||
|
const ThumbnailsList &thumbnails,
|
||||||
|
const std::string &prjname)
|
||||||
|
{
|
||||||
|
Zipper zipper{fname};
|
||||||
|
|
||||||
std::string project =
|
std::string project =
|
||||||
prjname.empty() ?
|
prjname.empty() ?
|
||||||
boost::filesystem::path(zipper.get_filename()).stem().string() :
|
boost::filesystem::path(zipper.get_filename()).stem().string() :
|
||||||
@ -512,6 +536,12 @@ void SL1Archive::export_print(Zipper& zipper,
|
|||||||
|
|
||||||
zipper.add_entry(imgname.c_str(), rst.data(), rst.size());
|
zipper.add_entry(imgname.c_str(), rst.data(), rst.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const ThumbnailData& data : thumbnails)
|
||||||
|
if (data.is_valid())
|
||||||
|
write_thumbnail(zipper, data);
|
||||||
|
|
||||||
|
zipper.finalize();
|
||||||
} catch(std::exception& e) {
|
} catch(std::exception& e) {
|
||||||
BOOST_LOG_TRIVIAL(error) << e.what();
|
BOOST_LOG_TRIVIAL(error) << e.what();
|
||||||
// Rethrow the exception
|
// Rethrow the exception
|
||||||
|
@ -3,8 +3,12 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "SLAArchive.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Zipper.hpp"
|
#include "libslic3r/Zipper.hpp"
|
||||||
#include "libslic3r/SLAPrint.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
|
|
||||||
|
struct indexed_triangle_set;
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@ -23,8 +27,11 @@ public:
|
|||||||
SL1Archive() = default;
|
SL1Archive() = default;
|
||||||
explicit SL1Archive(const SLAPrinterConfig &cfg): m_cfg(cfg) {}
|
explicit SL1Archive(const SLAPrinterConfig &cfg): m_cfg(cfg) {}
|
||||||
explicit SL1Archive(SLAPrinterConfig &&cfg): m_cfg(std::move(cfg)) {}
|
explicit SL1Archive(SLAPrinterConfig &&cfg): m_cfg(std::move(cfg)) {}
|
||||||
|
|
||||||
void export_print(Zipper &zipper, const SLAPrint &print, const std::string &projectname = "") override;
|
void export_print(const std::string fname,
|
||||||
|
const SLAPrint &print,
|
||||||
|
const ThumbnailsList &thumbnails,
|
||||||
|
const std::string &projectname = "") override;
|
||||||
};
|
};
|
||||||
|
|
||||||
ConfigSubstitutions import_sla_archive(const std::string &zipfname, DynamicPrintConfig &out);
|
ConfigSubstitutions import_sla_archive(const std::string &zipfname, DynamicPrintConfig &out);
|
||||||
|
@ -2,10 +2,13 @@
|
|||||||
#include "SLA/RasterBase.hpp"
|
#include "SLA/RasterBase.hpp"
|
||||||
#include "libslic3r/LocalesUtils.hpp"
|
#include "libslic3r/LocalesUtils.hpp"
|
||||||
#include "libslic3r/ClipperUtils.hpp"
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
|
#include "libslic3r/BoundingBox.hpp"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <string_view>
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@ -77,20 +80,23 @@ void append_svg(std::string &buf, const Polygon &poly)
|
|||||||
|
|
||||||
char intbuf[coord_t_bufsize];
|
char intbuf[coord_t_bufsize];
|
||||||
|
|
||||||
buf += std::string("<path d=\"M ") + decimal_from(c.x(), intbuf);
|
buf += "<path d=\"M "sv;
|
||||||
buf += std::string(" ") + decimal_from(c.y(), intbuf) + " m";
|
buf += decimal_from(c.x(), intbuf);
|
||||||
|
buf += " "sv;
|
||||||
|
buf += decimal_from(c.y(), intbuf);
|
||||||
|
buf += " m"sv;
|
||||||
|
|
||||||
for (auto &p : poly) {
|
for (auto &p : poly) {
|
||||||
auto d = p - c;
|
auto d = p - c;
|
||||||
if (d.squaredNorm() == 0) continue;
|
if (d.squaredNorm() == 0) continue;
|
||||||
buf += " ";
|
buf += " "sv;
|
||||||
buf += decimal_from(p.x() - c.x(), intbuf);
|
buf += decimal_from(p.x() - c.x(), intbuf);
|
||||||
buf += " ";
|
buf += " "sv;
|
||||||
buf += decimal_from(p.y() - c.y(), intbuf);
|
buf += decimal_from(p.y() - c.y(), intbuf);
|
||||||
c = p;
|
c = p;
|
||||||
}
|
}
|
||||||
buf += " z\""; // mark path as closed
|
buf += " z\""sv; // mark path as closed
|
||||||
buf += " />\n";
|
buf += " />\n"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -167,12 +173,12 @@ public:
|
|||||||
sla::EncodedRaster encode(sla::RasterEncoder /*encoder*/) const override
|
sla::EncodedRaster encode(sla::RasterEncoder /*encoder*/) const override
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
constexpr const char finish[] = "</svg>\n";
|
constexpr auto finish = "</svg>\n"sv;
|
||||||
|
|
||||||
data.reserve(m_svg.size() + std::size(finish));
|
data.reserve(m_svg.size() + std::size(finish));
|
||||||
|
|
||||||
std::copy(m_svg.begin(), m_svg.end(), std::back_inserter(data));
|
std::copy(m_svg.begin(), m_svg.end(), std::back_inserter(data));
|
||||||
std::copy(finish, finish + std::size(finish) - 1, std::back_inserter(data));
|
std::copy(finish.begin(), finish.end() - 1, std::back_inserter(data));
|
||||||
|
|
||||||
return sla::EncodedRaster{std::move(data), "svg"};
|
return sla::EncodedRaster{std::move(data), "svg"};
|
||||||
}
|
}
|
||||||
|
74
src/libslic3r/Format/SLAArchive.cpp
Normal file
74
src/libslic3r/Format/SLAArchive.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "SLAArchive.hpp"
|
||||||
|
|
||||||
|
#include "SL1.hpp"
|
||||||
|
#include "SL1_SVG.hpp"
|
||||||
|
#include "pwmx.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
using ArchiveFactory = std::function<std::unique_ptr<SLAArchive>(const SLAPrinterConfig&)>;
|
||||||
|
|
||||||
|
struct ArchiveEntry {
|
||||||
|
const char *ext;
|
||||||
|
ArchiveFactory factoryfn;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::map<std::string, ArchiveEntry> REGISTERED_ARCHIVES {
|
||||||
|
{
|
||||||
|
"SL1",
|
||||||
|
{ "sl1", [] (const auto &cfg) { return std::make_unique<SL1Archive>(cfg); } }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SL2",
|
||||||
|
{ "sl2", [] (const auto &cfg) { return std::make_unique<SL1_SVGArchive>(cfg); } }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pwmx",
|
||||||
|
{ "pwmx", [] (const auto &cfg) { return std::make_unique<PwmxArchive>(cfg); } }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<SLAArchive>
|
||||||
|
SLAArchive::create(const std::string &archtype, const SLAPrinterConfig &cfg)
|
||||||
|
{
|
||||||
|
auto entry = REGISTERED_ARCHIVES.find(archtype);
|
||||||
|
|
||||||
|
if (entry != REGISTERED_ARCHIVES.end())
|
||||||
|
return entry->second.factoryfn(cfg);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<const char*>& SLAArchive::registered_archives()
|
||||||
|
{
|
||||||
|
static std::vector<const char*> archnames;
|
||||||
|
|
||||||
|
if (archnames.empty()) {
|
||||||
|
archnames.reserve(REGISTERED_ARCHIVES.size());
|
||||||
|
|
||||||
|
for (auto &[name, _] : REGISTERED_ARCHIVES)
|
||||||
|
archnames.emplace_back(name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return archnames;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *SLAArchive::get_extension(const char *archtype)
|
||||||
|
{
|
||||||
|
static const char* DEFAULT_EXT = "zip";
|
||||||
|
|
||||||
|
auto entry = REGISTERED_ARCHIVES.find(archtype);
|
||||||
|
if (entry != REGISTERED_ARCHIVES.end())
|
||||||
|
return entry->second.ext;
|
||||||
|
|
||||||
|
return DEFAULT_EXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
64
src/libslic3r/Format/SLAArchive.hpp
Normal file
64
src/libslic3r/Format/SLAArchive.hpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#ifndef SLAARCHIVE_HPP
|
||||||
|
#define SLAARCHIVE_HPP
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "libslic3r/SLA/RasterBase.hpp"
|
||||||
|
#include "libslic3r/Execution/ExecutionTBB.hpp"
|
||||||
|
#include "libslic3r/GCode/ThumbnailData.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class SLAPrint;
|
||||||
|
class SLAPrinterConfig;
|
||||||
|
|
||||||
|
class SLAArchive {
|
||||||
|
protected:
|
||||||
|
std::vector<sla::EncodedRaster> m_layers;
|
||||||
|
|
||||||
|
virtual std::unique_ptr<sla::RasterBase> create_raster() const = 0;
|
||||||
|
virtual sla::RasterEncoder get_encoder() const = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~SLAArchive() = default;
|
||||||
|
|
||||||
|
// Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid);
|
||||||
|
template<class Fn, class CancelFn, class EP = ExecutionTBB>
|
||||||
|
void draw_layers(
|
||||||
|
size_t layer_num,
|
||||||
|
Fn && drawfn,
|
||||||
|
CancelFn cancelfn = []() { return false; },
|
||||||
|
const EP & ep = {})
|
||||||
|
{
|
||||||
|
m_layers.resize(layer_num);
|
||||||
|
execution::for_each(
|
||||||
|
ep, size_t(0), m_layers.size(),
|
||||||
|
[this, &drawfn, &cancelfn](size_t idx) {
|
||||||
|
if (cancelfn()) return;
|
||||||
|
|
||||||
|
sla::EncodedRaster &enc = m_layers[idx];
|
||||||
|
auto rst = create_raster();
|
||||||
|
drawfn(*rst, idx);
|
||||||
|
enc = rst->encode(get_encoder());
|
||||||
|
},
|
||||||
|
execution::max_concurrency(ep));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the print into an archive using the provided filename.
|
||||||
|
virtual void export_print(const std::string fname,
|
||||||
|
const SLAPrint &print,
|
||||||
|
const ThumbnailsList &thumbnails,
|
||||||
|
const std::string &projectname = "") = 0;
|
||||||
|
|
||||||
|
// Factory method to create an archiver instance
|
||||||
|
static std::unique_ptr<SLAArchive> create(const std::string &archtype, const SLAPrinterConfig&);
|
||||||
|
|
||||||
|
// Get the names of currently known archiver implementations
|
||||||
|
static const std::vector<const char *> & registered_archives();
|
||||||
|
|
||||||
|
// Get the default file extension belonging to an archive format
|
||||||
|
static const char *get_extension(const char *archtype);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
#endif // SLAARCHIVE_HPP
|
564
src/libslic3r/Format/pwmx.cpp
Normal file
564
src/libslic3r/Format/pwmx.cpp
Normal file
@ -0,0 +1,564 @@
|
|||||||
|
#include "pwmx.hpp"
|
||||||
|
#include "GCode/ThumbnailData.hpp"
|
||||||
|
#include "SLA/RasterBase.hpp"
|
||||||
|
#include "libslic3r/SLAPrint.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#define TAG_INTRO "ANYCUBIC\0\0\0\0"
|
||||||
|
#define TAG_HEADER "HEADER\0\0\0\0\0\0"
|
||||||
|
#define TAG_PREVIEW "PREVIEW\0\0\0\0\0"
|
||||||
|
#define TAG_LAYERS "LAYERDEF\0\0\0\0"
|
||||||
|
|
||||||
|
#define CFG_LIFT_DISTANCE "LIFT_DISTANCE"
|
||||||
|
#define CFG_LIFT_SPEED "LIFT_SPEED"
|
||||||
|
#define CFG_RETRACT_SPEED "RETRACT_SPEED"
|
||||||
|
#define CFG_DELAY_BEFORE_EXPOSURE "DELAY_BEFORE_EXPOSURE"
|
||||||
|
#define CFG_BOTTOM_LIFT_SPEED "BOTTOM_LIFT_SPEED"
|
||||||
|
#define CFG_BOTTOM_LIFT_DISTANCE "BOTTOM_LIFT_DISTANCE"
|
||||||
|
|
||||||
|
#define PREV_W 224
|
||||||
|
#define PREV_H 168
|
||||||
|
#define PREV_DPI 42
|
||||||
|
|
||||||
|
#define LAYER_SIZE_ESTIMATE (32 * 1024)
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
static void pwx_get_pixel_span(const std::uint8_t* ptr, const std::uint8_t* end,
|
||||||
|
std::uint8_t& pixel, size_t& span_len)
|
||||||
|
{
|
||||||
|
size_t max_len;
|
||||||
|
|
||||||
|
span_len = 0;
|
||||||
|
pixel = (*ptr) & 0xF0;
|
||||||
|
// the maximum length of the span depends on the pixel color
|
||||||
|
max_len = (pixel == 0 || pixel == 0xF0) ? 0xFFF : 0xF;
|
||||||
|
while (ptr < end && span_len < max_len && ((*ptr) & 0xF0) == pixel) {
|
||||||
|
span_len++;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PWXRasterEncoder
|
||||||
|
{
|
||||||
|
sla::EncodedRaster operator()(const void *ptr,
|
||||||
|
size_t w,
|
||||||
|
size_t h,
|
||||||
|
size_t num_components)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> dst;
|
||||||
|
size_t span_len;
|
||||||
|
std::uint8_t pixel;
|
||||||
|
auto size = w * h * num_components;
|
||||||
|
dst.reserve(size);
|
||||||
|
|
||||||
|
const std::uint8_t *src = reinterpret_cast<const std::uint8_t *>(ptr);
|
||||||
|
const std::uint8_t *src_end = src + size;
|
||||||
|
while (src < src_end) {
|
||||||
|
pwx_get_pixel_span(src, src_end, pixel, span_len);
|
||||||
|
src += span_len;
|
||||||
|
// fully transparent of fully opaque pixel
|
||||||
|
if (pixel == 0 || pixel == 0xF0) {
|
||||||
|
pixel = pixel | (span_len >> 8);
|
||||||
|
std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst));
|
||||||
|
pixel = span_len & 0xFF;
|
||||||
|
std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst));
|
||||||
|
}
|
||||||
|
// antialiased pixel
|
||||||
|
else {
|
||||||
|
pixel = pixel | span_len;
|
||||||
|
std::copy(&pixel, (&pixel) + 1, std::back_inserter(dst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sla::EncodedRaster(std::move(dst), "pwx");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using ConfMap = std::map<std::string, std::string>;
|
||||||
|
|
||||||
|
typedef struct pwmx_format_intro
|
||||||
|
{
|
||||||
|
char tag[12];
|
||||||
|
std::uint32_t version; // value 1
|
||||||
|
std::uint32_t area_num; // unknown - usually 4
|
||||||
|
std::uint32_t header_data_offset;
|
||||||
|
std::float_t intro24; // unknown - usually 0
|
||||||
|
std::uint32_t preview_data_offset;
|
||||||
|
std::float_t intro32; // unknown
|
||||||
|
std::uint32_t layer_data_offset;
|
||||||
|
std::float_t intro40; // unknown
|
||||||
|
std::uint32_t image_data_offset;
|
||||||
|
} pwmx_format_intro;
|
||||||
|
|
||||||
|
typedef struct pwmx_format_header
|
||||||
|
{
|
||||||
|
char tag[12];
|
||||||
|
std::uint32_t payload_size;
|
||||||
|
std::float_t pixel_size_um;
|
||||||
|
std::float_t layer_height_mm;
|
||||||
|
std::float_t exposure_time_s;
|
||||||
|
std::float_t delay_before_exposure_s;
|
||||||
|
std::float_t bottom_exposure_time_s;
|
||||||
|
std::float_t bottom_layer_count;
|
||||||
|
std::float_t lift_distance_mm;
|
||||||
|
std::float_t lift_speed_mms;
|
||||||
|
std::float_t retract_speed_mms;
|
||||||
|
std::float_t volume_ml;
|
||||||
|
std::uint32_t antialiasing;
|
||||||
|
std::uint32_t res_x;
|
||||||
|
std::uint32_t res_y;
|
||||||
|
std::float_t weight_g;
|
||||||
|
std::float_t price;
|
||||||
|
std::uint32_t price_currency;
|
||||||
|
std::uint32_t per_layer_override; // ? unknown meaning ?
|
||||||
|
std::uint32_t print_time_s;
|
||||||
|
std::uint32_t transition_layer_count;
|
||||||
|
std::uint32_t unknown; // ? usually 0 ?
|
||||||
|
|
||||||
|
} pwmx_format_header;
|
||||||
|
|
||||||
|
typedef struct pwmx_format_preview
|
||||||
|
{
|
||||||
|
char tag[12];
|
||||||
|
std::uint32_t payload_size;
|
||||||
|
std::uint32_t preview_w;
|
||||||
|
std::uint32_t preview_dpi;
|
||||||
|
std::uint32_t preview_h;
|
||||||
|
// raw image data in BGR565 format
|
||||||
|
std::uint8_t pixels[PREV_W * PREV_H * 2];
|
||||||
|
} pwmx_format_preview;
|
||||||
|
|
||||||
|
typedef struct pwmx_format_layers_header
|
||||||
|
{
|
||||||
|
char tag[12];
|
||||||
|
std::uint32_t payload_size;
|
||||||
|
std::uint32_t layer_count;
|
||||||
|
} pwmx_format_layers_header;
|
||||||
|
|
||||||
|
typedef struct pwmx_format_layer
|
||||||
|
{
|
||||||
|
std::uint32_t image_offset;
|
||||||
|
std::uint32_t image_size;
|
||||||
|
std::float_t lift_distance_mm;
|
||||||
|
std::float_t lift_speed_mms;
|
||||||
|
std::float_t exposure_time_s;
|
||||||
|
std::float_t layer_height_mm;
|
||||||
|
std::float_t layer44; // unkown - usually 0
|
||||||
|
std::float_t layer48; // unkown - usually 0
|
||||||
|
} pwmx_format_layer;
|
||||||
|
|
||||||
|
typedef struct pwmx_format_misc
|
||||||
|
{
|
||||||
|
std::float_t bottom_layer_height_mm;
|
||||||
|
std::float_t bottom_lift_distance_mm;
|
||||||
|
std::float_t bottom_lift_speed_mms;
|
||||||
|
|
||||||
|
} pwmx_format_misc;
|
||||||
|
|
||||||
|
class PwmxFormatConfigDef : public ConfigDef
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PwmxFormatConfigDef()
|
||||||
|
{
|
||||||
|
add(CFG_LIFT_DISTANCE, coFloat);
|
||||||
|
add(CFG_LIFT_SPEED, coFloat);
|
||||||
|
add(CFG_RETRACT_SPEED, coFloat);
|
||||||
|
add(CFG_DELAY_BEFORE_EXPOSURE, coFloat);
|
||||||
|
add(CFG_BOTTOM_LIFT_DISTANCE, coFloat);
|
||||||
|
add(CFG_BOTTOM_LIFT_SPEED, coFloat);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PwmxFormatDynamicConfig : public DynamicConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PwmxFormatDynamicConfig(){};
|
||||||
|
const ConfigDef *def() const override { return &config_def; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PwmxFormatConfigDef config_def;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::float_t get_cfg_value_f(const DynamicConfig &cfg,
|
||||||
|
const std::string &key,
|
||||||
|
const std::float_t &def = 0.f)
|
||||||
|
{
|
||||||
|
if (cfg.has(key)) {
|
||||||
|
if (auto opt = cfg.option(key))
|
||||||
|
return opt->getFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_cfg_value_i(const DynamicConfig &cfg,
|
||||||
|
const std::string &key,
|
||||||
|
const int &def = 0)
|
||||||
|
{
|
||||||
|
if (cfg.has(key)) {
|
||||||
|
if (auto opt = cfg.option(key))
|
||||||
|
return opt->getInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> void crop_value(T &val, T val_min, T val_max)
|
||||||
|
{
|
||||||
|
if (val < val_min) {
|
||||||
|
val = val_min;
|
||||||
|
} else if (val > val_max) {
|
||||||
|
val = val_max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_preview(pwmx_format_preview &p,
|
||||||
|
pwmx_format_misc &/*m*/,
|
||||||
|
const ThumbnailsList &thumbnails)
|
||||||
|
{
|
||||||
|
|
||||||
|
p.preview_w = PREV_W;
|
||||||
|
p.preview_h = PREV_H;
|
||||||
|
p.preview_dpi = PREV_DPI;
|
||||||
|
p.payload_size = sizeof(p) - sizeof(p.tag) - sizeof(p.payload_size);
|
||||||
|
|
||||||
|
std::memset(p.pixels, 0 , sizeof(p.pixels));
|
||||||
|
if (!thumbnails.empty()) {
|
||||||
|
std::uint32_t dst_index;
|
||||||
|
std::uint32_t i = 0;
|
||||||
|
size_t len;
|
||||||
|
size_t pixel_x = 0;
|
||||||
|
auto t = thumbnails[0]; //use the first thumbnail
|
||||||
|
len = t.pixels.size();
|
||||||
|
//sanity check
|
||||||
|
if (len != PREV_W * PREV_H * 4) {
|
||||||
|
printf("incorrect thumbnail size. expected %ix%i\n", PREV_W, PREV_H);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// rearange pixels: they seem to be stored from bottom to top.
|
||||||
|
dst_index = (PREV_W * (PREV_H - 1) * 2);
|
||||||
|
while (i < len) {
|
||||||
|
std::uint32_t pixel;
|
||||||
|
std::uint32_t r = t.pixels[i++];
|
||||||
|
std::uint32_t g = t.pixels[i++];
|
||||||
|
std::uint32_t b = t.pixels[i++];
|
||||||
|
i++; // Alpha
|
||||||
|
// convert to BGRA565
|
||||||
|
pixel = ((b >> 3) << 11) | ((g >>2) << 5) | (r >> 3);
|
||||||
|
p.pixels[dst_index++] = pixel & 0xFF;
|
||||||
|
p.pixels[dst_index++] = (pixel >> 8) & 0xFF;
|
||||||
|
pixel_x++;
|
||||||
|
if (pixel_x == PREV_W) {
|
||||||
|
pixel_x = 0;
|
||||||
|
dst_index -= (PREV_W * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fill_header(pwmx_format_header &h,
|
||||||
|
pwmx_format_misc &m,
|
||||||
|
const SLAPrint &print,
|
||||||
|
std::uint32_t layer_count)
|
||||||
|
{
|
||||||
|
CNumericLocalesSetter locales_setter;
|
||||||
|
|
||||||
|
std::float_t bottle_weight_g;
|
||||||
|
std::float_t bottle_volume_ml;
|
||||||
|
std::float_t bottle_cost;
|
||||||
|
std::float_t material_density;
|
||||||
|
auto &cfg = print.full_print_config();
|
||||||
|
auto mat_opt = cfg.option("material_notes");
|
||||||
|
std::string mnotes = mat_opt? cfg.option("material_notes")->serialize() : "";
|
||||||
|
// create a config parser from the material notes
|
||||||
|
Slic3r::PwmxFormatDynamicConfig mat_cfg;
|
||||||
|
SLAPrintStatistics stats = print.print_statistics();
|
||||||
|
|
||||||
|
// sanitize the string config
|
||||||
|
boost::replace_all(mnotes, "\\n", "\n");
|
||||||
|
boost::replace_all(mnotes, "\\r", "\r");
|
||||||
|
mat_cfg.load_from_ini_string(mnotes,
|
||||||
|
ForwardCompatibilitySubstitutionRule::Enable);
|
||||||
|
|
||||||
|
h.layer_height_mm = get_cfg_value_f(cfg, "layer_height");
|
||||||
|
m.bottom_layer_height_mm = get_cfg_value_f(cfg, "initial_layer_height");
|
||||||
|
h.exposure_time_s = get_cfg_value_f(cfg, "exposure_time");
|
||||||
|
h.bottom_exposure_time_s = get_cfg_value_f(cfg, "initial_exposure_time");
|
||||||
|
h.bottom_layer_count = get_cfg_value_i(cfg, "faded_layers");
|
||||||
|
if (layer_count < h.bottom_layer_count) {
|
||||||
|
h.bottom_layer_count = layer_count;
|
||||||
|
}
|
||||||
|
h.res_x = get_cfg_value_i(cfg, "display_pixels_x");
|
||||||
|
h.res_y = get_cfg_value_i(cfg, "display_pixels_y");
|
||||||
|
bottle_weight_g = get_cfg_value_f(cfg, "bottle_weight") * 1000.0f;
|
||||||
|
bottle_volume_ml = get_cfg_value_f(cfg, "bottle_volume");
|
||||||
|
bottle_cost = get_cfg_value_f(cfg, "bottle_cost");
|
||||||
|
material_density = bottle_weight_g / bottle_volume_ml;
|
||||||
|
|
||||||
|
h.volume_ml = (stats.objects_used_material + stats.support_used_material) / 1000;
|
||||||
|
h.weight_g = h.volume_ml * material_density;
|
||||||
|
h.price = (h.volume_ml * bottle_cost) / bottle_volume_ml;
|
||||||
|
h.price_currency = '$';
|
||||||
|
h.antialiasing = 1;
|
||||||
|
h.per_layer_override = 0;
|
||||||
|
|
||||||
|
// TODO - expose these variables to the UI rather than using material notes
|
||||||
|
h.delay_before_exposure_s = get_cfg_value_f(mat_cfg, CFG_DELAY_BEFORE_EXPOSURE, 0.5f);
|
||||||
|
crop_value(h.delay_before_exposure_s, 0.0f, 1000.0f);
|
||||||
|
|
||||||
|
h.lift_distance_mm = get_cfg_value_f(mat_cfg, CFG_LIFT_DISTANCE, 8.0f);
|
||||||
|
crop_value(h.lift_distance_mm, 0.0f, 100.0f);
|
||||||
|
|
||||||
|
if (mat_cfg.has(CFG_BOTTOM_LIFT_DISTANCE)) {
|
||||||
|
m.bottom_lift_distance_mm = get_cfg_value_f(mat_cfg,
|
||||||
|
CFG_BOTTOM_LIFT_DISTANCE,
|
||||||
|
8.0f);
|
||||||
|
crop_value(h.lift_distance_mm, 0.0f, 100.0f);
|
||||||
|
} else {
|
||||||
|
m.bottom_lift_distance_mm = h.lift_distance_mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
h.lift_speed_mms = get_cfg_value_f(mat_cfg, CFG_LIFT_SPEED, 2.0f);
|
||||||
|
crop_value(m.bottom_lift_speed_mms, 0.1f, 20.0f);
|
||||||
|
|
||||||
|
if (mat_cfg.has(CFG_BOTTOM_LIFT_SPEED)) {
|
||||||
|
m.bottom_lift_speed_mms = get_cfg_value_f(mat_cfg, CFG_BOTTOM_LIFT_SPEED, 2.0f);
|
||||||
|
crop_value(m.bottom_lift_speed_mms, 0.1f, 20.0f);
|
||||||
|
} else {
|
||||||
|
m.bottom_lift_speed_mms = h.lift_speed_mms;
|
||||||
|
}
|
||||||
|
|
||||||
|
h.retract_speed_mms = get_cfg_value_f(mat_cfg, CFG_RETRACT_SPEED, 3.0f);
|
||||||
|
crop_value(h.lift_speed_mms, 0.1f, 20.0f);
|
||||||
|
|
||||||
|
h.print_time_s = (h.bottom_layer_count * h.bottom_exposure_time_s) +
|
||||||
|
((layer_count - h.bottom_layer_count) *
|
||||||
|
h.exposure_time_s) +
|
||||||
|
(layer_count * h.lift_distance_mm / h.retract_speed_mms) +
|
||||||
|
(layer_count * h.lift_distance_mm / h.lift_speed_mms) +
|
||||||
|
(layer_count * h.delay_before_exposure_s);
|
||||||
|
|
||||||
|
|
||||||
|
h.payload_size = sizeof(h) - sizeof(h.tag) - sizeof(h.payload_size);
|
||||||
|
h.pixel_size_um = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<sla::RasterBase> PwmxArchive::create_raster() const
|
||||||
|
{
|
||||||
|
sla::Resolution res;
|
||||||
|
sla::PixelDim pxdim;
|
||||||
|
std::array<bool, 2> mirror;
|
||||||
|
|
||||||
|
double w = m_cfg.display_width.getFloat();
|
||||||
|
double h = m_cfg.display_height.getFloat();
|
||||||
|
auto pw = size_t(m_cfg.display_pixels_x.getInt());
|
||||||
|
auto ph = size_t(m_cfg.display_pixels_y.getInt());
|
||||||
|
|
||||||
|
mirror[X] = m_cfg.display_mirror_x.getBool();
|
||||||
|
mirror[Y] = m_cfg.display_mirror_y.getBool();
|
||||||
|
|
||||||
|
auto ro = m_cfg.display_orientation.getInt();
|
||||||
|
sla::RasterBase::Orientation orientation =
|
||||||
|
ro == sla::RasterBase::roPortrait ? sla::RasterBase::roPortrait :
|
||||||
|
sla::RasterBase::roLandscape;
|
||||||
|
|
||||||
|
if (orientation == sla::RasterBase::roPortrait) {
|
||||||
|
std::swap(w, h);
|
||||||
|
std::swap(pw, ph);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = sla::Resolution{pw, ph};
|
||||||
|
pxdim = sla::PixelDim{w / pw, h / ph};
|
||||||
|
sla::RasterBase::Trafo tr{orientation, mirror};
|
||||||
|
|
||||||
|
double gamma = m_cfg.gamma_correction.getFloat();
|
||||||
|
|
||||||
|
return sla::create_raster_grayscale_aa(res, pxdim, gamma, tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
sla::RasterEncoder PwmxArchive::get_encoder() const
|
||||||
|
{
|
||||||
|
return PWXRasterEncoder{};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endian safe write of little endian 32bit ints
|
||||||
|
static void pwmx_write_int32(std::ofstream &out, std::uint32_t val)
|
||||||
|
{
|
||||||
|
const char i1 = (val & 0xFF);
|
||||||
|
const char i2 = (val >> 8) & 0xFF;
|
||||||
|
const char i3 = (val >> 16) & 0xFF;
|
||||||
|
const char i4 = (val >> 24) & 0xFF;
|
||||||
|
|
||||||
|
out.write((const char *) &i1, 1);
|
||||||
|
out.write((const char *) &i2, 1);
|
||||||
|
out.write((const char *) &i3, 1);
|
||||||
|
out.write((const char *) &i4, 1);
|
||||||
|
}
|
||||||
|
static void pwmx_write_float(std::ofstream &out, std::float_t val)
|
||||||
|
{
|
||||||
|
std::uint32_t *f = (std::uint32_t *) &val;
|
||||||
|
pwmx_write_int32(out, *f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pwmx_write_intro(std::ofstream &out, pwmx_format_intro &i)
|
||||||
|
{
|
||||||
|
out.write(TAG_INTRO, sizeof(i.tag));
|
||||||
|
pwmx_write_int32(out, i.version);
|
||||||
|
pwmx_write_int32(out, i.area_num);
|
||||||
|
pwmx_write_int32(out, i.header_data_offset);
|
||||||
|
pwmx_write_int32(out, i.intro24);
|
||||||
|
pwmx_write_int32(out, i.preview_data_offset);
|
||||||
|
pwmx_write_int32(out, i.intro32);
|
||||||
|
pwmx_write_int32(out, i.layer_data_offset);
|
||||||
|
pwmx_write_int32(out, i.intro40);
|
||||||
|
pwmx_write_int32(out, i.image_data_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pwmx_write_header(std::ofstream &out, pwmx_format_header &h)
|
||||||
|
{
|
||||||
|
out.write(TAG_HEADER, sizeof(h.tag));
|
||||||
|
pwmx_write_int32(out, h.payload_size);
|
||||||
|
pwmx_write_float(out, h.pixel_size_um);
|
||||||
|
pwmx_write_float(out, h.layer_height_mm);
|
||||||
|
pwmx_write_float(out, h.exposure_time_s);
|
||||||
|
pwmx_write_float(out, h.delay_before_exposure_s);
|
||||||
|
pwmx_write_float(out, h.bottom_exposure_time_s);
|
||||||
|
pwmx_write_float(out, h.bottom_layer_count);
|
||||||
|
pwmx_write_float(out, h.lift_distance_mm);
|
||||||
|
pwmx_write_float(out, h.lift_speed_mms);
|
||||||
|
pwmx_write_float(out, h.retract_speed_mms);
|
||||||
|
pwmx_write_float(out, h.volume_ml);
|
||||||
|
pwmx_write_int32(out, h.antialiasing);
|
||||||
|
pwmx_write_int32(out, h.res_x);
|
||||||
|
pwmx_write_int32(out, h.res_y);
|
||||||
|
pwmx_write_float(out, h.weight_g);
|
||||||
|
pwmx_write_float(out, h.price);
|
||||||
|
pwmx_write_int32(out, h.price_currency);
|
||||||
|
pwmx_write_int32(out, h.per_layer_override);
|
||||||
|
pwmx_write_int32(out, h.print_time_s);
|
||||||
|
pwmx_write_int32(out, h.transition_layer_count);
|
||||||
|
pwmx_write_int32(out, h.unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pwmx_write_preview(std::ofstream &out, pwmx_format_preview &p)
|
||||||
|
{
|
||||||
|
out.write(TAG_PREVIEW, sizeof(p.tag));
|
||||||
|
pwmx_write_int32(out, p.payload_size);
|
||||||
|
pwmx_write_int32(out, p.preview_w);
|
||||||
|
pwmx_write_int32(out, p.preview_dpi);
|
||||||
|
pwmx_write_int32(out, p.preview_h);
|
||||||
|
out.write((const char*) p.pixels, sizeof(p.pixels));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pwmx_write_layers_header(std::ofstream &out, pwmx_format_layers_header &h)
|
||||||
|
{
|
||||||
|
out.write(TAG_LAYERS, sizeof(h.tag));
|
||||||
|
pwmx_write_int32(out, h.payload_size);
|
||||||
|
pwmx_write_int32(out, h.layer_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pwmx_write_layer(std::ofstream &out, pwmx_format_layer &l)
|
||||||
|
{
|
||||||
|
pwmx_write_int32(out, l.image_offset);
|
||||||
|
pwmx_write_int32(out, l.image_size);
|
||||||
|
pwmx_write_float(out, l.lift_distance_mm);
|
||||||
|
pwmx_write_float(out, l.lift_speed_mms);
|
||||||
|
pwmx_write_float(out, l.exposure_time_s);
|
||||||
|
pwmx_write_float(out, l.layer_height_mm);
|
||||||
|
pwmx_write_float(out, l.layer44);
|
||||||
|
pwmx_write_float(out, l.layer48);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PwmxArchive::export_print(const std::string fname,
|
||||||
|
const SLAPrint &print,
|
||||||
|
const ThumbnailsList &thumbnails,
|
||||||
|
const std::string &/*projectname*/)
|
||||||
|
{
|
||||||
|
std::uint32_t layer_count = m_layers.size();
|
||||||
|
|
||||||
|
pwmx_format_intro intro = {};
|
||||||
|
pwmx_format_header header = {};
|
||||||
|
pwmx_format_preview preview = {};
|
||||||
|
pwmx_format_layers_header layers_header = {};
|
||||||
|
pwmx_format_misc misc = {};
|
||||||
|
std::vector<uint8_t> layer_images;
|
||||||
|
std::uint32_t image_offset;
|
||||||
|
|
||||||
|
intro.version = 1;
|
||||||
|
intro.area_num = 4;
|
||||||
|
intro.header_data_offset = sizeof(intro);
|
||||||
|
intro.preview_data_offset = sizeof(intro) + sizeof(header);
|
||||||
|
intro.layer_data_offset = intro.preview_data_offset + sizeof(preview);
|
||||||
|
intro.image_data_offset = intro.layer_data_offset +
|
||||||
|
sizeof(layers_header) +
|
||||||
|
(sizeof(pwmx_format_layer) * layer_count);
|
||||||
|
|
||||||
|
fill_header(header, misc, print, layer_count);
|
||||||
|
fill_preview(preview, misc, thumbnails);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// open the file and write the contents
|
||||||
|
std::ofstream out;
|
||||||
|
out.open(fname, std::ios::binary | std::ios::out | std::ios::trunc);
|
||||||
|
pwmx_write_intro(out, intro);
|
||||||
|
pwmx_write_header(out, header);
|
||||||
|
pwmx_write_preview(out, preview);
|
||||||
|
|
||||||
|
layers_header.payload_size = intro.image_data_offset - intro.layer_data_offset -
|
||||||
|
sizeof(layers_header.tag) - sizeof(layers_header.payload_size);
|
||||||
|
layers_header.layer_count = layer_count;
|
||||||
|
pwmx_write_layers_header(out, layers_header);
|
||||||
|
|
||||||
|
//layers
|
||||||
|
layer_images.reserve(layer_count * LAYER_SIZE_ESTIMATE);
|
||||||
|
image_offset = intro.image_data_offset;
|
||||||
|
size_t i = 0;
|
||||||
|
for (const sla::EncodedRaster &rst : m_layers) {
|
||||||
|
pwmx_format_layer l;
|
||||||
|
std::memset(&l, 0, sizeof(l));
|
||||||
|
l.image_offset = image_offset;
|
||||||
|
l.image_size = rst.size();
|
||||||
|
if (i < header.bottom_layer_count) {
|
||||||
|
l.exposure_time_s = header.bottom_exposure_time_s;
|
||||||
|
l.layer_height_mm = misc.bottom_layer_height_mm;
|
||||||
|
l.lift_distance_mm = misc.bottom_lift_distance_mm;
|
||||||
|
l.lift_speed_mms = misc.bottom_lift_speed_mms;
|
||||||
|
} else {
|
||||||
|
l.exposure_time_s = header.exposure_time_s;
|
||||||
|
l.layer_height_mm = header.layer_height_mm;
|
||||||
|
l.lift_distance_mm = header.lift_distance_mm;
|
||||||
|
l.lift_speed_mms = header.lift_speed_mms;
|
||||||
|
}
|
||||||
|
image_offset += l.image_size;
|
||||||
|
pwmx_write_layer(out, l);
|
||||||
|
// add the rle encoded layer image into the buffer
|
||||||
|
const char* img_start = reinterpret_cast<const char*>(rst.data());
|
||||||
|
const char* img_end = img_start + rst.size();
|
||||||
|
std::copy(img_start, img_end, std::back_inserter(layer_images));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
const char* img_buffer = reinterpret_cast<const char*>(layer_images.data());
|
||||||
|
out.write(img_buffer, layer_images.size());
|
||||||
|
out.close();
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << e.what();
|
||||||
|
// Rethrow the exception
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
37
src/libslic3r/Format/pwmx.hpp
Normal file
37
src/libslic3r/Format/pwmx.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef _SLIC3R_FORMAT_PWMX_HPP_
|
||||||
|
#define _SLIC3R_FORMAT_PWMX_HPP_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "SLAArchive.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class PwmxArchive: public SLAArchive {
|
||||||
|
SLAPrinterConfig m_cfg;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<sla::RasterBase> create_raster() const override;
|
||||||
|
sla::RasterEncoder get_encoder() const override;
|
||||||
|
|
||||||
|
SLAPrinterConfig & cfg() { return m_cfg; }
|
||||||
|
const SLAPrinterConfig & cfg() const { return m_cfg; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PwmxArchive() = default;
|
||||||
|
explicit PwmxArchive(const SLAPrinterConfig &cfg): m_cfg(cfg) {}
|
||||||
|
explicit PwmxArchive(SLAPrinterConfig &&cfg): m_cfg(std::move(cfg)) {}
|
||||||
|
|
||||||
|
void export_print(const std::string fname,
|
||||||
|
const SLAPrint &print,
|
||||||
|
const ThumbnailsList &thumbnails,
|
||||||
|
const std::string &projectname = "") override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Slic3r::sla
|
||||||
|
|
||||||
|
#endif // _SLIC3R_FORMAT_PWMX_HPP_
|
@ -274,7 +274,6 @@ namespace Slic3r {
|
|||||||
// Otherwise, leave control to the user completely.
|
// Otherwise, leave control to the user completely.
|
||||||
std::string toolchange_gcode_str;
|
std::string toolchange_gcode_str;
|
||||||
const std::string& toolchange_gcode = gcodegen.config().toolchange_gcode.value;
|
const std::string& toolchange_gcode = gcodegen.config().toolchange_gcode.value;
|
||||||
// m_max_layer_z = std::max(m_max_layer_z, tcr.print_z);
|
|
||||||
if (! toolchange_gcode.empty()) {
|
if (! toolchange_gcode.empty()) {
|
||||||
DynamicConfig config;
|
DynamicConfig config;
|
||||||
int previous_extruder_id = gcodegen.writer().extruder() ? (int)gcodegen.writer().extruder()->id() : -1;
|
int previous_extruder_id = gcodegen.writer().extruder() ? (int)gcodegen.writer().extruder()->id() : -1;
|
||||||
@ -283,7 +282,7 @@ namespace Slic3r {
|
|||||||
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
|
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
|
||||||
config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z));
|
config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z));
|
||||||
config.set_key_value("toolchange_z", new ConfigOptionFloat(z));
|
config.set_key_value("toolchange_z", new ConfigOptionFloat(z));
|
||||||
// config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z));
|
||||||
toolchange_gcode_str = gcodegen.placeholder_parser_process("toolchange_gcode", toolchange_gcode, new_extruder_id, &config);
|
toolchange_gcode_str = gcodegen.placeholder_parser_process("toolchange_gcode", toolchange_gcode, new_extruder_id, &config);
|
||||||
check_add_eol(toolchange_gcode_str);
|
check_add_eol(toolchange_gcode_str);
|
||||||
}
|
}
|
||||||
@ -305,6 +304,9 @@ namespace Slic3r {
|
|||||||
if (!start_filament_gcode.empty()) {
|
if (!start_filament_gcode.empty()) {
|
||||||
// Process the start_filament_gcode for the active filament only.
|
// Process the start_filament_gcode for the active filament only.
|
||||||
DynamicConfig config;
|
DynamicConfig config;
|
||||||
|
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
|
||||||
|
config.set_key_value("layer_z", new ConfigOptionFloat(gcodegen.writer().get_position()(2) - gcodegen.m_config.z_offset.value));
|
||||||
|
config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z));
|
||||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_extruder_id));
|
config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_extruder_id));
|
||||||
start_filament_gcode_str = gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id, &config);
|
start_filament_gcode_str = gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id, &config);
|
||||||
check_add_eol(start_filament_gcode_str);
|
check_add_eol(start_filament_gcode_str);
|
||||||
@ -1274,15 +1276,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||||||
// Write the custom start G-code
|
// Write the custom start G-code
|
||||||
file.writeln(start_gcode);
|
file.writeln(start_gcode);
|
||||||
|
|
||||||
// Process filament-specific gcode.
|
|
||||||
/* if (has_wipe_tower) {
|
|
||||||
// Wipe tower will control the extruder switching, it will call the start_filament_gcode.
|
|
||||||
} else {
|
|
||||||
DynamicConfig config;
|
|
||||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(initial_extruder_id)));
|
|
||||||
file.writeln(this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id, &config));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
|
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
|
||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
|
|
||||||
@ -1899,6 +1892,8 @@ namespace ProcessLayer
|
|||||||
// && !MMU1
|
// && !MMU1
|
||||||
) {
|
) {
|
||||||
//! FIXME_in_fw show message during print pause
|
//! FIXME_in_fw show message during print pause
|
||||||
|
// FIXME: Why is pause_print_gcode here? Why is it supplied "color_change_extruder"? Why is that not
|
||||||
|
// passed to color_change_gcode below?
|
||||||
DynamicConfig cfg;
|
DynamicConfig cfg;
|
||||||
cfg.set_key_value("color_change_extruder", new ConfigOptionInt(m600_extruder_before_layer));
|
cfg.set_key_value("color_change_extruder", new ConfigOptionInt(m600_extruder_before_layer));
|
||||||
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id, &cfg);
|
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id, &cfg);
|
||||||
@ -2109,10 +2104,10 @@ GCode::LayerResult GCode::process_layer(
|
|||||||
DynamicConfig config;
|
DynamicConfig config;
|
||||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||||
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
|
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
|
||||||
|
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||||
gcode += this->placeholder_parser_process("layer_gcode",
|
gcode += this->placeholder_parser_process("layer_gcode",
|
||||||
print.config().layer_gcode.value, m_writer.extruder()->id(), &config)
|
print.config().layer_gcode.value, m_writer.extruder()->id(), &config)
|
||||||
+ "\n";
|
+ "\n";
|
||||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! first_layer && ! m_second_layer_things_done) {
|
if (! first_layer && ! m_second_layer_things_done) {
|
||||||
@ -3146,7 +3141,9 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
|||||||
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
|
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
|
||||||
if (! start_filament_gcode.empty()) {
|
if (! start_filament_gcode.empty()) {
|
||||||
// Process the start_filament_gcode for the filament.
|
// Process the start_filament_gcode for the filament.
|
||||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id);
|
DynamicConfig config;
|
||||||
|
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
|
||||||
|
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
|
||||||
check_add_eol(gcode);
|
check_add_eol(gcode);
|
||||||
}
|
}
|
||||||
gcode += m_writer.toolchange(extruder_id);
|
gcode += m_writer.toolchange(extruder_id);
|
||||||
@ -3215,7 +3212,9 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
|||||||
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
|
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
|
||||||
if (! start_filament_gcode.empty()) {
|
if (! start_filament_gcode.empty()) {
|
||||||
// Process the start_filament_gcode for the new filament.
|
// Process the start_filament_gcode for the new filament.
|
||||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id);
|
DynamicConfig config;
|
||||||
|
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
|
||||||
|
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
|
||||||
check_add_eol(gcode);
|
check_add_eol(gcode);
|
||||||
}
|
}
|
||||||
// Set the new extruder to the operating temperature.
|
// Set the new extruder to the operating temperature.
|
||||||
|
@ -1196,6 +1196,7 @@ void GCodeProcessor::reset()
|
|||||||
m_line_id = 0;
|
m_line_id = 0;
|
||||||
m_last_line_id = 0;
|
m_last_line_id = 0;
|
||||||
m_feedrate = 0.0f;
|
m_feedrate = 0.0f;
|
||||||
|
m_feed_multiply.reset();
|
||||||
m_width = 0.0f;
|
m_width = 0.0f;
|
||||||
m_height = 0.0f;
|
m_height = 0.0f;
|
||||||
m_forced_width = 0.0f;
|
m_forced_width = 0.0f;
|
||||||
@ -1698,6 +1699,7 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line, bool
|
|||||||
break;
|
break;
|
||||||
case '2':
|
case '2':
|
||||||
switch (cmd[3]) {
|
switch (cmd[3]) {
|
||||||
|
case '0': { process_M220(line); break; } // Set Feedrate Percentage
|
||||||
case '1': { process_M221(line); break; } // Set extrude factor override percentage
|
case '1': { process_M221(line); break; } // Set extrude factor override percentage
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@ -2498,7 +2500,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
|||||||
|
|
||||||
// updates feedrate from line, if present
|
// updates feedrate from line, if present
|
||||||
if (line.has_f())
|
if (line.has_f())
|
||||||
m_feedrate = line.f() * MMMIN_TO_MMSEC;
|
m_feedrate = m_feed_multiply.current * line.f() * MMMIN_TO_MMSEC;
|
||||||
|
|
||||||
// calculates movement deltas
|
// calculates movement deltas
|
||||||
float max_abs_delta = 0.0f;
|
float max_abs_delta = 0.0f;
|
||||||
@ -2863,7 +2865,7 @@ void GCodeProcessor::process_G61(const GCodeReader::GCodeLine& line)
|
|||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
if (line.has_f())
|
if (line.has_f())
|
||||||
m_feedrate = line.f();
|
m_feedrate = m_feed_multiply.current * line.f();
|
||||||
|
|
||||||
if (!modified)
|
if (!modified)
|
||||||
m_end_position = m_saved_position;
|
m_end_position = m_saved_position;
|
||||||
@ -3136,6 +3138,20 @@ void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GCodeProcessor::process_M220(const GCodeReader::GCodeLine& line)
|
||||||
|
{
|
||||||
|
if (m_flavor != gcfMarlinLegacy && m_flavor != gcfMarlinFirmware)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (line.has('B'))
|
||||||
|
m_feed_multiply.saved = m_feed_multiply.current;
|
||||||
|
float value;
|
||||||
|
if (line.has_value('S', value))
|
||||||
|
m_feed_multiply.current = value * 0.01f;
|
||||||
|
if (line.has('R'))
|
||||||
|
m_feed_multiply.current = m_feed_multiply.saved;
|
||||||
|
}
|
||||||
|
|
||||||
void GCodeProcessor::process_M221(const GCodeReader::GCodeLine& line)
|
void GCodeProcessor::process_M221(const GCodeReader::GCodeLine& line)
|
||||||
{
|
{
|
||||||
float value_s;
|
float value_s;
|
||||||
|
@ -525,6 +525,17 @@ namespace Slic3r {
|
|||||||
unsigned int m_line_id;
|
unsigned int m_line_id;
|
||||||
unsigned int m_last_line_id;
|
unsigned int m_last_line_id;
|
||||||
float m_feedrate; // mm/s
|
float m_feedrate; // mm/s
|
||||||
|
struct FeedMultiply
|
||||||
|
{
|
||||||
|
float current; // percentage
|
||||||
|
float saved; // percentage
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
current = 1.0f;
|
||||||
|
saved = 1.0f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FeedMultiply m_feed_multiply;
|
||||||
float m_width; // mm
|
float m_width; // mm
|
||||||
float m_height; // mm
|
float m_height; // mm
|
||||||
float m_forced_width; // mm
|
float m_forced_width; // mm
|
||||||
@ -719,6 +730,9 @@ namespace Slic3r {
|
|||||||
// Advanced settings
|
// Advanced settings
|
||||||
void process_M205(const GCodeReader::GCodeLine& line);
|
void process_M205(const GCodeReader::GCodeLine& line);
|
||||||
|
|
||||||
|
// Set Feedrate Percentage
|
||||||
|
void process_M220(const GCodeReader::GCodeLine& line);
|
||||||
|
|
||||||
// Set extrude factor override percentage
|
// Set extrude factor override percentage
|
||||||
void process_M221(const GCodeReader::GCodeLine& line);
|
void process_M221(const GCodeReader::GCodeLine& line);
|
||||||
|
|
||||||
|
@ -982,7 +982,7 @@ bool SupportTreeBuildsteps::connect_to_model_body(Head &head)
|
|||||||
double w = dist - 2 * head.r_pin_mm - head.r_back_mm;
|
double w = dist - 2 * head.r_pin_mm - head.r_back_mm;
|
||||||
|
|
||||||
if (w < 0.) {
|
if (w < 0.) {
|
||||||
BOOST_LOG_TRIVIAL(error) << "Pinhead width is negative!";
|
BOOST_LOG_TRIVIAL(warning) << "Pinhead width is negative!";
|
||||||
w = 0.;
|
w = 0.;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "Format/SL1.hpp"
|
#include "Format/SL1.hpp"
|
||||||
#include "Format/SL1_SVG.hpp"
|
#include "Format/SL1_SVG.hpp"
|
||||||
|
#include "Format/pwmx.hpp"
|
||||||
|
|
||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
@ -244,12 +245,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
|
|||||||
// Handle changes to object config defaults
|
// Handle changes to object config defaults
|
||||||
m_default_object_config.apply_only(config, object_diff, true);
|
m_default_object_config.apply_only(config, object_diff, true);
|
||||||
|
|
||||||
if (!m_archiver || !printer_diff.empty()) {
|
if (!m_archiver || !printer_diff.empty())
|
||||||
if (m_printer_config.sla_archive_format.value == "SL1")
|
m_archiver = SLAArchive::create(m_printer_config.sla_archive_format.value.c_str(), m_printer_config);
|
||||||
m_archiver = std::make_unique<SL1Archive>(m_printer_config);
|
|
||||||
else if (m_printer_config.sla_archive_format.value == "SL2")
|
|
||||||
m_archiver = std::make_unique<SL1_SVGArchive>(m_printer_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ModelObjectStatus {
|
struct ModelObjectStatus {
|
||||||
enum Status {
|
enum Status {
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
#include "MTUtils.hpp"
|
#include "MTUtils.hpp"
|
||||||
#include "Zipper.hpp"
|
#include "Zipper.hpp"
|
||||||
|
#include "Format/SLAArchive.hpp"
|
||||||
|
#include "GCode/ThumbnailData.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Execution/ExecutionTBB.hpp"
|
#include "libslic3r/Execution/ExecutionTBB.hpp"
|
||||||
|
|
||||||
@ -389,47 +391,6 @@ struct SLAPrintStatistics
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SLAArchive {
|
|
||||||
protected:
|
|
||||||
std::vector<sla::EncodedRaster> m_layers;
|
|
||||||
|
|
||||||
virtual std::unique_ptr<sla::RasterBase> create_raster() const = 0;
|
|
||||||
virtual sla::RasterEncoder get_encoder() const = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual ~SLAArchive() = default;
|
|
||||||
|
|
||||||
// Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid);
|
|
||||||
template<class Fn, class CancelFn, class EP = ExecutionTBB>
|
|
||||||
void draw_layers(
|
|
||||||
size_t layer_num,
|
|
||||||
Fn && drawfn,
|
|
||||||
CancelFn cancelfn = []() { return false; },
|
|
||||||
const EP & ep = {})
|
|
||||||
{
|
|
||||||
m_layers.resize(layer_num);
|
|
||||||
execution::for_each(
|
|
||||||
ep, size_t(0), m_layers.size(),
|
|
||||||
[this, &drawfn, &cancelfn](size_t idx) {
|
|
||||||
if (cancelfn()) return;
|
|
||||||
|
|
||||||
sla::EncodedRaster &enc = m_layers[idx];
|
|
||||||
auto rst = create_raster();
|
|
||||||
drawfn(*rst, idx);
|
|
||||||
enc = rst->encode(get_encoder());
|
|
||||||
},
|
|
||||||
execution::max_concurrency(ep));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Export the print into an archive using the provided zipper.
|
|
||||||
// TODO: Use an archive writer interface instead of Zipper.
|
|
||||||
// This is quite limiting as the Zipper is a complete class, not an interface.
|
|
||||||
// The output can only be a zip archive.
|
|
||||||
virtual void export_print(Zipper &zipper,
|
|
||||||
const SLAPrint &print,
|
|
||||||
const std::string &projectname = "") = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This class is the high level FSM for the SLA printing process.
|
* @brief This class is the high level FSM for the SLA printing process.
|
||||||
*
|
*
|
||||||
@ -534,15 +495,17 @@ public:
|
|||||||
// TODO: use this structure for the preview in the future.
|
// TODO: use this structure for the preview in the future.
|
||||||
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
|
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
|
||||||
|
|
||||||
void export_print(Zipper &zipper, const std::string &projectname = "")
|
|
||||||
{
|
|
||||||
m_archiver->export_print(zipper, *this, projectname);
|
|
||||||
}
|
|
||||||
|
|
||||||
void export_print(const std::string &fname, const std::string &projectname = "")
|
void export_print(const std::string &fname, const std::string &projectname = "")
|
||||||
{
|
{
|
||||||
Zipper zipper(fname);
|
ThumbnailsList thumbnails; //empty thumbnail list
|
||||||
export_print(zipper, projectname);
|
export_print(fname, thumbnails, projectname);
|
||||||
|
}
|
||||||
|
|
||||||
|
void export_print(const std::string &fname,
|
||||||
|
const ThumbnailsList &thumbnails,
|
||||||
|
const std::string &projectname = "")
|
||||||
|
{
|
||||||
|
m_archiver->export_print(fname, *this, thumbnails, projectname);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -76,6 +76,8 @@
|
|||||||
#define ENABLE_RELOAD_FROM_DISK_REWORK (1 && ENABLE_2_5_0_ALPHA1)
|
#define ENABLE_RELOAD_FROM_DISK_REWORK (1 && ENABLE_2_5_0_ALPHA1)
|
||||||
// Enable showing toolpaths center of gravity
|
// Enable showing toolpaths center of gravity
|
||||||
#define ENABLE_SHOW_TOOLPATHS_COG (1 && ENABLE_2_5_0_ALPHA1)
|
#define ENABLE_SHOW_TOOLPATHS_COG (1 && ENABLE_2_5_0_ALPHA1)
|
||||||
|
// Enable recalculating toolpaths when switching to/from volumetric rate visualization
|
||||||
|
#define ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC (1 && ENABLE_2_5_0_ALPHA1)
|
||||||
|
|
||||||
|
|
||||||
#endif // _prusaslicer_technologies_h_
|
#endif // _prusaslicer_technologies_h_
|
||||||
|
@ -270,7 +270,7 @@ endforeach()
|
|||||||
|
|
||||||
encoding_check(libslic3r_gui)
|
encoding_check(libslic3r_gui)
|
||||||
|
|
||||||
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
|
target_link_libraries(libslic3r_gui libslic3r avrdude libcereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
target_link_libraries(libslic3r_gui Setupapi.lib)
|
target_link_libraries(libslic3r_gui Setupapi.lib)
|
||||||
|
@ -312,8 +312,7 @@ void Bed3D::init_triangles()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
GLModel::Geometry init_data;
|
GLModel::Geometry init_data;
|
||||||
const GLModel::Geometry::EIndexType index_type = (triangles.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT;
|
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, GLModel::Geometry::index_type(triangles.size()) };
|
||||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3T2, index_type };
|
|
||||||
init_data.reserve_vertices(triangles.size());
|
init_data.reserve_vertices(triangles.size());
|
||||||
init_data.reserve_indices(triangles.size() / 3);
|
init_data.reserve_indices(triangles.size() / 3);
|
||||||
|
|
||||||
@ -335,10 +334,10 @@ void Bed3D::init_triangles()
|
|||||||
unsigned int vertices_counter = 0;
|
unsigned int vertices_counter = 0;
|
||||||
for (const Vec2f& v : triangles) {
|
for (const Vec2f& v : triangles) {
|
||||||
const Vec3f p = { v.x(), v.y(), GROUND_Z };
|
const Vec3f p = { v.x(), v.y(), GROUND_Z };
|
||||||
init_data.add_vertex(p, (Vec2f)v.cwiseProduct(inv_size).eval());
|
init_data.add_vertex(p, (Vec2f)(v - min).cwiseProduct(inv_size).eval());
|
||||||
++vertices_counter;
|
++vertices_counter;
|
||||||
if (vertices_counter % 3 == 0) {
|
if (vertices_counter % 3 == 0) {
|
||||||
if (index_type == GLModel::Geometry::EIndexType::USHORT)
|
if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||||
init_data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1);
|
init_data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1);
|
||||||
else
|
else
|
||||||
init_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1);
|
init_data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1);
|
||||||
@ -381,8 +380,7 @@ void Bed3D::init_gridlines()
|
|||||||
std::copy(contour_lines.begin(), contour_lines.end(), std::back_inserter(gridlines));
|
std::copy(contour_lines.begin(), contour_lines.end(), std::back_inserter(gridlines));
|
||||||
|
|
||||||
GLModel::Geometry init_data;
|
GLModel::Geometry init_data;
|
||||||
const GLModel::Geometry::EIndexType index_type = (2 * gridlines.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT;
|
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * gridlines.size()) };
|
||||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type };
|
|
||||||
init_data.reserve_vertices(2 * gridlines.size());
|
init_data.reserve_vertices(2 * gridlines.size());
|
||||||
init_data.reserve_indices(2 * gridlines.size());
|
init_data.reserve_indices(2 * gridlines.size());
|
||||||
|
|
||||||
@ -390,7 +388,7 @@ void Bed3D::init_gridlines()
|
|||||||
init_data.add_vertex(Vec3f(unscale<float>(l.a.x()), unscale<float>(l.a.y()), GROUND_Z));
|
init_data.add_vertex(Vec3f(unscale<float>(l.a.x()), unscale<float>(l.a.y()), GROUND_Z));
|
||||||
init_data.add_vertex(Vec3f(unscale<float>(l.b.x()), unscale<float>(l.b.y()), GROUND_Z));
|
init_data.add_vertex(Vec3f(unscale<float>(l.b.x()), unscale<float>(l.b.y()), GROUND_Z));
|
||||||
const unsigned int vertices_counter = (unsigned int)init_data.vertices_count();
|
const unsigned int vertices_counter = (unsigned int)init_data.vertices_count();
|
||||||
if (index_type == GLModel::Geometry::EIndexType::USHORT)
|
if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||||
init_data.add_ushort_line((unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1);
|
init_data.add_ushort_line((unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1);
|
||||||
else
|
else
|
||||||
init_data.add_uint_line(vertices_counter - 2, vertices_counter - 1);
|
init_data.add_uint_line(vertices_counter - 2, vertices_counter - 1);
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
#if ENABLE_SMOOTH_NORMALS
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
#include <igl/per_face_normals.h>
|
#include <igl/per_face_normals.h>
|
||||||
#include <igl/per_corner_normals.h>
|
#include <igl/per_corner_normals.h>
|
||||||
#include <igl/per_vertex_normals.h>
|
#include <igl/per_vertex_normals.h>
|
||||||
#endif // ENABLE_SMOOTH_NORMALS
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
#include "3DScene.hpp"
|
#include "3DScene.hpp"
|
||||||
#include "GLShader.hpp"
|
#include "GLShader.hpp"
|
||||||
@ -69,6 +71,7 @@ void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
#if ENABLE_SMOOTH_NORMALS
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
static void smooth_normals_corner(TriangleMesh& mesh, std::vector<stl_normal>& normals)
|
static void smooth_normals_corner(TriangleMesh& mesh, std::vector<stl_normal>& normals)
|
||||||
{
|
{
|
||||||
@ -287,6 +290,7 @@ void GLIndexedVertexArray::render(
|
|||||||
|
|
||||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||||
}
|
}
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
const float GLVolume::SinkingContours::HalfWidth = 0.25f;
|
const float GLVolume::SinkingContours::HalfWidth = 0.25f;
|
||||||
|
|
||||||
@ -400,8 +404,7 @@ void GLVolume::NonManifoldEdges::update()
|
|||||||
if (!edges.empty()) {
|
if (!edges.empty()) {
|
||||||
GUI::GLModel::Geometry init_data;
|
GUI::GLModel::Geometry init_data;
|
||||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
const GUI::GLModel::Geometry::EIndexType index_type = (2 * edges.size() < 65536) ? GUI::GLModel::Geometry::EIndexType::USHORT : GUI::GLModel::Geometry::EIndexType::UINT;
|
init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Lines, GUI::GLModel::Geometry::EVertexLayout::P3, GUI::GLModel::Geometry::index_type(2 * edges.size()) };
|
||||||
init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Lines, GUI::GLModel::Geometry::EVertexLayout::P3, index_type };
|
|
||||||
init_data.reserve_vertices(2 * edges.size());
|
init_data.reserve_vertices(2 * edges.size());
|
||||||
init_data.reserve_indices(2 * edges.size());
|
init_data.reserve_indices(2 * edges.size());
|
||||||
|
|
||||||
@ -411,7 +414,7 @@ void GLVolume::NonManifoldEdges::update()
|
|||||||
init_data.add_vertex((Vec3f)mesh.its.vertices[edge.first].cast<float>());
|
init_data.add_vertex((Vec3f)mesh.its.vertices[edge.first].cast<float>());
|
||||||
init_data.add_vertex((Vec3f)mesh.its.vertices[edge.second].cast<float>());
|
init_data.add_vertex((Vec3f)mesh.its.vertices[edge.second].cast<float>());
|
||||||
vertices_count += 2;
|
vertices_count += 2;
|
||||||
if (index_type == GUI::GLModel::Geometry::EIndexType::USHORT)
|
if (init_data.format.index_type == GUI::GLModel::Geometry::EIndexType::USHORT)
|
||||||
init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1);
|
init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1);
|
||||||
else
|
else
|
||||||
init_data.add_uint_line(vertices_count - 2, vertices_count - 1);
|
init_data.add_uint_line(vertices_count - 2, vertices_count - 1);
|
||||||
@ -484,7 +487,9 @@ GLVolume::GLVolume(float r, float g, float b, float a)
|
|||||||
, force_neutral_color(false)
|
, force_neutral_color(false)
|
||||||
, force_sinking_contours(false)
|
, force_sinking_contours(false)
|
||||||
, tverts_range(0, size_t(-1))
|
, tverts_range(0, size_t(-1))
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
, qverts_range(0, size_t(-1))
|
, qverts_range(0, size_t(-1))
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
{
|
{
|
||||||
color = { r, g, b, a };
|
color = { r, g, b, a };
|
||||||
set_render_color(color);
|
set_render_color(color);
|
||||||
@ -600,6 +605,36 @@ const BoundingBoxf3& GLVolume::transformed_non_sinking_bounding_box() const
|
|||||||
return *m_transformed_non_sinking_bounding_box;
|
return *m_transformed_non_sinking_bounding_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void GLVolume::set_range(double min_z, double max_z)
|
||||||
|
{
|
||||||
|
this->tverts_range.first = 0;
|
||||||
|
this->tverts_range.second = this->model.indices_count();
|
||||||
|
|
||||||
|
if (!this->print_zs.empty()) {
|
||||||
|
// The Z layer range is specified.
|
||||||
|
// First test whether the Z span of this object is not out of (min_z, max_z) completely.
|
||||||
|
if (this->print_zs.front() > max_z || this->print_zs.back() < min_z)
|
||||||
|
this->tverts_range.second = 0;
|
||||||
|
else {
|
||||||
|
// Then find the lowest layer to be displayed.
|
||||||
|
size_t i = 0;
|
||||||
|
for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++i);
|
||||||
|
if (i == this->print_zs.size())
|
||||||
|
// This shall not happen.
|
||||||
|
this->tverts_range.second = 0;
|
||||||
|
else {
|
||||||
|
// Remember start of the layer.
|
||||||
|
this->tverts_range.first = this->offsets[i];
|
||||||
|
// Some layers are above $min_z. Which?
|
||||||
|
for (; i < this->print_zs.size() && this->print_zs[i] <= max_z; ++i);
|
||||||
|
if (i < this->print_zs.size())
|
||||||
|
this->tverts_range.second = this->offsets[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
void GLVolume::set_range(double min_z, double max_z)
|
void GLVolume::set_range(double min_z, double max_z)
|
||||||
{
|
{
|
||||||
this->qverts_range.first = 0;
|
this->qverts_range.first = 0;
|
||||||
@ -612,7 +647,8 @@ void GLVolume::set_range(double min_z, double max_z)
|
|||||||
if (this->print_zs.front() > max_z || this->print_zs.back() < min_z) {
|
if (this->print_zs.front() > max_z || this->print_zs.back() < min_z) {
|
||||||
this->qverts_range.second = 0;
|
this->qverts_range.second = 0;
|
||||||
this->tverts_range.second = 0;
|
this->tverts_range.second = 0;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// Then find the lowest layer to be displayed.
|
// Then find the lowest layer to be displayed.
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++ i);
|
for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++ i);
|
||||||
@ -620,7 +656,8 @@ void GLVolume::set_range(double min_z, double max_z)
|
|||||||
// This shall not happen.
|
// This shall not happen.
|
||||||
this->qverts_range.second = 0;
|
this->qverts_range.second = 0;
|
||||||
this->tverts_range.second = 0;
|
this->tverts_range.second = 0;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// Remember start of the layer.
|
// Remember start of the layer.
|
||||||
this->qverts_range.first = this->offsets[i * 2];
|
this->qverts_range.first = this->offsets[i * 2];
|
||||||
this->tverts_range.first = this->offsets[i * 2 + 1];
|
this->tverts_range.first = this->offsets[i * 2 + 1];
|
||||||
@ -634,8 +671,9 @@ void GLVolume::set_range(double min_z, double max_z)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
void GLVolume::render() const
|
void GLVolume::render()
|
||||||
{
|
{
|
||||||
if (!is_active)
|
if (!is_active)
|
||||||
return;
|
return;
|
||||||
@ -646,7 +684,14 @@ void GLVolume::render() const
|
|||||||
glsafe(::glPushMatrix());
|
glsafe(::glPushMatrix());
|
||||||
glsafe(::glMultMatrixd(world_matrix().data()));
|
glsafe(::glMultMatrixd(world_matrix().data()));
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
if (tverts_range == std::make_pair<size_t, size_t>(0, -1))
|
||||||
|
model.render();
|
||||||
|
else
|
||||||
|
model.render(this->tverts_range);
|
||||||
|
#else
|
||||||
this->indexed_vertex_array.render(this->tverts_range, this->qverts_range);
|
this->indexed_vertex_array.render(this->tverts_range, this->qverts_range);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
glsafe(::glPopMatrix());
|
glsafe(::glPopMatrix());
|
||||||
if (this->is_left_handed())
|
if (this->is_left_handed())
|
||||||
@ -681,36 +726,59 @@ void GLVolume::render_non_manifold_edges()
|
|||||||
}
|
}
|
||||||
#endif // ENABLE_SHOW_NON_MANIFOLD_EDGES
|
#endif // ENABLE_SHOW_NON_MANIFOLD_EDGES
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
std::vector<int> GLVolumeCollection::load_object(
|
||||||
|
const ModelObject* model_object,
|
||||||
|
int obj_idx,
|
||||||
|
const std::vector<int>& instance_idxs)
|
||||||
|
#else
|
||||||
std::vector<int> GLVolumeCollection::load_object(
|
std::vector<int> GLVolumeCollection::load_object(
|
||||||
const ModelObject *model_object,
|
const ModelObject *model_object,
|
||||||
int obj_idx,
|
int obj_idx,
|
||||||
const std::vector<int> &instance_idxs,
|
const std::vector<int> &instance_idxs,
|
||||||
const std::string &color_by,
|
|
||||||
bool opengl_initialized)
|
bool opengl_initialized)
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
{
|
{
|
||||||
std::vector<int> volumes_idx;
|
std::vector<int> volumes_idx;
|
||||||
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx)
|
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx)
|
||||||
for (int instance_idx : instance_idxs)
|
for (int instance_idx : instance_idxs)
|
||||||
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized));
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx));
|
||||||
|
#else
|
||||||
|
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, opengl_initialized));
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
return volumes_idx;
|
return volumes_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
int GLVolumeCollection::load_object_volume(
|
||||||
|
const ModelObject* model_object,
|
||||||
|
int obj_idx,
|
||||||
|
int volume_idx,
|
||||||
|
int instance_idx)
|
||||||
|
#else
|
||||||
int GLVolumeCollection::load_object_volume(
|
int GLVolumeCollection::load_object_volume(
|
||||||
const ModelObject *model_object,
|
const ModelObject *model_object,
|
||||||
int obj_idx,
|
int obj_idx,
|
||||||
int volume_idx,
|
int volume_idx,
|
||||||
int instance_idx,
|
int instance_idx,
|
||||||
const std::string &color_by,
|
|
||||||
bool opengl_initialized)
|
bool opengl_initialized)
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
{
|
{
|
||||||
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
||||||
const int extruder_id = model_volume->extruder_id();
|
const int extruder_id = model_volume->extruder_id();
|
||||||
const ModelInstance *instance = model_object->instances[instance_idx];
|
const ModelInstance *instance = model_object->instances[instance_idx];
|
||||||
const TriangleMesh &mesh = model_volume->mesh();
|
const TriangleMesh &mesh = model_volume->mesh();
|
||||||
ColorRGBA color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4];
|
this->volumes.emplace_back(new GLVolume());
|
||||||
color.a(model_volume->is_model_part() ? 1.0f : 0.5f);
|
|
||||||
this->volumes.emplace_back(new GLVolume(color));
|
|
||||||
GLVolume& v = *this->volumes.back();
|
GLVolume& v = *this->volumes.back();
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
v.model.init_from(mesh, true);
|
||||||
|
#else
|
||||||
|
v.model.init_from(mesh);
|
||||||
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
v.model.set_color(color_from_model_volume(*model_volume));
|
||||||
|
#else
|
||||||
v.set_color(color_from_model_volume(*model_volume));
|
v.set_color(color_from_model_volume(*model_volume));
|
||||||
#if ENABLE_SMOOTH_NORMALS
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
v.indexed_vertex_array.load_mesh(mesh, true);
|
v.indexed_vertex_array.load_mesh(mesh, true);
|
||||||
@ -718,9 +786,9 @@ int GLVolumeCollection::load_object_volume(
|
|||||||
v.indexed_vertex_array.load_mesh(mesh);
|
v.indexed_vertex_array.load_mesh(mesh);
|
||||||
#endif // ENABLE_SMOOTH_NORMALS
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
|
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
|
||||||
if (model_volume->is_model_part())
|
if (model_volume->is_model_part()) {
|
||||||
{
|
|
||||||
// GLVolume will reference a convex hull from model_volume!
|
// GLVolume will reference a convex hull from model_volume!
|
||||||
v.set_convex_hull(model_volume->get_convex_hull_shared_ptr());
|
v.set_convex_hull(model_volume->get_convex_hull_shared_ptr());
|
||||||
if (extruder_id != -1)
|
if (extruder_id != -1)
|
||||||
@ -737,6 +805,16 @@ int GLVolumeCollection::load_object_volume(
|
|||||||
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
||||||
// This function produces volumes for multiple instances in a single shot,
|
// This function produces volumes for multiple instances in a single shot,
|
||||||
// as some object specific mesh conversions may be expensive.
|
// as some object specific mesh conversions may be expensive.
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void GLVolumeCollection::load_object_auxiliary(
|
||||||
|
const SLAPrintObject* print_object,
|
||||||
|
int obj_idx,
|
||||||
|
// pairs of <instance_idx, print_instance_idx>
|
||||||
|
const std::vector<std::pair<size_t, size_t>>& instances,
|
||||||
|
SLAPrintObjectStep milestone,
|
||||||
|
// Timestamp of the last change of the milestone
|
||||||
|
size_t timestamp)
|
||||||
|
#else
|
||||||
void GLVolumeCollection::load_object_auxiliary(
|
void GLVolumeCollection::load_object_auxiliary(
|
||||||
const SLAPrintObject *print_object,
|
const SLAPrintObject *print_object,
|
||||||
int obj_idx,
|
int obj_idx,
|
||||||
@ -746,6 +824,7 @@ void GLVolumeCollection::load_object_auxiliary(
|
|||||||
// Timestamp of the last change of the milestone
|
// Timestamp of the last change of the milestone
|
||||||
size_t timestamp,
|
size_t timestamp,
|
||||||
bool opengl_initialized)
|
bool opengl_initialized)
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
{
|
{
|
||||||
assert(print_object->is_step_done(milestone));
|
assert(print_object->is_step_done(milestone));
|
||||||
Transform3d mesh_trafo_inv = print_object->trafo().inverse();
|
Transform3d mesh_trafo_inv = print_object->trafo().inverse();
|
||||||
@ -758,12 +837,21 @@ void GLVolumeCollection::load_object_auxiliary(
|
|||||||
const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
|
const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
|
||||||
this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
|
this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
|
||||||
GLVolume& v = *this->volumes.back();
|
GLVolume& v = *this->volumes.back();
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
v.model.init_from(mesh, true);
|
||||||
|
#else
|
||||||
|
v.model.init_from(mesh);
|
||||||
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
v.model.set_color((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR);
|
||||||
|
#else
|
||||||
#if ENABLE_SMOOTH_NORMALS
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
v.indexed_vertex_array.load_mesh(mesh, true);
|
v.indexed_vertex_array.load_mesh(mesh, true);
|
||||||
#else
|
#else
|
||||||
v.indexed_vertex_array.load_mesh(mesh);
|
v.indexed_vertex_array.load_mesh(mesh);
|
||||||
#endif // ENABLE_SMOOTH_NORMALS
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first);
|
v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first);
|
||||||
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
|
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
|
||||||
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
|
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
|
||||||
@ -779,6 +867,17 @@ void GLVolumeCollection::load_object_auxiliary(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
int GLVolumeCollection::load_wipe_tower_preview(
|
||||||
|
float pos_x, float pos_y, float width, float depth, float height,
|
||||||
|
float rotation_angle, bool size_unknown, float brim_width)
|
||||||
|
#else
|
||||||
|
int GLVolumeCollection::load_wipe_tower_preview(
|
||||||
|
int obj_idx, float pos_x, float pos_y, float width, float depth, float height,
|
||||||
|
float rotation_angle, bool size_unknown, float brim_width)
|
||||||
|
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
#else
|
||||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
int GLVolumeCollection::load_wipe_tower_preview(
|
int GLVolumeCollection::load_wipe_tower_preview(
|
||||||
float pos_x, float pos_y, float width, float depth, float height,
|
float pos_x, float pos_y, float width, float depth, float height,
|
||||||
@ -788,6 +887,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height,
|
int obj_idx, float pos_x, float pos_y, float width, float depth, float height,
|
||||||
float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized)
|
float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized)
|
||||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
{
|
{
|
||||||
if (depth < 0.01f)
|
if (depth < 0.01f)
|
||||||
return int(this->volumes.size() - 1);
|
return int(this->volumes.size() - 1);
|
||||||
@ -844,9 +944,16 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||||||
|
|
||||||
volumes.emplace_back(new GLVolume(color));
|
volumes.emplace_back(new GLVolume(color));
|
||||||
GLVolume& v = *volumes.back();
|
GLVolume& v = *volumes.back();
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
v.model.init_from(mesh);
|
||||||
|
v.model.set_color(color);
|
||||||
|
#else
|
||||||
v.indexed_vertex_array.load_mesh(mesh);
|
v.indexed_vertex_array.load_mesh(mesh);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
v.set_convex_hull(mesh.convex_hull_3d());
|
v.set_convex_hull(mesh.convex_hull_3d());
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
|
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
|
||||||
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
|
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
|
||||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
@ -861,6 +968,22 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||||||
return int(volumes.size() - 1);
|
return int(volumes.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba)
|
||||||
|
{
|
||||||
|
GLVolume* out = new_nontoolpath_volume(rgba);
|
||||||
|
out->is_extrusion_path = true;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba)
|
||||||
|
{
|
||||||
|
GLVolume* out = new GLVolume(rgba);
|
||||||
|
out->is_extrusion_path = false;
|
||||||
|
this->volumes.emplace_back(out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
#else
|
||||||
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats)
|
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats)
|
||||||
{
|
{
|
||||||
GLVolume *out = new_nontoolpath_volume(rgba, reserve_vbo_floats);
|
GLVolume *out = new_nontoolpath_volume(rgba, reserve_vbo_floats);
|
||||||
@ -877,6 +1000,7 @@ GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba, size
|
|||||||
this->volumes.emplace_back(out);
|
this->volumes.emplace_back(out);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func)
|
GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func)
|
||||||
{
|
{
|
||||||
@ -965,7 +1089,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
|||||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||||
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||||
|
|
||||||
shader->set_uniform("uniform_color", volume.first->render_color);
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
if (!volume.first->model.is_initialized())
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
shader->set_uniform("uniform_color", volume.first->render_color);
|
||||||
shader->set_uniform("z_range", m_z_range, 2);
|
shader->set_uniform("z_range", m_z_range, 2);
|
||||||
shader->set_uniform("clipping_plane", m_clipping_plane, 4);
|
shader->set_uniform("clipping_plane", m_clipping_plane, 4);
|
||||||
shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type));
|
shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type));
|
||||||
@ -985,6 +1112,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
|||||||
#endif // ENABLE_ENVIRONMENT_MAP
|
#endif // ENABLE_ENVIRONMENT_MAP
|
||||||
glcheck();
|
glcheck();
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
if (volume.first->model.is_initialized())
|
||||||
|
volume.first->model.set_color(volume.first->render_color);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
volume.first->render();
|
volume.first->render();
|
||||||
|
|
||||||
#if ENABLE_ENVIRONMENT_MAP
|
#if ENABLE_ENVIRONMENT_MAP
|
||||||
@ -1220,6 +1351,466 @@ std::string GLVolumeCollection::log_memory_info() const
|
|||||||
return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")";
|
return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
static void thick_lines_to_geometry(
|
||||||
|
const Lines& lines,
|
||||||
|
const std::vector<double>& widths,
|
||||||
|
const std::vector<double>& heights,
|
||||||
|
bool closed,
|
||||||
|
double top_z,
|
||||||
|
GUI::GLModel::Geometry& geometry)
|
||||||
|
{
|
||||||
|
assert(!lines.empty());
|
||||||
|
if (lines.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
enum Direction : unsigned char
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Top,
|
||||||
|
Bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
// right, left, top, bottom
|
||||||
|
std::array<int, 4> idx_prev = { -1, -1, -1, -1 };
|
||||||
|
std::array<int, 4> idx_initial = { -1, -1, -1, -1 };
|
||||||
|
|
||||||
|
double bottom_z_prev = 0.0;
|
||||||
|
Vec2d b1_prev(Vec2d::Zero());
|
||||||
|
Vec2d v_prev(Vec2d::Zero());
|
||||||
|
double len_prev = 0.0;
|
||||||
|
double width_initial = 0.0;
|
||||||
|
double bottom_z_initial = 0.0;
|
||||||
|
|
||||||
|
// loop once more in case of closed loops
|
||||||
|
const size_t lines_end = closed ? (lines.size() + 1) : lines.size();
|
||||||
|
for (size_t ii = 0; ii < lines_end; ++ii) {
|
||||||
|
const size_t i = (ii == lines.size()) ? 0 : ii;
|
||||||
|
const Line& line = lines[i];
|
||||||
|
const double bottom_z = top_z - heights[i];
|
||||||
|
const double middle_z = 0.5 * (top_z + bottom_z);
|
||||||
|
const double width = widths[i];
|
||||||
|
|
||||||
|
const bool is_first = (ii == 0);
|
||||||
|
const bool is_last = (ii == lines_end - 1);
|
||||||
|
const bool is_closing = closed && is_last;
|
||||||
|
|
||||||
|
const Vec2d v = unscale(line.vector()).normalized();
|
||||||
|
const double len = unscale<double>(line.length());
|
||||||
|
|
||||||
|
const Vec2d a = unscale(line.a);
|
||||||
|
const Vec2d b = unscale(line.b);
|
||||||
|
Vec2d a1 = a;
|
||||||
|
Vec2d a2 = a;
|
||||||
|
Vec2d b1 = b;
|
||||||
|
Vec2d b2 = b;
|
||||||
|
{
|
||||||
|
const double dist = 0.5 * width; // scaled
|
||||||
|
const double dx = dist * v.x();
|
||||||
|
const double dy = dist * v.y();
|
||||||
|
a1 += Vec2d(+dy, -dx);
|
||||||
|
a2 += Vec2d(-dy, +dx);
|
||||||
|
b1 += Vec2d(+dy, -dx);
|
||||||
|
b2 += Vec2d(-dy, +dx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate new XY normals
|
||||||
|
const Vec2d xy_right_normal = unscale(line.normal()).normalized();
|
||||||
|
|
||||||
|
std::array<int, 4> idx_a = { 0, 0, 0, 0 };
|
||||||
|
std::array<int, 4> idx_b = { 0, 0, 0, 0 };
|
||||||
|
int idx_last = int(geometry.vertices_count());
|
||||||
|
|
||||||
|
const bool bottom_z_different = bottom_z_prev != bottom_z;
|
||||||
|
bottom_z_prev = bottom_z;
|
||||||
|
|
||||||
|
if (!is_first && bottom_z_different) {
|
||||||
|
// Found a change of the layer thickness -> Add a cap at the end of the previous segment.
|
||||||
|
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]);
|
||||||
|
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Share top / bottom vertices if possible.
|
||||||
|
if (is_first) {
|
||||||
|
idx_a[Top] = idx_last++;
|
||||||
|
geometry.add_vertex(Vec3f(a.x(), a.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
idx_a[Top] = idx_prev[Top];
|
||||||
|
|
||||||
|
if (is_first || bottom_z_different) {
|
||||||
|
// Start of the 1st line segment or a change of the layer thickness while maintaining the print_z.
|
||||||
|
idx_a[Bottom] = idx_last++;
|
||||||
|
geometry.add_vertex(Vec3f(a.x(), a.y(), bottom_z), Vec3f(0.0f, 0.0f, -1.0f));
|
||||||
|
idx_a[Left] = idx_last++;
|
||||||
|
geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f));
|
||||||
|
idx_a[Right] = idx_last++;
|
||||||
|
geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
idx_a[Bottom] = idx_prev[Bottom];
|
||||||
|
|
||||||
|
if (is_first) {
|
||||||
|
// Start of the 1st line segment.
|
||||||
|
width_initial = width;
|
||||||
|
bottom_z_initial = bottom_z;
|
||||||
|
idx_initial = idx_a;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Continuing a previous segment.
|
||||||
|
// Share left / right vertices if possible.
|
||||||
|
const double v_dot = v_prev.dot(v);
|
||||||
|
// To reduce gpu memory usage, we try to reuse vertices
|
||||||
|
// To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges
|
||||||
|
// is longer than a fixed threshold.
|
||||||
|
// The following value is arbitrary, it comes from tests made on a bunch of models showing the visual artifacts
|
||||||
|
const double len_threshold = 2.5;
|
||||||
|
|
||||||
|
// Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met
|
||||||
|
const bool sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold);
|
||||||
|
if (sharp) {
|
||||||
|
if (!bottom_z_different) {
|
||||||
|
// Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
|
||||||
|
idx_a[Right] = idx_last++;
|
||||||
|
geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
|
||||||
|
idx_a[Left] = idx_last++;
|
||||||
|
geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f));
|
||||||
|
if (cross2(v_prev, v) > 0.0) {
|
||||||
|
// Right turn. Fill in the right turn wedge.
|
||||||
|
geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]);
|
||||||
|
geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Left turn. Fill in the left turn wedge.
|
||||||
|
geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]);
|
||||||
|
geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!bottom_z_different) {
|
||||||
|
// The two successive segments are nearly collinear.
|
||||||
|
idx_a[Left] = idx_prev[Left];
|
||||||
|
idx_a[Right] = idx_prev[Right];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_closing) {
|
||||||
|
if (!sharp) {
|
||||||
|
if (!bottom_z_different) {
|
||||||
|
// Closing a loop with smooth transition. Unify the closing left / right vertices.
|
||||||
|
geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left]));
|
||||||
|
geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right]));
|
||||||
|
geometry.remove_vertex(geometry.vertices_count() - 1);
|
||||||
|
geometry.remove_vertex(geometry.vertices_count() - 1);
|
||||||
|
// Replace the left / right vertex indices to point to the start of the loop.
|
||||||
|
const size_t indices_count = geometry.indices_count();
|
||||||
|
for (size_t u = indices_count - 24; u < indices_count; ++u) {
|
||||||
|
const unsigned int id = geometry.extract_uint_index(u);
|
||||||
|
if (id == (unsigned int)idx_prev[Left])
|
||||||
|
geometry.set_uint_index(u, (unsigned int)idx_initial[Left]);
|
||||||
|
else if (id == (unsigned int)idx_prev[Right])
|
||||||
|
geometry.set_uint_index(u, (unsigned int)idx_initial[Right]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This is the last iteration, only required to solve the transition.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only new allocate top / bottom vertices, if not closing a loop.
|
||||||
|
if (is_closing)
|
||||||
|
idx_b[Top] = idx_initial[Top];
|
||||||
|
else {
|
||||||
|
idx_b[Top] = idx_last++;
|
||||||
|
geometry.add_vertex(Vec3f(b.x(), b.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_closing && width == width_initial && bottom_z == bottom_z_initial)
|
||||||
|
idx_b[Bottom] = idx_initial[Bottom];
|
||||||
|
else {
|
||||||
|
idx_b[Bottom] = idx_last++;
|
||||||
|
geometry.add_vertex(Vec3f(b.x(), b.y(), bottom_z), Vec3f(0.0f, 0.0f, -1.0f));
|
||||||
|
}
|
||||||
|
// Generate new vertices for the end of this line segment.
|
||||||
|
idx_b[Left] = idx_last++;
|
||||||
|
geometry.add_vertex(Vec3f(b2.x(), b2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f));
|
||||||
|
idx_b[Right] = idx_last++;
|
||||||
|
geometry.add_vertex(Vec3f(b1.x(), b1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
|
||||||
|
|
||||||
|
idx_prev = idx_b;
|
||||||
|
bottom_z_prev = bottom_z;
|
||||||
|
b1_prev = b1;
|
||||||
|
v_prev = v;
|
||||||
|
len_prev = len;
|
||||||
|
|
||||||
|
if (bottom_z_different && (closed || (!is_first && !is_last))) {
|
||||||
|
// Found a change of the layer thickness -> Add a cap at the beginning of this segment.
|
||||||
|
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!closed) {
|
||||||
|
// Terminate open paths with caps.
|
||||||
|
if (is_first) {
|
||||||
|
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]);
|
||||||
|
}
|
||||||
|
// We don't use 'else' because both cases are true if we have only one line.
|
||||||
|
if (is_last) {
|
||||||
|
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]);
|
||||||
|
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add quads for a straight hollow tube-like segment.
|
||||||
|
// bottom-right face
|
||||||
|
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]);
|
||||||
|
// top-right face
|
||||||
|
geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]);
|
||||||
|
// top-left face
|
||||||
|
geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]);
|
||||||
|
// bottom-left face
|
||||||
|
geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// caller is responsible for supplying NO lines with zero length
|
||||||
|
static void thick_lines_to_geometry(
|
||||||
|
const Lines3& lines,
|
||||||
|
const std::vector<double>& widths,
|
||||||
|
const std::vector<double>& heights,
|
||||||
|
bool closed,
|
||||||
|
GUI::GLModel::Geometry& geometry)
|
||||||
|
{
|
||||||
|
assert(!lines.empty());
|
||||||
|
if (lines.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
enum Direction : unsigned char
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Top,
|
||||||
|
Bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
// left, right, top, bottom
|
||||||
|
std::array<int, 4> idx_prev = { -1, -1, -1, -1 };
|
||||||
|
std::array<int, 4> idx_initial = { -1, -1, -1, -1 };
|
||||||
|
|
||||||
|
double z_prev = 0.0;
|
||||||
|
double len_prev = 0.0;
|
||||||
|
Vec3d n_right_prev = Vec3d::Zero();
|
||||||
|
Vec3d n_top_prev = Vec3d::Zero();
|
||||||
|
Vec3d unit_v_prev = Vec3d::Zero();
|
||||||
|
double width_initial = 0.0;
|
||||||
|
|
||||||
|
// new vertices around the line endpoints
|
||||||
|
// left, right, top, bottom
|
||||||
|
std::array<Vec3d, 4> a = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
|
||||||
|
std::array<Vec3d, 4> b = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
|
||||||
|
|
||||||
|
// loop once more in case of closed loops
|
||||||
|
const size_t lines_end = closed ? (lines.size() + 1) : lines.size();
|
||||||
|
for (size_t ii = 0; ii < lines_end; ++ii) {
|
||||||
|
const size_t i = (ii == lines.size()) ? 0 : ii;
|
||||||
|
|
||||||
|
const Line3& line = lines[i];
|
||||||
|
const double height = heights[i];
|
||||||
|
const double width = widths[i];
|
||||||
|
|
||||||
|
const Vec3d unit_v = unscale(line.vector()).normalized();
|
||||||
|
const double len = unscale<double>(line.length());
|
||||||
|
|
||||||
|
Vec3d n_top = Vec3d::Zero();
|
||||||
|
Vec3d n_right = Vec3d::Zero();
|
||||||
|
|
||||||
|
if (line.a.x() == line.b.x() && line.a.y() == line.b.y()) {
|
||||||
|
// vertical segment
|
||||||
|
n_top = Vec3d::UnitY();
|
||||||
|
n_right = Vec3d::UnitX();
|
||||||
|
if (line.a.z() < line.b.z())
|
||||||
|
n_right = -n_right;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// horizontal segment
|
||||||
|
n_right = unit_v.cross(Vec3d::UnitZ()).normalized();
|
||||||
|
n_top = n_right.cross(unit_v).normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vec3d rl_displacement = 0.5 * width * n_right;
|
||||||
|
const Vec3d tb_displacement = 0.5 * height * n_top;
|
||||||
|
const Vec3d l_a = unscale(line.a);
|
||||||
|
const Vec3d l_b = unscale(line.b);
|
||||||
|
|
||||||
|
a[Right] = l_a + rl_displacement;
|
||||||
|
a[Left] = l_a - rl_displacement;
|
||||||
|
a[Top] = l_a + tb_displacement;
|
||||||
|
a[Bottom] = l_a - tb_displacement;
|
||||||
|
b[Right] = l_b + rl_displacement;
|
||||||
|
b[Left] = l_b - rl_displacement;
|
||||||
|
b[Top] = l_b + tb_displacement;
|
||||||
|
b[Bottom] = l_b - tb_displacement;
|
||||||
|
|
||||||
|
const Vec3d n_bottom = -n_top;
|
||||||
|
const Vec3d n_left = -n_right;
|
||||||
|
|
||||||
|
std::array<int, 4> idx_a = { 0, 0, 0, 0};
|
||||||
|
std::array<int, 4> idx_b = { 0, 0, 0, 0 };
|
||||||
|
int idx_last = int(geometry.vertices_count());
|
||||||
|
|
||||||
|
const bool z_different = (z_prev != l_a.z());
|
||||||
|
z_prev = l_b.z();
|
||||||
|
|
||||||
|
// Share top / bottom vertices if possible.
|
||||||
|
if (ii == 0) {
|
||||||
|
idx_a[Top] = idx_last++;
|
||||||
|
geometry.add_vertex((Vec3f)a[Top].cast<float>(), (Vec3f)n_top.cast<float>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
idx_a[Top] = idx_prev[Top];
|
||||||
|
|
||||||
|
if (ii == 0 || z_different) {
|
||||||
|
// Start of the 1st line segment or a change of the layer thickness while maintaining the print_z.
|
||||||
|
idx_a[Bottom] = idx_last++;
|
||||||
|
geometry.add_vertex((Vec3f)a[Bottom].cast<float>(), (Vec3f)n_bottom.cast<float>());
|
||||||
|
idx_a[Left] = idx_last++;
|
||||||
|
geometry.add_vertex((Vec3f)a[Left].cast<float>(), (Vec3f)n_left.cast<float>());
|
||||||
|
idx_a[Right] = idx_last++;
|
||||||
|
geometry.add_vertex((Vec3f)a[Right].cast<float>(), (Vec3f)n_right.cast<float>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
idx_a[Bottom] = idx_prev[Bottom];
|
||||||
|
|
||||||
|
if (ii == 0) {
|
||||||
|
// Start of the 1st line segment.
|
||||||
|
width_initial = width;
|
||||||
|
idx_initial = idx_a;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Continuing a previous segment.
|
||||||
|
// Share left / right vertices if possible.
|
||||||
|
const double v_dot = unit_v_prev.dot(unit_v);
|
||||||
|
const bool is_right_turn = n_top_prev.dot(unit_v_prev.cross(unit_v)) > 0.0;
|
||||||
|
|
||||||
|
// To reduce gpu memory usage, we try to reuse vertices
|
||||||
|
// To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges
|
||||||
|
// is longer than a fixed threshold.
|
||||||
|
// The following value is arbitrary, it comes from tests made on a bunch of models showing the visual artifacts
|
||||||
|
const double len_threshold = 2.5;
|
||||||
|
|
||||||
|
// Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met
|
||||||
|
const bool is_sharp = v_dot < 0.707 || len_prev > len_threshold || len > len_threshold;
|
||||||
|
if (is_sharp) {
|
||||||
|
// Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
|
||||||
|
idx_a[Right] = idx_last++;
|
||||||
|
geometry.add_vertex((Vec3f)a[Right].cast<float>(), (Vec3f)n_right.cast<float>());
|
||||||
|
idx_a[Left] = idx_last++;
|
||||||
|
geometry.add_vertex((Vec3f)a[Left].cast<float>(), (Vec3f)n_left.cast<float>());
|
||||||
|
|
||||||
|
if (is_right_turn) {
|
||||||
|
// Right turn. Fill in the right turn wedge.
|
||||||
|
geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]);
|
||||||
|
geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Left turn. Fill in the left turn wedge.
|
||||||
|
geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]);
|
||||||
|
geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The two successive segments are nearly collinear.
|
||||||
|
idx_a[Left] = idx_prev[Left];
|
||||||
|
idx_a[Right] = idx_prev[Right];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ii == lines.size()) {
|
||||||
|
if (!is_sharp) {
|
||||||
|
// Closing a loop with smooth transition. Unify the closing left / right vertices.
|
||||||
|
geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left]));
|
||||||
|
geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right]));
|
||||||
|
geometry.remove_vertex(geometry.vertices_count() - 1);
|
||||||
|
geometry.remove_vertex(geometry.vertices_count() - 1);
|
||||||
|
// Replace the left / right vertex indices to point to the start of the loop.
|
||||||
|
const size_t indices_count = geometry.indices_count();
|
||||||
|
for (size_t u = indices_count - 24; u < indices_count; ++u) {
|
||||||
|
const unsigned int id = geometry.extract_uint_index(u);
|
||||||
|
if (id == (unsigned int)idx_prev[Left])
|
||||||
|
geometry.set_uint_index(u, (unsigned int)idx_initial[Left]);
|
||||||
|
else if (id == (unsigned int)idx_prev[Right])
|
||||||
|
geometry.set_uint_index(u, (unsigned int)idx_initial[Right]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the last iteration, only required to solve the transition.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only new allocate top / bottom vertices, if not closing a loop.
|
||||||
|
if (closed && ii + 1 == lines.size())
|
||||||
|
idx_b[Top] = idx_initial[Top];
|
||||||
|
else {
|
||||||
|
idx_b[Top] = idx_last++;
|
||||||
|
geometry.add_vertex((Vec3f)b[Top].cast<float>(), (Vec3f)n_top.cast<float>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closed && ii + 1 == lines.size() && width == width_initial)
|
||||||
|
idx_b[Bottom] = idx_initial[Bottom];
|
||||||
|
else {
|
||||||
|
idx_b[Bottom] = idx_last++;
|
||||||
|
geometry.add_vertex((Vec3f)b[Bottom].cast<float>(), (Vec3f)n_bottom.cast<float>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new vertices for the end of this line segment.
|
||||||
|
idx_b[Left] = idx_last++;
|
||||||
|
geometry.add_vertex((Vec3f)b[Left].cast<float>(), (Vec3f)n_left.cast<float>());
|
||||||
|
idx_b[Right] = idx_last++;
|
||||||
|
geometry.add_vertex((Vec3f)b[Right].cast<float>(), (Vec3f)n_right.cast<float>());
|
||||||
|
|
||||||
|
idx_prev = idx_b;
|
||||||
|
n_right_prev = n_right;
|
||||||
|
n_top_prev = n_top;
|
||||||
|
unit_v_prev = unit_v;
|
||||||
|
len_prev = len;
|
||||||
|
|
||||||
|
if (!closed) {
|
||||||
|
// Terminate open paths with caps.
|
||||||
|
if (i == 0) {
|
||||||
|
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't use 'else' because both cases are true if we have only one line.
|
||||||
|
if (i + 1 == lines.size()) {
|
||||||
|
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]);
|
||||||
|
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add quads for a straight hollow tube-like segment.
|
||||||
|
// bottom-right face
|
||||||
|
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]);
|
||||||
|
// top-right face
|
||||||
|
geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]);
|
||||||
|
// top-left face
|
||||||
|
geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]);
|
||||||
|
// bottom-left face
|
||||||
|
geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]);
|
||||||
|
geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
// caller is responsible for supplying NO lines with zero length
|
// caller is responsible for supplying NO lines with zero length
|
||||||
static void thick_lines_to_indexed_vertex_array(
|
static void thick_lines_to_indexed_vertex_array(
|
||||||
const Lines &lines,
|
const Lines &lines,
|
||||||
@ -1729,7 +2320,30 @@ static void point_to_indexed_vertex_array(const Vec3crd& point,
|
|||||||
volume.push_triangle(idxs[3], idxs[1], idxs[4]);
|
volume.push_triangle(idxs[3], idxs[1], idxs[4]);
|
||||||
volume.push_triangle(idxs[0], idxs[3], idxs[4]);
|
volume.push_triangle(idxs[0], idxs[3], idxs[4]);
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void _3DScene::thick_lines_to_verts(
|
||||||
|
const Lines& lines,
|
||||||
|
const std::vector<double>& widths,
|
||||||
|
const std::vector<double>& heights,
|
||||||
|
bool closed,
|
||||||
|
double top_z,
|
||||||
|
GUI::GLModel::Geometry& geometry)
|
||||||
|
{
|
||||||
|
thick_lines_to_geometry(lines, widths, heights, closed, top_z, geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _3DScene::thick_lines_to_verts(
|
||||||
|
const Lines3& lines,
|
||||||
|
const std::vector<double>& widths,
|
||||||
|
const std::vector<double>& heights,
|
||||||
|
bool closed,
|
||||||
|
GUI::GLModel::Geometry& geometry)
|
||||||
|
{
|
||||||
|
thick_lines_to_geometry(lines, widths, heights, closed, geometry);
|
||||||
|
}
|
||||||
|
#else
|
||||||
void _3DScene::thick_lines_to_verts(
|
void _3DScene::thick_lines_to_verts(
|
||||||
const Lines &lines,
|
const Lines &lines,
|
||||||
const std::vector<double> &widths,
|
const std::vector<double> &widths,
|
||||||
@ -1771,8 +2385,21 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, flo
|
|||||||
{
|
{
|
||||||
extrusionentity_to_verts(extrusion_path.polyline, extrusion_path.width, extrusion_path.height, print_z, volume);
|
extrusionentity_to_verts(extrusion_path.polyline, extrusion_path.width, extrusion_path.height, print_z, volume);
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
// Fill in the qverts and tverts with quads and triangles for the extrusion_path.
|
// Fill in the qverts and tverts with quads and triangles for the extrusion_path.
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void _3DScene::extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
|
||||||
|
{
|
||||||
|
Polyline polyline = extrusion_path.polyline;
|
||||||
|
polyline.remove_duplicate_points();
|
||||||
|
polyline.translate(copy);
|
||||||
|
const Lines lines = polyline.lines();
|
||||||
|
std::vector<double> widths(lines.size(), extrusion_path.width);
|
||||||
|
std::vector<double> heights(lines.size(), extrusion_path.height);
|
||||||
|
thick_lines_to_verts(lines, widths, heights, false, print_z, geometry);
|
||||||
|
}
|
||||||
|
#else
|
||||||
void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point ©, GLVolume &volume)
|
void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point ©, GLVolume &volume)
|
||||||
{
|
{
|
||||||
Polyline polyline = extrusion_path.polyline;
|
Polyline polyline = extrusion_path.polyline;
|
||||||
@ -1783,8 +2410,27 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, flo
|
|||||||
std::vector<double> heights(lines.size(), extrusion_path.height);
|
std::vector<double> heights(lines.size(), extrusion_path.height);
|
||||||
thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
|
thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
// Fill in the qverts and tverts with quads and triangles for the extrusion_loop.
|
// Fill in the qverts and tverts with quads and triangles for the extrusion_loop.
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void _3DScene::extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
|
||||||
|
{
|
||||||
|
Lines lines;
|
||||||
|
std::vector<double> widths;
|
||||||
|
std::vector<double> heights;
|
||||||
|
for (const ExtrusionPath& extrusion_path : extrusion_loop.paths) {
|
||||||
|
Polyline polyline = extrusion_path.polyline;
|
||||||
|
polyline.remove_duplicate_points();
|
||||||
|
polyline.translate(copy);
|
||||||
|
const Lines lines_this = polyline.lines();
|
||||||
|
append(lines, lines_this);
|
||||||
|
widths.insert(widths.end(), lines_this.size(), extrusion_path.width);
|
||||||
|
heights.insert(heights.end(), lines_this.size(), extrusion_path.height);
|
||||||
|
}
|
||||||
|
thick_lines_to_verts(lines, widths, heights, true, print_z, geometry);
|
||||||
|
}
|
||||||
|
#else
|
||||||
void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, float print_z, const Point ©, GLVolume &volume)
|
void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, float print_z, const Point ©, GLVolume &volume)
|
||||||
{
|
{
|
||||||
Lines lines;
|
Lines lines;
|
||||||
@ -1801,8 +2447,27 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, flo
|
|||||||
}
|
}
|
||||||
thick_lines_to_verts(lines, widths, heights, true, print_z, volume);
|
thick_lines_to_verts(lines, widths, heights, true, print_z, volume);
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
// Fill in the qverts and tverts with quads and triangles for the extrusion_multi_path.
|
// Fill in the qverts and tverts with quads and triangles for the extrusion_multi_path.
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
|
||||||
|
{
|
||||||
|
Lines lines;
|
||||||
|
std::vector<double> widths;
|
||||||
|
std::vector<double> heights;
|
||||||
|
for (const ExtrusionPath& extrusion_path : extrusion_multi_path.paths) {
|
||||||
|
Polyline polyline = extrusion_path.polyline;
|
||||||
|
polyline.remove_duplicate_points();
|
||||||
|
polyline.translate(copy);
|
||||||
|
const Lines lines_this = polyline.lines();
|
||||||
|
append(lines, lines_this);
|
||||||
|
widths.insert(widths.end(), lines_this.size(), extrusion_path.width);
|
||||||
|
heights.insert(heights.end(), lines_this.size(), extrusion_path.height);
|
||||||
|
}
|
||||||
|
thick_lines_to_verts(lines, widths, heights, false, print_z, geometry);
|
||||||
|
}
|
||||||
|
#else
|
||||||
void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_multi_path, float print_z, const Point ©, GLVolume &volume)
|
void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_multi_path, float print_z, const Point ©, GLVolume &volume)
|
||||||
{
|
{
|
||||||
Lines lines;
|
Lines lines;
|
||||||
@ -1819,13 +2484,49 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_mult
|
|||||||
}
|
}
|
||||||
thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
|
thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
|
||||||
|
{
|
||||||
|
for (const ExtrusionEntity* extrusion_entity : extrusion_entity_collection.entities)
|
||||||
|
extrusionentity_to_verts(extrusion_entity, print_z, copy, geometry);
|
||||||
|
}
|
||||||
|
#else
|
||||||
void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection &extrusion_entity_collection, float print_z, const Point ©, GLVolume &volume)
|
void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection &extrusion_entity_collection, float print_z, const Point ©, GLVolume &volume)
|
||||||
{
|
{
|
||||||
for (const ExtrusionEntity *extrusion_entity : extrusion_entity_collection.entities)
|
for (const ExtrusionEntity *extrusion_entity : extrusion_entity_collection.entities)
|
||||||
extrusionentity_to_verts(extrusion_entity, print_z, copy, volume);
|
extrusionentity_to_verts(extrusion_entity, print_z, copy, volume);
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void _3DScene::extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
|
||||||
|
{
|
||||||
|
if (extrusion_entity != nullptr) {
|
||||||
|
auto* extrusion_path = dynamic_cast<const ExtrusionPath*>(extrusion_entity);
|
||||||
|
if (extrusion_path != nullptr)
|
||||||
|
extrusionentity_to_verts(*extrusion_path, print_z, copy, geometry);
|
||||||
|
else {
|
||||||
|
auto* extrusion_loop = dynamic_cast<const ExtrusionLoop*>(extrusion_entity);
|
||||||
|
if (extrusion_loop != nullptr)
|
||||||
|
extrusionentity_to_verts(*extrusion_loop, print_z, copy, geometry);
|
||||||
|
else {
|
||||||
|
auto* extrusion_multi_path = dynamic_cast<const ExtrusionMultiPath*>(extrusion_entity);
|
||||||
|
if (extrusion_multi_path != nullptr)
|
||||||
|
extrusionentity_to_verts(*extrusion_multi_path, print_z, copy, geometry);
|
||||||
|
else {
|
||||||
|
auto* extrusion_entity_collection = dynamic_cast<const ExtrusionEntityCollection*>(extrusion_entity);
|
||||||
|
if (extrusion_entity_collection != nullptr)
|
||||||
|
extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, geometry);
|
||||||
|
else
|
||||||
|
throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, float print_z, const Point ©, GLVolume &volume)
|
void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, float print_z, const Point ©, GLVolume &volume)
|
||||||
{
|
{
|
||||||
if (extrusion_entity != nullptr) {
|
if (extrusion_entity != nullptr) {
|
||||||
@ -1844,9 +2545,8 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity,
|
|||||||
auto *extrusion_entity_collection = dynamic_cast<const ExtrusionEntityCollection*>(extrusion_entity);
|
auto *extrusion_entity_collection = dynamic_cast<const ExtrusionEntityCollection*>(extrusion_entity);
|
||||||
if (extrusion_entity_collection != nullptr)
|
if (extrusion_entity_collection != nullptr)
|
||||||
extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, volume);
|
extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, volume);
|
||||||
else {
|
else
|
||||||
throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()");
|
throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1865,5 +2565,6 @@ void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height
|
|||||||
{
|
{
|
||||||
thick_point_to_verts(point, width, height, volume);
|
thick_point_to_verts(point, width, height, volume);
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -46,6 +46,7 @@ enum ModelInstanceEPrintVolumeState : unsigned char;
|
|||||||
// Return appropriate color based on the ModelVolume.
|
// Return appropriate color based on the ModelVolume.
|
||||||
extern ColorRGBA color_from_model_volume(const ModelVolume& model_volume);
|
extern ColorRGBA color_from_model_volume(const ModelVolume& model_volume);
|
||||||
|
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
// A container for interleaved arrays of 3D vertices and normals,
|
// A container for interleaved arrays of 3D vertices and normals,
|
||||||
// possibly indexed by triangles and / or quads.
|
// possibly indexed by triangles and / or quads.
|
||||||
class GLIndexedVertexArray {
|
class GLIndexedVertexArray {
|
||||||
@ -246,6 +247,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
BoundingBox m_bounding_box;
|
BoundingBox m_bounding_box;
|
||||||
};
|
};
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
class GLVolume {
|
class GLVolume {
|
||||||
public:
|
public:
|
||||||
@ -388,11 +390,17 @@ public:
|
|||||||
// Is mouse or rectangle selection over this object to select/deselect it ?
|
// Is mouse or rectangle selection over this object to select/deselect it ?
|
||||||
EHoverState hover;
|
EHoverState hover;
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
GUI::GLModel model;
|
||||||
|
#else
|
||||||
// Interleaved triangles & normals with indexed triangles & quads.
|
// Interleaved triangles & normals with indexed triangles & quads.
|
||||||
GLIndexedVertexArray indexed_vertex_array;
|
GLIndexedVertexArray indexed_vertex_array;
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
// Ranges of triangle and quad indices to be rendered.
|
// Ranges of triangle and quad indices to be rendered.
|
||||||
std::pair<size_t, size_t> tverts_range;
|
std::pair<size_t, size_t> tverts_range;
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
std::pair<size_t, size_t> qverts_range;
|
std::pair<size_t, size_t> qverts_range;
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
// If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts
|
// If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts
|
||||||
// of the extrusions per layer.
|
// of the extrusions per layer.
|
||||||
@ -402,13 +410,17 @@ public:
|
|||||||
|
|
||||||
// Bounding box of this volume, in unscaled coordinates.
|
// Bounding box of this volume, in unscaled coordinates.
|
||||||
BoundingBoxf3 bounding_box() const {
|
BoundingBoxf3 bounding_box() const {
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
return this->model.get_bounding_box();
|
||||||
|
#else
|
||||||
BoundingBoxf3 out;
|
BoundingBoxf3 out;
|
||||||
if (! this->indexed_vertex_array.bounding_box().isEmpty()) {
|
if (!this->indexed_vertex_array.bounding_box().isEmpty()) {
|
||||||
out.min = this->indexed_vertex_array.bounding_box().min().cast<double>();
|
out.min = this->indexed_vertex_array.bounding_box().min().cast<double>();
|
||||||
out.max = this->indexed_vertex_array.bounding_box().max().cast<double>();
|
out.max = this->indexed_vertex_array.bounding_box().max().cast<double>();
|
||||||
out.defined = true;
|
out.defined = true;
|
||||||
};
|
}
|
||||||
return out;
|
return out;
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_color(const ColorRGBA& rgba) { color = rgba; }
|
void set_color(const ColorRGBA& rgba) { color = rgba; }
|
||||||
@ -498,14 +510,20 @@ public:
|
|||||||
// convex hull
|
// convex hull
|
||||||
const TriangleMesh* convex_hull() const { return m_convex_hull.get(); }
|
const TriangleMesh* convex_hull() const { return m_convex_hull.get(); }
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
bool empty() const { return this->model.is_empty(); }
|
||||||
|
#else
|
||||||
bool empty() const { return this->indexed_vertex_array.empty(); }
|
bool empty() const { return this->indexed_vertex_array.empty(); }
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
void set_range(double low, double high);
|
void set_range(double low, double high);
|
||||||
|
|
||||||
void render() const;
|
void render();
|
||||||
|
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); }
|
void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); }
|
||||||
void release_geometry() { this->indexed_vertex_array.release_geometry(); }
|
void release_geometry() { this->indexed_vertex_array.release_geometry(); }
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
void set_bounding_boxes_as_dirty() {
|
void set_bounding_boxes_as_dirty() {
|
||||||
m_transformed_bounding_box.reset();
|
m_transformed_bounding_box.reset();
|
||||||
@ -524,12 +542,20 @@ public:
|
|||||||
#endif // ENABLE_SHOW_NON_MANIFOLD_EDGES
|
#endif // ENABLE_SHOW_NON_MANIFOLD_EDGES
|
||||||
|
|
||||||
// Return an estimate of the memory consumed by this class.
|
// Return an estimate of the memory consumed by this class.
|
||||||
size_t cpu_memory_used() const {
|
size_t cpu_memory_used() const {
|
||||||
//FIXME what to do wih m_convex_hull?
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
return sizeof(*this) + this->model.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) +
|
||||||
|
this->offsets.capacity() * sizeof(size_t);
|
||||||
|
}
|
||||||
|
// Return an estimate of the memory held by GPU vertex buffers.
|
||||||
|
size_t gpu_memory_used() const { return this->model.gpu_memory_used(); }
|
||||||
|
#else
|
||||||
|
//FIXME what to do wih m_convex_hull?
|
||||||
return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t);
|
return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t);
|
||||||
}
|
}
|
||||||
// Return an estimate of the memory held by GPU vertex buffers.
|
// Return an estimate of the memory held by GPU vertex buffers.
|
||||||
size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); }
|
size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); }
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
|
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -589,11 +615,40 @@ public:
|
|||||||
GLVolumeCollection() { set_default_slope_normal_z(); }
|
GLVolumeCollection() { set_default_slope_normal_z(); }
|
||||||
~GLVolumeCollection() { clear(); }
|
~GLVolumeCollection() { clear(); }
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
std::vector<int> load_object(
|
||||||
|
const ModelObject* model_object,
|
||||||
|
int obj_idx,
|
||||||
|
const std::vector<int>& instance_idxs);
|
||||||
|
|
||||||
|
int load_object_volume(
|
||||||
|
const ModelObject* model_object,
|
||||||
|
int obj_idx,
|
||||||
|
int volume_idx,
|
||||||
|
int instance_idx);
|
||||||
|
|
||||||
|
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
||||||
|
void load_object_auxiliary(
|
||||||
|
const SLAPrintObject* print_object,
|
||||||
|
int obj_idx,
|
||||||
|
// pairs of <instance_idx, print_instance_idx>
|
||||||
|
const std::vector<std::pair<size_t, size_t>>& instances,
|
||||||
|
SLAPrintObjectStep milestone,
|
||||||
|
// Timestamp of the last change of the milestone
|
||||||
|
size_t timestamp);
|
||||||
|
|
||||||
|
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
int load_wipe_tower_preview(
|
||||||
|
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width);
|
||||||
|
#else
|
||||||
|
int load_wipe_tower_preview(
|
||||||
|
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width);
|
||||||
|
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
#else
|
||||||
std::vector<int> load_object(
|
std::vector<int> load_object(
|
||||||
const ModelObject *model_object,
|
const ModelObject *model_object,
|
||||||
int obj_idx,
|
int obj_idx,
|
||||||
const std::vector<int> &instance_idxs,
|
const std::vector<int> &instance_idxs,
|
||||||
const std::string &color_by,
|
|
||||||
bool opengl_initialized);
|
bool opengl_initialized);
|
||||||
|
|
||||||
int load_object_volume(
|
int load_object_volume(
|
||||||
@ -601,7 +656,6 @@ public:
|
|||||||
int obj_idx,
|
int obj_idx,
|
||||||
int volume_idx,
|
int volume_idx,
|
||||||
int instance_idx,
|
int instance_idx,
|
||||||
const std::string &color_by,
|
|
||||||
bool opengl_initialized);
|
bool opengl_initialized);
|
||||||
|
|
||||||
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
||||||
@ -622,13 +676,20 @@ public:
|
|||||||
int load_wipe_tower_preview(
|
int load_wipe_tower_preview(
|
||||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized);
|
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized);
|
||||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
GLVolume* new_toolpath_volume(const ColorRGBA& rgba);
|
||||||
|
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba);
|
||||||
|
#else
|
||||||
GLVolume* new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
|
GLVolume* new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
|
||||||
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
|
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
// Render the volumes by OpenGL.
|
// Render the volumes by OpenGL.
|
||||||
void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
|
void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
|
||||||
|
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
// Finalize the initialization of the geometry & indices,
|
// Finalize the initialization of the geometry & indices,
|
||||||
// upload the geometry and indices to OpenGL VBO objects
|
// upload the geometry and indices to OpenGL VBO objects
|
||||||
// and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.
|
// and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.
|
||||||
@ -636,11 +697,12 @@ public:
|
|||||||
// Release the geometry data assigned to the volumes.
|
// Release the geometry data assigned to the volumes.
|
||||||
// If OpenGL VBOs were allocated, an OpenGL context has to be active to release them.
|
// If OpenGL VBOs were allocated, an OpenGL context has to be active to release them.
|
||||||
void release_geometry() { for (auto *v : volumes) v->release_geometry(); }
|
void release_geometry() { for (auto *v : volumes) v->release_geometry(); }
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
// Clear the geometry
|
// Clear the geometry
|
||||||
void clear() { for (auto *v : volumes) delete v; volumes.clear(); }
|
void clear() { for (auto *v : volumes) delete v; volumes.clear(); }
|
||||||
|
|
||||||
bool empty() const { return volumes.empty(); }
|
bool empty() const { return volumes.empty(); }
|
||||||
void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); }
|
void set_range(double low, double high) { for (GLVolume* vol : this->volumes) vol->set_range(low, high); }
|
||||||
|
|
||||||
void set_print_volume(const PrintVolume& print_volume) { m_print_volume = print_volume; }
|
void set_print_volume(const PrintVolume& print_volume) { m_print_volume = print_volume; }
|
||||||
|
|
||||||
@ -685,9 +747,18 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
|
|||||||
|
|
||||||
struct _3DScene
|
struct _3DScene
|
||||||
{
|
{
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GUI::GLModel::Geometry& geometry);
|
||||||
|
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GUI::GLModel::Geometry& geometry);
|
||||||
|
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
|
||||||
|
static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
|
||||||
|
static void extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
|
||||||
|
static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
|
||||||
|
static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
|
||||||
|
#else
|
||||||
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
|
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
|
||||||
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
|
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
|
||||||
static void extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume);
|
static void extrusionentity_to_verts(const Polyline& polyline, float width, float height, float print_z, GLVolume& volume);
|
||||||
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume);
|
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume);
|
||||||
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume);
|
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume);
|
||||||
static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume);
|
static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume);
|
||||||
@ -696,6 +767,7 @@ struct _3DScene
|
|||||||
static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GLVolume& volume);
|
static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GLVolume& volume);
|
||||||
static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume);
|
static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume);
|
||||||
static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume);
|
static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -165,17 +165,6 @@ void BackgroundSlicingProcess::process_fff()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_thumbnail(Zipper& zipper, const ThumbnailData& data)
|
|
||||||
{
|
|
||||||
size_t png_size = 0;
|
|
||||||
void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1);
|
|
||||||
if (png_data != nullptr)
|
|
||||||
{
|
|
||||||
zipper.add_entry("thumbnail/thumbnail" + std::to_string(data.width) + "x" + std::to_string(data.height) + ".png", (const std::uint8_t*)png_data, png_size);
|
|
||||||
mz_free(png_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackgroundSlicingProcess::process_sla()
|
void BackgroundSlicingProcess::process_sla()
|
||||||
{
|
{
|
||||||
assert(m_print == m_sla_print);
|
assert(m_print == m_sla_print);
|
||||||
@ -189,12 +178,7 @@ void BackgroundSlicingProcess::process_sla()
|
|||||||
ThumbnailsList thumbnails = this->render_thumbnails(
|
ThumbnailsList thumbnails = this->render_thumbnails(
|
||||||
ThumbnailsParams{current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true});
|
ThumbnailsParams{current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true});
|
||||||
|
|
||||||
Zipper zipper(export_path);
|
m_sla_print->export_print(export_path, thumbnails);
|
||||||
m_sla_print->export_print(zipper);
|
|
||||||
for (const ThumbnailData& data : thumbnails)
|
|
||||||
if (data.is_valid())
|
|
||||||
write_thumbnail(zipper, data);
|
|
||||||
zipper.finalize();
|
|
||||||
|
|
||||||
m_print->set_status(100, (boost::format(_utf8(L("Masked SLA file exported to %1%"))) % export_path).str());
|
m_print->set_status(100, (boost::format(_utf8(L("Masked SLA file exported to %1%"))) % export_path).str());
|
||||||
} else if (! m_upload_job.empty()) {
|
} else if (! m_upload_job.empty()) {
|
||||||
@ -739,13 +723,7 @@ void BackgroundSlicingProcess::prepare_upload()
|
|||||||
|
|
||||||
ThumbnailsList thumbnails = this->render_thumbnails(
|
ThumbnailsList thumbnails = this->render_thumbnails(
|
||||||
ThumbnailsParams{current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true});
|
ThumbnailsParams{current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true});
|
||||||
// true, false, true, true); // renders also supports and pad
|
m_sla_print->export_print(source_path.string(),thumbnails, m_upload_job.upload_data.upload_path.string());
|
||||||
Zipper zipper{source_path.string()};
|
|
||||||
m_sla_print->export_print(zipper, m_upload_job.upload_data.upload_path.string());
|
|
||||||
for (const ThumbnailData& data : thumbnails)
|
|
||||||
if (data.is_valid())
|
|
||||||
write_thumbnail(zipper, data);
|
|
||||||
zipper.finalize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str());
|
m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str());
|
||||||
|
@ -103,7 +103,11 @@ void GCodeViewer::IBuffer::reset()
|
|||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
bool GCodeViewer::Path::matches(const GCodeProcessorResult::MoveVertex& move, bool account_for_volumetric_rate) const
|
||||||
|
#else
|
||||||
bool GCodeViewer::Path::matches(const GCodeProcessorResult::MoveVertex& move) const
|
bool GCodeViewer::Path::matches(const GCodeProcessorResult::MoveVertex& move) const
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
{
|
{
|
||||||
auto matches_percent = [](float value1, float value2, float max_percent) {
|
auto matches_percent = [](float value1, float value2, float max_percent) {
|
||||||
return std::abs(value2 - value1) / value1 <= max_percent;
|
return std::abs(value2 - value1) / value1 <= max_percent;
|
||||||
@ -120,10 +124,22 @@ bool GCodeViewer::Path::matches(const GCodeProcessorResult::MoveVertex& move) co
|
|||||||
case EMoveType::Seam:
|
case EMoveType::Seam:
|
||||||
case EMoveType::Extrude: {
|
case EMoveType::Extrude: {
|
||||||
// use rounding to reduce the number of generated paths
|
// use rounding to reduce the number of generated paths
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
if (account_for_volumetric_rate)
|
||||||
|
return type == move.type && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id && role == move.extrusion_role &&
|
||||||
|
move.position.z() <= sub_paths.front().first.position.z() && feedrate == move.feedrate && fan_speed == move.fan_speed &&
|
||||||
|
height == round_to_bin(move.height) && width == round_to_bin(move.width) &&
|
||||||
|
matches_percent(volumetric_rate, move.volumetric_rate(), 0.001f);
|
||||||
|
else
|
||||||
|
return type == move.type && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id && role == move.extrusion_role &&
|
||||||
|
move.position.z() <= sub_paths.front().first.position.z() && feedrate == move.feedrate && fan_speed == move.fan_speed &&
|
||||||
|
height == round_to_bin(move.height) && width == round_to_bin(move.width);
|
||||||
|
#else
|
||||||
return type == move.type && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id && role == move.extrusion_role &&
|
return type == move.type && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id && role == move.extrusion_role &&
|
||||||
move.position.z() <= sub_paths.front().first.position.z() && feedrate == move.feedrate && fan_speed == move.fan_speed &&
|
move.position.z() <= sub_paths.front().first.position.z() && feedrate == move.feedrate && fan_speed == move.fan_speed &&
|
||||||
height == round_to_bin(move.height) && width == round_to_bin(move.width) &&
|
height == round_to_bin(move.height) && width == round_to_bin(move.width) &&
|
||||||
matches_percent(volumetric_rate, move.volumetric_rate(), 0.05f);
|
matches_percent(volumetric_rate, move.volumetric_rate(), 0.05f);
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
}
|
}
|
||||||
case EMoveType::Travel: {
|
case EMoveType::Travel: {
|
||||||
return type == move.type && feedrate == move.feedrate && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id;
|
return type == move.type && feedrate == move.feedrate && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id;
|
||||||
@ -695,13 +711,26 @@ void GCodeViewer::init()
|
|||||||
m_gl_data_initialized = true;
|
m_gl_data_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print)
|
||||||
|
#else
|
||||||
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized)
|
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized)
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
{
|
{
|
||||||
// avoid processing if called with the same gcode_result
|
// avoid processing if called with the same gcode_result
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
if (m_last_result_id == gcode_result.id &&
|
||||||
|
(m_last_view_type == m_view_type || (m_last_view_type != EViewType::VolumetricRate && m_view_type != EViewType::VolumetricRate)))
|
||||||
|
return;
|
||||||
|
#else
|
||||||
if (m_last_result_id == gcode_result.id)
|
if (m_last_result_id == gcode_result.id)
|
||||||
return;
|
return;
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
|
||||||
m_last_result_id = gcode_result.id;
|
m_last_result_id = gcode_result.id;
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
m_last_view_type = m_view_type;
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
|
||||||
// release gpu memory, if used
|
// release gpu memory, if used
|
||||||
reset();
|
reset();
|
||||||
@ -725,7 +754,11 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr
|
|||||||
m_filament_densities = gcode_result.filament_densities;
|
m_filament_densities = gcode_result.filament_densities;
|
||||||
|
|
||||||
if (wxGetApp().is_editor())
|
if (wxGetApp().is_editor())
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
load_shells(print);
|
||||||
|
#else
|
||||||
load_shells(print, initialized);
|
load_shells(print, initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
else {
|
else {
|
||||||
Pointfs bed_shape;
|
Pointfs bed_shape;
|
||||||
std::string texture;
|
std::string texture;
|
||||||
@ -1266,9 +1299,15 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
// add current vertex
|
// add current vertex
|
||||||
add_vertex(curr);
|
add_vertex(curr);
|
||||||
};
|
};
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
auto add_indices_as_line = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer,
|
||||||
|
unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id, bool account_for_volumetric_rate) {
|
||||||
|
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr, account_for_volumetric_rate)) {
|
||||||
|
#else
|
||||||
auto add_indices_as_line = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer,
|
auto add_indices_as_line = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer,
|
||||||
unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id) {
|
unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id) {
|
||||||
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) {
|
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) {
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
// add starting index
|
// add starting index
|
||||||
indices.push_back(static_cast<IBufferType>(indices.size()));
|
indices.push_back(static_cast<IBufferType>(indices.size()));
|
||||||
buffer.add_path(curr, ibuffer_id, indices.size() - 1, move_id - 1);
|
buffer.add_path(curr, ibuffer_id, indices.size() - 1, move_id - 1);
|
||||||
@ -1287,7 +1326,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
};
|
};
|
||||||
|
|
||||||
// format data into the buffers to be rendered as solid
|
// format data into the buffers to be rendered as solid
|
||||||
auto add_vertices_as_solid = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer, unsigned int vbuffer_id, VertexBuffer& vertices, size_t move_id) {
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
auto add_vertices_as_solid = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer,
|
||||||
|
unsigned int vbuffer_id, VertexBuffer& vertices, size_t move_id, bool account_for_volumetric_rate) {
|
||||||
|
#else
|
||||||
|
auto add_vertices_as_solid = [](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, TBuffer& buffer,
|
||||||
|
unsigned int vbuffer_id, VertexBuffer& vertices, size_t move_id) {
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
auto store_vertex = [](VertexBuffer& vertices, const Vec3f& position, const Vec3f& normal) {
|
auto store_vertex = [](VertexBuffer& vertices, const Vec3f& position, const Vec3f& normal) {
|
||||||
// append position
|
// append position
|
||||||
vertices.push_back(position.x());
|
vertices.push_back(position.x());
|
||||||
@ -1299,7 +1344,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
vertices.push_back(normal.z());
|
vertices.push_back(normal.z());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr, account_for_volumetric_rate)) {
|
||||||
|
#else
|
||||||
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) {
|
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) {
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
buffer.add_path(curr, vbuffer_id, vertices.size(), move_id - 1);
|
buffer.add_path(curr, vbuffer_id, vertices.size(), move_id - 1);
|
||||||
buffer.paths.back().sub_paths.back().first.position = prev.position;
|
buffer.paths.back().sub_paths.back().first.position = prev.position;
|
||||||
}
|
}
|
||||||
@ -1344,8 +1393,15 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
|
|
||||||
last_path.sub_paths.back().last = { vbuffer_id, vertices.size(), move_id, curr.position };
|
last_path.sub_paths.back().last = { vbuffer_id, vertices.size(), move_id, curr.position };
|
||||||
};
|
};
|
||||||
auto add_indices_as_solid = [&](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr, const GCodeProcessorResult::MoveVertex* next,
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
TBuffer& buffer, size_t& vbuffer_size, unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id) {
|
auto add_indices_as_solid = [&](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr,
|
||||||
|
const GCodeProcessorResult::MoveVertex* next, TBuffer& buffer, size_t& vbuffer_size, unsigned int ibuffer_id,
|
||||||
|
IndexBuffer& indices, size_t move_id, bool account_for_volumetric_rate) {
|
||||||
|
#else
|
||||||
|
auto add_indices_as_solid = [&](const GCodeProcessorResult::MoveVertex& prev, const GCodeProcessorResult::MoveVertex& curr,
|
||||||
|
const GCodeProcessorResult::MoveVertex* next, TBuffer& buffer, size_t& vbuffer_size, unsigned int ibuffer_id,
|
||||||
|
IndexBuffer& indices, size_t move_id) {
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
static Vec3f prev_dir;
|
static Vec3f prev_dir;
|
||||||
static Vec3f prev_up;
|
static Vec3f prev_up;
|
||||||
static float sq_prev_length;
|
static float sq_prev_length;
|
||||||
@ -1390,7 +1446,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
store_triangle(indices, v_offsets[4], v_offsets[5], v_offsets[6]);
|
store_triangle(indices, v_offsets[4], v_offsets[5], v_offsets[6]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr, account_for_volumetric_rate)) {
|
||||||
|
#else
|
||||||
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) {
|
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) {
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
buffer.add_path(curr, ibuffer_id, indices.size(), move_id - 1);
|
buffer.add_path(curr, ibuffer_id, indices.size(), move_id - 1);
|
||||||
buffer.paths.back().sub_paths.back().first.position = prev.position;
|
buffer.paths.back().sub_paths.back().first.position = prev.position;
|
||||||
}
|
}
|
||||||
@ -1474,7 +1534,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
vbuffer_size += 6;
|
vbuffer_size += 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
if (next != nullptr && (curr.type != next->type || !last_path.matches(*next, account_for_volumetric_rate)))
|
||||||
|
#else
|
||||||
if (next != nullptr && (curr.type != next->type || !last_path.matches(*next)))
|
if (next != nullptr && (curr.type != next->type || !last_path.matches(*next)))
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
// ending cap triangles
|
// ending cap triangles
|
||||||
append_ending_cap_triangles(indices, is_first_segment ? first_seg_v_offsets : non_first_seg_v_offsets);
|
append_ending_cap_triangles(indices, is_first_segment ? first_seg_v_offsets : non_first_seg_v_offsets);
|
||||||
|
|
||||||
@ -1614,6 +1678,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
m_sequential_view.gcode_ids.push_back(move.gcode_id);
|
m_sequential_view.gcode_ids.push_back(move.gcode_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
bool account_for_volumetric_rate = m_view_type == EViewType::VolumetricRate;
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
|
||||||
std::vector<MultiVertexBuffer> vertices(m_buffers.size());
|
std::vector<MultiVertexBuffer> vertices(m_buffers.size());
|
||||||
std::vector<MultiIndexBuffer> indices(m_buffers.size());
|
std::vector<MultiIndexBuffer> indices(m_buffers.size());
|
||||||
std::vector<InstanceBuffer> instances(m_buffers.size());
|
std::vector<InstanceBuffer> instances(m_buffers.size());
|
||||||
@ -1678,7 +1746,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
v_multibuffer.push_back(VertexBuffer());
|
v_multibuffer.push_back(VertexBuffer());
|
||||||
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle) {
|
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle) {
|
||||||
Path& last_path = t_buffer.paths.back();
|
Path& last_path = t_buffer.paths.back();
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
if (prev.type == curr.type && last_path.matches(curr, account_for_volumetric_rate))
|
||||||
|
#else
|
||||||
if (prev.type == curr.type && last_path.matches(curr))
|
if (prev.type == curr.type && last_path.matches(curr))
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
last_path.add_sub_path(prev, static_cast<unsigned int>(v_multibuffer.size()) - 1, 0, move_id - 1);
|
last_path.add_sub_path(prev, static_cast<unsigned int>(v_multibuffer.size()) - 1, 0, move_id - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1689,7 +1761,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
{
|
{
|
||||||
case TBuffer::ERenderPrimitiveType::Point: { add_vertices_as_point(curr, v_buffer); break; }
|
case TBuffer::ERenderPrimitiveType::Point: { add_vertices_as_point(curr, v_buffer); break; }
|
||||||
case TBuffer::ERenderPrimitiveType::Line: { add_vertices_as_line(prev, curr, v_buffer); break; }
|
case TBuffer::ERenderPrimitiveType::Line: { add_vertices_as_line(prev, curr, v_buffer); break; }
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast<unsigned int>(v_multibuffer.size()) - 1, v_buffer, move_id, account_for_volumetric_rate); break; }
|
||||||
|
#else
|
||||||
case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast<unsigned int>(v_multibuffer.size()) - 1, v_buffer, move_id); break; }
|
case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast<unsigned int>(v_multibuffer.size()) - 1, v_buffer, move_id); break; }
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
case TBuffer::ERenderPrimitiveType::InstancedModel:
|
case TBuffer::ERenderPrimitiveType::InstancedModel:
|
||||||
{
|
{
|
||||||
add_model_instance(curr, inst_buffer, inst_id_buffer, move_id);
|
add_model_instance(curr, inst_buffer, inst_id_buffer, move_id);
|
||||||
@ -2053,12 +2129,20 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TBuffer::ERenderPrimitiveType::Line: {
|
case TBuffer::ERenderPrimitiveType::Line: {
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
add_indices_as_line(prev, curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id, account_for_volumetric_rate);
|
||||||
|
#else
|
||||||
add_indices_as_line(prev, curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id);
|
add_indices_as_line(prev, curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id);
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
curr_vertex_buffer.second += t_buffer.max_vertices_per_segment();
|
curr_vertex_buffer.second += t_buffer.max_vertices_per_segment();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TBuffer::ERenderPrimitiveType::Triangle: {
|
case TBuffer::ERenderPrimitiveType::Triangle: {
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id, account_for_volumetric_rate);
|
||||||
|
#else
|
||||||
add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id);
|
add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id);
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TBuffer::ERenderPrimitiveType::BatchedModel: {
|
case TBuffer::ERenderPrimitiveType::BatchedModel: {
|
||||||
@ -2213,7 +2297,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
progress_dialog->Destroy();
|
progress_dialog->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void GCodeViewer::load_shells(const Print& print)
|
||||||
|
#else
|
||||||
void GCodeViewer::load_shells(const Print& print, bool initialized)
|
void GCodeViewer::load_shells(const Print& print, bool initialized)
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
{
|
{
|
||||||
if (print.objects().empty())
|
if (print.objects().empty())
|
||||||
// no shells, return
|
// no shells, return
|
||||||
@ -2230,7 +2318,11 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t current_volumes_count = m_shells.volumes.volumes.size();
|
size_t current_volumes_count = m_shells.volumes.volumes.size();
|
||||||
m_shells.volumes.load_object(model_obj, object_id, instance_ids, "object", initialized);
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
m_shells.volumes.load_object(model_obj, object_id, instance_ids);
|
||||||
|
#else
|
||||||
|
m_shells.volumes.load_object(model_obj, object_id, instance_ids, initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
// adjust shells' z if raft is present
|
// adjust shells' z if raft is present
|
||||||
const SlicingParameters& slicing_parameters = obj->slicing_parameters();
|
const SlicingParameters& slicing_parameters = obj->slicing_parameters();
|
||||||
@ -2254,6 +2346,15 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
|
|||||||
const float depth = print.wipe_tower_data(extruders_count).depth;
|
const float depth = print.wipe_tower_data(extruders_count).depth;
|
||||||
const float brim_width = print.wipe_tower_data(extruders_count).brim_width;
|
const float brim_width = print.wipe_tower_data(extruders_count).brim_width;
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||||
|
!print.is_step_done(psWipeTower), brim_width);
|
||||||
|
#else
|
||||||
|
m_shells.volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||||
|
!print.is_step_done(psWipeTower), brim_width);
|
||||||
|
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
#else
|
||||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||||
!print.is_step_done(psWipeTower), brim_width, initialized);
|
!print.is_step_done(psWipeTower), brim_width, initialized);
|
||||||
@ -2261,6 +2362,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
|
|||||||
m_shells.volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
m_shells.volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||||
!print.is_step_done(psWipeTower), brim_width, initialized);
|
!print.is_step_done(psWipeTower), brim_width, initialized);
|
||||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3123,6 +3225,7 @@ void GCodeViewer::render_shells()
|
|||||||
if (shader == nullptr)
|
if (shader == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
// when the background processing is enabled, it may happen that the shells data have been loaded
|
// when the background processing is enabled, it may happen that the shells data have been loaded
|
||||||
// before opengl has been initialized for the preview canvas.
|
// before opengl has been initialized for the preview canvas.
|
||||||
// when this happens, the volumes' data have not been sent to gpu yet.
|
// when this happens, the volumes' data have not been sent to gpu yet.
|
||||||
@ -3130,6 +3233,7 @@ void GCodeViewer::render_shells()
|
|||||||
if (!v->indexed_vertex_array.has_VBOs())
|
if (!v->indexed_vertex_array.has_VBOs())
|
||||||
v->finalize_geometry(true);
|
v->finalize_geometry(true);
|
||||||
}
|
}
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
// glsafe(::glDepthMask(GL_FALSE));
|
// glsafe(::glDepthMask(GL_FALSE));
|
||||||
|
|
||||||
|
@ -212,7 +212,11 @@ class GCodeViewer
|
|||||||
unsigned char cp_color_id{ 0 };
|
unsigned char cp_color_id{ 0 };
|
||||||
std::vector<Sub_Path> sub_paths;
|
std::vector<Sub_Path> sub_paths;
|
||||||
|
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
bool matches(const GCodeProcessorResult::MoveVertex& move, bool account_for_volumetric_rate) const;
|
||||||
|
#else
|
||||||
bool matches(const GCodeProcessorResult::MoveVertex& move) const;
|
bool matches(const GCodeProcessorResult::MoveVertex& move) const;
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
size_t vertices_count() const {
|
size_t vertices_count() const {
|
||||||
return sub_paths.empty() ? 0 : sub_paths.back().last.s_id - sub_paths.front().first.s_id + 1;
|
return sub_paths.empty() ? 0 : sub_paths.back().last.s_id - sub_paths.front().first.s_id + 1;
|
||||||
}
|
}
|
||||||
@ -762,6 +766,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool m_gl_data_initialized{ false };
|
bool m_gl_data_initialized{ false };
|
||||||
unsigned int m_last_result_id{ 0 };
|
unsigned int m_last_result_id{ 0 };
|
||||||
|
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
|
EViewType m_last_view_type{ EViewType::Count };
|
||||||
|
#endif // ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
|
||||||
size_t m_moves_count{ 0 };
|
size_t m_moves_count{ 0 };
|
||||||
std::vector<TBuffer> m_buffers{ static_cast<size_t>(EMoveType::Extrude) };
|
std::vector<TBuffer> m_buffers{ static_cast<size_t>(EMoveType::Extrude) };
|
||||||
// bounding box of toolpaths
|
// bounding box of toolpaths
|
||||||
@ -816,7 +823,11 @@ public:
|
|||||||
void init();
|
void init();
|
||||||
|
|
||||||
// extract rendering data from the given parameters
|
// extract rendering data from the given parameters
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void load(const GCodeProcessorResult& gcode_result, const Print& print);
|
||||||
|
#else
|
||||||
void load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized);
|
void load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
// recalculate ranges in dependence of what is visible and sets tool/print colors
|
// recalculate ranges in dependence of what is visible and sets tool/print colors
|
||||||
void refresh(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors);
|
void refresh(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors);
|
||||||
#if ENABLE_PREVIEW_LAYOUT
|
#if ENABLE_PREVIEW_LAYOUT
|
||||||
@ -876,7 +887,11 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void load_toolpaths(const GCodeProcessorResult& gcode_result);
|
void load_toolpaths(const GCodeProcessorResult& gcode_result);
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void load_shells(const Print& print);
|
||||||
|
#else
|
||||||
void load_shells(const Print& print, bool initialized);
|
void load_shells(const Print& print, bool initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
#if !ENABLE_PREVIEW_LAYOUT
|
#if !ENABLE_PREVIEW_LAYOUT
|
||||||
void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const;
|
void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const;
|
||||||
#endif // !ENABLE_PREVIEW_LAYOUT
|
#endif // !ENABLE_PREVIEW_LAYOUT
|
||||||
|
@ -87,9 +87,11 @@ static const Slic3r::ColorRGB ERROR_BG_LIGHT_COLOR = { 0.753f, 0.192f, 0.039f
|
|||||||
// Number of floats
|
// Number of floats
|
||||||
static constexpr const size_t MAX_VERTEX_BUFFER_SIZE = 131072 * 6; // 3.15MB
|
static constexpr const size_t MAX_VERTEX_BUFFER_SIZE = 131072 * 6; // 3.15MB
|
||||||
// Reserve size in number of floats.
|
// Reserve size in number of floats.
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
static constexpr const size_t VERTEX_BUFFER_RESERVE_SIZE = 131072 * 2; // 1.05MB
|
static constexpr const size_t VERTEX_BUFFER_RESERVE_SIZE = 131072 * 2; // 1.05MB
|
||||||
// Reserve size in number of floats, maximum sum of all preallocated buffers.
|
// Reserve size in number of floats, maximum sum of all preallocated buffers.
|
||||||
//static constexpr const size_t VERTEX_BUFFER_RESERVE_SIZE_SUM_MAX = 1024 * 1024 * 128 / 4; // 128MB
|
//static constexpr const size_t VERTEX_BUFFER_RESERVE_SIZE_SUM_MAX = 1024 * 1024 * 128 / 4; // 128MB
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
@ -447,8 +449,7 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect)
|
|||||||
m_profile.profile.reset();
|
m_profile.profile.reset();
|
||||||
|
|
||||||
GLModel::Geometry init_data;
|
GLModel::Geometry init_data;
|
||||||
const GLModel::Geometry::EIndexType index_type = (m_layer_height_profile.size() / 2 < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT;
|
init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, GLModel::Geometry::index_type(m_layer_height_profile.size() / 2) };
|
||||||
init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P2, index_type };
|
|
||||||
init_data.color = ColorRGBA::BLUE();
|
init_data.color = ColorRGBA::BLUE();
|
||||||
init_data.reserve_vertices(m_layer_height_profile.size() / 2);
|
init_data.reserve_vertices(m_layer_height_profile.size() / 2);
|
||||||
init_data.reserve_indices(m_layer_height_profile.size() / 2);
|
init_data.reserve_indices(m_layer_height_profile.size() / 2);
|
||||||
@ -457,7 +458,7 @@ void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect)
|
|||||||
for (unsigned int i = 0; i < (unsigned int)m_layer_height_profile.size(); i += 2) {
|
for (unsigned int i = 0; i < (unsigned int)m_layer_height_profile.size(); i += 2) {
|
||||||
init_data.add_vertex(Vec2f(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x,
|
init_data.add_vertex(Vec2f(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x,
|
||||||
bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y));
|
bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y));
|
||||||
if (index_type == GLModel::Geometry::EIndexType::USHORT)
|
if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||||
init_data.add_ushort_index((unsigned short)i / 2);
|
init_data.add_ushort_index((unsigned short)i / 2);
|
||||||
else
|
else
|
||||||
init_data.add_uint_index(i / 2);
|
init_data.add_uint_index(i / 2);
|
||||||
@ -496,17 +497,17 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G
|
|||||||
{
|
{
|
||||||
assert(this->is_allowed());
|
assert(this->is_allowed());
|
||||||
assert(this->last_object_id != -1);
|
assert(this->last_object_id != -1);
|
||||||
|
|
||||||
|
GLShaderProgram* current_shader = wxGetApp().get_current_shader();
|
||||||
|
ScopeGuard guard([current_shader]() { if (current_shader != nullptr) current_shader->start_using(); });
|
||||||
|
if (current_shader != nullptr)
|
||||||
|
current_shader->stop_using();
|
||||||
|
|
||||||
GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height");
|
GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height");
|
||||||
if (shader == nullptr)
|
if (shader == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GLShaderProgram* current_shader = wxGetApp().get_current_shader();
|
shader->start_using();
|
||||||
if (shader->get_id() != current_shader->get_id())
|
|
||||||
// The layer editing shader is not yet active. Activate it.
|
|
||||||
shader->start_using();
|
|
||||||
else
|
|
||||||
// The layer editing shader was already active.
|
|
||||||
current_shader = nullptr;
|
|
||||||
|
|
||||||
generate_layer_height_texture();
|
generate_layer_height_texture();
|
||||||
|
|
||||||
@ -517,29 +518,27 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G
|
|||||||
shader->set_uniform("z_cursor_band_width", float(this->band_width));
|
shader->set_uniform("z_cursor_band_width", float(this->band_width));
|
||||||
|
|
||||||
// Initialize the layer height texture mapping.
|
// Initialize the layer height texture mapping.
|
||||||
GLsizei w = (GLsizei)m_layers_texture.width;
|
const GLsizei w = (GLsizei)m_layers_texture.width;
|
||||||
GLsizei h = (GLsizei)m_layers_texture.height;
|
const GLsizei h = (GLsizei)m_layers_texture.height;
|
||||||
GLsizei half_w = w / 2;
|
const GLsizei half_w = w / 2;
|
||||||
GLsizei half_h = h / 2;
|
const GLsizei half_h = h / 2;
|
||||||
glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id));
|
glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id));
|
||||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
|
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
|
||||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
|
glsafe(::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
|
||||||
glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data()));
|
glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data()));
|
||||||
glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4));
|
glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4));
|
||||||
for (const GLVolume* glvolume : volumes.volumes) {
|
for (GLVolume* glvolume : volumes.volumes) {
|
||||||
// Render the object using the layer editing shader and texture.
|
// Render the object using the layer editing shader and texture.
|
||||||
if (! glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier)
|
if (!glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
shader->set_uniform("volume_world_matrix", glvolume->world_matrix());
|
shader->set_uniform("volume_world_matrix", glvolume->world_matrix());
|
||||||
shader->set_uniform("object_max_z", GLfloat(0));
|
shader->set_uniform("object_max_z", 0.0f);
|
||||||
glvolume->render();
|
glvolume->render();
|
||||||
}
|
}
|
||||||
// Revert back to the previous shader.
|
// Revert back to the previous shader.
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
if (current_shader != nullptr)
|
|
||||||
current_shader->start_using();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::LayersEditing::adjust_layer_height_profile()
|
void GLCanvas3D::LayersEditing::adjust_layer_height_profile()
|
||||||
@ -1107,7 +1106,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
|
|||||||
, m_moving(false)
|
, m_moving(false)
|
||||||
, m_tab_down(false)
|
, m_tab_down(false)
|
||||||
, m_cursor_type(Standard)
|
, m_cursor_type(Standard)
|
||||||
, m_color_by("volume")
|
|
||||||
, m_reload_delayed(false)
|
, m_reload_delayed(false)
|
||||||
#if ENABLE_RENDER_PICKING_PASS
|
#if ENABLE_RENDER_PICKING_PASS
|
||||||
, m_show_picking_texture(false)
|
, m_show_picking_texture(false)
|
||||||
@ -1158,6 +1156,7 @@ bool GLCanvas3D::init()
|
|||||||
glsafe(::glEnable(GL_BLEND));
|
glsafe(::glEnable(GL_BLEND));
|
||||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||||
|
|
||||||
|
#if !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
// Set antialiasing / multisampling
|
// Set antialiasing / multisampling
|
||||||
glsafe(::glDisable(GL_LINE_SMOOTH));
|
glsafe(::glDisable(GL_LINE_SMOOTH));
|
||||||
glsafe(::glDisable(GL_POLYGON_SMOOTH));
|
glsafe(::glDisable(GL_POLYGON_SMOOTH));
|
||||||
@ -1187,6 +1186,7 @@ bool GLCanvas3D::init()
|
|||||||
// A handy trick -- have surface material mirror the color.
|
// A handy trick -- have surface material mirror the color.
|
||||||
glsafe(::glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE));
|
glsafe(::glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE));
|
||||||
glsafe(::glEnable(GL_COLOR_MATERIAL));
|
glsafe(::glEnable(GL_COLOR_MATERIAL));
|
||||||
|
#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
|
||||||
if (m_multisample_allowed)
|
if (m_multisample_allowed)
|
||||||
glsafe(::glEnable(GL_MULTISAMPLE));
|
glsafe(::glEnable(GL_MULTISAMPLE));
|
||||||
@ -1194,9 +1194,11 @@ bool GLCanvas3D::init()
|
|||||||
if (m_main_toolbar.is_enabled())
|
if (m_main_toolbar.is_enabled())
|
||||||
m_layers_editing.init();
|
m_layers_editing.init();
|
||||||
|
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
// on linux the gl context is not valid until the canvas is not shown on screen
|
// on linux the gl context is not valid until the canvas is not shown on screen
|
||||||
// we defer the geometry finalization of volumes until the first call to render()
|
// we defer the geometry finalization of volumes until the first call to render()
|
||||||
m_volumes.finalize_geometry(true);
|
m_volumes.finalize_geometry(true);
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
if (m_gizmos.is_enabled() && !m_gizmos.init())
|
if (m_gizmos.is_enabled() && !m_gizmos.init())
|
||||||
std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl;
|
std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl;
|
||||||
@ -1357,11 +1359,6 @@ void GLCanvas3D::bed_shape_changed()
|
|||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::set_color_by(const std::string& value)
|
|
||||||
{
|
|
||||||
m_color_by = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLCanvas3D::refresh_camera_scene_box()
|
void GLCanvas3D::refresh_camera_scene_box()
|
||||||
{
|
{
|
||||||
wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box());
|
wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box());
|
||||||
@ -1806,7 +1803,11 @@ std::vector<int> GLCanvas3D::load_object(const ModelObject& model_object, int ob
|
|||||||
instance_idxs.emplace_back(i);
|
instance_idxs.emplace_back(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_initialized);
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
return m_volumes.load_object(&model_object, obj_idx, instance_idxs);
|
||||||
|
#else
|
||||||
|
return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
|
std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
|
||||||
@ -2031,7 +2032,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||||||
// Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh
|
// Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh
|
||||||
// later in this function.
|
// later in this function.
|
||||||
it->volume_idx = m_volumes.volumes.size();
|
it->volume_idx = m_volumes.volumes.size();
|
||||||
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized);
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx);
|
||||||
|
#else
|
||||||
|
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
m_volumes.volumes.back()->geometry_id = key.geometry_id;
|
m_volumes.volumes.back()->geometry_id = key.geometry_id;
|
||||||
update_object_list = true;
|
update_object_list = true;
|
||||||
} else {
|
} else {
|
||||||
@ -2088,31 +2093,55 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||||||
GLVolume &volume = *m_volumes.volumes[it->volume_idx];
|
GLVolume &volume = *m_volumes.volumes[it->volume_idx];
|
||||||
if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) {
|
if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) {
|
||||||
// The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen.
|
// The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen.
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
volume.model.reset();
|
||||||
|
#else
|
||||||
volume.indexed_vertex_array.release_geometry();
|
volume.indexed_vertex_array.release_geometry();
|
||||||
if (state.step[istep].state == PrintStateBase::DONE) {
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
if (state.step[istep].state == PrintStateBase::DONE) {
|
||||||
TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles);
|
TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles);
|
||||||
assert(! mesh.empty());
|
assert(! mesh.empty());
|
||||||
mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse());
|
mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse());
|
||||||
#if ENABLE_SMOOTH_NORMALS
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
volume.model.init_from(mesh, true);
|
||||||
|
#else
|
||||||
volume.indexed_vertex_array.load_mesh(mesh, true);
|
volume.indexed_vertex_array.load_mesh(mesh, true);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#else
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
volume.model.init_from(mesh);
|
||||||
#else
|
#else
|
||||||
volume.indexed_vertex_array.load_mesh(mesh);
|
volume.indexed_vertex_array.load_mesh(mesh);
|
||||||
#endif // ENABLE_SMOOTH_NORMALS
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
} else {
|
|
||||||
// Reload the original volume.
|
|
||||||
#if ENABLE_SMOOTH_NORMALS
|
|
||||||
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
|
|
||||||
#else
|
|
||||||
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
|
|
||||||
#endif // ENABLE_SMOOTH_NORMALS
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// Reload the original volume.
|
||||||
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
|
||||||
|
#else
|
||||||
|
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#else
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
|
||||||
|
#else
|
||||||
|
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
}
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
volume.finalize_geometry(true);
|
volume.finalize_geometry(true);
|
||||||
}
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
}
|
||||||
//FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable
|
//FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable
|
||||||
// to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables
|
// to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables
|
||||||
// of various concenrs (model vs. 3D print path).
|
// of various concenrs (model vs. 3D print path).
|
||||||
volume.offsets = { state.step[istep].timestamp };
|
volume.offsets = { state.step[istep].timestamp };
|
||||||
} else if (state.step[istep].state == PrintStateBase::DONE) {
|
}
|
||||||
|
else if (state.step[istep].state == PrintStateBase::DONE) {
|
||||||
// Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created.
|
// Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created.
|
||||||
ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
|
ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
|
||||||
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
|
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
|
||||||
@ -2124,7 +2153,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||||||
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
|
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
|
||||||
else
|
else
|
||||||
shift_zs[object_idx] = 0.;
|
shift_zs[object_idx] = 0.;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
|
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
|
||||||
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
|
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
|
||||||
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
|
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
|
||||||
@ -2134,7 +2164,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||||||
|
|
||||||
for (size_t istep = 0; istep < sla_steps.size(); ++istep)
|
for (size_t istep = 0; istep < sla_steps.size(); ++istep)
|
||||||
if (!instances[istep].empty())
|
if (!instances[istep].empty())
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
|
||||||
|
#else
|
||||||
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized);
|
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
|
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
|
||||||
@ -2164,6 +2198,17 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||||||
float depth = print->wipe_tower_data(extruders_count).depth;
|
float depth = print->wipe_tower_data(extruders_count).depth;
|
||||||
float brim_width = print->wipe_tower_data(extruders_count).brim_width;
|
float brim_width = print->wipe_tower_data(extruders_count).brim_width;
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
||||||
|
x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
||||||
|
brim_width);
|
||||||
|
#else
|
||||||
|
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
||||||
|
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
||||||
|
brim_width);
|
||||||
|
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
#else
|
||||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
||||||
x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
||||||
@ -2173,6 +2218,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||||||
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
||||||
brim_width, m_initialized);
|
brim_width, m_initialized);
|
||||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
if (volume_idx_wipe_tower_old != -1)
|
if (volume_idx_wipe_tower_old != -1)
|
||||||
map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new;
|
map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new;
|
||||||
}
|
}
|
||||||
@ -2232,9 +2278,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume& vol_old, bool gl_initialized, size_t prealloc_size = VERTEX_BUFFER_RESERVE_SIZE)
|
static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume& vol_old, bool gl_initialized, size_t prealloc_size = VERTEX_BUFFER_RESERVE_SIZE)
|
||||||
{
|
{
|
||||||
// Assign the large pre-allocated buffers to the new GLVolume.
|
// Assign the large pre-allocated buffers to the new GLVolume.
|
||||||
vol_new.indexed_vertex_array = std::move(vol_old.indexed_vertex_array);
|
vol_new.indexed_vertex_array = std::move(vol_old.indexed_vertex_array);
|
||||||
// Copy the content back to the old GLVolume.
|
// Copy the content back to the old GLVolume.
|
||||||
vol_old.indexed_vertex_array = vol_new.indexed_vertex_array;
|
vol_old.indexed_vertex_array = vol_new.indexed_vertex_array;
|
||||||
@ -2246,10 +2293,15 @@ static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume&
|
|||||||
// Finalize the old geometry, possibly move data to the graphics card.
|
// Finalize the old geometry, possibly move data to the graphics card.
|
||||||
vol_old.finalize_geometry(gl_initialized);
|
vol_old.finalize_geometry(gl_initialized);
|
||||||
}
|
}
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors)
|
void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors)
|
||||||
{
|
{
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
m_gcode_viewer.load(gcode_result, *this->fff_print());
|
||||||
|
#else
|
||||||
m_gcode_viewer.load(gcode_result, *this->fff_print(), m_initialized);
|
m_gcode_viewer.load(gcode_result, *this->fff_print(), m_initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
if (wxGetApp().is_editor()) {
|
if (wxGetApp().is_editor()) {
|
||||||
m_gcode_viewer.update_shells_color_by_extruder(m_config);
|
m_gcode_viewer.update_shells_color_by_extruder(m_config);
|
||||||
@ -4345,7 +4397,11 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
|||||||
shader->set_uniform("emission_factor", 0.0f);
|
shader->set_uniform("emission_factor", 0.0f);
|
||||||
|
|
||||||
for (GLVolume* vol : visible_volumes) {
|
for (GLVolume* vol : visible_volumes) {
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
vol->model.set_color((vol->printable && !vol->is_outside) ? (current_printer_technology() == ptSLA ? vol->color : ColorRGBA::ORANGE()) : ColorRGBA::GRAY());
|
||||||
|
#else
|
||||||
shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? (current_printer_technology() == ptSLA ? vol->color : ColorRGBA::ORANGE()) : ColorRGBA::GRAY());
|
shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? (current_printer_technology() == ptSLA ? vol->color : ColorRGBA::ORANGE()) : ColorRGBA::GRAY());
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
// the volume may have been deactivated by an active gizmo
|
// the volume may have been deactivated by an active gizmo
|
||||||
bool is_active = vol->is_active;
|
bool is_active = vol->is_active;
|
||||||
vol->is_active = true;
|
vol->is_active = true;
|
||||||
@ -5014,9 +5070,9 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be
|
|||||||
|
|
||||||
// clamp max bb size with respect to bed bb size
|
// clamp max bb size with respect to bed bb size
|
||||||
if (!m_picking_enabled) {
|
if (!m_picking_enabled) {
|
||||||
static const double max_scale_factor = 1.5;
|
static const double max_scale_factor = 2.0;
|
||||||
const Vec3d bb_size = bb.size();
|
const Vec3d bb_size = bb.size();
|
||||||
const Vec3d bed_bb_size = bed_bb.size();
|
const Vec3d bed_bb_size = m_bed.build_volume().bounding_volume().size();
|
||||||
if (bb_size.x() > max_scale_factor * bed_bb_size.x() ||
|
if (bb_size.x() > max_scale_factor * bed_bb_size.x() ||
|
||||||
bb_size.y() > max_scale_factor * bed_bb_size.y() ||
|
bb_size.y() > max_scale_factor * bed_bb_size.y() ||
|
||||||
bb_size.z() > max_scale_factor * bed_bb_size.z()) {
|
bb_size.z() > max_scale_factor * bed_bb_size.z()) {
|
||||||
@ -5551,6 +5607,12 @@ void GLCanvas3D::_render_overlays()
|
|||||||
|
|
||||||
void GLCanvas3D::_render_volumes_for_picking() const
|
void GLCanvas3D::_render_volumes_for_picking() const
|
||||||
{
|
{
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||||
|
if (shader == nullptr)
|
||||||
|
return;
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
// do not cull backfaces to show broken geometry, if any
|
// do not cull backfaces to show broken geometry, if any
|
||||||
glsafe(::glDisable(GL_CULL_FACE));
|
glsafe(::glDisable(GL_CULL_FACE));
|
||||||
|
|
||||||
@ -5566,9 +5628,17 @@ void GLCanvas3D::_render_volumes_for_picking() const
|
|||||||
// we reserve color = (0,0,0) for occluders (as the printbed)
|
// we reserve color = (0,0,0) for occluders (as the printbed)
|
||||||
// so we shift volumes' id by 1 to get the proper color
|
// so we shift volumes' id by 1 to get the proper color
|
||||||
const unsigned int id = 1 + volume.second.first;
|
const unsigned int id = 1 + volume.second.first;
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
volume.first->model.set_color(picking_decode(id));
|
||||||
|
shader->start_using();
|
||||||
|
#else
|
||||||
glsafe(::glColor4fv(picking_decode(id).data()));
|
glsafe(::glColor4fv(picking_decode(id).data()));
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
volume.first->render();
|
volume.first->render();
|
||||||
}
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
shader->stop_using();
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
||||||
@ -5783,32 +5853,81 @@ void GLCanvas3D::_render_sla_slices()
|
|||||||
if (!obj->is_step_done(slaposSliceSupports))
|
if (!obj->is_step_done(slaposSliceSupports))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
SlaCap::ObjectIdToModelsMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i);
|
||||||
|
SlaCap::ObjectIdToModelsMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i);
|
||||||
|
#else
|
||||||
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i);
|
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i);
|
||||||
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i);
|
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i);
|
||||||
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
{
|
{
|
||||||
if (it_caps_bottom == m_sla_caps[0].triangles.end())
|
if (it_caps_bottom == m_sla_caps[0].triangles.end())
|
||||||
it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first;
|
it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first;
|
||||||
if (!m_sla_caps[0].matches(clip_min_z)) {
|
if (!m_sla_caps[0].matches(clip_min_z)) {
|
||||||
m_sla_caps[0].z = clip_min_z;
|
m_sla_caps[0].z = clip_min_z;
|
||||||
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
it_caps_bottom->second.object.reset();
|
||||||
|
it_caps_bottom->second.supports.reset();
|
||||||
|
#else
|
||||||
it_caps_bottom->second.object.clear();
|
it_caps_bottom->second.object.clear();
|
||||||
it_caps_bottom->second.supports.clear();
|
it_caps_bottom->second.supports.clear();
|
||||||
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
}
|
}
|
||||||
if (it_caps_top == m_sla_caps[1].triangles.end())
|
if (it_caps_top == m_sla_caps[1].triangles.end())
|
||||||
it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
|
it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
|
||||||
if (!m_sla_caps[1].matches(clip_max_z)) {
|
if (!m_sla_caps[1].matches(clip_max_z)) {
|
||||||
m_sla_caps[1].z = clip_max_z;
|
m_sla_caps[1].z = clip_max_z;
|
||||||
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
it_caps_top->second.object.reset();
|
||||||
|
it_caps_top->second.supports.reset();
|
||||||
|
#else
|
||||||
it_caps_top->second.object.clear();
|
it_caps_top->second.object.clear();
|
||||||
it_caps_top->second.supports.clear();
|
it_caps_top->second.supports.clear();
|
||||||
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
GLModel& bottom_obj_triangles = it_caps_bottom->second.object;
|
||||||
|
GLModel& bottom_sup_triangles = it_caps_bottom->second.supports;
|
||||||
|
GLModel& top_obj_triangles = it_caps_top->second.object;
|
||||||
|
GLModel& top_sup_triangles = it_caps_top->second.supports;
|
||||||
|
#else
|
||||||
Pointf3s &bottom_obj_triangles = it_caps_bottom->second.object;
|
Pointf3s &bottom_obj_triangles = it_caps_bottom->second.object;
|
||||||
Pointf3s &bottom_sup_triangles = it_caps_bottom->second.supports;
|
Pointf3s &bottom_sup_triangles = it_caps_bottom->second.supports;
|
||||||
Pointf3s &top_obj_triangles = it_caps_top->second.object;
|
Pointf3s &top_obj_triangles = it_caps_top->second.object;
|
||||||
Pointf3s &top_sup_triangles = it_caps_top->second.supports;
|
Pointf3s &top_sup_triangles = it_caps_top->second.supports;
|
||||||
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
|
||||||
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
auto init_model = [](GLModel& model, const Pointf3s& triangles, const ColorRGBA& color) {
|
||||||
|
GLModel::Geometry init_data;
|
||||||
|
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(triangles.size()) };
|
||||||
|
init_data.reserve_vertices(triangles.size());
|
||||||
|
init_data.reserve_indices(triangles.size() / 3);
|
||||||
|
init_data.color = color;
|
||||||
|
|
||||||
|
unsigned int vertices_count = 0;
|
||||||
|
for (const Vec3d& v : triangles) {
|
||||||
|
init_data.add_vertex((Vec3f)v.cast<float>());
|
||||||
|
++vertices_count;
|
||||||
|
if (vertices_count % 3 == 0) {
|
||||||
|
if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||||
|
init_data.add_ushort_triangle((unsigned short)vertices_count - 3, (unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1);
|
||||||
|
else
|
||||||
|
init_data.add_uint_triangle(vertices_count - 3, vertices_count - 2, vertices_count - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!init_data.is_empty())
|
||||||
|
model.init_from(std::move(init_data));
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((!bottom_obj_triangles.is_initialized() || !bottom_sup_triangles.is_initialized() ||
|
||||||
|
!top_obj_triangles.is_initialized() || !top_sup_triangles.is_initialized()) && !obj->get_slice_index().empty()) {
|
||||||
|
#else
|
||||||
if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) &&
|
if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) &&
|
||||||
!obj->get_slice_index().empty())
|
!obj->get_slice_index().empty()) {
|
||||||
{
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
double layer_height = print->default_object_config().layer_height.value;
|
double layer_height = print->default_object_config().layer_height.value;
|
||||||
double initial_layer_height = print->material_config().initial_layer_height.value;
|
double initial_layer_height = print->material_config().initial_layer_height.value;
|
||||||
bool left_handed = obj->is_left_handed();
|
bool left_handed = obj->is_left_handed();
|
||||||
@ -5823,39 +5942,81 @@ void GLCanvas3D::_render_sla_slices()
|
|||||||
const SliceRecord& slice_high = obj->closest_slice_to_print_level(key_high, coord_t(SCALED_EPSILON));
|
const SliceRecord& slice_high = obj->closest_slice_to_print_level(key_high, coord_t(SCALED_EPSILON));
|
||||||
|
|
||||||
// Offset to avoid OpenGL Z fighting between the object's horizontal surfaces and the triangluated surfaces of the cuts.
|
// Offset to avoid OpenGL Z fighting between the object's horizontal surfaces and the triangluated surfaces of the cuts.
|
||||||
double plane_shift_z = 0.002;
|
const double plane_shift_z = 0.002;
|
||||||
|
|
||||||
if (slice_low.is_valid()) {
|
if (slice_low.is_valid()) {
|
||||||
const ExPolygons& obj_bottom = slice_low.get_slice(soModel);
|
const ExPolygons& obj_bottom = slice_low.get_slice(soModel);
|
||||||
const ExPolygons& sup_bottom = slice_low.get_slice(soSupport);
|
const ExPolygons& sup_bottom = slice_low.get_slice(soSupport);
|
||||||
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
// calculate model bottom cap
|
||||||
|
if (!bottom_obj_triangles.is_initialized() && !obj_bottom.empty())
|
||||||
|
init_model(bottom_obj_triangles, triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, !left_handed), { 1.0f, 0.37f, 0.0f, 1.0f });
|
||||||
|
// calculate support bottom cap
|
||||||
|
if (!bottom_sup_triangles.is_initialized() && !sup_bottom.empty())
|
||||||
|
init_model(bottom_sup_triangles, triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, !left_handed), { 1.0f, 0.0f, 0.37f, 1.0f });
|
||||||
|
#else
|
||||||
// calculate model bottom cap
|
// calculate model bottom cap
|
||||||
if (bottom_obj_triangles.empty() && !obj_bottom.empty())
|
if (bottom_obj_triangles.empty() && !obj_bottom.empty())
|
||||||
bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, ! left_handed);
|
bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, ! left_handed);
|
||||||
// calculate support bottom cap
|
// calculate support bottom cap
|
||||||
if (bottom_sup_triangles.empty() && !sup_bottom.empty())
|
if (bottom_sup_triangles.empty() && !sup_bottom.empty())
|
||||||
bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, ! left_handed);
|
bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, !left_handed);
|
||||||
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slice_high.is_valid()) {
|
if (slice_high.is_valid()) {
|
||||||
const ExPolygons& obj_top = slice_high.get_slice(soModel);
|
const ExPolygons& obj_top = slice_high.get_slice(soModel);
|
||||||
const ExPolygons& sup_top = slice_high.get_slice(soSupport);
|
const ExPolygons& sup_top = slice_high.get_slice(soSupport);
|
||||||
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
// calculate model top cap
|
||||||
|
if (!top_obj_triangles.is_initialized() && !obj_top.empty())
|
||||||
|
init_model(top_obj_triangles, triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed), { 1.0f, 0.37f, 0.0f, 1.0f });
|
||||||
|
// calculate support top cap
|
||||||
|
if (!top_sup_triangles.is_initialized() && !sup_top.empty())
|
||||||
|
init_model(top_sup_triangles, triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed), { 1.0f, 0.0f, 0.37f, 1.0f });
|
||||||
|
#else
|
||||||
// calculate model top cap
|
// calculate model top cap
|
||||||
if (top_obj_triangles.empty() && !obj_top.empty())
|
if (top_obj_triangles.empty() && !obj_top.empty())
|
||||||
top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed);
|
top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed);
|
||||||
// calculate support top cap
|
// calculate support top cap
|
||||||
if (top_sup_triangles.empty() && !sup_top.empty())
|
if (top_sup_triangles.empty() && !sup_top.empty())
|
||||||
top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed);
|
top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed);
|
||||||
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||||
|
if (shader != nullptr) {
|
||||||
|
shader->start_using();
|
||||||
|
|
||||||
|
for (const SLAPrintObject::Instance& inst : obj->instances()) {
|
||||||
|
glsafe(::glPushMatrix());
|
||||||
|
glsafe(::glTranslated(unscale<double>(inst.shift.x()), unscale<double>(inst.shift.y()), 0.0));
|
||||||
|
glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0f, 0.0f, 1.0f));
|
||||||
|
if (obj->is_left_handed())
|
||||||
|
// The polygons are mirrored by X.
|
||||||
|
glsafe(::glScalef(-1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
|
bottom_obj_triangles.render();
|
||||||
|
top_obj_triangles.render();
|
||||||
|
bottom_sup_triangles.render();
|
||||||
|
top_sup_triangles.render();
|
||||||
|
|
||||||
|
glsafe(::glPopMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
shader->stop_using();
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty()) {
|
if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty()) {
|
||||||
for (const SLAPrintObject::Instance& inst : obj->instances()) {
|
for (const SLAPrintObject::Instance& inst : obj->instances()) {
|
||||||
glsafe(::glPushMatrix());
|
glsafe(::glPushMatrix());
|
||||||
glsafe(::glTranslated(unscale<double>(inst.shift.x()), unscale<double>(inst.shift.y()), 0));
|
glsafe(::glTranslated(unscale<double>(inst.shift.x()), unscale<double>(inst.shift.y()), 0.0));
|
||||||
glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0, 0.0, 1.0));
|
glsafe(::glRotatef(Geometry::rad2deg(inst.rotation), 0.0f, 0.0f, 1.0f));
|
||||||
if (obj->is_left_handed())
|
if (obj->is_left_handed())
|
||||||
// The polygons are mirrored by X.
|
// The polygons are mirrored by X.
|
||||||
glsafe(::glScalef(-1.0, 1.0, 1.0));
|
glsafe(::glScalef(-1.0f, 1.0f, 1.0f));
|
||||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||||
glsafe(::glColor3f(1.0f, 0.37f, 0.0f));
|
glsafe(::glColor3f(1.0f, 0.37f, 0.0f));
|
||||||
if (!bottom_obj_triangles.empty()) {
|
if (!bottom_obj_triangles.empty()) {
|
||||||
@ -5879,6 +6040,7 @@ void GLCanvas3D::_render_sla_slices()
|
|||||||
glsafe(::glPopMatrix());
|
glsafe(::glPopMatrix());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6062,23 +6224,48 @@ void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume)
|
|||||||
skirt_height = std::min(skirt_height, print_zs.size());
|
skirt_height = std::min(skirt_height, print_zs.size());
|
||||||
print_zs.erase(print_zs.begin() + skirt_height, print_zs.end());
|
print_zs.erase(print_zs.begin() + skirt_height, print_zs.end());
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
GLVolume* volume = m_volumes.new_toolpath_volume(color);
|
||||||
|
GLModel::Geometry init_data;
|
||||||
|
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT };
|
||||||
|
#else
|
||||||
GLVolume *volume = m_volumes.new_toolpath_volume(color, VERTEX_BUFFER_RESERVE_SIZE);
|
GLVolume *volume = m_volumes.new_toolpath_volume(color, VERTEX_BUFFER_RESERVE_SIZE);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
for (size_t i = 0; i < skirt_height; ++ i) {
|
for (size_t i = 0; i < skirt_height; ++ i) {
|
||||||
volume->print_zs.emplace_back(print_zs[i]);
|
volume->print_zs.emplace_back(print_zs[i]);
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
volume->offsets.emplace_back(init_data.indices_count());
|
||||||
|
if (i == 0)
|
||||||
|
_3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), init_data);
|
||||||
|
_3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), init_data);
|
||||||
|
#else
|
||||||
volume->offsets.emplace_back(volume->indexed_vertex_array.quad_indices.size());
|
volume->offsets.emplace_back(volume->indexed_vertex_array.quad_indices.size());
|
||||||
volume->offsets.emplace_back(volume->indexed_vertex_array.triangle_indices.size());
|
volume->offsets.emplace_back(volume->indexed_vertex_array.triangle_indices.size());
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
_3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), *volume);
|
_3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), *volume);
|
||||||
_3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume);
|
_3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
|
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
if (init_data.vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) {
|
||||||
|
volume->model.init_from(std::move(init_data));
|
||||||
|
#else
|
||||||
if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
|
if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
|
||||||
GLVolume &vol = *volume;
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
GLVolume &vol = *volume;
|
||||||
volume = m_volumes.new_toolpath_volume(vol.color);
|
volume = m_volumes.new_toolpath_volume(vol.color);
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized);
|
reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized);
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
volume->model.init_from(std::move(init_data));
|
||||||
|
volume->is_outside = !contains(build_volume, volume->model);
|
||||||
|
#else
|
||||||
volume->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(volume->indexed_vertex_array.vertices_and_normals_interleaved, volume->indexed_vertex_array.bounding_box());
|
volume->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(volume->indexed_vertex_array.vertices_and_normals_interleaved, volume->indexed_vertex_array.bounding_box());
|
||||||
volume->indexed_vertex_array.finalize_geometry(m_initialized);
|
volume->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume& build_volume, const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values)
|
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume& build_volume, const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values)
|
||||||
@ -6250,7 +6437,12 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||||||
// Allocate the volume before locking.
|
// Allocate the volume before locking.
|
||||||
GLVolume *volume = new GLVolume(color);
|
GLVolume *volume = new GLVolume(color);
|
||||||
volume->is_extrusion_path = true;
|
volume->is_extrusion_path = true;
|
||||||
tbb::spin_mutex::scoped_lock lock;
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
// to prevent sending data to gpu (in the main thread) while
|
||||||
|
// editing the model geometry
|
||||||
|
volume->model.disable_render();
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
tbb::spin_mutex::scoped_lock lock;
|
||||||
// Lock by ROII, so if the emplace_back() fails, the lock will be released.
|
// Lock by ROII, so if the emplace_back() fails, the lock will be released.
|
||||||
lock.acquire(new_volume_mutex);
|
lock.acquire(new_volume_mutex);
|
||||||
m_volumes.volumes.emplace_back(volume);
|
m_volumes.volumes.emplace_back(volume);
|
||||||
@ -6262,31 +6454,57 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||||||
tbb::blocked_range<size_t>(0, ctxt.layers.size(), grain_size),
|
tbb::blocked_range<size_t>(0, ctxt.layers.size(), grain_size),
|
||||||
[&ctxt, &new_volume, is_selected_separate_extruder, this](const tbb::blocked_range<size_t>& range) {
|
[&ctxt, &new_volume, is_selected_separate_extruder, this](const tbb::blocked_range<size_t>& range) {
|
||||||
GLVolumePtrs vols;
|
GLVolumePtrs vols;
|
||||||
auto volume = [&ctxt, &vols](size_t layer_idx, int extruder, int feature) -> GLVolume& {
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
return *vols[ctxt.color_by_color_print()?
|
std::vector<GLModel::Geometry> geometries;
|
||||||
|
auto select_geometry = [&ctxt, &geometries](size_t layer_idx, int extruder, int feature) -> GLModel::Geometry& {
|
||||||
|
return geometries[ctxt.color_by_color_print() ?
|
||||||
ctxt.color_print_color_idx_by_layer_idx_and_extruder(layer_idx, extruder) :
|
ctxt.color_print_color_idx_by_layer_idx_and_extruder(layer_idx, extruder) :
|
||||||
ctxt.color_by_tool() ?
|
ctxt.color_by_tool() ?
|
||||||
std::min<int>(ctxt.number_tools() - 1, std::max<int>(extruder - 1, 0)) :
|
std::min<int>(ctxt.number_tools() - 1, std::max<int>(extruder - 1, 0)) :
|
||||||
feature
|
feature
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
#else
|
||||||
|
auto volume = [&ctxt, &vols](size_t layer_idx, int extruder, int feature) -> GLVolume& {
|
||||||
|
return *vols[ctxt.color_by_color_print() ?
|
||||||
|
ctxt.color_print_color_idx_by_layer_idx_and_extruder(layer_idx, extruder) :
|
||||||
|
ctxt.color_by_tool() ?
|
||||||
|
std::min<int>(ctxt.number_tools() - 1, std::max<int>(extruder - 1, 0)) :
|
||||||
|
feature
|
||||||
|
];
|
||||||
|
};
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
if (ctxt.color_by_color_print() || ctxt.color_by_tool()) {
|
if (ctxt.color_by_color_print() || ctxt.color_by_tool()) {
|
||||||
for (size_t i = 0; i < ctxt.number_tools(); ++i)
|
for (size_t i = 0; i < ctxt.number_tools(); ++i) {
|
||||||
vols.emplace_back(new_volume(ctxt.color_tool(i)));
|
vols.emplace_back(new_volume(ctxt.color_tool(i)));
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
geometries.emplace_back(GLModel::Geometry());
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) };
|
vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) };
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
geometries = { GLModel::Geometry(), GLModel::Geometry(), GLModel::Geometry() };
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
assert(vols.size() == geometries.size());
|
||||||
|
for (GLModel::Geometry& g : geometries) {
|
||||||
|
g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT };
|
||||||
|
}
|
||||||
|
#else
|
||||||
for (GLVolume *vol : vols)
|
for (GLVolume *vol : vols)
|
||||||
// Reserving number of vertices (3x position + 3x color)
|
// Reserving number of vertices (3x position + 3x color)
|
||||||
vol->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6);
|
vol->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
|
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
|
||||||
const Layer *layer = ctxt.layers[idx_layer];
|
const Layer *layer = ctxt.layers[idx_layer];
|
||||||
|
|
||||||
if (is_selected_separate_extruder)
|
if (is_selected_separate_extruder) {
|
||||||
{
|
|
||||||
bool at_least_one_has_correct_extruder = false;
|
bool at_least_one_has_correct_extruder = false;
|
||||||
for (const LayerRegion* layerm : layer->regions())
|
for (const LayerRegion* layerm : layer->regions()) {
|
||||||
{
|
|
||||||
if (layerm->slices.surfaces.empty())
|
if (layerm->slices.surfaces.empty())
|
||||||
continue;
|
continue;
|
||||||
const PrintRegionConfig& cfg = layerm->region().config();
|
const PrintRegionConfig& cfg = layerm->region().config();
|
||||||
@ -6301,17 +6519,27 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GLVolume *vol : vols)
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
for (size_t i = 0; i < vols.size(); ++i) {
|
||||||
|
GLVolume* vol = vols[i];
|
||||||
|
if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) {
|
||||||
|
vol->print_zs.emplace_back(layer->print_z);
|
||||||
|
vol->offsets.emplace_back(geometries[i].indices_count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (GLVolume* vol : vols)
|
||||||
if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) {
|
if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) {
|
||||||
vol->print_zs.emplace_back(layer->print_z);
|
vol->print_zs.emplace_back(layer->print_z);
|
||||||
vol->offsets.emplace_back(vol->indexed_vertex_array.quad_indices.size());
|
vol->offsets.emplace_back(vol->indexed_vertex_array.quad_indices.size());
|
||||||
vol->offsets.emplace_back(vol->indexed_vertex_array.triangle_indices.size());
|
vol->offsets.emplace_back(vol->indexed_vertex_array.triangle_indices.size());
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
for (const PrintInstance &instance : *ctxt.shifted_copies) {
|
for (const PrintInstance &instance : *ctxt.shifted_copies) {
|
||||||
const Point © = instance.shift;
|
const Point © = instance.shift;
|
||||||
for (const LayerRegion *layerm : layer->regions()) {
|
for (const LayerRegion *layerm : layer->regions()) {
|
||||||
if (is_selected_separate_extruder)
|
if (is_selected_separate_extruder) {
|
||||||
{
|
|
||||||
const PrintRegionConfig& cfg = layerm->region().config();
|
const PrintRegionConfig& cfg = layerm->region().config();
|
||||||
if (cfg.perimeter_extruder.value != m_selected_extruder ||
|
if (cfg.perimeter_extruder.value != m_selected_extruder ||
|
||||||
cfg.infill_extruder.value != m_selected_extruder ||
|
cfg.infill_extruder.value != m_selected_extruder ||
|
||||||
@ -6319,19 +6547,31 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ctxt.has_perimeters)
|
if (ctxt.has_perimeters)
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
_3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
|
||||||
|
select_geometry(idx_layer, layerm->region().config().perimeter_extruder.value, 0));
|
||||||
|
#else
|
||||||
_3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
|
_3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
|
||||||
volume(idx_layer, layerm->region().config().perimeter_extruder.value, 0));
|
volume(idx_layer, layerm->region().config().perimeter_extruder.value, 0));
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
if (ctxt.has_infill) {
|
if (ctxt.has_infill) {
|
||||||
for (const ExtrusionEntity *ee : layerm->fills.entities) {
|
for (const ExtrusionEntity *ee : layerm->fills.entities) {
|
||||||
// fill represents infill extrusions of a single island.
|
// fill represents infill extrusions of a single island.
|
||||||
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||||
if (! fill->entities.empty())
|
if (! fill->entities.empty())
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
_3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy,
|
||||||
|
select_geometry(idx_layer, is_solid_infill(fill->entities.front()->role()) ?
|
||||||
|
layerm->region().config().solid_infill_extruder :
|
||||||
|
layerm->region().config().infill_extruder, 1));
|
||||||
|
#else
|
||||||
_3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy,
|
_3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy,
|
||||||
volume(idx_layer,
|
volume(idx_layer,
|
||||||
is_solid_infill(fill->entities.front()->role()) ?
|
is_solid_infill(fill->entities.front()->role()) ?
|
||||||
layerm->region().config().solid_infill_extruder :
|
layerm->region().config().solid_infill_extruder :
|
||||||
layerm->region().config().infill_extruder,
|
layerm->region().config().infill_extruder,
|
||||||
1));
|
1));
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6339,28 +6579,50 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||||||
const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(layer);
|
const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(layer);
|
||||||
if (support_layer) {
|
if (support_layer) {
|
||||||
for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities)
|
for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities)
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
_3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
|
||||||
|
select_geometry(idx_layer, (extrusion_entity->role() == erSupportMaterial) ?
|
||||||
|
support_layer->object()->config().support_material_extruder :
|
||||||
|
support_layer->object()->config().support_material_interface_extruder, 2));
|
||||||
|
#else
|
||||||
_3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
|
_3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
|
||||||
volume(idx_layer,
|
volume(idx_layer,
|
||||||
(extrusion_entity->role() == erSupportMaterial) ?
|
(extrusion_entity->role() == erSupportMaterial) ?
|
||||||
support_layer->object()->config().support_material_extruder :
|
support_layer->object()->config().support_material_extruder :
|
||||||
support_layer->object()->config().support_material_interface_extruder,
|
support_layer->object()->config().support_material_interface_extruder,
|
||||||
2));
|
2));
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
|
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
|
||||||
for (size_t i = 0; i < vols.size(); ++i) {
|
for (size_t i = 0; i < vols.size(); ++i) {
|
||||||
GLVolume &vol = *vols[i];
|
GLVolume &vol = *vols[i];
|
||||||
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
vols[i] = new_volume(vol.color);
|
if (geometries[i].vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) {
|
||||||
reserve_new_volume_finalize_old_volume(*vols[i], vol, false);
|
vol.model.init_from(std::move(geometries[i]));
|
||||||
}
|
#else
|
||||||
|
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
vols[i] = new_volume(vol.color);
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
reserve_new_volume_finalize_old_volume(*vols[i], vol, false);
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
for (size_t i = 0; i < vols.size(); ++i) {
|
||||||
|
if (!geometries[i].is_empty())
|
||||||
|
vols[i]->model.init_from(std::move(geometries[i]));
|
||||||
|
}
|
||||||
|
#else
|
||||||
for (GLVolume *vol : vols)
|
for (GLVolume *vol : vols)
|
||||||
// Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver,
|
// Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver,
|
||||||
// but this code runs in parallel and the OpenGL driver is not thread safe.
|
// but this code runs in parallel and the OpenGL driver is not thread safe.
|
||||||
vol->indexed_vertex_array.shrink_to_fit();
|
vol->indexed_vertex_array.shrink_to_fit();
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
});
|
});
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
|
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
|
||||||
@ -6375,8 +6637,14 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||||||
}
|
}
|
||||||
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) {
|
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) {
|
||||||
GLVolume* v = m_volumes.volumes[i];
|
GLVolume* v = m_volumes.volumes[i];
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
v->is_outside = !contains(build_volume, v->model);
|
||||||
|
// We are done editinig the model, now it can be sent to gpu
|
||||||
|
v->model.enable_render();
|
||||||
|
#else
|
||||||
v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box());
|
v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box());
|
||||||
v->indexed_vertex_array.finalize_geometry(m_initialized);
|
v->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
||||||
@ -6396,10 +6664,10 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
|
|||||||
|
|
||||||
struct Ctxt
|
struct Ctxt
|
||||||
{
|
{
|
||||||
const Print *print;
|
const Print *print;
|
||||||
const std::vector<ColorRGBA>* tool_colors;
|
const std::vector<ColorRGBA> *tool_colors;
|
||||||
Vec2f wipe_tower_pos;
|
Vec2f wipe_tower_pos;
|
||||||
float wipe_tower_angle;
|
float wipe_tower_angle;
|
||||||
|
|
||||||
static ColorRGBA color_support() { return ColorRGBA::GREENISH(); }
|
static ColorRGBA color_support() { return ColorRGBA::GREENISH(); }
|
||||||
|
|
||||||
@ -6441,6 +6709,11 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
|
|||||||
auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) {
|
auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) {
|
||||||
auto *volume = new GLVolume(color);
|
auto *volume = new GLVolume(color);
|
||||||
volume->is_extrusion_path = true;
|
volume->is_extrusion_path = true;
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
// to prevent sending data to gpu (in the main thread) while
|
||||||
|
// editing the model geometry
|
||||||
|
volume->model.disable_render();
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
tbb::spin_mutex::scoped_lock lock;
|
tbb::spin_mutex::scoped_lock lock;
|
||||||
lock.acquire(new_volume_mutex);
|
lock.acquire(new_volume_mutex);
|
||||||
m_volumes.volumes.emplace_back(volume);
|
m_volumes.volumes.emplace_back(volume);
|
||||||
@ -6454,23 +6727,46 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
|
|||||||
[&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) {
|
[&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) {
|
||||||
// Bounding box of this slab of a wipe tower.
|
// Bounding box of this slab of a wipe tower.
|
||||||
GLVolumePtrs vols;
|
GLVolumePtrs vols;
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
std::vector<GLModel::Geometry> geometries;
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
if (ctxt.color_by_tool()) {
|
if (ctxt.color_by_tool()) {
|
||||||
for (size_t i = 0; i < ctxt.number_tools(); ++i)
|
for (size_t i = 0; i < ctxt.number_tools(); ++i) {
|
||||||
vols.emplace_back(new_volume(ctxt.color_tool(i)));
|
vols.emplace_back(new_volume(ctxt.color_tool(i)));
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
geometries.emplace_back(GLModel::Geometry());
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
vols = { new_volume(ctxt.color_support()) };
|
vols = { new_volume(ctxt.color_support()) };
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
geometries = { GLModel::Geometry() };
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
assert(vols.size() == geometries.size());
|
||||||
|
for (GLModel::Geometry& g : geometries) {
|
||||||
|
g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT };
|
||||||
|
}
|
||||||
|
#else
|
||||||
for (GLVolume *volume : vols)
|
for (GLVolume *volume : vols)
|
||||||
// Reserving number of vertices (3x position + 3x color)
|
// Reserving number of vertices (3x position + 3x color)
|
||||||
volume->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6);
|
volume->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) {
|
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) {
|
||||||
const std::vector<WipeTower::ToolChangeResult> &layer = ctxt.tool_change(idx_layer);
|
const std::vector<WipeTower::ToolChangeResult> &layer = ctxt.tool_change(idx_layer);
|
||||||
for (size_t i = 0; i < vols.size(); ++i) {
|
for (size_t i = 0; i < vols.size(); ++i) {
|
||||||
GLVolume &vol = *vols[i];
|
GLVolume &vol = *vols[i];
|
||||||
if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) {
|
if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) {
|
||||||
vol.print_zs.emplace_back(layer.front().print_z);
|
vol.print_zs.emplace_back(layer.front().print_z);
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
vol.offsets.emplace_back(geometries[i].indices_count());
|
||||||
|
#else
|
||||||
vol.offsets.emplace_back(vol.indexed_vertex_array.quad_indices.size());
|
vol.offsets.emplace_back(vol.indexed_vertex_array.quad_indices.size());
|
||||||
vol.offsets.emplace_back(vol.indexed_vertex_array.triangle_indices.size());
|
vol.offsets.emplace_back(vol.indexed_vertex_array.triangle_indices.size());
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const WipeTower::ToolChangeResult &extrusions : layer) {
|
for (const WipeTower::ToolChangeResult &extrusions : layer) {
|
||||||
@ -6512,21 +6808,42 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
|
|||||||
|
|
||||||
e_prev = e;
|
e_prev = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
_3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z,
|
||||||
|
geometries[ctxt.volume_idx(e.tool, 0)]);
|
||||||
|
#else
|
||||||
_3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z,
|
_3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z,
|
||||||
*vols[ctxt.volume_idx(e.tool, 0)]);
|
*vols[ctxt.volume_idx(e.tool, 0)]);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < vols.size(); ++i) {
|
for (size_t i = 0; i < vols.size(); ++i) {
|
||||||
GLVolume &vol = *vols[i];
|
GLVolume &vol = *vols[i];
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
if (geometries[i].vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) {
|
||||||
|
vol.model.init_from(std::move(geometries[i]));
|
||||||
|
#else
|
||||||
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
|
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
vols[i] = new_volume(vol.color);
|
vols[i] = new_volume(vol.color);
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
reserve_new_volume_finalize_old_volume(*vols[i], vol, false);
|
reserve_new_volume_finalize_old_volume(*vols[i], vol, false);
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
for (size_t i = 0; i < vols.size(); ++i) {
|
||||||
|
if (!geometries[i].is_empty())
|
||||||
|
vols[i]->model.init_from(std::move(geometries[i]));
|
||||||
|
}
|
||||||
|
#else
|
||||||
for (GLVolume *vol : vols)
|
for (GLVolume *vol : vols)
|
||||||
vol->indexed_vertex_array.shrink_to_fit();
|
vol->indexed_vertex_array.shrink_to_fit();
|
||||||
});
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
});
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
|
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
|
||||||
// Remove empty volumes from the newly added volumes.
|
// Remove empty volumes from the newly added volumes.
|
||||||
@ -6540,8 +6857,14 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
|
|||||||
}
|
}
|
||||||
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) {
|
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) {
|
||||||
GLVolume* v = m_volumes.volumes[i];
|
GLVolume* v = m_volumes.volumes[i];
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
v->is_outside = !contains(build_volume, v->model);
|
||||||
|
// We are done editinig the model, now it can be sent to gpu
|
||||||
|
v->model.enable_render();
|
||||||
|
#else
|
||||||
v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box());
|
v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box());
|
||||||
v->indexed_vertex_array.finalize_geometry(m_initialized);
|
v->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
||||||
@ -6565,11 +6888,21 @@ void GLCanvas3D::_load_sla_shells()
|
|||||||
m_volumes.volumes.emplace_back(new GLVolume(color));
|
m_volumes.volumes.emplace_back(new GLVolume(color));
|
||||||
GLVolume& v = *m_volumes.volumes.back();
|
GLVolume& v = *m_volumes.volumes.back();
|
||||||
#if ENABLE_SMOOTH_NORMALS
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
v.model.init_from(mesh, true);
|
||||||
|
#else
|
||||||
v.indexed_vertex_array.load_mesh(mesh, true);
|
v.indexed_vertex_array.load_mesh(mesh, true);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#else
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
v.model.init_from(mesh);
|
||||||
#else
|
#else
|
||||||
v.indexed_vertex_array.load_mesh(mesh);
|
v.indexed_vertex_array.load_mesh(mesh);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
#endif // ENABLE_SMOOTH_NORMALS
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
v.indexed_vertex_array.finalize_geometry(m_initialized);
|
v.indexed_vertex_array.finalize_geometry(m_initialized);
|
||||||
|
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled;
|
v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled;
|
||||||
v.composite_id.volume_id = volume_id;
|
v.composite_id.volume_id = volume_id;
|
||||||
v.set_instance_offset(unscale(instance.shift.x(), instance.shift.y(), 0.0));
|
v.set_instance_offset(unscale(instance.shift.x(), instance.shift.y(), 0.0));
|
||||||
|
@ -335,6 +335,16 @@ class GLCanvas3D
|
|||||||
|
|
||||||
struct SlaCap
|
struct SlaCap
|
||||||
{
|
{
|
||||||
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
struct Triangles
|
||||||
|
{
|
||||||
|
GLModel object;
|
||||||
|
GLModel supports;
|
||||||
|
};
|
||||||
|
typedef std::map<unsigned int, Triangles> ObjectIdToModelsMap;
|
||||||
|
double z;
|
||||||
|
ObjectIdToModelsMap triangles;
|
||||||
|
#else
|
||||||
struct Triangles
|
struct Triangles
|
||||||
{
|
{
|
||||||
Pointf3s object;
|
Pointf3s object;
|
||||||
@ -343,6 +353,7 @@ class GLCanvas3D
|
|||||||
typedef std::map<unsigned int, Triangles> ObjectIdToTrianglesMap;
|
typedef std::map<unsigned int, Triangles> ObjectIdToTrianglesMap;
|
||||||
double z;
|
double z;
|
||||||
ObjectIdToTrianglesMap triangles;
|
ObjectIdToTrianglesMap triangles;
|
||||||
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
|
||||||
SlaCap() { reset(); }
|
SlaCap() { reset(); }
|
||||||
void reset() { z = DBL_MAX; triangles.clear(); }
|
void reset() { z = DBL_MAX; triangles.clear(); }
|
||||||
@ -473,7 +484,7 @@ private:
|
|||||||
std::array<ClippingPlane, 2> m_clipping_planes;
|
std::array<ClippingPlane, 2> m_clipping_planes;
|
||||||
ClippingPlane m_camera_clipping_plane;
|
ClippingPlane m_camera_clipping_plane;
|
||||||
bool m_use_clipping_planes;
|
bool m_use_clipping_planes;
|
||||||
SlaCap m_sla_caps[2];
|
std::array<SlaCap, 2> m_sla_caps;
|
||||||
std::string m_sidebar_field;
|
std::string m_sidebar_field;
|
||||||
// when true renders an extra frame by not resetting m_dirty to false
|
// when true renders an extra frame by not resetting m_dirty to false
|
||||||
// see request_extra_frame()
|
// see request_extra_frame()
|
||||||
@ -511,8 +522,6 @@ private:
|
|||||||
// I just don't want to do it now before a release (Lukas Matena 24.3.2019)
|
// I just don't want to do it now before a release (Lukas Matena 24.3.2019)
|
||||||
bool m_render_sla_auxiliaries;
|
bool m_render_sla_auxiliaries;
|
||||||
|
|
||||||
std::string m_color_by;
|
|
||||||
|
|
||||||
bool m_reload_delayed;
|
bool m_reload_delayed;
|
||||||
|
|
||||||
#if ENABLE_RENDER_PICKING_PASS
|
#if ENABLE_RENDER_PICKING_PASS
|
||||||
@ -681,8 +690,6 @@ public:
|
|||||||
bool get_use_clipping_planes() const { return m_use_clipping_planes; }
|
bool get_use_clipping_planes() const { return m_use_clipping_planes; }
|
||||||
const std::array<ClippingPlane, 2> &get_clipping_planes() const { return m_clipping_planes; };
|
const std::array<ClippingPlane, 2> &get_clipping_planes() const { return m_clipping_planes; };
|
||||||
|
|
||||||
void set_color_by(const std::string& value);
|
|
||||||
|
|
||||||
void refresh_camera_scene_box();
|
void refresh_camera_scene_box();
|
||||||
|
|
||||||
BoundingBoxf3 volumes_bounding_box() const;
|
BoundingBoxf3 volumes_bounding_box() const;
|
||||||
|
@ -8,15 +8,56 @@
|
|||||||
#include "libslic3r/TriangleMesh.hpp"
|
#include "libslic3r/TriangleMesh.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
#include "libslic3r/Polygon.hpp"
|
#include "libslic3r/Polygon.hpp"
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#include "libslic3r/BuildVolume.hpp"
|
||||||
|
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
#include <igl/per_face_normals.h>
|
||||||
|
#include <igl/per_corner_normals.h>
|
||||||
|
#include <igl/per_vertex_normals.h>
|
||||||
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
static void smooth_normals_corner(const TriangleMesh& mesh, std::vector<stl_normal>& normals)
|
||||||
|
{
|
||||||
|
using MapMatrixXfUnaligned = Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
|
||||||
|
using MapMatrixXiUnaligned = Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
|
||||||
|
|
||||||
|
std::vector<Vec3f> face_normals = its_face_normals(mesh.its);
|
||||||
|
|
||||||
|
Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(),
|
||||||
|
Eigen::Index(mesh.its.vertices.size()), 3).cast<double>();
|
||||||
|
Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(),
|
||||||
|
Eigen::Index(mesh.its.indices.size()), 3);
|
||||||
|
Eigen::MatrixXd in_normals = MapMatrixXfUnaligned(face_normals.front().data(),
|
||||||
|
Eigen::Index(face_normals.size()), 3).cast<double>();
|
||||||
|
Eigen::MatrixXd out_normals;
|
||||||
|
|
||||||
|
igl::per_corner_normals(vertices, indices, in_normals, 1.0, out_normals);
|
||||||
|
|
||||||
|
normals = std::vector<stl_normal>(mesh.its.vertices.size());
|
||||||
|
for (size_t i = 0; i < mesh.its.indices.size(); ++i) {
|
||||||
|
for (size_t j = 0; j < 3; ++j) {
|
||||||
|
normals[mesh.its.indices[i][j]] = out_normals.row(i * 3 + j).cast<float>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
void GLModel::Geometry::reserve_vertices(size_t vertices_count)
|
void GLModel::Geometry::reserve_vertices(size_t vertices_count)
|
||||||
{
|
{
|
||||||
@ -207,6 +248,37 @@ Vec2f GLModel::Geometry::extract_tex_coord_2(size_t id) const
|
|||||||
return { *(start + 0), *(start + 1) };
|
return { *(start + 0), *(start + 1) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void GLModel::Geometry::set_vertex(size_t id, const Vec3f& position, const Vec3f& normal)
|
||||||
|
{
|
||||||
|
assert(format.vertex_layout == EVertexLayout::P3N3);
|
||||||
|
assert(id < vertices_count());
|
||||||
|
if (id < vertices_count()) {
|
||||||
|
float* start = &vertices[id * vertex_stride_floats(format)];
|
||||||
|
*(start + 0) = position.x();
|
||||||
|
*(start + 1) = position.y();
|
||||||
|
*(start + 2) = position.z();
|
||||||
|
*(start + 3) = normal.x();
|
||||||
|
*(start + 4) = normal.y();
|
||||||
|
*(start + 5) = normal.z();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLModel::Geometry::set_ushort_index(size_t id, unsigned short index)
|
||||||
|
{
|
||||||
|
assert(id < indices_count());
|
||||||
|
if (id < indices_count())
|
||||||
|
::memcpy(indices.data() + id * sizeof(unsigned short), &index, sizeof(unsigned short));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLModel::Geometry::set_uint_index(size_t id, unsigned int index)
|
||||||
|
{
|
||||||
|
assert(id < indices_count());
|
||||||
|
if (id < indices_count())
|
||||||
|
::memcpy(indices.data() + id * sizeof(unsigned int), &index, sizeof(unsigned int));
|
||||||
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
unsigned int GLModel::Geometry::extract_uint_index(size_t id) const
|
unsigned int GLModel::Geometry::extract_uint_index(size_t id) const
|
||||||
{
|
{
|
||||||
if (format.index_type != EIndexType::UINT) {
|
if (format.index_type != EIndexType::UINT) {
|
||||||
@ -219,7 +291,7 @@ unsigned int GLModel::Geometry::extract_uint_index(size_t id) const
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int ret = -1;
|
unsigned int ret = (unsigned int)-1;
|
||||||
::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned int));
|
::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned int));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -236,11 +308,23 @@ unsigned short GLModel::Geometry::extract_ushort_index(size_t id) const
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned short ret = -1;
|
unsigned short ret = (unsigned short)-1;
|
||||||
::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned short));
|
::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned short));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void GLModel::Geometry::remove_vertex(size_t id)
|
||||||
|
{
|
||||||
|
assert(id < vertices_count());
|
||||||
|
if (id < vertices_count()) {
|
||||||
|
size_t stride = vertex_stride_floats(format);
|
||||||
|
std::vector<float>::iterator it = vertices.begin() + id * stride;
|
||||||
|
vertices.erase(it, it + stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
size_t GLModel::Geometry::vertex_stride_floats(const Format& format)
|
size_t GLModel::Geometry::vertex_stride_floats(const Format& format)
|
||||||
{
|
{
|
||||||
switch (format.vertex_layout)
|
switch (format.vertex_layout)
|
||||||
@ -328,6 +412,11 @@ size_t GLModel::Geometry::index_stride_bytes(const Format& format)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLModel::Geometry::EIndexType GLModel::Geometry::index_type(size_t vertices_count)
|
||||||
|
{
|
||||||
|
return (vertices_count < 65536) ? EIndexType::USHORT : EIndexType::UINT;
|
||||||
|
}
|
||||||
|
|
||||||
bool GLModel::Geometry::has_position(const Format& format)
|
bool GLModel::Geometry::has_position(const Format& format)
|
||||||
{
|
{
|
||||||
switch (format.vertex_layout)
|
switch (format.vertex_layout)
|
||||||
@ -456,10 +545,58 @@ void GLModel::init_from(const Geometry& data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
void GLModel::init_from(const TriangleMesh& mesh, bool smooth_normals)
|
||||||
|
{
|
||||||
|
if (smooth_normals) {
|
||||||
|
if (is_initialized()) {
|
||||||
|
// call reset() if you want to reuse this model
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mesh.its.vertices.empty() || mesh.its.indices.empty()) {
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<stl_normal> normals;
|
||||||
|
smooth_normals_corner(mesh, normals);
|
||||||
|
|
||||||
|
const indexed_triangle_set& its = mesh.its;
|
||||||
|
Geometry& data = m_render_data.geometry;
|
||||||
|
data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(3 * its.indices.size()) };
|
||||||
|
data.reserve_vertices(3 * its.indices.size());
|
||||||
|
data.reserve_indices(3 * its.indices.size());
|
||||||
|
|
||||||
|
// vertices
|
||||||
|
for (size_t i = 0; i < its.vertices.size(); ++i) {
|
||||||
|
data.add_vertex(its.vertices[i], normals[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// indices
|
||||||
|
for (size_t i = 0; i < its.indices.size(); ++i) {
|
||||||
|
const stl_triangle_vertex_indices& idx = its.indices[i];
|
||||||
|
if (data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||||
|
data.add_ushort_triangle((unsigned short)idx(0), (unsigned short)idx(1), (unsigned short)idx(2));
|
||||||
|
else
|
||||||
|
data.add_uint_triangle((unsigned int)idx(0), (unsigned int)idx(1), (unsigned int)idx(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// update bounding box
|
||||||
|
for (size_t i = 0; i < vertices_count(); ++i) {
|
||||||
|
m_bounding_box.merge(m_render_data.geometry.extract_position_3(i).cast<double>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
init_from(mesh.its);
|
||||||
|
}
|
||||||
|
#else
|
||||||
void GLModel::init_from(const TriangleMesh& mesh)
|
void GLModel::init_from(const TriangleMesh& mesh)
|
||||||
{
|
{
|
||||||
init_from(mesh.its);
|
init_from(mesh.its);
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
|
||||||
void GLModel::init_from(const indexed_triangle_set& its)
|
void GLModel::init_from(const indexed_triangle_set& its)
|
||||||
#else
|
#else
|
||||||
@ -479,21 +616,24 @@ void GLModel::init_from(const indexed_triangle_set& its, const BoundingBoxf3 &bb
|
|||||||
}
|
}
|
||||||
|
|
||||||
Geometry& data = m_render_data.geometry;
|
Geometry& data = m_render_data.geometry;
|
||||||
data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, Geometry::EIndexType::UINT };
|
data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(3 * its.indices.size()) };
|
||||||
data.reserve_vertices(3 * its.indices.size());
|
data.reserve_vertices(3 * its.indices.size());
|
||||||
data.reserve_indices(3 * its.indices.size());
|
data.reserve_indices(3 * its.indices.size());
|
||||||
|
|
||||||
// vertices + indices
|
// vertices + indices
|
||||||
unsigned int vertices_counter = 0;
|
unsigned int vertices_counter = 0;
|
||||||
for (uint32_t i = 0; i < its.indices.size(); ++i) {
|
for (uint32_t i = 0; i < its.indices.size(); ++i) {
|
||||||
stl_triangle_vertex_indices face = its.indices[i];
|
const stl_triangle_vertex_indices face = its.indices[i];
|
||||||
stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] };
|
const stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] };
|
||||||
stl_vertex n = face_normal_normalized(vertex);
|
const stl_vertex n = face_normal_normalized(vertex);
|
||||||
for (size_t j = 0; j < 3; ++j) {
|
for (size_t j = 0; j < 3; ++j) {
|
||||||
data.add_vertex(vertex[j], n);
|
data.add_vertex(vertex[j], n);
|
||||||
}
|
}
|
||||||
vertices_counter += 3;
|
vertices_counter += 3;
|
||||||
data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1);
|
if (data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||||
|
data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1);
|
||||||
|
else
|
||||||
|
data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update bounding box
|
// update bounding box
|
||||||
@ -716,6 +856,9 @@ void GLModel::render()
|
|||||||
void GLModel::render() const
|
void GLModel::render() const
|
||||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
{
|
{
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
render(std::make_pair<size_t, size_t>(0, indices_count()));
|
||||||
|
#else
|
||||||
GLShaderProgram* shader = wxGetApp().get_current_shader();
|
GLShaderProgram* shader = wxGetApp().get_current_shader();
|
||||||
|
|
||||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
@ -804,8 +947,71 @@ void GLModel::render() const
|
|||||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||||
}
|
}
|
||||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void GLModel::render(const std::pair<size_t, size_t>& range)
|
||||||
|
{
|
||||||
|
if (m_render_disabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (range.second == range.first)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GLShaderProgram* shader = wxGetApp().get_current_shader();
|
||||||
|
|
||||||
|
if (shader == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// sends data to gpu if not done yet
|
||||||
|
if (m_render_data.vbo_id == 0 || m_render_data.ibo_id == 0) {
|
||||||
|
if (m_render_data.geometry.vertices_count() > 0 && m_render_data.geometry.indices_count() > 0 && !send_to_gpu())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Geometry& data = m_render_data.geometry;
|
||||||
|
|
||||||
|
const GLenum mode = get_primitive_mode(data.format);
|
||||||
|
const GLenum index_type = get_index_type(data.format);
|
||||||
|
|
||||||
|
const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format);
|
||||||
|
const bool position = Geometry::has_position(data.format);
|
||||||
|
const bool normal = Geometry::has_normal(data.format);
|
||||||
|
const bool tex_coord = Geometry::has_tex_coord(data.format);
|
||||||
|
|
||||||
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id));
|
||||||
|
|
||||||
|
if (position) {
|
||||||
|
glsafe(::glVertexPointer(Geometry::position_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format)));
|
||||||
|
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||||
|
}
|
||||||
|
if (normal) {
|
||||||
|
glsafe(::glNormalPointer(GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format)));
|
||||||
|
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||||
|
}
|
||||||
|
if (tex_coord) {
|
||||||
|
glsafe(::glTexCoordPointer(Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::tex_coord_offset_bytes(data.format)));
|
||||||
|
glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
shader->set_uniform("uniform_color", data.color);
|
||||||
|
|
||||||
|
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id));
|
||||||
|
glsafe(::glDrawElements(mode, range.second - range.first + 1, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data.format))));
|
||||||
|
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||||
|
|
||||||
|
if (tex_coord)
|
||||||
|
glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||||
|
if (normal)
|
||||||
|
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
||||||
|
if (position)
|
||||||
|
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
||||||
|
|
||||||
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||||
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count)
|
void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count)
|
||||||
#else
|
#else
|
||||||
@ -1022,6 +1228,62 @@ static void append_triangle(GLModel::Geometry& data, unsigned short v1, unsigned
|
|||||||
}
|
}
|
||||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
template<typename Fn>
|
||||||
|
inline bool all_vertices_inside(const GLModel::Geometry& geometry, Fn fn)
|
||||||
|
{
|
||||||
|
const size_t position_stride_floats = geometry.position_stride_floats(geometry.format);
|
||||||
|
const size_t position_offset_floats = geometry.position_offset_floats(geometry.format);
|
||||||
|
assert(position_stride_floats == 3);
|
||||||
|
if (geometry.vertices.empty() || position_stride_floats != 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto it = geometry.vertices.begin(); it != geometry.vertices.end(); ) {
|
||||||
|
it += position_offset_floats;
|
||||||
|
if (!fn({ *it, *(it + 1), *(it + 2) }))
|
||||||
|
return false;
|
||||||
|
it += (geometry.vertex_stride_floats(geometry.format) - position_offset_floats - position_stride_floats);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_bottom)
|
||||||
|
{
|
||||||
|
static constexpr const double epsilon = BuildVolume::BedEpsilon;
|
||||||
|
switch (volume.type()) {
|
||||||
|
case BuildVolume::Type::Rectangle:
|
||||||
|
{
|
||||||
|
BoundingBox3Base<Vec3d> build_volume = volume.bounding_volume().inflated(epsilon);
|
||||||
|
if (volume.max_print_height() == 0.0)
|
||||||
|
build_volume.max.z() = std::numeric_limits<double>::max();
|
||||||
|
if (ignore_bottom)
|
||||||
|
build_volume.min.z() = -std::numeric_limits<double>::max();
|
||||||
|
const BoundingBoxf3& model_box = model.get_bounding_box();
|
||||||
|
return build_volume.contains(model_box.min) && build_volume.contains(model_box.max);
|
||||||
|
}
|
||||||
|
case BuildVolume::Type::Circle:
|
||||||
|
{
|
||||||
|
const Geometry::Circled& circle = volume.circle();
|
||||||
|
const Vec2f c = unscaled<float>(circle.center);
|
||||||
|
const float r = unscaled<double>(circle.radius) + float(epsilon);
|
||||||
|
const float r2 = sqr(r);
|
||||||
|
return volume.max_print_height() == 0.0 ?
|
||||||
|
all_vertices_inside(model.get_geometry(), [c, r2](const Vec3f& p) { return (to_2d(p) - c).squaredNorm() <= r2; }) :
|
||||||
|
|
||||||
|
all_vertices_inside(model.get_geometry(), [c, r2, z = volume.max_print_height() + epsilon](const Vec3f& p) { return (to_2d(p) - c).squaredNorm() <= r2 && p.z() <= z; });
|
||||||
|
}
|
||||||
|
case BuildVolume::Type::Convex:
|
||||||
|
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
|
||||||
|
case BuildVolume::Type::Custom:
|
||||||
|
return volume.max_print_height() == 0.0 ?
|
||||||
|
all_vertices_inside(model.get_geometry(), [&volume](const Vec3f& p) { return Geometry::inside_convex_polygon(volume.top_bottom_convex_hull_decomposition_bed(), to_2d(p).cast<double>()); }) :
|
||||||
|
all_vertices_inside(model.get_geometry(), [&volume, z = volume.max_print_height() + epsilon](const Vec3f& p) { return Geometry::inside_convex_polygon(volume.top_bottom_convex_hull_decomposition_bed(), to_2d(p).cast<double>()) && p.z() <= z; });
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height)
|
GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height)
|
||||||
{
|
{
|
||||||
#if !ENABLE_GLBEGIN_GLEND_REMOVAL
|
#if !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
@ -14,6 +14,9 @@ namespace Slic3r {
|
|||||||
class TriangleMesh;
|
class TriangleMesh;
|
||||||
class Polygon;
|
class Polygon;
|
||||||
using Polygons = std::vector<Polygon>;
|
using Polygons = std::vector<Polygon>;
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
class BuildVolume;
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
@ -83,11 +86,18 @@ namespace GUI {
|
|||||||
void reserve_vertices(size_t vertices_count);
|
void reserve_vertices(size_t vertices_count);
|
||||||
void reserve_indices(size_t indices_count);
|
void reserve_indices(size_t indices_count);
|
||||||
|
|
||||||
void add_vertex(const Vec2f& position);
|
void add_vertex(const Vec2f& position); // EVertexLayout::P2
|
||||||
void add_vertex(const Vec2f& position, const Vec2f& tex_coord);
|
void add_vertex(const Vec2f& position, const Vec2f& tex_coord); // EVertexLayout::P2T2
|
||||||
void add_vertex(const Vec3f& position);
|
void add_vertex(const Vec3f& position); // EVertexLayout::P3
|
||||||
void add_vertex(const Vec3f& position, const Vec2f& tex_coord);
|
void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2
|
||||||
void add_vertex(const Vec3f& position, const Vec3f& normal);
|
void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void set_vertex(size_t id, const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3
|
||||||
|
|
||||||
|
void set_ushort_index(size_t id, unsigned short index);
|
||||||
|
void set_uint_index(size_t id, unsigned int index);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
void add_ushort_index(unsigned short id);
|
void add_ushort_index(unsigned short id);
|
||||||
void add_uint_index(unsigned int id);
|
void add_uint_index(unsigned int id);
|
||||||
@ -106,7 +116,11 @@ namespace GUI {
|
|||||||
unsigned int extract_uint_index(size_t id) const;
|
unsigned int extract_uint_index(size_t id) const;
|
||||||
unsigned short extract_ushort_index(size_t id) const;
|
unsigned short extract_ushort_index(size_t id) const;
|
||||||
|
|
||||||
bool is_empty() const { return vertices.empty() || indices.empty(); }
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void remove_vertex(size_t id);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
|
bool is_empty() const { return vertices_count() == 0 || indices_count() == 0; }
|
||||||
|
|
||||||
size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); }
|
size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); }
|
||||||
size_t indices_count() const { return indices.size() / index_stride_bytes(format); }
|
size_t indices_count() const { return indices.size() / index_stride_bytes(format); }
|
||||||
@ -135,6 +149,8 @@ namespace GUI {
|
|||||||
|
|
||||||
static size_t index_stride_bytes(const Format& format);
|
static size_t index_stride_bytes(const Format& format);
|
||||||
|
|
||||||
|
static EIndexType index_type(size_t vertices_count);
|
||||||
|
|
||||||
static bool has_position(const Format& format);
|
static bool has_position(const Format& format);
|
||||||
static bool has_normal(const Format& format);
|
static bool has_normal(const Format& format);
|
||||||
static bool has_tex_coord(const Format& format);
|
static bool has_tex_coord(const Format& format);
|
||||||
@ -177,6 +193,16 @@ namespace GUI {
|
|||||||
std::vector<RenderData> m_render_data;
|
std::vector<RenderData> m_render_data;
|
||||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
// By default the vertex and index buffers data are sent to gpu at the first call to render() method.
|
||||||
|
// If you need to initialize a model from outside the main thread, so that a call to render() may happen
|
||||||
|
// before the initialization is complete, use the methods:
|
||||||
|
// disable_render()
|
||||||
|
// ... do your initialization ...
|
||||||
|
// enable_render()
|
||||||
|
// to keep the data on cpu side until needed.
|
||||||
|
bool m_render_disabled{ false };
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
BoundingBoxf3 m_bounding_box;
|
BoundingBoxf3 m_bounding_box;
|
||||||
std::string m_filename;
|
std::string m_filename;
|
||||||
|
|
||||||
@ -195,8 +221,16 @@ namespace GUI {
|
|||||||
|
|
||||||
size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry.format); }
|
size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry.format); }
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
const Geometry& get_geometry() const { return m_render_data.geometry; }
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
void init_from(Geometry&& data);
|
void init_from(Geometry&& data);
|
||||||
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
void init_from(const TriangleMesh& mesh, bool smooth_normals = false);
|
||||||
|
#else
|
||||||
void init_from(const TriangleMesh& mesh);
|
void init_from(const TriangleMesh& mesh);
|
||||||
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
#else
|
#else
|
||||||
void init_from(const Geometry& data);
|
void init_from(const Geometry& data);
|
||||||
void init_from(const indexed_triangle_set& its, const BoundingBoxf3& bbox);
|
void init_from(const indexed_triangle_set& its, const BoundingBoxf3& bbox);
|
||||||
@ -217,9 +251,15 @@ namespace GUI {
|
|||||||
void reset();
|
void reset();
|
||||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
void render();
|
void render();
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
void render(const std::pair<size_t, size_t>& range);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
void render_instanced(unsigned int instances_vbo, unsigned int instances_count);
|
void render_instanced(unsigned int instances_vbo, unsigned int instances_count);
|
||||||
|
|
||||||
bool is_initialized() const { return vertices_count() > 0 && indices_count() > 0; }
|
bool is_initialized() const { return vertices_count() > 0 && indices_count() > 0; }
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
bool is_empty() const { return m_render_data.geometry.is_empty(); }
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
#else
|
#else
|
||||||
void render() const;
|
void render() const;
|
||||||
void render_instanced(unsigned int instances_vbo, unsigned int instances_count) const;
|
void render_instanced(unsigned int instances_vbo, unsigned int instances_count) const;
|
||||||
@ -230,6 +270,29 @@ namespace GUI {
|
|||||||
const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; }
|
const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; }
|
||||||
const std::string& get_filename() const { return m_filename; }
|
const std::string& get_filename() const { return m_filename; }
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
bool is_render_disabled() const { return m_render_disabled; }
|
||||||
|
void enable_render() { m_render_disabled = false; }
|
||||||
|
void disable_render() { m_render_disabled = true; }
|
||||||
|
|
||||||
|
size_t cpu_memory_used() const {
|
||||||
|
size_t ret = 0;
|
||||||
|
if (!m_render_data.geometry.vertices.empty())
|
||||||
|
ret += vertices_size_bytes();
|
||||||
|
if (!m_render_data.geometry.indices.empty())
|
||||||
|
ret += indices_size_bytes();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
size_t gpu_memory_used() const {
|
||||||
|
size_t ret = 0;
|
||||||
|
if (m_render_data.geometry.vertices.empty())
|
||||||
|
ret += vertices_size_bytes();
|
||||||
|
if (m_render_data.geometry.indices.empty())
|
||||||
|
ret += indices_size_bytes();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
bool send_to_gpu();
|
bool send_to_gpu();
|
||||||
@ -238,6 +301,10 @@ namespace GUI {
|
|||||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_bottom = true);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
|
||||||
// create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution
|
// create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution
|
||||||
// the origin of the arrow is in the center of the stem cap
|
// the origin of the arrow is in the center of the stem cap
|
||||||
// the arrow has its axis of symmetry along the Z axis and is pointing upward
|
// the arrow has its axis of symmetry along the Z axis and is pointing upward
|
||||||
|
@ -98,7 +98,7 @@ namespace GUI {
|
|||||||
color[1] = (m_state == Select) ? 1.0f : 0.3f;
|
color[1] = (m_state == Select) ? 1.0f : 0.3f;
|
||||||
color[2] = 0.3f;
|
color[2] = 0.3f;
|
||||||
glsafe(::glColor3fv(color));
|
glsafe(::glColor3fv(color));
|
||||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
#endif // !ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
|
||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
|
|
||||||
|
@ -496,7 +496,7 @@ static const FileWildcards file_wildcards_by_type[FT_SIZE] = {
|
|||||||
|
|
||||||
/* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } },
|
/* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } },
|
||||||
|
|
||||||
/* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv } },
|
/* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv, ".pwmx"sv } },
|
||||||
};
|
};
|
||||||
|
|
||||||
// This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms.
|
// This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms.
|
||||||
|
@ -274,9 +274,13 @@ static void generate_thumbnail_from_model(const std::string& filename)
|
|||||||
|
|
||||||
GLVolumeCollection volumes;
|
GLVolumeCollection volumes;
|
||||||
volumes.volumes.push_back(new GLVolume());
|
volumes.volumes.push_back(new GLVolume());
|
||||||
GLVolume* volume = volumes.volumes[0];
|
GLVolume* volume = volumes.volumes.back();
|
||||||
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
|
volume->model.init_from(model.mesh());
|
||||||
|
#else
|
||||||
volume->indexed_vertex_array.load_mesh(model.mesh());
|
volume->indexed_vertex_array.load_mesh(model.mesh());
|
||||||
volume->indexed_vertex_array.finalize_geometry(true);
|
volume->indexed_vertex_array.finalize_geometry(true);
|
||||||
|
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
volume->set_instance_transformation(model.objects[0]->instances[0]->get_transformation());
|
volume->set_instance_transformation(model.objects[0]->instances[0]->get_transformation());
|
||||||
volume->set_volume_transformation(model.objects[0]->volumes[0]->get_transformation());
|
volume->set_volume_transformation(model.objects[0]->volumes[0]->get_transformation());
|
||||||
|
|
||||||
|
@ -395,14 +395,13 @@ void GLGizmoFlatten::update_planes()
|
|||||||
for (auto& plane : m_planes) {
|
for (auto& plane : m_planes) {
|
||||||
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
|
||||||
GLModel::Geometry init_data;
|
GLModel::Geometry init_data;
|
||||||
const GLModel::Geometry::EIndexType index_type = (plane.vertices.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT;
|
init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(plane.vertices.size()) };
|
||||||
init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3, index_type };
|
|
||||||
init_data.reserve_vertices(plane.vertices.size());
|
init_data.reserve_vertices(plane.vertices.size());
|
||||||
init_data.reserve_indices(plane.vertices.size());
|
init_data.reserve_indices(plane.vertices.size());
|
||||||
// vertices + indices
|
// vertices + indices
|
||||||
for (size_t i = 0; i < plane.vertices.size(); ++i) {
|
for (size_t i = 0; i < plane.vertices.size(); ++i) {
|
||||||
init_data.add_vertex((Vec3f)plane.vertices[i].cast<float>(), (Vec3f)plane.normal.cast<float>());
|
init_data.add_vertex((Vec3f)plane.vertices[i].cast<float>(), (Vec3f)plane.normal.cast<float>());
|
||||||
if (index_type == GLModel::Geometry::EIndexType::USHORT)
|
if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||||
init_data.add_ushort_index((unsigned short)i);
|
init_data.add_ushort_index((unsigned short)i);
|
||||||
else
|
else
|
||||||
init_data.add_uint_index((unsigned int)i);
|
init_data.add_uint_index((unsigned int)i);
|
||||||
|
@ -1254,8 +1254,7 @@ void TriangleSelectorGUI::update_paint_contour()
|
|||||||
|
|
||||||
GLModel::Geometry init_data;
|
GLModel::Geometry init_data;
|
||||||
const std::vector<Vec2i> contour_edges = this->get_seed_fill_contour();
|
const std::vector<Vec2i> contour_edges = this->get_seed_fill_contour();
|
||||||
const GLModel::Geometry::EIndexType index_type = (2 * contour_edges.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT;
|
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, GLModel::Geometry::index_type(2 * contour_edges.size()) };
|
||||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3, index_type };
|
|
||||||
init_data.reserve_vertices(2 * contour_edges.size());
|
init_data.reserve_vertices(2 * contour_edges.size());
|
||||||
init_data.reserve_indices(2 * contour_edges.size());
|
init_data.reserve_indices(2 * contour_edges.size());
|
||||||
// vertices + indices
|
// vertices + indices
|
||||||
@ -1264,7 +1263,7 @@ void TriangleSelectorGUI::update_paint_contour()
|
|||||||
init_data.add_vertex(m_vertices[edge(0)].v);
|
init_data.add_vertex(m_vertices[edge(0)].v);
|
||||||
init_data.add_vertex(m_vertices[edge(1)].v);
|
init_data.add_vertex(m_vertices[edge(1)].v);
|
||||||
vertices_count += 2;
|
vertices_count += 2;
|
||||||
if (index_type == GLModel::Geometry::EIndexType::USHORT)
|
if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||||
init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1);
|
init_data.add_ushort_line((unsigned short)vertices_count - 2, (unsigned short)vertices_count - 1);
|
||||||
else
|
else
|
||||||
init_data.add_uint_line(vertices_count - 2, vertices_count - 1);
|
init_data.add_uint_line(vertices_count - 2, vertices_count - 1);
|
||||||
|
@ -172,15 +172,14 @@ void GLGizmoRotate::on_render()
|
|||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
|
|
||||||
const float radius = Offset + m_parent.get_selection().get_bounding_box().radius();
|
const bool radius_changed = std::abs(m_old_radius - m_radius) > EPSILON;
|
||||||
const bool radius_changed = std::abs(m_old_radius - radius) > EPSILON;
|
m_old_radius = m_radius;
|
||||||
m_old_radius = radius;
|
|
||||||
|
|
||||||
ColorRGBA color((m_hover_id != -1) ? m_drag_color : m_highlight_color);
|
ColorRGBA color((m_hover_id != -1) ? m_drag_color : m_highlight_color);
|
||||||
render_circle(color, radius_changed);
|
render_circle(color, radius_changed);
|
||||||
if (m_hover_id != -1) {
|
if (m_hover_id != -1) {
|
||||||
const bool hover_radius_changed = std::abs(m_old_hover_radius - radius) > EPSILON;
|
const bool hover_radius_changed = std::abs(m_old_hover_radius - m_radius) > EPSILON;
|
||||||
m_old_hover_radius = radius;
|
m_old_hover_radius = m_radius;
|
||||||
|
|
||||||
render_scale(color, hover_radius_changed);
|
render_scale(color, hover_radius_changed);
|
||||||
render_snap_radii(color, hover_radius_changed);
|
render_snap_radii(color, hover_radius_changed);
|
||||||
|
@ -129,6 +129,14 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
|||||||
if (! has_points && ! has_holes)
|
if (! has_points && ! has_holes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light");
|
||||||
|
if (shader == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
shader->start_using();
|
||||||
|
ScopeGuard guard([shader]() { shader->stop_using(); });
|
||||||
|
#else
|
||||||
GLShaderProgram* shader = picking ? nullptr : wxGetApp().get_shader("gouraud_light");
|
GLShaderProgram* shader = picking ? nullptr : wxGetApp().get_shader("gouraud_light");
|
||||||
if (shader != nullptr)
|
if (shader != nullptr)
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
@ -136,6 +144,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
|||||||
if (shader != nullptr)
|
if (shader != nullptr)
|
||||||
shader->stop_using();
|
shader->stop_using();
|
||||||
});
|
});
|
||||||
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
|
|
||||||
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
|
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||||
const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse();
|
const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse();
|
||||||
@ -179,11 +188,12 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
|||||||
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
#if ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
m_cone.set_color(render_color);
|
m_cone.set_color(render_color);
|
||||||
m_sphere.set_color(render_color);
|
m_sphere.set_color(render_color);
|
||||||
|
if (!picking)
|
||||||
#else
|
#else
|
||||||
m_cone.set_color(-1, render_color);
|
m_cone.set_color(-1, render_color);
|
||||||
m_sphere.set_color(-1, render_color);
|
m_sphere.set_color(-1, render_color);
|
||||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
|
||||||
if (shader && !picking)
|
if (shader && !picking)
|
||||||
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
shader->set_uniform("emission_factor", 0.5f);
|
shader->set_uniform("emission_factor", 0.5f);
|
||||||
|
|
||||||
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
|
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
|
||||||
@ -238,9 +248,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
|||||||
m_cylinder.set_color(render_color);
|
m_cylinder.set_color(render_color);
|
||||||
#else
|
#else
|
||||||
m_cylinder.set_color(-1, render_color);
|
m_cylinder.set_color(-1, render_color);
|
||||||
|
if (shader != nu)
|
||||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||||
if (shader)
|
shader->set_uniform("emission_factor", 0.5f);
|
||||||
shader->set_uniform("emission_factor", 0.5f);
|
|
||||||
for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) {
|
for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) {
|
||||||
if (is_mesh_point_clipped(drain_hole.pos.cast<double>()))
|
if (is_mesh_point_clipped(drain_hole.pos.cast<double>()))
|
||||||
continue;
|
continue;
|
||||||
|
@ -1444,8 +1444,8 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
|
|||||||
{
|
{
|
||||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x);
|
const int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x);
|
||||||
int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y);
|
const int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y);
|
||||||
if (fb_width == 0 || fb_height == 0)
|
if (fb_width == 0 || fb_height == 0)
|
||||||
return;
|
return;
|
||||||
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
|
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
|
||||||
@ -1488,8 +1488,7 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
|
|||||||
|
|
||||||
// Render command lists
|
// Render command lists
|
||||||
ImVec2 pos = draw_data->DisplayPos;
|
ImVec2 pos = draw_data->DisplayPos;
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
for (int n = 0; n < draw_data->CmdListsCount; ++n) {
|
||||||
{
|
|
||||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
|
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
|
||||||
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
||||||
@ -1497,19 +1496,14 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
|
|||||||
glsafe(::glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv))));
|
glsafe(::glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv))));
|
||||||
glsafe(::glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col))));
|
glsafe(::glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col))));
|
||||||
|
|
||||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; ++cmd_i) {
|
||||||
{
|
|
||||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
if (pcmd->UserCallback)
|
if (pcmd->UserCallback)
|
||||||
{
|
|
||||||
// User callback (registered via ImDrawList::AddCallback)
|
// User callback (registered via ImDrawList::AddCallback)
|
||||||
pcmd->UserCallback(cmd_list, pcmd);
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
}
|
else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y);
|
ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y);
|
||||||
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) {
|
||||||
{
|
|
||||||
// Apply scissor/clipping rectangle
|
// Apply scissor/clipping rectangle
|
||||||
glsafe(::glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)));
|
glsafe(::glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)));
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "SLAImportJob.hpp"
|
#include "SLAImportJob.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/SLAPrint.hpp"
|
||||||
#include "libslic3r/Format/SL1.hpp"
|
#include "libslic3r/Format/SL1.hpp"
|
||||||
|
|
||||||
#include "slic3r/GUI/GUI.hpp"
|
#include "slic3r/GUI/GUI.hpp"
|
||||||
|
@ -189,8 +189,7 @@ void MeshClipper::recalculate_triangles()
|
|||||||
m_model.reset();
|
m_model.reset();
|
||||||
|
|
||||||
GLModel::Geometry init_data;
|
GLModel::Geometry init_data;
|
||||||
const GLModel::Geometry::EIndexType index_type = (m_triangles2d.size() < 65536) ? GLModel::Geometry::EIndexType::USHORT : GLModel::Geometry::EIndexType::UINT;
|
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(m_triangles2d.size()) };
|
||||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, index_type };
|
|
||||||
init_data.reserve_vertices(m_triangles2d.size());
|
init_data.reserve_vertices(m_triangles2d.size());
|
||||||
init_data.reserve_indices(m_triangles2d.size());
|
init_data.reserve_indices(m_triangles2d.size());
|
||||||
|
|
||||||
@ -200,7 +199,7 @@ void MeshClipper::recalculate_triangles()
|
|||||||
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
|
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
|
||||||
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
|
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
|
||||||
const size_t idx = it - m_triangles2d.cbegin();
|
const size_t idx = it - m_triangles2d.cbegin();
|
||||||
if (index_type == GLModel::Geometry::EIndexType::USHORT)
|
if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
|
||||||
init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2);
|
init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2);
|
||||||
else
|
else
|
||||||
init_data.add_uint_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2);
|
init_data.add_uint_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "libslic3r/Point.hpp"
|
#include "libslic3r/Point.hpp"
|
||||||
#include "libslic3r/Geometry.hpp"
|
#include "libslic3r/Geometry.hpp"
|
||||||
|
#include "libslic3r/TriangleMesh.hpp"
|
||||||
#include "libslic3r/SLA/IndexedMesh.hpp"
|
#include "libslic3r/SLA/IndexedMesh.hpp"
|
||||||
#include "admesh/stl.h"
|
#include "admesh/stl.h"
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ public:
|
|||||||
GetBtnsListCtrl()->Rescale();
|
GetBtnsListCtrl()->Rescale();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Notebook::OnNavigationKey(wxNavigationKeyEvent& event)
|
void OnNavigationKey(wxNavigationKeyEvent& event)
|
||||||
{
|
{
|
||||||
if (event.IsWindowChange()) {
|
if (event.IsWindowChange()) {
|
||||||
// change pages
|
// change pages
|
||||||
|
@ -233,8 +233,9 @@ OpenGLManager::~OpenGLManager()
|
|||||||
bool OpenGLManager::init_gl()
|
bool OpenGLManager::init_gl()
|
||||||
{
|
{
|
||||||
if (!m_gl_initialized) {
|
if (!m_gl_initialized) {
|
||||||
if (glewInit() != GLEW_OK) {
|
GLenum err = glewInit();
|
||||||
BOOST_LOG_TRIVIAL(error) << "Unable to init glew library";
|
if (err != GLEW_OK) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Unable to init glew library: " << glewGetErrorString(err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_gl_initialized = true;
|
m_gl_initialized = true;
|
||||||
|
@ -4,4 +4,6 @@ target_link_libraries(${_TEST_NAME}_tests test_common libnest2d )
|
|||||||
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")
|
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")
|
||||||
|
|
||||||
# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ")
|
# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ")
|
||||||
add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "${CATCH_EXTRA_ARGS} exclude:[NotWorking]")
|
set(_catch_args "exclude:[NotWorking]")
|
||||||
|
list(APPEND _catch_args "${CATCH_EXTRA_ARGS}")
|
||||||
|
add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${_catch_args})
|
||||||
|
@ -3,9 +3,14 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp
|
|||||||
sla_print_tests.cpp
|
sla_print_tests.cpp
|
||||||
sla_test_utils.hpp sla_test_utils.cpp
|
sla_test_utils.hpp sla_test_utils.cpp
|
||||||
sla_supptgen_tests.cpp
|
sla_supptgen_tests.cpp
|
||||||
sla_raycast_tests.cpp)
|
sla_raycast_tests.cpp
|
||||||
|
sla_archive_export_tests.cpp)
|
||||||
target_link_libraries(${_TEST_NAME}_tests test_common libslic3r)
|
target_link_libraries(${_TEST_NAME}_tests test_common libslic3r)
|
||||||
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")
|
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
prusaslicer_copy_dlls(${_TEST_NAME}_tests)
|
||||||
|
endif()
|
||||||
|
|
||||||
# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ")
|
# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ")
|
||||||
add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${CATCH_EXTRA_ARGS})
|
add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${CATCH_EXTRA_ARGS})
|
||||||
|
40
tests/sla_print/sla_archive_export_tests.cpp
Normal file
40
tests/sla_print/sla_archive_export_tests.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#include <test_utils.hpp>
|
||||||
|
|
||||||
|
#include "libslic3r/SLAPrint.hpp"
|
||||||
|
#include "libslic3r/Format/SLAArchive.hpp"
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
using namespace Slic3r;
|
||||||
|
|
||||||
|
TEST_CASE("Archive export test", "[sla_archives]") {
|
||||||
|
constexpr const char *PNAME = "20mm_cube";
|
||||||
|
|
||||||
|
for (auto &archname : SLAArchive::registered_archives()) {
|
||||||
|
INFO(std::string("Testing archive type: ") + archname);
|
||||||
|
SLAPrint print;
|
||||||
|
SLAFullPrintConfig fullcfg;
|
||||||
|
|
||||||
|
auto m = Model::read_from_file(TEST_DATA_DIR PATH_SEPARATOR + std::string(PNAME) + ".obj", nullptr);
|
||||||
|
|
||||||
|
fullcfg.set("sla_archive_format", archname);
|
||||||
|
fullcfg.set("supports_enable", false);
|
||||||
|
fullcfg.set("pad_enable", false);
|
||||||
|
|
||||||
|
DynamicPrintConfig cfg;
|
||||||
|
cfg.apply(fullcfg);
|
||||||
|
|
||||||
|
print.set_status_callback([](const PrintBase::SlicingStatus&) {});
|
||||||
|
print.apply(m, cfg);
|
||||||
|
print.process();
|
||||||
|
|
||||||
|
ThumbnailsList thumbnails;
|
||||||
|
auto outputfname = std::string("output.") + SLAArchive::get_extension(archname);
|
||||||
|
|
||||||
|
print.export_print(outputfname, thumbnails, PNAME);
|
||||||
|
|
||||||
|
// Not much can be checked about the archives...
|
||||||
|
REQUIRE(boost::filesystem::exists(outputfname));
|
||||||
|
}
|
||||||
|
}
|
@ -15,4 +15,6 @@ if (WIN32)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ")
|
# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ")
|
||||||
add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "${CATCH_EXTRA_ARGS} exclude:[NotWorking]")
|
set(_catch_args "exclude:[NotWorking]")
|
||||||
|
list(APPEND _catch_args "${CATCH_EXTRA_ARGS}")
|
||||||
|
add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${_catch_args})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user