mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-11 00:37:51 -06:00
Printbed textures generated from svg files
This commit is contained in:
parent
0b0457186b
commit
11fc849b1a
16 changed files with 5124 additions and 33 deletions
|
@ -1,3 +1,4 @@
|
|||
#include "libslic3r/libslic3r.h"
|
||||
#include "GLTexture.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
@ -5,10 +6,20 @@
|
|||
#include <wx/image.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#include "nanosvg/nanosvg.h"
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include "nanosvg/nanosvgrast.h"
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
@ -27,7 +38,34 @@ GLTexture::~GLTexture()
|
|||
reset();
|
||||
}
|
||||
|
||||
bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmaps)
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps)
|
||||
{
|
||||
reset();
|
||||
|
||||
if (!boost::filesystem::exists(filename))
|
||||
return false;
|
||||
|
||||
if (boost::algorithm::iends_with(filename, ".png"))
|
||||
return load_from_png(filename, use_mipmaps);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px)
|
||||
{
|
||||
reset();
|
||||
|
||||
if (!boost::filesystem::exists(filename))
|
||||
return false;
|
||||
|
||||
if (boost::algorithm::iends_with(filename, ".svg"))
|
||||
return load_from_svg(filename, use_mipmaps, max_size_px);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps)
|
||||
{
|
||||
reset();
|
||||
|
||||
|
@ -78,10 +116,10 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap
|
|||
::glGenTextures(1, &m_id);
|
||||
::glBindTexture(GL_TEXTURE_2D, m_id);
|
||||
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
|
||||
if (generate_mipmaps)
|
||||
if (use_mipmaps)
|
||||
{
|
||||
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
|
||||
unsigned int levels_count = _generate_mipmaps(image);
|
||||
unsigned int levels_count = generate_mipmaps(image);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1 + levels_count);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
|
@ -97,6 +135,7 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap
|
|||
m_source = filename;
|
||||
return true;
|
||||
}
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
void GLTexture::reset()
|
||||
{
|
||||
|
@ -109,26 +148,6 @@ void GLTexture::reset()
|
|||
m_source = "";
|
||||
}
|
||||
|
||||
unsigned int GLTexture::get_id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
int GLTexture::get_width() const
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
int GLTexture::get_height() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
const std::string& GLTexture::get_source() const
|
||||
{
|
||||
return m_source;
|
||||
}
|
||||
|
||||
void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top)
|
||||
{
|
||||
render_sub_texture(tex_id, left, right, bottom, top, FullTextureUVs);
|
||||
|
@ -157,7 +176,7 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right,
|
|||
::glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
unsigned int GLTexture::_generate_mipmaps(wxImage& image)
|
||||
unsigned int GLTexture::generate_mipmaps(wxImage& image)
|
||||
{
|
||||
int w = image.GetWidth();
|
||||
int h = image.GetHeight();
|
||||
|
@ -195,5 +214,152 @@ unsigned int GLTexture::_generate_mipmaps(wxImage& image)
|
|||
return (unsigned int)level;
|
||||
}
|
||||
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps)
|
||||
{
|
||||
// Load a PNG with an alpha channel.
|
||||
wxImage image;
|
||||
if (!image.LoadFile(wxString::FromUTF8(filename.c_str()), wxBITMAP_TYPE_PNG))
|
||||
{
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_width = image.GetWidth();
|
||||
m_height = image.GetHeight();
|
||||
int n_pixels = m_width * m_height;
|
||||
|
||||
if (n_pixels <= 0)
|
||||
{
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get RGB & alpha raw data from wxImage, pack them into an array.
|
||||
unsigned char* img_rgb = image.GetData();
|
||||
if (img_rgb == nullptr)
|
||||
{
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char* img_alpha = image.GetAlpha();
|
||||
|
||||
std::vector<unsigned char> data(n_pixels * 4, 0);
|
||||
for (int i = 0; i < n_pixels; ++i)
|
||||
{
|
||||
int data_id = i * 4;
|
||||
int img_id = i * 3;
|
||||
data[data_id + 0] = img_rgb[img_id + 0];
|
||||
data[data_id + 1] = img_rgb[img_id + 1];
|
||||
data[data_id + 2] = img_rgb[img_id + 2];
|
||||
data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255;
|
||||
}
|
||||
|
||||
// sends data to gpu
|
||||
::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
::glGenTextures(1, &m_id);
|
||||
::glBindTexture(GL_TEXTURE_2D, m_id);
|
||||
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
|
||||
if (use_mipmaps)
|
||||
{
|
||||
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
|
||||
unsigned int levels_count = generate_mipmaps(image);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1 + levels_count);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
}
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
::glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
m_source = filename;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px)
|
||||
{
|
||||
NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f);
|
||||
if (image == nullptr)
|
||||
{
|
||||
// printf("Could not open SVG image.\n");
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
float scale = (float)max_size_px / std::max(image->width, image->height);
|
||||
|
||||
m_width = (int)(scale * image->width);
|
||||
m_height = (int)(scale * image->height);
|
||||
int n_pixels = m_width * m_height;
|
||||
|
||||
if (n_pixels <= 0)
|
||||
{
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
NSVGrasterizer* rast = nsvgCreateRasterizer();
|
||||
if (rast == nullptr)
|
||||
{
|
||||
// printf("Could not init rasterizer.\n");
|
||||
nsvgDelete(image);
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
// creates the temporary buffer only once, with max size, and reuse it for all the levels, if generating mipmaps
|
||||
std::vector<unsigned char> data(n_pixels * 4, 0);
|
||||
nsvgRasterize(rast, image, 0, 0, scale, data.data(), m_width, m_height, m_width * 4);
|
||||
|
||||
// sends data to gpu
|
||||
::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
::glGenTextures(1, &m_id);
|
||||
::glBindTexture(GL_TEXTURE_2D, m_id);
|
||||
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
|
||||
if (use_mipmaps)
|
||||
{
|
||||
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
|
||||
int lod_w = m_width;
|
||||
int lod_h = m_height;
|
||||
GLint level = 0;
|
||||
while ((lod_w > 1) || (lod_h > 1))
|
||||
{
|
||||
++level;
|
||||
|
||||
lod_w = std::max(lod_w / 2, 1);
|
||||
lod_h = std::max(lod_h / 2, 1);
|
||||
scale /= 2.0f;
|
||||
|
||||
nsvgRasterize(rast, image, 0, 0, scale, data.data(), lod_w, lod_h, lod_w * 4);
|
||||
::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
|
||||
}
|
||||
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1 + level);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
}
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
::glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
m_source = filename;
|
||||
|
||||
nsvgDeleteRasterizer(rast);
|
||||
nsvgDelete(image);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue