PDA

View Full Version : glBlitFramebufferEXT and AA set by the Graphics card settings



Devdept2
05-25-2012, 06:28 AM
Hi,

I have a viewport created with a PixelFormat without multisampling (in theory).




pfd = new PixelFormatDescriptor();


OperatingSystem osInfo = System.Environment.OSVersion;

pfd.dwFlags = (int) (pixelFormat.DRAW_TO_WINDOW | pixelFormat.SUPPORT_OPENGL | pixelFormat.DOUBLEBUFFER);


if (osInfo.Version.Major >= 6)


pfd.dwFlags = pfd.dwFlags | (int)pixelFormat.SUPPORT_COMPOSITION;


pfd.PixelType = (int) pixelTypes.TYPE_RGBA;
pfd.ColorBits = 24;
pfd.AlphaBits = 8;
pfd.DepthBits = 24;


nPixelFormat = Windows.ChoosePixelFormat(theHdc, pfd);

bool valid = Windows.SetPixelFormat(theHdc, nPixelFormat, pfd);

theHrc = wglCreateContext(theHdc);

wglMakeCurrent(hdc, theHrc);


I create a Multisample FBO with a number of samples defined by my application




rbColor = gl.GenRenderbuffersEXT();
gl.BindRenderbufferEXT(gl.RENDERBUFFER_EXT, rbColor);
gl.RenderbufferStorageMultisampleEXT(gl.RENDERBUFF ER_EXT, samples, gl.RGB, Width, Height);


rbDepth = gl.GenRenderbuffersEXT();
gl.BindRenderbufferEXT(gl.RENDERBUFFER_EXT, rbDepth);
gl.RenderbufferStorageMultisampleEXT(gl.RENDERBUFF ER_EXT, samples, gl.DEPTH_COMPONENT, Width, Height);


fbo = gl.GenFramebuffersEXT();
FrameBufferObject.Enable(fbo);
gl.FramebufferRenderbufferEXT(gl.FRAMEBUFFER_EXT, gl.COLOR_ATTACHMENT0_EXT, gl.RENDERBUFFER_EXT, rbColor);
gl.FramebufferRenderbufferEXT(gl.FRAMEBUFFER_EXT, gl.DEPTH_ATTACHMENT_EXT, gl.RENDERBUFFER_EXT, rbDepth);


Status = gl.CheckFramebufferStatusEXT(gl.FRAMEBUFFER_EXT);


CheckFboStatus(Status);



Then I draw my scene on this FBO and I copy it (only the color bits) to the Framebuffer with glBlitFramebufferEXT:



gl.BindFramebufferEXT(gl.READ_FRAMEBUFFER_EXT, fbo);
gl.BindFramebufferEXT(gl.DRAW_FRAMEBUFFER_EXT, 0);


gl.BlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST);


gl.BindFramebufferEXT(gl.READ_FRAMEBUFFER_EXT, 0);
gl.BindFramebufferEXT(gl.DRAW_FRAMEBUFFER_EXT, 0);


Now, if the user overrides the Antialiasing settings on the "Graphics Card Settings" page and sets a number of samples different from the one used by my internal FBO, I get a GL_INVALID_OPERATION after the call to glBlitFramebufferEXT.

If instead the user sets the number of Samples equal to the one I use internally for the FBO, or if he leaves the Antialiasing settings to "Application Controlled" it works fine.

My guess is that when the option to override the application settings is set, the Framebuffer is craeted with the number of samples specified by the graphics card settings page and copying between buffers with different samples number gives the error.

Can anybody help?

Alfonse Reinheart
05-25-2012, 08:36 AM
The solution is to detect that the default framebuffer is a multisampled framebuffer. If it is, create your FBO buffers with the same number of samples. That way, you can successfully blit between them.

First, query `GL_SAMPLE_BUFFERS` (while the default framebuffer is bound); if it's 0, then the default framebuffer is not multisampled. If it's 1, then it is multisampled. To get the number of samples, query `GL_SAMPLES`, then use that count to create your multisampled framebuffer.

Devdept2
05-28-2012, 12:43 AM
Yeah that works!
Thank you very much Alfonse.

Devdept2
06-15-2012, 02:21 AM
It seems I was wrong: the copy from my FBO created with the same number of samples as the main framebuffer gives GL_Invalid_Operation. :(

I don't know why it seemed to work 2 weeks ago...

But if I copy from my multisample FBO to a non-multisample FBO and then to the main multisample framebuffer it works.

Is it really necessary to do this double copy, or should the Blit work directly between the two multisample FBO?

The documentation for glBlitFrameBuffer reports:



GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT and any of the following conditions hold:

The read buffer contains fixed-point or floating-point values and any draw buffer contains neither fixed-point nor floating-point values.

The read buffer contains unsigned integer values and any draw buffer does not contain unsigned integer values.

The read buffer contains signed integer values and any draw buffer does not contain signed integer values.




But I don't quite understand it: how do I know what kind of data my buffer contains?

kyle_
06-15-2012, 03:02 AM
If SAMPLE_BUFFERS for either the read framebuffer or draw framebuffer is
greater than zero, no copy is performed and an INVALID_OPERATION error is
generated if the dimensions of the source and destination rectangles provided to
BlitFramebuffer are not identical, or if the formats of the read and draw framebuffers
are not identical.

This is from the spec, not ext extension, but it applies there as wel iirc. Right now you dont know what is the format of your rbo - use sized internal format.


But I don't quite understand it: how do I know what kind of data my buffer contains?

You know that from the format of your attachemnts.

Also note that GL_RGB (or GL_RGB8 which would likely result from it) is not required renderbuffer format.

Devdept2
06-15-2012, 03:25 AM
Hi,

the size of the FBO and the Renderbuffer is the same.

My renderBuffer attached to the FBO is created with internal format GL_RGB.

kyle_
06-15-2012, 04:30 AM
My renderBuffer attached to the FBO is created with internal format GL_RGB.
No its not. RGB is not an internal format. Lots of functions take 'base internal formats' for whatever reason, but driver has to resolve this to actual internal format. (ie RGB can be either RGB8 or RGB16 or whatever)

Last part of what i quoted is important - _default_ fbo needs to have the same format as yours (and you usually do have alpha component on it).

Devdept2
06-15-2012, 05:10 AM
So how do I create a renderBuffer with the same internal format of the framebuffer?

kyle_
06-15-2012, 05:16 AM
So how do I create a renderBuffer with the same internal format of the framebuffer?

Funny thing is - it may not be possible :) If pixelformat advertises components that are shifted in a way that default framebuffer is BGRA then it cant be done, since GL doesnt expose such internal formats.

Theory aside, try putting GL_RGBA8 in your renderbuffer storage.

Devdept2
06-15-2012, 05:39 AM
I tried but with no success

Devdept2
06-18-2012, 01:21 AM
Am I the only one having this problem when blitting a multisample fbo on a renderbuffer that is forced to multisample by the graphics card settings?

I think I'll have to use the blit from my MSAA fbo to a non-MSAA fbo and then to the main framebuffer, since this way it seems to always work...

p.s. I noticed that the problem happens also if I create the main renderBuffer with the same number of samples of my FBO and try to blit directly between the two, not only if I force the MSAA from the Graphics Card settings.

Ilian Dinev
06-18-2012, 12:09 PM
2 things to try:

gl.RGB -> gl.RGBA // or maybe BGRA8 . This will generally match the format of the main FBO, which on Windows usually is BGRA8. (unless running in 16-bit mode, there's it's 565, blue at LSB).


Resolve your framebuffer into an FBO that uses textures instead of renderbuffers. Renderbuffers and the default FBO (which consists of color + depth/stencil renderbuffers) can be a subject to driver-overrides, it seems. Textures generally are left intact by the driver.

Dark Photon
06-18-2012, 06:37 PM
Am I the only one having this problem when blitting a multisample fbo on a renderbuffer that is forced to multisample by the graphics card settings? ... I noticed that the problem happens also if I create the main renderBuffer with the same number of samples of my FBO and try to blit directly between the two
It's worked for me when the number of MSAA samples is the same, but IIRC it's documented as not supported if the number of samples is different and both != 1. Which vendor/drivers? Ilian's got a good point about making sure the sample formats are exactly the same.

Devdept2
06-19-2012, 03:51 AM
Ok,

since I'm having too many problems using Multisample FBOs I decided to take another approach.

I draw normally on the main multisample framebuffer.

When I need to capture the image of the framebuffer, I blit the FrameBuffer to a FBO without multisampling and read it on a texture (I enable the FBO, set the glReadBuffer to gl.COLOR_ATTACHMENT0_EXT and I use glCopyTexSubImage2D to copy it on the texture).

Problem: on the ATI card the texture is flipped vertically, on NVidia card it is fine. O_O

Why???

I also found this topic (http://www.opengl.org/discussion_boards/showthread.php/169075-glBlitFramebuffer(EXT)-coordinates) that seems related to the same problem...

Devdept2
07-09-2012, 01:46 AM
Another false success.

Copying the Multisample Framebuffer to a non-multisample FBO and then reading the texture from that gives the same image on a Geforce 8600M GS but gives a different image on a Quadro 600 (there's a noticeable difference between the texture read from the FBO and the scene drawn on the framebuffer... :(

How can I fix it once and for all???

Dark Photon
07-09-2012, 04:46 AM
Just to clarify, what is the exact problem you're trying to solve? Is it that you are trying to get exactly the same visual result on each GPU+driver combination regardless of the AA setting of the system default framebuffer (where results may differ across different GPU+driver combos)? Or are you trying to get the exact same visual result across all possible combinations of GPU+driver+sysFBres (where results cannot differ across different GPU+driver combos)? The 1st may be possible, the 2nd probably not.

Have you found no way to override the default system FB format? For instance, nuke that default, set your own overrides, and create a new window? What OS is this?

Also, have you tried MSAA rendering to off-screen MS FBO, not to system FB. Then resolve. Then just blit to system FB?

I think it might be time to post a standalone GLUT test program illustrating your problem that we can run/test/hack/repost.

Devdept2
07-09-2012, 05:41 AM
Hi,

I want to read the scene rendered on an OpenGL window with AA into a texture so that I can use that for quick repaints of my scene when doing some mouse operations, and I want the texture to be exactly what I see in the framebuffer so the user won't notice this "repaint" trick.

I'm using a scene with only lines, so the difference in the AA rendering is quite noticeable.



Also, have you tried MSAA rendering to off-screen MS FBO, not to system FB. Then resolve. Then just blit to system FB?


Yes, I created a multisample FBO and a single sample FBO, drawn my scene on the first one, then blitted from the first to the second one and then from the second to the framebuffer.

That worked, but then I found problems when the multisample was forced by the driver settings and it also became very slow if the number of AA samples was high so I decided to quit this approach and try a simpler one: copy the Multisample Framebuffer to a non-multisample FBO, read the texture from that and then draw a screen aligned quad with that texture for my quick repaint.

That works on a Geforce 8600M GS but not on a Quadro 600 (the texture is a bit different from the rendered scene, and the same happens if I blit from the system FB to my FBO and then back on the system FB).

I'm on a Windows 7, 64 bit system.

It's not easy for me to create a standalone test program to reproduce it... :(

Devdept2
07-11-2012, 08:55 AM
Hi,
I created a sample that reproduces the problem:
It creates a multisample openGL window and draws some lines (you can move/zoom/rotate with the mouse)

Pressing the 'C' key I call the

void CaptureTexture()

function that copies the framebuffer to an FBO and reads the texture from it, and then the
successive draws are done by the

void DrawQuadWithTexture()

that simply draws a quad with the mapped texture.

On the NVidia card you can see a difference between using the texture and doing a standard DrawFrame().

Pressing 'C' again switches back to the standard drawing.

Here is the code for the 2 files needed:

main.cpp



#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif


#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <cmath>
#include <sstream>
#include <stdexcept>
#include <string>




#if defined(_DEBUG)
#include <crtdbg.h>
#endif


#include "bitmap.h"
#include "gl_font.h"
#include "WGL_ARB_multisample.h"
#include "glext.h"


//-----------------------------------------------------------------------------
// Constants.
//-----------------------------------------------------------------------------


#define APP_TITLE "OpenGL Anti-Aliasing Demo"


// Windows Vista compositing support.
#if !defined(PFD_SUPPORT_COMPOSITION)
#define PFD_SUPPORT_COMPOSITION 0x00008000
#endif


// GL_EXT_texture_filter_anisotropic
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF


// GL_SGIS_generate_mipmap
#define GL_GENERATE_MIPMAP_SGIS 0x8191


#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
#define GL_FRAMEBUFFER_EXT 0x8D40
#define GL_RENDERBUFFER_EXT 0x8D41


static PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT ;
static PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
static PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT ;
static PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT ;
static PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT ;
static PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT ;
static PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
static PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;


GLuint capturedTexture = 0;
GLuint fbo;
GLuint rbColor;
GLuint renderBuffer;


int texWidth;
int texHeight;




#define CAMERA_FOVY 45.0f
#define CAMERA_ZFAR 10.0f
#define CAMERA_ZNEAR 0.1f


#define MOUSE_ORBIT_SPEED 0.30f // 0 = SLOWEST, 1 = FASTEST
#define MOUSE_DOLLY_SPEED 0.02f // same as above...but much more sensitive
#define MOUSE_TRACK_SPEED 0.005f // same as above...but much more sensitive








//-----------------------------------------------------------------------------
// Globals.
//-----------------------------------------------------------------------------


HWND g_hWnd;
HDC g_hDC;
HGLRC g_hRC;
HINSTANCE g_hInstance;
int g_framesPerSecond;
int g_windowWidth;
int g_windowHeight;
int g_maxAnisotrophy;
float g_heading;
float g_pitch;
float g_cameraPos[3] = {0.0f, 0.0f, 4.0f};
float g_targetPos[3];
bool g_isFullScreen;
bool g_hasFocus;
bool g_enableVerticalSync;
bool g_enableAlphaToCoverage;
bool g_supportsGenerateMipMap;
bool g_displayHelp;
GLuint g_decalMap;


bool UseCopyTexture;


//-----------------------------------------------------------------------------
// Functions Prototypes.
//-----------------------------------------------------------------------------


void Cleanup();
void CleanupApp();
HWND CreateAppWindow(const WNDCLASSEX &wcl, const char *pszTitle);
void DrawFrame();
void DrawText();
void EnableVerticalSync(bool enableVerticalSync);
bool ExtensionSupported(const char *pszExtensionName);
float GetElapsedTimeInSeconds();
bool Init();
void InitApp();
void InitGL();
void Log(const char *pszMessage);
void ProcessMouseInput(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void SetProcessorAffinity();
void ToggleFullScreen();
void UpdateFrame(float elapsedTimeSec);
void UpdateFrameRate(float elapsedTimeSec);
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);




//-----------------------------------------------------------------------------
// Functions.
//-----------------------------------------------------------------------------


void DrawQuadWithTexture()
{
// Draw a screen Waud with the texture
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, g_windowWidth, g_windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, g_windowWidth, 0, g_windowHeight, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_LIGHTING);
//glDisable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT, GL_FILL);
glEnable(GL_TEXTURE_2D);


glBindTexture(GL_TEXTURE_2D, capturedTexture);
glColor3f(1, 1, 1);


double wRatio = (double)g_windowWidth / texWidth;
double hRatio = (double)g_windowHeight / texHeight;

glBegin(GL_QUADS);

glTexCoord2d(0, 0);
glVertex2i(0, 0);


glTexCoord2d(wRatio, 0);
glVertex2i(g_windowWidth, 0);


glTexCoord2d(wRatio, hRatio);
glVertex2i(g_windowWidth, g_windowHeight);


glTexCoord2d(0, hRatio);
glVertex2i(0, g_windowHeight);


glEnd();


glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_DEPTH_TEST);


DrawText();
}




