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

news2024/9/21 14:12:46

目 录
第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] = {'\0'};


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)\0*.ply\0";
	OPENFILENAME ofn;
	char pszFileLocn[256] = {'\0'};

	// 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);
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/61719.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【前沿技术RPA】 一文了解UiPath Orchestrator的触发器和监听器

&#x1f40b;作者简介&#xff1a;博主是一位.Net开发者&#xff0c;同时也是RPA和低代码平台的践行者。 &#x1f42c;个人主页&#xff1a;会敲键盘的肘子 &#x1f430;系列专栏&#xff1a;UiPath &#x1f980;专栏简介&#xff1a;UiPath在传统的RPA&#xff08;Robotic…

公众号接口免费调用

公众号接口免费调用 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 题库&#xff1a;题库后台&#xff08;点击跳转&#xff09;…

Express:CORS 跨域资源共享

CORS 跨域资源共享 Staticfile CDN 1. 接口的跨域问题 刚才编写的 GET 和 POST接口&#xff0c;存在一个很严重的问题&#xff1a;不支持跨域请求。 解决接口跨域问题的方案主要有两种&#xff1a; 1.CORS&#xff08;主流的解决方案&#xff0c;推荐使用&#xff09; 2.J…

Excel - 选择性粘贴和单元格引用规则

最基本的功能&#xff0c;才是最重要的功能&#xff0c;一定好好好理解。 最常用的复制、粘贴功能&#xff0c;在Excel里赋予了更多的选项&#xff0c;也变得更加强大。Excel里一般可复制的内容都是只单元格区域&#xff0c;其组成包括数据(文本或数值)、格式、公式、有效性验证…

FileZilla Server.xml 如何配置

要从xp.cn说起&#xff0c;因为它自带了一个ftp服务器。我点击配置后&#xff0c;就会直接用记事本打开FileZilla Server.xml让配置。我就很懵。不知道如何下手。 弹出的配置界面如下&#xff1a; 如何配置FileZilla Server.xml 我一开始想到去xp.cn找文档&#xff0c;可惜…

初探基因组组装——生信原理第四次实验报告

初探基因组组装——生信原理第四次实验报告 文章目录初探基因组组装——生信原理第四次实验报告实验目的实验内容实验题目第一题题目用SOAPdenovo 进行基因组组装评估组装质量第二题题目Canu组装Hifiasm组装基于nucmer的基因组比对过滤比对结果转换为可读性强的tab键分隔的文件…

期末论文LaTeX模板

简介 这学期的其中一门课程结束了&#xff0c;考核形式是写一篇中文的课程论文。于是&#xff0c;我使用了Elegant LaTeX 系列的模板。 小编已经把最新版本的三份模板放到公众号&#xff0c;后台回复[课程论文模板]即可获取。也欢迎大家去 GitHub 给贡献者点 star&#xff01;…

【从零开始玩量化13】quantstats:分析你的量化策略

背景 之前总结了一些获取量化数据的途径&#xff0c;数据是一个量化策略的“原材料”&#xff0c;接下来要考虑的问题就是如何使用这些数据。 本文&#xff0c;介绍一个量化指标分析工具quantstats&#xff0c;利用它可以很方便的分析你的策略。 Github地址&#xff1a;https…

[附源码]计算机毕业设计校园帮平台管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【5G MAC】随机接入流程中的 Msg3 —— Scheduled UL (PUSCH) Transmission

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

机器学习數據降維之主成分分析(PCA)

文章目录前言数据降维是什么&#xff1f;维度灾难与降维作用主成分分析PCA原理PCA算法小例實戰總結前言 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多人都开启了学习机器学习&#xff0c;本文就介绍了机器学习的基础内容…

cubeIDE开发,结合汉字取模工具,在LCD输出各种字体

一、汉字取模工具 嵌入式LCD屏显示无非就是不间断刷新LCD宽度*LCD高度的像素矩阵&#xff0c;并为每个像素指定特定颜色。对于LCD屏幕显示汉字&#xff0c;无非就是将字体形状转换为字体宽度*字体高度的像素矩阵&#xff0c;及指定每个字体像素的颜色&#xff0c;然后在LCD屏幕…

点击试剂Methyltetrazine-PEG4-NHS ester,甲基四嗪-PEG4-琥珀酰亚胺酯,CAS:1802907-9

An English name&#xff1a;Methyltetrazine-PEG4-NHS ester Chinese name&#xff1a;甲基四嗪-四聚乙二醇-琥珀酰亚胺酯 Item no&#xff1a;X-CL-1328 CAS&#xff1a;1802907-92-1 Formula&#xff1a;C24H31N5O9 MW&#xff1a;533.54 Purity&#xff1a;95% Avai…

基于MCMC的交通量逆建模(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

《人类简史》笔记四—— 想象构建的秩序

目录 一、盖起金字塔 1、未来的来临 2、 由想象构建的秩序 3、如何维持构建的秩序 二、 记忆过载 三、亚当和夏娃的一天 一、盖起金字塔 1、未来的来临 原始社会&#xff1a; 人口少&#xff1b; 狩猎和采集&#xff1b; 整体活动范围大&#xff08;有几十甚至上百平方…

【怎么理解回流与重绘?以及触发场景】

一、是什么 在HTML中&#xff0c;每个元素都可以理解成一个盒子&#xff0c;在浏览器解析过程中&#xff0c;会涉及到回流与重绘&#xff1a; 回流&#xff1a;布局引擎会根据各种样式计算每个盒子在页面上的大小与位置 重绘&#xff1a;当计算好盒模型的位置、大小及其他属性…

初学Nodejs(5):npm包管理器与包的发布

初学Nodejs 包 1、概念 什么是包 Nodejs中的第三方模块又叫做包。包的来源 不同于Nodejs中的内置模块与自定义模块&#xff0c;包是由第三方个人或团队开发出来的&#xff0c;免费供人使用。&#xff08;nodejs中的包都是免费且开源的&#xff0c;不需要付费即可免费下载使用…

2022年33个最佳WordPress健康与医疗主题

欢迎来到我们针对健康和保健相关网站和博客的最佳WordPress医疗主题的列表。这些涵盖了一切。您可以将它们用于医生、牙医、医院、健康诊所、内科医生、物理治疗师、外科医生以及健康领域的其他任何事物。大家有什么共同点&#xff1f;优质、100% 可定制的布局和 0 编码策略。 …

【论文精读8】MVSNet系列论文详解-UCS-Net

UCS-Net&#xff0c;论文名为&#xff1a;Deep Stereo using Adaptive Thin Volume Representation with Uncertainty Awareness&#xff0c;CVPR2020&#xff08;CCF A&#xff09; 本文是MVSNet系列的第8篇&#xff0c;建议看过【论文精读1】MVSNet系列论文详解-MVSNet之后再…

机器学习之过拟合和欠拟合

文章目录前言什麽是过拟合和欠拟合?过拟合和欠拟合产生的原因&#xff1a;欠拟合(underfitting)&#xff1a;过拟合(overfitting)&#xff1a;解决欠拟合(高偏差)的方法1、模型复杂化2、增加更多的特征&#xff0c;使输入数据具有更强的表达能力3、调整参数和超参数4、增加训练…