Statistics
| Revision:

root / PyOpenGL-Demo / NeHe / lesson44 / glCamera.py @ 1

 1 2 3 1 equemene # // Code writen by: Vic Hollis 09/07/2003  1 equemene # // I don't mind if you use this class in your own code. All I ask is  1 equemene # // that you give me credit for it if you do. And plug NeHe while your  1 equemene # // at it! :P Thanks go to David Steere, Cameron Tidwell, Bert Sammons,  1 equemene # // and Brannon Martindale for helping me test all the code! Enjoy.  1 equemene # //////////////////////////////////////////////////////////////////////  1 equemene # // glCamera.h: interface for the glCamera class.  1 equemene # //////////////////////////////////////////////////////////////////////  1 equemene #  1 equemene # //////////////////////////////////////////////////////////////////////  1 equemene # // Some minimal additions by rIO.Spinning Kids  1 equemene # // For testing flares against occluding objects.  1 equemene # // Not using proprietary extensions, this is PURE OpenGL1.1  1 equemene # //  1 equemene # // Just call the IsOccluded function, passing it the glPoint to check  1 equemene # //  1 equemene # //////////////////////////////////////////////////////////////////////  1 equemene #  1 equemene # Ported to Python, PyOpenGL by Brian Leair 2004.  1 equemene # The numarray python module can perform matrix math more effieciently  1 equemene # than direct python code. However, for this tutorial the differnce  1 equemene # in performance isn't huge and it makes for a better tutorial to see  1 equemene # the math operations directly.  1 equemene 1 equemene from OpenGL.GL import *  1 equemene from OpenGL.GLU import *  1 equemene from OpenGL.GLUT import *  1 equemene from glPoint import *  1 equemene from glVector import *  1 equemene from math import sqrt, fabs  1 equemene 1 equemene try:  1 equemene  import numpy as Numeric  1 equemene except ImportError, err:  1 equemene  try:  1 equemene  import Numeric  1 equemene  except ImportError, err:  1 equemene  print "This demo requires the numpy or Numeric extension, sorry"  1 equemene  import sys  1 equemene  sys.exit()  1 equemene import copy  1 equemene 1 equemene class glCamera:  1 equemene  # //////////// CONSTRUCTORS /////////////////////////////////////////  1 equemene  def __init__ (self):  1 equemene  # // Initalize all our member varibles.  1 equemene  self.m_MaxPitchRate = 0.0;  1 equemene  self.m_MaxHeadingRate = 0.0;  1 equemene  self.m_HeadingDegrees = 0.0;  1 equemene  self.m_PitchDegrees = 0.0;  1 equemene  self.m_MaxForwardVelocity = 0.0;  1 equemene  self.m_ForwardVelocity = 0.0;  1 equemene  self.m_GlowTexture = None;  1 equemene  # bleair: NOTE that glCamera.cpp has a bug. m_BigGlowTexture isn't initialized.  1 equemene  # Very minor bug because only in the case where we fail to get an earlier  1 equemene  # texture will the class potentially read from the uninited memory. Most of  1 equemene  # the time the field is assigned to straight away in InitGL ().  1 equemene  self.m_BigGlowTexture = None;  1 equemene  self.m_HaloTexture = None;  1 equemene  self.m_StreakTexture = None;  1 equemene  self.m_MaxPointSize = 0.0;  1 equemene  self.m_Frustum = Numeric.zeros ( (6,4), 'f')  1 equemene 1 equemene  self.m_LightSourcePos = glPoint ()  1 equemene  self.m_Position = glPoint ()  1 equemene  self.m_DirectionVector = glVector ()  1 equemene  self.m_ptIntersect = glPoint ()  1 equemene 1 equemene 1 equemene 1 equemene 1 equemene  def __del__ (self):  1 equemene  self.release ()  1 equemene  return  1 equemene 1 equemene  def release (self):  1 equemene  if (self.m_GlowTexture != None):  1 equemene  glDeleteTextures (self.m_GlowTexture)  1 equemene  if (self.m_HaloTexture != None):  1 equemene  glDeleteTextures (self.m_HaloTexture)  1 equemene  if (self.m_BigGlowTexture != None):  1 equemene  glDeleteTextures (self.m_BigGlowTexture)  1 equemene  if (self.m_StreakTexture != None):  1 equemene  glDeleteTextures (self.m_StreakTexture)  1 equemene  return  1 equemene 1 equemene  def ChangePitch (self, degrees):  1 equemene  if (fabs (degrees) < fabs (self.m_MaxPitchRate)):  1 equemene  # // Our pitch is less than the max pitch rate that we  1 equemene  # // defined so lets increment it.  1 equemene  self.m_PitchDegrees += degrees;  1 equemene  else:  1 equemene  # // Our pitch is greater than the max pitch rate that  1 equemene  # // we defined so we can only increment our pitch by the  1 equemene  # // maximum allowed value.  1 equemene  if(degrees < 0):  1 equemene  # // We are pitching down so decrement  1 equemene  self.m_PitchDegrees -= self.m_MaxPitchRate;  1 equemene  else:  1 equemene  # // We are pitching up so increment  1 equemene  self.m_PitchDegrees += self.m_MaxPitchRate;  1 equemene 1 equemene  # // We don't want our pitch to run away from us. Although it  1 equemene  # // really doesn't matter I prefer to have my pitch degrees  1 equemene  # // within the range of -360.0f to 360.0f  1 equemene  if (self.m_PitchDegrees > 360.0):  1 equemene  self.m_PitchDegrees -= 360.0;  1 equemene  elif (self.m_PitchDegrees < -360.0):  1 equemene  self.m_PitchDegrees += 360.0;  1 equemene 1 equemene  return  1 equemene 1 equemene  def ChangeHeading (self, degrees):  1 equemene  if(fabs(degrees) < fabs(self.m_MaxHeadingRate)):  1 equemene  # // Our Heading is less than the max heading rate that we  1 equemene  # // defined so lets increment it but first we must check  1 equemene  # // to see if we are inverted so that our heading will not  1 equemene  # // become inverted.  1 equemene  if (self.m_PitchDegrees > 90 and self.m_PitchDegrees < 270 or  1 equemene  (self.m_PitchDegrees < -90 and self.m_PitchDegrees > -270)):  1 equemene  self.m_HeadingDegrees -= degrees;  1 equemene  else:  1 equemene  self.m_HeadingDegrees += degrees;  1 equemene  else:  1 equemene  # // Our heading is greater than the max heading rate that  1 equemene  # // we defined so we can only increment our heading by the  1 equemene  # // maximum allowed value.  1 equemene  if(degrees < 0):  1 equemene  # // Check to see if we are upside down.  1 equemene  if ((self.m_PitchDegrees > 90 and self.m_PitchDegrees < 270) or  1 equemene  (self.m_PitchDegrees < -90 and self.m_PitchDegrees > -270)):  1 equemene  # // Ok we would normally decrement here but since we are upside  1 equemene  # // down then we need to increment our heading  1 equemene  self.m_HeadingDegrees += self.m_MaxHeadingRate;  1 equemene  else:  1 equemene  # // We are not upside down so decrement as usual  1 equemene  self.m_HeadingDegrees -= self.m_MaxHeadingRate;  1 equemene  else:  1 equemene  # // Check to see if we are upside down.  1 equemene  if (self.m_PitchDegrees > 90 and self.m_PitchDegrees < 270 or  1 equemene  (self.m_PitchDegrees < -90 and self.m_PitchDegrees > -270)):  1 equemene  # // Ok we would normally increment here but since we are upside  1 equemene  # // down then we need to decrement our heading.  1 equemene  self.m_HeadingDegrees -= self.m_MaxHeadingRate;  1 equemene  else:  1 equemene  # // We are not upside down so increment as usual.  1 equemene  self.m_HeadingDegrees += self.m_MaxHeadingRate;  1 equemene 1 equemene  # // We don't want our heading to run away from us either. Although it  1 equemene  # // really doesn't matter I prefer to have my heading degrees  1 equemene  # // within the range of -360.0f to 360.0f  1 equemene  if(self.m_HeadingDegrees > 360.0):  1 equemene  self.m_HeadingDegrees -= 360.0;  1 equemene  elif(self.m_HeadingDegrees < -360.0):  1 equemene  self.m_HeadingDegrees += 360.0;  1 equemene 1 equemene  return  1 equemene 1 equemene  # //////////// FUNCTIONS TO CHANGE CAMERA ORIENTATION AND SPEED /////  1 equemene  def ChangeVelocity(self, vel):  1 equemene  if(fabs(vel) < fabs(self.m_MaxForwardVelocity)):  1 equemene  # // Our velocity is less than the max velocity increment that we  1 equemene  # // defined so lets increment it.  1 equemene  self.m_ForwardVelocity += vel;  1 equemene  else:  1 equemene  # // Our velocity is greater than the max velocity increment that  1 equemene  # // we defined so we can only increment our velocity by the  1 equemene  # // maximum allowed value.  1 equemene  if(vel < 0):  1 equemene  # // We are slowing down so decrement  1 equemene  self.m_ForwardVelocity -= -self.m_MaxForwardVelocity;  1 equemene  else:  1 equemene  # // We are speeding up so increment  1 equemene  self.m_ForwardVelocity += self.m_MaxForwardVelocity;  1 equemene 1 equemene  return  1 equemene 1 equemene  def UpdateFrustum(self):  1 equemene  """ // I found this code here: http://www.markmorley.com/opengl/frustumculling.html  1 equemene  // and decided to make it part of  1 equemene  // the camera class just in case I might want to rotate  1 equemene  // and translate the projection matrix. This code will  1 equemene  // make sure that the Frustum is updated correctly but  1 equemene  // this member is computational expensive with:  1 equemene  // 82 muliplications, 72 additions, 24 divisions, and  1 equemene  // 12 subtractions for a total of 190 operations. Ouch! """  1 equemene 1 equemene  # /* Get the current PROJECTION matrix from OpenGL */  1 equemene  proj = glGetFloatv( GL_PROJECTION_MATRIX);  1 equemene 1 equemene  # /* Get the current MODELVIEW matrix from OpenGL */  1 equemene  modl = glGetFloatv( GL_MODELVIEW_MATRIX);  1 equemene 1 equemene  # /* Combine the two matrices (multiply projection by modelview) */  1 equemene  # Careful, Note, that replication is simple scalars is OK, but replicate of objects  1 equemene  # and lists is very bad.  1 equemene  clip = [None,] * 16  1 equemene  # clip = Numeric.zeros ( (16), 'f')  1 equemene  clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];  1 equemene  clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];  1 equemene  clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];  1 equemene  clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];  1 equemene 1 equemene  clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];  1 equemene  clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];  1 equemene  clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];  1 equemene  clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];  1 equemene 1 equemene  clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];  1 equemene  clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];  1 equemene  clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];  1 equemene  clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];  1 equemene 1 equemene  clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];  1 equemene  clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];  1 equemene  clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];  1 equemene  clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];  1 equemene 1 equemene  # ### Use a shortened name to reference to our camera's Frustum (does  1 equemene  # ### not copy anything, just a ref to make code less wordy  1 equemene  Frustum = self.m_Frustum  1 equemene 1 equemene  # /* Extract the numbers for the RIGHT plane */  1 equemene  Frustum[0][0] = clip[ 3] - clip[ 0];  1 equemene  Frustum[0][1] = clip[ 7] - clip[ 4];  1 equemene  Frustum[0][2] = clip[11] - clip[ 8];  1 equemene  Frustum[0][3] = clip[15] - clip[12];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = (sqrt( Frustum[0][0] * Frustum[0][0] + \  1 equemene  Frustum[0][1] * Frustum[0][1] + Frustum[0][2] * Frustum[0][2] ));  1 equemene  Frustum[0][0] /= t;  1 equemene  Frustum[0][1] /= t;  1 equemene  Frustum[0][2] /= t;  1 equemene  Frustum[0][3] /= t;  1 equemene 1 equemene  # /* Extract the numbers for the LEFT plane */  1 equemene  Frustum[1][0] = clip[ 3] + clip[ 0];  1 equemene  Frustum[1][1] = clip[ 7] + clip[ 4];  1 equemene  Frustum[1][2] = clip[11] + clip[ 8];  1 equemene  Frustum[1][3] = clip[15] + clip[12];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( Frustum[1][0] * Frustum[1][0] + Frustum[1][1] * Frustum[1][1] + Frustum[1][2] * Frustum[1][2] );  1 equemene  Frustum[1][0] /= t;  1 equemene  Frustum[1][1] /= t;  1 equemene  Frustum[1][2] /= t;  1 equemene  Frustum[1][3] /= t;  1 equemene 1 equemene  # /* Extract the BOTTOM plane */  1 equemene  Frustum[2][0] = clip[ 3] + clip[ 1];  1 equemene  Frustum[2][1] = clip[ 7] + clip[ 5];  1 equemene  Frustum[2][2] = clip[11] + clip[ 9];  1 equemene  Frustum[2][3] = clip[15] + clip[13];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( Frustum[2][0] * Frustum[2][0] + Frustum[2][1] * Frustum[2][1] + Frustum[2][2] * Frustum[2][2] );  1 equemene  Frustum[2][0] /= t;  1 equemene  Frustum[2][1] /= t;  1 equemene  Frustum[2][2] /= t;  1 equemene  Frustum[2][3] /= t;  1 equemene 1 equemene  # /* Extract the TOP plane */  1 equemene  Frustum[3][0] = clip[ 3] - clip[ 1];  1 equemene  Frustum[3][1] = clip[ 7] - clip[ 5];  1 equemene  Frustum[3][2] = clip[11] - clip[ 9];  1 equemene  Frustum[3][3] = clip[15] - clip[13];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( Frustum[3][0] * Frustum[3][0] + Frustum[3][1] * Frustum[3][1] + Frustum[3][2] * Frustum[3][2] )  1 equemene  Frustum[3][0] /= t;  1 equemene  Frustum[3][1] /= t;  1 equemene  Frustum[3][2] /= t;  1 equemene  Frustum[3][3] /= t;  1 equemene 1 equemene  # /* Extract the FAR plane */  1 equemene  Frustum[4][0] = clip[ 3] - clip[ 2];  1 equemene  Frustum[4][1] = clip[ 7] - clip[ 6];  1 equemene  Frustum[4][2] = clip[11] - clip[10];  1 equemene  Frustum[4][3] = clip[15] - clip[14];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( Frustum[4][0] * Frustum[4][0] + Frustum[4][1] * Frustum[4][1] + Frustum[4][2] * Frustum[4][2] )  1 equemene  Frustum[4][0] /= t;  1 equemene  Frustum[4][1] /= t;  1 equemene  Frustum[4][2] /= t;  1 equemene  Frustum[4][3] /= t;  1 equemene 1 equemene  # /* Extract the NEAR plane */  1 equemene  Frustum[5][0] = clip[ 3] + clip[ 2];  1 equemene  Frustum[5][1] = clip[ 7] + clip[ 6];  1 equemene  Frustum[5][2] = clip[11] + clip[10];  1 equemene  Frustum[5][3] = clip[15] + clip[14];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( Frustum[5][0] * Frustum[5][0] + Frustum[5][1] * Frustum[5][1] + Frustum[5][2] * Frustum[5][2] );  1 equemene  Frustum[5][0] /= t;  1 equemene  Frustum[5][1] /= t;  1 equemene  Frustum[5][2] /= t;  1 equemene  Frustum[5][3] /= t;  1 equemene 1 equemene  return  1 equemene 1 equemene  # //////////// FUNCTIONS TO UPDATE THE FRUSTUM //////////////////////  1 equemene  def UpdateFrustumFaster (self):  1 equemene  """ // This is the much faster version of the above member  1 equemene  // function, however the speed increase is not gained  1 equemene  // without a cost. If you rotate or translate the projection  1 equemene  // matrix then this member will not work correctly. That is acceptable  1 equemene  // in my book considering I very rarely do such a thing.  1 equemene  // This function has far fewer operations in it and I  1 equemene  // shaved off 2 square root functions by passing in the  1 equemene  // near and far values. This member has:  1 equemene  // 38 muliplications, 28 additions, 24 divisions, and  1 equemene  // 12 subtractions for a total of 102 operations. Still hurts  1 equemene  // but at least it is decent now. In practice this will  1 equemene  // run about 2 times faster than the above function. """  1 equemene 1 equemene  # /* Get the current PROJECTION matrix from OpenGL */  1 equemene  proj = glGetFloatv( GL_PROJECTION_MATRIX);  1 equemene 1 equemene  # /* Get the current MODELVIEW matrix from OpenGL */  1 equemene  modl = glGetFloatv( GL_MODELVIEW_MATRIX);  1 equemene 1 equemene  # /* Combine the two matrices (multiply projection by modelview)  1 equemene  # but keep in mind this function will only work if you do NOT  1 equemene  # rotate or translate your projection matrix */  1 equemene  clip = [0,] * 16  1 equemene  modl_row1 = modl [0]  1 equemene  clip[ 0] = modl [0] [0] * proj[0][0];  1 equemene  clip[ 1] = modl [0][ 1] * proj[1][1];  1 equemene  clip[ 2] = modl [0][ 2] * proj[2][2] + modl_row1[ 3] * proj[3][2]  1 equemene  clip[ 3] = modl [0][ 2] * proj[2][3]  1 equemene 1 equemene  modl_row2 = modl [1]  1 equemene  clip[ 4] = modl_row2[ 0] * proj[0][0]  1 equemene  clip[ 5] = modl_row2[ 1] * proj[1][1]  1 equemene  clip[ 6] = modl_row2[ 2] * proj[2][2] + modl_row2[ 3] * proj[3][2]  1 equemene  clip[ 7] = modl_row2[ 2] * proj[2][3]  1 equemene 1 equemene  modl_row3 = modl [2]  1 equemene  clip[ 8] = modl_row3[ 0] * proj[0][0];  1 equemene  clip[ 9] = modl_row3[ 1] * proj[1][1]  1 equemene  clip[10] = modl_row3[2] * proj[2][2] + modl_row3[3] * proj[3][2]  1 equemene  clip[11] = modl_row3[2] * proj[2][3]  1 equemene 1 equemene  modl_row4 = modl [3]  1 equemene  clip[12] = modl_row4[0] * proj[0][0]  1 equemene  clip[13] = modl_row4[1] * proj[1][1]  1 equemene  clip[14] = modl_row4[2] * proj[2][2] + modl_row4[3] * proj[3][2]  1 equemene  clip[15] = modl_row4[2] * proj[2][3]  1 equemene 1 equemene  # ### Use a shortened name to reference to our camera's Frustum (does  1 equemene  # ### not copy anything, just a ref to make code less wordy  1 equemene  Frustum = self.m_Frustum  1 equemene 1 equemene  # /* Extract the numbers for the RIGHT plane */  1 equemene  Frustum[0][0] = clip[ 3] - clip[ 0];  1 equemene  Frustum[0][1] = clip[ 7] - clip[ 4];  1 equemene  Frustum[0][2] = clip[11] - clip[ 8];  1 equemene  Frustum[0][3] = clip[15] - clip[12];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( (Frustum[0][0] * Frustum[0][0]) + (Frustum[0][1] * Frustum[0][1]) + (Frustum[0][2] * Frustum[0][2]) );  1 equemene  Frustum[0][0] /= t;  1 equemene  Frustum[0][1] /= t;  1 equemene  Frustum[0][2] /= t;  1 equemene  Frustum[0][3] /= t;  1 equemene 1 equemene  # /* Extract the numbers for the LEFT plane */  1 equemene  Frustum[1][0] = clip[ 3] + clip[ 0];  1 equemene  Frustum[1][1] = clip[ 7] + clip[ 4];  1 equemene  Frustum[1][2] = clip[11] + clip[ 8];  1 equemene  Frustum[1][3] = clip[15] + clip[12];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( Frustum[1][0] * Frustum[1][0] + Frustum[1][1] * Frustum[1][1] + Frustum[1][2] * Frustum[1][2] );  1 equemene  Frustum[1][0] /= t;  1 equemene  Frustum[1][1] /= t;  1 equemene  Frustum[1][2] /= t;  1 equemene  Frustum[1][3] /= t;  1 equemene 1 equemene  # /* Extract the BOTTOM plane */  1 equemene  Frustum[2][0] = clip[ 3] + clip[ 1];  1 equemene  Frustum[2][1] = clip[ 7] + clip[ 5];  1 equemene  Frustum[2][2] = clip[11] + clip[ 9];  1 equemene  Frustum[2][3] = clip[15] + clip[13];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( Frustum[2][0] * Frustum[2][0] + Frustum[2][1] * Frustum[2][1] + Frustum[2][2] * Frustum[2][2] );  1 equemene  Frustum[2][0] /= t;  1 equemene  Frustum[2][1] /= t;  1 equemene  Frustum[2][2] /= t;  1 equemene  Frustum[2][3] /= t;  1 equemene 1 equemene  # /* Extract the TOP plane */  1 equemene  Frustum[3][0] = clip[ 3] - clip[ 1];  1 equemene  Frustum[3][1] = clip[ 7] - clip[ 5];  1 equemene  Frustum[3][2] = clip[11] - clip[ 9];  1 equemene  Frustum[3][3] = clip[15] - clip[13];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( Frustum[3][0] * Frustum[3][0] + Frustum[3][1] * Frustum[3][1] + Frustum[3][2] * Frustum[3][2] );  1 equemene  Frustum[3][0] /= t;  1 equemene  Frustum[3][1] /= t;  1 equemene  Frustum[3][2] /= t;  1 equemene  Frustum[3][3] /= t;  1 equemene 1 equemene  # /* Extract the FAR plane */  1 equemene  Frustum[4][0] = clip[ 3] - clip[ 2];  1 equemene  Frustum[4][1] = clip[ 7] - clip[ 6];  1 equemene  Frustum[4][2] = clip[11] - clip[10];  1 equemene  Frustum[4][3] = clip[15] - clip[14];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( (Frustum[4][0] * Frustum[4][0]) + (Frustum[4][1] * Frustum[4][1]) + (Frustum[4][2] * Frustum[4][2]) );  1 equemene  Frustum[4][0] /= t;  1 equemene  Frustum[4][1] /= t;  1 equemene  Frustum[4][2] /= t;  1 equemene  Frustum[4][3] /= t;  1 equemene 1 equemene  # /* Extract the NEAR plane */  1 equemene  Frustum[5][0] = clip[ 3] + clip[ 2];  1 equemene  Frustum[5][1] = clip[ 7] + clip[ 6];  1 equemene  Frustum[5][2] = clip[11] + clip[10];  1 equemene  Frustum[5][3] = clip[15] + clip[14];  1 equemene 1 equemene  # /* Normalize the result */  1 equemene  t = sqrt( Frustum[5][0] * Frustum[5][0] + Frustum[5][1] * Frustum[5][1] + Frustum[5][2] * Frustum[5][2] );  1 equemene  Frustum[5][0] /= t;  1 equemene  Frustum[5][1] /= t;  1 equemene  Frustum[5][2] /= t;  1 equemene  Frustum[5][3] /= t;  1 equemene 1 equemene  return  1 equemene 1 equemene 1 equemene 1 equemene  # //////////// FRUSTUM TESTING FUNCTIONS ////////////////////////////  1 equemene  def SphereInFrustum(self, p, Radius):  1 equemene  """ // This member function checks to see if a sphere is in  1 equemene  // the viewing volume. """  1 equemene 1 equemene  Frustum = self.m_Frustum  1 equemene  # // The idea here is the same as the PointInFrustum function.  1 equemene  if (Radius != 0):  1 equemene  for i in xrange (6):  1 equemene  # // If the point is outside of the plane then its not in the viewing volume.  1 equemene  if(Frustum[i][0] * p.x + Frustum[i][1] * p.y + Frustum[i][2] * p.z + Frustum[i][3] <= -Radius):  1 equemene  return(False);  1 equemene  else:  1 equemene  # // The idea here is the same as the PointInFrustum function.  1 equemene  for i in xrange (6):  1 equemene  # // If the point is outside of the plane then its not in the viewing volume.  1 equemene  if(Frustum[i][0] * p.x + Frustum[i][1] * p.y + Frustum[i][2] * p.z + Frustum[i][3] <= 0):  1 equemene  return(False);  1 equemene 1 equemene  return(True);  1 equemene 1 equemene  def PointInFrustum(self, x,y,z):  1 equemene  """ // This member fuction checks to see if a point is in  1 equemene  // the viewing volume. """  1 equemene 1 equemene  # // The idea behind this algorithum is that if the point  1 equemene  # // is inside all 6 clipping planes then it is inside our  1 equemene  # // viewing volume so we can return true.  1 equemene 1 equemene  Frustum = self.m_Frustum  1 equemene  # // Loop through all our clipping planes  1 equemene  for i in xrange (6):  1 equemene  # // If the point is outside of the plane then its not in the viewing volume.  1 equemene  if(Frustum[i][0] * x + Frustum[i][1] * y + Frustum[i][2] * z + Frustum[i][3] <= 0):  1 equemene  return(False);  1 equemene 1 equemene  return(True);  1 equemene 1 equemene  # /////////// OCCLUSION TESTING FUNCTIONS ///////////////////////////  1 equemene  def IsOccluded (self, p):  1 equemene  # // Now we will ask OGL to project some geometry for us using the gluProject function.  1 equemene  # // Practically we ask OGL to guess where a point in space will be projected in our current viewport,  1 equemene  # // using arbitrary viewport and transform matrices we pass to the function.  1 equemene  # // If we pass to the function the current matrices (retrievede with the glGet funcs)  1 equemene  # // we will have the real position on screen where the dot will be drawn.  1 equemene  # // The interesting part is that we also get a Z value back, this means that  1 equemene  # // reading the REAL buffer for Z values we can discover if the flare is in front or  1 equemene  # // if it's occluded by some objects.  1 equemene  # ### This function should be a flat function, not a function of the camera as we  1 equemene  # ### use the immediate GL rendering state entirely.  1 equemene 1 equemene 1 equemene  # ### Viewport is the rectangle of window pixels that OpenGL is rasterizing into.  1 equemene  viewport = glGetIntegerv (GL_VIEWPORT); # //get actual viewport  1 equemene  mvmatrix = glGetDoublev (GL_MODELVIEW_MATRIX); # //get actual model view matrix  1 equemene  projmatrix = glGetDoublev (GL_PROJECTION_MATRIX); # //get actual projiection matrix  1 equemene 1 equemene  # // this asks OGL to guess the 2d position of a 3d point inside the viewport  1 equemene  winx, winy, winz = gluProject(p.x, p.y, p.z, mvmatrix, projmatrix, viewport)  1 equemene  flareZ = winz;  1 equemene 1 equemene  # // we read back one pixel from th depth buffer (exactly where our flare should be drawn)  1 equemene  glPixelStorei(GL_PACK_ALIGNMENT, 1)  1 equemene 1 equemene  # PyOpenGL 2.0.1.07 bug, Only the type clarified function works.  1 equemene  # bufferZ = glReadPixels(int(winx), int(winy),1,1,GL_DEPTH_COMPONENT, GL_FLOAT)  1 equemene  bufferZ = glReadPixelsf(int(winx), int(winy),1,1,GL_DEPTH_COMPONENT)  1 equemene 1 equemene  # // if the buffer Z is lower than our flare guessed Z then don't draw  1 equemene  # // this means there is something in front of our flare  1 equemene  if (bufferZ [0] [0] < flareZ):  1 equemene  return True;  1 equemene  else:  1 equemene  return False;  1 equemene 1 equemene  # //////////// FUNCTIONS TO RENDER LENS FLARES //////////////////////  1 equemene  def RenderLensFlare(self):  1 equemene  # // Draw the flare only If the light source is in our line of sight (inside the Frustum)  1 equemene  if (self.SphereInFrustum(self.m_LightSourcePos, 1.0) == True):  1 equemene 1 equemene  # Vector pointing from the light's position toward the camera's position (the camera might  1 equemene  # be pointing elsewhere, this vector is pointing from the light to the camera)  1 equemene  self.vLightSourceToCamera = self.m_Position - self.m_LightSourcePos; # // Lets compute the vector that points to the camera from  1 equemene  # // the light source.  1 equemene 1 equemene  Length = self.vLightSourceToCamera.Magnitude () # // Save the length we will need it in a minute  1 equemene 1 equemene  # Move down our look-toward direction vector. Move down the look-toward the same dist. as the  1 equemene  # distance between camera and the light.  1 equemene  intersect = self.m_DirectionVector * Length  1 equemene  self.m_ptIntersect = glPoint (intersect.i, intersect.j, intersect.k)  1 equemene  # // Now lets find an point along the cameras direction  1 equemene  # // vector that we can use as an intersection point.  1 equemene  # // Lets translate down this vector the same distance  1 equemene  # // that the camera is away from the light source.  1 equemene  ptIntersect = self.m_ptIntersect  1 equemene  # Did the motion in the correct direction above, now translate the intersection position  1 equemene  # relative to our camera location.  1 equemene  ptIntersect += self.m_Position;  1 equemene 1 equemene 1 equemene  self.vLightSourceToIntersect = ptIntersect - self.m_LightSourcePos; # // Lets compute the vector that points to the Intersect  1 equemene  # // point from the light source  1 equemene 1 equemene  Length = self.vLightSourceToIntersect.Magnitude(); # // Save the length we will need it later.  1 equemene  self.vLightSourceToIntersect.Normalize(); # // Normalize the vector so its unit length  1 equemene  vLightSourceToIntersect = self.vLightSourceToIntersect  1 equemene 1 equemene  glEnable(GL_BLEND); # // You should already know what this does  1 equemene  glBlendFunc(GL_SRC_ALPHA, GL_ONE); # // You should already know what this does  1 equemene  glDisable(GL_DEPTH_TEST); # // You should already know what this does  1 equemene  glEnable(GL_TEXTURE_2D); # // You should already know what this does  1 equemene 1 equemene  # /////////// Differenet Color Glows & Streaks /////////////////////  1 equemene  # //RenderBigGlow(1.0f, 1.0f, 1.0f, 1.0f, m_LightSourcePos, 1.0f);  1 equemene  # //RenderStreaks(1.0f, 1.0f, 0.8f, 1.0f, m_LightSourcePos, 0.7f);  1 equemene  # //  1 equemene  # //RenderBigGlow(1.0f, 0.9f, 1.0f, 1.0f, m_LightSourcePos, 1.0f);  1 equemene  # //RenderStreaks(1.0f, 0.9f, 1.0f, 1.0f, m_LightSourcePos, 0.7f);  1 equemene  # //////////////////////////////////////////////////////////////////  1 equemene 1 equemene 1 equemene  # //########################## NEW STUFF ##################################  1 equemene 1 equemene  if (not self.IsOccluded(self.m_LightSourcePos)): # //Check if the center of the flare is occluded  1 equemene  # // Render the large hazy glow  1 equemene  self.RenderBigGlow(0.60, 0.60, 0.8, 1.0, self.m_LightSourcePos, 16.0);  1 equemene  # // Render the streaks  1 equemene  self.RenderStreaks(0.60, 0.60, 0.8, 1.0, self.m_LightSourcePos, 16.0);  1 equemene  # // Render the small Glow  1 equemene  self.RenderGlow(0.8, 0.8, 1.0, 0.5, self.m_LightSourcePos, 3.5);  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.1)); # // Lets compute a point that is 20%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderGlow(0.9, 0.6, 0.4, 0.5, pt, 0.6); # // Render the small Glow  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.15)); # // Lets compute a point that is 30%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderHalo(0.8, 0.5, 0.6, 0.5, pt, 1.7); # // Render the a Halo  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.175)); # // Lets compute a point that is 35%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderHalo(0.9, 0.2, 0.1, 0.5, pt, 0.83); # // Render the a Halo  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.285)); # // Lets compute a point that is 57%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderHalo(0.7, 0.7, 0.4, 0.5, pt, 1.6); # // Render the a Halo  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.2755)); # // Lets compute a point that is 55.1%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderGlow(0.9, 0.9, 0.2, 0.5, pt, 0.8); # // Render the small Glow  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.4775)); # // Lets compute a point that is 95.5%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderGlow(0.93, 0.82, 0.73, 0.5, pt, 1.0); # // Render the small Glow  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.49)); # // Lets compute a point that is 98%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderHalo(0.7, 0.6, 0.5, 0.5, pt, 1.4); # // Render the a Halo  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.65)); # // Lets compute a point that is 130%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderGlow(0.7, 0.8, 0.3, 0.5, pt, 1.8); # // Render the small Glow  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.63)); # // Lets compute a point that is 126%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderGlow(0.4, 0.3, 0.2, 0.5, pt, 1.4); # // Render the small Glow  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.8)); # // Lets compute a point that is 160%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderHalo(0.7, 0.5, 0.5, 0.5, pt, 1.4); # // Render the a Halo  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.7825)); # // Lets compute a point that is 156.5%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderGlow(0.8, 0.5, 0.1, 0.5, pt, 0.6); # // Render the small Glow  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 1.0)); # // Lets compute a point that is 200%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderHalo(0.5, 0.5, 0.7, 0.5, pt, 1.7); # // Render the a Halo  1 equemene 1 equemene  pt = glPoint (vLightSourceToIntersect * (Length * 0.975)); # // Lets compute a point that is 195%  1 equemene  pt += self.m_LightSourcePos; # // away from the light source in the  1 equemene  # // direction of the intersection point.  1 equemene 1 equemene  self.RenderGlow(0.4, 0.1, 0.9, 0.5, pt, 2.0); # // Render the small Glow  1 equemene 1 equemene  glDisable(GL_BLEND ); # // You should already know what this does  1 equemene  glEnable(GL_DEPTH_TEST); # // You should already know what this does  1 equemene  glDisable(GL_TEXTURE_2D); # // You should already know what this does  1 equemene  return  1 equemene 1 equemene  def RenderHalo (self, r, g, b, a, p, scale):  1 equemene  self.RenderFlareTexture (self.m_HaloTexture, r, g, b, a, p, scale)  1 equemene  return  1 equemene 1 equemene  def RenderGlow (self, r, g, b, a, p, scale):  1 equemene  self.RenderFlareTexture (self.m_GlowTexture, r, g, b, a, p, scale)  1 equemene  return  1 equemene 1 equemene  def RenderBigGlow (self, r, g, b, a, p, scale):  1 equemene  self.RenderFlareTexture (self.m_BigGlowTexture, r, g, b, a, p, scale)  1 equemene  return  1 equemene 1 equemene  def RenderStreaks (self, r, g, b, a, p, scale):  1 equemene  self.RenderFlareTexture (self.m_StreakTexture, r, g, b, a, p, scale)  1 equemene  return  1 equemene 1 equemene  def RenderFlareTexture (self, tex_ID, r, g, b, a, p, scale):  1 equemene  # bleair: Duplicate functions all the same except for the texture to bind to.  1 equemene 1 equemene  q = []  1 equemene  q.append (glPoint ())  1 equemene  q.append (glPoint ())  1 equemene  q.append (glPoint ())  1 equemene  q.append (glPoint ())  1 equemene  # // Basically we are just going to make a 2D box  1 equemene  # // from four points we don't need a z coord because  1 equemene  # // we are rotating the camera by the inverse so the  1 equemene  # // texture mapped quads will always face us.  1 equemene 1 equemene  q[0].x = (p.x - scale); # // Set the x coordinate -scale units from the center point.  1 equemene  q[0].y = (p.y - scale); # // Set the y coordinate -scale units from the center point.  1 equemene 1 equemene  q[1].x = (p.x - scale); # // Set the x coordinate -scale units from the center point.  1 equemene  q[1].y = (p.y + scale); # // Set the y coordinate scale units from the center point.  1 equemene 1 equemene  q[2].x = (p.x + scale); # // Set the x coordinate scale units from the center point.  1 equemene  q[2].y = (p.y - scale); # // Set the y coordinate -scale units from the center point.  1 equemene 1 equemene  q[3].x = (p.x + scale); # // Set the x coordinate scale units from the center point.  1 equemene  q[3].y = (p.y + scale); # // Set the y coordinate scale units from the center point.  1 equemene 1 equemene  glPushMatrix(); # // Save the model view matrix  1 equemene  glTranslatef(p.x, p.y, p.z); # // Translate to our point  1 equemene  glRotatef(-self.m_HeadingDegrees, 0.0, 1.0, 0.0);  1 equemene  glRotatef(-self.m_PitchDegrees, 1.0, 0.0, 0.0);  1 equemene  glBindTexture(GL_TEXTURE_2D, tex_ID); # // Bind to the Big Glow texture  1 equemene  glColor4f(r, g, b, a); # // Set the color since the texture is a gray scale  1 equemene 1 equemene  glBegin(GL_TRIANGLE_STRIP); # // Draw the Big Glow on a Triangle Strip  1 equemene  glTexCoord2f(0.0, 0.0);  1 equemene  glVertex2f(q[0].x, q[0].y);  1 equemene  glTexCoord2f(0.0, 1.0);  1 equemene  glVertex2f(q[1].x, q[1].y);  1 equemene  glTexCoord2f(1.0, 0.0);  1 equemene  glVertex2f(q[2].x, q[2].y);  1 equemene  glTexCoord2f(1.0, 1.0);  1 equemene  glVertex2f(q[3].x, q[3].y);  1 equemene  glEnd();  1 equemene  glPopMatrix(); # // Restore the model view matrix  1 equemene  return  1 equemene 1 equemene 1 equemene 1 equemene 1 equemene  def SetPrespective (self):  1 equemene  # Matrix = [0] * 16 # // A (list) array to hold the model view matrix.  1 equemene 1 equemene  # However the MODELVIEW was oriented, we now rotate it based upon our Camer object's state.  1 equemene  # // Going to use glRotate to calculate our direction vector  1 equemene  glRotatef(self.m_HeadingDegrees, 0.0, 1.0, 0.0); # turn your head left/right (around y axe)  1 equemene  glRotatef(self.m_PitchDegrees, 1.0, 0.0, 0.0); # nod your head up/down (around x axe)  1 equemene 1 equemene  # // Get the resulting matrix from OpenGL it will have our  1 equemene  # // direction vector in the 3rd row.  1 equemene  Matrix = glGetFloatv(GL_MODELVIEW_MATRIX);  1 equemene 1 equemene  # // Get the direction vector from the matrix. Element 10 must  1 equemene  # // be inverted!  1 equemene  self.m_DirectionVector.i = Matrix[2] [0] #[8];  1 equemene  self.m_DirectionVector.j = Matrix[2] [1] #[9];  1 equemene  self.m_DirectionVector.k = -Matrix[2] [2] #[10];  1 equemene 1 equemene  # #### bleair: no need to do this as this. Previous rotates already here (because  1 equemene  # #### all invocations have the modelview at identity.  1 equemene  # #### Suspect this was just a bit of code that was mvoed up and not deleted here.  1 equemene  # // Ok erase the results of the last computation.  1 equemene  glLoadIdentity();  1 equemene 1 equemene  # // Rotate the scene to get the right orientation.  1 equemene  glRotatef(self.m_PitchDegrees, 1.0, 0.0, 0.0);  1 equemene  glRotatef(self.m_HeadingDegrees, 0.0, 1.0, 0.0);  1 equemene 1 equemene  # // A vector to hold our cameras direction * the forward velocity  1 equemene  # // we don't want to destory the Direction vector by using it instead.  1 equemene  # // Scale the direction by our speed.  1 equemene  v = copy.copy (self.m_DirectionVector);  1 equemene  v *= self.m_ForwardVelocity;  1 equemene 1 equemene  # // Increment our position by the vector  1 equemene  self.m_Position.x += v.i;  1 equemene  self.m_Position.y += v.j;  1 equemene  self.m_Position.z += v.k;  1 equemene 1 equemene  # // Translate to our new position.  1 equemene  glTranslatef(-self.m_Position.x, -self.m_Position.y, -self.m_Position.z);  1 equemene  return  1 equemene 1 equemene 1 equemene """  1 equemene  //////////// MEMBER VARIBLES //////////////////////////////////////  1 equemene  glVector vLightSourceToCamera, vLightSourceToIntersect;  1 equemene  glPoint ptIntersect, pt;  1 equemene  GLsizei m_WindowHeight;  1 equemene  GLsizei m_WindowWidth;  1 equemene  GLuint m_StreakTexture;  1 equemene  GLuint m_HaloTexture;  1 equemene  GLuint m_GlowTexture;  1 equemene  GLuint m_BigGlowTexture;  1 equemene  GLfloat m_MaxPointSize;  1 equemene  GLfloat m_Frustum[6][4];  1 equemene  glPoint m_LightSourcePos;  1 equemene  GLfloat m_MaxPitchRate;  1 equemene  GLfloat m_MaxHeadingRate;  1 equemene  GLfloat m_HeadingDegrees;  1 equemene  GLfloat m_PitchDegrees;  1 equemene  GLfloat m_MaxForwardVelocity;  1 equemene  GLfloat m_ForwardVelocity;  1 equemene  glPoint m_Position;  1 equemene  glVector m_DirectionVector;  1 equemene """