int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
#if defined _DEBUG
_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
#endif


MSG msg = {0};
WNDCLASSEX wcl = {0};


wcl.cbSize = sizeof(wcl);
wcl.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wcl.lpfnWndProc = WindowProc;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hInstance = g_hInstance = hInstance;
wcl.hIcon = LoadIcon(0, IDI_APPLICATION);
wcl.hCursor = LoadCursor(0, IDC_ARROW);
wcl.hbrBackground = 0;
wcl.lpszMenuName = 0;
wcl.lpszClassName = "GLWindowClass";
wcl.hIconSm = 0;


if (!RegisterClassEx(&wcl))
return 0;


g_hWnd = CreateAppWindow(wcl, APP_TITLE);


if (g_hWnd)
{
SetProcessorAffinity();


if (Init())
{
ShowWindow(g_hWnd, nShowCmd);
UpdateWindow(g_hWnd);


while (true)
{
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;


TranslateMessage(&msg);
DispatchMessage(&msg);
}


if (msg.message == WM_QUIT)
break;


if (g_hasFocus)
{
UpdateFrame(GetElapsedTimeInSeconds());


if (UseCopyTexture)
DrawQuadWithTexture();
else
DrawFrame();
SwapBuffers(g_hDC);
}
else
{
WaitMessage();
}
}
}


Cleanup();
UnregisterClass(wcl.lpszClassName, hInstance);
}


return static_cast<int>(msg.wParam);
}




void CaptureTexture()
{
if (capturedTexture == 0)
{
// Initialize Texture and FBO
texWidth = pow(2, ceil(log10 ((double)g_windowWidth) / log10((double)2)));
texHeight = pow(2, ceil(log10((double)g_windowHeight) / log10((double)2)));


glGenTextures(1, &capturedTexture);
glBindTexture( GL_TEXTURE_2D, capturedTexture);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture( GL_TEXTURE_2D, 0);

glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);


glGenRenderbuffersEXT(1, &rbColor);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbColor);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, g_windowWidth, g_windowHeight);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, rbColor);


int _status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
}


DrawFrame();


// Copy Frambuffer to FBO
glReadBuffer(GL_BACK);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo);
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);


glBlitFramebufferEXT(0, 0, g_windowWidth, g_windowHeight, 0, 0, g_windowWidth, g_windowHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);


// Copy FrameBuffer to the texture
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glBindTexture(GL_TEXTURE_2D, capturedTexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, g_windowWidth, g_windowHeight);


glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glReadBuffer(GL_BACK);
}


LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_ACTIVATE:
switch (wParam)
{
default:
break;


case WA_ACTIVE:
case WA_CLICKACTIVE:
g_hasFocus = true;
break;


case WA_INACTIVE:
if (g_isFullScreen)
ShowWindow(hWnd, SW_MINIMIZE);
g_hasFocus = false;
break;
}
break;


