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);
+};