add load image from url
This commit is contained in:
@@ -150,6 +150,79 @@ bool Asset::create_dir(const std::string& path)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t curl_data_handler_asset(void* contents, size_t size, size_t nmemb, void* userp)
|
||||||
|
{
|
||||||
|
auto buffer = reinterpret_cast<std::vector<uint8_t>*>(userp);
|
||||||
|
buffer->insert(buffer->end(), (char*)contents, (char*)contents + (size * nmemb));
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int progress_callback_asset_download(void* clientp, curl_off_t dltotal,
|
||||||
|
curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
||||||
|
{
|
||||||
|
Asset* ass = static_cast<Asset*>(clientp);
|
||||||
|
if (ass->m_stop_async)
|
||||||
|
{
|
||||||
|
LOG("interrupt download of %s", ass->m_current_url.c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
float p = dltotal > 0 ? (float)dlnow / (float)dltotal : 0.f;
|
||||||
|
bool cont = ass->on_progress(p);
|
||||||
|
return cont ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Asset::open_url(const std::string& url, std::function<bool(float)> progress /*= nullptr*/)
|
||||||
|
{
|
||||||
|
CURL* curl = curl_easy_init();
|
||||||
|
if (curl)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
LOG("download %s", url.c_str());
|
||||||
|
m_current_url = url;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_handler_asset);
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
|
#endif
|
||||||
|
if (progress)
|
||||||
|
{
|
||||||
|
on_progress = progress;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback_asset_download);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||||
|
}
|
||||||
|
auto err = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
if (err == CURLE_OK)
|
||||||
|
{
|
||||||
|
if (m_data)
|
||||||
|
delete m_data;
|
||||||
|
m_data = new uint8_t[data.size()];
|
||||||
|
std::copy(data.begin(), data.end(), m_data);
|
||||||
|
m_len = data.size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::future<bool>& Asset::open_url_async(const std::string& url,
|
||||||
|
std::function<bool(float)> progress /*= nullptr*/, std::function<void(bool)> complete /*= nullptr*/)
|
||||||
|
{
|
||||||
|
close_remote();
|
||||||
|
m_stop_async = false;
|
||||||
|
remote_future = std::async([this, url, progress, complete] {
|
||||||
|
bool ok = open_url(url, progress);
|
||||||
|
if (ok && complete)
|
||||||
|
complete(ok);
|
||||||
|
return ok;
|
||||||
|
});
|
||||||
|
return remote_future;
|
||||||
|
}
|
||||||
|
|
||||||
bool Asset::open(const char* path)
|
bool Asset::open(const char* path)
|
||||||
{
|
{
|
||||||
//LOG("Asset::open %s", path);
|
//LOG("Asset::open %s", path);
|
||||||
@@ -249,3 +322,18 @@ void Asset::close()
|
|||||||
m_fp = nullptr;
|
m_fp = nullptr;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Asset::close_remote()
|
||||||
|
{
|
||||||
|
if (remote_future.valid())
|
||||||
|
{
|
||||||
|
m_stop_async = true;
|
||||||
|
remote_future.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Asset::~Asset()
|
||||||
|
{
|
||||||
|
close_remote();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|||||||
12
src/asset.h
12
src/asset.h
@@ -13,13 +13,23 @@ public:
|
|||||||
static std::string absolute(const std::string& path);
|
static std::string absolute(const std::string& path);
|
||||||
static bool is_asset(const std::string& path);
|
static bool is_asset(const std::string& path);
|
||||||
static bool create_dir(const std::string& path);
|
static bool create_dir(const std::string& path);
|
||||||
|
|
||||||
|
bool m_stop_async = false;
|
||||||
|
std::function<bool(float)> on_progress;
|
||||||
|
std::future<bool> remote_future;
|
||||||
|
|
||||||
std::string m_current_path;
|
std::string m_current_path;
|
||||||
|
std::string m_current_url;
|
||||||
FILE* m_fp = nullptr;
|
FILE* m_fp = nullptr;
|
||||||
int m_len = 0;
|
int m_len = 0;
|
||||||
uint8_t* m_data = nullptr;
|
uint8_t* m_data = nullptr;
|
||||||
bool open(const char* path);
|
bool open(const char* path);
|
||||||
|
bool open_url(const std::string& url, std::function<bool(float)> progress = nullptr);
|
||||||
|
std::future<bool>& open_url_async(const std::string& url, std::function<bool(float)> progress = nullptr,
|
||||||
|
std::function<void(bool)> complete = nullptr);
|
||||||
uint8_t* read_all();
|
uint8_t* read_all();
|
||||||
void close();
|
void close();
|
||||||
~Asset() { close(); }
|
void close_remote();
|
||||||
|
~Asset();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -321,7 +321,8 @@ void Node::loaded()
|
|||||||
|
|
||||||
void Node::added(Node* parent)
|
void Node::added(Node* parent)
|
||||||
{
|
{
|
||||||
|
for (auto& c : m_children)
|
||||||
|
c->added(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::removed(Node* parent)
|
void Node::removed(Node* parent)
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ enum class kAttribute : uint16_t
|
|||||||
Justify = const_hash("justify"),
|
Justify = const_hash("justify"),
|
||||||
Align = const_hash("align"),
|
Align = const_hash("align"),
|
||||||
Path = const_hash("path"),
|
Path = const_hash("path"),
|
||||||
|
Url = const_hash("url"),
|
||||||
Region = const_hash("region"),
|
Region = const_hash("region"),
|
||||||
Position = const_hash("position"),
|
Position = const_hash("position"),
|
||||||
Positioning = const_hash("positioning"),
|
Positioning = const_hash("positioning"),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "node_image.h"
|
#include "node_image.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
Plane NodeImage::m_plane;
|
Plane NodeImage::m_plane;
|
||||||
Sampler NodeImage::m_sampler;
|
Sampler NodeImage::m_sampler;
|
||||||
@@ -30,6 +31,9 @@ void NodeImage::clone_copy(Node* dest) const
|
|||||||
n->m_sz = m_sz;
|
n->m_sz = m_sz;
|
||||||
n->m_path = m_path;
|
n->m_path = m_path;
|
||||||
n->m_tex_id = m_tex_id;
|
n->m_tex_id = m_tex_id;
|
||||||
|
n->m_url = m_url;
|
||||||
|
n->m_remote_texture = m_remote_texture;
|
||||||
|
n->m_autosize = m_autosize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeImage::create()
|
void NodeImage::create()
|
||||||
@@ -64,6 +68,9 @@ void NodeImage::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* at
|
|||||||
m_path = attr->Value();
|
m_path = attr->Value();
|
||||||
m_tex_id = const_hash(attr->Value());
|
m_tex_id = const_hash(attr->Value());
|
||||||
break;
|
break;
|
||||||
|
case kAttribute::Url:
|
||||||
|
m_url = attr->Value();
|
||||||
|
break;
|
||||||
case kAttribute::Region:
|
case kAttribute::Region:
|
||||||
{
|
{
|
||||||
glm::vec4 v;
|
glm::vec4 v;
|
||||||
@@ -85,9 +92,13 @@ void NodeImage::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* at
|
|||||||
|
|
||||||
void NodeImage::draw()
|
void NodeImage::draw()
|
||||||
{
|
{
|
||||||
|
m_remote_texture ?
|
||||||
|
m_remote_texture->bind() :
|
||||||
TextureManager::get(m_tex_id).bind();
|
TextureManager::get(m_tex_id).bind();
|
||||||
|
|
||||||
auto& sampler = m_use_mipmaps ? m_sampler_mips : m_sampler;
|
auto& sampler = m_use_mipmaps ? m_sampler_mips : m_sampler;
|
||||||
sampler.bind(0);
|
sampler.bind(0);
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
if (m_use_atlas)
|
if (m_use_atlas)
|
||||||
{
|
{
|
||||||
@@ -103,7 +114,6 @@ void NodeImage::draw()
|
|||||||
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp * glm::scale(glm::vec3(m_scale, 1.f)));
|
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp * glm::scale(glm::vec3(m_scale, 1.f)));
|
||||||
m_plane.draw_fill();
|
m_plane.draw_fill();
|
||||||
sampler.unbind();
|
sampler.unbind();
|
||||||
TextureManager::get(m_tex_id).unbind();
|
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,3 +132,36 @@ bool NodeImage::set_image(const std::string& path)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeImage::load_url(const std::string& url)
|
||||||
|
{
|
||||||
|
m_remote_asset = std::make_shared<Asset>();
|
||||||
|
m_remote_asset->open_url_async(url,
|
||||||
|
[this] (float progress) -> bool {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[this] (bool success) {
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
int w, h, c;
|
||||||
|
uint8_t* rgba = stbi_load_from_memory(m_remote_asset->m_data, m_remote_asset->m_len, &w, &h, &c, 4);
|
||||||
|
m_remote_texture = std::make_shared<Texture2D>();
|
||||||
|
m_remote_texture->create(w, h, GL_RGBA8, GL_RGBA, rgba);
|
||||||
|
m_remote_texture->auto_destroy = true;
|
||||||
|
if (m_use_mipmaps)
|
||||||
|
m_remote_texture->create_mipmaps();
|
||||||
|
delete rgba;
|
||||||
|
if (m_autosize)
|
||||||
|
SetAspectRatio(w / h);
|
||||||
|
}
|
||||||
|
m_remote_asset.reset();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeImage::added(Node* parent)
|
||||||
|
{
|
||||||
|
Node::added(parent);
|
||||||
|
if (!m_url.empty() && root() == App::I->layout.get(App::I->main_id))
|
||||||
|
load_url(m_url);
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,7 +17,10 @@ public:
|
|||||||
glm::vec2 m_sz;
|
glm::vec2 m_sz;
|
||||||
glm::vec2 m_scale = { 1.f, 1.f };
|
glm::vec2 m_scale = { 1.f, 1.f };
|
||||||
std::string m_path;
|
std::string m_path;
|
||||||
|
std::string m_url;
|
||||||
uint16_t m_tex_id;
|
uint16_t m_tex_id;
|
||||||
|
std::shared_ptr<Asset> m_remote_asset;
|
||||||
|
std::shared_ptr<Texture2D> m_remote_texture;
|
||||||
static void static_init();
|
static void static_init();
|
||||||
virtual Node* clone_instantiate() const override;
|
virtual Node* clone_instantiate() const override;
|
||||||
virtual void clone_copy(Node* dest) const override;
|
virtual void clone_copy(Node* dest) const override;
|
||||||
@@ -25,5 +28,7 @@ public:
|
|||||||
virtual void restore_context() override;
|
virtual void restore_context() override;
|
||||||
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
|
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
|
||||||
virtual void draw() override;
|
virtual void draw() override;
|
||||||
|
virtual void added(Node* parent) override;
|
||||||
bool set_image(const std::string& path);
|
bool set_image(const std::string& path);
|
||||||
|
void load_url(const std::string& url);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user