Click here to Skip to main content
15,896,557 members
Articles / Desktop Programming / MFC

Mouse Selection in OpenGL Scene

Rate me:
Please Sign up or sign in to vote.
4.82/5 (20 votes)
25 Oct 2002CPOL3 min read 249.3K   12.5K   83  
One another approach for picking objects with the mouse in OpenGL scene.
// MouseSelView.cpp : implementation of the CMouseSelView class
//

#include "stdafx.h"
#include "MouseSel.h"

#include "MouseSelDoc.h"
#include "MouseSelView.h"
#include "Sphere.h"
#include "SpherePropDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMouseSelView

IMPLEMENT_DYNCREATE(CMouseSelView, CView)

BEGIN_MESSAGE_MAP(CMouseSelView, CView)
	ON_COMMAND(ID_EDIT_PROPERTIES, OnEditProperties)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_CREATE()
	ON_WM_ERASEBKGND()
	ON_WM_SIZE()
	ON_WM_DESTROY()
	ON_WM_PAINT()
END_MESSAGE_MAP()

// CMouseSelView construction/destruction

CMouseSelView::CMouseSelView()
{
	// OpenGL
	m_hGLContext = NULL;
	m_GLPixelIndex = 0;
	
	// Mouse
	m_LeftButtonDown = FALSE;
	m_RightButtonDown = FALSE;
	m_sph=NULL;

}

CMouseSelView::~CMouseSelView()
{
}

BOOL CMouseSelView::PreCreateWindow(CREATESTRUCT& cs)
{
	cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
	return CView::PreCreateWindow(cs);
}

// CMouseSelView drawing

void CMouseSelView::OnDraw(CDC* /*pDC*/)
{
	CMouseSelDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	// TODO: add draw code for native data here
}


// CMouseSelView diagnostics

#ifdef _DEBUG
void CMouseSelView::AssertValid() const
{
	CView::AssertValid();
}

void CMouseSelView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CMouseSelDoc* CMouseSelView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMouseSelDoc)));
	return (CMouseSelDoc*)m_pDocument;
}
#endif //_DEBUG


// CMouseSelView message handlers

void CMouseSelView::OnEditProperties()
{
	CMouseSelDoc* pDoc = (CMouseSelDoc*)GetDocument();
	if(m_sph!=NULL)
	{
	CSpherePropDlg m_propDlg;	
	m_propDlg.m_Red=m_sph->m_RedColor*255;
	m_propDlg.m_Green=m_sph->m_GreenColor*255;
	m_propDlg.m_Blue=m_sph->m_BlueColor*255;
	m_propDlg.m_dRadius=m_sph->m_Radius;
	
	if(m_propDlg.DoModal()==IDOK)
	{
		m_sph->m_RedColor=(double) m_propDlg.m_Red/255.0;
		m_sph->m_GreenColor= (double)m_propDlg.m_Green/255.0;
		m_sph->m_BlueColor= (double)m_propDlg.m_Blue/255.0;
		m_sph->m_Radius=m_propDlg.m_dRadius;
		Invalidate();
		pDoc->SetModifiedFlag(TRUE);
	}
		
		
	}
	else
	{
		AfxMessageBox("Select sphere!",MB_OK);
	}
}

void CMouseSelView::OnLButtonDown(UINT nFlags, CPoint point)
{
	m_LeftButtonDown = TRUE;
	m_LeftDownPos = point;
	SetCapture();
	if(m_sph!=NULL)
	m_sph->m_Select=FALSE;
	m_sph=NULL;
	CMouseSelDoc* pDoc = (CMouseSelDoc*)GetDocument();
	ASSERT(pDoc);
    CTypedPtrList<CObList,CSphere*>& sphereList =pDoc->m_SphereList;
	POSITION pos = sphereList.GetHeadPosition();
	while (pos != NULL)
	{
       CSphere* spheres = sphereList.GetNext(pos);
		spheres->m_Select=FALSE;
		if(spheres->GetRect().PtInRect(point))
		{
			m_sph=spheres;
			m_sph->m_Select=TRUE;
			break;
		}
	}
		
	Invalidate();
	CView::OnLButtonDown(nFlags, point);
}

void CMouseSelView::OnLButtonUp(UINT nFlags, CPoint point)
{
	m_RightButtonDown = FALSE;
	m_LeftButtonDown = FALSE;
	ReleaseCapture();
	CView::OnLButtonUp(nFlags, point);
}

void CMouseSelView::OnMouseMove(UINT nFlags, CPoint point)
{
	CMouseSelDoc* pDoc = (CMouseSelDoc*)GetDocument();
	// Both : rotation
	if(m_LeftButtonDown && m_RightButtonDown)
	{
		if(m_xyRotation)
		{
			m_yRotation -= (float)(m_LeftDownPos.x - point.x) * m_SpeedRotation;
			m_xRotation -= (float)(m_LeftDownPos.y - point.y) * m_SpeedRotation;
		}
		else
		{
			m_zRotation -= (float)(m_LeftDownPos.x - point.x) * m_SpeedRotation;
			m_xRotation -= (float)(m_LeftDownPos.y - point.y) * m_SpeedRotation;
		}
		m_LeftDownPos = point;
		m_RightDownPos = point;
	Invalidate();
		
	}

	else

	// Left : x / y translation
	if(m_LeftButtonDown)
	{
		m_xTranslation -= (float)(m_LeftDownPos.x - point.x) * m_SpeedTranslation;
		m_yTranslation += (float)(m_LeftDownPos.y - point.y) * m_SpeedTranslation;
		m_LeftDownPos = point;
		Invalidate();
	}

	else

	// Right : z translation
	if(m_RightButtonDown)
	{
		m_zTranslation += (float)(m_RightDownPos.y - point.y) * m_SpeedTranslation;
		m_RightDownPos = point;
		Invalidate();
	}

	CView::OnMouseMove(nFlags, point);
}

void CMouseSelView::OnRButtonDblClk(UINT nFlags, CPoint point)
{
	m_xyRotation=m_xyRotation ? FALSE : TRUE;
	
	CView::OnRButtonDblClk(nFlags, point);
}

void CMouseSelView::OnRButtonDown(UINT nFlags, CPoint point)
{
	m_RightButtonDown = TRUE;
	m_RightDownPos = point;
	SetCapture();

	CView::OnRButtonDown(nFlags, point);
}

void CMouseSelView::OnRButtonUp(UINT nFlags, CPoint point)
{
	m_RightButtonDown = FALSE;
	m_LeftButtonDown = FALSE;
	ReleaseCapture();
	CView::OnRButtonUp(nFlags, point);
}

int CMouseSelView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if(CView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	HWND hWnd = GetSafeHwnd();
	HDC hDC = ::GetDC(hWnd);

	if(SetWindowPixelFormat(hDC)==FALSE)
		return 0;
	
	if(CreateViewGLContext(hDC)==FALSE)
		return 0;

	
    glShadeModel(GL_SMOOTH);
	glEnable(GL_NORMALIZE);

	
	glClearColor(0,0,0,1.0f);
    glClearDepth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	// Perspective
	CRect rect;
	GetClientRect(&rect);
	double	aspect = (rect.Height() == 0) ? rect.Width() : (double)rect.Width()/(double)rect.Height();
	gluPerspective(45,aspect,0.1,70.0);

	glEnable(GL_DEPTH_TEST);

	return 1;
}

BOOL CMouseSelView::OnEraseBkgnd(CDC* pDC)
{
	return 1;//Prevent flicker
	//return CView::OnEraseBkgnd(pDC);
}

void CMouseSelView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);
	
	HWND hWnd = GetSafeHwnd();
	HDC hDC = ::GetDC(hWnd);
	wglMakeCurrent(hDC,m_hGLContext);

	double	 aspect = (cy == 0) ? cx : (double)cx/(double)cy;
	
	glViewport(0,0,cx,cy);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45,aspect,0.1,170.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glDrawBuffer(GL_BACK);

	// Release
	::ReleaseDC(hWnd,hDC);
}

void CMouseSelView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
	HWND hWnd = GetSafeHwnd();
	HDC hDC = ::GetDC(hWnd);
	wglMakeCurrent(hDC,m_hGLContext);
	::ReleaseDC(hWnd,hDC);
	CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
}

void CMouseSelView::OnInitialUpdate()
{
	CView::OnInitialUpdate();
	InitGeometry();
}

void CMouseSelView::OnDestroy()
{
	if(wglGetCurrentContext() != NULL)
		wglMakeCurrent(NULL,NULL);
	
	if(m_hGLContext != NULL)
	{
		wglDeleteContext(m_hGLContext);
		m_hGLContext = NULL;
	}

	CView::OnDestroy();
}

void CMouseSelView::OnPaint()
{
	// Device context for painting
	CPaintDC dc(this); 
	
	// pointer to Doc
	CMouseSelDoc* pDoc = (CMouseSelDoc*)GetDocument();
	ASSERT_VALID(pDoc);
    
	// for MDI 
	HWND hWnd = GetSafeHwnd();
	HDC hDC = ::GetDC(hWnd);
	wglMakeCurrent(hDC,m_hGLContext);
	
	//Painting background
	glClearColor(0,0,0,1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glPushMatrix();
	
	// Position / translation / scale
	glTranslated(m_xTranslation,m_yTranslation,m_zTranslation);
	glRotatef(m_xRotation, 1.0, 0.0, 0.0);
	glRotatef(m_yRotation, 0.0, 1.0, 0.0);
	glRotatef(m_zRotation, 0.0, 0.0, 1.0);

	
	UpdateDoc();
	// Start rendering...
	BeginWaitCursor();
	pDoc->RenderScene();
	EndWaitCursor();
	
	glPopMatrix();

	// Double buffer
	SwapBuffers(dc.m_ps.hdc);
	glFlush();

	// Release
	::ReleaseDC(hWnd,hDC);
}
BOOL CMouseSelView::SetWindowPixelFormat(HDC hDC)
{
	PIXELFORMATDESCRIPTOR pixelDesc;
	
	pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
	pixelDesc.nVersion = 1;
	
	pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
		PFD_DOUBLEBUFFER | PFD_STEREO_DONTCARE;
	
	pixelDesc.iPixelType = PFD_TYPE_RGBA;
	pixelDesc.cColorBits = 32;
	pixelDesc.cRedBits = 8;
	pixelDesc.cRedShift = 16;
	pixelDesc.cGreenBits = 8;
	pixelDesc.cGreenShift = 8;
	pixelDesc.cBlueBits = 8;
	pixelDesc.cBlueShift = 0;
	pixelDesc.cAlphaBits = 0;
	pixelDesc.cAlphaShift = 0;
	pixelDesc.cAccumBits = 64;
	pixelDesc.cAccumRedBits = 16;
	pixelDesc.cAccumGreenBits = 16;
	pixelDesc.cAccumBlueBits = 16;
	pixelDesc.cAccumAlphaBits = 0;
	pixelDesc.cDepthBits = 32;
	pixelDesc.cStencilBits = 8;
	pixelDesc.cAuxBuffers = 0;
	pixelDesc.iLayerType = PFD_MAIN_PLANE;
	pixelDesc.bReserved = 0;
	pixelDesc.dwLayerMask = 0;
	pixelDesc.dwVisibleMask = 0;
	pixelDesc.dwDamageMask = 0;
	
	m_GLPixelIndex = ChoosePixelFormat(hDC,&pixelDesc);
	if(m_GLPixelIndex == 0) // Choose default
	{
		m_GLPixelIndex = 1;
		if(DescribePixelFormat(hDC,m_GLPixelIndex,
			sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0)
			return FALSE;
	}
	
	if(!SetPixelFormat(hDC,m_GLPixelIndex,&pixelDesc))
		return FALSE;
	return TRUE;

}
BOOL CMouseSelView::CreateViewGLContext(HDC hDC)
{
	m_hGLContext = wglCreateContext(hDC);
	
	if(m_hGLContext==NULL)
		return FALSE;
	
	if(wglMakeCurrent(hDC,m_hGLContext)==FALSE)
		return FALSE;
	
	return TRUE;

}

void CMouseSelView::InitGeometry()
{
	CMouseSelDoc* pDoc = (CMouseSelDoc*)GetDocument();
	m_xRotation = pDoc->m_xRotation;
	m_yRotation = pDoc->m_yRotation;
	m_zRotation =pDoc-> m_zRotation;

	m_xTranslation = pDoc->m_xTranslation;
	m_yTranslation = pDoc->m_yTranslation;
	m_zTranslation = pDoc->m_zTranslation;

    m_SpeedRotation = pDoc->m_SpeedRotation;
	m_SpeedTranslation =pDoc->m_SpeedTranslation ;

	m_xyRotation =pDoc->m_xyRotation;

}

void CMouseSelView::UpdateDoc()
{
	CMouseSelDoc* pDoc = (CMouseSelDoc*)GetDocument();
	//ASSERT_VALID(pDoc);
	pDoc->m_xRotation=m_xRotation;
	pDoc->m_yRotation=	m_yRotation;
	pDoc->m_zRotation=m_zRotation;

	pDoc->m_xTranslation=m_xTranslation;
	pDoc->m_yTranslation=	m_yTranslation ;
	pDoc->m_zTranslation=m_zTranslation ;

	pDoc->m_SpeedRotation=m_SpeedRotation ;
	pDoc->m_SpeedTranslation=m_SpeedTranslation  ;

	pDoc->m_xyRotation=m_xyRotation ;


}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Bosnia and Herzegovina Bosnia and Herzegovina
Bahrudin Hrnjica holds a Ph.D. degree in Technical Science/Engineering from University in Bihać.
Besides teaching at University, he is in the software industry for more than two decades, focusing on development technologies e.g. .NET, Visual Studio, Desktop/Web/Cloud solutions.

He works on the development and application of different ML algorithms. In the development of ML-oriented solutions and modeling, he has more than 10 years of experience. His field of interest is also the development of predictive models with the ML.NET and Keras, but also actively develop two ML-based .NET open source projects: GPdotNET-genetic programming tool and ANNdotNET - deep learning tool on .NET platform. He works in multidisciplinary teams with the mission of optimizing and selecting the ML algorithms to build ML models.

He is the author of several books, and many online articles, writes a blog at http://bhrnjica.net, regularly holds lectures at local and regional conferences, User groups and Code Camp gatherings, and is also the founder of the Bihac Developer Meetup Group. Microsoft recognizes his work and awarded him with the prestigious Microsoft MVP title for the first time in 2011, which he still holds today.

Comments and Discussions