mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-03 08:12:07 +00:00
Compare commits
5 Commits
feature/up
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bf43d92b9 | ||
|
|
95b781745d | ||
|
|
80e64f80a6 | ||
|
|
477208a969 | ||
|
|
2e08b19d6b |
2
.github/workflows/update-translation.yml
vendored
2
.github/workflows/update-translation.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v7
|
||||||
with:
|
with:
|
||||||
python-version: '3.12'
|
python-version: '3.12'
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
#version 140
|
#version 140
|
||||||
|
// Multisample depth texture for the anti-aliased outline (see 3DScene.cpp render_with_outline).
|
||||||
|
// Optional on the GLSL 140 path: if unavailable, fallback to a non-multisample depth texture.
|
||||||
|
#extension GL_ARB_texture_multisample : enable
|
||||||
|
|
||||||
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||||
//BBS: add grey and orange
|
//BBS: add grey and orange
|
||||||
@@ -36,7 +39,14 @@ uniform SlopeDetection slope;
|
|||||||
|
|
||||||
//BBS: add outline_color
|
//BBS: add outline_color
|
||||||
uniform bool is_outline;
|
uniform bool is_outline;
|
||||||
|
// The outline is a per-fragment discard mask, which the framebuffer MSAA cannot smooth, so the
|
||||||
|
// silhouette is resolved per sample from a multisample copy of the outlined model's depth buffer.
|
||||||
|
#ifdef GL_ARB_texture_multisample
|
||||||
|
uniform sampler2DMS depth_tex;
|
||||||
|
uniform int msaa_samples; // samples in depth_tex, 1 when MSAA is off
|
||||||
|
#else
|
||||||
uniform sampler2D depth_tex;
|
uniform sampler2D depth_tex;
|
||||||
|
#endif
|
||||||
uniform vec2 screen_size;
|
uniform vec2 screen_size;
|
||||||
|
|
||||||
#ifdef ENABLE_ENVIRONMENT_MAP
|
#ifdef ENABLE_ENVIRONMENT_MAP
|
||||||
@@ -99,7 +109,22 @@ float GetTolerance(float d, float k)
|
|||||||
return -k*(d+A)*(d+A)/B;
|
return -k*(d+A)*(d+A)/B;
|
||||||
}
|
}
|
||||||
|
|
||||||
float DetectSilho(vec2 fragCoord, vec2 dir)
|
// Depth of sample s at integer pixel coord.
|
||||||
|
#ifdef GL_ARB_texture_multisample
|
||||||
|
float FetchDepth(ivec2 coord, int s)
|
||||||
|
{
|
||||||
|
// texelFetch has no wrap mode, so clamp to the edge texel (sampler2D used CLAMP_TO_EDGE).
|
||||||
|
ivec2 sz = textureSize(depth_tex);
|
||||||
|
return abs(texelFetch(depth_tex, clamp(coord, ivec2(0), sz - 1), s).r);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
float FetchDepth(ivec2 coord, int s)
|
||||||
|
{
|
||||||
|
return abs(texture(depth_tex, (vec2(coord) + 0.5) / screen_size).r);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float DetectSilho(ivec2 coord, ivec2 dir, int s)
|
||||||
{
|
{
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
// x0 ___ x1----o
|
// x0 ___ x1----o
|
||||||
@@ -112,11 +137,10 @@ float DetectSilho(vec2 fragCoord, vec2 dir)
|
|||||||
// and expected (as if x0..3 where on the same
|
// and expected (as if x0..3 where on the same
|
||||||
// plane) depth values.
|
// plane) depth values.
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
|
float x0 = FetchDepth(coord + dir*-2, s);
|
||||||
float x0 = abs(texture(depth_tex, (fragCoord + dir*-2.0) / screen_size).r);
|
float x1 = FetchDepth(coord + dir*-1, s);
|
||||||
float x1 = abs(texture(depth_tex, (fragCoord + dir*-1.0) / screen_size).r);
|
float x2 = FetchDepth(coord, s);
|
||||||
float x2 = abs(texture(depth_tex, (fragCoord + dir* 0.0) / screen_size).r);
|
float x3 = FetchDepth(coord + dir* 1, s);
|
||||||
float x3 = abs(texture(depth_tex, (fragCoord + dir* 1.0) / screen_size).r);
|
|
||||||
|
|
||||||
float d0 = (x1-x0);
|
float d0 = (x1-x0);
|
||||||
float d1 = (x2-x3);
|
float d1 = (x2-x3);
|
||||||
@@ -127,17 +151,45 @@ float DetectSilho(vec2 fragCoord, vec2 dir)
|
|||||||
float tol = GetTolerance(x2, 0.04);
|
float tol = GetTolerance(x2, 0.04);
|
||||||
|
|
||||||
return smoothstep(0.0, tol*tol, max( - r0*r1, 0.0));
|
return smoothstep(0.0, tol*tol, max( - r0*r1, 0.0));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float DetectSilho(vec2 fragCoord)
|
float DetectSilho(ivec2 coord, int s)
|
||||||
{
|
{
|
||||||
return max(
|
return max(
|
||||||
DetectSilho(fragCoord, vec2(1,0)), // Horizontal
|
DetectSilho(coord, ivec2(1,0), s), // Horizontal
|
||||||
DetectSilho(fragCoord, vec2(0,1)) // Vertical
|
DetectSilho(coord, ivec2(0,1), s) // Vertical
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Full response of one sample. Reduce the max() per sample and average only afterwards:
|
||||||
|
// max(mean) <= mean(max), and averaging first hollows out diagonal and curved lines.
|
||||||
|
float DetectSilhoSample(ivec2 coord, int s)
|
||||||
|
{
|
||||||
|
float v = DetectSilho(coord, s);
|
||||||
|
// Makes silhouettes thicker.
|
||||||
|
for (int i = 1; i <= INFLATE; ++i)
|
||||||
|
{
|
||||||
|
v = max(v, DetectSilho(coord + ivec2(i, 0), s));
|
||||||
|
v = max(v, DetectSilho(coord + ivec2(0, i), s));
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Average the per-sample coverage into the sub-pixel anti-aliasing of the line.
|
||||||
|
float DetectSilho(vec2 fragCoord)
|
||||||
|
{
|
||||||
|
ivec2 coord = ivec2(fragCoord);
|
||||||
|
#ifdef GL_ARB_texture_multisample
|
||||||
|
int n = max(msaa_samples, 1);
|
||||||
|
#else
|
||||||
|
const int n = 1;
|
||||||
|
#endif
|
||||||
|
float acc = 0.0;
|
||||||
|
for (int s = 0; s < n; ++s)
|
||||||
|
acc += DetectSilhoSample(coord, s);
|
||||||
|
return acc / float(n);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns a lighting multiplier in [1 - shadow_intensity, 1]: < 1 where the fragment is
|
// Returns a lighting multiplier in [1 - shadow_intensity, 1]: < 1 where the fragment is
|
||||||
// occluded from the light in the shadow map. 3x3 PCF softens the edges.
|
// occluded from the light in the shadow map. 3x3 PCF softens the edges.
|
||||||
float shadow_shade()
|
float shadow_shade()
|
||||||
@@ -224,14 +276,7 @@ void main()
|
|||||||
//BBS: add outline_color
|
//BBS: add outline_color
|
||||||
if (is_outline) {
|
if (is_outline) {
|
||||||
color = vec4((vec3(intensity.y) + color.rgb * intensity.x) * shade, color.a);
|
color = vec4((vec3(intensity.y) + color.rgb * intensity.x) * shade, color.a);
|
||||||
vec2 fragCoord = gl_FragCoord.xy;
|
float s = DetectSilho(gl_FragCoord.xy);
|
||||||
float s = DetectSilho(fragCoord);
|
|
||||||
// Makes silhouettes thicker.
|
|
||||||
for(int i=1;i<=INFLATE; i++)
|
|
||||||
{
|
|
||||||
s = max(s, DetectSilho(fragCoord.xy + vec2(i, 0)));
|
|
||||||
s = max(s, DetectSilho(fragCoord.xy + vec2(0, i)));
|
|
||||||
}
|
|
||||||
if (s < 0.01)
|
if (s < 0.01)
|
||||||
discard;
|
discard;
|
||||||
out_color = vec4(mix(color.rgb, getBackfaceColor(color.rgb), s), color.a);
|
out_color = vec4(mix(color.rgb, getBackfaceColor(color.rgb), s), color.a);
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
#version 140
|
#version 140
|
||||||
|
// Multisample depth texture for the anti-aliased outline (see 3DScene.cpp render_with_outline).
|
||||||
|
// Optional on the GLSL 140 path: if unavailable, fallback to a non-multisample depth texture.
|
||||||
|
#extension GL_ARB_texture_multisample : enable
|
||||||
|
|
||||||
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||||
const vec3 LightRed = vec3(0.78, 0.0, 0.0);
|
const vec3 LightRed = vec3(0.78, 0.0, 0.0);
|
||||||
@@ -51,7 +54,14 @@ uniform SlopeDetection slope;
|
|||||||
|
|
||||||
//BBS: add outline_color
|
//BBS: add outline_color
|
||||||
uniform bool is_outline;
|
uniform bool is_outline;
|
||||||
|
// The outline is a per-fragment discard mask, which the framebuffer MSAA cannot smooth, so the
|
||||||
|
// silhouette is resolved per sample from a multisample copy of the outlined model's depth buffer.
|
||||||
|
#ifdef GL_ARB_texture_multisample
|
||||||
|
uniform sampler2DMS depth_tex;
|
||||||
|
uniform int msaa_samples; // samples in depth_tex, 1 when MSAA is off
|
||||||
|
#else
|
||||||
uniform sampler2D depth_tex;
|
uniform sampler2D depth_tex;
|
||||||
|
#endif
|
||||||
uniform vec2 screen_size;
|
uniform vec2 screen_size;
|
||||||
|
|
||||||
#ifdef ENABLE_ENVIRONMENT_MAP
|
#ifdef ENABLE_ENVIRONMENT_MAP
|
||||||
@@ -100,12 +110,27 @@ float GetTolerance(float d, float k)
|
|||||||
return -k*(d+A)*(d+A)/B;
|
return -k*(d+A)*(d+A)/B;
|
||||||
}
|
}
|
||||||
|
|
||||||
float DetectSilho(vec2 fragCoord, vec2 dir)
|
// Depth of sample s at integer pixel coord.
|
||||||
|
#ifdef GL_ARB_texture_multisample
|
||||||
|
float FetchDepth(ivec2 coord, int s)
|
||||||
{
|
{
|
||||||
float x0 = abs(texture(depth_tex, (fragCoord + dir*-2.0) / screen_size).r);
|
// texelFetch has no wrap mode, so clamp to the edge texel (sampler2D used CLAMP_TO_EDGE).
|
||||||
float x1 = abs(texture(depth_tex, (fragCoord + dir*-1.0) / screen_size).r);
|
ivec2 sz = textureSize(depth_tex);
|
||||||
float x2 = abs(texture(depth_tex, (fragCoord + dir* 0.0) / screen_size).r);
|
return abs(texelFetch(depth_tex, clamp(coord, ivec2(0), sz - 1), s).r);
|
||||||
float x3 = abs(texture(depth_tex, (fragCoord + dir* 1.0) / screen_size).r);
|
}
|
||||||
|
#else
|
||||||
|
float FetchDepth(ivec2 coord, int s)
|
||||||
|
{
|
||||||
|
return abs(texture(depth_tex, (vec2(coord) + 0.5) / screen_size).r);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float DetectSilho(ivec2 coord, ivec2 dir, int s)
|
||||||
|
{
|
||||||
|
float x0 = FetchDepth(coord + dir*-2, s);
|
||||||
|
float x1 = FetchDepth(coord + dir*-1, s);
|
||||||
|
float x2 = FetchDepth(coord, s);
|
||||||
|
float x3 = FetchDepth(coord + dir* 1, s);
|
||||||
|
|
||||||
float d0 = (x1-x0);
|
float d0 = (x1-x0);
|
||||||
float d1 = (x2-x3);
|
float d1 = (x2-x3);
|
||||||
@@ -116,17 +141,45 @@ float DetectSilho(vec2 fragCoord, vec2 dir)
|
|||||||
float tol = GetTolerance(x2, 0.04);
|
float tol = GetTolerance(x2, 0.04);
|
||||||
|
|
||||||
return smoothstep(0.0, tol*tol, max( - r0*r1, 0.0));
|
return smoothstep(0.0, tol*tol, max( - r0*r1, 0.0));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float DetectSilho(vec2 fragCoord)
|
float DetectSilho(ivec2 coord, int s)
|
||||||
{
|
{
|
||||||
return max(
|
return max(
|
||||||
DetectSilho(fragCoord, vec2(1,0)),
|
DetectSilho(coord, ivec2(1,0), s),
|
||||||
DetectSilho(fragCoord, vec2(0,1))
|
DetectSilho(coord, ivec2(0,1), s)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Full response of one sample. Reduce the max() per sample and average only afterwards:
|
||||||
|
// max(mean) <= mean(max), and averaging first hollows out diagonal and curved lines.
|
||||||
|
float DetectSilhoSample(ivec2 coord, int s)
|
||||||
|
{
|
||||||
|
float v = DetectSilho(coord, s);
|
||||||
|
// Makes silhouettes thicker.
|
||||||
|
for (int i = 1; i <= INFLATE; ++i)
|
||||||
|
{
|
||||||
|
v = max(v, DetectSilho(coord + ivec2(i, 0), s));
|
||||||
|
v = max(v, DetectSilho(coord + ivec2(0, i), s));
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Average the per-sample coverage into the sub-pixel anti-aliasing of the line.
|
||||||
|
float DetectSilho(vec2 fragCoord)
|
||||||
|
{
|
||||||
|
ivec2 coord = ivec2(fragCoord);
|
||||||
|
#ifdef GL_ARB_texture_multisample
|
||||||
|
int n = max(msaa_samples, 1);
|
||||||
|
#else
|
||||||
|
const int n = 1;
|
||||||
|
#endif
|
||||||
|
float acc = 0.0;
|
||||||
|
for (int s = 0; s < n; ++s)
|
||||||
|
acc += DetectSilhoSample(coord, s);
|
||||||
|
return acc / float(n);
|
||||||
|
}
|
||||||
|
|
||||||
float compute_ssao_factor(vec3 normal, vec3 view_dir, vec3 eye_pos)
|
float compute_ssao_factor(vec3 normal, vec3 view_dir, vec3 eye_pos)
|
||||||
{
|
{
|
||||||
vec3 normal_dx = dFdx(normal);
|
vec3 normal_dx = dFdx(normal);
|
||||||
@@ -270,13 +323,7 @@ void main()
|
|||||||
if (is_outline) {
|
if (is_outline) {
|
||||||
vec3 shaded_rgb = (vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS * shade;
|
vec3 shaded_rgb = (vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS * shade;
|
||||||
vec4 shaded_color = vec4(clamp(shaded_rgb, vec3(0.0), vec3(1.0)), color.a);
|
vec4 shaded_color = vec4(clamp(shaded_rgb, vec3(0.0), vec3(1.0)), color.a);
|
||||||
vec2 fragCoord = gl_FragCoord.xy;
|
float s = DetectSilho(gl_FragCoord.xy);
|
||||||
float s = DetectSilho(fragCoord);
|
|
||||||
for(int i=1;i<=INFLATE; i++)
|
|
||||||
{
|
|
||||||
s = max(s, DetectSilho(fragCoord.xy + vec2(i, 0)));
|
|
||||||
s = max(s, DetectSilho(fragCoord.xy + vec2(0, i)));
|
|
||||||
}
|
|
||||||
if (s < 0.01)
|
if (s < 0.01)
|
||||||
discard;
|
discard;
|
||||||
out_color = vec4(mix(shaded_color.rgb, getBackfaceColor(shaded_color.rgb), s), shaded_color.a);
|
out_color = vec4(mix(shaded_color.rgb, getBackfaceColor(shaded_color.rgb), s), shaded_color.a);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public:
|
|||||||
min(p1), max(p1), defined(false) { merge(p2); merge(p3); }
|
min(p1), max(p1), defined(false) { merge(p2); merge(p3); }
|
||||||
|
|
||||||
template<class It, class = IteratorOnly<It>>
|
template<class It, class = IteratorOnly<It>>
|
||||||
BoundingBoxBase(It from, It to)
|
BoundingBoxBase(It from, It to) : BoundingBoxBase()
|
||||||
{ construct(*this, from, to); }
|
{ construct(*this, from, to); }
|
||||||
|
|
||||||
BoundingBoxBase(const PointsType &points)
|
BoundingBoxBase(const PointsType &points)
|
||||||
|
|||||||
@@ -1857,12 +1857,12 @@ static inline void base_support_extend_infill_lines(Polylines &infill, BoundaryI
|
|||||||
const bool first = graph.first(cp);
|
const bool first = graph.first(cp);
|
||||||
int extend_next_idx = -1;
|
int extend_next_idx = -1;
|
||||||
int extend_prev_idx = -1;
|
int extend_prev_idx = -1;
|
||||||
coord_t dist_y_prev;
|
coord_t dist_y_prev = 0;
|
||||||
coord_t dist_y_next;
|
coord_t dist_y_next = 0;
|
||||||
double arc_len_prev;
|
double arc_len_prev = 0;
|
||||||
double arc_len_next;
|
double arc_len_next = 0;
|
||||||
|
|
||||||
if (! graph.next_vertical(cp)){
|
if (! graph.next_vertical(cp)) {
|
||||||
size_t i = cp.point_idx;
|
size_t i = cp.point_idx;
|
||||||
size_t j = next_idx_modulo(i, contour);
|
size_t j = next_idx_modulo(i, contour);
|
||||||
while (j != cp.next_on_contour->point_idx) {
|
while (j != cp.next_on_contour->point_idx) {
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ struct LayerResult {
|
|||||||
// It is used for the pressure equalizer because it needs to buffer one layer back.
|
// It is used for the pressure equalizer because it needs to buffer one layer back.
|
||||||
bool nop_layer_result { false };
|
bool nop_layer_result { false };
|
||||||
|
|
||||||
static LayerResult make_nop_layer_result() { return {"", std::numeric_limits<coord_t>::max(), false, false, true}; }
|
static LayerResult make_nop_layer_result() { return {"", std::numeric_limits<size_t>::max(), false, false, true}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class GCode {
|
class GCode {
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ float FullTransparentModdifiedToFixAlpha = 0.3f;
|
|||||||
// value like 0.18f could not because in C++ (int)(0.18f * 255) == 45 however in OpenGL it renders this as 46
|
// value like 0.18f could not because in C++ (int)(0.18f * 255) == 45 however in OpenGL it renders this as 46
|
||||||
// which breaks the `SelectMachineDialog::record_edge_pixels_data()` function!
|
// which breaks the `SelectMachineDialog::record_edge_pixels_data()` function!
|
||||||
float FULL_BLACK_THRESHOLD = 0.2f;
|
float FULL_BLACK_THRESHOLD = 0.2f;
|
||||||
|
// Keep depth_tex away from texture unit 0 to avoid sampler-type aliasing with
|
||||||
|
// shadow/environment samplers when realistic view is disabled.
|
||||||
|
static constexpr int OUTLINE_DEPTH_TEX_UNIT = 5;
|
||||||
|
|
||||||
Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors)
|
Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors)
|
||||||
{
|
{
|
||||||
@@ -518,6 +521,37 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size)
|
|||||||
glsafe(::glStencilMask(0xFF));
|
glsafe(::glStencilMask(0xFF));
|
||||||
glsafe(::glDisable(GL_STENCIL_TEST));
|
glsafe(::glDisable(GL_STENCIL_TEST));
|
||||||
// render the outline using depth buffer and discard the pixels that are not on the outline
|
// render the outline using depth buffer and discard the pixels that are not on the outline
|
||||||
|
// The silhouette is resolved per sample in the shader (see DetectSilho in gouraud.fs/phong.fs).
|
||||||
|
// That needs the GL 3.2 entry points and a shader that declares depth_tex as sampler2DMS, which
|
||||||
|
// only the 140 ones do and only under GL_ARB_texture_multisample - so ask the compiled program
|
||||||
|
// rather than the GL version, or a sampler2D ends up bound to a multisample texture.
|
||||||
|
// Only the Arb branch below allocates a multisample texture, so keep the target consistent with it.
|
||||||
|
const bool use_msaa_outline = framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb &&
|
||||||
|
GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 2) &&
|
||||||
|
shader->get_uniform_location("msaa_samples") >= 0;
|
||||||
|
const GLenum depth_tex_target = use_msaa_outline ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
|
||||||
|
// Keep the depth texture off image unit 0. The object shaders leave shadow_map (and
|
||||||
|
// environment_tex) at the default sampler value 0 whenever the shadow pass is skipped - which is
|
||||||
|
// the case with realistic view off - and GL forbids two sampler types referring to the same image
|
||||||
|
// unit. A sampler2DMS on unit 0 then makes every draw fail with INVALID_OPERATION on drivers that
|
||||||
|
// enforce it (Mesa), i.e. the model disappears entirely. Unit 5 is unused (shadow_map takes 4).
|
||||||
|
const int depth_tex_unit = OUTLINE_DEPTH_TEX_UNIT;
|
||||||
|
int aa_samples = 1;
|
||||||
|
if (use_msaa_outline) {
|
||||||
|
if (const AppConfig* app_config = GUI::wxGetApp().app_config; app_config != nullptr) {
|
||||||
|
const std::string value = app_config->get(SETTING_OPENGL_AA_SAMPLES);
|
||||||
|
if (value == "2" || value == "4" || value == "8" || value == "16")
|
||||||
|
aa_samples = ::atoi(value.c_str());
|
||||||
|
}
|
||||||
|
// Never request more samples than the driver supports for depth textures (a 1-sample texture
|
||||||
|
// is used when MSAA is disabled, keeping a single code path for the sampler2DMS shader).
|
||||||
|
GLint max_samples = 1;
|
||||||
|
glsafe(::glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &max_samples));
|
||||||
|
if (aa_samples > max_samples)
|
||||||
|
aa_samples = max_samples < 1 ? 1 : max_samples;
|
||||||
|
if (aa_samples < 1)
|
||||||
|
aa_samples = 1;
|
||||||
|
}
|
||||||
// 1st. render pass, render the model into a separate render target that has only depth buffer
|
// 1st. render pass, render the model into a separate render target that has only depth buffer
|
||||||
GLuint depth_fbo = 0;
|
GLuint depth_fbo = 0;
|
||||||
GLuint depth_tex = 0;
|
GLuint depth_tex = 0;
|
||||||
@@ -525,21 +559,26 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size)
|
|||||||
glsafe(::glGenFramebuffers(1, &depth_fbo));
|
glsafe(::glGenFramebuffers(1, &depth_fbo));
|
||||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo));
|
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo));
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit));
|
||||||
glsafe(::glGenTextures(1, &depth_tex));
|
glsafe(::glGenTextures(1, &depth_tex));
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, depth_tex));
|
glsafe(::glBindTexture(depth_tex_target, depth_tex));
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
if (use_msaa_outline) {
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
// Multisample textures do not take filter/wrap parameters.
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
glsafe(::glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, aa_samples, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), GL_TRUE));
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
} else {
|
||||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr));
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||||
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||||
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||||
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||||
|
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, cnv_size.get_width(), cnv_size.get_height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_tex, 0));
|
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_tex_target, depth_tex, 0));
|
||||||
} else {
|
} else {
|
||||||
glsafe(::glGenFramebuffersEXT(1, &depth_fbo));
|
glsafe(::glGenFramebuffersEXT(1, &depth_fbo));
|
||||||
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, depth_fbo));
|
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, depth_fbo));
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit));
|
||||||
glsafe(::glGenTextures(1, &depth_tex));
|
glsafe(::glGenTextures(1, &depth_tex));
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, depth_tex));
|
glsafe(::glBindTexture(GL_TEXTURE_2D, depth_tex));
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||||
@@ -550,12 +589,15 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size)
|
|||||||
|
|
||||||
glsafe(::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_tex, 0));
|
glsafe(::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_tex, 0));
|
||||||
}
|
}
|
||||||
|
// Unbind before drawing: the texture is this framebuffer's depth attachment, so leaving it bound
|
||||||
|
// to a sampled unit would be a feedback loop.
|
||||||
|
glsafe(::glBindTexture(depth_tex_target, 0));
|
||||||
|
glsafe(::glActiveTexture(GL_TEXTURE0));
|
||||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||||
if (tverts_range == std::make_pair<size_t, size_t>(0, -1))
|
if (tverts_range == std::make_pair<size_t, size_t>(0, -1))
|
||||||
model.render(shader);
|
model.render(shader);
|
||||||
else
|
else
|
||||||
model.render(this->tverts_range, shader);
|
model.render(this->tverts_range, shader);
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
|
||||||
|
|
||||||
// 2nd. render pass, just a normal render with the depth buffer passed as a texture
|
// 2nd. render pass, just a normal render with the depth buffer passed as a texture
|
||||||
if (framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb) {
|
if (framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb) {
|
||||||
@@ -565,13 +607,17 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size)
|
|||||||
}
|
}
|
||||||
shader->set_uniform("is_outline", true);
|
shader->set_uniform("is_outline", true);
|
||||||
shader->set_uniform("screen_size", Vec2f{cnv_size.get_width(), cnv_size.get_height()});
|
shader->set_uniform("screen_size", Vec2f{cnv_size.get_width(), cnv_size.get_height()});
|
||||||
glActiveTexture(GL_TEXTURE0);
|
shader->set_uniform("msaa_samples", aa_samples);
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, depth_tex));
|
glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit));
|
||||||
shader->set_uniform("depth_tex", 0);
|
glsafe(::glBindTexture(depth_tex_target, depth_tex));
|
||||||
|
glsafe(::glActiveTexture(GL_TEXTURE0));
|
||||||
|
shader->set_uniform("depth_tex", depth_tex_unit);
|
||||||
simple_render(shader, model_objects, colors);
|
simple_render(shader, model_objects, colors);
|
||||||
|
|
||||||
// Some clean up to do
|
// Some clean up to do
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
glsafe(::glActiveTexture(GL_TEXTURE0 + depth_tex_unit));
|
||||||
|
glsafe(::glBindTexture(depth_tex_target, 0));
|
||||||
|
glsafe(::glActiveTexture(GL_TEXTURE0));
|
||||||
shader->set_uniform("is_outline", false);
|
shader->set_uniform("is_outline", false);
|
||||||
if (framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb) {
|
if (framebuffers_type == GUI::OpenGLManager::EFramebufferType::Arb) {
|
||||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||||
@@ -1075,6 +1121,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
|
|||||||
|
|
||||||
const float support_normal_z = get_selection_support_normal_z();
|
const float support_normal_z = get_selection_support_normal_z();
|
||||||
|
|
||||||
|
// Prime depth_tex on every frame so non-outline draws do not keep the
|
||||||
|
// default sampler unit 0, which can conflict with other sampler types.
|
||||||
|
shader->set_uniform("depth_tex", OUTLINE_DEPTH_TEX_UNIT);
|
||||||
|
|
||||||
for (GLVolumeWithIdAndZ& volume : to_render) {
|
for (GLVolumeWithIdAndZ& volume : to_render) {
|
||||||
#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
|
#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
|
||||||
if (type == ERenderType::Transparent) {
|
if (type == ERenderType::Transparent) {
|
||||||
|
|||||||
@@ -548,7 +548,7 @@ void RemoveButtonBorder(wxWindow* win)
|
|||||||
GtkCssProvider* provider = gtk_css_provider_new();
|
GtkCssProvider* provider = gtk_css_provider_new();
|
||||||
|
|
||||||
const char* css =
|
const char* css =
|
||||||
"button {"
|
"button, button:hover, button:active, button:focus {"
|
||||||
" border: none;"
|
" border: none;"
|
||||||
" outline: none;"
|
" outline: none;"
|
||||||
" box-shadow: none;"
|
" box-shadow: none;"
|
||||||
@@ -589,6 +589,58 @@ void RemoveButtonBorder(wxWindow* win)
|
|||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoveInputBorder(wxWindow* win)
|
||||||
|
{
|
||||||
|
GtkWidget* widget = win->GetHandle();
|
||||||
|
if (!widget) return;
|
||||||
|
|
||||||
|
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||||
|
// GTK3+: use CSS provider
|
||||||
|
GtkCssProvider* provider = gtk_css_provider_new();
|
||||||
|
|
||||||
|
// Target 'entry' and its inner subnodes (like text selection areas)
|
||||||
|
const char* css =
|
||||||
|
"entry, entry text, entry undershoot {"
|
||||||
|
" border: none;"
|
||||||
|
" outline: none;"
|
||||||
|
" box-shadow: none;"
|
||||||
|
" padding: 0px;"
|
||||||
|
" margin: 0px;"
|
||||||
|
" min-height: 0px;"
|
||||||
|
" min-width: 0px;"
|
||||||
|
" background: none;"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
#if GTK_CHECK_VERSION(4, 0, 0)
|
||||||
|
// GTK4
|
||||||
|
gtk_css_provider_load_from_data(provider, css, -1);
|
||||||
|
#else
|
||||||
|
// GTK3
|
||||||
|
gtk_css_provider_load_from_data(provider, css, -1, nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GtkStyleContext* ctx = gtk_widget_get_style_context(widget);
|
||||||
|
gtk_style_context_add_provider(
|
||||||
|
ctx,
|
||||||
|
GTK_STYLE_PROVIDER(provider),
|
||||||
|
GTK_STYLE_PROVIDER_PRIORITY_USER
|
||||||
|
);
|
||||||
|
g_object_unref(provider);
|
||||||
|
|
||||||
|
#else
|
||||||
|
// GTK2: Target the x/y thickness of the entry widget
|
||||||
|
gtk_rc_parse_string(
|
||||||
|
"style \"no-padding-entry\" {"
|
||||||
|
" xthickness = 0"
|
||||||
|
" ythickness = 0"
|
||||||
|
" GtkEntry::inner-border = { 0, 0, 0, 0 }"
|
||||||
|
" GtkEntry::focus-line-width = 0"
|
||||||
|
"}"
|
||||||
|
"class \"GtkEntry\" style \"no-padding-entry\""
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
#endif // __WXGTK__
|
#endif // __WXGTK__
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
|||||||
@@ -472,8 +472,9 @@ void dataview_remove_insets(wxDataViewCtrl* dv);
|
|||||||
void staticbox_remove_margin(wxStaticBox* sb);
|
void staticbox_remove_margin(wxStaticBox* sb);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __WXGTK3__
|
#ifdef __WXGTK__
|
||||||
void RemoveButtonBorder(wxWindow* win);
|
void RemoveButtonBorder(wxWindow* win); // for wxButton/wxBitmapToggleButton based controls (SwitchButton, CheckBox)
|
||||||
|
void RemoveInputBorder(wxWindow* win); // for TextCtrl based controls (TextInput, ComboBox, SpinInput..)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__WXOSX__) || defined(__linux__)
|
#if defined(__WXOSX__) || defined(__linux__)
|
||||||
|
|||||||
@@ -865,6 +865,9 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset
|
|||||||
clr_picker = new wxBitmapButton(parent, wxID_ANY, {}, wxDefaultPosition, wxSize(FromDIP(20), FromDIP(20)), wxBU_EXACTFIT | wxBU_AUTODRAW | wxBORDER_NONE);
|
clr_picker = new wxBitmapButton(parent, wxID_ANY, {}, wxDefaultPosition, wxSize(FromDIP(20), FromDIP(20)), wxBU_EXACTFIT | wxBU_AUTODRAW | wxBORDER_NONE);
|
||||||
clr_picker->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));
|
clr_picker->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));
|
||||||
clr_picker->SetToolTip(_L("Click to select filament color"));
|
clr_picker->SetToolTip(_L("Click to select filament color"));
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
RemoveButtonBorder(clr_picker);
|
||||||
|
#endif
|
||||||
clr_picker->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
|
clr_picker->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
|
||||||
// Check if it's an official filament
|
// Check if it's an official filament
|
||||||
auto fila_type = Preset::remove_suffix_modified(GetValue().ToUTF8().data());
|
auto fila_type = Preset::remove_suffix_modified(GetValue().ToUTF8().data());
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "../wxExtensions.hpp"
|
#include "../wxExtensions.hpp"
|
||||||
|
|
||||||
#ifdef __WXGTK3__
|
#ifdef __WXGTK__
|
||||||
#include "../GUI_Utils.hpp"
|
#include "../GUI_Utils.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ CheckBox::CheckBox(wxWindow *parent, int id)
|
|||||||
Bind(wxEVT_LEAVE_WINDOW, &CheckBox::updateBitmap, this);
|
Bind(wxEVT_LEAVE_WINDOW, &CheckBox::updateBitmap, this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __WXGTK3__
|
#ifdef __WXGTK__
|
||||||
Slic3r::GUI::RemoveButtonBorder(this);
|
Slic3r::GUI::RemoveButtonBorder(this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
#include "../wxExtensions.hpp"
|
#include "../wxExtensions.hpp"
|
||||||
|
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
#include "../GUI_Utils.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
RadioBox::RadioBox(wxWindow *parent)
|
RadioBox::RadioBox(wxWindow *parent)
|
||||||
@@ -15,6 +19,7 @@ RadioBox::RadioBox(wxWindow *parent)
|
|||||||
// Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); });
|
// Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); });
|
||||||
update();
|
update();
|
||||||
#ifdef __WXGTK__
|
#ifdef __WXGTK__
|
||||||
|
Slic3r::GUI::RemoveButtonBorder(this);
|
||||||
wxSize bestSize = GetBestSize();
|
wxSize bestSize = GetBestSize();
|
||||||
bestSize.IncTo(m_on.GetBmpSize());
|
bestSize.IncTo(m_on.GetBmpSize());
|
||||||
SetSize(bestSize);
|
SetSize(bestSize);
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
#include <wx/dcgraph.h>
|
#include <wx/dcgraph.h>
|
||||||
|
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
#include "../GUI_Utils.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(SpinInput, StaticBox)
|
BEGIN_EVENT_TABLE(SpinInput, StaticBox)
|
||||||
|
|
||||||
EVT_KEY_DOWN(SpinInput::keyPressed)
|
EVT_KEY_DOWN(SpinInput::keyPressed)
|
||||||
@@ -58,6 +62,11 @@ void SpinInput::Create(wxWindow *parent,
|
|||||||
state_handler.attach({&label_color, &text_color});
|
state_handler.attach({&label_color, &text_color});
|
||||||
state_handler.update_binds();
|
state_handler.update_binds();
|
||||||
text_ctrl = new TextCtrl(this, wxID_ANY, text, {20, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER, wxTextValidator(wxFILTER_DIGITS));
|
text_ctrl = new TextCtrl(this, wxID_ANY, text, {20, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER, wxTextValidator(wxFILTER_DIGITS));
|
||||||
|
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
Slic3r::GUI::RemoveInputBorder(text_ctrl);
|
||||||
|
#endif
|
||||||
|
|
||||||
text_ctrl->SetFont(Label::Body_14);
|
text_ctrl->SetFont(Label::Body_14);
|
||||||
text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
||||||
text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states()));
|
text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states()));
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#include "libslic3r/MacUtils.hpp"
|
#include "libslic3r/MacUtils.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __WXGTK3__
|
#ifdef __WXGTK__
|
||||||
#include "../GUI_Utils.hpp"
|
#include "../GUI_Utils.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ SwitchButton::SwitchButton(wxWindow* parent, wxWindowID id)
|
|||||||
Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); });
|
Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); });
|
||||||
SetFont(Label::Body_12);
|
SetFont(Label::Body_12);
|
||||||
|
|
||||||
#ifdef __WXGTK3__
|
#ifdef __WXGTK__
|
||||||
Slic3r::GUI::RemoveButtonBorder(this);
|
Slic3r::GUI::RemoveButtonBorder(this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
#include <wx/dcclient.h>
|
#include <wx/dcclient.h>
|
||||||
#include <wx/dcgraph.h>
|
#include <wx/dcgraph.h>
|
||||||
|
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
#include "../GUI_Utils.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(TextInput, StaticBox)
|
BEGIN_EVENT_TABLE(TextInput, StaticBox)
|
||||||
|
|
||||||
EVT_PAINT(TextInput::paintEvent)
|
EVT_PAINT(TextInput::paintEvent)
|
||||||
@@ -60,6 +64,11 @@ void TextInput::Create(wxWindow * parent,
|
|||||||
state_handler.attach({&label_color, & text_color});
|
state_handler.attach({&label_color, & text_color});
|
||||||
state_handler.update_binds();
|
state_handler.update_binds();
|
||||||
text_ctrl = new TextCtrl(this, wxID_ANY, text, {4, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER);
|
text_ctrl = new TextCtrl(this, wxID_ANY, text, {4, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER);
|
||||||
|
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
Slic3r::GUI::RemoveInputBorder(text_ctrl);
|
||||||
|
#endif
|
||||||
|
|
||||||
text_ctrl->SetFont(Label::Body_14);
|
text_ctrl->SetFont(Label::Body_14);
|
||||||
text_ctrl->SetInitialSize(text_ctrl->GetBestSize());
|
text_ctrl->SetInitialSize(text_ctrl->GetBestSize());
|
||||||
text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
||||||
|
|||||||
@@ -1022,6 +1022,10 @@ ScalableButton::ScalableButton( wxWindow * parent,
|
|||||||
m_width = size.x * 10 / em;
|
m_width = size.x * 10 / em;
|
||||||
m_height= size.y * 10 / em;
|
m_height= size.y * 10 / em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
Slic3r::GUI::RemoveButtonBorder(this);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user