Regular window screen capture using openGL - c++

I'm trying to my desktop image capture. (All images, including the desktop output to the monitor)
It's easy using window API (BitBlt or CImageClass) and it's not the way I want.
I want do it using opengl. so I found glReadPixel funtion and window TRANSPARENT.
But it just read pixel own Windows application screen.(Save as bmp file and check)
Initialize()
glfwSetErrorCallback(errorCallback);
if (!glfwInit()) {
std::cerr << "Error: GLFW " << std::endl;
exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_DEPTH_BITS, 16);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4);
const int Monitor_count = GetMonitors();
GLwindow = glfwCreateWindow(
nWidth, // width
nHeight, // height
"OpenGL_Test", // window title
NULL, NULL);
if (!GLwindow) {
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSwapInterval(1);
if (glfwGetWindowAttrib(GLwindow, GLFW_TRANSPARENT_FRAMEBUFFER))
{
//...
}
glfwSetWindowOpacity(GLwindow, 0.0f);
auto Mode = glfwGetVideoMode(Monitor[0]);
glfwMakeContextCurrent(GLwindow);
glfwSetKeyCallback(GLwindow, keyCallback);
glewExperimental = GL_TRUE;
GLenum errorCode = glewInit();
if (GLEW_OK != errorCode) {
std::cerr << "Error: GLEW - " << glewGetErrorString(errorCode) << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
if (!GLEW_VERSION_3_3) {
std::cerr << "OpenGL 3.3 API is not available." << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
glViewport(0, 0, nWidth, nHeight);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "Error: " << std::endl;
}
return true;
Roop
while (!glfwWindowShouldClose(GLwindow)) {
Sleep(10);
glClearColor(0.0f, 0.3f, 0.3f, 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
unsigned char *image = (unsigned char*)malloc(sizeof(unsigned char)*nWidth*nHeight * 3);
glReadPixels(0, 0, nWidth, nHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, image);
glfwPollEvents();
}
return true;
Q1. Is it possible desktop capture(Full Image GPU output) with OPENGL?
Q2. If Q1 is possible, Should I use FBO and PBO GL_BACK??
Q3. How to access to mother window or GPU adapter? >> GL seems to strongly reject this.(I don't want any rendering, just read pixel data from GPU(Desktop image. not rendered by my application.)(If it is possible ...))
Anybody shows to me about link or idea?

What you're asking for is something completely outside the scope of OpenGL. OpenGL is designed to be a platform-agnostic API for applications to talk about drawing stuff into framebuffers in an abstract fashion. OpenGL has no notion of windows*, screens, or a desktop. OpenGL doesn't operate at a level where such concepts exist. Heck, OpenGL doesn't even know what a GPU is. OpenGL is supposed to be initialized through platform-specific mechanisms to establish a context which assigns actual meaning to OpenGL API calls. As far as I know, there is no way to set up an OpenGL context with a framebuffer whose contents would somehow correspond to the desktop on Windows (or any other platform I'm aware of). As far as my understanding goes, this wouldn't really make sense…
To do what you want to do, you'll have to rely on the respective platform-specific APIs. The probably simplest way on Windows is to get an HDC for the entire desktop and BitBlt from there. See, e.g., this question for more on that. A more modern approach would be to use the DXGI Desktop Duplication API.
(*) yes, I know the OpenGL specification technically does talk about "windows" in a few places; but it only really does so when it's talking about all the things it's not responsible for…

I'm trying to my desktop image capture. (All images, including the desktop output to the monitor)
It's easy using window API (BitBlt or CImageClass) and it's not the way I want.
But it's the way it's supposed to be done.
I want do it using opengl. so I found glReadPixel funtion
You can't. OpenGL doesn't "know" about the desktop, or other windows (or actually what windows are at all). The function glReadPixels will work reliably only for images that have been drawn with OpenGL itself.
You can't use OpenGL to take screenshots! On older computers it might seem to work, but that's only because of their older memory management where when you create a new window, its memory will be "cut" from what was below and if you read that, it looks like a way to make screenshots. But it is not.

Related

openGL PBO use wglcontext, Not create window

My goal is get pixel data from main window. nothing any rendering.
like we see the monitor such as screencapture.
I tried to TRANSPARENT windows, glReadPixel.
so I have a TRANSPARENT windows and context.
glfwSetErrorCallback(errorCallback);
if (!glfwInit()) {
std::cerr << "Error: GLFW " << std::endl;
exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_DEPTH_BITS, 16);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4);
const int Monitor_count = GetMonitors();
GLwindow = glfwCreateWindow(
nWidth, // width
nHeight, // height
"OpenGL_Test", // window title
NULL, NULL);
if (!GLwindow) {
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSwapInterval(1);
//glfwShowWindow(GLwindow);
if (glfwGetWindowAttrib(GLwindow, GLFW_TRANSPARENT_FRAMEBUFFER))
{
// ..
}
glfwSetWindowOpacity(GLwindow, 0.0f);
glfwMakeContextCurrent(GLwindow);
glfwSetKeyCallback(GLwindow, keyCallback);
glewExperimental = GL_TRUE;
GLenum errorCode = glewInit();
But I want get pixel data from GPU without create windows.
So I use wglcreatecontext Get mother window DC, HGLRC.
And When I set bind buffer, It gives runtime error.
if (!glfwInit()) {
std::cerr << "Error: GLFW" << std::endl;
exit(EXIT_FAILURE);
}
HDCC = GetDC(m_hWndCopy);
// HDC TDC = CreateCompatibleDC(HDCC);
HGLRC DC = wglCreateContext(HDCC);
GLuint pbo;
glGenBuffersARB(1, &pbo); <<Error Here
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo);
How can I solve problem?
Any idea or link?
From your question and comment replies I gather, that you want to use OpenGL to grab a screenshot of an arbitrary window? If so, then this is not what OpenGL is meant for. You cannot use OpenGL for taking screenshots reliably.
glReadPixels will work reliably only for things that you did draw with OpenGL in the first place!

OpenGL glClearColor always make a black screen

I'm trying to run my first opengl program in C++, which opens a window, sets a background color, and gives a title, from Terminal on Mac OS X.
The code compiles and links fine. When I run the program the window and title open fine but the background color is always black.
It is my understanding that the function glClearColor sets the background color. However, no matter what parameters I pass to the function, the background color of the window is always black.
If anyone can explain to me what errors I'm making, I would very much appreciate it. Thanks and below is the code:
#include <iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
const GLint WIDTH = 800, HEIGHT = 600;
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Learn OpenGL", nullptr, nullptr);
int screenWidth, screenHeight;
glfwGetFramebufferSize(window, &screenWidth, &screenHeight);
if(nullptr == window)
{
std::cout << "Failed to create GLFW window" << '\n';
glfwTerminate();
return -1;
}
glewExperimental = GL_TRUE;
GLenum err=glewInit();
if(err != glewInit())
{
std::cout << "Failed to initialize GLEW" << '\n';
return -1;
}
glViewport(0, 0, screenWidth, screenHeight);
while(!glfwWindowShouldClose(window))
{
glfwPollEvents();
glClearColor(0.2f, 0.2f, 0.9f, 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
glClearColor, like all OpenGL functions, works on the current OpenGL context.
You're not setting your window's context as current for your calling thread, so your call to glClearColor does nothing here. Add:
glfwMakeContextCurrent(window);
before your loop.
From glfwMakeContextCurrent docs:
This function makes the OpenGL or OpenGL ES context of the specified window current on the calling thread. A context can only be made current on a single thread at a time and each thread can have only a single current context at a time.
For those of you crazy enough to use pure WIN32 programming:
If your PIXELFORMATDESCRIPTOR has the flag:
PFD_DOUBLEBUFFER
Then all draw calls target the back buffer.
You need to use the windows GDI32 call "SwapBuffers( HDC )" to show the results of your OpenGL calls.
wlgMakeCurrent()
glClearColor( R, G, B, 1.0 ); //: <--Make sure alpha isn't transparent.
glClear( GL_COLOR_BUFFER_BIT )
SwapBuffers( your_window_HDC ); //: from GDI32.dll
To get access to SwapBuffers I use LoadLibrary and GetProcAddress and
put the function pointer in my Win32 functions library.
Also notworthy:
Call SwapBuffers on the same thread as your OpenGL calls.
One more thing. I used multiple threads. So this might be helpful to know:
My window was created in thread "B"
My Context was created in thread "A" using HDC from thread "B"
My openGL draw calls are in thread "A".
I mention this because before I found out about SwapBuffers I thought the problem was because of my multi threading. OpenGL wasn't giving me any errors though, so I had to guess around and experiment and read.

glClearBufferfv - not declared in this scope?

EDIT: If anyone has this kind of error, and is using GLEW, when using OpenGL 4.5 functions, the following will help:
glewExperimental = GL_TRUE;
after that just initialize GLEW and you'll be fine.
I´m just starting out with OpenGL. Currently I am trying to clear the whole screen with red, as seen in this code here:
#include "GLFW/glfw3.h"
#define WIDTH 1280
#define HEIGHT 720
int main(void)
{
GLFWwindow *window;
if(!glfwInit()) {
return -1;
}
window = glfwCreateWindow(WIDTH, HEIGHT, "Test OpenGL", NULL, NULL);
if(!window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
static GLfloat red[] = {1.0f, 0.0f, 0.0f, 1.0f};
glClearBufferfv(GL_COLOR, 0, red);
while(!glfwWindowShouldClose(window)) {
//glEnableClientState(GL_VERTEX_ARRAY);
//glDisableClientState(GL_VERTEX_ARRAY);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
But there is a problem. I am using g++ to compile the code written in Code::Blocks. Also, I am learning with the OpenGL SuperBible 7th edition, where I got the code for clearing the screen with red. Before I was using glClearColor(255, 0, 0, 0) and then glClear(GL_COLOR_BUFFER_BIT);
But in this book the screen is cleared with glClearBufferfv, which throws the following exception:
error: 'glClearBufferfv' was not declared in this scope
Of course I want to use the code in the book for learning purposes, so it would be great, if that would work. Sadly, it doesn´t. Any idea, why?
glClearBufferfv is a newer OpenGL function, which means it is technically possible that a graphics card that speaks OpenGL doesn't support it. This means that the function needs to be loaded, either by you or by an OpenGL loading library, before you can use it.
The SuperBible example code comes with the gl3w loader as part of its s7 helper library. You could either:
use s7, which the other examples in the book will likely depend on as well
skip s7 and use gl3w or any other loader, like my personal favourite libepoxy
don't use a loader and load the functions you need by hand. This gets tedious very quick, but it does mean you get to see what's going on.
The GLFW documentation has some useful pointers as well.

OpenGL Invalid Operation with GenVertexArrays

I am creating a grid in opengl, very simple, but am getting an error when I call gl::GenVertexArrays. Below is the code. I am using glfw3.
GLuint vao = 0;
check_gl_error();
gl::GenVertexArrays(1, &vao);
check_gl_error(); //the error is caught here and its a INVALID_OPERATION
gl::BindVertexArray(vao);
check_gl_error();
I do not have much experience with OpenGL, however I have used opengl on the same computer using glfw and have had projects working with GenVertexArrays.
EDIT:
My program is setup with
if (!glfwInit()) {
std::cout << "Init GLFW failed" << std::endl;
exit(EXIT_FAILURE);
}
GLFWwindow* window = glfwCreateWindow(800, 800, "My Title", NULL, NULL); //glfwGetPrimaryMonitor() full screen
if (!window) {
std::cout << "Init window failed" << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
gl::sys::LoadFunctions();
//check_gl_error();
glfwMakeContextCurrent(window);
check_gl_error();
glfwSwapInterval(1);
check_gl_error();
GLuint programID = gl::CreateProgram();
Do you use GLEW or glLoadGen or something? You need to tell it to update its entry points again after you make the actual context current.
In Windows, only ancient OpenGL is available until you make a more modern context current. Only then will the higher-version entry points become available for lookup by GLEW/glLoadGen's code.
In other words, all those OpenGL function pointers suddenly may point to different code, because the OpenGL version changed. That is how wgl works.

Cannot create GLFWwindow in C++ - glfwCreateWindow returns nullptr?

After running several tests on the code, I have determined that both GLFW and GLEW are initialised successfully yet when I try and create a GLFWwindow* object to be used with GLFW functions, the glfwCreateWindow() function returns a nullptr. Why is this and how do I fix it? Here is my code:
#include <iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
const GLuint windowWidth = 500, windowHeight = 500;
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(windowWidth, windowHeight, "Learn OpenGL", nullptr, nullptr);
if (window == nullptr) {
std::cout << "Failed to create GLFW window!" << std::endl;
char myvar1; std::cin >> myvar1;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if (glewInit() != GL_TRUE) {
std::cout << "Failed to initialize GLEW" << std::endl;
char myvar2; std::cin >> myvar2;
return -1;
}
glViewport(0, 0, windowWidth, windowHeight);
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
This is probably because you are specifying version 3.3 for the context creation and your opengl version is lower than 3.3.
OpenGL: GLFW_CONTEXT_VERSION_MAJOR and GLFW_CONTEXT_VERSION_MINOR are not hard constraints, but creation will fail if the OpenGL version of the created context is less than the one requested.
This might happen if you are using a laptop that has 2 GPU's. They do that for power-consumption reasons, most applications will be run with the standard GPU and for games for example it will use the high performance one.
For example my laptop has a built-in Intel(R) HD Graphics 3000(3.1 opengl version) GPU and a NVIDIA geforce gt 630M(4.4 opengl version) GPU.
You can see if your laptop has this functionality if you right click on an application shortcut and have the option "run with graphics processor": - "High performance (NVIDIA) processor" - "Integrated graphics (default)"
The problem is that the editor(eclipse/ms visual studio, etc..)(in which you run your code) will use the default one and usually has a much lower version of opengl than your other GPU.
You can fix this by always running your editor program with your high performance GPU.
If you're not using a laptop or only have one GPU then try updating your drivers.