07: Add basic boilerplate for batching

This commit is contained in:
Kevin J. 2023-12-15 21:43:42 +01:00
parent ced87e0af1
commit 6fdbcc8825
32 changed files with 8637 additions and 27 deletions

View File

@ -25,6 +25,18 @@
/processorParam:TextureFormat=Color /processorParam:TextureFormat=Color
/build:button-default-texture.png /build:button-default-texture.png
#begin button.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:button.png
#begin Fonts/default.spritefont #begin Fonts/default.spritefont
/importer:FontDescriptionImporter /importer:FontDescriptionImporter
/processor:LocalizedFontProcessor /processor:LocalizedFontProcessor

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -29,8 +29,7 @@ public class Game1 : Game
Scene.content = Content; Scene.content = Content;
mainScene = new Scene(); mainScene = new Scene();
DrawableData drawableData = new DrawableData(null); DrawableData drawableData = new DrawableData("button");
drawableData.scale = new Vector2(120.0f, 40.0f);
drawableData.position = new Vector2(100.0f, 100.0f); drawableData.position = new Vector2(100.0f, 100.0f);
void buttonOnClick(Button obj) void buttonOnClick(Button obj)
@ -39,8 +38,6 @@ public class Game1 : Game
} }
ButtonData buttonData = new ButtonData(buttonOnClick); ButtonData buttonData = new ButtonData(buttonOnClick);
buttonData.bgColor = Color.Red;
buttonData.fgColor = Color.White;
buttonData.text = "Click me!"; buttonData.text = "Click me!";
Button mainButton = new Button(drawableData, buttonData); Button mainButton = new Button(drawableData, buttonData);

View File

@ -12,14 +12,14 @@ public class ButtonData
public Color bgColor; public Color bgColor;
public Color fgColor; public Color fgColor;
public Color hoverBgColor; public Color? hoverBgColor;
public Color hoverFgColor; public Color? hoverFgColor;
public Color pressedBgColor; public Color? pressedBgColor;
public Color pressedFgColor; public Color? pressedFgColor;
public Color idleBgColor; public Color idleBgColor = Color.Black;
public Color idleFgColor; public Color idleFgColor = Color.White;
public bool isPressed = false; public bool isPressed = false;
public bool isReleased = false; public bool isReleased = false;
@ -31,6 +31,7 @@ public class ButtonData
public string text = ""; public string text = "";
public Vector2 textPosition; public Vector2 textPosition;
public Vector2 textResolution; public Vector2 textResolution;
public Vector2 textScale;
public ButtonData(Action<Button>? onClick) public ButtonData(Action<Button>? onClick)
{ {
@ -61,9 +62,8 @@ public class Button : Drawable
if (_buttonData.isPressed) if (_buttonData.isPressed)
return; return;
Console.WriteLine("I'm being pressed!"); _buttonData.bgColor = _buttonData.pressedBgColor ?? _buttonData.idleBgColor;
_buttonData.bgColor = Color.Red; _buttonData.fgColor = _buttonData.pressedFgColor ?? _buttonData.idleFgColor;
_buttonData.fgColor = Color.Black;
if (_buttonData.onClick is not null) if (_buttonData.onClick is not null)
_buttonData.onClick(this); _buttonData.onClick(this);
@ -77,8 +77,8 @@ public class Button : Drawable
if (!_buttonData.isPressed) if (!_buttonData.isPressed)
return; return;
_buttonData.bgColor = Color.Yellow; _buttonData.bgColor = _buttonData.hoverBgColor ?? _buttonData.idleBgColor;
_buttonData.fgColor = Color.Red; _buttonData.fgColor = _buttonData.hoverFgColor ?? _buttonData.idleFgColor;
_buttonData.isPressed = false; _buttonData.isPressed = false;
_buttonData.isReleased = true; _buttonData.isReleased = true;
@ -89,17 +89,16 @@ public class Button : Drawable
if (_buttonData.isHovered) if (_buttonData.isHovered)
return; return;
Console.WriteLine("I'm being hovered!"); _buttonData.bgColor = _buttonData.hoverBgColor ?? _buttonData.idleBgColor;
_buttonData.bgColor = Color.Yellow; _buttonData.fgColor = _buttonData.hoverFgColor ?? _buttonData.idleFgColor;
_buttonData.fgColor = Color.Red;
_buttonData.isHovered = true; _buttonData.isHovered = true;
} }
void onIdle() void onIdle()
{ {
_buttonData.bgColor = Color.Red; _buttonData.bgColor = _buttonData.idleBgColor;
_buttonData.fgColor = Color.Yellow; _buttonData.fgColor = _buttonData.idleFgColor;
_buttonData.isPressed = false; _buttonData.isPressed = false;
_buttonData.isReleased = false; _buttonData.isReleased = false;
@ -141,7 +140,7 @@ public class Button : Drawable
_buttonData.textResolution = buttonFont.MeasureString(_buttonData.text); _buttonData.textResolution = buttonFont.MeasureString(_buttonData.text);
// we want to center the text so // we want to center the text so
Vector2 buttonCenter = (_drawableData.position + (_drawableData.scale / 2.0f)); Vector2 buttonCenter = (_drawableData.position + (Vector2.One / 2.0f));
Vector2 textHalfResolution = _buttonData.textResolution / 2.0f; Vector2 textHalfResolution = _buttonData.textResolution / 2.0f;
_buttonData.textPosition = buttonCenter - textHalfResolution; _buttonData.textPosition = buttonCenter - textHalfResolution;
@ -153,10 +152,10 @@ public class Button : Drawable
_drawableData.texture, _drawableData.texture,
_drawableData.position, _drawableData.position,
null, null,
_buttonData.bgColor, Color.White,
_drawableData.rotation, _drawableData.rotation,
Vector2.Zero, Vector2.Zero,
_drawableData.scale, _drawableData.scale,
SpriteEffects.None, SpriteEffects.None,
0f 0f
); );
@ -168,7 +167,7 @@ public class Button : Drawable
_buttonData.fgColor, _buttonData.fgColor,
_drawableData.rotation, _drawableData.rotation,
Vector2.Zero, Vector2.Zero,
Vector2.One, _drawableData.scale,
SpriteEffects.None, SpriteEffects.None,
0f, 0f,
false false

View File

@ -9,14 +9,23 @@ public class DrawableData
{ {
public Texture2D texture; public Texture2D texture;
public Vector2 position = Vector2.Zero; public Vector2 position = Vector2.Zero;
public Vector2 scale = Vector2.One; private Vector2 scale_multiplier = Vector2.One;
public Vector2 scale
{
get { return scale_multiplier * new Vector2(texture.Width, texture.Height); }
set
{
scale_multiplier = value;
}
}
public float rotation = 0.0f; public float rotation = 0.0f;
public DrawableData(Texture2D? texture) public DrawableData(string? texture)
{ {
if (texture is not null) if (texture is not null)
{ {
this.texture = texture; this.texture = Scene.content.Load<Texture2D>(texture);
return; return;
} }

28
07-boilerplate/Makefile Normal file
View File

@ -0,0 +1,28 @@
CC=g++
CFLAGS=-std=c++20 `pkg-config --cflags glfw3 glew glm`
LDFLAGS=`pkg-config --libs glfw3 glew glm`
TARGET=boilerplate
SDIR=src
ADIR=assets
ODIR=build
SRC=$(shell find $(SDIR) -type f -name *.cpp)
OBJ=$(SRC:.cpp=.o)
all: $(TARGET)
.PHONY: default
$(TARGET): $(OBJ)
mkdir -p build
cp -rf $(ADIR) $(ODIR)/$(ADIR)
$(CC) -o $(ODIR)/$@ $^ $(LDFLAGS)
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $<
run:
$(ODIR)/$(TARGET)
.PHONY: clean
clean:
rm -f $(ODIR)/$(TARGET) $(OBJ)

3
07-boilerplate/README.md Normal file
View File

@ -0,0 +1,3 @@
# Boilerplate API
Creating a boilerplate API to abstract away OpenGL

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,12 @@
#version 330 core
in vec4 _color;
in vec2 _texture_position;
in float _ctt;
out vec4 color;
void main() {
// color = texture(sampler, _texture_position);
//color = vec4(1.0, 1.0, 1.0, 1.0);
color = _color;
}

View File

@ -0,0 +1,23 @@
#version 330 core
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 origin;
layout (location = 2) in vec4 color;
layout (location = 3) in vec2 texture_position;
layout (location = 4) in float ctt;
uniform mat4 view_matrix;
uniform mat4 projection_matrix;
out vec4 _color;
out vec2 _texture_position;
out float _ctt;
void main() {
vec3 origined_position = origin.xyz + position.xyz;
//gl_Position = projection_matrix * view_matrix * position;
gl_Position = projection_matrix * view_matrix * vec4(position.xyz, 1.0);
_color = color;
_texture_position = texture_position;
_ctt = ctt;
}

View File

@ -0,0 +1,13 @@
#version 330 core
out vec4 color;
in vec2 tex_coord;
uniform sampler2D sampler;
void main() {
color = texture(sampler, tex_coord);
// color = vec4(1.0, 0.0, 0.0, 1.0);
if (color.a < 0.1)
discard;
}

View File

@ -0,0 +1,14 @@
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texture_coord;
uniform mat4 view;
uniform mat4 projection;
out vec2 tex_coord;
void main() {
gl_Position = projection * view * vec4(pos.xyz, 1.0);
tex_coord = texture_coord;
}

View File

@ -0,0 +1,22 @@
#include <iostream>
#include <fstream>
#include "common.hpp"
std::string read_file(const char *path) {
std::string content;
std::ifstream fs(path, std::ios::in);
if(!fs.is_open()) {
std::cerr << "Error: Could not read file " << path << ". File does not exist." << std::endl;
return NULL;
}
std::string line = "";
while(!fs.eof()) {
std::getline(fs, line);
content.append(line + "\n");
}
fs.close();
return content;
}

View File

@ -0,0 +1,5 @@
#pragma once
#include <string>
std::string read_file(const char *path);

View File

@ -0,0 +1,10 @@
#pragma once
#define DEFAULT_POSITION_ATTRIBUTE 0
#define DEFAULT_ORIGIN_ATTRIBUTE 1
#define DEFAULT_COLOR_ATTRIBUTE 2
#define DEFAULT_TEXTURE_ATTRIBUTE 3
#define DEFAULT_CTT_ATTRIBUTE 4
#define QUAD 6
#define DEFAULT_VBO_SIZE QUAD * 1000 // unit: rows of RenderData

View File

@ -0,0 +1,38 @@
#include <iostream>
#include <GL/glew.h>
#include "program.hpp"
#include "../macros.hpp"
Program::Program() {
this->id = glCreateProgram();
}
int Program::add_shader(const char *path, unsigned int type) {
Shader new_shader;
unsigned int ret = new_shader.load(path, type);
if (!ret)
return RET_ERR;
this->shaders.push_back(new_shader);
return 0;
}
int Program::link() {
for (int shader = 0; shader < this->shaders.size(); shader++)
glAttachShader(this->id, this->shaders[shader].id);
glLinkProgram(this->id);
int success;
char info_log[512];
glGetProgramiv(this->id, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(this->id, 512, NULL, info_log);
return RET_ERR;
}
return 0;
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <GL/glew.h>
#include <vector>
#include "shader.hpp"
struct Program {
GLuint id;
std::vector<Shader> shaders;
Program();
int add_shader(const char *path, unsigned int type);
int link();
};

View File

@ -0,0 +1,142 @@
#include <optional>
#include <glm/vec3.hpp>
#include <glm/mat4x4.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "renderer.hpp"
#include "../macros.hpp"
#include "graphics.hpp"
Renderer::Renderer(Window &window) : window(window) {
pack = RendererPack();
this->window = window;
glGenBuffers(1, &this->vertex_buffer_id);
glGenVertexArrays(1, &this->array_buffer_id);
this->view_matrix = glm::mat4(1.0f);
this->projection_matrix = glm::mat4(1.0f);
}
int Renderer::setup(std::optional<Program> program) {
int ret;
if (program != std::nullopt)
this->program = program.value();
else {
Program new_program = Program();
ret = new_program.add_shader("assets/shaders/default_vertex.glsl", GL_VERTEX_SHADER);
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed adding vertex shader to program");
return RET_ERR;
}
ret = new_program.add_shader("assets/shaders/default_fragment.glsl", GL_FRAGMENT_SHADER);
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed adding fragment shader to program");
return RET_ERR;
}
ret = new_program.link();
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed linking program");
return RET_ERR;
}
this->program = new_program;
}
glBindVertexArray(this->array_buffer_id);
glBindBuffer(GL_ARRAY_BUFFER, this->vertex_buffer_id);
glBufferData(GL_ARRAY_BUFFER, sizeof(struct RendererData) * DEFAULT_VBO_SIZE, nullptr, GL_DYNAMIC_DRAW);
glVertexAttribPointer(
DEFAULT_POSITION_ATTRIBUTE,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, vertex)
);
glEnableVertexAttribArray(DEFAULT_POSITION_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_ORIGIN_ATTRIBUTE,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, origin)
);
glEnableVertexAttribArray(DEFAULT_ORIGIN_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_COLOR_ATTRIBUTE,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, color)
);
glEnableVertexAttribArray(DEFAULT_COLOR_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_TEXTURE_ATTRIBUTE,
2,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, tex)
);
glEnableVertexAttribArray(DEFAULT_TEXTURE_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_COLOR_ATTRIBUTE,
1,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, ctt_ratio)
);
glEnableVertexAttribArray(DEFAULT_CTT_ATTRIBUTE);
// setup matrices
this->view_matrix = glm::translate(this->view_matrix, glm::vec3(0.0f, 0.0f, -3.0f));
return RET_OK;
}
void Renderer::render() {
glBindVertexArray(this->array_buffer_id);
glBindBuffer(GL_ARRAY_BUFFER, this->vertex_buffer_id);
glUseProgram(this->program.id);
glUniformMatrix4fv(glGetUniformLocation(this->program.id, "view_matrix"), 1, GL_FALSE, &this->view_matrix[0][0]);
glUniformMatrix4fv(glGetUniformLocation(this->program.id, "projection_matrix"), 1, GL_FALSE, &this->projection_matrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, DEFAULT_VBO_SIZE);
}
void Renderer::logic() {
int window_width;
int window_height;
float half_width;
float half_height;
this->window.get_size(&window_width, &window_height);
half_width = window_width / 2.0f;
half_height = window_height / 2.0f;
this->projection_matrix = glm::ortho(-half_width/100, half_width/100, -half_height/100, half_height/100, 0.1f, 100.0f);
}
Renderer::~Renderer() {
glDisableVertexAttribArray(DEFAULT_POSITION_ATTRIBUTE);
glDisableVertexAttribArray(DEFAULT_COLOR_ATTRIBUTE);
glDisableVertexAttribArray(DEFAULT_TEXTURE_ATTRIBUTE);
glDisableVertexAttribArray(DEFAULT_CTT_ATTRIBUTE);
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <GL/glew.h>
#include <optional>
#include <glm/mat4x4.hpp>
#include "renderer_pack.hpp"
#include "program.hpp"
#include "../window/window.hpp"
class Renderer {
public:
GLuint array_buffer_id;
GLuint vertex_buffer_id;
Program program;
RendererPack pack;
glm::mat4 view_matrix;
glm::mat4 projection_matrix;
Window &window;
Renderer(Window &window);
~Renderer();
int setup(std::optional<Program> program = std::nullopt);
void logic();
void render();
};

View File

@ -0,0 +1,9 @@
#include "renderer_pack.hpp"
RendererPack::RendererPack() {
this->data = std::vector<struct RendererData>();
}
RendererPack::~RendererPack(){
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <iostream>
#include <vector>
#include <glm/vec4.hpp>
#include <glm/vec2.hpp>
struct RendererData {
glm::vec4 vertex;
glm::vec4 origin;
glm::vec4 color;
glm::vec2 tex;
float ctt_ratio; // color to texture ratio (i.e. how much does the color affect the texture)
};
class RendererPack {
public:
std::vector<struct RendererData> data;
RendererPack();
~RendererPack();
};

View File

@ -0,0 +1,33 @@
#include <iostream>
#include <GL/glew.h>
#include "shader.hpp"
#include "../common.hpp"
#include "../macros.hpp"
unsigned int Shader::load(const char *path, unsigned int type) {
std::string source_s = read_file(path);
const char *source = source_s.c_str();
unsigned int new_shader = glCreateShader(type);
if (!new_shader)
return 0;
glShaderSource(new_shader, 1, &source, NULL);
glCompileShader(new_shader);
int success;
char info_log[512];
glGetShaderiv(new_shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(new_shader, 512, NULL, info_log);
std::cout << "Error: failed compiling new shader " << info_log << std::endl;
LOG(LOG_ERR, "Failed compiling new shader");
return RET_OK;
}
this->id = new_shader;
this->type = type;
return new_shader;
}

View File

@ -0,0 +1,8 @@
#pragma once
struct Shader {
unsigned int id;
unsigned int type;
unsigned int load(const char *path, unsigned int type);
};

View File

@ -0,0 +1,12 @@
#pragma once
#include <iostream>
#define LOG_DEBUG "debug"
#define LOG_WARN "warning"
#define LOG_ERR "error"
#define LOG(level, ...) std::cout << "[" << __TIME__ << " " << level << "]: " << __VA_ARGS__ << std::endl;
#define RET_OK 0
#define RET_ERR -1

View File

@ -0,0 +1,39 @@
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "window.hpp"
#include "../macros.hpp"
int Window::init(int width, int height, std::string title) {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
this->window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
if (this->window == NULL) {
LOG(LOG_ERR, "Failed creating window");
glfwTerminate();
return RET_ERR;
}
glfwMakeContextCurrent(this->window);
GLenum err = glewInit();
if (err != GLEW_OK) {
LOG(LOG_ERR, "FAiled initializing Glew");
return RET_ERR;
}
glfwSetFramebufferSizeCallback(this->window, this->resize_callback);
return RET_OK;
}
void Window::resize_callback(GLFWwindow *window, int new_width, int new_height) {
glViewport(0, 0, new_width, new_height);
}
void Window::get_size(int *width, int *height) {
glfwGetWindowSize(this->window, width, height);
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <iostream>
#include <GLFW/glfw3.h>
class Window {
public:
int init(int width, int height, std::string title);
static void resize_callback(GLFWwindow *window, int new_width, int new_height);
void get_size(int *width, int *height);
GLFWwindow *window;
};

View File

@ -0,0 +1,46 @@
#include <iostream>
#include <fstream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stb/stb_image.h>
#include "base/window/window.hpp"
#include "base/graphics/renderer.hpp"
#include "base/macros.hpp"
#include "sprites/sprite.hpp"
const int initial_width = 1000;
const int initial_height = 600;
int main() {
Window window;
window.init(initial_width, initial_height, "OpenGL");
Renderer main_renderer(window);
int ret = main_renderer.setup();
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed setting up a new renderer");
return RET_ERR;
}
Sprite new_sprite(main_renderer.vertex_buffer_id);
new_sprite.bake();
new_sprite.origin = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
new_sprite.color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);
while (!glfwWindowShouldClose(window.window)) {
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
new_sprite.update();
main_renderer.logic();
main_renderer.render();
glfwPollEvents();
glfwSwapBuffers(window.window);
}
glfwTerminate();
return RET_OK;
}

View File

@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
#include <iostream>
#include <vector>
#include <glm/vec4.hpp>
#include <glm/vec2.hpp>
#include <GL/glew.h>
#include "../base/graphics/renderer_pack.hpp"
#include "sprite.hpp"
Sprite::Sprite(GLuint vertex_buffer_id) {
this->vertices = std::vector<glm::vec4>();
this->origin = glm::vec4(1.0f);
this->color = glm::vec4(1.0f);
this->texture_position = glm::vec2(0.0f);
this->ctt = 1.0f;
this->vertex_buffer_id = vertex_buffer_id;
}
void Sprite::bake() {
this->vertices.push_back(glm::vec4(0.5f, 0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(0.5f, -0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(-0.5f, -0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(-0.5f, 0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(0.5f, 0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(-0.5f, -0.5f, 0.0f, 0.0f));
}
void Sprite::update() {
for (int i = 0; i < this->vertices.size(); i++) {
struct RendererData data = {
.vertex = this->vertices[i],
.origin = this->origin,
.color = this->color,
.tex = this->texture_position,
.ctt_ratio = this->ctt
};
glBindBuffer(GL_ARRAY_BUFFER, this->vertex_buffer_id);
glBufferSubData(GL_ARRAY_BUFFER, i*sizeof(struct RendererData), sizeof(struct RendererData), &data);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
Sprite::~Sprite() {
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <iostream>
#include <vector>
#include <glm/vec4.hpp>
#include <glm/vec2.hpp>
#include <GL/glew.h>
class Sprite {
public:
std::vector<glm::vec4> vertices;
glm::vec4 origin;
glm::vec4 color;
glm::vec2 texture_position;
float ctt;
GLuint vertex_buffer_id;
Sprite(GLuint vertex_buffer_id);
~Sprite();
void bake();
void update();
};