Click here to Skip to main content
15,881,882 members
Articles / Desktop Programming / ATL

3D Graph ActiveX Control

Rate me:
Please Sign up or sign in to vote.
4.90/5 (100 votes)
2 Aug 2003MIT3 min read 770.4K   50K   284  
An ATL/STL ActiveX control based on OpenGL library for 3D data visualization
// GraphCtl.cpp : Implementation of CGraphCtl
//
// Autor : Nikolai Teofilov  nteofilov@yahoo.de
//			
// Comment	: Use with your own risk !
//
// Copyright (c) 2003.

#include "stdafx.h"
#include "NTGraph3D.h"
#include "GraphCtl.h"


static const FONTDESC _fontdesc =
      {sizeof(FONTDESC), OLESTR("times new roman"), FONTSIZE( 14 ),
      FW_BOLD, ANSI_CHARSET, TRUE, FALSE, FALSE };

/////////////////////////////////////////////////////////////////////////////
// CGraphCtl
unsigned char threeto8[8] =
{
	0, 0111>>1, 0222>>1, 0333>>1, 0444>>1, 0555>>1, 0666>>1, 0377
};

unsigned char twoto8[4] =
{
	0, 0x55, 0xaa, 0xff
};

unsigned char oneto8[2] =
{
	0, 255
};

static int defaultOverride[13] =
{
	0, 3, 24, 27, 64, 67, 88, 173, 181, 236, 247, 164, 91
};

static PALETTEENTRY defaultPalEntry[20] =
{
	{ 0,   0,   0,    0 },
	{ 0x80,0,   0,    0 },
	{ 0,   0x80,0,    0 },
	{ 0x80,0x80,0,    0 },
	{ 0,   0,   0x80, 0 },
	{ 0x80,0,   0x80, 0 },
	{ 0,   0x80,0x80, 0 },
	{ 0xC0,0xC0,0xC0, 0 },

	{ 192, 220, 192,  0 },
	{ 166, 202, 240,  0 },
	{ 255, 251, 240,  0 },
	{ 160, 160, 164,  0 },

	{ 0x80,0x80,0x80, 0 },
	{ 0xFF,0,   0,    0 },
	{ 0,   0xFF,0,    0 },
	{ 0xFF,0xFF,0,    0 },
	{ 0,   0,   0xFF, 0 },
	{ 0xFF,0,   0xFF, 0 },
	{ 0,   0xFF,0xFF, 0 },
	{ 0xFF,0xFF,0xFF, 0 }
};

void CGraphCtl::CreateContext(HDC hdc, RECT& rc)
{
	PIXELFORMATDESCRIPTOR pfd;
	GLfloat     fMaxObjSize, fAspect;
	GLfloat     fNearPlane, fFarPlane;

	if (!bSetupPixelFormat(hdc))
		return;

	CreateRGBPalette(hdc);

	::SelectPalette(hdc, m_hPal, FALSE);
	::RealizePalette(hdc);

	int n = ::GetPixelFormat(hdc);
	::DescribePixelFormat(hdc, n, sizeof(pfd), &pfd);


	m_hrc = wglCreateContext(hdc);
	wglMakeCurrent(hdc, m_hrc);

	glClearDepth(10.0f);
	glEnable(GL_DEPTH_TEST);

	if (rc.bottom)
		fAspect = (GLfloat)rc.right/rc.bottom;
	else    // don't divide by zero, not that we should ever run into that...
		fAspect = 1.0f;

	fNearPlane = 3.0f;
	fFarPlane = 20.0f;
	fMaxObjSize = 3.0f;
	m_fRadius = fNearPlane + fMaxObjSize / 2.0f;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// update the camera
 	if (m_nProjection == Orthographic)	
		glOrtho(-1,1,-1,1,fNearPlane,fFarPlane);	
	else
	    gluPerspective(30.0f, fAspect, fNearPlane, fFarPlane);

	glMatrixMode(GL_MODELVIEW);
}

LRESULT CGraphCtl::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// Won't be here unless we just got activated and created a window
	HDC hdc = GetDC();
	RECT rc;
	GetClientRect(&rc);
	CreateContext(hdc, rc);
	return 0;
}

LRESULT CGraphCtl::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{

	::wglMakeCurrent(NULL,  NULL);

	if (m_hrc)
	{
		::wglDeleteContext(m_hrc);
		m_hrc = NULL;
	}
	return 0;
}

LRESULT CGraphCtl::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	SetCapture();
	m_bMouseCaptured = TRUE;
	m_xPos = (short)LOWORD(lParam);  // horizontal position of cursor
	m_yPos = (short)HIWORD(lParam);  // vertical position of cursor
	return 0;
}
LRESULT CGraphCtl::OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	m_bMouseCaptured = FALSE;
	ReleaseCapture();
	FireViewChange();

	return 0;
}

LRESULT CGraphCtl::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	if (m_bMouseCaptured)
	{
		int xPos = (short)LOWORD(lParam);  // horizontal position of cursor
		int yPos = (short)HIWORD(lParam);  // vertical position of cursor
		GLfloat fNearPlane = 3.0f;
		GLfloat fFarPlane = 7.0f;
		GLfloat fMaxObjSize = 3.0f;

		if (m_nTrackState == Zoom)
		{
			m_fRadius += (float)(m_xPos - xPos)/100.0f;
			FireViewChange();
		}
		else if (m_nTrackState == Rotate) 
		{
			m_wAngleX -= (float)(m_yPos - yPos)/2.0f;
			m_wAngleY -= (float)(m_xPos - xPos)/2.0f;
			FireViewChange();
		}
		else if (m_nTrackState == Pan)
		{
			DoPan(xPos,yPos);			
		}

		m_xPos = xPos;
		m_yPos = yPos;
	}
	return 0;
}

void CGraphCtl::DoPan(int x, int y)
{
	double Y1 = y + dRangeY[MIN]/(dRangeY[MAX]-dRangeY[MIN]) + 0.5;
	double Y2 = m_yPos + dRangeY[MIN]/(dRangeY[MAX]-dRangeY[MIN]) + 0.5;
	double yOffset = (Y1 - Y2)/100.0;

	double X1 = x + dRangeX[MIN]/(dRangeX[MAX]-dRangeX[MIN]) + 0.5;
	double X2 = m_xPos + dRangeX[MIN]/(dRangeX[MAX]-dRangeX[MIN]) + 0.5;
	double xOffset = (X1 - X2)/100.0;


	SetRange(dRangeX[MIN] - xOffset, dRangeX[MAX] - xOffset, 
			 dRangeY[MIN] + yOffset, dRangeY[MAX] + yOffset,
			 dRangeZ[MIN] + xOffset, dRangeZ[MAX] + xOffset);

}

HRESULT CGraphCtl::OnDraw(ATL_DRAWINFO& di)
{
	HDC hdc = di.hdcDraw;
	RECT& rc = *(RECT*)di.prcBounds;
	DrawGraph(hdc, rc);
	
	return 1;
}

STDMETHODIMP CGraphCtl::CopyToClipboard()
{

	HDC hdc = GetDC();
	
    // Get client geometry 
	RECT rc;
	GetClientRect(&rc);
	LONG
	   width = rc.right  - rc.left,
	   height = rc.bottom - rc.top; 

	int bitsPerPixel = ::GetDeviceCaps(hdc, BITSPIXEL);

	switch(bitsPerPixel)
	{
		case 8:
		case 24: 
				 width -= width % 4; 
			     break;
		case 16: 
			     width -= width % 2; 
			     break;
		case 32:
		default: 
			     break;
	}

	// Alloc pixel bytes 
	int NbBytes = bitsPerPixel/8 * width * height; 

	// Fill header 
	BITMAPINFOHEADER header; 
	header.biWidth = width; 
	header.biHeight = height; 
	header.biSizeImage = NbBytes; 
	header.biSize = 40; 
	header.biPlanes = 1; 
	header.biBitCount =  3 * 8; // RGB 
	header.biCompression = 0; 
	header.biXPelsPerMeter = 0; 
	header.biYPelsPerMeter = 0; 
	header.biClrUsed = 0; 
	header.biClrImportant = 0; 

	// Generate handle 
	HANDLE handle = (HANDLE)::GlobalAlloc (GHND,sizeof(BITMAPINFOHEADER) + NbBytes); 
	if(handle != NULL) 
	{ 
		// Lock handle 
		char *pData = (char *) ::GlobalLock((HGLOBAL)handle); 
		// Copy header and data 
		memcpy(pData,&header,sizeof(BITMAPINFOHEADER)); 
		::glReadPixels(0,0,width,height,GL_BGR_EXT,GL_UNSIGNED_BYTE,pData+sizeof(BITMAPINFOHEADER)); 
		// Unlock 
		::GlobalUnlock((HGLOBAL)handle); 

		// Push DIB in clipboard 
		OpenClipboard(); 
		EmptyClipboard(); 
		SetClipboardData(CF_DIB,handle); 
		CloseClipboard(); 
	} 


	ReleaseDC(hdc);
	return S_OK;
}
void CGraphCtl::DrawBorder(HDC hdc, RECT rc)
{

 if (m_bBorderVisible)
	   switch(m_nBorderStyle)
	   {
		   case bump:
			 if(m_nAppearance)
				 ::DrawEdge(hdc, &rc, EDGE_BUMP|EDGE_SUNKEN, BF_RECT);
			 else
				 ::DrawEdge(hdc, &rc, EDGE_BUMP, BF_RECT);

			 break;
		   case etched:
			 if(m_nAppearance)
				 ::DrawEdge(hdc, &rc, EDGE_ETCHED|EDGE_SUNKEN, BF_RECT);
			 else
				 ::DrawEdge(hdc, &rc, EDGE_ETCHED, BF_RECT);
    		 break;
		   case raised:
			if(m_nAppearance)
				::DrawEdge(hdc, &rc, EDGE_RAISED|EDGE_SUNKEN, BF_RECT);
			else
				::DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT);
    		break;
		   default:
			     ::DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT);
			break;

	   }
  else if(m_nAppearance && !m_bBorderVisible)
	   ::DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT);

} 
void CGraphCtl::DrawGraph(HDC hdc, RECT rc)
{
	::SelectPalette(hdc, m_hPal, FALSE);
	::RealizePalette(hdc);

	wglMakeCurrent(hdc, m_hrc);

	COLORREF colBkgn;
	OleTranslateColor(m_clrBackColor, m_hPal, &colBkgn);
	SetTextColor(hdc, colBkgn);

    SetBkColor(colBkgn);
	

	glPushMatrix();

		glTranslatef(0.0f, 0.0f, -m_fRadius);
		glRotatef(m_wAngleX, 1.0f, 0.0f, 0.0f);
		glRotatef(m_wAngleY, 0.0f, 1.0f, 0.0f);
		glRotatef(m_wAngleZ, 0.0f, 0.0f, 1.0f);

		if(m_bMouseCaptured && m_nTrackState != Pan)
			DrawAxis();
		else 
		{
			DrawAxisBox();
			DrawAxisGrid();
			DrawAxisLabels(hdc);
			PlotElement();
		}

	glPopMatrix();

	glFinish();
	SwapBuffers(wglGetCurrentDC());

    DrawGraphTitle(hdc,rc);
	DrawBorder(hdc,rc);


}

void CGraphCtl::DrawGraphTitle(HDC hdc, RECT rc)
{
	COLORREF colT;
	OleTranslateColor(m_clrCaptionColor, m_hPal, &colT);
	SetTextColor(hdc, colT);
	SetBkMode(hdc, TRANSPARENT);
	USES_CONVERSION;
	LPCTSTR lpsz = OLE2T(m_bstrCaption);
	DrawText(hdc, lpsz, -1, &rc, DT_CENTER | DT_TOP | DT_SINGLELINE);
} 

void CGraphCtl::DrawAxis()
{
// draw carthesian axes
	glBegin(GL_LINES);
		// red x axis
		glColor3f(1.f,0.f,0.f);	

		glVertex3f(-0.5f,-0.5f,-0.5f);
		glVertex3f(0.5f,-0.5f,-0.5f);

		glVertex3f(0.4f, -0.4f, -0.5f);
		glVertex3f(0.5f, -0.5f, -0.5f);
		glVertex3f(0.4f, -0.6f, -0.5f);
		glVertex3f(0.5f,-0.5f,-0.5f);

		glVertex3f(0.6f,-0.6f,-0.5f);
	    glVertex3f(0.7f,-0.4f,-0.5f);
	    glVertex3f(0.7f,-0.6f,-0.5f);
	    glVertex3f(0.6f,-0.4f,-0.5f);
        
		// green y axis
		glColor3f(0.0f, 1.0f, 0.0f);

		glVertex3f(-0.5f,-0.5f,-0.5f);
		glVertex3f(-0.5f,0.5f,-0.5f);

		glVertex3f(-0.5f,0.5f,-0.5f);
		glVertex3f(-0.4f,0.4f,-0.5f);
		glVertex3f(-0.5f,0.5f,-0.5f);	
		glVertex3f(-0.6f,0.4f,-0.5f);
		
		glVertex3f(-0.5f,0.6f,-0.5f);
		glVertex3f(-0.5f,0.7f,-0.5f);
		glVertex3f(-0.5f,0.7f,-0.5f);
		glVertex3f(-0.6f,0.8f,-0.5f);
		glVertex3f(-0.6f,0.8f,-0.5f);
	    glVertex3f(-0.5f,0.7f,-0.5f);
		glVertex3f(-0.5f,0.7f,-0.5f);
		glVertex3f(-0.4f,0.8f,-0.5f);
     
		// blue z axis
		glColor3f(0.f,0.f,1.f);
		glVertex3f(-0.5f, -0.5f, -0.5f);
		glVertex3f(-0.5f, -0.5f, 0.5f);

		glVertex3f(-0.5f, -0.5f, 0.5f);
		glVertex3f(-0.5f, -0.6f, 0.4f);
		glVertex3f(-0.5f, -0.5f, 0.5f);
		glVertex3f(-0.5f, -0.4f, 0.4f);

		glVertex3f(-0.5f,-0.4f,0.7f);
		glVertex3f(-0.5f,-0.4f,0.6f);
		glVertex3f(-0.5f,-0.4f,0.6f);
		glVertex3f(-0.5f,-0.6f,0.7f);
		glVertex3f(-0.5f,-0.6f,0.7f);
	    glVertex3f(-0.5f,-0.6f,0.6f);
    glEnd();

//	glColor3f(1.0f, 0.0f, 0.0f);
//	auxWireSphere(2.5);
}

void CGraphCtl::DrawAxisBox()
{
	COLORREF colX,colY,colZ;
	OleTranslateColor(m_clrXGridColor, m_hPal, &colX);
	OleTranslateColor(m_clrYGridColor, m_hPal, &colY);
	OleTranslateColor(m_clrZGridColor, m_hPal, &colZ);

	glLineWidth(1.0f);

		glBegin(GL_LINE_STRIP);
		// x axis
		SetColor(colX);
		glVertex3f(-0.5f, -0.5f, -0.5f);
		glVertex3f(0.5f, -0.5f, -0.5f);
		glVertex3f(0.5f, -0.5f, -0.5f);
		glVertex3f(0.5f, 0.5f, -0.5f);
		glVertex3f(0.5f, 0.5f, -0.5f);
		glVertex3f(-0.5f, 0.5f, -0.5f);
		// y axis
		SetColor(colY);
		glVertex3f(-0.5f, -0.5f, -0.5f);
		glVertex3f(-0.5f, 0.5f, -0.5f);
		glVertex3f(-0.5f, 0.5f, -0.5f);
		glVertex3f(-0.5f, 0.5f, 0.5f);
		glVertex3f(-0.5f, 0.5f, 0.5f);
		glVertex3f(-0.5f, -0.5f, 0.5f);
		// z axis
		SetColor(colZ);
		glVertex3f(-0.5f, -0.5f, -0.5f);
		glVertex3f(-0.5f, -0.5f, 0.5f);
		glVertex3f(-0.5f, -0.5f, 0.5f);
		glVertex3f(0.5f, -0.5f, 0.5f);
		glVertex3f(0.5f, -0.5f, 0.5f);
		glVertex3f(0.5f, -0.5f, 0.5f);
		glVertex3f(0.5f, -0.5f, -0.5f);
	glEnd();

}
void CGraphCtl::DrawAxisGrid()
{

	glBegin(GL_LINES);
    
	float X,Y,Z;

	int i;

	COLORREF colX, colY, colZ;
	OleTranslateColor(m_clrXGridColor, m_hPal, &colX);
	OleTranslateColor(m_clrYGridColor, m_hPal, &colY);
	OleTranslateColor(m_clrZGridColor, m_hPal, &colZ);
		
// Draw X Grid
	for ( i = 0 ; i <= m_nGridX ; i++)
	{
		X = ((float)i)/m_nGridX;
			
		// x axis
	    SetColor(colX);	

		glVertex3f(X-0.5f, -0.5f,	-0.5f);
		glVertex3f(X-0.5f,  0.5f,	-0.5f);

		SetColor(colZ);

		glVertex3f(X-0.5f, -0.5f,	-0.5f);
		glVertex3f(X-0.5f, -0.5f,	 0.5f);

	}
		
// Draw Y Grid	
	for ( i = 0 ; i <= m_nGridY ; i++)
	{
		
	    Y = ((float)i)/m_nGridY;

		// y axis
		SetColor(colX);

		glVertex3f(-0.5f,	Y-0.5f, -0.5f);
		glVertex3f( 0.5f,	Y-0.5f, -0.5f);

		SetColor(colY);

		glVertex3f(-0.5f,	Y-0.5f, -0.5f);
		glVertex3f(-0.5f,	Y-0.5f,  0.5f);

	}		

// Draw Z Grid		
	for ( i = 0 ; i <= m_nGridZ ; i++)
	{
		Z = ((float)i)/m_nGridZ;

		// z axis
		SetColor(colZ);

		glVertex3f(-0.5f  ,-0.5f  ,Z-0.5f);
		glVertex3f( 0.5f  ,-0.5f  ,Z-0.5f);

		SetColor(colY);

		glVertex3f(-0.5f  ,-0.5f  ,Z-0.5f);
		glVertex3f(-0.5f  , 0.5f  ,Z-0.5f);
	}		

	glEnd();

}

void CGraphCtl::DrawAxisLabels(HDC hdc)
{

	float X,Y,Z,res;
	int i;
	char str[50]; 
	CPoint3D pt;

	COLORREF colX, colY, colZ;
	OleTranslateColor(m_clrXGridColor, m_hPal, &colX);
	OleTranslateColor(m_clrYGridColor, m_hPal, &colY);
	OleTranslateColor(m_clrZGridColor, m_hPal, &colZ);


// Draw X Grid Label
	res = (dRangeX[MAX] - dRangeX[MIN]) / m_nGridX ;
	
	for ( i = 0 ; i <= m_nGridX ; i++)
	{
		X = dRangeX[MIN] + (res * (float)i);
		sprintf(str,"%g",X);

		X = ((float)i)/m_nGridX;
	
		// red x axis
		//glColor3f(1.f,0.f,0.f);
		SetColor(colX);

		pt=CPoint3D(-0.5,-0.5,0.5);
		pt.Translate(X,0.0,0.3);
		
		PrintText(hdc, pt, str);
	}
		
// Draw Y Grid Label
	res = (dRangeY[MAX] - dRangeY[MIN]) / m_nGridY ;
	
	for ( i = 0 ; i <= m_nGridY ; i++)
	{
		Y = dRangeY[MIN] + (res * (float)i) ;
		sprintf(str,"%g",Y);

        Y = ((float)i)/m_nGridY;
		
		// green y axis
		//glColor3f(0.f,1.f,0.f);
		SetColor(colY);
		
		pt = CPoint3D(-0.5,-0.5,0.5);
		pt.Translate(0.0,Y,0.3);
		PrintText(hdc, pt, str);
	}		

// Draw Z Grid Label
	res = (dRangeZ[MAX] - dRangeZ[MIN]) / m_nGridZ ;
	
	for ( i = 0 ; i <= m_nGridZ ; i++)
	{
		Z = dRangeZ[MIN] + (res * (float)i) ;
		sprintf(str,"%g",Z);

		Z = ((float)i)/m_nGridZ;

		// blue z axis
		//glColor3f(0.f,0.f,1.f);
		SetColor(colZ);

		pt = CPoint3D(0.5,-0.5,-0.5);
		pt.Translate (0.2,0.0,Z);
		PrintText(hdc, pt, str);

	}		

	// Draw Axis Titles
    SetColor(RGB(0,0,0));

	// Native C++ compiler COM support 
	// BSTR, VARIANT wrappers header
	using namespace _com_util; 

	SetColor(colX);
	PrintText(hdc,CPoint3D(0.0f,0.7f,-0.5f),
		ConvertBSTRToString(m_bstrXLabel));
	SetColor(colY);
	PrintText(hdc,CPoint3D(0.7f,0.0f,-0.5f),
		ConvertBSTRToString(m_bstrYLabel));
	SetColor(colZ);
	PrintText(hdc,CPoint3D(-0.5f,0.7f,0.0f),
		ConvertBSTRToString(m_bstrZLabel));

	glEnd();

}

BOOL CGraphCtl::bSetupPixelFormat(HDC hdc)
{
	static PIXELFORMATDESCRIPTOR pfd =
	{
		sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
		1,                              // version number
		PFD_DRAW_TO_WINDOW |            // support window
		  PFD_SUPPORT_OPENGL |          // support OpenGL
		  PFD_DOUBLEBUFFER,             // double buffered
		PFD_TYPE_RGBA,                  // RGBA type
		24,                             // 24-bit color depth
		0, 0, 0, 0, 0, 0,               // color bits ignored
		0,                              // no alpha buffer
		0,                              // shift bit ignored
		0,                              // no accumulation buffer
		0, 0, 0, 0,                     // accum bits ignored
		32,                             // 32-bit z-buffer
		0,                              // no stencil buffer
		0,                              // no auxiliary buffer
		PFD_MAIN_PLANE,                 // main layer
		0,                              // reserved
		0, 0, 0                         // layer masks ignored
	};
	int pixelformat;

	if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == 0 )
	{
		ATLASSERT(FALSE);
		return FALSE;
	}

	if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE)
	{
		ATLASSERT(FALSE);
		return FALSE;
	}

	return TRUE;
}

void CGraphCtl::PrintText(HDC hdc, CPoint3D pt, const char *str)
{
	HFONT hOldFont = NULL;
	if (m_pFont)
	{
		CComPtr<IFont> pFont;
		m_pFont->QueryInterface(IID_IFont, (void**)&pFont);
		HFONT hfont;
		pFont->get_hFont(&hfont);
		hOldFont = (HFONT) SelectObject(hdc, hfont);
	}
	else
		SelectObject (hdc, GetStockObject (SYSTEM_FONT)); 

	// create bitmaps for the device context font's first 256 glyphs 
	wglUseFontBitmaps(hdc, 0, 256, 1000); 

	// move to position
	glRasterPos3f(pt.x,pt.y,pt.z); 
	 
	// set up for a string-drawing display list call 
	glListBase(1000); 
 
	// draw a string using font display lists 
	glCallLists(strlen(str), GL_UNSIGNED_BYTE, (GLubyte*)str);
 
	// get all those commands to execute 
	glFlush(); 
 
	// delete our 256 glyph display lists 
	glDeleteLists(1000, 256) ; 

	if (hOldFont)
		SelectObject(hdc, hOldFont);
}
unsigned char CGraphCtl::ComponentFromIndex(int i, UINT nbits, UINT shift)
{
	unsigned char val;

	val = (unsigned char) (i >> shift);
	switch (nbits)
	{

	case 1:
		val &= 0x1;
		return oneto8[val];
	case 2:
		val &= 0x3;
		return twoto8[val];
	case 3:
		val &= 0x7;
		return threeto8[val];

	default:
		return 0;
	}
}


void CGraphCtl::CreateRGBPalette(HDC hdc)
{
	PIXELFORMATDESCRIPTOR pfd;
	int n, i;

	if (m_pPal)
		return;

	n = ::GetPixelFormat(hdc);
	::DescribePixelFormat(hdc, n, sizeof(pfd), &pfd);

	if (pfd.dwFlags & PFD_NEED_PALETTE)
	{
		n = 1 << pfd.cColorBits;
		m_pPal = (PLOGPALETTE) new char[sizeof(LOGPALETTE) + n * sizeof(PALETTEENTRY)];

		ATLASSERT(m_pPal != NULL);

		m_pPal->palVersion = 0x300;
		m_pPal->palNumEntries = n;
		for (i=0; i<n; i++)
		{
			m_pPal->palPalEntry[i].peRed =
					ComponentFromIndex(i, pfd.cRedBits, pfd.cRedShift);
			m_pPal->palPalEntry[i].peGreen =
					ComponentFromIndex(i, pfd.cGreenBits, pfd.cGreenShift);
			m_pPal->palPalEntry[i].peBlue =
					ComponentFromIndex(i, pfd.cBlueBits, pfd.cBlueShift);
			m_pPal->palPalEntry[i].peFlags = 0;
		}

		/* fix up the palette to include the default GDI palette */
		if ((pfd.cColorBits == 8)                           &&
			(pfd.cRedBits   == 3) && (pfd.cRedShift   == 0) &&
			(pfd.cGreenBits == 3) && (pfd.cGreenShift == 3) &&
			(pfd.cBlueBits  == 2) && (pfd.cBlueShift  == 6)
		   )
		{
			for (i = 1 ; i <= 12 ; i++)
				m_pPal->palPalEntry[defaultOverride[i]] = defaultPalEntry[i];
		}

		m_hPal = ::CreatePalette((LPLOGPALETTE)m_pPal);
//        delete pPal;

		::SelectPalette(hdc, m_hPal, FALSE);
		::RealizePalette(hdc);
	}
}

STDMETHODIMP CGraphCtl::get_CaptionColor(OLE_COLOR *pVal)
{
	*pVal = m_clrCaptionColor;
	return S_OK;
}

STDMETHODIMP CGraphCtl::put_CaptionColor(OLE_COLOR newVal)
{
	m_clrCaptionColor = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}


STDMETHODIMP CGraphCtl::SetRange(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax)
{
	if (xmin==xmax || ymin==ymax || zmin==zmax)
		return S_OK;
	else if (xmin>xmax || ymin>ymax || zmin>zmax)
		return S_OK;
	else 
	{
		dRangeX[MIN]=xmin;
		dRangeX[MAX]=xmax;
		dRangeY[MIN]=ymin;
		dRangeY[MAX]=ymax;
		dRangeZ[MIN]=zmin;
		dRangeZ[MAX]=zmax;
    }
	
	FireViewChange(); // call the InvalidateRect API directly!
	SetDirty(TRUE);
	return S_OK;
}

STDMETHODIMP CGraphCtl::AutoRange()
{
	if (!bIsPlotAvailable) {

	SetRange(0,1,0,1,0,1);
	return S_OK;

	}
	SetRange(dAutoRangeX[MIN],dAutoRangeX[MAX],
		     dAutoRangeY[MIN],dAutoRangeY[MAX],
			 dAutoRangeZ[MIN],dAutoRangeZ[MAX]);

	return S_OK;
}

STDMETHODIMP CGraphCtl::ShowPropertyPages()
{
	DoVerbProperties(NULL,NULL);

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_TrackMode(short *pVal)
{
	*pVal = m_nTrackState;
	return S_OK;
}

STDMETHODIMP CGraphCtl::put_TrackMode(short newVal)
{
   if (newVal >= 0 && newVal < 4)
   {
      m_nTrackState = newVal;
      SetDirty(TRUE);

      return S_OK;
   }
   else
      return Error(_T("Track State must have between 0 and 3"));


	return S_OK;
}

STDMETHODIMP CGraphCtl::put_Projection(short newVal)
{
	newVal = newVal < 0 ? 0: newVal;
	newVal = newVal > 1 ? 1: newVal;

	m_nProjection = newVal;
	SetDirty(TRUE);
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// update the camera
 	if (m_nProjection == Orthographic)	
		glOrtho(-1,1,-1,1,3.0f,20.0f);	
	else
	    gluPerspective(30.0f, 1.0f, 3.0f, 20.0f);

	glMatrixMode(GL_MODELVIEW);
	
	FireViewChange();
	
	return S_OK;
}
STDMETHODIMP CGraphCtl::get_Projection(short *pVal)
{
	*pVal = m_nProjection;

	return S_OK;
}


STDMETHODIMP CGraphCtl::get_XLabel(BSTR *pVal)
{
	ATLTRACE(_T("IGraph3D::get_XLabel\n"));
	*pVal = m_bstrXLabel.Copy();

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_XLabel(BSTR newVal)
{
	USES_CONVERSION;
	ATLTRACE(_T("IGraph3D::put_XLabel\n"));
	m_bstrXLabel = newVal;
	SetDirty(TRUE);
	FireViewChange(); 


	return S_OK;
}

STDMETHODIMP CGraphCtl::get_YLabel(BSTR *pVal)
{
	ATLTRACE(_T("IGraph3D::get_YLabel\n"));
	*pVal = m_bstrYLabel.Copy();

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_YLabel(BSTR newVal)
{
	USES_CONVERSION;
	ATLTRACE(_T("IGraph3D::put_YLabel\n"));
	m_bstrYLabel = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ZLabel(BSTR *pVal)
{
	ATLTRACE(_T("IGraph3D::get_ZLabel\n"));
	*pVal = m_bstrZLabel.Copy();

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ZLabel(BSTR newVal)
{
	USES_CONVERSION;
	ATLTRACE(_T("IGraph3D::put_ZLabel\n"));
	m_bstrZLabel = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_XGridNumber(short *pVal)
{
    *pVal = m_nGridX;
	return S_OK;
}

STDMETHODIMP CGraphCtl::put_XGridNumber(short newVal)
{
	newVal = newVal < 0 ? 1: newVal;
	newVal = newVal > 10 ? 10: newVal;

	m_nGridX = newVal;
	SetDirty(TRUE);

	FireViewChange(); // call the InvalidateRect API directly!

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_YGridNumber(short *pVal)
{
    *pVal = m_nGridY;
	return S_OK;
}

STDMETHODIMP CGraphCtl::put_YGridNumber(short newVal)
{
	newVal = newVal < 0 ? 1: newVal;
	newVal = newVal > 10 ? 10: newVal;

	m_nGridY = newVal;
	SetDirty(TRUE);

	FireViewChange(); // call the InvalidateRect API directly!

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ZGridNumber(short *pVal)
{
    *pVal = m_nGridZ;
	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ZGridNumber(short newVal)
{
	newVal = newVal < 0 ? 1: newVal;
	newVal = newVal > 10 ? 10: newVal;

	m_nGridZ = newVal;
	SetDirty(TRUE);

	FireViewChange(); // call the InvalidateRect API directly!

	return S_OK;
}


STDMETHODIMP CGraphCtl::get_XGridColor(OLE_COLOR *pVal)
{
	*pVal = m_clrXGridColor;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_XGridColor(OLE_COLOR newVal)
{
	m_clrXGridColor = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_YGridColor(OLE_COLOR *pVal)
{
	*pVal = m_clrYGridColor;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_YGridColor(OLE_COLOR newVal)
{
	m_clrYGridColor = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ZGridColor(OLE_COLOR *pVal)
{
	*pVal = m_clrZGridColor;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ZGridColor(OLE_COLOR newVal)
{
	m_clrZGridColor = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

void CGraphCtl::PlotElement()
{

	ELEMENTVECTOR::iterator theElement;

	for (theElement = m_ElementList.begin(); 
	     theElement != m_ElementList.end();
         theElement++)
	{
		 
		// Prevent plotting of non-existing data
		if (! theElement->bIsPlotAvailable )
		   continue;
		
		//////////////////////////////////
		// Check show state of the element
		if (! theElement->m_bShow )
			continue;

		if (theElement->m_bLights)
		{
          SetLight(theElement);
		  glEnable(GL_LIGHTING);  // Lighting will be used
		  glEnable(GL_LIGHT0);    // Only one (first) source of light
		  glEnable(GL_DEPTH_TEST);// The depth of the Z-buffer will be taken into account
		  glEnable(GL_COLOR_MATERIAL);// Material colors will be taken into account
		  
		}

		POINTVECTOR::iterator aPoint;
		
        // Draw Lines
		if (theElement->m_nType == Lines || theElement->m_nType == LinePoint)
		{
			glLineWidth(theElement->m_LineWidth);
			glBegin(GL_LINE_STRIP);

			SetColor(theElement->m_LineColor);

			aPoint = theElement->m_PointList.begin();
			for (aPoint; aPoint != theElement->m_PointList.end(); aPoint++)
			{
				if (PtInRange(aPoint))
				{
					CPoint3D pt = Corrdinate(aPoint);
					glVertex3f(pt.x,pt.y,pt.z);
				}
			}
			glEnd();
		 }

		 // Now draw points.
		 if ( theElement->m_nType == Points || theElement->m_nType == LinePoint )
         {
			glPointSize(theElement->m_PointSize);
			glBegin(GL_POINTS);
			SetColor(theElement->m_PointColor);

			aPoint = theElement->m_PointList.begin();
			for (aPoint; aPoint != theElement->m_PointList.end(); aPoint++)
			{
				if (PtInRange(aPoint))
				{
					CPoint3D pt = Corrdinate(aPoint);
					glVertex3f(pt.x,pt.y,pt.z);
				}
			}
			glEnd();
		 }
		 
		 if ( theElement->m_nType == Surface )
		 {
					
		    	// Set the polygon filling mode
				if (theElement->m_bFill)
					glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
				else
					glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
				
				if (theElement->m_bFlat)
					glShadeModel(GL_FLAT);
				else
					glShadeModel(GL_SMOOTH);

				// Turn on the primitive connection mode (not connected)
				glBegin (GL_QUADS);

				int i, npt = sqrt(theElement->m_PointList.size());
												
				aPoint = theElement->m_PointList.begin();
				for (aPoint, i=0; aPoint != theElement->m_PointList.end(); aPoint++,i++)
				{
					
					int j,k,n;
					if (PtInRange(&(theElement->m_PointList[i])))
					{
						// i, j, k, n � 4 indices of a quad
						// Counter Clockwise direction
                      
						    j = i + npt; // Other vertices indices
							k = j+1;
							n = i+1;
					
						// Get coordinates of 4 vertices
						CPoint3D 
							iPt = Corrdinate(&(theElement->m_PointList[i])),
							jPt = Corrdinate(&(theElement->m_PointList[j])),
							kPt = Corrdinate(&(theElement->m_PointList[k])),
							nPt = Corrdinate(&(theElement->m_PointList[n]));

						float
							// Quad side lines vectors coordinates
							ax = iPt.x-nPt.x,
							ay = iPt.y-nPt.y,

							by = jPt.y-iPt.y,
							bz = jPt.z-iPt.z,

							// Normal vector coordinates
							vx = ay*bz,
							vy = -bz*ax,
							vz = ax*by,

							// Normal vector length
							v  = float(sqrt(vx*vx + vy*vy + vz*vz));
						
						// Scale to unity
						vx /= v;
						vy /= v;
						vz /= v;

						// Set the normal vector
						glNormal3f (vx,vy,vz);

						glColor3f (0.2f, 0.8f, 1.f);
						if (PtInAxisBox(&iPt))
							glVertex3f (iPt.x, iPt.y, iPt.z);
						
						glColor3f (0.6f, 0.7f, 1.f);
						if (PtInAxisBox(&jPt))
							glVertex3f (jPt.x, jPt.y, jPt.z);
												
						glColor3f (0.7f, 0.9f, 1.f);
						if (PtInAxisBox(&kPt))
							glVertex3f (kPt.x, kPt.y, kPt.z);
						
						glColor3f (0.7f, 0.8f, 1.f);
						if (PtInAxisBox(&nPt))
							glVertex3f (nPt.x, nPt.y, nPt.z);

					}
				}
				glEnd();
		 }

		if(glIsEnabled(GL_LIGHTING))
       			glDisable(GL_LIGHTING);
	
	}
}
BOOL CGraphCtl::PtInRange(CPoint3D *pt)
{
	if (pt->x>=dRangeX[MIN] && pt->x<=dRangeX[MAX] &&
		pt->y>=dRangeY[MIN] && pt->y<=dRangeY[MAX] &&
		pt->z>=dRangeZ[MIN] && pt->z<=dRangeZ[MAX])
		return TRUE;
	return FALSE;
}

BOOL CGraphCtl::PtInAxisBox(CPoint3D* pt)
{
	float xF=dRangeX[MAX]-dRangeX[MIN];
	float yF=dRangeY[MAX]-dRangeY[MIN];
	float zF=dRangeZ[MAX]-dRangeZ[MIN];

	CPoint3D point;

	point.x = (pt->x+dRangeX[MIN])/xF + 0.5f;
	point.y = (pt->y+dRangeY[MIN])/yF + 0.5f;
	point.z = (pt->z+dRangeZ[MIN])/zF + 0.5f;
	
	return (PtInRange(&point));
}

void CGraphCtl::SetLight(CElement *pElement)
{
	//====== Both surface sides are considered when calculating
	//====== each pixel color with the lighting formula

	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,1);

	//====== Light source position depends on the object sizes scaled to (0,100)

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

	//====== Ambient light intensity
	float f = (pElement->m_LightParam[3])/100.f;
	float fAmbient[4] = { f, f, f, 0.f };
	glLightfv(GL_LIGHT0, GL_AMBIENT, fAmbient);

	//====== Diffuse light intensity
	f = (pElement->m_LightParam[4])/100.f;	
	float fDiffuse[4] = { f, f, f, 0.f };
	glLightfv(GL_LIGHT0, GL_DIFFUSE, fDiffuse);

	//====== Specular light intensity
	f = (pElement->m_LightParam[5])/100.f;
	float fSpecular[4] = { f, f, f, 0.f };
	glLightfv(GL_LIGHT0, GL_SPECULAR, fSpecular);

	//====== Surface material reflection properties for each light component
	f = (pElement->m_LightParam[6])/100.f;
	float fAmbMat[4] = { f, f, f, 0.f };
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, fAmbMat);

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

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

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

	//====== Material light emission property
	f = (pElement->m_LightParam[10])/100.f;
	float fEmission[4] = { f, f, f, 0.f };
	glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, fEmission);
}

CPoint3D CGraphCtl::Corrdinate(CPoint3D *point)
{
	float xF=dRangeX[MAX]-dRangeX[MIN];
	float yF=dRangeY[MAX]-dRangeY[MIN];
	float zF=dRangeZ[MAX]-dRangeZ[MIN];

	CPoint3D result;

	result.x = (point->x-dRangeX[MIN])/xF - 0.5f;
	result.y = (point->y-dRangeY[MIN])/yF - 0.5f;
	result.z = (point->z-dRangeZ[MIN])/zF - 0.5f;

	return result;
}

STDMETHODIMP CGraphCtl::AddElement()
{
	CElement Element ;
	m_ElementList.push_back(Element);
		
	SetDirty(TRUE);
	return S_OK;
}

STDMETHODIMP CGraphCtl::DeleteElement(short ElementID)
{
	if (m_ElementList.empty() || m_ElementList.size() < ElementID - 1)
		return Error (_T("Well I never ...!"));
    else
		m_ElementList.erase (m_ElementList.begin() + ElementID - 1);

	return S_OK;
}

STDMETHODIMP CGraphCtl::ClearGraph()
{
	if (m_ElementList.empty())
		return S_OK;
    else
		m_ElementList.clear ();

	bIsPlotAvailable = FALSE;

	return S_OK;
}

STDMETHODIMP CGraphCtl::PlotXYZ(double x, double y, double z, short ElementID)
{
	if (m_ElementList.empty())
		return Error(_T("You didn't say please first."));

	if(bIsPlotAvailable) 
	{
		if(x<dAutoRangeX[MIN])	dAutoRangeX[MIN]=floor(x);
		if(y<dAutoRangeY[MIN])	dAutoRangeY[MIN]=floor(y);
		if(z<dAutoRangeZ[MIN])	dAutoRangeZ[MIN]=floor(z);

		if(x>dAutoRangeX[MAX])	dAutoRangeX[MAX]=ceil(x);
		if(y>dAutoRangeY[MAX])  dAutoRangeY[MAX]=ceil(y);
		if(z>dAutoRangeZ[MAX])  dAutoRangeZ[MAX]=ceil(z);
		
	} else {

        dAutoRangeX[MIN] = floor(x);
        dAutoRangeY[MIN] = floor(y);
        dAutoRangeZ[MIN] = floor(z);

		dAutoRangeX[MAX] = ceil(x);
		dAutoRangeY[MAX] = ceil(y);
        dAutoRangeZ[MAX] = ceil(z);

		bIsPlotAvailable= TRUE ;
    }
	

	CPoint3D point(x,y,z);

	// Gets the position of the element by index.
   
	m_ElementList[ElementID].m_PointList.push_back(point);
	
	if(m_ElementList[ElementID].min.x > point.x)
			 m_ElementList[ElementID].min.x=point.x ;
    
	if(m_ElementList[ElementID].min.y > point.y)
			 m_ElementList[ElementID].min.y=point.y ;
    
	if(m_ElementList[ElementID].min.z > point.z)
			 m_ElementList[ElementID].min.z=point.z ;

    if(m_ElementList[ElementID].max.x < point.x)
			 m_ElementList[ElementID].max.x=point.x ;
	
	if(m_ElementList[ElementID].max.y < point.y)
			 m_ElementList[ElementID].max.y=point.y ;
    
	if(m_ElementList[ElementID].max.z < point.z)
			 m_ElementList[ElementID].max.z=point.z ;
	
	m_ElementList[ElementID].bIsPlotAvailable = TRUE ;

	FireViewChange(); // call the InvalidateRect API directly!

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementLineColor(short ElementID, OLE_COLOR *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));
	
	*pVal = m_ElementList[ElementID].m_LineColor;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementLineColor(short ElementID, OLE_COLOR newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LineColor = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementPointColor(short ElementID, OLE_COLOR *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_PointColor;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementPointColor(short ElementID, OLE_COLOR newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));

	m_ElementList[ElementID].m_PointColor = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementLineWidth(short ElementID, float *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_LineWidth;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementLineWidth(short ElementID, float newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LineWidth = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementPointSize(short ElementID, float *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_PointSize;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementPointSize(short ElementID, float newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));

	m_ElementList[ElementID].m_PointSize = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementType(short ElementID, short *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_nType;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementType(short ElementID, short newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_nType = (LineType)newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementShow(short ElementID, BOOL *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_bShow;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementShow(short ElementID, BOOL newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_bShow = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementSurfaceFill(short ElementID, BOOL *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_bFill;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementSurfaceFill(short ElementID, BOOL newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_bFill = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementSurfaceFlat(short ElementID, BOOL *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_bFlat;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementSurfaceFlat(short ElementID, BOOL newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_bFlat = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementLight(short ElementID, BOOL *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_bLights;

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementLight(short ElementID, BOOL newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_bLights = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementLightingAmbient(short ElementID, short *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_LightParam[3];

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementLightingAmbient(short ElementID, short newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LightParam[3] = newVal;
	SetDirty(TRUE);
	FireViewChange(); 


	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementLightingDiffuse(short ElementID, short *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_LightParam[4];

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementLightingDiffuse(short ElementID, short newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LightParam[4] = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementLightingSpecular(short ElementID, short *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_LightParam[5];

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementLightingSpecular(short ElementID, short newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LightParam[5] = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementMaterialAmbient(short ElementID, short *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_LightParam[6];

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementMaterialAmbient(short ElementID, short newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LightParam[7] = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementMaterialDiffuse(short ElementID, short *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_LightParam[7];

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementMaterialDiffuse(short ElementID, short newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LightParam[7] = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementMaterialSpecular(short ElementID, short *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_LightParam[8];

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementMaterialSpecular(short ElementID, short newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LightParam[8] = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementMaterialShinines(short ElementID, short *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_LightParam[9];

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementMaterialShinines(short ElementID, short newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LightParam[9] = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::get_ElementMaterialEmission(short ElementID, short *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_LightParam[10];

	return S_OK;
}

STDMETHODIMP CGraphCtl::put_ElementMaterialEmission(short ElementID, short newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LightParam[10] = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

STDMETHODIMP CGraphCtl::SetLightCoordinates(short ElementID, float x, float y, float z)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_LightParam[0] = x;
	m_ElementList[ElementID].m_LightParam[1] = y;
	m_ElementList[ElementID].m_LightParam[2] = z;

	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}



STDMETHODIMP CGraphCtl::get_Lighting(short ElementID, BOOL *pVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Yo ho ho and a bottle of rum for that!"));

	*pVal = m_ElementList[ElementID].m_bLights;
	return S_OK;
}

STDMETHODIMP CGraphCtl::put_Lighting(short ElementID, BOOL newVal)
{
	if (m_ElementList.empty() || m_ElementList.size() - 1 < ElementID)
	      return Error(_T("Your mother never allows you that!"));
	
	m_ElementList[ElementID].m_bLights = newVal;
	SetDirty(TRUE);
	FireViewChange(); 

	return S_OK;
}

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

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

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions