📄 copenglview.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
//
// COpenGLView.cpp : implementation of the COpenGLView class
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
//#include "resource.h" // main symbols
#include "COpenGLView.h"
#include <mmsystem.h> // for MM timers (you'll need WINMM.LIB)
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// add support for OpenGL 1.1 if we're using an old header
// These are new PIXELFORMATDESCRIPTOR flags for OpenGL 1.1
#ifndef PFD_GENERIC_ACCELERATED
#define PFD_GENERIC_ACCELERATED 0x00001000
#endif
#ifndef PFD_DEPTH_DONTCARE
#define PFD_DEPTH_DONTCARE 0x20000000
#endif
#define INSTALLABLE_DRIVER_TYPE_MASK (PFD_GENERIC_ACCELERATED|PFD_GENERIC_FORMAT)
/////////////////////////////////////////////////////////////////////////////
const char* const COpenGLView::_ErrorStrings[]= {
{"No Error"}, // 0
{"Unable to get a DC"}, // 1
{"ChoosePixelFormat failed"}, // 2
{"SelectPixelFormat failed"}, // 3
{"wglCreateContext failed"}, // 4
{"wglMakeCurrent failed"}, // 5
{"wglDeleteContext failed"}, // 6
{"SwapBuffers failed"}, // 7
};
/////////////////////////////////////////////////////////////////////////////
// COpenGLView
IMPLEMENT_DYNCREATE(COpenGLView, CView)
BEGIN_MESSAGE_MAP(COpenGLView, CView)
//{{AFX_MSG_MAP(COpenGLView)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_ERASEBKGND()
ON_WM_SIZE()
// If you don't have an ID_ANIMATE, you can either add one
// to your menu (Add an Animate command) or comment out the
// references
#if defined ID_ANIMATE
ON_COMMAND(ID_ANIMATE, OnAnimate)
ON_UPDATE_COMMAND_UI(ID_ANIMATE, OnUpdateAnimate)
#else
#pragma message( "No Animation Accelerator Interface Defined in COpenGLView" )
#endif
ON_WM_KEYDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COpenGLView construction/destruction
COpenGLView::COpenGLView()
: m_StockSceneListIndex(0), m_DefaultTextID(0),
m_DefaultFlatTextID(0),
m_SelectedStockScene( eStockSceneCheckerboard ),
m_bAnimationRunning(FALSE),
m_PixelFormat(0),m_hRC(0), m_pDC(0),
m_ErrorString(_ErrorStrings[0]),
m_deltaX(0), m_deltaY(0), m_deltaZ(0),
m_accelX(0), m_accelY(0), m_accelZ(0),
m_rotdeltaX(0), m_rotdeltaY(0), m_rotdeltaZ(0),
m_rotaccelX(0), m_rotaccelY(0), m_rotaccelZ(0),
m_rotX(0), m_rotY(0), m_rotZ(0),
m_X(0), m_Y(0), m_Z(0),
m_MaxVelocity(5.0), m_MaxRotation(90.0), // in units/sec
m_ElapsedTime( ~(DWORD)0 ), // initialize to a big number
m_eCurrentDriver(eGeneric) // driver for current pixel format
{
// TODO: add construction code here
}
/////////////////////////////////////////////////////////////////////////////
COpenGLView::~COpenGLView()
{
// clean up the extensions array
if ( m_ExtensionPtr )
{
m_ExtensionArray.RemoveAll();
delete[] m_ExtensionPtr;
}
}
/////////////////////////////////////////////////////////////////////////////
BOOL COpenGLView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code here and/or call the base class
// An OpenGL window must be created with the following flags and must not
// include CS_PARENTDC for the class style. Refer to SetPixelFormat
// documentation in the "Comments" section for further information.
cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
return CView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// COpenGLView drawing
void COpenGLView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if ( m_bAnimationRunning )
{
// Get the system time, in milliseconds.
// The system time is the time elapsed since Windows was started.
// NOTE: This value wraps about every 50 days, not that I worry
// about it.
// The accuracy depends upon the OS that you're running
// Win95 has accuracy to 1 ms, while WinNT will average about
// 5 ms or more (fine for our purposes). If you're running NT you can
// set the accuracy to a finer value. See the documentation.
// (However, this runs fine under NT as it is...)
m_ElapsedTime = ::timeGetTime(); // get current time
// Now invalidate the rect and post the message to repaint.
// Note that posting merely places the message in the queue.
// We HAVE to do this before we short circut the animation code
// since we'd never get called again if we didn't.
InvalidateRect( 0, FALSE );
GetParent()->PostMessage(WM_PAINT);
// this statement will limit the refresh rate of the
// window to 1000/30 frames/sec (about 33).
// Comment it out or modify it if you really want
// faster rates. See if you can tell the difference between a
// limited animation and an unlimited one. Resize the window
// and watch the rates change. With a tiny window you can easily get
// it over 150 frames/sec (with a simple scene).
if ( ElapsedTimeinMSSinceLastRender() < 30 )
return;
// Now do the time-based dynamic calculations for things like
// accelerations, velocity, rotations, etc...
CalculateDynamics();
}
// Clear out the color & depth buffers
::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
PreRenderScene();
::glPushMatrix();
RenderStockScene();
::glPopMatrix();
::glPushMatrix();
RenderScene();
::glPopMatrix();
// Tell OpenGL to flush its pipeline
::glFinish();
// Now Swap the buffers
if ( FALSE == ::SwapBuffers( m_pDC->GetSafeHdc() ) )
{
SetError(7);
}
PostRenderScene();
// the very last thing we do is to save
// the elapsed time, this is used with the
// next elapsed time to calculate the
// elapsed time since a render and the frame rate
m_previousElapsedTime = m_ElapsedTime;
}
//////////////////////////////////////////////////////////////////////////////
// PostRenderScene
// perform post display processing
//
// The default PostRenderScene places the framerate in the
// view's title. Replace this with your own title if you like.
void COpenGLView::PostRenderScene( void )
{
// Only update the title every 15 redraws (this is about
// every 1/2 second)
static int updateFrame = 15;
if ( !m_bAnimationRunning || 16 > ++updateFrame )
return;
updateFrame = 0;
char string[256];
_snprintf( string, 200, "%s ( %d Frames/sec )",
(const char*)m_WindowTitle, FramesPerSecond() );
GetParentFrame()->SetWindowText( string );
}
//////////////////////////////////////////////////////////////////////////////
// FramesPerSecond
// fetch frame rate calculations
int COpenGLView::FramesPerSecond( void )
{
double eTime = ElapsedTimeinMSSinceLastRender();
if ( 0 == (int)eTime )
return 0;
return (int)(1000/(int)eTime);
}
/////////////////////////////////////////////////////////////////////////////
// COpenGLView diagnostics
#ifdef _DEBUG
/////////////////////////////////////////////////////////////////////////////
void COpenGLView::AssertValid() const
{
CView::AssertValid();
}
/////////////////////////////////////////////////////////////////////////////
void COpenGLView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
CDocument* COpenGLView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDocument)));
return (CDocument*)m_pDocument;
}
/////////////////////////////////////////////////////////////////////////////
int COpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
GetParentFrame()->GetWindowText( m_WindowTitle );
// get rid of that " - Untitled" stuff
GetParentFrame()->ModifyStyle(FWS_ADDTOTITLE,0);
InitializeOpenGL();
// Now we initialize the animation code
m_StartTime = ::timeGetTime(); // get time in ms
// need a previous time if we start off animated
if ( m_bAnimationRunning )
{
m_previousElapsedTime = m_StartTime;
}
m_HomeX = m_X; // initialize dynamic starting values
m_HomeY = m_Y;
m_HomeZ = m_Z;
m_HomerotX = m_rotX;
m_HomerotY = m_rotY;
m_HomerotZ = m_rotZ;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
void COpenGLView::OnDestroy()
{
CView::OnDestroy();
// TODO: Add your message handler code here
// NOTE:wglDeleteContext makes the RC non-current, so this step is unnecessary
// (but you can do it if it makes you feel secure)
// if ( FALSE == ::wglMakeCurrent( 0, 0 ) )
// {
// SetError(2);
// return FALSE;
// }
if ( FALSE == ::wglDeleteContext( m_hRC ) )
{
SetError(6);
}
// For Color-Index mode, you should reset the palette to the original here
if ( m_pDC )
{
delete m_pDC;
}
}
/////////////////////////////////////////////////////////////////////////////
// OnEraseBkgnd
// OpenGL has its own routine to erase the background. Here we tell MFC
// not to do it, that we'll take care of it. If we didn't the scene might
// flash.
BOOL COpenGLView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
// return CView::OnEraseBkgnd(pDC);
return TRUE; // tell Windows not to erase the background
}
/////////////////////////////////////////////////////////////////////////////
// OnSize
// We need to set up the viewport when the size changes, and this is the best
// place for it, as long as you don't need to render more than one scene, in which
// case you'd have to do it just before each scene gets rendered.
// We also set up the viewing volumn here since we're using perspective mode. For
// Orthographic you could do it anywhere since you don't need the aspect ratio.
// Finally we also set up the default veiwing transform. For an animated scene you'd
// have to do it just before the scene was rendered.
void COpenGLView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
GLdouble aspect_ratio; // width/height ratio
if ( 0 >= cx || 0 >= cy )
{
return;
}
SetupViewport( cx, cy );
// compute the aspect ratio
// this will keep all dimension scales equal
aspect_ratio = (GLdouble)cx/(GLdouble)cy;
// select the projection matrix and clear it
::glMatrixMode(GL_PROJECTION);
::glLoadIdentity();
// select the viewing volumn
SetupViewingFrustum( aspect_ratio );
// switch back to the modelview matrix and clear it
::glMatrixMode(GL_MODELVIEW);
::glLoadIdentity();
// now perform any viewing transformations
SetupViewingTransform();
}
//////////////////////////////////////////////////////////////////////////////
// SetError-error string manipulation
/////////////////////////////////////////////////////////////////////////////
void COpenGLView::SetError( int e )
{
// if there was no previous error,
// then save this one
if ( _ErrorStrings[0] == m_ErrorString )
{
m_ErrorString = _ErrorStrings[e];
}
}
//////////////////////////////////////////////////////////////////////////////
// InitializeOpenGL
// - just that. This is set up for RGB mode, though I've indicated
// where you would add code for color-index mode.
BOOL COpenGLView::InitializeOpenGL()
{
// Can we put this in the constructor?
m_pDC = new CClientDC(this);
if ( NULL == m_pDC ) // failure to get DC
{
SetError(1);
return FALSE;
}
if (!SetupPixelFormat())
{
return FALSE;
}
// For Color-Index mode, you'd probably create your palette here, right
// after you select the pixel format
if ( 0 == (m_hRC = ::wglCreateContext( m_pDC->GetSafeHdc() ) ) )
{
SetError(4);
return FALSE;
}
if ( FALSE == ::wglMakeCurrent( m_pDC->GetSafeHdc(), m_hRC ) )
{
SetError(5);
return FALSE;
}
// get the extended information about the currently running
// OpenGL implementation
FetchExtendedInformation();
// select our default display fonts
// (this may take a while....)
SetDefaultFonts();
// specify black as clear color
::glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// specify the back of the buffer as clear depth
::glClearDepth(1.0f);
// enable depth testing
::glEnable(GL_DEPTH_TEST);
// Save the initial positions and rotations
m_HomeX = m_X;
m_HomeY = m_Y;
m_HomeZ = m_Y;
m_HomerotX = m_rotX;
m_HomerotY = m_rotY;
m_HomerotZ = m_rotY;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
BOOL COpenGLView::SetupPixelFormat()
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -