aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/Text.hpp71
-rw-r--r--src/engine.cpp49
-rw-r--r--src/events/render.hpp16
-rw-r--r--src/render.cpp212
-rw-r--r--src/render.hpp20
-rw-r--r--src/script.cpp13
-rw-r--r--src/script.hpp6
-rw-r--r--src/text.cpp223
-rw-r--r--src/text.hpp105
-rw-r--r--src/world.cpp39
10 files changed, 657 insertions, 97 deletions
diff --git a/src/components/Text.hpp b/src/components/Text.hpp
new file mode 100644
index 0000000..9566499
--- /dev/null
+++ b/src/components/Text.hpp
@@ -0,0 +1,71 @@
+/**
+ * @file Text.hpp
+ * Allows text to be shown with an entity.
+ *
+ * Copyright (C) 2019 Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COMPONENT_TEXT_HPP_
+#define COMPONENT_TEXT_HPP_
+
+#include "Component.hpp"
+
+struct Text : Component<Text>
+{
+public:
+ std::string font;
+ std::string text;
+ double offsetX, offsetY;
+
+ Text(const std::string& _font, const std::string& _text) :
+ font(_font), text(_text), offsetX(0), offsetY(0) {}
+ Text(const std::string& _font, const std::string& _text,
+ double _x, double _y) :
+ font(_font), text(_text), x(_x), y(_y) {}
+
+ Text FromLua(sol::object ref)
+ {
+ if (ref.get_type() == sol::type::table) {
+ sol::table tab = ref;
+ if (tab["font"] != nullptr)
+ this->font = tab["font"];
+ if (tab["text"] != nullptr)
+ this->text = tab["text"];
+ if (tab["x"] != nullptr)
+ this->x = tab["x"];
+ if (tab["y"] != nullptr)
+ this->y = tab["y"];
+ } else {
+ throw std::string("Text table not formatted properly");
+ }
+ return *this;
+ }
+
+ void serialize(cereal::JSONOutputArchive& ar) final {
+ ar(CEREAL_NVP(font), CEREAL_NVP(text), CEREAL_NVP(x), CEREAL_NVP(y));
+ }
+
+ void serialize(cereal::JSONInputArchive& ar) final {
+ ar(CEREAL_NVP(font), CEREAL_NVP(text), CEREAL_NVP(x), CEREAL_NVP(y));
+ }
+
+ std::string serializeName(void) const final {
+ return "Text";
+ }
+};
+
+#endif // COMPONENT_TEXT_HPP_
+
diff --git a/src/engine.cpp b/src/engine.cpp
index a2d0e9b..a000979 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -27,6 +27,7 @@
#include "script.hpp"
#include "render.hpp"
#include "physics.hpp"
+#include "text.hpp"
#include "components/EventListener.hpp"
#include "components/Script.hpp"
@@ -48,10 +49,22 @@ int Engine::init(void)
systems.add<RenderSystem>();
systems.add<ScriptSystem>(entities, *(systems.system<WorldSystem>().get()));
systems.add<PhysicsSystem>();
+ systems.add<TextSystem>();
systems.configure();
// Load game script and entity data
- systems.system<ScriptSystem>()->init();
+ auto* script = systems.system<ScriptSystem>().get();
+ script->addToGameNamespace("loadFont",
+ [this](std::string name, std::string file, int size) {
+ systems.system<TextSystem>().get()->loadFont(name, file, size);
+ });
+ script->addToGameNamespace("puts",
+ [this](std::string name, float x, float y, std::string text) {
+ systems.system<TextSystem>().get()->put(name, x, y, text);
+ });
+ script->init();
+
+
if (GameState::load("save.json", entities)) {
std::cout << "Loaded from save.json. Delete the file if you don't want "
"it." << std::endl;
@@ -71,8 +84,15 @@ void Engine::logicLoop(void)
the logic loop is run during our first
loop. */
+ auto start = mc::now();
while (shouldRun()) {
- auto start = mc::now();
+ auto end = start;
+ start = mc::now();
+ auto diff = start-end;
+ auto micros = cr::duration_cast<cr::microseconds>(diff);
+ auto msc = micros.count();
+ dt = static_cast<double>(msc) / 1000.0;
+ elapsed += dt;
systems.update<InputSystem>(dt);
//systems.update<ScriptSystem>(dt);
@@ -94,41 +114,34 @@ void Engine::logicLoop(void)
}
std::this_thread::yield();
-
- auto end = mc::now();
- auto diff = end - start;
- auto micros = cr::duration_cast<cr::microseconds>(diff);
- auto msc = micros.count();
- dt = static_cast<double>(msc) / 1000.0;
- elapsed += dt;
}
}
void Engine::physicsLoop(void)
{
entityx::TimeDelta dt = 0; /**< Elapsed milliseconds since each loop */
-
+ auto start = mc::now();
while (shouldRun()) {
- auto start = mc::now();
+ auto end = start;
+ start = mc::now();
+
+ auto diff = start - end;
+ auto micros = cr::duration_cast<cr::microseconds>(diff);
+ auto msc = micros.count();
+ dt = static_cast<double>(msc) / 1000.0;
// Update the entities physics/position
systems.update<PhysicsSystem>(dt);
std::this_thread::yield();
-
- auto end = mc::now();
- auto diff = end - start;
- auto micros = cr::duration_cast<cr::microseconds>(diff);
- auto msc = micros.count();
- dt = static_cast<double>(msc) / 1000.0;
}
- std::cout << std::endl;
}
void Engine::renderLoop(void)
{
entityx::TimeDelta dt = 0; /**< Elapsed milliseconds since each loop */
while (shouldRun()) {
+ systems.update<TextSystem>(dt);
systems.update<RenderSystem>(dt);
}
}
diff --git a/src/events/render.hpp b/src/events/render.hpp
new file mode 100644
index 0000000..bcecac6
--- /dev/null
+++ b/src/events/render.hpp
@@ -0,0 +1,16 @@
+#ifndef EVENTS_RENDER_HPP_
+#define EVENTS_RENDER_HPP_
+
+struct NewRenderEvent
+{
+ GLuint vbo;
+ GLuint tex;
+ GLuint normal;
+ unsigned int vertex;
+
+ NewRenderEvent(GLuint _vbo, GLuint _tex, GLuint _normal, unsigned int _vertex) :
+ vbo(_vbo), tex(_tex), normal(_normal), vertex(_vertex) {}
+};
+
+#endif // EVENTS_RENDER_HPP_
+
diff --git a/src/render.cpp b/src/render.cpp
index 2b49b2c..9e63a71 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -27,8 +27,10 @@
void RenderSystem::configure([[maybe_unused]] entityx::EntityManager& entities,
[[maybe_unused]] entityx::EventManager& events)
{
+ events.subscribe<NewRenderEvent>(*this);
events.subscribe<WorldMeshUpdateEvent>(*this);
events.subscribe<entityx::ComponentAddedEvent<Player>>(*this);
+
init();
}
@@ -37,24 +39,34 @@ void RenderSystem::update([[maybe_unused]] entityx::EntityManager& entities,
[[maybe_unused]] entityx::TimeDelta dt)
{
// TODO move these to only happen once to speed up rendering
- GLuint s = worldShader.getProgram();
- GLuint v = worldShader.getUniform("view");
- GLuint p = worldShader.getUniform("projection");
- GLuint m = worldShader.getUniform("model");
- GLuint a = worldShader.getAttribute("vertex");
- GLuint t = worldShader.getAttribute("texc");
-
- GLuint q = worldShader.getUniform("textu");
- GLuint n = worldShader.getUniform("normu");
- GLuint b = worldShader.getUniform("AmbientLight");
- GLuint f = worldShader.getUniform("Flipped");
+ static GLuint s = worldShader.getProgram();
+ static GLuint v = worldShader.getUniform("view");
+ static GLuint p = worldShader.getUniform("projection");
+ static GLuint m = worldShader.getUniform("model");
+ static GLuint a = worldShader.getAttribute("vertex");
+ static GLuint t = worldShader.getAttribute("texc");
+ static GLuint r = worldShader.getAttribute("trans");
+
+ static GLuint q = worldShader.getUniform("textu");
+ static GLuint n = worldShader.getUniform("normu");
+ static GLuint b = worldShader.getUniform("AmbientLight");
+ static GLuint f = worldShader.getUniform("Flipped");
+
+ static glm::vec3 rot = glm::vec3(0.0f, 0.0f, -1.0f);
+ camPos.z = 15.0f;
/***********
* SETUP *
***********/
+
+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_POLYGON_OFFSET_FILL);
+
glm::mat4 view = glm::lookAt(camPos, // Pos
- glm::vec3(camPos.x, camPos.y, 0.0f), // Facing
+ camPos + rot, // Facing
glm::vec3(0.0f, 1.0f, 0.0f)); // Up
//glm::mat4 projection = glm::perspective(45.0f,
@@ -66,30 +78,32 @@ void RenderSystem::update([[maybe_unused]] entityx::EntityManager& entities,
float scaleWidth = static_cast<float>(width) / scale;
float scaleHeight = static_cast<float>(height) / scale;
- glm::mat4 projection = glm::ortho(-(scaleWidth/2), // Left
- (scaleWidth/2), // Right
- -(scaleHeight/2), // Bottom
- (scaleHeight/2), // Top
- 10.0f, // zFar
- -10.0f // zNear
- );
+ //glm::mat4 projection = glm::ortho(-(scaleWidth/2), // Left
+ // (scaleWidth/2), // Right
+ // -(scaleHeight/2), // Bottom
+ // (scaleHeight/2), // Top
+ // 100.0f, // zFar
+ // -100.0f // zNear
+ // );
+
+ glm::mat4 projection = glm::perspective(45.0f,
+ ((float)width/(float)height),
+ 0.01f,
+ 2048.0f);
glm::mat4 model = glm::mat4(1.0f);
+ model = glm::scale(model, glm::vec3(1.0f, 1.0f, -1.0f));
glUseProgram(s);
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
- glEnable(GL_DEPTH_TEST);
glUniformMatrix4fv(v, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(p, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(m, 1, GL_FALSE, glm::value_ptr(model));
- glEnable(GL_CULL_FACE);
- glEnable(GL_POLYGON_OFFSET_FILL);
-
glEnableVertexAttribArray(a);
glEnableVertexAttribArray(t);
+ glEnableVertexAttribArray(r);
// Ambient light, for now this is static
GLfloat amb[4] = {1.0f, 1.0f, 1.0f, 0.0f};
@@ -138,9 +152,9 @@ void RenderSystem::update([[maybe_unused]] entityx::EntityManager& entities,
*************/
entities.each<Render, Position>(
- [this, a, q, t, n, f](entityx::Entity, Render &r, Position &p) {
+ [this](entityx::Entity, Render &rend, Position &p) {
- if (!r.visible)
+ if (!rend.visible)
return;
// If our component was created via script, call the entity's
@@ -150,28 +164,28 @@ void RenderSystem::update([[maybe_unused]] entityx::EntityManager& entities,
//}
float w = 0.5f;
- float h = (float)r.texture.height/r.texture.width;
+ float h = (float)rend.texture.height/rend.texture.width;
GLuint tri_vbo;
GLfloat tri_data[] = {
- (float)p.x-w, (float)p.y , 00.0f, 0.0f, 1.0f,
- (float)p.x+w, (float)p.y , 00.0f, 1.0f, 1.0f,
- (float)p.x-w, (float)p.y+h, 00.0f, 0.0f, 0.0f,
-
- (float)p.x+w, (float)p.y , 00.0f, 1.0f, 1.0f,
- (float)p.x+w, (float)p.y+h, 00.0f, 1.0f, 0.0f,
- (float)p.x-w, (float)p.y+h, 00.0f, 0.0f, 0.0f,
+ (float)p.x-w, (float)p.y , 0.0f, 0.0f, 1.0f, 1.0f,
+ (float)p.x+w, (float)p.y , 0.0f, 1.0f, 1.0f, 1.0f,
+ (float)p.x-w, (float)p.y+h, 0.0f, 0.0f, 0.0f, 1.0f,
+
+ (float)p.x+w, (float)p.y , 0.0f, 1.0f, 1.0f, 1.0f,
+ (float)p.x+w, (float)p.y+h, 0.0f, 1.0f, 0.0f, 1.0f,
+ (float)p.x-w, (float)p.y+h, 0.0f, 0.0f, 0.0f, 1.0f,
};
bool flipped = false;
// TODO flip nicely (aka model transformations)
- if (r.flipX) {
- std::swap(tri_data[3], tri_data[8]);
- tri_data[13] = tri_data[3];
+ if (rend.flipX) {
+ std::swap(tri_data[3], tri_data[9]);
+ tri_data[15] = tri_data[3];
- std::swap(tri_data[23], tri_data[28]);
- tri_data[18] = tri_data[23];
+ std::swap(tri_data[27], tri_data[33]);
+ tri_data[21] = tri_data[27];
flipped = true;
}
@@ -179,11 +193,11 @@ void RenderSystem::update([[maybe_unused]] entityx::EntityManager& entities,
glUniform1i(f, flipped ? 1 : 0);
glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, r.texture.tex);
+ glBindTexture(GL_TEXTURE_2D, rend.texture.tex);
glUniform1i(q, 0);
glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, r.normal.tex);
+ glBindTexture(GL_TEXTURE_2D, rend.normal.tex);
glUniform1i(n, 1);
glGenBuffers(1, &tri_vbo);
@@ -191,9 +205,11 @@ void RenderSystem::update([[maybe_unused]] entityx::EntityManager& entities,
glBufferData(GL_ARRAY_BUFFER, sizeof(tri_data), tri_data, GL_STREAM_DRAW);
glVertexAttribPointer(a, 3, GL_FLOAT, GL_FALSE,
- 5*sizeof(float), 0);
- glVertexAttribPointer(t, 2, GL_FLOAT, GL_FALSE,
- 5*sizeof(float), (void*)(3*sizeof(float)));
+ 6*sizeof(float), 0);
+ glVertexAttribPointer(t, 2, GL_FLOAT, GL_FALSE,
+ 6*sizeof(float), (void*)(3*sizeof(float)));
+ glVertexAttribPointer(r, 1, GL_FLOAT, GL_FALSE,
+ 6*sizeof(float), (void*)(5*sizeof(float)));
glDrawArrays(GL_TRIANGLES, 0, 6);
});
glUniform1i(f, 0);
@@ -209,37 +225,91 @@ void RenderSystem::update([[maybe_unused]] entityx::EntityManager& entities,
glUniform1i(n, 1);
glBindBuffer(GL_ARRAY_BUFFER, worldVBO);
- //glBufferData(GL_ARRAY_BUFFER,
- // wm.size() * sizeof(WorldMeshData),
- // &wm.front(),
- // GL_STREAM_DRAW);
-
glVertexAttribPointer(a, 3, GL_FLOAT, GL_FALSE,
6*sizeof(float), 0);
glVertexAttribPointer(t, 2, GL_FLOAT, GL_FALSE,
6*sizeof(float), (void*)(3*sizeof(float)));
+ glVertexAttribPointer(r, 1, GL_FLOAT, GL_FALSE,
+ 6*sizeof(float), (void*)(5*sizeof(float)));
glDrawArrays(GL_TRIANGLES, 0, worldVertex);
}
+ glDisableVertexAttribArray(a);
+ glDisableVertexAttribArray(t);
+
+ glUseProgram(0);
+
+ /******************
+ * UI RENDERING *
+ ******************/
+
+ static GLuint uiS = uiShader.getProgram();
+ static GLuint uiS_v = uiShader.getUniform("view");
+ static GLuint uiS_p = uiShader.getUniform("projection");
+ static GLuint uiS_m = uiShader.getUniform("model");
+ static GLuint uiS_a = uiShader.getAttribute("coord2d");
+ static GLuint uiS_t = uiShader.getAttribute("tex_coord");
+ static GLuint uiS_q = uiShader.getUniform("sampler");
+
+ glUseProgram(uiS);
+
+ view = glm::lookAt(glm::vec3(0.0f, 0.0f, 10.0f), // Pos
+ glm::vec3(0.0f, 0.0f, 1.0f), // Facing
+ glm::vec3(0.0f, 1.0f, 0.0f)); // Up
+
+ scale = 1.0f;
+ scaleWidth = static_cast<float>(width) / scale;
+ scaleHeight = static_cast<float>(height) / scale;
+
+ projection = glm::ortho(-scaleWidth/2.0f, // Left
+ scaleWidth/2, // Right
+ -scaleHeight/2, // Bottom
+ scaleHeight/2, // Top
+ 100.0f, // zFar
+ -100.0f); // zNear
+
+ model = glm::mat4(1.0f);
+
+ glUniformMatrix4fv(uiS_v, 1, GL_FALSE, glm::value_ptr(view));
+ glUniformMatrix4fv(uiS_p, 1, GL_FALSE, glm::value_ptr(projection));
+ glUniformMatrix4fv(uiS_m, 1, GL_FALSE, glm::value_ptr(model));
+
+ glEnableVertexAttribArray(uiS_a);
+ glEnableVertexAttribArray(uiS_t);
+
+ // Update all UI VBOs
+ for (auto& r : uiRenders) {
+ auto& render = r.second;
+
+ glActiveTexture(GL_TEXTURE9);
+ glBindTexture(GL_TEXTURE_2D, render.tex);
+ glUniform1i(uiS_q, 9);
+
+ glBindBuffer(GL_ARRAY_BUFFER, r.first);
+ glVertexAttribPointer(uiS_a, 3, GL_FLOAT, GL_FALSE,
+ 6*sizeof(float), 0);
+ glVertexAttribPointer(uiS_t, 2, GL_FLOAT, GL_FALSE,
+ 6*sizeof(float), (void*)(3*sizeof(float)));
+ glDrawArrays(GL_TRIANGLES, 0, render.vertex);
+ }
+
+ glDisableVertexAttribArray(uiS_a);
+ glDisableVertexAttribArray(uiS_t);
+
/*************
* CLEANUP *
*************/
- glDisableVertexAttribArray(a);
- glDisableVertexAttribArray(t);
+
+ glUseProgram(0);
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_CULL_FACE);
- glUseProgram(0);
-
SDL_GL_SwapWindow(window.get());
}
int RenderSystem::init(void)
{
- // Select an OpenGL 4.3 profile.
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
std::cerr << "SDL video failed to initialize: "
@@ -259,6 +329,13 @@ int RenderSystem::init(void)
return -1;
}
+ // Select an OpenGL 4.3 profile.
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
+ SDL_GL_CONTEXT_PROFILE_CORE);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+ SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
+
context = SDL_GL_CreateContext(window.get());
GLenum err;
@@ -284,6 +361,7 @@ int RenderSystem::init(void)
worldShader.addAttribute("vertex");
worldShader.addAttribute("texc");
+ worldShader.addAttribute("trans");
worldShader.addUniform("textu");
worldShader.addUniform("normu");
@@ -294,10 +372,20 @@ int RenderSystem::init(void)
worldShader.addUniform("AmbientLight");
worldShader.addUniform("Flipped");
+ uiShader.createProgram("Shaders/ui.vert", "Shaders/ui.frag");
+
+ uiShader.addUniform("projection");
+ uiShader.addUniform("view");
+ uiShader.addUniform("model");
+
+ uiShader.addAttribute("coord2d");
+ uiShader.addAttribute("tex_coord");
+
+ uiShader.addUniform("sampler");
+
glEnableVertexAttribArray(worldShader.getAttribute("vertex"));
- glUseProgram(worldShader.getProgram());
+ glEnableVertexAttribArray(uiShader.getAttribute("coord2d"));
- // TODO
//glPolygonOffset(1.0, 1.0);
//glClearColor(0.6, 0.8, 1.0, 0.0);
@@ -310,6 +398,13 @@ int RenderSystem::init(void)
/************
* EVENTS *
************/
+
+void RenderSystem::receive(const NewRenderEvent &nre)
+{
+ uiRenders.insert_or_assign(nre.vbo,
+ UIRenderData(nre.tex, nre.normal, nre.vertex));
+}
+
void RenderSystem::receive(const WorldMeshUpdateEvent &wmu)
{
worldVBO = wmu.worldVBO;
@@ -322,3 +417,4 @@ void RenderSystem::receive(const entityx::ComponentAddedEvent<Player> &cae)
{
player = cae.entity;
}
+
diff --git a/src/render.hpp b/src/render.hpp
index f3064d1..88668cc 100644
--- a/src/render.hpp
+++ b/src/render.hpp
@@ -36,9 +36,21 @@
#include "shader.hpp"
#include "world.hpp"
+#include "components/Player.hpp"
+#include "events/render.hpp"
#include "events/world.hpp"
-#include "components/Player.hpp"
+#include <map>
+
+struct UIRenderData
+{
+ GLuint tex;
+ GLuint normal;
+ unsigned int vertex;
+
+ UIRenderData(GLuint _tex, GLuint _normal, unsigned int _vertex) :
+ tex(_tex), normal(_normal), vertex(_vertex) {}
+};
class RenderSystem : public entityx::System<RenderSystem>,
public entityx::Receiver<RenderSystem>
@@ -52,8 +64,12 @@ private:
SDL_GLContext context;
Shader worldShader;
+ Shader uiShader;
glm::vec3 camPos;
+ // Map of VBOs and their render data
+ std::map<GLuint, UIRenderData> uiRenders;
+
GLuint worldVBO = 0;
unsigned int worldVertex = 0;
GLuint worldTexture = 0;
@@ -92,8 +108,8 @@ public:
* EVENTS *
************/
void receive(const WorldMeshUpdateEvent &wmu);
+ void receive(const NewRenderEvent &nre);
void receive(const entityx::ComponentAddedEvent<Player> &cae);
-
};
#endif // SYSTEM_RENDER_HPP_
diff --git a/src/script.cpp b/src/script.cpp
index fd99228..6cda627 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -31,6 +31,9 @@ void ScriptSystem::configure([[maybe_unused]] entityx::EntityManager& entities,
// Init after systems.configure() in engine.cpp
//init();
+ lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string);
+
+ scriptExport();
}
#include <components/Script.hpp>
@@ -54,9 +57,6 @@ void ScriptSystem::receive([[maybe_unused]] const EntitySpawnEvent &toSpawn)
int ScriptSystem::init(void)
{
- lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string);
-
- scriptExport();
doFile();
return 0;
@@ -136,10 +136,9 @@ void ScriptSystem::scriptExport(void)
"setSize", &World::setSize,
"getSize", &World::getSize);
-
- auto gamespace = lua["game"].get_or_create<sol::table>();
- gamespace.set_function("spawn", entitySpawn);
- gamespace.set_function("worldRegister", worldRegister);
+ game = lua["game"].get_or_create<sol::table>();
+ game.set_function("spawn", entitySpawn);
+ game.set_function("worldRegister", worldRegister);
}
sol::table ScriptSystem::spawn(sol::object param)
diff --git a/src/script.hpp b/src/script.hpp
index 87027d5..0ac9e63 100644
--- a/src/script.hpp
+++ b/src/script.hpp
@@ -47,6 +47,7 @@ private:
* interactions between C and Lua
*/
sol::state lua;
+ sol::table game;
entityx::EntityManager& manager;
@@ -102,6 +103,11 @@ public:
* Contains all calls that export components/functions to lua.
*/
void scriptExport(void);
+
+ template<typename F>
+ void addToGameNamespace(const std::string& name, F func) {
+ game.set_function(name, func);
+ }
};
#endif // SYSTEM_SCRIPT_HPP_
diff --git a/src/text.cpp b/src/text.cpp
new file mode 100644
index 0000000..e0eb158
--- /dev/null
+++ b/src/text.cpp
@@ -0,0 +1,223 @@
+#include "text.hpp"
+
+#include "events/render.hpp"
+
+#include <iostream>
+
+void TextSystem::configure([[maybe_unused]] entityx::EntityManager& entities,
+ [[maybe_unused]] entityx::EventManager& events)
+{
+ if (FT_Init_FreeType(&freetype) != 0) {
+ // TODO handle error
+ }
+
+ shouldUpdateVBOs = false;
+}
+
+/**
+ * Draws the text for all entities.
+ */
+void TextSystem::update([[maybe_unused]] entityx::EntityManager& entites,
+ entityx::EventManager& events,
+ [[maybe_unused]] entityx::TimeDelta dt)
+{
+ if (shouldUpdateVBOs) {
+ shouldUpdateVBOs = false;
+ updateVBOs();
+
+ for (auto& data : fontData) {
+ auto& d = data.second;
+ if (d.text.size() == 0)
+ continue;
+
+ // TODO make normal
+ events.emit<NewRenderEvent>(d.vbo, d.tex, 0, d.buffer.size());
+ }
+ }
+}
+
+void TextSystem::loadFont(const std::string& name,
+ const std::string& file,
+ int size)
+{
+ // Find or load font at given size
+ //
+
+ if (fonts.find(file) == fonts.end()) {
+ FT_Face face;
+ if (FT_New_Face(freetype, file.c_str(), 0, &face)) {
+ // TODO handle this error
+ }
+ fonts.emplace(file, face);
+ }
+
+ auto& face = fonts[file];
+ FT_Set_Pixel_Sizes(face, 0, size);
+ fontData.try_emplace(name);
+
+ // Calculate dimensions of final texture
+ //
+
+ float width = 0, height = 0;
+ for (int c = 32; c < 128; c++) {
+ FT_Load_Char(face, c, FT_LOAD_RENDER);
+ width += face->glyph->bitmap.width + 1;
+ height = std::max(height, static_cast<float>(face->glyph->bitmap.rows));
+ }
+
+ // Generate texture to hold entire font
+ //
+
+ auto& font = fontData[name];
+ glGenBuffers(1, &font.vbo);
+
+ glGenTextures(1, &font.tex);
+ glBindTexture(GL_TEXTURE_2D, font.tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height,
+ 0, GL_RED, GL_UNSIGNED_BYTE, 0);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ // // convert red-on-black to RGBA
+ // auto& g = face->glyph;
+ // std::vector<uint32_t> buf (g->bitmap.width * g->bitmap.rows, 0xFFFFFF);
+ // for (auto j = buf.size(); j--;)
+ // buf[j] |= g->bitmap.buffer[j] << 24;
+
+ // Load each character and add it to the texture
+ //
+
+ font.width = width;
+ font.height = height;
+
+ float offsetX = 0, offsetY = 0;
+ for (int c = 32; c < 128; c++) {
+ if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
+ std::cerr << "Unrecognized character: " << c << std::endl;
+ continue;
+ }
+
+ auto* g = face->glyph;
+ glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY,
+ g->bitmap.width, g->bitmap.rows,
+ GL_RED, GL_UNSIGNED_BYTE,
+ g->bitmap.buffer);
+
+ auto& d = font.data[c-32];
+ d.dim = { g->bitmap.width, g->bitmap.rows };
+ d.bitmap = { g->bitmap_left, g->bitmap_top };
+ d.advance = { g->advance.x >> 6, g->advance.y >> 6 };
+
+ d.offset = { offsetX / width, offsetY / height };
+ offsetX += g->bitmap.width;// + 1.0f;
+ // Keep offsetY at zero?
+ }
+
+ std::cout << "Loaded font: " << file << " (size: " << size << ", tex: "
+ << font.tex << ")" << std::endl;
+}
+
+void TextSystem::put(const std::string& font,
+ float x,
+ float y,
+ const std::string& text)
+{
+ if (fontData.find(font) == fontData.end())
+ return;
+
+ fontData[font].text.emplace_back(text, x, y, -9.0f);
+ shouldUpdateVBOs = true;
+}
+
+void TextSystem::updateVBOs(void)
+{
+ for (auto& data : fontData) {
+ auto& d = data.second;
+ d.buffer.clear();
+ for (auto& text : d.text) {
+ float tx = text.x;
+ float ty = text.y;
+ for (char c : text.text) {
+ if (c < 32)
+ continue;
+
+ c -= 32;
+
+ float x = tx + d.data[c].bitmap.first;
+ float y = ty - (d.data[c].dim.second - d.data[c].bitmap.second);
+ float z = text.z;
+
+ float w = d.data[c].dim.first;
+ float h = d.data[c].dim.second;
+
+ tx += d.data[c].advance.first;
+ ty += d.data[c].advance.second;
+
+ if (w == 0.0f || h == 0.0f)
+ continue;
+
+ d.buffer += {
+ x,
+ y,
+ z,
+ d.data[c].offset.first,
+ d.data[c].offset.second+d.data[c].dim.second/d.height,
+ 1.0f
+ };
+ d.buffer += {
+ x+w,
+ y,
+ z,
+ d.data[c].offset.first+d.data[c].dim.first/d.width,
+ d.data[c].offset.second+d.data[c].dim.second/d.height,
+ 1.0f
+ };
+ d.buffer += {
+ x,
+ y+h,
+ z,
+ d.data[c].offset.first,
+ d.data[c].offset.second,
+ 1.0f
+ };
+
+ d.buffer += {
+ x+w,
+ y,
+ z,
+ d.data[c].offset.first+d.data[c].dim.first/d.width,
+ d.data[c].offset.second+d.data[c].dim.second/d.height,
+ 1.0f
+ };
+ d.buffer += {
+ x+w,
+ y+h,
+ z,
+ d.data[c].offset.first+d.data[c].dim.first/d.width,
+ d.data[c].offset.second,
+ 1.0f
+ };
+ d.buffer += {
+ x,
+ y+h,
+ z,
+ d.data[c].offset.first,
+ d.data[c].offset.second,
+ 1.0f
+ };
+ }
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, d.vbo);
+ glBufferData(GL_ARRAY_BUFFER,
+ d.buffer.size() * sizeof(TextMeshData), d.buffer.data(),
+ GL_DYNAMIC_DRAW);
+ }
+}
+
diff --git a/src/text.hpp b/src/text.hpp
new file mode 100644
index 0000000..d68613d
--- /dev/null
+++ b/src/text.hpp
@@ -0,0 +1,105 @@
+/**
+ * @file text.hpp
+ * Manages entity text.
+ *
+ * Copyright (C) 2019 Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// hello
+
+#ifndef SYSTEM_TEXT_HPP_
+#define SYSTEM_TEXT_HPP_
+
+#include <entityx/entityx.h>
+#include <ft2build.h>
+#include <freetype/freetype.h>
+#include <GL/glew.h>
+#include <SDL2/SDL_opengl.h>
+
+#include <map>
+#include <string>
+#include <tuple>
+#include <vector>
+
+struct TextMeshData
+{
+ float posX, posY, posZ;
+ float texX, texY;
+ float transparency;
+} __attribute__ ((packed));
+
+struct FT_Info {
+ std::pair<float, float> offset;
+ std::pair<float, float> dim;
+ std::pair<float, float> bitmap;
+ std::pair<float, float> advance;
+};
+
+struct Text {
+ std::string text;
+ float x;
+ float y;
+ float z;
+
+ Text(std::string _text, float _x, float _y, float _z = 0.0f) :
+ text(_text), x(_x), y(_y), z(_z) {}
+};
+
+// Stores texture and placement data for a font at a size.
+struct Font {
+ GLuint tex;
+ GLuint vbo;
+
+ float width;
+ float height;
+
+ std::array<FT_Info, 96> data;
+ // Stores currently shown text at given index into VBO?
+ std::vector<Text> text;
+ std::basic_string<TextMeshData> buffer;
+};
+
+class TextSystem : public entityx::System<TextSystem>
+{
+public:
+ /**
+ * Prepares the system for running.
+ */
+ void configure(entityx::EntityManager& entities,
+ entityx::EventManager& events) final;
+
+ /**
+ * Draws the text for all entities.
+ */
+ void update(entityx::EntityManager& entites,
+ entityx::EventManager& events,
+ entityx::TimeDelta dt) final;
+
+ void put(const std::string& font, float x, float y, const std::string& text);
+
+ void loadFont(const std::string& name, const std::string& file, int size);
+
+private:
+ FT_Library freetype;
+ std::map<std::string, FT_Face> fonts;
+ std::map<std::string, Font> fontData;
+ bool shouldUpdateVBOs;
+
+ void updateVBOs(void);
+};
+
+#endif // SYSTEM_TEXT_HPP_
+
diff --git a/src/world.cpp b/src/world.cpp
index c20ce17..cd89a22 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -18,6 +18,7 @@
*/
#include "world.hpp"
+#include "events/render.hpp"
#include "events/world.hpp"
/*****************
@@ -136,7 +137,7 @@ void World::generateMesh()
// Preallocate size of vertexes
mesh = std::basic_string<WorldMeshData>();
- for (float Z = 0; Z < data.size(); Z++) {
+ for (float Z = data.size() - 1; Z >= 0; Z--) {
for (float X = 0; X < data.at(Z).size(); X++) {
for (float Y = 0; Y < data.at(Z).at(X).size(); Y++) {
int d = data.at(Z).at(X).at(Y);
@@ -148,22 +149,35 @@ void World::generateMesh()
glm::vec2& to = t.offset;
glm::vec2& ts = t.size;
- mesh += {X , Y , Z, to.x , to.y+ts.y, 1.0};
- mesh += {X+1, Y , Z, to.x+ts.x, to.y+ts.y, 1.0};
- mesh += {X , Y+1, Z, to.x , to.y , 1.0};
+ float tr = 1.0f;
+
+ // TODO play with this a bit so it only goes trans
+ // if player is behind the front layer
+ try {
+ if (Z < data.size() - 1 && Z >= 0) {
+ if (data.at(Z+1).at(X).at(Y) == -1)
+ tr = 1.0f;
+ }
+ } catch (...) {
+ tr = 1.0f;
+ }
+
+ mesh += {X , Y , Z, to.x , to.y+ts.y, tr};
+ mesh += {X+1, Y , Z, to.x+ts.x, to.y+ts.y, tr};
+ mesh += {X , Y+1, Z, to.x , to.y , tr};
- mesh += {X+1, Y , Z, to.x+ts.x, to.y+ts.y, 1.0};
- mesh += {X+1, Y+1, Z, to.x+ts.x, to.y , 1.0};
- mesh += {X , Y+1, Z, to.x , to.y , 1.0};
+ mesh += {X+1, Y , Z, to.x+ts.x, to.y+ts.y, tr};
+ mesh += {X+1, Y+1, Z, to.x+ts.x, to.y , tr};
+ mesh += {X , Y+1, Z, to.x , to.y , tr};
}
}
}
glBindBuffer(GL_ARRAY_BUFFER, worldVBO);
glBufferData(GL_ARRAY_BUFFER,
- mesh.size() * sizeof(mesh),
- &mesh.front(),
- GL_STREAM_DRAW);
+ mesh.size() * sizeof(WorldMeshData),
+ mesh.data(),
+ GL_STATIC_DRAW);
meshUpdated = true;
}
@@ -199,7 +213,9 @@ double World::getHeight(double x, double y, double z)
}
}
} catch (...) { // If we get any errors, just let the character
- return y;
+ //return y;
+ (void)y;
+ return 0.0;
}
return Y;
@@ -229,7 +245,6 @@ void WorldSystem::update([[maybe_unused]]entityx::EntityManager& entities,
if (currentWorld == nullptr) {
currentWorld = &(worlds.front());
events.emit<WorldChangeEvent>(currentWorld);
- std::cout << "Emitted" << std::endl;
}
if (currentWorld->meshUpdated) {