work on text

This commit is contained in:
2026-02-22 22:48:26 -06:00
parent ce43c56ea6
commit a5c21ea30d
7 changed files with 480 additions and 162 deletions

View File

@@ -14,8 +14,8 @@ namespace Archimedes {
public: public:
Body(RenderTarget rt, glm::mat4 t = glm::mat4(1.0f)) : Object(t), mesh(rt) {}; Body(RenderTarget rt, glm::mat4 t = glm::mat4(1.0f)) : Object(t), mesh(rt) {};
Body(VertexBuffer vb, IndexArray ia, VertexLayout vl, Shader s, RenderMode rm = RenderMode::Triangles, glm::mat4 t = glm::mat4(1.0f)) Body(VertexBuffer vb, IndexArray ia, VertexLayout vl, Shader s, std::optional<Texture> tex = std::nullopt, RenderMode rm = RenderMode::Triangles, glm::mat4 t = glm::mat4(1.0f))
: Object(t), mesh(vb, ia, vl, s, rm) {} : Object(t), mesh(vb, ia, vl, s, tex, rm) {}
Body() : Object(glm::mat4(1.0f)) {} Body() : Object(glm::mat4(1.0f)) {}

View File

@@ -17,32 +17,72 @@ namespace Archimedes {
Polygon Polygon
}; };
class Texture {
public:
Texture() {}
Texture(std::vector<unsigned char> bin, size_t width, size_t height)
: bin(bin), width(width), height(height) {}
~Texture() {}
const void* getBin() { return bin.data(); }
void setActive(bool b) { active = b; }
const bool getActive() const { return active; }
size_t getWidth() { return width; }
size_t getHeight() { return height; }
unsigned int id;
private:
std::vector<unsigned char> bin;
bool active = false;
size_t width, height;
};
class LayoutElement { class LayoutElement {
public: public:
LayoutElement(unsigned int type, size_t count) : type(type), count(count) {}
enum class Type {
Float,
UInt,
Int,
Double
};
LayoutElement(Type type, size_t count, size_t stride, size_t offset)
: type(type), count(count), stride(stride), offset(offset) {}
~LayoutElement() {} ~LayoutElement() {}
unsigned int getType() const { return type; } Type getType() const { return type; }
size_t getSize() const { return size; }
size_t getCount() const { return count; } size_t getCount() const { return count; }
size_t getStride() const { return stride; }
size_t getOffset() const { return offset; }
private: private:
unsigned int type; Type type;
size_t size;
size_t count; size_t count;
size_t stride;
size_t offset;
}; };
class VertexLayout { class VertexLayout {
public: public:
VertexLayout() {} VertexLayout() {}
VertexLayout(std::vector<LayoutElement> elements) : elements(elements) {}
~VertexLayout() {} ~VertexLayout() {}
const std::vector<LayoutElement>& getElements() const { return elements; } std::vector<LayoutElement>& getElements() { return elements; }
private: private:
std::vector<LayoutElement> elements; std::vector<LayoutElement> elements;
@@ -58,11 +98,15 @@ namespace Archimedes {
~VertexBuffer() {} ~VertexBuffer() {}
void setActive(bool b) { active = b; }
const bool getActive() const { return active; }
const void* getData() const { return data.data(); } const void* getData() const { return data.data(); }
size_t getSize() const { return data.size() * sizeof(float); } size_t getSize() const { return data.size() * sizeof(float); }
unsigned int id; unsigned int id;
private: private:
bool active = false;
std::vector<float> data; std::vector<float> data;
}; };
@@ -74,9 +118,12 @@ namespace Archimedes {
~VertexArray() {} ~VertexArray() {}
void setActive(bool b) { active = b; }
const bool getActive() const { return active; }
unsigned int id; unsigned int id;
private: private:
bool active = false;
}; };
class IndexArray { class IndexArray {
@@ -89,11 +136,15 @@ namespace Archimedes {
~IndexArray() {} ~IndexArray() {}
void setActive(bool b) { active = b; }
const bool getActive() const { return active; }
const void* getIndicies() const { return indices.data(); } const void* getIndicies() const { return indices.data(); }
size_t getCount() const { return indices.size(); } size_t getCount() const { return indices.size(); }
unsigned int id; unsigned int id;
private: private:
bool active = false;
std::vector<unsigned int> indices; std::vector<unsigned int> indices;
}; };
@@ -118,14 +169,15 @@ namespace Archimedes {
void init(const std::string& vs, const std::string& fs, LoadType loadType) { void init(const std::string& vs, const std::string& fs, LoadType loadType) {
switch(loadType) { switch(loadType) {
case LoadType::FromSource: case LoadType::FromSource:
this->vs = vs; this->shader = source { vs, fs };
this->fs = fs;
break; break;
case LoadType::FromBin: case LoadType::FromBin:
break; break;
case LoadType::FromFileSource: case LoadType::FromFileSource:
this->vs = readSourceFile(vs); this->shader = source {
this->fs = readSourceFile(fs); readSourceFile(vs),
readSourceFile(fs)
};
break; break;
case LoadType::FromFileBin: case LoadType::FromFileBin:
break; break;
@@ -134,13 +186,47 @@ namespace Archimedes {
} }
} }
std::string getVSource() const { return vs; } void init(const std::vector<unsigned char>& vs, const std::vector<unsigned char>& fs, LoadType loadType) {
std::string getFSource() const { return fs; } switch(loadType) {
case LoadType::FromSource:
break;
case LoadType::FromBin:
this->shader = bin { vs, fs };
break;
case LoadType::FromFileSource:
break;
case LoadType::FromFileBin:
break;
default:
break;
}
}
void setActive(bool b) { active = b; }
const bool getActive() const { return active; }
std::string getVSource() const { return std::get<source>(shader).vertex; }
std::string getFSource() const { return std::get<source>(shader).fragment; }
std::vector<unsigned char>& getVbin() { return std::get<bin>(shader).vertex; }
std::vector<unsigned char>& getFbin() { return std::get<bin>(shader).fragment; }
unsigned int id; unsigned int id;
private: private:
std::string vs;
std::string fs; struct source {
std::string vertex;
std::string fragment;
};
struct bin {
std::vector<unsigned char> vertex;
std::vector<unsigned char> fragment;
};
std::variant<source, bin> shader;
bool active = false;
std::string readSourceFile(const std::string& path) { std::string readSourceFile(const std::string& path) {
@@ -159,25 +245,38 @@ namespace Archimedes {
return s; return s;
} }
std::vector<unsigned char> readBinFile(const std::string& path) {
std::ifstream file(path, std::ios::binary);
if(!file.is_open()) {
return std::vector<unsigned char>();
}
std::vector<unsigned char> s;
s.reserve(10000);
while(!file.eof()) {
s.push_back(file.get());
}
return s;
}
}; };
class RenderTarget { class RenderTarget {
public: public:
RenderTarget(const std::vector<float> data, const std::vector<unsigned int> indices, VertexLayout layout, const std::string& vs, const std::string& fs, RenderMode rm = RenderMode::Triangles)
: vertexBuffer(data),
indexArray(indices),
layout(layout),
shader(vs, fs, Shader::LoadType::FromFileSource),
renderMode(rm) {
} RenderTarget(VertexBuffer vb, IndexArray ia, VertexLayout vl, Shader s, std::optional<Texture> t = std::nullopt, RenderMode rm = RenderMode::Triangles)
RenderTarget(VertexBuffer vb, IndexArray ia, VertexLayout vl, Shader s, RenderMode rm = RenderMode::Triangles)
: vertexBuffer(vb), : vertexBuffer(vb),
indexArray(ia), indexArray(ia),
layout(vl), layout(vl),
shader(s), shader(s),
texture(t),
renderMode(rm) { renderMode(rm) {
} }
@@ -186,6 +285,15 @@ namespace Archimedes {
~RenderTarget() {} ~RenderTarget() {}
void setup(VertexBuffer vb, IndexArray ia, VertexLayout vl, Shader s, std::optional<Texture> t = std::nullopt, RenderMode rm = RenderMode::Triangles) {
vertexBuffer = vb;
indexArray = ia;
layout = vl;
shader = s;
texture = t;
renderMode = rm;
}
void setActive(bool b) { active = b; } void setActive(bool b) { active = b; }
const bool getActive() const { return active; } const bool getActive() const { return active; }
@@ -201,6 +309,8 @@ namespace Archimedes {
Shader shader; Shader shader;
std::optional<Texture> texture;
RenderMode renderMode; RenderMode renderMode;
bool active = false; bool active = false;

View File

@@ -26,16 +26,11 @@ namespace Archimedes {
virtual void render() = 0; virtual void render() = 0;
virtual Shader createShader(const std::string& vs, const std::string& fs, const Shader::LoadType& lt) = 0;
virtual void setupShader(Shader& shader) = 0; virtual void setupShader(Shader& shader) = 0;
virtual RenderTarget createRenderTarget( virtual void setupTexture(Texture& texture) = 0;
VertexBuffer vb,
IndexArray ia, virtual void updateTexture(Texture& texture) = 0;
VertexLayout layout,
Shader& s
) = 0;
virtual void setupRenderTarget(RenderTarget& rt) = 0; virtual void setupRenderTarget(RenderTarget& rt) = 0;

View File

@@ -39,59 +39,6 @@ namespace Archimedes {
} }
Shader createShader(const std::string& vs, const std::string& fs, const Shader::LoadType& lt) override {
Shader shader(vs, fs, lt);
std::string vss = shader.getVSource();
std::string fss = shader.getFSource();
const char* vsc = vss.c_str();
const char* fsc = fss.c_str();
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vsc, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// fragment shader
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fsc, NULL);
glCompileShader(fragmentShader);
// check for shader compile errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// link shaders
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
shader.id = shaderProgram;
return shader;
}
void setupShader(Shader& shader) override { void setupShader(Shader& shader) override {
std::string vss = shader.getVSource(); std::string vss = shader.getVSource();
@@ -141,14 +88,16 @@ namespace Archimedes {
} }
RenderTarget createRenderTarget(VertexBuffer vb, IndexArray ia, VertexLayout layout, Shader& s) override { void setupTexture(Texture& texture) override {
glGenTextures(1, &texture.id);
updateTexture(texture);
}
auto rt = RenderTarget(vb, ia, layout, s); void updateTexture(Texture& texture) override {
glBindTexture(GL_TEXTURE_2D, texture.id);
setupRenderTarget(rt); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture.getWidth(), texture.getHeight(), 0, GL_ALPHA, GL_UNSIGNED_BYTE, texture.getBin());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
return rt; }
};
void setupRenderTarget(RenderTarget& rt) override { void setupRenderTarget(RenderTarget& rt) override {
@@ -158,26 +107,85 @@ namespace Archimedes {
glGenBuffers(1, &rt.indexArray.id); glGenBuffers(1, &rt.indexArray.id);
rt.vertexArray.setActive(true);
rt.vertexBuffer.setActive(true);
rt.indexArray.setActive(true);
if(rt.texture.has_value()) {
glGenTextures(1, &rt.texture.value().id);
rt.texture.value().setActive(true);
}
updateRenderTarget(rt); updateRenderTarget(rt);
rt.setActive(true);
}; };
void updateRenderTarget(RenderTarget& rt) override { void updateRenderTarget(RenderTarget& rt) override {
glBindVertexArray(rt.vertexArray.id); if(rt.vertexArray.getActive()) {
glBindBuffer(GL_ARRAY_BUFFER, rt.vertexBuffer.id); glBindVertexArray(rt.vertexArray.id);
glBufferData(GL_ARRAY_BUFFER, rt.vertexBuffer.getSize(), rt.vertexBuffer.getData(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rt.indexArray.id); if(rt.vertexBuffer.getActive()) {
glBufferData(GL_ELEMENT_ARRAY_BUFFER, rt.indexArray.getCount() * sizeof(unsigned int), rt.indexArray.getIndicies(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, rt.vertexBuffer.id);
glBufferData(GL_ARRAY_BUFFER, rt.vertexBuffer.getSize(), rt.vertexBuffer.getData(), GL_STATIC_DRAW);
}
glUseProgram(rt.shader.id);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); if(rt.indexArray.getActive()) {
glEnableVertexAttribArray(0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rt.indexArray.id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, rt.indexArray.getCount() * sizeof(unsigned int), rt.indexArray.getIndicies(), GL_STATIC_DRAW);
}
glBindVertexArray(0); if(rt.texture.has_value()) {
glBindBuffer(GL_ARRAY_BUFFER, 0); if(rt.texture.value().getActive()) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rt.texture.value().id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, rt.texture.value().getWidth(), rt.texture.value().getHeight(), 0, GL_ALPHA, GL_UNSIGNED_BYTE, rt.texture.value().getBin());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
}
if(rt.shader.getActive()) {
glUseProgram(rt.shader.id);
}
unsigned int i = 0;
for(LayoutElement e : rt.layout.getElements()) {
switch(e.getType()) {
case LayoutElement::Type::Float:
glVertexAttribPointer(i, e.getCount(), GL_FLOAT, GL_FALSE, e.getStride(), (void*)e.getOffset());
glEnableVertexAttribArray(i);
break;
case LayoutElement::Type::Double:
glVertexAttribPointer(i, e.getCount(), GL_DOUBLE, GL_FALSE, e.getStride(), (void*)e.getOffset());
glEnableVertexAttribArray(i);
break;
case LayoutElement::Type::Int:
glVertexAttribPointer(i, e.getCount(), GL_INT, GL_FALSE, e.getStride(), (void*)e.getOffset());
glEnableVertexAttribArray(i);
break;
case LayoutElement::Type::UInt:
glVertexAttribPointer(i, e.getCount(), GL_UNSIGNED_INT, GL_FALSE, e.getStride(), (void*)e.getOffset());
glEnableVertexAttribArray(i);
break;
default:
break;
}
i++;
}
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}; };
@@ -186,6 +194,12 @@ namespace Archimedes {
glDeleteVertexArrays(1, &rt.vertexArray.id); glDeleteVertexArrays(1, &rt.vertexArray.id);
glDeleteBuffers(1, &rt.vertexBuffer.id); glDeleteBuffers(1, &rt.vertexBuffer.id);
glDeleteBuffers(1, &rt.indexArray.id); glDeleteBuffers(1, &rt.indexArray.id);
rt.vertexArray.setActive(false);
rt.vertexBuffer.setActive(false);
rt.indexArray.setActive(false);
rt.setActive(false);
}; };
void draw( void draw(
@@ -210,6 +224,18 @@ namespace Archimedes {
unsigned int colorLoc = glGetUniformLocation(rt.shader.id, "color"); unsigned int colorLoc = glGetUniformLocation(rt.shader.id, "color");
glUniform4f(colorLoc, color.r, color.g, color.b, color.a); glUniform4f(colorLoc, color.r, color.g, color.b, color.a);
if(rt.texture.has_value()) {
if(rt.texture.value().getActive()) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rt.texture.value().id);
glUniform1i(glGetUniformLocation(rt.shader.id, "tex"), 0);
}
}
glBindVertexArray(rt.vertexArray.id); glBindVertexArray(rt.vertexArray.id);
switch(rt.renderMode) { switch(rt.renderMode) {

View File

@@ -3,7 +3,6 @@
#include "utils/Objects/Body.h" #include "utils/Objects/Body.h"
#define STB_TRUETYPE_IMPLIMENTATION
#include <stb/stb_truetype.h> #include <stb/stb_truetype.h>
#include <GL/glew.h> #include <GL/glew.h>
@@ -12,25 +11,162 @@ namespace Archimedes {
class Text { class Text {
GLuint tex; unsigned int tex;
std::vector<unsigned char> ttf; std::vector<unsigned char> ttf;
stbtt_bakedchar cdata[96]; stbtt_bakedchar cdata[96];
std::string path; std::string fontPath;
std::string vs = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTex;\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 proj;\n"
"out vec2 TexCoord;\n"
"void main()\n"
"{\n"
" gl_Position = proj * view * model * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
" TexCoord = aTex;\n"
"}\0";
std::string fs = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D tex;\n"
"uniform vec4 color;\n"
"void main()\n"
"{\n"
" FragColor = vec4(0.6f, 0.1f, 0.1f, texture(tex, TexCoord).a);\n"
//" FragColor = vec4(1.0f);\n"
"}\n\0";
public: public:
Shader shader;
Texture texture;
Text(std::string p) : path(p) {} Text() {}
~Text() {} ~Text() {}
void textInit() { //////////////////////////////////////
// Load a TTF file into a texture and return the character data.
stbtt_packedchar* LoadFont(const char* filename) {
// Load TTF file into memory.
std::ifstream file(filename, std::ios::ate | std::ios::binary);
size_t fileSize = (size_t)file.tellg();
char* ttfData = (char*)calloc(fileSize + 1, sizeof(char));
file.seekg(0);
file.read(ttfData, fileSize);
file.close();
// Pack TTF into pixel data using stb_truetype.
stbtt_pack_context packContext;
stbtt_packedchar *charData = (stbtt_packedchar*)calloc(126, sizeof(stbtt_packedchar));
unsigned char* pixels = (unsigned char*)calloc(1024 * 1024, sizeof(char));
stbtt_PackBegin(&packContext, pixels, 1024, 1024, 1024, 1, NULL);
// Pack unicode codepoints 0 to 125 into the texture and character data. If a different starting
// point than 0 is picked then lookups in charData array must be offset by that number.
// With 0-125 the uppercase A will be at charData[65].
// With 32-125 the uppercase A will be at charData[65-32].
stbtt_PackFontRange(&packContext, (unsigned char*)ttfData, 0, 200.0f, 0, 125, charData);
stbtt_PackEnd(&packContext);
// Create OpenGL texture with the font pack pixel data.
// Only uses one color channel since font data is a monochrome alpha mask.
GLuint fontTexture;
glGenTextures(1, &fontTexture);
glBindTexture(GL_TEXTURE_2D, fontTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 1024, 1024, 0, GL_RED, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return charData;
}
// Calculate pixel width of a string.
float TextWidth(const char* text, float height, stbtt_packedchar *charData) {
float w = 0.0f;
for (int i = 0; i < strlen(text); i++) {
stbtt_packedchar c = charData[text[i]];
w += c.xadvance;
}
// Scale width by rendered height to texture generated height ratio for final size.
return w * (height / 200.0f);
}
// Render string using glDrawArrays.
// X indicates the leftmost, center or rightmost point of the based on align (0:left, 1:center, 2:rigght).
// Y is the baseline of the text.
void RenderString(const char* text, float x, float y, float height, int align, stbtt_packedchar *charData, GLuint program) {
// Scale of actual text compared to size on stb_truetype generated texture.
float scale = height / 200.0f;
// Resolution of window/display for shader position calculations.
float resolution[2] = { 1024, 1024 };
float position[2] = {x, y};
if (align == 1) {
// Center align
position[0] -= TextWidth(text, height, charData) / 2.0f;
} else if (align == 2) {
// Right align
position[0] -= TextWidth(text, height, charData);
}
glUniform2fv(glGetUniformLocation(program, "resolution"), 1, resolution);
for (int i = 0; i < strlen(text); i++) {
// Lookup current character data from stb_truetype.
stbtt_packedchar c = charData[text[i]];
// Position of character in texture.
float charPosition[4] = {static_cast<float>(c.x0), static_cast<float>(c.y0), static_cast<float>(c.x1), static_cast<float>(c.y1)};
// Find the actual size of character since fonts can be variable width.
// 'M' usually is wider than '!', 'L' taller than 'o', etc.
// Calculated by substracting start-offset from end-offset.
// xoff is start offset from the left.
// xoff2 is end offset from the left.
// yoff is start offset from the baseline (will be negative if above baseline).
// yoff2 is end offset from the baseline.
float size[2] = {(c.xoff2 - c.xoff) * scale, (c.yoff2 - c.yoff) * scale};
// The actual position of character based on its offset form left/baseline.
float renderPos[2] = {position[0] + c.xoff * scale, position[1] - c.yoff2 * scale};
glUniform4fv(glGetUniformLocation(program, "charPosition"), 1, charPosition);
glUniform2fv(glGetUniformLocation(program, "position"), 1, renderPos);
glUniform2fv(glGetUniformLocation(program, "size"), 1, size);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Advance x position to start of next character.
position[0] += c.xadvance * scale;
}
}
///////////////////////////////////////////
void textInit(std::string p) {
fontPath = p;
ttf.reserve(1<<20);
unsigned char temp_bitmap[1024*1024]; unsigned char temp_bitmap[1024*1024];
std::ifstream file(path, std::ios::binary); std::ifstream file(fontPath, std::ios::binary);
file.seekg(0, std::ios::end);
auto&& size = file.tellg();
file.seekg(0, std::ios::beg);
ttf.reserve(size);
if(!file.is_open()) { if(!file.is_open()) {
std::cout << "ttf won't open!\n"; std::cout << "ttf won't open!\n";
@@ -43,23 +179,35 @@ namespace Archimedes {
file.close(); file.close();
stbtt_BakeFontBitmap(ttf.data(),0, 64.0, temp_bitmap,1024,1024, 32,96, cdata); stbtt_BakeFontBitmap(ttf.data(),0, 200.0f, temp_bitmap,1024,1024, 32,96, cdata);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex); std::vector<unsigned char> bin;
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 1024,1024,0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); bin.reserve(1024 * 1024);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
for(unsigned char c : temp_bitmap) {
bin.push_back(c);
}
shader = Shader(vs, fs, Shader::LoadType::FromSource);
texture = Texture(bin, 1024, 1024);
} }
Body* genText(float x, float y, std::string text) { Body* genText(std::vector<std::string> texts) {
// assume orthographic projection with units = screen pixels, origin at top left // assume orthographic projection with units = screen pixels, origin at top left
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
std::vector<float> v; std::vector<float> v;
std::vector<unsigned int> i; std::vector<unsigned int> i;
float x = 0, y = 0, oX = 0, dY = 0;
std::string text = "";
for(std::string s : texts) {
text += s + " ";
}
for(unsigned int j = 0; j < text.length(); j++) { for(unsigned int j = 0; j < text.length(); j++) {
if (text[j] >= 32) { if (text[j] >= 32) {
stbtt_aligned_quad q; stbtt_aligned_quad q;
@@ -72,7 +220,6 @@ namespace Archimedes {
v.push_back(q.s0); v.push_back(q.s0);
v.push_back(q.t0); v.push_back(q.t0);
i.push_back(j * 4);
v.push_back(q.x1); v.push_back(q.x1);
@@ -82,7 +229,6 @@ namespace Archimedes {
v.push_back(q.s1); v.push_back(q.s1);
v.push_back(q.t0); v.push_back(q.t0);
i.push_back(j * 4 + 1);
@@ -93,7 +239,6 @@ namespace Archimedes {
v.push_back(q.s1); v.push_back(q.s1);
v.push_back(q.t1); v.push_back(q.t1);
i.push_back(j * 4 + 2);
@@ -104,15 +249,27 @@ namespace Archimedes {
v.push_back(q.s0); v.push_back(q.s0);
v.push_back(q.t1); v.push_back(q.t1);
i.push_back(j * 4);
i.push_back(j * 4 + 1);
i.push_back(j * 4 + 2);
i.push_back(j * 4 + 2);
i.push_back(j * 4 + 3); i.push_back(j * 4 + 3);
i.push_back(j * 4);
dY = q.y1 - q.y0;
} }
} }
return new Body( return new Body(
VertexBuffer(v), VertexBuffer(v),
IndexArray(i), IndexArray(i),
VertexLayout(), VertexLayout({
Shader() LayoutElement(LayoutElement::Type::Float, 3, 5 * sizeof(float), 0),
LayoutElement(LayoutElement::Type::Float, 2, 5 * sizeof(float), 3 * sizeof(float))
}),
shader,
texture
); );
} }
}; };
@@ -122,10 +279,10 @@ namespace Archimedes {
class JObject { class JObject {
public: public:
JObject() = default; JObject() {}
void load(std::string path) { void load(std::string pathJSON, std::string pathFont) {
std::ifstream file(path); std::ifstream file(pathJSON);
if (!file.is_open()) goodJSON = false; if (!file.is_open()) goodJSON = false;
document = json::parse(file); document = json::parse(file);
file.close(); file.close();
@@ -136,6 +293,8 @@ namespace Archimedes {
cameras = document["Cameras"]; cameras = document["Cameras"];
lights = document["Lights"]; lights = document["Lights"];
actions = document["Actions"]; actions = document["Actions"];
text.textInit(pathFont);
} }
bool isValid() const { return goodJSON; } bool isValid() const { return goodJSON; }
@@ -157,8 +316,9 @@ namespace Archimedes {
return new Body( return new Body(
VertexBuffer(v), VertexBuffer(v),
IndexArray(i), IndexArray(i),
VertexLayout(), layout,
shader, shader,
std::nullopt,
RenderMode::ConnectedLinesLooped RenderMode::ConnectedLinesLooped
); );
@@ -197,8 +357,9 @@ namespace Archimedes {
return new Body( return new Body(
VertexBuffer(v), VertexBuffer(v),
IndexArray(i), IndexArray(i),
VertexLayout(), layout,
shader, shader,
std::nullopt,
RenderMode::ConnectedLinesLooped RenderMode::ConnectedLinesLooped
); );
} }
@@ -237,8 +398,9 @@ namespace Archimedes {
return new Body( return new Body(
VertexBuffer(v), VertexBuffer(v),
IndexArray(i), IndexArray(i),
VertexLayout(), layout,
shader, shader,
std::nullopt,
RenderMode::ConnectedLinesLooped RenderMode::ConnectedLinesLooped
); );
} }
@@ -262,24 +424,25 @@ namespace Archimedes {
return new Body( return new Body(
VertexBuffer(v), VertexBuffer(v),
IndexArray(i), IndexArray(i),
VertexLayout(), layout,
shader, shader,
std::nullopt,
RenderMode::ConnectedLinesLooped RenderMode::ConnectedLinesLooped
); );
} }
Body* createText(json& element, std::string name) { Body* createText(json& element, std::string name) {
std::vector<float> v;
std::vector<unsigned int> i;
//do something //do something
json lines = element["text"];
return new Body( std::vector<std::string> theText;
VertexBuffer(v), for (json::const_iterator it = lines.cbegin(); it != lines.cend(); it++)
IndexArray(i), {
VertexLayout(), std::string line = *it;
shader theText.push_back(line);
); }
return text.genText(theText);
} }
void buildObjects() { void buildObjects() {
@@ -303,7 +466,7 @@ namespace Archimedes {
objectMap[name] = createPoly(element, name); objectMap[name] = createPoly(element, name);
} }
if (type == "TEXT") { if (type == "TEXT") {
objectMap[name] = nullptr; objectMap[name] = createText(element, name);
} }
} }
@@ -355,8 +518,13 @@ namespace Archimedes {
std::unordered_map<std::string, Body*> objectMap; std::unordered_map<std::string, Body*> objectMap;
Shader shader; Shader shader;
Text text;
private: private:
Archimedes::VertexLayout layout = Archimedes::VertexLayout({
Archimedes::LayoutElement(Archimedes::LayoutElement::Type::Float, 3, 0, 0)
});
std::unordered_map<std::string, Body> templateMap; std::unordered_map<std::string, Body> templateMap;

View File

@@ -3,6 +3,8 @@
#include "Sandbox.h" #include "Sandbox.h"
#define STB_TRUETYPE_IMPLEMENTATION
#include <stb/stb_truetype.h>
Sandbox::Sandbox(Archimedes::App* a, void* h) : Archimedes::Module(a, h) { Sandbox::Sandbox(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
@@ -58,7 +60,7 @@ void Sandbox::onLoad() {
cube = Archimedes::Body( cube = Archimedes::Body(
Archimedes::VertexBuffer(vertices), Archimedes::VertexBuffer(vertices),
Archimedes::IndexArray(indices), Archimedes::IndexArray(indices),
Archimedes::VertexLayout(), layout,
cubeShader cubeShader
); );
@@ -67,7 +69,7 @@ void Sandbox::onLoad() {
grid = Archimedes::Body( grid = Archimedes::Body(
Archimedes::VertexBuffer(gridVertices), Archimedes::VertexBuffer(gridVertices),
Archimedes::IndexArray(gridIndices), Archimedes::IndexArray(gridIndices),
Archimedes::VertexLayout(), layout,
cubeShader cubeShader
); );
@@ -115,7 +117,7 @@ void Sandbox::run() {
camera.setTransform(glm::lookAt( camera.setTransform(glm::lookAt(
camPos, camPos,
glm::normalize(glm::vec3(glm::cos(camRot.x) * glm::sin(camRot.y), glm::sin(camRot.x), glm::cos(camRot.x) * glm::cos(camRot.y))), camPos + glm::normalize(glm::vec3(glm::cos(camRot.x) * glm::sin(camRot.y), glm::sin(camRot.x), glm::cos(camRot.x) * glm::cos(camRot.y))),
glm::vec3(0.0f, 1.0f, 0.0f) glm::vec3(0.0f, 1.0f, 0.0f)
)); ));
@@ -209,13 +211,18 @@ void Sandbox::run() {
} else { } else {
static std::string path = "/home/nathan/Projects/tests/buildzone/test.json"; static std::string pathJSON = "/home/nathan/Projects/tests/buildzone/test.json";
ImGui::InputText("JSON Path", &path); static std::string pathFont = "/nix/store/05zf1s3wlw0k90l34iaby4ysrafv6w95-nerd-fonts-fira-code-3.4.0+6.2/share/fonts/truetype/NerdFonts/FiraCode/FiraCodeNerdFontMono-Regular.ttf";
ImGui::InputText("JSON Path", &pathJSON);
ImGui::InputText("Font Path", &pathFont);
if(ImGui::Button("load")) { if(ImGui::Button("load")) {
jObject.shader = cubeShader; jObject.shader = cubeShader;
jObject.load(path); jObject.load(pathJSON, pathFont);
window->getRenderer()->setupShader(jObject.text.shader);
//window->getRenderer()->setupTexture(jObject.text.texture);
jObject.buildObjects(); jObject.buildObjects();
@@ -258,7 +265,15 @@ bool Sandbox::onEvent(const Archimedes::Event& e) {
ImGuiIO& io = ImGui::GetIO(); (void)io; ImGuiIO& io = ImGui::GetIO(); (void)io;
if(type == app->getEventType(Archimedes::KeyPressedWindowEvent()) && !io.WantCaptureKeyboard) { if(type == app->getEventType(Archimedes::ResizeWindowEvent())) {
Archimedes::ResizeWindowEvent event = (Archimedes::ResizeWindowEvent&) e;
for(auto o : jObject.objectMap) {
if(o.second != nullptr) {
o.second->scaleRel(1.0f / (float)event.height);
}
}
} else if(type == app->getEventType(Archimedes::KeyPressedWindowEvent()) && !io.WantCaptureKeyboard) {
return false; return false;
} else if(type == app->getEventType(Archimedes::KeyReleasedWindowEvent()) && !io.WantCaptureKeyboard) { } else if(type == app->getEventType(Archimedes::KeyReleasedWindowEvent()) && !io.WantCaptureKeyboard) {

View File

@@ -59,6 +59,10 @@ class Sandbox : public Archimedes::Module {
Archimedes::Shader cubeShader, gridShader; Archimedes::Shader cubeShader, gridShader;
Archimedes::Body cube, grid, hexagon; Archimedes::Body cube, grid, hexagon;
Archimedes::VertexLayout layout = Archimedes::VertexLayout({
Archimedes::LayoutElement(Archimedes::LayoutElement::Type::Float, 3, 0, 0)
});
Archimedes::Camera camera; Archimedes::Camera camera;
std::vector<float> gridVertices = { std::vector<float> gridVertices = {