三维模型的简化算法研究(任务书+lunwen+外文翻译+源码+查重报告)

目 录
第1章 绪论 1
1.1 研究背景 1
1.2 内存网格简化算法 1
1.2.1 顶点聚类 1
1.2.2 区域合并 2
1.2.3 迭代式消除 4
1.2.4 随机重采样 5
1.3 三维模型简化算法 6
1.3.1 分片简化 6
1.3.2 使用外部数据结构 7
1.3.3 网格批处理 9
1.3.4 流式简化 10
1.3.5 小结 11
1.4 自适应等值面生成算法 11
1.5 论文的主要内容及章节安排 12
第2章 基于点分片的三维模型简化 13
2.1 边收缩操作对边界拓扑结构的自动保持 13
2.2 算法概述 14
2.3 LRU缓存系统 19
2.4 分片文件格式设计 21
2.5 单个分片的简化 22
2.6 分片合并 23
2.7 执行结果 24
2.8 本章小结 27
第3章 三维模型简化 31
3.1 算法概述 31
3.2 等值面生成过程中终结信息的判断 31
3.3 生成边界的延伸与模型的简化 34
3.4 顶点拓扑关系的重建与网格数据结构的设计 35
3.5 执行结果 36
3.6 本章小结 38
第4章 基于八叉树单形分割的并行等值面生成 41
4.1 算法概述 41
4.2 自适应八叉树的四面体分割 42
4.3 对偶点的求取 43
4.4 八叉树的建立 45
4.5 最小边的查找 47
4.6 四面体与等值面生成 49
4.7 执行结果 51
4.8 本章小结 52
第5章 总结与展望 53
5.1 总结 53
5.2 展望 53
参考文献 54
致 谢 57
声 明 58
第2章 基于点分片的三维模型简化
使用分片进行三维模型简化具有简化质量好、操作较为简单等优势。但现存网格分片算法有一些劣势:
(1). 大部分算法由于分片简化的过程中不能对边界进行简化,因此必须对合并后的网格再进行一次处理。
(2). 有的方法在合并网格的过程中需要将所有简化后分片的顶点都载入内存,对简化后网格的大小做出了限制。
相对于原分片简化算法的缺点,本章节算法的主要特点是:
(1). 由于使用了对点而非对三角形进行分割的方法,简化过程不需要对分片的边界进行保持,分片合并后不会产生严重的分片边界与内部顶点的密度不统一,因此不需要在分片合并后再对网格进行处理。
(2). 由于算法在对分片进行合并的时候只需要保持输出网格的一部分信息,因此算法对输出网格的大小没有限制。算法可以输出一个大于内存装载能力的网格。
两种分片方法的对比如图2.1所示。其中(a)为原始网格;(b)©为对三角形进行分片的简化过程,由于边界不能被简化,导致了密度不统一;(d)(e)为对点进行分片的简化过程,由于所有点均可以被简化,因此没有产生密度不统一的情况。
2.1 边收缩操作对边界拓扑结构的自动保持
在简化分片的时候,我们选择了边收缩作为简化操作。边收缩操作最早在Hoppe的论文[19]中被提出。边收缩与边分裂是一对互逆的操作(如图2.2),它将一条边的两个端点合并为一个新的顶点,并消除邻接这条边的三角形。
如图2.1-(a)、2.1-(b)所示,在使用对点进行分片的三维模型简化算法中,使用了边收缩的内存简化不会产生拓扑结构的不一致性。这是因为,边收缩对分片的拓扑结构改变可以保持在分片之内,而不影响其他分片。这保证了分片之间简化的独立性,使得边界被简化变得可能。
如图2.3所示,AB为一条处在边界上的可被收缩的边,CD为另一边界上的可收缩的边。在收缩操作中,A与B收缩为点A’,C与D收缩为点C’。两次不同分片中的收缩操作所影响的不属于本分片的三角形仅仅为处在分片边界上的三角形(图中的亮蓝色三角形区域)。在后续的处理中,算法将移除这些退化的边界三角形。需要注意的是,在边被收缩的时候,需要检查是否有代表顶点跨越了边界(如图2.4所示)。这个问题可以通过判断收缩后的点是否落在了本分片的包围盒之内来解决。如果出现了越界的情况,则可以使用两个端点的中点作为代表顶点。
第2章 基于点分片的三维模型简化
使用分片进行三维模型简化具有简化质量好、操作较为简单等优势。但现存网格分片算法有一些劣势:
(1). 大部分算法由于分片简化的过程中不能对边界进行简化,因此必须对合并后的网格再进行一次处理。
(2). 有的方法在合并网格的过程中需要将所有简化后分片的顶点都载入内存,对简化后网格的大小做出了限制。
相对于原分片简化算法的缺点,本章节算法的主要特点是:
(1). 由于使用了对点而非对三角形进行分割的方法,简化过程不需要对分片的边界进行保持,分片合并后不会产生严重的分片边界与内部顶点的密度不统一,因此不需要在分片合并后再对网格进行处理。
(2). 由于算法在对分片进行合并的时候只需要保持输出网格的一部分信息,因此算法对输出网格的大小没有限制。算法可以输出一个大于内存装载能力的网格。
两种分片方法的对比如图2.1所示。其中(a)为原始网格;(b)©为对三角形进行分片的简化过程,由于边界不能被简化,导致了密度不统一;(d)(e)为对点进行分片的简化过程,由于所有点均可以被简化,因此没有产生密度不统一的情况。
2.1 边收缩操作对边界拓扑结构的自动保持
在简化分片的时候,我们选择了边收缩作为简化操作。边收缩操作最早在Hoppe的论文[19]中被提出。边收缩与边分裂是一对互逆的操作(如图2.2),它将一条边的两个端点合并为一个新的顶点,并消除邻接这条边的三角形。
如图2.1-(a)、2.1-(b)所示,在使用对点进行分片的三维模型简化算法中,使用了边收缩的内存简化不会产生拓扑结构的不一致性。这是因为,边收缩对分片的拓扑结构改变可以保持在分片之内,而不影响其他分片。这保证了分片之间简化的独立性,使得边界被简化变得可能。
如图2.3所示,AB为一条处在边界上的可被收缩的边,CD为另一边界上的可收缩的边。在收缩操作中,A与B收缩为点A’,C与D收缩为点C’。两次不同分片中的收缩操作所影响的不属于本分片的三角形仅仅为处在分片边界上的三角形(图中的亮蓝色三角形区域)。在后续的处理中,算法将移除这些退化的边界三角形。需要注意的是,在边被收缩的时候,需要检查是否有代表顶点跨越了边界(如图2.4所示)。这个问题可以通过判断收缩后的点是否落在了本分片的包围盒之内来解决。如果出现了越界的情况,则可以使用两个端点的中点作为代表顶点。
在这里插入图片描述
在这里插入图片描述

(a) (b)
在这里插入图片描述
在这里插入图片描述

© (d)
图2.1 (a)、(b):对三角形进行分片的简化过程。©、(d):对点进行分片的简化过程。图中,不同颜色(紫,绿,灰)的三角形、边和顶点代表不同分片中的元素。(a)、(b)中白色边和顶点代表对三角形分割的分片边界,边界附近黑色的边代表不能被收缩的边。©、(d)中的白色三角形代表对点分割的分片边界,边界上黑色的边代表不能被收缩的边。
并不是所有简化操作都具有这种分片边界简化的独立性。以顶点移除为例,在图2.5中,不同分片中的边界顶点A与B被执行了顶点移除操作,对他们的操作影响到了分片之外的顶点。图2.5中对B的移除实际上是对B和A做了一次边收缩,对A的移除则是与B做了一次边收缩并在由绿色标记的边上做了一次边交换(边收缩和边交换操作可以产生任意拓扑结构的简化网格[37])。在论文[12]中,作者在三角化的时候试图优化产生的三角形的质量,这使得三角化的方法具有不确定性。
事实上,所有顶点聚类操作都具有对拓扑结构的自动保持特性。边收缩操作可以转化为顶点聚类操作。
2.2 算法概述
本章算法的流程如图2.6所示。算法首先对网格中的顶点做一次扫描,获取网格的包围盒,并将顶点的信息写入二进制顶点文件。二进制顶点文件用来在后续的对三角形进行分片的过程中,根据顶点索引来取得三维坐标。使用二进制文件是因为,这样可以根据顶点的索引来确定数据在文件中的位置。算法随后对网格进行分割。被分割的网格会被写入分片文件中,每个分片将进行一次内存简化。最后,算法合并所有分片并生成最终的网格。
(a) (b)
© (d)
图2.1 (a)、(b):对三角形进行分片的简化过程。©、(d):对点进行分片的简化过程。图中,不同颜色(紫,绿,灰)的三角形、边和顶点代表不同分片中的元素。(a)、(b)中白色边和顶点代表对三角形分割的分片边界,边界附近黑色的边代表不能被收缩的边。©、(d)中的白色三角形代表对点分割的分片边界,边界上黑色的边代表不能被收缩的边。
并不是所有简化操作都具有这种分片边界简化的独立性。以顶点移除为例,在图2.5中,不同分片中的边界顶点A与B被执行了顶点移除操作,对他们的操作影响到了分片之外的顶点。图2.5中对B的移除实际上是对B和A做了一次边收缩,对A的移除则是与B做了一次边收缩并在由绿色标记的边上做了一次边交换(边收缩和边交换操作可以产生任意拓扑结构的简化网格[37])。在论文[12]中,作者在三角化的时候试图优化产生的三角形的质量,这使得三角化的方法具有不确定性。
事实上,所有顶点聚类操作都具有对拓扑结构的自动保持特性。边收缩操作可以转化为顶点聚类操作。
2.2 算法概述
本章算法的流程如图2.6所示。算法首先对网格中的顶点做一次扫描,获取网格的包围盒,并将顶点的信息写入二进制顶点文件。二进制顶点文件用来在后续的对三角形进行分片的过程中,根据顶点索引来取得三维坐标。使用二进制文件是因为,这样可以根据顶点的索引来确定数据在文件中的位置。算法随后对网格进行分割。被分割的网格会被写入分片文件中,每个分片将进行一次内存简化。最后,算法合并所有分片并生成最终的网格。



//#define WIN32_LEAN_AND_MEAN // we can't use this because we use the OPENFILENAME struct.
#include <windows.h>		// Header File For Windows
#include <sys/stat.h>
#include <cstdio>

#if defined (_MSC_VER) && (_MSC_VER >= 1020)
#pragma warning(disable:4710) // function not inlined
#pragma warning(disable:4702) // unreachable code
#pragma warning(disable:4514) // unreferenced inline function has been removed
#pragma warning(disable:4786) // disable "identifier was truncated to '255' characters in the browser information" warning in Visual C++ 6*
#endif

#include "resource.h"
#include "mesh.h"
#include "pmesh.h"
#include "glmodelwin.h"

// Menu positions
const int SIMPLICATION_MENU = 1;
const int UPDATE_MENU		= 2;
const int FILL_MENU         = 3;
const int SHADING_MENU      = 4;


// App. Instance
HINSTANCE	g_hInstance = NULL;

// Triangle model
Mesh* g_pMesh = NULL;

// Progressive Mesh
PMesh* g_pProgMesh = NULL;

// Edge Collapse Options
PMesh::EdgeCost g_edgemethod = PMesh::QUADRICTRI;

// OpenGL Window
glModelWindow* g_pWindow = NULL;

// file name
char g_filename[256] = {''};


LRESULT	CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT WINAPI aboutDlgProc( HWND, UINT, WPARAM, LPARAM);


// allow user to chose which mesh to load.
void loadMesh()
{
	static char szFilter[]= "Ply files (*.ply)*.ply";
	OPENFILENAME ofn;
	char pszFileLocn[256] = {''};

	// Set up OPENFILENAME struct to use commond dialog box for open

	ZeroMemory(&ofn, sizeof(OPENFILENAME));
	ofn.lStructSize = sizeof(ofn);	// size of struct
	ofn.hwndOwner = NULL;			// window that owns Dlg
	ofn.lpstrFilter = szFilter;		// Filter text
	ofn.lpstrFile = pszFileLocn;		// File name string
	ofn.nMaxFile = sizeof(pszFileLocn); // size of file name
	ofn.Flags = OFN_HIDEREADONLY;	// don't display "Read Only"
	ofn.lpstrDefExt = "ply";		// extension name
	ofn.lpstrTitle = "Open Mesh File"; // title of dlg box

	// call common dlg control for file open
	if (!GetOpenFileName(&ofn)) {
		return ;	
	}

	// see if file exists
    struct stat fileStat;
    if (stat(ofn.lpstrFile, &fileStat))
	{
		char errormsg[1024];
		sprintf(errormsg, "%s not found.", ofn.lpstrFile);
		MessageBox(NULL,errormsg,"File Not Found Error",MB_OK | MB_ICONINFORMATION);
		return ;	
	}

	if (!g_pProgMesh) // 1st time through
	{
		// load "plus sign" cursor
		SetClassLong(g_pWindow->getHWnd(), GCL_HCURSOR, (LONG) LoadCursor(NULL, IDC_CROSS));
	}

	delete g_pMesh;
	g_pMesh = NULL; // not necessary, but a nice CYA habit
	delete g_pProgMesh;
	g_pProgMesh = NULL;

	SetWindowText(g_pWindow->getHWnd(), "Jeff Somers Mesh Simplification Viewer - (loading....)");
	g_pMesh = new Mesh(ofn.lpstrFile);
	strcpy(g_filename, ofn.lpstrFile);

	if (g_pMesh) g_pMesh->Normalize();// center mesh around the origin & shrink to fit

	g_pProgMesh = new PMesh(g_pMesh, g_edgemethod );
	
	// reset the position of the mesh
	g_pWindow->resetOrientation();

	g_pWindow->displayWindowTitle();
}


// User has selected a new mesh simplification algorithm
void changeSimplificationAlgorithm(const char* name, const PMesh::EdgeCost &ec)
{
	if (ec != g_edgemethod)
	{
		char temp[1024];
		strcpy(temp, "Jeff Somers Mesh Simplification Viewer - ");
		strcat(temp, name);
		SetWindowText(g_pWindow->getHWnd(), temp);
		g_edgemethod = ec;
		if (0 != strlen(g_filename))
		{
			strcat(temp, " (loading....)");
			SetWindowText(g_pWindow->getHWnd(), temp);
			if (g_pMesh == NULL)
			{
				g_pMesh = new Mesh(g_filename);
				if (g_pMesh) g_pMesh->Normalize();
			}
			delete g_pProgMesh;
			g_pProgMesh = new PMesh(g_pMesh, g_edgemethod);
			g_pWindow->displayWindowTitle();
			InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
		}
	}
}

// User selected a menu item
int handleMenuCommands(WPARAM wParam, LPARAM lParam)
{
	const int REDUCE_TRI_PERCENT = 5;	// when page up/page down, inc/dec # tris by this percent 
										// (percent applies to # of tris in *original* mesh.)
	const int NUM_PAGEUPDN_INTERVALS = 100/REDUCE_TRI_PERCENT;

	switch (LOWORD(wParam)) 
	{
		case IDM_FILE_EXIT: 
		{
			SendMessage (g_pWindow->getHWnd(), WM_CLOSE, wParam, lParam) ;
			return 0 ;
		}

		case IDM_FILE_OPEN:
		{
			loadMesh();
			InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			return 0;
		}
		case IDM_UPDATE_ADDONETRI:  // split vertex
		{
			if (g_pProgMesh)
			{
				bool ret = g_pProgMesh->splitVertex();
				if (!ret) MessageBeep(0);
				g_pWindow->displayWindowTitle();
				InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			}
			return 0;
		}
		case IDM_UPDATE_REMOVEONETRI: // collapse vertex
		{
			if (g_pProgMesh)
			{
				bool ret = g_pProgMesh->collapseEdge();
				if (!ret) MessageBeep(0);
				g_pWindow->displayWindowTitle();
				InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			}
			return 0;
		}
		case IDM_UPDATE_INCREASETRI5PERC: // split vertices
		{
			if (g_pProgMesh)
			{
				int size = (g_pProgMesh->numEdgeCollapses()) / NUM_PAGEUPDN_INTERVALS;
				if (size == 0) size = 1;
				bool ret = true;
				for (int i = 0; ret && i < size; ++i) {
					 ret = g_pProgMesh->splitVertex();
				}
				if (!ret) MessageBeep(0);
				g_pWindow->displayWindowTitle();
				InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			}
			return 0;
		}
		case IDM_UPDATE_REDUCETRI5PERC: // collapse vertices
		{
			if (g_pProgMesh)
			{
				int size = (g_pProgMesh->numEdgeCollapses()) / NUM_PAGEUPDN_INTERVALS;
				if (size == 0) size = 1;
				bool ret = true;
				for (int i = 0; ret && i < size; ++i) {
					 ret = g_pProgMesh->collapseEdge();
				}
				if (!ret) MessageBeep(0);
				g_pWindow->displayWindowTitle();
				InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			}
			return 0;
		}

		case IDM_METHOD_QUADRIC:
		{
			changeSimplificationAlgorithm("Quadric", PMesh::QUADRIC);
			return 0;
		}

		case IDM_METHOD_QUADRICTRI:
		{
			changeSimplificationAlgorithm("Quadric Weighted by Triangle Area", PMesh::QUADRICTRI );
			return 0;
		}

		case IDM_METHOD_MELAX:
		{
			changeSimplificationAlgorithm("Melax", PMesh::MELAX);
			return 0;
		}

		case IDM_METHOD_SHORTEST:
		{
			changeSimplificationAlgorithm("Shortest Edge", PMesh::SHORTEST);
			return 0;
		}

		case IDM_FULLSCREEN_FULLSCREEN_640X480:
		{
			// Set settings for new display mode
			g_pWindow->flipFullScreen(640, 480);
			InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			return 0;
		}
		case IDM_FULLSCREEN_FULLSCREEN_800X600:
		{
			// Set settings for new display mode
			g_pWindow->flipFullScreen(800, 600);
			InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			return 0;
		}
		case IDM_FULLSCREEN_FULLSCREEN_1024X768:
		{
			// Set settings for new display mode
			g_pWindow->flipFullScreen(1024, 768);
			InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			return 0;
		}
		case IDM_FULLSCREEN_FULLSCREEN_1280X1024:
		{
			// Set settings for new display mode
			g_pWindow->flipFullScreen(1280, 1024);
			InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			return 0;
		}
		case IDM_FULLSCREEN_FULLSCREEN_1600X1200:
		{
			// Set settings for new display mode
			g_pWindow->flipFullScreen(1600, 1200);
			InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			return 0;
		}
		case IDM_FILL_FILLED:
		{
			if (!g_pWindow->isFillTriMode())
			{
				g_pWindow->setFillTriMode(true);
				InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			}
			return 0;
		}
		case IDM_FILL_WIREFRAME:
		{
			if (g_pWindow->isFillTriMode())
			{
				g_pWindow->setFillTriMode(false);
				InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			}
			return 0;
		}
		case IDM_SHADING_FLATSHADING:
		{
			if (g_pWindow->isSmoothShadingMode())
			{
				g_pWindow->setSmoothShadingMode(false);
				InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			}
			return 0;
		}
		case IDM_SHADING_SMOOTHSHADING:
		{
			if (!g_pWindow->isSmoothShadingMode())
			{
				g_pWindow->setSmoothShadingMode(true);
				InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			}
			return 0;
		}
		case IDM_HELP_ABOUT:
		{
			DialogBox( g_hInstance, MAKEINTRESOURCE(IDD_ABOUT_DIALOG), g_pWindow->getHWnd(), (DLGPROC)
				aboutDlgProc );
			return 0;
		}
		default:
		{
			break;
		}
	}
	return 0;
}

// The popup menu is coming down.  Find out if menu items
// are currently set or reset, and gray out the inappropriate items.
void handleInitMenuPopup(WPARAM wParam, int menu)
{
	if (menu == SIMPLICATION_MENU) 
	{
		switch(g_edgemethod)
		{
		case PMesh::QUADRICTRI:
		{
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_QUADRICTRI, MF_CHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_QUADRIC, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_MELAX, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_SHORTEST, MF_UNCHECKED) ;
			break;
		}
		case PMesh::QUADRIC:
		{
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_QUADRICTRI, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_QUADRIC, MF_CHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_MELAX, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_SHORTEST, MF_UNCHECKED) ;
			break;
		}
		case PMesh::MELAX:
		{
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_QUADRICTRI, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_QUADRIC, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_MELAX, MF_CHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_SHORTEST, MF_UNCHECKED) ;
			break;
		}
		case PMesh::SHORTEST:
		{
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_QUADRICTRI, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_QUADRIC, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_MELAX, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_METHOD_SHORTEST, MF_CHECKED) ;
			break;
		}
		}
	}
	else if (menu == UPDATE_MENU)
	{
		if (g_pMesh)
		{
			EnableMenuItem ((HMENU)wParam,IDM_UPDATE_REDUCETRI5PERC, MF_ENABLED) ;
			EnableMenuItem ((HMENU)wParam,IDM_UPDATE_INCREASETRI5PERC, MF_ENABLED) ;
			EnableMenuItem ((HMENU)wParam,IDM_UPDATE_REMOVEONETRI, MF_ENABLED) ;
			EnableMenuItem ((HMENU)wParam,IDM_UPDATE_ADDONETRI, MF_ENABLED) ;
		}
		else
		{
			EnableMenuItem ((HMENU)wParam,IDM_UPDATE_REDUCETRI5PERC, MF_GRAYED) ;
			EnableMenuItem ((HMENU)wParam,IDM_UPDATE_INCREASETRI5PERC, MF_GRAYED) ;
			EnableMenuItem ((HMENU)wParam,IDM_UPDATE_REMOVEONETRI, MF_GRAYED) ;
			EnableMenuItem ((HMENU)wParam,IDM_UPDATE_ADDONETRI, MF_GRAYED) ;
		}
	}
	else if (menu == FILL_MENU)
	{
		if (g_pWindow->isFillTriMode())
		{
			CheckMenuItem ((HMENU)wParam,IDM_FILL_WIREFRAME, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_FILL_FILLED, MF_CHECKED) ;
		}
		else
		{
			CheckMenuItem ((HMENU)wParam,IDM_FILL_WIREFRAME, MF_CHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_FILL_FILLED, MF_UNCHECKED) ;
		}
	}
	else if (menu == SHADING_MENU)
	{
		if (g_pWindow->isSmoothShadingMode())
		{
			CheckMenuItem ((HMENU)wParam,IDM_SHADING_FLATSHADING, MF_UNCHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_SHADING_SMOOTHSHADING, MF_CHECKED) ;
		}
		else
		{
			CheckMenuItem ((HMENU)wParam,IDM_SHADING_FLATSHADING, MF_CHECKED) ;
			CheckMenuItem ((HMENU)wParam,IDM_SHADING_SMOOTHSHADING, MF_UNCHECKED) ;
		}
	}
}


