#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)wglGetProcAddress("glFramebufferRenderbufferEXT");
glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddress("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;
}
}