case WM_CHAR:
switch (static_cast<int>(wParam))
{
case VK_ESCAPE:
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;


case VK_SPACE:
if (g_enableAlphaToCoverage = !g_enableAlphaToCoverage)
glEnable(GL_MULTISAMPLE_ARB);
else
glDisable(GL_MULTISAMPLE_ARB);
break;


case 'c':
case 'C':
UseCopyTexture = !UseCopyTexture;
if (UseCopyTexture)
CaptureTexture();

break;


case 'h':
case 'H':
g_displayHelp = !g_displayHelp;
break;


case 'v':
case 'V':
EnableVerticalSync(!g_enableVerticalSync);
break;


default:
break;
}
break;


case WM_DESTROY:
PostQuitMessage(0);
return 0;


case WM_SIZE:
g_windowWidth = static_cast<int>(LOWORD(lParam));
g_windowHeight = static_cast<int>(HIWORD(lParam));
break;


case WM_SYSKEYDOWN:
if (wParam == VK_RETURN)
ToggleFullScreen();
break;


default:
ProcessMouseInput(hWnd, msg, wParam, lParam);
break;
}


return DefWindowProc(hWnd, msg, wParam, lParam);
}


void Cleanup()
{
CleanupApp();


if (g_hDC)
{
if (g_hRC)
{
wglMakeCurrent(g_hDC, 0);
wglDeleteContext(g_hRC);
g_hRC = 0;
}


ReleaseDC(g_hWnd, g_hDC);
g_hDC = 0;
}
}


void CleanupApp()
{
if (g_decalMap)
{
glDeleteTextures(1, &g_decalMap);
g_decalMap = 0;
}
}


HWND CreateAppWindow(const WNDCLASSEX &wcl, const char *pszTitle)
{
// Create a window that is centered on the desktop. It's exactly 1/4 the
// size of the desktop. Don't allow it to be resized.


DWORD wndExStyle = WS_EX_OVERLAPPEDWINDOW;
DWORD wndStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
WS_MINIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;


HWND hWnd = CreateWindowEx(wndExStyle, wcl.lpszClassName, pszTitle,
wndStyle, 0, 0, 0, 0, 0, 0, wcl.hInstance, 0);


if (hWnd)
{
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
int halfScreenWidth = screenWidth / 2;
int halfScreenHeight = screenHeight / 2;
int left = (screenWidth - halfScreenWidth) / 2;
int top = (screenHeight - halfScreenHeight) / 2;
RECT rc = {0};


SetRect(&rc, left, top, left + halfScreenWidth, top + halfScreenHeight);
AdjustWindowRectEx(&rc, wndStyle, FALSE, wndExStyle);
MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);


GetClientRect(hWnd, &rc);
g_windowWidth = rc.right - rc.left;
g_windowHeight = rc.bottom - rc.top;
}


return hWnd;
}


void DrawFrame()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);


// Setup view port.
glViewport(0, 0, g_windowWidth, g_windowHeight);
glClearColor(0.3f, 0.5f, 0.9f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


// Setup projection matrix.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(CAMERA_FOVY,
static_cast<float>(g_windowWidth) / static_cast<float>(g_windowHeight),
CAMERA_ZNEAR, CAMERA_ZFAR);


// Setup view matrix.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(g_cameraPos[0], g_cameraPos[1], g_cameraPos[2],
g_targetPos[0], g_targetPos[1], g_targetPos[2],
0.0f, 1.0f, 0.0f);


// Rotate the scene using the mouse.
glRotatef(g_pitch, 1.0f, 0.0f, 0.0f);
glRotatef(g_heading, 0.0f, 1.0f, 0.0f);


glDisable(GL_TEXTURE_2D);
glColor3f(0,0,0);
glBegin(GL_LINE_STRIP);

for (int xInc = 0; xInc <10; xInc++)
for (int yInc = 0; yInc <10; yInc++)
for (int zInc = 0; zInc <10; zInc++)
{
glVertex3f(xInc/10.0, yInc/10.0, zInc/10.0);
}
glEnd();


// Display text.
DrawText();
}


void DrawText()
{
static RECT rcClient;
static char szBuffer[512];


if (g_displayHelp)
{
if (UseCopyTexture)


sprintf(szBuffer,
"Left mouse click and drag to track the camera\n"
"Middle mouse click and drag to dolly the camera\n"
"Right mouse click and drag to orbit the camera\n\n"
"Press V to enable/disable vertical sync\n"
"Press SPACE to enable/disable alpha to coverage sampling\n"
"Press ALT + ENTER to toggle full screen\n"
"Press ESC to exit\n\n"
"Press H to hide help\n"
"DRAWING THE CAPTURED TEXTURE");


else
sprintf(szBuffer,
"Left mouse click and drag to track the camera\n"
"Middle mouse click and drag to dolly the camera\n"
"Right mouse click and drag to orbit the camera\n\n"
"Press V to enable/disable vertical sync\n"
"Press SPACE to enable/disable alpha to coverage sampling\n"
"Press ALT + ENTER to toggle full screen\n"
"Press ESC to exit\n\n"
"Press H to hide help");



}
else
{
if (UseCopyTexture)


sprintf(szBuffer,
"FPS: %d\n"
"Vertical sync: %s\n"
"Anti-aliasing: %s\n"
"Anisotropic filtering: %dx\n"
"Alpha to coverage: %s\n\n"
"Press H to display help\n"
"DRAWING THE CAPTURED TEXTURE",
g_framesPerSecond,
((g_enableVerticalSync) ? "enabled" : "disabled"),
GetAntiAliasingPixelFormatString(),
g_maxAnisotrophy,
((g_enableAlphaToCoverage) ? "enabled" : "disabled"));


else




sprintf(szBuffer,
"FPS: %d\n"
"Vertical sync: %s\n"
"Anti-aliasing: %s\n"
"Anisotropic filtering: %dx\n"
"Alpha to coverage: %s\n\n"
"Press H to display help",
g_framesPerSecond,
((g_enableVerticalSync) ? "enabled" : "disabled"),
GetAntiAliasingPixelFormatString(),
g_maxAnisotrophy,
((g_enableAlphaToCoverage) ? "enabled" : "disabled"));
}


}


void EnableVerticalSync(bool enableVerticalSync)
{
// WGL_EXT_swap_control.


typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(GLint);


static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT =
reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(
wglGetProcAddress("wglSwapIntervalEXT"));


if (wglSwapIntervalEXT)
{
wglSwapIntervalEXT(enableVerticalSync ? 1 : 0);
g_enableVerticalSync = enableVerticalSync;
}
}


bool ExtensionSupported(const char *pszExtensionName)
{
static const char *pszGLExtensions = 0;
static const char *pszWGLExtensions = 0;


if (!pszGLExtensions)
pszGLExtensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));


if (!pszWGLExtensions)
{
// WGL_ARB_extensions_string.


typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC);


PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB =
reinterpret_cast<PFNWGLGETEXTENSIONSSTRINGARBPROC>(
wglGetProcAddress("wglGetExtensionsStringARB"));


if (wglGetExtensionsStringARB)
pszWGLExtensions = wglGetExtensionsStringARB(g_hDC);
}


if (!strstr(pszGLExtensions, pszExtensionName))
{
if (!strstr(pszWGLExtensions, pszExtensionName))
return false;
}


return true;
}


float GetElapsedTimeInSeconds()
{
// Returns the elapsed time (in seconds) since the last time this function
// was called. This elaborate setup is to guard against large spikes in
// the time returned by QueryPerformanceCounter().


static const int MAX_SAMPLE_COUNT = 50;


static float frameTimes[MAX_SAMPLE_COUNT];
static float timeScale = 0.0f;
static float actualElapsedTimeSec = 0.0f;
static INT64 freq = 0;
static INT64 lastTime = 0;
static int sampleCount = 0;
static bool initialized = false;


INT64 time = 0;
float elapsedTimeSec = 0.0f;


if (!initialized)
{
initialized = true;
QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&freq));
QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&lastTime));
timeScale = 1.0f / freq;
}


QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&time));
elapsedTimeSec = (time - lastTime) * timeScale;
lastTime = time;


if (fabsf(elapsedTimeSec - actualElapsedTimeSec) < 1.0f)
{
memmove(&frameTimes[1], frameTimes, sizeof(frameTimes) - sizeof(frameTimes[0]));
frameTimes[0] = elapsedTimeSec;


if (sampleCount < MAX_SAMPLE_COUNT)
++sampleCount;
}


actualElapsedTimeSec = 0.0f;


for (int i = 0; i < sampleCount; ++i)
actualElapsedTimeSec += frameTimes[i];


if (sampleCount > 0)
actualElapsedTimeSec /= sampleCount;


return actualElapsedTimeSec;
}


bool Init()
{
try
{
InitGL();
InitApp();
return true;
}
catch (const std::exception &e)
{
std::ostringstream msg;


msg << "Application initialization failed!" << std::endl << std::endl;
msg << e.what();


Log(msg.str().c_str());
return false;
}
}


void InitApp()
{
}


void InitGL()
{
if (!(g_hDC = GetDC(g_hWnd)))
throw std::runtime_error("GetDC() failed.");


int pf = 0;
PIXELFORMATDESCRIPTOR pfd = {0};
OSVERSIONINFO osvi = {0};


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 = 16;
pfd.iLayerType = PFD_MAIN_PLANE;


osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);


if (!GetVersionEx(&osvi))
throw std::runtime_error("GetVersionEx() failed.");


// When running under Windows Vista or later support desktop composition.
if (osvi.dwMajorVersion > 6 || (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion >= 0))
pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;


// Setting up your Windows application to use multisample anti-aliasing
// (MSAA) is platform dependent. The actual process varies between
// operating systems. Under Windows we use the WGL_ARB_pixel_format and the
// WGL_ARB_multisample OpenGL extensions to enumerate an extended pixel
// format that supports MSAA.
//
// For further details check out the source code for these functions
// (found in the WGL_ARB_multisample.cpp file):
// ChooseBestAntiAliasingPixelFormat()
// ChooseAntiAliasingPixelFormat()


// Select a pixel format supporting the highest quality MSAA.
ChooseBestAntiAliasingPixelFormat(pf);
g_enableAlphaToCoverage = true;


UseCopyTexture = false;

// Here's an example of how to select a pixel format that supports a
// specific number of samples. Here we have chosen 4x MSAA.
if (false)
{
ChooseAntiAliasingPixelFormat(pf, 4);


if (pf)
g_enableAlphaToCoverage = true;
}


// It's always a good idea to fall back to a standard pixel format in case
// MSAA is not supported. Most modern video cards should support some form
// of MSAA - one exception is older embedded video cards.
if (!pf)
{
pf = ChoosePixelFormat(g_hDC, &pfd);
g_enableAlphaToCoverage = false;
}


if (!SetPixelFormat(g_hDC, pf, &pfd))
throw std::runtime_error("SetPixelFormat() failed.");


if (!(g_hRC = wglCreateContext(g_hDC)))
throw std::runtime_error("wglCreateContext() failed.");


if (!wglMakeCurrent(g_hDC, g_hRC))
throw std::runtime_error("wglMakeCurrent() failed.");


EnableVerticalSync(false);


// Check for GL_EXT_texture_filter_anisotropic support.
if (ExtensionSupported("GL_EXT_texture_filter_anisotropic"))
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &g_maxAnisotrophy);
else
g_maxAnisotrophy = 1;


// Check for GL_SGIS_generate_mipmap support.
if (ExtensionSupported("GL_SGIS_generate_mipmap"))
g_supportsGenerateMipMap = true;
else
g_supportsGenerateMipMap = false;




glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)wglGetProcAddress ("glRenderbufferStorageEXT");
glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)wglGetProcAdd ress("glFramebufferRenderbufferEXT");
glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddr ess("glCheckFramebufferStatusEXT");
glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)wglGetProcAddress("glGenRenderbuffersEXT");
glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)wglGetProcAddress("glBindFramebufferEXT");
glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC)wglGetProcAddress("glBlitFramebufferEXT");
glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)wglGetProcAddress("glGenFramebuffersEXT");
glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)wglGetProcAddress("glBindRenderbufferEXT");
}




void Log(const char *pszMessage)
{
MessageBox(0, pszMessage, "Error", MB_ICONSTOP);
}


void ProcessMouseInput(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Use the left mouse button to track the camera.
// Use the middle mouse button to dolly the camera.
// Use the right mouse button to orbit the camera.


enum CameraMode {CAMERA_NONE, CAMERA_TRACK, CAMERA_DOLLY, CAMERA_ORBIT};


static CameraMode cameraMode = CAMERA_NONE;
static POINT ptMousePrev = {0};
static POINT ptMouseCurrent = {0};
static int mouseButtonsDown = 0;
static float dx = 0.0f;
static float dy = 0.0f;


switch (msg)
{
case WM_LBUTTONDOWN:
cameraMode = CAMERA_TRACK;
++mouseButtonsDown;
SetCapture(hWnd);
ptMousePrev.x = static_cast<int>(static_cast<short>(LOWORD(lParam)));
ptMousePrev.y = static_cast<int>(static_cast<short>(HIWORD(lParam)));
ClientToScreen(hWnd, &ptMousePrev);
break;


case WM_RBUTTONDOWN:
cameraMode = CAMERA_ORBIT;
++mouseButtonsDown;
SetCapture(hWnd);
ptMousePrev.x = static_cast<int>(static_cast<short>(LOWORD(lParam)));
ptMousePrev.y = static_cast<int>(static_cast<short>(HIWORD(lParam)));
ClientToScreen(hWnd, &ptMousePrev);
break;


case WM_MBUTTONDOWN:
cameraMode = CAMERA_DOLLY;
++mouseButtonsDown;
SetCapture(hWnd);
ptMousePrev.x = static_cast<int>(static_cast<short>(LOWORD(lParam)));
ptMousePrev.y = static_cast<int>(static_cast<short>(HIWORD(lParam)));
ClientToScreen(hWnd, &ptMousePrev);
break;


case WM_MOUSEMOVE:
ptMouseCurrent.x = static_cast<int>(static_cast<short>(LOWORD(lParam)));
ptMouseCurrent.y = static_cast<int>(static_cast<short>(HIWORD(lParam)));
ClientToScreen(hWnd, &ptMouseCurrent);


switch (cameraMode)
{
case CAMERA_TRACK:
dx = static_cast<float>(ptMouseCurrent.x - ptMousePrev.x);
dx *= MOUSE_TRACK_SPEED;


dy = static_cast<float>(ptMouseCurrent.y - ptMousePrev.y);
dy *= MOUSE_TRACK_SPEED;


g_cameraPos[0] -= dx;
g_cameraPos[1] += dy;


g_targetPos[0] -= dx;
g_targetPos[1] += dy;


break;


case CAMERA_DOLLY:
dy = static_cast<float>(ptMouseCurrent.y - ptMousePrev.y);
dy *= MOUSE_DOLLY_SPEED;


g_cameraPos[2] += dy;


if (g_cameraPos[2] > (CAMERA_ZFAR - 2.0f))
g_cameraPos[2] = CAMERA_ZFAR - 2.0f;


if (g_cameraPos[2] < (CAMERA_ZNEAR + 1.0f))
g_cameraPos[2] = CAMERA_ZNEAR + 1.0f;


break;


case CAMERA_ORBIT:
dx = static_cast<float>(ptMouseCurrent.x - ptMousePrev.x);
dx *= MOUSE_ORBIT_SPEED;


dy = static_cast<float>(ptMouseCurrent.y - ptMousePrev.y);
dy *= MOUSE_ORBIT_SPEED;


g_heading += dx;
g_pitch += dy;


if (g_pitch > 90.0f)
g_pitch = 90.0f;


if (g_pitch < -90.0f)
g_pitch = -90.0f;


break;
}


ptMousePrev.x = ptMouseCurrent.x;
ptMousePrev.y = ptMouseCurrent.y;
break;


case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
if (--mouseButtonsDown <= 0)
{
mouseButtonsDown = 0;
cameraMode = CAMERA_NONE;
ReleaseCapture();
}
else
{
if (wParam & MK_LBUTTON)
cameraMode = CAMERA_TRACK;
else if (wParam & MK_RBUTTON)
cameraMode = CAMERA_ORBIT;
else if (wParam & MK_MBUTTON)
cameraMode = CAMERA_DOLLY;
}
break;


default:
break;
}
}


void SetProcessorAffinity()
{
// Assign the current thread to one processor. This ensures that timing
// code runs on only one processor, and will not suffer any ill effects
// from power management.
//
// Based on DXUTSetProcessorAffinity() function from the DXUT framework.


DWORD_PTR dwProcessAffinityMask = 0;
DWORD_PTR dwSystemAffinityMask = 0;
HANDLE hCurrentProcess = GetCurrentProcess();


if (!GetProcessAffinityMask(hCurrentProcess, &dwProcessAffinityMask, &dwSystemAffinityMask))
return;


if (dwProcessAffinityMask)
{
// Find the lowest processor that our process is allowed to run against.


DWORD_PTR dwAffinityMask = (dwProcessAffinityMask & ((~dwProcessAffinityMask) + 1));


// Set this as the processor that our thread must always run against.
// This must be a subset of the process affinity mask.


HANDLE hCurrentThread = GetCurrentThread();


if (hCurrentThread != INVALID_HANDLE_VALUE)
{
SetThreadAffinityMask(hCurrentThread, dwAffinityMask);
CloseHandle(hCurrentThread);
}
}


CloseHandle(hCurrentProcess);
}


void ToggleFullScreen()
{
static DWORD savedExStyle;
static DWORD savedStyle;
static RECT rcSaved;


g_isFullScreen = !g_isFullScreen;


if (g_isFullScreen)
{
// Moving to full screen mode.


savedExStyle = GetWindowLong(g_hWnd, GWL_EXSTYLE);
savedStyle = GetWindowLong(g_hWnd, GWL_STYLE);
GetWindowRect(g_hWnd, &rcSaved);


SetWindowLong(g_hWnd, GWL_EXSTYLE, 0);
SetWindowLong(g_hWnd, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
SetWindowPos(g_hWnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_SHOWWINDOW);


g_windowWidth = GetSystemMetrics(SM_CXSCREEN);
g_windowHeight = GetSystemMetrics(SM_CYSCREEN);


SetWindowPos(g_hWnd, HWND_TOPMOST, 0, 0,
g_windowWidth, g_windowHeight, SWP_SHOWWINDOW);
}
else
{
// Moving back to windowed mode.


SetWindowLong(g_hWnd, GWL_EXSTYLE, savedExStyle);
SetWindowLong(g_hWnd, GWL_STYLE, savedStyle);
SetWindowPos(g_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_SHOWWINDOW);


g_windowWidth = rcSaved.right - rcSaved.left;
g_windowHeight = rcSaved.bottom - rcSaved.top;


SetWindowPos(g_hWnd, HWND_NOTOPMOST, rcSaved.left, rcSaved.top,
g_windowWidth, g_windowHeight, SWP_SHOWWINDOW);
}
}


void UpdateFrame(float elapsedTimeSec)
{
UpdateFrameRate(elapsedTimeSec);
}


void UpdateFrameRate(float elapsedTimeSec)
{
static float accumTimeSec = 0.0f;
static int frames = 0;


accumTimeSec += elapsedTimeSec;


if (accumTimeSec > 1.0f)
{
g_framesPerSecond = frames;


frames = 0;
accumTimeSec = 0.0f;
}
else
{
++frames;
}
}



wgl_Arb_multisample.cpp


//-----------------------------------------------------------------------------
// Copyright (c) 2006-2008 dhpoware. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------


#include <cassert>
#include <cstdio>
#include <cstring>
#include "WGL_ARB_multisample.h"


namespace
{
WNDCLASSEX g_wcl;
HWND g_hWnd;
HDC g_hDC;
HGLRC g_hRC;
char g_szAAPixelFormat[32];


LRESULT CALLBACK DummyGLWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
if (!(g_hDC = GetDC(hWnd)))
return -1;
break;


case WM_DESTROY:
if (g_hDC)
{
if (g_hRC)
{
wglMakeCurrent(g_hDC, 0);
wglDeleteContext(g_hRC);
g_hRC = 0;
}


ReleaseDC(hWnd, g_hDC);
g_hDC = 0;
}


PostQuitMessage(0);
return 0;


default:
break;
}


return DefWindowProc(hWnd, msg, wParam, lParam);
}


bool CreateDummyGLWindow()
{
g_wcl.cbSize = sizeof(g_wcl);
g_wcl.style = CS_OWNDC;
g_wcl.lpfnWndProc = DummyGLWndProc;
g_wcl.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0));
g_wcl.lpszClassName = "DummyGLWindowClass";


if (!RegisterClassEx(&g_wcl))
return false;


g_hWnd = CreateWindow(g_wcl.lpszClassName, "", WS_OVERLAPPEDWINDOW,
0, 0, 0, 0, 0, 0, g_wcl.hInstance, 0);


if (!g_hWnd)
return false;


PIXELFORMATDESCRIPTOR pfd = {0};


pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;


int pf = ChoosePixelFormat(g_hDC, &pfd);


if (!SetPixelFormat(g_hDC, pf, &pfd))
return false;


if (!(g_hRC = wglCreateContext(g_hDC)))
return false;


if (!wglMakeCurrent(g_hDC, g_hRC))
return false;


return true;
}


void ChooseBestCSAAPixelFormat(int &pf)
{
struct CSAAPixelFormat
{
int numColorSamples;
int numCoverageSamples;
const char *pszDescription;
};


CSAAPixelFormat csaaPixelFormats[] =
{
{ 4, 8, "8x CSAA" },
{ 4, 16, "16x CSAA" },
{ 8, 8, "8xQ (Quality) CSAA" },
{ 8, 16, "16xQ (Quality) CSAA" }
};


int totalCSAAFormats = static_cast<int>(sizeof(csaaPixelFormats) /
sizeof(CSAAPixelFormat));


int attributes[] =
{
WGL_SAMPLE_BUFFERS_ARB, 1,
WGL_COLOR_SAMPLES_NV, 0,
WGL_COVERAGE_SAMPLES_NV, 0,
WGL_DOUBLE_BUFFER_ARB, 1,
0, 0
};


int returnedPixelFormat = 0;
UINT numFormats = 0;
BOOL bStatus = FALSE;


for (int i = totalCSAAFormats - 1; i >= 0; --i)
{
attributes[3] = csaaPixelFormats[i].numColorSamples;
attributes[5] = csaaPixelFormats[i].numCoverageSamples;


bStatus = wglChoosePixelFormatARB(g_hDC, attributes, 0, 1,
&returnedPixelFormat, &numFormats);


if (bStatus == TRUE && numFormats)
{
pf = returnedPixelFormat;
strcpy(g_szAAPixelFormat, csaaPixelFormats[i].pszDescription);
break;
}
}


if (bStatus == FALSE)
g_szAAPixelFormat[0] = '\0';
}


void ChooseBestMSAAPixelFormat(int &pf)
{
int attributes[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_COLOR_BITS_ARB, 24,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
WGL_SAMPLES_ARB, 0,
0, 0
};


int returnedPixelFormat = 0;
UINT numFormats = 0;
BOOL bStatus = FALSE;

for (int samples = 16; samples > 0; samples /= 2)
{
attributes[17] = samples;


bStatus = wglChoosePixelFormatARB(g_hDC, attributes, 0, 1,
&returnedPixelFormat, &numFormats);


if (bStatus == TRUE && numFormats)
{
pf = returnedPixelFormat;
sprintf(g_szAAPixelFormat, "%dx MSAA", samples);
break;
}
}


if (bStatus == FALSE)
g_szAAPixelFormat[0] = '\0';
}


void ChooseCSAAPixelFormat(int &pf, int samples)
{
struct CSAAPixelFormat
{
int numColorSamples;
int numCoverageSamples;
const char *pszDescription;
};


CSAAPixelFormat csaaPixelFormats[] =
{
{ 4, 16, "16x CSAA" },
{ 4, 8, "8x CSAA" }
};


CSAAPixelFormat csaaQualityPixelFormats[] =
{
{ 8, 16, "16xQ (Quality) CSAA" },
{ 8, 8, "8xQ (Quality) CSAA" }
};


CSAAPixelFormat *pCSAAFormats = 0;


int attributes[] =
{
WGL_SAMPLE_BUFFERS_ARB, 1,
WGL_COLOR_SAMPLES_NV, 0,
WGL_COVERAGE_SAMPLES_NV, 0,
WGL_DOUBLE_BUFFER_ARB, 1,
0, 0
};


int returnedPixelFormat = 0;
UINT numFormats = 0;
BOOL bStatus = FALSE;


if (samples >= 8)
pCSAAFormats = csaaQualityPixelFormats;
else
pCSAAFormats = csaaPixelFormats;

for (int i = 0; i < 2; ++i)
{
attributes[3] = pCSAAFormats[i].numColorSamples;
attributes[5] = pCSAAFormats[i].numCoverageSamples;


bStatus = wglChoosePixelFormatARB(g_hDC, attributes, 0, 1,
&returnedPixelFormat, &numFormats);


if (bStatus == TRUE && numFormats)
{
pf = returnedPixelFormat;
strcpy(g_szAAPixelFormat, pCSAAFormats[i].pszDescription);
break;
}
}


if (bStatus == FALSE)
g_szAAPixelFormat[0] = '\0';
}


void ChooseMSAAPixelFormat(int &pf, int samples)
{
int attributes[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_COLOR_BITS_ARB, 24,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
WGL_SAMPLES_ARB, samples,
0, 0
};


int returnedPixelFormat = 0;
UINT numFormats = 0;
BOOL bStatus = wglChoosePixelFormatARB(g_hDC, attributes, 0, 1,
&returnedPixelFormat, &numFormats);


if (bStatus == TRUE && numFormats)
{
pf = returnedPixelFormat;
sprintf(g_szAAPixelFormat, "%dx MSAA", samples);
}
else
{
g_szAAPixelFormat[0] = '\0';
}
}


void DestroyDummyGLWindow()
{
if (g_hWnd)
{
PostMessage(g_hWnd, WM_CLOSE, 0, 0);


BOOL bRet;
MSG msg;


while ((bRet = GetMessage(&msg, 0, 0, 0)) != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}


UnregisterClass(g_wcl.lpszClassName, g_wcl.hInstance);
}


bool ExtensionSupported(const char *pszExtensionName)
{
static const char *pszGLExtensions = 0;
static const char *pszWGLExtensions = 0;


if (!pszGLExtensions)
pszGLExtensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));


if (!pszWGLExtensions)
{
// WGL_ARB_extensions_string.


typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC);


PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB =
reinterpret_cast<PFNWGLGETEXTENSIONSSTRINGARBPROC>(
wglGetProcAddress("wglGetExtensionsStringARB"));


if (wglGetExtensionsStringARB)
pszWGLExtensions = wglGetExtensionsStringARB(wglGetCurrentDC());
}


if (!strstr(pszGLExtensions, pszExtensionName))
{
if (!strstr(pszWGLExtensions, pszExtensionName))
return false;
}


return true;
}
}


void ChooseBestAntiAliasingPixelFormat(int &pf)
{
pf = 0;

if (!CreateDummyGLWindow())
{
DestroyDummyGLWindow();
return;
}

if (ExtensionSupported("GL_NV_multisample_coverage") &&
ExtensionSupported("WGL_NV_multisample_coverage"))
{
ChooseBestCSAAPixelFormat(pf);
}
else
{
ChooseBestMSAAPixelFormat(pf);
}


DestroyDummyGLWindow();
}


void ChooseAntiAliasingPixelFormat(int &pf, int samples)
{
pf = 0;


if (!CreateDummyGLWindow())
{
DestroyDummyGLWindow();
return;
}


if (ExtensionSupported("GL_NV_multisample_coverage") &&
ExtensionSupported("WGL_NV_multisample_coverage"))
{
ChooseCSAAPixelFormat(pf, samples);
}
else
{
ChooseMSAAPixelFormat(pf, samples);
}


DestroyDummyGLWindow();
}


const char *GetAntiAliasingPixelFormatString()
{
return g_szAAPixelFormat;
}


// GL_ARB_multisample


void glSampleCoverageARB(GLclampf value, GLboolean invert)
{
typedef void (APIENTRY * PFNGLSAMPLECOVERAGEARBPROC)(GLclampf value, GLboolean invert);
static PFNGLSAMPLECOVERAGEARBPROC pfnSampleCoverageARB = 0;


if (!pfnSampleCoverageARB)
{
pfnSampleCoverageARB = reinterpret_cast<PFNGLSAMPLECOVERAGEARBPROC>(wglGetProcAddress("glSampleCoverageARB"));
assert(pfnSampleCoverageARB != 0);
}


pfnSampleCoverageARB(value, invert);
}


// WGL_ARB_pixel_format


BOOL wglGetPixelFormatAttribivARB(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues)
{
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
static PFNWGLGETPIXELFORMATATTRIBIVARBPROC pfnGetPixelFormatAttribivARB = 0;


if (!pfnGetPixelFormatAttribivARB)
{
pfnGetPixelFormatAttribivARB = reinterpret_cast<PFNWGLGETPIXELFORMATATTRIBIVARBPROC>(wglGetProcAddress("wglGetPixelFormatAttribivARB"));
assert(pfnGetPixelFormatAttribivARB != 0);
}


return pfnGetPixelFormatAttribivARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues);
}


BOOL wglGetPixelFormatAttribfvARB(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues)
{
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC)(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);
static PFNWGLGETPIXELFORMATATTRIBFVARBPROC pfnGetPixelFormatAttribfvARB = 0;


if (!pfnGetPixelFormatAttribfvARB)
{
pfnGetPixelFormatAttribfvARB = reinterpret_cast<PFNWGLGETPIXELFORMATATTRIBFVARBPROC>(wglGetProcAddress("wglGetPixelFormatAttribfvARB"));
assert(pfnGetPixelFormatAttribfvARB != 0);
}


return pfnGetPixelFormatAttribfvARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues);
}


BOOL wglChoosePixelFormatARB(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats)
{
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
static PFNWGLCHOOSEPIXELFORMATARBPROC pfnChoosePixelFormatARB = 0;


if (!pfnChoosePixelFormatARB)
{
pfnChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(wglGetProcAddress("wglChoosePixelFormatARB"));
assert(pfnChoosePixelFormatARB != 0);
}


return pfnChoosePixelFormatARB(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats);
}

Devdept2
07-13-2012, 01:59 AM
Anybody could help please?

Dark Photon
07-13-2012, 05:14 AM
Would have run it, but it's MSWindows only (running Linux here), and uses other code not included. A simple GLUT test program with no dependencies besides std C/C++ would have been better.

devdept
07-24-2012, 12:36 AM
Dark Photon,

Do you know where we can ask help directly to NVidia for this?

Thanks,

Alberto