// Handles Windows Messages
LRESULT CALLBACK wndProc(HWND hWnd,	UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
		case WM_SYSCOMMAND:
		{
			switch (wParam)
			{
				case SC_MONITORPOWER: // Prevent screen saver, monitor from	going into Power Save mode
				case SC_SCREENSAVE:
				return 0;
			}
			break;
		}

		case WM_CLOSE:
		{
			PostQuitMessage(0);
			return 0;
		}

		case WM_LBUTTONDOWN:
		{
			SetCapture(g_pWindow->getHWnd()); // capture mouse outside client area
			g_pWindow->setNewXY(LOWORD(lParam), HIWORD(lParam));
			return 0;
		}

		case WM_LBUTTONUP:
		{
			ReleaseCapture(); // stop capturing mouse outside client area
			return 0;
		}

		case WM_RBUTTONDOWN:
		{
			SetCapture(g_pWindow->getHWnd()); // capture mouse outside client area
			g_pWindow->setNewXY(LOWORD(lParam), HIWORD(lParam));
			return 0;
		}

		case WM_RBUTTONUP:
		{
			ReleaseCapture(); // stop capturing mouse outside client area
			return 0;
		}

		case WM_MOUSEMOVE:
		{
			if ((wParam & MK_LBUTTON) || (wParam & MK_RBUTTON)) // if left or right button pressed
			{
				bool leftButton = (wParam & MK_LBUTTON) ? true : false;
				bool rightButton = (wParam & MK_RBUTTON) ? true : false;;
				g_pWindow->mouseMotion(LOWORD(lParam), HIWORD(lParam), leftButton, rightButton);
				InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
			}
			return 0;
		}

		case WM_PAINT:
		{
			static PAINTSTRUCT ps;

			BeginPaint(g_pWindow->getHWnd(), &ps);
			g_pWindow->displayMesh();
			EndPaint(g_pWindow->getHWnd(), &ps);
			return 0;
		}

		case WM_SIZE:
		{
			g_pWindow->reSizeScene(LOWORD(lParam),HIWORD(lParam));
			return 0;
		}
		case WM_COMMAND:
	  	{
			handleMenuCommands(wParam, lParam);
			return 0;
		}
		case WM_CHAR:
				// handle keyboard input 
				switch ((int)wParam) {
				case VK_ESCAPE: // fall through
				case VK_SPACE:  // fall through
				case VK_RETURN: // fall through
					if (g_pWindow->isFullScreen())
					{
						// exit Full screen mode
						g_pWindow->flipFullScreen(0, 0);
						InvalidateRect(g_pWindow->getHWnd(), NULL, TRUE);
					}
					return 0;
				default:
					break;
				}

		case WM_INITMENUPOPUP:
		{
			// Deal with menu initialization
			handleInitMenuPopup(wParam, LOWORD(lParam));
			return 0;
		}
		default:
		{
			break;
		}
	}

	// Pass All Unhandled Messages To DefWindowProc
	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

// Handle the "About" Dialog
LRESULT CALLBACK aboutDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM  )
{
   switch( uMsg ) {
      case WM_INITDIALOG:
         return true;
      case WM_COMMAND:
         switch( wParam ) {
            case IDOK:
               EndDialog( hDlg, TRUE );
               return true;
         }
      break;
   }
   return false;
}

// Main function for executable
int PASCAL WinMain(HINSTANCE  hInst,HINSTANCE  ,LPSTR  ,int  )
{
	MSG msg;
	HACCEL hAccel; /* Keyboard accelerators */

	g_hInstance	= hInst;

	/* Load keyboard shortcuts */
	hAccel = LoadAccelerators(g_hInstance, "MAINACCEL");

	bool bFullScreen = false;

	int width = 640; // initial width
	int height = 480; // initial height
	unsigned char depth = 16; // 16 bit color

	// Create Window
	g_pWindow = new glModelWindow();
	if (!g_pWindow || !g_pWindow->createMyWindow(width,height,depth,bFullScreen))
	{
		return 0;
	}

	// We don't use PeekMessage here since this is not an interactive
	// game.  Framerate is not crucial.
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(g_pWindow->getHWnd(), hAccel, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	// Shutdown
	g_pWindow->killMyWindow();

	delete g_pProgMesh; // this is here to keep Boundschecker happy
	delete g_pMesh;

	return (msg.wParam);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>