Initial Commit

This commit is contained in:
2024-02-15 19:08:03 -05:00
commit 83f3231fdc
11 changed files with 752 additions and 0 deletions

47
CMakeLists.txt Normal file
View File

@@ -0,0 +1,47 @@
cmake_minimum_required(VERSION 3.27)
project(text_rendering_2)
set(CMAKE_CXX_STANDARD 17)
# Enable Package Managers
include(cmake/CPM.cmake)
CPMAddPackage(
NAME GLAD
URL https://git.redacted.cc/Redacted/glad/archive/v2.1.zip
)
CPMAddPackage(
NAME glm
GITHUB_REPOSITORY g-truc/glm
OPTIONS "GLM_STATIC_LIBRARY_ENABLE"
#SOURCE_SUBDIR glm
GIT_TAG 0.9.9.8
)
find_package(glm REQUIRED)
find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)
find_package(Freetype REQUIRED)
find_package(glfw3 REQUIRED)
find_package(GLEW REQUIRED)
add_executable(text_rendering_2 main.cpp
Shader.h
common/shader_utils.cpp
common/shader_utils.h)
include_directories(${OPENGL_INCLUDE_DIRS})
include_directories(${GLUT_INCLUDE_DIRS})
include_directories(${glad_SOURCE_DIR}/include)
include_directories(${GLFW_INCLUDE_DIRS})
include_directories(${GLEW_INCLUDE_DIRS})
target_link_libraries(text_rendering_2 PUBLIC ${OPENGL_LIBRARIES})
target_link_libraries(text_rendering_2 PUBLIC ${GLUT_LIBRARIES})
target_link_libraries(text_rendering_2 PRIVATE ${FREETYPE_LIBRARIES})
target_include_directories(text_rendering_2 PRIVATE ${FREETYPE_INCLUDE_DIRS})
target_link_libraries(text_rendering_2 PRIVATE glad glfw GLEW)
target_link_libraries(text_rendering_2 PRIVATE glm::glm)

BIN
FreeSans.ttf Normal file

Binary file not shown.

194
Shader.h Normal file
View File

@@ -0,0 +1,194 @@
#ifndef SHADER_H
#define SHADER_H
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::string geometryCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
gShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
try
{
// open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
// if geometry shader path is present, also load a geometry shader
if(geometryPath != nullptr)
{
gShaderFile.open(geometryPath);
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometryCode = gShaderStream.str();
}
}
catch (std::ifstream::failure& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char * fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader
unsigned int geometry;
if(geometryPath != nullptr)
{
//const char * gShaderCode = geometryCode.c_str();
//geometry = glCreateShader(GL_GEOMETRY_SHADER);
//glShaderSource(geometry, 1, &gShaderCode, NULL);
//glCompileShader(geometry);
//checkCompileErrors(geometry, "GEOMETRY");
}
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
if(geometryPath != nullptr)
glAttachShader(ID, geometry);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
if(geometryPath != nullptr)
glDeleteShader(geometry);
}
// activate the shader
// ------------------------------------------------------------------------
void use()
{
glUseProgram(ID);
}
// utility uniform functions
// ------------------------------------------------------------------------
void setBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
// ------------------------------------------------------------------------
void setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setVec2(const std::string &name, const glm::vec2 &value) const
{
glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec2(const std::string &name, float x, float y) const
{
glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
}
// ------------------------------------------------------------------------
void setVec3(const std::string &name, const glm::vec3 &value) const
{
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec3(const std::string &name, float x, float y, float z) const
{
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}
// ------------------------------------------------------------------------
void setVec4(const std::string &name, const glm::vec4 &value) const
{
glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec4(const std::string &name, float x, float y, float z, float w)
{
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}
// ------------------------------------------------------------------------
void setMat2(const std::string &name, const glm::mat2 &mat) const
{
glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
// ------------------------------------------------------------------------
void setMat3(const std::string &name, const glm::mat3 &mat) const
{
glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
// ------------------------------------------------------------------------
void setMat4(const std::string &name, const glm::mat4 &mat) const
{
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(GLuint shader, std::string type)
{
GLint success;
GLchar infoLog[1024];
if(type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if(!success)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
}
};
#endif

24
cmake/CPM.cmake Normal file
View File

@@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
set(CPM_DOWNLOAD_VERSION 0.38.7)
set(CPM_HASH_SUM "83e5eb71b2bbb8b1f2ad38f1950287a057624e385c238f6087f94cdfc44af9c5")
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)
include(${CPM_DOWNLOAD_LOCATION})

213
common/shader_utils.cpp Normal file
View File

@@ -0,0 +1,213 @@
/**
* From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/OpenGL_Programming
* This file is in the public domain.
* Contributors: Sylvain Beucler
*/
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
/**
* Store all the file's contents in memory, useful to pass shaders
* source code to OpenGL
*/
char* file_read(const char* filename)
{
FILE* in = fopen(filename, "rb");
if (in == NULL) return NULL;
int res_size = BUFSIZ;
char* res = (char*)malloc(res_size);
int nb_read_total = 0;
while (!feof(in) && !ferror(in)) {
if (nb_read_total + BUFSIZ > res_size) {
if (res_size > 10*1024*1024) break;
res_size = res_size * 2;
res = (char*)realloc(res, res_size);
}
char* p_res = res + nb_read_total;
nb_read_total += fread(p_res, 1, BUFSIZ, in);
}
fclose(in);
res = (char*)realloc(res, nb_read_total + 1);
res[nb_read_total] = '\0';
return res;
}
/**
* Display compilation errors from the OpenGL shader compiler
*/
void print_log(GLuint object)
{
GLint log_length = 0;
if (glIsShader(object))
glGetShaderiv(object, GL_INFO_LOG_LENGTH, &log_length);
else if (glIsProgram(object))
glGetProgramiv(object, GL_INFO_LOG_LENGTH, &log_length);
else {
fprintf(stderr, "printlog: Not a shader or a program\n");
return;
}
char* log = (char*)malloc(log_length);
if (glIsShader(object))
glGetShaderInfoLog(object, log_length, NULL, log);
else if (glIsProgram(object))
glGetProgramInfoLog(object, log_length, NULL, log);
fprintf(stderr, "%s", log);
free(log);
}
/**
* Compile the shader from file 'filename', with error handling
*/
GLuint create_shader(const char* filename, GLenum type)
{
const GLchar* source = file_read(filename);
if (source == NULL) {
fprintf(stderr, "Error opening %s: ", filename); perror("");
return 0;
}
GLuint res = glCreateShader(type);
const GLchar* sources[] = {
// Define GLSL version
#ifdef GL_ES_VERSION_2_0
"#version 100\n" // OpenGL ES 2.0
#else
"#version 120\n" // OpenGL 2.1
#endif
,
// GLES2 precision specifiers
#ifdef GL_ES_VERSION_2_0
// Define default float precision for fragment shaders:
(type == GL_FRAGMENT_SHADER) ?
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
"precision highp float; \n"
"#else \n"
"precision mediump float; \n"
"#endif \n"
: ""
// Note: OpenGL ES automatically defines this:
// #define GL_ES
#else
// Ignore GLES 2 precision specifiers:
"#define lowp \n"
"#define mediump\n"
"#define highp \n"
#endif
,
source };
glShaderSource(res, 3, sources, NULL);
free((void*)source);
glCompileShader(res);
GLint compile_ok = GL_FALSE;
glGetShaderiv(res, GL_COMPILE_STATUS, &compile_ok);
if (compile_ok == GL_FALSE) {
fprintf(stderr, "%s:", filename);
print_log(res);
glDeleteShader(res);
return 0;
}
return res;
}
GLuint create_program(const char *vertexfile, const char *fragmentfile) {
GLuint program = glCreateProgram();
GLuint shader;
if(vertexfile) {
shader = create_shader(vertexfile, GL_VERTEX_SHADER);
if(!shader)
return 0;
glAttachShader(program, shader);
}
if(fragmentfile) {
shader = create_shader(fragmentfile, GL_FRAGMENT_SHADER);
if(!shader)
return 0;
glAttachShader(program, shader);
}
glLinkProgram(program);
GLint link_ok = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
if (!link_ok) {
fprintf(stderr, "glLinkProgram:");
print_log(program);
glDeleteProgram(program);
return 0;
}
return program;
}
#ifdef GL_GEOMETRY_SHADER
GLuint create_gs_program(const char *vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices) {
GLuint program = glCreateProgram();
GLuint shader;
if(vertexfile) {
shader = create_shader(vertexfile, GL_VERTEX_SHADER);
if(!shader)
return 0;
glAttachShader(program, shader);
}
if(geometryfile) {
shader = create_shader(geometryfile, GL_GEOMETRY_SHADER);
if(!shader)
return 0;
glAttachShader(program, shader);
glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, input);
glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output);
glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, vertices);
}
if(fragmentfile) {
shader = create_shader(fragmentfile, GL_FRAGMENT_SHADER);
if(!shader)
return 0;
glAttachShader(program, shader);
}
glLinkProgram(program);
GLint link_ok = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
if (!link_ok) {
fprintf(stderr, "glLinkProgram:");
print_log(program);
glDeleteProgram(program);
return 0;
}
return program;
}
#else
GLuint create_gs_program(const char *vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices) {
fprintf(stderr, "Missing support for geometry shaders.\n");
return 0;
}
#endif
GLint get_attrib(GLuint program, const char *name) {
GLint attribute = glGetAttribLocation(program, name);
if(attribute == -1)
fprintf(stderr, "Could not bind attribute %s\n", name);
return attribute;
}
GLint get_uniform(GLuint program, const char *name) {
GLint uniform = glGetUniformLocation(program, name);
if(uniform == -1)
fprintf(stderr, "Could not bind uniform %s\n", name);
return uniform;
}

16
common/shader_utils.h Normal file
View File

@@ -0,0 +1,16 @@
/**
* From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/OpenGL_Programming
* This file is in the public domain.
* Contributors: Sylvain Beucler
*/
#ifndef _SHADER_UTILS_H
#define _SHADER_UTILS_H
#include <GL/glew.h>
char* file_read(const char* filename);
void print_log(GLuint object);
GLuint create_shader(const char* filename, GLenum type);
GLuint create_program(const char* vertexfile, const char *fragmentfile);
GLuint create_gs_program(const char* vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices);
GLint get_attrib(GLuint program, const char *name);
GLint get_uniform(GLuint program, const char *name);
#endif

220
main.cpp Normal file
View File

@@ -0,0 +1,220 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "common/shader_utils.h"
GLuint program;
GLint attribute_coord;
GLint uniform_tex;
GLint uniform_color;
struct point {
GLfloat x;
GLfloat y;
GLfloat s;
GLfloat t;
};
GLuint vbo;
FT_Library ft;
FT_Face face;
const char *fontfilename;
int init_resources() {
/* Initialize the FreeType2 library */
if (FT_Init_FreeType(&ft)) {
fprintf(stderr, "Could not init freetype library\n");
return 0;
}
/* Load a font */
if (FT_New_Face(ft, fontfilename, 0, &face)) {
fprintf(stderr, "Could not open font %s\n", fontfilename);
return 0;
}
program = create_program("text.v.glsl", "text.f.glsl");
if(program == 0)
return 0;
attribute_coord = get_attrib(program, "coord");
uniform_tex = get_uniform(program, "tex");
uniform_color = get_uniform(program, "color");
if(attribute_coord == -1 || uniform_tex == -1 || uniform_color == -1)
return 0;
// Create the vertex buffer object
glGenBuffers(1, &vbo);
return 1;
}
/**
* Render text using the currently loaded font and currently set font size.
* Rendering starts at coordinates (x, y), z is always 0.
* The pixel coordinates that the FreeType2 library uses are scaled by (sx, sy).
*/
void render_text(const char *text, float x, float y, float sx, float sy) {
const char *p;
FT_GlyphSlot g = face->glyph;
/* Create a texture that will be used to hold one "glyph" */
GLuint tex;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(uniform_tex, 0);
/* We require 1 byte alignment when uploading texture data */
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
/* Clamping to edges is important to prevent artifacts when scaling */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
/* Linear filtering usually looks best for text */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* Set up the VBO for our vertex data */
glEnableVertexAttribArray(attribute_coord);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
/* Loop through all characters */
for (p = text; *p; p++) {
/* Try to load and render the character */
if (FT_Load_Char(face, *p, FT_LOAD_RENDER))
continue;
/* Upload the "bitmap", which contains an 8-bit grayscale image, as an alpha texture */
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
/* Calculate the vertex and texture coordinates */
float x2 = x + g->bitmap_left * sx;
float y2 = -y - g->bitmap_top * sy;
float w = g->bitmap.width * sx;
float h = g->bitmap.rows * sy;
point box[4] = {
{x2, -y2, 0, 0},
{x2 + w, -y2, 1, 0},
{x2, -y2 - h, 0, 1},
{x2 + w, -y2 - h, 1, 1},
};
/* Draw the character on the screen */
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* Advance the cursor to the start of the next character */
x += (g->advance.x >> 6) * sx;
y += (g->advance.y >> 6) * sy;
}
glDisableVertexAttribArray(attribute_coord);
glDeleteTextures(1, &tex);
}
void display() {
float sx = 2.0 / glutGet(GLUT_WINDOW_WIDTH);
float sy = 2.0 / glutGet(GLUT_WINDOW_HEIGHT);
glUseProgram(program);
/* White background */
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
/* Enable blending, necessary for our alpha texture */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLfloat black[4] = { 0, 0, 0, 1 };
GLfloat red[4] = { 1, 0, 0, 1 };
GLfloat transparent_green[4] = { 0, 1, 0, 0.5 };
/* Set font size to 48 pixels, color to black */
FT_Set_Pixel_Sizes(face, 0, 48);
glUniform4fv(uniform_color, 1, black);
/* Effects of alignment */
render_text("The Quick Brown Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 50 * sy, sx, sy);
render_text("The Misaligned Fox Jumps Over The Lazy Dog", -1 + 8.5 * sx, 1 - 100.5 * sy, sx, sy);
/* Scaling the texture versus changing the font size */
render_text("The Small Texture Scaled Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 175 * sy, sx * 0.5, sy * 0.5);
FT_Set_Pixel_Sizes(face, 0, 24);
render_text("The Small Font Sized Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 200 * sy, sx, sy);
FT_Set_Pixel_Sizes(face, 0, 48);
render_text("The Tiny Texture Scaled Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 235 * sy, sx * 0.25, sy * 0.25);
FT_Set_Pixel_Sizes(face, 0, 12);
render_text("The Tiny Font Sized Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 250 * sy, sx, sy);
FT_Set_Pixel_Sizes(face, 0, 48);
/* Colors and transparency */
render_text("The Solid Black Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 430 * sy, sx, sy);
glUniform4fv(uniform_color, 1, red);
render_text("The Solid Red Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 330 * sy, sx, sy);
render_text("The Solid Red Fox Jumps Over The Lazy Dog", -1 + 28 * sx, 1 - 450 * sy, sx, sy);
glUniform4fv(uniform_color, 1, transparent_green);
render_text("The Transparent Green Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 380 * sy, sx, sy);
render_text("The Transparent Green Fox Jumps Over The Lazy Dog", -1 + 18 * sx, 1 - 440 * sy, sx, sy);
glutSwapBuffers();
}
void free_resources() {
glDeleteProgram(program);
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitContextVersion(2,0);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize(640, 480);
glutCreateWindow("Basic Text");
if (argc > 1)
fontfilename = argv[1];
else
fontfilename = "FreeSans.ttf";
GLenum glew_status = glewInit();
if (GLEW_OK != glew_status) {
fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status));
return 1;
}
if (!GLEW_VERSION_2_0) {
fprintf(stderr, "No support for OpenGL 2.0 found\n");
return 1;
}
if (init_resources()) {
glutDisplayFunc(display);
glutMainLoop();
}
free_resources();
return 0;
}

12
shader.fs Normal file
View File

@@ -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;
}

11
shader.vs Normal file
View File

@@ -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;
}

7
text.f.glsl Normal file
View File

@@ -0,0 +1,7 @@
varying vec2 texpos;
uniform sampler2D tex;
uniform vec4 color;
void main(void) {
gl_FragColor = vec4(1, 1, 1, texture2D(tex, texpos).a) * color;
}

8
text.v.glsl Normal file
View File

@@ -0,0 +1,8 @@
attribute vec4 coord;
varying vec2 texpos;
void main(void) {
gl_Position = vec4(coord.xy, 0, 1);
texpos = coord.zw;
}