implement multithreaded rendering with context switch, gl state save/restore, add progress bar ui node, implement stencil texture for brush, implement multithreaded canvas load/save/export pano. Missing multithread in windows.

This commit is contained in:
2017-10-20 09:16:12 +01:00
parent 32ede1be90
commit 283e4e2b5c
42 changed files with 610 additions and 65 deletions

View File

@@ -8,6 +8,12 @@
#include <Foundation/Foundation.h>
#endif
#ifdef __ANDROID__
void android_async_lock(struct engine* engine);
void android_async_swap(struct engine* engine);
void android_async_unlock(struct engine* engine);
#endif
using namespace ui;
App App::I; // singleton
@@ -113,6 +119,49 @@ void App::init()
glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, width_range);
LOG("GL line range: %f - %f", width_range[0], width_range[1]);
LOG("Screen Size: %f %f", width, height);
GLint fb0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fb0);
LOG("Default Framebuffer %d", fb0);
}
void App::async_start()
{
#if __OSX__
[osx_view async_lock];
#elif __IOS__
[ios_view async_lock];
#elif __ANDROID__
android_async_lock(and_engine);
#endif
}
void App::async_update()
{
#if __IOS__
[ios_view->glview bindDrawable];
#endif
redraw = true;
clear();
update(0);
#if __OSX__
[osx_view async_swap];
#elif __IOS__
[ios_view async_swap];
#elif __ANDROID__
android_async_swap(and_engine);
#endif
}
void App::async_end()
{
#if __OSX__
[osx_view async_unlock];
#elif __IOS__
[ios_view async_unlock];
#elif __ANDROID__
android_async_unlock(and_engine);
#endif
}
void App::update(float dt)
@@ -155,6 +204,11 @@ void App::update(float dt)
}
};
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#if __IOS__
[ios_view->glview bindDrawable];
#else
glBindFramebuffer(GL_FRAMEBUFFER, 0);
#endif
glEnable(GL_SCISSOR_TEST);
if (auto* main = layout[main_id])
main->watch(observer);

View File

@@ -22,6 +22,14 @@
#import "GameViewController.h"
#endif
#if defined(__OBJC__) && defined(__OSX__)
#import "main.h"
#endif
#ifdef __ANDROID__
#include "main.h"
#endif
class App
{
public:
@@ -68,8 +76,14 @@ public:
#if defined(__IOS__) && defined(__OBJC__)
GameViewController* ios_view;
#endif
#if defined(__OSX__) && defined(__OBJC__)
View* osx_view;
#endif
#ifdef __ANDROID__
struct android_app* and_app;
struct engine* and_engine;
#endif
void showKeyboard();
void hideKeyboard();
@@ -83,6 +97,9 @@ public:
void clear();
void update_memory_usage(size_t bytes);
void update(float dt);
void async_start();
void async_update();
void async_end();
void resize(float w, float h);
bool mouse_down(int button, float x, float y, float pressure, kEventSource source);
bool mouse_move(float x, float y, float pressure, kEventSource source);

View File

@@ -3,6 +3,7 @@
#include "node_icon.h"
#include "node_dialog_open.h"
#include "node_text.h"
#include "node_progress_bar.h"
using namespace ui;
@@ -528,7 +529,9 @@ void App::initLayout()
canvas->m_brush = b;
brush_update();
TextureManager::load("data/paper.jpg");
// hacky thing to make the toolbar buttons not steal events when moving cursor fast
if (auto* toolbar = layout[main_id]->find<Node>("toolbar"))
toolbar->m_flood_events = true;

View File

@@ -47,6 +47,18 @@ void App::initShaders()
" vec4(clamp(vec3(.3)+c.rgb, vec3(0), vec3(1)), c.a) : \n"
" texture(tex, uv.xy) * vec4(1,1,1,alpha);\n"
"}\n";
// STROKE PREVIEW
static const char* shader_stroke_preview_f =
SHADER_VERSION
"uniform sampler2D tex;\n"
"uniform mediump float alpha;\n"
"uniform mediump vec4 col;\n"
"in mediump vec3 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump float stroke = 1.0 - texture(tex, uv.xy).r;\n"
" frag = vec4(col.rgb, stroke * alpha);\n"
"}";
// TEXTURE COMP ERASE
static const char* shader_comp_erase_f =
SHADER_VERSION
@@ -69,6 +81,8 @@ void App::initShaders()
"uniform sampler2D tex;\n"
"uniform sampler2D tex_stroke;\n"
"uniform sampler2D tex_mask;\n"
"uniform sampler2D tex_stencil;\n"
//"uniform image2D img_mixer;\n"
"uniform mediump float alpha;\n"
"uniform bool lock;\n"
"uniform bool mask;\n"
@@ -88,8 +102,10 @@ void App::initShaders()
" return sum / vec4(9.0);\n"
"}\n"
"void main(){\n"
" mediump vec2 uv2 = gl_FragCoord.st / vec2(2048) * 20.0;\n"
" mediump vec4 base = texture(tex, uv.xy);\n"
" mediump vec4 stroke = texture(tex_stroke, uv.xy);\n"
" mediump float stencil = pow(texture(tex_stencil, uv2).r, 8.0);\n"
" stroke.a = mask ? stroke.a * alpha * blur(tex_mask, uv.xy).r : stroke.a * alpha;\n"
" mediump float contribution = (1.0 - base.a) * stroke.a;\n"
@@ -222,12 +238,16 @@ void App::initShaders()
SHADER_VERSION
#ifdef __IOS__
"#extension GL_EXT_shader_framebuffer_fetch : enable\n"
// "#extension GL_EXT_shader_image_load_store : enable\n"
#endif
"uniform mediump sampler2D tex;\n"
"uniform mediump sampler2D tex_bg;\n"
"uniform mediump sampler2D tex_stencil;\n"
//"layout (binding=3, rgba8) uniform image2D tex_mix;\n"
"uniform mediump vec4 col;\n"
"uniform mediump vec2 resolution;\n"
"uniform mediump float alpha;\n"
"uniform mediump vec2 stencil_offset;\n"
"in mediump vec2 uv;\n"
"in mediump float q;\n"
#ifdef __IOS__
@@ -237,6 +257,7 @@ void App::initShaders()
#endif
"void main(){\n"
" mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
" mediump float stencil = 1-(texture(tex_stencil, (uv2+stencil_offset) * 5.0).r * 0.9);\n"
" mediump float brush_alpha = ( 1.0 - texture(tex, uv/q).r ) * alpha;\n"
" mediump vec4 fg = vec4(col.rgb, brush_alpha);\n"
#ifdef __IOS__
@@ -245,7 +266,7 @@ void App::initShaders()
" mediump vec4 bg = texture(tex_bg, uv2);\n"
#endif
" if (fg.a < 1.0/255.0) { frag = bg; return; }\n"
" mediump float contribution = max((1.0 - bg.a) * fg.a, 1.0/255.0);\n"
" mediump float contribution = max((1.0 - bg.a) * fg.a, 1.0/255.0) * stencil;\n"
" mediump float alpha_tot = bg.a + contribution;"
" mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n"
" frag = vec4(rgb, clamp(alpha_tot, 0.0, 1.0));\n"
@@ -307,6 +328,8 @@ void App::initShaders()
LOG("Failed to create shader Texture");
if (!ShaderManager::create(kShader::TextureAlpha, shader_v, shader_alpha_f))
LOG("Failed to create shader TextureAlpha");
if (!ShaderManager::create(kShader::StrokePreview, shader_v, shader_stroke_preview_f))
LOG("Failed to create shader StrokePreview");
if (!ShaderManager::create(kShader::CompErase, shader_v, shader_comp_erase_f))
LOG("Failed to create shader CompErase");
if (!ShaderManager::create(kShader::CompDraw, shader_v, shader_comp_draw_f))

View File

@@ -1,6 +1,9 @@
#include "pch.h"
#include "log.h"
#include "canvas.h"
#include "app.h"
#include "node_progress_bar.h"
#include <thread>
#ifdef __APPLE__
#include <Foundation/Foundation.h>
@@ -196,10 +199,16 @@ void ui::Canvas::stroke_draw()
auto m_brush = m_current_stroke->m_brush;
auto samples = m_current_stroke->compute_samples();
auto& tex = TextureManager::get(m_brush.m_tex_id);
auto& stencil = TextureManager::get(const_hash("data/paper.jpg"));
glActiveTexture(GL_TEXTURE0);
tex.bind();
m_sampler_brush.bind(0);
m_sampler_bg.bind(1);
m_sampler_mask.bind(2);
m_sampler_stencil.bind(3);
glActiveTexture(GL_TEXTURE3);
stencil.bind();
for (int i = 0; i < 6; i++)
{
@@ -230,8 +239,10 @@ void ui::Canvas::stroke_draw()
ShaderManager::use(ui::kShader::Stroke);
ShaderManager::u_int(kShaderUniform::Tex, 0); // brush
ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg
ShaderManager::u_int(kShaderUniform::TexStencil, 3); // stencil
ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color);
ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height });
ShaderManager::u_vec2(kShaderUniform::StencilOffset, glm::vec2((rand()%1000)*0.001f, (rand()%1000)*0.001f));
for (const auto& s : samples)
{
glm::vec2 dx(s.size * 0.5f, 0), dy(0, s.size * 0.5f);
@@ -458,6 +469,7 @@ void ui::Canvas::stroke_commit()
m_sampler.bind(0);
m_sampler_bg.bind(1);
m_sampler_mask.bind(2);
m_sampler_stencil.bind(3);
if (m_state == kCanvasMode::Erase)
{
ui::ShaderManager::use(kShader::CompErase);
@@ -482,6 +494,8 @@ void ui::Canvas::stroke_commit()
}
else
{
auto& paper = TextureManager::get(const_hash("data/paper.jpg"));
ui::ShaderManager::use(kShader::CompDraw);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
@@ -496,7 +510,11 @@ void ui::Canvas::stroke_commit()
m_tmp[i].bindTexture();
glActiveTexture(GL_TEXTURE2);
m_smask.m_rtt[i].bindTexture();
glActiveTexture(GL_TEXTURE3);
paper.bind();
m_plane.draw_fill();
paper.unbind();
glActiveTexture(GL_TEXTURE2);
m_smask.m_rtt[i].unbindTexture();
glActiveTexture(GL_TEXTURE1);
m_tmp[i].unbindTexture();
@@ -712,9 +730,11 @@ bool ui::Canvas::create(int width, int height)
m_sampler_brush.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR);
m_sampler_bg.create(GL_NEAREST);
m_sampler_mask.create(GL_LINEAR);
m_sampler_stencil.create(GL_LINEAR, GL_REPEAT);
m_plane.create<1>(1, 1);
m_plane_brush.create<1>(1, 1);
m_mesh.create();
m_brush_mix.create(8, 8);
for (auto& l : m_layers)
{
l.create(width, height, "");
@@ -755,11 +775,27 @@ void ui::Canvas::clear_context()
}
};
#ifdef __IOS__
UIImage *image;
#endif
void ui::Canvas::export_equirectangular(std::string data_path)
{
std::thread t(&ui::Canvas::export_equirectangular_thread, this, data_path);
t.detach();
}
void ui::Canvas::export_equirectangular_thread(std::string data_path)
{
gl_state gl;
App::I.async_start();
auto pb = std::make_shared<NodeProgressBar>();
pb->m_manager = &App::I.layout;
pb->init();
pb->create();
pb->loaded();
pb->m_progress->SetWidthP(0);
pb->m_title->set_text("Export Pano Image");
App::I.layout[App::I.main_id]->add_child(pb);
App::I.async_update();
// save viewport and clear color states
GLint vp[4];
GLfloat cc[4];
@@ -788,13 +824,16 @@ void ui::Canvas::export_equirectangular(std::string data_path)
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, // bottom
};
ShaderManager::use(ui::kShader::TextureAlpha);
ShaderManager::u_int(kShaderUniform::Highlight, false);
ShaderManager::u_int(kShaderUniform::Tex, 0);
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
int progress = 0;
int total = 6 + 2;
for (int i = 0; i < 6; i++)
{
ShaderManager::use(ui::kShader::TextureAlpha);
ShaderManager::u_int(kShaderUniform::Highlight, false);
ShaderManager::u_int(kShaderUniform::Tex, 0);
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
m_tmp[i].bindFramebuffer();
m_tmp[i].clear({ 1, 1, 1, 1 });
@@ -815,6 +854,14 @@ void ui::Canvas::export_equirectangular(std::string data_path)
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
m_tmp[i].unbindFramebuffer();
progress++;
float p = (float)progress / total * 100.f;
pb->m_progress->SetWidthP(p);
LOG("progress: %f", p);
gl.save();
App::I.async_update();
gl.restore();
}
//auto data = std::make_unique<uint8_t[]>(m_tmp[0].bytes());
@@ -843,6 +890,17 @@ void ui::Canvas::export_equirectangular(std::string data_path)
{
auto latlong_data = std::make_unique<uint8_t[]>(m_latlong.bytes());
m_latlong.readTextureData(latlong_data.get());
{
progress++;
float p = (float)progress / total * 100.f;
pb->m_progress->SetWidthP(p);
LOG("progress: %f", p);
gl.save();
App::I.async_update();
gl.restore();
}
static char name[128];
sprintf(name, "%s/latlong.jpg", data_path.c_str());
LOG("writing %s", name);
@@ -850,6 +908,17 @@ void ui::Canvas::export_equirectangular(std::string data_path)
params.m_quality = 100;
bool saved = jpge::compress_image_to_jpeg_file(name, m_latlong.getWidth(), m_latlong.getHeight(), 4, latlong_data.get(), params);
inject_xmp(name);
{
progress++;
float p = (float)progress / total * 100.f;
pb->m_progress->SetWidthP(p);
LOG("progress: %f", p);
gl.save();
App::I.async_update();
gl.restore();
}
//int ret = stbi_write_png(name, m_latlong.getWidth(), m_latlong.getHeight(), 4, latlong_data.get(), m_latlong.stride());
#ifdef __IOS__
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
@@ -875,6 +944,10 @@ void ui::Canvas::export_equirectangular(std::string data_path)
glViewport(vp[0], vp[1], vp[2], vp[3]);
glClearColor(cc[0], cc[1], cc[2], cc[3]);
glActiveTexture(GL_TEXTURE0);
pb->destroy();
App::I.async_update();
App::I.async_end();
}
void ui::Canvas::inject_xmp(std::string jpg_path)
@@ -1043,6 +1116,13 @@ void ui::Canvas::export_anim(std::string data_path)
void ui::Canvas::project_save(std::string data_path)
{
std::thread t(&ui::Canvas::project_save_thread, this, data_path);
t.detach();
}
void ui::Canvas::project_save_thread(std::string data_path)
{
gl_state gl;
// static char name[128];
// sprintf(name, "%s/latlong.pano", data_path.c_str());
FILE* fp = fopen(data_path.c_str(), "wb");
@@ -1053,7 +1133,19 @@ void ui::Canvas::project_save(std::string data_path)
}
// load thumbnail
App::I.async_start();
Image thumb = thumbnail_generate(128, 128);
auto pb = std::make_shared<NodeProgressBar>();
pb->m_manager = &App::I.layout;
pb->init();
pb->create();
pb->loaded();
pb->m_progress->SetWidthP(0);
pb->m_title->set_text("Saving Pano Project");
App::I.layout[App::I.main_id]->add_child(pb);
App::I.async_update();
App::I.async_end();
thumb.flip();
fwrite(&thumb.width, sizeof(int), 1, fp);
fwrite(&thumb.height, sizeof(int), 1, fp);
@@ -1066,6 +1158,9 @@ void ui::Canvas::project_save(std::string data_path)
int n_layers = (int)m_layers.size();
fwrite(&n_layers, sizeof(int), 1, fp);
int progress = 0;
int total = (int)m_layers.size() * 6;
for (int i = 0; i < (int)m_layers.size(); i++)
{
int n_order = m_order[i];
@@ -1075,7 +1170,10 @@ void ui::Canvas::project_save(std::string data_path)
fwrite(&name_len, sizeof(int), 1, fp);
fwrite(m_layers[i].m_name.data(), name_len, 1, fp);
App::I.async_start();
auto snap = m_layers[i].snapshot(data_path);
App::I.async_update();
App::I.async_end();
for (int plane_index = 0; plane_index < 6; plane_index++)
{
int has_data = snap.m_dirty_face[plane_index] ? 1 : 0;
@@ -1100,13 +1198,31 @@ void ui::Canvas::project_save(std::string data_path)
fwrite(compressed.data(), 1, compressed.size(), fp);
}
progress++;
float p = (float)progress / total * 100.f;
App::I.async_start();
pb->m_progress->SetWidthP(p);
LOG("progress: %f", p);
App::I.async_update();
App::I.async_end();
}
}
fclose(fp);
LOG("project saved to %s", data_path.c_str());
App::I.async_start();
pb->destroy();
App::I.async_update();
App::I.async_end();
}
void ui::Canvas::project_open(std::string data_path)
{
std::thread t(&ui::Canvas::project_open_thread, this, data_path);
t.detach();
//project_open_thread(data_path);
}
void ui::Canvas::project_open_thread(std::string data_path)
{
// static char name[128];
// sprintf(name, "%s/latlong.pano", data_path.c_str());
@@ -1117,6 +1233,22 @@ void ui::Canvas::project_open(std::string data_path)
return;
}
gl_state gl;
App::I.async_start();
auto pb = std::make_shared<NodeProgressBar>();
pb->m_manager = &App::I.layout;
pb->init();
pb->create();
pb->loaded();
pb->m_progress->SetWidthP(0);
pb->m_title->set_text("Opening Pano Project");
App::I.layout[App::I.main_id]->add_child(pb);
gl.save();
App::I.async_update();
gl.restore();
App::I.async_end();
LOG("skip thumb");
// skip thumbnail
Image thumb;
fread(&thumb.width, sizeof(int), 1, fp);
@@ -1127,15 +1259,23 @@ void ui::Canvas::project_open(std::string data_path)
fread(&m_width, sizeof(int), 1, fp);
fread(&m_height, sizeof(int), 1, fp);
int n_layers = (int)m_layers.size();
int n_layers = 0;
fread(&n_layers, sizeof(int), 1, fp);
const int bytes = m_width * m_height * 4;
Layer::Snapshot snap;
snap.create(m_width, m_height); // allocate single data, no box should be bigger
int progress = 0;
int total = n_layers * 6;
App::I.async_start();
for (auto& l : m_layers)
l.destroy();
m_layers.clear();
m_order.clear();
App::I.async_end();
for (int i = 0; i < n_layers; i++)
{
int n_order;
@@ -1168,17 +1308,36 @@ void ui::Canvas::project_open(std::string data_path)
std::copy(rgba, rgba + (imgw*imgh * 4), snap.image[plane_index].get());
delete rgba;
}
progress++;
float p = (float)progress / total * 100.f;
LOG("progress: %f", p);
App::I.async_start();
pb->m_progress->SetWidthP(p);
gl.save();
App::I.async_update();
gl.restore();
App::I.async_end();
}
App::I.async_start();
m_layers.emplace_back();
m_layers.back().create(m_width, m_height, name.c_str());
m_layers.back().restore(snap);
App::I.async_end();
}
fclose(fp);
LOG("project restore from %s", data_path.c_str());
App::I.async_start();
pb->destroy();
gl.save();
App::I.async_update();
gl.restore();
App::I.async_end();
}
ui::Image ui::Canvas::thumbnail_generate(int w, int h)
{
// save viewport and clear color states
GLint vp[4];
GLfloat cc[4];

View File

@@ -41,12 +41,13 @@ public:
class Canvas
{
public:
Plane m_plane;
Plane m_plane_brush;
BrushMesh m_mesh;
bool m_dirty = false;
bool m_commit_delayed = false;
public:
static Canvas* I;
bool m_alpha_lock = false;
bool m_touch_lock = true;
@@ -67,6 +68,7 @@ public:
Layer m_smask; // selection mask
bool m_smask_active = false;
RTT m_tmp[6];
Texture2D m_brush_mix;
Texture2D m_tex[6];
Texture2D m_tex2[6];
bool m_pick_ready[6];
@@ -79,6 +81,7 @@ public:
Sampler m_sampler_brush;
Sampler m_sampler_bg;
Sampler m_sampler_mask;
Sampler m_sampler_stencil;
glm::vec2 m_cam_rot;
glm::vec3 m_cam_pos;
float m_cam_fov = 85;
@@ -125,9 +128,12 @@ public:
void snap_history(const std::vector<int>& planes);
void clear_context();
void export_equirectangular(std::string data_path);
void export_equirectangular_thread(std::string data_path);
void export_anim(std::string data_path);
void project_save(std::string data_path);
void project_save_thread(std::string data_path);
void project_open(std::string data_path);
void project_open_thread(std::string data_path);
void inject_xmp(std::string jpg_path);
ui::Image thumbnail_generate(int w, int h);
ui::Image thumbnail_read(std::string data_path);

View File

@@ -116,6 +116,7 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
App::I.color->m_hue->set_value(hsv.x);
App::I.color->m_quad->set_value(1.f - hsv.y, 1.f - hsv.z);
}
m_cur_pos = loc;
break;
case kEventType::MouseCancel:
if (m_dragging)
@@ -134,6 +135,35 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
}
}
void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
#ifndef __IOS__
if (!m_dragging && !m_picking)
{
ui::ShaderManager::use(ui::kShader::StrokePreview);
ui::ShaderManager::u_int(ui::kShaderUniform::Tex, 0);
ui::ShaderManager::u_float(ui::kShaderUniform::Alpha, node->m_brush.m_tip_flow);
auto tip_color = glm::vec4(glm::vec3(node->m_brush.m_tip_color), 1);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, tip_color);
ui::ShaderManager::u_int(ui::kShaderUniform::Highlight, 0);
float tip_scale = 1.f / glm::tan(glm::radians(ui::Canvas::I->m_cam_fov * 0.5f));
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP,
glm::scale(glm::vec3(1, -1, 1)) *
ortho *
glm::translate(glm::vec3(m_cur_pos, 0)) *
glm::scale(glm::vec3(node->m_brush.m_tip_size * 800.f * tip_scale))
);
glEnable(GL_BLEND);
glActiveTexture(GL_TEXTURE0);
auto& tex = TextureManager::get(node->m_brush.m_tex_id);
tex.bind();
canvas->m_sampler_brush.bind(0);
canvas->m_plane.draw_fill();
tex.unbind();
}
#endif
}
void CanvasModePen::leave()
{
m_brush = node->m_brush;

View File

@@ -39,6 +39,7 @@ class CanvasModePen : public CanvasMode
{
bool m_dragging = false;
glm::vec2 m_pan_start;
glm::vec2 m_cur_pos;
float m_camera_fov;
float m_zoom_canvas = 1.f;
float m_zoom_start;
@@ -46,6 +47,7 @@ class CanvasModePen : public CanvasMode
ui::Brush m_brush;
public:
virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override;
virtual void on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) override;
virtual void enter() override;
virtual void leave() override;
bool m_picking = false;

View File

@@ -15,6 +15,7 @@ void NodeCanvas::init()
m_canvas = std::make_unique<ui::Canvas>();
m_canvas->create(RES, RES);
m_sampler.create(GL_NEAREST);
m_sampler_stencil.create(GL_LINEAR, GL_REPEAT);
m_face_plane.create<1>(2, 2);
m_line.create();
CanvasMode::node = this;
@@ -79,6 +80,7 @@ void NodeCanvas::draw()
m_sampler.bind(0);
m_sampler.bind(1);
m_sampler.bind(2);
m_sampler_stencil.bind(3);
auto blend = glIsEnabled(GL_BLEND);
auto depth = glIsEnabled(GL_DEPTH_TEST);
@@ -141,10 +143,12 @@ void NodeCanvas::draw()
}
else if(m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index)
{
auto& paper = TextureManager::get(const_hash("data/paper.jpg"));
ui::ShaderManager::use(kShader::CompDraw);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
ui::ShaderManager::u_int(kShaderUniform::TexMask, 2);
ui::ShaderManager::u_int(kShaderUniform::TexStencil, 3);
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[m_canvas->m_current_layer_idx].m_alpha_locked);
ui::ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
@@ -155,7 +159,11 @@ void NodeCanvas::draw()
m_canvas->m_tmp[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE2);
m_canvas->m_smask.m_rtt[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE3);
paper.bind();
m_face_plane.draw_fill();
paper.unbind();
glActiveTexture(GL_TEXTURE2);
m_canvas->m_smask.m_rtt[plane_index].unbindTexture();
glActiveTexture(GL_TEXTURE1);
m_canvas->m_tmp[plane_index].unbindTexture();

View File

@@ -9,6 +9,7 @@ public:
std::unique_ptr<ui::Canvas> m_canvas;
ui::Brush m_brush;
Sampler m_sampler;
Sampler m_sampler_stencil;
ui::Plane m_face_plane;
ui::LineSegment m_line;
virtual Node* clone_instantiate() const override;

View File

@@ -104,6 +104,7 @@ void NodePanelBrush::select_brush(int brush_id)
{
b->m_selected = true;
m_current = b;
TextureManager::load(b->high_path.c_str(), true);
}
}
}

View File

@@ -0,0 +1,24 @@
#include "pch.h"
#include "log.h"
#include "node_progress_bar.h"
#include "layout.h"
Node* NodeProgressBar::clone_instantiate() const
{
return new NodeProgressBar();
}
void NodeProgressBar::init()
{
auto tpl = static_cast<const NodeBorder*>(init_template("progress-bar"));
m_color = tpl->m_color;
m_border_color = tpl->m_border_color;
m_thinkness = tpl->m_thinkness;
m_title = find<NodeText>("title");
btn_cancel = find<NodeButton>("btn-cancel");
btn_cancel->on_click = [&](Node*) { destroy(); };
m_progress = find<NodeBorder>("progress");
m_progress->SetWidthP(10);
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include "node.h"
#include "node_button.h"
#include "node_text.h"
#include "node_border.h"
class NodeProgressBar : public NodeBorder
{
public:
Node* m_template;
NodeButton* btn_cancel;
NodeText* m_title;
NodeBorder* m_progress;
virtual Node* clone_instantiate() const override;
virtual void init() override;
};

View File

@@ -11,6 +11,8 @@ enum class kShaderUniform : uint16_t
TexBG = const_hash("tex_bg"),
TexMask = const_hash("tex_mask"),
TexStroke = const_hash("tex_stroke"),
TexStencil= const_hash("tex_stencil"),
StencilOffset = const_hash("stencil_offset"),
Lock = const_hash("lock"),
Col = const_hash("col"),
Tof = const_hash("tof"),
@@ -34,6 +36,7 @@ enum class kShader : uint16_t
Font = const_hash("font"),
Atlas = const_hash("atlas"),
Stroke = const_hash("stroke"),
StrokePreview = const_hash("stroke-preview"),
Checkerboard= const_hash("checkerboard"),
Equirect = const_hash("equirect"),
};

View File

@@ -111,4 +111,55 @@ public:
}
};
struct gl_state
{
GLboolean blend;
GLboolean depth_test;
GLboolean scissor_test;
GLint vp[4];
GLfloat cc[4];
GLint tex[10];
GLint cube;
GLint sampler[10];
GLint program;
GLint fb;
GLint active_tex;
void save()
{
blend = glIsEnabled(GL_BLEND);
depth_test = glIsEnabled(GL_DEPTH_TEST);
scissor_test = glIsEnabled(GL_SCISSOR_TEST);
glGetIntegerv(GL_VIEWPORT, vp);
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fb);
glGetIntegerv(GL_ACTIVE_TEXTURE, &active_tex);
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &cube);
for (int i = 0; i < 10; ++i)
{
glActiveTexture(GL_TEXTURE0 + i);
glGetIntegerv(GL_TEXTURE_BINDING_2D, tex + i);
glGetIntegerv(GL_SAMPLER_BINDING, sampler + i);
}
}
void restore()
{
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
scissor_test ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST);
glViewport(vp[0], vp[1], vp[2], vp[3]);
glClearColor(cc[0], cc[1], cc[2], cc[3]);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glUseProgram(program);
for (int i = 0; i < 10; ++i)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, tex[i]);
glBindSampler(i, sampler[i]);
}
glActiveTexture(active_tex);
glBindTexture(GL_TEXTURE_BINDING_CUBE_MAP, cube);
}
};
NS_END