www.pudn.com > 3dSimplifier.zip > ChildView.cpp, change:2000-01-14,size:30030b


// ChildView.cpp : implementation of the CChildView class 
// 
 
#include "stdafx.h" 
#include <GL/gl.h> 
#include <GL/glu.h> 
#include <GL/glaux.h> 
#include "Simplifier.h" 
#include "ChildView.h" 
#include "MainFrm.h" 
#include "InitOpenGL.h" 
#include "SimplifyDiag.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CChildView 
 
CChildView::CChildView() 
{ 
	m_fViewHeight = 2.0; 
	m_fViewNear = -2.0; 
	m_fViewFar = 2.0; 
 
	m_nMouseAct = MOUSE_SPIN; 
	m_bAnimate = FALSE; 
	m_bAxes = TRUE; 
 
	m_spinAngle = 0.0; 
	m_spinAxes[0] = m_spinAxes[2] = 0.0; m_spinAxes[1] = 1.0; 
 
	m_sEye.origin.x = m_sEye.origin.y = m_sEye.origin.z = 0.0; 
	m_sEye.center.x = m_sEye.center.y = 0.0; m_sEye.center.z = -1.0; 
	m_sEye.up.x = m_sEye.up.z = 0.0; m_sEye.up.y = 1.0; 
	m_sEye.axisX.y = m_sEye.axisX.z = 0.0; m_sEye.axisX.x = 1.0; 
	m_sEye.axisY.x = m_sEye.axisY.z = 0.0; m_sEye.axisY.y = 1.0; 
	m_sEye.axisZ.x = m_sEye.axisZ.y = 0.0; m_sEye.axisZ.z = -1.0; 
	m_vProjectCenter[0] = 0.0f; 
	m_vProjectCenter[1] = 0.0f; 
	m_vProjectCenter[2] = (m_fViewNear+m_fViewFar)/2; 
 
	m_nRenderModel = 1; 
	m_nRenderMode = 1; 
	m_pModel = NULL; 
	m_nFaceNo = 0; 
} 
 
CChildView::~CChildView() 
{ 
	if (m_pModel) 
		delete m_pModel; 
} 
 
 
BEGIN_MESSAGE_MAP(CChildView,CWnd ) 
	//{{AFX_MSG_MAP(CChildView) 
	ON_WM_PAINT() 
	ON_WM_SIZE() 
	ON_WM_CREATE() 
	ON_WM_MOUSEMOVE() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_LBUTTONUP( ) 
	ON_WM_SETCURSOR() 
	ON_WM_TIMER() 
	ON_WM_CONTEXTMENU() 
	ON_COMMAND(ID_MOUSE_SPIN, OnMouseSpin) 
	ON_UPDATE_COMMAND_UI(ID_MOUSE_SPIN, OnUpdateMouseSpin) 
	ON_COMMAND(ID_MOUSE_TRANSLATE, OnMouseTranslate) 
	ON_UPDATE_COMMAND_UI(ID_MOUSE_TRANSLATE, OnUpdateMouseTranslate) 
	ON_COMMAND(ID_MOUSE_ZOOM, OnMouseZoom) 
	ON_UPDATE_COMMAND_UI(ID_MOUSE_ZOOM, OnUpdateMouseZoom) 
	ON_COMMAND(ID_ANIMATE, OnAnimate) 
	ON_UPDATE_COMMAND_UI(ID_ANIMATE, OnUpdateAnimate) 
	ON_COMMAND(ID_SPIN_XCCW, OnSpinXccw) 
	ON_COMMAND(ID_SPIN_XCW, OnSpinXcw) 
	ON_COMMAND(ID_SPIN_YCCW, OnSpinYccw) 
	ON_COMMAND(ID_SPIN_YCW, OnSpinYcw) 
	ON_COMMAND(ID_SPIN_ZCCW, OnSpinZccw) 
	ON_COMMAND(ID_SPIN_ZCW, OnSpinZcw) 
	ON_COMMAND(ID_ZOOM_IN, OnZoomIn) 
	ON_COMMAND(ID_ZOOM_OUT, OnZoomOut) 
	ON_COMMAND(ID_OPEN_FILE, OnOpenFile) 
	ON_COMMAND(IDM_ORIGINAL_MODEL, OnOriginalModel) 
	ON_UPDATE_COMMAND_UI(IDM_ORIGINAL_MODEL, OnUpdateOriginalModel) 
	ON_COMMAND(IDM_SIMPLIFIED_MODEL, OnSimplifiedModel) 
	ON_UPDATE_COMMAND_UI(IDM_SIMPLIFIED_MODEL, OnUpdateSimplifiedModel) 
	ON_COMMAND(IDM_WIREFRAME, OnWireframe) 
	ON_UPDATE_COMMAND_UI(IDM_WIREFRAME, OnUpdateWireframe) 
	ON_COMMAND(IDM_FLAT, OnFlat) 
	ON_UPDATE_COMMAND_UI(IDM_FLAT, OnUpdateFlat) 
	ON_COMMAND(ID_SIMPLIFY, OnSimplify) 
	ON_COMMAND(ID_SAVE_FILE, OnSaveFile) 
	ON_COMMAND(ID_AXES, OnAxes) 
	ON_UPDATE_COMMAND_UI(ID_AXES, OnUpdateAxes) 
	ON_COMMAND(IDM_SAVE_PICTURE, OnSavePicture) 
	ON_UPDATE_COMMAND_UI(ID_SIMPLIFY, OnUpdateSimplify) 
	ON_UPDATE_COMMAND_UI(ID_SAVE_FILE, OnUpdateSaveFile) 
	ON_COMMAND(ID_CLOSE_FILE, OnCloseFile) 
	ON_UPDATE_COMMAND_UI(ID_CLOSE_FILE, OnUpdateCloseFile) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CChildView message handlers 
 
