Text now renders and have a framebuffer system to potentially only render once then reuse the image.

master
Zed A. Shaw 3 weeks ago
parent f2c6110058
commit 21ad27d146
  1. BIN
      assets/fonts/text.ttf
  2. 11
      meson.build
  3. 11
      shaders/screen.frag.glsl
  4. 11
      shaders/screen.vert.glsl
  5. 12
      shaders/text.frag.glsl
  6. 11
      shaders/text.vert.glsl
  7. 311
      src/KHR/khrplatform.h
  8. 6
      src/config.hpp
  9. 16
      src/dbc.cpp
  10. 17
      src/dbc.hpp
  11. 55
      src/framebuffer.cpp
  12. 17
      src/framebuffer.hpp
  13. 1140
      src/glad/glad.cpp
  14. 2129
      src/glad/glad.h
  15. 142
      src/main.cpp
  16. 18
      src/screen.cpp
  17. 23
      src/screen.hpp
  18. 148
      src/shader.cpp
  19. 37
      src/shader.hpp
  20. 2
      src/stb_image.cpp
  21. 7988
      src/stb_image.h
  22. 114
      src/text.cpp
  23. 24
      src/text.hpp
  24. 11
      wraps/freetype2.wrap
  25. 13
      wraps/glfw.wrap
  26. 13
      wraps/glm.wrap

Binary file not shown.

@ -21,15 +21,24 @@ exe_defaults = [ 'warning_level=2', 'werror=false']
fmt = subproject('fmt').get_variable('fmt_dep')
fuc2 = subproject('fuc2').get_variable('fuc2_dep')
sol2 = subproject('sol2').get_variable('sol2_dep')
glfw3 = subproject('glfw').get_variable('glfw_dep')
glm = subproject('glm').get_variable('glm_dep')
freetype2 = subproject('freetype2').get_variable('freetype_dep')
dependencies = [fmt, fuc2, sol2]
dependencies = [fmt, fuc2, sol2, glfw3, glm, freetype2]
sources = [
'src/glad/glad.cpp',
'src/stb_image.cpp',
'src/shader.cpp',
'src/text.cpp',
'src/stats.cpp',
'src/dbc.cpp',
'src/builder.cpp',
'src/bezos.cpp',
'src/document.cpp',
'src/framebuffer.cpp',
'src/screen.cpp',
]
tests = [

@ -0,0 +1,11 @@
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D screenTexture;
void main()
{
FragColor = texture(screenTexture, TexCoords);
}

@ -0,0 +1,11 @@
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
TexCoords = aTexCoords;
}

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

@ -0,0 +1,11 @@
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>
out vec2 TexCoords;
uniform mat4 projection;
void main()
{
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
TexCoords = vertex.zw;
}

@ -0,0 +1,311 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */

@ -0,0 +1,6 @@
#pragma once
#define INSTANCE_COUNT 5
const unsigned int SCR_WIDTH = 1792;
const unsigned int SCR_HEIGHT = 1008;

