]> git.localhorst.tv Git - blobs.git/commitdiff
basic creature model
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 15 Nov 2017 21:09:46 +0000 (22:09 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 15 Nov 2017 21:09:46 +0000 (22:09 +0100)
12 files changed:
assets
src/app/Assets.hpp
src/app/app.cpp
src/app/states.cpp
src/blobs.cpp
src/graphics/CreatureSkin.hpp [new file with mode: 0644]
src/graphics/shader.cpp
src/world/Body.hpp
src/world/Creature.hpp [new file with mode: 0644]
src/world/Planet.hpp
src/world/creature.cpp [new file with mode: 0644]
src/world/world.cpp

diff --git a/assets b/assets
index a8e34c508dc619ed8643875431baac64d88765b2..cc062273ae5591bfa7910ca7fd71f23a35a3270e 160000 (submodule)
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit a8e34c508dc619ed8643875431baac64d88765b2
+Subproject commit cc062273ae5591bfa7910ca7fd71f23a35a3270e
index b95ee48ea4f75a615cbee85d93a83e5ace754f3a..4ea7f57458f1f8c2435114eb561f40688c364bbc 100644 (file)
@@ -2,6 +2,7 @@
 #define BLOBS_APP_ASSETS_HPP_
 
 #include "../graphics/ArrayTexture.hpp"
+#include "../graphics/CreatureSkin.hpp"
 #include "../graphics/PlanetSurface.hpp"
 #include "../graphics/SunSurface.hpp"
 
@@ -15,14 +16,17 @@ struct Assets {
 
        std::string path;
        std::string tile_path;
+       std::string skin_path;
 
        struct {
                graphics::ArrayTexture tiles;
+               graphics::ArrayTexture skins;
        } textures;
 
        struct {
                graphics::PlanetSurface planet_surface;
                graphics::SunSurface sun_surface;
+               graphics::CreatureSkin creature_skin;
        } shaders;
 
        Assets();
@@ -35,6 +39,7 @@ struct Assets {
        Assets &operator =(Assets &&) = delete;
 
        void LoadTileTexture(const std::string &name, graphics::ArrayTexture &, int layer) const;
+       void LoadSkinTexture(const std::string &name, graphics::ArrayTexture &, int layer) const;
 
 };
 
index 8c0f8e13521547cd16624e3d793926064ed50b90..6b8cfbfd5421e6061d2db1895d3824e4f87126bd 100644 (file)
@@ -167,7 +167,8 @@ void State::OnQuit() {
 
 Assets::Assets()
 : path("assets/")
-, tile_path(path + "tiles/") {
+, tile_path(path + "tiles/")
+, skin_path(path + "skins/") {
        graphics::Format format;
        textures.tiles.Bind();
        textures.tiles.Reserve(256, 256, 9, format);
@@ -180,6 +181,17 @@ Assets::Assets()
        LoadTileTexture("7", textures.tiles, 6);
        LoadTileTexture("8", textures.tiles, 7);
        LoadTileTexture("9", textures.tiles, 8);
+       textures.skins.Bind();
+       textures.skins.Reserve(256, 256, 9, format);
+       LoadSkinTexture("1", textures.skins, 0);
+       LoadSkinTexture("2", textures.skins, 1);
+       LoadSkinTexture("3", textures.skins, 2);
+       LoadSkinTexture("4", textures.skins, 3);
+       LoadSkinTexture("5", textures.skins, 4);
+       LoadSkinTexture("6", textures.skins, 5);
+       LoadSkinTexture("7", textures.skins, 6);
+       LoadSkinTexture("8", textures.skins, 7);
+       LoadSkinTexture("9", textures.skins, 8);
 }
 
 Assets::~Assets() {
@@ -200,5 +212,20 @@ void Assets::LoadTileTexture(const std::string &name, graphics::ArrayTexture &te
        SDL_FreeSurface(srf);
 }
 
+void Assets::LoadSkinTexture(const std::string &name, graphics::ArrayTexture &tex, int layer) const {
+       std::string path = skin_path + name + ".png";
+       SDL_Surface *srf = IMG_Load(path.c_str());
+       if (!srf) {
+               throw SDLError("IMG_Load");
+       }
+       try {
+               tex.Data(layer, *srf);
+       } catch (...) {
+               SDL_FreeSurface(srf);
+               throw;
+       }
+       SDL_FreeSurface(srf);
+}
+
 }
 }
index 86b2e82c3b71e3d9d9ab630a515facde11573ab9..5a9ae0a3379760711ef75ddd2048d183e734df5b 100644 (file)
@@ -1,6 +1,7 @@
 #include "MasterState.hpp"
 
 #include "../world/Body.hpp"
+#include "../world/Creature.hpp"
 #include "../world/Planet.hpp"
 #include "../world/Simulation.hpp"
 #include "../world/Sun.hpp"
@@ -56,36 +57,43 @@ void MasterState::OnKeyDown(const SDL_KeyboardEvent &e) {
 }
 
 void MasterState::OnRender(graphics::Viewport &viewport) {
-       assets.shaders.planet_surface.Activate();
-       assets.shaders.planet_surface.SetTexture(assets.textures.tiles);
 
        int num_lights = 0;
        for (auto sun : sim.Suns()) {
                // TODO: source sun's light color and strength
-               assets.shaders.planet_surface.SetLight(
-                       num_lights,
-                       glm::vec3(cam.View() * cam.Model(*sun)[3]),
-                       glm::vec3(1.0f, 1.0f, 1.0f),
-                       1.0e6f);
+               glm::vec3 pos(cam.View() * cam.Model(*sun)[3]);
+               glm::vec3 col(1.0f, 1.0f, 1.0f);
+               float str = 1.0e6f;
+               assets.shaders.planet_surface.Activate();
+               assets.shaders.planet_surface.SetLight(num_lights, pos, col, str);
+               assets.shaders.creature_skin.Activate();
+               assets.shaders.creature_skin.SetLight(num_lights, pos, col, str);
                ++num_lights;
-               if (num_lights >= graphics::PlanetSurface::MAX_LIGHTS) {
+               if (num_lights >= graphics::PlanetSurface::MAX_LIGHTS || num_lights >= graphics::CreatureSkin::MAX_LIGHTS) {
                        break;
                }
        }
        for (auto planet : sim.Planets()) {
                // TODO: indirect light from planets, calculate strength and get color somehow
-               assets.shaders.planet_surface.SetLight(
-                       num_lights,
-                       glm::vec3(cam.View() * cam.Model(*planet)[3]),
-                       glm::vec3(1.0f, 1.0f, 1.0f),
-                       10.0f);
+               glm::vec3 pos(cam.View() * cam.Model(*planet)[3]);
+               glm::vec3 col(1.0f, 1.0f, 1.0f);
+               float str = 10.0f;
+               assets.shaders.planet_surface.Activate();
+               assets.shaders.planet_surface.SetLight(num_lights, pos, col, str);
+               assets.shaders.creature_skin.Activate();
+               assets.shaders.creature_skin.SetLight(num_lights, pos, col, str);
                ++num_lights;
-               if (num_lights >= graphics::PlanetSurface::MAX_LIGHTS) {
+               if (num_lights >= graphics::PlanetSurface::MAX_LIGHTS || num_lights >= graphics::CreatureSkin::MAX_LIGHTS) {
                        break;
                }
        }
+       assets.shaders.planet_surface.Activate();
        assets.shaders.planet_surface.SetNumLights(num_lights);
+       assets.shaders.creature_skin.Activate();
+       assets.shaders.creature_skin.SetNumLights(num_lights);
 
+       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());
                planet->Draw(assets, viewport);
@@ -100,6 +108,14 @@ void MasterState::OnRender(graphics::Viewport &viewport) {
                assets.shaders.sun_surface.SetLight(glm::vec3(1.0f, 1.0f, 1.0f), 1.0e6f);
                assets.shaders.sun_surface.Draw();
        }
+
+       assets.shaders.creature_skin.Activate();
+       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());
+               c->Draw(assets, viewport);
+       }
 }
 
 }
index b1fb631d42d89ccb2eed6ed9e7521d13a0d71ceb..c09aea6b21279d6802fc518dab089532286f9577 100644 (file)
@@ -3,6 +3,7 @@
 #include "app/Assets.hpp"
 #include "app/init.hpp"
 #include "app/MasterState.hpp"
+#include "world/Creature.hpp"
 #include "world/Planet.hpp"
 #include "world/Simulation.hpp"
 #include "world/Sun.hpp"
@@ -76,6 +77,12 @@ int main(int argc, char *argv[]) {
        std::cout << "moon cycle in days: " << (moon.OrbitalPeriod() / planet.RotationalPeriod()) << std::endl;
        std::cout << "moon cycles per year: " << (planet.OrbitalPeriod() / moon.OrbitalPeriod()) << std::endl;
 
+       auto blob = new world::Creature;
+       blob->BuildVAO();
+       planet.AddCreature(blob);
+       blob->Surface(0);
+       blob->Position(glm::dvec3(0.0, 0.0, 0.0));
+
        app::MasterState state(assets, sim);
        state.GetCamera()
                .Reference(planet)
diff --git a/src/graphics/CreatureSkin.hpp b/src/graphics/CreatureSkin.hpp
new file mode 100644 (file)
index 0000000..78cf658
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef BLOBS_GRAPHICS_CREATURESKIN_HPP_
+#define BLOBS_GRAPHICS_CREATURESKIN_HPP_
+
+#include "Program.hpp"
+
+#include "glm.hpp"
+
+
+namespace blobs {
+namespace graphics {
+
+class ArrayTexture;
+
+class CreatureSkin {
+
+public:
+       static constexpr int MAX_LIGHTS = 8;
+
+public:
+       CreatureSkin();
+       ~CreatureSkin();
+
+       CreatureSkin(const CreatureSkin &) = delete;
+       CreatureSkin &operator =(const CreatureSkin &) = delete;
+
+       CreatureSkin(CreatureSkin &&) = delete;
+       CreatureSkin &operator =(CreatureSkin &&) = delete;
+
+public:
+       void Activate() 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;
+       void SetNumLights(int n) 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; }
+
+private:
+       Program prog;
+
+       int num_lights;
+
+       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 num_lights_handle;
+       GLuint light_handle[MAX_LIGHTS * 3];
+
+};
+
+}
+}
+
+#endif
index 573e90c3731d6f25fce4cc3a7a9e4ae7b98d3d97..c7b5fdd326e58bcd26651aaf0e925206daf877ef 100644 (file)
@@ -1,3 +1,4 @@
+#include "CreatureSkin.hpp"
 #include "PlanetSurface.hpp"
 #include "Program.hpp"
 #include "Shader.hpp"
@@ -447,5 +448,127 @@ void SunSurface::Draw() const noexcept {
        vao.DrawTriangles(36);
 }
 
+
+constexpr int CreatureSkin::MAX_LIGHTS;
+
+CreatureSkin::CreatureSkin()
+: prog() {
+       prog.LoadShader(
+               GL_VERTEX_SHADER,
+               "#version 330 core\n"
+
+               "layout(location = 0) in vec3 vtx_position;\n"
+               "layout(location = 1) in vec3 vtx_normal;\n"
+               "layout(location = 2) in vec3 vtx_tex_uv;\n"
+
+               "uniform mat4 M;\n"
+               "uniform mat4 MV;\n"
+               "uniform mat4 MVP;\n"
+
+               "out vec3 vtx_viewspace;\n"
+               "out vec3 frag_tex_uv;\n"
+               "out vec3 normal;\n"
+
+               "void main() {\n"
+                       "gl_Position = MVP * vec4(vtx_position, 1);\n"
+                       "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
+                       "normal = normalize((MV * vec4(vtx_normal, 0)).xyz);\n"
+                       "frag_tex_uv = vtx_tex_uv;\n"
+               "}\n"
+       );
+       prog.LoadShader(
+               GL_FRAGMENT_SHADER,
+               "#version 330 core\n"
+
+               "struct LightSource {\n"
+                       "vec3 position;\n"
+                       "vec3 color;\n"
+                       "float strength;\n"
+               "};\n"
+
+               "in vec3 vtx_viewspace;\n"
+               "in vec3 frag_tex_uv;\n"
+               "in vec3 normal;\n"
+
+               "uniform sampler2DArray tex_sampler;\n"
+               "uniform int num_lights;\n"
+               "uniform LightSource light[8];\n"
+
+               "out vec3 color;\n"
+
+               "void main() {\n"
+                       "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n"
+                       "vec3 total_light = tex_color * vec3(0.01, 0.01, 0.01);\n"
+                       "for (int i = 0; i < num_lights; ++i) {\n"
+                               "vec3 to_light = light[i].position - vtx_viewspace;\n"
+                               "float distance = length(to_light) + length(vtx_viewspace);\n"
+                               "vec3 light_dir = normalize(to_light);\n"
+                               "float attenuation = light[i].strength / (distance * distance);\n"
+                               "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * tex_color;\n"
+                               "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
+                               "vec3 specular = vec3(0.0, 0.0, 0.0);\n"
+                               "if (dot(normal, light_dir) >= 0.0) {\n"
+                                       "attenuation * light[i].color * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), 25.0);\n"
+                               "}\n"
+                               "total_light = total_light + diffuse + specular;\n"
+                       "}\n"
+                       "color = total_light;\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");
+       num_lights_handle = prog.UniformLocation("num_lights");
+       for (int i = 0; i < MAX_LIGHTS; ++i) {
+               light_handle[3 * i + 0]  = prog.UniformLocation("light[" + std::to_string(i) + "].position");
+               light_handle[3 * i + 1]  = prog.UniformLocation("light[" + std::to_string(i) + "].color");
+               light_handle[3 * i + 2]  = prog.UniformLocation("light[" + std::to_string(i) + "].strength");
+       }
+}
+
+CreatureSkin::~CreatureSkin() {
+}
+
+void CreatureSkin::Activate() noexcept {
+       prog.Use();
+       glEnable(GL_DEPTH_TEST);
+       glDepthFunc(GL_LESS);
+       glEnable(GL_CULL_FACE);
+       glDisable(GL_BLEND);
+}
+
+void CreatureSkin::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 CreatureSkin::SetTexture(ArrayTexture &tex) noexcept {
+       glActiveTexture(GL_TEXTURE0);
+       tex.Bind();
+       prog.Uniform(sampler_handle, GLint(0));
+}
+
+void CreatureSkin::SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
+       prog.Uniform(light_handle[3 * n + 0], pos);
+       prog.Uniform(light_handle[3 * n + 1], color);
+       prog.Uniform(light_handle[3 * n + 2], strength);
+}
+
+void CreatureSkin::SetNumLights(int n) noexcept {
+       prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
+}
+
 }
 }
index 5f82be232b4dc3e78029fd27338b122ab4a41421..fba121b90995d113c2fad374c39db8bd7ae28942 100644 (file)
@@ -16,6 +16,7 @@ namespace graphics {
 }
 namespace world {
 
+class Creature;
 class Simulation;
 
 class Body {
@@ -83,6 +84,11 @@ public:
 
        void Cache() noexcept;
 
+       // body takes over ownership of given pointer
+       void AddCreature(Creature *);
+       std::vector<Creature *> &Creatures() noexcept { return creatures; }
+       const std::vector<Creature *> &Creatures() const noexcept { return creatures; }
+
 private:
        void AddChild(Body &);
        void RemoveChild(Body &);
@@ -104,6 +110,8 @@ private:
        glm::dmat4 local;
        glm::dmat4 inverse_local;
 
+       std::vector<Creature *> creatures;
+
 };
 
 }
diff --git a/src/world/Creature.hpp b/src/world/Creature.hpp
new file mode 100644 (file)
index 0000000..170d52b
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef BLOBS_WORLD_CREATURE_HPP_
+#define BLOBS_WORLD_CREATURE_HPP_
+
+#include "../graphics/glm.hpp"
+#include "../graphics/SimpleVAO.hpp"
+
+
+namespace blobs {
+namespace app {
+       struct Assets;
+}
+namespace graphics {
+       class Viewport;
+}
+namespace world {
+
+class Body;
+
+class Creature {
+
+public:
+       Creature();
+       ~Creature();
+
+       Creature(const Creature &) = delete;
+       Creature &operator =(const Creature &) = delete;
+
+       Creature(Creature &&) = delete;
+       Creature &operator =(Creature &&) = delete;
+
+public:
+       void SetBody(Body &b) noexcept { body = &b; }
+       Body &GetBody() noexcept { return *body; }
+       const Body &GetBody() const noexcept { return *body; }
+
+       void Surface(int s) noexcept { surface = s; }
+       void Position(const glm::dvec3 &p) noexcept { position = p; }
+
+       glm::dmat4 LocalTransform() noexcept;
+
+       void BuildVAO();
+       void Draw(app::Assets &, graphics::Viewport &);
+
+private:
+       Body *body;
+       int surface;
+       glm::dvec3 position;
+
+       struct Attributes {
+               glm::vec3 position;
+               glm::vec3 normal;
+               glm::vec3 texture;
+       };
+       graphics::SimpleVAO<Attributes, unsigned short> vao;
+
+};
+
+}
+}
+
+#endif
index a95238a914338851df9dee7120c494310c2c684a..900ebbbe8ae4fb6412e337e43566fc7899df1da8 100644 (file)
@@ -8,7 +8,7 @@
 #include "../graphics/SimpleVAO.hpp"
 
 #include <cassert>
-#include <memory>
+#include <vector>
 #include <GL/glew.h>
 
 
@@ -63,12 +63,12 @@ public:
 
        glm::dvec3 TileCenter(int surface, int x, int y) const noexcept;
 
-       void BuildVAOs(const TileSet &);
+       void BuildVAO(const TileSet &);
        void Draw(app::Assets &, graphics::Viewport &) override;
 
 private:
        int sidelength;
-       std::unique_ptr<Tile []> tiles;
+       std::vector<Tile> tiles;
 
        struct Attributes {
                glm::vec3 position;
diff --git a/src/world/creature.cpp b/src/world/creature.cpp
new file mode 100644 (file)
index 0000000..aa85b59
--- /dev/null
@@ -0,0 +1,114 @@
+#include "Creature.hpp"
+
+#include "Body.hpp"
+
+#include <glm/gtx/transform.hpp>
+
+
+namespace blobs {
+namespace world {
+
+Creature::Creature()
+: vao() {
+}
+
+Creature::~Creature() {
+}
+
+
+glm::dmat4 Creature::LocalTransform() noexcept {
+       // TODO: surface transform
+       constexpr double half_height = 0.25;
+       return glm::translate(glm::dvec3(position.x, position.y, position.z + body->Radius() + half_height))
+               * glm::scale(glm::dvec3(half_height, half_height, half_height));
+}
+
+void Creature::BuildVAO() {
+       vao.Bind();
+       vao.BindAttributes();
+       vao.EnableAttribute(0);
+       vao.EnableAttribute(1);
+       vao.EnableAttribute(2);
+       vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
+       vao.AttributePointer<glm::vec3>(1, false, offsetof(Attributes, normal));
+       vao.AttributePointer<glm::vec3>(2, false, offsetof(Attributes, texture));
+       vao.ReserveAttributes(6 * 4, GL_STATIC_DRAW);
+       {
+               auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
+               const float offset = 1.0f;
+               for (int surface = 0; surface < 6; ++surface) {
+                       const float tex_u_begin = surface < 3 ? 1.0f : 0.0f;
+                       const float tex_u_end = surface < 3 ? 0.0f : 1.0f;
+
+                       attrib[4 * surface + 0].position[(surface + 0) % 3] = -offset;
+                       attrib[4 * surface + 0].position[(surface + 1) % 3] = -offset;
+                       attrib[4 * surface + 0].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
+                       attrib[4 * surface + 0].normal[(surface + 0) % 3] = 0.0f;
+                       attrib[4 * surface + 0].normal[(surface + 1) % 3] = 0.0f;
+                       attrib[4 * surface + 0].normal[(surface + 2) % 3] = surface < 3 ? 1.0f : -1.0f;
+                       attrib[4 * surface + 0].texture.x = tex_u_begin;
+                       attrib[4 * surface + 0].texture.y = 1.0f;
+                       attrib[4 * surface + 0].texture.z = surface;
+
+                       attrib[4 * surface + 1].position[(surface + 0) % 3] = -offset;
+                       attrib[4 * surface + 1].position[(surface + 1) % 3] =  offset;
+                       attrib[4 * surface + 1].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
+                       attrib[4 * surface + 1].normal[(surface + 0) % 3] = 0.0f;
+                       attrib[4 * surface + 1].normal[(surface + 1) % 3] = 0.0f;
+                       attrib[4 * surface + 1].normal[(surface + 2) % 3] = surface < 3 ? 1.0f : -1.0f;
+                       attrib[4 * surface + 1].texture.x = tex_u_end;
+                       attrib[4 * surface + 1].texture.y = 1.0f;
+                       attrib[4 * surface + 1].texture.z = surface;
+
+                       attrib[4 * surface + 2].position[(surface + 0) % 3] =  offset;
+                       attrib[4 * surface + 2].position[(surface + 1) % 3] = -offset;
+                       attrib[4 * surface + 2].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
+                       attrib[4 * surface + 2].normal[(surface + 0) % 3] = 0.0f;
+                       attrib[4 * surface + 2].normal[(surface + 1) % 3] = 0.0f;
+                       attrib[4 * surface + 2].normal[(surface + 2) % 3] = surface < 3 ? 1.0f : -1.0f;
+                       attrib[4 * surface + 2].texture.x = tex_u_begin;
+                       attrib[4 * surface + 2].texture.y = 0.0f;
+                       attrib[4 * surface + 2].texture.z = surface;
+
+                       attrib[4 * surface + 3].position[(surface + 0) % 3] = offset;
+                       attrib[4 * surface + 3].position[(surface + 1) % 3] = offset;
+                       attrib[4 * surface + 3].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
+                       attrib[4 * surface + 3].normal[(surface + 0) % 3] = 0.0f;
+                       attrib[4 * surface + 3].normal[(surface + 1) % 3] = 0.0f;
+                       attrib[4 * surface + 3].normal[(surface + 2) % 3] = surface < 3 ? 1.0f : -1.0f;
+                       attrib[4 * surface + 3].texture.x = tex_u_end;
+                       attrib[4 * surface + 3].texture.y = 0.0f;
+                       attrib[4 * surface + 3].texture.z = surface;
+               }
+       }
+       vao.BindElements();
+       vao.ReserveElements(6 * 6, GL_STATIC_DRAW);
+       {
+               auto element = vao.MapElements(GL_WRITE_ONLY);
+               for (int surface = 0; surface < 3; ++surface) {
+                       element[6 * surface + 0] = 4 * surface + 0;
+                       element[6 * surface + 1] = 4 * surface + 2;
+                       element[6 * surface + 2] = 4 * surface + 1;
+                       element[6 * surface + 3] = 4 * surface + 1;
+                       element[6 * surface + 4] = 4 * surface + 2;
+                       element[6 * surface + 5] = 4 * surface + 3;
+               }
+               for (int surface = 3; surface < 6; ++surface) {
+                       element[6 * surface + 0] = 4 * surface + 0;
+                       element[6 * surface + 1] = 4 * surface + 1;
+                       element[6 * surface + 2] = 4 * surface + 2;
+                       element[6 * surface + 3] = 4 * surface + 2;
+                       element[6 * surface + 4] = 4 * surface + 1;
+                       element[6 * surface + 5] = 4 * surface + 3;
+               }
+       }
+       vao.Unbind();
+}
+
+void Creature::Draw(app::Assets &assets, graphics::Viewport &viewport) {
+       vao.Bind();
+       vao.DrawTriangles(6 * 6);
+}
+
+}
+}
index a939b3e586e129e748984e0c55ef9386701ea95d..fb57c7c09bde150172b0304ceabd580624728e90 100644 (file)
@@ -7,6 +7,7 @@
 #include "TileSet.hpp"
 #include "TileType.hpp"
 
+#include "Creature.hpp"
 #include "../const.hpp"
 #include "../app/Assets.hpp"
 #include "../graphics/Viewport.hpp"
@@ -47,10 +48,14 @@ Body::Body()
 , orbital(1.0)
 , inverse_orbital(1.0)
 , local(1.0)
-, inverse_local(1.0) {
+, inverse_local(1.0)
+, creatures() {
 }
 
 Body::~Body() {
+       for (Creature *c : creatures) {
+               delete c;
+       }
 }
 
 void Body::SetSimulation(Simulation &s) noexcept {
@@ -151,6 +156,11 @@ void Body::Cache() noexcept {
                * glm::eulerAngleY(-rotation);
 }
 
+void Body::AddCreature(Creature *c) {
+       c->SetBody(*this);
+       creatures.push_back(c);
+}
+
 
 Orbit::Orbit()
 : sma(1.0)
@@ -256,7 +266,7 @@ glm::dmat4 Orbit::InverseMatrix(double t) const noexcept {
 Planet::Planet(int sidelength)
 : Body()
 , sidelength(sidelength)
-, tiles(new Tile[TilesTotal()])
+, tiles(TilesTotal())
 , vao() {
        Radius(double(sidelength) / 2.0);
 }
@@ -272,7 +282,7 @@ glm::dvec3 Planet::TileCenter(int surface, int x, int y) const noexcept {
        return center;
 }
 
-void Planet::BuildVAOs(const TileSet &ts) {
+void Planet::BuildVAO(const TileSet &ts) {
        vao.Bind();
        vao.BindAttributes();
        vao.EnableAttribute(0);
@@ -421,7 +431,7 @@ void GenerateEarthlike(const TileSet &tiles, Planet &p) noexcept {
                        }
                }
        }
-       p.BuildVAOs(tiles);
+       p.BuildVAO(tiles);
 }
 
 void GenerateTest(const TileSet &tiles, Planet &p) noexcept {
@@ -436,7 +446,7 @@ void GenerateTest(const TileSet &tiles, Planet &p) noexcept {
                        }
                }
        }
-       p.BuildVAOs(tiles);
+       p.BuildVAO(tiles);
 }