#include "pch.h" #include "log.h" #include "node_image.h" #include "renderer_gl/opengl_capabilities.h" #include "shader.h" #include "app.h" Plane NodeImage::m_plane; Sampler NodeImage::m_sampler; Sampler NodeImage::m_sampler_mips; void NodeImage::static_init() { m_plane.create<1>(1, 1); m_sampler.create(); m_sampler_mips.create(); m_sampler_mips.set_filter( pp::renderer::gl::linear_mipmap_linear_texture_filter(), pp::renderer::gl::linear_texture_filter()); } Node* NodeImage::clone_instantiate() const { return new NodeImage(); } void NodeImage::clone_copy(Node* dest) const { Node::clone_copy(dest); NodeImage* n = static_cast(dest); n->m_use_atlas = m_use_atlas; n->m_region = m_region; n->m_off = m_off; n->m_sz = m_sz; n->m_path = m_path; 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() { Node::create(); if (!m_path.empty() && TextureManager::load(m_path.c_str(), m_use_mipmaps)) { //LOG("load image node %s", m_path.c_str()); auto tex_sz = TextureManager::get(m_tex_id).size(); m_off = xy(m_region) / tex_sz; m_sz = (zw(m_region) - xy(m_region)) / tex_sz; if (m_autosize) SetAspectRatio(tex_sz.x / tex_sz.y); } } void NodeImage::restore_context() { Node::restore_context(); create(); } void NodeImage::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) { Node::parse_attributes(ka, attr); switch (ka) { case kAttribute::Mips: m_use_mipmaps = attr->BoolValue(); break; case kAttribute::Path: m_path = attr->Value(); m_tex_id = const_hash(attr->Value()); break; case kAttribute::Url: m_url = attr->Value(); break; case kAttribute::Region: { glm::vec4 v; int n = sscanf(attr->Value(), "%f %f %f %f", &v.x, &v.y, &v.z, &v.w); if (n == 4) { m_region = v; m_use_atlas = true; } break; } case kAttribute::AutoSize: m_autosize = attr->BoolValue(); break; default: break; } } void NodeImage::draw() { m_remote_texture ? m_remote_texture->bind() : TextureManager::get(m_tex_id).bind(); auto& sampler = m_use_mipmaps ? m_sampler_mips : m_sampler; sampler.bind(0); glEnable(pp::renderer::gl::blend_state()); if (m_use_atlas) { ShaderManager::use(kShader::Atlas); ShaderManager::u_vec2(kShaderUniform::Tof, m_off); ShaderManager::u_vec2(kShaderUniform::Tsz, m_sz); } else { ShaderManager::use(kShader::Texture); } ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp * glm::scale(glm::vec3(m_scale, 1.f))); m_plane.draw_fill(); sampler.unbind(); glDisable(pp::renderer::gl::blend_state()); } bool NodeImage::set_image(const std::string& path) { m_path = path; m_tex_id = const_hash(path.c_str()); if (!m_path.empty() && TextureManager::load(m_path.c_str(), m_use_mipmaps)) { auto tex_sz = TextureManager::get(m_tex_id).size(); m_off = xy(m_region) / tex_sz; m_sz = (zw(m_region) - xy(m_region)) / tex_sz; if (m_autosize) SetAspectRatio(tex_sz.x / tex_sz.y); return true; } return false; } void NodeImage::load_url(const std::string& url) { m_remote_header_decoded = false; m_remote_asset = std::make_shared(); m_remote_asset->open_url_async(url, [this] (float progress) -> bool { int w, h, c; if (!m_remote_header_decoded && stbi_info_from_memory(m_remote_asset->tmp_data.data(), m_remote_asset->tmp_data.size(), &w, &h, &c)) { if (m_autosize) SetAspectRatio((float)w / (float)h); m_remote_header_decoded = true; } 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(); m_remote_texture->create( w, h, pp::renderer::gl::rgba8_internal_format(), pp::renderer::gl::rgba_pixel_format(), rgba); if (m_use_mipmaps) m_remote_texture->create_mipmaps(); delete rgba; if (m_autosize) SetAspectRatio((float)w / (float)h); } m_remote_asset.reset(); } ); } void NodeImage::added(Node* parent) { Node::added(parent); if (!m_url.empty() && added_to_root()) load_url(m_url); }