add support for high res brush textures, implement mipmaps on brush

This commit is contained in:
2017-09-30 16:35:12 +01:00
parent 763e446cc5
commit 964795b44d
17 changed files with 61 additions and 20 deletions

3
.gitignore vendored
View File

@@ -11,3 +11,6 @@ android/.gradle/
android/.externalNativeBuild/
android/src/main/assets/
android/.idea
android/android.iml
android/local.properties

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
data/brushes/Round-Hard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

BIN
data/thumbs/Round-Brush.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
data/thumbs/Round-Hard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
data/thumbs/Square-Hard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

View File

@@ -129,8 +129,8 @@ void App::init_sidebar()
}
brushes->on_brush_changed = [this](Node* target, int index) {
auto tid = brushes->get_texture_id(index);
stroke->m_canvas->m_brush.m_tex_id = tid;
stroke->m_canvas->m_brush.m_tex_id = brushes->get_texture_id(index);
stroke->m_canvas->m_brush.id = brushes->get_brush_id(index);
stroke->m_canvas->draw_stroke();
canvas->m_brush = stroke->m_canvas->m_brush;
if (on_brush_select)
@@ -375,7 +375,7 @@ void App::init_menu_edit()
void App::brush_update()
{
brushes->set_texture_id(canvas->m_brush.m_tex_id);
brushes->select_brush(canvas->m_brush.id);
stroke->set_params(canvas->m_brush);
}

View File

@@ -226,7 +226,7 @@ void ui::Stroke::add_point(glm::vec2 pos, float pressure)
pressure = pressure * glm::pow(m_curve, 2.f);
if (m_brush.m_tip_size_pressure)
m_step = glm::max(m_brush.m_tip_spacing * m_brush.m_tip_size * 100 * pressure, 1.f);
m_step = glm::max(glm::pow(m_brush.m_tip_spacing * 4.f, 2.f) * glm::pow(m_brush.m_tip_size, 3.f) * 800.f * pressure, 1.f);
float dist = m_keypoints.empty() ? 0.f :
m_keypoints.back().dist + glm::distance(m_keypoints.back().pos, pos);
@@ -244,7 +244,7 @@ void ui::Stroke::start(const ui::Brush& brush)
m_curve_angles.clear();
m_last_kp = 0;
m_dist = 0.f;
m_step = glm::max(brush.m_tip_spacing * brush.m_tip_size * 100, 1.f);
m_brush = brush;
m_step = glm::max(glm::pow(m_brush.m_tip_spacing * 4.f, 2.f) * glm::pow(m_brush.m_tip_size, 3.f) * 800.f, 1.f);
prng.seed(0);
}

View File

@@ -196,7 +196,7 @@ void ui::Canvas::stroke_draw()
auto samples = m_current_stroke->compute_samples();
auto& tex = TextureManager::get(m_brush.m_tex_id);
tex.bind();
m_sampler.bind(0);
m_sampler_brush.bind(0);
m_sampler_bg.bind(1);
m_sampler_mask.bind(2);
@@ -233,7 +233,7 @@ void ui::Canvas::stroke_draw()
ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height });
for (const auto& s : samples)
{
glm::vec2 dx(s.size, 0), dy(0, s.size);
glm::vec2 dx(s.size * 0.5f, 0), dy(0, s.size * 0.5f);
glm::vec2 off[4] = {
- dx - dy, // A - bottom-left
- dx + dy, // B - top-left
@@ -317,7 +317,7 @@ void ui::Canvas::stroke_draw()
glDisable(GL_BLEND);
glActiveTexture(GL_TEXTURE0);
m_sampler.unbind();
m_sampler_brush.unbind();
m_sampler_bg.unbind();
m_sampler_mask.unbind();
tex.unbind();
@@ -695,6 +695,8 @@ bool ui::Canvas::create(int width, int height)
m_tex2[i].create(width, height); // TODO: destroy before recreating
}
m_sampler.create(GL_NEAREST);
m_sampler_brush.create();
m_sampler_brush.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR);
m_sampler_bg.create(GL_NEAREST);
m_sampler_mask.create(GL_NEAREST);
m_plane.create<1>(1, 1);

View File

@@ -74,6 +74,7 @@ public:
static glm::vec3 m_plane_tangent[6];
static glm::mat4 m_plane_transform[6];
Sampler m_sampler;
Sampler m_sampler_brush;
Sampler m_sampler_bg;
Sampler m_sampler_mask;
glm::vec2 m_cam_rot;

View File

@@ -2,6 +2,7 @@
#include "log.h"
#include "node_panel_brush.h"
#include "asset.h"
#include "texture.h"
#ifdef __APPLE__
#include <Foundation/Foundation.h>
@@ -44,14 +45,15 @@ void NodePanelBrush::init()
{
init_template("tpl-panel-brushes");
//m_layers_container = find<NodeBorder>("layers-container");
static auto icons = Asset::list_files("data/Icons", true, ".*\\.png$");
static auto icons = Asset::list_files("data/thumbs", true, ".*\\.png$");
if ((m_container = find<NodeBorder>("brushes")))
{
int count = 0;
for (auto& i : icons)
{
std::string path = "data/Icons/" + i;
std::string path = "data/thumbs/" + i;
std::string path_hi = "data/brushes/" + i;
NodeButtonBrush* brush = new NodeButtonBrush;
m_container->add_child(brush);
brush->init();
@@ -59,6 +61,8 @@ void NodePanelBrush::init()
brush->loaded();
brush->set_icon(path.c_str());
brush->m_brushID = count++;
brush->high_path = path_hi;
brush->high_id = const_hash(path_hi.c_str());
m_brushes.push_back(brush);
brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1);
}
@@ -79,17 +83,23 @@ void NodePanelBrush::handle_click(Node* target)
uint16_t NodePanelBrush::get_texture_id(int index) const
{
return m_brushes[index]->img->m_tex_id;
TextureManager::load(m_brushes[index]->high_path.c_str(), true);
return m_brushes[index]->high_id;
}
int NodePanelBrush::get_brush_id(int index) const
{
return m_brushes[index]->m_brushID;
}
// select the current brush based on the texture id
void NodePanelBrush::set_texture_id(int texid)
void NodePanelBrush::select_brush(int brush_id)
{
if (m_current)
m_current->m_selected = false;
for (auto b : m_brushes)
{
if (b->img->m_tex_id == texid)
if (b->m_brushID == brush_id)
{
b->m_selected = true;
m_current = b;

View File

@@ -8,6 +8,8 @@ class NodeButtonBrush : public NodeButtonCustom
public:
int m_brushID;
bool m_selected = false;
std::string high_path;
uint16_t high_id;
NodeImage* img;
virtual Node* clone_instantiate() const override;
virtual void init() override;
@@ -27,5 +29,6 @@ public:
void handle_click(Node* target);
std::vector<std::string> FindAllBrushes(const std::string& folder);
uint16_t get_texture_id(int index) const;
void set_texture_id(int texid);
int get_brush_id(int index) const;
void select_brush(int brush_id);
};

View File

@@ -30,6 +30,7 @@ void NodeStrokePreview::init_controls()
{
m_mesh.create();
m_sampler.create();
m_sampler_brush.create(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR);
TextureManager::load("data/Icons/Round-Hard.png");
m_brush.m_tex_id = const_hash("data/Icons/Round-Hard.png");
}
@@ -66,7 +67,7 @@ void NodeStrokePreview::draw_stroke()
glm::mat4 proj = glm::ortho<float>(0, (float)m_rtt.getWidth(), 0, (float)m_rtt.getHeight(), -1, 1);
auto b = m_brush;
b.m_tip_size *= .7f; // reduce the size in the preview
//b.m_tip_size *= .7f; // reduce the size in the preview
m_stroke.reset();
m_stroke.start(b);
if (!m_stroke.m_keypoints.empty())
@@ -74,7 +75,7 @@ void NodeStrokePreview::draw_stroke()
auto samples = m_stroke.compute_samples();
auto& tex = TextureManager::get(m_brush.m_tex_id);
tex.bind();
m_sampler.bind(0);
m_sampler_brush.bind(0);
if (true)
{
@@ -100,7 +101,7 @@ void NodeStrokePreview::draw_stroke()
// }
//}
m_sampler.unbind();
m_sampler_brush.unbind();
tex.unbind();
glDisable(GL_BLEND);
@@ -126,6 +127,7 @@ void NodeStrokePreview::draw()
void NodeStrokePreview::handle_resize(glm::vec2 old_size, glm::vec2 new_size)
{
float pad = 30.f;
new_size *= root()->m_zoom;
float w = new_size.x;
float h = new_size.y;
std::vector<glm::vec2> kp = { { pad, pad },{ pad, h - pad },{ w - pad, pad },{ w - pad, h - pad } };

View File

@@ -8,6 +8,7 @@ class NodeStrokePreview : public NodeBorder
{
RTT m_rtt;
Sampler m_sampler;
Sampler m_sampler_brush;
ui::BrushMesh m_mesh;
public:
ui::Brush m_brush;

View File

@@ -5,12 +5,15 @@
std::map<uint16_t, Texture2D> TextureManager::m_textures;
bool TextureManager::load(const char* path)
bool TextureManager::load(const char* path, bool generate_mipmaps)
{
uint16_t id = const_hash(path);
if (m_textures.count(id) == 0 || !m_textures[id].ready())
{
return m_textures[id].load(path);
if (!m_textures[id].load(path))
return false;
if (generate_mipmaps)
m_textures[id].create_mipmaps();
}
return true;
}
@@ -54,6 +57,13 @@ bool Texture2D::create(const ui::Image& img)
return create(img.width, img.height, iformats[img.comp - 1], formats[img.comp - 1], img.data());
}
void Texture2D::create_mipmaps()
{
bind();
glGenerateMipmap(GL_TEXTURE_2D);
unbind();
}
void Texture2D::assign(GLuint tex, int w/* = -1*/, int h/* = -1*/, GLuint internal_format/* = GL_RGBA8*/, GLuint format/* = GL_RGBA*/)
{
m_tex = tex;
@@ -102,6 +112,13 @@ void Sampler::set(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter);
#endif // USE_SAMPLER
}
void Sampler::set_filter(GLint filter_min, GLint filter_mag)
{
#if USE_SAMPLER
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter_min);
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter_mag);
#endif // USE_SAMPLER
}
void Sampler::bind(int unit)
{
current_unit = unit;

View File

@@ -18,6 +18,7 @@ public:
void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); }
void update(const uint8_t* data);
bool ready() const { return m_tex != 0; }
void create_mipmaps();
glm::vec2 size() const;
};
@@ -28,6 +29,7 @@ class Sampler
public:
bool create(GLint filter = GL_LINEAR, GLint wrap = GL_CLAMP_TO_EDGE);
void set(GLint filter = GL_LINEAR, GLint wrap = GL_CLAMP_TO_EDGE);
void set_filter(GLint filter_min, GLint filter_mag);
void bind(int unit);
void unbind();
bool ready() const { return id != 0; }
@@ -37,7 +39,7 @@ class TextureManager
{
public:
static std::map<uint16_t, Texture2D> m_textures;
static bool load(const char* path);
static bool load(const char* path, bool generate_mipmpas = false);
static void assign(uint16_t id, GLuint tex, int w = -1, int h = -1, GLuint internal_format = GL_RGBA8, GLuint format = GL_RGBA);
static Texture2D& get(uint16_t id);
static void invalidate();