I'm currently facing challenges in changing the text color when rendering text using FTGL and OpenGL. Despite efforts to set the text color, the rendered text appears to be in a default color (red). I've tried adjusting the color parameters, but the results remain unchanged.
I've tried changing
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);
To the following and setting the following for the color
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
Here is the full code and also my rendering window. Thanks in advance!
void CreateTransparentWindow() {
// Initialize GLFW
if (!glfwInit()) {
obs_log(LOG_INFO, "GlfwInit failed to initilize.");
return false;
}
// Set window hints for borderless and transparent window
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
// 4x antialiasing - Makes things look sharper.
glfwWindowHint(GLFW_SAMPLES, 4);
// Create a windowed mode window and its OpenGL context
window = glfwCreateWindow(1919, 1079, "Qt281QWindowIcon", NULL, NULL);
if (!window) {
obs_log(LOG_INFO, "Failed to create window.");
glfwTerminate();
return false;
}
// Make the window's context current
glfwMakeContextCurrent(window);
// Set up the projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1919, 1079, 0, -1, 1); // Custom coordinates
glMatrixMode(GL_MODELVIEW);
glEnable(GL_MULTISAMPLE); // Anti antialiasing
//Initilize FT Libary and Text Attributes.
FT_Init_FreeType(&ft);
FT_New_Face(ft, "C:\\Users\\Joel\\Desktop\\Roboto-Regular.ttf", 0, &face);
glEnable(GL_TEXTURE_2D);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Get the HWND of the GLFW window
HWND hwnd = glfwGetWin32Window(window);
// Set the window to be click-through
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TRANSPARENT);
// Set the layered attribute to enable transparency
SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LWA_COLORKEY);
// Make the window always on top
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
// Set V-Sync to 1 (enabled)
glfwSwapInterval(0);
return true;
}
void DrawTextGL(int x, int y, int size, const char *text, COLORREF color)
{
// Set font size and color
FT_Set_Pixel_Sizes(face, 0, size);
// Create and bind texture outside the loop
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
// Set texture parameters
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_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
for (const char *c = text; *c; ++c) {
if (FT_Load_Char(face, *c, FT_LOAD_RENDER) != 0) {
continue;
}
// Copy glyph bitmap to 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);
// Calculate texture coordinates
float tx1 = x + face->glyph->bitmap_left;
float ty1 = y - face->glyph->bitmap_top;
float tx2 = tx1 + face->glyph->bitmap.width;
float ty2 = ty1 + face->glyph->bitmap.rows;
// Render textured quad
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex2f(tx1, ty1);
glTexCoord2f(1.0, 0.0);
glVertex2f(tx2, ty1);
glTexCoord2f(1.0, 1.0);
glVertex2f(tx2, ty2);
glTexCoord2f(0.0, 1.0);
glVertex2f(tx1, ty2);
glEnd();
// Advance position
x += (face->glyph->advance.x >> 6);
y += (face->glyph->advance.y >> 6);
}
// Clean up: delete texture after the loop
glDeleteTextures(1, &textureID);
}
Without shaders, GL_RED
won't do what you want, as if fixes G/B/A channels as 0/0/1. Programmable shaders will let you repurpose the channel, but it appears you are using legacy OpenGL, which doesn't offer you that.
To do what you want without programmable shaders, one solution is to change to using RGBA (or RGB), as you have begun doing. However, you will also need to take the single 8-bit channel data in face->glyph->bitmap.buffer
and build a new RGBA buffer. You can then pass the RGBA buffer into glTexImage2D
instead.
Edit: If you don't mind the background of the text forced to black, you could alternately use internal format GL_RGBA
, and format GL_LUMINANCE
. This puts the value from the 8-bit source channel into each of the three color channels R/G/B and 1.0 in the alpha channel... in other words: opaque grayscale. (I thought GL_INTENSITY
was supposed to copy it to all four channels, but it did not seem to work when I tested it.)
If you run glPixelTransferf()
on GL_RED_SCALE
, GL_GREEN_SCALE
, and GL_BLUE_SCALE
before glTexImage2D()
, you can change from grayscale to shades of another color.
Edit 2: Similarly, you can create a black texture with alpha-mask using GL_RGBA
/GL_ALPHA
. The color can be adjusted to another color by setting GL_RED_BIAS
, GL_GREEN_BIAS
, and GL_BLUE_BIAS
using glPixelTransferf()
ahead of time. It'd also probably a good idea to set these back to 0 once you're done loading the glyph textures.