int CChildView::OnCreate( LPCREATESTRUCT lpCreateStruct ) 
{ 
	if (CWnd::OnCreate(lpCreateStruct) == -1) 
		return -1; 
 
	Init(); 
 
	return 0; 
} 
 
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)  
{ 
	cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ; 
	cs.dwExStyle |= WS_EX_CLIENTEDGE; 
	cs.style &= ~WS_BORDER; 
	cs.lpszClass = AfxRegisterWndClass(CS_OWNDC|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,  
		::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL); 
	 
	if (!CWnd::PreCreateWindow(cs)) 
		return FALSE; 
 
	return TRUE; 
} 
 
void CChildView::OnPaint()  
{ 
	CPaintDC dc(this); // device context for painting 
	 
	// TODO: Add your message handler code here 
	DrawScene(); 
	// Do not call CWnd::OnPaint() for painting messages 
} 
 
void CChildView::OnSize( UINT nType, int cx, int cy ) 
{ 
	CWnd::OnSize(nType, cx, cy); 
	Project(); 
} 
 
BOOL CChildView::OnCommand(WPARAM wParam, LPARAM lParam)  
{ 
	WORD nID = wParam & 0x0000ffff; 
 
	switch (nID) 
	{ 
	case ID_ZOOM_IN: 
		OnZoomIn(); 
		break; 
	case ID_ZOOM_OUT: 
		OnZoomOut(); 
		break; 
	case ID_SPIN_XCW: 
		OnSpinXcw(); 
		break; 
	case ID_SPIN_XCCW: 
		OnSpinXccw(); 
		break; 
	case ID_SPIN_YCW: 
		OnSpinYcw(); 
		break; 
	case ID_SPIN_YCCW: 
		OnSpinYccw(); 
		break; 
	case ID_SPIN_ZCW: 
		OnSpinZcw(); 
		break; 
	case ID_SPIN_ZCCW: 
		OnSpinZccw(); 
		break; 
	} 
	 
	return CWnd ::OnCommand(wParam, lParam); 
} 
 
void CChildView::OnTimer( UINT nIDEvent ) 
{ 
	if (nIDEvent == TIMER_ANIMATE) 
	{ 
		if (m_bAnimate && (m_spinAngle!=0.0) ) 
			SpinGlobal(m_spinAxes, m_spinAngle);		 
	} 
	else if (nIDEvent == TIMER_TOOLBAR) 
	{ 
		CMainFrame *pFrameWnd = (CMainFrame*)AfxGetMainWnd(); 
		int count = (pFrameWnd->m_wndInteractRight).GetToolBarCtrl().GetButtonCount(); 
		int nIndex; 
 
		for( nIndex = 0; nIndex  count; nIndex++) 
		{ 
			if( (pFrameWnd->m_wndInteractRight).GetToolBarCtrl().IsButtonPressed( (pFrameWnd->m_wndInteractRight).GetItemID( nIndex))) 
			{ 
				pFrameWnd->SendMessage( WM_COMMAND,  
					(pFrameWnd->m_wndInteractRight).GetItemID( nIndex), (LPARAM)m_hWnd); 
				break; 
			} 
		} 
	} 
} 
 
void CChildView::OnContextMenu( CWnd* pWnd, CPoint pos ) 
{ 
	CMenu menu; 
	menu.LoadMenu(IDR_CONTEXTMENU); 
	TRACE("%d  %d  \n",pos.x,pos.y); 
	menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, 
		pos.x,pos.y,this); 
} 
 
void CChildView::OnMouseMove( UINT nFlags, CPoint point ) 
{ 
	if (m_nMouseAct == MOUSE_SPIN) 
	{ 
		MouseSpinGlobal(nFlags, point.x, point.y, 0); 
	} 
	else if (m_nMouseAct == MOUSE_ZOOM) 
	{ 
		MouseZoom(nFlags, point.x, point.y); 
	} 
	else if (m_nMouseAct == MOUSE_TRANSLATE) 
	{ 
		MouseTranslate(nFlags, point.x, point.y); 
	} 
	 
	CWnd::OnMouseMove(nFlags, point); 
} 
 
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
	m_spinAngle = 0.0f; 
	if (m_nMouseAct == MOUSE_SPIN) 
	{ 
		if (m_bAnimate) 
			SetTimer(TIMER_ANIMATE,ANIMATE_RATE,NULL); 
 
		MouseSpinGlobal(nFlags, point.x, point.y, 1); 
	} 
	else if (m_nMouseAct == MOUSE_ZOOM) 
	{ 
		MouseZoom(nFlags, point.x, point.y); 
	} 
	else if (m_nMouseAct == MOUSE_TRANSLATE) 
	{ 
		MouseTranslate(nFlags, point.x, point.y); 
	} 
	 
	CWnd::OnLButtonDown(nFlags, point); 
 
	MSG msg; 
	while(::PeekMessage( &msg, m_hWnd, 
		WM_MOUSEMOVE, WM_MOUSEMOVE, 
		PM_REMOVE)) 
		; 
 
	m_bLButtonDown = TRUE; 
} 
 
void CChildView::OnLButtonUp(UINT nFlags, CPoint point) 
{ 
	m_bLButtonDown = FALSE; 
 
	MSG msg; 
	while(::PeekMessage( &msg, m_hWnd, 
		WM_MOUSEMOVE, WM_MOUSEMOVE, 
		PM_REMOVE)) 
		; 
 
	CWnd::OnLButtonUp(nFlags, point); 
} 
 
BOOL CChildView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{ 
	HCURSOR hCursor; 
 
	switch (m_nMouseAct) 
	{ 
	case MOUSE_SPIN: 
		hCursor = AfxGetApp()->LoadCursor( IDC_SPIN ); 
		SetCursor( hCursor ); 
		break; 
	case MOUSE_ZOOM: 
		hCursor = AfxGetApp()->LoadCursor( IDC_ZOOM ); 
		SetCursor( hCursor ); 
		break; 
	case MOUSE_TRANSLATE: 
		hCursor = AfxGetApp()->LoadCursor( IDC_TRANSLATE ); 
		SetCursor( hCursor ); 
		break; 
	default: 
		hCursor = AfxGetApp()->LoadCursor( IDC_ARROW ); 
		SetCursor( hCursor ); 
		break; 
	} 
 
	return TRUE; 
} 
 
void CChildView::OnOriginalModel()  
{ 
	if (m_nRenderModel == 1) 
	{ 
		m_nRenderModel = 0; 
		DrawScene(); 
	} 
} 
 
void CChildView::OnUpdateOriginalModel(CCmdUI* pCmdUI)  
{ 
	pCmdUI->SetCheck(m_nRenderModel == 0); 
} 
 
void CChildView::OnSimplifiedModel()  
{ 
	if (m_nRenderModel == 0) 
	{ 
		m_nRenderModel = 1; 
		DrawScene(); 
	} 
} 
 
void CChildView::OnUpdateSimplifiedModel(CCmdUI* pCmdUI)  
{ 
	pCmdUI->SetCheck(m_nRenderModel == 1); 
} 
 
void CChildView::OnWireframe()  
{ 
	if (m_nRenderMode == 1) 
	{ 
		m_nRenderMode = 0; 
		DrawScene(); 
	} 
} 
 
void CChildView::OnUpdateWireframe(CCmdUI* pCmdUI)  
{ 
	pCmdUI->SetCheck(m_nRenderMode == 0);	 
} 
 
void CChildView::OnFlat()  
{ 
	if (m_nRenderMode == 0) 
	{ 
		m_nRenderMode = 1; 
		DrawScene(); 
	} 
} 
 
void CChildView::OnUpdateFlat(CCmdUI* pCmdUI)  
{ 
	pCmdUI->SetCheck(m_nRenderMode == 1);	 
} 
 
void CChildView::OnOpenFile()  
{ 
	CFileDialog loadmesh(TRUE,  "tm" , NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "tm文件(*.tm)|*.tm||"); 
	loadmesh.m_ofn.lpstrTitle ="打开模型文件"; 
	 
	//SetCurrentDirectory(".\\"); 
	if (loadmesh.DoModal() == IDOK ) 
	{ 
		CString filename; 
		CString fileext; 
 
		fileext  = loadmesh.GetFileExt(); 
		filename = loadmesh.GetPathName(); 
		if (!filename.IsEmpty()) { 
			FILE *fp; 
 
			fp = fopen(filename, "r"); 
			if (!fp) { 
				AfxMessageBox("Can't open file to load"); 
				return; 
			} 
			if (!fileext.CompareNoCase("tm")) 
			{ 
				if (m_pModel) 
					delete m_pModel; 
				m_pModel = new CMesh; 
 
				HCURSOR hCursor, hOldCursor; 
				hCursor = AfxGetApp()->LoadCursor( IDC_MY_WAIT ); 
				hOldCursor = SetCursor( hCursor ); 
				 
				CMainFrame *pFrameWnd = (CMainFrame*)AfxGetMainWnd(); 
				pFrameWnd->m_Progress.SetPos(0); 
				m_pModel->m_pProgress = &(pFrameWnd->m_Progress); 
 
				m_nFaceNo = m_pModel->ReadData(fp); 
				if (m_bAnimate) 
					OnAnimate(); 
				m_spinAngle = 0.0; 
 
				pFrameWnd->m_Progress.SetPos(0); 
				m_pModel->m_pProgress = NULL; 
				SetCursor(hOldCursor); 
			} 
			fclose(fp); 
 
			CMainFrame *pFrameWnd = (CMainFrame*)AfxGetMainWnd(); 
			char tmps[80]; 
			sprintf(tmps,"原始模型:%d", m_nFaceNo); 
			pFrameWnd->m_wndStatusBar.SetPaneText(1,tmps); 
			m_nsFaceNo = m_nFaceNo; 
			sprintf(tmps,"简化模型:%d", m_nsFaceNo); 
			pFrameWnd->m_wndStatusBar.SetPaneText(2,tmps); 
 
			DrawScene(); 
		} 
	}	 
} 
 
void CChildView::OnSaveFile()  
{ 
	if (!m_pModel) 
		return; 
 
	CFileDialog savemesh(FALSE,  "tm" , NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "tm文件(*.tm)|*.tm||"); 
	savemesh.m_ofn.lpstrTitle ="保存模型文件"; 
 
	SetCurrentDirectory(".\\Mesh"); 
	if (savemesh.DoModal() == IDOK ) 
	{ 
		CString filename; 
		CString fileext; 
 
		fileext  = savemesh.GetFileExt(); 
		filename = savemesh.GetPathName(); 
		if (!filename.IsEmpty()) { 
			FILE *fp; 
 
			fp = fopen(filename, "w"); 
			if (!fp) { 
				AfxMessageBox("Can't open file to load"); 
				return; 
			} 
			if (!fileext.CompareNoCase("tm")) 
			{ 
				HCURSOR hCursor, hOldCursor; 
				hCursor = AfxGetApp()->LoadCursor( IDC_MY_WAIT ); 
				hOldCursor = SetCursor( hCursor ); 
				 
				CMainFrame *pFrameWnd = (CMainFrame*)AfxGetMainWnd(); 
				pFrameWnd->m_Progress.SetPos(0); 
				m_pModel->m_pProgress = &(pFrameWnd->m_Progress); 
 
				m_pModel->SaveData(fp); 
 
				pFrameWnd->m_Progress.SetPos(0); 
				m_pModel->m_pProgress = NULL; 
				SetCursor(hOldCursor); 
			} 
			fclose(fp); 
		} 
	}		 
} 
 
void CChildView::OnUpdateSaveFile(CCmdUI* pCmdUI)  
{ 
	pCmdUI->Enable(m_pModel != NULL); 
} 
 
void CChildView::OnSavePicture()  
{ 
	CFileDialog savefile(FALSE, ".bmp", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "BMP文件(*.bmp)|*.bmp||");  
	savefile.m_ofn.lpstrTitle = "存为BMP图象" ; 
 
	if ( savefile.DoModal() == IDOK ) 
	{ 
		CString filename; 
		char temp[80]; 
 
		filename = savefile.GetPathName(); 
		sprintf(temp,"%s",filename); 
		SaveAsBMP(temp); 
	} 
} 
 
void CChildView::OnSimplify()  
{ 
	if (!m_pModel) 
		return; 
 
	HCURSOR hCursor, hOldCursor; 
 
	CSimplifyDiag diag(m_nFaceNo); 
 
	if (diag.DoModal() == IDOK) 
	{ 
		hCursor = AfxGetApp()->LoadCursor( IDC_MY_WAIT ); 
		hOldCursor = SetCursor( hCursor ); 
		 
		CMainFrame *pFrameWnd = (CMainFrame*)AfxGetMainWnd(); 
 
		pFrameWnd->m_Progress.SetPos(1); 
 
		m_pModel->m_pProgress = &(pFrameWnd->m_Progress); 
 
		if ((diag.m_nInputMode == 0)&&(diag.m_nFaceNo>0)&&(diag.m_nFaceNo<m_nFaceNo)) 
			m_nsFaceNo = m_pModel->Simplify(diag.m_nFaceNo); 
		else if (diag.m_nInputMode == 1) 
			m_nsFaceNo = m_pModel->Simplify(diag.m_fRate/100); 
 
		if (m_nRenderModel == 1) 
			DrawScene(); 
 
		pFrameWnd->m_Progress.SetPos(0); 
		m_pModel->m_pProgress = NULL; 
 
		char tmps[80]; 
		sprintf(tmps,"简化模型:%d", m_nsFaceNo); 
		pFrameWnd->m_wndStatusBar.SetPaneText(2,tmps); 
 
		SetCursor(hOldCursor); 
	} 
} 
 
void CChildView::OnUpdateSimplify(CCmdUI* pCmdUI)  
{ 
	pCmdUI->Enable(m_pModel != NULL); 
} 
 
void CChildView::OnCloseFile()  
{ 
	if (m_pModel) 
		delete m_pModel; 
	m_pModel = NULL; 
	DrawScene(); 
} 
 
void CChildView::OnUpdateCloseFile(CCmdUI* pCmdUI)  
{ 
	pCmdUI->Enable(m_pModel != NULL); 
} 
 
void CChildView::OnAxes()  
{ 
	m_bAxes = !m_bAxes; 
	DrawScene(); 
} 
 
void CChildView::OnUpdateAxes(CCmdUI* pCmdUI)  
{ 
	pCmdUI->SetCheck(m_bAxes);	 
} 
 
void CChildView::OnAnimate()  
{ 
	if (m_bAnimate) 
		KillTimer(TIMER_ANIMATE); 
	else 
		SetTimer( TIMER_ANIMATE, ANIMATE_RATE, NULL ); 
	m_bAnimate = !m_bAnimate; 
} 
 
void CChildView::OnUpdateAnimate(CCmdUI* pCmdUI)  
{ 
	pCmdUI->SetCheck(m_bAnimate); 
} 
 
void CChildView::OnMouseSpin()  
{ 
	m_nMouseAct = MOUSE_SPIN; 
} 
 
void CChildView::OnUpdateMouseSpin(CCmdUI* pCmdUI)  
{ 
	pCmdUI->SetCheck( m_nMouseAct == MOUSE_SPIN); 
} 
 
void CChildView::OnMouseTranslate()  
{ 
	m_nMouseAct = MOUSE_TRANSLATE; 
} 
 
void CChildView::OnUpdateMouseTranslate(CCmdUI* pCmdUI)  
{ 
	pCmdUI->SetCheck( m_nMouseAct == MOUSE_TRANSLATE); 
} 
 
void CChildView::OnMouseZoom()  
{ 
	m_nMouseAct = MOUSE_ZOOM; 
} 
 
void CChildView::OnUpdateMouseZoom(CCmdUI* pCmdUI)  
{ 
	pCmdUI->SetCheck( m_nMouseAct == MOUSE_ZOOM); 
} 
 
BOOL CChildView::SetThePixelFormat(CDC *pDC) 
{ 
    static PIXELFORMATDESCRIPTOR pfd = { 
		sizeof(PIXELFORMATDESCRIPTOR),	// size of this pfd 
		1,                              // version number 
		PFD_DRAW_TO_WINDOW |            // support window 
		PFD_SUPPORT_OPENGL |            // support OpenGL 
		PFD_DOUBLEBUFFER,               // double buffered 
		PFD_TYPE_RGBA,                  // RGBA type 
		24,                             // 24-bit color depth 
		0, 0, 0, 0, 0, 0,               // color bits ignored 
		0,                              // no alpha buffer 
		0,                              // shift bit ignored 
		0,                              // no accumulation buffer 
		0, 0, 0, 0,                     // accum bits ignored 
		32,                             // 32-bit z-buffer	 
		0,                              // no stencil buffer 
		0,                              // no auxiliary buffer 
		PFD_MAIN_PLANE,                 // main layer 
		0,                              // reserved 
		0, 0, 0                         // layer masks ignored 
    }; 
 
	int pixelformat; 
    if((pixelformat = ChoosePixelFormat(m_hDc, &pfd)) == 0) 
    { 
        MessageBox( "ChoosePixelFormat failed", "Error", MB_OK); 
        return FALSE; 
    } 
 
    if(SetPixelFormat(m_hDc, pixelformat, &pfd) == FALSE) 
    { 
        MessageBox( "SetPixelFormat failed", "Error", MB_OK); 
        return FALSE; 
    } 
 
    CreateRGBPalette(m_hDc); 
 
    return TRUE; 
} 
 
void CChildView::MouseSpinGlobal(UINT nFlags, int x, int y, int init) 
{ 
	// use mouse to play 3D trackball transformation 
	// see also Intel 3DR 
 
	float centerX, centerY; 
	float radius; 
	float w, h;  // window 
 
    RECT rect; 
    GetClientRect( &rect); 
    w =(float)rect.right; 
	h =(float)rect.bottom; 
    h = (h == 0.0f) ? 1.0f : h; 
 
    centerX = w / 2.0f; 
	centerY = h / 2.0f; 
	radius  = (w > h) ? centerY : centerX ; 
 
	if (init) 
	{ 
		 //	And call Trackball() with current center, radius  
		 // and current cursor position (in client coordinates)  
		 // to initialize trackball internal parameters. 
		 //	Note that we must stop animation at that time. 
 
		Trackball( 0, radius, centerX, centerY, (float)x, (float)(h-y),  
		           m_spinAxes[0], m_spinAxes[1], m_spinAxes[2], m_spinAngle); 
	} 
	else if ( nFlags & MK_LBUTTON ) 
	{ 
	    Trackball(1, radius, centerX, centerY, (float)x, (float)(h-y),  
			      m_spinAxes[0], m_spinAxes[1], m_spinAxes[2], m_spinAngle); 
		SpinGlobal(m_spinAxes, m_spinAngle); 
	} 
} 
 
void CChildView::SpinGlobal(float axes[], float angle) 
{ 
	EyeRotate(m_vProjectCenter, axes, angle, m_sEye ); 
	DrawScene();  
} 
 
void CChildView::MouseZoom(UINT nFlags, int x, int y) 
{ 
	float w, h; 
	float scale; 
	static float oldY, dy ; 
 
	RECT rect; 
	GetClientRect( &rect); 
	w =(float)rect.right; 
	h =(float)rect.bottom; 
	h = (h == 0.0f) ? 1.0f : h; 
 
	if( m_bLButtonDown && (nFlags & MK_LBUTTON)) 
	{ 
		dy=oldY-y; 
		scale=1.0f+dy/h; 
		Zoom(scale); 
		oldY=(float)y; 
	} 
	else 
	{ 
		oldY=(float)y; 
	} 
} 
 
void CChildView::Zoom(float scale) 
{ 
	if(scale<0.001) return; 
	m_fViewHeight/=scale; 
	Project(); 
	DrawScene(); 
} 
 
void CChildView::MouseTranslate(UINT nFlags, int x, int y) 
{ 
	float w, h; 
	static float oldX, oldY, dx, dy, d[3] ; 
 
	RECT rect; 
	GetClientRect( &rect); 
	w =(float)rect.right; 
	h =(float)rect.bottom; 
	h = (h == 0.0f) ? 1.0f : h; 
 
	if( m_bLButtonDown && (nFlags & MK_LBUTTON)) 
	{ 
		dx=x-oldX; 
		dy=oldY-y; 
		d[0]=m_fViewWidth*dx/w*0.8f; 
		d[1]=m_fViewHeight*dy/h*0.8f;            
		d[2]=0.0f; 
		Translate(d);    
		oldX=(float)x; 
		oldY=(float)y; 
	} 
	else 
	{ 
		oldX=(float)x; 
		oldY=(float)y; 
	} 
} 
 
void CChildView::Translate(float d[]) 
{ 
	EyeTranslate(d, m_sEye); 
	DrawScene(); 
} 
 
void CChildView::OnSpinXccw()  
{ 
	KillTimer(TIMER_ANIMATE); 
 
	glRotatef(ROTATE_RATE, 1.0f, 0.0f, 0.0f); 
	DrawScene(); 
} 
 
void CChildView::OnSpinXcw()  
{ 
	KillTimer(TIMER_ANIMATE); 
 
	MSG msg; 
	while(::PeekMessage( &msg, m_hWnd, 
			WM_TIMER, WM_TIMER, 
			PM_REMOVE)); 
 
	glRotatef(-ROTATE_RATE, 1.0f, 0.0f, 0.0f); 
	DrawScene(); 
} 
 
void CChildView::OnSpinYccw()  
{ 
	KillTimer(TIMER_ANIMATE); 
 
	MSG msg; 
	while(::PeekMessage( &msg, m_hWnd, 
			WM_TIMER, WM_TIMER, 
			PM_REMOVE)); 
 
	glRotatef(ROTATE_RATE, 0.0f, 1.0f, 0.0f); 
	DrawScene(); 
} 
 
void CChildView::OnSpinYcw()  
{ 
	KillTimer(TIMER_ANIMATE); 
 
	MSG msg; 
	while(::PeekMessage( &msg, m_hWnd, 
			WM_TIMER, WM_TIMER, 
			PM_REMOVE)); 
 
	glRotatef(-ROTATE_RATE, 0.0f, 1.0f, 0.0f); 
	DrawScene(); 
} 
 
void CChildView::OnSpinZccw()  
{ 
	KillTimer(TIMER_ANIMATE); 
 
	MSG msg; 
	while(::PeekMessage( &msg, m_hWnd, 
			WM_TIMER, WM_TIMER, 
			PM_REMOVE)); 
 
	glRotatef(ROTATE_RATE, 0.0f, 0.0f, 1.0f); 
	DrawScene(); 
} 
 
void CChildView::OnSpinZcw()  
{ 
	KillTimer(TIMER_ANIMATE); 
 
	MSG msg; 
	while(::PeekMessage( &msg, m_hWnd, 
			WM_TIMER, WM_TIMER, 
			PM_REMOVE)); 
 
	glRotatef(-ROTATE_RATE, 0.0f, 0.0f, 1.0f); 
	DrawScene(); 
} 
 
void CChildView::OnZoomIn()  
{ 
	KillTimer(TIMER_ANIMATE); 
 
	MSG msg; 
	while(::PeekMessage( &msg, m_hWnd, 
			WM_TIMER, WM_TIMER, 
			PM_REMOVE)); 
 
	Zoom(1.0f + ZOOM_RATE ); 
} 
 
void CChildView::OnZoomOut()  
{ 
	KillTimer(TIMER_ANIMATE); 
 
	MSG msg; 
	while(::PeekMessage( &msg, m_hWnd, 
			WM_TIMER, WM_TIMER, 
			PM_REMOVE)); 
 
	Zoom(1.0f - ZOOM_RATE ); 
} 
 
void CChildView::Init() 
{ 
	CDC *pDC = GetDC(); 
	m_hDc = pDC->GetSafeHdc(); 
	SetThePixelFormat(pDC); 
	m_hRc = wglCreateContext(m_hDc); 
	wglMakeCurrent(m_hDc,m_hRc); 
	ReleaseDC(pDC); 
 
	glEnable(GL_DEPTH_TEST); 
	glEnable(GL_LIGHTING); 
	glEnable(GL_LIGHT0); 
	glEnable(GL_AUTO_NORMAL); 
 
	glColor3f(1.0f, 1.0f, 0.0f); 
 
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1); 
 
	GLfloat light[] = {1.0f,1.0f,1.0f,1.0f}; 
	glLightfv(GL_LIGHT0,GL_DIFFUSE,light); 
 
	float ambient[4] = {0.2f, 0.2f, 0.0f, 1.0f}; 
	float diffuse[4] = {0.95f, 0.95f, 0.0f, 1.0f}; 
	float specular[4] = {0.0f, 0.0f, 0.1f, 1.0f}; 
	glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, ambient); 
	glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse); 
	glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR,specular); 
 
	SetTimer( TIMER_TOOLBAR, TOOLBAR_RATE, NULL); 
	if (m_bAnimate) 
		SetTimer( TIMER_ANIMATE, ANIMATE_RATE, NULL ); 
 
	CMainFrame *pFrameWnd = (CMainFrame*)AfxGetMainWnd(); 
 
	m_nsFaceNo = m_nFaceNo = 0; 
} 
 
void CChildView::DrawAxes() 
{ 
	glDisable(GL_LIGHTING); 
	glMatrixMode(GL_MODELVIEW); 
	glPushMatrix(); 
 
	glScalef(1.4f, 1.4f, 1.4f); 
 
	glBegin(GL_LINES);	 
	// x axis 
	glColor3f ( 1.0f, 0.0f, 0.0f); 
	glVertex3f( 0.0f, 0.0f, 0.0f); 
	glVertex3f( 1.0f, 0.0f, 0.0f); 
 
	// y axis 
	glColor3f ( 0.0f, 1.0f, 0.0f); 
	glVertex3f( 0.0f, 0.0f, 0.0f); 
	glVertex3f( 0.0f, 1.0f, 0.0f); 
 
	// z axis 
	glColor3f ( 0.0f, 0.0f, 1.0f); 
	glVertex3f( 0.0f, 0.0f, 0.0f); 
	glVertex3f( 0.0f, 0.0f, 1.0f); 
	glEnd(); 
 
	glBegin(GL_TRIANGLES);	 
 
	// x axis arrow 
	glColor3f ( 1.0f, 0.0f,  0.0f); 
	glVertex3f(1.0f,    0.0f,    0.0f); 
	glVertex3f(0.9f,    0.0f,    0.04f); 
	glVertex3f(0.9f,    0.028f,  0.028f); 
	glVertex3f(0.9f,    0.0f,    0.04f); 
	glVertex3f(0.9f,    0.028f,  0.028f); 
	glVertex3f(0.9f,    0.0f,    0.0f); 
	glVertex3f(1.0f,    0.0f,    0.0f); 
	glVertex3f(0.9f,    0.028f,  0.028f); 
	glVertex3f(0.9f,    0.04f,   0.0f); 
	glVertex3f(0.9f,    0.028f,  0.028f); 
	glVertex3f(0.9f,    0.04f,   0.0f); 
	glVertex3f(0.9f,    0.0f,    0.0f); 
	glVertex3f(1.0f,    0.0f,    0.0f); 
	glVertex3f(0.9f,    0.04f,   0.0f); 
	glVertex3f(0.9f,    0.028f,  -0.028f); 
	glVertex3f(0.9f,    0.04f,   0.0f); 
	glVertex3f(0.9f,    0.028f,  -0.028f); 
	glVertex3f(0.9f,    0.0f,    0.0f); 
	glVertex3f(1.0f,    0.0f,    0.0f); 
	glVertex3f(0.9f,    0.028f,  -0.028f); 
	glVertex3f(0.9f,    0.0f,    -0.04f); 
	glVertex3f(0.9f,    0.028f,  -0.028f); 
	glVertex3f(0.9f,    0.0f,    -0.04f); 
	glVertex3f(0.9f,    0.0f,    0.0f); 
	glVertex3f(1.0f,    0.0f,    0.0f); 
	glVertex3f(0.9f,    0.0f,    -0.04f); 
	glVertex3f(0.9f,    -0.028f, -0.028f); 
	glVertex3f(0.9f,    0.0f,    -0.04f); 
	glVertex3f(0.9f,    -0.028f, -0.028f); 
	glVertex3f(0.9f,    0.0f,    0.0f); 
	glVertex3f(1.0f,    0.0f,    0.0f); 
	glVertex3f(0.9f,    -0.028f, -0.028f); 
	glVertex3f(0.9f,    -0.04f,  0.0f); 
	glVertex3f(0.9f,    -0.028f, -0.028f); 
	glVertex3f(0.9f,    -0.04f,  0.0f); 
	glVertex3f(0.9f,    0.0f,    0.0f); 
	glVertex3f(1.0f,    0.0f,    0.0f); 
	glVertex3f(0.9f,    -0.04f,  0.0f); 
	glVertex3f(0.9f,    -0.028f, 0.028f); 
	glVertex3f(0.9f,    -0.04f,  0.0f); 
	glVertex3f(0.9f,    -0.028f, 0.028f); 
	glVertex3f(0.9f,    0.0f,    0.0f); 
	glVertex3f(1.0f,    0.0f,    0.0f); 
	glVertex3f(0.9f,    -0.028f, 0.028f); 
	glVertex3f(0.9f,    0.0f,    0.04f); 
	glVertex3f(0.9f,    -0.028f, 0.028f); 
	glVertex3f(0.9f,    0.0f,    0.04f); 
	glVertex3f(0.9f,    0.0f,    0.0f); 
 
	// y axis arrow 
	glColor3f ( 0.0f, 1.0f, 0.0f); 
	glVertex3f(0.0f,    1.0f,    0.0f); 
	glVertex3f(0.0f,    0.9f,    0.04f); 
	glVertex3f(0.028f,  0.9f,    0.028f); 
	glVertex3f(0.0f,    0.9f,    0.04f); 
	glVertex3f(0.028f,  0.9f,    0.028f); 
	glVertex3f(0.0f,    0.9f,    0.0f); 
	glVertex3f(0.0f,    1.0f,    0.0f); 
	glVertex3f(0.028f,  0.9f,    0.028f); 
	glVertex3f(0.04f,   0.9f,    0.0f); 
	glVertex3f(0.028f,  0.9f,    0.028f); 
	glVertex3f(0.04f,   0.9f,    0.0f); 
	glVertex3f(0.0f,    0.9f,    0.0f); 
	glVertex3f(0.0f,    1.0f,    0.0f); 
	glVertex3f(0.04f,   0.9f,    0.0f); 
	glVertex3f(0.028f,  0.9f,    -0.028f); 
	glVertex3f(0.04f,   0.9f,    0.0f); 
	glVertex3f(0.028f,  0.9f,    -0.028f); 
	glVertex3f(0.0f,    0.9f,    0.0f); 
	glVertex3f(0.0f,    1.0f,    0.0f); 
	glVertex3f(0.028f,  0.9f,    -0.028f); 
	glVertex3f(0.0f,    0.9f,    -0.04f); 
	glVertex3f(0.028f,  0.9f,    -0.028f); 
	glVertex3f(0.0f,    0.9f,    -0.04f); 
	glVertex3f(0.0f,    0.9f,    0.0f); 
	glVertex3f(0.0f,    1.0f,    0.0f); 
	glVertex3f(0.0f,    0.9f,    -0.04f); 
	glVertex3f(-0.028f, 0.9f,    -0.028f); 
	glVertex3f(0.0f,    0.9f,    -0.04f); 
	glVertex3f(-0.028f, 0.9f,    -0.028f); 
	glVertex3f(0.0f,    0.9f,    0.0f); 
	glVertex3f(0.0f,    1.0f,    0.0f); 
	glVertex3f(-0.028f, 0.9f,    -0.028f); 
	glVertex3f(-0.04f,  0.9f,    0.0f); 
	glVertex3f(-0.028f, 0.9f,    -0.028f); 
	glVertex3f(-0.04f,  0.9f,    0.0f); 
	glVertex3f(0.0f,    0.9f,    0.0f); 
	glVertex3f(0.0f,    1.0f,    0.0f); 
	glVertex3f(-0.04f,  0.9f,    0.0f); 
	glVertex3f(-0.028f, 0.9f,    0.028f); 
	glVertex3f(-0.04f,  0.9f,    0.0f); 
	glVertex3f(-0.028f, 0.9f,    0.028f); 
	glVertex3f(0.0f,    0.9f,    0.0f); 
	glVertex3f(0.0f,    1.0f,    0.0f); 
	glVertex3f(-0.028f, 0.9f,    0.028f); 
	glVertex3f(0.0f,    0.9f,    0.04f); 
	glVertex3f(-0.028f, 0.9f,    0.028f); 
	glVertex3f(0.0f,    0.9f,    0.04f); 
	glVertex3f(0.0f,    0.9f,    0.0f); 
 
	// z axis arrow 
	glColor3f ( 0.0f, 0.0f, 1.0f); 
	glVertex3f(0.0f,    0.0f,    1.0f); 
	glVertex3f(0.0f,    0.04f,   0.9f); 
	glVertex3f(0.028f,  0.028f,  0.9f); 
	glVertex3f(0.0f,    0.04f,   0.9f); 
	glVertex3f(0.028f,  0.028f,  0.9f); 
	glVertex3f(0.0f,    0.0f,    0.9f); 
	glVertex3f(0.0f,    0.0f,    1.0f); 
	glVertex3f(0.028f,  0.028f,  0.9f); 
	glVertex3f(0.04f,   0.0f,    0.9f); 
	glVertex3f(0.028f,  0.028f,  0.9f); 
	glVertex3f(0.04f,   0.0f,    0.9f); 
	glVertex3f(0.0f,    0.0f,    0.9f); 
	glVertex3f(0.0f,    0.0f,    1.0f); 
	glVertex3f(0.04f,   0.0f,    0.9f); 
	glVertex3f(0.028f,  -0.028f, 0.9f); 
	glVertex3f(0.04f,   0.0f,    0.9f); 
	glVertex3f(0.028f,  -0.028f, 0.9f); 
	glVertex3f(0.0f,    0.0f,    0.9f); 
	glVertex3f(0.0f,    0.0f,    1.0f); 
	glVertex3f(0.028f,  -0.028f, 0.9f); 
	glVertex3f(0.0f,    -0.04f,  0.9f); 
	glVertex3f(0.028f,  -0.028f, 0.9f); 
	glVertex3f(0.0f,    -0.04f,  0.9f); 
	glVertex3f(0.0f,    0.0f,    0.9f); 
	glVertex3f(0.0f,    0.0f,    1.0f); 
	glVertex3f(0.0f,    -0.04f,  0.9f); 
	glVertex3f(-0.028f, -0.028f, 0.9f); 
	glVertex3f(0.0f,    -0.04f,  0.9f); 
	glVertex3f(-0.028f, -0.028f, 0.9f); 
	glVertex3f(0.0f,    0.0f,    0.9f); 
	glVertex3f(0.0f,    0.0f,    1.0f); 
	glVertex3f(-0.028f, -0.028f, 0.9f); 
	glVertex3f(-0.04f,  0.0f,    0.9f); 
	glVertex3f(-0.028f, -0.028f, 0.9f); 
	glVertex3f(-0.04f,  0.0f,    0.9f); 
	glVertex3f(0.0f,    0.0f,    0.9f); 
	glVertex3f(0.0f,    0.0f,    1.0f); 
	glVertex3f(-0.04f,  0.0f,    0.9f); 
	glVertex3f(-0.028f, 0.028f,  0.9f); 
	glVertex3f(-0.04f,  0.0f,    0.9f); 
	glVertex3f(-0.028f, 0.028f,  0.9f); 
	glVertex3f(0.0f,    0.0f,    0.9f); 
	glVertex3f(0.0f,    0.0f,    1.0f); 
	glVertex3f(-0.028f, 0.028f,  0.9f); 
	glVertex3f(0.0f,    0.04f,   0.9f); 
	glVertex3f(-0.028f, 0.028f,  0.9f); 
	glVertex3f(0.0f,    0.04f,   0.9f); 
	glVertex3f(0.0f,    0.0f,    0.9f); 
 
	glEnd(); 
	glPopMatrix(); 
	glEnable(GL_LIGHTING); 
	glColor3f ( 1.0f, 1.0f, 0.0f); 
} 
 
void CChildView::SetupBmpHeader(BITMAPINFOHEADER *pbmih, int sx, int sy, int bpp) 
{ 
	pbmih->biSize = sizeof(BITMAPINFOHEADER); 
	pbmih->biWidth = sx; 
	pbmih->biHeight = sy; 
	pbmih->biPlanes = 1; 
	pbmih->biBitCount = bpp; 
	pbmih->biCompression = BI_RGB; 
	pbmih->biSizeImage = sx * sy * (bpp/8); 
	pbmih->biXPelsPerMeter = 2925; 
	pbmih->biYPelsPerMeter = 2925; 
	pbmih->biClrUsed = 0; 
	pbmih->biClrImportant = 0; 
} 
 
BOOL CChildView::SaveAsBMP(char *bmpFileName) 
{ 
	GLubyte  *lpBits; 
	RECT  rect; 
 
	GetClientRect(&rect); 
 
	CDC *pDC = GetDC(); 
	ASSERT(pDC->m_hDC); 
 
	// Creating Compatible Memory Device Context 
	CDC *pMemDC = new CDC; 
	if (!pMemDC->CreateCompatibleDC(pDC)) 
	{ 
		MessageBox("CompatibleDC Error"); 
		return 0; 
	} 
 
	// Preparing bitmap header for DIB section 
	BITMAPINFO bi; 
	int bpp, sx, sy; 
	ZeroMemory(&bi, sizeof(BITMAPINFO)); 
	// Making a DIB image which is half size of GL window and full color(24 bpp) 
	sx = (rect.right-rect.left) ; 
	sy = (rect.bottom-rect.top) ; 
	sx=sx-sx % 4;  // BMP 要求扫描线为 4 的倍数 
    bpp = 24; 
 
	long dwSizeImage = sx * sy * bpp / 8; // 8 means 8 bit/byte 
    SetupBmpHeader(&(bi.bmiHeader), sx, sy, bpp); 
 
	// Creating a DIB surface 
	HBITMAP hBm, hBmOld; 
    hBm = CreateDIBSection(pDC->GetSafeHdc(), &bi, DIB_RGB_COLORS,  
			       			(void **)&lpBits, NULL, (DWORD)0); 
	if (!hBm) 
	{ 
		MessageBox("CreateDIBSection Error"); 
		return 0; 
	} 
 
    // Selecting the DIB Surface 
	hBmOld = (HBITMAP)::SelectObject(pMemDC->GetSafeHdc(), hBm); 
	if (!hBmOld) 
	{ 
		MessageBox("Select Object Error"); 
		return 0; 
	} 
     
 
	glReadBuffer(GL_BACK); 
	glReadPixels(rect.left,rect.top,sx,//rect.right-rect.left, 
		rect.bottom-rect.top,GL_BGR_EXT,GL_UNSIGNED_BYTE,lpBits); 
 
	// Preparing BMP file header information 
 
	BITMAPFILEHEADER bmfh; 
	bmfh.bfType = 0x4d42;  // 'BM' 
	long nSize =  sizeof(BITMAPINFOHEADER) +  dwSizeImage; 
	bmfh.bfSize = nSize + sizeof(BITMAPFILEHEADER); 
	bmfh.bfReserved1 = bmfh.bfReserved2 = 0; 
	bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);	 
 
    CFile *pbmpFile; 
    CFileException fileException; 
 
    pbmpFile = new CFile; 
    if (!pbmpFile->Open(bmpFileName ,  
		  CFile::modeCreate | CFile::modeWrite ) ) 
    { 
		TRACE( "Unable to open file: %s\n, error = %u\n", 
        "" ,fileException.m_cause); 
    } 
 
	// Wrinting the DIB image 
	TRY  
	{ 
		pbmpFile->Write(&bmfh, sizeof(BITMAPFILEHEADER)); 
		pbmpFile->Write(&(bi.bmiHeader), sizeof(BITMAPINFOHEADER)); 
		pbmpFile->Write(lpBits,dwSizeImage); 
		pbmpFile->Flush(); 
	} 
	CATCH (CException, e)  
	{ 
		AfxMessageBox("write error"); 
		return 0; 
	} 
	END_CATCH 
 
	// Cleaning 
    pbmpFile->Close(); 
	delete pbmpFile; 
 
	hBm = (HBITMAP)::SelectObject(pMemDC->GetSafeHdc(), hBmOld); 
	DeleteObject(hBm); 
 
	delete pMemDC; 
	ReleaseDC(pDC); 
 
	return 1; 
} 
 
void CChildView::Project() 
{ 
	RECT	rect; 
 
	GetClientRect( &rect); 
	GLsizei nWidth = rect.right; 
	GLsizei nHeight = rect.bottom; 
	nHeight = (nHeight == 0) ? 1 : nHeight; 
	float dAspect = (float)nWidth/(float)nHeight; 
	m_fViewWidth = m_fViewHeight * dAspect; 
 
	glMatrixMode(GL_PROJECTION); 
	glLoadIdentity(); 
	glOrtho(-m_fViewWidth,m_fViewWidth,-m_fViewHeight,m_fViewHeight,m_fViewNear,m_fViewFar); 
	glViewport(0,0,nWidth,nHeight); 
	glMatrixMode(GL_MODELVIEW);	 
} 
 
void CChildView::DrawScene() 
{ 
	int nTriangles = 0; 
 
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
 
	glMatrixMode(GL_MODELVIEW); 
	glPushMatrix(); 
 
	if (m_pModel) 
		m_pModel->DrawModel(m_nRenderMode, m_nRenderModel); 
 
	if (m_bAxes) 
		DrawAxes(); 
 
	glMatrixMode(GL_MODELVIEW); 
	glPopMatrix(); 
 
	glFlush(); 
	SwapBuffers(m_hDc); 
}