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:
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user