computer-graphics

Transparent framebuffer & borderless window using GLFW

How to draw in OpenGL over a transparent window? Here your answer

A short time ago, I have addressed the problem to render a ghost window 👻. It means, using a 3D animation in OpenGL floating over the screen in Windows.

In that case, the idea is to set the windows without a border with a transparent background. A transparent background means a transparent framebuffer, aka all the untouched fragments 😃

For this purpose, the GLFW library was set using Window (the operating system is relevant to select the window handler library). A good way to start with GFLW is the great documentation available on the official page. The GLFW: Getting started is your starting point on this.

Then, a single hello world window drawing a quad is shown in the following code:

#include <windows.h>
#include <GLFW/glfw3.h>

// change this to int main() to allow the console
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char*, int nShowCmd)
{
  GLFWwindow* window;
  int windowSizeW = 640, windowSizeH = 480;
  // initialize the library
  if (!glfwInit())
    return -1;

  // create a windowed mode window and its OpenGL context
  window = glfwCreateWindow(windowSizeW, windowSizeH, "Hello World", NULL, NULL);
  if (!window)
  {
    glfwTerminate();
    return -1;
  }

  // make the window's context current
  glfwMakeContextCurrent(window);

  // reset the window hints to default
  glfwDefaultWindowHints();

  // show the window
  glfwShowWindow(window);

  // Loop until the user closes the window
  while (!glfwWindowShouldClose(window))
  {
    // render
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_QUADS);
    glColor3f(0, 0, 1);
    glVertex3f(-0.5, -0.5, -1);
    glColor3f(0, 1, 0);
    glVertex3f(0.5, -0.5, -1);
    glColor3f(1, 0, 1);
    glVertex3f(0.5, 0.5, -1);
    glColor3f(1, 1, 0);
    glVertex3f(-0.5, 0.5, -1);
    glEnd();

    // swap front and back buffers
    glfwSwapBuffers(window);

    // poll for and process events
    glfwPollEvents();
  }

  glfwTerminate();
  return 0;
}

There are a few things to notice on the previous code:

  • Instead of the classic int main, the WinMain is used. This is to avoid seeing the console.
  • The quad displayed is with Legacy OpenGL (not recommended). However, to set my point is enough instead the boilerplate code using GLSL.
  • There are 2 variables with the width and height of the window (those should be used later).

The output window of the previous code look like:

Let's start adding things

The first thing to include will be the transparent framebuffer parameter. Lamentably, it does not work at the first shot. This code should be written after the glfwInit and before the glfwCreateWindow instruction, as follows:

glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);

Great, the further step is to extract the dimension of the output window (e.g. monitors). Expressly, we are assuming computation will be over the first monitor (indexing as zero). These values are practical to set the position of the window:

int count, windowWidth, windowHeight, monitorX, monitorY;

// I am assuming that main monitor is in the 0 position
GLFWmonitor** monitors = glfwGetMonitors(&count);
const GLFWvidmode* videoMode = glfwGetVideoMode(monitors[0]);
// width: 75% of the screen
windowWidth = static_cast<int>(videoMode->width / 1.5);
// aspect ratio 16 to 9
windowHeight = static_cast<int>(videoMode->height / 16 * 9);

glfwGetMonitorPos(monitors[0], &monitorX, &monitorY);

The latter thing to setup is the visibility window hint to false for subsequent window creation 🤓

glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);

After this instruction is mandatory the creation of the window with the glfwCreateWindow command. Ok, everything looks good, and we need to place the window in the position where it should appear (glfwSetWindowPos), remember do not forget the glfwShowWindow.

glfwSetWindowPos(window, monitorX + (videoMode->width - windowWidth) / 2, monitorY + (videoMode->height - windowHeight) / 2);

Do not hesitate, at the end is the full code to consult it. As follows, we should display the following window:

Notice that the framebuffer is already transparent (the code behind). The latter step is to remove the border of the window and icons for minimizing, maximizing, and closing at the top right:

glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_FALSE);

It is done! Just see the video where I added the quad in rotation and the code is also available in Github Gist at the end.

Take into consideration that the window is still a window (not a background process running over all windows). Then, you can (also, without buttons minimize, maximize, and close) explore between opened applications using Ctrl + Tab or any other way.

I hope this would be valuable to other developers 🤖

From a geek to geeks.

Main file to create a transparency window + transparency framebuffer using GLFW. This sample only draws a rotating rectangle.
Main file to create a transparency window + transparency framebuffer using GLFW. This sample only draws a rotating rectangle. - transparency_glfw.cpp

Share Tweet Send
0 Comments
Loading...
You've successfully subscribed to The ecode.DEV repository
Great! Next, complete checkout for full access to The ecode.DEV repository
Welcome back! You've successfully signed in
Success! Your account is fully activated, you now have access to all content.