mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-06 05:05:11 +08:00
Merge remote-tracking branch 'remotes/origin/et_custom_bed'
This commit is contained in:
commit
ca1c78b3fc
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -5,16 +5,30 @@ const vec3 back_color_light = vec3(0.365, 0.365, 0.365);
|
|||||||
|
|
||||||
uniform sampler2D texture;
|
uniform sampler2D texture;
|
||||||
uniform bool transparent_background;
|
uniform bool transparent_background;
|
||||||
|
uniform bool svg_source;
|
||||||
|
|
||||||
varying vec2 tex_coords;
|
varying vec2 tex_coords;
|
||||||
|
|
||||||
void main()
|
vec4 svg_color()
|
||||||
{
|
{
|
||||||
|
// takes foreground from texture
|
||||||
|
vec4 fore_color = texture2D(texture, tex_coords);
|
||||||
|
|
||||||
// calculates radial gradient
|
// calculates radial gradient
|
||||||
vec3 back_color = vec3(mix(back_color_light, back_color_dark, smoothstep(0.0, 0.5, length(abs(tex_coords.xy) - vec2(0.5)))));
|
vec3 back_color = vec3(mix(back_color_light, back_color_dark, smoothstep(0.0, 0.5, length(abs(tex_coords.xy) - vec2(0.5)))));
|
||||||
|
|
||||||
vec4 fore_color = texture2D(texture, tex_coords);
|
|
||||||
|
|
||||||
// blends foreground with background
|
// blends foreground with background
|
||||||
gl_FragColor = vec4(mix(back_color, fore_color.rgb, fore_color.a), transparent_background ? fore_color.a : 1.0);
|
return vec4(mix(back_color, fore_color.rgb, fore_color.a), transparent_background ? fore_color.a : 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 non_svg_color()
|
||||||
|
{
|
||||||
|
// takes foreground from texture
|
||||||
|
vec4 color = texture2D(texture, tex_coords);
|
||||||
|
return vec4(color.rgb, transparent_background ? color.a * 0.25 : color.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_FragColor = svg_source ? svg_color() : non_svg_color();
|
||||||
}
|
}
|
@ -51,6 +51,16 @@ void PrintConfigDef::init_common_params()
|
|||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionPoints{ Vec2d(0, 0), Vec2d(200, 0), Vec2d(200, 200), Vec2d(0, 200) });
|
def->set_default_value(new ConfigOptionPoints{ Vec2d(0, 0), Vec2d(200, 0), Vec2d(200, 200), Vec2d(0, 200) });
|
||||||
|
|
||||||
|
def = this->add("bed_custom_texture", coString);
|
||||||
|
def->label = L("Bed custom texture");
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionString(""));
|
||||||
|
|
||||||
|
def = this->add("bed_custom_model", coString);
|
||||||
|
def->label = L("Bed custom model");
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionString(""));
|
||||||
|
|
||||||
def = this->add("layer_height", coFloat);
|
def = this->add("layer_height", coFloat);
|
||||||
def->label = L("Layer height");
|
def->label = L("Layer height");
|
||||||
def->category = L("Layers and Perimeters");
|
def->category = L("Layers and Perimeters");
|
||||||
|
@ -32,13 +32,4 @@
|
|||||||
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1)
|
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1)
|
||||||
|
|
||||||
|
|
||||||
//====================
|
|
||||||
// 1.42.0.alpha7 techs
|
|
||||||
//====================
|
|
||||||
#define ENABLE_1_42_0_ALPHA7 1
|
|
||||||
|
|
||||||
// Printbed textures generated from svg files
|
|
||||||
#define ENABLE_TEXTURES_FROM_SVG (1 && ENABLE_1_42_0_ALPHA7)
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _technologies_h_
|
#endif // _technologies_h_
|
||||||
|
@ -18,10 +18,9 @@ wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(25 * wxGetApp().em_unit(), -
|
|||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
m_user_drawn_background = false;
|
m_user_drawn_background = false;
|
||||||
#endif /*__APPLE__*/
|
#endif /*__APPLE__*/
|
||||||
Bind(wxEVT_PAINT, ([this](wxPaintEvent &/* e */) { repaint(); }));
|
|
||||||
Bind(wxEVT_SIZE, ([this](wxSizeEvent & /* e */) { Refresh(); }));
|
|
||||||
}
|
}
|
||||||
void Bed_2D::repaint()
|
|
||||||
|
void Bed_2D::repaint(const std::vector<Vec2d>& shape)
|
||||||
{
|
{
|
||||||
wxAutoBufferedPaintDC dc(this);
|
wxAutoBufferedPaintDC dc(this);
|
||||||
auto cw = GetSize().GetWidth();
|
auto cw = GetSize().GetWidth();
|
||||||
@ -41,7 +40,7 @@ void Bed_2D::repaint()
|
|||||||
dc.DrawRectangle(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight());
|
dc.DrawRectangle(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_bed_shape.empty())
|
if (shape.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// reduce size to have some space around the drawn shape
|
// reduce size to have some space around the drawn shape
|
||||||
@ -52,10 +51,9 @@ void Bed_2D::repaint()
|
|||||||
auto ccenter = cbb.center();
|
auto ccenter = cbb.center();
|
||||||
|
|
||||||
// get bounding box of bed shape in G - code coordinates
|
// get bounding box of bed shape in G - code coordinates
|
||||||
auto bed_shape = m_bed_shape;
|
auto bed_polygon = Polygon::new_scale(shape);
|
||||||
auto bed_polygon = Polygon::new_scale(m_bed_shape);
|
auto bb = BoundingBoxf(shape);
|
||||||
auto bb = BoundingBoxf(m_bed_shape);
|
bb.merge(Vec2d(0, 0)); // origin needs to be in the visible area
|
||||||
bb.merge(Vec2d(0, 0)); // origin needs to be in the visible area
|
|
||||||
auto bw = bb.size()(0);
|
auto bw = bb.size()(0);
|
||||||
auto bh = bb.size()(1);
|
auto bh = bb.size()(1);
|
||||||
auto bcenter = bb.center();
|
auto bcenter = bb.center();
|
||||||
@ -73,8 +71,8 @@ void Bed_2D::repaint()
|
|||||||
// draw bed fill
|
// draw bed fill
|
||||||
dc.SetBrush(wxBrush(wxColour(255, 255, 255), wxBRUSHSTYLE_SOLID));
|
dc.SetBrush(wxBrush(wxColour(255, 255, 255), wxBRUSHSTYLE_SOLID));
|
||||||
wxPointList pt_list;
|
wxPointList pt_list;
|
||||||
for (auto pt: m_bed_shape)
|
for (auto pt : shape)
|
||||||
{
|
{
|
||||||
Point pt_pix = to_pixels(pt, ch);
|
Point pt_pix = to_pixels(pt, ch);
|
||||||
pt_list.push_back(new wxPoint(pt_pix(0), pt_pix(1)));
|
pt_list.push_back(new wxPoint(pt_pix(0), pt_pix(1)));
|
||||||
}
|
}
|
||||||
@ -155,13 +153,13 @@ void Bed_2D::repaint()
|
|||||||
|
|
||||||
|
|
||||||
// convert G - code coordinates into pixels
|
// convert G - code coordinates into pixels
|
||||||
Point Bed_2D::to_pixels(Vec2d point, int height)
|
Point Bed_2D::to_pixels(const Vec2d& point, int height)
|
||||||
{
|
{
|
||||||
auto p = point * m_scale_factor + m_shift;
|
auto p = point * m_scale_factor + m_shift;
|
||||||
return Point(p(0) + Border, height - p(1) + Border);
|
return Point(p(0) + Border, height - p(1) + Border);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bed_2D::set_pos(Vec2d pos)
|
void Bed_2D::set_pos(const Vec2d& pos)
|
||||||
{
|
{
|
||||||
m_pos = pos;
|
m_pos = pos;
|
||||||
Refresh();
|
Refresh();
|
||||||
|
@ -17,16 +17,13 @@ class Bed_2D : public wxPanel
|
|||||||
Vec2d m_shift = Vec2d::Zero();
|
Vec2d m_shift = Vec2d::Zero();
|
||||||
Vec2d m_pos = Vec2d::Zero();
|
Vec2d m_pos = Vec2d::Zero();
|
||||||
|
|
||||||
Point to_pixels(Vec2d point, int height);
|
Point to_pixels(const Vec2d& point, int height);
|
||||||
void repaint();
|
void set_pos(const Vec2d& pos);
|
||||||
void set_pos(Vec2d pos);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Bed_2D(wxWindow* parent);
|
explicit Bed_2D(wxWindow* parent);
|
||||||
~Bed_2D() {}
|
|
||||||
|
|
||||||
std::vector<Vec2d> m_bed_shape;
|
|
||||||
|
|
||||||
|
void repaint(const std::vector<Vec2d>& shape);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
#include <boost/filesystem/operations.hpp>
|
||||||
|
|
||||||
static const float GROUND_Z = -0.02f;
|
static const float GROUND_Z = -0.02f;
|
||||||
|
|
||||||
@ -22,7 +23,6 @@ namespace GUI {
|
|||||||
|
|
||||||
bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z, bool generate_tex_coords)
|
bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z, bool generate_tex_coords)
|
||||||
{
|
{
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
m_vertices.clear();
|
m_vertices.clear();
|
||||||
unsigned int v_size = 3 * (unsigned int)triangles.size();
|
unsigned int v_size = 3 * (unsigned int)triangles.size();
|
||||||
|
|
||||||
@ -82,75 +82,12 @@ bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z, bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
m_vertices.clear();
|
|
||||||
m_tex_coords.clear();
|
|
||||||
|
|
||||||
unsigned int v_size = 9 * (unsigned int)triangles.size();
|
|
||||||
unsigned int t_size = 6 * (unsigned int)triangles.size();
|
|
||||||
if (v_size == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_vertices = std::vector<float>(v_size, 0.0f);
|
|
||||||
if (generate_tex_coords)
|
|
||||||
m_tex_coords = std::vector<float>(t_size, 0.0f);
|
|
||||||
|
|
||||||
float min_x = unscale<float>(triangles[0].points[0](0));
|
|
||||||
float min_y = unscale<float>(triangles[0].points[0](1));
|
|
||||||
float max_x = min_x;
|
|
||||||
float max_y = min_y;
|
|
||||||
|
|
||||||
unsigned int v_coord = 0;
|
|
||||||
unsigned int t_coord = 0;
|
|
||||||
for (const Polygon& t : triangles)
|
|
||||||
{
|
|
||||||
for (unsigned int v = 0; v < 3; ++v)
|
|
||||||
{
|
|
||||||
const Point& p = t.points[v];
|
|
||||||
float x = unscale<float>(p(0));
|
|
||||||
float y = unscale<float>(p(1));
|
|
||||||
|
|
||||||
m_vertices[v_coord++] = x;
|
|
||||||
m_vertices[v_coord++] = y;
|
|
||||||
m_vertices[v_coord++] = z;
|
|
||||||
|
|
||||||
if (generate_tex_coords)
|
|
||||||
{
|
|
||||||
m_tex_coords[t_coord++] = x;
|
|
||||||
m_tex_coords[t_coord++] = y;
|
|
||||||
|
|
||||||
min_x = std::min(min_x, x);
|
|
||||||
max_x = std::max(max_x, x);
|
|
||||||
min_y = std::min(min_y, y);
|
|
||||||
max_y = std::max(max_y, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (generate_tex_coords)
|
|
||||||
{
|
|
||||||
float size_x = max_x - min_x;
|
|
||||||
float size_y = max_y - min_y;
|
|
||||||
|
|
||||||
if ((size_x != 0.0f) && (size_y != 0.0f))
|
|
||||||
{
|
|
||||||
float inv_size_x = 1.0f / size_x;
|
|
||||||
float inv_size_y = -1.0f / size_y;
|
|
||||||
for (unsigned int i = 0; i < m_tex_coords.size(); i += 2)
|
|
||||||
{
|
|
||||||
m_tex_coords[i] = (m_tex_coords[i] - min_x) * inv_size_x;
|
|
||||||
m_tex_coords[i + 1] = (m_tex_coords[i + 1] - min_y) * inv_size_y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeometryBuffer::set_from_lines(const Lines& lines, float z)
|
bool GeometryBuffer::set_from_lines(const Lines& lines, float z)
|
||||||
{
|
{
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
m_vertices.clear();
|
m_vertices.clear();
|
||||||
|
|
||||||
unsigned int v_size = 2 * (unsigned int)lines.size();
|
unsigned int v_size = 2 * (unsigned int)lines.size();
|
||||||
@ -174,37 +111,14 @@ bool GeometryBuffer::set_from_lines(const Lines& lines, float z)
|
|||||||
v2.position[2] = z;
|
v2.position[2] = z;
|
||||||
++v_count;
|
++v_count;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
m_vertices.clear();
|
|
||||||
m_tex_coords.clear();
|
|
||||||
|
|
||||||
unsigned int size = 6 * (unsigned int)lines.size();
|
|
||||||
if (size == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_vertices = std::vector<float>(size, 0.0f);
|
|
||||||
|
|
||||||
unsigned int coord = 0;
|
|
||||||
for (const Line& l : lines)
|
|
||||||
{
|
|
||||||
m_vertices[coord++] = unscale<float>(l.a(0));
|
|
||||||
m_vertices[coord++] = unscale<float>(l.a(1));
|
|
||||||
m_vertices[coord++] = z;
|
|
||||||
m_vertices[coord++] = unscale<float>(l.b(0));
|
|
||||||
m_vertices[coord++] = unscale<float>(l.b(1));
|
|
||||||
m_vertices[coord++] = z;
|
|
||||||
}
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
const float* GeometryBuffer::get_vertices_data() const
|
const float* GeometryBuffer::get_vertices_data() const
|
||||||
{
|
{
|
||||||
return (m_vertices.size() > 0) ? (const float*)m_vertices.data() : nullptr;
|
return (m_vertices.size() > 0) ? (const float*)m_vertices.data() : nullptr;
|
||||||
}
|
}
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
const double Bed3D::Axes::Radius = 0.5;
|
const double Bed3D::Axes::Radius = 0.5;
|
||||||
const double Bed3D::Axes::ArrowBaseRadius = 2.5 * Bed3D::Axes::Radius;
|
const double Bed3D::Axes::ArrowBaseRadius = 2.5 * Bed3D::Axes::Radius;
|
||||||
@ -274,22 +188,41 @@ void Bed3D::Axes::render_axis(double length) const
|
|||||||
|
|
||||||
Bed3D::Bed3D()
|
Bed3D::Bed3D()
|
||||||
: m_type(Custom)
|
: m_type(Custom)
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
, m_custom_texture("")
|
||||||
|
, m_custom_model("")
|
||||||
, m_requires_canvas_update(false)
|
, m_requires_canvas_update(false)
|
||||||
, m_vbo_id(0)
|
, m_vbo_id(0)
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
, m_scale_factor(1.0f)
|
, m_scale_factor(1.0f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bed3D::set_shape(const Pointfs& shape)
|
bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model)
|
||||||
{
|
{
|
||||||
EType new_type = detect_type(shape);
|
EType new_type = detect_type(shape);
|
||||||
if (m_shape == shape && m_type == new_type)
|
|
||||||
|
// check that the passed custom texture filename is valid
|
||||||
|
std::string cst_texture(custom_texture);
|
||||||
|
if (!cst_texture.empty())
|
||||||
|
{
|
||||||
|
if ((!boost::algorithm::iends_with(custom_texture, ".png") && !boost::algorithm::iends_with(custom_texture, ".svg")) || !boost::filesystem::exists(custom_texture))
|
||||||
|
cst_texture = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the passed custom texture filename is valid
|
||||||
|
std::string cst_model(custom_model);
|
||||||
|
if (!cst_model.empty())
|
||||||
|
{
|
||||||
|
if (!boost::algorithm::iends_with(custom_model, ".stl") || !boost::filesystem::exists(custom_model))
|
||||||
|
cst_model = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_shape == shape) && (m_type == new_type) && (m_custom_texture == cst_texture) && (m_custom_model == cst_model))
|
||||||
// No change, no need to update the UI.
|
// No change, no need to update the UI.
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_shape = shape;
|
m_shape = shape;
|
||||||
|
m_custom_texture = cst_texture;
|
||||||
|
m_custom_model = cst_model;
|
||||||
m_type = new_type;
|
m_type = new_type;
|
||||||
|
|
||||||
calc_bounding_boxes();
|
calc_bounding_boxes();
|
||||||
@ -307,9 +240,9 @@ bool Bed3D::set_shape(const Pointfs& shape)
|
|||||||
|
|
||||||
m_polygon = offset_ex(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0].contour;
|
m_polygon = offset_ex(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0].contour;
|
||||||
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
reset();
|
reset();
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
m_texture.reset();
|
||||||
|
m_model.reset();
|
||||||
|
|
||||||
// Set the origin and size for painting of the coordinate system axes.
|
// Set the origin and size for painting of the coordinate system axes.
|
||||||
m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z);
|
m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z);
|
||||||
@ -329,11 +262,12 @@ Point Bed3D::point_projection(const Point& point) const
|
|||||||
return m_polygon.point_projection(point);
|
return m_polygon.point_projection(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor) const
|
||||||
void Bed3D::render(GLCanvas3D* canvas, float theta, float scale_factor) const
|
|
||||||
{
|
{
|
||||||
m_scale_factor = scale_factor;
|
m_scale_factor = scale_factor;
|
||||||
|
|
||||||
|
render_axes();
|
||||||
|
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
case MK2:
|
case MK2:
|
||||||
@ -354,51 +288,11 @@ void Bed3D::render(GLCanvas3D* canvas, float theta, float scale_factor) const
|
|||||||
default:
|
default:
|
||||||
case Custom:
|
case Custom:
|
||||||
{
|
{
|
||||||
render_custom();
|
render_custom(canvas, theta > 90.0f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
void Bed3D::render(float theta, float scale_factor) const
|
|
||||||
{
|
|
||||||
m_scale_factor = scale_factor;
|
|
||||||
|
|
||||||
if (m_shape.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (m_type)
|
|
||||||
{
|
|
||||||
case MK2:
|
|
||||||
{
|
|
||||||
render_prusa("mk2", theta);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MK3:
|
|
||||||
{
|
|
||||||
render_prusa("mk3", theta);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SL1:
|
|
||||||
{
|
|
||||||
render_prusa("sl1", theta);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
case Custom:
|
|
||||||
{
|
|
||||||
render_custom();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
void Bed3D::render_axes() const
|
|
||||||
{
|
|
||||||
if (!m_shape.empty())
|
|
||||||
m_axes.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Bed3D::calc_bounding_boxes() const
|
void Bed3D::calc_bounding_boxes() const
|
||||||
{
|
{
|
||||||
@ -423,7 +317,7 @@ void Bed3D::calc_triangles(const ExPolygon& poly)
|
|||||||
Polygons triangles;
|
Polygons triangles;
|
||||||
poly.triangulate(&triangles);
|
poly.triangulate(&triangles);
|
||||||
|
|
||||||
if (!m_triangles.set_from_triangles(triangles, GROUND_Z, m_type != Custom))
|
if (!m_triangles.set_from_triangles(triangles, GROUND_Z, true))
|
||||||
printf("Unable to create bed triangles\n");
|
printf("Unable to create bed triangles\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,31 +389,76 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
void Bed3D::render_axes() const
|
||||||
void Bed3D::render_prusa(GLCanvas3D* canvas, const std::string &key, bool bottom) const
|
|
||||||
{
|
{
|
||||||
std::string tex_path = resources_dir() + "/icons/bed/" + key;
|
if (!m_shape.empty())
|
||||||
|
m_axes.render();
|
||||||
|
}
|
||||||
|
|
||||||
std::string model_path = resources_dir() + "/models/" + key;
|
void Bed3D::render_prusa(GLCanvas3D& canvas, const std::string& key, bool bottom) const
|
||||||
|
{
|
||||||
|
if (!bottom)
|
||||||
|
render_model(m_custom_model.empty() ? resources_dir() + "/models/" + key + "_bed.stl" : m_custom_model);
|
||||||
|
|
||||||
// use higher resolution images if graphic card and opengl version allow
|
render_texture(m_custom_texture.empty() ? resources_dir() + "/icons/bed/" + key + ".svg" : m_custom_texture, bottom, canvas);
|
||||||
GLint max_tex_size = GLCanvas3DManager::get_gl_info().get_max_tex_size();
|
}
|
||||||
|
|
||||||
std::string filename = tex_path + ".svg";
|
void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D& canvas) const
|
||||||
|
{
|
||||||
|
if (filename.empty())
|
||||||
|
{
|
||||||
|
m_texture.reset();
|
||||||
|
render_default(bottom);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((m_texture.get_id() == 0) || (m_texture.get_source() != filename))
|
if ((m_texture.get_id() == 0) || (m_texture.get_source() != filename))
|
||||||
{
|
{
|
||||||
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
|
m_texture.reset();
|
||||||
if (!m_temp_texture.load_from_svg_file(filename, false, false, false, max_tex_size / 8))
|
|
||||||
{
|
|
||||||
render_custom();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// starts generating the main texture, compression will run asynchronously
|
if (boost::algorithm::iends_with(filename, ".svg"))
|
||||||
if (!m_texture.load_from_svg_file(filename, true, true, true, max_tex_size))
|
|
||||||
{
|
{
|
||||||
render_custom();
|
// use higher resolution images if graphic card and opengl version allow
|
||||||
|
GLint max_tex_size = GLCanvas3DManager::get_gl_info().get_max_tex_size();
|
||||||
|
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != filename))
|
||||||
|
{
|
||||||
|
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
|
||||||
|
if (!m_temp_texture.load_from_svg_file(filename, false, false, false, max_tex_size / 8))
|
||||||
|
{
|
||||||
|
render_default(bottom);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// starts generating the main texture, compression will run asynchronously
|
||||||
|
if (!m_texture.load_from_svg_file(filename, true, true, true, max_tex_size))
|
||||||
|
{
|
||||||
|
render_default(bottom);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (boost::algorithm::iends_with(filename, ".png"))
|
||||||
|
{
|
||||||
|
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
|
||||||
|
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != filename))
|
||||||
|
{
|
||||||
|
if (!m_temp_texture.load_from_file(filename, false, GLTexture::None, false))
|
||||||
|
{
|
||||||
|
render_default(bottom);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// starts generating the main texture, compression will run asynchronously
|
||||||
|
if (!m_texture.load_from_file(filename, true, GLTexture::MultiThreaded, true))
|
||||||
|
{
|
||||||
|
render_default(bottom);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
render_default(bottom);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -536,292 +475,161 @@ void Bed3D::render_prusa(GLCanvas3D* canvas, const std::string &key, bool bottom
|
|||||||
}
|
}
|
||||||
else if (m_requires_canvas_update && m_texture.all_compressed_data_sent_to_gpu())
|
else if (m_requires_canvas_update && m_texture.all_compressed_data_sent_to_gpu())
|
||||||
{
|
{
|
||||||
if (canvas != nullptr)
|
canvas.stop_keeping_dirty();
|
||||||
canvas->stop_keeping_dirty();
|
|
||||||
|
|
||||||
m_requires_canvas_update = false;
|
m_requires_canvas_update = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bottom)
|
if (m_triangles.get_vertices_count() > 0)
|
||||||
{
|
{
|
||||||
filename = model_path + "_bed.stl";
|
if (m_shader.get_shader_program_id() == 0)
|
||||||
if ((m_model.get_filename() != filename) && m_model.init_from_file(filename)) {
|
m_shader.init("printbed.vs", "printbed.fs");
|
||||||
Vec3d offset = m_bounding_box.center() - Vec3d(0.0, 0.0, 0.5 * m_model.get_bounding_box().size()(2));
|
|
||||||
if (key == "mk2")
|
|
||||||
// hardcoded value to match the stl model
|
|
||||||
offset += Vec3d(0.0, 7.5, -0.03);
|
|
||||||
else if (key == "mk3")
|
|
||||||
// hardcoded value to match the stl model
|
|
||||||
offset += Vec3d(0.0, 5.5, 2.43);
|
|
||||||
else if (key == "sl1")
|
|
||||||
// hardcoded value to match the stl model
|
|
||||||
offset += Vec3d(0.0, 0.0, -0.03);
|
|
||||||
|
|
||||||
m_model.center_around(offset);
|
if (m_shader.is_initialized())
|
||||||
|
|
||||||
// update extended bounding box
|
|
||||||
calc_bounding_boxes();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_model.get_filename().empty())
|
|
||||||
{
|
{
|
||||||
glsafe(::glEnable(GL_LIGHTING));
|
m_shader.start_using();
|
||||||
m_model.render();
|
m_shader.set_uniform("transparent_background", bottom);
|
||||||
glsafe(::glDisable(GL_LIGHTING));
|
m_shader.set_uniform("svg_source", boost::algorithm::iends_with(m_texture.get_source(), ".svg"));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int triangles_vcount = m_triangles.get_vertices_count();
|
if (m_vbo_id == 0)
|
||||||
if (triangles_vcount > 0)
|
{
|
||||||
{
|
glsafe(::glGenBuffers(1, &m_vbo_id));
|
||||||
if (m_vbo_id == 0)
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
||||||
{
|
glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW));
|
||||||
glsafe(::glGenBuffers(1, &m_vbo_id));
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
|
glsafe(::glDepthMask(GL_FALSE));
|
||||||
|
|
||||||
|
glsafe(::glEnable(GL_BLEND));
|
||||||
|
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||||
|
|
||||||
|
if (bottom)
|
||||||
|
glsafe(::glFrontFace(GL_CW));
|
||||||
|
|
||||||
|
unsigned int stride = m_triangles.get_vertex_data_size();
|
||||||
|
|
||||||
|
GLint position_id = m_shader.get_attrib_location("v_position");
|
||||||
|
GLint tex_coords_id = m_shader.get_attrib_location("v_tex_coords");
|
||||||
|
|
||||||
|
// show the temporary texture while no compressed data is available
|
||||||
|
GLuint tex_id = (GLuint)m_temp_texture.get_id();
|
||||||
|
if (tex_id == 0)
|
||||||
|
tex_id = (GLuint)m_texture.get_id();
|
||||||
|
|
||||||
|
glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id));
|
||||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
||||||
glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW));
|
|
||||||
|
if (position_id != -1)
|
||||||
|
{
|
||||||
|
glsafe(::glEnableVertexAttribArray(position_id));
|
||||||
|
glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_position_offset()));
|
||||||
|
}
|
||||||
|
if (tex_coords_id != -1)
|
||||||
|
{
|
||||||
|
glsafe(::glEnableVertexAttribArray(tex_coords_id));
|
||||||
|
glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_tex_coords_offset()));
|
||||||
|
}
|
||||||
|
|
||||||
|
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count()));
|
||||||
|
|
||||||
|
if (tex_coords_id != -1)
|
||||||
|
glsafe(::glDisableVertexAttribArray(tex_coords_id));
|
||||||
|
|
||||||
|
if (position_id != -1)
|
||||||
|
glsafe(::glDisableVertexAttribArray(position_id));
|
||||||
|
|
||||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||||
}
|
|
||||||
|
|
||||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
|
||||||
glsafe(::glDepthMask(GL_FALSE));
|
|
||||||
|
|
||||||
glsafe(::glEnable(GL_BLEND));
|
|
||||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
|
||||||
|
|
||||||
if (bottom)
|
|
||||||
glsafe(::glFrontFace(GL_CW));
|
|
||||||
|
|
||||||
render_prusa_shader(bottom);
|
|
||||||
|
|
||||||
if (bottom)
|
|
||||||
glsafe(::glFrontFace(GL_CCW));
|
|
||||||
|
|
||||||
glsafe(::glDisable(GL_BLEND));
|
|
||||||
glsafe(::glDepthMask(GL_TRUE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Bed3D::render_prusa_shader(bool transparent) const
|
|
||||||
{
|
|
||||||
if (m_shader.get_shader_program_id() == 0)
|
|
||||||
m_shader.init("printbed.vs", "printbed.fs");
|
|
||||||
|
|
||||||
if (m_shader.is_initialized())
|
|
||||||
{
|
|
||||||
m_shader.start_using();
|
|
||||||
m_shader.set_uniform("transparent_background", transparent);
|
|
||||||
|
|
||||||
unsigned int stride = m_triangles.get_vertex_data_size();
|
|
||||||
|
|
||||||
GLint position_id = m_shader.get_attrib_location("v_position");
|
|
||||||
GLint tex_coords_id = m_shader.get_attrib_location("v_tex_coords");
|
|
||||||
|
|
||||||
// show the temporary texture while no compressed data is available
|
|
||||||
GLuint tex_id = (GLuint)m_temp_texture.get_id();
|
|
||||||
if (tex_id == 0)
|
|
||||||
tex_id = (GLuint)m_texture.get_id();
|
|
||||||
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id));
|
|
||||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
|
||||||
|
|
||||||
if (position_id != -1)
|
|
||||||
{
|
|
||||||
glsafe(::glEnableVertexAttribArray(position_id));
|
|
||||||
glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_position_offset()));
|
|
||||||
}
|
|
||||||
if (tex_coords_id != -1)
|
|
||||||
{
|
|
||||||
glsafe(::glEnableVertexAttribArray(tex_coords_id));
|
|
||||||
glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_tex_coords_offset()));
|
|
||||||
}
|
|
||||||
|
|
||||||
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count()));
|
|
||||||
|
|
||||||
if (tex_coords_id != -1)
|
|
||||||
glsafe(::glDisableVertexAttribArray(tex_coords_id));
|
|
||||||
|
|
||||||
if (position_id != -1)
|
|
||||||
glsafe(::glDisableVertexAttribArray(position_id));
|
|
||||||
|
|
||||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
|
||||||
|
|
||||||
m_shader.stop_using();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void Bed3D::render_prusa(const std::string& key, float theta) const
|
|
||||||
{
|
|
||||||
std::string tex_path = resources_dir() + "/icons/bed/" + key;
|
|
||||||
|
|
||||||
// use higher resolution images if graphic card allows
|
|
||||||
GLint max_tex_size;
|
|
||||||
glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size));
|
|
||||||
|
|
||||||
// temporary set to lowest resolution
|
|
||||||
max_tex_size = 2048;
|
|
||||||
|
|
||||||
if (max_tex_size >= 8192)
|
|
||||||
tex_path += "_8192";
|
|
||||||
else if (max_tex_size >= 4096)
|
|
||||||
tex_path += "_4096";
|
|
||||||
|
|
||||||
std::string model_path = resources_dir() + "/models/" + key;
|
|
||||||
|
|
||||||
// use anisotropic filter if graphic card allows
|
|
||||||
GLfloat max_anisotropy = 0.0f;
|
|
||||||
if (glewIsSupported("GL_EXT_texture_filter_anisotropic"))
|
|
||||||
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy));
|
|
||||||
|
|
||||||
std::string filename = tex_path + "_top.png";
|
|
||||||
if ((m_top_texture.get_id() == 0) || (m_top_texture.get_source() != filename))
|
|
||||||
{
|
|
||||||
if (!m_top_texture.load_from_file(filename, true, true))
|
|
||||||
{
|
|
||||||
render_custom();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_anisotropy > 0.0f)
|
|
||||||
{
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_top_texture.get_id()));
|
|
||||||
glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||||
|
|
||||||
|
if (bottom)
|
||||||
|
glsafe(::glFrontFace(GL_CCW));
|
||||||
|
|
||||||
|
glsafe(::glDisable(GL_BLEND));
|
||||||
|
glsafe(::glDepthMask(GL_TRUE));
|
||||||
|
|
||||||
|
m_shader.stop_using();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = tex_path + "_bottom.png";
|
|
||||||
if ((m_bottom_texture.get_id() == 0) || (m_bottom_texture.get_source() != filename))
|
|
||||||
{
|
|
||||||
if (!m_bottom_texture.load_from_file(filename, true, true))
|
|
||||||
{
|
|
||||||
render_custom();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_anisotropy > 0.0f)
|
|
||||||
{
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_bottom_texture.get_id()));
|
|
||||||
glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (theta <= 90.0f)
|
|
||||||
{
|
|
||||||
filename = model_path + "_bed.stl";
|
|
||||||
if ((m_model.get_filename() != filename) && m_model.init_from_file(filename)) {
|
|
||||||
Vec3d offset = m_bounding_box.center() - Vec3d(0.0, 0.0, 0.5 * m_model.get_bounding_box().size()(2));
|
|
||||||
if (key == "mk2")
|
|
||||||
// hardcoded value to match the stl model
|
|
||||||
offset += Vec3d(0.0, 7.5, -0.03);
|
|
||||||
else if (key == "mk3")
|
|
||||||
// hardcoded value to match the stl model
|
|
||||||
offset += Vec3d(0.0, 5.5, 2.43);
|
|
||||||
else if (key == "sl1")
|
|
||||||
// hardcoded value to match the stl model
|
|
||||||
offset += Vec3d(0.0, 0.0, -0.03);
|
|
||||||
|
|
||||||
m_model.center_around(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_model.get_filename().empty())
|
|
||||||
{
|
|
||||||
glsafe(::glEnable(GL_LIGHTING));
|
|
||||||
m_model.render();
|
|
||||||
glsafe(::glDisable(GL_LIGHTING));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int triangles_vcount = m_triangles.get_vertices_count();
|
|
||||||
if (triangles_vcount > 0)
|
|
||||||
{
|
|
||||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
|
||||||
glsafe(::glDepthMask(GL_FALSE));
|
|
||||||
|
|
||||||
glsafe(::glEnable(GL_BLEND));
|
|
||||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
|
||||||
|
|
||||||
glsafe(::glEnable(GL_TEXTURE_2D));
|
|
||||||
glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE));
|
|
||||||
|
|
||||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
|
||||||
glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
|
||||||
|
|
||||||
if (theta > 90.0f)
|
|
||||||
glsafe(::glFrontFace(GL_CW));
|
|
||||||
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, (theta <= 90.0f) ? (GLuint)m_top_texture.get_id() : (GLuint)m_bottom_texture.get_id()));
|
|
||||||
glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices()));
|
|
||||||
glsafe(::glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)m_triangles.get_tex_coords()));
|
|
||||||
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount));
|
|
||||||
|
|
||||||
if (theta > 90.0f)
|
|
||||||
glsafe(::glFrontFace(GL_CCW));
|
|
||||||
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
|
||||||
glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY));
|
|
||||||
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
|
||||||
|
|
||||||
glsafe(::glDisable(GL_TEXTURE_2D));
|
|
||||||
|
|
||||||
glsafe(::glDisable(GL_BLEND));
|
|
||||||
glsafe(::glDepthMask(GL_TRUE));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
void Bed3D::render_custom() const
|
void Bed3D::render_model(const std::string& filename) const
|
||||||
{
|
{
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
if (filename.empty())
|
||||||
m_texture.reset();
|
return;
|
||||||
#else
|
|
||||||
m_top_texture.reset();
|
|
||||||
m_bottom_texture.reset();
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
unsigned int triangles_vcount = m_triangles.get_vertices_count();
|
if ((m_model.get_filename() != filename) && m_model.init_from_file(filename))
|
||||||
if (triangles_vcount > 0)
|
{
|
||||||
|
// move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad
|
||||||
|
Vec3d shift = m_bounding_box.center();
|
||||||
|
shift(2) = -0.03;
|
||||||
|
m_model.set_offset(shift);
|
||||||
|
|
||||||
|
// update extended bounding box
|
||||||
|
calc_bounding_boxes();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_model.get_filename().empty())
|
||||||
{
|
{
|
||||||
glsafe(::glEnable(GL_LIGHTING));
|
glsafe(::glEnable(GL_LIGHTING));
|
||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
m_model.render();
|
||||||
|
|
||||||
glsafe(::glEnable(GL_BLEND));
|
|
||||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
|
||||||
|
|
||||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
|
||||||
|
|
||||||
glsafe(::glColor4f(0.35f, 0.35f, 0.35f, 0.4f));
|
|
||||||
glsafe(::glNormal3d(0.0f, 0.0f, 1.0f));
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data()));
|
|
||||||
#else
|
|
||||||
glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices()));
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount));
|
|
||||||
|
|
||||||
// draw grid
|
|
||||||
unsigned int gridlines_vcount = m_gridlines.get_vertices_count();
|
|
||||||
|
|
||||||
// we need depth test for grid, otherwise it would disappear when looking the object from below
|
|
||||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
|
||||||
glsafe(::glLineWidth(3.0f * m_scale_factor));
|
|
||||||
glsafe(::glColor4f(0.2f, 0.2f, 0.2f, 0.4f));
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data()));
|
|
||||||
#else
|
|
||||||
glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_gridlines.get_vertices()));
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)gridlines_vcount));
|
|
||||||
|
|
||||||
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
|
||||||
|
|
||||||
glsafe(::glDisable(GL_BLEND));
|
|
||||||
glsafe(::glDisable(GL_LIGHTING));
|
glsafe(::glDisable(GL_LIGHTING));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const
|
||||||
|
{
|
||||||
|
if (m_custom_texture.empty() && m_custom_model.empty())
|
||||||
|
{
|
||||||
|
render_default(bottom);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bottom)
|
||||||
|
render_model(m_custom_model);
|
||||||
|
|
||||||
|
render_texture(m_custom_texture, bottom, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bed3D::render_default(bool bottom) const
|
||||||
|
{
|
||||||
|
m_texture.reset();
|
||||||
|
|
||||||
|
unsigned int triangles_vcount = m_triangles.get_vertices_count();
|
||||||
|
if (triangles_vcount > 0)
|
||||||
|
{
|
||||||
|
bool has_model = !m_model.get_filename().empty();
|
||||||
|
|
||||||
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
|
glsafe(::glEnable(GL_BLEND));
|
||||||
|
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||||
|
|
||||||
|
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||||
|
|
||||||
|
if (!has_model && !bottom)
|
||||||
|
{
|
||||||
|
// draw background
|
||||||
|
glsafe(::glColor4f(0.35f, 0.35f, 0.35f, 0.4f));
|
||||||
|
glsafe(::glNormal3d(0.0f, 0.0f, 1.0f));
|
||||||
|
glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data()));
|
||||||
|
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount));
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw grid
|
||||||
|
glsafe(::glLineWidth(3.0f * m_scale_factor));
|
||||||
|
if (has_model && !bottom)
|
||||||
|
glsafe(::glColor4f(0.75f, 0.75f, 0.75f, 1.0f));
|
||||||
|
else
|
||||||
|
glsafe(::glColor4f(0.2f, 0.2f, 0.2f, 0.4f));
|
||||||
|
glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data()));
|
||||||
|
glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_gridlines.get_vertices_count()));
|
||||||
|
|
||||||
|
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
||||||
|
|
||||||
|
glsafe(::glDisable(GL_BLEND));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Bed3D::reset()
|
void Bed3D::reset()
|
||||||
{
|
{
|
||||||
if (m_vbo_id > 0)
|
if (m_vbo_id > 0)
|
||||||
@ -830,7 +638,6 @@ void Bed3D::reset()
|
|||||||
m_vbo_id = 0;
|
m_vbo_id = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
} // GUI
|
} // GUI
|
||||||
} // Slic3r
|
} // Slic3r
|
@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
#include "GLTexture.hpp"
|
#include "GLTexture.hpp"
|
||||||
#include "3DScene.hpp"
|
#include "3DScene.hpp"
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
#include "GLShader.hpp"
|
#include "GLShader.hpp"
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
class GLUquadric;
|
class GLUquadric;
|
||||||
typedef class GLUquadric GLUquadricObj;
|
typedef class GLUquadric GLUquadricObj;
|
||||||
@ -17,7 +15,6 @@ class GLCanvas3D;
|
|||||||
|
|
||||||
class GeometryBuffer
|
class GeometryBuffer
|
||||||
{
|
{
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
struct Vertex
|
struct Vertex
|
||||||
{
|
{
|
||||||
float position[3];
|
float position[3];
|
||||||
@ -31,27 +28,17 @@ class GeometryBuffer
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Vertex> m_vertices;
|
std::vector<Vertex> m_vertices;
|
||||||
#else
|
|
||||||
std::vector<float> m_vertices;
|
|
||||||
std::vector<float> m_tex_coords;
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool set_from_triangles(const Polygons& triangles, float z, bool generate_tex_coords);
|
bool set_from_triangles(const Polygons& triangles, float z, bool generate_tex_coords);
|
||||||
bool set_from_lines(const Lines& lines, float z);
|
bool set_from_lines(const Lines& lines, float z);
|
||||||
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
const float* get_vertices_data() const;
|
const float* get_vertices_data() const;
|
||||||
unsigned int get_vertices_data_size() const { return (unsigned int)m_vertices.size() * get_vertex_data_size(); }
|
unsigned int get_vertices_data_size() const { return (unsigned int)m_vertices.size() * get_vertex_data_size(); }
|
||||||
unsigned int get_vertex_data_size() const { return (unsigned int)(5 * sizeof(float)); }
|
unsigned int get_vertex_data_size() const { return (unsigned int)(5 * sizeof(float)); }
|
||||||
size_t get_position_offset() const { return 0; }
|
size_t get_position_offset() const { return 0; }
|
||||||
size_t get_tex_coords_offset() const { return (size_t)(3 * sizeof(float)); }
|
size_t get_tex_coords_offset() const { return (size_t)(3 * sizeof(float)); }
|
||||||
unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size(); }
|
unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size(); }
|
||||||
#else
|
|
||||||
const float* get_vertices() const { return m_vertices.data(); }
|
|
||||||
const float* get_tex_coords() const { return m_tex_coords.data(); }
|
|
||||||
unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size() / 3; }
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Bed3D
|
class Bed3D
|
||||||
@ -87,12 +74,13 @@ public:
|
|||||||
private:
|
private:
|
||||||
EType m_type;
|
EType m_type;
|
||||||
Pointfs m_shape;
|
Pointfs m_shape;
|
||||||
|
std::string m_custom_texture;
|
||||||
|
std::string m_custom_model;
|
||||||
mutable BoundingBoxf3 m_bounding_box;
|
mutable BoundingBoxf3 m_bounding_box;
|
||||||
mutable BoundingBoxf3 m_extended_bounding_box;
|
mutable BoundingBoxf3 m_extended_bounding_box;
|
||||||
Polygon m_polygon;
|
Polygon m_polygon;
|
||||||
GeometryBuffer m_triangles;
|
GeometryBuffer m_triangles;
|
||||||
GeometryBuffer m_gridlines;
|
GeometryBuffer m_gridlines;
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
mutable GLTexture m_texture;
|
mutable GLTexture m_texture;
|
||||||
// temporary texture shown until the main texture has still no levels compressed
|
// temporary texture shown until the main texture has still no levels compressed
|
||||||
mutable GLTexture m_temp_texture;
|
mutable GLTexture m_temp_texture;
|
||||||
@ -100,10 +88,6 @@ private:
|
|||||||
mutable bool m_requires_canvas_update;
|
mutable bool m_requires_canvas_update;
|
||||||
mutable Shader m_shader;
|
mutable Shader m_shader;
|
||||||
mutable unsigned int m_vbo_id;
|
mutable unsigned int m_vbo_id;
|
||||||
#else
|
|
||||||
mutable GLTexture m_top_texture;
|
|
||||||
mutable GLTexture m_bottom_texture;
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
mutable GLBed m_model;
|
mutable GLBed m_model;
|
||||||
Axes m_axes;
|
Axes m_axes;
|
||||||
|
|
||||||
@ -111,9 +95,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Bed3D();
|
Bed3D();
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
~Bed3D() { reset(); }
|
~Bed3D() { reset(); }
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
EType get_type() const { return m_type; }
|
EType get_type() const { return m_type; }
|
||||||
|
|
||||||
@ -122,34 +104,26 @@ public:
|
|||||||
|
|
||||||
const Pointfs& get_shape() const { return m_shape; }
|
const Pointfs& get_shape() const { return m_shape; }
|
||||||
// Return true if the bed shape changed, so the calee will update the UI.
|
// Return true if the bed shape changed, so the calee will update the UI.
|
||||||
bool set_shape(const Pointfs& shape);
|
bool set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model);
|
||||||
|
|
||||||
const BoundingBoxf3& get_bounding_box(bool extended) const { return extended ? m_extended_bounding_box : m_bounding_box; }
|
const BoundingBoxf3& get_bounding_box(bool extended) const { return extended ? m_extended_bounding_box : m_bounding_box; }
|
||||||
bool contains(const Point& point) const;
|
bool contains(const Point& point) const;
|
||||||
Point point_projection(const Point& point) const;
|
Point point_projection(const Point& point) const;
|
||||||
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
void render(GLCanvas3D& canvas, float theta, float scale_factor) const;
|
||||||
void render(GLCanvas3D* canvas, float theta, float scale_factor) const;
|
|
||||||
#else
|
|
||||||
void render(float theta, float scale_factor) const;
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
void render_axes() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void calc_bounding_boxes() const;
|
void calc_bounding_boxes() const;
|
||||||
void calc_triangles(const ExPolygon& poly);
|
void calc_triangles(const ExPolygon& poly);
|
||||||
void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox);
|
void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox);
|
||||||
EType detect_type(const Pointfs& shape) const;
|
EType detect_type(const Pointfs& shape) const;
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
void render_axes() const;
|
||||||
void render_prusa(GLCanvas3D* canvas, const std::string& key, bool bottom) const;
|
void render_prusa(GLCanvas3D& canvas, const std::string& key, bool bottom) const;
|
||||||
void render_prusa_shader(bool transparent) const;
|
void render_texture(const std::string& filename, bool bottom, GLCanvas3D& canvas) const;
|
||||||
#else
|
void render_model(const std::string& filename) const;
|
||||||
void render_prusa(const std::string& key, float theta) const;
|
void render_custom(GLCanvas3D& canvas, bool bottom) const;
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
void render_default(bool bottom) const;
|
||||||
void render_custom() const;
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
void reset();
|
void reset();
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // GUI
|
} // GUI
|
||||||
|
@ -1736,13 +1736,7 @@ bool GLBed::on_init_from_file(const std::string& filename)
|
|||||||
|
|
||||||
m_filename = filename;
|
m_filename = filename;
|
||||||
|
|
||||||
ModelObject* model_object = model.objects.front();
|
m_volume.indexed_vertex_array.load_mesh(model.mesh());
|
||||||
model_object->center_around_origin();
|
|
||||||
|
|
||||||
TriangleMesh mesh = model.mesh();
|
|
||||||
mesh.repair();
|
|
||||||
|
|
||||||
m_volume.indexed_vertex_array.load_mesh(mesh);
|
|
||||||
|
|
||||||
float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f };
|
float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f };
|
||||||
set_color(color, 4);
|
set_color(color, 4);
|
||||||
|
@ -4,23 +4,25 @@
|
|||||||
#include <wx/numformatter.h>
|
#include <wx/numformatter.h>
|
||||||
#include <wx/sizer.h>
|
#include <wx/sizer.h>
|
||||||
#include <wx/statbox.h>
|
#include <wx/statbox.h>
|
||||||
|
#include <wx/tooltip.h>
|
||||||
|
|
||||||
#include "libslic3r/BoundingBox.hpp"
|
#include "libslic3r/BoundingBox.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
#include "libslic3r/Polygon.hpp"
|
#include "libslic3r/Polygon.hpp"
|
||||||
|
|
||||||
#include "boost/nowide/iostream.hpp"
|
#include "boost/nowide/iostream.hpp"
|
||||||
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
void BedShapeDialog::build_dialog(ConfigOptionPoints* default_pt)
|
void BedShapeDialog::build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model)
|
||||||
{
|
{
|
||||||
SetFont(wxGetApp().normal_font());
|
SetFont(wxGetApp().normal_font());
|
||||||
m_panel = new BedShapePanel(this);
|
m_panel = new BedShapePanel(this);
|
||||||
m_panel->build_panel(default_pt);
|
m_panel->build_panel(default_pt, custom_texture, custom_model);
|
||||||
|
|
||||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
main_sizer->Add(m_panel, 1, wxEXPAND);
|
main_sizer->Add(m_panel, 1, wxEXPAND);
|
||||||
@ -51,59 +53,69 @@ void BedShapeDialog::on_dpi_changed(const wxRect &suggested_rect)
|
|||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
const std::string BedShapePanel::NONE = "None";
|
||||||
|
const std::string BedShapePanel::EMPTY_STRING = "";
|
||||||
|
|
||||||
|
void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model)
|
||||||
{
|
{
|
||||||
|
m_shape = default_pt.values;
|
||||||
|
m_custom_texture = custom_texture.value.empty() ? NONE : custom_texture.value;
|
||||||
|
m_custom_model = custom_model.value.empty() ? NONE : custom_model.value;
|
||||||
|
|
||||||
auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape")));
|
auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape")));
|
||||||
|
sbsizer->GetStaticBox()->SetFont(wxGetApp().bold_font());
|
||||||
|
|
||||||
// shape options
|
// shape options
|
||||||
m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition,
|
m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition, wxSize(25*wxGetApp().em_unit(), -1), wxCHB_TOP);
|
||||||
wxSize(25*wxGetApp().em_unit(), -1), wxCHB_TOP);
|
|
||||||
sbsizer->Add(m_shape_options_book);
|
sbsizer->Add(m_shape_options_book);
|
||||||
|
|
||||||
auto optgroup = init_shape_options_page(_(L("Rectangular")));
|
auto optgroup = init_shape_options_page(_(L("Rectangular")));
|
||||||
ConfigOptionDef def;
|
ConfigOptionDef def;
|
||||||
def.type = coPoints;
|
def.type = coPoints;
|
||||||
def.set_default_value(new ConfigOptionPoints{ Vec2d(200, 200) });
|
def.set_default_value(new ConfigOptionPoints{ Vec2d(200, 200) });
|
||||||
def.label = L("Size");
|
def.label = L("Size");
|
||||||
def.tooltip = L("Size in X and Y of the rectangular plate.");
|
def.tooltip = L("Size in X and Y of the rectangular plate.");
|
||||||
Option option(def, "rect_size");
|
Option option(def, "rect_size");
|
||||||
optgroup->append_single_option_line(option);
|
optgroup->append_single_option_line(option);
|
||||||
|
|
||||||
def.type = coPoints;
|
def.type = coPoints;
|
||||||
def.set_default_value(new ConfigOptionPoints{ Vec2d(0, 0) });
|
def.set_default_value(new ConfigOptionPoints{ Vec2d(0, 0) });
|
||||||
def.label = L("Origin");
|
def.label = L("Origin");
|
||||||
def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.");
|
def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.");
|
||||||
option = Option(def, "rect_origin");
|
option = Option(def, "rect_origin");
|
||||||
optgroup->append_single_option_line(option);
|
optgroup->append_single_option_line(option);
|
||||||
|
|
||||||
optgroup = init_shape_options_page(_(L("Circular")));
|
optgroup = init_shape_options_page(_(L("Circular")));
|
||||||
def.type = coFloat;
|
def.type = coFloat;
|
||||||
def.set_default_value(new ConfigOptionFloat(200));
|
def.set_default_value(new ConfigOptionFloat(200));
|
||||||
def.sidetext = L("mm");
|
def.sidetext = L("mm");
|
||||||
def.label = L("Diameter");
|
def.label = L("Diameter");
|
||||||
def.tooltip = L("Diameter of the print bed. It is assumed that origin (0,0) is located in the center.");
|
def.tooltip = L("Diameter of the print bed. It is assumed that origin (0,0) is located in the center.");
|
||||||
option = Option(def, "diameter");
|
option = Option(def, "diameter");
|
||||||
optgroup->append_single_option_line(option);
|
optgroup->append_single_option_line(option);
|
||||||
|
|
||||||
optgroup = init_shape_options_page(_(L("Custom")));
|
optgroup = init_shape_options_page(_(L("Custom")));
|
||||||
Line line{ "", "" };
|
Line line{ "", "" };
|
||||||
line.full_width = 1;
|
line.full_width = 1;
|
||||||
line.widget = [this](wxWindow* parent) {
|
line.widget = [this](wxWindow* parent) {
|
||||||
auto shape_btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")));
|
wxButton* shape_btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")));
|
||||||
wxSizer* shape_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxSizer* shape_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
shape_sizer->Add(shape_btn, 1, wxEXPAND);
|
shape_sizer->Add(shape_btn, 1, wxEXPAND);
|
||||||
|
|
||||||
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
sizer->Add(shape_sizer, 1, wxEXPAND);
|
sizer->Add(shape_sizer, 1, wxEXPAND);
|
||||||
|
|
||||||
shape_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
shape_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||||
{
|
{
|
||||||
load_stl();
|
load_stl();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return sizer;
|
return sizer;
|
||||||
};
|
};
|
||||||
optgroup->append_line(line);
|
optgroup->append_line(line);
|
||||||
|
|
||||||
|
wxPanel* texture_panel = init_texture_panel();
|
||||||
|
wxPanel* model_panel = init_model_panel();
|
||||||
|
|
||||||
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e)
|
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e)
|
||||||
{
|
{
|
||||||
@ -112,13 +124,17 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||||||
|
|
||||||
// right pane with preview canvas
|
// right pane with preview canvas
|
||||||
m_canvas = new Bed_2D(this);
|
m_canvas = new Bed_2D(this);
|
||||||
m_canvas->m_bed_shape = default_pt->values;
|
m_canvas->Bind(wxEVT_PAINT, [this](wxPaintEvent& e) { m_canvas->repaint(m_shape); });
|
||||||
|
m_canvas->Bind(wxEVT_SIZE, [this](wxSizeEvent& e) { m_canvas->Refresh(); });
|
||||||
|
|
||||||
// main sizer
|
wxSizer* left_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
auto top_sizer = new wxBoxSizer(wxHORIZONTAL);
|
left_sizer->Add(sbsizer, 0, wxEXPAND);
|
||||||
top_sizer->Add(sbsizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 10);
|
left_sizer->Add(texture_panel, 1, wxEXPAND);
|
||||||
if (m_canvas)
|
left_sizer->Add(model_panel, 1, wxEXPAND);
|
||||||
top_sizer->Add(m_canvas, 1, wxEXPAND | wxALL, 10) ;
|
|
||||||
|
wxSizer* top_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
top_sizer->Add(left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 10);
|
||||||
|
top_sizer->Add(m_canvas, 1, wxEXPAND | wxALL, 10);
|
||||||
|
|
||||||
SetSizerAndFit(top_sizer);
|
SetSizerAndFit(top_sizer);
|
||||||
|
|
||||||
@ -134,20 +150,155 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||||||
// Create a panel for a rectangular / circular / custom bed shape.
|
// Create a panel for a rectangular / circular / custom bed shape.
|
||||||
ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& title)
|
ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& title)
|
||||||
{
|
{
|
||||||
auto panel = new wxPanel(m_shape_options_book);
|
wxPanel* panel = new wxPanel(m_shape_options_book);
|
||||||
ConfigOptionsGroupShp optgroup;
|
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Settings")));
|
||||||
optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Settings")));
|
|
||||||
|
|
||||||
optgroup->label_width = 10;
|
optgroup->label_width = 10;
|
||||||
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||||
update_shape();
|
update_shape();
|
||||||
};
|
};
|
||||||
|
|
||||||
m_optgroups.push_back(optgroup);
|
m_optgroups.push_back(optgroup);
|
||||||
panel->SetSizerAndFit(optgroup->sizer);
|
panel->SetSizerAndFit(optgroup->sizer);
|
||||||
m_shape_options_book->AddPage(panel, title);
|
m_shape_options_book->AddPage(panel, title);
|
||||||
|
|
||||||
return optgroup;
|
return optgroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxPanel* BedShapePanel::init_texture_panel()
|
||||||
|
{
|
||||||
|
wxPanel* panel = new wxPanel(this);
|
||||||
|
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Texture")));
|
||||||
|
|
||||||
|
optgroup->label_width = 10;
|
||||||
|
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||||
|
update_shape();
|
||||||
|
};
|
||||||
|
|
||||||
|
Line line{ "", "" };
|
||||||
|
line.full_width = 1;
|
||||||
|
line.widget = [this](wxWindow* parent) {
|
||||||
|
wxButton* load_btn = new wxButton(parent, wxID_ANY, _(L("Load...")));
|
||||||
|
wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
load_sizer->Add(load_btn, 1, wxEXPAND);
|
||||||
|
|
||||||
|
wxStaticText* filename_lbl = new wxStaticText(parent, wxID_ANY, _(NONE));
|
||||||
|
wxSizer* filename_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
filename_sizer->Add(filename_lbl, 1, wxEXPAND);
|
||||||
|
|
||||||
|
wxButton* remove_btn = new wxButton(parent, wxID_ANY, _(L("Remove")));
|
||||||
|
wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
remove_sizer->Add(remove_btn, 1, wxEXPAND);
|
||||||
|
|
||||||
|
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
sizer->Add(filename_sizer, 1, wxEXPAND);
|
||||||
|
sizer->Add(load_sizer, 1, wxEXPAND);
|
||||||
|
sizer->Add(remove_sizer, 1, wxEXPAND);
|
||||||
|
|
||||||
|
load_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||||
|
{
|
||||||
|
load_texture();
|
||||||
|
}));
|
||||||
|
|
||||||
|
remove_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||||
|
{
|
||||||
|
m_custom_texture = NONE;
|
||||||
|
update_shape();
|
||||||
|
}));
|
||||||
|
|
||||||
|
filename_lbl->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e)
|
||||||
|
{
|
||||||
|
e.SetText(_(boost::filesystem::path(m_custom_texture).filename().string()));
|
||||||
|
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
|
||||||
|
if (lbl != nullptr)
|
||||||
|
{
|
||||||
|
wxString tooltip_text = (m_custom_texture == NONE) ? _(L("")) : _(m_custom_texture);
|
||||||
|
wxToolTip* tooltip = lbl->GetToolTip();
|
||||||
|
if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text))
|
||||||
|
lbl->SetToolTip(tooltip_text);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
remove_btn->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e)
|
||||||
|
{
|
||||||
|
e.Enable(m_custom_texture != NONE);
|
||||||
|
}));
|
||||||
|
|
||||||
|
return sizer;
|
||||||
|
};
|
||||||
|
optgroup->append_line(line);
|
||||||
|
|
||||||
|
panel->SetSizerAndFit(optgroup->sizer);
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxPanel* BedShapePanel::init_model_panel()
|
||||||
|
{
|
||||||
|
wxPanel* panel = new wxPanel(this);
|
||||||
|
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Model")));
|
||||||
|
|
||||||
|
optgroup->label_width = 10;
|
||||||
|
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||||
|
update_shape();
|
||||||
|
};
|
||||||
|
|
||||||
|
Line line{ "", "" };
|
||||||
|
line.full_width = 1;
|
||||||
|
line.widget = [this](wxWindow* parent) {
|
||||||
|
wxButton* load_btn = new wxButton(parent, wxID_ANY, _(L("Load...")));
|
||||||
|
wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
load_sizer->Add(load_btn, 1, wxEXPAND);
|
||||||
|
|
||||||
|
wxStaticText* filename_lbl = new wxStaticText(parent, wxID_ANY, _(NONE));
|
||||||
|
wxSizer* filename_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
filename_sizer->Add(filename_lbl, 1, wxEXPAND);
|
||||||
|
|
||||||
|
wxButton* remove_btn = new wxButton(parent, wxID_ANY, _(L("Remove")));
|
||||||
|
wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
remove_sizer->Add(remove_btn, 1, wxEXPAND);
|
||||||
|
|
||||||
|
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
sizer->Add(filename_sizer, 1, wxEXPAND);
|
||||||
|
sizer->Add(load_sizer, 1, wxEXPAND);
|
||||||
|
sizer->Add(remove_sizer, 1, wxEXPAND);
|
||||||
|
|
||||||
|
load_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||||
|
{
|
||||||
|
load_model();
|
||||||
|
}));
|
||||||
|
|
||||||
|
remove_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||||
|
{
|
||||||
|
m_custom_model = NONE;
|
||||||
|
update_shape();
|
||||||
|
}));
|
||||||
|
|
||||||
|
filename_lbl->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e)
|
||||||
|
{
|
||||||
|
e.SetText(_(boost::filesystem::path(m_custom_model).filename().string()));
|
||||||
|
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
|
||||||
|
if (lbl != nullptr)
|
||||||
|
{
|
||||||
|
wxString tooltip_text = (m_custom_model == NONE) ? _(L("")) : _(m_custom_model);
|
||||||
|
wxToolTip* tooltip = lbl->GetToolTip();
|
||||||
|
if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text))
|
||||||
|
lbl->SetToolTip(tooltip_text);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
remove_btn->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e)
|
||||||
|
{
|
||||||
|
e.Enable(m_custom_model != NONE);
|
||||||
|
}));
|
||||||
|
|
||||||
|
return sizer;
|
||||||
|
};
|
||||||
|
optgroup->append_line(line);
|
||||||
|
|
||||||
|
panel->SetSizerAndFit(optgroup->sizer);
|
||||||
|
|
||||||
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from the constructor.
|
// Called from the constructor.
|
||||||
@ -155,20 +306,20 @@ ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& tit
|
|||||||
// Deduce the bed shape type(rect, circle, custom)
|
// Deduce the bed shape type(rect, circle, custom)
|
||||||
// This routine shall be smart enough if the user messes up
|
// This routine shall be smart enough if the user messes up
|
||||||
// with the list of points in the ini file directly.
|
// with the list of points in the ini file directly.
|
||||||
void BedShapePanel::set_shape(ConfigOptionPoints* points)
|
void BedShapePanel::set_shape(const ConfigOptionPoints& points)
|
||||||
{
|
{
|
||||||
auto polygon = Polygon::new_scale(points->values);
|
auto polygon = Polygon::new_scale(points.values);
|
||||||
|
|
||||||
// is this a rectangle ?
|
// is this a rectangle ?
|
||||||
if (points->size() == 4) {
|
if (points.size() == 4) {
|
||||||
auto lines = polygon.lines();
|
auto lines = polygon.lines();
|
||||||
if (lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3])) {
|
if (lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3])) {
|
||||||
// okay, it's a rectangle
|
// okay, it's a rectangle
|
||||||
// find origin
|
// find origin
|
||||||
coordf_t x_min, x_max, y_min, y_max;
|
coordf_t x_min, x_max, y_min, y_max;
|
||||||
x_max = x_min = points->values[0](0);
|
x_max = x_min = points.values[0](0);
|
||||||
y_max = y_min = points->values[0](1);
|
y_max = y_min = points.values[0](1);
|
||||||
for (auto pt : points->values)
|
for (auto pt : points.values)
|
||||||
{
|
{
|
||||||
x_min = std::min(x_min, pt(0));
|
x_min = std::min(x_min, pt(0));
|
||||||
x_max = std::max(x_max, pt(0));
|
x_max = std::max(x_max, pt(0));
|
||||||
@ -219,8 +370,8 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (points->size() < 3) {
|
if (points.size() < 3) {
|
||||||
// Invalid polygon.Revert to default bed dimensions.
|
// Invalid polygon.Revert to default bed dimensions.
|
||||||
m_shape_options_book->SetSelection(SHAPE_RECTANGULAR);
|
m_shape_options_book->SetSelection(SHAPE_RECTANGULAR);
|
||||||
auto optgroup = m_optgroups[SHAPE_RECTANGULAR];
|
auto optgroup = m_optgroups[SHAPE_RECTANGULAR];
|
||||||
optgroup->set_value("rect_size", new ConfigOptionPoints{ Vec2d(200, 200) });
|
optgroup->set_value("rect_size", new ConfigOptionPoints{ Vec2d(200, 200) });
|
||||||
@ -232,7 +383,7 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
|
|||||||
// This is a custom bed shape, use the polygon provided.
|
// This is a custom bed shape, use the polygon provided.
|
||||||
m_shape_options_book->SetSelection(SHAPE_CUSTOM);
|
m_shape_options_book->SetSelection(SHAPE_CUSTOM);
|
||||||
// Copy the polygon to the canvas, make a copy of the array.
|
// Copy the polygon to the canvas, make a copy of the array.
|
||||||
m_loaded_bed_shape = points->values;
|
m_loaded_shape = points.values;
|
||||||
update_shape();
|
update_shape();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,11 +428,11 @@ void BedShapePanel::update_shape()
|
|||||||
x1 -= dx;
|
x1 -= dx;
|
||||||
y0 -= dy;
|
y0 -= dy;
|
||||||
y1 -= dy;
|
y1 -= dy;
|
||||||
m_canvas->m_bed_shape = { Vec2d(x0, y0),
|
m_shape = { Vec2d(x0, y0),
|
||||||
Vec2d(x1, y0),
|
Vec2d(x1, y0),
|
||||||
Vec2d(x1, y1),
|
Vec2d(x1, y1),
|
||||||
Vec2d(x0, y1)};
|
Vec2d(x0, y1) };
|
||||||
}
|
}
|
||||||
else if(page_idx == SHAPE_CIRCULAR) {
|
else if(page_idx == SHAPE_CIRCULAR) {
|
||||||
double diameter;
|
double diameter;
|
||||||
try{
|
try{
|
||||||
@ -293,16 +444,16 @@ void BedShapePanel::update_shape()
|
|||||||
if (diameter == 0.0) return ;
|
if (diameter == 0.0) return ;
|
||||||
auto r = diameter / 2;
|
auto r = diameter / 2;
|
||||||
auto twopi = 2 * PI;
|
auto twopi = 2 * PI;
|
||||||
auto edges = 60;
|
auto edges = 72;
|
||||||
std::vector<Vec2d> points;
|
std::vector<Vec2d> points;
|
||||||
for (size_t i = 1; i <= 60; ++i) {
|
for (size_t i = 1; i <= edges; ++i) {
|
||||||
auto angle = i * twopi / edges;
|
auto angle = i * twopi / edges;
|
||||||
points.push_back(Vec2d(r*cos(angle), r*sin(angle)));
|
points.push_back(Vec2d(r*cos(angle), r*sin(angle)));
|
||||||
}
|
}
|
||||||
m_canvas->m_bed_shape = points;
|
m_shape = points;
|
||||||
}
|
}
|
||||||
else if (page_idx == SHAPE_CUSTOM)
|
else if (page_idx == SHAPE_CUSTOM)
|
||||||
m_canvas->m_bed_shape = m_loaded_bed_shape;
|
m_shape = m_loaded_shape;
|
||||||
|
|
||||||
update_preview();
|
update_preview();
|
||||||
}
|
}
|
||||||
@ -310,27 +461,27 @@ void BedShapePanel::update_shape()
|
|||||||
// Loads an stl file, projects it to the XY plane and calculates a polygon.
|
// Loads an stl file, projects it to the XY plane and calculates a polygon.
|
||||||
void BedShapePanel::load_stl()
|
void BedShapePanel::load_stl()
|
||||||
{
|
{
|
||||||
auto dialog = new wxFileDialog(this, _(L("Choose a file to import bed shape from (STL/OBJ/AMF/3MF/PRUSA):")), "", "",
|
wxFileDialog dialog(this, _(L("Choose an STL file to import bed shape from:")), "", "", file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||||
file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
if (dialog.ShowModal() != wxID_OK)
|
||||||
if (dialog->ShowModal() != wxID_OK) {
|
return;
|
||||||
dialog->Destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wxArrayString input_file;
|
|
||||||
dialog->GetPaths(input_file);
|
|
||||||
dialog->Destroy();
|
|
||||||
|
|
||||||
std::string file_name = input_file[0].ToUTF8().data();
|
std::string file_name = dialog.GetPath().ToUTF8().data();
|
||||||
|
if (!boost::algorithm::iends_with(file_name, ".stl"))
|
||||||
|
{
|
||||||
|
show_error(this, _(L("Invalid file format.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxBusyCursor wait;
|
||||||
|
|
||||||
Model model;
|
Model model;
|
||||||
try {
|
try {
|
||||||
model = Model::read_from_file(file_name);
|
model = Model::read_from_file(file_name);
|
||||||
}
|
|
||||||
catch (std::exception &e) {
|
|
||||||
auto msg = _(L("Error!")) + " " + file_name + " : " + e.what() + ".";
|
|
||||||
show_error(this, msg);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
catch (std::exception &) {
|
||||||
|
show_error(this, _(L("Error! Invalid model")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto mesh = model.mesh();
|
auto mesh = model.mesh();
|
||||||
auto expolygons = mesh.horizontal_projection();
|
auto expolygons = mesh.horizontal_projection();
|
||||||
@ -349,7 +500,53 @@ void BedShapePanel::load_stl()
|
|||||||
for (auto pt : polygon.points)
|
for (auto pt : polygon.points)
|
||||||
points.push_back(unscale(pt));
|
points.push_back(unscale(pt));
|
||||||
|
|
||||||
m_loaded_bed_shape = points;
|
m_loaded_shape = points;
|
||||||
|
update_shape();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BedShapePanel::load_texture()
|
||||||
|
{
|
||||||
|
wxFileDialog dialog(this, _(L("Choose a file to import bed texture from (PNG/SVG):")), "", "",
|
||||||
|
file_wildcards(FT_TEX), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||||
|
|
||||||
|
if (dialog.ShowModal() != wxID_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_custom_texture = NONE;
|
||||||
|
|
||||||
|
std::string file_name = dialog.GetPath().ToUTF8().data();
|
||||||
|
if (!boost::algorithm::iends_with(file_name, ".png") && !boost::algorithm::iends_with(file_name, ".svg"))
|
||||||
|
{
|
||||||
|
show_error(this, _(L("Invalid file format.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxBusyCursor wait;
|
||||||
|
|
||||||
|
m_custom_texture = file_name;
|
||||||
|
update_shape();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BedShapePanel::load_model()
|
||||||
|
{
|
||||||
|
wxFileDialog dialog(this, _(L("Choose an STL file to import bed model from:")), "", "",
|
||||||
|
file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||||
|
|
||||||
|
if (dialog.ShowModal() != wxID_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_custom_model = NONE;
|
||||||
|
|
||||||
|
std::string file_name = dialog.GetPath().ToUTF8().data();
|
||||||
|
if (!boost::algorithm::iends_with(file_name, ".stl"))
|
||||||
|
{
|
||||||
|
show_error(this, _(L("Invalid file format.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxBusyCursor wait;
|
||||||
|
|
||||||
|
m_custom_model = file_name;
|
||||||
update_shape();
|
update_shape();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,27 +16,40 @@ namespace GUI {
|
|||||||
using ConfigOptionsGroupShp = std::shared_ptr<ConfigOptionsGroup>;
|
using ConfigOptionsGroupShp = std::shared_ptr<ConfigOptionsGroup>;
|
||||||
class BedShapePanel : public wxPanel
|
class BedShapePanel : public wxPanel
|
||||||
{
|
{
|
||||||
|
static const std::string NONE;
|
||||||
|
static const std::string EMPTY_STRING;
|
||||||
|
|
||||||
Bed_2D* m_canvas;
|
Bed_2D* m_canvas;
|
||||||
std::vector<Vec2d> m_loaded_bed_shape;
|
std::vector<Vec2d> m_shape;
|
||||||
|
std::vector<Vec2d> m_loaded_shape;
|
||||||
|
std::string m_custom_texture;
|
||||||
|
std::string m_custom_model;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BedShapePanel(wxWindow* parent) : wxPanel(parent, wxID_ANY) {}
|
BedShapePanel(wxWindow* parent) : wxPanel(parent, wxID_ANY), m_custom_texture(NONE), m_custom_model(NONE) {}
|
||||||
~BedShapePanel() {}
|
|
||||||
|
|
||||||
void build_panel(ConfigOptionPoints* default_pt);
|
void build_panel(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model);
|
||||||
|
|
||||||
|
// Returns the resulting bed shape polygon. This value will be stored to the ini file.
|
||||||
|
const std::vector<Vec2d>& get_shape() const { return m_shape; }
|
||||||
|
const std::string& get_custom_texture() const { return (m_custom_texture != NONE) ? m_custom_texture : EMPTY_STRING; }
|
||||||
|
const std::string& get_custom_model() const { return (m_custom_model != NONE) ? m_custom_model : EMPTY_STRING; }
|
||||||
|
|
||||||
|
private:
|
||||||
ConfigOptionsGroupShp init_shape_options_page(const wxString& title);
|
ConfigOptionsGroupShp init_shape_options_page(const wxString& title);
|
||||||
void set_shape(ConfigOptionPoints* points);
|
wxPanel* init_texture_panel();
|
||||||
void update_preview();
|
wxPanel* init_model_panel();
|
||||||
|
void set_shape(const ConfigOptionPoints& points);
|
||||||
|
void update_preview();
|
||||||
void update_shape();
|
void update_shape();
|
||||||
void load_stl();
|
void load_stl();
|
||||||
|
void load_texture();
|
||||||
// Returns the resulting bed shape polygon. This value will be stored to the ini file.
|
void load_model();
|
||||||
std::vector<Vec2d> GetValue() { return m_canvas->m_bed_shape; }
|
|
||||||
|
|
||||||
wxChoicebook* m_shape_options_book;
|
wxChoicebook* m_shape_options_book;
|
||||||
std::vector <ConfigOptionsGroupShp> m_optgroups;
|
std::vector <ConfigOptionsGroupShp> m_optgroups;
|
||||||
|
|
||||||
|
friend class BedShapeDialog;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BedShapeDialog : public DPIDialog
|
class BedShapeDialog : public DPIDialog
|
||||||
@ -45,10 +58,12 @@ class BedShapeDialog : public DPIDialog
|
|||||||
public:
|
public:
|
||||||
BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")),
|
BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")),
|
||||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {}
|
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {}
|
||||||
~BedShapeDialog() {}
|
|
||||||
|
|
||||||
void build_dialog(ConfigOptionPoints* default_pt);
|
void build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model);
|
||||||
std::vector<Vec2d> GetValue() { return m_panel->GetValue(); }
|
|
||||||
|
const std::vector<Vec2d>& get_shape() const { return m_panel->get_shape(); }
|
||||||
|
const std::string& get_custom_texture() const { return m_panel->get_custom_texture(); }
|
||||||
|
const std::string& get_custom_model() const { return m_panel->get_custom_model(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||||
|
@ -532,15 +532,21 @@ PageBedShape::PageBedShape(ConfigWizard *parent)
|
|||||||
{
|
{
|
||||||
append_text(_(L("Set the shape of your printer's bed.")));
|
append_text(_(L("Set the shape of your printer's bed.")));
|
||||||
|
|
||||||
shape_panel->build_panel(wizard_p()->custom_config->option<ConfigOptionPoints>("bed_shape"));
|
shape_panel->build_panel(*wizard_p()->custom_config->option<ConfigOptionPoints>("bed_shape"),
|
||||||
|
*wizard_p()->custom_config->option<ConfigOptionString>("bed_custom_texture"),
|
||||||
|
*wizard_p()->custom_config->option<ConfigOptionString>("bed_custom_model"));
|
||||||
|
|
||||||
append(shape_panel);
|
append(shape_panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageBedShape::apply_custom_config(DynamicPrintConfig &config)
|
void PageBedShape::apply_custom_config(DynamicPrintConfig &config)
|
||||||
{
|
{
|
||||||
const auto points(shape_panel->GetValue());
|
const std::vector<Vec2d>& points = shape_panel->get_shape();
|
||||||
auto *opt = new ConfigOptionPoints(points);
|
const std::string& custom_texture = shape_panel->get_custom_texture();
|
||||||
config.set_key_value("bed_shape", opt);
|
const std::string& custom_model = shape_panel->get_custom_model();
|
||||||
|
config.set_key_value("bed_shape", new ConfigOptionPoints(points));
|
||||||
|
config.set_key_value("bed_custom_texture", new ConfigOptionString(custom_texture));
|
||||||
|
config.set_key_value("bed_custom_model", new ConfigOptionString(custom_model));
|
||||||
}
|
}
|
||||||
|
|
||||||
PageDiameters::PageDiameters(ConfigWizard *parent)
|
PageDiameters::PageDiameters(ConfigWizard *parent)
|
||||||
@ -1086,7 +1092,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason)
|
|||||||
|
|
||||||
p->load_vendors();
|
p->load_vendors();
|
||||||
p->custom_config.reset(DynamicPrintConfig::new_from_defaults_keys({
|
p->custom_config.reset(DynamicPrintConfig::new_from_defaults_keys({
|
||||||
"gcode_flavor", "bed_shape", "nozzle_diameter", "filament_diameter", "temperature", "bed_temperature",
|
"gcode_flavor", "bed_shape", "bed_custom_texture", "bed_custom_model", "nozzle_diameter", "filament_diameter", "temperature", "bed_temperature",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
p->index = new ConfigWizardIndex(this);
|
p->index = new ConfigWizardIndex(this);
|
||||||
|
@ -116,87 +116,6 @@ void Size::set_scale_factor(int scale_factor)
|
|||||||
m_scale_factor = scale_factor;
|
m_scale_factor = scale_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !ENABLE_TEXTURES_FROM_SVG
|
|
||||||
GLCanvas3D::Shader::Shader()
|
|
||||||
: m_shader(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
GLCanvas3D::Shader::~Shader()
|
|
||||||
{
|
|
||||||
_reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLCanvas3D::Shader::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename)
|
|
||||||
{
|
|
||||||
if (is_initialized())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
m_shader = new GLShader();
|
|
||||||
if (m_shader != nullptr)
|
|
||||||
{
|
|
||||||
if (!m_shader->load_from_file(fragment_shader_filename.c_str(), vertex_shader_filename.c_str()))
|
|
||||||
{
|
|
||||||
std::cout << "Compilaton of shader failed:" << std::endl;
|
|
||||||
std::cout << m_shader->last_error << std::endl;
|
|
||||||
_reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLCanvas3D::Shader::is_initialized() const
|
|
||||||
{
|
|
||||||
return (m_shader != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLCanvas3D::Shader::start_using() const
|
|
||||||
{
|
|
||||||
if (is_initialized())
|
|
||||||
{
|
|
||||||
m_shader->enable();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLCanvas3D::Shader::stop_using() const
|
|
||||||
{
|
|
||||||
if (m_shader != nullptr)
|
|
||||||
m_shader->disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLCanvas3D::Shader::set_uniform(const std::string& name, float value) const
|
|
||||||
{
|
|
||||||
if (m_shader != nullptr)
|
|
||||||
m_shader->set_uniform(name.c_str(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLCanvas3D::Shader::set_uniform(const std::string& name, const float* matrix) const
|
|
||||||
{
|
|
||||||
if (m_shader != nullptr)
|
|
||||||
m_shader->set_uniform(name.c_str(), matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
const GLShader* GLCanvas3D::Shader::get_shader() const
|
|
||||||
{
|
|
||||||
return m_shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLCanvas3D::Shader::_reset()
|
|
||||||
{
|
|
||||||
if (m_shader != nullptr)
|
|
||||||
{
|
|
||||||
m_shader->release();
|
|
||||||
delete m_shader;
|
|
||||||
m_shader = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // !ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
GLCanvas3D::LayersEditing::LayersEditing()
|
GLCanvas3D::LayersEditing::LayersEditing()
|
||||||
: m_enabled(false)
|
: m_enabled(false)
|
||||||
, m_z_texture_id(0)
|
, m_z_texture_id(0)
|
||||||
@ -383,7 +302,7 @@ void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas
|
|||||||
if (m_tooltip_texture.get_id() == 0)
|
if (m_tooltip_texture.get_id() == 0)
|
||||||
{
|
{
|
||||||
std::string filename = resources_dir() + "/icons/variable_layer_height_tooltip.png";
|
std::string filename = resources_dir() + "/icons/variable_layer_height_tooltip.png";
|
||||||
if (!m_tooltip_texture.load_from_file(filename, false, true))
|
if (!m_tooltip_texture.load_from_file(filename, false, GLTexture::SingleThreaded, false))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,7 +334,7 @@ void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) co
|
|||||||
if (m_reset_texture.get_id() == 0)
|
if (m_reset_texture.get_id() == 0)
|
||||||
{
|
{
|
||||||
std::string filename = resources_dir() + "/icons/variable_layer_height_reset.png";
|
std::string filename = resources_dir() + "/icons/variable_layer_height_reset.png";
|
||||||
if (!m_reset_texture.load_from_file(filename, false, true))
|
if (!m_reset_texture.load_from_file(filename, false, GLTexture::SingleThreaded, false))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1642,19 +1561,10 @@ void GLCanvas3D::render()
|
|||||||
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||||
_render_background();
|
_render_background();
|
||||||
|
|
||||||
// textured bed needs to be rendered after objects if the texture is transparent
|
|
||||||
bool early_bed_render = m_bed.is_custom() || (theta <= 90.0f);
|
|
||||||
if (early_bed_render)
|
|
||||||
_render_bed(theta);
|
|
||||||
|
|
||||||
_render_objects();
|
_render_objects();
|
||||||
_render_sla_slices();
|
_render_sla_slices();
|
||||||
_render_selection();
|
_render_selection();
|
||||||
|
_render_bed(theta);
|
||||||
_render_axes();
|
|
||||||
|
|
||||||
if (!early_bed_render)
|
|
||||||
_render_bed(theta);
|
|
||||||
|
|
||||||
#if ENABLE_RENDER_SELECTION_CENTER
|
#if ENABLE_RENDER_SELECTION_CENTER
|
||||||
_render_selection_center();
|
_render_selection_center();
|
||||||
@ -3986,16 +3896,7 @@ void GLCanvas3D::_render_bed(float theta) const
|
|||||||
#if ENABLE_RETINA_GL
|
#if ENABLE_RETINA_GL
|
||||||
scale_factor = m_retina_helper->get_scale_factor();
|
scale_factor = m_retina_helper->get_scale_factor();
|
||||||
#endif // ENABLE_RETINA_GL
|
#endif // ENABLE_RETINA_GL
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
m_bed.render(const_cast<GLCanvas3D&>(*this), theta, scale_factor);
|
||||||
m_bed.render(const_cast<GLCanvas3D*>(this), theta, scale_factor);
|
|
||||||
#else
|
|
||||||
m_bed.render(theta, scale_factor);
|
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLCanvas3D::_render_axes() const
|
|
||||||
{
|
|
||||||
m_bed.render_axes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::_render_objects() const
|
void GLCanvas3D::_render_objects() const
|
||||||
|
@ -158,32 +158,6 @@ class GLCanvas3D
|
|||||||
void reset() { first_volumes.clear(); }
|
void reset() { first_volumes.clear(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !ENABLE_TEXTURES_FROM_SVG
|
|
||||||
class Shader
|
|
||||||
{
|
|
||||||
GLShader* m_shader;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Shader();
|
|
||||||
~Shader();
|
|
||||||
|
|
||||||
bool init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename);
|
|
||||||
|
|
||||||
bool is_initialized() const;
|
|
||||||
|
|
||||||
bool start_using() const;
|
|
||||||
void stop_using() const;
|
|
||||||
|
|
||||||
void set_uniform(const std::string& name, float value) const;
|
|
||||||
void set_uniform(const std::string& name, const float* matrix) const;
|
|
||||||
|
|
||||||
const GLShader* get_shader() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void _reset();
|
|
||||||
};
|
|
||||||
#endif // !ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
class LayersEditing
|
class LayersEditing
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -688,7 +662,6 @@ private:
|
|||||||
void _rectangular_selection_picking_pass() const;
|
void _rectangular_selection_picking_pass() const;
|
||||||
void _render_background() const;
|
void _render_background() const;
|
||||||
void _render_bed(float theta) const;
|
void _render_bed(float theta) const;
|
||||||
void _render_axes() const;
|
|
||||||
void _render_objects() const;
|
void _render_objects() const;
|
||||||
void _render_selection() const;
|
void _render_selection() const;
|
||||||
#if ENABLE_RENDER_SELECTION_CENTER
|
#if ENABLE_RENDER_SELECTION_CENTER
|
||||||
|
@ -268,7 +268,6 @@ sub SetMatrix
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
Shader::Shader()
|
Shader::Shader()
|
||||||
: m_shader(nullptr)
|
: m_shader(nullptr)
|
||||||
{
|
{
|
||||||
@ -363,6 +362,5 @@ void Shader::reset()
|
|||||||
m_shader = nullptr;
|
m_shader = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -37,7 +37,6 @@ public:
|
|||||||
std::string last_error;
|
std::string last_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
|
||||||
class Shader
|
class Shader
|
||||||
{
|
{
|
||||||
GLShader* m_shader;
|
GLShader* m_shader;
|
||||||
@ -66,7 +65,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ GLTexture::~GLTexture()
|
|||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps, bool compress)
|
bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps, ECompressionType compression_type, bool apply_anisotropy)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps, bo
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (boost::algorithm::iends_with(filename, ".png"))
|
if (boost::algorithm::iends_with(filename, ".png"))
|
||||||
return load_from_png(filename, use_mipmaps, compress);
|
return load_from_png(filename, use_mipmaps, compression_type, apply_anisotropy);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -354,49 +354,10 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right,
|
|||||||
glsafe(::glDisable(GL_BLEND));
|
glsafe(::glDisable(GL_BLEND));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int GLTexture::generate_mipmaps(wxImage& image, bool compress)
|
bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECompressionType compression_type, bool apply_anisotropy)
|
||||||
{
|
{
|
||||||
int w = image.GetWidth();
|
bool compression_enabled = (compression_type != None) && GLEW_EXT_texture_compression_s3tc;
|
||||||
int h = image.GetHeight();
|
|
||||||
GLint level = 0;
|
|
||||||
std::vector<unsigned char> data(w * h * 4, 0);
|
|
||||||
|
|
||||||
while ((w > 1) || (h > 1))
|
|
||||||
{
|
|
||||||
++level;
|
|
||||||
|
|
||||||
w = std::max(w / 2, 1);
|
|
||||||
h = std::max(h / 2, 1);
|
|
||||||
|
|
||||||
int n_pixels = w * h;
|
|
||||||
|
|
||||||
image = image.ResampleBicubic(w, h);
|
|
||||||
|
|
||||||
unsigned char* img_rgb = image.GetData();
|
|
||||||
unsigned char* img_alpha = image.GetAlpha();
|
|
||||||
|
|
||||||
data.resize(n_pixels * 4);
|
|
||||||
for (int i = 0; i < n_pixels; ++i)
|
|
||||||
{
|
|
||||||
int data_id = i * 4;
|
|
||||||
int img_id = i * 3;
|
|
||||||
data[data_id + 0] = img_rgb[img_id + 0];
|
|
||||||
data[data_id + 1] = img_rgb[img_id + 1];
|
|
||||||
data[data_id + 2] = img_rgb[img_id + 2];
|
|
||||||
data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compress && GLEW_EXT_texture_compression_s3tc)
|
|
||||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
|
|
||||||
else
|
|
||||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return (unsigned int)level;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, bool compress)
|
|
||||||
{
|
|
||||||
// Load a PNG with an alpha channel.
|
// Load a PNG with an alpha channel.
|
||||||
wxImage image;
|
wxImage image;
|
||||||
if (!image.LoadFile(wxString::FromUTF8(filename.c_str()), wxBITMAP_TYPE_PNG))
|
if (!image.LoadFile(wxString::FromUTF8(filename.c_str()), wxBITMAP_TYPE_PNG))
|
||||||
@ -407,8 +368,32 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, boo
|
|||||||
|
|
||||||
m_width = image.GetWidth();
|
m_width = image.GetWidth();
|
||||||
m_height = image.GetHeight();
|
m_height = image.GetHeight();
|
||||||
int n_pixels = m_width * m_height;
|
|
||||||
|
|
||||||
|
bool requires_rescale = false;
|
||||||
|
|
||||||
|
if (compression_enabled && (compression_type == MultiThreaded))
|
||||||
|
{
|
||||||
|
// the stb_dxt compression library seems to like only texture sizes which are a multiple of 4
|
||||||
|
int width_rem = m_width % 4;
|
||||||
|
int height_rem = m_height % 4;
|
||||||
|
|
||||||
|
if (width_rem != 0)
|
||||||
|
{
|
||||||
|
m_width += (4 - width_rem);
|
||||||
|
requires_rescale = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height_rem != 0)
|
||||||
|
{
|
||||||
|
m_height += (4 - height_rem);
|
||||||
|
requires_rescale = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requires_rescale)
|
||||||
|
image = image.ResampleBicubic(m_width, m_height);
|
||||||
|
|
||||||
|
int n_pixels = m_width * m_height;
|
||||||
if (n_pixels <= 0)
|
if (n_pixels <= 0)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
@ -440,28 +425,99 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, boo
|
|||||||
glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
||||||
glsafe(::glGenTextures(1, &m_id));
|
glsafe(::glGenTextures(1, &m_id));
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_id));
|
glsafe(::glBindTexture(GL_TEXTURE_2D, m_id));
|
||||||
if (compress && GLEW_EXT_texture_compression_s3tc)
|
|
||||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
|
if (apply_anisotropy)
|
||||||
|
{
|
||||||
|
GLfloat max_anisotropy = GLCanvas3DManager::get_gl_info().get_max_anisotropy();
|
||||||
|
if (max_anisotropy > 1.0f)
|
||||||
|
glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compression_enabled)
|
||||||
|
{
|
||||||
|
if (compression_type == SingleThreaded)
|
||||||
|
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// initializes the texture on GPU
|
||||||
|
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
|
||||||
|
// and send the uncompressed data to the compressor
|
||||||
|
m_compressor.add_level((unsigned int)m_width, (unsigned int)m_height, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
|
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
|
||||||
|
|
||||||
if (use_mipmaps)
|
if (use_mipmaps)
|
||||||
{
|
{
|
||||||
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
|
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
|
||||||
unsigned int levels_count = generate_mipmaps(image, compress);
|
int lod_w = m_width;
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels_count));
|
int lod_h = m_height;
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
|
GLint level = 0;
|
||||||
|
// we do not need to generate all levels down to 1x1
|
||||||
|
while ((lod_w > 16) || (lod_h > 16))
|
||||||
|
{
|
||||||
|
++level;
|
||||||
|
|
||||||
|
lod_w = std::max(lod_w / 2, 1);
|
||||||
|
lod_h = std::max(lod_h / 2, 1);
|
||||||
|
n_pixels = lod_w * lod_h;
|
||||||
|
|
||||||
|
image = image.ResampleBicubic(lod_w, lod_h);
|
||||||
|
|
||||||
|
data.resize(n_pixels * 4);
|
||||||
|
|
||||||
|
img_rgb = image.GetData();
|
||||||
|
img_alpha = image.GetAlpha();
|
||||||
|
|
||||||
|
for (int i = 0; i < n_pixels; ++i)
|
||||||
|
{
|
||||||
|
int data_id = i * 4;
|
||||||
|
int img_id = i * 3;
|
||||||
|
data[data_id + 0] = img_rgb[img_id + 0];
|
||||||
|
data[data_id + 1] = img_rgb[img_id + 1];
|
||||||
|
data[data_id + 2] = img_rgb[img_id + 2];
|
||||||
|
data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compression_enabled)
|
||||||
|
{
|
||||||
|
if (compression_type == SingleThreaded)
|
||||||
|
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// initializes the texture on GPU
|
||||||
|
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
|
||||||
|
// and send the uncompressed data to the compressor
|
||||||
|
m_compressor.add_level((unsigned int)lod_w, (unsigned int)lod_h, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!compression_enabled)
|
||||||
|
{
|
||||||
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level));
|
||||||
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||||
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||||
|
|
||||||
m_source = filename;
|
m_source = filename;
|
||||||
|
|
||||||
|
if (compression_enabled && (compression_type == MultiThreaded))
|
||||||
|
// start asynchronous compression
|
||||||
|
m_compressor.start_compressing();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,7 +528,6 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
|
|||||||
NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f);
|
NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f);
|
||||||
if (image == nullptr)
|
if (image == nullptr)
|
||||||
{
|
{
|
||||||
// printf("Could not open SVG image.\n");
|
|
||||||
reset();
|
reset();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -507,7 +562,6 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
|
|||||||
NSVGrasterizer* rast = nsvgCreateRasterizer();
|
NSVGrasterizer* rast = nsvgCreateRasterizer();
|
||||||
if (rast == nullptr)
|
if (rast == nullptr)
|
||||||
{
|
{
|
||||||
// printf("Could not init rasterizer.\n");
|
|
||||||
nsvgDelete(image);
|
nsvgDelete(image);
|
||||||
reset();
|
reset();
|
||||||
return false;
|
return false;
|
||||||
@ -579,6 +633,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
|
|||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||||
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||||
|
@ -48,6 +48,13 @@ namespace GUI {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum ECompressionType : unsigned char
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
SingleThreaded,
|
||||||
|
MultiThreaded
|
||||||
|
};
|
||||||
|
|
||||||
struct UV
|
struct UV
|
||||||
{
|
{
|
||||||
float u;
|
float u;
|
||||||
@ -75,7 +82,7 @@ namespace GUI {
|
|||||||
GLTexture();
|
GLTexture();
|
||||||
virtual ~GLTexture();
|
virtual ~GLTexture();
|
||||||
|
|
||||||
bool load_from_file(const std::string& filename, bool use_mipmaps, bool compress);
|
bool load_from_file(const std::string& filename, bool use_mipmaps, ECompressionType compression_type, bool apply_anisotropy);
|
||||||
bool load_from_svg_file(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px);
|
bool load_from_svg_file(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px);
|
||||||
// meanings of states: (std::pair<int, bool>)
|
// meanings of states: (std::pair<int, bool>)
|
||||||
// first field (int):
|
// first field (int):
|
||||||
@ -101,11 +108,8 @@ namespace GUI {
|
|||||||
static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top);
|
static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top);
|
||||||
static void render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const Quad_UVs& uvs);
|
static void render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const Quad_UVs& uvs);
|
||||||
|
|
||||||
protected:
|
|
||||||
unsigned int generate_mipmaps(wxImage& image, bool compress);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool load_from_png(const std::string& filename, bool use_mipmaps, bool compress);
|
bool load_from_png(const std::string& filename, bool use_mipmaps, ECompressionType compression_type, bool apply_anisotropy);
|
||||||
bool load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px);
|
bool load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px);
|
||||||
|
|
||||||
friend class Compressor;
|
friend class Compressor;
|
||||||
|
@ -174,7 +174,7 @@ bool GLToolbar::init(const BackgroundTexture::Metadata& background_texture)
|
|||||||
bool res = false;
|
bool res = false;
|
||||||
|
|
||||||
if (!background_texture.filename.empty())
|
if (!background_texture.filename.empty())
|
||||||
res = m_background_texture.texture.load_from_file(path + background_texture.filename, false, true);
|
res = m_background_texture.texture.load_from_file(path + background_texture.filename, false, GLTexture::SingleThreaded, false);
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
m_background_texture.metadata = background_texture;
|
m_background_texture.metadata = background_texture;
|
||||||
|
@ -67,9 +67,12 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
|||||||
/* FT_MODEL */ "Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF;*.prusa;*.PRUSA",
|
/* FT_MODEL */ "Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF;*.prusa;*.PRUSA",
|
||||||
/* FT_PROJECT */ "Project files (*.3mf, *.amf)|*.3mf;*.3MF;*.amf;*.AMF",
|
/* FT_PROJECT */ "Project files (*.3mf, *.amf)|*.3mf;*.3MF;*.amf;*.AMF",
|
||||||
|
|
||||||
/* FT_INI */ "INI files (*.ini)|*.ini;*.INI",
|
/* FT_INI */ "INI files (*.ini)|*.ini;*.INI",
|
||||||
/* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG",
|
/* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG",
|
||||||
/* FT_PNGZIP */"Masked SLA files (*.sl1)|*.sl1;*.SL1",
|
|
||||||
|
/* FT_TEX */ "Texture (*.png, *.svg)|*.png;*.PNG;*.svg;*.SVG",
|
||||||
|
|
||||||
|
/* FT_PNGZIP */ "Masked SLA files (*.sl1)|*.sl1;*.SL1",
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string out = defaults[file_type];
|
std::string out = defaults[file_type];
|
||||||
|
@ -44,6 +44,9 @@ enum FileType
|
|||||||
|
|
||||||
FT_INI,
|
FT_INI,
|
||||||
FT_SVG,
|
FT_SVG,
|
||||||
|
|
||||||
|
FT_TEX,
|
||||||
|
|
||||||
FT_PNGZIP,
|
FT_PNGZIP,
|
||||||
|
|
||||||
FT_SIZE,
|
FT_SIZE,
|
||||||
|
@ -43,7 +43,7 @@ bool GLGizmosManager::init()
|
|||||||
|
|
||||||
if (!m_background_texture.metadata.filename.empty())
|
if (!m_background_texture.metadata.filename.empty())
|
||||||
{
|
{
|
||||||
if (!m_background_texture.texture.load_from_file(resources_dir() + "/icons/" + m_background_texture.metadata.filename, false, true))
|
if (!m_background_texture.texture.load_from_file(resources_dir() + "/icons/" + m_background_texture.metadata.filename, false, GLTexture::SingleThreaded, false))
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
return false;
|
return false;
|
||||||
|
@ -1853,7 +1853,7 @@ struct Plater::priv
|
|||||||
// triangulate the bed and store the triangles into m_bed.m_triangles,
|
// triangulate the bed and store the triangles into m_bed.m_triangles,
|
||||||
// fills the m_bed.m_grid_lines and sets m_bed.m_origin.
|
// fills the m_bed.m_grid_lines and sets m_bed.m_origin.
|
||||||
// Sets m_bed.m_polygon to limit the object placement.
|
// Sets m_bed.m_polygon to limit the object placement.
|
||||||
void set_bed_shape(const Pointfs& shape);
|
void set_bed_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model);
|
||||||
|
|
||||||
bool can_delete() const;
|
bool can_delete() const;
|
||||||
bool can_delete_all() const;
|
bool can_delete_all() const;
|
||||||
@ -1914,7 +1914,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||||||
: q(q)
|
: q(q)
|
||||||
, main_frame(main_frame)
|
, main_frame(main_frame)
|
||||||
, config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({
|
, config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({
|
||||||
"bed_shape", "complete_objects", "duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance",
|
"bed_shape", "bed_custom_texture", "bed_custom_model", "complete_objects", "duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance",
|
||||||
"brim_width", "variable_layer_height", "serial_port", "serial_speed", "host_type", "print_host",
|
"brim_width", "variable_layer_height", "serial_port", "serial_speed", "host_type", "print_host",
|
||||||
"printhost_apikey", "printhost_cafile", "nozzle_diameter", "single_extruder_multi_material",
|
"printhost_apikey", "printhost_cafile", "nozzle_diameter", "single_extruder_multi_material",
|
||||||
"wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle",
|
"wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle",
|
||||||
@ -2017,11 +2017,21 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||||||
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this);
|
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this);
|
||||||
view3D_canvas->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this);
|
view3D_canvas->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this);
|
||||||
view3D_canvas->Bind(EVT_GLCANVAS_INIT, [this](SimpleEvent&) { init_view_toolbar(); });
|
view3D_canvas->Bind(EVT_GLCANVAS_INIT, [this](SimpleEvent&) { init_view_toolbar(); });
|
||||||
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [this](SimpleEvent&) { set_bed_shape(config->option<ConfigOptionPoints>("bed_shape")->values); });
|
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [this](SimpleEvent&)
|
||||||
|
{
|
||||||
|
set_bed_shape(config->option<ConfigOptionPoints>("bed_shape")->values,
|
||||||
|
config->option<ConfigOptionString>("bed_custom_texture")->value,
|
||||||
|
config->option<ConfigOptionString>("bed_custom_model")->value);
|
||||||
|
});
|
||||||
|
|
||||||
// Preview events:
|
// Preview events:
|
||||||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_QUESTION_MARK, [this](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); });
|
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_QUESTION_MARK, [this](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); });
|
||||||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [this](SimpleEvent&) { set_bed_shape(config->option<ConfigOptionPoints>("bed_shape")->values); });
|
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [this](SimpleEvent&)
|
||||||
|
{
|
||||||
|
set_bed_shape(config->option<ConfigOptionPoints>("bed_shape")->values,
|
||||||
|
config->option<ConfigOptionString>("bed_custom_texture")->value,
|
||||||
|
config->option<ConfigOptionString>("bed_custom_model")->value);
|
||||||
|
});
|
||||||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_TAB, [this](SimpleEvent&) { select_next_view_3D(); });
|
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_TAB, [this](SimpleEvent&) { select_next_view_3D(); });
|
||||||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, [this](wxKeyEvent& evt) { preview->move_double_slider(evt); });
|
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, [this](wxKeyEvent& evt) { preview->move_double_slider(evt); });
|
||||||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_EDIT_COLOR_CHANGE, [this](wxKeyEvent& evt) { preview->edit_double_slider(evt); });
|
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_EDIT_COLOR_CHANGE, [this](wxKeyEvent& evt) { preview->edit_double_slider(evt); });
|
||||||
@ -3625,9 +3635,9 @@ bool Plater::priv::can_mirror() const
|
|||||||
return get_selection().is_from_single_instance();
|
return get_selection().is_from_single_instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::set_bed_shape(const Pointfs& shape)
|
void Plater::priv::set_bed_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model)
|
||||||
{
|
{
|
||||||
bool new_shape = bed.set_shape(shape);
|
bool new_shape = bed.set_shape(shape, custom_texture, custom_model);
|
||||||
if (new_shape)
|
if (new_shape)
|
||||||
{
|
{
|
||||||
if (view3D) view3D->bed_shape_changed();
|
if (view3D) view3D->bed_shape_changed();
|
||||||
@ -4559,7 +4569,7 @@ void Plater::on_config_change(const DynamicPrintConfig &config)
|
|||||||
p->config->set_key_value(opt_key, config.option(opt_key)->clone());
|
p->config->set_key_value(opt_key, config.option(opt_key)->clone());
|
||||||
if (opt_key == "printer_technology")
|
if (opt_key == "printer_technology")
|
||||||
this->set_printer_technology(config.opt_enum<PrinterTechnology>(opt_key));
|
this->set_printer_technology(config.opt_enum<PrinterTechnology>(opt_key));
|
||||||
else if (opt_key == "bed_shape") {
|
else if ((opt_key == "bed_shape") || (opt_key == "bed_custom_texture") || (opt_key == "bed_custom_model")) {
|
||||||
bed_shape_changed = true;
|
bed_shape_changed = true;
|
||||||
update_scheduled = true;
|
update_scheduled = true;
|
||||||
}
|
}
|
||||||
@ -4593,7 +4603,9 @@ void Plater::on_config_change(const DynamicPrintConfig &config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bed_shape_changed)
|
if (bed_shape_changed)
|
||||||
p->set_bed_shape(p->config->option<ConfigOptionPoints>("bed_shape")->values);
|
p->set_bed_shape(p->config->option<ConfigOptionPoints>("bed_shape")->values,
|
||||||
|
p->config->option<ConfigOptionString>("bed_custom_texture")->value,
|
||||||
|
p->config->option<ConfigOptionString>("bed_custom_model")->value);
|
||||||
|
|
||||||
if (update_scheduled)
|
if (update_scheduled)
|
||||||
update();
|
update();
|
||||||
|
@ -411,7 +411,7 @@ const std::vector<std::string>& Preset::printer_options()
|
|||||||
if (s_opts.empty()) {
|
if (s_opts.empty()) {
|
||||||
s_opts = {
|
s_opts = {
|
||||||
"printer_technology",
|
"printer_technology",
|
||||||
"bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
"bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
||||||
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||||
"host_type", "print_host", "printhost_apikey", "printhost_cafile",
|
"host_type", "print_host", "printhost_apikey", "printhost_cafile",
|
||||||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||||
@ -512,6 +512,7 @@ const std::vector<std::string>& Preset::sla_printer_options()
|
|||||||
if (s_opts.empty()) {
|
if (s_opts.empty()) {
|
||||||
s_opts = {
|
s_opts = {
|
||||||
"printer_technology",
|
"printer_technology",
|
||||||
|
"bed_shape", "bed_custom_texture", "bed_custom_model", "max_print_height",
|
||||||
"bed_shape", "max_print_height",
|
"bed_shape", "max_print_height",
|
||||||
"display_width", "display_height", "display_pixels_x", "display_pixels_y",
|
"display_width", "display_height", "display_pixels_x", "display_pixels_y",
|
||||||
"display_mirror_x", "display_mirror_y",
|
"display_mirror_x", "display_mirror_y",
|
||||||
|
@ -1862,12 +1862,18 @@ void TabPrinter::build_fff()
|
|||||||
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
|
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
|
||||||
{
|
{
|
||||||
BedShapeDialog dlg(this);
|
BedShapeDialog dlg(this);
|
||||||
dlg.build_dialog(m_config->option<ConfigOptionPoints>("bed_shape"));
|
dlg.build_dialog(*m_config->option<ConfigOptionPoints>("bed_shape"),
|
||||||
|
*m_config->option<ConfigOptionString>("bed_custom_texture"),
|
||||||
|
*m_config->option<ConfigOptionString>("bed_custom_model"));
|
||||||
if (dlg.ShowModal() == wxID_OK) {
|
if (dlg.ShowModal() == wxID_OK) {
|
||||||
std::vector<Vec2d> shape = dlg.GetValue();
|
const std::vector<Vec2d>& shape = dlg.get_shape();
|
||||||
|
const std::string& custom_texture = dlg.get_custom_texture();
|
||||||
|
const std::string& custom_model = dlg.get_custom_model();
|
||||||
if (!shape.empty())
|
if (!shape.empty())
|
||||||
{
|
{
|
||||||
load_key_value("bed_shape", shape);
|
load_key_value("bed_shape", shape);
|
||||||
|
load_key_value("bed_custom_texture", custom_texture);
|
||||||
|
load_key_value("bed_custom_model", custom_model);
|
||||||
update_changed_ui();
|
update_changed_ui();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2095,12 +2101,18 @@ void TabPrinter::build_sla()
|
|||||||
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
|
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
|
||||||
{
|
{
|
||||||
BedShapeDialog dlg(this);
|
BedShapeDialog dlg(this);
|
||||||
dlg.build_dialog(m_config->option<ConfigOptionPoints>("bed_shape"));
|
dlg.build_dialog(*m_config->option<ConfigOptionPoints>("bed_shape"),
|
||||||
|
*m_config->option<ConfigOptionString>("bed_custom_texture"),
|
||||||
|
*m_config->option<ConfigOptionString>("bed_custom_model"));
|
||||||
if (dlg.ShowModal() == wxID_OK) {
|
if (dlg.ShowModal() == wxID_OK) {
|
||||||
std::vector<Vec2d> shape = dlg.GetValue();
|
const std::vector<Vec2d>& shape = dlg.get_shape();
|
||||||
|
const std::string& custom_texture = dlg.get_custom_texture();
|
||||||
|
const std::string& custom_model = dlg.get_custom_model();
|
||||||
if (!shape.empty())
|
if (!shape.empty())
|
||||||
{
|
{
|
||||||
load_key_value("bed_shape", shape);
|
load_key_value("bed_shape", shape);
|
||||||
|
load_key_value("bed_custom_texture", custom_texture);
|
||||||
|
load_key_value("bed_custom_model", custom_model);
|
||||||
update_changed_ui();
|
update_changed_ui();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user