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>
|
<text text="Open PanoPainter Project" font-face="arial" font-size="11"></text>
|
||||||
</border>
|
</border>
|
||||||
<border width="400" color="0 0 0 .9" pad="10" dir="col">
|
<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>
|
<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">
|
<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"/>
|
<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*) {
|
button->on_click = [this,button](Node*) {
|
||||||
if (canvas)
|
if (canvas)
|
||||||
{
|
{
|
||||||
canvas->m_canvas->open_project(data_path);
|
//canvas->m_canvas->project_open(data_path);
|
||||||
for (auto& i : canvas->m_canvas->m_order)
|
//for (auto& i : canvas->m_canvas->m_order)
|
||||||
layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
|
// 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*) {
|
button->on_click = [this,button](Node*) {
|
||||||
if (canvas)
|
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()
|
void ui::Canvas::stroke_commit()
|
||||||
{
|
{
|
||||||
if (!m_dirty)
|
if (!m_dirty || m_layers.empty())
|
||||||
return;
|
return;
|
||||||
m_dirty = false;
|
m_dirty = false;
|
||||||
|
|
||||||
@@ -503,7 +503,7 @@ void ui::Canvas::save(std::string data_path)
|
|||||||
glActiveTexture(GL_TEXTURE0);
|
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];
|
static char name[128];
|
||||||
sprintf(name, "%s/latlong.pano", data_path.c_str());
|
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);
|
LOG("cannot write project to %s", name);
|
||||||
return;
|
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_width, sizeof(int), 1, fp);
|
||||||
fwrite(&m_height, 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);
|
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];
|
static char name[128];
|
||||||
sprintf(name, "%s/latlong.pano", data_path.c_str());
|
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);
|
LOG("cannot write project to %s", name);
|
||||||
return;
|
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_width, sizeof(int), 1, fp);
|
||||||
fread(&m_height, 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);
|
fclose(fp);
|
||||||
LOG("project restore from %s", name);
|
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()
|
void ui::Layer::destroy()
|
||||||
|
|||||||
@@ -84,8 +84,11 @@ public:
|
|||||||
void snapshot_restore();
|
void snapshot_restore();
|
||||||
void clear_context();
|
void clear_context();
|
||||||
void save(std::string data_path);
|
void save(std::string data_path);
|
||||||
void save_project(std::string data_path);
|
void project_save(std::string data_path);
|
||||||
void open_project(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;
|
std::unique_ptr<uint8_t[]> m_data;
|
||||||
public:
|
public:
|
||||||
int width;
|
int width = 0;
|
||||||
int height;
|
int height = 0;
|
||||||
int comp;
|
int comp = 4;
|
||||||
bool load(std::string filename);
|
bool load(std::string filename);
|
||||||
const uint8_t* data() const { return m_data.get(); }
|
const uint8_t* data() const { return m_data.get(); }
|
||||||
int size() const { return width * height * comp; }
|
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::Node, Node);
|
||||||
CASE(kWidget::Border, NodeBorder);
|
CASE(kWidget::Border, NodeBorder);
|
||||||
CASE(kWidget::Image, NodeImage);
|
CASE(kWidget::Image, NodeImage);
|
||||||
|
CASE(kWidget::ImageTexture, NodeImageTexture);
|
||||||
CASE(kWidget::Icon, NodeIcon);
|
CASE(kWidget::Icon, NodeIcon);
|
||||||
CASE(kWidget::Text, NodeText);
|
CASE(kWidget::Text, NodeText);
|
||||||
CASE(kWidget::TextInput, NodeTextInput);
|
CASE(kWidget::TextInput, NodeTextInput);
|
||||||
@@ -474,6 +475,8 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
|
|||||||
auto id = const_hash(ids);
|
auto id = const_hash(ids);
|
||||||
auto& ref = (*m_manager)[id]->m_children[0];
|
auto& ref = (*m_manager)[id]->m_children[0];
|
||||||
auto n = ref->clone();
|
auto n = ref->clone();
|
||||||
|
n->m_nodeID_s = ids;
|
||||||
|
n->m_nodeID = id;
|
||||||
add_child(n);
|
add_child(n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ enum class kWidget : uint16_t
|
|||||||
Text = const_hash("text"),
|
Text = const_hash("text"),
|
||||||
TextInput = const_hash("text-input"),
|
TextInput = const_hash("text-input"),
|
||||||
Image = const_hash("image"),
|
Image = const_hash("image"),
|
||||||
|
ImageTexture = const_hash("image-texture"),
|
||||||
Icon = const_hash("icon"),
|
Icon = const_hash("icon"),
|
||||||
Button = const_hash("button"),
|
Button = const_hash("button"),
|
||||||
ButtonCustom = const_hash("button-custom"),
|
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
|
class NodeButton : public Node
|
||||||
{
|
{
|
||||||
public:
|
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::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 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 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_mv = camera;
|
||||||
m_canvas->m_proj = proj;
|
m_canvas->m_proj = proj;
|
||||||
|
|||||||
Reference in New Issue
Block a user