Merge remote-tracking branch 'remotes/origin/et_custom_bed'
This commit is contained in:
commit
ca1c78b3fc
27 changed files with 780 additions and 817 deletions
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 bool transparent_background;
|
||||
uniform bool svg_source;
|
||||
|
||||
varying vec2 tex_coords;
|
||||
|
||||
void main()
|
||||
vec4 svg_color()
|
||||
{
|
||||
// takes foreground from texture
|
||||
vec4 fore_color = texture2D(texture, tex_coords);
|
||||
|
||||
// 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)))));
|
||||
|
||||
vec4 fore_color = texture2D(texture, tex_coords);
|
||||
|
||||
// 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->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->label = L("Layer height");
|
||||
def->category = L("Layers and Perimeters");
|
||||
|
|
|
@ -32,13 +32,4 @@
|
|||
#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_
|
||||
|
|
|
@ -18,10 +18,9 @@ wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(25 * wxGetApp().em_unit(), -
|
|||
#ifdef __APPLE__
|
||||
m_user_drawn_background = false;
|
||||
#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);
|
||||
auto cw = GetSize().GetWidth();
|
||||
|
@ -41,7 +40,7 @@ void Bed_2D::repaint()
|
|||
dc.DrawRectangle(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight());
|
||||
}
|
||||
|
||||
if (m_bed_shape.empty())
|
||||
if (shape.empty())
|
||||
return;
|
||||
|
||||
// reduce size to have some space around the drawn shape
|
||||
|
@ -52,10 +51,9 @@ void Bed_2D::repaint()
|
|||
auto ccenter = cbb.center();
|
||||
|
||||
// get bounding box of bed shape in G - code coordinates
|
||||
auto bed_shape = m_bed_shape;
|
||||
auto bed_polygon = Polygon::new_scale(m_bed_shape);
|
||||
auto bb = BoundingBoxf(m_bed_shape);
|
||||
bb.merge(Vec2d(0, 0)); // origin needs to be in the visible area
|
||||
auto bed_polygon = Polygon::new_scale(shape);
|
||||
auto bb = BoundingBoxf(shape);
|
||||
bb.merge(Vec2d(0, 0)); // origin needs to be in the visible area
|
||||
auto bw = bb.size()(0);
|
||||
auto bh = bb.size()(1);
|
||||
auto bcenter = bb.center();
|
||||
|
@ -73,8 +71,8 @@ void Bed_2D::repaint()
|
|||
// draw bed fill
|
||||
dc.SetBrush(wxBrush(wxColour(255, 255, 255), wxBRUSHSTYLE_SOLID));
|
||||
wxPointList pt_list;
|
||||
for (auto pt: m_bed_shape)
|
||||
{
|
||||
for (auto pt : shape)
|
||||
{
|
||||
Point pt_pix = to_pixels(pt, ch);
|
||||
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
|
||||
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;
|
||||
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;
|
||||
Refresh();
|
||||
|
|
|
@ -17,16 +17,13 @@ class Bed_2D : public wxPanel
|
|||
Vec2d m_shift = Vec2d::Zero();
|
||||
Vec2d m_pos = Vec2d::Zero();
|
||||
|
||||
Point to_pixels(Vec2d point, int height);
|
||||
void repaint();
|
||||
void set_pos(Vec2d pos);
|
||||
Point to_pixels(const Vec2d& point, int height);
|
||||
void set_pos(const Vec2d& pos);
|
||||
|
||||
public:
|
||||
Bed_2D(wxWindow* parent);
|
||||
~Bed_2D() {}
|
||||
explicit Bed_2D(wxWindow* parent);
|
||||
|
||||
std::vector<Vec2d> m_bed_shape;
|
||||
|
||||
void repaint(const std::vector<Vec2d>& shape);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <GL/glew.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
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)
|
||||
{
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
m_vertices.clear();
|
||||
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;
|
||||
}
|
||||
|
||||
bool GeometryBuffer::set_from_lines(const Lines& lines, float z)
|
||||
{
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
m_vertices.clear();
|
||||
|
||||
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;
|
||||
++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;
|
||||
}
|
||||
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
const float* GeometryBuffer::get_vertices_data() const
|
||||
{
|
||||
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::ArrowBaseRadius = 2.5 * Bed3D::Axes::Radius;
|
||||
|
@ -274,22 +188,41 @@ void Bed3D::Axes::render_axis(double length) const
|
|||
|
||||
Bed3D::Bed3D()
|
||||
: m_type(Custom)
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
, m_custom_texture("")
|
||||
, m_custom_model("")
|
||||
, m_requires_canvas_update(false)
|
||||
, m_vbo_id(0)
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
, 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);
|
||||
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.
|
||||
return false;
|
||||
|
||||
m_shape = shape;
|
||||
m_custom_texture = cst_texture;
|
||||
m_custom_model = cst_model;
|
||||
m_type = new_type;
|
||||
|
||||
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;
|
||||
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
reset();
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
m_texture.reset();
|
||||
m_model.reset();
|
||||
|
||||
// Set the origin and size for painting of the coordinate system axes.
|
||||
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);
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
render_axes();
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
case MK2:
|
||||
|
@ -354,51 +288,11 @@ void Bed3D::render(GLCanvas3D* canvas, float theta, float scale_factor) const
|
|||
default:
|
||||
case Custom:
|
||||
{
|
||||
render_custom();
|
||||
render_custom(canvas, theta > 90.0f);
|
||||
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
|
||||
{
|
||||
|
@ -423,7 +317,7 @@ void Bed3D::calc_triangles(const ExPolygon& poly)
|
|||
Polygons 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");
|
||||
}
|
||||
|
||||
|
@ -495,31 +389,76 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const
|
|||
return type;
|
||||
}
|
||||
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
void Bed3D::render_prusa(GLCanvas3D* canvas, const std::string &key, bool bottom) const
|
||||
void Bed3D::render_axes() 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
|
||||
GLint max_tex_size = GLCanvas3DManager::get_gl_info().get_max_tex_size();
|
||||
render_texture(m_custom_texture.empty() ? resources_dir() + "/icons/bed/" + key + ".svg" : m_custom_texture, bottom, canvas);
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
// 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_custom();
|
||||
return;
|
||||
}
|
||||
m_texture.reset();
|
||||
|
||||
// starts generating the main texture, compression will run asynchronously
|
||||
if (!m_texture.load_from_svg_file(filename, true, true, true, max_tex_size))
|
||||
if (boost::algorithm::iends_with(filename, ".svg"))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
{
|
||||
if (canvas != nullptr)
|
||||
canvas->stop_keeping_dirty();
|
||||
|
||||
canvas.stop_keeping_dirty();
|
||||
m_requires_canvas_update = false;
|
||||
}
|
||||
|
||||
if (!bottom)
|
||||
if (m_triangles.get_vertices_count() > 0)
|
||||
{
|
||||
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);
|
||||
if (m_shader.get_shader_program_id() == 0)
|
||||
m_shader.init("printbed.vs", "printbed.fs");
|
||||
|
||||
m_model.center_around(offset);
|
||||
|
||||
// update extended bounding box
|
||||
calc_bounding_boxes();
|
||||
}
|
||||
|
||||
if (!m_model.get_filename().empty())
|
||||
if (m_shader.is_initialized())
|
||||
{
|
||||
glsafe(::glEnable(GL_LIGHTING));
|
||||
m_model.render();
|
||||
glsafe(::glDisable(GL_LIGHTING));
|
||||
}
|
||||
}
|
||||
m_shader.start_using();
|
||||
m_shader.set_uniform("transparent_background", bottom);
|
||||
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 (triangles_vcount > 0)
|
||||
{
|
||||
if (m_vbo_id == 0)
|
||||
{
|
||||
glsafe(::glGenBuffers(1, &m_vbo_id));
|
||||
if (m_vbo_id == 0)
|
||||
{
|
||||
glsafe(::glGenBuffers(1, &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));
|
||||
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(::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(::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));
|
||||
|
||||
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
|
||||
m_texture.reset();
|
||||
#else
|
||||
m_top_texture.reset();
|
||||
m_bottom_texture.reset();
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
if (filename.empty())
|
||||
return;
|
||||
|
||||
unsigned int triangles_vcount = m_triangles.get_vertices_count();
|
||||
if (triangles_vcount > 0)
|
||||
if ((m_model.get_filename() != filename) && m_model.init_from_file(filename))
|
||||
{
|
||||
// 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(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
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));
|
||||
m_model.render();
|
||||
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()
|
||||
{
|
||||
if (m_vbo_id > 0)
|
||||
|
@ -830,7 +638,6 @@ void Bed3D::reset()
|
|||
m_vbo_id = 0;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
|
@ -3,9 +3,7 @@
|
|||
|
||||
#include "GLTexture.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
#include "GLShader.hpp"
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
class GLUquadric;
|
||||
typedef class GLUquadric GLUquadricObj;
|
||||
|
@ -17,7 +15,6 @@ class GLCanvas3D;
|
|||
|
||||
class GeometryBuffer
|
||||
{
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
struct Vertex
|
||||
{
|
||||
float position[3];
|
||||
|
@ -31,27 +28,17 @@ class GeometryBuffer
|
|||
};
|
||||
|
||||
std::vector<Vertex> m_vertices;
|
||||
#else
|
||||
std::vector<float> m_vertices;
|
||||
std::vector<float> m_tex_coords;
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
public:
|
||||
bool set_from_triangles(const Polygons& triangles, float z, bool generate_tex_coords);
|
||||
bool set_from_lines(const Lines& lines, float z);
|
||||
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
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_vertex_data_size() const { return (unsigned int)(5 * sizeof(float)); }
|
||||
size_t get_position_offset() const { return 0; }
|
||||
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(); }
|
||||
#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
|
||||
|
@ -87,12 +74,13 @@ public:
|
|||
private:
|
||||
EType m_type;
|
||||
Pointfs m_shape;
|
||||
std::string m_custom_texture;
|
||||
std::string m_custom_model;
|
||||
mutable BoundingBoxf3 m_bounding_box;
|
||||
mutable BoundingBoxf3 m_extended_bounding_box;
|
||||
Polygon m_polygon;
|
||||
GeometryBuffer m_triangles;
|
||||
GeometryBuffer m_gridlines;
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
mutable GLTexture m_texture;
|
||||
// temporary texture shown until the main texture has still no levels compressed
|
||||
mutable GLTexture m_temp_texture;
|
||||
|
@ -100,10 +88,6 @@ private:
|
|||
mutable bool m_requires_canvas_update;
|
||||
mutable Shader m_shader;
|
||||
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;
|
||||
Axes m_axes;
|
||||
|
||||
|
@ -111,9 +95,7 @@ private:
|
|||
|
||||
public:
|
||||
Bed3D();
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
~Bed3D() { reset(); }
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
EType get_type() const { return m_type; }
|
||||
|
||||
|
@ -122,34 +104,26 @@ public:
|
|||
|
||||
const Pointfs& get_shape() const { return m_shape; }
|
||||
// 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; }
|
||||
bool contains(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;
|
||||
#else
|
||||
void render(float theta, float scale_factor) const;
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
void render_axes() const;
|
||||
void render(GLCanvas3D& canvas, float theta, float scale_factor) const;
|
||||
|
||||
private:
|
||||
void calc_bounding_boxes() const;
|
||||
void calc_triangles(const ExPolygon& poly);
|
||||
void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox);
|
||||
EType detect_type(const Pointfs& shape) const;
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
void render_prusa(GLCanvas3D* canvas, const std::string& key, bool bottom) const;
|
||||
void render_prusa_shader(bool transparent) const;
|
||||
#else
|
||||
void render_prusa(const std::string& key, float theta) const;
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
void render_custom() const;
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
void render_axes() const;
|
||||
void render_prusa(GLCanvas3D& canvas, const std::string& key, bool bottom) const;
|
||||
void render_texture(const std::string& filename, bool bottom, GLCanvas3D& canvas) const;
|
||||
void render_model(const std::string& filename) const;
|
||||
void render_custom(GLCanvas3D& canvas, bool bottom) const;
|
||||
void render_default(bool bottom) const;
|
||||
void reset();
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
};
|
||||
|
||||
} // GUI
|
||||
|
|
|
@ -1736,13 +1736,7 @@ bool GLBed::on_init_from_file(const std::string& filename)
|
|||
|
||||
m_filename = filename;
|
||||
|
||||
ModelObject* model_object = model.objects.front();
|
||||
model_object->center_around_origin();
|
||||
|
||||
TriangleMesh mesh = model.mesh();
|
||||
mesh.repair();
|
||||
|
||||
m_volume.indexed_vertex_array.load_mesh(mesh);
|
||||
m_volume.indexed_vertex_array.load_mesh(model.mesh());
|
||||
|
||||
float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f };
|
||||
set_color(color, 4);
|
||||
|
|
|
@ -4,23 +4,25 @@
|
|||
#include <wx/numformatter.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/tooltip.h>
|
||||
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
|
||||
#include "boost/nowide/iostream.hpp"
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Slic3r {
|
||||
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());
|
||||
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);
|
||||
main_sizer->Add(m_panel, 1, wxEXPAND);
|
||||
|
@ -51,59 +53,69 @@ void BedShapeDialog::on_dpi_changed(const wxRect &suggested_rect)
|
|||
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")));
|
||||
sbsizer->GetStaticBox()->SetFont(wxGetApp().bold_font());
|
||||
|
||||
// shape options
|
||||
m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition,
|
||||
wxSize(25*wxGetApp().em_unit(), -1), wxCHB_TOP);
|
||||
m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition, wxSize(25*wxGetApp().em_unit(), -1), wxCHB_TOP);
|
||||
sbsizer->Add(m_shape_options_book);
|
||||
|
||||
auto optgroup = init_shape_options_page(_(L("Rectangular")));
|
||||
ConfigOptionDef def;
|
||||
def.type = coPoints;
|
||||
def.set_default_value(new ConfigOptionPoints{ Vec2d(200, 200) });
|
||||
def.label = L("Size");
|
||||
def.tooltip = L("Size in X and Y of the rectangular plate.");
|
||||
Option option(def, "rect_size");
|
||||
optgroup->append_single_option_line(option);
|
||||
ConfigOptionDef def;
|
||||
def.type = coPoints;
|
||||
def.set_default_value(new ConfigOptionPoints{ Vec2d(200, 200) });
|
||||
def.label = L("Size");
|
||||
def.tooltip = L("Size in X and Y of the rectangular plate.");
|
||||
Option option(def, "rect_size");
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
def.type = coPoints;
|
||||
def.set_default_value(new ConfigOptionPoints{ Vec2d(0, 0) });
|
||||
def.label = L("Origin");
|
||||
def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.");
|
||||
option = Option(def, "rect_origin");
|
||||
optgroup->append_single_option_line(option);
|
||||
def.type = coPoints;
|
||||
def.set_default_value(new ConfigOptionPoints{ Vec2d(0, 0) });
|
||||
def.label = L("Origin");
|
||||
def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.");
|
||||
option = Option(def, "rect_origin");
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
optgroup = init_shape_options_page(_(L("Circular")));
|
||||
def.type = coFloat;
|
||||
def.set_default_value(new ConfigOptionFloat(200));
|
||||
def.sidetext = L("mm");
|
||||
def.label = L("Diameter");
|
||||
def.tooltip = L("Diameter of the print bed. It is assumed that origin (0,0) is located in the center.");
|
||||
option = Option(def, "diameter");
|
||||
optgroup->append_single_option_line(option);
|
||||
optgroup = init_shape_options_page(_(L("Circular")));
|
||||
def.type = coFloat;
|
||||
def.set_default_value(new ConfigOptionFloat(200));
|
||||
def.sidetext = L("mm");
|
||||
def.label = L("Diameter");
|
||||
def.tooltip = L("Diameter of the print bed. It is assumed that origin (0,0) is located in the center.");
|
||||
option = Option(def, "diameter");
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
optgroup = init_shape_options_page(_(L("Custom")));
|
||||
Line line{ "", "" };
|
||||
line.full_width = 1;
|
||||
line.widget = [this](wxWindow* parent) {
|
||||
auto shape_btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")));
|
||||
wxSizer* shape_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
shape_sizer->Add(shape_btn, 1, wxEXPAND);
|
||||
optgroup = init_shape_options_page(_(L("Custom")));
|
||||
Line line{ "", "" };
|
||||
line.full_width = 1;
|
||||
line.widget = [this](wxWindow* parent) {
|
||||
wxButton* shape_btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")));
|
||||
wxSizer* shape_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
shape_sizer->Add(shape_btn, 1, wxEXPAND);
|
||||
|
||||
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(shape_sizer, 1, wxEXPAND);
|
||||
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(shape_sizer, 1, wxEXPAND);
|
||||
|
||||
shape_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||
{
|
||||
load_stl();
|
||||
}));
|
||||
shape_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||
{
|
||||
load_stl();
|
||||
}));
|
||||
|
||||
return sizer;
|
||||
};
|
||||
optgroup->append_line(line);
|
||||
return sizer;
|
||||
};
|
||||
optgroup->append_line(line);
|
||||
|
||||
wxPanel* texture_panel = init_texture_panel();
|
||||
wxPanel* model_panel = init_model_panel();
|
||||
|
||||
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e)
|
||||
{
|
||||
|
@ -112,13 +124,17 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||
|
||||
// right pane with preview canvas
|
||||
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
|
||||
auto top_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
top_sizer->Add(sbsizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 10);
|
||||
if (m_canvas)
|
||||
top_sizer->Add(m_canvas, 1, wxEXPAND | wxALL, 10) ;
|
||||
wxSizer* left_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
left_sizer->Add(sbsizer, 0, wxEXPAND);
|
||||
left_sizer->Add(texture_panel, 1, wxEXPAND);
|
||||
left_sizer->Add(model_panel, 1, wxEXPAND);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -134,20 +150,155 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||
// Create a panel for a rectangular / circular / custom bed shape.
|
||||
ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& title)
|
||||
{
|
||||
auto panel = new wxPanel(m_shape_options_book);
|
||||
ConfigOptionsGroupShp optgroup;
|
||||
optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Settings")));
|
||||
wxPanel* panel = new wxPanel(m_shape_options_book);
|
||||
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Settings")));
|
||||
|
||||
optgroup->label_width = 10;
|
||||
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||
update_shape();
|
||||
};
|
||||
|
||||
m_optgroups.push_back(optgroup);
|
||||
panel->SetSizerAndFit(optgroup->sizer);
|
||||
m_shape_options_book->AddPage(panel, title);
|
||||
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||
update_shape();
|
||||
};
|
||||
|
||||
m_optgroups.push_back(optgroup);
|
||||
panel->SetSizerAndFit(optgroup->sizer);
|
||||
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.
|
||||
|
@ -155,20 +306,20 @@ ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& tit
|
|||
// Deduce the bed shape type(rect, circle, custom)
|
||||
// This routine shall be smart enough if the user messes up
|
||||
// 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 ?
|
||||
if (points->size() == 4) {
|
||||
auto lines = polygon.lines();
|
||||
if (points.size() == 4) {
|
||||
auto lines = polygon.lines();
|
||||
if (lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3])) {
|
||||
// okay, it's a rectangle
|
||||
// find origin
|
||||
coordf_t x_min, x_max, y_min, y_max;
|
||||
x_max = x_min = points->values[0](0);
|
||||
y_max = y_min = points->values[0](1);
|
||||
for (auto pt : points->values)
|
||||
x_max = x_min = points.values[0](0);
|
||||
y_max = y_min = points.values[0](1);
|
||||
for (auto pt : points.values)
|
||||
{
|
||||
x_min = std::min(x_min, pt(0));
|
||||
x_max = std::max(x_max, pt(0));
|
||||
|
@ -219,8 +370,8 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
|
|||
}
|
||||
}
|
||||
|
||||
if (points->size() < 3) {
|
||||
// Invalid polygon.Revert to default bed dimensions.
|
||||
if (points.size() < 3) {
|
||||
// Invalid polygon.Revert to default bed dimensions.
|
||||
m_shape_options_book->SetSelection(SHAPE_RECTANGULAR);
|
||||
auto optgroup = m_optgroups[SHAPE_RECTANGULAR];
|
||||
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.
|
||||
m_shape_options_book->SetSelection(SHAPE_CUSTOM);
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
@ -277,11 +428,11 @@ void BedShapePanel::update_shape()
|
|||
x1 -= dx;
|
||||
y0 -= dy;
|
||||
y1 -= dy;
|
||||
m_canvas->m_bed_shape = { Vec2d(x0, y0),
|
||||
Vec2d(x1, y0),
|
||||
Vec2d(x1, y1),
|
||||
Vec2d(x0, y1)};
|
||||
}
|
||||
m_shape = { Vec2d(x0, y0),
|
||||
Vec2d(x1, y0),
|
||||
Vec2d(x1, y1),
|
||||
Vec2d(x0, y1) };
|
||||
}
|
||||
else if(page_idx == SHAPE_CIRCULAR) {
|
||||
double diameter;
|
||||
try{
|
||||
|
@ -293,16 +444,16 @@ void BedShapePanel::update_shape()
|
|||
if (diameter == 0.0) return ;
|
||||
auto r = diameter / 2;
|
||||
auto twopi = 2 * PI;
|
||||
auto edges = 60;
|
||||
std::vector<Vec2d> points;
|
||||
for (size_t i = 1; i <= 60; ++i) {
|
||||
auto angle = i * twopi / edges;
|
||||
auto edges = 72;
|
||||
std::vector<Vec2d> points;
|
||||
for (size_t i = 1; i <= edges; ++i) {
|
||||
auto angle = i * twopi / edges;
|
||||
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)
|
||||
m_canvas->m_bed_shape = m_loaded_bed_shape;
|
||||
m_shape = m_loaded_shape;
|
||||
|
||||
update_preview();
|
||||
}
|
||||
|
@ -310,27 +461,27 @@ void BedShapePanel::update_shape()
|
|||
// Loads an stl file, projects it to the XY plane and calculates a polygon.
|
||||
void BedShapePanel::load_stl()
|
||||
{
|
||||
auto dialog = new wxFileDialog(this, _(L("Choose a file to import bed shape from (STL/OBJ/AMF/3MF/PRUSA):")), "", "",
|
||||
file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
if (dialog->ShowModal() != wxID_OK) {
|
||||
dialog->Destroy();
|
||||
return;
|
||||
}
|
||||
wxArrayString input_file;
|
||||
dialog->GetPaths(input_file);
|
||||
dialog->Destroy();
|
||||
wxFileDialog dialog(this, _(L("Choose an STL file to import bed shape from:")), "", "", file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
if (dialog.ShowModal() != wxID_OK)
|
||||
return;
|
||||
|
||||
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;
|
||||
try {
|
||||
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);
|
||||
model = Model::read_from_file(file_name);
|
||||
}
|
||||
catch (std::exception &) {
|
||||
show_error(this, _(L("Error! Invalid model")));
|
||||
return;
|
||||
}
|
||||
|
||||
auto mesh = model.mesh();
|
||||
auto expolygons = mesh.horizontal_projection();
|
||||
|
@ -349,7 +500,53 @@ void BedShapePanel::load_stl()
|
|||
for (auto pt : polygon.points)
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,27 +16,40 @@ namespace GUI {
|
|||
using ConfigOptionsGroupShp = std::shared_ptr<ConfigOptionsGroup>;
|
||||
class BedShapePanel : public wxPanel
|
||||
{
|
||||
static const std::string NONE;
|
||||
static const std::string EMPTY_STRING;
|
||||
|
||||
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:
|
||||
BedShapePanel(wxWindow* parent) : wxPanel(parent, wxID_ANY) {}
|
||||
~BedShapePanel() {}
|
||||
BedShapePanel(wxWindow* parent) : wxPanel(parent, wxID_ANY), m_custom_texture(NONE), m_custom_model(NONE) {}
|
||||
|
||||
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);
|
||||
void set_shape(ConfigOptionPoints* points);
|
||||
void update_preview();
|
||||
wxPanel* init_texture_panel();
|
||||
wxPanel* init_model_panel();
|
||||
void set_shape(const ConfigOptionPoints& points);
|
||||
void update_preview();
|
||||
void update_shape();
|
||||
void load_stl();
|
||||
|
||||
// Returns the resulting bed shape polygon. This value will be stored to the ini file.
|
||||
std::vector<Vec2d> GetValue() { return m_canvas->m_bed_shape; }
|
||||
void load_texture();
|
||||
void load_model();
|
||||
|
||||
wxChoicebook* m_shape_options_book;
|
||||
std::vector <ConfigOptionsGroupShp> m_optgroups;
|
||||
|
||||
friend class BedShapeDialog;
|
||||
};
|
||||
|
||||
class BedShapeDialog : public DPIDialog
|
||||
|
@ -45,10 +58,12 @@ class BedShapeDialog : public DPIDialog
|
|||
public:
|
||||
BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")),
|
||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {}
|
||||
~BedShapeDialog() {}
|
||||
|
||||
void build_dialog(ConfigOptionPoints* default_pt);
|
||||
std::vector<Vec2d> GetValue() { return m_panel->GetValue(); }
|
||||
void build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model);
|
||||
|
||||
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:
|
||||
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.")));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void PageBedShape::apply_custom_config(DynamicPrintConfig &config)
|
||||
{
|
||||
const auto points(shape_panel->GetValue());
|
||||
auto *opt = new ConfigOptionPoints(points);
|
||||
config.set_key_value("bed_shape", opt);
|
||||
const std::vector<Vec2d>& points = shape_panel->get_shape();
|
||||
const std::string& custom_texture = shape_panel->get_custom_texture();
|
||||
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)
|
||||
|
@ -1086,7 +1092,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason)
|
|||
|
||||
p->load_vendors();
|
||||
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);
|
||||
|
|
|
@ -116,87 +116,6 @@ void Size::set_scale_factor(int 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()
|
||||
: m_enabled(false)
|
||||
, 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -415,7 +334,7 @@ void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) co
|
|||
if (m_reset_texture.get_id() == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1642,19 +1561,10 @@ void GLCanvas3D::render()
|
|||
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
_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_sla_slices();
|
||||
_render_selection();
|
||||
|
||||
_render_axes();
|
||||
|
||||
if (!early_bed_render)
|
||||
_render_bed(theta);
|
||||
_render_bed(theta);
|
||||
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
_render_selection_center();
|
||||
|
@ -3986,16 +3896,7 @@ void GLCanvas3D::_render_bed(float theta) const
|
|||
#if ENABLE_RETINA_GL
|
||||
scale_factor = m_retina_helper->get_scale_factor();
|
||||
#endif // ENABLE_RETINA_GL
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
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();
|
||||
m_bed.render(const_cast<GLCanvas3D&>(*this), theta, scale_factor);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_objects() const
|
||||
|
|
|
@ -158,32 +158,6 @@ class GLCanvas3D
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
@ -688,7 +662,6 @@ private:
|
|||
void _rectangular_selection_picking_pass() const;
|
||||
void _render_background() const;
|
||||
void _render_bed(float theta) const;
|
||||
void _render_axes() const;
|
||||
void _render_objects() const;
|
||||
void _render_selection() const;
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
|
|
|
@ -268,7 +268,6 @@ sub SetMatrix
|
|||
}
|
||||
*/
|
||||
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
Shader::Shader()
|
||||
: m_shader(nullptr)
|
||||
{
|
||||
|
@ -363,6 +362,5 @@ void Shader::reset()
|
|||
m_shader = nullptr;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -37,7 +37,6 @@ public:
|
|||
std::string last_error;
|
||||
};
|
||||
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
class Shader
|
||||
{
|
||||
GLShader* m_shader;
|
||||
|
@ -66,7 +65,6 @@ public:
|
|||
private:
|
||||
void reset();
|
||||
};
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ GLTexture::~GLTexture()
|
|||
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();
|
||||
|
||||
|
@ -142,7 +142,7 @@ bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps, bo
|
|||
return false;
|
||||
|
||||
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
|
||||
return false;
|
||||
}
|
||||
|
@ -354,49 +354,10 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right,
|
|||
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();
|
||||
int h = image.GetHeight();
|
||||
GLint level = 0;
|
||||
std::vector<unsigned char> data(w * h * 4, 0);
|
||||
bool compression_enabled = (compression_type != None) && GLEW_EXT_texture_compression_s3tc;
|
||||
|
||||
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.
|
||||
wxImage image;
|
||||
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_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)
|
||||
{
|
||||
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(::glGenTextures(1, &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
|
||||
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)
|
||||
{
|
||||
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
|
||||
unsigned int levels_count = generate_mipmaps(image, compress);
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels_count));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
|
||||
int lod_w = m_width;
|
||||
int lod_h = m_height;
|
||||
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
|
||||
{
|
||||
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_MAG_FILTER, GL_LINEAR));
|
||||
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
m_source = filename;
|
||||
|
||||
if (compression_enabled && (compression_type == MultiThreaded))
|
||||
// start asynchronous compression
|
||||
m_compressor.start_compressing();
|
||||
|
||||
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);
|
||||
if (image == nullptr)
|
||||
{
|
||||
// printf("Could not open SVG image.\n");
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
@ -507,7 +562,6 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
|
|||
NSVGrasterizer* rast = nsvgCreateRasterizer();
|
||||
if (rast == nullptr)
|
||||
{
|
||||
// printf("Could not init rasterizer.\n");
|
||||
nsvgDelete(image);
|
||||
reset();
|
||||
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_MAX_LEVEL, 0));
|
||||
}
|
||||
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
|
|
@ -48,6 +48,13 @@ namespace GUI {
|
|||
};
|
||||
|
||||
public:
|
||||
enum ECompressionType : unsigned char
|
||||
{
|
||||
None,
|
||||
SingleThreaded,
|
||||
MultiThreaded
|
||||
};
|
||||
|
||||
struct UV
|
||||
{
|
||||
float u;
|
||||
|
@ -75,7 +82,7 @@ namespace GUI {
|
|||
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);
|
||||
// meanings of states: (std::pair<int, bool>)
|
||||
// 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_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:
|
||||
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);
|
||||
|
||||
friend class Compressor;
|
||||
|
|
|
@ -174,7 +174,7 @@ bool GLToolbar::init(const BackgroundTexture::Metadata& background_texture)
|
|||
bool res = false;
|
||||
|
||||
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)
|
||||
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_PROJECT */ "Project files (*.3mf, *.amf)|*.3mf;*.3MF;*.amf;*.AMF",
|
||||
|
||||
/* FT_INI */ "INI files (*.ini)|*.ini;*.INI",
|
||||
/* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG",
|
||||
/* FT_PNGZIP */"Masked SLA files (*.sl1)|*.sl1;*.SL1",
|
||||
/* FT_INI */ "INI files (*.ini)|*.ini;*.INI",
|
||||
/* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG",
|
||||
|
||||
/* FT_TEX */ "Texture (*.png, *.svg)|*.png;*.PNG;*.svg;*.SVG",
|
||||
|
||||
/* FT_PNGZIP */ "Masked SLA files (*.sl1)|*.sl1;*.SL1",
|
||||
};
|
||||
|
||||
std::string out = defaults[file_type];
|
||||
|
|
|
@ -44,6 +44,9 @@ enum FileType
|
|||
|
||||
FT_INI,
|
||||
FT_SVG,
|
||||
|
||||
FT_TEX,
|
||||
|
||||
FT_PNGZIP,
|
||||
|
||||
FT_SIZE,
|
||||
|
|
|
@ -43,7 +43,7 @@ bool GLGizmosManager::init()
|
|||
|
||||
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();
|
||||
return false;
|
||||
|
|
|
@ -1853,7 +1853,7 @@ struct Plater::priv
|
|||
// 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.
|
||||
// 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_all() const;
|
||||
|
@ -1914,7 +1914,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
: q(q)
|
||||
, main_frame(main_frame)
|
||||
, 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",
|
||||
"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",
|
||||
|
@ -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_LAYERSEDITING, &priv::on_action_layersediting, this);
|
||||
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->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_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); });
|
||||
|
@ -3625,9 +3635,9 @@ bool Plater::priv::can_mirror() const
|
|||
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 (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());
|
||||
if (opt_key == "printer_technology")
|
||||
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;
|
||||
update_scheduled = true;
|
||||
}
|
||||
|
@ -4593,7 +4603,9 @@ void Plater::on_config_change(const DynamicPrintConfig &config)
|
|||
}
|
||||
|
||||
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)
|
||||
update();
|
||||
|
|
|
@ -411,7 +411,7 @@ const std::vector<std::string>& Preset::printer_options()
|
|||
if (s_opts.empty()) {
|
||||
s_opts = {
|
||||
"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",
|
||||
"host_type", "print_host", "printhost_apikey", "printhost_cafile",
|
||||
"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()) {
|
||||
s_opts = {
|
||||
"printer_technology",
|
||||
"bed_shape", "bed_custom_texture", "bed_custom_model", "max_print_height",
|
||||
"bed_shape", "max_print_height",
|
||||
"display_width", "display_height", "display_pixels_x", "display_pixels_y",
|
||||
"display_mirror_x", "display_mirror_y",
|
||||
|
|
|
@ -1862,12 +1862,18 @@ void TabPrinter::build_fff()
|
|||
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
|
||||
{
|
||||
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) {
|
||||
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())
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -2095,12 +2101,18 @@ void TabPrinter::build_sla()
|
|||
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
|
||||
{
|
||||
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) {
|
||||
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())
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue