///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004 Intel Corporation 
// All rights reserved. 
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met: 
//
// * Redistributions of source code must retain the above copyright notice, 
// this list of conditions and the following disclaimer. 
// * Redistributions in binary form must reproduce the above copyright notice, 
// this list of conditions and the following disclaimer in the documentation 
// and/or other materials provided with the distribution. 
// * Neither name of Intel Corporation nor the names of its contributors 
// may be used to endorse or promote products derived from this software 
// without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////

// testView.cpp : implementation of the CTestView class
//

#include "stdafx.h"

#include <GL/gl.h>
#include <GL/glu.h>
#include <ipp.h>

#include "ObjectViewer.h"

#include "ObjectViewerDoc.h"
#include "ObjectViewerView.h"

#include "Viewer2.h"
#include "3ds.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CTestView

IMPLEMENT_DYNCREATE(CTestView, CView)

BEGIN_MESSAGE_MAP(CTestView, CView)
	//{{AFX_MSG_MAP(CTestView)
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEWHEEL()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
	ON_COMMAND(ID_SHOW_MODEL_MATRIX, OnShowModelMatrix)
	ON_COMMAND(ID_SHOW_VIEW_MATRIX, OnShowViewMatrix)
	ON_UPDATE_COMMAND_UI(ID_SHOW_MODEL_MATRIX, OnUpdateShowModelMatrix)
	ON_COMMAND(ID_PROJECT_PLANE, OnProjectPlane)
	ON_COMMAND(ID_OBJECT_DUPLICATE, OnObjectDuplicate)
	ON_COMMAND(ID_SHOW_NORMALS, OnShowNormals)
	ON_UPDATE_COMMAND_UI(ID_SHOW_NORMALS, OnUpdateShowNormals)
	ON_UPDATE_COMMAND_UI(ID_OBJECT_DUPLICATE, OnUpdateObjectDuplicate)
	ON_COMMAND(ID_SHOW_RAYTRACE, OnShowRaytrace)
	ON_UPDATE_COMMAND_UI(ID_SHOW_RAYTRACE, OnUpdateShowRaytrace)
	ON_COMMAND(ID_SHOW_NORMALS_2, OnShowNormals2)
	ON_UPDATE_COMMAND_UI(ID_SHOW_NORMALS_2, OnUpdateShowNormals2)
	ON_COMMAND(ID_TOGGLE_FILL, OnToggleFill)
	ON_UPDATE_COMMAND_UI(ID_TOGGLE_FILL, OnUpdateToggleFill)
	ON_COMMAND(ID_SHOW_SIDE_NORMALS, OnShowSideNormals)
	ON_UPDATE_COMMAND_UI(ID_SHOW_SIDE_NORMALS, OnUpdateShowSideNormals)
	ON_COMMAND(ID_MUTATE_MODEL, OnMutateModel)
	ON_UPDATE_COMMAND_UI(ID_MUTATE_MODEL, OnUpdateMutateModel)
	ON_COMMAND(ID_SHOW_CENTER_OF_MASS, OnShowCenterOfMass)
	ON_UPDATE_COMMAND_UI(ID_SHOW_CENTER_OF_MASS, OnUpdateShowCenterOfMass)
	ON_UPDATE_COMMAND_UI(ID_PROJECT_PLANE, OnUpdateProjectPlane)
	ON_UPDATE_COMMAND_UI(ID_TOOL_GRAB, OnUpdateToolGrab)
	ON_COMMAND(ID_TOOL_GRAB, OnToolGrab)
	ON_COMMAND(ID_TOOL_ARROW, OnToolArrow)
	ON_UPDATE_COMMAND_UI(ID_TOOL_ARROW, OnUpdateToolArrow)
	ON_COMMAND(ID_SHOW_INTERSECT, OnShowIntersect)
	ON_UPDATE_COMMAND_UI(ID_SHOW_INTERSECT, OnUpdateShowIntersect)
	ON_COMMAND(ID_USE_VERTEX_NORMALS, OnUseVertexNormals)
	ON_UPDATE_COMMAND_UI(ID_USE_VERTEX_NORMALS, OnUpdateUseVertexNormals)
	ON_UPDATE_COMMAND_UI(ID_USE_TRIANGLE_NORMALS, OnUpdateUseTriangleNormals)
	ON_COMMAND(ID_USE_TRIANGLE_NORMALS, OnUseTriangleNormals)
	ON_COMMAND(ID_SHOW_TIME_CALCPLANES, OnShowTimeCalcplanes)
	ON_UPDATE_COMMAND_UI(ID_SHOW_TIME_CALCPLANES, OnUpdateShowTimeCalcplanes)
	ON_UPDATE_COMMAND_UI(ID_SHOW_VIEW_MATRIX, OnUpdateShowViewMatrix)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTestView construction/destruction

CTestView::CTestView()
{
	// TODO: add construction code here
	m_prevMousePos_.x = -1;
	m_prevMousePos_.y = -1;
	m_showDuplicate_ = 0;
	m_showNormals_ = 0;
	m_showSideNormals_ = 0;
	m_showNormals2_ = 0;
	m_showModelMatrix_ = 0;
	m_showViewMatrix_ = 0;
	m_showRayTrace_ = 0;
	m_showFill_ = 1;
	m_pMask_ = 0;
	m_pMask2_ = 0;
	m_showCenterOfMass_ = 0;
	m_projectPlane_ = 0;
	m_showIntersect_ = 0;
	m_intersectInvalid_ = 0;

	m_showTimeCalcplanes_ = 0;
	m_normalsToUse_ = VERTEX_NORMALS;
	m_toolType_ = TOOL_ARROW;

//	m_wndToolBar.LoadToolBar(IDR_TIMERS);
//	if (!m_timerBar_.CreateEx(GetParentFrame(),
//		TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
//		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
//		!m_timerBar_.LoadToolBar(IDR_TIMERS))
//	{
//		TRACE0("Failed to create toolbar\n");
//	}
//	CMainFramethis->GetTopLevelFrame()->m_wndToolBar.
}

CTestView::~CTestView()
{
	wglMakeCurrent(NULL, NULL);
	wglDeleteContext(m_hglrc_);
	if (m_pMask_) { delete m_pMask_; m_pMask_ = 0;}
	if (m_pMask2_) { delete m_pMask2_; m_pMask2_ = 0;}
}

BOOL CTestView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CTestView drawing

void CTestView::OnDraw(CDC* pDC)
{
	Draw(pDC);
}

void CTestView::Draw(CDC*pDC)
{
	if (!pDC) pDC = this->GetDC();
	CTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	Ipp64u startTime, time1, time2;
	int pTime[10];
	CRect rect;
//	Mask3DS mask;
//	mask.CopySettings(*pDoc->m_pData);
	float pRayStart[4], pRayDir[4];
	
	GetClientRect(rect);
	m_render3DS_.Reshape(rect);
	m_render3DS_.SetFill(m_showFill_);
//	m_render3DS_.SetLight1Color(1.0f,1.0f,1.0f);
//	m_render3DS_.SetLight2Color(1.0f,1.0f,1.0f);
	if (m_normalsToUse_ == VERTEX_NORMALS)
		m_render3DS_.UseVertexNormals();
	else
		m_render3DS_.UseTriangleNormals();
	m_render3DS_.DisplayInit();
	if (pDoc->m_pData)
		if (m_showIntersect_ && pDoc->m_pData2)
		{
			if (!m_pMask_)
				m_pMask_ = new char[pDoc->m_pData->m_numTriangles];
			if (!m_pMask2_)
				m_pMask2_ = new char[pDoc->m_pData2->m_numTriangles];
//			GetCurrentRay(pRayStart, pRayDir);
//			startTime = ippCoreGetCpuClocks();
			if (m_intersectInvalid_)
			{
				m_intersectInvalid_ = 0;
				ippsZero_8u((Ipp8u*)m_pMask_, pDoc->m_pData->m_numTriangles);
				ippsZero_8u((Ipp8u*)m_pMask2_, pDoc->m_pData2->m_numTriangles);
				pDoc->m_pData->IntersectObject(*pDoc->m_pData2,
					(Ipp8u*)m_pMask_, (Ipp8u*)m_pMask2_);
			}
//			time1 = ippCoreGetCpuClocks() - startTime;
//			startTime = ippCoreGetCpuClocks();
//			pDoc->m_pData->IntersectRay(pRayStart, pRayDir, (unsigned char*)m_pMask_,1);
//			time2 = ippCoreGetCpuClocks() - startTime;
//			float pLine[8];
//			for (int i=0; i<4; i++) pLine[i] = pRayStart[i];
//			for (i=0; i<4; i++) pLine[i+4] = pRayDir[i];
//			m_render3DS_.DrawLine(pLine);

			m_render3DS_.Display(*pDoc->m_pData, m_pMask_);
			m_render3DS_.Display(*pDoc->m_pData2, m_pMask2_);
		}
		else if (m_showRayTrace_)
		{
			if (!m_pMask_)
				m_pMask_ = new char[pDoc->m_pData->m_numTriangles];
			GetCurrentRay(pRayStart, pRayDir);
			startTime = ippCoreGetCpuClocks();
			ippsZero_8u((Ipp8u*)m_pMask_, pDoc->m_pData->m_numTriangles);
			pDoc->m_pData->IntersectRay(pRayStart, pRayDir, (unsigned char*)m_pMask_);
			time1 = ippCoreGetCpuClocks() - startTime;
			startTime = ippCoreGetCpuClocks();
			pDoc->m_pData->IntersectRay(pRayStart, pRayDir, (unsigned char*)m_pMask_,1);
			time2 = ippCoreGetCpuClocks() - startTime;
//			float pLine[8];
//			for (int i=0; i<4; i++) pLine[i] = pRayStart[i];
//			for (i=0; i<4; i++) pLine[i+4] = pRayDir[i];
//			m_render3DS_.DrawLine(pLine);

			m_render3DS_.Display(*pDoc->m_pData, m_pMask_);
			if (pDoc->m_pData2 && m_showDuplicate_)
				m_render3DS_.Display(*pDoc->m_pData2);
		}
		else
		{
			m_render3DS_.Display(*pDoc->m_pData);
			if (pDoc->m_pData2 && m_showDuplicate_)
				m_render3DS_.Display(*pDoc->m_pData2);
		}
	if (m_showNormals_)
		m_render3DS_.DisplayNormals(*pDoc->m_pData, 1.0, 0.0, 0.0);
	if (m_showNormals2_)
		m_render3DS_.DisplayTriangleNormals(*pDoc->m_pData, Render3DS::PLANE,
			1.0, 0.0, 0.0);
	if (m_showSideNormals_)
	{
		m_render3DS_.DisplayTriangleNormals(*pDoc->m_pData, Render3DS::SIDE1,
			1.0, 0.0, 0.0);
		m_render3DS_.DisplayTriangleNormals(*pDoc->m_pData, Render3DS::SIDE2,
			1.0, 0.0, 0.0);
		m_render3DS_.DisplayTriangleNormals(*pDoc->m_pData, Render3DS::SIDE3,
			1.0, 0.0, 0.0);
	}
	if (m_showCenterOfMass_)
	{
		float pTriangle[12] = {
			m_pCenterOfMass_[0], m_pCenterOfMass_[1],
			m_pCenterOfMass_[2], 1.0f,
			m_pCenterOfMass_[0], m_pCenterOfMass_[1]+0.1f,
			m_pCenterOfMass_[2]+0.05f, 1.0f, 
			m_pCenterOfMass_[0], m_pCenterOfMass_[1]+0.05f,
			m_pCenterOfMass_[2]+0.1f, 1.0f
		};

		m_render3DS_.DrawTriangle(pTriangle);

	}

//	float pMatrix[16], pMatrixInv[16];

	GetClientRect(rect);
//	float x = m_currMousePos_.x, y = m_currMousePos_.y;
//	float pTriangle[12] = { x, y, 0.5, 1.0, 
//		x+0.1, y, 0.5, 1.0, x, y+0.1, 0.5, 1.0 };

//	float x,y,z;
//	if (m_showRayTrace_)
//	{
//		float left, right, top, bottom;
//		m_render3DS_.GetBounds(rect, &left, &right, &top, &bottom);
//		x = ((float)m_currMousePos_.x-(float)rect.Width()/2.0) /
//			(float)rect.Width()*(right-left);
//		y = ((float)m_currMousePos_.y-(float)rect.Height()/2.0) / 
//			(float)rect.Height()*(bottom-top);
//		z = m_render3DS_.GetZMax()-0.01;
//		float pTriangle[12] = {
//			x, y, z, 1.0, 
//			x+0.5, y-0.2, z, 1.0,
//			x+0.2, y-0.5, z, 1.0 };
//			x, y, 0.0, z,
//			x, y+0.5, 0.0, z };
//		ippmInvert_m_32f_4x4(
//			m_render3DS_.ModelViewMatrix, 4*4,
//			pMatrixInv, 4*4);
//		ippmMul_mTva_32f_4x4(pMatrixInv, 4*4,
//			pTriangle, 4*4, pTriangle, 4*4, 3);
//		m_render3DS_.DrawTriangle(pTriangle);
//		m_render3DS_.DrawLine(pTriangle);
//	}

	m_render3DS_.DisplayDone();
	SwapBuffers(pDC->m_hDC);

	if (m_showModelMatrix_ || m_showViewMatrix_)
	{
		float pMatrix[16];
		glGetFloatv(GL_MODELVIEW_MATRIX, pMatrix);
		CString matString;
		for (int i=0; i<4; i++)
			matString.Format("%5.2f, %5.2f, %5.2f, %5.2f\n" 
				"%5.2f, %5.2f, %5.2f, %5.2f\n" 
				"%5.2f, %5.2f, %5.2f, %5.2f\n" 
				"%5.2f, %5.2f, %5.2f, %5.2f\n", 
				pMatrix[0], pMatrix[4], pMatrix[8], pMatrix[12],
				pMatrix[1], pMatrix[5], pMatrix[9], pMatrix[13],
				pMatrix[2], pMatrix[6], pMatrix[10], pMatrix[14],
				pMatrix[3], pMatrix[7], pMatrix[11], pMatrix[15]);
		pDC->DrawText(matString, &rect, DT_RIGHT|DT_BOTTOM);
	}
	else if (m_showRayTrace_)
	{
		GetClientRect(rect);
		CString str;
		str.Format("Time - Algorithm 1: %d, Algorithm 2: %d",
			(int)time1, (int)time2);
		pDC->DrawText(str, &rect, DT_RIGHT|DT_BOTTOM);
	}
	else if (m_showCenterOfMass_)
	{
		GetClientRect(rect);
		CString str;
		str.Format("Time - Algorithm 0: %d\nAlgorithm 1: %d\n"
			"Algorithm 2: %d\nAlgorithm 3: %d",
			(int)m_time_[0], (int)m_time_[1],
			(int)m_time_[2], (int)m_time_[3]);
			
		pDC->DrawText(str, &rect, DT_RIGHT|DT_BOTTOM);

//		str.Format("x = %d, y= %d\nx = %5.2f, y = %5.2f, z = %5.2f\n",
//			m_currMousePos_.x, m_currMousePos_.y, x, y,z);
//		int vp[4];
//		glGetIntegerv(GL_VIEWPORT, vp);
//		str.Format("x = %d, y= %d\nx = %5.2f, y = %5.2f, z = %5.2f\n",
//			m_currMousePos_.x, m_currMousePos_.y, x, y,z);
//		pDC->DrawText(str, &rect, DT_RIGHT|DT_BOTTOM);
	}
	else if (m_showTimeCalcplanes_)
	{
		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcPlanes(0);
		pTime[0] = ippCoreGetCpuClocks() - startTime;

		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcPlanes(1);
		pTime[1] = ippCoreGetCpuClocks() - startTime;

		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcPlanes(2);
		pTime[2] = ippCoreGetCpuClocks() - startTime;

		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcPlanes(3);
		pTime[3] = ippCoreGetCpuClocks() - startTime;

		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcPlanes(30);
		pTime[4] = ippCoreGetCpuClocks() - startTime;

		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcPlanes(4);
		pTime[5] = ippCoreGetCpuClocks() - startTime;

		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcPlanes(40);
		pTime[6] = ippCoreGetCpuClocks() - startTime;

		GetClientRect(rect);
		CString str;
		str.Format("CalcPlanes time - Algorithm 0: %d\n"
			"Algorithm 1: %d\n"
			"Algorithm 2: %d\nAlgorithm 3: %d\nAlgorithm 30: %d\n"
			"Algorithm 4: %d\nAlgorithm 40: %d\n",
			pTime[0], pTime[1], pTime[2], pTime[3], pTime[4],
			pTime[5], pTime[6] );
//			(int)time1, (int)time2, (int)time3, (int)time4);
		pDC->DrawText(str, &rect, DT_RIGHT|DT_BOTTOM);

//		pDoc->m_pData->CalcPlanes();
	}
}

void CTestView::GetCurrentRay(float* pStart, float* pDir)
{
	float pMatrixInv[16];

	ippmInvert_m_32f_4x4(
		m_render3DS_.ModelViewMatrix, 4*4,
		pMatrixInv, 4*4);

	CRect rect;
	GetClientRect(rect);
	float left, right, top, bottom;
	m_render3DS_.GetBounds(rect, &left, &right, &top, &bottom);
	float x = ((float)m_currMousePos_.x-(float)rect.Width()/2.0f) /
		(float)rect.Width()*(right-left);
	float y = ((float)m_currMousePos_.y-(float)rect.Height()/2.0f) / 
		(float)rect.Height()*(bottom-top);
	float z = m_render3DS_.GetZMax()-0.01f;
	float pEnd[4], pScreenStart[4] = {x, y, 1.0f, 1.0f}, 
		pScreenEnd[4] = {x, y, -1.0f, 1.0f};
	ippmMul_mTv_32f_4x4(pMatrixInv,	4*4, pScreenStart, pStart);
	ippmMul_mTv_32f_4x4(pMatrixInv, 4*4, pScreenEnd, pEnd);
	ippmSub_vv_32f_4x1(pEnd, pStart, pDir);
}

/*
void CTestView::GetCurrentRay(float* pScreen, float* pView)
{
	float pMatrixInv[16];

	ippmInvert_m_32f_4x4(
		m_render3DS_.ModelViewMatrix, 4*4,
		pMatrixInv, 4*4);

	ippmMul_mTv_32f_4x4(pMatrixInv,	4*4, pScreenStart, pStart);
}
*/

/////////////////////////////////////////////////////////////////////////////
// CTestView printing

BOOL CTestView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CTestView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CTestView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CTestView diagnostics

#ifdef _DEBUG
void CTestView::AssertValid() const
{
	CView::AssertValid();
}

void CTestView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CTestDoc* CTestView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTestDoc)));
	return (CTestDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CTestView message handlers

void CTestView::OnInitialUpdate() 
{
	CView::OnInitialUpdate();
	
	// TODO: Add your specialized code here and/or call the base class

	HDC hDC = this->GetDC()->m_hDC;

	PIXELFORMATDESCRIPTOR pfd = { 
    sizeof(PIXELFORMATDESCRIPTOR),   // size of this pfd 
    1,                     // version number 
    PFD_DRAW_TO_WINDOW |   // support window 
//    PFD_SUPPORT_OPENGL,   // support OpenGL 
    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  iPixelFormat; 
 
	// get the best available match of pixel format for the device context  
	iPixelFormat = ChoosePixelFormat(hDC, &pfd); 
 
	// make that the pixel format of the device context 
	SetPixelFormat(hDC, iPixelFormat, &pfd); 

	m_hglrc_ = wglCreateContext(hDC);
	wglMakeCurrent(hDC, m_hglrc_);
}

void CTestView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) 
{
	// TODO: Add your specialized code here and/or call the base class
	CView::OnPrepareDC(pDC, pInfo);
}

void CTestView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	m_prevMousePos_ = point;
	
	CView::OnLButtonDown(nFlags, point);
}

void CTestView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	CView::OnLButtonUp(nFlags, point);
}

void CTestView::OnMouseMove(UINT nFlags, CPoint point) 
{
	m_currMousePos_ = point;
	if (m_toolType_ == TOOL_ARROW)
	{
		if (nFlags & (MK_LBUTTON | MK_RBUTTON))
	{
		CTestDoc* pDoc = GetDocument();
		ASSERT_VALID(pDoc);
		if (nFlags & MK_LBUTTON)
		{
	 
			RECT rect;
			this->GetClientRect(&rect);

			CRect crect(rect);
			m_render3DS_.Rotate(
				point.x, point.y, m_prevMousePos_.x, m_prevMousePos_.y, crect);
			m_prevMousePos_ = point;
			Invalidate(false);
//			Draw(0);
		}
		else if (nFlags & MK_RBUTTON)
		{
	 
			RECT rect;
			this->GetClientRect(&rect);

			CRect crect(rect);
			m_render3DS_.Translate(
				point.x, point.y, m_prevMousePos_.x, m_prevMousePos_.y, crect);
			m_prevMousePos_ = point;
			Invalidate(false);
//			Draw(0);
		}
	}
	}
	else if ((m_toolType_ == TOOL_GRAB) && 
		(nFlags & MK_LBUTTON))
	{
		CTestDoc* pDoc = GetDocument();
		ASSERT_VALID(pDoc);

		m_intersectInvalid_ = 1;
//		Ipp32f pTranslate[] = {
//			1.0f, 0.0f, 0.0f, 0.0f,
//			0.0f, 1.0f, 0.0f, 0.0f,
//			0.0f, 0.0f, 1.0f, 0.0f,
//			point.x-m_prevMousePos_.x,
//			point.y-m_prevMousePos_.y,
		CRect rect;
		GetClientRect(rect);
		float left, right, top, bottom;
		m_render3DS_.GetBounds(rect, &left, &right, &top, &bottom);
		float x = ((float)point.x - (float)m_prevMousePos_.x)/
			(float)rect.Width()*(right-left);
//		(float)point.x-(float)m_prevMousePos_.x,
		float y = ((float)point.y - (float)m_prevMousePos_.y)/
			(float)rect.Height()*(bottom-top);
//		(float)point.y-(float)m_prevMousePos_.y
		float pShift[4] = { x, y, 0.0f, 0.0f};
		float pModelShift[4];
		float pMatrixInv[16];

		ippmInvert_m_32f_4x4(
			m_render3DS_.ModelViewMatrix, 4*4,
			pMatrixInv, 4*4);

		ippmMul_mTv_32f_4x4(pMatrixInv,	4*4, pShift, pModelShift);

		ippmAdd_vav_32f_3x1(
			(Ipp32f*)pDoc->m_pData->m_vertexData, sizeof(VertexData),
			pModelShift,
			(Ipp32f*)pDoc->m_pData->m_vertexData, sizeof(VertexData),
			pDoc->m_pData->m_numVertex);
		m_prevMousePos_ = point;
		pDoc->Reinit();
		Invalidate(false);
	}
	if (m_showRayTrace_)
	{
//		Draw(0);
		Invalidate(false);
	}

	CView::OnMouseMove(nFlags, point);
}

BOOL CTestView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	RECT rect;
	this->GetClientRect(&rect);
	CRect crect(rect);
	m_render3DS_.Scale(zDelta/WHEEL_DELTA*3, crect);

	CTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	Invalidate(false);
//	Draw(0);
	
	return CView::OnMouseWheel(nFlags, zDelta, pt);
}

void CTestView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	m_prevMousePos_ = point;

	CView::OnRButtonDown(nFlags, point);
}

void CTestView::OnRButtonUp(UINT nFlags, CPoint point) 
{
	
	CView::OnRButtonUp(nFlags, point);
}

void CTestView::OnEditCopy() 
{
	BeginWaitCursor(); 

	RECT rect;
	GetClientRect(&rect);

	int w = rect.right-rect.left, h = rect.bottom-rect.top;
	int wb = 3*w+(3-(3*w-1)%4);
	int imagesize = h*wb;

	HANDLE hBitmapCopy =
		::GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER)+imagesize);
	BITMAPINFOHEADER* pBitmapCopy =
		(BITMAPINFOHEADER*)::GlobalLock((HGLOBAL)hBitmapCopy);
	void* pImageData = (char*)pBitmapCopy+sizeof(BITMAPINFOHEADER);

	pBitmapCopy->biSize = sizeof( BITMAPINFOHEADER );
	pBitmapCopy->biWidth = w;
	pBitmapCopy->biHeight = h;
	pBitmapCopy->biPlanes = 1;
	pBitmapCopy->biBitCount = 24;
	pBitmapCopy->biCompression = BI_RGB;
	pBitmapCopy->biSizeImage = imagesize;
	pBitmapCopy->biXPelsPerMeter = 0;
	pBitmapCopy->biYPelsPerMeter = 0;
	pBitmapCopy->biClrUsed = 0;
	pBitmapCopy->biClrImportant = 0; 

	::glReadPixels(0,0,w,h,GL_RGB,GL_UNSIGNED_BYTE,pImageData); 
	::GlobalUnlock((HGLOBAL)hBitmapCopy);

	OpenClipboard();
	EmptyClipboard();
	SetClipboardData(CF_DIB, hBitmapCopy);
	CloseClipboard();

	EndWaitCursor();
}

void CTestView::OnShowModelMatrix() 
{
	m_showModelMatrix_ = !m_showModelMatrix_;
	m_showViewMatrix_ = 0;
	RECT rect;
	GetClientRect(&rect);
	Invalidate();
//	Draw(0);
}

void CTestView::OnShowViewMatrix() 
{
	m_showViewMatrix_ = !m_showViewMatrix_;
	m_showModelMatrix_ = 0;
	RECT rect;
	GetClientRect(&rect);
	Invalidate();
//	Draw(0);
}

void CTestView::OnUpdateShowViewMatrix(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_showViewMatrix_ != 0));
}

void CTestView::OnUpdateShowModelMatrix(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_showModelMatrix_ != 0));

}

void CTestView::OnProjectPlane() 
{
	CTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	m_projectPlane_ = !m_projectPlane_;

	if (m_projectPlane_)
	{
	Ipp32f pMatrix[16], pMatrixTmp[16], pMatrixInv[16];
//	Ipp32f pZNormal[4] = { 0.0f, 0.0f, 1.0f, 0.0f }, pNormal[4];
	Ipp32f pZNormal[4] = { 0.0f, 0.0f, 1.0f, 0.0f }, pNormal[4];
	Ipp32f pZFlat[16] = 
	{
		1.0f, 0.0f, 0.0f, 0.0f,
		0.0f, 1.0f, 0.0f, 0.0f,
//		0.0f, 0.0f, 0.0001f, 0.0f,
		0.0f, 0.0f, 0.0f, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f};

//	glGetFloatv(GL_MODELVIEW_MATRIX, pMatrix);
	ippsCopy_32f(m_render3DS_.ModelViewMatrix, pMatrix, 16);
	ippmMul_mv_32f_4x4(pMatrix, 16, pZNormal, pNormal);

	ippmInvert_m_32f_4x4(pMatrix, 16, pMatrixInv, 16);
	ippmMul_mm_32f_4x4(pMatrix, 16, pZFlat, 16, pMatrixTmp, 16);
	ippmMul_mm_32f_4x4(pMatrixTmp, 16, pMatrixInv, 16, pMatrix, 16);

	ippmMul_mva_32f_3x3(
		pMatrix, sizeof(Ipp32f)*4,
//		(Ipp32f*)pDoc->m_pData->m_vertexData, sizeof(VertexData),
		&pDoc->m_pData->m_vertexData->x, sizeof(VertexData),
		&pDoc->m_pData->m_vertexData->x, sizeof(VertexData),
//		(Ipp32f*)pDoc->m_pData->m_vertexData, sizeof(VertexData),
		pDoc->m_pData->m_numVertex);

	IppiSize sizeAsImage = { 1, pDoc->m_pData->m_numVertex };
	int stride = sizeof(VertexData);
	ippiSet_32f_C3R(pNormal, &pDoc->m_pData->m_vertexData[0].nx, stride, sizeAsImage);

	pDoc->Reinit();
	}
	else
		pDoc->Reload();
	Invalidate();
}

void CTestView::OnUpdateProjectPlane(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_projectPlane_ != 0));
}

void CTestView::OnMutateModel() 
{
	// Multiply the array of vectors by matrix ProjectionMatrix 
	CTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	ippmMul_mTva_32f_3x3(
		m_render3DS_.ModelViewMatrix, sizeof(Ipp32f)*4,
		(Ipp32f*)pDoc->m_pData->m_vertexData, sizeof(VertexData),
		(Ipp32f*)pDoc->m_pData->m_vertexData, sizeof(VertexData),
		pDoc->m_pData->m_numVertex);
	ippmAdd_vav_32f_3x1(
		(Ipp32f*)pDoc->m_pData->m_vertexData, sizeof(VertexData),
		&m_render3DS_.ModelViewMatrix[12],
		(Ipp32f*)pDoc->m_pData->m_vertexData, sizeof(VertexData),
		pDoc->m_pData->m_numVertex);

	// Handle normals
	Ipp32f pMatrixInv[16];
	ippmInvert_m_32f_4x4(m_render3DS_.ModelViewMatrix, 16,
		pMatrixInv, 16);

	ippmMul_mva_32f_3x3(
		pMatrixInv, sizeof(Ipp32f)*4,
		&pDoc->m_pData->m_vertexData->nx, sizeof(VertexData),
		&pDoc->m_pData->m_vertexData->nx, sizeof(VertexData),
		pDoc->m_pData->m_numVertex);

	// Reset the view matrix
	m_render3DS_.Reset();
	pDoc->Reinit();

	Invalidate(false);	
}

void CTestView::OnUpdateMutateModel(CCmdUI* pCmdUI) 
{
}	

void CTestView::OnObjectDuplicate() 
{
	CTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	pDoc->DuplicateObject();
	m_showDuplicate_ = !m_showDuplicate_;
	Invalidate(false);
}

void CTestView::OnUpdateObjectDuplicate(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_showDuplicate_ != 0));
}

void CTestView::OnShowNormals() 
{
	m_showNormals_ = !m_showNormals_;
	m_showNormals2_ = 0;
	Invalidate(false);
}

void CTestView::OnUpdateShowNormals(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_showNormals_ != 0));
}

void CTestView::OnShowRaytrace() 
{
	m_showRayTrace_ = !m_showRayTrace_;
	Invalidate(false);
}

void CTestView::OnUpdateShowRaytrace(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_showRayTrace_ != 0));
	
}

void CTestView::OnShowNormals2() 
{
	m_showNormals2_ = !m_showNormals2_;
	m_showNormals_ = 0;

	Invalidate(false);
}

void CTestView::OnUpdateShowNormals2(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_showNormals2_ != 0));
}

void CTestView::OnToggleFill() 
{
	m_showFill_ = !m_showFill_;
	Invalidate(false);
}

void CTestView::OnUpdateToggleFill(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_showFill_ != 0));
}

void CTestView::OnShowSideNormals() 
{
	m_showSideNormals_ = !m_showSideNormals_;
	Invalidate(false);
}

void CTestView::OnUpdateShowSideNormals(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_showSideNormals_ != 0));
}


void CTestView::OnShowCenterOfMass() 
{
	m_showCenterOfMass_ = !m_showCenterOfMass_;

	if (m_showCenterOfMass_)
	{
		Ipp64u startTime;
		CTestDoc* pDoc = GetDocument();
		ASSERT_VALID(pDoc);

		pDoc->m_pData->CalcCenterOfMass(m_pCenterOfMass_, &m_mass_,0);
		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcCenterOfMass(m_pCenterOfMass_, &m_mass_,0);
		m_time_[0] = ippCoreGetCpuClocks() - startTime;

		pDoc->m_pData->CalcCenterOfMass(m_pCenterOfMass_, &m_mass_,1);
		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcCenterOfMass(m_pCenterOfMass_, &m_mass_,1);
		m_time_[1] = ippCoreGetCpuClocks() - startTime;

		pDoc->m_pData->CalcCenterOfMass(m_pCenterOfMass_, &m_mass_);
		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcCenterOfMass(m_pCenterOfMass_, &m_mass_);
		m_time_[3] = ippCoreGetCpuClocks() - startTime;

		pDoc->m_pData->CalcCenterOfMass(m_pCenterOfMass_, &m_mass_,2);
		startTime = ippCoreGetCpuClocks();
		pDoc->m_pData->CalcCenterOfMass(m_pCenterOfMass_, &m_mass_,2);
		m_time_[2] = ippCoreGetCpuClocks() - startTime;

		Invalidate(false);
	}
}

void CTestView::OnUpdateShowCenterOfMass(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_showCenterOfMass_ != 0));
}

void CTestView::OnUpdateToolGrab(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_toolType_ == TOOL_GRAB));
}

void CTestView::OnToolGrab() 
{
	m_toolType_ = TOOL_GRAB;
	AfxGetApp()->LoadCursor(IDC_HAND_OPEN);
}

void CTestView::OnToolArrow() 
{
	m_toolType_ = TOOL_ARROW;
	AfxGetApp()->LoadStandardCursor(IDC_ARROW);
}

void CTestView::OnUpdateToolArrow(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_toolType_ == TOOL_ARROW));
}

void CTestView::OnShowIntersect() 
{
	m_showIntersect_ = !m_showIntersect_;
	m_intersectInvalid_ = 1;
	Invalidate(false);
}

void CTestView::OnUpdateShowIntersect(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_showIntersect_ != 0);
}

void CTestView::OnUseVertexNormals() 
{
	m_normalsToUse_ = VERTEX_NORMALS;
	Invalidate(false);
}

void CTestView::OnUseTriangleNormals() 
{
	m_normalsToUse_ = TRIANGLE_NORMALS;
	Invalidate(false);
}

void CTestView::OnUpdateUseVertexNormals(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_normalsToUse_ == VERTEX_NORMALS);
}

void CTestView::OnUpdateUseTriangleNormals(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_normalsToUse_ == TRIANGLE_NORMALS);
}


void CTestView::OnShowTimeCalcplanes() 
{
	m_showTimeCalcplanes_ = !m_showTimeCalcplanes_;
}

void CTestView::OnUpdateShowTimeCalcplanes(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck((m_showTimeCalcplanes_!=0));
}