@ -9,16 +9,16 @@ void dbc::log(const string &message, const std::source_location location) {
}
void dbc::sentinel(const string &message, const std::source_location location) {
string err = fmt::format("[SENTINEL!] {}", message);
string err = $F("[SENTINEL!] {}", message);
dbc::log(err, location);
throw dbc::SentinelError{err};
throw dbc::SentinelError(err);
}
void dbc::pre(const string &message, bool test, const std::source_location location) {
if(!test) {
string err = fmt::format("[PRE!] {}", message);
string err = $F("[PRE!] {}", message);
dbc::log(err, location);
throw dbc::PreCondError{err};
throw dbc::PreCondError(err);
}
}
@ -28,9 +28,9 @@ void dbc::pre(const string &message, std::function<bool()> tester, const std::so
void dbc::post(const string &message, bool test, const std::source_location location) {
if(!test) {
string err = fmt::format("[POST!] {}", message);
string err = $F("[POST!] {}", message);
dbc::log(err, location);
throw dbc::PostCondError{err};
throw dbc::PostCondError(err);
}
}
@ -40,8 +40,8 @@ void dbc::post(const string &message, std::function<bool()> tester, const std::s
void dbc::check(bool test, const string &message, const std::source_location location) {
if(!test) {
string err = fmt::format("[CHECK!] {}\n", message);
string err = $F("[CHECK!] {}\n", message);
dbc::log(err, location);
throw dbc::CheckError{err};
throw dbc::CheckError(err);
}
}

@ -5,21 +5,16 @@
#include <functional>
#include <source_location>
// AKA the Fuckit macro
#define $F(FMT, ...) fmt::format(FMT, ##__VA_ARGS__)
namespace dbc {
using std::string;
class Error {
public:
const string message;
Error(string m) : message{m} {}
Error(const char *m) : message{m} {}
};
class CheckError : public Error {};
class SentinelError : public Error {};
class PreCondError : public Error {};
class PostCondError : public Error {};
using CheckError = std::runtime_error;
using SentinelError = std::runtime_error;
using PreCondError = std::runtime_error;
using PostCondError = std::runtime_error;
void log(const string &message,
const std::source_location location =

@ -0,0 +1,55 @@
#include "framebuffer.hpp"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "config.hpp"
void FrameBuffer::init() {
glGenFramebuffers(1, &target_fb);
glBindFramebuffer(GL_FRAMEBUFFER, target_fb);
glGenTextures(1, &texture_color_buffer);
glBindTexture(GL_TEXTURE_2D, texture_color_buffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_color_buffer, 0);
glGenRenderbuffers(1, &target_rbo);
glBindRenderbuffer(GL_RENDERBUFFER, target_rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, target_rbo);
dbc::check(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Failed to init framebuffer.");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
invariant();
}
void FrameBuffer::begin() {
glBindFramebuffer(GL_FRAMEBUFFER, target_fb);
glEnable(GL_DEPTH_TEST);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void FrameBuffer::commit() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);
glClearColor(0.0f, 0.0f, 1.0, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
void FrameBuffer::draw(Screen& screen) {
screen.shader.use();
glBindVertexArray(screen.target_VAO);
glActiveTexture(GL_TEXTURE0 + screen.texture_id);
glBindTexture(GL_TEXTURE_2D, texture_color_buffer);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
void FrameBuffer::invariant() {
dbc::check(target_fb != UINT_MAX, "target_fb not initialized");
dbc::check(texture_color_buffer != UINT_MAX, "texture_color_buffer not initialized");
}

@ -0,0 +1,17 @@
#pragma once
#include "shader.hpp"
#include "screen.hpp"
struct FrameBuffer {
unsigned int target_fb = UINT_MAX;
unsigned int target_rbo = UINT_MAX;
unsigned int texture_color_buffer = UINT_MAX;
void init();
void begin();
void commit();
void draw(Screen& screen);
void invariant();
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,6 +1,140 @@
#include "bezos.hpp"
#define _USE_MATH_DEFINES
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <stb_image.h>
#include <fmt/core.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "text.hpp"
#include "config.hpp"
#include "screen.hpp"
#include "framebuffer.hpp"
int main(int argc, char *argv[]) {
Deck deck = Bezos::load("lua/builder_test.lua");
Bezos::dump(deck);
float mouse_x = 0;
float mouse_y = 0;
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
struct State {
FrameBuffer framebuffer;
Screen screen;
std::string text_content{"Hi!"};
Text text{.font_size=202};
State() {
text.load_font();
screen.init();
framebuffer.init();
}
};
void init_glfw() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
}
void framebuffer_size_callback(GLFWwindow *, int width, int height) {
glViewport(0, 0, width, height);
}
void mouse_callback(GLFWwindow *window, double xpos, double ypos) {
fmt::println("mouse click: {},{}", xpos, ypos);
mouse_x = xpos;
mouse_y = ypos;
}
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) {
}
GLFWwindow* create_window() {
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
dbc::check(window != NULL, "failed to open window");
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
auto good = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
dbc::check(good, "failed to load GLAD");
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
return window;
}
void process_input(GLFWwindow *window) {
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
if(glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
fmt::println("move window left");
}
if(glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
fmt::println("move window left");
}
}
void setup() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
glEnable(GL_MULTISAMPLE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LESS);
}
void update(GLFWwindow* window) {
glfwPollEvents();
process_input(window);
}
void render(GLFWwindow* window, State &state) {
state.framebuffer.begin();
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
state.text.render(state.text_content, 25.0f, SCR_HEIGHT - state.text.font_size - 20, 1.0f,
glm::vec3(1.0f, 1.0f, 1.0f));
state.framebuffer.commit();
state.framebuffer.draw(state.screen);
glfwSwapBuffers(window);
}
void quit(GLFWwindow* window) {
glfwTerminate();
}
int main() {
init_glfw();
auto window = create_window();
setup();
State state;
// glfwSetWindowUserPointer(window, scene.get());
while(!glfwWindowShouldClose(window)) {
update(window);
render(window, state);
}
quit(window);
return 0;
}

@ -0,0 +1,18 @@
#include "screen.hpp"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
void Screen::init() {
shader.use();
shader.setInt("screenTexture", texture_id);
glGenVertexArrays(1, &target_VAO);
glGenBuffers(1, &target_VBO);
glBindVertexArray(target_VAO);
glBindBuffer(GL_ARRAY_BUFFER, target_VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
}

@ -0,0 +1,23 @@
#pragma once
#include "shader.hpp"
struct Screen {
Shader shader{{"shaders/screen.vert.glsl", "shaders/screen.frag.glsl", ""}};
unsigned int target_VAO = 0;
unsigned int target_VBO = 0;
unsigned int texture_id = 10;
float vertices[24] = {
// vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
void init();
};

@ -0,0 +1,148 @@
#include "shader.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <print>
#include <filesystem>
#include "dbc.hpp"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
namespace fs = std::filesystem;
inline std::string read_file(const std::string& filename) {
// load the file
std::ifstream in_file{filename, std::ios::binary};
// get the size of the file
std::stringstream in_str;
in_str << in_file.rdbuf();
return in_str.str();
}
void check_error(const std::string& what, unsigned int thing, GLenum check_type) {
int success = 0;
char infoLog[512] = {0};
if(check_type == GL_LINK_STATUS) {
glGetProgramiv(thing, check_type, &success);
if(!success) {
glGetProgramInfoLog(thing, 512, NULL, infoLog);
dbc::sentinel(std::format("ERROR: Program {} compile failed: {}", what, infoLog));
}
} else {
glGetShaderiv(thing, check_type, &success);
if(!success) {
glGetShaderInfoLog(thing, 512, NULL, infoLog);
dbc::sentinel(std::format("ERROR: Shader {} compile failed: {}", what, infoLog));
}
}
}
unsigned int Shader::load_shader(const std::string& filename, GLenum shader_type) {
dbc::log($F("Loading shader {}", filename));
dbc::check(fs::exists(filename),
std::format("shader file {} does not exist", filename));
// create the shader
std::string shader_code = read_file(filename);
const char* shader_code_ptr = shader_code.c_str();
int shader_id = glCreateShader(shader_type);
glShaderSource(shader_id, 1, &shader_code_ptr, NULL);
glCompileShader(shader_id);
check_error(filename, shader_id, GL_COMPILE_STATUS);
// check compile error
return shader_id;
}
Shader::Shader(ShaderConfig c) : config(c)
{
dbc::log($F("Loading shaders vert={}, frag={}, geom={}", config.vertex_path, config.frag_path, config.geometry_path));
unsigned int vertex = load_shader(config.vertex_path, GL_VERTEX_SHADER);
unsigned int fragment = load_shader(config.frag_path, GL_FRAGMENT_SHADER);
unsigned int geometry = UINT_MAX;
ID = glCreateProgram();
dbc::log($F("Created shader program ID: {}", ID));
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
if(config.geometry_path != "") {
geometry = load_shader(config.geometry_path, GL_GEOMETRY_SHADER);
glAttachShader(ID, geometry);
}
glLinkProgram(ID);
check_error("link", ID, GL_LINK_STATUS);
glDeleteShader(vertex);
glDeleteShader(fragment);
if(config.geometry_path != "") {
glDeleteShader(geometry);
}
}
void Shader::use() const {
glUseProgram(ID);
}
void Shader::cleanup() {
glDeleteProgram(ID);
}
void Shader::setBool(const std::string &name, bool value) const {
auto uniform = glGetUniformLocation(ID, name.c_str());
glUniform1i(uniform, (int)value);
}
void Shader::setInt(const std::string &name, int value) const {
auto uniform = glGetUniformLocation(ID, name.c_str());
glUniform1i(uniform, value);
}
void Shader::setFloat(const std::string &name, float value) const {
auto uniform = glGetUniformLocation(ID, name.c_str());
glUniform1f(uniform, value);
}
void Shader::setVec4(const std::string &name, float v1, float v2, float v3, float v4) const {
auto uniform = glGetUniformLocation(ID, name.c_str());
glUniform4f(uniform, v1, v2, v3, v4);
}
void Shader::setVec4(const std::string &name, const glm::vec4& value) const
{
auto uniform = glGetUniformLocation(ID, name.c_str());
glUniform4fv(uniform, 1, &value[0]);
}
void Shader::setVec2(const std::string &name, const glm::vec2& value) const
{
auto uniform = glGetUniformLocation(ID, name.c_str());
glUniform2fv(uniform, 1, &value[0]);
}
void Shader::setVec3(const std::string &name, const glm::vec3& value) const
{
auto uniform = glGetUniformLocation(ID, name.c_str());
glUniform3fv(uniform, 1, &value[0]);
}
void Shader::setVec3(const std::string &name, float v1, float v2, float v3) const {
auto uniform = glGetUniformLocation(ID, name.c_str());
glUniform3f(uniform, v1, v2, v3);
}
void Shader::setMat4(const std::string &name, const glm::mat4& mat) const {
unsigned int loc = glGetUniformLocation(ID, name.c_str());
glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(mat));
}

@ -0,0 +1,37 @@
#pragma once
#include <glad/glad.h>
#include <string>
#include <climits>
#include <glm/glm.hpp>
#include <vector>
#include <format>
#include "dbc.hpp"
struct ShaderConfig {
std::string vertex_path;
std::string frag_path;
std::string geometry_path;
};
class Shader
{
public:
unsigned int ID = UINT_MAX;
ShaderConfig config;
Shader(ShaderConfig config);
unsigned int load_shader(const std::string& filename, GLenum shader_type);
void use() const;
void setBool(const std::string &name, bool value) const;
void setInt(const std::string &name, int value) const;
void setFloat(const std::string &name, float value) const;
void setVec4(const std::string &name, float v1, float v2, float v3, float v4) const;
void setVec4(const std::string &name, const glm::vec4& value) const;
void setVec3(const std::string &name, float v1, float v2, float v3) const;
void setVec3(const std::string &name, const glm::vec3& value) const;
void setVec2(const std::string &name, const glm::vec2& value) const;
void setMat4(const std::string &name, const glm::mat4& what) const;
void cleanup();
};

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

File diff suppressed because it is too large Load Diff

@ -0,0 +1,114 @@
#include "text.hpp"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <ft2build.h>
#include "config.hpp"
#include FT_FREETYPE_H
void Text::render(const std::string& text, float x, float y, float scale, glm::vec3 color) {
text_shader.use();
glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(SCR_WIDTH), 0.0f, static_cast<float>(SCR_HEIGHT));
text_shader.setMat4("projection", projection);
glUniform3f(glGetUniformLocation(text_shader.ID, "textColor"), color.x, color.y, color.z);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(text_vao);
for(auto c : text) {
auto& ch = characters.at(c);
float xpos = x + ch.bearing.x * scale;
float ypos = y - (ch.size.y - ch.bearing.y) * scale;
float w = ch.size.x * scale;
float h = ch.size.y * scale;
float vertices[6][4] = {
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos, ypos, 0.0f, 1.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos + w, ypos + h, 1.0f, 0.0f }
};
// rander glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.texture_id);
// update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, text_vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
x += (ch.advance >> 6) * scale;
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
void Text::load_font() {
FT_Library ft;
int fail = FT_Init_FreeType(&ft);
dbc::check(fail == 0, "FreeType failed.");
FT_Face face;
fail = FT_New_Face(ft, font.c_str(), 0, &face);
dbc::check(fail == 0, "Failed to load font.");
// load the font bitmaps
FT_Set_Pixel_Sizes(face, 0, font_size);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for(unsigned char c = 0; c < 255; c++) {
fail = FT_Load_Char(face, c, FT_LOAD_RENDER);
dbc::check(fail == 0, $F("Failed to load char {}", int(c)));
unsigned int texture = UINT_MAX;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
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);
characters.try_emplace(c,
texture,
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
static_cast<unsigned int>(face->glyph->advance.x));
}
// unbind
glBindTexture(GL_TEXTURE_2D, 0);
// cleanup
FT_Done_Face(face);
FT_Done_FreeType(ft);
// create teh vao/vbo
glGenVertexArrays(1, &text_vao);
glGenBuffers(1, &text_vbo);
glBindVertexArray(text_vao);
glBindBuffer(GL_ARRAY_BUFFER, text_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glBindVertexArray(0);
}

@ -0,0 +1,24 @@
#pragma once
#include "shader.hpp"
#include <string>
#include <unordered_map>
#include <glm/glm.hpp>
struct Character {
unsigned int texture_id;
glm::ivec2 size;
glm::ivec2 bearing;
unsigned int advance;
};
struct Text {
int font_size = 48;
std::string font{"assets/fonts/text.ttf"};
Shader text_shader{{"shaders/text.vert.glsl", "shaders/text.frag.glsl", ""}};
unsigned int text_vao = UINT_MAX;
unsigned int text_vbo = UINT_MAX;
std::unordered_map<unsigned char, Character> characters{};
void render(const std::string& text, float x, float y, float scale, glm::vec3 color);
void load_font();
};

@ -0,0 +1,11 @@
[wrap-file]
directory = freetype-2.13.3
source_url = https://download.savannah.gnu.org/releases/freetype/freetype-2.13.3.tar.xz
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/freetype2_2.13.3-1/freetype-2.13.3.tar.xz
source_filename = freetype-2.13.3.tar.xz
source_hash = 0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289
wrapdb_version = 2.13.3-1
[provide]
freetype2 = freetype_dep
freetype = freetype_dep

@ -0,0 +1,13 @@
[wrap-file]
directory = glfw-3.4
source_url = https://github.com/glfw/glfw/archive/refs/tags/3.4.tar.gz
source_filename = glfw-3.4.tar.gz
source_hash = c038d34200234d071fae9345bc455e4a8f2f544ab60150765d7704e08f3dac01
patch_filename = glfw_3.4-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/glfw_3.4-1/get_patch
patch_hash = 58a6a6cdb28195d7f7e6f5de85dff7044d378e49b46bf1d4a9b04c97ed93e6b0
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/glfw_3.4-1/glfw-3.4.tar.gz
wrapdb_version = 3.4-1
[provide]
glfw3 = glfw_dep

@ -0,0 +1,13 @@
[wrap-file]
directory = glm-1.0.1
source_url = https://github.com/g-truc/glm/archive/refs/tags/1.0.1.tar.gz
source_filename = glm-1.0.1.tar.gz
source_hash = 9f3174561fd26904b23f0db5e560971cbf9b3cbda0b280f04d5c379d03bf234c
patch_filename = glm_1.0.1-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/glm_1.0.1-1/get_patch
patch_hash = 25679275e26bc4c36bb617d1b4a52197039402af828d2a4bf67b3c0260a5df6a
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/glm_1.0.1-1/glm-1.0.1.tar.gz
wrapdb_version = 1.0.1-1
[provide]
glm = glm_dep
Loading…
Cancel
Save