// App.cpp: implementation of the CApp class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "resource.h"
#include "App.h"
#include <crtdbg.h>
CApp* CApp::m_pAppInstance = NULL;
/////////////////////////////////////////////////////////////////////////////
// Global functions
/////////////////////////////////////////////////////////////////////////////
//
// WinMain()
// The applications entry point.
//
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
_ASSERT(CApp::m_pAppInstance); // Need one CApp instance!
return CApp::m_pAppInstance->Run(hInstance, nCmdShow, lpCmdLine);
}
//
// WndProc()
// Window procedure for the main window. Simply calls CApp::WindowProc.
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return CApp::m_pAppInstance->WindowProc(hWnd, message, wParam, lParam);
}
[!if CHK_OPENGL]
//
// GLCube()
// Renders a cube.
//
void GLCube(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2)
{
glBegin(GL_QUADS);
glNormal3f(0.0f, 0.0f, 1.0f);
glVertex3f(x2, y2, z2); glVertex3f(x1, y2, z2); glVertex3f(x1, y1, z2); glVertex3f(x2, y1, z2);
glNormal3f(0.0f, 0.0f, -1.0f);
glVertex3f(x2, y2, z1); glVertex3f(x2, y1, z1); glVertex3f(x1, y1, z1); glVertex3f(x1, y2, z1);
glNormal3f(-1.0f, 0.0f, 0.0f);
glVertex3f(x1, y2, z2); glVertex3f(x1, y2, z1); glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z2);
glNormal3f(1.0f, 0.0f, 0.0f);
glVertex3f(x2, y2, z2); glVertex3f(x2, y1, z2); glVertex3f(x2, y1, z1); glVertex3f(x2, y2, z1);
glNormal3f(0.0f, 1.0f, 0.0f);
glVertex3f(x1, y2, z1); glVertex3f(x1, y2, z2); glVertex3f(x2, y2, z2); glVertex3f(x2, y2, z1);
glNormal3f(0.0f, -1.0f, 0.0f);
glVertex3f(x1, y1, z1); glVertex3f(x2, y1, z1); glVertex3f(x2, y1, z2); glVertex3f(x1, y1, z2);
glEnd();
}
[!endif]
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CApp::CApp():
m_hDC(0),
[!if CHK_ACCEL]
m_hAccelTable(0),
[!endif]
m_hInstance(0),
m_hWnd(NULL),
[!if CHK_OPENGL]
m_hRC(NULL),
m_fFovy(30.0f),
m_fZNear(1.0f),
m_fZFar(10.0f),
[!endif]
m_nFrames(0),
m_bFPSTimer(FALSE)
{
_ASSERT(m_pAppInstance == NULL); // Only one CApp instace allowed
m_pAppInstance = this;
}
CApp::~CApp()
{
}
//////////////////////////////////////////////////////////////////////
// CApp member functions
//////////////////////////////////////////////////////////////////////
void CApp::PreCreateWindow(WNDCLASSEX &wcex, DWORD &dwStyle, DWORD &dwExStyle, int &x, int &y, int &cx, int &cy)
{
// Window class info
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = m_hInstance;
wcex.hIcon = LoadIcon(m_hInstance, (LPCTSTR)IDR_MAINFRAME);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
[!if CHK_OPENGL]
wcex.hbrBackground = 0;
[!else]
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
[!endif]
[!if CHK_MENU]
wcex.lpszMenuName = (LPCSTR)IDC_MAINFRAME;
[!else]
wcex.lpszMenuName = NULL;
[!endif]
wcex.hIconSm = (HICON)LoadImage(m_hInstance, (LPCTSTR)IDR_MAINFRAME, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
// Window style
dwStyle = WS_OVERLAPPED | WS_THICKFRAME | WS_CAPTION |WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU;
// Extended window style
dwExStyle = WS_EX_APPWINDOW;
// Window position and size
x = y = cx = cy = CW_USEDEFAULT;
}
//
// Run()
// Starts the message pump
//
int CApp::Run(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
{
if (!InitInstance(hInstance, nCmdShow, lpCmdLine))
return FALSE;
MSG msg;
while(TRUE)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if(!GetMessage(&msg, NULL, 0, 0))
break;
[!if CHK_ACCEL]
if (!TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
[!else]
TranslateMessage(&msg);
DispatchMessage(&msg);
[!endif]
}
else
OnIdle();
}
ExitInstance();
return msg.wParam;
}
//
// InitInstance()
// Called when the application starts. Creates and shows the main window.
//
BOOL CApp::InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
{
const char szWindowClass[] = "[!output PROJECT_NAME]WindowClass";
const char szWindowTitle[] = "[!output PROJECT_NAME]";
m_hInstance = hInstance;
DWORD dwStyle, dwExStyle;
int x, y, cx, cy;
// Register main window class
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = szWindowClass;
PreCreateWindow(wcex, dwStyle, dwExStyle, x, y, cx, cy);
wcex.style|= CS_OWNDC;
if(!RegisterClassEx(&wcex))
return FALSE;
[!if CHK_ACCEL]
// Load accelerator table
m_hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MAINFRAME);
[!endif]
// Create main window
m_hWnd = CreateWindowEx(dwExStyle, szWindowClass, szWindowTitle, dwStyle, x, y, cx, cy, 0, 0, hInstance, NULL);
if (!m_hWnd)
return FALSE;
OnCreate();
// Show the main window
ShowWindow(m_hWnd, nCmdShow);
UpdateWindow(m_hWnd);
return TRUE;
}
//
// ExitInstance()
// Called when the application exits.
//
void CApp::ExitInstance()
{
}
//
// OnIdle()
// Called when there are no messages in the message queue.
//
void CApp::OnIdle()
{
[!if CHK_OPENGL]
if(Tick())
FireDrawScene();
[!else]
if(Tick())
InvalidateRect(m_hWnd, NULL, FALSE);
[!endif]
}
[!if CHK_OPENGL]
//
// FireDrawScene()
// Sets current OpenGL RC and calls DrawScene()
//
void CApp::FireDrawScene()
{
_ASSERT(m_hDC);
wglMakeCurrent(m_hDC, m_hRC);
DrawScene();
SwapBuffers(m_hDC);
wglMakeCurrent(0, 0);
m_nFrames++;
}
[!endif]
//
// OnCommand()
// Handles WM_COMMAND messages
//
BOOL CApp::OnCommand(int nCmdID, int nEvent)
{
return TRUE;
}
[!if CHK_ABOUT]
//
// AboutProc()
// Handles messages sent to the About dialog
//
LRESULT CALLBACK CApp::AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
//
// ShowAboutDialog()
// Shows the About dialog
//
int CApp::ShowAboutDialog()
{
return DialogBox(m_hInstance, (LPCTSTR)IDD_ABOUTBOX, m_hWnd, (DLGPROC)AboutProc);
}
[!endif]
//
// WindowProc()
// Handles messages sent to the main window
//
LRESULT CApp::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hDC;
switch (message)
{
case WM_CLOSE:
DestroyWindow(m_hWnd);
m_hWnd = 0;
break;
case WM_COMMAND:
if(!OnCommand(LOWORD(wParam), HIWORD(wParam)))
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
OnPaint(hDC);
EndPaint(hWnd, &ps);
m_nFrames++;
break;
// case WM_CREATE:
// break;
case WM_DESTROY:
OnDestroy();
PostQuitMessage(0);
break;
case WM_SIZE:
OnSize(LOWORD(lParam), HIWORD(lParam));
break;
case WM_TIMER:
if(wParam == FPS_TIMER_ID)
{
OnUpdateFPS((1000.0f*(float)m_nFrames) / ((float)FRAME_INTERVAL));
m_nFrames = 0;
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
[!if CHK_OPENGL]
//
// PreCreateRC()
// Set default params for OpenGL RC
//
void CApp::PreCreateRC(PIXELFORMATDESCRIPTOR &pfd)
{
pfd.nVersion = 1;
[!if CHK_DBLBUF]
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
[!else]
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
[!endif]
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = [!output LST_COLORDEPTH];
pfd.cDepthBits = [!output LST_ZDEPTH];
pfd.iLayerType = PFD_MAIN_PLANE;
}
[!endif]
//
// OnCreate()
// Called when the main window has been created.
//
void CApp::OnCreate()
{
[!if CHK_OPENGL]
// Define pixel format
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, NULL, sizeof(pfd));
pfd.nSize = sizeof(pfd);
PreCreateRC(pfd);
// Set pixel format
m_hDC = GetDC(m_hWnd);
int nPixelFormat = ChoosePixelFormat(m_hDC, &pfd);
SetPixelFormat(m_hDC, nPixelFormat, &pfd);
// Create RC
m_hRC = wglCreateContext(m_hDC);
wglMakeCurrent(m_hDC, m_hRC);
InitScene();
wglMakeCurrent(0, 0);
// Size viewport
RECT rc;
GetClientRect(m_hWnd, &rc);
OnSize(rc.right-rc.left, rc.bottom-rc.top);
[!endif]
// Start timer for FPS updates
SetFPSTimer(TRUE);
}
//
// OnDestroy()
// Called when the main window is destroyed.
//
void CApp::OnDestroy()
{
[!if CHK_OPENGL]
_ASSERT(m_hDC);
wglMakeCurrent(m_hDC, m_hRC);
KillScene();
wglMakeCurrent(0, 0);
wglDeleteContext(m_hRC);
ReleaseDC(m_hWnd, m_hDC);
m_hDC = 0;
[!endif]
}
//
// OnSize()
// Called when the main window is resized.
//
void CApp::OnSize(int cx, int cy)
{
if(cx==0 || cy ==0 || m_hWnd==NULL)
return;
[!if CHK_OPENGL]
SetViewPort(m_fFovy, m_fZNear, m_fZFar, TRUE);
[!endif]
}
[!if CHK_OPENGL]
//
// SetViewPort()
// Defines OpenGL viewport: Field of view and near/far clipping plane
//
void CApp::SetViewPort(float fFovy, float fZNear, float fZFar, BOOL bApply)
{
m_fFovy = fFovy;
m_fZNear = fZNear;
m_fZFar = fZFar;
if(bApply)
{
wglMakeCurrent(m_hDC, m_hRC);
// Calculate viewport aspect
RECT rv;
GetClientRect(m_hWnd, &rv);
GLfloat fAspect = (GLfloat)(rv.right-rv.left) / (GLfloat)(rv.bottom-rv.top);
// Define viewport
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(m_fFovy, fAspect, m_fZNear, m_fZFar);
glViewport(rv.left, rv.top, rv.right-rv.left, rv.bottom-rv.top);
glMatrixMode(GL_MODELVIEW);
wglMakeCurrent(0, 0);
}
}
[!endif]
//
// OnPaint()
// Handles WM_PAINT messages. Redraws the OpenGL scene.
//
void CApp::OnPaint(HDC hDC)
{
[!if CHK_OPENGL]
_ASSERT(hDC == m_hDC);
wglMakeCurrent(m_hDC, m_hRC);
DrawScene();
SwapBuffers(m_hDC);
wglMakeCurrent(0, 0);
[!endif]
}
//
// SetFPSTimer()
// Start/stop timer for FPS updates.
//
void CApp::SetFPSTimer(BOOL bStart)
{
if(m_bFPSTimer)
KillTimer(m_hWnd, FPS_TIMER_ID);
m_nFrames = 0;
if(bStart)
{
SetTimer(m_hWnd, FPS_TIMER_ID, FRAME_INTERVAL, 0);
OnUpdateFPS(0);
}
m_bFPSTimer = bStart;
}
//
// GetFPSTimer()
// Returns TRUE if FPS timer is active
//
BOOL CApp::GetFPSTimer()
{
return m_bFPSTimer;
}