Automatic generation of variants of icons for toolbars and gizmos

This commit is contained in:
Enrico Turri 2019-02-26 12:56:13 +01:00
parent 987a83bb0c
commit a8610f990e
6 changed files with 120 additions and 16 deletions

View file

@ -3276,7 +3276,12 @@ bool GLCanvas3D::Gizmos::generate_icons_texture() const
}
}
bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, GLGizmoBase::Num_States, (unsigned int)(m_overlay_icons_size * m_overlay_scale));
std::vector<std::pair<int, bool>> states;
states.push_back(std::make_pair(1, false));
states.push_back(std::make_pair(0, false));
states.push_back(std::make_pair(0, true));
bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, (unsigned int)(m_overlay_icons_size * m_overlay_scale));
if (res)
m_icons_texture_dirty = false;
@ -3713,7 +3718,11 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
#endif
, m_in_render(false)
, m_bed(nullptr)
#if ENABLE_SVG_ICONS
, m_toolbar(GLToolbar::Normal, "Top")
#else
, m_toolbar(GLToolbar::Normal)
#endif // ENABLE_SVG_ICONS
, m_view_toolbar(nullptr)
, m_use_clipping_planes(false)
, m_sidebar_field("")
@ -5988,7 +5997,7 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "split_parts.svg";
#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Split to parts");
item.sprite_id = 8;
item.sprite_id = 7;
item.action_event = EVT_GLTOOLBAR_SPLIT_VOLUMES;
if (!m_toolbar.add_item(item))
return false;
@ -6001,7 +6010,7 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "layers.svg";
#endif // ENABLE_SVG_ICONS
item.tooltip = GUI::L_str("Layers editing");
item.sprite_id = 7;
item.sprite_id = 8;
item.is_toggable = true;
item.action_event = EVT_GLTOOLBAR_LAYERSEDITING;
if (!m_toolbar.add_item(item))

View file

@ -138,19 +138,19 @@ bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps)
#endif // ENABLE_TEXTURES_FROM_SVG
#if ENABLE_SVG_ICONS
bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::string>& filenames, unsigned int num_states, unsigned int sprite_size_px)
bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::string>& filenames, const std::vector<std::pair<int, bool>>& states, unsigned int sprite_size_px)
{
static int pass = 0;
++pass;
reset();
if (filenames.empty() || (num_states == 0) || (sprite_size_px == 0))
if (filenames.empty() || states.empty() || (sprite_size_px == 0))
return false;
m_width = (int)(sprite_size_px * num_states);
m_width = (int)(sprite_size_px * states.size());
m_height = (int)(sprite_size_px * filenames.size());
int n_pixels = m_width * m_height;
int sprite_n_pixels = sprite_size_px * sprite_size_px;
int sprite_bytes = sprite_n_pixels * 4;
int sprite_stride = sprite_size_px * 4;
if (n_pixels <= 0)
{
@ -159,7 +159,10 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
}
std::vector<unsigned char> data(n_pixels * 4, 0);
std::vector<unsigned char> sprite_data(sprite_size_px * sprite_size_px * 4, 0);
std::vector<unsigned char> sprite_data(sprite_bytes, 0);
std::vector<unsigned char> sprite_white_only_data(sprite_bytes, 0);
std::vector<unsigned char> sprite_gray_only_data(sprite_bytes, 0);
std::vector<unsigned char> output_data(sprite_bytes, 0);
NSVGrasterizer* rast = nsvgCreateRasterizer();
if (rast == nullptr)
@ -185,16 +188,58 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
float scale = (float)sprite_size_px / std::max(image->width, image->height);
nsvgRasterize(rast, image, 0, 0, scale, sprite_data.data(), sprite_size_px, sprite_size_px, sprite_size_px * 4);
nsvgRasterize(rast, image, 0, 0, scale, sprite_data.data(), sprite_size_px, sprite_size_px, sprite_stride);
// makes white only copy of the sprite
::memcpy((void*)sprite_white_only_data.data(), (const void*)sprite_data.data(), sprite_bytes);
for (int i = 0; i < sprite_n_pixels; ++i)
{
if (sprite_white_only_data.data()[i * 4] != 0)
::memset((void*)&sprite_white_only_data.data()[i * 4], 255, 3);
}
// makes gray only copy of the sprite
::memcpy((void*)sprite_gray_only_data.data(), (const void*)sprite_data.data(), sprite_bytes);
for (int i = 0; i < sprite_n_pixels; ++i)
{
if (sprite_gray_only_data.data()[i * 4] != 0)
::memset((void*)&sprite_gray_only_data.data()[i * 4], 128, 3);
}
int sprite_offset_px = sprite_id * sprite_size_px * m_width;
for (unsigned int i = 0; i < num_states; ++i)
int state_id = -1;
for (const std::pair<int, bool>& state : states)
{
int state_offset_px = sprite_offset_px + i * sprite_size_px;
++state_id;
// select the sprite variant
std::vector<unsigned char>* src = nullptr;
switch (state.first)
{
case 1: { src = &sprite_white_only_data; break; }
case 2: { src = &sprite_gray_only_data; break; }
default: { src = &sprite_data; break; }
}
::memcpy((void*)output_data.data(), (const void*)src->data(), sprite_bytes);
// applies background, if needed
if (state.second)
{
for (int i = 0; i < sprite_n_pixels; ++i)
{
float alpha = (float)output_data.data()[i * 4 + 3] / 255.0f;
output_data.data()[i * 4 + 0] = (unsigned char)(0 * (1.0f - alpha) + output_data.data()[i * 4 + 0] * alpha);
output_data.data()[i * 4 + 1] = (unsigned char)(0 * (1.0f - alpha) + output_data.data()[i * 4 + 1] * alpha);
output_data.data()[i * 4 + 2] = (unsigned char)(0 * (1.0f - alpha) + output_data.data()[i * 4 + 2] * alpha);
output_data.data()[i * 4 + 3] = (unsigned char)(128 * (1.0f - alpha) + output_data.data()[i * 4 + 3] * alpha);
}
}
int state_offset_px = sprite_offset_px + state_id * sprite_size_px;
for (int j = 0; j < sprite_size_px; ++j)
{
int data_offset = (state_offset_px + j * m_width) * 4;
::memcpy((void*)&data.data()[data_offset], (const void*)&sprite_data.data()[j * sprite_size_px * 4], sprite_size_px * 4);
::memcpy((void*)&data.data()[data_offset], (const void*)&output_data.data()[j * sprite_stride], sprite_stride);
}
}
@ -216,6 +261,11 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
m_source = filenames.front();
#if 0
// debug output
static int pass = 0;
++pass;
wxImage output(m_width, m_height);
output.InitAlpha();
@ -232,6 +282,7 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
}
output.SaveFile("C:/prusa/slic3r/svg_icons/temp/test_" + std::to_string(pass) + ".png", wxBITMAP_TYPE_PNG);
#endif // 0
return true;
}

