Click here to Skip to main content
15,881,715 members
Articles / Multimedia / OpenGL

CGLEnabledView - An MDI view class supporting OpenGL

Rate me:
Please Sign up or sign in to vote.
4.77/5 (26 votes)
30 Nov 19992 min read 228.1K   9.5K   55  
A plug-in view class that provides OpenGL support
/*****************************************************
Copyright Notice & Disclaimer

Copyright �1998-1999 Alessandro Falappa

Permission to use, copy, modify, and distribute this software
and its documentation for any purpose is hereby granted without
fee, provided that the above copyright notice, author statement
appear in all copies of this software and related documentation.

If you make enhancement or you find (and possibly fix) bugs,
please let me know

THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF
ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT
LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A
PARTICULAR PURPOSE.

IN NO EVENT SHALL ALESSANDRO FALAPPA BE LIABLE FOR ANY
SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE,
AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

///////////////////////////////////////////////
History

v 1.0: first version
v 1.1: added CGLDispList helper class
	   changed previous disp list service in StockDispList
v 1.2: added CGLTesselator helper class
	   added GLCommands pair
	   added CGLQuadric wrapper class
v 1.3: changed window initialization with creation of a windowclass (this solved little NT bug)
	   added GLU library information retrieval
	   introduced GL/GLU Information Structure
v 1.4: introduced GL/GLU error checking in OnDraw message handler after scene drawing
	   improved GL/GLU library information retrieval and modified GL/GLU Information Structure accordingly (added implementation dependent values retrieval)
	   added 2D bitmap text and 3D polygonal text routines

******************************************************/
// CGLEnabledView.cpp : implementation file
//

#include "stdafx.h"
/*******************
 NOTE ABOUT LIBRARIES INCLUSION:
 - Remember to include the appropriate libraries in the link phase
   (look at Project Settings under the Link tab)
 - If you were lucky enough to get SGI's implementation (at present it's
   not availabl nor supported) you can play with it also, just include
   that libraries. SGI's version is faster if you have no GL acceleration
   and if you own a MMX processor
 - These includes below can be moved to stdafx.h to speed up compilation
********************/
/* MS openGL libraries (link with OPENGL32.LIB and GLU32.LIB)
#include "gl\gl.h"	// moved to stdafx.h
#include "gl\glu.h"
//*/
/* SGI openGL libraries (link with OPENGL.LIB and GLU.LIB)
#include "[path-of-SGI-sdk]\include\gl\gl.h"
#include "[path-of-SGI-sdk]\include\gl\glu.h"
//*/

#include "GLEnabledView.h"

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

#define MAX_LISTS 20
// used to identify a MCD video driver (partial OGL acceleration)
#define ICD_DRIVER_MASK  (PFD_GENERIC_ACCELERATED | PFD_GENERIC_FORMAT)

/////////////////////////////////////////////////////////////////////////////
// Global Functions/variables
// These functions are used by CGLTesselator class

struct GarbListItem{
	GLdouble *pvert;
	GarbListItem* next;};

GarbListItem* m_garbagelist=NULL;

void AddGarbage(GLdouble * ptr)
{
	ASSERT(ptr!=NULL);
// allocate mem for new list item
	GarbListItem* temp=new GarbListItem;
// store pointer
	temp->pvert=ptr;
// add at head of list
	temp->next=m_garbagelist;
	m_garbagelist=temp;
}

void DeleteGarbage()
{
	if(m_garbagelist!=NULL)
	{
		GarbListItem* punt=m_garbagelist;
		GarbListItem* temp=m_garbagelist;
// scan the list
		while(punt!=NULL)
		{
// delete vertex
			delete[] punt->pvert;
			punt=punt->next;
// delete list item
			delete temp;
			temp=punt;
		};
		m_garbagelist=NULL;
	};
}

void CALLBACK BeginCallback(GLenum type)
{
// issue corresponding GL call
	glBegin(type);
}

void CALLBACK ErrorCallback(GLenum errorCode)
{
	const GLubyte *estring;
	CString mexstr;
// get the error descritption from OGL
	estring = gluErrorString(errorCode);
// prepare and show a message box
	mexstr.Format("Tessellation/Quadric Error: %s\n", estring);
	AfxMessageBox(mexstr,MB_OK | MB_ICONEXCLAMATION);
// replicate mex to debug trace
	TRACE0(mexstr);
}

void CALLBACK EndCallback()
{
// issue corresponding GL call
	glEnd();
}

void CALLBACK VertexCallback(GLvoid *vertex)
{
// issue corresponding GL call (double is used to get max precision)
	glVertex3dv( (const double *)vertex );
}

void CALLBACK CombineCallback(GLdouble coords[3], GLdouble *data[4], GLfloat weight[4], GLdouble **dataOut )
{
// allocate memory for a new vertex
	GLdouble *vertex;
	vertex = new GLdouble[3];
// store reported vertex
	vertex[0] = coords[0];
	vertex[1] = coords[1];
	vertex[2] = coords[2];
// return vertex to OGL
	*dataOut = vertex;
// add vertex pointer to garbage collection routines
	AddGarbage(vertex);
}

/////////////////////////////////////////////////////////////////////////////
// CGLEnabledView

IMPLEMENT_DYNCREATE(CGLEnabledView, CView)

CGLEnabledView::CGLEnabledView():
	m_dAspectRatio(1.0),
	m_numchars(128),
	m_bInsideDispList(FALSE), m_bExternDispListCall(FALSE),
	m_bExternGLCall(FALSE),
	m_gmfvector(NULL),
	m_charsetDListBase(0)
{
// define a default cursor
	m_hMouseCursor=AfxGetApp()->LoadStandardCursor(IDC_SIZEALL);
// set the disp list vector to all zeros
	for (int c=0;c<MAX_LISTS;c++) m_DispListVector[c]=0;
}

CGLEnabledView::~CGLEnabledView()
{
	if(m_gmfvector!=NULL) delete[] m_gmfvector;
}


BEGIN_MESSAGE_MAP(CGLEnabledView, CView)
	//{{AFX_MSG_MAP(CGLEnabledView)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_ERASEBKGND()
	ON_WM_SIZE()
	ON_WM_SETCURSOR()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CGLEnabledView drawing

void CGLEnabledView::OnDraw(CDC* pDC)
{
// prepare a semaphore
	static BOOL 	bBusy = FALSE;
// use the semaphore to enter this critic section
	if(bBusy) return;
	bBusy = TRUE;

// specify the target DeviceContext of the subsequent OGL calls
	wglMakeCurrent(m_pCDC->GetSafeHdc(), m_hRC);

// clear background
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// call the virtual drawing procedure (to be overridden by user)
	OnDrawGL();

// execute OGL commands (flush the OGL graphical pipeline)
//	glFinish(); // useless cause swapbuffers issues an implicit glFinish

// if double buffering is used it's time to swap the buffers
	SwapBuffers(m_pCDC->GetSafeHdc());

// check for errors
	m_glErrorCode=glGetError();
	if(m_glErrorCode != GL_NO_ERROR)
	{
		const GLubyte *estring;
		CString mexstr;
// get the error descritption from OGL
		estring = gluErrorString(m_glErrorCode);
// prepare and show a message box
		mexstr.Format("GLEnabledView:\n\tAn OpenGL error occurred: %s\n", estring);
		AfxMessageBox(mexstr,MB_OK | MB_ICONEXCLAMATION);
// replicate mex to debug trace
		TRACE0(mexstr);
// turn the semaphore "red" to avoid other wrong drawings
		bBusy=TRUE;
	}
	else
	{
// turn the semaphore "green"
		bBusy = FALSE;
	}

// free the target DeviceContext (window)
    wglMakeCurrent(NULL,NULL);
}

void CGLEnabledView::OnDrawGL()
{
// draw carthesian axes
	glBegin(GL_LINES);
		// red x axis
		glColor3f(1.f,0.f,0.f);
		glVertex3f(0.0f,0.0f,0.0f);
		glVertex3f(1.0f,0.0f,0.0f);
		glVertex3f(1.0f,0.0f,0.0f);
		glVertex3f(0.9f,0.1f,0.0f);
		glVertex3f(1.0f,0.0f,0.0f);
		glVertex3f(0.9f,-0.1f,0.0f);
		// green y axis
		glColor3f(0.f,1.f,0.f);
		glVertex3f(0.0f,0.0f,0.0f);
		glVertex3f(0.0f,1.0f,0.0f);
		glVertex3f(0.0f,1.0f,0.0f);
		glVertex3f(0.1f,0.9f,0.0f);
		glVertex3f(0.0f,1.0f,0.0f);
		glVertex3f(-0.1f,0.9f,0.0f);
		// blue z axis
		glColor3f(0.f,0.f,1.f);
		glVertex3f(0.0f,0.0f,0.0f);
		glVertex3f(0.0f,0.0f,1.0f);
		glVertex3f(0.0f,0.0f,1.0f);
		glVertex3f(0.0f,0.1f,0.9f);
		glVertex3f(0.0f,0.0f,1.0f);
		glVertex3f(0.0f,-0.1f,0.9f);
	glEnd();
}

/////////////////////////////////////////////////////////////////////////////
// CGLEnabledView diagnostics

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

void CGLEnabledView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
// dump some infos
	CString str;
	GetWindowText(str);
	afxDump<<"\nView Parameters\n\tClient Rectangle :"<<m_ClientRect<<"\n\tAspect Ratio :"<<m_dAspectRatio<<"\n";
	afxDump<<"\nWindowTitle :"<<str<<"\n";
}
#endif //_DEBUG

/////////////////////////////////////////////////////////
// CGLEnabledView Constants

// these are used to construct an equilibrated 256 color palette
static unsigned char _threeto8[8] = 
{
	0, 0111>>1, 0222>>1, 0333>>1, 0444>>1, 0555>>1, 0666>>1, 0377
};

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

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

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

// Windows Default Palette
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 }
};

/////////////////////////////////////////////////////////////////////////////
// CGLEnabledView initialization and palette helpers

BOOL CGLEnabledView::bSetupPixelFormat()
{
// define a default desired video mode (pixel format)
	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
        16,                             // 16-bit z-buffer
        0,                              // no stencil buffer
        0,                              // no auxiliary buffer
        PFD_MAIN_PLANE,                 // main layer
        0,                              // reserved
        0, 0, 0                         // layer masks ignored
    };
// let the user change some parameters if he wants
	BOOL bDoublBuf;
	ColorsNumber cnum;
	ZAccuracy zdepth;
	VideoMode(cnum,zdepth,bDoublBuf);
//set the user changes
	if(bDoublBuf) pfd.dwFlags=PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |PFD_DOUBLEBUFFER;
	else pfd.dwFlags=PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
	switch(cnum)
	{
	case INDEXED:
		pfd.cColorBits=8;
		pfd.iPixelType=PFD_TYPE_COLORINDEX;
		break;
	case THOUSANDS:
		pfd.cColorBits=16;
		break;
	case MILLIONS_WITH_TRANSPARENCY:
		pfd.cColorBits=32;
		break;
	case MILLIONS:
	default:
		pfd.cColorBits=24;
		break;
	};
	switch(zdepth)
	{
	case NORMAL:
		pfd.cDepthBits=16;
		break;
	case ACCURATE:
		pfd.cDepthBits=32;
		break;
	};

// ask the system for such video mode
    ASSERT(m_pCDC != NULL);
    int pixelformat;
	if ( (pixelformat = ChoosePixelFormat(m_pCDC->GetSafeHdc(), &pfd)) == 0 )
    {
        AfxMessageBox("ChoosePixelFormat failed");
        return FALSE;
    }
// try to set this video mode    
	if (SetPixelFormat(m_pCDC->GetSafeHdc(), pixelformat, &pfd) == FALSE)
    {
// the requested video mode is not available so get a default one (the first)
        pixelformat = 1;	
		if (DescribePixelFormat(m_pCDC->GetSafeHdc(), pixelformat, sizeof(PIXELFORMATDESCRIPTOR), &pfd)==0)
		{
// neither the requested nor the default are available: fail
			AfxMessageBox("SetPixelFormat failed (no OpenGL compatible video mode)");
			return FALSE;
		}
    }
    return TRUE;
}

