Can I create a hRC and use wglMakeCurrent() set the hRC to multiple hDCs? I found that every window should have a unique hRC and hDC. Then how can I put the same context to different windows?
Can I create a hRC and use wglMakeCurrent() set the hRC to multiple hDCs?
Yes. You can set a HGLRC to one particular HDC at a particular time in one particular thread, but you can switch it at any time. Also you can have an arbitrary number of HLGLRCs made current on the same HDC, each in a different thread.
The only constraint is that the HGLRC and the HDC to be made current with each other must be compatible in their pixelformat.
I found that every window should have a unique hRC and hDC
That's not correct. Also any window may have an arbitrary number of HDCs.
Then how can I put the same context to different windows?
By calling wglMakeCurrent with the new HGLRC-HDC combination to make current in the thread that is making the call.
Related
I have created an OpenGL application running on Windows. Is there any way I can query information about the pixel format of my current rendering window?
(the window was created using the GLFW library)
What I'm interested in:
Color bits
Depth bits
Pixel type
etc.
I do it like this:
int i;
HDC hdc;
PIXELFORMATDESCRIPTOR pfd;
hdc = GetDC(window_handle); // get device context
i=GetPixelFormat(hdc); // pixel format descriptor index
DescribePixelFormat(hdc,i,sizeof(pfd),&pfd); // format from index
Where window_handle is handle of your apps window. If you got access to the hdc directly than you can skip the first line GetDC. This is how I print the info using VCL and my GL engine:
scr.text(AnsiString().sprintf("color: %i bit R%i G%i B%i A%i",pfd.cColorBits,pfd.cRedBits,pfd.cGreenBits,pfd.cBlueBits,pfd.cAlphaBits));
scr.text(AnsiString().sprintf("accum: %i",pfd.cAccumBits));
scr.text(AnsiString().sprintf("depth: %i",pfd.cDepthBits));
scr.text(AnsiString().sprintf("stenc: %i",pfd.cStencilBits));
scr.text(AnsiString().sprintf("auxil: %i",pfd.cAuxBuffers));
so just use what you got at your disposal for text print. There is a bit more in the pfd structure like bit-shifts, masks etc just inspect it and print what you need.
In the GLFW doc you can read about using the OpenGL API directly by for example glGetFramebufferAttachmentParameteriv or glGetIntegerv.
You can call glfwGetWin32Window function (from glfw3native.h) and retrieve handle of window.
Get HDC form handle (with GetDC(window_handle) function) Then pass this HDC to GetPixelFormat function and call DescribePixelFormat.
See example of usage GetPixelFormat + DescribePixelFormat here:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd318349(v=vs.85).aspx
I am trying to create an OpenGL application on windows. As far as I can understand, one of the first things I must acquire is a Device Context, which must be passed on to a couple of functions that choose and set a pixel format and create a rendering context. I used the OpenGL wiki to get a rough idea about what I should do.
My code is something like:
#include <iostream>
#include <windef.h>
#include <wingdi.h>
HDC hdc;
int main() {
hdc = wglGetCurrentDC();
std::cout << "HDC: " << hdc << std::endl;
return 0;
}
This prints
HDC: 0
I assumed a Device Context refers to a physical device, but I read somewhere that it refers to any drawable "surface". In both cases is my question: how can I obtain a non-null DC? Or should I perform a completely different set of steps in order to set up this whole OpenGL system?
I found a lot of tutorials online, but they all use GLUT, GLEW, GLFW, X11, SDL etc. which are libraries. Libraries make certain things easier, but they usually do not perform tasks that are impossible without using them. This time, I want to try to do things the hard way and therefore use no libraries, just plain OpenGL.
I found, at last, a tutorial that only used the windows libraries for creating a window.
You did not state your OS but I assume Windows from the function names. The problem is exactly as Reto Koradi stated in the comment. To set up OpenGL you need to do this:
Obtain OS handle to object with valid device context
It can be OS window or OS bitmap. If you have just console app then you need to create a valid OS window first and use its handle (to my knowledge console does not have Canvas).
you can use GLUT for the window creation or If your compiler IDE has an window App you can use that. You can also combine OpenGL and Window components. VCL is also not a problem (I am using it for years with OpenGL)
In windows you can use CreateWindowEx so google an example for it...
Anyway you should have your handle in a variable like:
HWND hwin=NULL;
If you have no experience with windows applications then use GLUT for this. Otherwise you would need to learn a lot of stuff just to cover window creation, message handling of events and user/app interaction which can be really overwhelming for a rookie without guide.
Get Device context for that handle
HDC hdc = GetDC(hwin);
Set pixel format you need of device context
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory( &pfd, sizeof( pfd ) ); // set the pixel format for the DC
pfd.nSize = sizeof( pfd );
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 24;
pfd.iLayerType = PFD_MAIN_PLANE;
SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);
Create OpenGL rendering context for device context
HGLRC hrc = wglCreateContext(hdc);
Set it as default OpenGL context
wglMakeCurrent(hdc, hrc);
This is absolute minimum without any error checking , additional buffers etc. For more info and actual code see related QA's:
How to render an openGL frame in C++ builder? for oldstyle GL
simple complete GL+VAO/VBO+GLSL+shaders example in C++ with the new stuff
You can use GLUT for all of this. This is first hit I found by quick search:
How can I set an OpenGL display (Window created by OpenGL) to maximized?
Or follow OpenGL tutorials there are tons of them out there ...
I am implementing a plug-in inside a 3rd party program in C++ on Windows.
The 3rd party program has a window that displays 3D graphics using OpenGL.
However I need the plug-in to create another window that also displays 3D graphics using OpenGL.
Do I need to create a new OpenGL rendering context for my window or is there some way that I can "reuse" the OpenGL rendering context used by the 3rd party program?
I assumed that I had to create a new OpenGL rendering context and tried the following:
// create a rendering context
hglrc = wglCreateContext (hdc);
// make it the calling thread's current rendering context
wglMakeCurrent (hdc, hglrc);
However the last function failed.
Reading the documentation of wglMakeCurrent I notice that
A thread can have one current rendering context. A process can have multiple rendering contexts by means of multithreading.
Does this mean that my window need to run in a separate thread from the 3rd party program?
You didn't post error code generated by wglMakeCurrent(), so I won't be guessing the reason. It's not the binding itself, however. Sentence 'A thread can have one current rendering context' means, that new context will 'replace' the old one and become the current. I don't know why are you trying to set two contexts as current (or run another thread), but it's not the way to go. Avoid multithreading in rendering unless it's absolutely necessary.
So, answering your question:
Yes, you CAN 'reuse' OpenGL rendering context.
Why, you may ask? Rendering context is created for specific device context (HDC), which is exclusive property of each window (HWND)! How is this possible, then?!
Well, it seems somehow impossible because of function prototypes:
HWND my_window = CreateWindow(...);
HDC my_dc = GetDC(my_new_window);
//Setup pixel format for 'my_dc'...
HGLRC my_rc = wglCreateContext(my_dc);
wglMakeCurrent(my_dc, my_rc);
This really lets you think that rendering context is bound to this specific device context and valid only for it. But it's not.
The critical part is the comment (setup pixel format). Rendering context is created for specific CLASS of DCs, to be more precise: for DCs with the same pixel format. So code below is perfectly valid:
//window_1 = main window, window_2 = your window
HDC dc_1 = GetDC(window_1);
Set_pixel_format_for_dc_1(); //Usual stuff
HGLRC rc = wglCreateContext(dc_1);
wglMakeCurrent(dc_1, rc);
ultra_super_draw();
//.....
HDC dc_2 = GetDC(window_2);
//Get dc_1's PF to make sure it's compatible with rc.
int pf_index = GetPixelFormat(dc_1);
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
DescribePixelFormat(dc_1, pf_index, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
SetPixelFormat(dc_2, pf_index, &pfd);
wglMakeCurrent(dc_2, rc);
another_awesome_render();
wglMakeCurrent(NULL, NULL);
If you are still not convinced, MSDN:
wglMakeCurrent(hdc, hglrc): The hdc parameter must refer to a drawing surface supported by OpenGL. It need not be the same hdc that was passed to wglCreateContext when hglrc was created, but it must be on the same device and have the same pixel format.
I guess you are already familiar with these calls. Now, I don't know what are the conditions that your rendering must meet, but without additional requirements, I don't see any difficulties from this point:
HDC my_dc = Create_my_DC();
//...
void my_new_render
{
//Probably you want to save current binding:
HDC current_dc = wglGetCurrentDC();
HGLRC current_context = wglGetCurrentContext();
wglMakeCurrent(my_dc, current_context);
MyUltraSuperRender(...);
wglMakeCurrent(current_dc, current_context);
}
Hope this helps :)
First things first, you actually should create a separate OpenGL context for your plugin, for the simple reason that it gives you a separate state space that doesn't interfere with the main programs OpenGL context.
You misunderstood the part about multiple rendering contexts though. It's perfectly possible to have an arbitrary number of OpenGL contexts for a process. But each thread of the process can bind only one context at a time. That one binding also includes the window DC the context is bound to. It is however perfectly legal change a context binding at any time. Either you change the window a given context is bound to, or you switch the context or you do both at the same time.
So in your situation I suggest you create a custom context for your plug-in, that you use for all the windows your plug-in creates.
That your simple context "creation" code fails has one simple reason: Your window will most likely not have a pixel format descriptor set.
I suggest you use the following method to create your new windows and contexts:
/* first get hold of the HDC/HRC of the parent */
HDC parentDC = wglGetCurrentDC();
HRC parentRC = wglGetCurrentContext();
int pixelformatID = GetPixelFormat(parentDC);
/* we use the same PFD as the parent */
PIXELFORMATDESCRIPTOR pixelformat;
memset(pixelformat, 0, sizeof(pixelformat);
DescribePixelFormat(parentDC, pixelformatID, sizeof(pixelformat), &pixelformat);
/* create a window and set it's pixelformat to the parent one's */
HWND myWND = create_my_window();
HDC myDC = GetDC(myWND);
SetPixelFormat(myDC, pixelformatID, &pixelformat);
/* finally we can create a rendering context
* it doesn't matter if we create it against
* the parent or our own DC.
*/
HRC myRC = wglCreateContext(myDC);
/* we're done here... */
Now whenever your plugin wants to render something it should bind its own context, do its thing and bind the context that was bound before:
HDC prevDC = wglGetCurrentDC();
HRC prevRC = wglGetCurrentContext();
wglMakeCurrent(myDC, myRC);
/* do OpenGL stuff */
wglMakeCurrent(prevDC, prevRC);
I am using `QGLWidget and OpenCL.
To set the CL-GL interoperation I need
HGLRC glContext
HDC deviceGLContext
How to get it using Qt?
You can select the QGLWidget for current OpenGL operations with QGLWidget::makeCurrent() and then retrieve current HGLRC and HDC with wglGetCurrentContext and wglGetCurrentDC, respectively.
I'm writing an unmanaged Win32 C++ function that gets a handle to a bitmap, and I need to draw on it.
My problem is that to draw I need to get a device context, but when I do GetDC (NULL), it gives me a device context for the WINDOW! The parameter for GetDC () is a window handle (HWND), but I don't have a window; just a bitmap handle.
How can I draw on this bitmap? Thanks!
In addition to Pavel's answer, the "compatible with the screen" always bugged me too, but, since CreateCompatibleDC(NULL) is universally used for that purpose, I assume it is correct.
I think that the "compatible" thing is related just to DDB (the DC is set up to write on the correct DDB type for the current screen), but does not affect read/writes on DIBs.
So, to be safe, always use DIBs and not DDBs if you need to work on bitmaps that doesn't just have to go temporarily onscreen, nowadays the difference in performance is negligible. See here for more info about DIBs and DDBs.
CreateCompatibleDC() and SelectObject() your bitmap into it.
However, not every bitmap can be selected into any DC.
You might have to play with mapping mode and other options of memory DCs.
The basic win32 paradigm for drawing on a bitmap is that you select the bitmap onto a device context, after which, all drawing operations on that device context are stored in the bitmap. You then use one of the various 'blit' operations (e.g. StretchBlt) to transfer this to a display surface, which is just the device context of a window client area.
Others have provided better detail, this is just the high-level view.
Well, this is a bit outside the box.. I guess.. But I do know that Graphics can return a HDC, and Graphics take a Bitmap as an argument to its ctor . A Bitmap in turn can be created from a HBITMAP and a HPALETTE. The only problem here is that I do not know if the HPALETTE argument can be NULL.
Graphics* g;
Bitmap* bitmap;
HBITMAP _bitmap; // <- this one is yours
bitmap = Bitmap::FromHBITMAP(_bitmap, NULL);
g = new Graphics(bitmap);
HDC hdc = g->GetHDC();
// when done, call g->ReleaseHDC(hdc);
However, I would urge you to receive the HDC as an argument to your function as well.. I do not think that anyone will have a BITMAP and NOT have the DC to it.
If you're having these issues with finding a HDC to a HBITMAP, so will everyone else.