#include <math.h>
#include <gl/gl.h>
#include <gl/glu.h>

inline void MinMax (float d, float& Min, float& Max)
{
	if (d > Max)
		Max = d;
	else if (d < Min)
		Min = d;
}



// OpenGL.h : Declaration of the COpenGL
#pragma once
#include "resource.h"       // main symbols
#include <atlctl.h>
#include "_IOpenGLEvents_CP.h"

//==========  
class CPoint3D
{
public:
	float x;
	float y;
	float z;		//    3D

	//======     
	CPoint3D () { x = y = z = 0; }

	CPoint3D (float c1, float c2, float c3)
	{
		x = c1;
		z = c2;
		y = c3;
	}

	CPoint3D& operator=(const CPoint3D& pt)
	{
		x = pt.x;
		z = pt.z;
		y = pt.y;
		return *this;
	}

	CPoint3D (const CPoint3D& pt)
	{
		*this = pt;
	}
};

//======  ,   IOpenGL
class ATL_NO_VTABLE COpenGL : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public CStockPropImpl<COpenGL, IOpenGL>,
	public IPersistStreamInitImpl<COpenGL>,
	public IOleControlImpl<COpenGL>,
	public IOleObjectImpl<COpenGL>,
	public IOleInPlaceActiveObjectImpl<COpenGL>,
	public IViewObjectExImpl<COpenGL>,
	public IOleInPlaceObjectWindowlessImpl<COpenGL>,
	public ISupportErrorInfo,
	public IConnectionPointContainerImpl<COpenGL>,
	public CProxy_IOpenGLEvents<COpenGL>, 
	public IPersistStorageImpl<COpenGL>,
	public ISpecifyPropertyPagesImpl<COpenGL>,
	public IQuickActivateImpl<COpenGL>,
	public IDataObjectImpl<COpenGL>,
	public IProvideClassInfo2Impl<&CLSID_OpenGL,
			&__uuidof(_IOpenGLEvents), &LIBID_ATLGLLib>,
	public CComCoClass<COpenGL, &CLSID_OpenGL>,
	public CComControl<COpenGL>
{
public:

	//===== ,    
	OLE_COLOR m_clrFillColor;	//   
	int			m_LightParam[11];//  
	int			m_xPos, m_yPos; 	//   
	HGLRC		m_hRC;				//  OpenGL
	HDC			m_hdc; 			//  Windows
	GLfloat	m_AngleX;			//     X
	GLfloat	m_AngleY;			//     Y
	GLfloat	m_AngleView;		//  
	GLfloat	m_fRangeX;		//    X
	GLfloat	m_fRangeY;		//    Y
	GLfloat	m_fRangeZ;		//    Z
	GLfloat	m_dx;				//    X
	GLfloat	m_dy;				//    Y
	GLfloat	m_xTrans;			// C  X
	GLfloat	m_yTrans;			// C  Y
	GLfloat	m_zTrans;			// C  Z
	GLenum		m_FillMode;		//   
	bool		m_bCaptured;		//   
	bool		m_bRightButton;	//    
	bool		m_bQuad;			//   GL_QUAD
	UINT		m_xSize;			//     X
	UINT		m_zSize;			//     Y

	//======   
	vector <CPoint3D> m_cPoints;

	//====== ,    
	COpenGL();
	HRESULT OnDraw(ATL_DRAWINFO& di);
	void OnFillColorChanged();

DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE | 
	OLEMISC_CANTLINKINSIDE | 
	OLEMISC_INSIDEOUT | 
	OLEMISC_ACTIVATEWHENVISIBLE | 
	OLEMISC_SETCLIENTSITEFIRST
)

DECLARE_REGISTRY_RESOURCEID(IDR_OPENGL)

BEGIN_COM_MAP(COpenGL)
	COM_INTERFACE_ENTRY(IOpenGL)
	COM_INTERFACE_ENTRY(IDispatch)
	COM_INTERFACE_ENTRY(IViewObjectEx)
	COM_INTERFACE_ENTRY(IViewObject2)
	COM_INTERFACE_ENTRY(IViewObject)
	COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
	COM_INTERFACE_ENTRY(IOleInPlaceObject)
	COM_INTERFACE_ENTRY2(IOleWindow,
							IOleInPlaceObjectWindowless)
	COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
	COM_INTERFACE_ENTRY(IOleControl)
	COM_INTERFACE_ENTRY(IOleObject)
	COM_INTERFACE_ENTRY(IPersistStreamInit)
	COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
	COM_INTERFACE_ENTRY(ISupportErrorInfo)
	COM_INTERFACE_ENTRY(IConnectionPointContainer)
	COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
	COM_INTERFACE_ENTRY(IQuickActivate)
	COM_INTERFACE_ENTRY(IPersistStorage)
	COM_INTERFACE_ENTRY(IDataObject)
	COM_INTERFACE_ENTRY(IProvideClassInfo)
	COM_INTERFACE_ENTRY(IProvideClassInfo2)
END_COM_MAP()

BEGIN_PROP_MAP(COpenGL)
	PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
	PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
	PROP_ENTRY("FillColor",DISPID_FILLCOLOR,
					CLSID_StockColorPage)
END_PROP_MAP()

BEGIN_CONNECTION_POINT_MAP(COpenGL)
	CONNECTION_POINT_ENTRY(DIID__IOpenGLEvents)
END_CONNECTION_POINT_MAP()

