Add opencsg demo sandbox
This commit is contained in:
parent
9a0a4a5327
commit
66759e10e3
8 changed files with 1176 additions and 2 deletions
|
@ -1,3 +1,4 @@
|
|||
#add_subdirectory(slasupporttree)
|
||||
#add_subdirectory(openvdb)
|
||||
add_subdirectory(meshboolean)
|
||||
#add_subdirectory(meshboolean)
|
||||
add_subdirectory(opencsg)
|
||||
|
|
21
sandboxes/opencsg/CMakeLists.txt
Normal file
21
sandboxes/opencsg/CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(OpenCSG-example)
|
||||
|
||||
add_executable(opencsg_example main.cpp GLScene.hpp GLScene.cpp Canvas.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/ProgressStatusBar.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.cpp)
|
||||
|
||||
find_package(wxWidgets 3.1 REQUIRED COMPONENTS core base gl html)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GLEW REQUIRED)
|
||||
find_package(OpenCSG REQUIRED)
|
||||
find_package(GLUT REQUIRED)
|
||||
include(${wxWidgets_USE_FILE})
|
||||
|
||||
|
||||
target_link_libraries(opencsg_example libslic3r)
|
||||
target_include_directories(opencsg_example PRIVATE ${wxWidgets_INCLUDE_DIRS})
|
||||
target_compile_definitions(opencsg_example PRIVATE ${wxWidgets_DEFINITIONS})
|
||||
target_link_libraries(opencsg_example ${wxWidgets_LIBRARIES} GLEW::GLEW OpenCSG::opencsg GLUT::GLUT OpenGL::OpenGL -lXrandr -lXext -lX11)
|
112
sandboxes/opencsg/Canvas.hpp
Normal file
112
sandboxes/opencsg/Canvas.hpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
#ifndef CANVAS_HPP
|
||||
#define CANVAS_HPP
|
||||
|
||||
#include <memory>
|
||||
|
||||
// For compilers that support precompilation, includes "wx/wx.h".
|
||||
#include <wx/wxprec.h>
|
||||
#ifndef WX_PRECOMP
|
||||
#include <wx/wx.h>
|
||||
#endif
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
#include "GLScene.hpp"
|
||||
|
||||
namespace Slic3r { namespace GL {
|
||||
|
||||
class Canvas: public wxGLCanvas, public Slic3r::GL::Display
|
||||
{
|
||||
std::unique_ptr<wxGLContext> m_context;
|
||||
public:
|
||||
|
||||
void set_active(long w, long h) override
|
||||
{
|
||||
SetCurrent(*m_context);
|
||||
Slic3r::GL::Display::set_active(w, h);
|
||||
}
|
||||
|
||||
void repaint(long width, long height) override
|
||||
{
|
||||
Slic3r::GL::Display::repaint(width, height);
|
||||
}
|
||||
|
||||
using Slic3r::GL::Display::repaint;
|
||||
|
||||
void swap_buffers() override { SwapBuffers(); }
|
||||
|
||||
void on_scroll(long v, long d, Slic3r::GL::MouseInput::WheelAxis wa) override
|
||||
{
|
||||
Slic3r::GL::Display::on_scroll(v, d, wa);
|
||||
}
|
||||
|
||||
template<class...Args>
|
||||
Canvas(Args &&...args): wxGLCanvas(std::forward<Args>(args)...)
|
||||
{
|
||||
auto ctx = new wxGLContext(this);
|
||||
if (!ctx || !ctx->IsOK()) {
|
||||
wxMessageBox("Could not create OpenGL context.", "Error",
|
||||
wxOK | wxICON_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
m_context.reset(ctx);
|
||||
|
||||
Bind(
|
||||
wxEVT_MOUSEWHEEL,
|
||||
[this](wxMouseEvent &evt) {
|
||||
on_scroll(evt.GetWheelRotation(), evt.GetWheelDelta(),
|
||||
evt.GetWheelAxis() == wxMOUSE_WHEEL_VERTICAL ?
|
||||
Slic3r::GL::MouseInput::waVertical :
|
||||
Slic3r::GL::MouseInput::waHorizontal);
|
||||
},
|
||||
GetId());
|
||||
|
||||
Bind(
|
||||
wxEVT_MOTION,
|
||||
[this](wxMouseEvent &evt) {
|
||||
on_moved_to(evt.GetPosition().x, evt.GetPosition().y);
|
||||
},
|
||||
GetId());
|
||||
|
||||
Bind(
|
||||
wxEVT_RIGHT_DOWN,
|
||||
[this](wxMouseEvent & /*evt*/) { on_right_click_down(); },
|
||||
GetId());
|
||||
|
||||
Bind(
|
||||
wxEVT_RIGHT_UP,
|
||||
[this](wxMouseEvent & /*evt*/) { on_right_click_up(); },
|
||||
GetId());
|
||||
|
||||
Bind(
|
||||
wxEVT_LEFT_DOWN,
|
||||
[this](wxMouseEvent & /*evt*/) { on_left_click_down(); },
|
||||
GetId());
|
||||
|
||||
Bind(
|
||||
wxEVT_LEFT_UP,
|
||||
[this](wxMouseEvent & /*evt*/) { on_left_click_up(); },
|
||||
GetId());
|
||||
|
||||
Bind(wxEVT_PAINT, [this](wxPaintEvent &) {
|
||||
// This is required even though dc is not used otherwise.
|
||||
wxPaintDC dc(this);
|
||||
|
||||
// Set the OpenGL viewport according to the client size of this
|
||||
// canvas. This is done here rather than in a wxSizeEvent handler
|
||||
// because our OpenGL rendering context (and thus viewport setting) is
|
||||
// used with multiple canvases: If we updated the viewport in the
|
||||
// wxSizeEvent handler, changing the size of one canvas causes a
|
||||
// viewport setting that is wrong when next another canvas is
|
||||
// repainted.
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
repaint(ClientSize.x, ClientSize.y);
|
||||
}, GetId());
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GL
|
||||
|
||||
#endif // CANVAS_HPP
|
509
sandboxes/opencsg/GLScene.cpp
Normal file
509
sandboxes/opencsg/GLScene.cpp
Normal file
|
@ -0,0 +1,509 @@
|
|||
#include "GLScene.hpp"
|
||||
#include <libslic3r/Utils.hpp>
|
||||
#include <libslic3r/SLAPrint.hpp>
|
||||
#include <libslic3r/MTUtils.hpp>
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <GLUT/glut.h>
|
||||
#else
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define HAS_GLSAFE
|
||||
#endif
|
||||
|
||||
#ifdef HAS_GLSAFE
|
||||
extern void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char *function_name);
|
||||
inline void glAssertRecentCall() { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); }
|
||||
#define glsafe(cmd) do { cmd; glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } while (false)
|
||||
#define glcheck() do { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } while (false)
|
||||
|
||||
void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char *function_name)
|
||||
{
|
||||
GLenum err = glGetError();
|
||||
if (err == GL_NO_ERROR)
|
||||
return;
|
||||
const char *sErr = 0;
|
||||
switch (err) {
|
||||
case GL_INVALID_ENUM: sErr = "Invalid Enum"; break;
|
||||
case GL_INVALID_VALUE: sErr = "Invalid Value"; break;
|
||||
// be aware that GL_INVALID_OPERATION is generated if glGetError is executed between the execution of glBegin and the corresponding execution of glEnd
|
||||
case GL_INVALID_OPERATION: sErr = "Invalid Operation"; break;
|
||||
case GL_STACK_OVERFLOW: sErr = "Stack Overflow"; break;
|
||||
case GL_STACK_UNDERFLOW: sErr = "Stack Underflow"; break;
|
||||
case GL_OUT_OF_MEMORY: sErr = "Out Of Memory"; break;
|
||||
default: sErr = "Unknown"; break;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(error) << "OpenGL error in " << file_name << ":" << line << ", function " << function_name << "() : " << (int)err << " - " << sErr;
|
||||
assert(false);
|
||||
}
|
||||
|
||||
#else
|
||||
inline void glAssertRecentCall() { }
|
||||
#define glsafe(cmd) cmd
|
||||
#define glcheck()
|
||||
#endif
|
||||
|
||||
namespace Slic3r { namespace GL {
|
||||
|
||||
Scene::Scene() = default;
|
||||
|
||||
Scene::~Scene() = default;
|
||||
|
||||
void renderfps () {
|
||||
static std::ostringstream fpsStream;
|
||||
static int fps = 0;
|
||||
static int ancient = 0;
|
||||
static int last = 0;
|
||||
static int msec = 0;
|
||||
|
||||
last = msec;
|
||||
msec = glutGet(GLUT_ELAPSED_TIME);
|
||||
if (last / 1000 != msec / 1000) {
|
||||
|
||||
float correctedFps = fps * 1000.0f / float(msec - ancient);
|
||||
fpsStream.str("");
|
||||
fpsStream << "fps: " << correctedFps << std::ends;
|
||||
|
||||
ancient = msec;
|
||||
fps = 0;
|
||||
}
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glColor3f(0.0f, 0.0f, 0.0f);
|
||||
glRasterPos2f(-1.0f, -1.0f);
|
||||
glDisable(GL_LIGHTING);
|
||||
std::string s = fpsStream.str();
|
||||
for (unsigned int i=0; i<s.size(); ++i) {
|
||||
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, s[i]);
|
||||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
++fps;
|
||||
glFlush();
|
||||
}
|
||||
|
||||
void Display::render_scene()
|
||||
{
|
||||
GLfloat color[] = {1.f, 1.f, 0.f, 0.f};
|
||||
glsafe(::glColor4fv(color));
|
||||
|
||||
OpenCSG::render(m_scene->csg_primitives());
|
||||
|
||||
glDepthFunc(GL_EQUAL);
|
||||
for (auto& p : m_scene->csg_primitives()) p->render();
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
for (auto& p : m_scene->free_primitives()) p->render();
|
||||
|
||||
glFlush();
|
||||
}
|
||||
|
||||
template<class It,
|
||||
class Trafo,
|
||||
class GetPt,
|
||||
class V = typename std::iterator_traits<It>::value_type>
|
||||
std::vector<V> transform_pts(
|
||||
It from, It to, Trafo &&tr, GetPt &&point)
|
||||
{
|
||||
auto ret = reserve_vector<V>(to - from);
|
||||
for(auto it = from; it != to; ++it) {
|
||||
V v = *it;
|
||||
v.pos = tr * point(*it);
|
||||
ret.emplace_back(std::move(v));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Scene::set_print(uqptr<SLAPrint> &&print)
|
||||
{
|
||||
m_print = std::move(print);
|
||||
|
||||
for (const SLAPrintObject *po : m_print->objects()) {
|
||||
const ModelObject *mo = po->model_object();
|
||||
TriangleMesh msh = mo->raw_mesh();
|
||||
|
||||
sla::DrainHoles holedata = mo->sla_drain_holes;
|
||||
|
||||
for (const ModelInstance *mi : mo->instances) {
|
||||
|
||||
TriangleMesh mshinst = msh;
|
||||
auto interior = po->hollowed_interior_mesh();
|
||||
interior.transform(po->trafo().inverse());
|
||||
|
||||
mshinst.merge(interior);
|
||||
mshinst.require_shared_vertices();
|
||||
|
||||
mi->transform_mesh(&mshinst);
|
||||
|
||||
auto bb = mshinst.bounding_box();
|
||||
auto center = bb.center().cast<float>();
|
||||
mshinst.translate(-center);
|
||||
|
||||
mshinst.require_shared_vertices();
|
||||
add_mesh(mshinst, OpenCSG::Intersection, 15);
|
||||
|
||||
auto tr = Transform3f::Identity();
|
||||
tr.translate(-center);
|
||||
|
||||
transform_pts(holedata.begin(), holedata.end(), tr,
|
||||
[](const sla::DrainHole &dh) {
|
||||
return dh.pos;
|
||||
});
|
||||
|
||||
transform_pts(holedata.begin(), holedata.end(), tr,
|
||||
[](const sla::DrainHole &dh) {
|
||||
return dh.normal;
|
||||
});
|
||||
}
|
||||
|
||||
for (const sla::DrainHole &holept : holedata) {
|
||||
TriangleMesh holemesh = sla::to_triangle_mesh(holept.to_mesh());
|
||||
holemesh.require_shared_vertices();
|
||||
add_mesh(holemesh, OpenCSG::Subtraction, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Notify displays
|
||||
call(&Display::on_scene_updated, m_displays);
|
||||
}
|
||||
|
||||
BoundingBoxf3 Scene::get_bounding_box() const
|
||||
{
|
||||
return m_print->model().bounding_box();
|
||||
}
|
||||
|
||||
shptr<Primitive> Scene::add_mesh(const TriangleMesh &mesh)
|
||||
{
|
||||
auto p = std::make_shared<Primitive>();
|
||||
p->load_mesh(mesh);
|
||||
m_primitives.emplace_back(p);
|
||||
m_primitives_free.emplace_back(p.get());
|
||||
return p;
|
||||
}
|
||||
|
||||
shptr<Primitive> Scene::add_mesh(const TriangleMesh &mesh, OpenCSG::Operation o, unsigned c)
|
||||
{
|
||||
auto p = std::make_shared<Primitive>(o, c);
|
||||
p->load_mesh(mesh);
|
||||
m_primitives.emplace_back(p);
|
||||
m_primitives_csg.emplace_back(p.get());
|
||||
return p;
|
||||
}
|
||||
|
||||
void IndexedVertexArray::push_geometry(float x, float y, float z, float nx, float ny, float nz)
|
||||
{
|
||||
assert(this->vertices_and_normals_interleaved_VBO_id == 0);
|
||||
if (this->vertices_and_normals_interleaved_VBO_id != 0)
|
||||
return;
|
||||
|
||||
if (this->vertices_and_normals_interleaved.size() + 6 > this->vertices_and_normals_interleaved.capacity())
|
||||
this->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(this->vertices_and_normals_interleaved.size() + 6));
|
||||
this->vertices_and_normals_interleaved.emplace_back(nx);
|
||||
this->vertices_and_normals_interleaved.emplace_back(ny);
|
||||
this->vertices_and_normals_interleaved.emplace_back(nz);
|
||||
this->vertices_and_normals_interleaved.emplace_back(x);
|
||||
this->vertices_and_normals_interleaved.emplace_back(y);
|
||||
this->vertices_and_normals_interleaved.emplace_back(z);
|
||||
|
||||
this->vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size();
|
||||
}
|
||||
|
||||
void IndexedVertexArray::push_triangle(int idx1, int idx2, int idx3) {
|
||||
assert(this->vertices_and_normals_interleaved_VBO_id == 0);
|
||||
if (this->vertices_and_normals_interleaved_VBO_id != 0)
|
||||
return;
|
||||
|
||||
if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity())
|
||||
this->triangle_indices.reserve(next_highest_power_of_2(this->triangle_indices.size() + 3));
|
||||
this->triangle_indices.emplace_back(idx1);
|
||||
this->triangle_indices.emplace_back(idx2);
|
||||
this->triangle_indices.emplace_back(idx3);
|
||||
this->triangle_indices_size = this->triangle_indices.size();
|
||||
}
|
||||
|
||||
void IndexedVertexArray::load_mesh(const TriangleMesh &mesh)
|
||||
{
|
||||
assert(triangle_indices.empty() && vertices_and_normals_interleaved_size == 0);
|
||||
assert(quad_indices.empty() && triangle_indices_size == 0);
|
||||
assert(vertices_and_normals_interleaved.size() % 6 == 0 && quad_indices_size == vertices_and_normals_interleaved.size());
|
||||
|
||||
this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count());
|
||||
|
||||
int vertices_count = 0;
|
||||
for (size_t i = 0; i < mesh.stl.stats.number_of_facets; ++i) {
|
||||
const stl_facet &facet = mesh.stl.facet_start[i];
|
||||
for (int j = 0; j < 3; ++j)
|
||||
this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2));
|
||||
|
||||
this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2);
|
||||
vertices_count += 3;
|
||||
}
|
||||
}
|
||||
|
||||
void IndexedVertexArray::finalize_geometry()
|
||||
{
|
||||
assert(this->vertices_and_normals_interleaved_VBO_id == 0);
|
||||
assert(this->triangle_indices_VBO_id == 0);
|
||||
assert(this->quad_indices_VBO_id == 0);
|
||||
|
||||
if (!this->vertices_and_normals_interleaved.empty()) {
|
||||
glsafe(
|
||||
::glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER,
|
||||
this->vertices_and_normals_interleaved_VBO_id));
|
||||
glsafe(
|
||||
::glBufferData(GL_ARRAY_BUFFER,
|
||||
GLsizeiptr(
|
||||
this->vertices_and_normals_interleaved.size() *
|
||||
4),
|
||||
this->vertices_and_normals_interleaved.data(),
|
||||
GL_STATIC_DRAW));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
this->vertices_and_normals_interleaved.clear();
|
||||
}
|
||||
if (!this->triangle_indices.empty()) {
|
||||
glsafe(::glGenBuffers(1, &this->triangle_indices_VBO_id));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
|
||||
this->triangle_indices_VBO_id));
|
||||
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
GLsizeiptr(this->triangle_indices.size() * 4),
|
||||
this->triangle_indices.data(), GL_STATIC_DRAW));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
this->triangle_indices.clear();
|
||||
}
|
||||
if (!this->quad_indices.empty()) {
|
||||
glsafe(::glGenBuffers(1, &this->quad_indices_VBO_id));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
|
||||
this->quad_indices_VBO_id));
|
||||
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
GLsizeiptr(this->quad_indices.size() * 4),
|
||||
this->quad_indices.data(), GL_STATIC_DRAW));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
this->quad_indices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void IndexedVertexArray::release_geometry()
|
||||
{
|
||||
if (this->vertices_and_normals_interleaved_VBO_id) {
|
||||
glsafe(
|
||||
::glDeleteBuffers(1,
|
||||
&this->vertices_and_normals_interleaved_VBO_id));
|
||||
this->vertices_and_normals_interleaved_VBO_id = 0;
|
||||
}
|
||||
if (this->triangle_indices_VBO_id) {
|
||||
glsafe(::glDeleteBuffers(1, &this->triangle_indices_VBO_id));
|
||||
this->triangle_indices_VBO_id = 0;
|
||||
}
|
||||
if (this->quad_indices_VBO_id) {
|
||||
glsafe(::glDeleteBuffers(1, &this->quad_indices_VBO_id));
|
||||
this->quad_indices_VBO_id = 0;
|
||||
}
|
||||
this->clear();
|
||||
}
|
||||
|
||||
void IndexedVertexArray::render() const
|
||||
{
|
||||
assert(this->vertices_and_normals_interleaved_VBO_id != 0);
|
||||
assert(this->triangle_indices_VBO_id != 0 ||
|
||||
this->quad_indices_VBO_id != 0);
|
||||
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER,
|
||||
this->vertices_and_normals_interleaved_VBO_id));
|
||||
glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float),
|
||||
reinterpret_cast<const void *>(3 * sizeof(float))));
|
||||
glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr));
|
||||
|
||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||
|
||||
// Render using the Vertex Buffer Objects.
|
||||
if (this->triangle_indices_size > 0) {
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
|
||||
this->triangle_indices_VBO_id));
|
||||
glsafe(::glDrawElements(GL_TRIANGLES,
|
||||
GLsizei(this->triangle_indices_size),
|
||||
GL_UNSIGNED_INT, nullptr));
|
||||
glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
}
|
||||
if (this->quad_indices_size > 0) {
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
|
||||
this->quad_indices_VBO_id));
|
||||
glsafe(::glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size),
|
||||
GL_UNSIGNED_INT, nullptr));
|
||||
glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
}
|
||||
|
||||
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
||||
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
||||
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
}
|
||||
|
||||
void IndexedVertexArray::clear() {
|
||||
this->vertices_and_normals_interleaved.clear();
|
||||
this->triangle_indices.clear();
|
||||
this->quad_indices.clear();
|
||||
vertices_and_normals_interleaved_size = 0;
|
||||
triangle_indices_size = 0;
|
||||
quad_indices_size = 0;
|
||||
}
|
||||
|
||||
void IndexedVertexArray::shrink_to_fit() {
|
||||
this->vertices_and_normals_interleaved.shrink_to_fit();
|
||||
this->triangle_indices.shrink_to_fit();
|
||||
this->quad_indices.shrink_to_fit();
|
||||
}
|
||||
|
||||
void Primitive::render()
|
||||
{
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glMultMatrixd(m_trafo.get_matrix().data()));
|
||||
m_geom.render();
|
||||
glsafe(::glPopMatrix());
|
||||
}
|
||||
|
||||
void Display::clear_screen()
|
||||
{
|
||||
glViewport(0, 0, GLsizei(m_size.x()), GLsizei(m_size.y()));
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void Display::set_active(long width, long height)
|
||||
{
|
||||
static int argc = 0;
|
||||
|
||||
if (!m_initialized) {
|
||||
glewInit();
|
||||
glutInit(&argc, nullptr);
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
m_size = {width, height};
|
||||
|
||||
// gray background
|
||||
glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
|
||||
|
||||
// Enable two OpenGL lights
|
||||
GLfloat light_diffuse[] = { 1.0f, 1.0f, 0.0f, 1.0f}; // White diffuse light
|
||||
GLfloat light_position0[] = {-1.0f, -1.0f, -1.0f, 0.0f}; // Infinite light location
|
||||
GLfloat light_position1[] = { 1.0f, 1.0f, 1.0f, 0.0f}; // Infinite light location
|
||||
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
|
||||
glEnable(GL_LIGHT0);
|
||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
|
||||
glLightfv(GL_LIGHT1, GL_POSITION, light_position1);
|
||||
glEnable(GL_LIGHT1);
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_NORMALIZE);
|
||||
|
||||
// Use depth buffering for hidden surface elimination
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
|
||||
m_camera->set_screen(width, height);
|
||||
}
|
||||
|
||||
void Display::repaint(long width, long height)
|
||||
{
|
||||
if (m_size.x() != width || m_size.y() != height)
|
||||
m_camera->set_screen(width, height);
|
||||
|
||||
m_size = {width, height};
|
||||
|
||||
clear_screen();
|
||||
|
||||
m_camera->view();
|
||||
render_scene();
|
||||
|
||||
renderfps();
|
||||
|
||||
swap_buffers();
|
||||
}
|
||||
|
||||
void Display::on_scroll(long v, long d, MouseInput::WheelAxis wa)
|
||||
{
|
||||
m_wheel_pos += v / d;
|
||||
|
||||
m_camera->set_zoom(m_wheel_pos);
|
||||
|
||||
m_scene->on_scroll(v, d, wa);
|
||||
|
||||
repaint(m_size.x(), m_size.y());
|
||||
}
|
||||
|
||||
void Display::on_moved_to(long x, long y)
|
||||
{
|
||||
if (m_left_btn) {
|
||||
m_camera->rotate((Vec2i{x, y} - m_mouse_pos).cast<float>());
|
||||
repaint();
|
||||
}
|
||||
m_mouse_pos = {x, y};
|
||||
}
|
||||
|
||||
void CSGSettings::set_csg_algo(OpenCSG::Algorithm alg) { m_csgalg = alg; }
|
||||
|
||||
void Display::on_scene_updated()
|
||||
{
|
||||
auto bb = m_scene->get_bounding_box();
|
||||
double d = std::max(std::max(bb.size().x(), bb.size().y()), bb.size().z());
|
||||
m_wheel_pos = long(2 * d);
|
||||
m_camera->set_zoom(m_wheel_pos);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void Display::set_scene(shptr<Scene> scene)
|
||||
{
|
||||
m_scene = scene;
|
||||
m_scene->add_display(shared_from_this());
|
||||
}
|
||||
|
||||
void Camera::view()
|
||||
{
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(0.0, m_zoom, 0.0, /* eye is at (0,zoom,0) */
|
||||
m_referene.x(), m_referene.y(), m_referene.z(),
|
||||
0.0, 0.0, 1.0); /* up is in positive Y direction */
|
||||
|
||||
// TODO Could have been set in prevoius gluLookAt in first argument
|
||||
glRotatef(m_rot.y(), 1.0, 0.0, 0.0);
|
||||
glRotatef(m_rot.x(), 0.0, 0.0, 1.0);
|
||||
|
||||
// glClipPlane()
|
||||
}
|
||||
|
||||
void PerspectiveCamera::set_screen(long width, long height)
|
||||
{
|
||||
// Setup the view of the CSG shape
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(45.0, width / double(height), .1, 200.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
bool enable_multisampling(bool e)
|
||||
{
|
||||
if (!e) { glDisable(GL_MULTISAMPLE); return false; }
|
||||
|
||||
GLint is_ms_context;
|
||||
glGetIntegerv(GL_SAMPLE_BUFFERS, &is_ms_context);
|
||||
|
||||
if (is_ms_context) { glEnable(GL_MULTISAMPLE); return true; }
|
||||
else return false;
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GL
|
321
sandboxes/opencsg/GLScene.hpp
Normal file
321
sandboxes/opencsg/GLScene.hpp
Normal file
|
@ -0,0 +1,321 @@
|
|||
#ifndef GLSCENE_HPP
|
||||
#define GLSCENE_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <libslic3r/Geometry.hpp>
|
||||
#include <libslic3r/Model.hpp>
|
||||
#include <libslic3r/TriangleMesh.hpp>
|
||||
#include <libslic3r/SLA/Hollowing.hpp>
|
||||
#include <opencsg/opencsg.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class SLAPrint;
|
||||
|
||||
namespace GL {
|
||||
|
||||
template<class T> using shptr = std::shared_ptr<T>;
|
||||
template<class T> using uqptr = std::unique_ptr<T>;
|
||||
template<class T> using wkptr = std::weak_ptr<T>;
|
||||
|
||||
template<class T, class A = std::allocator<T>>
|
||||
using Collection = std::vector<T, A>;
|
||||
|
||||
template<class L> void cleanup(Collection<std::weak_ptr<L>> &listeners) {
|
||||
auto it = std::remove_if(listeners.begin(), listeners.end(),
|
||||
[](auto &l) { return !l.lock(); });
|
||||
listeners.erase(it, listeners.end());
|
||||
}
|
||||
|
||||
template<class F, class L, class...Args>
|
||||
void call(F &&f, Collection<std::weak_ptr<L>> &listeners, Args&&... args) {
|
||||
for (auto &l : listeners)
|
||||
if (auto p = l.lock()) ((p.get())->*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
class MouseInput
|
||||
{
|
||||
public:
|
||||
|
||||
enum WheelAxis {
|
||||
waVertical, waHorizontal
|
||||
};
|
||||
|
||||
class Listener {
|
||||
public:
|
||||
|
||||
virtual ~Listener() = default;
|
||||
|
||||
virtual void on_left_click_down() {}
|
||||
virtual void on_left_click_up() {}
|
||||
virtual void on_right_click_down() {}
|
||||
virtual void on_right_click_up() {}
|
||||
virtual void on_double_click() {}
|
||||
virtual void on_scroll(long /*v*/, long /*delta*/, WheelAxis ) {}
|
||||
virtual void on_moved_to(long /*x*/, long /*y*/) {}
|
||||
};
|
||||
|
||||
private:
|
||||
Collection<wkptr<Listener>> m_listeners;
|
||||
|
||||
public:
|
||||
virtual ~MouseInput() = default;
|
||||
|
||||
virtual void left_click_down()
|
||||
{
|
||||
call(&Listener::on_left_click_down, m_listeners);
|
||||
}
|
||||
virtual void left_click_up()
|
||||
{
|
||||
call(&Listener::on_left_click_up, m_listeners);
|
||||
}
|
||||
virtual void right_click_down()
|
||||
{
|
||||
call(&Listener::on_right_click_down, m_listeners);
|
||||
}
|
||||
virtual void right_click_up()
|
||||
{
|
||||
call(&Listener::on_right_click_up, m_listeners);
|
||||
}
|
||||
virtual void double_click()
|
||||
{
|
||||
call(&Listener::on_double_click, m_listeners);
|
||||
}
|
||||
virtual void scroll(long v, long d, WheelAxis wa)
|
||||
{
|
||||
call(&Listener::on_scroll, m_listeners, v, d, wa);
|
||||
}
|
||||
virtual void move_to(long x, long y)
|
||||
{
|
||||
call(&Listener::on_moved_to, m_listeners, x, y);
|
||||
}
|
||||
|
||||
void add_listener(shptr<Listener> listener)
|
||||
{
|
||||
m_listeners.emplace_back(listener);
|
||||
cleanup(m_listeners);
|
||||
}
|
||||
};
|
||||
|
||||
class IndexedVertexArray {
|
||||
public:
|
||||
~IndexedVertexArray() { release_geometry(); }
|
||||
|
||||
// Vertices and their normals, interleaved to be used by void
|
||||
// glInterleavedArrays(GL_N3F_V3F, 0, x)
|
||||
Collection<float> vertices_and_normals_interleaved;
|
||||
Collection<int> triangle_indices;
|
||||
Collection<int> quad_indices;
|
||||
|
||||
// When the geometry data is loaded into the graphics card as Vertex
|
||||
// Buffer Objects, the above mentioned std::vectors are cleared and the
|
||||
// following variables keep their original length.
|
||||
size_t vertices_and_normals_interleaved_size{ 0 };
|
||||
size_t triangle_indices_size{ 0 };
|
||||
size_t quad_indices_size{ 0 };
|
||||
|
||||
// IDs of the Vertex Array Objects, into which the geometry has been loaded.
|
||||
// Zero if the VBOs are not sent to GPU yet.
|
||||
unsigned int vertices_and_normals_interleaved_VBO_id{ 0 };
|
||||
unsigned int triangle_indices_VBO_id{ 0 };
|
||||
unsigned int quad_indices_VBO_id{ 0 };
|
||||
|
||||
|
||||
void push_geometry(float x, float y, float z, float nx, float ny, float nz);
|
||||
|
||||
inline void push_geometry(
|
||||
double x, double y, double z, double nx, double ny, double nz)
|
||||
{
|
||||
push_geometry(float(x), float(y), float(z), float(nx), float(ny), float(nz));
|
||||
}
|
||||
|
||||
inline void push_geometry(const Vec3d &p, const Vec3d &n)
|
||||
{
|
||||
push_geometry(p(0), p(1), p(2), n(0), n(1), n(2));
|
||||
}
|
||||
|
||||
void push_triangle(int idx1, int idx2, int idx3);
|
||||
|
||||
void load_mesh(const TriangleMesh &mesh);
|
||||
|
||||
inline bool has_VBOs() const
|
||||
{
|
||||
return vertices_and_normals_interleaved_VBO_id != 0;
|
||||
}
|
||||
|
||||
// Finalize the initialization of the geometry & indices,
|
||||
// upload the geometry and indices to OpenGL VBO objects
|
||||
// and shrink the allocated data, possibly relasing it if it has been
|
||||
// loaded into the VBOs.
|
||||
void finalize_geometry();
|
||||
// Release the geometry data, release OpenGL VBOs.
|
||||
void release_geometry();
|
||||
|
||||
void render() const;
|
||||
|
||||
// Is there any geometry data stored?
|
||||
bool empty() const { return vertices_and_normals_interleaved_size == 0; }
|
||||
|
||||
void clear();
|
||||
|
||||
// Shrink the internal storage to tighly fit the data stored.
|
||||
void shrink_to_fit();
|
||||
};
|
||||
|
||||
bool enable_multisampling(bool e = true);
|
||||
void renderfps();
|
||||
|
||||
class Primitive : public OpenCSG::Primitive
|
||||
{
|
||||
IndexedVertexArray m_geom;
|
||||
Geometry::Transformation m_trafo;
|
||||
public:
|
||||
|
||||
using OpenCSG::Primitive::Primitive;
|
||||
|
||||
Primitive() : OpenCSG::Primitive(OpenCSG::Intersection, 1) {}
|
||||
|
||||
void render();
|
||||
|
||||
void translation(const Vec3d &offset) { m_trafo.set_offset(offset); }
|
||||
void rotation(const Vec3d &rot) { m_trafo.set_rotation(rot); }
|
||||
void scale(const Vec3d &scaleing) { m_trafo.set_scaling_factor(scaleing); }
|
||||
void scale(double s) { scale({s, s, s}); }
|
||||
|
||||
inline void load_mesh(const TriangleMesh &mesh) {
|
||||
m_geom.load_mesh(mesh);
|
||||
m_geom.finalize_geometry();
|
||||
}
|
||||
};
|
||||
|
||||
class Scene;
|
||||
|
||||
class Camera {
|
||||
protected:
|
||||
Vec2f m_rot = {0., 0.};
|
||||
Vec3d m_referene = {0., 0., 0.};
|
||||
double m_zoom = 0.;
|
||||
double m_clip_z = 0.;
|
||||
public:
|
||||
|
||||
virtual ~Camera() = default;
|
||||
|
||||
virtual void view();
|
||||
virtual void set_screen(long width, long height) = 0;
|
||||
|
||||
void set_rotation(const Vec2f &rotation) { m_rot = rotation; }
|
||||
void rotate(const Vec2f &rotation) { m_rot += rotation; }
|
||||
void set_zoom(double z) { m_zoom = z; }
|
||||
void set_reference_point(const Vec3d &p) { m_referene = p; }
|
||||
void set_clip_z(double z) { m_clip_z = z; }
|
||||
};
|
||||
|
||||
class PerspectiveCamera: public Camera {
|
||||
public:
|
||||
|
||||
void set_screen(long width, long height) override;
|
||||
};
|
||||
|
||||
class CSGSettings {
|
||||
OpenCSG::Algorithm m_csgalg = OpenCSG::Algorithm::Automatic;
|
||||
public:
|
||||
void set_csg_algo(OpenCSG::Algorithm alg);
|
||||
};
|
||||
|
||||
class Display : public std::enable_shared_from_this<Display>,
|
||||
public MouseInput::Listener
|
||||
{
|
||||
protected:
|
||||
shptr<Scene> m_scene;
|
||||
long m_wheel_pos = 0;
|
||||
Vec2i m_mouse_pos, m_mouse_pos_rprev, m_mouse_pos_lprev;
|
||||
Vec2i m_size;
|
||||
bool m_initialized = false, m_left_btn = false, m_right_btn = false;
|
||||
|
||||
CSGSettings m_csgsettings;
|
||||
|
||||
shptr<Camera> m_camera;
|
||||
|
||||
public:
|
||||
Display(shptr<Scene> scene = nullptr, shptr<Camera> camera = nullptr)
|
||||
: m_scene(scene)
|
||||
, m_camera(camera ? camera : std::make_shared<PerspectiveCamera>())
|
||||
{}
|
||||
|
||||
virtual void swap_buffers() = 0;
|
||||
|
||||
virtual void set_active(long width, long height);
|
||||
|
||||
virtual void repaint(long width, long height);
|
||||
void repaint() { repaint(m_size.x(), m_size.y()); }
|
||||
|
||||
void set_scene(shptr<Scene> scene);
|
||||
shptr<Scene> get_scene() { return m_scene; }
|
||||
|
||||
bool is_initialized() const { return m_initialized; }
|
||||
|
||||
void on_scroll(long v, long d, MouseInput::WheelAxis wa) override;
|
||||
void on_moved_to(long x, long y) override;
|
||||
void on_left_click_down() override { m_left_btn = true; }
|
||||
void on_left_click_up() override { m_left_btn = false; }
|
||||
void on_right_click_down() override { m_right_btn = true; }
|
||||
void on_right_click_up() override { m_right_btn = false; }
|
||||
|
||||
void move_clip_plane(double z) { m_camera->set_clip_z(z); }
|
||||
|
||||
const CSGSettings & csgsettings() const { return m_csgsettings; }
|
||||
void csgsettings(const CSGSettings &settings) { m_csgsettings = settings; }
|
||||
|
||||
virtual void on_scene_updated();
|
||||
virtual void clear_screen();
|
||||
virtual void render_scene();
|
||||
};
|
||||
|
||||
class Scene: public MouseInput::Listener
|
||||
{
|
||||
Collection<shptr<Primitive>> m_primitives;
|
||||
Collection<Primitive *> m_primitives_free;
|
||||
Collection<OpenCSG::Primitive *> m_primitives_csg;
|
||||
|
||||
uqptr<SLAPrint> m_print;
|
||||
public:
|
||||
|
||||
Scene();
|
||||
~Scene();
|
||||
|
||||
const Collection<Primitive*>& free_primitives() const
|
||||
{
|
||||
return m_primitives_free;
|
||||
}
|
||||
|
||||
const Collection<OpenCSG::Primitive*>& csg_primitives() const
|
||||
{
|
||||
return m_primitives_csg;
|
||||
}
|
||||
|
||||
void add_display(shptr<Display> disp)
|
||||
{
|
||||
m_displays.emplace_back(disp);
|
||||
cleanup(m_displays);
|
||||
}
|
||||
|
||||
void set_print(uqptr<SLAPrint> &&print);
|
||||
|
||||
BoundingBoxf3 get_bounding_box() const;
|
||||
|
||||
protected:
|
||||
|
||||
shptr<Primitive> add_mesh(const TriangleMesh &mesh);
|
||||
shptr<Primitive> add_mesh(const TriangleMesh &mesh,
|
||||
OpenCSG::Operation op,
|
||||
unsigned covexity);
|
||||
|
||||
private:
|
||||
|
||||
Collection<wkptr<Display>> m_displays;
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GL
|
||||
#endif // GLSCENE_HPP
|
195
sandboxes/opencsg/main.cpp
Normal file
195
sandboxes/opencsg/main.cpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <opencsg/opencsg.h>
|
||||
// For compilers that support precompilation, includes "wx/wx.h".
|
||||
#include <wx/wxprec.h>
|
||||
#ifndef WX_PRECOMP
|
||||
#include <wx/wx.h>
|
||||
#endif
|
||||
|
||||
#include <wx/slider.h>
|
||||
#include <wx/tglbtn.h>
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/glcanvas.h>
|
||||
|
||||
#include "Canvas.hpp"
|
||||
#include "GLScene.hpp"
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Format/3mf.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
|
||||
#include "slic3r/GUI/Job.hpp"
|
||||
#include "slic3r/GUI/ProgressStatusBar.hpp"
|
||||
//#include "slic3r/GUI/3DEngine.hpp"
|
||||
|
||||
using namespace Slic3r::GL;
|
||||
|
||||
class MyFrame: public wxFrame
|
||||
{
|
||||
std::shared_ptr<Canvas> m_canvas;
|
||||
std::shared_ptr<Slic3r::GUI::ProgressStatusBar> m_stbar;
|
||||
std::unique_ptr<Slic3r::GUI::Job> m_ui_job;
|
||||
|
||||
class SLAJob: public Slic3r::GUI::Job {
|
||||
MyFrame *m_parent;
|
||||
std::unique_ptr<Slic3r::SLAPrint> m_print;
|
||||
std::string m_fname;
|
||||
public:
|
||||
|
||||
SLAJob(MyFrame *frame, const std::string &fname)
|
||||
: Slic3r::GUI::Job{frame->m_stbar}
|
||||
, m_parent{frame}
|
||||
, m_fname{fname}
|
||||
{
|
||||
}
|
||||
|
||||
void process() override
|
||||
{
|
||||
using Status = Slic3r::PrintBase::SlicingStatus;
|
||||
|
||||
Slic3r::DynamicPrintConfig cfg;
|
||||
auto model = Slic3r::Model::read_from_file(m_fname, &cfg);
|
||||
|
||||
m_print = std::make_unique<Slic3r::SLAPrint>();
|
||||
m_print->apply(model, cfg);
|
||||
|
||||
m_print->set_status_callback([this](const Status &status) {
|
||||
update_status(status.percent, status.text);
|
||||
});
|
||||
|
||||
m_print->process();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void finalize() override
|
||||
{
|
||||
m_parent->m_canvas->get_scene()->set_print(std::move(m_print));
|
||||
m_parent->m_stbar->set_status_text(
|
||||
wxString::Format("Model %s loaded.", m_fname));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size):
|
||||
wxFrame(nullptr, wxID_ANY, title, pos, size)
|
||||
{
|
||||
wxMenu *menuFile = new wxMenu;
|
||||
menuFile->Append(wxID_OPEN);
|
||||
menuFile->Append(wxID_EXIT);
|
||||
wxMenuBar *menuBar = new wxMenuBar;
|
||||
menuBar->Append( menuFile, "&File" );
|
||||
SetMenuBar( menuBar );
|
||||
|
||||
m_stbar = std::make_shared<Slic3r::GUI::ProgressStatusBar>(this);
|
||||
m_stbar->embed(this);
|
||||
|
||||
SetStatusText( "Welcome to wxWidgets!" );
|
||||
|
||||
int attribList[] =
|
||||
{WX_GL_RGBA, WX_GL_DOUBLEBUFFER,
|
||||
// RGB channels each should be allocated with 8 bit depth. One
|
||||
// should almost certainly get these bit depths by default.
|
||||
WX_GL_MIN_RED, 8, WX_GL_MIN_GREEN, 8, WX_GL_MIN_BLUE, 8,
|
||||
// Requesting an 8 bit alpha channel. Interestingly, the NVIDIA
|
||||
// drivers would most likely work with some alpha plane, but
|
||||
// glReadPixels would not return the alpha channel on NVIDIA if
|
||||
// not requested when the GL context is created.
|
||||
WX_GL_MIN_ALPHA, 8, WX_GL_DEPTH_SIZE, 8, WX_GL_STENCIL_SIZE, 8, WX_GL_SAMPLE_BUFFERS,
|
||||
GL_TRUE, WX_GL_SAMPLES, 4, 0};
|
||||
|
||||
m_canvas = std::make_shared<Canvas>(this, wxID_ANY, attribList,
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE);
|
||||
|
||||
wxPanel *control_panel = new wxPanel(this);
|
||||
auto controlsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto slider_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
auto console_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
auto slider = new wxSlider(control_panel, wxID_ANY, 0, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL);
|
||||
auto toggle = new wxToggleButton(control_panel, wxID_ANY, "Multisampling");
|
||||
wxString algorithms [] = {"Default", "Different"};
|
||||
auto alg_select = new wxComboBox(control_panel, wxID_ANY, "Default", wxDefaultPosition, wxDefaultSize, 2, algorithms);
|
||||
|
||||
slider_sizer->Add(slider, 1, wxEXPAND);
|
||||
console_sizer->Add(toggle, 0, wxALL, 5);
|
||||
console_sizer->Add(alg_select, 0, wxALL, 5);
|
||||
controlsizer->Add(slider_sizer, 0, wxEXPAND);
|
||||
controlsizer->Add(console_sizer, 1, wxEXPAND);
|
||||
control_panel->SetSizer(controlsizer);
|
||||
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(m_canvas.get(), 1, wxEXPAND);
|
||||
sizer->Add(control_panel, 0, wxEXPAND);
|
||||
SetSizer(sizer);
|
||||
|
||||
Bind(wxEVT_MENU, &MyFrame::OnOpen, this, wxID_OPEN);
|
||||
Bind(wxEVT_MENU, &MyFrame::OnExit, this, wxID_EXIT);
|
||||
Bind(wxEVT_SHOW, &MyFrame::OnShown, this, GetId());
|
||||
Bind(wxEVT_SLIDER, [this, slider](wxCommandEvent &) {
|
||||
m_canvas->move_clip_plane(double(slider->GetValue()));
|
||||
}, slider->GetId());
|
||||
|
||||
Bind(wxEVT_TOGGLEBUTTON, [this, toggle](wxCommandEvent &){
|
||||
enable_multisampling(toggle->GetValue());
|
||||
m_canvas->repaint();
|
||||
}, toggle->GetId());
|
||||
|
||||
m_canvas->set_scene(std::make_shared<Slic3r::GL::Scene>());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void OnExit(wxCommandEvent& /*event*/)
|
||||
{
|
||||
RemoveChild(m_canvas.get());
|
||||
m_canvas->Destroy();
|
||||
Close( true );
|
||||
}
|
||||
|
||||
void OnOpen(wxCommandEvent &/*evt*/)
|
||||
{
|
||||
wxFileDialog dlg(this, "Select project file",
|
||||
wxEmptyString, wxEmptyString, "*.3mf");
|
||||
|
||||
if (dlg.ShowModal() == wxID_OK)
|
||||
{
|
||||
m_ui_job = std::make_unique<SLAJob>(this, dlg.GetPath().ToStdString());
|
||||
m_ui_job->start();
|
||||
}
|
||||
}
|
||||
|
||||
void OnShown(wxShowEvent&)
|
||||
{
|
||||
const wxSize ClientSize = GetClientSize();
|
||||
m_canvas->set_active(ClientSize.x, ClientSize.y);
|
||||
|
||||
m_canvas->repaint(ClientSize.x, ClientSize.y);
|
||||
|
||||
// Do the repaint continuously
|
||||
Bind(wxEVT_IDLE, [this](wxIdleEvent &evt) {
|
||||
m_canvas->repaint();
|
||||
evt.RequestMore();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
class App : public wxApp {
|
||||
MyFrame *m_frame;
|
||||
public:
|
||||
bool OnInit() override {
|
||||
|
||||
m_frame = new MyFrame( "PrusaSlicer OpenCSG Demo", wxDefaultPosition, wxSize(1024, 768) );
|
||||
m_frame->Show( true );
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
wxIMPLEMENT_APP(App);
|
|
@ -5,6 +5,7 @@
|
|||
#include <libslic3r/SLA/Hollowing.hpp>
|
||||
#include <libslic3r/SLA/Contour3D.hpp>
|
||||
#include <libslic3r/SLA/EigenMesh3D.hpp>
|
||||
#include <libslic3r/SLA/SupportTreeBuilder.hpp>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
|
@ -120,6 +121,17 @@ std::unique_ptr<TriangleMesh> generate_interior(const TriangleMesh & mesh,
|
|||
hc.closing_distance));
|
||||
}
|
||||
|
||||
Contour3D DrainHole::to_mesh() const
|
||||
{
|
||||
auto r = double(radius);
|
||||
auto h = double(height);
|
||||
sla::Contour3D hole = sla::cylinder(r, h);
|
||||
Eigen::Quaterniond q;
|
||||
q.setFromTwoVectors(Vec3d{0., 0., 1.}, normal.cast<double>());
|
||||
for(auto& p : hole.points) p = q * p + pos.cast<double>();
|
||||
return hole;
|
||||
}
|
||||
|
||||
bool DrainHole::operator==(const DrainHole &sp) const
|
||||
{
|
||||
return (pos == sp.pos) && (normal == sp.normal) &&
|
||||
|
@ -131,7 +143,7 @@ bool DrainHole::is_inside(const Vec3f& pt) const
|
|||
{
|
||||
Eigen::Hyperplane<float, 3> plane(normal, pos);
|
||||
float dist = plane.signedDistance(pt);
|
||||
if (dist < EPSILON || dist > height)
|
||||
if (dist < float(EPSILON) || dist > height)
|
||||
return false;
|
||||
|
||||
Eigen::ParametrizedLine<float, 3> axis(pos, normal);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <memory>
|
||||
#include <libslic3r/SLA/Common.hpp>
|
||||
#include <libslic3r/SLA/Contour3D.hpp>
|
||||
#include <libslic3r/SLA/JobController.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
@ -42,6 +43,8 @@ struct DrainHole
|
|||
bool get_intersections(const Vec3f& s, const Vec3f& dir,
|
||||
std::array<std::pair<float, Vec3d>, 2>& out) const;
|
||||
|
||||
Contour3D to_mesh() const;
|
||||
|
||||
template<class Archive> inline void serialize(Archive &ar)
|
||||
{
|
||||
ar(pos, normal, radius, height);
|
||||
|
|
Loading…
Reference in a new issue