View file

@ -42,7 +42,15 @@ namespace GUI {
bool load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px);
#endif // ENABLE_TEXTURES_FROM_SVG
#if ENABLE_SVG_ICONS
bool load_from_svg_files_as_sprites_array(const std::vector<std::string>& filenames, unsigned int num_states, unsigned int sprite_size_px);
// meanings of states: (std::pair<int, bool>)
// first field (int):
// 0 -> no changes
// 1 -> use white only color variant
// 2 -> use gray only color variant
// second field (bool):
// false -> no changes
// true -> add background color
bool load_from_svg_files_as_sprites_array(const std::vector<std::string>& filenames, const std::vector<std::pair<int, bool>>& states, unsigned int sprite_size_px);
#endif // ENABLE_SVG_ICONS
void reset();

View file

@ -124,8 +124,15 @@ GLToolbar::Layout::Layout()
{
}
#if ENABLE_SVG_ICONS
GLToolbar::GLToolbar(GLToolbar::EType type, const std::string& name)
#else
GLToolbar::GLToolbar(GLToolbar::EType type)
#endif // ENABLE_SVG_ICONS
: m_type(type)
#if ENABLE_SVG_ICONS
, m_name(name)
#endif // ENABLE_SVG_ICONS
, m_enabled(false)
#if ENABLE_SVG_ICONS
, m_icons_texture_dirty(true)
@ -1231,7 +1238,25 @@ bool GLToolbar::generate_icons_texture() const
filenames.push_back(path + icon_filename);
}
bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, GLToolbarItem::Num_States, (unsigned int)(m_layout.icons_size * m_layout.scale));
std::vector<std::pair<int, bool>> states;
if (m_name == "Top")
{
states.push_back(std::make_pair(1, false));
states.push_back(std::make_pair(0, false));
states.push_back(std::make_pair(2, false));
states.push_back(std::make_pair(0, false));
states.push_back(std::make_pair(0, false));
}
else if (m_name == "View")
{
states.push_back(std::make_pair(1, false));
states.push_back(std::make_pair(1, true));
states.push_back(std::make_pair(1, false));
states.push_back(std::make_pair(0, false));
states.push_back(std::make_pair(1, true));
}
bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, (unsigned int)(m_layout.icons_size * m_layout.scale));
if (res)
m_icons_texture_dirty = false;

View file

@ -203,6 +203,9 @@ private:
typedef std::vector<GLToolbarItem*> ItemsList;
EType m_type;
#if ENABLE_SVG_ICONS
std::string m_name;
#endif // ENABLE_SVG_ICONS
bool m_enabled;
#if ENABLE_SVG_ICONS
mutable GLTexture m_icons_texture;
@ -216,7 +219,11 @@ private:
ItemsList m_items;
public:
#if ENABLE_SVG_ICONS
GLToolbar(EType type, const std::string& name);
#else
explicit GLToolbar(EType type);
#endif // ENABLE_SVG_ICONS
~GLToolbar();
#if ENABLE_SVG_ICONS

View file

@ -1178,7 +1178,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
, sidebar(new Sidebar(q))
, delayed_scene_refresh(false)
, project_filename(wxEmptyString)
#if ENABLE_SVG_ICONS
, view_toolbar(GLToolbar::Radio, "View")
#else
, view_toolbar(GLToolbar::Radio)
#endif // ENABLE_SVG_ICONS
{
arranging.store(false);
rotoptimizing.store(false);