Added UIElement and Text; Custom fonts are supported

This commit is contained in:
Grayson Riffe (Laptop) 2021-09-01 19:17:24 -05:00
parent c0f7634b5f
commit 65fd8e89bb
30 changed files with 346 additions and 35 deletions

View File

@ -9,7 +9,7 @@ MainState::MainState(nf::Application* app) :
void MainState::onEnter() {
Log("MainState onEnter!");
}
}
void MainState::update(double deltaTime) {

Binary file not shown.

View File

@ -0,0 +1,13 @@
#version 330 core
out vec4 color;
uniform sampler2D text;
uniform vec3 textColor;
in vec2 texCoord;
void main() {
vec4 temp = vec4(1.0, 1.0, 1.0, texture(text, texCoord).r);
color = vec4(textColor.xyz, 1.0) * temp;
}

View File

@ -0,0 +1,14 @@
#version 330 core
layout(location = 0) in vec2 pos;
layout(location = 1) in vec2 texCoords;
//uniform mat4 model;
uniform mat4 proj;
out vec2 texCoord;
void main() {
gl_Position = proj * vec4(pos, 0.0, 1.0);
texCoord = texCoords;
}

View File

@ -75,7 +75,7 @@ int main(int argc, char* argv[]) {
}
std::set<std::string> extensions;
extensions.insert({ "obj", "png", "shader" });
extensions.insert({ "obj", "png", "shader", "ttf" });
unsigned int dirCount = 0;
const std::filesystem::path workingDir = std::filesystem::current_path();

View File

@ -104,7 +104,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>glew32s.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>glew32s.lib;opengl32.lib;freetype.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
<Lib>
<AdditionalLibraryDirectories>$(ProjectDir)dep\lib\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -132,7 +132,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>glew32s.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>glew32s.lib;opengl32.lib;freetype.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
<Lib>
<AdditionalLibraryDirectories>$(ProjectDir)dep\lib\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -156,7 +156,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>glew32s.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>glew32s.lib;opengl32.lib;freetype.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
<Lib>
<AdditionalLibraryDirectories>$(ProjectDir)dep\lib\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -184,7 +184,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>glew32s.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>glew32s.lib;opengl32.lib;freetype.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
<Lib>
<AdditionalLibraryDirectories>$(ProjectDir)dep\lib\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -203,6 +203,8 @@
<ClCompile Include="src\Renderer\Drawable\Drawable.cpp" />
<ClCompile Include="src\Renderer\Drawable\Entity.cpp" />
<ClCompile Include="src\Renderer\Drawable\Model.cpp" />
<ClCompile Include="src\Renderer\Drawable\Text.cpp" />
<ClCompile Include="src\Renderer\Drawable\UIElement.cpp" />
<ClCompile Include="src\Renderer\IndexBuffer.cpp" />
<ClCompile Include="src\Renderer\Renderer.cpp" />
<ClCompile Include="src\Renderer\Shader.cpp" />
@ -226,7 +228,9 @@
<ClInclude Include="src\include\NothinFancy.h" />
<ClInclude Include="src\include\Renderer.h" />
<ClInclude Include="src\include\Shader.h" />
<ClInclude Include="src\include\Text.h" />
<ClInclude Include="src\include\Texture.h" />
<ClInclude Include="src\include\UIElement.h" />
<ClInclude Include="src\include\Utility.h" />
<ClInclude Include="src\include\VertexArray.h" />
<ClInclude Include="src\include\VertexBuffer.h" />

View File

@ -60,6 +60,12 @@
<ClCompile Include="src\Renderer\Camera.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Renderer\Drawable\UIElement.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Renderer\Drawable\Text.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\include\Config.h">
@ -116,6 +122,12 @@
<ClInclude Include="src\include\Camera.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\include\UIElement.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\include\Text.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Natvis Include="NatvisFile.natvis" />

View File

@ -20,6 +20,10 @@ namespace nf {
}
AFont::~AFont() {
}
AssetPack::AssetPack() {
}
@ -73,6 +77,14 @@ namespace nf {
m_assets[assetName] = shader;
continue;
}
if (extension == "ttf") {
AFont* font = new AFont;
font->data = new char[assetSize];
std::memcpy(font->data, &assetContents[0], assetSize);
font->size = assetSize;
m_assets[assetName] = font;
continue;
}
Error("Invalid asset extention in pack \"" + (std::string)packName + (std::string)"\"!");
}
}
@ -100,4 +112,6 @@ namespace nf {
AModel* BaseAssets::cone;
AModel* BaseAssets::cylinder;
AModel* BaseAssets::torus;
AFont* BaseAssets::defaultFont;
}

