📄 cacti.cpp
字号:
/****************************************************************************
cacti.cpp
This demo program demonstrates the use of billboarding by drawing cacti
on a desert landscape.
Author : Dave Astle
Date : 4/3/2001
Written for OpenGL Game Programming
*****************************************************************************/
/********************************* Includes *********************************/
#define WIN32_LEAN_AND_MEAN // get rid of Windows things we don't need
#include <windows.h> // included in all Windows apps
#include <winuser.h> // Windows constants
#include <gl/gl.h> // OpenGL include
#include <gl/glu.h> // OpenGL utilty library
#include "vectorlib.h"
#include "bitmap.h"
#define WND_CLASS_NAME "OpenGL Window Class"
/*************************** Constants and Macros ***************************/
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
const int SCREEN_BPP = 32;
const bool USE_FULLSCREEN = false;
const char *APP_TITLE = "Billboarding Demo";
#define MAP_X 32 // size of map along x-axis
#define MAP_Z 32 // size of map along z-axis
#define MAP_SCALE 25.0f // the scale of the terrain map
#define PI 3.14159
#define NUM_CACTI 40
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
#define RAND_COORD(x) ((float)rand()/RAND_MAX * (x))
typedef void (APIENTRY * PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
typedef void (APIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void);
/********************************* Globals **********************************/
HDC g_hdc; // device context
HGLRC g_hrc; // rendering context
BOOL g_isFullscreen = TRUE; // toggles fullscreen and windowed display
BOOL g_isActive = TRUE; // false if window is minimized
HWND g_hwnd = NULL; // main window handle
HINSTANCE g_hInstance; // application instance
GLuint g_sand; // sand texture
GLuint g_cactus; // cactus texture
GLboolean g_keys[256];
// terrain data
float g_terrain[MAP_X * MAP_Z][3]; // heightfield terrain data (0-255); 256x256
GLuint g_indexArray[MAP_X * MAP_Z * 2]; // vertex array
float g_colorArray[MAP_X * MAP_Z][3]; // color array
float g_texcoordArray[MAP_X * MAP_Z][2]; // tex coord array
// compiled array extensions
PFNGLLOCKARRAYSEXTPROC glLockArraysEXT = 0;
PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT = 0;
/******************************** Prototypes ********************************/
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL SetupWindow(const char *title, int width, int height, int bits, bool isFullscreen);
BOOL KillWindow();
GLvoid ResizeScene(GLsizei width, GLsizei height);
BOOL InitializeScene();
void InitializeTerrain();
BOOL DisplayScene();
BOOL Cleanup();
void DrawCacti();
void DrawSand();
void LoadTexture(char *filename, GLuint &texture);
float GetHeight(float x, float z);
/*****************************************************************************
WinMain()
Windows entry point
*****************************************************************************/
int WINAPI WinMain(HINSTANCE g_hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
MSG msg; // message
BOOL isDone; // flag indicatingen the app is done
// if the window is set up correctly, we can proceed with the message loop
if (SetupWindow(APP_TITLE, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, USE_FULLSCREEN))
isDone = FALSE;
// otherwise, we need to never enter the loop and proceed to exit
else
isDone = TRUE;
// main message loop
while (!isDone)
{
if(PeekMessage(&msg, g_hwnd, NULL, NULL, PM_REMOVE))
{
if (msg.message == WM_QUIT) // do we receive a WM_QUIT message?
{
isDone = TRUE; // if so, time to quit the application
}
else
{
TranslateMessage(&msg); // translate and dispatch to event queue
DispatchMessage(&msg);
}
}
// don't update the scene if the app is minimized
if (g_isActive)
{
// update the scene every time through the loop
DisplayScene();
// switch the front and back buffers to display the updated scene
SwapBuffers(g_hdc);
}
}
Cleanup();
KillWindow();
return msg.wParam;
} // end WinMain()
/*****************************************************************************
WndProc()
Windows message handler
*****************************************************************************/
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_ACTIVATE: // watch for the window being minimized and restored
{
if (!HIWORD(wParam))
{
// program was restored or maximized
g_isActive = TRUE;
}
else
{
// program was minimized
g_isActive=FALSE;
}
return 0;
}
case WM_SYSCOMMAND: // look for screensavers and powersave mode
{
switch (wParam)
{
case SC_SCREENSAVE: // screensaver trying to start
case SC_MONITORPOWER: // monitor going to powersave mode
// returning 0 prevents either from happening
return 0;
default:
break;
}
} break;
case WM_CLOSE: // window is being closed
{
// send WM_QUIT to message queue
PostQuitMessage(0);
return 0;
}
case WM_SIZE:
{
// update perspective with new width and height
ResizeScene(LOWORD(lParam), HIWORD(lParam));
return 0;
}
case WM_KEYDOWN:
{
switch (toupper(wParam))
{
case VK_ESCAPE:
{
// send WM_QUIT to message queue
PostQuitMessage(0);
return 0;
}
default:
{
g_keys[wParam] = GL_TRUE;
return 0;
}
};
}
case WM_KEYUP:
{
g_keys[wParam] = GL_FALSE;
return 0;
}
default:
break;
}
return (DefWindowProc(hwnd, message, wParam, lParam));
} // end WndProc()
/*****************************************************************************
SetupWindow()
Create the window and everything else we need, including the device and
rendering context. If a fullscreen window has been requested but can't be
created, the user will be prompted to attempt windowed mode. Finally,
InitializeScene is called for application-specific setup.
Returns TRUE if everything goes well, or FALSE if an unrecoverable error
occurs. Note that if this is called twice within a program, KillWindow needs
to be called before subsequent calls to SetupWindow.
*****************************************************************************/
BOOL SetupWindow(const char *title, int width, int height, int bits, bool isFullscreen)
{
// set the global flag
g_isFullscreen = isFullscreen;
// get our instance handle
g_hInstance = GetModuleHandle(NULL);
WNDCLASSEX wc; // window class
// fill out the window class structure
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // default icon
wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO); // windows logo small icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // default arrow
wc.hbrBackground = NULL; // no background needed
wc.lpszMenuName = NULL; // no menu
wc.lpszClassName = WND_CLASS_NAME;
// register the windows class
if (!RegisterClassEx(&wc))
{
MessageBox(NULL,"Unable to register the window class", "Error", MB_OK | MB_ICONEXCLAMATION);
// exit and return FALSE
return FALSE;
}
// if we're in fullscreen mode, set the display up for it
if (g_isFullscreen)
{
// set up the device mode structure
DEVMODE screenSettings;
memset(&screenSettings,0,sizeof(screenSettings));
screenSettings.dmSize = sizeof(screenSettings);
screenSettings.dmPelsWidth = width; // screen width
screenSettings.dmPelsHeight = height; // screen height
screenSettings.dmBitsPerPel = bits; // bits per pixel
screenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
// attempt to switch to the resolution and bit depth we've selected
if (ChangeDisplaySettings(&screenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
// if we can't get fullscreen, let them choose to quit or try windowed mode
if (MessageBox(NULL, "Cannot run in the fullscreen mode at the selected resolution\n"
"on your video card. Try windowed mode instead?",
"OpenGL Game Programming",
MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
{
g_isFullscreen = FALSE;
}
else
{
return FALSE;
}
}
}
DWORD dwExStyle;
DWORD dwStyle;
// set the window style appropriately, depending on whether we're in fullscreen mode
if (g_isFullscreen)
{
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP; // simple window with no borders or title bar
ShowCursor(FALSE); // hide the cursor for now
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
}
// set up the window we're rendering to so that the top left corner is at (0,0)
// and the bottom right corner is (height,width)
RECT windowRect;
windowRect.left = 0;
windowRect.right = (LONG) width;
windowRect.top = 0;
windowRect.bottom = (LONG) height;
// change the size of the rect to account for borders, etc. set by the style
AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);
// class registered, so now create our window
g_hwnd = CreateWindowEx(dwExStyle, // extended style
WND_CLASS_NAME, // class name
title, // app name
dwStyle | // window style
WS_CLIPCHILDREN | // required for
WS_CLIPSIBLINGS, // using OpenGL
0, 0, // x,y coordinate
windowRect.right - windowRect.left, // width
windowRect.bottom - windowRect.top, // height
NULL, // handle to parent
NULL, // handle to menu
g_hInstance, // application instance
NULL); // no extra params
// see if our window handle is valid
if (!g_hwnd)
{
MessageBox(NULL, "Unable to create window", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// get a device context
if (!(g_hdc = GetDC(g_hwnd)))
{
MessageBox(NULL,"Unable to create device context", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// set the pixel format we want
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of structure
1, // default version
PFD_DRAW_TO_WINDOW | // window drawing support
PFD_SUPPORT_OPENGL | // OpenGL support
PFD_DOUBLEBUFFER, // double buffering support
PFD_TYPE_RGBA, // RGBA color mode
bits, // 32 bit color mode
0, 0, 0, 0, 0, 0, // ignore color bits, non-palettized mode
0, // no alpha buffer
0, // ignore shift bit
0, // no accumulation buffer
0, 0, 0, 0, // ignore accumulation bits
16, // 16 bit z-buffer size
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main drawing plane
0, // reserved
0, 0, 0 }; // layer masks ignored
GLuint pixelFormat;
// choose best matching pixel format
if (!(pixelFormat = ChoosePixelFormat(g_hdc, &pfd)))
{
MessageBox(NULL, "Can't find an appropriate pixel format", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// set pixel format to device context
if(!SetPixelFormat(g_hdc, pixelFormat,&pfd))
{
MessageBox(NULL, "Unable to set pixel format", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// create the OpenGL rendering context
if (!(g_hrc = wglCreateContext(g_hdc)))
{
MessageBox(NULL, "Unable to create OpenGL rendering context", "Error",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// now make the rendering context the active one
if(!wglMakeCurrent(g_hdc, g_hrc))
{
MessageBox(NULL,"Unable to activate OpenGL rendering context", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// show the window in the forground, and set the keyboard focus to it
ShowWindow(g_hwnd, SW_SHOW);
SetForegroundWindow(g_hwnd);
SetFocus(g_hwnd);
// set up the perspective for the current screen size
ResizeScene(width, height);
// do one-time initialization
if (!InitializeScene())
{
MessageBox(NULL, "Initialization failed", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
return TRUE;
} // end SetupWindow()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -