#ifndef BLOBS_APP_ASSETS_HPP_
#define BLOBS_APP_ASSETS_HPP_
+#include "../graphics/AlphaSprite.hpp"
#include "../graphics/ArrayTexture.hpp"
#include "../graphics/CreatureSkin.hpp"
+#include "../graphics/Font.hpp"
+#include "../graphics/PlainColor.hpp"
#include "../graphics/PlanetSurface.hpp"
#include "../graphics/SunSurface.hpp"
#include "../world/Resource.hpp"
std::string path;
std::string data_path;
+ std::string font_path;
std::string skin_path;
std::string tile_path;
world::Set<world::TileType> tiles;
} data;
+ struct {
+ graphics::Font large;
+ graphics::Font medium;
+ graphics::Font small;
+ } fonts;
+
struct {
graphics::ArrayTexture tiles;
graphics::ArrayTexture skins;
} textures;
struct {
+ graphics::AlphaSprite alpha_sprite;
+ graphics::PlainColor plain_color;
graphics::PlanetSurface planet_surface;
graphics::SunSurface sun_surface;
graphics::CreatureSkin creature_skin;
#include "Assets.hpp"
#include "../graphics/Camera.hpp"
+#include "../ui/CreaturePanel.hpp"
namespace blobs {
graphics::Camera &GetCamera() noexcept { return cam; }
const graphics::Camera &GetCamera() const noexcept { return cam; }
+ ui::CreaturePanel &GetCreaturePanel() noexcept { return cp; }
+ const ui::CreaturePanel &GetCreaturePanel() const noexcept { return cp; }
+
private:
void OnResize(int w, int h) override;
world::Simulation ∼
graphics::Camera cam;
+ ui::CreaturePanel cp;
int remain;
int thirds;
Assets::Assets()
: path("assets/")
, data_path(path + "data/")
+, font_path(path + "fonts/")
, skin_path(path + "skins/")
-, tile_path(path + "tiles/") {
+, tile_path(path + "tiles/")
+, fonts{
+ graphics::Font(font_path + "DejaVuSans.ttf", 32),
+ graphics::Font(font_path + "DejaVuSans.ttf", 24),
+ graphics::Font(font_path + "DejaVuSans.ttf", 16)
+} {
{
std::ifstream resource_file(data_path + "resources");
io::TokenStreamReader resource_reader(resource_file);
ReadTileTypes(tile_reader);
}
+
graphics::Format format;
textures.tiles.Bind();
textures.tiles.Reserve(256, 256, 14, format);
#include "MasterState.hpp"
#include "../creature/Creature.hpp"
+#include "../graphics/Viewport.hpp"
#include "../world/Body.hpp"
#include "../world/Planet.hpp"
#include "../world/Simulation.hpp"
, assets(assets)
, sim(sim)
, cam(sim.Root())
+, cp(assets)
, remain(0)
, thirds(0)
, paused(false) {
void MasterState::OnResize(int w, int h) {
+ assets.shaders.plain_color.Activate();
+ assets.shaders.plain_color.SetVP(glm::mat4(1.0f), glm::ortho(0.0f, float(w), float(h), 0.0f, 1.0e4f, -1.0e4f));
+ assets.shaders.alpha_sprite.Activate();
+ assets.shaders.alpha_sprite.SetVP(glm::mat4(1.0f), glm::ortho(0.0f, float(w), float(h), 0.0f, 1.0e4f, -1.0e4f));
+
cam.Aspect(float(w), float(h));
+ assets.shaders.planet_surface.Activate();
+ assets.shaders.planet_surface.SetVP(cam.View(), cam.Projection());
+ assets.shaders.sun_surface.Activate();
+ assets.shaders.sun_surface.SetVP(cam.View(), cam.Projection());
+ assets.shaders.creature_skin.Activate();
+ assets.shaders.creature_skin.SetVP(cam.View(), cam.Projection());
}
void MasterState::OnUpdate(int dt) {
}
void MasterState::OnRender(graphics::Viewport &viewport) {
-
int num_lights = 0;
for (auto sun : sim.Suns()) {
// TODO: source sun's light color and strength
assets.shaders.planet_surface.Activate();
assets.shaders.planet_surface.SetTexture(assets.textures.tiles);
for (auto planet : sim.Planets()) {
- assets.shaders.planet_surface.SetMVP(cam.Model(*planet), cam.View(), cam.Projection());
+ assets.shaders.planet_surface.SetM(cam.Model(*planet));
planet->Draw(assets, viewport);
}
assets.shaders.sun_surface.Activate();
for (auto sun : sim.Suns()) {
double sun_radius = sun->Radius();
- assets.shaders.sun_surface.SetMVP(
- cam.Model(*sun) * glm::scale(glm::vec3(sun_radius, sun_radius, sun_radius)),
- cam.View(), cam.Projection());
+ assets.shaders.sun_surface.SetM(
+ cam.Model(*sun) * glm::scale(glm::vec3(sun_radius, sun_radius, sun_radius)));
assets.shaders.sun_surface.SetLight(glm::vec3(1.0f, 1.0f, 1.0f), 1.0e6f);
assets.shaders.sun_surface.Draw();
}
assets.shaders.creature_skin.SetTexture(assets.textures.skins);
// TODO: extend to nearby bodies as well
for (auto c : cam.Reference().Creatures()) {
- assets.shaders.creature_skin.SetMVP(cam.Model(c->GetBody()) * glm::mat4(c->LocalTransform()), cam.View(), cam.Projection());
+ assets.shaders.creature_skin.SetM(cam.Model(c->GetBody()) * glm::mat4(c->LocalTransform()));
c->Draw(assets, viewport);
}
+
+ viewport.ClearDepth();
+ cp.Draw(assets, viewport);
}
}
std::cout << "moon cycles per year: " << (planet.OrbitalPeriod() / moon.OrbitalPeriod()) << std::endl;
auto blob = new creature::Creature;
- blob->BuildVAO();
Spawn(*blob, planet, assets);
+ blob->BuildVAO();
+ blob->Name("Blob");
app::MasterState state(assets, sim);
state.GetCamera()
// .Reference(sun)
// .Orbital(glm::vec3(-500.0f, 500.0f, 500.0f))
//;
+ state.GetCreaturePanel().Show(*blob);
app::Application app(init.window, init.viewport);
app.PushState(&state);
--- /dev/null
+#ifndef BLOBS_GRAPHICS_ALPHASPRITE_HPP_
+#define BLOBS_GRAPHICS_ALPHASPRITE_HPP_
+
+#include "Program.hpp"
+#include "SimpleVAO.hpp"
+
+#include "glm.hpp"
+
+#include <cstdint>
+
+
+namespace blobs {
+namespace graphics {
+
+class Texture;
+
+class AlphaSprite {
+
+public:
+ AlphaSprite();
+ ~AlphaSprite();
+
+ AlphaSprite(const AlphaSprite &) = delete;
+ AlphaSprite &operator =(const AlphaSprite &) = delete;
+
+ AlphaSprite(AlphaSprite &&) = delete;
+ AlphaSprite &operator =(AlphaSprite &&) = delete;
+
+public:
+ void Activate() noexcept;
+
+ void SetM(const glm::mat4 &m) noexcept;
+ void SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept;
+ void SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept;
+ void SetTexture(Texture &) noexcept;
+ void SetFgColor(const glm::vec4 &) noexcept;
+ void SetBgColor(const glm::vec4 &) noexcept;
+
+ const glm::mat4 &M() const noexcept { return m; }
+ const glm::mat4 &V() const noexcept { return v; }
+ const glm::mat4 &P() const noexcept { return p; }
+ const glm::mat4 &MV() const noexcept { return mv; }
+ const glm::mat4 &MVP() const noexcept { return mvp; }
+
+ void DrawRect() const noexcept;
+
+private:
+ struct Attributes {
+ glm::vec3 position;
+ glm::vec2 texture;
+ };
+ SimpleVAO<Attributes, std::uint8_t> vao;
+ Program prog;
+
+ glm::mat4 m;
+ glm::mat4 v;
+ glm::mat4 p;
+ glm::mat4 mv;
+ glm::mat4 mvp;
+
+ GLuint m_handle;
+ GLuint mv_handle;
+ GLuint mvp_handle;
+
+ GLuint sampler_handle;
+ GLuint fg_color_handle;
+ GLuint bg_color_handle;
+
+};
+
+}
+}
+
+#endif
public:
void Activate() noexcept;
+ void SetM(const glm::mat4 &m) noexcept;
+ void SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept;
void SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept;
void SetTexture(ArrayTexture &) noexcept;
void SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept;
#include "glm.hpp"
+#include <string>
#include <SDL_ttf.h>
};
public:
+ Font(const std::string &src, int size, long index = 0);
Font(const char *src, int size, long index = 0);
~Font();
bool HasGlyph(Uint16) const noexcept;
glm::ivec2 TextSize(const char *) const;
+ glm::ivec2 TextSize(const std::string &) const;
Texture Render(const char *) const;
+ Texture Render(const std::string &) const;
void Render(const char *, Texture &) const;
+ void Render(const std::string &, Texture &) const;
private:
TTF_Font *handle;
--- /dev/null
+#ifndef BLOBS_GRAPHICS_PLAINCOLOR_HPP_
+#define BLOBS_GRAPHICS_PLAINCOLOR_HPP_
+
+#include "Program.hpp"
+#include "SimpleVAO.hpp"
+
+#include "glm.hpp"
+
+#include <cstdint>
+
+
+namespace blobs {
+namespace graphics {
+
+class PlainColor {
+
+public:
+ PlainColor();
+ ~PlainColor();
+
+ PlainColor(const PlainColor &) = delete;
+ PlainColor &operator =(const PlainColor &) = delete;
+
+ PlainColor(PlainColor &&) = delete;
+ PlainColor &operator =(PlainColor &&) = delete;
+
+public:
+ void Activate() noexcept;
+
+ void SetM(const glm::mat4 &m) noexcept;
+ void SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept;
+ void SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept;
+ void SetColor(const glm::vec3 &color) noexcept;
+
+ const glm::mat4 &M() const noexcept { return m; }
+ const glm::mat4 &V() const noexcept { return v; }
+ const glm::mat4 &P() const noexcept { return p; }
+ const glm::mat4 &MV() const noexcept { return mv; }
+ const glm::mat4 &MVP() const noexcept { return mvp; }
+
+ void DrawRect() const noexcept;
+ void OutlineRect() const noexcept;
+
+private:
+ struct Attributes {
+ glm::vec3 position;
+ };
+ SimpleVAO<Attributes, std::uint8_t> vao;
+ Program prog;
+
+ glm::mat4 m;
+ glm::mat4 v;
+ glm::mat4 p;
+ glm::mat4 mv;
+ glm::mat4 mvp;
+
+ GLuint m_handle;
+ GLuint mv_handle;
+ GLuint mvp_handle;
+
+ GLuint fg_color_handle;
+
+};
+
+}
+}
+
+#endif
public:
void Activate() noexcept;
+ void SetM(const glm::mat4 &m) noexcept;
+ void SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept;
void SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept;
void SetNormal(const glm::vec3 &) noexcept;
void SetTexture(ArrayTexture &) noexcept;
MappedBuffer<Element> MapElements(GLenum access) {
return MappedBuffer<Element>(GL_ELEMENT_ARRAY_BUFFER, access);
}
+ void Draw(GLenum mode, std::size_t size, std::size_t offset = 0) const noexcept {
+ glDrawElements(mode, size, gl_traits<Element>::type, ((Element *) nullptr) + offset);
+ }
void DrawTriangles(std::size_t size, std::size_t offset = 0) const noexcept {
- glDrawElements(GL_TRIANGLES, size, gl_traits<Element>::type, ((Element *) nullptr) + offset);
+ Draw(GL_TRIANGLES, size, offset);
+ }
+ void DrawTriangleStrip(std::size_t size, std::size_t offset = 0) const noexcept {
+ Draw(GL_TRIANGLE_STRIP, size, offset);
+ }
+ void DrawLineLoop(std::size_t size, std::size_t offset = 0) const noexcept {
+ Draw(GL_LINE_LOOP, size, offset);
}
private:
public:
void Activate() noexcept;
+ void SetM(const glm::mat4 &m) noexcept;
+ void SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept;
void SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept;
void SetLight(const glm::vec3 &color, float strength) noexcept;
public:
GLsizei Width() const noexcept { return width; }
GLsizei Height() const noexcept { return height; }
+ glm::vec2 Size() const noexcept { return glm::vec2(width, height); }
void Data(const SDL_Surface &, bool pad2 = true) noexcept;
void Data(GLsizei w, GLsizei h, const Format &, GLvoid *data) noexcept;
void Resize(int w, int h);
void Clear();
+ void ClearDepth();
private:
int width;
namespace blobs {
namespace graphics {
+Font::Font(const std::string &src, int size, long index)
+: Font(src.c_str(), size, index) {
+}
+
Font::Font(const char *src, int size, long index)
: handle(TTF_OpenFontIndex(src, size, index)) {
if (!handle) {
return size;
}
+glm::ivec2 Font::TextSize(const std::string &text) const {
+ return TextSize(text.c_str());
+}
+
Texture Font::Render(const char *text) const {
Texture tex;
Render(text, tex);
return tex;
}
+Texture Font::Render(const std::string &text) const {
+ return Render(text.c_str());
+}
+
void Font::Render(const char *text, Texture &tex) const {
SDL_Surface *srf = TTF_RenderUTF8_Blended(handle, text, { 0xFF, 0xFF, 0xFF, 0xFF });
if (!srf) {
SDL_FreeSurface(srf);
}
+void Font::Render(const std::string &text, Texture &tex) const {
+ Render(text.c_str(), tex);
+}
+
Format::Format() noexcept
: format(GL_BGRA)
, type(GL_UNSIGNED_INT_8_8_8_8_REV)
+#include "AlphaSprite.hpp"
#include "CreatureSkin.hpp"
+#include "PlainColor.hpp"
#include "PlanetSurface.hpp"
#include "Program.hpp"
#include "Shader.hpp"
#include "SunSurface.hpp"
#include "ArrayTexture.hpp"
+#include "Texture.hpp"
#include "../app/init.hpp"
#include <algorithm>
glDisable(GL_BLEND);
}
+void PlanetSurface::SetM(const glm::mat4 &mm) noexcept {
+ m = mm;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(m_handle, m);
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
+void PlanetSurface::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
+ v = vv;
+ p = pp;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
void PlanetSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
m = mm;
v = vv;
glDisable(GL_BLEND);
}
+void SunSurface::SetM(const glm::mat4 &mm) noexcept {
+ m = mm;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(m_handle, m);
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
+void SunSurface::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
+ v = vv;
+ p = pp;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
void SunSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
m = mm;
v = vv;
glDisable(GL_BLEND);
}
+void CreatureSkin::SetM(const glm::mat4 &mm) noexcept {
+ m = mm;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(m_handle, m);
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
+void CreatureSkin::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
+ v = vv;
+ p = pp;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
void CreatureSkin::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
m = mm;
v = vv;
prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
}
+
+PlainColor::PlainColor()
+: prog() {
+ prog.LoadShader(
+ GL_VERTEX_SHADER,
+ "#version 330 core\n"
+
+ "layout(location = 0) in vec3 vtx_position;\n"
+
+ "uniform mat4 M;\n"
+ "uniform mat4 MV;\n"
+ "uniform mat4 MVP;\n"
+
+ "void main() {\n"
+ "gl_Position = MVP * vec4(vtx_position, 1);\n"
+ "}\n"
+ );
+ prog.LoadShader(
+ GL_FRAGMENT_SHADER,
+ "#version 330 core\n"
+
+ "uniform vec3 fg_color;\n"
+
+ "out vec3 color;\n"
+
+ "void main() {\n"
+ "color = fg_color;\n"
+ "}\n"
+ );
+ prog.Link();
+ if (!prog.Linked()) {
+ prog.Log(std::cerr);
+ throw std::runtime_error("link program");
+ }
+ m_handle = prog.UniformLocation("M");
+ mv_handle = prog.UniformLocation("MV");
+ mvp_handle = prog.UniformLocation("MVP");
+ fg_color_handle = prog.UniformLocation("fg_color");
+
+ vao.Bind();
+ vao.BindAttributes();
+ vao.EnableAttribute(0);
+ vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
+ vao.ReserveAttributes(4, GL_STATIC_DRAW);
+ {
+ auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
+ attrib[0].position = glm::vec3(-1.0f, -1.0f, 0.0f);
+ attrib[1].position = glm::vec3(-1.0f, 1.0f, 0.0f);
+ attrib[2].position = glm::vec3( 1.0f, -1.0f, 0.0f);
+ attrib[3].position = glm::vec3( 1.0f, 1.0f, 0.0f);
+ }
+ vao.BindElements();
+ vao.ReserveElements(7, GL_STATIC_DRAW);
+ {
+ auto element = vao.MapElements(GL_WRITE_ONLY);
+ element[ 0] = 0;
+ element[ 1] = 3;
+ element[ 2] = 2;
+ element[ 3] = 0;
+ element[ 4] = 1;
+ element[ 5] = 3;
+ element[ 6] = 2;
+ }
+ vao.Unbind();
+}
+
+PlainColor::~PlainColor() {
+}
+
+void PlainColor::Activate() noexcept {
+ prog.Use();
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+}
+
+void PlainColor::SetM(const glm::mat4 &mm) noexcept {
+ m = mm;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(m_handle, m);
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
+void PlainColor::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
+ v = vv;
+ p = pp;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
+void PlainColor::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
+ m = mm;
+ v = vv;
+ p = pp;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(m_handle, m);
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
+void PlainColor::SetColor(const glm::vec3 &color) noexcept {
+ prog.Uniform(fg_color_handle, color);
+}
+
+void PlainColor::DrawRect() const noexcept {
+ vao.Bind();
+ vao.DrawTriangles(6);
+}
+
+void PlainColor::OutlineRect() const noexcept {
+ vao.Bind();
+ vao.DrawLineLoop(4, 3);
+}
+
+
+AlphaSprite::AlphaSprite()
+: prog() {
+ prog.LoadShader(
+ GL_VERTEX_SHADER,
+ "#version 330 core\n"
+
+ "layout(location = 0) in vec3 vtx_position;\n"
+ "layout(location = 1) in vec2 vtx_texture;\n"
+
+ "uniform mat4 M;\n"
+ "uniform mat4 MV;\n"
+ "uniform mat4 MVP;\n"
+
+ "out vec2 frag_tex_uv;\n"
+
+ "void main() {\n"
+ "gl_Position = MVP * vec4(vtx_position, 1);\n"
+ "frag_tex_uv = vtx_texture;\n"
+ "}\n"
+ );
+ prog.LoadShader(
+ GL_FRAGMENT_SHADER,
+ "#version 330 core\n"
+
+ "in vec2 frag_tex_uv;\n"
+
+ "uniform sampler2D tex_sampler;\n"
+ "uniform vec4 fg_color;\n"
+ "uniform vec4 bg_color;\n"
+
+ "out vec4 color;\n"
+
+ "void main() {\n"
+ "vec4 tex_color = texture(tex_sampler, frag_tex_uv);\n"
+ "vec4 factor = mix(bg_color, fg_color, tex_color.a);\n"
+ "color = vec4((tex_color * factor).rgb, factor.a);\n"
+ "}\n"
+ );
+ prog.Link();
+ if (!prog.Linked()) {
+ prog.Log(std::cerr);
+ throw std::runtime_error("link program");
+ }
+ m_handle = prog.UniformLocation("M");
+ mv_handle = prog.UniformLocation("MV");
+ mvp_handle = prog.UniformLocation("MVP");
+ sampler_handle = prog.UniformLocation("tex_sampler");
+ fg_color_handle = prog.UniformLocation("fg_color");
+ bg_color_handle = prog.UniformLocation("bg_color");
+
+ vao.Bind();
+ vao.BindAttributes();
+ vao.EnableAttribute(0);
+ vao.EnableAttribute(1);
+ vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
+ vao.AttributePointer<glm::vec2>(1, false, offsetof(Attributes, texture));
+ vao.ReserveAttributes(4, GL_STATIC_DRAW);
+ {
+ auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
+ attrib[0].position = glm::vec3(-1.0f, -1.0f, 0.0f);
+ attrib[0].texture = glm::vec2(0.0f, 0.0f);
+ attrib[1].position = glm::vec3(-1.0f, 1.0f, 0.0f);
+ attrib[1].texture = glm::vec2(0.0f, 1.0f);
+ attrib[2].position = glm::vec3( 1.0f, -1.0f, 0.0f);
+ attrib[2].texture = glm::vec2(1.0f, 0.0f);
+ attrib[3].position = glm::vec3( 1.0f, 1.0f, 0.0f);
+ attrib[3].texture = glm::vec2(1.0f, 1.0f);
+ }
+ vao.BindElements();
+ vao.ReserveElements(7, GL_STATIC_DRAW);
+ {
+ auto element = vao.MapElements(GL_WRITE_ONLY);
+ element[ 0] = 0;
+ element[ 1] = 1;
+ element[ 2] = 2;
+ element[ 3] = 3;
+ }
+ vao.Unbind();
+}
+
+AlphaSprite::~AlphaSprite() {
+}
+
+void AlphaSprite::Activate() noexcept {
+ prog.Use();
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+void AlphaSprite::SetM(const glm::mat4 &mm) noexcept {
+ m = mm;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(m_handle, m);
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
+void AlphaSprite::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
+ v = vv;
+ p = pp;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
+void AlphaSprite::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
+ m = mm;
+ v = vv;
+ p = pp;
+ mv = v * m;
+ mvp = p * mv;
+ prog.Uniform(m_handle, m);
+ prog.Uniform(mv_handle, mv);
+ prog.Uniform(mvp_handle, mvp);
+}
+
+void AlphaSprite::SetTexture(Texture &tex) noexcept {
+ glActiveTexture(GL_TEXTURE0);
+ tex.Bind();
+ prog.Uniform(sampler_handle, GLint(0));
+}
+
+void AlphaSprite::SetFgColor(const glm::vec4 &color) noexcept {
+ prog.Uniform(fg_color_handle, color);
+}
+
+void AlphaSprite::SetBgColor(const glm::vec4 &color) noexcept {
+ prog.Uniform(bg_color_handle, color);
+}
+
+void AlphaSprite::DrawRect() const noexcept {
+ vao.Bind();
+ vao.DrawTriangleStrip(4);
+}
+
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
+void Viewport::ClearDepth() {
+ glClear(GL_DEPTH_BUFFER_BIT);
+}
+
}
}
--- /dev/null
+#ifndef BLOBS_UI_CREATUREPANEL_HPP_
+#define BLOBS_UI_CREATUREPANEL_HPP_
+
+#include "Label.hpp"
+
+
+namespace blobs {
+namespace app {
+ struct Assets;
+}
+namespace creature {
+ class Creature;
+}
+namespace graphics {
+ class Viewport;
+}
+namespace ui {
+
+class CreaturePanel {
+
+public:
+ explicit CreaturePanel(const app::Assets &);
+ ~CreaturePanel();
+
+ CreaturePanel(const CreaturePanel &) = delete;
+ CreaturePanel &operator =(const CreaturePanel &) = delete;
+
+ CreaturePanel(CreaturePanel &&) = delete;
+ CreaturePanel &operator =(CreaturePanel &&) = delete;
+
+public:
+ void Show(creature::Creature &);
+ void Hide() noexcept;
+
+ void Draw(app::Assets &, graphics::Viewport &) noexcept;
+
+private:
+ creature::Creature *c;
+
+ Label name;
+
+};
+
+}
+}
+
+#endif
--- /dev/null
+#ifndef BLOBS_UI_LABEL_HPP_
+#define BLOBS_UI_LABEL_HPP_
+
+#include "align.hpp"
+#include "../graphics/Texture.hpp"
+
+#include <string>
+
+
+namespace blobs {
+namespace app {
+ struct Assets;
+}
+namespace graphics {
+ class Font;
+ class Viewport;
+}
+namespace ui {
+
+class Label {
+
+public:
+ explicit Label(const graphics::Font &);
+ ~Label();
+
+ Label(const Label &) = delete;
+ Label &operator =(const Label &) = delete;
+
+ Label(Label &&) = delete;
+ Label &operator =(Label &&) = delete;
+
+public:
+ Label &Text(const std::string &);
+ Label &Font(const graphics::Font &);
+ Label &Foreground(const glm::vec4 &);
+ Label &Background(const glm::vec4 &);
+
+ Label &Position(const glm::vec3 &p) noexcept { pos = p; return *this; }
+ const glm::vec3 &Position() const noexcept { return pos; }
+
+ Label &Origin(Gravity o) noexcept { origin = o; return *this; }
+ Gravity Origin() const noexcept { return origin; }
+
+ glm::vec2 Size();
+ void Draw(app::Assets &, graphics::Viewport &) noexcept;
+
+private:
+ void Update();
+
+private:
+ const graphics::Font *font;
+ std::string text;
+ graphics::Texture tex;
+ glm::vec4 fg_color;
+ glm::vec4 bg_color;
+ glm::vec3 pos;
+ Gravity origin;
+ bool dirty;
+
+};
+
+}
+}
+
+#endif
--- /dev/null
+#ifndef BLOBS_UI_ALIGN_HPP_
+#define BLOBS_UI_ALIGN_HPP_
+
+#include "../graphics/glm.hpp"
+
+
+namespace blobs {
+namespace ui {
+
+enum class Align {
+ BEGIN,
+ MIDDLE,
+ END,
+};
+
+enum class Gravity {
+ NORTH_WEST,
+ NORTH,
+ NORTH_EAST,
+ WEST,
+ CENTER,
+ EAST,
+ SOUTH_WEST,
+ SOUTH,
+ SOUTH_EAST,
+};
+
+inline Align get_x(Gravity g) noexcept {
+ return Align(int(g) % 3);
+}
+
+inline Align get_y(Gravity g) noexcept {
+ return Align(int(g) / 3);
+}
+
+inline Gravity get_gravity(Align x, Align y) noexcept {
+ return Gravity(int(y) * 3 + int(x));
+}
+
+inline glm::vec2 align(
+ Gravity g,
+ const glm::vec2 &size,
+ const glm::vec2 &offset = glm::vec2(0.0f, 0.0f)
+) {
+ return glm::vec2(
+ size.x * 0.5f * (1 - int(get_x(g))) + offset.x,
+ size.y * 0.5f * (1 - int(get_y(g))) + offset.y
+ );
+}
+
+inline glm::vec3 align(
+ Gravity g,
+ const glm::vec2 &size,
+ const glm::vec3 &offset
+) {
+ return glm::vec3(
+ size.x * 0.5f * (1 - int(get_x(g))) + offset.x,
+ size.y * 0.5f * (1 - int(get_y(g))) + offset.y,
+ offset.z
+ );
+}
+
+}
+}
+
+#endif
--- /dev/null
+#include "CreaturePanel.hpp"
+
+#include "../app/Assets.hpp"
+#include "../creature/Creature.hpp"
+#include "../graphics/Viewport.hpp"
+
+#include <glm/gtx/transform.hpp>
+
+#include <iostream>
+#include <glm/gtx/io.hpp>
+
+
+namespace blobs {
+namespace ui {
+
+CreaturePanel::CreaturePanel(const app::Assets &assets)
+: c(nullptr)
+, name(assets.fonts.large) {
+ name.Origin(Gravity::NORTH_EAST);
+}
+
+CreaturePanel::~CreaturePanel() {
+}
+
+
+void CreaturePanel::Show(creature::Creature &cr) {
+ c = &cr;
+ name.Text(c->Name());
+}
+
+void CreaturePanel::Hide() noexcept {
+ c = nullptr;
+}
+
+void CreaturePanel::Draw(app::Assets &assets, graphics::Viewport &viewport) noexcept {
+ if (!c) return;
+
+ const glm::vec2 margin(20.0f);
+ const glm::vec2 padding(10.0f);
+
+ const glm::vec2 size(name.Size() + 2.0f * padding);
+ const glm::vec2 half_size = size * 0.5f;
+
+ const glm::vec3 top_right(viewport.Width() - margin.x, margin.y, 0.0f);
+ name.Position(top_right - glm::vec3(padding.x, -padding.y, 1.0f));
+
+ assets.shaders.plain_color.Activate();
+ assets.shaders.plain_color.SetM(
+ glm::translate(glm::vec3(top_right.x - half_size.x, top_right.y + half_size.y, 0.0f))
+ * glm::scale(glm::vec3(half_size.x, half_size.y, 1.0f)));
+ assets.shaders.plain_color.SetColor(glm::vec3(0.7f, 0.7f, 0.7f));
+ assets.shaders.plain_color.DrawRect();
+
+ name.Draw(assets, viewport);
+}
+
+
+Label::Label(const graphics::Font &f)
+: font(&f)
+, text()
+, tex()
+, fg_color(0.0f, 0.0f, 0.0f, 1.0f)
+, bg_color(0.0f, 0.0f, 0.0f, 0.0f)
+, pos(0.0f, 0.0f, 0.0f)
+, origin(Gravity::CENTER)
+, dirty(true) {
+}
+
+Label::~Label() {
+}
+
+Label &Label::Text(const std::string &t) {
+ if (text != t) {
+ dirty = true;
+ }
+ text = t;
+ return *this;
+}
+
+Label &Label::Font(const graphics::Font &f) {
+ if (font != &f) {
+ dirty = true;
+ }
+ font = &f;
+ return *this;
+}
+
+Label &Label::Foreground(const glm::vec4 &c) {
+ fg_color = c;
+ return *this;
+}
+
+Label &Label::Background(const glm::vec4 &c) {
+ bg_color = c;
+ return *this;
+}
+
+glm::vec2 Label::Size() {
+ Update();
+ return tex.Size();
+}
+
+void Label::Draw(app::Assets &assets, graphics::Viewport &viewport) noexcept {
+ Update();
+ glm::vec2 size = Size();
+ glm::vec3 position = align(origin, size, pos);
+
+ std::cout << "pos: " << pos << ", size: " << size << ", position: " << position << std::endl;
+
+ assets.shaders.alpha_sprite.Activate();
+ assets.shaders.alpha_sprite.SetM(glm::translate(position)
+ * glm::scale(glm::vec3(size.x * 0.5f, size.y * 0.5f, 1.0f)));
+ assets.shaders.alpha_sprite.SetTexture(tex);
+ assets.shaders.alpha_sprite.SetFgColor(fg_color);
+ assets.shaders.alpha_sprite.SetBgColor(bg_color);
+ assets.shaders.alpha_sprite.DrawRect();
+}
+
+void Label::Update() {
+ if (!dirty) return;
+ font->Render(text, tex);
+ dirty = false;
+}
+
+}
+}