add NodeImageTexture for dynamic images, test image thumbnail opening and rendering
This commit is contained in:
@@ -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"/>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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()); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user