mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-12 02:29:03 +08:00
Basic Plate3D implementation (selection not working)
Additionally, OpenGL added to the cmakelist and xs/slic3r/GUI files fixed to be compiled.
This commit is contained in:
parent
e0aa6d2f85
commit
f352d433bc
@ -249,11 +249,14 @@ IF(wxWidgets_FOUND)
|
|||||||
${GUI_LIBDIR}/GUI.cpp
|
${GUI_LIBDIR}/GUI.cpp
|
||||||
${GUI_LIBDIR}/MainFrame.cpp
|
${GUI_LIBDIR}/MainFrame.cpp
|
||||||
${GUI_LIBDIR}/Plater.cpp
|
${GUI_LIBDIR}/Plater.cpp
|
||||||
|
${GUI_LIBDIR}/Scene3D.cpp
|
||||||
${GUI_LIBDIR}/Plater/Plate2D.cpp
|
${GUI_LIBDIR}/Plater/Plate2D.cpp
|
||||||
|
${GUI_LIBDIR}/Plater/Plate3D.cpp
|
||||||
${GUI_LIBDIR}/Plater/PlaterObject.cpp
|
${GUI_LIBDIR}/Plater/PlaterObject.cpp
|
||||||
${GUI_LIBDIR}/ProgressStatusBar.cpp
|
${GUI_LIBDIR}/ProgressStatusBar.cpp
|
||||||
${GUI_LIBDIR}/Settings.cpp
|
${GUI_LIBDIR}/Settings.cpp
|
||||||
${GUI_LIBDIR}/misc_ui.cpp
|
${GUI_LIBDIR}/misc_ui.cpp
|
||||||
|
${LIBDIR}/slic3r/GUI/3DScene.cpp
|
||||||
)
|
)
|
||||||
target_compile_features(slic3r_gui PUBLIC cxx_std_14)
|
target_compile_features(slic3r_gui PUBLIC cxx_std_14)
|
||||||
#only build GUI lib if building with wx
|
#only build GUI lib if building with wx
|
||||||
@ -301,7 +304,8 @@ ELSE(wxWidgets_FOUND)
|
|||||||
#skip gui when no wx included
|
#skip gui when no wx included
|
||||||
ENDIF(wxWidgets_FOUND)
|
ENDIF(wxWidgets_FOUND)
|
||||||
|
|
||||||
target_link_libraries (slic3r libslic3r ${LIBSLIC3R_DEPENDS})
|
find_package(OpenGL)
|
||||||
|
target_link_libraries (slic3r libslic3r ${LIBSLIC3R_DEPENDS} ${OPENGL_LIBRARIES})
|
||||||
|
|
||||||
if (BUILD_EXTRUDE_TIN)
|
if (BUILD_EXTRUDE_TIN)
|
||||||
add_executable(extrude-tin utils/extrude-tin.cpp)
|
add_executable(extrude-tin utils/extrude-tin.cpp)
|
||||||
|
112
src/GUI/Plater/Plate3D.cpp
Normal file
112
src/GUI/Plater/Plate3D.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#include "Plater/Plate3D.hpp"
|
||||||
|
#include "misc_ui.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
|
Plate3D::Plate3D(wxWindow* parent, const wxSize& size, std::vector<PlaterObject>& _objects, std::shared_ptr<Model> _model, std::shared_ptr<Config> _config) :
|
||||||
|
Scene3D(parent, size), objects(_objects), model(_model), config(_config)
|
||||||
|
{
|
||||||
|
|
||||||
|
//this->glContext = new wxGLContext(this);
|
||||||
|
//this->Bind(wxEVT_PAINT, [this](wxPaintEvent& e) { this->repaint(e); });
|
||||||
|
//delete this->glContext;
|
||||||
|
//this->glContext = new wxGLContext(this); // Update glContext (look for better way)
|
||||||
|
//});
|
||||||
|
|
||||||
|
// Bind the varying mouse events
|
||||||
|
this->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { this->mouse_down(e); });
|
||||||
|
this->Bind(wxEVT_RIGHT_DOWN, [this](wxMouseEvent &e) { this->mouse_down(e); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plate3D::mouse_down(wxMouseEvent &e){
|
||||||
|
if(!hover){
|
||||||
|
//select logic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Plate3D::mouse_move(wxMouseEvent &e){
|
||||||
|
if(!e.Dragging()){
|
||||||
|
pos = Point(e.GetX(),e.GetY());
|
||||||
|
mouse = true;
|
||||||
|
Refresh();
|
||||||
|
} else {
|
||||||
|
Scene3D::mouse_move(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Plate3D::update(){
|
||||||
|
volumes.clear();
|
||||||
|
for(const PlaterObject &object: objects){
|
||||||
|
const auto &modelobj = model->objects.at(object.identifier);
|
||||||
|
for(ModelInstance *instance: modelobj->instances){
|
||||||
|
for(ModelVolume* volume: modelobj->volumes){
|
||||||
|
volumes.push_back(load_object(*volume,*instance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plate3D::color_volumes(){
|
||||||
|
uint i = 0;
|
||||||
|
for(const PlaterObject &object: objects){
|
||||||
|
const auto &modelobj = model->objects.at(object.identifier);
|
||||||
|
for(ModelInstance *instance: modelobj->instances){
|
||||||
|
for(ModelVolume* volume: modelobj->volumes){
|
||||||
|
auto& rendervolume = volumes.at(i);
|
||||||
|
if(object.selected){
|
||||||
|
rendervolume.color = ui_settings->color->SELECTED_COLOR();
|
||||||
|
}else{
|
||||||
|
rendervolume.color = wxColor(255,255,0);//ui_settings->color->COLOR_PARTS(); <- invisible because alpha is 1 (out of 255)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(hover){
|
||||||
|
volumes.at(hover_volume).color = ui_settings->color->HOVER_COLOR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plate3D::before_render(){
|
||||||
|
if (!mouse)return;
|
||||||
|
|
||||||
|
//glDisable(GL_MULTISAMPLE) if ($self->{can_multisample});
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
uint i = 0;
|
||||||
|
for(Volume &volume : volumes){
|
||||||
|
volume.color = wxColor((i>>16)&0xFF,(i>>8)&0xFF,i&0xFF);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
draw_volumes();
|
||||||
|
glFlush();
|
||||||
|
glFinish();
|
||||||
|
GLubyte color[4] = {0,0,0,0};
|
||||||
|
glReadPixels(pos.x, /*offset*/GetSize().GetHeight()- pos.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
|
||||||
|
|
||||||
|
uint index = color[0] + (color[1]<<8) + (color[2]<<16);
|
||||||
|
hover = false;
|
||||||
|
///*$self->_hover_volume_idx(undef);
|
||||||
|
//$_->hover(0) for @{$self->volumes};
|
||||||
|
if (index < volumes.size()) {
|
||||||
|
hover = true;
|
||||||
|
hover_volume = index;
|
||||||
|
/*
|
||||||
|
$self->volumes->[$volume_idx]->hover(1);
|
||||||
|
my $group_id = $self->volumes->[$volume_idx]->select_group_id;
|
||||||
|
if ($group_id != -1) {
|
||||||
|
$_->hover(1) for grep { $_->select_group_id == $group_id } @{$self->volumes};
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//$self->on_hover->($volume_idx) if $self->on_hover;
|
||||||
|
}
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
glFlush();
|
||||||
|
glFinish();
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
color_volumes();
|
||||||
|
mouse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} } // Namespace Slic3r::GUI
|
@ -4,18 +4,27 @@
|
|||||||
#ifndef WX_PRECOMP
|
#ifndef WX_PRECOMP
|
||||||
#include <wx/wx.h>
|
#include <wx/wx.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include "Plater/PlaterObject.hpp"
|
||||||
|
#include "Scene3D.hpp"
|
||||||
|
#include "Settings.hpp"
|
||||||
#include "Model.hpp"
|
#include "Model.hpp"
|
||||||
#include "Config.hpp"
|
#include "Config.hpp"
|
||||||
|
|
||||||
namespace Slic3r { namespace GUI {
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
class Plate3D : public wxPanel {
|
class Plate3D : public Scene3D {
|
||||||
public:
|
public:
|
||||||
void update() {};
|
void update();
|
||||||
Plate3D(wxWindow* parent, const wxSize& size, std::vector<PlaterObject>& _objects, std::shared_ptr<Model> _model, std::shared_ptr<Config> _config) :
|
Plate3D(wxWindow* parent, const wxSize& size, std::vector<PlaterObject>& _objects, std::shared_ptr<Model> _model, std::shared_ptr<Config> _config);
|
||||||
wxPanel(parent, wxID_ANY, wxDefaultPosition, size, wxTAB_TRAVERSAL), objects(_objects), model(_model), config(_config)
|
protected:
|
||||||
{}
|
void before_render();
|
||||||
|
void mouse_move(wxMouseEvent &e);
|
||||||
|
void mouse_down(wxMouseEvent &e);
|
||||||
private:
|
private:
|
||||||
|
void color_volumes();
|
||||||
|
Point pos;
|
||||||
|
bool hover = false, mouse = false;
|
||||||
|
uint hover_volume;
|
||||||
std::vector<PlaterObject>& objects; //< reference to parent vector
|
std::vector<PlaterObject>& objects; //< reference to parent vector
|
||||||
std::shared_ptr<Slic3r::Model> model;
|
std::shared_ptr<Slic3r::Model> model;
|
||||||
std::shared_ptr<Slic3r::Config> config;
|
std::shared_ptr<Slic3r::Config> config;
|
||||||
|
508
src/GUI/Scene3D.cpp
Normal file
508
src/GUI/Scene3D.cpp
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
#include "Scene3D.hpp"
|
||||||
|
#include "Line.hpp"
|
||||||
|
#include "ClipperUtils.hpp"
|
||||||
|
#include "misc_ui.hpp"
|
||||||
|
|
||||||
|
#include <GL/glu.h>
|
||||||
|
|
||||||
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
|
Scene3D::Scene3D(wxWindow* parent, const wxSize& size) :
|
||||||
|
wxGLCanvas(parent, wxID_ANY, wxDefaultPosition, size)
|
||||||
|
{
|
||||||
|
|
||||||
|
this->glContext = new wxGLContext(this);
|
||||||
|
this->Bind(wxEVT_PAINT, [this](wxPaintEvent &e) { this->repaint(e); });
|
||||||
|
this->Bind(wxEVT_SIZE, [this](wxSizeEvent &e ){
|
||||||
|
dirty = true;
|
||||||
|
Refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Bind the varying mouse events
|
||||||
|
this->Bind(wxEVT_MOTION, [this](wxMouseEvent &e) { this->mouse_move(e); });
|
||||||
|
this->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent &e) { this->mouse_up(e); });
|
||||||
|
this->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent &e) { this->mouse_up(e); });
|
||||||
|
this->Bind(wxEVT_MIDDLE_DCLICK, [this](wxMouseEvent &e) { this->mouse_dclick(e); });
|
||||||
|
this->Bind(wxEVT_MOUSEWHEEL, [this](wxMouseEvent &e) { this->mouse_wheel(e); });
|
||||||
|
/*
|
||||||
|
if (user_drawn_background) {
|
||||||
|
this->Bind(wxEVT_ERASE_BACKGROUND, [this](wxEraseEvent& e){ });
|
||||||
|
}
|
||||||
|
|
||||||
|
this->Bind(wxEVT_CHAR, [this](wxKeyEvent &e) { this->nudge_key(e);});
|
||||||
|
*/
|
||||||
|
Points p;
|
||||||
|
const coord_t w = scale_(200), z = 0;
|
||||||
|
p.push_back(Point(z,z));
|
||||||
|
p.push_back(Point(z,w));
|
||||||
|
p.push_back(Point(w,w));
|
||||||
|
p.push_back(Point(w,z));
|
||||||
|
set_bed_shape(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
float clamp(float low, float x, float high){
|
||||||
|
if(x < low) return low;
|
||||||
|
if(x > high) return high;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
Linef3 mouse_ray(Point win){
|
||||||
|
GLdouble proj[16], mview[16];
|
||||||
|
glGetDoublev(GL_MODELVIEW_MATRIX, mview);
|
||||||
|
glGetDoublev(GL_PROJECTION_MATRIX, proj);
|
||||||
|
GLint view[4];
|
||||||
|
glGetIntegerv(GL_VIEWPORT, view);
|
||||||
|
win.y = view[3]-win.y;
|
||||||
|
GLdouble x = 0.0, y = 0.0, z = 0.0;
|
||||||
|
gluUnProject(win.x,win.y,0,mview,proj,view,&x,&y,&z);
|
||||||
|
Pointf3 first = Pointf3(x,y,z);
|
||||||
|
GLint a = gluUnProject(win.x,win.y,1,mview,proj,view,&x,&y,&z);
|
||||||
|
return Linef3(first,Pointf3(x,y,z));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::mouse_move(wxMouseEvent &e){
|
||||||
|
if(e.Dragging()){
|
||||||
|
//const auto s = GetSize();
|
||||||
|
const auto pos = Point(e.GetX(),e.GetY());
|
||||||
|
if(dragging){
|
||||||
|
if (e.ShiftDown()) { // TODO: confirm alt -> shift is ok
|
||||||
|
// Move the camera center on the Z axis based on mouse Y axis movement
|
||||||
|
_camera_target.translate(0, 0, (pos.y - drag_start.y));
|
||||||
|
} else if (e.LeftIsDown()) {
|
||||||
|
// if dragging over blank area with left button, rotate
|
||||||
|
//if (TURNTABLE_MODE) {
|
||||||
|
const float TRACKBALLSIZE = 0.8f, GIMBAL_LOCK_THETA_MAX = 170.0f;
|
||||||
|
|
||||||
|
phi += (pos.x - drag_start.x) * TRACKBALLSIZE;
|
||||||
|
theta -= (pos.y - drag_start.y) * TRACKBALLSIZE;
|
||||||
|
theta = clamp(0, theta, GIMBAL_LOCK_THETA_MAX);
|
||||||
|
/*} else {
|
||||||
|
my $size = $self->GetClientSize;
|
||||||
|
my @quat = trackball(
|
||||||
|
$orig->x / ($size->width / 2) - 1,
|
||||||
|
1 - $orig->y / ($size->height / 2), #/
|
||||||
|
$pos->x / ($size->width / 2) - 1,
|
||||||
|
1 - $pos->y / ($size->height / 2), #/
|
||||||
|
);
|
||||||
|
$self->_quat(mulquats($self->_quat, \@quat));
|
||||||
|
}*/
|
||||||
|
} else if (e.MiddleIsDown() || e.RightIsDown()) {
|
||||||
|
// if dragging over blank area with right button, translate
|
||||||
|
// get point in model space at Z = 0
|
||||||
|
const auto current = mouse_ray(pos).intersect_plane(0);
|
||||||
|
const auto old = mouse_ray(drag_start).intersect_plane(0);
|
||||||
|
_camera_target.translate(current.vector_to(old));
|
||||||
|
}
|
||||||
|
//$self->on_viewport_changed->() if $self->on_viewport_changed;
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
dragging = true;
|
||||||
|
drag_start = pos;
|
||||||
|
}else{
|
||||||
|
e.Skip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::mouse_up(wxMouseEvent &e){
|
||||||
|
dragging = false;
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::mouse_wheel(wxMouseEvent &e){
|
||||||
|
// Calculate the zoom delta and apply it to the current zoom factor
|
||||||
|
auto _zoom = ((float)e.GetWheelRotation()) / e.GetWheelDelta();
|
||||||
|
/*if ($Slic3r::GUI::Settings->{_}{invert_zoom}) {
|
||||||
|
_zoom *= -1;
|
||||||
|
}*/
|
||||||
|
_zoom = clamp(-4, _zoom,4);
|
||||||
|
_zoom /= 10;
|
||||||
|
zoom /= 1-_zoom;
|
||||||
|
/*
|
||||||
|
# In order to zoom around the mouse point we need to translate
|
||||||
|
# the camera target
|
||||||
|
my $size = Slic3r::Pointf->new($self->GetSizeWH);
|
||||||
|
my $pos = Slic3r::Pointf->new($e->GetX, $size->y - $e->GetY); #-
|
||||||
|
$self->_camera_target->translate(
|
||||||
|
# ($pos - $size/2) represents the vector from the viewport center
|
||||||
|
# to the mouse point. By multiplying it by $zoom we get the new,
|
||||||
|
# transformed, length of such vector.
|
||||||
|
# Since we want that point to stay fixed, we move our camera target
|
||||||
|
# in the opposite direction by the delta of the length of such vector
|
||||||
|
# ($zoom - 1). We then scale everything by 1/$self->_zoom since
|
||||||
|
# $self->_camera_target is expressed in terms of model units.
|
||||||
|
-($pos->x - $size->x/2) * ($zoom) / $self->_zoom,
|
||||||
|
-($pos->y - $size->y/2) * ($zoom) / $self->_zoom,
|
||||||
|
0,
|
||||||
|
) if 0;
|
||||||
|
*/
|
||||||
|
|
||||||
|
dirty = true;
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::mouse_dclick(wxMouseEvent &e){
|
||||||
|
/*
|
||||||
|
if (@{$self->volumes}) {
|
||||||
|
$self->zoom_to_volumes;
|
||||||
|
} else {
|
||||||
|
$self->zoom_to_bed;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
dirty = true;
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::resize(){
|
||||||
|
if(!dirty)return;
|
||||||
|
dirty = false;
|
||||||
|
const auto s = GetSize();
|
||||||
|
glViewport(0,0,s.GetWidth(),s.GetHeight());
|
||||||
|
const auto x = s.GetWidth()/zoom,
|
||||||
|
y = s.GetHeight()/zoom,
|
||||||
|
depth = 1000.0f; // my $depth = 10 * max(@{ $self->max_bounding_box->size });
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glLoadIdentity();
|
||||||
|
glOrtho(
|
||||||
|
-x/2, x/2, -y/2, y/2,
|
||||||
|
-depth, 2*depth
|
||||||
|
);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::set_bed_shape(Points _bed_shape){
|
||||||
|
|
||||||
|
bed_shape = _bed_shape;
|
||||||
|
const float GROUND_Z = -0.02f;
|
||||||
|
|
||||||
|
// triangulate bed
|
||||||
|
const auto expoly = ExPolygon(Polygon(bed_shape));
|
||||||
|
const auto box = expoly.bounding_box();
|
||||||
|
bed_bound = box;
|
||||||
|
{
|
||||||
|
std::vector<Polygon> triangles;
|
||||||
|
expoly.triangulate(&triangles);
|
||||||
|
bed_verts.clear();
|
||||||
|
for(const auto &triangle : triangles){
|
||||||
|
for(const auto &point : triangle.points){
|
||||||
|
bed_verts.push_back(unscale(point.x));
|
||||||
|
bed_verts.push_back(unscale(point.y));
|
||||||
|
bed_verts.push_back(GROUND_Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::vector<Polyline> lines;
|
||||||
|
Points tmp;
|
||||||
|
for (coord_t x = box.min.x; x <= box.max.x; x += scale_(10)) {
|
||||||
|
lines.push_back(Polyline());
|
||||||
|
lines.back().append(Point(x,box.min.y));
|
||||||
|
lines.back().append(Point(x,box.max.y));
|
||||||
|
}
|
||||||
|
for (coord_t y = box.min.y; y <= box.max.y; y += scale_(10)) {
|
||||||
|
lines.push_back(Polyline());
|
||||||
|
lines.back().append(Point(box.min.x,y));
|
||||||
|
lines.back().append(Point(box.max.x,y));
|
||||||
|
}
|
||||||
|
// clip with a slightly grown expolygon because our lines lay on the contours and
|
||||||
|
// may get erroneously clipped
|
||||||
|
// my @lines = map Slic3r::Line->new(@$_[0,-1]),
|
||||||
|
grid_verts.clear();
|
||||||
|
const Polylines clipped = intersection_pl(lines,offset_ex(expoly,SCALED_EPSILON).at(0));
|
||||||
|
for(const Polyline &line : clipped){
|
||||||
|
for(const Point &point : line.points){
|
||||||
|
grid_verts.push_back(unscale(point.x));
|
||||||
|
grid_verts.push_back(unscale(point.y));
|
||||||
|
grid_verts.push_back(GROUND_Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// append bed contours
|
||||||
|
for(const Line &line : expoly.lines()){
|
||||||
|
grid_verts.push_back(unscale(line.a.x));
|
||||||
|
grid_verts.push_back(unscale(line.a.y));
|
||||||
|
grid_verts.push_back(GROUND_Z);
|
||||||
|
grid_verts.push_back(unscale(line.b.x));
|
||||||
|
grid_verts.push_back(unscale(line.b.y));
|
||||||
|
grid_verts.push_back(GROUND_Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//$self->origin(Slic3r::Pointf->new(0,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::init_gl(){
|
||||||
|
if(this->init)return;
|
||||||
|
this->init = true;
|
||||||
|
|
||||||
|
glClearColor(0, 0, 0, 1);
|
||||||
|
glColor3f(1, 0, 0);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glClearDepth(1.0);
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
// Set antialiasing/multisampling
|
||||||
|
glDisable(GL_LINE_SMOOTH);
|
||||||
|
glDisable(GL_POLYGON_SMOOTH);
|
||||||
|
//glEnable(GL_MULTISAMPLE) if ($self->{can_multisample});
|
||||||
|
|
||||||
|
// ambient lighting
|
||||||
|
GLfloat ambient[] = {0.1f, 0.1f, 0.1f, 1.0f};
|
||||||
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
|
||||||
|
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
glEnable(GL_LIGHT0);
|
||||||
|
glEnable(GL_LIGHT1);
|
||||||
|
|
||||||
|
// light from camera
|
||||||
|
GLfloat pos[] = {1.0f, 0.0f, 1.0f, 0.0f}, spec[] = {0.8f, 0.8f, 0.8f, 1.0f}, diff[] = {0.4f, 0.4f, 0.4f, 1.0f};
|
||||||
|
glLightfv(GL_LIGHT1, GL_POSITION, pos);
|
||||||
|
glLightfv(GL_LIGHT1, GL_SPECULAR, spec);
|
||||||
|
glLightfv(GL_LIGHT1, GL_DIFFUSE, diff);
|
||||||
|
|
||||||
|
// Enables Smooth Color Shading; try GL_FLAT for (lack of) fun. Default: GL_SMOOTH
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
|
||||||
|
GLfloat fbdiff[] = {0.3f, 0.3f, 0.3f,1}, fbspec[] = {1.0f, 1.0f, 1.0f, 1.0f}, fbemis[] = {0.1f,0.1f,0.1f,0.9f};
|
||||||
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, fbdiff);
|
||||||
|
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, fbspec);
|
||||||
|
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50);
|
||||||
|
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, fbemis);
|
||||||
|
|
||||||
|
// A handy trick -- have surface material mirror the color.
|
||||||
|
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
|
||||||
|
glEnable(GL_COLOR_MATERIAL);
|
||||||
|
//glEnable(GL_MULTISAMPLE) if ($self->{can_multisample});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::draw_background(){
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
auto bottom = ui_settings->color->BOTTOM_COLOR(), top = ui_settings->color->TOP_COLOR();
|
||||||
|
if(ui_settings->color->SOLID_BACKGROUNDCOLOR()){
|
||||||
|
bottom = top = ui_settings->color->BACKGROUND_COLOR();
|
||||||
|
}
|
||||||
|
glColor3ub(bottom.Red(), bottom.Green(), bottom.Blue());
|
||||||
|
glVertex2f(-1.0,-1.0);
|
||||||
|
glVertex2f(1,-1.0);
|
||||||
|
glColor3ub(top.Red(), top.Green(), top.Blue());
|
||||||
|
glVertex2f(1, 1);
|
||||||
|
glVertex2f(-1.0, 1);
|
||||||
|
glEnd();
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::draw_ground(){
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
/*my $triangle_vertex;
|
||||||
|
if (HAS_VBO) {
|
||||||
|
($triangle_vertex) =
|
||||||
|
glGenBuffersARB_p(1);
|
||||||
|
$self->bed_triangles->bind($triangle_vertex);
|
||||||
|
glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $self->bed_triangles, GL_STATIC_DRAW_ARB);
|
||||||
|
glVertexPointer_c(3, GL_FLOAT, 0, 0);
|
||||||
|
} else {*/
|
||||||
|
// fall back on old behavior
|
||||||
|
glVertexPointer(3, GL_FLOAT, 0, bed_verts.data());
|
||||||
|
const auto ground = ui_settings->color->GROUND_COLOR(), grid = ui_settings->color->GRID_COLOR();
|
||||||
|
|
||||||
|
glColor4ub(ground.Red(), ground.Green(), ground.Blue(),ground.Alpha());
|
||||||
|
glNormal3d(0,0,1);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, bed_verts.size() / 3);
|
||||||
|
|
||||||
|
// we need depth test for grid, otherwise it would disappear when looking
|
||||||
|
// the object from below
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
// draw grid
|
||||||
|
glLineWidth(2);
|
||||||
|
/*my $grid_vertex;
|
||||||
|
if (HAS_VBO) {
|
||||||
|
($grid_vertex) =
|
||||||
|
glGenBuffersARB_p(1);
|
||||||
|
$self->bed_grid_lines->bind($grid_vertex);
|
||||||
|
glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $self->bed_grid_lines, GL_STATIC_DRAW_ARB);
|
||||||
|
glVertexPointer_c(3, GL_FLOAT, 0, 0);
|
||||||
|
} else {*/
|
||||||
|
// fall back on old behavior
|
||||||
|
glVertexPointer(3, GL_FLOAT, 0, grid_verts.data());
|
||||||
|
|
||||||
|
glColor4ub(grid.Red(), grid.Green(), grid.Blue(),grid.Alpha());
|
||||||
|
glNormal3d(0,0,1);
|
||||||
|
glDrawArrays(GL_LINES, 0, grid_verts.size() / 3);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
/*if (HAS_VBO) {
|
||||||
|
# Turn off buffer objects to let the rest of the draw code work.
|
||||||
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||||
|
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
|
||||||
|
glDeleteBuffersARB_p($grid_vertex);
|
||||||
|
glDeleteBuffersARB_p($triangle_vertex);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::draw_axes (Pointf3 center, float length, int width, bool always_visible){
|
||||||
|
/*
|
||||||
|
my $volumes_bb = $self->volumes_bounding_box;
|
||||||
|
|
||||||
|
{
|
||||||
|
# draw axes
|
||||||
|
# disable depth testing so that axes are not covered by ground
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
my $origin = $self->origin;
|
||||||
|
my $axis_len = max(
|
||||||
|
max(@{ $self->bed_bounding_box->size }),
|
||||||
|
1.2 * max(@{ $volumes_bb->size }),
|
||||||
|
);
|
||||||
|
glLineWidth(2);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
# draw line for x axis
|
||||||
|
glColor3f(1, 0, 0);
|
||||||
|
glVertex3f(@$origin, $ground_z);
|
||||||
|
glVertex3f($origin->x + $axis_len, $origin->y, $ground_z); #,,
|
||||||
|
# draw line for y axis
|
||||||
|
glColor3f(0, 1, 0);
|
||||||
|
glVertex3f(@$origin, $ground_z);
|
||||||
|
glVertex3f($origin->x, $origin->y + $axis_len, $ground_z); #++
|
||||||
|
glEnd();
|
||||||
|
# draw line for Z axis
|
||||||
|
# (re-enable depth test so that axis is correctly shown when objects are behind it)
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glColor3f(0, 0, 1);
|
||||||
|
glVertex3f(@$origin, $ground_z);
|
||||||
|
glVertex3f(@$origin, $ground_z+$axis_len);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (always_visible) {
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
} else {
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
}
|
||||||
|
glLineWidth(width);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
// draw line for x axis
|
||||||
|
glColor3f(1, 0, 0);
|
||||||
|
glVertex3f(center.x, center.y, center.z);
|
||||||
|
glVertex3f(center.x + length, center.y, center.z);
|
||||||
|
// draw line for y axis
|
||||||
|
glColor3f(0, 1, 0);
|
||||||
|
glVertex3f(center.x, center.y, center.z);
|
||||||
|
glVertex3f(center.x, center.y + length, center.z);
|
||||||
|
// draw line for Z axis
|
||||||
|
glColor3f(0, 0, 1);
|
||||||
|
glVertex3f(center.x, center.y, center.z);
|
||||||
|
glVertex3f(center.x, center.y, center.z + length);
|
||||||
|
glEnd();
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
}
|
||||||
|
void Scene3D::draw_volumes(){
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
|
|
||||||
|
for(const Volume &volume : volumes){
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(volume.origin.x, volume.origin.y, volume.origin.z);
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
glVertexPointer(3, GL_FLOAT, 0, volume.model.verts.data());
|
||||||
|
glNormalPointer(GL_FLOAT, 0, volume.model.norms.data());
|
||||||
|
glColor4ub(volume.color.Red(), volume.color.Green(), volume.color.Blue(), volume.color.Alpha());
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, volume.model.verts.size()/3);
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisableClientState(GL_NORMAL_ARRAY);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene3D::repaint(wxPaintEvent& e) {
|
||||||
|
if(!this->IsShownOnScreen())return;
|
||||||
|
// There should be a context->IsOk check once wx is updated
|
||||||
|
if(!this->SetCurrent(*(this->glContext)))return;
|
||||||
|
init_gl();
|
||||||
|
resize();
|
||||||
|
|
||||||
|
glClearColor(1, 1, 1, 1);
|
||||||
|
glClearDepth(1);
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
glRotatef(-theta, 1, 0, 0); // pitch
|
||||||
|
glRotatef(phi, 0, 0, 1); // yaw
|
||||||
|
/*} else {
|
||||||
|
my @rotmat = quat_to_rotmatrix($self->quat);
|
||||||
|
glMultMatrixd_p(@rotmat[0..15]);
|
||||||
|
}*/
|
||||||
|
glTranslatef(-_camera_target.x, -_camera_target.y, -_camera_target.z);
|
||||||
|
|
||||||
|
// light from above
|
||||||
|
GLfloat pos[] = {-0.5f, -0.5f, 1.0f, 0.0f}, spec[] = {0.2f, 0.2f, 0.2f, 1.0f}, diff[] = {0.5f, 0.5f, 0.5f, 1.0f};
|
||||||
|
glLightfv(GL_LIGHT0, GL_POSITION, pos);
|
||||||
|
glLightfv(GL_LIGHT0, GL_SPECULAR, spec);
|
||||||
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, diff);
|
||||||
|
|
||||||
|
before_render();
|
||||||
|
|
||||||
|
draw_background();
|
||||||
|
draw_ground();
|
||||||
|
/*my $origin = $self->origin;
|
||||||
|
my $axis_len = max(
|
||||||
|
max(@{ $self->bed_bounding_box->size }),
|
||||||
|
1.2 * max(@{ $volumes_bb->size }),
|
||||||
|
);*/
|
||||||
|
draw_axes(Pointf3(0.0f,0.0f,0.0f),
|
||||||
|
unscale(bed_bound.radius()),2,true/*origin,calulcated length,2, true*/);
|
||||||
|
|
||||||
|
// draw objects
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
draw_volumes();
|
||||||
|
|
||||||
|
after_render();
|
||||||
|
|
||||||
|
if (dragging/*defined $self->_drag_start_pos || defined $self->_drag_start_xy*/) {
|
||||||
|
draw_axes(_camera_target, 10.0f, 1, true/*camera,10,1,true*/);
|
||||||
|
draw_axes(_camera_target, 10.0f, 4, false/*camera,10,4,false*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
SwapBuffers();
|
||||||
|
// Calling glFinish has a performance penalty, but it seems to fix some OpenGL driver hang-up with extremely large scenes.
|
||||||
|
glFinish();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Volume Scene3D::load_object(ModelVolume &mv, ModelInstance &mi){
|
||||||
|
TriangleMesh copy = mv.mesh;
|
||||||
|
mi.transform_mesh(©);
|
||||||
|
GLVertexArray model;
|
||||||
|
model.load_mesh(copy);
|
||||||
|
return Volume{ wxColor(200,200,200), Pointf3(0,0,0), model, copy.bounding_box()};
|
||||||
|
}
|
||||||
|
|
||||||
|
} } // Namespace Slic3r::GUI
|
55
src/GUI/Scene3D.hpp
Normal file
55
src/GUI/Scene3D.hpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef SCENE3D_HPP
|
||||||
|
#define SCENE3D_HPP
|
||||||
|
#include <wx/wxprec.h>
|
||||||
|
#ifndef WX_PRECOMP
|
||||||
|
#include <wx/wx.h>
|
||||||
|
#endif
|
||||||
|
#include <wx/glcanvas.h>
|
||||||
|
#include "Settings.hpp"
|
||||||
|
#include "Point.hpp"
|
||||||
|
#include "3DScene.hpp"
|
||||||
|
#include "BoundingBox.hpp"
|
||||||
|
#include "Model.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
|
struct Volume {
|
||||||
|
wxColor color;
|
||||||
|
Pointf3 origin;
|
||||||
|
GLVertexArray model;
|
||||||
|
BoundingBoxf3 bb;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Scene3D : public wxGLCanvas {
|
||||||
|
public:
|
||||||
|
Scene3D(wxWindow* parent, const wxSize& size);
|
||||||
|
private:
|
||||||
|
wxGLContext* glContext;
|
||||||
|
bool init = false, dirty = true, dragging = false;
|
||||||
|
float zoom = 5.0f, phi = 0.0f, theta = 0.0f;
|
||||||
|
Point drag_start = Point(0,0);
|
||||||
|
Pointf3 _camera_target = Pointf3(0.0f,0.0f,0.0f);
|
||||||
|
std::vector<float> bed_verts, grid_verts;
|
||||||
|
Points bed_shape;
|
||||||
|
BoundingBox bed_bound;
|
||||||
|
void resize();
|
||||||
|
void repaint(wxPaintEvent &e);
|
||||||
|
void init_gl();
|
||||||
|
void draw_background();
|
||||||
|
void draw_ground();
|
||||||
|
void draw_axes(Pointf3 center, float length, int width, bool alwaysvisible);
|
||||||
|
protected:
|
||||||
|
void draw_volumes();
|
||||||
|
virtual void mouse_up(wxMouseEvent &e);
|
||||||
|
virtual void mouse_move(wxMouseEvent &e);
|
||||||
|
virtual void mouse_dclick(wxMouseEvent &e);
|
||||||
|
virtual void mouse_wheel(wxMouseEvent &e);
|
||||||
|
virtual void before_render(){};
|
||||||
|
virtual void after_render(){};
|
||||||
|
Volume load_object(ModelVolume &mv, ModelInstance &mi);
|
||||||
|
void set_bed_shape(Points _bed_shape);
|
||||||
|
std::vector<Volume> volumes;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } // Namespace Slic3r::GUI
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user