void CGLEnabledView::CreateRGBPalette()
{
    PIXELFORMATDESCRIPTOR pfd;
    LOGPALETTE *pPal;
    int n, i;

// get the initially choosen video mode
	n = ::GetPixelFormat(m_pCDC->GetSafeHdc());
    ::DescribePixelFormat(m_pCDC->GetSafeHdc(), n, sizeof(pfd), &pfd);

// if is an indexed one...
    if (pfd.dwFlags & PFD_NEED_PALETTE)
    {
// ... construct an equilibrated palette (3 red bits, 3 green bits, 2 blue bits)
// NOTE: this code has been taken from MFC example Cube
		n = 1 << pfd.cColorBits;
        pPal = (PLOGPALETTE) new char[sizeof(LOGPALETTE) + n * sizeof(PALETTEENTRY)];

        ASSERT(pPal != NULL);

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

// fix up the palette to include the default Windows 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++)
                pPal->palPalEntry[defaultOverride[i]] = defaultPalEntry[i];
        }

        m_CurrentPalette.CreatePalette(pPal);
        delete pPal;

// set the palette
        m_pOldPalette=m_pCDC->SelectPalette(&m_CurrentPalette, FALSE);
        m_pCDC->RealizePalette();
    }
}

unsigned char CGLEnabledView::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;
    }
}

/////////////////////////////////////////////////////////////////////////////
// CGLEnabledView message handlers and overridables

int CGLEnabledView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CView::OnCreate(lpCreateStruct) == -1) return -1;
	
// OpenGL rendering context creation
	PIXELFORMATDESCRIPTOR pfd;
    int         n;

// initialize the private member
	m_pCDC= new CClientDC(this);

// choose the requested video mode
    if (!bSetupPixelFormat()) return 0;
	
// ask the system if the video mode is supported
    n=::GetPixelFormat(m_pCDC->GetSafeHdc());
    ::DescribePixelFormat(m_pCDC->GetSafeHdc(),n,sizeof(pfd),&pfd);

// create a palette if the requested video mode has 256 colors (indexed mode)
    CreateRGBPalette();

// link the Win Device Context with the OGL Rendering Context
    m_hRC = wglCreateContext(m_pCDC->GetSafeHdc());

// specify the target DeviceContext (window) of the subsequent OGL calls
    wglMakeCurrent(m_pCDC->GetSafeHdc(), m_hRC);

// performs default setting of rendering mode,etc..
	OnCreateGL();

// free the target DeviceContext (window)
    wglMakeCurrent(NULL,NULL);
	
	return 0;
}

void CGLEnabledView::OnCreateGL()
{
// perform hidden line/surface removal (enabling Z-Buffer)
	glEnable(GL_DEPTH_TEST);

// set background color to black
	glClearColor(0.f,0.f,0.f,1.0f );

// set clear Z-Buffer value
	glClearDepth(1.0f);
}

void CGLEnabledView::OnDestroy() 
{
// specify the target DeviceContext (window) of the subsequent OGL calls
    wglMakeCurrent(m_pCDC->GetSafeHdc(), m_hRC);

// remove all display lists
	for (int c=0;c<MAX_LISTS;c++) if(m_DispListVector[c]) glDeleteLists(m_DispListVector[c],1);

// release definitely OGL Rendering Context
	if (m_hRC!=NULL) ::wglDeleteContext(m_hRC);

// Select our palette out of the dc
	CPalette palDefault;
	palDefault.CreateStockObject(DEFAULT_PALETTE);
	m_pCDC->SelectPalette(&palDefault, FALSE);

// destroy Win Device Context
	if(m_pCDC) delete m_pCDC;

// finally call the base function
	CView::OnDestroy();	
}

BOOL CGLEnabledView::PreCreateWindow(CREATESTRUCT& cs) 
{
// these styles are requested by OpenGL
   cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS);          
 
// call base class PreCreateWindow to get the cs.lpszClass filled in with the MFC default class name
   if( !CView::PreCreateWindow(cs) )
     return 0;

// Register the window class if it has not already been registered.
   WNDCLASS wndcls;
   HINSTANCE hInst = AfxGetInstanceHandle();
// this is the new registered window class
#define CUSTOM_CLASSNAME _T("GL_WINDOW_CLASS")
// check if our class has been already registered (typical in MDI environment)
   if(!(::GetClassInfo(hInst, CUSTOM_CLASSNAME, &wndcls)))
   {
// get default MFC class settings
		if(::GetClassInfo(hInst, cs.lpszClass, &wndcls))
		{
// set our class name
			wndcls.lpszClassName = CUSTOM_CLASSNAME;
// these styles are set for GL to work in MDI
			wndcls.style |= (CS_OWNDC | CS_HREDRAW | CS_VREDRAW);
			wndcls.hbrBackground = NULL;
// try to register class (else throw exception)
			if (!AfxRegisterClass(&wndcls)) AfxThrowResourceException();
		}
// default MFC class not registered
		else AfxThrowResourceException();
	}
// set our class name in CREATESTRUCT
    cs.lpszClass = CUSTOM_CLASSNAME;
// we're all set
    return 1;
}


BOOL CGLEnabledView::OnEraseBkgnd(CDC* pDC) 
{
// OGL has his own background erasing so tell Windows to skip (avoids flicker)
	return TRUE;
}

void CGLEnabledView::OnSize(UINT nType, int cx, int cy) 
{
	CView::OnSize(nType, cx, cy);
// when called with a nonzero window:
	if ( 0 < cx && 0 < cy )
	{
// update the rect and the aspect ratio
		m_ClientRect.right = cx;
		m_ClientRect.bottom = cy;
		m_dAspectRatio=double(cx)/double(cy);

// specify the target DeviceContext of the OGL calls below
		wglMakeCurrent(m_pCDC->GetSafeHdc(), m_hRC);

// call the virtual sizing procedure (to be overridden by user)
		OnSizeGL(cx,cy);

// free the target DeviceContext (window)
		wglMakeCurrent(NULL,NULL);

// force redraw
		Invalidate(TRUE);
	};
}

void CGLEnabledView::OnSizeGL(int cx, int cy)
{
// set correspondence between window and OGL viewport
		glViewport(0,0,cx,cy);

// update the camera
 		glPushMatrix();
			glMatrixMode(GL_PROJECTION);
				glLoadIdentity();
				gluPerspective(40.0,m_dAspectRatio,0.1f, 10.0f);
				glTranslatef(0.0f,0.0f,-4.f);
			glMatrixMode(GL_MODELVIEW);
		glPopMatrix();
}

BOOL CGLEnabledView::OnSetCursor(CWnd* /*pWnd*/, UINT /*nHitTest*/, UINT /*message*/) 
{
	ASSERT(m_hMouseCursor!=NULL);
	::SetCursor(m_hMouseCursor);
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CGLEnabledView public members

void CGLEnabledView::VideoMode(ColorsNumber &c, ZAccuracy &z, BOOL &dbuf)
{
// set default videomode
	c=MILLIONS;
	z=NORMAL;
	dbuf=TRUE;
}

void CGLEnabledView::SetMouseCursor(HCURSOR mcursor)
{
// set the specified cursor (only if it is a valid one)
	if(mcursor!=NULL) m_hMouseCursor=mcursor;
}

GLInfoStruct CGLEnabledView::GetInformation()
{
	PIXELFORMATDESCRIPTOR pfd;
	GLInfoStruct str;
	HDC curr_dc=m_pCDC->GetSafeHdc();
// Get information about the DC's current pixel format 
	::DescribePixelFormat(curr_dc , ::GetPixelFormat(curr_dc),sizeof(PIXELFORMATDESCRIPTOR), &pfd ); 
// specify the target Rendering Context of the subsequent OGL calls
	wglMakeCurrent(curr_dc, m_hRC);
// Extract driver information
	if( 0==(ICD_DRIVER_MASK & pfd.dwFlags) )
		str.acceleration="Fully Accelerated (ICD)"; // fully in hardware (fastest)
		else if (ICD_DRIVER_MASK==(ICD_DRIVER_MASK & pfd.dwFlags) )
			str.acceleration="Partially Accelerated (MCD)"; // partially in hardware (pretty fast, maybe..)
			else str.acceleration="Not Accelerated (Software)";	// software
// get the company name responsible for this implementation
	str.vendor=(char*)::glGetString(GL_VENDOR);
	if ( ::glGetError()!=GL_NO_ERROR) str.vendor.Format("Not Available");// failed!
// get the renderer name; this is specific of an hardware configuration
	str.renderer=(char*)::glGetString(GL_RENDERER);
	if ( ::glGetError()!=GL_NO_ERROR) str.renderer.Format("Not Available");// failed!
// get the version of the GL library
	str.glversion=(char*)::glGetString(GL_VERSION);
	if ( ::glGetError()!=GL_NO_ERROR) str.glversion.Format("Not Available");// failed!
// return a space separated list of extensions
	str.glextensions=(char*)::glGetString(GL_EXTENSIONS);
	if ( ::glGetError()!=GL_NO_ERROR) str.glextensions.Format("Not Available");// failed!
// get the version of the GLU library
	str.gluversion=(char*)::gluGetString(GLU_VERSION);
	if ( ::glGetError()!=GL_NO_ERROR) str.gluversion.Format("Not Available");// failed!
// as above a space separated list of extensions
	str.gluextensions=(char*)::gluGetString(GLU_EXTENSIONS);
	if ( ::glGetError()!=GL_NO_ERROR) str.gluextensions.Format("Not Available");// failed!
	glGetIntegerv(GL_MAX_LIGHTS,&str.max_lights);
	glGetIntegerv(GL_MAX_CLIP_PLANES,&str.max_clip_planes);
	glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH,&str.max_model_stack_depth);
	glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH,&str.max_proj_stack_depth);
	glGetIntegerv(GL_MAX_TEXTURE_STACK_DEPTH,&str.max_txtr_stack_depth);
	glGetIntegerv(GL_MAX_NAME_STACK_DEPTH,&str.max_name_stack_depth);
	glGetIntegerv(GL_MAX_ATTRIB_STACK_DEPTH,&str.max_attrib_stack_depth);
	glGetIntegerv(GL_MAX_TEXTURE_SIZE,&str.max_texture_size);
	glGetIntegerv(GL_MAX_LIST_NESTING,&str.max_list_nesting);
	glGetIntegerv(GL_MAX_EVAL_ORDER,&str.max_eval_order);
	int tempint[2];
	glGetIntegerv(GL_MAX_VIEWPORT_DIMS,&tempint[0]);
	str.max_viewport_dims.cx=tempint[0];
	str.max_viewport_dims.cy=tempint[1];
	glGetIntegerv(GL_AUX_BUFFERS,&str.auxiliary_buffers);
	float tempval[2];
	glGetFloatv(GL_POINT_SIZE_RANGE,&tempval[0]);
	str.min_smooth_point_size=int(tempval[0]);
	str.max_smooth_point_size=int(tempval[1]);
	glGetFloatv(GL_POINT_SIZE_GRANULARITY,&str.smooth_point_granularity);
	glGetFloatv(GL_LINE_WIDTH_RANGE,&tempval[0]);
	str.min_smooth_line_size=int(tempval[0]);
	str.max_smooth_line_size=int(tempval[1]);
	glGetFloatv(GL_LINE_WIDTH_GRANULARITY,&str.smooth_line_granularity);
	glGetIntegerv(GL_RED_BITS,&str.red_bits);
	glGetIntegerv(GL_BLUE_BITS,&str.blue_bits);
	glGetIntegerv(GL_GREEN_BITS,&str.green_bits);
	glGetIntegerv(GL_ALPHA_BITS,&str.alpha_bits);
	glGetIntegerv(GL_DEPTH_BITS,&str.depth_bits);
	glGetIntegerv(GL_STENCIL_BITS,&str.stencil_bits);
// free the target DeviceContext (window) and return the result
	wglMakeCurrent(NULL,NULL);
	return str;
}

void CGLEnabledView::DrawStockDispLists()
{
// check if we are already inside a drawing session
	if(m_hRC==wglGetCurrentContext() && m_pCDC->GetSafeHdc()==wglGetCurrentDC() )
	{
// draw directly all display lists
		for (int c=0;c<MAX_LISTS;c++) if(m_DispListVector[c]) glCallList(m_DispListVector[c]);
	}
	else
	{
// specify the target DeviceContext of the subsequent OGL calls
		wglMakeCurrent(m_pCDC->GetSafeHdc(), m_hRC);
// draw all display lists
		for (int c=0;c<MAX_LISTS;c++) if(m_DispListVector[c]) glCallList(m_DispListVector[c]);
// free the target DeviceContext (window)
		wglMakeCurrent(NULL,NULL);
	};
}

void CGLEnabledView::StartStockDListDef()
{
// check if we aren't inside another couple begin/end
	if(!m_bInsideDispList)
	{
// search a free slot
		for (int c=0;m_DispListVector[c]!=0;c++);
// check if we are inside a drawing session or not....
		if(!( m_hRC==wglGetCurrentContext() && m_pCDC->GetSafeHdc()==wglGetCurrentDC() ))
		{
// ...if not specify the target DeviceContext of the subsequent OGL calls
			wglMakeCurrent(m_pCDC->GetSafeHdc(), m_hRC);
// set a warning for EndDispList
			m_bExternDispListCall=TRUE;
		};
// create a handle to the disp list (actually an integer)
		m_DispListVector[c]=glGenLists(1);
// set a semaphore
		m_bInsideDispList=TRUE;
// start the disp list: all subsequent OGL calls will be redirected to the list
		glNewList(m_DispListVector[c],GL_COMPILE);
	};
}

void CGLEnabledView::EndStockListDef()
{
// close the disp list
	glEndList();
// unset the semaphore
	m_bInsideDispList=FALSE;
// if beginDispList set the warn free the target DeviceContext
	if(m_bExternDispListCall) wglMakeCurrent(NULL,NULL);
}

void CGLEnabledView::ClearStockDispLists()
{
// check if we are referring to the right Rendering Context
	if(m_hRC==wglGetCurrentContext() && m_pCDC->GetSafeHdc()==wglGetCurrentDC() )
	{
// delete active display lists
		for (int c=0;c<MAX_LISTS;c++) if(m_DispListVector[c]) glDeleteLists(m_DispListVector[c],1);
	}
	else
	{
// specify the target Rendering Context of the subsequent OGL calls
		wglMakeCurrent(m_pCDC->GetSafeHdc(), m_hRC);
// delete active display lists
		for (int c=0;c<MAX_LISTS;c++) if(m_DispListVector[c]) glDeleteLists(m_DispListVector[c],1);
// free the target Rendering Context (window)
		wglMakeCurrent(NULL,NULL);
	};
}

void CGLEnabledView::BeginGLCommands()
{
// check if we are inside a drawing session or not....
	if(!( m_hRC==wglGetCurrentContext() && m_pCDC->GetSafeHdc()==wglGetCurrentDC() ))
	{
// ...if not specify the target DeviceContext of the subsequent OGL calls
		wglMakeCurrent(m_pCDC->GetSafeHdc(), m_hRC);
// set a warning for EndGLCommands
		m_bExternGLCall=TRUE;
	};
}

void CGLEnabledView::EndGLCommands()
{
// if BeginGLCommands set the warn free the target DeviceContext
	if(m_bExternGLCall) wglMakeCurrent(NULL,NULL);
}

void CGLEnabledView::PrepareCharset3D(CString fontname,float extrusion,BOOL boldface,BOOL italicface,BOOL uselines,float precision)
{
	// debug checks
	ASSERT(extrusion>=0.f && precision>=0.f);
	ASSERT(!fontname.IsEmpty());
	// variables initialization
	int mode=uselines ? WGL_FONT_LINES : WGL_FONT_POLYGONS;
	if(m_gmfvector==NULL) m_gmfvector=new GLYPHMETRICSFLOAT[m_numchars];
	// prepare to ask for the requested font
	LOGFONT lg;
	memset(&lg, 0, sizeof(LOGFONT));
	lg.lfHeight=14;// for 3D text the height doesn't matter since the characters will be always of unit height
	lg.lfWidth=0;
	lg.lfEscapement=lg.lfOrientation=0;
	lg.lfItalic=unsigned char(italicface);
	if(boldface)lg.lfWeight=FW_BOLD;
	else lg.lfWeight=FW_NORMAL;
	lg.lfUnderline=FALSE;
	lg.lfStrikeOut=FALSE;
	lg.lfCharSet=ANSI_CHARSET;
	lg.lfOutPrecision=OUT_DEFAULT_PRECIS;
	lg.lfClipPrecision=CLIP_DEFAULT_PRECIS; 
	lg.lfQuality=DEFAULT_QUALITY;
	lg.lfPitchAndFamily=DEFAULT_PITCH |FF_DONTCARE;
	strcpy(lg.lfFaceName, fontname);        
	// ask for the font
	CFont fnt;
	if(!fnt.CreateFontIndirect(&lg))
	{
		TRACE("CGLEnabledView::PrepareCharset3D:\n\tUnable to create the requested font.\n");
		m_charsetDListBase=0;
		return;
	};
	//select the font into the DC
	CFont* def_font = m_pCDC->SelectObject(&fnt);
	// create or recreate the display lists
	if(m_charsetDListBase>0)
		glDeleteLists(m_charsetDListBase,m_numchars);	
	if (0 == (m_charsetDListBase=glGenLists(m_numchars)))
	{
		TRACE("CGLEnabledView::PrepareCharset3D:\n\tUnable to create the charset (no memory for display lists).\n");
		goto end;
	};
	// build the charset display lists
	if(!wglUseFontOutlines(m_pCDC->GetSafeHdc(),0,m_numchars-1,m_charsetDListBase,precision,extrusion,mode,m_gmfvector))
	{
		TRACE("CGLEnabledView::PrepareCharset3D:\n\tUnable to create the charset (internal error).\n");
		glDeleteLists(m_charsetDListBase,m_numchars);
		m_charsetDListBase=0;
	};
	// deselect and dispose of the GDI font
end:
	m_pCDC->SelectObject(def_font);
	fnt.DeleteObject();
}

void CGLEnabledView::PrepareCharset3D(const LOGFONT* pLF,float extrusion,BOOL uselines,float precision)
{
	// debug checks
	ASSERT(extrusion>=0.f && precision>=0.f);
	ASSERT(pLF!=NULL);
	// variables initialization
	int mode=uselines ? WGL_FONT_LINES : WGL_FONT_POLYGONS;
	if(m_gmfvector==NULL) m_gmfvector=new GLYPHMETRICSFLOAT[m_numchars];
	// ask for the font
	CFont fnt;
	if(!fnt.CreateFontIndirect(pLF))
	{
		TRACE("CGLEnabledView::PrepareCharset3D:\n\tUnable to create a font from the passed logical font descriptor.\n");
		return;
	}
	//select the font into the DC
	CFont* def_font = m_pCDC->SelectObject(&fnt);
	// create or recreate the display lists
	if(m_charsetDListBase>0) glDeleteLists(m_charsetDListBase,m_numchars);	
	if (0 == (m_charsetDListBase=glGenLists(m_numchars)))
	{
		TRACE("CGLEnabledView::PrepareCharset3D:\n\tUnable to create the charset (no memory for display lists).\n");
		goto end;
	};
	// build the charset display lists
	if(!wglUseFontOutlines(m_pCDC->GetSafeHdc(),0,m_numchars-1,m_charsetDListBase,precision,extrusion,mode,m_gmfvector))
	{
		TRACE("CGLEnabledView::PrepareCharset3D:\n\tUnable to create the charset (internal error).\n");
		glDeleteLists(m_charsetDListBase,m_numchars);
		m_charsetDListBase=0;
	};
	// deselect and dispose of the GDI font
end:
	m_pCDC->SelectObject(def_font);
	fnt.DeleteObject();
}

void CGLEnabledView::PrepareCharset2D(CString fontname,int height,BOOL boldface,BOOL italicface)
{
	// debug checks
	ASSERT(!fontname.IsEmpty() && height>0);
	// prepare to ask for the requested font
	LOGFONT lg;
	memset(&lg, 0, sizeof(LOGFONT));
	lg.lfHeight=height;// for 2D text the height is taken into consideration
	lg.lfWidth=0;
	lg.lfEscapement=lg.lfOrientation=0;
	lg.lfItalic=unsigned char(italicface);
	if(boldface)lg.lfWeight=FW_BOLD;
	else lg.lfWeight=FW_NORMAL;
	lg.lfUnderline=FALSE;
	lg.lfStrikeOut=FALSE;
	lg.lfCharSet=ANSI_CHARSET;
	lg.lfOutPrecision=OUT_DEFAULT_PRECIS;
	lg.lfClipPrecision=CLIP_DEFAULT_PRECIS; 
	lg.lfQuality=DEFAULT_QUALITY;
	lg.lfPitchAndFamily=DEFAULT_PITCH |FF_DONTCARE;
	strcpy(lg.lfFaceName, fontname);        
	// ask for the font
	CFont fnt;
	if(!fnt.CreateFontIndirect(&lg))
	{
		TRACE("CGLEnabledView::PrepareCharset2D:\n\tUnable to create the requested font.\n");
		m_charsetDListBase=0;
		return;
	};
	//select the font into the DC
	CFont* def_font = m_pCDC->SelectObject(&fnt);
	// create or recreate the display lists
	if(m_charsetDListBase>0)
		glDeleteLists(m_charsetDListBase,m_numchars);	
	if (0 == (m_charsetDListBase=glGenLists(m_numchars)))
	{
		TRACE("CGLEnabledView::PrepareCharset2D:\n\tUnable to create the charset (no memory for display lists).\n");
		goto end;
	};
	// build the charset display lists
	if(!wglUseFontBitmaps(m_pCDC->GetSafeHdc(),0,m_numchars-1,m_charsetDListBase))
	{
		TRACE("CGLEnabledView::PrepareCharset2D:\n\tUnable to create the charset (internal error).\n");
		glDeleteLists(m_charsetDListBase,m_numchars);
		m_charsetDListBase=0;
	};
	// deselect and dispose of the GDI font
end:
	m_pCDC->SelectObject(def_font);
	fnt.DeleteObject();
}

void CGLEnabledView::PrepareCharset2D(const LOGFONT* pLF)
{
	// debug checks
	ASSERT(pLF!=NULL);
	// ask for the font
	CFont fnt;
	if(!fnt.CreateFontIndirect(pLF))
	{
		TRACE("CGLEnabledView::PrepareCharset2D:\n\tUnable to create a font from the passed logical font descriptor.\n");
		return;
	}
	//select the font into the DC
	CFont* def_font = m_pCDC->SelectObject(&fnt);
	// create or recreate the display lists
	if(m_charsetDListBase>0) glDeleteLists(m_charsetDListBase,m_numchars);	
	if (0 == (m_charsetDListBase=glGenLists(m_numchars)))
	{
		TRACE("CGLEnabledView::PrepareCharset2D:\n\tUnable to create the charset (no memory for display lists).\n");
		goto end;
	};
	// build the charset display lists
	if(!wglUseFontBitmaps(m_pCDC->GetSafeHdc(),0,m_numchars-1,m_charsetDListBase))
	{
		TRACE("CGLEnabledView::PrepareCharset2D:\n\tUnable to create the charset (internal error).\n");
		glDeleteLists(m_charsetDListBase,m_numchars);
		m_charsetDListBase=0;
	};
	// deselect and dispose of the GDI font
end:
	m_pCDC->SelectObject(def_font);
	fnt.DeleteObject();
}

float CGLEnabledView::Text3D(CString text)
{
	float retlen=0.f;
	int textlen=0;
	if(m_charsetDListBase!=0)
	{
		if( (textlen=text.GetLength()) >0)
		{
			// output the outlines corresponding to the requested text srting
			glListBase(m_charsetDListBase);
			glCallLists(textlen,GL_UNSIGNED_BYTE,LPCTSTR(text));
			// calculate and return the length of the produced outlines
			for(int c=0;c<textlen;c++)
				retlen+=m_gmfvector[char(text[c])].gmfCellIncX;
		}
	}
	else TRACE("CGLEnabledView::Text3D:\n\tNo charset available. Use PrepareCharset3D routines first.\n");
	return retlen;
}

void CGLEnabledView::Text2D(CString text)
{
	int textlen=0;
	if(m_charsetDListBase!=0)
	{
		if( (textlen=text.GetLength()) >0)
		{
			// output the outlines corresponding to the requested text srting
			glListBase(m_charsetDListBase);
			glCallLists(textlen,GL_UNSIGNED_BYTE,LPCTSTR(text));
		}
	}
	else TRACE("CGLEnabledView::Text2D:\n\tNo charset available. Use PrepareCharset2D routines first.\n");
}

//////////////////////////////////////////////////////////////////////
//
// Implementation of CGLEnabledView::CGLDispList class.
//
/*** DESCRIPTION

  This is actually a helper class which wraps the
  use of display list in OGL.
  It must be used inside an GLEnabledView cause
  a display list must refer to a Rendering Context.
  At present there is no support for Disp. Lists
  Sharing among multiple RCs (that is multiple MDI
  child windows).

****************************************/

//////////////////////////////////////////////////////////////////////
// Construction/Destruction

CGLEnabledView::CGLDispList::CGLDispList():
	m_glListId(0), m_bIsolated(FALSE)
{
}

CGLEnabledView::CGLDispList::~CGLDispList()
{
// remove display list
	glDeleteLists(m_glListId,1); 
}

//////////////////////////////////////////////////////////////////////
// Member functions

void CGLEnabledView::CGLDispList::Draw()
{
// if the list is not empty...
	if(m_glListId)
	{
		if(m_bIsolated)
		{
// save current transformation matrix
			glPushMatrix();
// save current OGL internal state (lighting, shading, and such)
			glPushAttrib(GL_ALL_ATTRIB_BITS);
		};
// draw the list
		glCallList(m_glListId);
		if(m_bIsolated)
		{
// restore transformation matrix
			glPopMatrix();
// restore OGL internal state
			glPopAttrib();
		};
	};
}

void CGLEnabledView::CGLDispList::StartDef(BOOL bImmediateExec)
{
// check if another list is under construction
	int cur;
	glGetIntegerv(GL_LIST_INDEX,&cur);
	if(cur != 0)
	{
		TRACE0("CGLEnabledView\n\tError: Nested display list definition!\n");
		ASSERT(FALSE);
	};
// if the list is empty firstly allocate one
	if(!m_glListId) m_glListId=glGenLists(1);

// start or replace a list definition
	if (bImmediateExec) glNewList(m_glListId,GL_COMPILE_AND_EXECUTE);
	else  glNewList(m_glListId,GL_COMPILE);
}

void CGLEnabledView::CGLDispList::EndDef()
{
// check the coupling with a preceding call to StartDef()
	int cur;
	glGetIntegerv(GL_LIST_INDEX,&cur);
	if(cur != m_glListId) {TRACE0("CGLDispList:Missing StartDef() before EndDef()\n");return;};
// close list definition
	glEndList();
}

//////////////////////////////////////////////////////////////////////
//
// Implementation of CGLEnabledView::CGLTesselator class.
//
/*** DESCRIPTION

  This is actually a helper class which wraps the
  use of tessellation objects in OGL (see guide).
  It must be used inside an GLEnabledView cause
  a tesselator object must refer to a Rendering Context.

****************************************/

//////////////////////////////////////////////////////////////////////
// Construction/Destruction

CGLEnabledView::CGLTesselator::CGLTesselator()
{
// create tessellation object
	m_tessObj=gluNewTess();
// set callback functions
	gluTessCallback(m_tessObj,GLU_TESS_BEGIN,(void (CALLBACK*)())&BeginCallback); 
	gluTessCallback(m_tessObj,GLU_TESS_VERTEX,(void (CALLBACK*)())&VertexCallback); 
	gluTessCallback(m_tessObj,GLU_TESS_END,(void (CALLBACK*)())&EndCallback);
	gluTessCallback(m_tessObj,GLU_TESS_COMBINE,(void (CALLBACK*)())&CombineCallback);
	gluTessCallback(m_tessObj,GLU_TESS_ERROR,(void (CALLBACK*)())&ErrorCallback);
}

CGLEnabledView::CGLTesselator::~CGLTesselator()
{
// remove tessellation object
	gluDeleteTess(m_tessObj);	
}

//////////////////////////////////////////////////////////////////////
// Member functions

void CGLEnabledView::CGLTesselator::SetWindingRule(GLdouble which)
{
// issue the equivalent GL call
	gluTessProperty(m_tessObj,GLU_TESS_WINDING_RULE,which); 
}

GLdouble CGLEnabledView::CGLTesselator::GetWindingRule()
{
//retrieve attribute
	GLdouble temp=-1.0;
	gluTessProperty(m_tessObj,GLU_TESS_WINDING_RULE,temp);
// return value
	return temp;
}

void CGLEnabledView::CGLTesselator::SetFilling(BOOL bFill)
{
// issue the equivalent GL calls
	if(bFill) gluTessProperty(m_tessObj,GLU_TESS_BOUNDARY_ONLY,GL_FALSE);
	else gluTessProperty(m_tessObj,GLU_TESS_BOUNDARY_ONLY,GL_TRUE);
}

BOOL CGLEnabledView::CGLTesselator::GetFilling()
{
//retrieve attribute
	GLdouble temp=-1.0;
	gluTessProperty(m_tessObj,GLU_TESS_BOUNDARY_ONLY,temp);
// convert to a boolean
	return (temp==GL_TRUE);
}

void CGLEnabledView::CGLTesselator::StartDef()
{
// start a polygon definition
	gluTessBeginPolygon(m_tessObj,NULL);
// start a contour definition
	gluTessBeginContour(m_tessObj);
}

void CGLEnabledView::CGLTesselator::EndDef()
{
// end contour and polygon definition
	gluTessEndContour(m_tessObj);
	gluTessEndPolygon(m_tessObj);
// free new vertices created by tessellation
	::DeleteGarbage();
}

void CGLEnabledView::CGLTesselator::ContourSeparator()
{
// insert a contour separation
	gluTessEndContour(m_tessObj);
	gluTessBeginContour(m_tessObj);
}

void CGLEnabledView::CGLTesselator::AddVertex(GLdouble vertData[3])
{
// IMPORTANT: the 3rd parameter must be given otherwise an access
// violation will occur, moreover every vertex must have it's own memory
// location till the closing of the polygon (that is you can't pass all
// the vertices trough the same variable in a for loop).
	gluTessVertex(m_tessObj,vertData,vertData); 
}

void CGLEnabledView::CGLTesselator::AddVertexArray(GLdouble arr[][3], int size)
{
	ASSERT(arr!=NULL);
// pass the vertices to the tessellation object
	for(int ct=0;ct<size;ct++) gluTessVertex(m_tessObj,arr[ct],arr[ct]);
}

//////////////////////////////////////////////////////////////////////
//
// Implementation of CGLEnabledView::CGLQuadric class.
//
/*** DESCRIPTION

  This is actually a helper class which wraps the
  use of quadric objects in OGL (see guide).
  It must be used inside an GLEnabledView cause
  a quadric object must refer to a Rendering Context.

****************************************/

//////////////////////////////////////////////////////////////////////
// Construction/Destruction

CGLEnabledView::CGLQuadric::CGLQuadric(GLenum drwStyle,GLenum normals,GLenum side,BOOL bGenerateTxtrCoords)
{
// check validity of parameters
	ASSERT(normals==GLU_NONE || normals==GLU_FLAT || normals==GLU_SMOOTH);
	ASSERT(drwStyle==GLU_FILL || drwStyle==GLU_LINE || drwStyle==GLU_SILHOUETTE|| drwStyle==GLU_POINT);
	ASSERT(side==GLU_INSIDE || side==GLU_OUTSIDE);
// create quadric object
	m_quadrObj=gluNewQuadric();
// set error callback function (shared with tesselators)
	gluQuadricCallback(m_quadrObj,GLU_ERROR,(void (CALLBACK*)())&ErrorCallback);
// set normal generation
	gluQuadricNormals(m_quadrObj,normals);
// set Texture Coordinates generation
	if(bGenerateTxtrCoords) gluQuadricTexture(m_quadrObj,GL_TRUE);
	else gluQuadricTexture(m_quadrObj,GL_FALSE);
// set how the qadric will be generated
	gluQuadricDrawStyle(m_quadrObj,drwStyle);
// set which side of the quadric is to be considered inside
	gluQuadricOrientation(m_quadrObj,side);
}

CGLEnabledView::CGLQuadric::~CGLQuadric()
{
// remove quadric object
	gluDeleteQuadric(m_quadrObj);	
}

//////////////////////////////////////////////////////////////////////
// Member functions

void CGLEnabledView::CGLQuadric::SetNormals(GLenum type)
{
// check validity of type parameter it must be one of these:
	ASSERT(type==GLU_NONE || type==GLU_FLAT || type==GLU_SMOOTH);
// issue corresponding GL command
	gluQuadricNormals(m_quadrObj,type);
}

void CGLEnabledView::CGLQuadric::SetTextureCoordsGen(BOOL flag)
{
// issue corresponding GL commands
	if(flag) gluQuadricTexture(m_quadrObj,GL_TRUE);
	else gluQuadricTexture(m_quadrObj,GL_FALSE);
}

void CGLEnabledView::CGLQuadric::SetOrientation(GLenum type)
{
// check validity of type parameter it must be one of these:
	ASSERT(type==GLU_INSIDE || type==GLU_OUTSIDE);
// issue corresponding GL command
	gluQuadricOrientation(m_quadrObj,type);
}

void CGLEnabledView::CGLQuadric::SetDrawStyle(GLenum style)
{
// check validity of type parameter it must be one of these:
	ASSERT(style==GLU_FILL || style==GLU_LINE || style==GLU_SILHOUETTE|| style==GLU_POINT);
// issue corresponding GL command
	gluQuadricDrawStyle(m_quadrObj,style);
}

void CGLEnabledView::CGLQuadric::DrawSphere(GLdouble radius, int longitudeSubdiv, int latitudeSubdiv)
{
// issue corresponding GL command
	gluSphere(m_quadrObj,radius,longitudeSubdiv,latitudeSubdiv);
}

void CGLEnabledView::CGLQuadric::DrawCylinder(GLdouble baseRadius,GLdouble topRadius,GLdouble height,int slices,int stacks)
{
// issue corresponding GL command
	gluCylinder(m_quadrObj,baseRadius,topRadius,height,slices,stacks);
}

void CGLEnabledView::CGLQuadric::DrawDisk(GLdouble innerRadius,GLdouble outerRadius,int slices,int loops)
{
// issue corresponding GL command
	gluDisk(m_quadrObj,innerRadius,outerRadius,slices,loops);
}

void CGLEnabledView::CGLQuadric::DrawPartialDisk(GLdouble innerRadius,GLdouble outerRadius,int slices,int loops,GLdouble startAngle,GLdouble sweepAngle)
{
// issue corresponding GL command
	gluPartialDisk(m_quadrObj,innerRadius,outerRadius,slices,loops,startAngle,sweepAngle);
}

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


Written By
Software Developer (Senior)
Italy Italy
Male.
Living in Rome, Italy
Computer addict since 12 years old (first computer: Commodore 64).
Master degree in Computer Science.
Very interested in computer generated graphics both real time (mainly OpenGL) and photorealistic rendering.

Comments and Discussions