View File

@ -24,8 +24,6 @@ namespace nf {
m_app->trackMouse(true);
else
m_app->trackMouse(false);
m_yaw = -90.0f;
m_pitch = 0.0f;
}
}

View File

@ -2,6 +2,8 @@
#include<vector>
#include "Shader.h"
namespace nf {
Entity::Entity() :
m_model(nullptr),

View File

@ -7,7 +7,10 @@
#include "Texture.h"
namespace nf {
Model::Model() {
Model::Model() :
m_texture(nullptr)
{
}
void Model::create(const void* vertexBufferData, const size_t vertexBufferSize, const void* indexBufferData, size_t indexBufferCount, const void* textureCoordinatesBufferData, size_t textureCoordinatesBufferSize, const char* textureData, size_t textureSize) {

View File

@ -0,0 +1,113 @@
#include "Text.h"
#include "GL/glew.h"
#include "ft2build.h"
#include FT_FREETYPE_H
#include "UIElement.h"
#include "Shader.h"
namespace nf {
Text::Text() :
m_centered(false)
{
}
void Text::create(const std::string& string, const Vec2& position, const Vec3& color, unsigned int size, Asset* font) {
m_string = string;
m_position = position;
m_color = color;
FT_Library ft;
if (FT_Init_FreeType(&ft))
Error("Could not initialize FreeType!");
FT_Face face;
AFont& newFont = *(AFont*)font;
if (FT_New_Memory_Face(ft, (const unsigned char*)newFont.data, newFont.size, 0, &face))
Error("Could not load font!");
FT_Set_Pixel_Sizes(face, 0, size);
for (unsigned char c = 0; c < 128; c++) {
FT_Load_Char(face, c, FT_LOAD_RENDER);
unsigned int tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character ch = { tex, Vec2((float)face->glyph->bitmap.width, (float)face->glyph->bitmap.rows), Vec2(face->glyph->bitmap_left, face->glyph->bitmap_top), (unsigned int)face->glyph->advance.x };
m_font[c] = ch;
}
FT_Done_Face(face);
FT_Done_FreeType(ft);
m_vao = new VertexArray;
m_vao->addBuffer(nullptr, 0);
m_vao->push<float>(2);
m_vao->finishBufferLayout();
m_vao->addBuffer(nullptr, 0);
m_vao->push<float>(2);
m_vao->finishBufferLayout();
}
void Text::centered(bool centered) {
m_centered = centered;
}
const char* Text::identity() {
return "text";
}
void Text::render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight) {
float scale = windowWidth / 4000.0f;
m_vao->bind();
std::string::const_iterator si;
float currX = (float)m_position.x * windowWidth, currY = (float)m_position.y * windowHeight;
if (m_centered) {
float textWidth = 0.0f;
float textHeight = 0.0f;
for (si = m_string.begin(); si != m_string.end(); si++) {
Character& c = m_font[*si];
textWidth += (c.advance >> 6) * scale;
if (c.size.y >= textHeight)
textHeight = (float)c.size.y * scale;
}
currX = ((float)windowWidth - textWidth) / 2;
currY = ((float)windowHeight - textHeight) / 2;
}
glm::vec3 color = { m_color.x, m_color.y, m_color.z };
shader->setUniform("textColor", color);
for (si = m_string.begin(); si != m_string.end(); si++) {
Character& c = m_font[*si];
float x = currX + (float)c.bearing.x * scale;
float y = currY - float(c.size.y - c.bearing.y) * scale;
float w = (float)c.size.x * scale;
float h = (float)c.size.y * scale;
float vb[3][4] = {
x, y + h,
x, y,
x + w, y,
x, y + h,
x + w, y,
x + w, y + h
};
float tc[3][4] = {
0.0, 0.0,
0.0, 1.0,
1.0, 1.0,
0.0, 0.0,
1.0, 1.0,
1.0, 0.0
};
glBindTexture(GL_TEXTURE_2D, c.texID);
m_vao->setBufferData(0, vb, sizeof(vb));
m_vao->setBufferData(1, tc, sizeof(tc));
glDrawArrays(GL_TRIANGLES, 0, 6);
currX += (c.advance >> 6) * scale;
}
}
Text::~Text() {
}
}

View File

@ -0,0 +1,19 @@
#include "UIElement.h"
namespace nf {
UIElement::UIElement() {
}
const char* UIElement::identity() {
return "none";
}
void UIElement::render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight) {
}
UIElement::~UIElement() {
}
}

View File

@ -5,6 +5,8 @@
#include "glm/glm.hpp"
#include "Application.h"
#include "Shader.h"
#include "UIElement.h"
#include "Utility.h"
namespace nf {
@ -52,12 +54,16 @@ namespace nf {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_CULL_FACE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
baseAP.load("base.nfpack");
const char* defaultVertex = baseAP["defaultVertex.shader"]->data;
const char* defaultFragment = baseAP["defaultFragment.shader"]->data;
m_defaultShader = new Shader(defaultVertex, defaultFragment);
const char* entityVertex = baseAP["entityVertex.shader"]->data;
const char* entityFragment = baseAP["entityFragment.shader"]->data;
m_entityShader = new Shader(entityVertex, entityFragment);
const char* textVertex = baseAP["textVertex.shader"]->data;
const char* textFragment = baseAP["textFragment.shader"]->data;
m_textShader = new Shader(textVertex, textFragment);
BaseAssets::cube = (AModel*)baseAP["cube.obj"];
BaseAssets::plane = (AModel*)baseAP["plane.obj"];
@ -65,6 +71,7 @@ namespace nf {
BaseAssets::cone = (AModel*)baseAP["cone.obj"];
BaseAssets::cylinder = (AModel*)baseAP["cylinder.obj"];
BaseAssets::torus = (AModel*)baseAP["torus.obj"];
BaseAssets::defaultFont = (AFont*)baseAP["default.ttf"];
}
void Renderer::render(Entity& in) {
@ -73,25 +80,38 @@ namespace nf {
m_lGame.push_back(&in);
//TODO: Sort transparent objects by distance; Farthest first
}
void Renderer::render(UIElement& in) {
if (&in == nullptr)
Error("Tried to render Entity before being created!");
m_lUI.push_back(&in);
//TODO: Sort transparent objects by distance; Farthest first
}
void Renderer::doFrame(Camera* camera) {
glViewport(0, 0, m_app->getConfig().width, m_app->getConfig().height);
glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)m_app->getConfig().width / (float)m_app->getConfig().height, 0.1f, 100000.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)m_app->getConfig().width / (float)m_app->getConfig().height, 0.1f, 100000.0f);
for (Entity* draw : m_lGame) {
Entity& curr = *draw;
curr.bind(m_defaultShader);
m_defaultShader->setUniform("proj", proj);
camera->bind(m_defaultShader);
curr.bind(m_entityShader);
m_entityShader->setUniform("proj", proj);
camera->bind(m_entityShader);
//TODO: Clean this up a bit
glDrawElements(GL_TRIANGLES, curr.getModel()->getIndexCount(), GL_UNSIGNED_INT, nullptr);
}
m_lGame.clear();
for (Drawable* draw : m_lUI) {
Drawable& curr = *draw;
proj = glm::ortho(0.0f, (float)m_app->getConfig().width, 0.0f, (float)m_app->getConfig().height);
for (UIElement* draw : m_lUI) {
UIElement& curr = *draw;
if (curr.identity() == "text") {
m_textShader->bind();
m_textShader->setUniform("proj", proj);
curr.render(m_textShader, m_app->getConfig().width, m_app->getConfig().height);
continue;
}
//TODO: Add else if for UI texture
}
m_lUI.clear();

View File

@ -52,6 +52,11 @@ namespace nf {
getUniformLocation(name);
glUniformMatrix4fv(m_uniformLocations[name], 1, GL_FALSE, glm::value_ptr(data));
}
void Shader::setUniform(const char* name, glm::vec3& data) {
if (m_uniformLocations.find(name) == m_uniformLocations.end())
getUniformLocation(name);
glUniform3fv(m_uniformLocations[name], 1, glm::value_ptr(data));
}
void Shader::getUniformLocation(const char* uniformName) {
unsigned int loc = glGetUniformLocation(m_id, uniformName);

View File

@ -50,6 +50,12 @@ namespace nf {
glBindVertexArray(m_id);
}
void VertexArray::setBufferData(unsigned int buffer, const void* data, const size_t dataSize) {
bind();
m_buffers[buffer]->bind();
glBufferData(GL_ARRAY_BUFFER, dataSize, data, GL_STATIC_DRAW);
}
VertexArray::~VertexArray() {
for (VertexBuffer* curr : m_buffers) {
delete curr;

View File

@ -52,7 +52,7 @@ namespace nf {
LPCWSTR m_wclassName;
HWND m_window;
LONG m_defaultWindowStyle;
int m_altWidth, m_altHeight;
unsigned int m_altWidth, m_altHeight;
std::chrono::duration<double> m_fpsDuration;
double m_deltaTime;
@ -75,7 +75,7 @@ namespace nf {
//Array of booleans that represent keyboard and mouse input minus the scrollwheel
bool m_input[164];
int m_mouseX, m_mouseY;
unsigned int m_mouseX, m_mouseY;
bool m_trackingMouse;
bool m_mouseTrackFirst;
int m_mouseDiffX, m_mouseDiffY;

View File

@ -27,6 +27,12 @@ namespace nf {
~AShader() override;
};
struct AFont : Asset {
size_t size;
~AFont() override;
};
class AssetPack {
public:
AssetPack();
@ -48,6 +54,8 @@ namespace nf {
static AModel* cylinder;
static AModel* torus;
static ATexture* logo;
static AFont* defaultFont;
//static ATexture* logo;
};
}

View File

@ -3,8 +3,8 @@
namespace nf {
struct Config {
public:
int width;
int height;
unsigned int width;
unsigned int height;
bool fullscreen;
const char* title;
};

View File

@ -1,5 +1,4 @@
#pragma once
#include "Shader.h"
#include "VertexArray.h"
#include "IndexBuffer.h"

View File

@ -4,6 +4,8 @@
#include "Utility.h"
namespace nf {
class Shader;
class Entity {
public:
Entity();

View File

@ -9,6 +9,8 @@
#include "Utility.h"
#include "IntroGamestate.h"
#include "Assets.h"
#include "Text.h"
#include "Input.h"
namespace nf {
class Drawable;
@ -48,7 +50,7 @@ namespace nf {
Renderer(Application* app);
void render(Entity& in);
//TODO: Create second render function for UIElements
void render(UIElement& in);
void doFrame(Camera* camera);
@ -59,9 +61,12 @@ namespace nf {
HDC m_hdc;
HGLRC m_hglrc;
AssetPack baseAP;
std::vector<Entity*> m_lGame;
std::vector<Drawable*> m_lUI;
Shader* m_defaultShader;
std::vector<UIElement*> m_lUI;
Shader* m_entityShader;
Shader* m_textShader;
};
class Application {
@ -107,7 +112,7 @@ namespace nf {
LPCWSTR m_wclassName;
HWND m_window;
LONG m_defaultWindowStyle;
int m_altWidth, m_altHeight;
unsigned int m_altWidth, m_altHeight;
std::chrono::duration<double> m_fpsDuration;
double m_deltaTime;
@ -130,7 +135,7 @@ namespace nf {
//Array of booleans that represent keyboard and mouse input minus the scrollwheel
bool m_input[164];
int m_mouseX, m_mouseY;
unsigned int m_mouseX, m_mouseY;
bool m_trackingMouse;
bool m_mouseTrackFirst;
int m_mouseDiffX, m_mouseDiffY;
@ -138,5 +143,4 @@ namespace nf {
//Renderer object to use OpenGL to render the current state
Renderer* m_renderer;
};
}
#include "Input.h"
}

View File

@ -7,12 +7,14 @@
namespace nf {
class Application;
class UIElement;
class Renderer {
public:
Renderer(Application* app);
void render(Entity& in);
void render(UIElement& in);
//TODO: Create second render function for UIElements
void doFrame(Camera* camera);
@ -27,7 +29,8 @@ namespace nf {
AssetPack baseAP;
std::vector<Entity*> m_lGame;
std::vector<Drawable*> m_lUI;
Shader* m_defaultShader;
std::vector<UIElement*> m_lUI;
Shader* m_entityShader;
Shader* m_textShader;
};
}

View File

@ -10,6 +10,7 @@ namespace nf {
void bind();
void setUniform(const char* name, glm::mat4& data);
void setUniform(const char* name, glm::vec3& data);
~Shader();
private:

View File

@ -0,0 +1,34 @@
#pragma once
#include <map>
#include "UIElement.h"
#include "Assets.h"
#include "Utility.h"
namespace nf {
struct Character {
unsigned int texID;
Vec2 size;
Vec2 bearing;
unsigned int advance;
};
class Text : public UIElement {
public:
Text();
void create(const std::string& string, const Vec2& position, const Vec3& color = {1.0, 1.0, 1.0}, unsigned int size = 160, Asset* font = BaseAssets::defaultFont);
void centered(bool centered);
const char* identity() override;
void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight) override;
~Text();
private:
std::string m_string;
Vec2 m_position;
Vec3 m_color;
bool m_centered;
std::map<char, Character> m_font;
};
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "Drawable.h"
namespace nf {
class Shader;
class UIElement : public Drawable {
public:
UIElement();
virtual const char* identity();
virtual void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight);
~UIElement();
private:
};
}

View File

@ -38,7 +38,25 @@ __debugbreak();}
#define Error(x) {MessageBox(FindWindow(L"NFClass", NULL), toWide(x), L"NF Engine Error", MB_OK | MB_ICONERROR);\
std::exit(-1);}
#endif
struct Vec2 {
Vec2() : x(0.0), y(0.0) {}
Vec2(double x1) : x(x1), y(x1) {}
Vec2(double x1, double y1) : x(x1), y(y1) {}
Vec2 operator*(const double scalar) {
return Vec2(x * scalar, y * scalar);
}
Vec2& operator+=(const Vec2& rhs) {
this->x += rhs.x;
this->y += rhs.y;
return *this;
}
Vec2& operator-=(const Vec2& rhs) {
this->x -= rhs.x;
this->y -= rhs.y;
return *this;
}
double x, y;
};
struct Vec3 {
Vec3() : x(0.0), y(0.0), z(0.0) {}
Vec3(double x1) : x(x1), y(x1), z(x1) {}

View File

@ -19,6 +19,7 @@ namespace nf {
void push(unsigned int count);
void finishBufferLayout();
void bind();
void setBufferData(unsigned int buffer, const void* data, const size_t dataSize);
~VertexArray();
private: