diff --git a/data/icons.png b/data/icons.png new file mode 100644 index 0000000..97b6ba1 Binary files /dev/null and b/data/icons.png differ diff --git a/data/layout.xml b/data/layout.xml index bfd31cb..0cbb5b1 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -34,12 +34,24 @@ - + - - - + + + + + + + + + + + + + + + @@ -66,11 +78,13 @@ + + diff --git a/data/social.png b/data/social.png new file mode 100644 index 0000000..fd23a04 Binary files /dev/null and b/data/social.png differ diff --git a/engine/app.cpp b/engine/app.cpp index c93d968..5edde5f 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -38,6 +38,26 @@ void App::init() "void main(){" " frag = vec4(uv.xy,0,1);" "}"; + static const char* shader_atlas_v = + "#version 150\n" + "uniform mat4 mvp;" + "uniform vec2 tof;" + "uniform vec2 tsz;" + "in vec2 pos;" + "in vec2 uvs;" + "out vec2 uv;" + "void main(){" + " uv = tof + uvs * tsz;" + " gl_Position = mvp * vec4(pos, 0, 1);" + "}"; + static const char* shader_atlas_f = + "#version 150\n" + "uniform sampler2D tex;" + "in vec2 uv;" + "out vec4 frag;" + "void main(){" + " frag = texture(tex, uv);" + "}"; static const char* shader_color_v = "#version 150\n" "uniform mat4 mvp;" @@ -99,7 +119,7 @@ void App::init() const char* ttf = "/Library/Fonts/Arial.ttf"; #endif FontManager::init(); - FontManager::load(kFont::Arial_11, ttf, 13); + FontManager::load(kFont::Arial_11, ttf, 15); FontManager::load(kFont::Arial_30, ttf, 30); layout.load("data/layout.xml"); @@ -110,7 +130,9 @@ void App::init() ShaderManager::create(kShader::Color, shader_color_v, shader_color_f); ShaderManager::create(kShader::UVs, shader_v, shader_uv_f); ShaderManager::create(kShader::Font, shader_font_v, shader_font_f); - WidgetBorder::m_plane.create<1>(1, 1); + ShaderManager::create(kShader::Atlas, shader_atlas_v, shader_atlas_f); + WidgetBorder::init(); + WidgetImage::init(); if (!tex.load("data/uvs.jpg")) printf("error loading image\n"); diff --git a/engine/image.cpp b/engine/image.cpp index de117c0..2a9f860 100644 --- a/engine/image.cpp +++ b/engine/image.cpp @@ -5,7 +5,7 @@ bool Image::load(std::string filename) { - stbi_set_flip_vertically_on_load(true); + //stbi_set_flip_vertically_on_load(true); uint8_t* buffer = stbi_load(filename.c_str(), &width, &height, nullptr, 4); comp = 4; m_data = std::unique_ptr(buffer); diff --git a/engine/layout.cpp b/engine/layout.cpp index edb6201..93214c4 100644 --- a/engine/layout.cpp +++ b/engine/layout.cpp @@ -3,6 +3,8 @@ #include "util.h" Plane WidgetBorder::m_plane; +Plane WidgetImage::m_plane; +Sampler WidgetImage::m_sampler; void Node::update(float width, float height) { @@ -221,6 +223,9 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node) case kWidget::Text: m_widget = std::make_unique(); break; + case kWidget::Image: + m_widget = std::make_unique(); + break; } while (attr) diff --git a/engine/layout.h b/engine/layout.h index 72cc0b3..41fdbee 100644 --- a/engine/layout.h +++ b/engine/layout.h @@ -31,6 +31,8 @@ enum class kAttribute : uint16_t FontSize = const_hash("font-size"), Justify = const_hash("justify"), Align = const_hash("align"), + Path = const_hash("path"), + Region = const_hash("region"), }; enum class kWidget : uint16_t @@ -38,6 +40,7 @@ enum class kWidget : uint16_t Border = const_hash("border"), Shape = const_hash("shape"), Text = const_hash("text"), + Image = const_hash("image"), Ref = const_hash("ref"), }; @@ -80,6 +83,10 @@ public: glm::vec4 m_color; glm::vec4 m_border_color; float m_thinkness{ 1 }; + static void init() + { + m_plane.create<1>(1, 1); + } virtual std::unique_ptr clone() override { auto ret = std::make_unique(); @@ -281,6 +288,82 @@ public: } }; +class WidgetImage : public Widget +{ +public: + static Plane m_plane; + static Sampler m_sampler; + bool m_use_atlas; + glm::vec4 m_region; + glm::vec2 m_off; + glm::vec2 m_sz; + std::string m_path; + uint16_t m_id; + static void init() + { + m_plane.create<1>(1, 1); + m_sampler.create(); + } + virtual std::unique_ptr clone() override + { + auto ret = std::make_unique(); + *ret = *this; + return std::move(ret); + } + virtual void create() override + { + if (TextureManager::load(m_path.c_str())) + { + auto tex_sz = TextureManager::get(m_id).size(); + m_off = m_region.xy / tex_sz; + m_sz = (m_region.zw - m_region.xy) / tex_sz; + } + } + virtual void draw() override + { + TextureManager::get(m_id).bind(); + m_sampler.bind(0); + 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, mvp); + m_plane.draw_fill(); + m_sampler.unbind(); + TextureManager::get(m_id).unbind(); + } + virtual void parse_attributes(kAttribute id, const tinyxml2::XMLAttribute* attr) override + { + switch (id) + { + case kAttribute::Path: + m_path = attr->Value(); + m_id = const_hash(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; + } + default: + break; + } + } +}; + class Node { friend class LayoutManager; diff --git a/engine/shader.h b/engine/shader.h index 5bcb5ec..257ae81 100644 --- a/engine/shader.h +++ b/engine/shader.h @@ -6,8 +6,8 @@ enum class kShaderUniform : uint16_t MVP = const_hash("mvp"), Tex = const_hash("tex"), Col = const_hash("col"), - Tof = const_hash("texoff"), - Tsz = const_hash("texsz"), + Tof = const_hash("tof"), + Tsz = const_hash("tsz"), }; class Shader @@ -29,6 +29,7 @@ enum class kShader : uint16_t Texture = const_hash("texture"), UVs = const_hash("uvs"), Font = const_hash("font"), + Atlas = const_hash("atlas"), }; class ShaderManager diff --git a/engine/texture.cpp b/engine/texture.cpp index 63a0304..807cb2a 100644 --- a/engine/texture.cpp +++ b/engine/texture.cpp @@ -1,6 +1,24 @@ #include "pch.h" #include "texture.h" #include "image.h" +#include "util.h" + +std::map TextureManager::m_textures; + +bool TextureManager::load(const char* path) +{ + uint16_t id = const_hash(path); + if (m_textures.count(id) == 0 || !m_textures[id].ready()) + { + return m_textures[id].load(path); + } + return true; +} + +Texture2D& TextureManager::get(uint16_t id) +{ + return m_textures[id]; +} bool Texture2D::create(int width, int height, GLint format, const uint8_t* data) { @@ -31,6 +49,11 @@ void Texture2D::update(const uint8_t* data) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, m_format, GL_UNSIGNED_BYTE, data); } +glm::vec2 Texture2D::size() const +{ + return { m_width, m_height }; +} + bool Sampler::create(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*/) { glGenSamplers(1, &id); @@ -55,3 +78,4 @@ void Sampler::unbind() { glBindSampler(current_unit, 0); } + diff --git a/engine/texture.h b/engine/texture.h index 165c2a8..fa119ad 100644 --- a/engine/texture.h +++ b/engine/texture.h @@ -15,6 +15,7 @@ public: void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } void update(const uint8_t* data); bool ready() const { return m_tex != 0; } + glm::vec2 size() const; }; class Sampler @@ -28,3 +29,11 @@ public: void unbind(); bool ready() const { return id != 0; } }; + +class TextureManager +{ +public: + static std::map m_textures; + static bool load(const char* path); + static Texture2D& get(uint16_t id); +};