BEGIN_MSG_MAP(COpenGL)
	CHAIN_MSG_MAP(CComControl<COpenGL>)
	DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()

	//======   ISupportsErrorInfo
	STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
	{
		static const IID* arr[] = 
		{
			&IID_IOpenGL,
		};

		for (int i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
		{
			if (InlineIsEqualGUID(*arr[i], riid))
				return S_OK;
		}
		return S_FALSE;
	}

	//======   IViewObjectEx
	DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND |
							VIEWSTATUS_OPAQUE)

	//======   IOpenGL
public:
	DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{
		return S_OK;
	}
	
	void FinalRelease() 
	{
	}

//======  
	STDMETHODIMP GetLightParams(int* pPos);
	STDMETHODIMP SetLightParam(short lp, int nPos);
	STDMETHODIMP ReadData(void);

	//======   
	
	//======   
	void SetLight();
	//======   
	void DefaultGraphic();

	//======      
	bool DoRead(HANDLE hFile);

	//        
	void SetGraphPoints(BYTE* buff, DWORD nSize);

	//======    
	void SetBkColor();

	//==       OpenGL
	void DrawScene();
};

OBJECT_ENTRY_AUTO(__uuidof(OpenGL), COpenGL)



LRESULT COpenGL::OnEraseBkgnd(UINT /*uMsg*/, WPARAM
			 /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
	//======    
	bHandled = TRUE;
	return 0;
}



LRESULT COpenGL::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/,
							LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	//=======    OpenGL
	PIXELFORMATDESCRIPTOR pfd =
	{
		sizeof(PIXELFORMATDESCRIPTOR),//  
		1,							//  
		PFD_DRAW_TO_WINDOW |	//  GDI
		PFD_SUPPORT_OPENGL |	//  OpenGL
		PFD_DOUBLEBUFFER,		//  
		PFD_TYPE_RGBA,			//  RGBA,  
		24, 						//  
		 							//    
		24,	0,						//   Red
		24,	0,						//   Green
		24,	0,						//   Blue
		24,	0,						//   Alpha
		0,							//  
									//  Accumulation
		0,			 				//     Red
		0,			 				//   Green
		0,							//   Blue
		0,							//   Alpha
		32, 						//  Z-
		0,							//   Stencil
		0,							//   Auxiliary
		0,				 			//  
		0,							//  
		0,							//  
		0,							//   
		0							//  
	};

	//       
	m_hdc = GetDC();
	int iD = ChoosePixelFormat(m_hdc, &pfd);
	if ( !iD )
	{
		ATLASSERT(FALSE);
		return -1;
	}
	//======    
	if ( !SetPixelFormat (m_hdc, iD, &pfd))
	{
		ATLASSERT(FALSE);
		return -1;
	}
	//======     OpenGL
	if ( !(m_hRC = wglCreateContext (m_hdc)))
	{
		ATLASSERT(FALSE);
		return -1;
	}
	//======      
	if ( !wglMakeCurrent (m_hdc, m_hRC))
	{
		ATLASSERT(FALSE);
		return -1;
	}

	//======     OpenGL
	glEnable(GL_LIGHTING);		//  
	glEnable(GL_LIGHT0);		//  1 
	glEnable(GL_DEPTH_TEST);	//   ( Z)
	//======    
	glEnable(GL_COLOR_MATERIAL);
	//======   
	SetBkColor();
	return 0;
}



LRESULT COpenGL::OnSize(UINT /*uMsg*/, WPARAM /*wParam*/,
								LPARAM lParam, BOOL& /*bHandled*/)
{
	//       
	UINT cx = LOWORD(lParam), cy = HIWORD(lParam);

	//======    
	double dAspect = cx<=cy ? double(cy)/cx 
								: double(cx)/cy;

	//     ( )
	glMatrixMode (GL_PROJECTION);
	//======     
	glLoadIdentity();

	//==   (45  -  )
	gluPerspective (45., dAspect, 1., 10000.);

	glViewport(0, 0, cx, cy);
	DrawScene();
	return 0;
}



LRESULT COpenGL::OnDestroy(UINT /*uMsg*/, WPARAM
		 /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	KillTimer(1);
	if (m_hRC)
	{
		wglDeleteContext(m_hRC);
		m_hRC = 0;
	}
	return 0;
}



COpenGL:: COpenGL()
{
	//======    
	m_hRC = 0;

	//======   
	m_AngleX = 35.f;
	m_AngleY = 20.f;

	//======     
	m_AngleView = 45.f;

	//======   
	m_clrFillColor = RGB(255,245,255);

	//======   
	//======   
	m_FillMode = GL_FILL;

	//======    
	DefaultGraphic();

	//===     
	//===      
	m_zTrans = -1.5f*m_fRangeX;
	m_xTrans = m_yTrans = 0.f;

	//     ( )
	m_dx = m_dy = 0.f;

	//===   
	m_bCaptured = false;
	//===     
	m_bRightButton = false;
	//===  
	m_bQuad = true;

	//======    
	m_LightParam[0] = 50;	// X position
	m_LightParam[1] = 80;	// Y position
	m_LightParam[2] = 100;	// Z position
	m_LightParam[3] = 15;	// Ambient light
	m_LightParam[4] = 70;	// Diffuse light
	m_LightParam[5] = 100;	// Specular light
	m_LightParam[6] = 100;	// Ambient material
	m_LightParam[7] = 100;	// Diffuse material
	m_LightParam[8] = 40;	// Specular material
	m_LightParam[9] = 70;	// Shininess material
	m_LightParam[10] = 0;	// Emission material
}



HRESULT COpenGL::OnDraw(ATL_DRAWINFO& di)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	//======   
	SetLight();

	//======   
	glTranslatef(m_xTrans,m_yTrans,m_zTrans);
	glRotatef (m_AngleX, 1.0f, 0.0f, 0.0f );
	glRotatef (m_AngleY, 0.0f, 1.0f, 0.0f );

	//======     
	glCallList(1);

	//======  
	SwapBuffers(m_hdc);
	return S_OK;
}



void COpenGL::SetBkColor()
{
	//======     
	GLclampf red	= GetRValue(m_clrFillColor)/255.f,
			 green	= GetGValue(m_clrFillColor)/255.f,
			 blue	= GetBValue(m_clrFillColor)/255.f;
	//======    () 
	glClearColor (red, green, blue, 0.f);
	//======  
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}


void COpenGL::OnFillColorChanged()
{
	//======    ,
	if (m_clrFillColor & 0x80000000)
		//======     
		m_clrFillColor = ::GetSysColor(m_clrFillColor & 0x1f);

	//======     OpenGL
	SetBkColor();	
}



//======  
void COpenGL::DrawScene()
{
	//======    
	glNewList(1, GL_COMPILE);
	//======   
	//======   
	glPolygonMode(GL_FRONT_AND_BACK, m_FillMode);

	//======   
	UINT	nx = m_xSize-1,
			nz = m_zSize-1;

	//======    
	if (m_bQuad)
		glBegin (GL_QUADS);

	//===      ( Z)
	for (UINT z=0, i=0;  z<nz;  z++, i++)
	{
		//===   
		//===    
		if (!m_bQuad)
			glBegin(GL_QUAD_STRIP);

		//===     X
		for (UINT x=0;  x<nx;  x++, i++)
		{
			// i, j, k, n - 4    
			//      

			int	j = i + m_xSize,	//     Z
				k = j+1,			//    
				n = i+1; 			//   

				//   4-   
			float
				xi = m_cPoints[i].x,
				yi = m_cPoints[i].y,
				zi = m_cPoints[i].z,

				xj = m_cPoints[j].x,
				yj = m_cPoints[j].y,
				zj = m_cPoints[j].z,

				xk = m_cPoints[k].x,
				yk = m_cPoints[k].y,
				zk = m_cPoints[k].z,

				xn = m_cPoints[n].x,
				yn = m_cPoints[n].y,
				zn = m_cPoints[n].z,

				//===    
				ax = xi-xn,
				ay = yi-yn,

				by = yj-yi,
				bz = zj-zi,

				//===   
				vx = ay*bz,
				vy = -bz*ax,
				vz = ax*by,
	
				//===  
				v  = float(sqrt(vx*vx + vy*vy + vz*vz));

			//======   
			vx /= v;
			vy /= v;
			vz /= v;

			//======   
			glNormal3f (vx,vy,vz);

			//===    
			if (m_bQuad)
			{
				//======   
				//===     
				glColor3f (0.2f, 0.8f, 1.f);
				glVertex3f (xi, yi, zi);
				glColor3f (0.6f, 0.7f, 1.f);
				glVertex3f (xj, yj, zj);
				glColor3f (0.7f, 0.9f, 1.f);
				glVertex3f (xk, yk, zk);
				glColor3f (0.7f, 0.8f, 1.f);
				glVertex3f (xn, yn, zn);
			}
			else
			//======    
			{
				glColor3f (0.9f, 0.9f, 1.0f);
				glVertex3f (xi, yi, zi);
				glColor3f (0.5f, 0.8f, 1.0f);
				glVertex3f (xj, yj, zj);
			}
		}
		//======    GL_QUAD_STRIP
		if (!m_bQuad)
			glEnd();
	}
	//======    GL_QUADS
	if (m_bQuad)
		glEnd();

	//======    OpenGL
	glEndList();
}


void COGView::DefaultGraphic()
{
	//======   
	m_xSize = m_zSize = 33;
	//======       
	UINT	nz = m_zSize - 1,
			nx = m_xSize - 1;
	//        
	DWORD nSize = m_xSize * m_zSize * sizeof(float)
						+ 2*sizeof(UINT);

	//======     
	BYTE *buff = new BYTE[nSize+1];

	//======      
	UINT *p = (UINT*)buff;
		//    
	*p++ = m_xSize;
	*p++ = m_zSize;

	//======   ,   
	//======    
	float *pf = (float*)p;

	//    
	double fi = atan(1.)*12, kx=fi/nx, kz=fi/nz;

	//===       
	//===        float
	for (UINT i=0;  i<m_zSize;  i++)
		for (UINT j=0;  j<m_xSize;  j++)
			*pf++ = float (exp(-(i+20.*j)/256.)
					*sin(kz*(i-nz/2.))*sin(kx*(j-nx/2.)));

	//===   ,   
	//===      
	DWORD nBytes;
	//===      sin.dat
	HANDLE hFile = CreateFile(_T("sin.dat"), GENERIC_WRITE,
					0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);

	//===     
	WriteFile(hFile,(LPCVOID)buff, nSize,&nBytes, 0);

	CloseHandle(hFile);		//  

	//===    m_cPoints
	SetGraphPoints (buff, nSize);

	//===   
	delete [] buff;
}



STDMETHODIMP COpenGL::ReadData(void)
{
	//=== ,      
	TCHAR szFile[MAX_PATH] = { 0 };
	//===    
	TCHAR *szFilter =TEXT("Graphics Data Files (*.dat)\0")
						TEXT("*.dat\0")
						TEXT("All Files\0")
						TEXT("*.*\0");

	//===   	
	TCHAR szCurDir[MAX_PATH];
	::GetCurrentDirectory(MAX_PATH-1,szCurDir);

	//  ,   
	OPENFILENAME ofn;
	ZeroMemory(&ofn,sizeof(OPENFILENAME));

	//===    
	ofn.lStructSize	= sizeof(OPENFILENAME);
	//=== - 
	ofn.hwndOwner = GetSafeHwnd();
	ofn.lpstrFilter	= szFilter;
	//===    (  )
	ofn.nFilterIndex	= 1;
	ofn.lpstrFile		= szFile;
	ofn.nMaxFile		= sizeof(szFile);
	//===   
	ofn.lpstrTitle	= _T("   ");
	ofn.nMaxFileTitle = sizeof (ofn.lpstrTitle);
	//===    (  Win2K)
	ofn.Flags			= OFN_EXPLORER;

	//===    
	//    GetOpenFileName  0
	if (GetOpenFileName(&ofn))
	{
		//   ,   
		HANDLE hFile = CreateFile(ofn.lpstrFile, GENERIC_READ,
				FILE_SHARE_READ, 0, OPEN_EXISTING,
				FILE_ATTRIBUTE_NORMAL, 0);

		//===    CreateFile  -1
		if (hFile == (HANDLE)-1)
		{
			MessageBox(_T("   "));
			return S_FALSE;
		}

		//===      
		if (!DoRead(hFile))
			return S_FALSE;

		//======   
		DrawScene();

		//======   OpenGL
		Invalidate(FALSE);
	}
	return S_OK;
}



void COGView::SetLight()
{
	//======    
	//======      
	//======   
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,1);

	//======   
	//======    
	float fPos[] =
	{
		(m_LightParam[0]-50)*m_fRangeX/100,
		(m_LightParam[1]-50)*m_fRangeY/100,
		(m_LightParam[2]-50)*m_fRangeZ/100,
		1.f
	};
	glLightfv(GL_LIGHT0, GL_POSITION, fPos);

	//======   
	float f = m_LightParam[3]/100.f;
	float fAmbient[4] = { f, f, f, 0.f };
	glLightfv(GL_LIGHT0, GL_AMBIENT, fAmbient);

	//======   
	f = m_LightParam[4]/100.f;	
	float fDiffuse[4] = { f, f, f, 0.f };
	glLightfv(GL_LIGHT0, GL_DIFFUSE, fDiffuse);

	//======   
	f = m_LightParam[5]/100.f;
	float fSpecular[4] = { f, f, f, 0.f };
	glLightfv(GL_LIGHT0, GL_SPECULAR, fSpecular);

	//======   
	//======    
	f = m_LightParam[6]/100.f;
	float fAmbMat[4] = { f, f, f, 0.f };
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, fAmbMat);

	f = m_LightParam[7]/100.f;
	float fDifMat[4] = { f, f, f, 1.f };
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fDifMat);

	f = m_LightParam[8]/100.f;
	float fSpecMat[4] = { f, f, f, 0.f };
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, fSpecMat);

	//=======  
	float fShine = 128 * m_LightParam[9]/100.f;
	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, fShine);

	//=======   
	f = m_LightParam[10]/100.f;
	float fEmission[4] = { f, f, f, 0.f };
	glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, fEmission);
}


STDMETHODIMP COpenGL::GetLightParams(int* pPos)
{
	//=======    
	for (int i=0; i<11; i++)
		//=======    pPos
		pPos[i] = m_LightParam[i];

	return S_OK;
}

STDMETHODIMP COpenGL::SetLightParam(short lp, int nPos)
{
	//======   lp  
	//======    nPos
	m_LightParam[lp] = nPos;
	//======     
	FireViewChange();
	return S_OK;
}
	


m_bWindowOnly = TRUE;



STDMETHODIMP COpenGL::GetFillMode(DWORD* pMode)
{
	//=======   
	*pMode = m_FillMode;
	return S_OK;
}

STDMETHODIMP COpenGL::SetFillMode(DWORD nMode)
{
	m_FillMode = nMode;
	//======     OpenGL
	DrawScene();

	//     
	FireViewChange();
	return S_OK;
}

STDMETHODIMP COpenGL::GetQuad(BOOL* bQuad)
{
	//=======   
	*bQuad = m_bQuad;
	return S_OK;
}

STDMETHODIMP COpenGL::SetQuad(BOOL bQuad)
{
	m_bQuad = bQuad == TRUE;
	//=======     OpenGL
	DrawScene();
	//=======   
	FireViewChange();
	return S_OK;
}



library ATLGLLib
{
	importlib("stdole32.tlb");
	importlib("stdole2.tlb");

	[
		uuid(6DEBB446-C43A-4AB5-BEE1-110510C7AC89),
		helpstring("_IOpenGLEvents Interface")
	]
	dispinterface _IOpenGLEvents
	{
		properties:
		methods:
	};

	[
		uuid(5B3EF182-CD91-426F-9309-2E4869C353DB),
		helpstring("OpenGL Class")
	]
	coclass COpenGL
	{
		[default] interface IOpenGL;
		[default, source] dispinterface _IOpenGLEvents;
	};
	//======      
	[
		uuid(3AE16CD6-4558-460F-8A7E-5AB83D40DE9A),
		helpstring("_IGraphPropEvents Interface")
	]
	dispinterface _IGraphPropEvents
	{
		properties:
		methods:
	};

	[
		uuid(1A0C756A-DA17-4630-91B0-72722950B8F7),
		helpstring("GraphProp Class")
	]
	coclass PropDlg
	{
		interface IUnknown;
		[default, source] dispinterface _IGraphPropEvents;
	};



CPropDlg()
{
	m_dwTitleID = IDS_TITLEPropDlg;
	m_dwHelpFileID = IDS_HELPFILEPropDlg;
	m_dwDocStringID = IDS_DOCSTRINGPropDlg;
}



	//======     Apply
	STDMETHOD(Apply)(void)
	{
		ATLTRACE(_T("CPropDlg::Apply\n"));
		for (UINT i = 0; i < m_nObjects; i++)
		{
			// Do something interesting here
			// ICircCtl* pCirc;
			// m_ppUnk[i]->QueryInterface(IID_ICircCtl,
			//					(void**)&pCirc);
			// pCirc->put_Caption(CComBSTR("smth	special"));
			// pCirc->Release();
		}
		m_bDirty = FALSE;
		return S_OK;
	}






IDD_PROPDLG
    
IDC_AMBIENT
    
IDC_DIFFUSE
    
IDC_SPECULAR
Text      
IDC_AMB_TEXT
Text      
IDC_DIFFUSE_TEXT
Text      
IDC_SPECULAR_TEXT
    
IDC_AMBMAT
    
IDC_DIFFMAT
    
IDC_SPECMAT
Text      
IDC_AMBMAT_TEXT
Text      
IDC_DIFFMAT_TEXT
Text      
IDC_SPECMAT_TEXT
 
IDC_SHINE
 
IDC_EMISSION
Text   
IDC_SHINE_TEXT
Text   
IDC_EMISSION_TEXT
 X
IDC_XPOS
 Y
IDC_YPOS
 Z
IDC_ZPOS
Text   X
IDC_XPOS_TEXT
Text   Y
IDC_YPOS_TEXT
Text   Z
IDC_ZPOS_TEXT
  
IDC_FILLMODE
 Quads
IDC_QUADS
  
IDC_FILENAME



LRESULT CPropDlg::OnInitDialog(UINT uMsg, WPARAM wParam,
								LPARAM lParam, BOOL& bHandled)
{
	__super::OnInitDialog(uMsg, wParam, lParam, bHandled);

	//======      IOpenGL
	CComQIPtr<IOpenGL> p(m_ppUnk[0]);
	
	//===     COpenGL  
	//===   m_FillMode
	//===       
	DWORD mode;
	if FAILED (p->GetFillMode(&mode))
	{
		ShowError();
		return 0;
	}

	//======   combobox   API
	//======  Windows- 
	HWND hwnd = GetDlgItem(IDC_FILLMODE);

	//======    
	SendMessage(hwnd, CB_ADDSTRING, 0,
						(LPARAM)(LPCTSTR)"Points");
	SendMessage(hwnd, CB_ADDSTRING, 0,
						(LPARAM)(LPCTSTR)"Lines");
	SendMessage(hwnd, CB_ADDSTRING, 0,
						(LPARAM)(LPCTSTR)"Fill");

	//      
	//  ,   COpenGL
	WPARAM w = mode == GL_POINT ? 0 
				: mode == GL_LINE ? 1 : 2;
	SendMessage(hwnd, CB_SETCURSEL, w, 0);

	//       
	if FAILED (p->GetLightParams(m_Pos))
	{
		ShowError();
		return 0;
	}
	
	//===      
	//===      
	UINT IDs[] = 
	{
		IDC_XPOS,		IDC_YPOS,		IDC_ZPOS,
		IDC_AMBIENT,
		IDC_DIFFUSE,
		IDC_SPECULAR,
		IDC_AMBMAT,
		IDC_DIFFMAT,
		IDC_SPECMAT,
		IDC_SHINE,
		IDC_EMISSION 
	};

	//===       
	for (int i=0; i<sizeof(IDs)/sizeof(IDs[0]); i++)
	{
		//======   
		hwnd = GetDlgItem(IDs[i]);
		UINT nID;
	
		//======   
		int num = GetSliderNum(hwnd, nID);

		//======  
		SendMessage(hwnd, TBM_SETPOS, TRUE, (LPARAM)m_Pos[i]);

		//===     
		char s[8];
		sprintf (s,"%d",m_Pos[i]);
		SetDlgItemText(nID, s);
	}

	//===     
	if FAILED (p->GetQuad(&m_bQuad))
	{
		ShowError();
		return 0;
	}

	//======  
	SetDlgItemText(IDC_QUADS, m_bQuad ? "Quads" : "Strips");

	return 1;
}



int CPropDlg::GetSliderNum(HWND hwnd, UINT& nID)
{
	//      
	switch (::GetDlgCtrlID(hwnd))
	{
	case IDC_XPOS:
		nID = IDC_XPOS_TEXT;
		return 0;
	case IDC_YPOS:
		nID = IDC_YPOS_TEXT;
		return 1;
	case IDC_ZPOS:
		nID = IDC_ZPOS_TEXT;
		return 2;
	case IDC_AMBIENT:
		nID = IDC_AMB_TEXT;
		return 3;
	case IDC_DIFFUSE:
		nID = IDC_DIFFUSE_TEXT;
		return 4;
	case IDC_SPECULAR:
		nID = IDC_SPECULAR_TEXT;
		return 5;
	case IDC_AMBMAT:
		nID = IDC_AMBMAT_TEXT;
		return 6;
	case IDC_DIFFMAT:
		nID = IDC_DIFFMAT_TEXT;
		return 7;
	case IDC_SPECMAT:
		nID = IDC_SPECMAT_TEXT;
		return 8;
	case IDC_SHINE:
		nID = IDC_SHINE_TEXT;
		return 9;
	case IDC_EMISSION:
		nID = IDC_EMISSION_TEXT;
		return 10;
	}
	return 0;
}



void CPropDlg::ShowError()
{
	USES_CONVERSION;
	//======   
	CComPtr<IErrorInfo> pError;
	//======     Unicode-
	CComBSTR sError;
	//======   
	GetErrorInfo(0, &pError);
	pError->GetDescription(&sError);

	//        
	MessageBox(OLE2T(sError),_T("Error"),MB_ICONEXCLAMATION);
}



LRESULT CPropDlg::OnHScroll(UINT /*uMsg*/, WPARAM wParam,
							LPARAM lParam, BOOL& /*bHandled*/)
{
	//======      wParam
	int	nCode = LOWORD(wParam),
		nPos  = HIWORD(wParam),
		delta,
		newPos;
	HWND hwnd = (HWND) lParam;
		
	//      
	UINT nID;
	int num = GetSliderNum(hwnd, nID); 

	//======   
	switch (nCode)
	{
	case SB_THUMBTRACK:		
	case SB_THUMBPOSITION:
		m_Pos[num] = nPos;
		break;

	//======     ( Home)
	case SB_LEFT:
		delta = -100;
		goto New_Pos;

	//======     ( End)
	case SB_RIGHT:
		delta = +100;
		goto New_Pos;
	case SB_LINELEFT: //  ..
		delta = -1;
		goto New_Pos;
	case SB_LINERIGHT:
		delta = +1;
		goto New_Pos;
	case SB_PAGELEFT:
		delta = -20;
		goto New_Pos;
	case SB_PAGERIGHT:
		delta = +20;
		goto New_Pos;
	New_Pos:
		newPos = m_Pos[num] + delta;
		m_Pos[num] = newPos<0 ? 0 
					: newPos>100 ? 100 : newPos;
		break;
	case SB_ENDSCROLL:
	default:	
		return 0;
	}
	
	//===     
	char s[8];
	sprintf (s,"%d",m_Pos[num]);
	SetDlgItemText(nID, (LPCTSTR)s);

	//======       PropDlg
	for (UINT i = 0; i < m_nObjects; i++)
	{
		//======   
		CComQIPtr<IOpenGL, &IID_IOpenGL> p(m_ppUnk[i]);

		//======   
		if FAILED (p->SetLightParam (num,  m_Pos[num]))
		{
			ShowError();
			return 0;
		}
	}
	return 0;
}



LRESULT CPropDlg::OnSelchangeFillmode(WORD /*wNotifyCode*/,
		 WORD /*wID*/, HWND hWndCtl, BOOL& /*bHandled*/)
{
	//======       PropDlg
	for (UINT i = 0; i < m_nObjects; i++)
	{
		CComQIPtr<IOpenGL, &IID_IOpenGL> p(m_ppUnk[i]);
		
		//===   ,    
		DWORD sel = (DWORD)SendMessage(hWndCtl,
										CB_GETCURSEL,0,0);
		//===      
		sel = sel==0 ? GL_POINT
			 : sel==1 ? GL_LINE : GL_FILL;

		//======     COpenGL
		if FAILED (p->SetFillMode(sel))
		{
			ShowError();
			return 0;
		}
	}
	return 0;
}



LRESULT CPropDlg::OnClickedQuads(WORD /*wNotifyCode*/,
		WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	//======    PropDlg
	for (UINT i = 0; i < m_nObjects; i++)
	{
		//======   
		CComQIPtr<IOpenGL, &IID_IOpenGL> p(m_ppUnk[i]);

		//======  
		m_bQuad = !m_bQuad;

		//======    
		SetDlgItemText(IDC_QUADS, m_bQuad ? "Quads" 
												: "Strip");
		if FAILED (p->SetQuad(m_bQuad))
		{
			ShowError();
			return 0;
		}
	}
	return 0;
}



LRESULT CPropDlg::OnClickedFilename(WORD /*wNotifyCode*/,
		WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	for (UINT i = 0; i < m_nObjects; i++)
	{
		CComQIPtr<IOpenGL, &IID_IOpenGL> p(m_ppUnk[i]);

		//======    COpenGL		
		if FAILED (p->ReadData())
		{
			ShowError();
			return 0;
		}
	}
	return 0;
}



void COpenGL::LimitAngles()
{
	//======    , 
	//======      (-360(, +360()
	while (m_AngleX < -360.f)
		m_AngleX += 360.f;
	while (m_AngleX > 360.f)
		m_AngleX -= 360.f;
	while (m_AngleY < -360.f)
		m_AngleY += 360.f;
	while (m_AngleY > 360.f)
		m_AngleY -= 360.f;
}



LRESULT COpenGL::OnMouseMove(UINT /*uMsg*/, WPARAM wParam,
					LPARAM lParam, BOOL& /*bHandled*/)
{
	//======   
	if (m_bCaptured)
	{
		//======    
		short xPos = (short)LOWORD(lParam);
		short yPos = (short)HIWORD(lParam);
		
		m_dy = float(yPos - m_yPos)/20.f;
		m_dx = float(xPos - m_xPos)/20.f;
		
		//======     Ctrl,
		if (wParam & MK_CONTROL)
		{
			//===    
			m_xTrans += m_dx;
			m_yTrans -= m_dy;
		}
		else 
		{
			//======     
			if (m_bRightButton)
				//======   
				m_zTrans += (m_dx + m_dy)/2.f;
			else
			{
				//====== ,   
				//======    
				LimitAngles();
				//===      
				double a = fabs(m_AngleX);
				//     ( )
				if (90. < a && a < 270.)
					m_dx = -m_dx;
				m_AngleX += m_dy;
				m_AngleY += m_dx;
			}
		}
		//===       
		m_xPos = xPos;
		m_yPos = yPos;
		FireViewChange();
	}
	return 0;
}
 
LRESULT COpenGL::OnTimer(UINT /*uMsg*/, WPARAM /*wParam*/,
						LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	//======   
	LimitAngles();

	//======   
	m_AngleX += m_dy;
	m_AngleY += m_dx;
	
	//======   
	FireViewChange();
	return 0;
}



LRESULT COpenGL::OnLButtonDown(UINT /*uMsg*/, WPARAM
				/*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
	//======  
	KillTimer(1);

	//======   
	m_dx = 0.f;
	m_dy = 0.f;
	//======   ,
	//======     
	SetCapture();
	//======   
	m_bCaptured = true;
	//======   
	m_xPos = (short)LOWORD(lParam);
	m_yPos = (short)HIWORD(lParam);
	return 0;
}



LRESULT COpenGL::OnLButtonUp(UINT /*uMsg*/, WPARAM 
		/*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	//======   ,
	if (m_bCaptured)
	{
		//===     
		//===    
		if (fabs(m_dx) > 0.5f || fabs(m_dy) > 0.5f)
			//======    
			SetTimer(1,33);
		else
			//======    
			KillTimer(1);

		//======    
		m_bCaptured = false;
		//======   
		ReleaseCapture();
	}
	return 0;
}



LRESULT COpenGL::OnRButtonDown(UINT uMsg, WPARAM wParam,
								LPARAM lParam, BOOL& bHandled)
{
	//======     
	m_bRightButton = true;

	//======     
	OnLButtonDown(uMsg, wParam, lParam, bHandled);
	return 0;
}


LRESULT COpenGL::OnRButtonUp(UINT /*uMsg*/, WPARAM
		 /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	m_bRightButton = false;
	m_bCaptured = false;
	ReleaseCapture();
	return 0;
}



#pragma once

//=========== COpenGL wrapper class
class COpenGL : public CWnd
{
protected:
	DECLARE_DYNCREATE(COpenGL)
public:

	//====    CLSID  
	CLSID const& GetClsid()
	{
		static CLSID const clsid =
		{
			0x519d9ed8, 0xbc46, 0x4367, { 0x9c, 0xc0, 0x49,
			0x81, 0x40, 0xf3, 0x94, 0x16 }
		};
		return clsid;
	}

	virtual BOOL Create(LPCTSTR lpszClassName,
			LPCTSTR lpszWindowName, DWORD dwStyle,
			const RECT& rect, CWnd* pParentWnd, UINT nID,
			CCreateContext* pContext = NULL)
	{
		return CreateControl(GetClsid(), lpszWindowName,
							dwStyle, rect, pParentWnd, nID);
	}

	BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle,
		const RECT& rect, CWnd* pParentWnd, UINT nID,
		CFile* pPersist = NULL, BOOL bStorage = FALSE,
		BSTR bstrLicKey = NULL)
	{
		return CreateControl(GetClsid(), lpszWindowName,
					dwStyle, rect, pParentWnd, nID,
					pPersist, bStorage, bstrLicKey);
	}

//====== ,   ActiveX
public:
	void SetFillColor(unsigned long newValue);
	unsigned long GetFillColor();
	void GetLightParams(long* pPos);
	void SetLightParam(short lp, long nPos);
	void ReadData();
	void SetFillMode(DWORD mode);
	void GetFillMode(DWORD* pMode);
	void GetQuad(BOOL* bQuad);
	void SetQuad(BOOL bQuad);
};



	CLSID const& GetClsid()
	{
		//      ATLGL.IDL
		// 519D9ED8-BC46-4367-9CC0-498140F39416

		static CLSID const clsid =
		{
			//========      ATLGL.IDL
			0x519d9ed8, 0xbc46, 0x4367, { 0x9c, 0xc0, 0x49,
			0x81, 0x40, 0xf3, 0x94, 0x16 }
		};
		return clsid;
	}



#include "stdafx.h"
#include "opengl.h"

IMPLEMENT_DYNCREATE(COpenGL, CWnd)

//======   
//======     Get/Set
void COpenGL::SetFillColor(unsigned long newValue)
{
	static BYTE parms[] =
		VTS_I4;
	InvokeHelper(0xfffffe02, DISPATCH_PROPERTYPUT, VT_EMPTY,
					NULL, parms, newValue);
}

//======  
unsigned long COpenGL::GetFillColor()
{
	unsigned long result;
	InvokeHelper(0xfffffe02, DISPATCH_PROPERTYGET, VT_I4,
					(void*)&result, NULL);
	return result;
}

//======   
void COpenGL::GetLightParams(long* pPos)
{
	static BYTE parms[] =
		VTS_PI4;
	InvokeHelper(0x1, DISPATCH_METHOD, VT_EMPTY, NULL,
					parms, pPos);
}

void COpenGL::SetLightParam(short lp, long nPos)
{
	static BYTE parms[] =
		VTS_I2 VTS_I4;
	InvokeHelper(0x2, DISPATCH_METHOD, VT_EMPTY, NULL,
					parms, lp, nPos);
}

void COpenGL::ReadData()
{
	InvokeHelper(0x3, DISPATCH_METHOD, VT_EMPTY, 0, 0);
}

