📄 copenglview.cpp
字号:
// if ticks < 0 and delta is larger than 1, place the ticks
// on each scales unit length
if ( 0 > ticks )
{
float delta = finish-start;
ticks = delta > 1.0 ? (int)delta : 0;
}
// draw the tickmarked axes
Draw3DAxesLine( start, finish, 0, ticks );
Draw3DAxesLine( start, finish, 1, ticks );
Draw3DAxesLine( start, finish, 2, ticks );
}
/////////////////////////////////////////////////////////////////////////////
// Draw3DAxesLine
// This routine draws a colored line along a specified axis.
// axis_id = 0 for the x, 1 for the y, and anything else for the z
// start and finish are the starting and ending location, start < finish.
// ticks is the number of ticks to place along the axis.
// If you are using lighting/materials, you might want to wrapper this routine
// so that it's called with lighting disabled, or else the axis lines will be effected
// by lighting claculations - which generally means hard to see.
void COpenGLView::Draw3DAxesLine( float start, float finish, int axis_id, int ticks )
{
float *px, *py, *pz, zero = 0.0f;
float tickx, ticky, tickz;
float *pdx, *pdy, *pdz, tinytick, delta = (finish-start)/(ticks<1?1:ticks);
GLfloat negativeColor[3] = { 1.0f, 0.0f, 0.0f };
GLfloat positiveColor[3] = { 0.0f, 1.0f, 0.0f };
pdx = pdy = pdz = px = py = pz = &zero;
tickx = ticky = tickz = 0.0f;
tinytick = 0.05f;
// select which of the 3 axes is going to vary
if ( 0 == axis_id ) // X axis
{
pdx = δ
ticky = tinytick;
px = &start;
}
else if ( 1 == axis_id ) // Y axis
{
pdy = δ
tickx = tinytick;
py = &start;
}
else // default Z axis
{
pdz = δ
ticky = tinytick;
pz = &start;
}
// turn off the lighting effects
// since we don't want the axes lines effected by the
// lighting. You might need to call ::glDisable(GL_LIGHTING)
// before this routine
::glBegin(GL_LINES);
// now draw the two lines that make up the axis
::glColor3fv( negativeColor ); // negative color
::glVertex3f( *px, *py, *pz );
::glVertex3f( 0.0f, 0.0f, 0.0f );
::glColor3fv( positiveColor ); // positive color
::glVertex3f( 0.0f, 0.0f, 0.0f );
::glVertex3f( *px+*pdx*ticks, *py+*pdy*ticks, *pz+*pdz*ticks );
// now draw the tick marks
int i;
for ( i = 0; i < ticks ; i++ )
{
if ( i < ticks/2 )
{
::glColor3fv( negativeColor );
}
else
{
::glColor3fv( positiveColor );
}
::glVertex3f( *px-tickx, *py-ticky, *pz-tickz );
::glVertex3f( *px+tickx, *py+ticky, *pz+tickz );
*px += *pdx;
*py += *pdy;
*pz += *pdz;
}
::glEnd();
// don't forget to turn lighting effects back on
// via glEnable(GL_LIGHTING)
}
/////////////////////////////////////////////////////////////////////////////
// COpenGLView Text-Specific routines follow
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// GenerateDefaultFonts
// Generate the default 3D and flat text disp;ay lists
void COpenGLView::GenerateDefaultFonts( char* font3D, char* fontFlat )
{
m_DefaultTextID = GenerateDisplayListForFont( font3D );
m_DefaultFlatTextID = GenerateBitmapListForFont( fontFlat );
}
/////////////////////////////////////////////////////////////////////////////
// GLTextOut
// Output text (either Bitmap or Outline)
void COpenGLView::GLTextOut( GLuint id, const char * const textstring )
{
if ( 0 == id || 0 == textstring )
{
return;
}
GLsizei size = strlen( textstring );
::glListBase( id );
::glCallLists( size, GL_UNSIGNED_BYTE, (const GLvoid*)textstring );
}
/////////////////////////////////////////////////////////////////////////////
// GenerateDisplayListForFont
// The routines used for generating 3D text.
GLuint COpenGLView::GenerateDisplayListForFont( char* fontname, double xt )
{
GLuint id;
if ( 0 == m_pDC ||
0 == fontname ||
(GLuint)0 == (id = GetNewDisplayListIDs(256)) )
{
return 0;
}
LOGFONT logfont;
GLYPHMETRICSFLOAT gmf[256];
// lfHeight can't be used to change the font size
logfont.lfHeight = -12; // use glScale to change size
logfont.lfWidth = 0;
logfont.lfEscapement = 0;
logfont.lfOrientation = logfont.lfEscapement;
logfont.lfWeight = FW_NORMAL;
logfont.lfItalic = FALSE;
logfont.lfUnderline = FALSE;
logfont.lfStrikeOut = FALSE;
logfont.lfCharSet = ANSI_CHARSET;
logfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfQuality = DEFAULT_QUALITY;
logfont.lfPitchAndFamily = FF_DONTCARE|DEFAULT_PITCH;
lstrcpy ( logfont.lfFaceName, fontname );
CFont newfont;
// returns 0 if it fails
BOOL success = newfont.CreateFontIndirect( &logfont );
CFont* oldfont = m_pDC->SelectObject( &newfont );
ASSERT( 0 != oldfont );
// Create a set of display lists based on the glyphs of the TrueType font
// notice that we really waste the first 32 spaces....
// if there's a problem delete the display lists
// Note that this single call takes MOST of the initialization time
// for the COpenGLView class (probably a couple of seconds!) so if you don't
// want/need 3D text, you might comment this functionality out.
if ( 0 == success ||
FALSE == ::wglUseFontOutlines( m_pDC->m_hDC, 0, 256, id, 0.0f,
(float)xt, WGL_FONT_POLYGONS, gmf) )
{
::glDeleteLists( id, 256 );
id = 0;
}
else
{
m_pDC->SelectObject( oldfont );
}
return id;
}
/////////////////////////////////////////////////////////////////////////////
// GenerateBitmapListForFont
// The routines used for generating flat text
GLuint COpenGLView::GenerateBitmapListForFont( char* fontname )
{
GLuint id;
if ( 0 == m_pDC ||
(GLuint)0 == (id = GetNewDisplayListIDs(256)) )
{
return 0;
}
CFont newfont;
CFont* oldfont;
BOOL success;
if ( NULL != fontname )
{
LOGFONT logfont;
logfont.lfHeight = -12;
logfont.lfWidth = 0;
logfont.lfEscapement = 0;
logfont.lfOrientation = logfont.lfEscapement;
logfont.lfWeight = FW_NORMAL;
logfont.lfItalic = FALSE;
logfont.lfUnderline = FALSE;
logfont.lfStrikeOut = FALSE;
logfont.lfCharSet = ANSI_CHARSET;
logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfQuality = DEFAULT_QUALITY;
logfont.lfPitchAndFamily = FF_DONTCARE|DEFAULT_PITCH;
lstrcpy ( logfont.lfFaceName, fontname );
// returns 0 if it fails
success = newfont.CreateFontIndirect( &logfont );
oldfont = m_pDC->SelectObject( &newfont );
ASSERT( 0 != oldfont );
}
else
{
// make the system font the device context's selected font
oldfont = (CFont*)m_pDC->SelectStockObject( SYSTEM_FONT );
ASSERT( 0 != oldfont );
}
// Create a set of display lists based on the glyphs of the font
// notice that we really waste the first 32 spaces....
// if there's a problem delete the display lists
if ( 0 == success ||
FALSE == ::wglUseFontBitmaps( m_pDC->m_hDC, 0, 256, id ) )
{
::glDeleteLists( id, 256 );
id = 0;
}
else
{
m_pDC->SelectObject( oldfont );
}
return id;
}
/////////////////////////////////////////////////////////////////////////////
// Animation routines
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void COpenGLView::OnAnimate()
{
// TODO: Add your command handler code here
ToggleAnimationFlag();
if ( m_bAnimationRunning )
{
InvalidateRect( 0, FALSE );
UpdateWindow();
}
else
{
// turn off animation message
GetParentFrame()->SetWindowText( (const char*)m_WindowTitle );
}
}
/////////////////////////////////////////////////////////////////////////////
void COpenGLView::OnUpdateAnimate(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->SetCheck( m_bAnimationRunning );
}
/////////////////////////////////////////////////////////////////////////////
// CalculateDynamics
// This routine uses simple velocity-based values to change the viewpoint.
// Thus there is no acceleration component, just a velocity component.
// Most people can't get used to an acceleration-based control as it's
// too difficult to get used to. This setup is much more predictable.
//
// The values used for velocity, rotation, and acceleration are
// all in units per second. This allows you to pick reasonable,
// intuitive values.
void COpenGLView::CalculateDynamics()
{
ASSERT( AnimationRunning() );
double eTime = (double)ElapsedTimeinMSSinceLastRender()/1000.0;
// Limit translational acceleration values
if ( m_deltaZ > m_MaxVelocity )
m_deltaZ = m_MaxVelocity;
if ( m_deltaX > m_MaxVelocity )
m_deltaX = m_MaxVelocity;
if ( m_deltaY > m_MaxVelocity )
m_deltaY = m_MaxVelocity;
if ( -m_deltaZ > m_MaxVelocity )
m_deltaZ = -m_MaxVelocity;
if ( -m_deltaX > m_MaxVelocity )
m_deltaX = -m_MaxVelocity;
if ( -m_deltaY > m_MaxVelocity )
m_deltaY = -m_MaxVelocity;
// Limit rotational acceleration values
if ( m_rotdeltaZ > m_MaxRotation )
m_rotdeltaZ = m_MaxRotation;
if ( m_rotdeltaX > m_MaxRotation )
m_rotdeltaX = m_MaxRotation;
if ( m_rotdeltaY > m_MaxRotation )
m_rotdeltaY = m_MaxRotation;
if ( -m_rotdeltaZ > m_MaxRotation )
m_rotdeltaZ = -m_MaxRotation;
if ( -m_rotdeltaX > m_MaxRotation )
m_rotdeltaX = -m_MaxRotation;
if ( -m_rotdeltaY > m_MaxRotation )
m_rotdeltaY = -m_MaxRotation;
// This is where the actual values for rotation and
// acceleration change. Note that I'm really ignoring the acceleration
// values. Most people simply find changing velocity by
// tweaking the acceleration values too hard to understand, so I
// take the easy way out and hook up the user controls to the velocity
// instead. If you're building a space simulation, then you might want to
// redo these equations.
// (Actually, when I said I'm ingoring the acceleration values,
// I really meant that I was using the acceleration variables in place
// of the velocity variables in these equations. I do this so that if you
// wanted to correctly use acceleration to tweak velocity (via the UI)
// and then velocity to tweak position, only these equations would change.
m_X += m_accelX * eTime;
m_Y += m_accelY * eTime;
m_Z += m_accelZ * eTime;
m_rotX += m_rotaccelX * eTime;
m_rotY += m_rotaccelY * eTime;
m_rotZ += m_rotaccelZ * eTime;
}
/////////////////////////////////////////////////////////////////////////////
// ViewpointOriginRotation
// This viewpoint spins about the origin and accepts
// changes in rotation rates and distance from the origin.
// The distance to the origin can be varied
BOOL COpenGLView::ViewpointOriginRotation()
{
::glLoadIdentity();
// Move away from the origin
::glTranslatef( 0.0f, 0.0f, (GLfloat)m_Z );
// Rotate about the origin
::glRotatef( (GLfloat)m_rotX, 1.0f, 0.0f, 0.0f );
::glRotatef( (GLfloat)m_rotY, 0.0f, 1.0f, 0.0f );
::glRotatef( (GLfloat)m_rotZ, 0.0f, 0.0f, 1.0f );
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// OnKeyDown
// This routine runs the keyboard interface.
// Most of the keys accepted are from the numeric keypad
// HOME: Resets viewpoint to initial values (animation keeps going)
// SHIFT-HOME: reset viewpoint & clear movement vectors
// 5: Clear movement vectors
// Up/Down Arrows: change velocity in Z (if shifted, change rotation)
// Left/Right Arrows: change velocity in X (if shifted, change rotation)
// Plus/Minus: change velocity in Y (if shifted, change rotation)
// ESC: Exit animation
void COpenGLView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
BOOL ctrl = 0x8000 & GetKeyState( VK_CONTROL );
BOOL shift= 0x8000 & GetKeyState( VK_SHIFT );
if ( AnimationRunning() )
{
switch ( nChar )
{
case VK_HOME: // reset position to viewpoint's origin
m_X = m_HomeX;
m_Y = m_HomeY;
m_Z = m_HomeZ;
m_rotX = m_HomerotX;
m_rotY = m_HomerotY;
m_rotZ = m_HomerotZ;
if ( !shift ) // drop through if shifted
return;
// i.e shift home resets viewpoint AND movement
case VK_CLEAR: // numeric 5 keypad key
// kill velocity & acceleration & rotation
m_deltaX = m_deltaY = m_deltaZ = 0.0f;
m_accelX = m_accelY = m_accelZ = 0.0f;
m_rotdeltaX = m_rotdeltaY = m_rotdeltaZ = 0.0f;
m_rotaccelX = m_rotaccelY = m_rotaccelZ = 0.0f;
return;
case VK_UP: // up arrow
shift ?
IncreaseRotation( m_rotaccelZ ):
IncreaseVelocity(m_accelZ);
return;
case VK_DOWN: // down arrow
shift ?
DecreaseRotation( m_rotaccelZ ):
DecreaseVelocity(m_accelZ);
return;
case VK_LEFT: // left arrow
shift ?
IncreaseRotation( m_rotaccelX ):
IncreaseVelocity(m_accelX);
return;
case VK_RIGHT: // right arrow
shift ?
DecreaseRotation( m_rotaccelX ):
DecreaseVelocity(m_accelX);
return;
case VK_SUBTRACT: // minus
shift ?
IncreaseRotation( m_rotaccelY ):
IncreaseVelocity( m_accelY );
return;
case VK_ADD: // plus
shift ?
DecreaseRotation( m_rotaccelY ):
DecreaseVelocity( m_accelY );
return;
}
// end if animated
}
switch ( nChar )
{
case VK_ESCAPE: // close down the app
GetParent()->PostMessage(WM_CLOSE);
return;
default:
return;
}
// Probably don't ever need this
//CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -