diff --git a/src/libslic3r/Tesselate.cpp b/src/libslic3r/Tesselate.cpp new file mode 100644 index 000000000..fb7fd89d8 --- /dev/null +++ b/src/libslic3r/Tesselate.cpp @@ -0,0 +1,222 @@ +#include "Tesselate.hpp" + +#include "ExPolygon.hpp" + +#include + +namespace Slic3r { + +class GluTessWrapper { +public: + Pointf3s tesselate(const ExPolygon &expoly, double z_, bool flipped_) + { + z = z_; + flipped = flipped_; + triangles.clear(); + intersection_points.clear(); + std::vector coords; + { + size_t num_coords = expoly.contour.points.size(); + for (const Polygon &poly : expoly.holes) + num_coords += poly.points.size(); + coords.reserve(num_coords * 3); + } + GLUtesselator *tess = gluNewTess(); // create a tessellator + // register callback functions +#ifndef _GLUfuncptr + #ifdef _MSC_VER + typedef void (__stdcall *_GLUfuncptr)(void); + #else /* _MSC_VER */ + #ifdef GLAPIENTRYP + typedef void (GLAPIENTRYP _GLUfuncptr)(void); + #else /* GLAPIENTRYP */ + typedef void (*_GLUfuncptr)(void); + #endif + #endif /* _MSC_VER */ +#endif /* _GLUfuncptr */ + gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (_GLUfuncptr)tessBeginCB); + gluTessCallback(tess, GLU_TESS_END_DATA, (_GLUfuncptr)tessEndCB); + gluTessCallback(tess, GLU_TESS_ERROR_DATA, (_GLUfuncptr)tessErrorCB); + gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (_GLUfuncptr)tessVertexCB); + gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (_GLUfuncptr)tessCombineCB); + gluTessBeginPolygon(tess, (void*)this); + gluTessBeginContour(tess); + for (const Point &pt : expoly.contour.points) { + coords.emplace_back(unscale(pt[0])); + coords.emplace_back(unscale(pt[1])); + coords.emplace_back(0.); + gluTessVertex(tess, &coords[coords.size() - 3], &coords[coords.size() - 3]); + } + gluTessEndContour(tess); + for (const Polygon &poly : expoly.holes) { + gluTessBeginContour(tess); + for (const Point &pt : poly.points) { + coords.emplace_back(unscale(pt[0])); + coords.emplace_back(unscale(pt[1])); + coords.emplace_back(0.); + gluTessVertex(tess, &coords[coords.size() - 3], &coords[coords.size() - 3]); + } + gluTessEndContour(tess); + } + gluTessEndPolygon(tess); + gluDeleteTess(tess); + return std::move(triangles); + } + + Pointf3s tesselate(const ExPolygons &expolygons, double z_, bool flipped_) + { + z = z_; + flipped = flipped_; + triangles.clear(); + intersection_points.clear(); + std::vector coords; + { + size_t num_coords = 0; + for (const ExPolygon &expoly : expolygons) { + size_t num_coords_this = expoly.contour.points.size(); + for (const Polygon &poly : expoly.holes) + num_coords_this += poly.points.size(); + num_coords = std::max(num_coords, num_coords_this); + } + coords.assign(num_coords * 3, 0); + } + GLUtesselator *tess = gluNewTess(); // create a tessellator + // register callback functions +#ifndef _GLUfuncptr + #ifdef _MSC_VER + typedef void (__stdcall *_GLUfuncptr)(void); + #else /* _MSC_VER */ + #ifdef GLAPIENTRYP + typedef void (GLAPIENTRYP _GLUfuncptr)(void); + #else /* GLAPIENTRYP */ + typedef void (*_GLUfuncptr)(void); + #endif + #endif /* _MSC_VER */ +#endif /* _GLUfuncptr */ + gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (_GLUfuncptr)tessBeginCB); + gluTessCallback(tess, GLU_TESS_END_DATA, (_GLUfuncptr)tessEndCB); + gluTessCallback(tess, GLU_TESS_ERROR_DATA, (_GLUfuncptr)tessErrorCB); + gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (_GLUfuncptr)tessVertexCB); + gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (_GLUfuncptr)tessCombineCB); + for (const ExPolygon &expoly : expolygons) { + gluTessBeginPolygon(tess, (void*)this); + gluTessBeginContour(tess); + size_t idx = 0; + for (const Point &pt : expoly.contour.points) { + coords[idx ++] = unscale(pt[0]); + coords[idx ++] = unscale(pt[1]); + coords[idx ++] = 0.; + gluTessVertex(tess, &coords[idx - 3], &coords[idx - 3]); + } + gluTessEndContour(tess); + for (const Polygon &poly : expoly.holes) { + gluTessBeginContour(tess); + for (const Point &pt : poly.points) { + coords[idx ++] = unscale(pt[0]); + coords[idx ++] = unscale(pt[1]); + coords[idx ++] = 0.; + gluTessVertex(tess, &coords[idx - 3], &coords[idx - 3]); + } + gluTessEndContour(tess); + } + gluTessEndPolygon(tess); + } + gluDeleteTess(tess); + return std::move(triangles); + } + +private: + static void tessBeginCB(GLenum which, void *polygonData) { reinterpret_cast(polygonData)->tessBegin(which); } + static void tessEndCB(void *polygonData) { reinterpret_cast(polygonData)->tessEnd(); } + static void tessVertexCB(const GLvoid *data, void *polygonData) { reinterpret_cast(polygonData)->tessVertex(data); } + static void tessCombineCB(const GLdouble newVertex[3], const GLdouble *neighborVertex[4], const GLfloat neighborWeight[4], GLdouble **outData, void *polygonData) + { reinterpret_cast(polygonData)->tessCombine(newVertex, neighborVertex, neighborWeight, outData); } + static void tessErrorCB(GLenum errorCode, void *polygonData) { reinterpret_cast(polygonData)->tessError(errorCode); } + + void tessBegin(GLenum which) + { + assert(which == GL_TRIANGLES || which == GL_TRIANGLE_FAN || which == GL_TRIANGLE_STRIP); + if (!(which == GL_TRIANGLES || which == GL_TRIANGLE_FAN || which == GL_TRIANGLE_STRIP)) + printf("Co je to za haluz!?\n"); + primitive_type = which; + num_points = 0; + } + + void tessEnd() + { + num_points = 0; + } + + void tessVertex(const GLvoid *data) + { + if (data == nullptr) + return; + const GLdouble *ptr = (const GLdouble*)data; + ++ num_points; + if (num_points == 1) { + memcpy(pt0, ptr, sizeof(GLdouble) * 3); + } else if (num_points == 2) { + memcpy(pt1, ptr, sizeof(GLdouble) * 3); + } else { + bool flip = flipped; + if (primitive_type == GL_TRIANGLE_STRIP && num_points == 4) { + flip = !flip; + num_points = 2; + } + triangles.emplace_back(pt0[0], pt0[1], z); + if (flip) { + triangles.emplace_back(ptr[0], ptr[1], z); + triangles.emplace_back(pt1[0], pt1[1], z); + } else { + triangles.emplace_back(pt1[0], pt1[1], z); + triangles.emplace_back(ptr[0], ptr[1], z); + } + if (primitive_type == GL_TRIANGLE_STRIP) { + memcpy(pt0, pt1, sizeof(GLdouble) * 3); + memcpy(pt1, ptr, sizeof(GLdouble) * 3); + } else if (primitive_type == GL_TRIANGLE_FAN) { + memcpy(pt1, ptr, sizeof(GLdouble) * 3); + } else { + assert(primitive_type == GL_TRIANGLES); + assert(num_points == 3); + num_points = 0; + } + } + } + + void tessCombine(const GLdouble newVertex[3], const GLdouble *neighborVertex[4], const GLfloat neighborWeight[4], GLdouble **outData) + { + intersection_points.emplace_back(newVertex[0], newVertex[1], newVertex[2]); + *outData = intersection_points.back().data(); + } + + static void tessError(GLenum errorCode) + { +// const GLubyte *errorStr; +// errorStr = gluErrorString(errorCode); +// printf("Error: %s\n", (const char*)errorStr); + } + + GLenum primitive_type; + GLdouble pt0[3]; + GLdouble pt1[3]; + int num_points; + Pointf3s triangles; + std::deque intersection_points; + double z; + bool flipped; +}; + +Pointf3s triangulate_expolygons_3df(const ExPolygon &poly, coordf_t z, bool flip) +{ + GluTessWrapper tess; + return tess.tesselate(poly, z, flip); +} + +Pointf3s triangulate_expolygons_3df(const ExPolygons &polys, coordf_t z, bool flip) +{ + GluTessWrapper tess; + return tess.tesselate(polys, z, flip); +} + +} // namespace Slic3r diff --git a/src/libslic3r/Tesselate.hpp b/src/libslic3r/Tesselate.hpp new file mode 100644 index 000000000..a2c6d6b06 --- /dev/null +++ b/src/libslic3r/Tesselate.hpp @@ -0,0 +1,16 @@ +#ifndef slic3r_Tesselate_hpp_ +#define slic3r_Tesselate_hpp_ + +#include + +namespace Slic3r { + +class ExPolygon; +typedef std::vector ExPolygons; + +extern Pointf3s triangulate_expolygons_3df(const ExPolygon &poly, coordf_t z = 0, bool flip = false); +extern Pointf3s triangulate_expolygons_3df(const ExPolygons &polys, coordf_t z = 0, bool flip = false); + +} // namespace Slic3r + +#endif /* slic3r_Tesselate_hpp_ */