Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Professional User Interface Suite

, 13 Jan 2004
MFC extension library enabling software to be provided with a professional UI
prof-uis-223-freeware_src.zip
Prof-UIS
Bin_600
Bin_700
Bin_710
Include
profuisdll
idd_ext_color_dlg.ico
profuisdll.def
profuisdll_600.dsp
profuisdll_600.dsw
res
black_arrow_bottom.cur
black_arrow_left.cur
black_arrow_right.cur
black_arrow_top.cur
cmd00001.cur
cmd00002.cur
cmd00003.cur
cur_arrow_invert.cur
cur_black_finger.cur
cur_black_hand.cur
cur_hand_like.cur
cur_pan_all.cur
cur_pan_bottom.cur
cur_pan_bottom_left.cur
cur_pan_bottom_right.cur
cur_pan_horz.cur
cur_pan_left.cur
cur_pan_right.cur
cur_pan_top.cur
cur_pan_top_left.cur
cur_pan_top_right.cur
cur_pan_vert.cur
cur_resize_h1.cur
cur_resize_h2.cur
cur_resize_v1.cur
cur_resize_v2.cur
cur00001.cur
cur00002.cur
cur00003.cur
cur00004.cur
hollow_cross_normal.cur
hollow_cross_small.cur
ico00001.ico
id_view_.bmp
idd_ext_.ico
idd_icon.ico
ied_cp.cur
ied_el.cur
ied_fill.cur
ied_line.cur
ied_pen.cur
ied_rect.cur
ied_tool.cur
suppress.cur
suppress_arrow.cur
toolbar_.bmp
zoom_hollow.cur
zoom_minus.cur
zoom_plus.cur
profuislib
profuislib_600.dsp
profuislib_600.dsw
Samples
AviFrames
AviFrames_600.dsp
res
AviFrames.ico
CINEAPK.AVI
IDR_TOOLBAR_PLAYER.bmp
IDR_TOOLBAR_UISTYLE.bmp
Toolbar.bmp
toolbar2.bmp
xptheme.bin
DRAWCLI
DRAWCLI_600.dsp
L.JPN
RES
res
DRAWCLI.ICO
DRAWDOC.ICO
ico00001.ico
ico00002.ico
ico00003.ico
ico00004.ico
ico00005.ico
ico00006.ico
ico00007.ico
ico00008.ico
icon1.ico
id_objec.ico
id_scppv.ico
idr_abou.ico
PENCIL.CUR
TOOLBAR_1_16bit.bmp
TOOLBAR_1_4bit.bmp
TOOLBAR_2_16bit.bmp
TOOLBAR_2_4bit.bmp
FixedSizePanels
FixedSizePanels_600.dsp
res
bitmap_t.bmp
FixedSizePanels.ico
Toolbar.bmp
toolbar2.bmp
FullScreenState
FullScreenState_600.dsp
res
FullScreenState.ico
idr_mdit.ico
Toolbar.bmp
toolbar1.bmp
toolbar2.bmp
toolbar4.bmp
FunnyBars
FunnyBars_600.dsp
res
FunnyBars.ico
Toolbar.bmp
toolbar_16_16_8.bmp
toolbar_44_40_32.bmp
winXP.manifest
GLViews
GLViews_600.dsp
res
bitmap_i.bmp
bitmap_s.bmp
bitmap_t.bmp
bmp00001.bmp
btpnlane.bmp
CINEAPK.AVI
cur00001.cur
cur00002.cur
cursor_g.cur
earth.bmp
GLViews.ico
moon.bmp
ProfUisCubeSideOrange.bmp
ProfUisCubeSideWhite.bmp
ring.bmp
Toolbar.bmp
toolbar_.bmp
toolbar2.bmp
wndavipl.bmp
wndmirror.bmp
res_html
bodytop.gif
book_close.gif
book_open.gif
MDI
MDI_600.dsp
res
idr_mdit.ico
MDI.ico
Toolbar.bmp
toolbar2.bmp
MDI_InnerOuterBars
MDI_InnerOuterBars_600.dsp
res
bmp00001.bmp
idr_mdit.ico
MDI_InnerOuterBars.ico
Toolbar.bmp
toolbar_.bmp
toolbar2.bmp
MDIDOCVIEW
MDIDOCVIEW_600.dsp
res
MDIDOCVIEW.ico
MDIDOCVIEWDoc.ico
Toolbar.bmp
MthOutput
MthOutput_600.dsp
res
idr_mdit.ico
MthOutput.ico
Toolbar.bmp
toolbar1.bmp
toolbar2.bmp
ProfUIS_Controls
ProfUIS_Controls_600.dsp
res
bitmap1.bmp
bitmap2.bmp
icon1.ico
ProfUIS_Controls.ico
tab_imag.bmp
toolbar1.bmp
ResizableChildSheet
res
idr_chil.ico
ResizableChildSheet.ico
Toolbar.bmp
ResizableChildSheet_600.dsp
ResizablePropertySheet
res
bitmap1.bmp
bitmap2.bmp
ResizablePropertySheet.ico
ResizablePropertySheet_600.dsp
SDI
res
SDI.ico
Toolbar.bmp
toolbar2.bmp
SDI_600.dsp
SDIDOCVIEW
res
SDIDOCVIEW.ico
SDIDOCVIEWDoc.ico
Toolbar.bmp
SDIDOCVIEW_600.dsp
StateInFile
res
StateInFile.ico
Toolbar.bmp
StateInFile_600.dsp
StatusPanes
res
download.avi
StatusPanes.ico
Toolbar.bmp
toolbar2.bmp
StatusPanes_600.dsp
Src
Workspace
ProfUIS_600.dsw
profuis-v2.20_freeware.zip
Include
profuisdll
idd_ext_color_dlg.ico
profuisdll.def
profuisdll.dsp
res
profuislib
profuislib.dsp
Samples
DRAWCLI
MDI
MDIDOCVIEW
MDI_InnerOuterBars
ProfUIS_Controls
ResizablePropertySheet
SDI
SDIDOCVIEW
StateInFile
DRAWCLI.dsp
L.JPN
res
RES
DRAWCLI.ICO
DRAWDOC.ICO
ico00001.ico
ico00002.ico
icon1.ico
id_objec.ico
PENCIL.CUR
TOOLBAR.BMP
MDI.dsp
res
idr_mdit.ico
MDI.ico
Toolbar.bmp
toolbar2.bmp
MDIDOCVIEW.dsp
res
MDIDOCVIEW.ico
MDIDOCVIEWDoc.ico
Toolbar.bmp
MDI_InnerOuterBars.dsp
res
bmp00001.bmp
idr_mdit.ico
MDI_InnerOuterBars.ico
Toolbar.bmp
toolbar2.bmp
toolbar_.bmp
ProfUIS_Controls.dsp
res
bitmap1.bmp
bitmap2.bmp
icon1.ico
ProfUIS_Controls.ico
tab_imag.bmp
toolbar1.bmp
res
ResizablePropertySheet.dsp
ResizablePropertySheet.ico
res
SDI.dsp
SDI.ico
Toolbar.bmp
toolbar2.bmp
res
SDIDOCVIEW.dsp
SDIDOCVIEW.ico
SDIDOCVIEWDoc.ico
Toolbar.bmp
res
StateInFile.dsp
StateInFile.ico
Toolbar.bmp
Src
Workspace
ProfUIS.dsw
ProfUIS.suo
profuis21_bin.zip
Bin
MDI.exe
ProfUIS21.dll
ProfUIS_Controls.exe
SDI.exe
StateInFile.exe
profuis21_src.zip
idd_ext_color_dlg.ico
profuisdll.aps
profuisdll.clw
profuisdll.def
profuisdll.dep
profuisdll.dsp
profuisdll.mak
profuisdll.plg
MDI.APS
MDI.clw
MDI.dep
MDI.dsp
MDI.mak
MDI.plg
idr_mdit.ico
MDI.ico
Toolbar.bmp
toolbar2.bmp
ProfUIS_Controls.aps
ProfUIS_Controls.clw
ProfUIS_Controls.dep
ProfUIS_Controls.dsp
ProfUIS_Controls.mak
ProfUIS_Controls.ico
toolbar1.bmp
SDI.APS
SDI.clw
SDI.dep
SDI.dsp
SDI.mak
SDI.plg
SDI.ico
Toolbar.bmp
toolbar2.bmp
StateInFile.aps
StateInFile.clw
StateInFile.dep
StateInFile.dsp
StateInFile.mak
StateInFile.plg
StateInFile.ico
Toolbar.bmp
ProfUIS.dsw
ProfUIS.ncb
ProfUIS.opt
// ChildView.cpp : implementation of the CChildView class
//

#include "stdafx.h"
#include "GLViews.h"
#include "ChildView.h"
#include "MainFrm.h"

#include <io.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// C3DObject

IMPLEMENT_DYNCREATE( C3DObject, CObject );

C3DObject::C3DObject(
	LPCTSTR sName, // = GL_VIEWS_NONAME
	bool bEnabledParentDependency, //  = true
	bool bEnabledScale, //  = false
	bool bEnabledTranslation, //  = true
	bool bEnabledOrientation //  = true
	)
	: m_sName( sName )
	, m_pParent( NULL )
	, m_bEnabledParentDependency( bEnabledParentDependency )
	, m_bEnabledScale( bEnabledScale )
	, m_bEnabledTranslation( bEnabledTranslation )
	, m_bEnabledOrientation( bEnabledOrientation )
	, m_hti( NULL )
{
	ASSERT( sName != NULL );
	ASSERT( !m_sName.IsEmpty() );
	LocalLoadIdentity();
}

C3DObject::~C3DObject()
{
	ASSERT( m_pParent == NULL );
	for(	POSITION pos = m_listChilds.GetHeadPosition();
			pos != NULL;
			)
	{ // walk all childs
		C3DObject * pChild = m_listChilds.GetNext( pos );
		ASSERT_VALID( pChild );
		ASSERT( pChild->m_pParent == this );
		pChild->m_pParent = NULL;
		delete pChild;
	} // walk all childs
	m_listChilds.RemoveAll();
}

void C3DObject::SerializeState(
	CArchive & ar
	)
{
	ASSERT_VALID( this );
	if( ar.IsStoring() )
	{
		ar << m_v3LocalScale.x;
		ar << m_v3LocalScale.y;
		ar << m_v3LocalScale.z;
		
		ar << m_v3LocalTranslation.x;
		ar << m_v3LocalTranslation.y;
		ar << m_v3LocalTranslation.z;

		ar << m_quatLocalOrientation.x;
		ar << m_quatLocalOrientation.y;
		ar << m_quatLocalOrientation.z;
		ar << m_quatLocalOrientation.w;

//		ar << m_mtxLastTransformation.m11;
//		ar << m_mtxLastTransformation.m21;
//		ar << m_mtxLastTransformation.m31;
//		ar << m_mtxLastTransformation.m41;
//		ar << m_mtxLastTransformation.m12;
//		ar << m_mtxLastTransformation.m22;
//		ar << m_mtxLastTransformation.m32;
//		ar << m_mtxLastTransformation.m42;
//		ar << m_mtxLastTransformation.m13;
//		ar << m_mtxLastTransformation.m23;
//		ar << m_mtxLastTransformation.m33;
//		ar << m_mtxLastTransformation.m43;
//		ar << m_mtxLastTransformation.m14;
//		ar << m_mtxLastTransformation.m24;
//		ar << m_mtxLastTransformation.m34;
//		ar << m_mtxLastTransformation.m44;

		ar << m_sName;

		DWORD dwEnabledFlags = 0L;
		if( m_bEnabledParentDependency )
			dwEnabledFlags |= 0x00000001L;
		if( m_bEnabledScale )
			dwEnabledFlags |= 0x00000002L;
		if( m_bEnabledTranslation )
			dwEnabledFlags |= 0x00000004L;
		if( m_bEnabledOrientation )
			dwEnabledFlags |= 0x00000008L;

		ar << dwEnabledFlags;
	} // if( ar.IsStoring() )
	else
	{
		LocalLoadIdentity();

		ar >> m_v3LocalScale.x;
		ar >> m_v3LocalScale.y;
		ar >> m_v3LocalScale.z;
		
		ar >> m_v3LocalTranslation.x;
		ar >> m_v3LocalTranslation.y;
		ar >> m_v3LocalTranslation.z;

		ar >> m_quatLocalOrientation.x;
		ar >> m_quatLocalOrientation.y;
		ar >> m_quatLocalOrientation.z;
		ar >> m_quatLocalOrientation.w;

//		ar >> m_mtxLastTransformation.m11;
//		ar >> m_mtxLastTransformation.m21;
//		ar >> m_mtxLastTransformation.m31;
//		ar >> m_mtxLastTransformation.m41;
//		ar >> m_mtxLastTransformation.m12;
//		ar >> m_mtxLastTransformation.m22;
//		ar >> m_mtxLastTransformation.m32;
//		ar >> m_mtxLastTransformation.m42;
//		ar >> m_mtxLastTransformation.m13;
//		ar >> m_mtxLastTransformation.m23;
//		ar >> m_mtxLastTransformation.m33;
//		ar >> m_mtxLastTransformation.m43;
//		ar >> m_mtxLastTransformation.m14;
//		ar >> m_mtxLastTransformation.m24;
//		ar >> m_mtxLastTransformation.m34;
//		ar >> m_mtxLastTransformation.m44;

		ar >> m_sName;
		ASSERT( !m_sName.IsEmpty() );

		m_bEnabledParentDependency = false;
		m_bEnabledScale = false;
		m_bEnabledTranslation = false;
		m_bEnabledOrientation = false;
		DWORD dwEnabledFlags = 0L;
		ar >> dwEnabledFlags;
		if( (dwEnabledFlags&0x00000001L) != 0 )
			m_bEnabledParentDependency = true;
		if( (dwEnabledFlags&0x00000002L) != 0 )
			m_bEnabledScale = true;
		if( (dwEnabledFlags&0x00000004L) != 0 )
			m_bEnabledTranslation = true;
		if( (dwEnabledFlags&0x00000008L) != 0 )
			m_bEnabledOrientation = true;

	} // else from if( ar.IsStoring() )
}

void C3DObject::WalkTree(
	C3DObject::eWalkTreeQuery walkTreeQuery,
	C3DCamera * pCam,
	C3DView * pView3D,
	LPVOID lpvCookie,
	C3DMirror * pObjMirror // = NULL
	)
{
	ASSERT_VALID( this );
	if(	!OnWalkTree(
			walkTreeQuery,
			pCam,
			pView3D,
			lpvCookie,
			pObjMirror
			)
		)
		return;
	for(	POSITION pos = m_listChilds.GetHeadPosition();
			pos != NULL;
			)
	{ // walk all childs
		C3DObject * pChild = m_listChilds.GetNext( pos );
		ASSERT_VALID( pChild );
		ASSERT( pChild->m_pParent == this );
		if(		walkTreeQuery == EWTQ_RENDER
			&&	( !IsRenderSubtreeItem(pChild) )
			)
			continue;
		pChild->WalkTree(
			walkTreeQuery,
			pCam,
			pView3D,
			lpvCookie,
			pObjMirror
			);
	} // walk all childs
}

bool C3DObject::OnWalkTree(
	C3DObject::eWalkTreeQuery walkTreeQuery,
	C3DCamera * pCam,
	C3DView * pView3D,
	LPVOID lpvCookie,
	C3DMirror * pObjMirror
	)
{
bool bRetVal = true;
	ASSERT_VALID( this );
	switch( walkTreeQuery )
	{
	case EWTQ_THREAD_INIT:
		OnThreadInit( lpvCookie );
	break;
	case EWTQ_THREAD_DONE:
		OnThreadDone( lpvCookie );
	break;
	case EWTQ_PLAY:
		OnPlay( lpvCookie );
	break;
	case EWTQ_TRANSFORM:
		ASSERT_VALID( pCam );
		ASSERT_VALID( pView3D );
		OnTransform( pCam, pView3D, lpvCookie );
	break;
	case EWTQ_RENDER:
		ASSERT_VALID( pCam );
		ASSERT_VALID( pView3D );
		OnRender( pCam, pView3D, lpvCookie, pObjMirror );
		if( !IsRenderSubtree() )
			bRetVal = false;
	break;
	case EWTQ_ADD_TO_TREE:
		OnAddToTree( (CObjectHierarchyTreeCtrl*)lpvCookie );
	break;
	} // switch( walkTreeQuery )
	return bRetVal;
}

void C3DObject::OnThreadInit( LPVOID lpvCookie )
{
	ASSERT_VALID( this );
	lpvCookie;
}

void C3DObject::OnThreadDone( LPVOID lpvCookie )
{
	ASSERT_VALID( this );
	lpvCookie;
}

void C3DObject::OnPlay(
	LPVOID lpvCookie
	)
{
	ASSERT_VALID( this );
	lpvCookie;
}

void C3DObject::CalcTransformation(
	_mrct mtxParentTransformation
	)
{
	ASSERT_VALID( this );
	if( m_bEnabledParentDependency )
		m_mtxLastTransformation = mtxParentTransformation;
	else
		m_mtxLastTransformation.load_identity();
	if( m_bEnabledScale )
		m_mtxLastTransformation *= m_v3LocalScale.get_as_scale();
	if( m_bEnabledTranslation )
		m_mtxLastTransformation *= m_v3LocalTranslation.get_as_translation();
	if( m_bEnabledOrientation )
		m_mtxLastTransformation *= m_quatLocalOrientation;
}

void C3DObject::OnTransform(
	C3DCamera * pCam,
	C3DView * pView3D,
	LPVOID lpvCookie
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pCam );
	ASSERT_VALID( pView3D );
	pCam;
	pView3D;
	lpvCookie;
C3DObject * pParent = GetParent();
	if( pParent != NULL )
		CalcTransformation( pParent->m_mtxLastTransformation );
	else
	{
		_mt mtxIdentity;
		CalcTransformation( mtxIdentity );
	}
}

void C3DObject::OnRender(
	C3DCamera * pCam,
	C3DView * pView3D,
	LPVOID lpvCookie,
	C3DMirror * pObjMirror
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pCam );
	ASSERT_VALID( pView3D );
	pCam;
	pView3D;
	lpvCookie;
	pObjMirror;
}

bool C3DObject::IsRenderSubtree()
{
	ASSERT_VALID( this );
	return true;
}

bool C3DObject::IsRenderSubtreeItem( C3DObject * pObjChild )
{
	ASSERT_VALID( this );
	ASSERT_VALID( pObjChild );
	ASSERT( pObjChild->GetParent() == this );
	pObjChild;
	return true;
}

void C3DObject::OnAddToTree(
	CObjectHierarchyTreeCtrl * pTreeCtrl
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pTreeCtrl );
	ASSERT( pTreeCtrl->GetSafeHwnd() != NULL );
	ASSERT( ::IsWindow( pTreeCtrl->GetSafeHwnd() ) );
	ASSERT( m_hti == NULL );
HTREEITEM htiParent = TVI_ROOT;
C3DObject * pObjParent = GetParent();
	if( pObjParent != NULL )
	{
		ASSERT_VALID( pObjParent );
		htiParent = pObjParent->m_hti;
		ASSERT( htiParent != NULL );
	}
CString strTreeItemText;
int nTreeImageIndex = GL_VIEWS_TREE_IMG_IDX_GENERIC_OBJ;
	OnQueryTreeDisplayParms(
		strTreeItemText,
		nTreeImageIndex
		);
	ASSERT( !strTreeItemText.IsEmpty() );
	m_hti =
		pTreeCtrl->InsertItem(
			(LPCTSTR)strTreeItemText,
			nTreeImageIndex,
			nTreeImageIndex,
			htiParent,
			TVI_LAST
			);
	ASSERT( m_hti != NULL );
	VERIFY( pTreeCtrl->SetItemData( m_hti, (DWORD)this ) );
}

void C3DObject::OnTreeItemDblClick(
	CObjectHierarchyTreeCtrl * pTreeCtrl
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pTreeCtrl );
	ASSERT( pTreeCtrl->GetSafeHwnd() != NULL );
	ASSERT( ::IsWindow( pTreeCtrl->GetSafeHwnd() ) );
	ASSERT( m_hti != NULL );
	pTreeCtrl;
}

void C3DObject::OnQueryTreeDisplayParms(
	CString & strTreeItemText,
	int & nTreeImageIndex
	)
{
	ASSERT_VALID( this );
	strTreeItemText = GetName();
	ASSERT( !strTreeItemText.IsEmpty() );
	if( m_pParent == NULL )
		nTreeImageIndex = GL_VIEWS_TREE_IMG_IDX_ROOT;
}

void C3DObject::GenerateSphere(
	int nTextureIndex,
	_v3rct ptCenter,
	GLfloat fRadius,
	int nStacksCount,
	GLfloat fAngleTheta0,
	GLfloat fAngleTheta1,
	GLfloat fAngleTheta1Phi0,
	GLfloat fAngleTheta1Phi1,
	bool bNoDepth // = false
	)
{
	ASSERT( fRadius >= 0 && nStacksCount > 3 );
	for( int nStackIdx0 = 0; nStackIdx0 < (nStacksCount / 2); nStackIdx0++ )
	{
		GLfloat fAngleStack0 =
			fAngleTheta1Phi0 +
				( fAngleTheta1Phi1 - fAngleTheta1Phi0 ) /
					( nStacksCount / 2 ) * nStackIdx0 ;
		GLfloat fAngleStack1 =
			fAngleTheta1Phi0 +
				( fAngleTheta1Phi1 - fAngleTheta1Phi0 ) /
					( nStacksCount / 2 ) * ( nStackIdx0 + 1 );
		_v3t
			vNormalPrev0, vNormalCurr0, vNormalPrev1, vNormalCurr1,
			vVertexPrev0, vVertexCurr0, vVertexPrev1, vVertexCurr1;
		GLfloat
			fTextureCoordPrevX0 = 0.0f, fTextureCoordPrevY0 = 0.0f,
			fTextureCoordCurrX0 = 0.0f, fTextureCoordCurrY0 = 0.0f,
			fTextureCoordPrevX1 = 0.0f, fTextureCoordPrevY1 = 0.0f,
			fTextureCoordCurrX1 = 0.0f, fTextureCoordCurrY1 = 0.0f;
		for( int nStackIdx1 = 0; nStackIdx1 <= nStacksCount; nStackIdx1++ )
		{
			if( nStackIdx1 > 0 )
			{
				vNormalPrev0 = vNormalCurr0;
				vNormalPrev1 = vNormalCurr1;
				vVertexPrev0 = vVertexCurr0;
				vVertexPrev1 = vVertexCurr1;
				fTextureCoordPrevX0 = fTextureCoordCurrX0;
				fTextureCoordPrevX1 = fTextureCoordCurrX1;
				fTextureCoordPrevY0 = fTextureCoordCurrY0;
				fTextureCoordPrevY1 = fTextureCoordCurrY1;
			} // if( nStackIdx1 > 0 )
			GLfloat fAngleStack2 =
				fAngleTheta0 +
					nStackIdx1 * (fAngleTheta1 - fAngleTheta0)
						/ nStacksCount;
			vNormalCurr0.load_vector(
				_ntr::cos(fAngleStack0) * _ntr::cos(fAngleStack2),
				_ntr::sin(fAngleStack0),
				_ntr::cos(fAngleStack0) * _ntr::sin(fAngleStack2)
				);
			vVertexCurr0.load_vector(
				ptCenter.x + fRadius * vNormalCurr0.x,
				ptCenter.y + fRadius * vNormalCurr0.y,
				ptCenter.z + fRadius * vNormalCurr0.z
				);
			fTextureCoordCurrX0 = ((GLfloat)nStackIdx1) / ((GLfloat)nStacksCount);
			fTextureCoordCurrY0 = (2.0f * nStackIdx0) / ((GLfloat)nStacksCount);
			vNormalCurr1.load_vector(
				_ntr::cos(fAngleStack1) * _ntr::cos(fAngleStack2),
				_ntr::sin(fAngleStack1),
				_ntr::cos(fAngleStack1) * _ntr::sin(fAngleStack2)
				);
			vVertexCurr1.load_vector(
				ptCenter.x + fRadius * vNormalCurr1.x,
				ptCenter.y + fRadius * vNormalCurr1.y,
				ptCenter.z + fRadius * vNormalCurr1.z
				);
			fTextureCoordCurrX1 = ((GLfloat)nStackIdx1) / ((GLfloat)nStacksCount);
			fTextureCoordCurrY1 = (2 * (nStackIdx0 + 1)) / (GLfloat)nStacksCount;
			if( nStackIdx1 > 0 )
			{
				C3DSquare * pObjSquare = new C3DSquare;
				pObjSquare->m_nTextureIndex = nTextureIndex;
				pObjSquare->m_bNoDepth = bNoDepth;
				pObjSquare->m_bUseNormal = true;
				pObjSquare->m_vecNormal = vNormalCurr1;
				pObjSquare->m_arrTextureCoords[0].m_fX = fTextureCoordPrevX0;
				pObjSquare->m_arrTextureCoords[0].m_fY = fTextureCoordPrevY0;
				pObjSquare->m_arrPoints[0] = vVertexPrev0;
				pObjSquare->m_arrTextureCoords[1].m_fX = fTextureCoordPrevX1;
				pObjSquare->m_arrTextureCoords[1].m_fY = fTextureCoordPrevY1;
				pObjSquare->m_arrPoints[1] = vVertexPrev1;
				pObjSquare->m_arrTextureCoords[2].m_fX = fTextureCoordCurrX1;
				pObjSquare->m_arrTextureCoords[2].m_fY = fTextureCoordCurrY1;
				pObjSquare->m_arrPoints[2] = vVertexCurr1;
				pObjSquare->m_arrTextureCoords[3].m_fX = fTextureCoordCurrX0;
				pObjSquare->m_arrTextureCoords[3].m_fY = fTextureCoordCurrY0;
				pObjSquare->m_arrPoints[3] = vVertexCurr0;
				AddChild( pObjSquare );
			} // if( nStackIdx1 > 0 )
		} // for( int nStackIdx1 = 0; nStackIdx1 <= nStacksCount; nStackIdx1++ )
	} // for( int nStackIdx0 = 0; nStackIdx0 < (nStacksCount / 2); nStackIdx0++ )
}

bool C3DObject::stat_LoadResourceToMemory(
	LPCTSTR pszResId,
	LPCTSTR pszRsType,
	LPVOID * pLpvOutBuffer,
	DWORD * pDwOutSize
	)
{
	*pLpvOutBuffer = NULL;
	*pDwOutSize = 0L;
HINSTANCE hInst =
		::AfxFindResourceHandle( pszResId, pszRsType );
	if( hInst == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
HRSRC hRsrc = FindResource( hInst, pszResId, pszRsType );
	if( hRsrc == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
HGLOBAL hGlobal = LoadResource( hInst, hRsrc );
	if( hGlobal == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
LPVOID lpvData = LockResource( hGlobal );
DWORD dwSize = SizeofResource( hInst, hRsrc );
	if( lpvData == NULL )
	{
		ASSERT( FALSE );
		::UnlockResource( hGlobal );
		::FreeResource( hGlobal );
		return false;
	}
	if( dwSize == 0L )
	{
		ASSERT( FALSE );
		::UnlockResource( hGlobal );
		::FreeResource( hGlobal );
		return false;
	}
	*pLpvOutBuffer = malloc( dwSize );
	if( (*pLpvOutBuffer) == NULL )
	{
		ASSERT( FALSE );
		::UnlockResource( hGlobal );
		::FreeResource( hGlobal );
		return false;
	}
	memcpy( *pLpvOutBuffer, lpvData, dwSize );
	*pDwOutSize = dwSize;
	::UnlockResource( hGlobal );
	::FreeResource( hGlobal );
	return true;
}

bool C3DObject::stat_IsFileExists(
	LPCTSTR sFilePath
	)
{
	ASSERT( sFilePath != NULL );
	if( sFilePath == NULL )
		return false;
#if (defined _UNICODE)
		struct _wfinddata_t fd;
#else
		struct _finddata_t fd;
#endif
	long hNextFile =
#if (defined _UNICODE)
			_wfindfirst(
#else
			_findfirst(
#endif
				(LPTSTR)sFilePath,
				&fd
				);
bool bExists = true;
	if( hNextFile < 0 )
		bExists = false;
	else
	{
		if( (fd.attrib&_A_SUBDIR) != 0 )
			bExists = false;
	} // else from if( hNextFile < 0 )
	_findclose( hNextFile );
	return bExists;
}

/////////////////////////////////////////////////////////////////////////////
// C3DModifier

IMPLEMENT_DYNCREATE( C3DModifier, C3DObject );

C3DModifier::C3DModifier(
	LPCTSTR sName, // = GL_VIEWS_NONAME
	GLfloat fAnglePlayStepPitch, //  = 0.0f
	GLfloat fAnglePlayStepYaw, //  = 0.0f
	GLfloat fAnglePlayStepRoll //  = 0.0f
	)
	: C3DObject( sName )
	, m_fAnglePlayStepPitch( fAnglePlayStepPitch )
	, m_fAnglePlayStepYaw( fAnglePlayStepYaw )
	, m_fAnglePlayStepRoll( fAnglePlayStepRoll )
{
}

C3DModifier::~C3DModifier()
{
}

void C3DModifier::OnQueryTreeDisplayParms(
	CString & strTreeItemText,
	int & nTreeImageIndex
	)
{
	ASSERT_VALID( this );
	ASSERT( !m_sName.IsEmpty() );
int nCount = m_listChilds.GetCount();
	ASSERT( nCount > 0 );
	if( nCount > 1 )
	{
		strTreeItemText = _T("Group modifier \"");
		strTreeItemText += m_sName;
		strTreeItemText += _T("\"");
		nTreeImageIndex = GL_VIEWS_TREE_IMG_IDX_MODIFIER_GRP;
		return;
	} // if( nCount > 1 )
C3DObject * pObjHead = m_listChilds.GetHead();
	ASSERT_VALID( pObjHead );
CString strChildDisplayText;
	pObjHead->OnQueryTreeDisplayParms(
		strChildDisplayText,
		nTreeImageIndex
		);
	ASSERT( !strChildDisplayText.IsEmpty() );
	strTreeItemText = _T("Modifier for: ");
	strTreeItemText += strChildDisplayText;
	nTreeImageIndex = GL_VIEWS_TREE_IMG_IDX_MODIFIER_ONE;
}

void C3DModifier::OnPlay(
	LPVOID lpvCookie
	)
{
	ASSERT_VALID( this );
	lpvCookie;
#ifdef GL_VIEWS_DRAW_ANIMS
	if(		m_fAnglePlayStepPitch != 0.0f
		&&	m_fAnglePlayStepYaw != 0.0f
		&&	m_fAnglePlayStepRoll != 0.0f
		)
		LocalAdjustOrientation(
			m_fAnglePlayStepPitch,
			m_fAnglePlayStepYaw,
			m_fAnglePlayStepRoll
			);
#endif // GL_VIEWS_DRAW_ANIMS
}

/////////////////////////////////////////////////////////////////////////////
// C3DSquare

IMPLEMENT_DYNCREATE( C3DSquare, C3DObject );

C3DSquare::C3DSquare()
	: C3DObject( GL_VIEWS_SQUARE_NAME )
	, m_nTextureIndex( -1 )
	, m_bUseNormal( false )
	, m_bNoDepth( false )
	, m_bNoCullFace( false )
	, m_bAdjustAlphaFunc( false )
	, m_bAdjustBlendFunc( false )
	, m_gleAlphaFunc( GL_NOTEQUAL )
	, m_glcAlphaRef( 0.0f )
	, m_gleBlendFactorS( GL_SRC_ALPHA )
	, m_gleBlendFactorD( GL_ONE )
{
}

C3DSquare::~C3DSquare()
{
}

void C3DSquare::OnRender(
	C3DCamera * pCam,
	C3DView * pView3D,
	LPVOID lpvCookie,
	C3DMirror * pObjMirror
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pCam );
	ASSERT_VALID( pView3D );
	pCam;
	pView3D;
	lpvCookie;
	pObjMirror;
	glPushMatrix();
	glMultMatrixf( m_mtxLastTransformation.arr );
		if( m_bNoDepth )
		{
			glDisable( GL_DEPTH_TEST );
			GL_VIEWS_CHECK_OPENGL_ERROR
		} // if( m_bNoDepth )
		if( m_bNoCullFace )
		{
			glDisable( GL_CULL_FACE );
			GL_VIEWS_CHECK_OPENGL_ERROR
		} // if( m_bNoCullFace )
		if( m_bAdjustAlphaFunc )
		{
			glEnable( GL_ALPHA_TEST );
			GL_VIEWS_CHECK_OPENGL_ERROR
			glAlphaFunc( m_gleAlphaFunc, m_glcAlphaRef );
			GL_VIEWS_CHECK_OPENGL_ERROR
		} // if( m_bAdjustAlphaFunc )
		if( m_bAdjustBlendFunc )
		{
			glEnable( GL_BLEND );
			GL_VIEWS_CHECK_OPENGL_ERROR
			glBlendFunc( m_gleBlendFactorS, m_gleBlendFactorD );
			GL_VIEWS_CHECK_OPENGL_ERROR
		} // if( m_bAdjustBlendFunc )
		if( m_nTextureIndex >= 0 )
		{
			ASSERT( m_nTextureIndex < GL_VIEWS_TEXTURE_COUNT );
			glEnable( GL_TEXTURE_2D );
			GL_VIEWS_CHECK_OPENGL_ERROR
			glBindTexture(
				GL_TEXTURE_2D,
				pView3D->m_TextureIds[m_nTextureIndex]
				);
			GL_VIEWS_CHECK_OPENGL_ERROR
		} // if( m_nTextureIndex >= 0 )
		glBegin(GL_QUADS);
			for( int nVertexIdx = 0; nVertexIdx < 4; nVertexIdx++ )
			{
				glTexCoord2f(
					m_arrTextureCoords[nVertexIdx].m_fX,
					m_arrTextureCoords[nVertexIdx].m_fY
					);
				glVertex3fv(
					m_arrPoints[nVertexIdx].arr
					);
			}
		glEnd();
		if( m_nTextureIndex >= 0 )
		{
			ASSERT( m_nTextureIndex < GL_VIEWS_TEXTURE_COUNT );
			glDisable( GL_TEXTURE_2D );
			GL_VIEWS_CHECK_OPENGL_ERROR
		} // if( m_nTextureIndex >= 0 )
		if( m_bAdjustBlendFunc )
		{
			glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
			GL_VIEWS_CHECK_OPENGL_ERROR
			glDisable( GL_BLEND );
			GL_VIEWS_CHECK_OPENGL_ERROR
		} // if( m_bAdjustBlendFunc )
		if( m_bAdjustAlphaFunc )
		{
			glDisable( GL_ALPHA_TEST );
			GL_VIEWS_CHECK_OPENGL_ERROR
		} // if( m_bAdjustAlphaFunc )
		if( m_bNoCullFace )
		{
			glEnable( GL_CULL_FACE );
			GL_VIEWS_CHECK_OPENGL_ERROR
		} // if( m_bNoCullFace )
		if( m_bNoDepth )
		{
			glEnable( GL_DEPTH_TEST );
			GL_VIEWS_CHECK_OPENGL_ERROR
		} // if( m_bNoDepth )
	glPopMatrix();
}

/////////////////////////////////////////////////////////////////////////////
// C3DOuterScene

IMPLEMENT_DYNCREATE( C3DOuterScene, C3DObject );

volatile bool C3DOuterScene::g_bRenderOuterScene = true;
GLfloat C3DOuterScene::g_fBottomPlaneValX = 0.7f;
GLfloat C3DOuterScene::g_fBottomPlaneValY = 0.4f;
GLfloat C3DOuterScene::g_fBottomPlaneValZ = 0.7f;
GLfloat C3DOuterScene::g_fRingRadius = 0.80f;
GLint C3DOuterScene::g_nSphereValStacks = 12;

C3DOuterScene::C3DOuterScene()
	: C3DObject( GL_VIEWS_OUTER_SCENE_NAME )
{
}

C3DOuterScene::~C3DOuterScene()
{
}

void C3DOuterScene::OnThreadInit( LPVOID lpvCookie )
{
	ASSERT_VALID( this );
	lpvCookie;

C3DSquare * pObjSquare = new C3DSquare;
	pObjSquare->m_nTextureIndex = GL_VIEWS_TEXTURE_IDX_BOTTOM_PLANE;
	pObjSquare->m_bNoDepth = true;
	pObjSquare->m_arrTextureCoords[3].m_fX = 2.0f;
	pObjSquare->m_arrTextureCoords[3].m_fY = 2.0f;
	pObjSquare->m_arrPoints[3] = _v3t( -g_fBottomPlaneValX, -g_fBottomPlaneValY, -g_fBottomPlaneValZ );
	pObjSquare->m_arrTextureCoords[2].m_fX = 0.0f;
	pObjSquare->m_arrTextureCoords[2].m_fY = 2.0f;
	pObjSquare->m_arrPoints[2] = _v3t(  g_fBottomPlaneValX, -g_fBottomPlaneValY, -g_fBottomPlaneValZ );
	pObjSquare->m_arrTextureCoords[1].m_fX = 0.0f;
	pObjSquare->m_arrTextureCoords[1].m_fY = 0.0f;
	pObjSquare->m_arrPoints[1] = _v3t(  g_fBottomPlaneValX, -g_fBottomPlaneValY,  g_fBottomPlaneValZ );
	pObjSquare->m_arrTextureCoords[0].m_fX = 2.0f;
	pObjSquare->m_arrTextureCoords[0].m_fY = 0.0f;
	pObjSquare->m_arrPoints[0] = _v3t( -g_fBottomPlaneValX, -g_fBottomPlaneValY,  g_fBottomPlaneValZ );
	pObjSquare->m_bUseNormal = true;
_v3t pt0(
	pObjSquare->m_arrPoints[1].x - pObjSquare->m_arrPoints[0].x,
	pObjSquare->m_arrPoints[1].y - pObjSquare->m_arrPoints[0].y,
	pObjSquare->m_arrPoints[1].z - pObjSquare->m_arrPoints[0].z
	);
_v3t pt1(
	pObjSquare->m_arrPoints[2].x - pObjSquare->m_arrPoints[0].x,
	pObjSquare->m_arrPoints[2].y - pObjSquare->m_arrPoints[0].y,
	pObjSquare->m_arrPoints[2].z - pObjSquare->m_arrPoints[0].z
	);
_v3t vNormal = pt0 ^ pt1;
	vNormal.normalize();
	pObjSquare->m_vecNormal = vNormal;
	AddChild( pObjSquare );

	GenerateSphere(
		GL_VIEWS_TEXTURE_IDX_RING,
		_v3t( 0.0f, 0.0f, 0.0f ),
		g_fRingRadius,
		g_nSphereValStacks,
		_ntr::get_pi()*2.0f,
		0.0f,
		- 0.3f,
		+ 0.7f,
		true
		);
}

bool C3DOuterScene::IsRenderSubtree()
{
	ASSERT_VALID( this );
	return g_bRenderOuterScene;
}

void C3DOuterScene::OnQueryTreeDisplayParms(
	CString & strTreeItemText,
	int & nTreeImageIndex
	)
{
	ASSERT_VALID( this );
	C3DObject::OnQueryTreeDisplayParms(
		strTreeItemText,
		nTreeImageIndex
		);
	nTreeImageIndex = GL_VIEWS_TREE_IMG_IDX_OUTER_SCENE;
}

/////////////////////////////////////////////////////////////////////////////
// C3DCamera

IMPLEMENT_DYNCREATE( C3DCamera, C3DObject );

const GLfloat C3DCamera::g_arrFovValues[GL_VIEWS_FOV_COUNT] =
{
	(( 10.0f*3.1415926535897932384626433832795f)/180.0f ), //  0  10 degrees
	(( 15.0f*3.1415926535897932384626433832795f)/180.0f ), //  1  15 degrees
	(( 20.0f*3.1415926535897932384626433832795f)/180.0f ), //  2  20 degrees
	(( 25.0f*3.1415926535897932384626433832795f)/180.0f ), //  3  25 degrees
	(( 30.0f*3.1415926535897932384626433832795f)/180.0f ), //  4  30 degrees
	(( 35.0f*3.1415926535897932384626433832795f)/180.0f ), //  5  35 degrees
	(( 40.0f*3.1415926535897932384626433832795f)/180.0f ), //  6  40 degrees
	(( 45.0f*3.1415926535897932384626433832795f)/180.0f ), //  7  45 degrees
	(( 50.0f*3.1415926535897932384626433832795f)/180.0f ), //  8  50 degrees
	(( 55.0f*3.1415926535897932384626433832795f)/180.0f ), //  9  55 degrees
	(( 60.0f*3.1415926535897932384626433832795f)/180.0f ), // 10  60 degrees
	(( 65.0f*3.1415926535897932384626433832795f)/180.0f ), // 11  65 degrees
	(( 70.0f*3.1415926535897932384626433832795f)/180.0f ), // 12  70 degrees
	(( 75.0f*3.1415926535897932384626433832795f)/180.0f ), // 13  75 degrees
	(( 80.0f*3.1415926535897932384626433832795f)/180.0f ), // 14  80 degrees
	(( 85.0f*3.1415926535897932384626433832795f)/180.0f ), // 15  85 degrees
	(( 90.0f*3.1415926535897932384626433832795f)/180.0f ), // 16  90 degrees
	(( 95.0f*3.1415926535897932384626433832795f)/180.0f ), // 17  95 degrees
	((100.0f*3.1415926535897932384626433832795f)/180.0f ), // 18 100 degrees
	((110.0f*3.1415926535897932384626433832795f)/180.0f ), // 19 110 degrees
	((120.0f*3.1415926535897932384626433832795f)/180.0f ), // 20 120 degrees
	((130.0f*3.1415926535897932384626433832795f)/180.0f ), // 21 130 degrees
	((140.0f*3.1415926535897932384626433832795f)/180.0f ), // 22 140 degrees
	((150.0f*3.1415926535897932384626433832795f)/180.0f ), // 23 150 degrees
	((160.0f*3.1415926535897932384626433832795f)/180.0f ), // 24 160 degrees
	((170.0f*3.1415926535897932384626433832795f)/180.0f ), // 25 170 degrees
};

volatile bool C3DCamera::g_bRenderCameraAxes = true;
GLfloat C3DCamera::g_fAxisLineLength = 0.025f;
GLfloat C3DCamera::g_fAxisLineWidth = 2.0f;

C3DCamera::C3DCamera(
	UINT nTreeDblClickCmdID, // = 0L
	LPCTSTR sName, // = GL_VIEWS_NONAME
	int nFovIndex, // = GL_VIEWS_FOV_DEF_INDEX
	GLfloat fNearPlane, // = 1.0f
	GLfloat fFarPlane // = 5.0f
	)
	: C3DObject( sName )
	, m_nTreeDblClickCmdID( nTreeDblClickCmdID )
	, m_fAspect( 1.0f )
	, m_nFovIndex( nFovIndex )
	, m_fNearPlane( fNearPlane )
	, m_fFarPlane( fFarPlane )
{
	ASSERT( 0 <= m_nFovIndex && m_nFovIndex < GL_VIEWS_FOV_COUNT );
}

C3DCamera::~C3DCamera()
{
}

void C3DCamera::SerializeState(
	CArchive & ar
	)
{
	ASSERT_VALID( this );
	ASSERT( 0 <= m_nFovIndex && m_nFovIndex < GL_VIEWS_FOV_COUNT );
	C3DObject::SerializeState( ar );
	if( ar.IsStoring() )
	{
		ar << m_fAspect;
		ar << m_nFovIndex;
		ar << m_fNearPlane;
		ar << m_fFarPlane;
	} // if( ar.IsStoring() )
	else
	{
		ar >> m_fAspect;
		ar >> m_nFovIndex;
		ASSERT( 0 <= m_nFovIndex && m_nFovIndex < GL_VIEWS_FOV_COUNT );
		if( !(0 <= m_nFovIndex && m_nFovIndex < GL_VIEWS_FOV_COUNT) )
			m_nFovIndex = GL_VIEWS_FOV_DEF_INDEX;
		ar >> m_fNearPlane;
		ar >> m_fFarPlane;
	} // else from if( ar.IsStoring() )
}

void C3DCamera::OnRender(
	C3DCamera * pCam,
	C3DView * pView3D,
	LPVOID lpvCookie,
	C3DMirror * pObjMirror
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pCam );
	ASSERT_VALID( pView3D );
	pCam;
	pView3D;
	lpvCookie;
	if( (!g_bRenderCameraAxes) )
		return;
	if( pCam == this && pObjMirror == NULL )
		return;
	glPushMatrix();
	glMultMatrixf( m_mtxLastTransformation.arr );
		glLineWidth( g_fAxisLineWidth );
		GL_VIEWS_CHECK_OPENGL_ERROR
		glBegin( GL_LINES );
			glColor3f( 1.0f, 0.0f, 0.0f );	glVertex3f( 0.0f, 0.0f, 0.0f );	glVertex3f( g_fAxisLineLength,              0.0f,              0.0f );
			glColor3f( 0.0f, 1.0f, 0.0f );	glVertex3f( 0.0f, 0.0f, 0.0f );	glVertex3f(              0.0f, g_fAxisLineLength,              0.0f );
			glColor3f( 0.0f, 0.0f, 1.0f );	glVertex3f( 0.0f, 0.0f, 0.0f );	glVertex3f(              0.0f,              0.0f, g_fAxisLineLength );
			glColor3f( 1.0f, 1.0f, 1.0f ); 
		glEnd();
	glPopMatrix();
}

void C3DCamera::OnTreeItemDblClick(
	CObjectHierarchyTreeCtrl * pTreeCtrl
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pTreeCtrl );
	ASSERT( pTreeCtrl->GetSafeHwnd() != NULL );
	ASSERT( ::IsWindow( pTreeCtrl->GetSafeHwnd() ) );
	ASSERT( m_hti != NULL );
	if( m_nTreeDblClickCmdID == 0L )
		return;
CFrameWnd * pFrame = pTreeCtrl->GetParentFrame();
	ASSERT_VALID( pFrame );
	if( pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)) )
	{
		pFrame = pFrame->GetParentFrame();
		ASSERT_VALID( pFrame );
		ASSERT( !pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)) );
	}
	pFrame->SendMessage( WM_COMMAND, m_nTreeDblClickCmdID );
}

void C3DCamera::OnQueryTreeDisplayParms(
	CString & strTreeItemText,
	int & nTreeImageIndex
	)
{
	ASSERT_VALID( this );
	C3DObject::OnQueryTreeDisplayParms(
		strTreeItemText,
		nTreeImageIndex
		);
	nTreeImageIndex = GL_VIEWS_TREE_IMG_IDX_CAMERA_OBJ;
}

/////////////////////////////////////////////////////////////////////////////
// C3DCube

IMPLEMENT_DYNCREATE( C3DCube, C3DObject );

volatile bool C3DCube::g_bRenderCubeObjects = true;
GLfloat C3DCube::g_fCubeVal = 0.03f;
GLfloat C3DCube::g_fTranslateCubeVal = C3DCube::g_fCubeVal * 2.2f;

C3DCube::C3DCube(
	LPCTSTR sName, // = GL_VIEWS_NONAME
	bool bCenterCube // = false
	)
	: C3DObject( sName )
	, m_bCenterCube( bCenterCube )
{
}

C3DCube::~C3DCube()
{
}

GLfloat C3DCube::g_fCenterCubePlayPitch = _ntr::d2r(0.4f);
GLfloat C3DCube::g_fCenterCubePlayYaw = _ntr::d2r(0.3f);
GLfloat C3DCube::g_fCenterCubePlayRoll = _ntr::d2r(0.2f);

void C3DCube::OnThreadInit( LPVOID lpvCookie )
{
	ASSERT_VALID( this );
	lpvCookie;

static const struct
{
	int m_nTextureIndex;
	struct {
		GLfloat m_fTextureX, m_fTextureY,
			m_fPosX, m_fPosY, m_fPosZ;
	} m_arrVertexData[4];
} g_arrSquaresInitData[] = 
{
	{	GL_VIEWS_TEXTURE_IDX_CUBE_WHITE,
		{
			{ 0.0f, 0.0f, -g_fCubeVal, -g_fCubeVal,  g_fCubeVal },
			{ 1.0f, 0.0f,  g_fCubeVal, -g_fCubeVal,  g_fCubeVal },
			{ 1.0f, 1.0f,  g_fCubeVal,  g_fCubeVal,  g_fCubeVal },
			{ 0.0f, 1.0f, -g_fCubeVal,  g_fCubeVal,  g_fCubeVal },
		},
	},	
	{	GL_VIEWS_TEXTURE_IDX_CUBE_WHITE,
		{
			{ 1.0f, 0.0f, -g_fCubeVal, -g_fCubeVal, -g_fCubeVal },
			{ 1.0f, 1.0f, -g_fCubeVal,  g_fCubeVal, -g_fCubeVal },
			{ 0.0f, 1.0f,  g_fCubeVal,  g_fCubeVal, -g_fCubeVal },
			{ 0.0f, 0.0f,  g_fCubeVal, -g_fCubeVal, -g_fCubeVal },
		},
	},	
	{	GL_VIEWS_TEXTURE_IDX_CUBE_ORANGE,
		{
			{ 1.0f, 0.0f,  g_fCubeVal, -g_fCubeVal, -g_fCubeVal },
			{ 1.0f, 1.0f,  g_fCubeVal,  g_fCubeVal, -g_fCubeVal },
			{ 0.0f, 1.0f,  g_fCubeVal,  g_fCubeVal,  g_fCubeVal },
			{ 0.0f, 0.0f,  g_fCubeVal, -g_fCubeVal,  g_fCubeVal },
		},
	},	
	{	GL_VIEWS_TEXTURE_IDX_CUBE_ORANGE,
		{
			{ 0.0f, 0.0f, -g_fCubeVal, -g_fCubeVal, -g_fCubeVal },
			{ 1.0f, 0.0f, -g_fCubeVal, -g_fCubeVal,  g_fCubeVal },
			{ 1.0f, 1.0f, -g_fCubeVal,  g_fCubeVal,  g_fCubeVal },
			{ 0.0f, 1.0f, -g_fCubeVal,  g_fCubeVal, -g_fCubeVal },
		},
	},	
};

	for(	int nSquareIdx = 0;
			nSquareIdx < (sizeof(g_arrSquaresInitData)/sizeof(g_arrSquaresInitData[0]));
			nSquareIdx++
		)
	{
		C3DSquare * pObjSquare = new C3DSquare;
		pObjSquare->m_nTextureIndex =
			g_arrSquaresInitData[nSquareIdx].m_nTextureIndex;
		for( int nVertexIdx = 0; nVertexIdx < 4; nVertexIdx++ )
		{
			pObjSquare->m_arrTextureCoords[nVertexIdx].m_fX =
				g_arrSquaresInitData[nSquareIdx].m_arrVertexData[nVertexIdx].m_fTextureX;
			pObjSquare->m_arrTextureCoords[nVertexIdx].m_fY =
				g_arrSquaresInitData[nSquareIdx].m_arrVertexData[nVertexIdx].m_fTextureY;
			pObjSquare->m_arrPoints[nVertexIdx].x =
				g_arrSquaresInitData[nSquareIdx].m_arrVertexData[nVertexIdx].m_fPosX;
			pObjSquare->m_arrPoints[nVertexIdx].y =
				g_arrSquaresInitData[nSquareIdx].m_arrVertexData[nVertexIdx].m_fPosY;
			pObjSquare->m_arrPoints[nVertexIdx].z =
				g_arrSquaresInitData[nSquareIdx].m_arrVertexData[nVertexIdx].m_fPosZ;
		}
		pObjSquare->m_bNoCullFace = true;
		pObjSquare->m_bAdjustAlphaFunc = true;
		pObjSquare->m_bAdjustBlendFunc = true;
		AddChild( pObjSquare );
	}
}

void C3DCube::OnPlay(
	LPVOID lpvCookie
	)
{
	ASSERT_VALID( this );
	lpvCookie;
#ifdef GL_VIEWS_DRAW_ANIMS
	if( m_bCenterCube )
	{
		ASSERT_VALID( m_pParent );
		ASSERT_KINDOF( C3DModifier, m_pParent );
		m_pParent->LocalAdjustOrientation(
			g_fCenterCubePlayPitch,
			g_fCenterCubePlayYaw,
			g_fCenterCubePlayRoll
			);
	}
#endif // GL_VIEWS_DRAW_ANIMS
}

bool C3DCube::IsRenderSubtreeItem( C3DObject * pObjChild )
{
	ASSERT_VALID( this );
	ASSERT_VALID( pObjChild );
	ASSERT( pObjChild->GetParent() == this );
	if( g_bRenderCubeObjects )
		return true;
	if( pObjChild->IsKindOf(RUNTIME_CLASS(C3DSquare)) )
		return false;
	return true;
}

void C3DCube::OnQueryTreeDisplayParms(
	CString & strTreeItemText,
	int & nTreeImageIndex
	)
{
	ASSERT_VALID( this );
	strTreeItemText =
		m_bCenterCube
			? _T("center cube")
			: _T("leaf cube")
			;
	nTreeImageIndex =
		m_bCenterCube
			? GL_VIEWS_TREE_IMG_IDX_CUBE_CENTER
			: GL_VIEWS_TREE_IMG_IDX_CUBE_LEAF
			;
}

/////////////////////////////////////////////////////////////////////////////
// C3DPlanet

IMPLEMENT_DYNCREATE( C3DPlanet, C3DObject );

volatile bool C3DPlanet::g_bRenderPlanetObjects = true;
GLfloat C3DPlanet::g_fPlanetRadiusEarth = 0.04f;
GLfloat C3DPlanet::g_fPlanetRadiusMoon = 0.01f;
GLint C3DPlanet::g_nPlanetSphereStacks = 12;
GLfloat C3DPlanet::g_fAnglePlayStepPitchEarth = _ntr::d2r( 2.5f );
GLfloat C3DPlanet::g_fAnglePlayStepPitchMoon = _ntr::d2r( 4.5f );
GLfloat C3DPlanet::g_fAnglePlayStepYawEarth = _ntr::d2r( 1.5f );
GLfloat C3DPlanet::g_fAnglePlayStepYawMoon = _ntr::d2r( 2.5f );
GLfloat C3DPlanet::g_fAnglePlayStepRollEarth = _ntr::d2r( 4.0f );
GLfloat C3DPlanet::g_fAnglePlayStepRollMoon = _ntr::d2r( 6.0f );

C3DPlanet::C3DPlanet(
	LPCTSTR sName, // = GL_VIEWS_NONAME
	int nPlanetTextureIndex, // = GL_VIEWS_TEXTURE_IDX_EARTH
	GLint nPlanetStacks, // = C3DPlanet::g_nPlanetSphereStacks
	GLfloat fPlanetRadius, // = C3DPlanet::g_fPlanetRadiusEarth
	GLfloat fAnglePlayStepPitch, // = C3DPlanet::g_fAnglePlayStepPitchEarth
	GLfloat fAnglePlayStepYaw, // = C3DPlanet::g_fAnglePlayStepYawEarth
	GLfloat fAnglePlayStepRoll // = C3DPlanet::g_fAnglePlayStepRollMoon
	)
	: C3DObject( sName )
	, m_nPlanetTextureIndex( nPlanetTextureIndex )
	, m_nPlanetStacks( nPlanetStacks )
	, m_fPlanetRadius( fPlanetRadius )
	, m_fAnglePlayStepPitch( fAnglePlayStepPitch )
	, m_fAnglePlayStepYaw( fAnglePlayStepYaw )
	, m_fAnglePlayStepRoll( fAnglePlayStepRoll )
{
}

C3DPlanet::~C3DPlanet()
{
}

void C3DPlanet::OnThreadInit( LPVOID lpvCookie )
{
	ASSERT_VALID( this );
	lpvCookie;
	GenerateSphere(
		m_nPlanetTextureIndex,
		_v3t( 0.0f, 0.0f, 0.0f ),
		m_fPlanetRadius,
		m_nPlanetStacks,
		_ntr::get_pi() * 2.0f,
		0.0f,
		- _ntr::get_pi() / 2.0f,
		+ _ntr::get_pi() / 2.0f
		);
}

bool C3DPlanet::IsRenderSubtreeItem( C3DObject * pObjChild )
{
	ASSERT_VALID( this );
	ASSERT_VALID( pObjChild );
	ASSERT( pObjChild->GetParent() == this );
	if( g_bRenderPlanetObjects )
		return true;
	if( pObjChild->IsKindOf(RUNTIME_CLASS(C3DSquare)) )
		return false;
	return true;
}

void C3DPlanet::OnQueryTreeDisplayParms(
	CString & strTreeItemText,
	int & nTreeImageIndex
	)
{
	ASSERT_VALID( this );
	C3DObject::OnQueryTreeDisplayParms(
		strTreeItemText,
		nTreeImageIndex
		);
	//nTreeImageIndex = ....;
}

void C3DPlanet::OnPlay(
	LPVOID lpvCookie
	)
{
	ASSERT_VALID( this );
	lpvCookie;
	if( !g_bRenderPlanetObjects )
		return;
#ifdef GL_VIEWS_DRAW_ANIMS
	ASSERT_VALID( m_pParent );
	ASSERT_KINDOF( C3DModifier, m_pParent );
	m_pParent->LocalAdjustOrientation(
		m_fAnglePlayStepPitch,
		m_fAnglePlayStepYaw,
		m_fAnglePlayStepRoll
		);
#endif // GL_VIEWS_DRAW_ANIMS
}

/////////////////////////////////////////////////////////////////////////////
// C3DText

IMPLEMENT_DYNCREATE( C3DText, C3DObject );

volatile bool C3DText::g_bRenderTextObjects = true;
GLfloat C3DText::g_fScaleModifier = 0.03f;
GLfloat C3DText::g_fAnglePlayStepPitchText = 0.0f;
GLfloat C3DText::g_fAnglePlayStepYawText = 0.0f;
GLfloat C3DText::g_fAnglePlayStepRollText = _ntr::d2r( 2.0f );

C3DText::C3DText(
	LPCTSTR sName, // = GL_VIEWS_NONAME // should be used to set displayed text or one letter
	COLORREF clrText, // = RGB(255,255,255)
	GLfloat fAnglePlayStepPitch, // = C3DText::g_fAnglePlayStepPitchText
	GLfloat fAnglePlayStepYaw,   // = C3DText::g_fAnglePlayStepYawText
	GLfloat fAnglePlayStepRoll   // = C3DText::g_fAnglePlayStepRollText
	)
	: C3DObject( sName )
	, m_fRed(	GLfloat(GetRValue(clrText)) / 255.0f )
	, m_fGreen(	GLfloat(GetGValue(clrText)) / 255.0f )
	, m_fBlue(	GLfloat(GetBValue(clrText)) / 255.0f )
	, m_fAnglePlayStepPitch( fAnglePlayStepPitch )
	, m_fAnglePlayStepYaw( fAnglePlayStepYaw )
	, m_fAnglePlayStepRoll( fAnglePlayStepRoll )
{
}

C3DText::~C3DText()
{
}

void C3DText::OnPlay(
	LPVOID lpvCookie
	)
{
	ASSERT_VALID( this );
	lpvCookie;
	if( !g_bRenderTextObjects )
		return;
#ifdef GL_VIEWS_DRAW_ANIMS
	ASSERT_VALID( m_pParent );
	ASSERT_KINDOF( C3DModifier, m_pParent );
	m_pParent->LocalAdjustOrientation(
		m_fAnglePlayStepPitch,
		m_fAnglePlayStepYaw,
		m_fAnglePlayStepRoll
		);
#endif // GL_VIEWS_DRAW_ANIMS
}

void C3DText::OnRender(
	C3DCamera * pCam,
	C3DView * pView3D,
	LPVOID lpvCookie,
	C3DMirror * pObjMirror
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pCam );
	ASSERT_VALID( pView3D );
	pCam;
	lpvCookie;
	pObjMirror;
	if( !g_bRenderTextObjects )
		return;
	if( !pView3D->m_Font3D.IsFontCreated() )
		return;
LPCTSTR sText = GetName();
	ASSERT( sText != NULL );
	if( _tcslen(sText) == 0 )
		return;
	glEnable( GL_ALPHA_TEST );
	GL_VIEWS_CHECK_OPENGL_ERROR
	glAlphaFunc( GL_NOTEQUAL, 0.0 );
	GL_VIEWS_CHECK_OPENGL_ERROR
		glDisable( GL_CULL_FACE );
		GL_VIEWS_CHECK_OPENGL_ERROR
			glPushMatrix();
			glMultMatrixf( m_mtxLastTransformation.arr );
				glColor3f( m_fRed, m_fGreen, m_fBlue );
					glEnable( GL_BLEND );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glBlendFunc( GL_SRC_ALPHA, GL_ONE );
					GL_VIEWS_CHECK_OPENGL_ERROR
						glPushMatrix();
							glScalef(
								g_fScaleModifier,
								g_fScaleModifier,
								g_fScaleModifier
								);
							pView3D->m_Font3D.TextOut( sText );
						glPopMatrix();
					glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glDisable( GL_BLEND );
					GL_VIEWS_CHECK_OPENGL_ERROR
				glColor3f( 1.0f, 1.0f, 1.0f ); 
			glPopMatrix();
		glDisable( GL_ALPHA_TEST );
		GL_VIEWS_CHECK_OPENGL_ERROR
	glEnable( GL_CULL_FACE );
	GL_VIEWS_CHECK_OPENGL_ERROR
}

void C3DText::OnQueryTreeDisplayParms(
	CString & strTreeItemText,
	int & nTreeImageIndex
	)
{
	ASSERT_VALID( this );
	strTreeItemText.Format(
		_T("text \"%s\""),
		GetName()
		);
	ASSERT( !strTreeItemText.IsEmpty() );
	nTreeImageIndex = GL_VIEWS_TREE_IMG_IDX_TEXT_OBJ;
}

/////////////////////////////////////////////////////////////////////////////
// C3DWnd

IMPLEMENT_DYNCREATE( C3DWnd, C3DObject );

_v3t C3DWnd::g_arrDefPointsWndAviPlayer[4] =
{
	_v3t( -0.12f, -0.11f, -0.35f ),
	_v3t(  0.12f, -0.11f, -0.35f ),
	_v3t(  0.12f,  0.11f, -0.35f ),
	_v3t( -0.12f,  0.11f, -0.35f ),
};

_v3t C3DWnd::g_arrDefPointsWndMirror[4] =
{
	_v3t(  0.12f, -0.11f,  0.35f ),
	_v3t( -0.12f, -0.11f,  0.35f ),
	_v3t( -0.12f,  0.11f,  0.35f ),
	_v3t(  0.12f,  0.11f,  0.35f ),
};

C3DWnd::C3DWnd(
	LPCTSTR sName, // = GL_VIEWS_WND_AVI_PLAYER
	int nPlaneTextureIndex, // = GL_VIEWS_TEXTURE_IDX_WND_AVI_PLAYER
	_v3rct pt0, // = C3DWnd::g_arrDefPointsWndAviPlayer[0]
	_v3rct pt1, // = C3DWnd::g_arrDefPointsWndAviPlayer[1]
	_v3rct pt2, // = C3DWnd::g_arrDefPointsWndAviPlayer[2]
	_v3rct pt3  // = C3DWnd::g_arrDefPointsWndAviPlayer[3]
	)
	: C3DObject( sName )
	, m_nPlaneTextureIndex( nPlaneTextureIndex )
{
	m_arrWndPoints[0] = pt0;
	m_arrWndPoints[1] = pt1;
	m_arrWndPoints[2] = pt2;
	m_arrWndPoints[3] = pt3;
	_RecalcNormalAndContentArea();
}

C3DWnd::~C3DWnd()
{
}

void C3DWnd::_RecalcNormalAndContentArea()
{
	ASSERT_VALID( this );
_v3t pt0(
	m_arrWndPoints[1].x - m_arrWndPoints[0].x,
	m_arrWndPoints[1].y - m_arrWndPoints[0].y,
	m_arrWndPoints[1].z - m_arrWndPoints[0].z
	);
_v3t pt1(
	m_arrWndPoints[2].x - m_arrWndPoints[0].x,
	m_arrWndPoints[2].y - m_arrWndPoints[0].y,
	m_arrWndPoints[2].z - m_arrWndPoints[0].z
	);
	m_lastNormal = pt0 ^ pt1;
	m_lastNormal.normalize();

	stat_CalcWindowContentPlane(
		m_arrWndPoints,
		m_arrContentPoints
		);
}

void C3DWnd::stat_CalcWindowContentPlane(
	_v3t * arrWndPoints,
	_v3t * arrContentPoints
	)
{
	ASSERT( arrWndPoints != NULL );
	ASSERT( arrContentPoints != NULL );
	for( int i = 0; i< 4; i++ )
	{
//		arrContentPoints[i].x = arrWndPoints[i].x * 0.9700f;
//		arrContentPoints[i].y = arrWndPoints[i].y * 0.8000f;
//		arrContentPoints[i].z = arrWndPoints[i].z - arrWndPoints[i].z * 0.0001f;
		arrContentPoints[i].x = arrWndPoints[i].x * 0.9650f;
		arrContentPoints[i].y = arrWndPoints[i].y * ( (i < 2 ) ? 0.7850f : 0.7600f );
		arrContentPoints[i].z = arrWndPoints[i].z - arrWndPoints[i].z * 0.0001f;
	}
}

void C3DWnd::OnRender(
	C3DCamera * pCam,
	C3DView * pView3D,
	LPVOID lpvCookie,
	C3DMirror * pObjMirror
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pCam );
	ASSERT_VALID( pView3D );
	pCam;
	pView3D;
	lpvCookie;
	pObjMirror;
	glPushMatrix();
	glMultMatrixf( m_mtxLastTransformation.arr );
		glEnable( GL_ALPHA_TEST );
		GL_VIEWS_CHECK_OPENGL_ERROR
		glAlphaFunc( GL_NOTEQUAL, 0.0f );
		GL_VIEWS_CHECK_OPENGL_ERROR
			glEnable( GL_BLEND );
			GL_VIEWS_CHECK_OPENGL_ERROR
			glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR );
			GL_VIEWS_CHECK_OPENGL_ERROR
				glEnable( GL_TEXTURE_2D );
				GL_VIEWS_CHECK_OPENGL_ERROR
					glBindTexture(
						GL_TEXTURE_2D,
						pView3D->m_TextureIds[m_nPlaneTextureIndex]
						);
					GL_VIEWS_CHECK_OPENGL_ERROR
					glDisable( GL_DEPTH_TEST );
					GL_VIEWS_CHECK_OPENGL_ERROR
						glBegin(GL_QUADS);
							glNormal3fv( m_lastNormal.arr );
							glTexCoord2f(0.0f, 0.0f); glVertex3fv( m_arrWndPoints[0].arr );
							glTexCoord2f(1.0f, 0.0f); glVertex3fv( m_arrWndPoints[1].arr );
							glTexCoord2f(1.0f, 1.0f); glVertex3fv( m_arrWndPoints[2].arr );
							glTexCoord2f(0.0f, 1.0f); glVertex3fv( m_arrWndPoints[3].arr );
						glEnd();
					glEnable( GL_DEPTH_TEST );
					GL_VIEWS_CHECK_OPENGL_ERROR
				glDisable( GL_TEXTURE_2D );
				GL_VIEWS_CHECK_OPENGL_ERROR
			glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
			GL_VIEWS_CHECK_OPENGL_ERROR
			glDisable( GL_BLEND );
			GL_VIEWS_CHECK_OPENGL_ERROR
		glDisable( GL_ALPHA_TEST );
		GL_VIEWS_CHECK_OPENGL_ERROR
	glPopMatrix();
}

/////////////////////////////////////////////////////////////////////////////
// C3DMirror

IMPLEMENT_DYNCREATE( C3DMirror, C3DWnd );

volatile bool C3DMirror::g_bRenderMirrors = true;

C3DMirror::C3DMirror(
	LPCTSTR sName, // = GL_VIEWS_WND_MIRROR
	int nPlaneTextureIndex, // = GL_VIEWS_TEXTURE_IDX_WND_MIRROR
	_v3rct pt0, // = C3DWnd::g_arrDefPointsWndMirror[0]
	_v3rct pt1, // = C3DWnd::g_arrDefPointsWndMirror[1]
	_v3rct pt2, // = C3DWnd::g_arrDefPointsWndMirror[2]
	_v3rct pt3  // = C3DWnd::g_arrDefPointsWndMirror[3]
	)
	: C3DWnd( sName, nPlaneTextureIndex, pt0, pt1, pt2, pt3 )
	, m_bRenderingThisMirror( false )
{
}

C3DMirror::~C3DMirror()
{
}

void C3DMirror::OnRender(
	C3DCamera * pCam,
	C3DView * pView3D,
	LPVOID lpvCookie,
	C3DMirror * pObjMirror
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pCam );
	ASSERT_VALID( pView3D );
	pCam;
	pView3D;
	lpvCookie;
	if( m_bRenderingThisMirror )
		return;
	C3DWnd::OnRender( pCam, pView3D, lpvCookie, pObjMirror );
	if( !g_bRenderMirrors )
		return;
	if( pObjMirror != NULL )
		return; // multiply mirrors currently not supported by this sample
	m_bRenderingThisMirror = true;
		// clear mirror (make it black)
		glDisable( GL_DEPTH_TEST );
		GL_VIEWS_CHECK_OPENGL_ERROR
			glPushMatrix();
			glMultMatrixf( m_mtxLastTransformation.arr );
				glBegin( GL_QUADS );
					glColor3f( 0.0f, 0.0f, 0.0f );
						glVertex3fv( m_arrContentPoints[0].arr );
						glVertex3fv( m_arrContentPoints[1].arr );
						glVertex3fv( m_arrContentPoints[2].arr );
						glVertex3fv( m_arrContentPoints[3].arr );
					glColor3f( 1.0f, 1.0f, 1.0f );
				glEnd();
			glPopMatrix();
		glEnable( GL_DEPTH_TEST );
		GL_VIEWS_CHECK_OPENGL_ERROR
		// create content mask in the stencil buffer
		glEnable( GL_STENCIL_TEST );
		GL_VIEWS_CHECK_OPENGL_ERROR
		glStencilFunc( GL_ALWAYS, 1, 1 );
		GL_VIEWS_CHECK_OPENGL_ERROR
		glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
		GL_VIEWS_CHECK_OPENGL_ERROR
			glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
			GL_VIEWS_CHECK_OPENGL_ERROR
			glDisable( GL_DEPTH_TEST );
			GL_VIEWS_CHECK_OPENGL_ERROR
				glPushMatrix();
				glMultMatrixf( m_mtxLastTransformation.arr );
					glBegin( GL_QUADS );
						glVertex3fv( m_arrContentPoints[0].arr );
						glVertex3fv( m_arrContentPoints[1].arr );
						glVertex3fv( m_arrContentPoints[2].arr );
						glVertex3fv( m_arrContentPoints[3].arr );
					glEnd();
				glPopMatrix();
			glEnable( GL_DEPTH_TEST );
			GL_VIEWS_CHECK_OPENGL_ERROR
			glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
			GL_VIEWS_CHECK_OPENGL_ERROR
		// compute reflection matrix and render mirror content
		glStencilFunc( GL_EQUAL, 1, 1 );
		GL_VIEWS_CHECK_OPENGL_ERROR
		glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
		GL_VIEWS_CHECK_OPENGL_ERROR
			glPushMatrix();
				_mt _mtxReflection;
// TODO: calc dynamically m_arrContentPoints[0].z for _ptEq (plane equation)
_v4t _ptEq( m_lastNormal.x, m_lastNormal.y, m_lastNormal.z, m_arrContentPoints[0].z );
//_v4t _ptEq( 0.0f, 0.0f, -1.0f, 0.35f );
				_mtxReflection.load_reflection( _ptEq );
				glMultMatrixf( _mtxReflection.arr );
				double _ptEqDouble[4] = { _ptEq.a, _ptEq.b, _ptEq.c, _ptEq.d };
				glClipPlane( GL_CLIP_PLANE0, _ptEqDouble );
				GL_VIEWS_CHECK_OPENGL_ERROR
				glEnable( GL_CLIP_PLANE0 );
				GL_VIEWS_CHECK_OPENGL_ERROR
					glCullFace( GL_BACK );
					GL_VIEWS_CHECK_OPENGL_ERROR
						the3DPipe.GetRoot()->WalkTree(
							C3DObject::EWTQ_RENDER,
							pCam,
							pView3D,
							lpvCookie,
							this
							);
					glCullFace( GL_FRONT );
					GL_VIEWS_CHECK_OPENGL_ERROR
				glDisable( GL_CLIP_PLANE0 );
				GL_VIEWS_CHECK_OPENGL_ERROR
			glPopMatrix();
		glDisable( GL_STENCIL_TEST );
		GL_VIEWS_CHECK_OPENGL_ERROR
	m_bRenderingThisMirror = false;
}

void C3DMirror::OnQueryTreeDisplayParms(
	CString & strTreeItemText,
	int & nTreeImageIndex
	)
{
	ASSERT_VALID( this );
	C3DObject::OnQueryTreeDisplayParms(
		strTreeItemText,
		nTreeImageIndex
		);
	nTreeImageIndex = GL_VIEWS_TREE_IMG_IDX_WND_MIRROR;
}

/////////////////////////////////////////////////////////////////////////////
// C3DAviPlayer

IMPLEMENT_DYNCREATE( C3DAviPlayer, C3DWnd );

volatile bool C3DAviPlayer::g_bRenderAviPlayers = true;

static LPCTSTR g_sAviPlayerTempFilePath = _T(".\\AVITEMP.AVI");

C3DAviPlayer::C3DAviPlayer(
	LPCTSTR sName, // = GL_VIEWS_WND_AVI_PLAYER
	int nPlaneTextureIndex, // = GL_VIEWS_TEXTURE_IDX_WND_AVI_PLAYER
	int nSurfaceTextureIndex, // = GL_VIEWS_TEXTURE_IDX_AVI_SURFACE
	_v3rct pt0, // = C3DWnd::g_arrDefPointsWndAviPlayer[0]
	_v3rct pt1, // = C3DWnd::g_arrDefPointsWndAviPlayer[1]
	_v3rct pt2, // = C3DWnd::g_arrDefPointsWndAviPlayer[2]
	_v3rct pt3, // = C3DWnd::g_arrDefPointsWndAviPlayer[3]
	int nRenderWidth, // = 256
	int nRenderHeight // = 256
	)
	: C3DWnd( sName, nPlaneTextureIndex, pt0, pt1, pt2, pt3 )
	, m_bInitComplete( false )
	, m_pAviStream( NULL )
	, m_pGetFrame( NULL )
	, m_nAviWidth( 0 )
	, m_nAviHeight( 0 )
	, m_nRenderWidth( nRenderWidth )
	, m_nRenderHeight( nRenderHeight )
	, m_nRenderSize( nRenderWidth*nRenderHeight )
	, m_hDrawDib( NULL )
	, m_nFrameNumber( 0 )
	, m_nFrameCount( 0 )
	, m_hDC( NULL )
	, m_hBitmap( NULL )
	, m_pDibRawData( NULL )
	, m_nSurfaceTextureIndex( nSurfaceTextureIndex )
{
	ATLASSERT( m_nRenderWidth > 0 );
	ATLASSERT( m_nRenderHeight > 0 );
	ATLASSERT( m_nRenderSize > 0 );
}

C3DAviPlayer::~C3DAviPlayer()
{
	ASSERT( !m_bInitComplete );
}

void C3DAviPlayer::stat_AlertDisplay( LPCTSTR sText )
{
	ASSERT( sText != NULL );
	::AfxMessageBox( sText, MB_OK|MB_ICONERROR );
}

void C3DAviPlayer::OnThreadInit( LPVOID lpvCookie )
{
	ASSERT_VALID( this );
	C3DObject::OnThreadInit( lpvCookie );
	ATLASSERT( m_nRenderWidth > 0 );
	ATLASSERT( m_nRenderHeight > 0 );
	ATLASSERT( m_nRenderSize > 0 );
	
	if( !stat_IsFileExists(g_sAviPlayerTempFilePath) )
	{
		LPVOID lpvBuffer = NULL;
		DWORD dwSize = 0;
		if(		!stat_LoadResourceToMemory(
					MAKEINTRESOURCE(IDR_AVIFILE_FOR_PLAYER),
					_T("AVI"),
					&lpvBuffer,
					&dwSize
					)
			||	lpvBuffer == NULL
			||	dwSize == 0
			)
		{
			ASSERT( FALSE );
			stat_AlertDisplay( _T("Failed to load AVI resource") );
			return;
		}
	
		bool bFileSaved = false;
		try
		{
			CFile _file(
				g_sAviPlayerTempFilePath,
				CFile::modeCreate
					|CFile::modeWrite
					|CFile::typeBinary
					|CFile::shareExclusive
				);
			_file.Seek( 0, CFile::begin );
			_file.Write( lpvBuffer, dwSize );
			_file.Close();
			bFileSaved = true;
		} // try
		catch( CException * pXept )
		{
			pXept->Delete();
			ASSERT( FALSE );
		} // catch( CException * pXept )
		catch( ... )
		{
			ASSERT( FALSE );
		} // catch( ... )

		::free( lpvBuffer );

		if( !bFileSaved )
		{
			ASSERT( FALSE );
			stat_AlertDisplay( _T("Failed to extract AVI resource") );
			return;
		}
	} // if( !statIsFileExists(sFilePath) )
	
	::AVIFileInit();
	if( ::AVIStreamOpenFromFile(
			&m_pAviStream,
			g_sAviPlayerTempFilePath,
			streamtypeVIDEO,
			0,
			OF_READ,
			NULL
			) != 0
		)
	{
		ASSERT( FALSE );
		stat_AlertDisplay( _T("AVI stream initialization failed") );
		return;
	}
	::AVIStreamInfo(
		m_pAviStream,
		&m_pAviInfo,
		sizeof(m_pAviInfo)
		);
	m_nAviWidth =
		m_pAviInfo.rcFrame.right - m_pAviInfo.rcFrame.left;
	m_nAviHeight =
		m_pAviInfo.rcFrame.bottom - m_pAviInfo.rcFrame.top;
	m_nFrameCount =
		::AVIStreamLength( m_pAviStream );
	m_hDC =
		::CreateCompatibleDC( NULL );
	if( m_hDC == NULL )
	{
		ASSERT( FALSE );
		stat_AlertDisplay( _T("Failed to alloc HDC for AVI stream") );
		return;
	}
	::memset( &m_dataBmpInfoHdr, 0, sizeof(BITMAPINFOHEADER) );
	m_dataBmpInfoHdr.biSize = sizeof(BITMAPINFOHEADER);
	m_dataBmpInfoHdr.biPlanes = 1;
	m_dataBmpInfoHdr.biBitCount = 32; //24;
	m_dataBmpInfoHdr.biWidth = m_nRenderWidth;
	m_dataBmpInfoHdr.biHeight = m_nRenderHeight;
	m_dataBmpInfoHdr.biCompression = BI_RGB;
	m_hBitmap =
		::CreateDIBSection(
			m_hDC,
			(BITMAPINFO*)( &m_dataBmpInfoHdr ),
			DIB_RGB_COLORS,
			(void**)(&m_pDibRawData),
			NULL,
			NULL
			);
	if( m_hBitmap == NULL )
	{
		ASSERT( FALSE );
		stat_AlertDisplay( _T("Failed to create DIB section") );
		return;
	}
	ATLASSERT( m_pDibRawData != NULL );
	::SelectObject( m_hDC, m_hBitmap );
	m_pGetFrame =
		::AVIStreamGetFrameOpen(
			m_pAviStream,
			NULL
			);
	if( m_pGetFrame == NULL )
	{
		ASSERT( FALSE );
		stat_AlertDisplay( _T("AVI frame initialization failed") );
		return;
	}
	m_hDrawDib = ::DrawDibOpen();
	if( m_hDrawDib == NULL )
	{
		ASSERT( FALSE );
		stat_AlertDisplay( _T("DrawDibOpen() failed") );
		return;
	}
	m_bInitComplete = true;
}

void C3DAviPlayer::OnThreadDone( LPVOID lpvCookie )
{
	ASSERT_VALID( this );
	C3DObject::OnThreadDone( lpvCookie );
	if( m_hBitmap != NULL )
		::DeleteObject( m_hBitmap );
	if( m_hDrawDib != NULL )
		::DrawDibClose( m_hDrawDib );
	if( m_pGetFrame != NULL )
		::AVIStreamGetFrameClose( m_pGetFrame );
	if( m_pAviStream != NULL )
		::AVIStreamRelease( m_pAviStream );
	::AVIFileExit();
	try
	{
		CFile::Remove( g_sAviPlayerTempFilePath );
	} // try
	catch( CException * pXept )
	{
		pXept->Delete();
		ASSERT( FALSE );
	} // catch( CException * pXept )
	catch( ... )
	{
		ASSERT( FALSE );
	} // catch( ... )
	m_bInitComplete = false;
}

void C3DAviPlayer::OnRender(
	C3DCamera * pCam,
	C3DView * pView3D,
	LPVOID lpvCookie,
	C3DMirror * pObjMirror
	)
{
	ASSERT_VALID( this );
	ASSERT_VALID( pCam );
	ASSERT_VALID( pView3D );
	pCam;
	pView3D;
	lpvCookie;
	C3DWnd::OnRender( pCam, pView3D, lpvCookie, pObjMirror );
	if( (!g_bRenderAviPlayers) || (!m_bInitComplete) )
		return;
	glPushMatrix();
	glMultMatrixf( m_mtxLastTransformation.arr );
		glEnable( GL_TEXTURE_2D );
		GL_VIEWS_CHECK_OPENGL_ERROR
			glBindTexture(
				GL_TEXTURE_2D,
				pView3D->m_TextureIds[m_nSurfaceTextureIndex]
				);
			GL_VIEWS_CHECK_OPENGL_ERROR
			////////// begin get AVI frame //////////
				LPBITMAPINFOHEADER lpbi;
				lpbi = (LPBITMAPINFOHEADER)
					::AVIStreamGetFrame(
						m_pGetFrame,
						m_nFrameNumber
						);
				unsigned char * pAviFrameRawData = (unsigned char *)
					lpbi
					+ lpbi->biSize
					+ lpbi->biClrUsed * sizeof(RGBQUAD);
				::DrawDibDraw(
					m_hDrawDib,
					m_hDC,
					0, 0, m_nRenderWidth, m_nRenderHeight,
					lpbi,
					pAviFrameRawData,
					0, 0, m_nAviWidth, m_nAviHeight,
					0
					);
				unsigned char * pBufferRGBA = m_pDibRawData;
				for( int i = 0; i < m_nRenderSize; i++ )
				{
					unsigned char _byte = *pBufferRGBA;
					*pBufferRGBA = *(pBufferRGBA+2);
					pBufferRGBA ++;
					pBufferRGBA ++;
					*pBufferRGBA = _byte;
					pBufferRGBA ++;
					*pBufferRGBA = 255;
					pBufferRGBA ++;
				}
				glTexSubImage2D(
					GL_TEXTURE_2D, 0,
					0, 0, m_nRenderWidth, m_nRenderHeight,
					GL_RGBA, GL_UNSIGNED_BYTE,
					m_pDibRawData
					);
				GL_VIEWS_CHECK_OPENGL_ERROR
			////////// end get AVI frame //////////
			glBegin( GL_QUADS );
				glTexCoord2f( 0.0f, 0.0f ); glVertex3fv( m_arrContentPoints[0].arr );
				glTexCoord2f( 1.0f, 0.0f ); glVertex3fv( m_arrContentPoints[1].arr );
				glTexCoord2f( 1.0f, 1.0f ); glVertex3fv( m_arrContentPoints[2].arr );
				glTexCoord2f( 0.0f, 1.0f ); glVertex3fv( m_arrContentPoints[3].arr );
			glEnd();
		glDisable( GL_TEXTURE_2D );
		GL_VIEWS_CHECK_OPENGL_ERROR
	glPopMatrix();
}

void C3DAviPlayer::OnQueryTreeDisplayParms(
	CString & strTreeItemText,
	int & nTreeImageIndex
	)
{
	ASSERT_VALID( this );
	C3DObject::OnQueryTreeDisplayParms(
		strTreeItemText,
		nTreeImageIndex
		);
	nTreeImageIndex = GL_VIEWS_TREE_IMG_IDX_WND_AVI;
}

void C3DAviPlayer::OnPlay(
	LPVOID lpvCookie
	)
{
	ASSERT_VALID( this );
	lpvCookie;
#ifdef GL_VIEWS_DRAW_ANIMS
	if( m_bInitComplete && g_bRenderAviPlayers )
	{
		m_nFrameNumber ++;
		if( m_nFrameNumber >= m_nFrameCount )
			m_nFrameNumber = 0;
	} // if( m_bInitComplete && g_bRenderAviPlayers )
#endif // GL_VIEWS_DRAW_ANIMS
}

/////////////////////////////////////////////////////////////////////////////
// C3DTexture

void C3DTexture::_Destroy()
{
	if( m_sizeTexture.cx == 0 )
	{
		ASSERT( m_sizeTexture.cy == 0 );
		ASSERT( m_pData == NULL );
		return;
	}
	ASSERT( m_sizeTexture.cy != 0 );
	ASSERT( m_pData != NULL );
	free( m_pData );
	m_sizeTexture.cx = m_sizeTexture.cy = 0;
	m_pData = NULL;
	m_bAlphaLayerExist = false;
}

C3DTexture::C3DTexture()
	: m_sizeTexture( 0, 0 )
	, m_pData( NULL )
	, m_bAlphaLayerExist( false )
{
}

C3DTexture::~C3DTexture()
{
	_Destroy();
}

bool C3DTexture::LoadResourceBitmapAs32Bit(
	LPCTSTR lpszResource,
	unsigned char nAlphaClearVal // = 255
	)
{
	Empty();
CBitmap _bmp, _dib, *pBmpOldSrc = NULL, *pBmpOldDst = NULL;
	if( !_bmp.LoadBitmap(lpszResource) )
	{
		ASSERT( FALSE );
		return false;
	}
BITMAP _bmp_info;
	_bmp.GetBitmap( &_bmp_info );
	if(		_bmp_info.bmPlanes != 1
		||	_bmp_info.bmWidth <= 0
		||	_bmp_info.bmHeight <= 0
		)
	{
		ASSERT( FALSE );
		return false;
	}
const int nBytesPerPixel = 4;
int nPixelCount = _bmp_info.bmWidth * _bmp_info.bmHeight;
int nBytesCount = nPixelCount * nBytesPerPixel;

CWindowDC dcDesktop( NULL );
CDC dcSrc, dcDst;
	if(		!dcSrc.CreateCompatibleDC(&dcDesktop)
		||	!dcDst.CreateCompatibleDC(&dcDesktop)
		)
	{
		ASSERT( FALSE );
		return false;
	}
BITMAPINFOHEADER bih;
	::memset( (LPVOID)&bih, 0, sizeof(BITMAPINFOHEADER) );
	bih.biSize = sizeof(BITMAPINFOHEADER);
	bih.biWidth = _bmp_info.bmWidth;
	bih.biHeight = _bmp_info.bmHeight;
	bih.biPlanes = 1;
	bih.biBitCount = 32; /*_bmp_info.bmBitsPixel*/;
	bih.biCompression = BI_RGB;
	bih.biSizeImage = nPixelCount;
LPVOID pColorSurface = NULL;
HBITMAP	hDIB =
		::CreateDIBSection(
			dcDesktop.GetSafeHdc(),
			(LPBITMAPINFO)&bih,
			DIB_RGB_COLORS,
			&pColorSurface,
			NULL,
			NULL
			);
	if( hDIB == NULL || pColorSurface == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	_dib.Attach( hDIB );
	pBmpOldSrc = dcSrc.SelectObject( &_bmp );
	pBmpOldDst = dcDst.SelectObject( &_dib );
	dcDst.BitBlt(
		0, 0, _bmp_info.bmWidth, _bmp_info.bmHeight,
		&dcSrc, 
		0, 0,
		SRCCOPY
		);
	dcDst.SelectObject( pBmpOldDst );
	dcSrc.SelectObject( pBmpOldSrc );
	m_pData = ::malloc( nBytesCount );
	if( m_pData == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	::memcpy( m_pData, pColorSurface, nBytesCount );
	m_sizeTexture.cx = _bmp_info.bmWidth;
	m_sizeTexture.cy = _bmp_info.bmHeight;
	ASSERT( !m_bAlphaLayerExist );
	m_bAlphaLayerExist = true;
unsigned char
		_uc0, _uc1, _uc2,
		*pData = (unsigned char *)m_pData;
	for( int i = 0; i < nPixelCount; i++ )
	{
		_uc0 = pData[ 4*i + 0 ];
		_uc1 = pData[ 4*i + 1 ];
		_uc2 = pData[ 4*i + 2 ];
		pData[ 4*i + 0 ] = _uc2;
		pData[ 4*i + 1 ] = _uc1;
		pData[ 4*i + 2 ] = _uc0;
		pData[ 4*i + 3 ] = nAlphaClearVal;
	}
	return true;
}

bool C3DTexture::AddAlphaLayer(
	unsigned char nAlphaClearVal // = 255
	)
{
	if( IsEmpty() || m_bAlphaLayerExist )
		return false;
unsigned char * pDataOld = (unsigned char *)m_pData;
	ASSERT( pDataOld != NULL );
	ASSERT( m_sizeTexture.cx > 0 && m_sizeTexture.cy > 0 );
int nPixelCount = m_sizeTexture.cx * m_sizeTexture.cy;
unsigned char * pDataNew = new unsigned char[4*nPixelCount];
	for( int i = 0; i < nPixelCount; i++ )
	{
		pDataNew[ 4*i + 0 ] = pDataOld[ 3*i + 0 ];
		pDataNew[ 4*i + 1 ] = pDataOld[ 3*i + 1 ];
		pDataNew[ 4*i + 2 ] = pDataOld[ 3*i + 2 ];
		pDataNew[ 4*i + 3 ] = nAlphaClearVal;
	}
	delete [] pDataOld;
	pDataOld = pDataNew;
	return true;
}


bool C3DTexture::SetAlphaLayer(
	unsigned char nAlphaSetVal // = 255
	)
{
	if( IsEmpty() || (!m_bAlphaLayerExist) )
		return false;
unsigned char * pData = (unsigned char *)m_pData;
	ASSERT( pData != NULL );
	ASSERT( m_sizeTexture.cx > 0 && m_sizeTexture.cy > 0 );
int nPixelCount = m_sizeTexture.cx * m_sizeTexture.cy;
	for( int i = 0; i < nPixelCount; i++ )
		pData[ 4*i + 3 ] = nAlphaSetVal;
	return true;
}

bool C3DTexture::SetAlphaLayerIf(
	unsigned char nAlphaSetVal,
	COLORREF clr
	)
{
	if( IsEmpty() || (!m_bAlphaLayerExist) )
		return false;
unsigned char * pData = (unsigned char *)m_pData;
	ASSERT( pData != NULL );
	ASSERT( m_sizeTexture.cx > 0 && m_sizeTexture.cy > 0 );
int nPixelCount = m_sizeTexture.cx * m_sizeTexture.cy;
unsigned char byteR = GetRValue(clr);
unsigned char byteG = GetGValue(clr);
unsigned char byteB = GetBValue(clr);
	for( int i = 0; i < nPixelCount; i++ )
	{
		if(		byteR == pData[ 4*i + 0 ]
			&&	byteG == pData[ 4*i + 1 ]
			&&	byteB == pData[ 4*i + 2 ]
			)
			pData[ 4*i + 3 ] = nAlphaSetVal;
	}
	return true;
}

bool C3DTexture::SetAlphaLayerNB()
{
	if( IsEmpty() || (!m_bAlphaLayerExist) )
		return false;
unsigned char * pData = (unsigned char *)m_pData;
	ASSERT( pData != NULL );
	ASSERT( m_sizeTexture.cx > 0 && m_sizeTexture.cy > 0 );
int nPixelCount = m_sizeTexture.cx * m_sizeTexture.cy;
	for( int i = 0; i < nPixelCount; i++ )
	{
		unsigned char byteR = pData[ 4*i + 0 ];
		pData[ 4*i + 3 ] = byteR;
	}
	return true;
}

/////////////////////////////////////////////////////////////////////////////
// C3DView

IMPLEMENT_DYNCREATE( C3DView, CObject );

C3DView::C3DView(
	HWND hWndOutput // = NULL
	)
	: m_hWndOutput( hWndOutput )
	, m_sizeView( GL_VIEWS_MIN_VIEW_DX, GL_VIEWS_MIN_VIEW_DY )
	, m_sizeViewNE( GL_VIEWS_MIN_VIEW_DX, GL_VIEWS_MIN_VIEW_DY )
	, m_hOpenGlContext( NULL )
	, m_nCameraIndex( 0L )
	, m_strViewName( _T("noname") )
{
	ASSERT( m_hWndOutput != NULL );
	ASSERT( ::IsWindow(m_hWndOutput) );
	_Init();
}

C3DView::~C3DView()
{
	_Done();
}

bool C3DView::IsViewVisible() const
{
	ASSERT_VALID( this );
	ASSERT( m_hWndOutput != NULL );
	ASSERT( ::IsWindow( ((HWND)m_hWndOutput) ) );
	if( ::IsWindowVisible( ((HWND)m_hWndOutput) ) )
	{
		return (
			::SendMessage(
				m_hWndOutput,
				GL_VIEWS_WM_QUERY_VIEW_VISIBILITY,
				0L,
				0L
				) != 0
			) ? true : false;
//		HWND hWndParent = ::GetParent( m_hWndOutput );
//		ASSERT( hWndParent != NULL );
//		ASSERT( ::IsWindow( hWndParent ) );
//		if( ::IsWindowVisible( hWndParent ) )
//			return true;
	}
	return false;
}

void C3DView::Lock()
{
	ASSERT_VALID( this );
	m_csGDI.Lock();
}

void C3DView::Unlock()
{
	ASSERT_VALID( this );
	m_csGDI.Unlock();
}

void C3DView::_Init()
{
	m_dc.SetViewSize( m_sizeView, false );
	m_dc.GetInternalBitmap();
	ASSERT( m_dc.GetSafeHdc() != NULL );
	if( m_hOpenGlContext != NULL )
		return;
static PIXELFORMATDESCRIPTOR pfd =
{
	sizeof(PIXELFORMATDESCRIPTOR),
	1,									
	PFD_SUPPORT_OPENGL|PFD_DRAW_TO_BITMAP,
	PFD_TYPE_RGBA,
	OnGlGetBufferBits(__EBB_COLOR),
	0, 0, 0, 0, 0, 0,
	OnGlGetBufferBits(__EBB_ALPHA),
	0,
	OnGlGetBufferBits(__EBB_ACCUM),
	0, 0, 0, 0,
	OnGlGetBufferBits(__EBB_Z),
	OnGlGetBufferBits(__EBB_STENCIL),
	OnGlGetBufferBits(__EBB_AUXILIARY),
	PFD_MAIN_PLANE,
	0,
	0, 0, 0
};
GLuint PixelFormat = ChoosePixelFormat( m_dc.GetSafeHdc(), &pfd );
	if(	!PixelFormat )
	{
		OnGlAlertDisplay( _T("Failed to choose the pixel format") );
		ASSERT( FALSE );
		return;
	}
	if( !SetPixelFormat( m_dc.GetSafeHdc(), PixelFormat, &pfd ) )
	{
		OnGlAlertDisplay( _T("Failed to set the pixel format") );
		ASSERT( FALSE );
		return;
	}
	m_hOpenGlContext = wglCreateContext( m_dc.GetSafeHdc() );
	if( m_hOpenGlContext == NULL )
	{
		OnGlAlertDisplay( _T("Failed to create OpenGL rendering context") );
		ASSERT( FALSE );
		return;
	}

	if( !wglMakeCurrent( m_dc.GetSafeHdc(), m_hOpenGlContext ) )
	{
		OnGlAlertDisplay( _T("Failed to activate OpenGL rendering context") );
		ASSERT( FALSE );
		return;
	}
struct
{
	LPCTSTR m_lpszResource;
} _texture_init_data[GL_VIEWS_TEXTURE_COUNT] =
{
	{ MAKEINTRESOURCE(IDB_BITMAP_CUBE_ORANGE) },
	{ MAKEINTRESOURCE(IDB_BITMAP_CUBE_WHITE) },
	{ MAKEINTRESOURCE(IDB_BITMAP_RING) },
	{ MAKEINTRESOURCE(IDB_BITMAP_BOTTOM_PLANE) },
	{ MAKEINTRESOURCE(IDB_BITMAP_WND_AVI_PLAYER) },
	{ MAKEINTRESOURCE(IDB_BITMAP_WND_AVI_PLAYER) }, // for surface
	{ MAKEINTRESOURCE(IDB_BITMAP_WND_MIRROR) },
	{ MAKEINTRESOURCE(IDB_BITMAP_EARTH) },
	{ MAKEINTRESOURCE(IDB_BITMAP_MOON) },
};
	
	glEnable( GL_TEXTURE_2D );
	GL_VIEWS_CHECK_OPENGL_ERROR

	for( int nTextureIdx = 0; nTextureIdx < GL_VIEWS_TEXTURE_COUNT; nTextureIdx++ )
	{
		C3DTexture objTexture;
		if( !objTexture.LoadResourceBitmapAs32Bit(
				_texture_init_data[nTextureIdx].m_lpszResource
				)
			)
		{
			ASSERT( FALSE );
			return;
		}
		ASSERT(	objTexture.IsAlphaLayerExist() );
		objTexture.SetAlphaLayerIf( 180, RGB(245,21,3) );
		objTexture.SetAlphaLayerIf( 0, RGB(0,0,0) );
		glGenTextures( 1, &m_TextureIds[nTextureIdx] );
		GL_VIEWS_CHECK_OPENGL_ERROR
		glBindTexture( GL_TEXTURE_2D, m_TextureIds[nTextureIdx] );
		GL_VIEWS_CHECK_OPENGL_ERROR
		glTexImage2D(
			GL_TEXTURE_2D,
			0,
			GL_RGBA,
			objTexture.GetWidth(),
			objTexture.GetHeight(),
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			objTexture.GetData()
			);
		GL_VIEWS_CHECK_OPENGL_ERROR
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		GL_VIEWS_CHECK_OPENGL_ERROR
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
		GL_VIEWS_CHECK_OPENGL_ERROR
	}

	glDisable( GL_TEXTURE_2D );
	GL_VIEWS_CHECK_OPENGL_ERROR

	ASSERT( !m_Font3D.IsFontCreated() );
	VERIFY( m_Font3D.CreateFont( m_dc.GetSafeHdc() ) );
	
	if( !wglMakeCurrent( NULL, NULL ) )
	{
		OnGlAlertDisplay( _T("Failed to release contexts") );
		ASSERT( FALSE );
		return;
	}
}

void C3DView::_Done()
{
	m_Font3D.DeleteFont();
	if( m_hOpenGlContext != NULL )
	{
		if( !wglDeleteContext( m_hOpenGlContext ) )
		{
			OnGlAlertDisplay( _T("Failed to release rendering context") );
			ASSERT( FALSE );
		}
		m_hOpenGlContext = NULL;
	} // if( m_hOpenGlContext != NULL )
	m_dc.DeleteDC();
}

void C3DView::SetViewSize( CSize sizeView )
{
	ASSERT_VALID( this );
	ASSERT( m_sizeView.cx >= GL_VIEWS_MIN_VIEW_DX && m_sizeView.cy >= GL_VIEWS_MIN_VIEW_DY );
	ASSERT( m_sizeViewNE.cx >= GL_VIEWS_MIN_VIEW_DX && m_sizeViewNE.cy >= GL_VIEWS_MIN_VIEW_DY );
	Lock();
	m_sizeViewNE.cx = max( GL_VIEWS_MIN_VIEW_DX, sizeView.cx );
	m_sizeViewNE.cy = max( GL_VIEWS_MIN_VIEW_DY, sizeView.cy );
	Unlock();
}

void C3DView::AdjustViewSize(
	bool bLockView // = true
	)
{
	ASSERT_VALID( this );
	if(	m_sizeView == m_sizeViewNE )
		return;
	if( bLockView )
		Lock();
	ASSERT( m_sizeView.cx >= GL_VIEWS_MIN_VIEW_DX && m_sizeView.cy >= GL_VIEWS_MIN_VIEW_DY );
	ASSERT( m_sizeViewNE.cx >= GL_VIEWS_MIN_VIEW_DX && m_sizeViewNE.cy >= GL_VIEWS_MIN_VIEW_DY );
	_Done();
	m_sizeView = m_sizeViewNE;
	_Init();
	if( bLockView )
		Unlock();
}

void C3DView::DoStepLeft( GLfloat fStepSize )
{
	ASSERT_VALID( this );
	Lock();
C3DCamera * pCam = the3DPipe.GetCamera( m_nCameraIndex );
	ASSERT_VALID( pCam );
	pCam->DoStepLeft( fStepSize );
	Unlock();
}

void C3DView::DoStepUp( GLfloat fStepSize )
{
	ASSERT_VALID( this );
	Lock();
C3DCamera * pCam = the3DPipe.GetCamera( m_nCameraIndex );
	ASSERT_VALID( pCam );
	pCam->DoStepUp( fStepSize );
	Unlock();
}

void C3DView::DoStepForward( GLfloat fStepSize )
{
	ASSERT_VALID( this );
	Lock();
C3DCamera * pCam = the3DPipe.GetCamera( m_nCameraIndex );
	ASSERT_VALID( pCam );
	pCam->DoStepForward( fStepSize );
	Unlock();
}

void C3DView::DoLookLeft( GLfloat fAngleDegrees )
{
	ASSERT_VALID( this );
	Lock();
C3DCamera * pCam = the3DPipe.GetCamera( m_nCameraIndex );
	ASSERT_VALID( pCam );
	pCam->DoLookLeft( fAngleDegrees );
	Unlock();
}

void C3DView::DoLookUp( GLfloat fAngleDegrees )
{
	ASSERT_VALID( this );
	Lock();
C3DCamera * pCam = the3DPipe.GetCamera( m_nCameraIndex );
	ASSERT_VALID( pCam );
	pCam->DoLookUp( fAngleDegrees );
	Unlock();
}

void C3DView::DoLookOwnAxis( GLfloat fAngleDegrees )
{
	ASSERT_VALID( this );
	Lock();
C3DCamera * pCam = the3DPipe.GetCamera( m_nCameraIndex );
	ASSERT_VALID( pCam );
	pCam->DoLookOwnAxis( fAngleDegrees );
	Unlock();
}

/////////////////////////////////////////////////////////////////////////////
// C3DPipeThread

C3DPipeThread the3DPipe;

C3DPipeThread::C3DPipeThread()
	: m_bInitComplete( false )
	, m_eventShutdownStart( FALSE, FALSE, NULL, NULL )
	, m_eventShutdownComplete( FALSE, FALSE, NULL, NULL )
	, m_eventRenderViews( FALSE, FALSE, NULL, NULL )
	, m_pRoot( new C3DObject(GL_VIEWS_ROOTNAME) )
	, m_bTimerAnimationEnabled( false )
{
	m_bAutoDelete = FALSE;
}

C3DPipeThread::~C3DPipeThread()
{
	ASSERT( !m_bAutoDelete );
	_ResourcesFree();
	m_arrCams.RemoveAll();
	delete m_pRoot;
}

bool C3DPipeThread::_ResourcesInit()
{
	return true;
}

void C3DPipeThread::_ResourcesFree()
{
int nViewCount = m_arrViews.GetSize();
	for( int nViewIdx = 0; nViewIdx < nViewCount; nViewIdx++ )
	{
		C3DView * pView3D = m_arrViews[nViewIdx];
		ASSERT_VALID( pView3D );
		delete pView3D;
	}
	m_arrViews.RemoveAll();

	m_bInitComplete = false;
}

C3DObject * C3DPipeThread::GetRoot()
{
	ASSERT_VALID( this );
	ASSERT_VALID( m_pRoot );
	return m_pRoot;
}

const C3DObject * C3DPipeThread::GetRoot() const
{
	ASSERT_VALID( this );
	ASSERT_VALID( m_pRoot );
	return m_pRoot;
}

void C3DPipeThread::AddView( C3DView * pView3D )
{
	ASSERT_VALID( this );
	ASSERT_VALID( m_pRoot );
	ASSERT_VALID( pView3D );
	m_arrViews.Add( pView3D );
}

int C3DPipeThread::GetViewCount() const
{
	ASSERT_VALID( this );
	ASSERT_VALID( m_pRoot );
	return m_arrViews.GetSize();
}

C3DView * C3DPipeThread::GetView( int nIndex )
{
	ASSERT_VALID( this );
	ASSERT_VALID( m_pRoot );
	ASSERT( 0 <= nIndex && nIndex < m_arrViews.GetSize() );
C3DView * pView3D = m_arrViews[nIndex];
	ASSERT_VALID( pView3D );
	return pView3D;
}


void C3DPipeThread::AddCamera( C3DCamera * pCam )
{
	ASSERT_VALID( this );
	ASSERT_VALID( m_pRoot );
	ASSERT_VALID( pCam );
	ASSERT( !m_bInitComplete );
	m_pRoot->AddChild( pCam );
	m_arrCams.Add( pCam );
}

int C3DPipeThread::GetCameraCount() const
{
	ASSERT_VALID( this );
	ASSERT_VALID( m_pRoot );
	return m_arrCams.GetSize();
}

C3DCamera * C3DPipeThread::GetCamera( int nIndex )
{
	ASSERT_VALID( this );
	ASSERT_VALID( m_pRoot );
	ASSERT( 0 <= nIndex && nIndex < m_arrCams.GetSize() );
C3DCamera * pCam = m_arrCams[nIndex];
	ASSERT_VALID( pCam );
	return pCam;
}

void C3DPipeThread::Render()
{
	m_eventRenderViews.SetEvent();
}

void C3DPipeThread::ShutdownAndWaitFor()
{
	if( !m_bInitComplete )
		return;
	m_eventShutdownStart.SetEvent();
	for(	CExtPopupMenuWnd::PassMsgLoop(false);
			!m_eventShutdownComplete.Lock(500);
			CExtPopupMenuWnd::PassMsgLoop(false)
		);
}

BOOL C3DPipeThread::InitInstance()
{
	if( !_ResourcesInit() )
	{
		ASSERT( FALSE );
		return FALSE;
	}
	ASSERT( m_arrViews.GetSize() > 0 );
	m_bInitComplete = true;

	return TRUE;
}

void C3DPipeThread::Delete()
{
	ASSERT( !m_bAutoDelete );
	_ResourcesFree();
	CWinThread::Delete();
}

int C3DPipeThread::Run()
{
	ASSERT( m_bInitComplete );

	ASSERT_VALID( m_pRoot );
	ObjectWriteAccessSet( true );
		m_pRoot->WalkTree(
			C3DObject::EWTQ_THREAD_INIT,
			NULL,
			NULL,
			NULL,
			NULL
			);
	ObjectWriteAccessSet( false );

int nViewCount = m_arrViews.GetSize();
	ASSERT( nViewCount > 0 );

CSyncObject * arrToWait[2] =
{
	&m_eventShutdownStart,
	&m_eventRenderViews
};
CMultiLock _ml( arrToWait, 2, FALSE );
	for( ; true; )
	{
		DWORD dwWaitResult = _ml.Lock( INFINITE, FALSE, 0 );
		if( dwWaitResult != (WAIT_OBJECT_0 + 1) )
			break;
		bool bResetWriteAccess = false;
		for( int nViewIdx = 0; nViewIdx < nViewCount; nViewIdx++ )
		{
			C3DView * pView3D = m_arrViews[nViewIdx];
			ASSERT_VALID( pView3D );
			if( !pView3D->IsViewVisible() )
				continue;
			bool bSendMsgComplete = false;
			pView3D->Lock();
			ASSERT( !pView3D->m_strViewName.IsEmpty() );
			pView3D->AdjustViewSize( false );
			ASSERT( pView3D->Get3DDC().GetSafeHdc() != NULL );
			if( pView3D->Get3DDC().GetSafeHdc() != NULL )
			{
				if( !bResetWriteAccess )
				{
					ObjectWriteAccessSet( true );
					bResetWriteAccess = true;
				}
				ASSERT( GetCameraCount() > 0 );
				C3DCamera * pCam = GetCamera( pView3D->GetCameraIndex() );
				ASSERT_VALID( pCam );
				m_pRoot->WalkTree(
					C3DObject::EWTQ_TRANSFORM,
					pCam,
					pView3D,
					NULL,
					NULL
					);
				if( !wglMakeCurrent( pView3D->Get3DDC().GetSafeHdc(), pView3D->GetOpenGlContext() ) )
				{
					pView3D->OnGlAlertDisplay( _T("Failed to activate OpenGL rendering context") );
					ASSERT( FALSE );
					continue;
				} // if( !wglMakeCurrent( pView3D->Get3DDC().GetSafeHdc(), pView3D->GetOpenGlContext() ) )
				else
				{
#ifdef _DEBUG
					static int g_nRenderCounter = 0;
					TRACE2( "    >>> 3D-PIPE: rendering %s images (counter=%d)\n", (LPCTSTR)pView3D->m_strViewName, g_nRenderCounter );
					g_nRenderCounter++;
#endif // _DEBUG
					glShadeModel( GL_SMOOTH );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glClearDepth( 1.0f );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glEnable( GL_DEPTH_TEST );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glDepthFunc( GL_LEQUAL );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glDepthMask( GL_TRUE );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glClearStencil( 0 );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glEnable( GL_CULL_FACE );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glCullFace( GL_FRONT );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glFrontFace( GL_CW );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glClear(
						GL_COLOR_BUFFER_BIT
						|GL_DEPTH_BUFFER_BIT
						|GL_STENCIL_BUFFER_BIT
						);
					GL_VIEWS_CHECK_OPENGL_ERROR
					glColorMask( 1, 1, 1, 1 );
					GL_VIEWS_CHECK_OPENGL_ERROR
					CSize _sizeView3D = pView3D->GetViewSize();
					pCam->m_fAspect =
						((GLfloat)_sizeView3D.cx)
						/ ((GLfloat)_sizeView3D.cy)
						;
					glViewport(
						0,
						0,
						_sizeView3D.cx,
						_sizeView3D.cy
						);
					GL_VIEWS_CHECK_OPENGL_ERROR
					glMatrixMode( GL_PROJECTION );
					GL_VIEWS_CHECK_OPENGL_ERROR
					_mt mtxPerspective;
					mtxPerspective.load_perspective(
						pCam->GetFov(),
						pCam->m_fAspect,
						pCam->m_fNearPlane,
						pCam->m_fFarPlane
						);
					glLoadMatrixf( mtxPerspective.arr );
					GL_VIEWS_CHECK_OPENGL_ERROR
					glMatrixMode( GL_MODELVIEW );
					GL_VIEWS_CHECK_OPENGL_ERROR
					_mt _mtxCameraInversion( pCam->m_mtxLastTransformation );
					_mtxCameraInversion.load_inversion();
					glLoadMatrixf(_mtxCameraInversion.arr);
					GL_VIEWS_CHECK_OPENGL_ERROR
					m_pRoot->WalkTree(
						C3DObject::EWTQ_RENDER,
						pCam,
						pView3D,
						NULL,
						NULL
						);
					glFinish();
					GL_VIEWS_CHECK_OPENGL_ERROR
					if( !wglMakeCurrent( NULL, NULL ) )
					{
						pView3D->OnGlAlertDisplay( _T("Failed to release contexts") );
						ASSERT( FALSE );
					}
					bSendMsgComplete = true;
				} // else from if( !wglMakeCurrent( pView3D->Get3DDC().GetSafeHdc(), pView3D->GetOpenGlContext() ) )
			} // if( pView3D->Get3DDC().GetSafeHdc() != NULL )
			pView3D->Unlock();
			if( bSendMsgComplete )
			{
				if( bResetWriteAccess )
				{
					ObjectWriteAccessSet( false );
					bResetWriteAccess = false;
				}
				::SendMessage(
					pView3D->GetOutputHWND(),
					GL_VIEWS_WM_RENDER_FRAME_COMPLETE,
					0L,
					0L
					);
			}
		} // for( int nViewIdx = 0; nViewIdx < nViewCount; nViewIdx++ )
		if( m_bTimerAnimationEnabled )
		{
#ifdef _DEBUG
			static int g_nRecalcPosCounter = 0;
			TRACE1( "    >>> 3D-PIPE: recalculating object positions (counter=%d)\n", g_nRecalcPosCounter );
			g_nRecalcPosCounter++;
#endif // _DEBUG
			if( !bResetWriteAccess )
			{
				ObjectWriteAccessSet( true );
				bResetWriteAccess = true;
			}
			m_pRoot->WalkTree(
				C3DObject::EWTQ_PLAY,
				NULL,
				NULL,
				NULL,
				NULL
				);
		} // if( m_bTimerAnimationEnabled )
		if( bResetWriteAccess )
		{
			ObjectWriteAccessSet( false );
			bResetWriteAccess = false;
		}
	} // for( ; true; )
	
	ObjectWriteAccessSet( true );
		m_pRoot->WalkTree(
			C3DObject::EWTQ_THREAD_DONE,
			NULL,
			NULL,
			NULL,
			NULL
			);
	ObjectWriteAccessSet( false );
	
	_ResourcesFree();
	m_eventShutdownComplete.SetEvent();
	return 0L;
}

/////////////////////////////////////////////////////////////////////////////
// CCameraSelectionComboBox

IMPLEMENT_DYNAMIC( CCameraSelectionComboBox, CExtComboBox )

CCameraSelectionComboBox::CCameraSelectionComboBox()
{
}

CCameraSelectionComboBox::~CCameraSelectionComboBox()
{
}

BEGIN_MESSAGE_MAP( CCameraSelectionComboBox, CExtComboBox )
	//{{AFX_MSG_MAP(CCameraSelectionComboBox)
	//}}AFX_MSG_MAP
	ON_CONTROL_REFLECT(CBN_SELENDOK,OnReflectCbnSelEndOK)
END_MESSAGE_MAP()

void CCameraSelectionComboBox::SyncCameraWithSelectedItem(
	bool bSetFocusToView // = false
	)
{
	ASSERT_VALID( this );
CWnd * pWnd = GetParent();
	ASSERT_VALID( pWnd );
	ASSERT_KINDOF( CExtToolControlBar, pWnd );
CChildView * pChildView = STATIC_DOWNCAST( CChildView, pWnd->GetParent() );
	ASSERT_VALID( pChildView );
C3DView * pView3D = pChildView->m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
int nCurSel = GetCurSel();
	ASSERT( 0 <= nCurSel && nCurSel < GL_VIEWS_CAMERA_COUNT );
int nCamIdxOld = pView3D->GetCameraIndex();
	ASSERT( 0 <= nCamIdxOld && nCamIdxOld < GL_VIEWS_CAMERA_COUNT );
	if( nCamIdxOld != nCurSel )
	{
		pView3D->SetCameraIndex( nCurSel );
	} // if( nCamIdxOld != nCurSel )
	if( bSetFocusToView )
		pChildView->SetFocus();
	if( nCamIdxOld != nCurSel )
	{
		CFrameWnd * pFrame = GetParentFrame();
		ASSERT_VALID( pFrame );
		CMainFrame * pMainFrame =
			DYNAMIC_DOWNCAST( CMainFrame, pFrame );
		if( pMainFrame == NULL )
		{
			pMainFrame =
				DYNAMIC_DOWNCAST( CMainFrame, pFrame->GetParentFrame() );
			ASSERT_VALID( pMainFrame );
		}
		pMainFrame->SyncCameraFovValue();
	} // if( nCamIdxOld != nCurSel )
	the3DPipe.Render();
}

int CCameraSelectionComboBox::SetCurSel(
	int nSelect,
	bool bSetFocusToView // = false
	)
{
	ASSERT( 0 <= nSelect && nSelect < GL_VIEWS_CAMERA_COUNT );
int nRetVal = CExtComboBox::SetCurSel( nSelect );
	SyncCameraWithSelectedItem( bSetFocusToView );
	return nRetVal;
}

void CCameraSelectionComboBox::OnReflectCbnSelEndOK()
{
	ASSERT_VALID( this );
bool bSetFocusToView = false;
HWND hWndFocus = ::GetFocus();
	if( hWndFocus == m_hWnd )
		bSetFocusToView = true;
	SyncCameraWithSelectedItem( bSetFocusToView );
}


/////////////////////////////////////////////////////////////////////////////
// CCameraFovComboBox

IMPLEMENT_DYNAMIC( CCameraFovComboBox, CExtComboBox )

CCameraFovComboBox::CCameraFovComboBox()
{
}

CCameraFovComboBox::~CCameraFovComboBox()
{
}

BEGIN_MESSAGE_MAP( CCameraFovComboBox, CExtComboBox )
	//{{AFX_MSG_MAP(CCameraFovComboBox)
	//}}AFX_MSG_MAP
	ON_CONTROL_REFLECT(CBN_SELENDOK,OnReflectCbnSelEndOK)
END_MESSAGE_MAP()

void CCameraFovComboBox::SyncCameraWithSelectedItem(
	bool bSetFocusToView // = false
	)
{
	ASSERT_VALID( this );
CWnd * pWnd = GetParent();
	ASSERT_VALID( pWnd );
	ASSERT_KINDOF( CExtToolControlBar, pWnd );
CChildView * pChildView = STATIC_DOWNCAST( CChildView, pWnd->GetParent() );
	ASSERT_VALID( pChildView );
C3DView * pView3D = pChildView->m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
int nCamIdx = pView3D->GetCameraIndex();
	ASSERT( 0 <= nCamIdx && nCamIdx < GL_VIEWS_CAMERA_COUNT );
C3DCamera * pCam = the3DPipe.GetCamera( nCamIdx );
	ASSERT_VALID( pCam );

int nFovIdx = GetCurSel();
	ASSERT( 0 <= nFovIdx && nFovIdx < GL_VIEWS_FOV_COUNT );

bool bRender = false;
	the3DPipe.ObjectWriteAccessSet( true );
		if( pCam->m_nFovIndex != nFovIdx ) 
		{
			pCam->m_nFovIndex = nFovIdx;
			bRender = true;
		}
	the3DPipe.ObjectWriteAccessSet( false );

	if( bSetFocusToView )
		pChildView->SetFocus();
	if( bRender )
	{
		CFrameWnd * pFrame = GetParentFrame();
		ASSERT_VALID( pFrame );
		CMainFrame * pMainFrame =
			DYNAMIC_DOWNCAST( CMainFrame, pFrame );
		if( pMainFrame == NULL )
		{
			pMainFrame =
				DYNAMIC_DOWNCAST( CMainFrame, pFrame->GetParentFrame() );
			ASSERT_VALID( pMainFrame );
		}
		pMainFrame->SyncCameraFovValue( nCamIdx, nFovIdx );
		the3DPipe.Render();
	}
}

int CCameraFovComboBox::SetCurSel(
	int nSelect,
	bool bSetFocusToView // = false
	)
{
	ASSERT( 0 <= nSelect && nSelect < GL_VIEWS_FOV_COUNT );
int nRetVal = CExtComboBox::SetCurSel( nSelect );
	SyncCameraWithSelectedItem( bSetFocusToView );
	return nRetVal;
}

void CCameraFovComboBox::OnReflectCbnSelEndOK()
{
	ASSERT_VALID( this );
bool bSetFocusToView = false;
HWND hWndFocus = ::GetFocus();
	if( hWndFocus == m_hWnd )
		bSetFocusToView = true;
	SyncCameraWithSelectedItem( bSetFocusToView );
}


/////////////////////////////////////////////////////////////////////////////
// CObjectHierarchyTreeCtrl

IMPLEMENT_DYNAMIC( CObjectHierarchyTreeCtrl, CTreeCtrl )

CObjectHierarchyTreeCtrl::CObjectHierarchyTreeCtrl()
{
}

CObjectHierarchyTreeCtrl::~CObjectHierarchyTreeCtrl()
{
}

BEGIN_MESSAGE_MAP( CObjectHierarchyTreeCtrl, CTreeCtrl )
	//{{AFX_MSG_MAP(CObjectHierarchyTreeCtrl)
	ON_WM_LBUTTONDBLCLK()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CObjectHierarchyTreeCtrl message handlers

void CObjectHierarchyTreeCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	CTreeCtrl::OnLButtonDblClk(nFlags, point);
UINT htFlags = 0L;
HTREEITEM _hti = CTreeCtrl::HitTest( point, &htFlags );
	if(		_hti != NULL
		&&	(htFlags&(TVHT_ONITEM)) != 0
		)
	{
		C3DObject * pObj = (C3DObject *)
			CTreeCtrl::GetItemData( _hti );
		ASSERT( pObj != NULL );
		ASSERT_VALID( pObj );
		ASSERT_KINDOF( C3DObject, pObj );
		pObj->OnTreeItemDblClick( this );
	}

}

/////////////////////////////////////////////////////////////////////////////
// CChildView

IMPLEMENT_DYNAMIC( CChildView, CWnd )

GLfloat CChildView::g_fStepRotationAngle = 2.0f;
GLfloat CChildView::g_fStepWalkSize = 0.02f;

CChildView::CChildView(
	UINT nIdResourceCursor
	)
	: m_wndGlPanel( nIdResourceCursor )
{
	ASSERT( (ID_SELCAM9) == (ID_SELCAM8 + 1) );
	ASSERT( (ID_SELCAM8) == (ID_SELCAM7 + 1) );
	ASSERT( (ID_SELCAM7) == (ID_SELCAM6 + 1) );
	ASSERT( (ID_SELCAM6) == (ID_SELCAM5 + 1) );
	ASSERT( (ID_SELCAM5) == (ID_SELCAM4 + 1) );
	ASSERT( (ID_SELCAM4) == (ID_SELCAM3 + 1) );
	ASSERT( (ID_SELCAM3) == (ID_SELCAM2 + 1) );
	ASSERT( (ID_SELCAM2) == (ID_SELCAM1 + 1) );
	ASSERT( (ID_SELCAM1) == (ID_SELCAM0 + 1) );
}

CChildView::~CChildView()
{
}

BEGIN_MESSAGE_MAP( CChildView, CWnd )
	//{{AFX_MSG_MAP(CChildView)
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_COMMAND(ID_ROTATE_ABOUT_X0, OnRotateAboutX0)
	ON_COMMAND(ID_ROTATE_ABOUT_X1, OnRotateAboutX1)
	ON_COMMAND(ID_ROTATE_ABOUT_Y0, OnRotateAboutY0)
	ON_COMMAND(ID_ROTATE_ABOUT_Y1, OnRotateAboutY1)
	ON_COMMAND(ID_ROTATE_ABOUT_Z0, OnRotateAboutZ0)
	ON_COMMAND(ID_ROTATE_ABOUT_Z1, OnRotateAboutZ1)
	ON_COMMAND(ID_TRANSLATE_X0, OnTranslateX0)
	ON_COMMAND(ID_TRANSLATE_X1, OnTranslateX1)
	ON_COMMAND(ID_TRANSLATE_Y0, OnTranslateY0)
	ON_COMMAND(ID_TRANSLATE_Y1, OnTranslateY1)
	ON_COMMAND(ID_TRANSLATE_Z0, OnTranslateZ0)
	ON_COMMAND(ID_TRANSLATE_Z1, OnTranslateZ1)
	ON_WM_SETFOCUS()
	ON_WM_CONTEXTMENU()
	ON_UPDATE_COMMAND_UI(ID_BTN_MENU_ROTATION, OnUpdateEnabledBtnInBar)
	ON_COMMAND(ID_CAM_FOV_INC, OnCamFovInc)
	ON_UPDATE_COMMAND_UI(ID_CAM_FOV_INC, OnUpdateCamFovInc)
	ON_COMMAND(ID_CAM_FOV_DEC, OnCamFovDec)
	ON_UPDATE_COMMAND_UI(ID_CAM_FOV_DEC, OnUpdateCamFovDec)
	//}}AFX_MSG_MAP
	
	ON_COMMAND_RANGE( ID_SELCAM0, ID_SELCAM9, OnSelectCamera )
	ON_UPDATE_COMMAND_UI_RANGE( ID_SELCAM0, ID_SELCAM9, OnUpdateSelectCamera )
	
	ON_UPDATE_COMMAND_UI( ID_CAMERA_SELECTION_COMBO, OnUpdateEnabledBtnInBar )
	ON_UPDATE_COMMAND_UI( ID_CAMERA_FOV_COMBO, OnUpdateEnabledBtnInBar )
	ON_UPDATE_COMMAND_UI( ID_BTN_MENU_ROTATION, OnUpdateEnabledBtnInBar )
	ON_UPDATE_COMMAND_UI( ID_BTN_MENU_TRANSLATION, OnUpdateEnabledBtnInBar )
	
	ON_REGISTERED_MESSAGE(
		CExtPopupMenuWnd::g_nMsgPrepareMenu,
		OnExtMenuPrepare
		)

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChildView message handlers

LRESULT CChildView::OnExtMenuPrepare(WPARAM wParam, LPARAM lParam)
{
	lParam;
CExtPopupMenuWnd::MsgPrepareMenuData_t * pData =
		reinterpret_cast
			< CExtPopupMenuWnd::MsgPrepareMenuData_t * >
			( wParam );
	ASSERT( pData != NULL );
CExtPopupMenuWnd * pPopup = pData->m_pPopup;
	ASSERT( pPopup != NULL );

	// remove camera selection combo command
INT nPos = pPopup->ItemFindPosForCmdID(ID_CAMERA_SELECTION_COMBO);
	if( nPos >= 0 )
		pPopup->ItemRemove( nPos );
	if(		pPopup->ItemGetCount() > 0
		&&	pPopup->ItemGetInfo(0).IsSeparator()
		)
		pPopup->ItemRemove( 0 );

	// replace camera FOV combo command
	nPos = pPopup->ItemFindPosForCmdID(ID_CAMERA_FOV_COMBO);
	if( nPos >= 0 )
	{
		pPopup->ItemRemove( nPos );
		if( pPopup->ItemInsert(
				(UINT)CExtPopupMenuWnd::TYPE_POPUP,
				nPos,
				_T("Camera FOV"),
				NULL,
				m_hWnd
				)
			)
		{
			CExtPopupMenuWnd * pSubMenu =
				pPopup->ItemGetPopup( nPos );
			ASSERT_VALID( pSubMenu );
			VERIFY(
				pSubMenu->ItemInsert(
					ID_CAM_FOV_INC,
					-1,
					NULL,
					NULL,
					m_hWnd
					)
				);
			VERIFY(
				pSubMenu->ItemInsert(
					ID_CAM_FOV_DEC,
					-1,
					NULL,
					NULL,
					m_hWnd
					)
				);
			UpdateDialogControls( this, TRUE );
		}
#ifdef _DEBUG
		else
		{
			ASSERT( FALSE );
		}
#endif // _DEBUG
	}
	
	// remove leading separator if exist
	if(		pPopup->ItemGetCount() > 0
		&&	pPopup->ItemGetInfo(0).IsSeparator()
		)
		pPopup->ItemRemove( 0 );

	return TRUE;
}

BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) 
{
	if( ! (CExtWRB < CWnd > ::PreCreateWindow(cs) ) )
		return FALSE;

	cs.dwExStyle &= ~(WS_EX_STATICEDGE|WS_EX_CLIENTEDGE);
	cs.style &= ~WS_BORDER;
	cs.style |= WS_CLIPSIBLINGS;
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL);

	return TRUE;
}

void CChildView::OnPaint() 
{
CPaintDC dcPaint( this );
	CExtPaintManager::stat_ExcludeChildAreas(
		dcPaint.GetSafeHdc(),
		GetSafeHwnd()
		);
}

BOOL CChildView::OnEraseBkgnd(CDC* pDC) 
{
	pDC;
	return TRUE;
}


int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if( CExtWRB < CWnd >::OnCreate(lpCreateStruct) == -1 )
	{
		ASSERT( FALSE );
		return -1;
	}

	m_wndToolbar.m_bPresubclassDialogMode = true;
	if( !m_wndToolbar.Create(
			_T(""),
			this,
			AFX_IDW_DIALOGBAR,
			WS_CHILD|WS_VISIBLE
				|CBRS_ALIGN_TOP|CBRS_TOOLTIPS
				|CBRS_FLYBY|CBRS_SIZE_DYNAMIC
			)
		)
	{
		ASSERT( FALSE );
		return -1;
	}
	if( !m_wndToolbar.LoadToolBar(IDR_TOOLBAR_INVIEW) )
	{
		ASSERT( FALSE );
		return -1;
	}
	if( !m_wndToolbar.InitNavigationBar() )
		return -1;
	
	if(	!m_wndGlPanel.Create(
			this,
			GL_VIEWS_ID_VIEW_DLG_CTRL_ID
			)
		)
	{
		ASSERT( FALSE );
		return -1;
	}
	m_wndGlPanel.SetFont( CFont::FromHandle((HFONT)::GetStockObject(DEFAULT_GUI_FONT)) );

	CWnd::RepositionBars( 0, 0xFFFF, GL_VIEWS_ID_VIEW_DLG_CTRL_ID );
	return 0;
}


void CChildView::OnSize(UINT nType, int cx, int cy) 
{
	CExtWRB < CWnd > ::OnSize(nType, cx, cy);
	if( nType != SIZE_MINIMIZED )
		CWnd::RepositionBars( 0, 0xFFFF, GL_VIEWS_ID_VIEW_DLG_CTRL_ID );
}

void CChildView::OnUpdateEnabledBtnInBar(CCmdUI* pCmdUI) 
{
	ASSERT( pCmdUI != NULL );
	pCmdUI->Enable();
}

void CChildView::OnSetFocus(CWnd* pOldWnd) 
{
	CWnd ::OnSetFocus(pOldWnd);
	m_wndGlPanel.SetFocus();
}

void CChildView::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	pWnd;
	point;
}

void CChildView::OnRotateAboutX0() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoLookUp( g_fStepRotationAngle );
	the3DPipe.Render();
}
void CChildView::OnRotateAboutX1() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoLookUp( -g_fStepRotationAngle );
	the3DPipe.Render();
}

void CChildView::OnRotateAboutY0() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoLookLeft( g_fStepRotationAngle );
	the3DPipe.Render();
}
void CChildView::OnRotateAboutY1() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoLookLeft( -g_fStepRotationAngle );
	the3DPipe.Render();
}

void CChildView::OnRotateAboutZ0() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoLookOwnAxis( g_fStepRotationAngle );
	the3DPipe.Render();
}
void CChildView::OnRotateAboutZ1() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoLookOwnAxis( -g_fStepRotationAngle );
	the3DPipe.Render();
}

void CChildView::OnTranslateX0() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoStepLeft( g_fStepWalkSize );
	the3DPipe.Render();
}
void CChildView::OnTranslateX1() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoStepLeft( -g_fStepWalkSize );
	the3DPipe.Render();
}

void CChildView::OnTranslateY0() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoStepUp( g_fStepWalkSize );
	the3DPipe.Render();
}
void CChildView::OnTranslateY1() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoStepUp( -g_fStepWalkSize );
	the3DPipe.Render();
}

void CChildView::OnTranslateZ0() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoStepForward( g_fStepWalkSize );
	the3DPipe.Render();
}
void CChildView::OnTranslateZ1() 
{
	ASSERT_VALID( this );
C3DView * pView3D = m_wndGlPanel.GetView3D();
	if( pView3D == NULL )
		return;
	ASSERT_VALID( pView3D );
	pView3D->DoStepForward( -g_fStepWalkSize );
	the3DPipe.Render();
}

void CChildView::OnSelectCamera( UINT nCmdID )
{
	ASSERT_VALID( this );
	ASSERT( ID_SELCAM0 <= nCmdID && nCmdID <= ID_SELCAM9 );
int nCameraIndex = nCmdID - ID_SELCAM0;
	ASSERT( 0 <= nCameraIndex && nCameraIndex < GL_VIEWS_CAMERA_COUNT );
	m_wndToolbar.m_wndCameraSelCombo.SetCurSel( nCameraIndex );
}
void CChildView::OnUpdateSelectCamera(CCmdUI* pCmdUI)
{
	ASSERT_VALID( this );
	ASSERT( pCmdUI != NULL );
	ASSERT( ID_SELCAM0 <= pCmdUI->m_nID && pCmdUI->m_nID <= ID_SELCAM9 );
int nCameraIndexReal = m_wndToolbar.m_wndCameraSelCombo.GetCurSel();
	if( nCameraIndexReal < 0 )
	{
		pCmdUI->Enable( FALSE );
		return;
	}
	ASSERT( 0 <= nCameraIndexReal && nCameraIndexReal < GL_VIEWS_CAMERA_COUNT );
int nCameraIndexToCmp = pCmdUI->m_nID - ID_SELCAM0;
	ASSERT( 0 <= nCameraIndexToCmp && nCameraIndexToCmp < GL_VIEWS_CAMERA_COUNT );
	pCmdUI->Enable( TRUE );
	pCmdUI->SetRadio(
		(nCameraIndexReal == nCameraIndexToCmp)
			? TRUE
			: FALSE
		);
}


void CChildView::OnCamFovInc() 
{
	ASSERT_VALID( this );
int nCameraIndexReal = m_wndToolbar.m_wndCameraSelCombo.GetCurSel();
	ASSERT(
			( 0 <= nCameraIndexReal && nCameraIndexReal < GL_VIEWS_CAMERA_COUNT )
		||	nCameraIndexReal < 0
		);
	if( nCameraIndexReal < 0 )
		return;
C3DCamera * pCam = the3DPipe.GetCamera( nCameraIndexReal );
	ASSERT_VALID( pCam );
int nFovIdx = pCam->m_nFovIndex;
	ASSERT( 0 <= nFovIdx && nFovIdx < GL_VIEWS_FOV_COUNT );
	if( nFovIdx == (GL_VIEWS_FOV_COUNT-1) )
		return;
	m_wndToolbar.m_wndCameraFovCombo.SetCurSel( nFovIdx+1, false );
}
void CChildView::OnUpdateCamFovInc(CCmdUI* pCmdUI) 
{
	ASSERT_VALID( this );
	ASSERT( pCmdUI != NULL );
int nCameraIndexReal = m_wndToolbar.m_wndCameraSelCombo.GetCurSel();
	ASSERT(
			( 0 <= nCameraIndexReal && nCameraIndexReal < GL_VIEWS_CAMERA_COUNT )
		||	nCameraIndexReal < 0
		);
	if( nCameraIndexReal < 0 )
	{
		pCmdUI->Enable( FALSE );
		return;
	}
C3DCamera * pCam = the3DPipe.GetCamera( nCameraIndexReal );
	ASSERT_VALID( pCam );
int nFovIdx = pCam->m_nFovIndex;
	ASSERT( 0 <= nFovIdx && nFovIdx < GL_VIEWS_FOV_COUNT );
	pCmdUI->Enable(
		(nFovIdx < (GL_VIEWS_FOV_COUNT-1)) ? TRUE : FALSE
		);
}

void CChildView::OnCamFovDec() 
{
	ASSERT_VALID( this );
int nCameraIndexReal = m_wndToolbar.m_wndCameraSelCombo.GetCurSel();
	ASSERT(
			( 0 <= nCameraIndexReal && nCameraIndexReal < GL_VIEWS_CAMERA_COUNT )
		||	nCameraIndexReal < 0
		);
	if( nCameraIndexReal < 0 )
		return;
C3DCamera * pCam = the3DPipe.GetCamera( nCameraIndexReal );
	ASSERT_VALID( pCam );
int nFovIdx = pCam->m_nFovIndex;
	ASSERT( 0 <= nFovIdx && nFovIdx < GL_VIEWS_FOV_COUNT );
	if( nFovIdx == 0 )
		return;
	m_wndToolbar.m_wndCameraFovCombo.SetCurSel( nFovIdx-1, false );
}
void CChildView::OnUpdateCamFovDec(CCmdUI* pCmdUI) 
{
	ASSERT_VALID( this );
	ASSERT( pCmdUI != NULL );
int nCameraIndexReal = m_wndToolbar.m_wndCameraSelCombo.GetCurSel();
	ASSERT(
			( 0 <= nCameraIndexReal && nCameraIndexReal < GL_VIEWS_CAMERA_COUNT )
		||	nCameraIndexReal < 0
		);
	if( nCameraIndexReal < 0 )
	{
		pCmdUI->Enable( FALSE );
		return;
	}
C3DCamera * pCam = the3DPipe.GetCamera( nCameraIndexReal );
	ASSERT_VALID( pCam );
int nFovIdx = pCam->m_nFovIndex;
	ASSERT( 0 <= nFovIdx && nFovIdx < GL_VIEWS_FOV_COUNT );
	pCmdUI->Enable(
		(nFovIdx > 0) ? TRUE : FALSE
		);
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Sergiy Lavrynenko of Foss Software, Inc.
Architect Foss Software Inc
Ukraine Ukraine
No Biography provided

| Advertise | Privacy | Mobile
Web04 | 2.8.141022.2 | Last Updated 14 Jan 2004
Article Copyright 2002 by Sergiy Lavrynenko of Foss Software, Inc.
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid