Loading OpenGL > 1.1 functions Windows - c++

I'm having trouble setting up OpenGL with MSVS 2013. I'm aware that the opengl32.dll on my Windows
platform located at C:\Windows\System32 is an implementation of OpenGL 1.1.
What I'm trying to do is to load the newer OpenGL > 1.1 functions such as glBindBuffer and glBufferData. I have read that it's possible getting a pointer to the function using wglGetProcAddress. When using this function the returned pointer is always null, all the original functions in the dll using GetProcAddress(OpenGL32DLL, "...") work perfectly except the newer functions don't seem to load.
I'm hoping anybody here can help me go through my setup and point out what I did wrong or if I have missed something.
So here we go:
I have downloaded OpenGL Extensions Viewer 4.4 which points out I'm able to perfectly run upto OpenGL 2.1 which
should be more than enough to use or load glBindBuffer and glBufferData.
I downloaded Microsoft SDKs/v7.1 which includes the headers: gl/glu.h and gl/gl.h; I also downloaded the GLEXT extensions API
from here and linked the glext.lib + included the headers.
Files in the Linker:
C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\OpenGL32.Lib
C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\GlU32.Lib
C:\Users\user\Desktop\glext\lib\glext.lib
The CPP files included:
C:\Program Files\Microsoft SDKs\Windows\v7.1\Include -> GL.h, GLU.h
C:\Users\user\Desktop\glext\include -> glcorearb.h, glext.h, wglext.h

Instead of handling all these details yourself, I suggest you just grab yourself a copy of GLEW ( http://glew.sourceforge.net/ ) which handles all of this for you in a standard way. I currently use it on several published products without issues.
In your example, you'd be able to do the following:
if (GL_ARB_multi_bind) {
//glBindBuffer is available.
}
(Of course, after a call to glewInit(), possibly with glewExperimental = TRUE; - see documentation for details.)

When using this function the returned pointer is always null, all the original functions in the dll using GetProcAddress(OpenGL32DLL, "...") work perfectly except the newer functions don't seem to load.
Do you have a valid OpenGL context created and made current on the calling thread? In Windows extension functions are technically per-context, i.e. you have to get the pointers to the functions for each OpenGL context you create and make sure to use the right function pointers with the right context.
This of course also means that you must have a OpenGL context to begin with. The usual sequence of setting up an OpenGL context in Windows is:
pseudocode
struct glctx {
HGLRC rc
// dictionary for explanation purposes
// one would normally just have a bunch of
// structure elements here
functionpointer[string:name] extensionfunction
}
if not window_with_desired_pixelformat_exists: {
wnd := create_a_window
pixelformat := select_pixelformat
wnd→set_pixelformat pixelformat
}
dc := wnd→getDC
glctx ctx
ctx→rc := wglCreateContext(dc)
wglMakeCurrent(dc, ctx→rc);
foreach(fname in extensionfunctions_names): {
ctx→extensionfunction[name] = wglGetProcAddress(name)
}

I think that the problem is that there is no current context while calling wglGetProcAddress.
Function pointers can be specific for a precise pixel format, determined by tge context creation procedure.

Related

Correctly setting up MMDevice in a DirectX project

I am currently trying to piece together a shader-based music visualizer. The plan is to read data from the current MMDevice, which I'm trying to follow the documentation for, but I must be doing something wrong because I had to jump through all sorts of hoops to get even just the MMDeviceEnumerator to compile.
In order for the uuids of MMDeviceEnumerator and IMMDeviceEnumerator to be defined, I had to set #define WINAPI_FAMILY WINAPI_FAMILY_GAMES. This was also required for EDataFlow and ERole enumerations to be defined. My first question is if I've missed some configuration somewhere, or if this is the intended method of enabling these things.
Currently, I have the following code in an AudioStream class:
class AudioStream {
public:
AudioStream() {
//SUCCEEDING(CoInitializeEx(nullptr, COINIT_MULTITHREADED));
SUCCEEDING(CoCreateInstance(
__uuidof(IMMDeviceEnumerator),
NULL,
CLSCTX_ALL,
__uuidof(MMDeviceEnumerator),
(void**)&this->mmDeviceEnumerator));
SUCCEEDING(this->mmDeviceEnumerator->GetDefaultAudioEndpoint(
eRender,
eConsole,
&this->mmDevice));
}
private:
IAudioClient* audioClient = NULL;
IAudioCaptureClient* captureClient = NULL;
IMMDeviceEnumerator* mmDeviceEnumerator = NULL;
IMMDevice* mmDevice = NULL;
};
If you're familiar with what the DirectX 12 project template looks like, this object is being instantiated in the Sample3DSceneRenderer constructor. The main issue I'm having right now is the following two errors which are immediately raised during startup:
onecore\com\combase\dcomrem\resolver.cxx(2299)\combase.dll!75AA0DFF: (caller: 75B1CF2C) ReturnHr(1) tid(42a8) 80040154 Class not registered
onecore\com\combase\dcomrem\resolver.cxx(2507)\combase.dll!75B1CF4D: (caller: 75AA29E4) ReturnHr(2) tid(42a8) 80040154 Class not registered
This causes the entire app to hang, and the project template visualization to never appear (the succeeding macro exits). Does anyone have any idea why this is failing? It must have to be something with the CoCreateInstance call :(
You are writing a Universal Windows Platform (UWP) app because that's what the "built-in" DirectX 12 App project template creates in Visual Studio. UWPs do not have access to all the same APIs and IMMDevice is not part of the UWP API surface area.
The fact that you defined WINAPI_FAMILY_GAMES means you hacked the API Family Partition macros which will define the API in a UWP context, but it doesn't mean that API actually works from the AppContainer process that all UWPs run in.
You really have two options:
(1) If you want to write a UWP, then you will need to enumerate audio devices via the proper Windows Runtime APIs which are in the Windows::Devices::Enumeration namespace.
Assuming you are using C++/CX language extensions (instead of the more modern C++/WinRT projections), then this code works:
auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender);
while (operation->Status == Windows::Foundation::AsyncStatus::Started)
{
Sleep(100);
}
if (operation->Status != Windows::Foundation::AsyncStatus::Completed)
{
throw std::runtime_error("FindAllAsync");
}
DeviceInformationCollection^ devices = operation->GetResults();
for (unsigned i = 0; i < devices->Size; ++i)
{
using Windows::Devices::Enumeration::DeviceInformation;
DeviceInformation^ d = devices->GetAt(i);
// d->Id->Data();
// d->Name->Data();
}
Also, if you want to get access to the audio capture device from a UWP, you must add a capability to your manifest to request it via <DeviceCapability Name="microphone"/>. See Microsoft Docs.
You should take the time to read the Microsoft Docs on UWPs so you have a better idea of what's supported and what's not.
(2) If you want to write a Win32 desktop app, use the directx-vs-templates instead which include DirectX 12 starting templates for Win32 desktop apps (plus alternative DirectX templates for UWP if that's your thing).
Whichever appmodel you use, you may want to take a look at DirectX Tool Kit for Audio.
BTW, WINAPI_FAMILY_GAMES is used by the Microsoft GDK for Xbox which is for writing titles for Xbox One and Xbox Series X|S. It uses Win32 APIs and doesn't use Windows Runtime APIs, so it has the IMMDevice interface in it's API surface. See Microsoft Docs.

How to solve a function acting differently based on callsite?

Not sure how to word the title so feel free to rename, but the issue I'm having is that I've got a function that works in one project, but fails in another. Below is rough pseudocode to show that one call in LibraryProject works, whereas the call in GameProject doesn't.
In ChildClass::do_stuff, the win32_window HWND is valid, whereas the second one, failed_win32_window is null and glfw throws an error saying it isn't initialized, despite it already having been initialized (since the first glfw call was successful and I've manually stepped through to verify it was):
GLFWError #65537 Happen, The GLFW library is not initialized
Here's pseudocode showing the two projects, and the files. GLFW is set initialized properly since if I do all my glfw logic within LibraryProject, the window shows up as normal.
//LibraryProject
////library_header.h
class ParentClass {
GLFW* _mainWindow; //filled in elsewhere in the real code
HWND getWin32Window() { return glfwGetWin32Window(_mainWindow); }
}
//GameProject
////game_header.h
#include "library_header.h" //from other Project
class ChildClass : public ParentClass {
void do_stuff() {
HWND win32_window = this->getWin32Window(); //this works because it goes down into LibraryProject.dll's module
HWND failed_win32_window = glfwGetWin32Window(_mainWindow); //but literally the same call here doesn't because it happens within GameProject.exe
}
}
////game_body.cpp
void function_called_elsewhere_in_game() {
//called from GameProject.exe
auto child = ChildClass();
child.do_stuff();
}
I'm not sure if this is an issue with glfw and my setup, or just my misunderstanding how projects and dependencies work.
Things I've tried:
Downloading the latest glfw3
Rebuilding the entire solution
Toggling with References and Linking Dependency Inputs
Things to note:
This is happening in the main thread, nothing else is using glfw at the same time. Its 100% reproducible too.
glfw3.lib is always being created in my GameProject output folder, based on the one inside LibraryProject
Stepping through the disassembly for each of the two glfwGetWin32Window calls has different addresses in disassembly, leading me to believe they're two different copies of the same library, but I'm not sure.
This is not an issue with cocos2d, the game engine I'm using as starting a blank project and calling glfwGetWin32Window(..) returns a valid pointer, even in GameProject, so there's something that I'm doing wrong, but I don't know what.
Images showing off the actual behaviour. magnolia_cocos_proj is GameProject and is the exe I'm running, and libcocos2d is LibraryProject I'm using as a DLL (I'm unfamiliar with the details of how linking and dlls work).
win32_window has valid value
definition of getWin32Window() to be 100% sure. Notice the module is in libcocos2d.dll now.
after going over the second line, the error throws and the second window is null
As I understood from "glfw3.lib is always being created" you use static linking. Static linking of a lib to different dll and exe lead to duplicating of all static memory of the lib. You should use a dynamic library for GLFW in the case. It's glfw3dll.lib.
There are two main cases why this error could appear:
GLFWError #65537 Happen, The GLFW library is not initialised
Case One :
The mentioned error occurs if a GLFW function was called that mustn't be called unless the library is initialised. So, you need to initialise GLFW before calling any function that requires initialisation.
Read an API introduction for reference. Use if-else statement for handling glfwInit() and errors.
Reading Moving from GLFW 2 to 3 is also useful.
Case Two :
This error quite often occurs in the case you have previous versions of GLFW installed on your machine. GLFW3 doesn't like running along with previous version installed. So, delete all the GLFW libraries and linkers and reinstall the latest GLFW 3 from scratch.
Hope this helps.

wglCreateContextAttribsARB not defined?

C++ application, I define a temp context, make it current, and then try to use wglCreateContextAttribsARB, which is simply undefined. Most answers I have seen say to use PFNWGLCREATECONTEXTATTRIBSARBPROC. Which is also undefined. What am I missing?
I'm only using gl.h (provided by VS2015)
SetPixelFormat(g_hDc, chosenPixelFormat, &pfd);
HGLRC temporaryContext = wglCreateContext(g_hDc);
wglMakeCurrent(g_hDc, temporaryContext);
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB...
Both, however, are just unidentified. I initially tried calling wglCreateContextAttribsARB by itself, to no avail, anywhere in my code.
At this stage, I have a context working, windowed, 480p, updating, stable 60FPS. So I know my side is working. I'm getting no GL errors either. Where do I need to instantiate these two? Am I using the wrong gl header?
I'm using an updated ASUS Radeon R9-285
All data types and constants related to wgl extensions are declared in wglext.h.
You need to query the function pointer of type PFNWGLCREATECONTEXTATTRIBSARBPROC using your current context via the GL extension mechansim (e.g. wglGetProcAddress()).

OpenGL Multitexturing - glActiveTexture is NULL

I have started a new project, which I want to use multitexturing in.
I have done multixexturing before, and is supported by my version of OpenGL
In the header I have:
GLuint m_TerrainTexture[3];//heightmap, texture map and detail map
GLuint m_SkyboxTexture[5]; //left, front, right, back and top textures
PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB;
PFNGLACTIVETEXTUREARBPROC glActiveTexture;
In the constructor I have:
glActiveTexture = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress((LPCSTR)"glActiveTextureARB");
glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress((LPCSTR)"glMultiTexCoord2fARB");
if(!glActiveTexture || !glMultiTexCoord2fARB)
{
MessageBox(NULL, "multitexturing failed", "OGL_D3D Error", MB_OK);
}
glActiveTexture( GL_TEXTURE0_ARB );
...
This shows the message box "multitexturing failed" and the contents of glActiveTexture is 0x00000000
when it gets to glActiveTexture( GL_TEXTURE0_ARB ); I get an access violation error
I am implementing the MVC diagram, so this is all in my terrain view class
You quoted your code to load the extensions like following:
PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB;
PFNGLACTIVETEXTUREARBPROC glActiveTexture;
glActiveTexture = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress((LPCSTR)"glActiveTextureARB");
glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress((LPCSTR)"glMultiTexCoord2fARB");
This is very problematic, since it possibly redefines already existing symbols. The (dynamic) linker will eventually trip over this. For example it might happen that the assignment to the pointer variable glActiveTexture goes into some place, but whenever a function of the same name is called it calls something linked in from somewhere else.
In C you usually use a combination of preprocessor macros and custom prefix to avoid this problem, without having to adjust large portions of code.
PFNGLMULTITEXCOORD2FARBPROC myglMultiTexCoord2fARB;
#define glMultiTexCoord2fARB myglMultiTexCoord2fARB
PFNGLACTIVETEXTUREARBPROC myglActiveTexture;
#define glActiveTexture myglActiveTexture
glActiveTexture = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress((LPCSTR)"glActiveTextureARB");
glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress((LPCSTR)"glMultiTexCoord2fARB");
I really don't know of any other reason why things should fail if you have a valid render context active and the extensions supported.
GLEE is a dead library; it hasn't been updated in a long time.
GLEW is a fine extension loading library, but it has some issues working with core 3.2 and above.
I would suggest GL3W. The beauty of it is that it is self-updating; it downloads and parses the headers by itself. The downside is that you need a Python 2.6 installation to generate the loader. But it provides reasonably good results otherwise.
I recommend GLEW/GLEE for extension management.
Rastertek tutorial has the complete setup required to make wglGetProcAddress to work. GLEW doesn't work for me either, I've tried everything I could think of and I asked many people about it but it simply doesn't work in VS 2012, not to mention the enormous frustration I experienced when I wanted to compile a shader.

Using OpenGL extensions On Windows

I want to use the functions exposed under the OpenGL extensions. I'm on Windows, how do I do this?
Easy solution: Use GLEW. See how here.
Hard solution:
If you have a really strong reason not to use GLEW, here's how to achieve the same without it:
Identify the OpenGL extension and the extension APIs you wish to use. OpenGL extensions are listed in the OpenGL Extension Registry.
Example: I wish to use the capabilities of the EXT_framebuffer_object extension. The APIs I wish to use from this extension are:
glGenFramebuffersEXT()
glBindFramebufferEXT()
glFramebufferTexture2DEXT()
glCheckFramebufferStatusEXT()
glDeleteFramebuffersEXT()
Check if your graphic card supports the extension you wish to use. If it does, then your work is almost done! Download and install the latest drivers and SDKs for your graphics card.
Example: The graphics card in my PC is a NVIDIA 6600 GT. So, I visit the NVIDIA OpenGL Extension Specifications webpage and find that the EXT_framebuffer_object extension is supported. I then download the latest NVIDIA OpenGL SDK and install it.
Your graphic card manufacturer provides a glext.h header file (or a similarly named header file) with all the declarations needed to use the supported OpenGL extensions. (Note that not all extensions might be supported.) Either place this header file somewhere your compiler can pick it up or include its directory in your compiler's include directories list.
Add a #include <glext.h> line in your code to include the header file into your code.
Open glext.h, find the API you wish to use and grab its corresponding ugly-looking declaration.
Example: I search for the above framebuffer APIs and find their corresponding ugly-looking declarations:
typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); for GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei, GLuint *);
All this means is that your header file has the API declaration in 2 forms. One is a wgl-like ugly function pointer declaration. The other is a sane looking function declaration.
For each extension API you wish to use, add in your code declarations of the function name as a type of the ugly-looking string.
Example:
PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
Though it looks ugly, all we're doing is to declare function pointers of the type corresponding to the extension API.
Initialize these function pointers with their rightful functions. These functions are exposed by the library or driver. We need to use wglGetProcAddress() function to do this.
Example:
glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) wglGetProcAddress("glGenFramebuffersEXT");
glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) wglGetProcAddress("glBindFramebufferEXT");
glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) wglGetProcAddress("glFramebufferTexture2DEXT");
glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) wglGetProcAddress("glCheckFramebufferStatusEXT");
glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) wglGetProcAddress("glDeleteFramebuffersEXT");
Don't forget to check the function pointers for NULL. If by chance wglGetProcAddress() couldn't find the extension function, it would've initialized the pointer with NULL.
Example:
if (NULL == glGenFramebuffersEXT || NULL == glBindFramebufferEXT || NULL == glFramebufferTexture2DEXT
|| NULL == glCheckFramebufferStatusEXT || NULL == glDeleteFramebuffersEXT)
{
// Extension functions not loaded!
exit(1);
}
That's it, we're done! You can now use these function pointers just as if the function calls existed.
Example:
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, colorTex[0], 0);
Reference: Moving Beyond OpenGL 1.1 for Windows by Dave Astle — The article is a bit dated, but has all the information you need to understand why this pathetic situation exists on Windows and how to get around it.
A 'Very strong reason' not to use GLEW might be that the library is not supported by your compiler/IDE. E.g: Borland C++ Builder.
In that case, you might want to rebuild the library from source. If it works, great, otherwise manual extension loading isnt as bad as it is made to sound.
#Kronikarz: From the looks of it, GLEW seems to be the way of the future. NVIDIA already ships it along with its OpenGL SDK. And its latest release was in 2007 compared to GLEE which was in 2006.
But, the usage of both libraries looks almost the same to me. (GLEW has an init() which needs to be called before anything else though.) So, you don't need to switch unless you find some extension not being supported under GLEE.
GL3W is a public-domain script that creates a library which loads only core functionality for OpenGL 3/4. It can be found on github at:
https://github.com/skaslev/gl3w
GL3W requires Python 2.6 to generate the libraries and headers for OpenGL; it does not require Python after that.