diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 422b65408..dd5a1efe4 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -16,6 +16,424 @@ namespace Slic3r { namespace GUI { +void GLModel::Geometry::add_vertex(const Vec2f &position) +{ + assert(format.vertex_layout == EVertexLayout::P2); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); +} + +void GLModel::Geometry::add_vertex(const Vec2f &position, const Vec2f &tex_coord) +{ + assert(format.vertex_layout == EVertexLayout::P2T2); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(tex_coord.x()); + vertices.emplace_back(tex_coord.y()); +} + +void GLModel::Geometry::add_vertex(const Vec3f &position) +{ + assert(format.vertex_layout == EVertexLayout::P3); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); +} + +void GLModel::Geometry::add_vertex(const Vec3f &position, const Vec2f &tex_coord) +{ + assert(format.vertex_layout == EVertexLayout::P3T2); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); + vertices.emplace_back(tex_coord.x()); + vertices.emplace_back(tex_coord.y()); +} + +void GLModel::Geometry::add_vertex(const Vec3f &position, const Vec3f &normal) +{ + assert(format.vertex_layout == EVertexLayout::P3N3); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); + vertices.emplace_back(normal.x()); + vertices.emplace_back(normal.y()); + vertices.emplace_back(normal.z()); +} + +void GLModel::Geometry::add_vertex(const Vec3f &position, const Vec3f &normal, const Vec2f &tex_coord) +{ + assert(format.vertex_layout == EVertexLayout::P3N3T2); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); + vertices.emplace_back(normal.x()); + vertices.emplace_back(normal.y()); + vertices.emplace_back(normal.z()); + vertices.emplace_back(tex_coord.x()); + vertices.emplace_back(tex_coord.y()); +} + +void GLModel::Geometry::add_vertex(const Vec4f &position) +{ + assert(format.vertex_layout == EVertexLayout::P4); + vertices.emplace_back(position.x()); + vertices.emplace_back(position.y()); + vertices.emplace_back(position.z()); + vertices.emplace_back(position.w()); +} + +void GLModel::Geometry::add_index(unsigned int id) { indices.emplace_back(id); } + +void GLModel::Geometry::add_line(unsigned int id1, unsigned int id2) +{ + indices.emplace_back(id1); + indices.emplace_back(id2); +} + +void GLModel::Geometry::add_triangle(unsigned int id1, unsigned int id2, unsigned int id3) +{ + indices.emplace_back(id1); + indices.emplace_back(id2); + indices.emplace_back(id3); +} + +Vec2f GLModel::Geometry::extract_position_2(size_t id) const +{ + const size_t p_stride = position_stride_floats(format); + if (p_stride != 2) { + assert(false); + return {FLT_MAX, FLT_MAX}; + } + + if (vertices_count() <= id) { + assert(false); + return {FLT_MAX, FLT_MAX}; + } + + const float *start = &vertices[id * vertex_stride_floats(format) + position_offset_floats(format)]; + return {*(start + 0), *(start + 1)}; +} + +Vec3f GLModel::Geometry::extract_position_3(size_t id) const +{ + const size_t p_stride = position_stride_floats(format); + if (p_stride != 3) { + assert(false); + return {FLT_MAX, FLT_MAX, FLT_MAX}; + } + + if (vertices_count() <= id) { + assert(false); + return {FLT_MAX, FLT_MAX, FLT_MAX}; + } + + const float *start = &vertices[id * vertex_stride_floats(format) + position_offset_floats(format)]; + return {*(start + 0), *(start + 1), *(start + 2)}; +} + +Vec3f GLModel::Geometry::extract_normal_3(size_t id) const +{ + const size_t n_stride = normal_stride_floats(format); + if (n_stride != 3) { + assert(false); + return {FLT_MAX, FLT_MAX, FLT_MAX}; + } + + if (vertices_count() <= id) { + assert(false); + return {FLT_MAX, FLT_MAX, FLT_MAX}; + } + + const float *start = &vertices[id * vertex_stride_floats(format) + normal_offset_floats(format)]; + return {*(start + 0), *(start + 1), *(start + 2)}; +} + +Vec2f GLModel::Geometry::extract_tex_coord_2(size_t id) const +{ + const size_t t_stride = tex_coord_stride_floats(format); + if (t_stride != 2) { + assert(false); + return {FLT_MAX, FLT_MAX}; + } + + if (vertices_count() <= id) { + assert(false); + return {FLT_MAX, FLT_MAX}; + } + + const float *start = &vertices[id * vertex_stride_floats(format) + tex_coord_offset_floats(format)]; + return {*(start + 0), *(start + 1)}; +} + +void GLModel::Geometry::set_vertex(size_t id, const Vec3f &position, const Vec3f &normal) +{ + assert(format.vertex_layout == EVertexLayout::P3N3); + assert(id < vertices_count()); + if (id < vertices_count()) { + float *start = &vertices[id * vertex_stride_floats(format)]; + *(start + 0) = position.x(); + *(start + 1) = position.y(); + *(start + 2) = position.z(); + *(start + 3) = normal.x(); + *(start + 4) = normal.y(); + *(start + 5) = normal.z(); + } +} + +void GLModel::Geometry::set_index(size_t id, unsigned int index) +{ + assert(id < indices_count()); + if (id < indices_count()) indices[id] = index; +} + +unsigned int GLModel::Geometry::extract_index(size_t id) const +{ + if (indices_count() <= id) { + assert(false); + return -1; + } + + return indices[id]; +} + +void GLModel::Geometry::remove_vertex(size_t id) +{ + assert(id < vertices_count()); + if (id < vertices_count()) { + const size_t stride = vertex_stride_floats(format); + std::vector::const_iterator it = vertices.begin() + id * stride; + vertices.erase(it, it + stride); + } +} + +indexed_triangle_set GLModel::Geometry::get_as_indexed_triangle_set() const +{ + indexed_triangle_set its; + its.vertices.reserve(vertices_count()); + for (size_t i = 0; i < vertices_count(); ++i) { its.vertices.emplace_back(extract_position_3(i)); } + its.indices.reserve(indices_count() / 3); + for (size_t i = 0; i < indices_count() / 3; ++i) { + const size_t tri_id = i * 3; + its.indices.emplace_back(extract_index(tri_id), extract_index(tri_id + 1), extract_index(tri_id + 2)); + } + return its; +} + +size_t GLModel::Geometry::vertex_stride_floats(const Format &format) +{ + switch (format.vertex_layout) { + case EVertexLayout::P2: { + return 2; + } + case EVertexLayout::P2T2: { + return 4; + } + case EVertexLayout::P3: { + return 3; + } + case EVertexLayout::P3T2: { + return 5; + } + case EVertexLayout::P3N3: { + return 6; + } + case EVertexLayout::P3N3T2: { + return 8; + } + case EVertexLayout::P4: { + return 4; + } + default: { + assert(false); + return 0; + } + }; +} + +size_t GLModel::Geometry::position_stride_floats(const Format &format) +{ + switch (format.vertex_layout) { + case EVertexLayout::P2: + case EVertexLayout::P2T2: { + return 2; + } + case EVertexLayout::P3: + case EVertexLayout::P3T2: + case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: { + return 3; + } + case EVertexLayout::P4: { + return 4; + } + default: { + assert(false); + return 0; + } + }; +} + +size_t GLModel::Geometry::position_offset_floats(const Format &format) +{ + switch (format.vertex_layout) { + case EVertexLayout::P2: + case EVertexLayout::P2T2: + case EVertexLayout::P3: + case EVertexLayout::P3T2: + case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: + case EVertexLayout::P4: { + return 0; + } + default: { + assert(false); + return 0; + } + }; +} + +size_t GLModel::Geometry::normal_stride_floats(const Format &format) +{ + switch (format.vertex_layout) { + case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: { + return 3; + } + default: { + assert(false); + return 0; + } + }; +} + +size_t GLModel::Geometry::normal_offset_floats(const Format &format) +{ + switch (format.vertex_layout) { + case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: { + return 3; + } + default: { + assert(false); + return 0; + } + }; +} + +size_t GLModel::Geometry::tex_coord_stride_floats(const Format &format) +{ + switch (format.vertex_layout) { + case EVertexLayout::P2T2: + case EVertexLayout::P3T2: + case EVertexLayout::P3N3T2: { + return 2; + } + default: { + assert(false); + return 0; + } + }; +} + +size_t GLModel::Geometry::tex_coord_offset_floats(const Format &format) +{ + switch (format.vertex_layout) { + case EVertexLayout::P2T2: { + return 2; + } + case EVertexLayout::P3T2: { + return 3; + } + case EVertexLayout::P3N3T2: { + return 6; + } + default: { + assert(false); + return 0; + } + }; +} + +size_t GLModel::Geometry::index_stride_bytes(const Geometry &data) +{ + switch (data.index_type) { + case EIndexType::UINT: { + return sizeof(unsigned int); + } + case EIndexType::USHORT: { + return sizeof(unsigned short); + } + case EIndexType::UBYTE: { + return sizeof(unsigned char); + } + default: { + assert(false); + return 0; + } + }; +} + +bool GLModel::Geometry::has_position(const Format &format) +{ + switch (format.vertex_layout) { + case EVertexLayout::P2: + case EVertexLayout::P2T2: + case EVertexLayout::P3: + case EVertexLayout::P3T2: + case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: + case EVertexLayout::P4: { + return true; + } + default: { + assert(false); + return false; + } + }; +} + +bool GLModel::Geometry::has_normal(const Format &format) +{ + switch (format.vertex_layout) { + case EVertexLayout::P2: + case EVertexLayout::P2T2: + case EVertexLayout::P3: + case EVertexLayout::P3T2: + case EVertexLayout::P4: { + return false; + } + case EVertexLayout::P3N3: + case EVertexLayout::P3N3T2: { + return true; + } + default: { + assert(false); + return false; + } + }; +} + +bool GLModel::Geometry::has_tex_coord(const Format &format) +{ + switch (format.vertex_layout) { + case EVertexLayout::P2T2: + case EVertexLayout::P3T2: + case EVertexLayout::P3N3T2: { + return true; + } + case EVertexLayout::P2: + case EVertexLayout::P3: + case EVertexLayout::P3N3: + case EVertexLayout::P4: { + return false; + } + default: { + assert(false); + return false; + } + }; +} size_t GLModel::InitializationData::vertices_count() const { @@ -35,6 +453,46 @@ size_t GLModel::InitializationData::indices_count() const return ret; } +GLModel::~GLModel() +{ + reset(); + if (mesh) { delete mesh; } +} + +void GLModel::init_from(Geometry &&data, bool generate_mesh) +{ + if (is_initialized()) { + // call reset() if you want to reuse this model + assert(false); + return; + } + + if (data.vertices.empty() || data.indices.empty()) { + assert(false); + return; + } + m_render_data.clear(); + m_render_data.push_back(RenderData()); + m_render_data.back().indices_count = data.indices.size(); + m_render_data.back().type = data.format.type; + m_render_data.back().color = data.color.get_data(); + if (generate_mesh) { + if (!mesh) { mesh = new TriangleMesh(); } + mesh->its = std::move(data.get_as_indexed_triangle_set()); + } + m_render_data.back().geometry = std::move(data); + // update bounding box + for (size_t i = 0; i < data.vertices_count(); ++i) { + const size_t position_stride = Geometry::position_stride_floats(data.format); + if (position_stride == 3) + m_bounding_box.merge(m_render_data.back().geometry.extract_position_3(i).cast()); + else if (position_stride == 2) { + const Vec2f position = m_render_data.back().geometry.extract_position_2(i); + m_bounding_box.merge(Vec3f(position.x(), position.y(), 0.0f).cast()); + } + } +} + void GLModel::init_from(const InitializationData& data) { if (!m_render_data.empty()) // call reset() if you want to reuse this model @@ -193,8 +651,17 @@ void GLModel::render() const GLShaderProgram* shader = wxGetApp().get_current_shader(); for (const RenderData& data : m_render_data) { - if (data.vbo_id == 0 || data.ibo_id == 0) - continue; + // sends data to gpu if not done yet + if (data.vbo_id == 0 || data.ibo_id == 0) { + auto origin_data = const_cast(&data); + if (data.geometry.vertices_count() > 0 && data.geometry.indices_count() > 0 + && !send_to_gpu(*origin_data, data.geometry.vertices, data.geometry.indices)) + continue; + } + bool has_normal = true; + if (data.geometry.vertices_count() > 0) { + has_normal = Geometry::has_normal(data.geometry.format); + } GLenum mode; switch (data.type) @@ -207,11 +674,16 @@ void GLModel::render() const } glsafe(::glBindBuffer(GL_ARRAY_BUFFER, data.vbo_id)); - glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)0)); - glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); + if (has_normal) { + glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void *) 0)); + glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), (const void *) (3 * sizeof(float)))); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + } else { + glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), (const void *) 0)); + glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + } if (shader != nullptr) shader->set_uniform("uniform_color", data.color); @@ -306,10 +778,17 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } -void GLModel::send_to_gpu(RenderData& data, const std::vector& vertices, const std::vector& indices) +bool GLModel::send_to_gpu(RenderData& data, const std::vector& vertices, const std::vector& indices) const { - assert(data.vbo_id == 0); - assert(data.ibo_id == 0); + if (data.vbo_id > 0 || data.ibo_id > 0) { + assert(false); + return false; + } + + if (vertices.empty() || indices.empty()) { + assert(false); + return false; + } // vertex data -> send to gpu glsafe(::glGenBuffers(1, &data.vbo_id)); @@ -322,6 +801,7 @@ void GLModel::send_to_gpu(RenderData& data, const std::vector& vertices, glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ibo_id)); glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + return true; } GLModel::InitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height) @@ -744,5 +1224,181 @@ GLModel::InitializationData diamond(int resolution) return data; } +GLModel::Geometry smooth_sphere(unsigned int resolution, float radius) +{ + resolution = std::max(4, resolution); + + const unsigned int sectorCount = resolution; + const unsigned int stackCount = resolution; + + const float sectorStep = float(2.0 * M_PI / sectorCount); + const float stackStep = float(M_PI / stackCount); + + GLModel::Geometry data; + data.format = {GLModel::PrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3}; + data.reserve_vertices((stackCount - 1) * sectorCount + 2); + data.reserve_indices((2 * (stackCount - 1) * sectorCount) * 3); + + // vertices + for (unsigned int i = 0; i <= stackCount; ++i) { + // from pi/2 to -pi/2 + const double stackAngle = 0.5 * M_PI - stackStep * i; + const double xy = double(radius) * ::cos(stackAngle); + const double z = double(radius) * ::sin(stackAngle); + if (i == 0 || i == stackCount) { + const Vec3f v(float(xy), 0.0f, float(z)); + data.add_vertex(v, (Vec3f) v.normalized()); + } else { + for (unsigned int j = 0; j < sectorCount; ++j) { + // from 0 to 2pi + const double sectorAngle = sectorStep * j; + const Vec3f v(float(xy * std::cos(sectorAngle)), float(xy * std::sin(sectorAngle)), float(z)); + data.add_vertex(v, (Vec3f) v.normalized()); + } + } + } + + // triangles + for (unsigned int i = 0; i < stackCount; ++i) { + // Beginning of current stack. + unsigned int k1 = (i == 0) ? 0 : (1 + (i - 1) * sectorCount); + const unsigned int k1_first = k1; + // Beginning of next stack. + unsigned int k2 = (i == 0) ? 1 : (k1 + sectorCount); + const unsigned int k2_first = k2; + for (unsigned int j = 0; j < sectorCount; ++j) { + // 2 triangles per sector excluding first and last stacks + unsigned int k1_next = k1; + unsigned int k2_next = k2; + if (i != 0) { + k1_next = (j + 1 == sectorCount) ? k1_first : (k1 + 1); + data.add_triangle(k1, k2, k1_next); + } + if (i + 1 != stackCount) { + k2_next = (j + 1 == sectorCount) ? k2_first : (k2 + 1); + data.add_triangle(k1_next, k2, k2_next); + } + k1 = k1_next; + k2 = k2_next; + } + } + + return data; +} + +GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float height) +{ + resolution = std::max(4, resolution); + + const unsigned int sectorCount = resolution; + const float sectorStep = 2.0f * float(M_PI) / float(sectorCount); + + GLModel::Geometry data; + data.format = {GLModel::PrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3}; + data.reserve_vertices(sectorCount * 4 + 2); + data.reserve_indices(sectorCount * 4 * 3); + + auto generate_vertices_on_circle = [sectorCount, sectorStep](float radius) { + std::vector ret; + ret.reserve(sectorCount); + for (unsigned int i = 0; i < sectorCount; ++i) { + // from 0 to 2pi + const float sectorAngle = sectorStep * i; + ret.emplace_back(radius * std::cos(sectorAngle), radius * std::sin(sectorAngle), 0.0f); + } + return ret; + }; + + const std::vector base_vertices = generate_vertices_on_circle(radius); + const Vec3f h = height * Vec3f::UnitZ(); + + // stem vertices + for (unsigned int i = 0; i < sectorCount; ++i) { + const Vec3f &v = base_vertices[i]; + const Vec3f n = v.normalized(); + data.add_vertex(v, n); + data.add_vertex(v + h, n); + } + + // stem triangles + for (unsigned int i = 0; i < sectorCount; ++i) { + unsigned int v1 = i * 2; + unsigned int v2 = (i < sectorCount - 1) ? v1 + 2 : 0; + unsigned int v3 = v2 + 1; + unsigned int v4 = v1 + 1; + data.add_triangle(v1, v2, v3); + data.add_triangle(v1, v3, v4); + } + + // bottom cap vertices + Vec3f cap_center = Vec3f::Zero(); + unsigned int cap_center_id = data.vertices_count(); + Vec3f normal = -Vec3f::UnitZ(); + + data.add_vertex(cap_center, normal); + for (unsigned int i = 0; i < sectorCount; ++i) { data.add_vertex(base_vertices[i], normal); } + + // bottom cap triangles + for (unsigned int i = 0; i < sectorCount; ++i) { data.add_triangle(cap_center_id, (i < sectorCount - 1) ? cap_center_id + i + 2 : cap_center_id + 1, cap_center_id + i + 1); } + + // top cap vertices + cap_center += h; + cap_center_id = data.vertices_count(); + normal = -normal; + + data.add_vertex(cap_center, normal); + for (unsigned int i = 0; i < sectorCount; ++i) { data.add_vertex(base_vertices[i] + h, normal); } + + // top cap triangles + for (unsigned int i = 0; i < sectorCount; ++i) { data.add_triangle(cap_center_id, cap_center_id + i + 1, (i < sectorCount - 1) ? cap_center_id + i + 2 : cap_center_id + 1); } + + return data; +} + +GLModel::Geometry smooth_torus(unsigned int primary_resolution, unsigned int secondary_resolution, float radius, float thickness) +{ + const unsigned int torus_sector_count = std::max(4, primary_resolution); + const float torus_sector_step = 2.0f * float(M_PI) / float(torus_sector_count); + const unsigned int section_sector_count = std::max(4, secondary_resolution); + const float section_sector_step = 2.0f * float(M_PI) / float(section_sector_count); + + GLModel::Geometry data; + data.format = {GLModel::PrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3}; + data.reserve_vertices(torus_sector_count * section_sector_count); + data.reserve_indices(torus_sector_count * section_sector_count * 2 * 3); + + // vertices + for (unsigned int i = 0; i < torus_sector_count; ++i) { + const float section_angle = torus_sector_step * i; + const float csa = std::cos(section_angle); + const float ssa = std::sin(section_angle); + const Vec3f section_center(radius * csa, radius * ssa, 0.0f); + for (unsigned int j = 0; j < section_sector_count; ++j) { + const float circle_angle = section_sector_step * j; + const float thickness_xy = thickness * std::cos(circle_angle); + const float thickness_z = thickness * std::sin(circle_angle); + const Vec3f v(thickness_xy * csa, thickness_xy * ssa, thickness_z); + data.add_vertex(section_center + v, (Vec3f) v.normalized()); + } + } + + // triangles + for (unsigned int i = 0; i < torus_sector_count; ++i) { + const unsigned int ii = i * section_sector_count; + const unsigned int ii_next = ((i + 1) % torus_sector_count) * section_sector_count; + for (unsigned int j = 0; j < section_sector_count; ++j) { + const unsigned int j_next = (j + 1) % section_sector_count; + const unsigned int i0 = ii + j; + const unsigned int i1 = ii_next + j; + const unsigned int i2 = ii_next + j_next; + const unsigned int i3 = ii + j_next; + data.add_triangle(i0, i1, i2); + data.add_triangle(i0, i2, i3); + } + } + + return data; +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 5112b1558..8988da3a7 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -28,13 +28,110 @@ namespace GUI { LineLoop }; + struct Geometry + { + // enum class EPrimitiveType : unsigned char { Points, Triangles, TriangleStrip, TriangleFan, Lines, LineStrip, LineLoop }; + enum class EVertexLayout : unsigned char { + P2, // position 2 floats + P2T2, // position 2 floats + texture coords 2 floats + P3, // position 3 floats + P3T2, // position 3 floats + texture coords 2 floats + P3N3, // position 3 floats + normal 3 floats + P3N3T2, // position 3 floats + normal 3 floats + texture coords 2 floats + P4, // position 4 floats + }; + + enum class EIndexType : unsigned char { + UINT, // unsigned int + USHORT, // unsigned short + UBYTE // unsigned byte + }; + + struct Format + { + PrimitiveType type{PrimitiveType::Triangles}; + EVertexLayout vertex_layout{EVertexLayout::P3N3}; + }; + + Format format; + std::vector vertices; + std::vector indices; + EIndexType index_type{EIndexType::UINT}; + ColorRGBA color{ColorRGBA::BLACK()}; + + void reserve_vertices(size_t vertices_count) { vertices.reserve(vertices_count * vertex_stride_floats(format)); } + void reserve_indices(size_t indices_count) { indices.reserve(indices_count); } + + void add_vertex(const Vec2f &position); // EVertexLayout::P2 + void add_vertex(const Vec2f &position, const Vec2f &tex_coord); // EVertexLayout::P2T2 + void add_vertex(const Vec3f &position); // EVertexLayout::P3 + void add_vertex(const Vec3f &position, const Vec2f &tex_coord); // EVertexLayout::P3T2 + void add_vertex(const Vec3f &position, const Vec3f &normal); // EVertexLayout::P3N3 + void add_vertex(const Vec3f &position, const Vec3f &normal, const Vec2f &tex_coord); // EVertexLayout::P3N3T2 + void add_vertex(const Vec4f &position); // EVertexLayout::P4 + + void set_vertex(size_t id, const Vec3f &position, const Vec3f &normal); // EVertexLayout::P3N3 + + void set_index(size_t id, unsigned int index); + + void add_index(unsigned int id); + void add_line(unsigned int id1, unsigned int id2); + void add_triangle(unsigned int id1, unsigned int id2, unsigned int id3); + + Vec2f extract_position_2(size_t id) const; + Vec3f extract_position_3(size_t id) const; + Vec3f extract_normal_3(size_t id) const; + Vec2f extract_tex_coord_2(size_t id) const; + + unsigned int extract_index(size_t id) const; + + void remove_vertex(size_t id); + + bool is_empty() const { return vertices_count() == 0 || indices_count() == 0; } + + size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); } + size_t indices_count() const { return indices.size(); } + + size_t vertices_size_floats() const { return vertices.size(); } + size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } + size_t indices_size_bytes() const { return indices.size() * index_stride_bytes(*this); } + + indexed_triangle_set get_as_indexed_triangle_set() const; + + static size_t vertex_stride_floats(const Format &format); + static size_t vertex_stride_bytes(const Format &format) { return vertex_stride_floats(format) * sizeof(float); } + + static size_t position_stride_floats(const Format &format); + static size_t position_stride_bytes(const Format &format) { return position_stride_floats(format) * sizeof(float); } + static size_t position_offset_floats(const Format &format); + static size_t position_offset_bytes(const Format &format) { return position_offset_floats(format) * sizeof(float); } + + static size_t normal_stride_floats(const Format &format); + static size_t normal_stride_bytes(const Format &format) { return normal_stride_floats(format) * sizeof(float); } + static size_t normal_offset_floats(const Format &format); + static size_t normal_offset_bytes(const Format &format) { return normal_offset_floats(format) * sizeof(float); } + + static size_t tex_coord_stride_floats(const Format &format); + static size_t tex_coord_stride_bytes(const Format &format) { return tex_coord_stride_floats(format) * sizeof(float); } + static size_t tex_coord_offset_floats(const Format &format); + static size_t tex_coord_offset_bytes(const Format &format) { return tex_coord_offset_floats(format) * sizeof(float); } + + static size_t index_stride_bytes(const Geometry &data); + + static bool has_position(const Format &format); + static bool has_normal(const Format &format); + static bool has_tex_coord(const Format &format); + }; + struct RenderData { - PrimitiveType type; - unsigned int vbo_id{ 0 }; - unsigned int ibo_id{ 0 }; - size_t indices_count{ 0 }; - std::array color{ 1.0f, 1.0f, 1.0f, 1.0f }; + Geometry geometry; + + PrimitiveType type; + unsigned int vbo_id{0}; + unsigned int ibo_id{0}; + size_t indices_count{0}; + std::array color{1.0f, 1.0f, 1.0f, 1.0f}; }; struct InitializationData @@ -66,8 +163,11 @@ namespace GUI { public: GLModel() = default; - virtual ~GLModel() { reset(); } + virtual ~GLModel(); + TriangleMesh *mesh{nullptr}; + + void init_from(Geometry &&data, bool generate_mesh = false); void init_from(const InitializationData& data); void init_from(const indexed_triangle_set& its, const BoundingBoxf3& bbox); void init_from(const indexed_triangle_set& its); @@ -87,7 +187,7 @@ namespace GUI { const std::string& get_filename() const { return m_filename; } private: - void send_to_gpu(RenderData& data, const std::vector& vertices, const std::vector& indices); + bool send_to_gpu(RenderData &data, const std::vector &vertices, const std::vector &indices) const; }; // create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution @@ -113,7 +213,19 @@ namespace GUI { // the diamond is contained into a box with size [1, 1, 1] GLModel::InitializationData diamond(int resolution); -} // namespace GUI + // create a sphere with smooth normals + // the origin of the sphere is in its center + GLModel::Geometry smooth_sphere(unsigned int resolution, float radius); + // create a cylinder with smooth normals + // the axis of the cylinder is the Z axis + // the origin of the cylinder is the center of its bottom cap face + GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float height); + // create a torus with smooth normals + // the axis of the torus is the Z axis + // the origin of the torus is in its center + GLModel::Geometry smooth_torus(unsigned int primary_resolution, unsigned int secondary_resolution, float radius, float thickness); + + } // namespace GUI } // namespace Slic3r #endif // slic3r_GLModel_hpp_ diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 549090e53..9caec76c0 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -5983,6 +5983,12 @@ Sidebar& GUI_App::sidebar() return plater_->sidebar(); } +GizmoObjectManipulation *GUI_App::obj_manipul() +{ + // If this method is called before plater_ has been initialized, return nullptr (to avoid a crash) + return (plater_ != nullptr) ? &plater_->get_view3D_canvas3D()->get_gizmos_manager().get_object_manipulation() : nullptr; +} + ObjectSettings* GUI_App::obj_settings() { return sidebar().obj_settings(); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 03002924c..f517b5c43 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -130,6 +130,7 @@ enum CameraMenuIDs { class Tab; class ConfigWizard; +class GizmoObjectManipulation; static wxString dots("...", wxConvUTF8); @@ -527,6 +528,7 @@ public: #endif /* __APPLE */ Sidebar& sidebar(); + GizmoObjectManipulation *obj_manipul(); ObjectSettings* obj_settings(); ObjectList* obj_list(); ObjectLayers* obj_layers(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp index 5c2cb5010..a6401ff3a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp @@ -5,7 +5,7 @@ #include "GLGizmoRotate.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/CutUtils.hpp" -#include "slic3r/GUI/MeshUtils.hpp" + namespace Slic3r { enum class CutConnectorType : int; class ModelVolume; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 442eedb44..8eaff1263 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -6,6 +6,7 @@ #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GLModel.hpp" +#include "slic3r/GUI/MeshUtils.hpp" #include @@ -114,6 +115,21 @@ protected: std::string m_icon_filename; unsigned int m_sprite_id; int m_hover_id; + enum GripperType { + UNDEFINE, + POINT, + EDGE, + CIRCLE, + CIRCLE_1, + CIRCLE_2, + PLANE, + PLANE_1, + PLANE_2, + SPHERE_1, + SPHERE_2, + }; + std::map> m_gripper_id_raycast_map; + bool m_dragging; std::array m_base_color; std::array m_drag_color;