void COpenGL::GetFillMode(DWORD* pMode)
{
	static BYTE parms[] =
		VTS_PI4;
	InvokeHelper(0x4, DISPATCH_METHOD, VT_EMPTY, NULL,
					parms, pMode);
}

void COpenGL::SetFillMode(DWORD nMode)
{
	static BYTE parms[] =
		VTS_I4;
	InvokeHelper(0x5, DISPATCH_METHOD, VT_EMPTY, NULL,
					parms, nMode);
}

void COpenGL::GetQuad(BOOL* bQuad)
{
	static BYTE parms[] =
		VTS_PI4;
	InvokeHelper(0x6, DISPATCH_METHOD, VT_EMPTY, NULL,
					parms, bQuad);
}

void COpenGL::SetQuad(BOOL bQuad)
{
	static BYTE parms[] =
		VTS_I4;
	InvokeHelper(0x7, DISPATCH_METHOD, VT_EMPTY, NULL,
					parms, bQuad);
}






IDD_TESTGL_DIALOG
 Data File
IDC_FILENAME
 Back Color
IDC_BKCLR
 Quads
IDC_QUADS
 Strips
IDC_STRIPS
  Fill Mode
IDC_FILL
 Light (X)
IDC_XPOS
 Close
IDOK



//=====    ( TestGLDlg.h)
#include "opengl.h"

#pragma once

class CTestGLDlg : public CDialog
{
public:
	CTestGLDlg(CWnd* p = NULL);
	enum { IDD = IDD_TESTGL_DIALOG };

	//=======  -
	COpenGL	m_Ctrl;
	//=======   
	BOOL m_bQuads;

	//=======      
	void OnSelchangeFill(void);
	void OnClickedFilename(void);
	afx_msg void OnHScroll(UINT nSBCode, UINT nPos,
									CScrollBar* pScrollBar);
	void OnClickedBkclr(void);
	void OnClickedQuads(void);
	void OnClickedStrips(void);

protected:
	virtual void DoDataExchange(CDataExchange* pDX);
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	DECLARE_MESSAGE_MAP()
};



#include "stdafx.h"
#include "TestGL.h"
#include "TestGLDlg.h"

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

//======   
CTestGLDlg::CTestGLDlg(CWnd* p)
	: CDialog(CTestGLDlg::IDD, p){}

void CTestGLDlg::DoDataExchange(CDataExchange* pDX)
{
	//======    
	DDX_Control(pDX, IDC_OPENGL, m_Ctrl);
	CDialog::DoDataExchange(pDX);
}

//======    ON_WM_PAINT  . .
BEGIN_MESSAGE_MAP(CTestGLDlg, CDialog)
	ON_WM_SYSCOMMAND()
		//}}AFX_MSG_MAP
	ON_CBN_SELCHANGE(IDC_FILL, OnSelchangeFill)
	ON_BN_CLICKED(IDC_FILENAME, OnClickedFilename)
	ON_WM_HSCROLL()
	ON_BN_CLICKED(IDC_BKCLR, OnClickedBkclr)
	ON_BN_CLICKED(IDC_QUADS, OnClickedQuads)
	ON_BN_CLICKED(IDC_STRIPS, OnClickedStrips)
END_MESSAGE_MAP()

//===== CTestGLDlg message handlers
BOOL CTestGLDlg::OnInitDialog()
{
	//======     
	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu)
	{
		//======   About
		pSysMenu->AppendMenu(MF_SEPARATOR);
		pSysMenu->AppendMenu(MF_STRING,
							IDM_ABOUTBOX,"About...");
	}

	//======     
	HICON hMyIcon = ::LoadIcon(0,(char*)IDI_WINLOGO);
	SetIcon(hMyIcon, TRUE);			// Set big icon
	SetIcon(hMyIcon, FALSE);		// Set small icon

	CDialog::OnInitDialog();

	//======    
	CComboBox *pBox = (CComboBox*)GetDlgItem(IDC_FILL);
	pBox->AddString("Points");
	pBox->AddString("Lines");
	pBox->AddString("Fill");
	pBox->SetCurSel(2);

	//====     
	m_Ctrl.GetQuad(&m_bQuads);
		
	WPARAM w = m_bQuads ? BST_CHECKED : BST_UNCHECKED;

	//=====   
	GetDlgItem(IDC_QUADS)->SendMessage(BM_SETCHECK, w, 0);
	w = m_bQuads ? BST_UNCHECKED : BST_CHECKED;
	GetDlgItem(IDC_STRIPS)->SendMessage(BM_SETCHECK, w, 0);

	return TRUE;
}

void CTestGLDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CDialog(IDD_ABOUTBOX).DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

//======     Combo-box
void CTestGLDlg::OnSelchangeFill(void)
{
	DWORD sel = ((CComboBox*)GetDlgItem(IDC_FILL))
												->GetCurSel();
	sel = sel==0 ? GL_POINT 
		 : sel==1 ? GL_LINE 
					: GL_FILL;
	m_Ctrl.SetFillMode(sel);
}

//====      
void CTestGLDlg::OnClickedFilename(void)
{
	m_Ctrl.ReadData();
}

//======    
void CTestGLDlg::OnHScroll(UINT nSBCode, UINT nPos,
							CScrollBar* pScrollBar)
{
	//======   ,   
	//======      nPos
	nPos = ((CSliderCtrl*)GetDlgItem(IDC_XPOS))->GetPos();
	m_Ctrl.SetLightParam (0, nPos);
}

//======   
void CTestGLDlg::OnClickedBkclr(void)
{
	DWORD clr = m_Ctrl.GetFillColor();
	CColorDialog dlg(clr);
	dlg.m_cc.Flags |= CC_FULLOPEN;
	if (dlg.DoModal()==IDOK)
	{
		m_Ctrl.SetFillColor(dlg.m_cc.rgbResult);
	}
}

//======     
//======   
void CTestGLDlg::OnClickedQuads(void)
{
	m_Ctrl.SetQuad(m_bQuads = TRUE);
}

void CTestGLDlg::OnClickedStrips(void)
{
	m_Ctrl.SetQuad(m_bQuads = FALSE);
}




