📄 winmain.cpp
字号:
/*+-------------------------------------------------------------------
Ben Landon
CSCI E-235
Final Project
This is the main application file for a program that
attempts to do "Point-Based Radiosity". See the readme.txt
file for more details.
*/
#include <windows.h>
#include <stdio.h>
#include "gl_common.h"
#include "wgl.h"
#include "HemiCube.hpp"
#include "Scene.hpp"
#include "ppm_util.hpp"
#include "pgm_util.hpp"
#include "resource.h"
/*+-------------------------------------------------------------------
Function Prototypes
*/
static void panic_and_exit (int code, const char* message);
static void setup (HWND hwnd);
static void cleanup (HWND hwnd);
static void load_debugging_texture (void);
static void render_scene (void);
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam);
static void on_size_event (HWND hwnd, unsigned int width, unsigned int height);
static bool on_key_down (HWND hwnd, TCHAR key);
static bool on_command (HWND hwnd, int command);
static float do_one_radiosity_step (void);
static void do_radiosity (void);
/*+-------------------------------------------------------------------
Global Variables
*/
unsigned int g_window_width = 500;
unsigned int g_window_height = 500;
HemiCube* g_hemi_cube = NULL;
Scene* g_scene = NULL;
GLuint g_tex_id = 0;
GLuint g_debugging_texture = 0;
Point brightest_texel_point;
HDC g_hdc = NULL;
bool g_show_projected_points = false;
bool g_use_gl_points = false;
/*+-------------------------------------------------------------------
panic_and_exit
This function does no cleanup, it just shows an error
message and exits.
*/
void panic_and_exit (int code, const char* message)
{
MessageBox(NULL,
message,
"Panic - Something went really wrong",
MB_ICONSTOP);
exit(code);
}
/*+-------------------------------------------------------------------
setup
*/
void setup (HWND hwnd)
{
HGLRC hglrc = setup_opengl(hwnd);
SetWindowLong(hwnd, GWL_USERDATA, (LONG)hglrc);
g_hemi_cube = new HemiCube();
g_scene = Scene::load_simple_scene();
load_debugging_texture();
do_one_radiosity_step();
}
/*+-------------------------------------------------------------------
cleanup
This function is executed once at shutdown.
*/
void cleanup (HWND hwnd)
{
HGLRC hglrc = (HGLRC)GetWindowLong(hwnd, GWL_USERDATA);
if (hglrc)
{
cleanup_opengl(hglrc);
}
if (g_hemi_cube)
{
delete g_hemi_cube;
g_hemi_cube = NULL;
}
if (g_scene)
{
delete g_scene;
g_scene = NULL;
}
if (g_debugging_texture != 0)
{
glDeleteTextures(1, &g_debugging_texture);
g_debugging_texture = 0;
}
HMENU hMenu = GetMenu(hwnd);
SetMenu(hwnd, NULL);
DestroyMenu(hMenu);
ReleaseDC(hwnd, g_hdc);
}
/*+-------------------------------------------------------------------
load_debugging_texture
Load the texture used in debugging. This is a polka dot pattern.
It is useful just to make sure that the texture coordinates are
set properly .
*/
void load_debugging_texture (void)
{
FILE* file = fopen("polka_dots.ppm", "rb");
unsigned char* data = NULL;
unsigned int width = 0;
unsigned int height = 0;
unsigned int color_depth = 0;
if (file && read_PPM_file (file, &data, &width, &height, &color_depth))
{
glGenTextures(1, &g_debugging_texture);
glBindTexture(GL_TEXTURE_2D, g_debugging_texture);
int rc = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height,
GL_RGB, GL_UNSIGNED_BYTE, data);
}
fclose(file);
file = NULL;
}
/*+-------------------------------------------------------------------
debug_render_scene
Render the simple scene in the Scene object into
a small viewport. This is useful for debugging.
*/
void debug_render_scene (void)
{
glViewport(0, 0, g_window_width, g_window_height);
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -20.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0f, 1.0f, 1.0f, 60.0f);
if (g_scene)
{
g_scene->draw_with_accumulation_textures();
glDisable(GL_DEPTH_TEST);
if (g_show_projected_points)
g_scene->debug_draw_splats();
g_scene->draw_wireframe();
}
// Draw the brightest texel as a big
// magenta dot
float point_size;
glGetFloatv(GL_POINT_SIZE, &point_size);
glPointSize(10.0);
glBegin(GL_POINTS);
glColor3f(1.0f, 0.0f, 1.0f);
glVertex3f(brightest_texel_point.x(),
brightest_texel_point.y(),
brightest_texel_point.z());
glEnd();
glPointSize(point_size);
}
/*+-------------------------------------------------------------------
render_scene
*/
void render_scene (void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glRasterPos2i(0, 0);
debug_render_scene();
SwapBuffers(g_hdc);
}
/*+------------------------------------------------------------------
do_one_radiosity_step
*/
float do_one_radiosity_step (void)
{
assert(g_hemi_cube != NULL);
assert(g_scene != NULL);
assert(g_scene->num_triangles() > 0);
Color brightest_texel_color;
// Clear the scene of any existing splats
g_scene->clear_all_splats();
int total_splats_in_scene = g_scene->debug_num_splats();
int u, v;
u = v = 0;
SceneTriangle* triangle =
g_scene->get_brightest_texel(brightest_texel_point,
brightest_texel_color, u, v);
// FIXME - This is where we should check the energy
// epsilon.
assert(triangle != NULL);
g_hemi_cube->render_buffers(*g_scene,
brightest_texel_point,
triangle->normal(),
brightest_texel_color
);
g_hemi_cube->reconstruct(*g_scene);
// Now tell the scene to accumulate the splats
// that were created in the reconstruction method.
g_scene->accumulate_all_splats(g_use_gl_points);
// Subtract the emitting texel from the emissive
// texture that just emitted into the scene.
triangle->subtract_emissive_texel(brightest_texel_color,
u, v);
g_scene->reset_gl_textures();
// Return the sum (( R + B + G ) * A) of the
// emitting texel. This is interesting information
// to have to see if the radiosity process is
// converging (it usually doesn't at this point).
return brightest_texel_color.sum();
}
/*+-------------------------------------------------------------------
do_radiosity
Invoke "do_one_radiosity_step" 100 times.
*/
void do_radiosity (void)
{
char message[64];
int counter = 0;
while (counter < 100)
{
float intensity = do_one_radiosity_step();
sprintf(message, "Step: %d: %f\n", counter++, intensity);
OutputDebugString(message);
render_scene();
}
}
/*+-------------------------------------------------------------------
on_size_event
Proces a WM_SIZE event. The HWND, width and height parameters
are passed to this function.
*/
void on_size_event (HWND hwnd, unsigned int width, unsigned int height)
{
g_window_width = width;
g_window_height = height;
set_viewport(g_window_width, g_window_height, 1.0f);
}
/*+-------------------------------------------------------------------
on_key_down
Called when a key is pressed. This function should return
true if the message is processed, false otherwise.
*/
bool on_key_down (HWND hwnd, TCHAR key)
{
bool handled = false;
if ((key == 'g') || (key == 'G')) // G for Go!
{
do_radiosity();
handled = true;
}
else if ((key == 's') || (key == 'S')) // S for step
{
do_one_radiosity_step();
handled = true;
}
else if ((key == 'd') || (key == 'D')) // D for debug
{
g_show_projected_points = !g_show_projected_points;
handled = true;
}
else if ((key == 'p') || (key == 'P')) // P for points
{
g_use_gl_points = !g_use_gl_points;
handled = true;
}
InvalidateRect(hwnd, NULL, TRUE);
return handled;
}
/*+-------------------------------------------------------------------
on_command
Process menu commands
*/
bool on_command (HWND hwnd, int command)
{
switch(command)
{
case IDM_FILE_EXIT:
DestroyWindow(hwnd);
return true;
}
return false;
}
/*+-------------------------------------------------------------------
MainWndProc
Event handler callback for the main application window.
*/
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
cleanup(hwnd);
PostQuitMessage(1);
return 0L;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
render_scene();
EndPaint(hwnd, &ps);
}
return 0L;
case WM_SIZE:
on_size_event(hwnd, LOWORD(lParam), HIWORD(lParam));
return 0L;
case WM_CHAR:
if (on_key_down(hwnd, (TCHAR)wParam))
return 0L;
else
break;
case WM_COMMAND:
if (on_command(hwnd, LOWORD(wParam)))
return 0L;
else
break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
/*+-------------------------------------------------------------------
WinMain
*/
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE /* hPrevInstance */,
LPSTR /* lpszCmdLine */,
int nCmdShow)
{
MSG msg;
WNDCLASSEX wndclassx;
char szClassName[] = "CSCIE235_RADIOSITY";
ZeroMemory(&wndclassx, sizeof(wndclassx));
wndclassx.cbSize = sizeof(wndclassx);
wndclassx.style = CS_HREDRAW | CS_VREDRAW;
wndclassx.lpfnWndProc = MainWndProc;
wndclassx.cbClsExtra = 0;
wndclassx.cbWndExtra = 0;
wndclassx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclassx.hCursor = LoadCursor(NULL, IDC_ARROW);
// This is an application that uses OpenGL for rendering,
// we don't need a GDI background
wndclassx.hbrBackground = NULL;
wndclassx.hInstance = hInstance;
wndclassx.lpszMenuName = NULL;
wndclassx.lpszClassName = szClassName;
wndclassx.hIconSm = NULL;
ATOM aRC = RegisterClassEx(&wndclassx);
if (!aRC)
{
panic_and_exit(-1, "Could not register windows class");
}
HMENU hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1));
HWND hwnd = CreateWindowEx(WS_EX_APPWINDOW, szClassName,
"Ben's Project",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
g_window_width,
g_window_height,
NULL,
hMenu,
hInstance, NULL);
setup(hwnd);
g_hdc = GetDC(hwnd);
glClear(GL_COLOR_BUFFER_BIT);
SwapBuffers(g_hdc);
glClear(GL_COLOR_BUFFER_BIT);
SwapBuffers(g_hdc);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
GLfloat point_sizes[] = { -1.0f, -1.0f };
glGetFloatv(GL_POINT_SIZE_RANGE, point_sizes);
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -