wglGetProcAddress() strange behavior...?

Hello, could someone please explain this behavior to me…

I have an app running, with a window and all… then, if I use the code:

wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress(“wglGetExtensionsStringARB”);

it returns NULL to wglGetExtensionsStringARB.

However, if I create a GLUT window, and then use wglGetProcAddress(), it works fine. Why is that ?

It should only get the pointer to the extension string “getter”… right?

I’m trying to get rid of GLUT. I only need a pbuffer to work with my main app, no GLUT window (or any OpenGL window for that matter).

Do I have to create an invisible OpenGL window just to get that pointer? … or what?

I know there’s no OpenGL rendering context yet if I have no GLUT/GL window created, is that the problem?

I’ve read the “Rendering to an off-screen buffer with WGL_ARB_pbuffer” paper from ATI, and there’s no mention about having to have an OpenGL RC before getting those pointers. I also have used pbuffers before so I (think I) know how to set them up, but they always have had “regular” OpenGL windows accompanying them.

Thanks for any help,

Andru

“I know there’s no OpenGL rendering context yet if I have no GLUT/GL window created, is that the problem?”

Yes. RTFM

wglGetProcAddress:

"When the function succeeds, the return value is the address of the extension function.

When no current rendering context exists or the function fails, the return value is NULL. To get extended error information, call GetLastError."

Thanks for the swift clear-up, Relic

OK… guess I’ll just create a dummy window and hide it. I suppose I can destroy it once the pbuffer is created and the RC is switched to it… we’ll see what happens. No, I don’t like R’ing The FMs that much as you happened to observe

edit: btw I find it kinda dumb that you have to create a window in order to just draw to an offscreen pbuffer, but guess that’s just me :expressionless:

[This message has been edited by Andru (edited 07-04-2003).]

The problem is similar to needing to have any DLL dynamically loaded and initialized before calling GetProcAddress() to get the export function address. Until OpenGL32.DLL is loaded, there is no reason for the export function to be available. In your example, there is no reason for any GL extension function to be available until the GL state is opened by the first rendering context. You could just as well create the one and only rendering context for a bitmap memory DC rather than a window DC.

I am calling the function, wglGetProcAddress, after creating the RC but it is still not working? Is this because I am drawing in a bitmap instead of the actual window. BTW, the code is working find except the wglGetProcAddress. Does anybody has the answer?

// DrawOnBitmap.cpp : Defines the entry point for the application.
//

#include <windows.h> // Header File For Windows
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The Glaux Library

#include “MIPLib.h”

HDC hDC=NULL; // Private GDI Device Context
HGLRC hRC=NULL; // Permanent Rendering Context
HINSTANCE hInstance; // Holds The Instance Of The Application

bool keys[256]; // Array Used For The Keyboard Routine
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default

int WINAPI WinMain( HINSTANCE hInstance, // Instance
HINSTANCE hPrevInstance, // Previous Instance
LPSTR lpCmdLine, // Command Line Parameters
int nCmdShow) // Window Show State
{
CreateAWindow();

int width=512;
int height=512;
int bits=24;

BITMAPINFO g_BitmapInfo;
HDC hDc = GetDC( NULL );
memset( &g_BitmapInfo, 0, sizeof(BITMAPINFO) );
g_BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
g_BitmapInfo.bmiHeader.biWidth = width;
g_BitmapInfo.bmiHeader.biHeight = height;
g_BitmapInfo.bmiHeader.biPlanes = 1;
g_BitmapInfo.bmiHeader.biBitCount = 24;
g_BitmapInfo.bmiHeader.biCompression = BI_RGB;
BYTE **g_pBitmapBits;
HBITMAP g_hBitmapImage = CreateDIBSection( hDc, &g_BitmapInfo, DIB_RGB_COLORS,
(void **)(&g_pBitmapBits), NULL, 0 );
ReleaseDC( NULL, hDc );

PIXELFORMATDESCRIPTOR pfd ;
memset(&pfd,0,sizeof(PIXELFORMATDESCRIPTOR)) ;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR) ;
pfd.nVersion = 1 ;
pfd.dwFlags = PFD_DRAW_TO_BITMAP | // replaces PFD_DRAW_TO_WINDOW
			  PFD_SUPPORT_OPENGL |
			  PFD_SUPPORT_GDI|PFD_STEREO_DONTCARE ;
pfd.iPixelType = PFD_TYPE_RGBA ; 
pfd.cColorBits = 24 ;
pfd.cAlphaBits = 0;
pfd.cDepthBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE ; 


// create memory dc
HDC dcMem=CreateCompatibleDC(NULL);
if(dcMem==NULL)
{
	MessageBox(NULL,"Fail to create memory DC!","ERROR",MB_OK|MB_ICONEXCLAMATION);
	return -1;;								// return -1;
}

// select bitmap to the memory dc
SelectObject(dcMem,g_hBitmapImage);

GLuint		pxFormat;			// Holds The Results After Searching For A Match
if (!(pxFormat=ChoosePixelFormat(dcMem,&pfd)))	// Did Windows Find A Matching Pixel Format?
{
	MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
	DeleteDC(dcMem);
	DeleteObject(g_hBitmapImage);
	return -1;;								// return -1;
}

if(!SetPixelFormat(dcMem,pxFormat,&pfd))		// Are We Able To Set The Pixel Format?
{
	MessageBox(NULL,"Can't set the given PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
	DeleteDC(dcMem);
	DeleteObject(g_hBitmapImage);
	return -1;;								// return -1;
}

if (!(hRC=wglCreateContext(dcMem)))				// Are We Able To Get A Rendering Context?
{
	MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
	DeleteDC(dcMem);
	DeleteObject(g_hBitmapImage);
	return -1;;								// return -1;
}

if(!wglMakeCurrent(dcMem,hRC))					// Try To Activate The Rendering Context
{
	DeleteDC(dcMem);
	DeleteObject(g_hBitmapImage);
	wglDeleteContext(hRC);
	MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
	return -1;;								// return -1;
}

// set view port
glViewport(0,0,width,height);						// Reset The Current Viewport

// set the view port
glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
glLoadIdentity();									// Reset The Projection Matrix
glFrustum(-1.0,1.0,-1.0,1.0,1.0,5.0);
glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
glLoadIdentity();	

////////////
// init gl
glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				// Black Background
glClearDepth(1.0f);									// Depth Buffer Setup
glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations

////////////////////
// draw a triangle
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer

glLoadIdentity();									// Reset The Current Modelview Matrix
glTranslatef(0.0f,0.0f,-2.0f);						// Move Left 1.5 Units And Into The Screen 6.0
glBegin(GL_TRIANGLES);								// Drawing Using Triangles
	glVertex3f( 0.0f, 1.0f, 0.0f);					// Top
	glVertex3f(-1.0f,-1.0f, 0.0f);					// Bottom Left
	glVertex3f( 1.0f,-1.0f, 0.0f);					// Bottom Right
glEnd();

///////////////////////////
// save the result to a file
CRGBByteImage img(width,height);
glReadPixels(0,0,width,height,GL_RGB,GL_UNSIGNED_BYTE,img.GetPtrOfData());
img.FlipV();
img.SaveAsBmp("screen.bmp");

/////////// this line always returns NULL !!! Why????
PFNGLBLENDCOLORPROC glBlendColor=(PFNGLBLENDCOLORPROC)wglGetProcAddress("glBlendColor");

///////////////////////////
// close
MessageBox(NULL,"Done!","OK",MB_OK);

DeleteDC(dcMem);
DeleteObject(g_hBitmapImage);
if (hRC)											// Do We Have A Rendering Context?
{
	if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
	{
		MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
	}

	if (!wglDeleteContext(hRC))						// Are We Able To Delete The RC?
	{
		MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
	}
	hRC=NULL;										// Set RC To NULL
}

return 1;

}

If you are rendering into a bitmap, its all done using Microsoft’s software OpenGL renderer, which doesn’t support the WGL_ARB_extensions_string extension.

If you’re not drawing with anything else than OpenGL onto that bitmap, one way around this would be to use a pbuffer instead. It’s also invisible and you can render onto it in hardware.
You’re reading back the pixels for your SaveAsBmp anyway, (which is kind of unnecessary if your’re drawing to a bitmap already ).

[This message has been edited by Relic (edited 10-08-2003).]