add NodeImageTexture for dynamic images, test image thumbnail opening and rendering

This commit is contained in:
2017-05-01 22:22:16 +01:00
parent 3ea3fadc46
commit 16a53af679
7 changed files with 166 additions and 16 deletions

View File

@@ -173,6 +173,7 @@
<text text="Open PanoPainter Project" font-face="arial" font-size="11"></text>
</border>
<border width="400" color="0 0 0 .9" pad="10" dir="col">
<image-texture id="thumb-tex" width="64" height="64"/>
<text text="Longer description for the error or the message." font-face="arial" font-size="11"></text>
<node height="40" grow="1" dir="row" align="flex-end" justify="flex-end">
<button id="btn-ok" text="Open Project" width="100" height="30" margin="0 10 0 0"/>

View File

@@ -477,9 +477,20 @@ void App::initLayout()
button->on_click = [this,button](Node*) {
if (canvas)
{
canvas->m_canvas->open_project(data_path);
for (auto& i : canvas->m_canvas->m_order)
layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
//canvas->m_canvas->project_open(data_path);
//for (auto& i : canvas->m_canvas->m_order)
// layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
// load thumbnail test
auto open_dialog = layout[const_hash("popup-dialog-open")]->m_children[0]->clone();
layout[main_id]->add_child(open_dialog);
layout[main_id]->update();
if (open_dialog)
{
Image thumb = canvas->m_canvas->thumbnail_read(data_path);
auto image_tex = open_dialog->find<NodeImageTexture>("thumb-tex");
image_tex->tex.create(thumb);
}
}
};
}
@@ -488,7 +499,7 @@ void App::initLayout()
button->on_click = [this,button](Node*) {
if (canvas)
{
canvas->m_canvas->save_project(data_path);
canvas->m_canvas->project_save(data_path);
}
};
}

View File

@@ -212,7 +212,7 @@ void ui::Canvas::stroke_draw()
}
void ui::Canvas::stroke_commit()
{
if (!m_dirty)
if (!m_dirty || m_layers.empty())
return;
m_dirty = false;
@@ -503,7 +503,7 @@ void ui::Canvas::save(std::string data_path)
glActiveTexture(GL_TEXTURE0);
}
void ui::Canvas::save_project(std::string data_path)
void ui::Canvas::project_save(std::string data_path)
{
static char name[128];
sprintf(name, "%s/latlong.pano", data_path.c_str());
@@ -513,6 +513,14 @@ void ui::Canvas::save_project(std::string data_path)
LOG("cannot write project to %s", name);
return;
}
// load thumbnail
Image thumb = thumbnail_generate(64, 64);
fwrite(&thumb.width, sizeof(int), 1, fp);
fwrite(&thumb.height, sizeof(int), 1, fp);
fwrite(&thumb.comp, sizeof(int), 1, fp);
fwrite(thumb.data(), thumb.size(), 1, fp);
fwrite(&m_width, sizeof(int), 1, fp);
fwrite(&m_height, sizeof(int), 1, fp);
@@ -538,7 +546,7 @@ void ui::Canvas::save_project(std::string data_path)
LOG("project saved to %s", name);
}
void ui::Canvas::open_project(std::string data_path)
void ui::Canvas::project_open(std::string data_path)
{
static char name[128];
sprintf(name, "%s/latlong.pano", data_path.c_str());
@@ -548,6 +556,14 @@ void ui::Canvas::open_project(std::string data_path)
LOG("cannot write project to %s", name);
return;
}
// skip thumbnail
Image thumb;
fread(&thumb.width, sizeof(int), 1, fp);
fread(&thumb.height, sizeof(int), 1, fp);
fread(&thumb.comp, sizeof(int), 1, fp);
fseek(fp, thumb.size(), SEEK_CUR);
fread(&m_width, sizeof(int), 1, fp);
fread(&m_height, sizeof(int), 1, fp);
@@ -581,8 +597,86 @@ void ui::Canvas::open_project(std::string data_path)
fclose(fp);
LOG("project restore from %s", name);
}
ui::Image ui::Canvas::thumbnail_generate(int w, int h)
{
// save viewport and clear color states
GLint vp[4];
GLfloat cc[4];
glGetIntegerv(GL_VIEWPORT, vp);
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
GLboolean blend = glIsEnabled(GL_BLEND);
// prepare common states
glViewport(0, 0, w, h);
RTT fb;
fb.create(w, h);
fb.bindFramebuffer();
fb.clear({ 1, 1, 1, 1 });
ui::Plane m_face_plane;
m_face_plane.create<1>(2, 2);
// recalculate because of different aspect ratio than the m_proj matrix
glm::mat4 proj = glm::perspective(glm::radians(m_cam_fov), (float)w / (float)h, 0.1f, 1000.f);
glEnable(GL_BLEND);
for (int plane_index = 0; plane_index < 6; plane_index++)
{
auto plane_mvp = proj * m_mv * m_plane_transform[plane_index] * glm::translate(glm::vec3(0, 0, -1));
ui::ShaderManager::use(kShader::Checkerboard);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
m_face_plane.draw_fill();
ui::ShaderManager::use(kShader::TextureAlpha);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
for (auto layer_index : m_order)
{
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index].m_opacity);
m_layers[layer_index].m_rtt[plane_index].bindTexture();
m_face_plane.draw_fill();
m_layers[layer_index].m_rtt[plane_index].unbindTexture();
}
}
fb.unbindFramebuffer();
// read the rendered image
ui::Image image;
image.create(w, h);
fb.readTextureData((uint8_t*)image.data());
fb.destroy();
// restore viewport and clear color states
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
glViewport(vp[0], vp[1], vp[2], vp[3]);
glClearColor(cc[0], cc[1], cc[2], cc[3]);
glActiveTexture(GL_TEXTURE0);
return std::move(image);
}
ui::Image ui::Canvas::thumbnail_read(std::string data_path)
{
static char name[128];
sprintf(name, "%s/latlong.pano", data_path.c_str());
FILE* fp = fopen(name, "rb");
if (!fp)
{
LOG("cannot read project %s", name);
return {}; // return empty image
}
Image thumb;
fread(&thumb.width, sizeof(int), 1, fp);
fread(&thumb.height, sizeof(int), 1, fp);
fread(&thumb.comp, sizeof(int), 1, fp);
thumb.create();
fread((uint8_t*)thumb.data(), thumb.size(), 1, fp);
fclose(fp);
LOG("project thumbnail read from %s", name);
return std::move(thumb);
}
///////////////////////////////////////////////////////////////////////////////////////////
void ui::Layer::destroy()

View File

@@ -84,8 +84,11 @@ public:
void snapshot_restore();
void clear_context();
void save(std::string data_path);
void save_project(std::string data_path);
void open_project(std::string data_path);
void project_save(std::string data_path);
void project_open(std::string data_path);
ui::Image thumbnail_generate(int w, int h);
ui::Image thumbnail_read(std::string data_path);
void preview_generate();
};

View File

@@ -6,12 +6,20 @@ class Image
{
std::unique_ptr<uint8_t[]> m_data;
public:
int width;
int height;
int comp;
int width = 0;
int height = 0;
int comp = 4;
bool load(std::string filename);
const uint8_t* data() const { return m_data.get(); }
int size() const { return width * height * comp; }
void create(int w, int h)
{
width = w;
height = h;
comp = 4;
m_data = std::make_unique<uint8_t[]>(size());
}
void create() { m_data = std::make_unique<uint8_t[]>(size()); }
};
}

View File

@@ -448,6 +448,7 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
CASE(kWidget::Node, Node);
CASE(kWidget::Border, NodeBorder);
CASE(kWidget::Image, NodeImage);
CASE(kWidget::ImageTexture, NodeImageTexture);
CASE(kWidget::Icon, NodeIcon);
CASE(kWidget::Text, NodeText);
CASE(kWidget::TextInput, NodeTextInput);
@@ -474,6 +475,8 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
auto id = const_hash(ids);
auto& ref = (*m_manager)[id]->m_children[0];
auto n = ref->clone();
n->m_nodeID_s = ids;
n->m_nodeID = id;
add_child(n);
break;
}

View File

@@ -58,6 +58,7 @@ enum class kWidget : uint16_t
Text = const_hash("text"),
TextInput = const_hash("text-input"),
Image = const_hash("image"),
ImageTexture = const_hash("image-texture"),
Icon = const_hash("icon"),
Button = const_hash("button"),
ButtonCustom = const_hash("button-custom"),
@@ -547,6 +548,39 @@ public:
}
};
class NodeImageTexture : public Node
{
public:
Texture2D tex;
virtual Node* clone_instantiate() const override { return new NodeImageTexture(); }
virtual void clone_copy(Node* dest) const override
{
Node::clone_copy(dest);
NodeImageTexture* n = static_cast<NodeImageTexture*>(dest);
n->tex = tex;
}
// TODO: maybe we can save the texture data and restore later
//virtual void restore_context() override
//{
// Node::restore_context();
// create();
//}
virtual void draw() override
{
using namespace ui;
tex.bind();
NodeImage::m_sampler.bind(0);
glEnable(GL_BLEND);
ui::ShaderManager::use(kShader::Texture);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
NodeImage::m_plane.draw_fill();
NodeImage::m_sampler.unbind();
tex.unbind();
glDisable(GL_BLEND);
}
};
class NodeButton : public Node
{
public:
@@ -1928,10 +1962,6 @@ public:
//glm::mat4 proj = glm::ortho(0.f, box.z, 0.f, box.w, -1000.f, 1000.f);
glm::mat4 proj = glm::perspective(glm::radians(m_canvas->m_cam_fov), box.z / box.w, 0.1f, 1000.f);
glm::mat4 camera = glm::eulerAngleXY(m_canvas->m_cam_rot.y, m_canvas->m_cam_rot.x);
glm::mat4 transform =
glm::translate(glm::vec3(m_pan + m_size * 0.5f * zoom, -1)) * // pan
glm::scale(glm::vec3(zoom * m_zoom_canvas, zoom * m_zoom_canvas, 1)) *
glm::eulerAngleY(glm::radians(0.f));
m_canvas->m_mv = camera;
m_canvas->m_proj = proj;