/*
 * Test if a ray hits sphere.
 */
inline static BOOL RayHitsSphere(
  const FLOAT3D &vStart,
  const FLOAT3D &vEnd,
  const FLOAT3D &vSphereCenter,
  const FLOAT fSphereRadius,
  FLOAT &fDistance)
{
  const FLOAT3D vSphereCenterToStart = vStart - vSphereCenter;
  const FLOAT3D vStartToEnd          = vEnd - vStart;
  // calculate discriminant for intersection parameters
  const FLOAT fP = ((vStartToEnd%vSphereCenterToStart)/(vStartToEnd%vStartToEnd));
  const FLOAT fQ = (((vSphereCenterToStart%vSphereCenterToStart)
    - (fSphereRadius*fSphereRadius))/(vStartToEnd%vStartToEnd));
  const FLOAT fD = fP*fP-fQ;
  // if it is less than zero
  if (fD<0) {
    // no collision will occur
    return FALSE;
  }
  // calculate intersection parameters
  const FLOAT fSqrtD = sqrt(fD);
  const FLOAT fLambda1 = -fP+fSqrtD;
  const FLOAT fLambda2 = -fP-fSqrtD;
  // use lower one
  const FLOAT fMinLambda = Min(fLambda1, fLambda2);
  // calculate distance from parameter
  fDistance = fMinLambda*vStartToEnd.Length();
  return TRUE;
}
Exemplo n.º 2
0
// transform model to view space
static void PrepareView( CRenderModel &rm) 
{
  // prepare projections
  const FLOATmatrix3D &mViewer = _aprProjection->pr_ViewerRotationMatrix;
  const FLOAT3D &vViewer = _aprProjection->pr_vViewerPosition;
  FLOATmatrix3D &m = rm.rm_mObjectToView;
  // if half face forward
  if( rm.rm_pmdModelData->md_Flags&MF_HALF_FACE_FORWARD) {
    // get the y-axis vector of object rotation
    FLOAT3D vY(rm.rm_mObjectRotation(1,2), rm.rm_mObjectRotation(2,2), rm.rm_mObjectRotation(3,2));
    // find z axis of viewer
    FLOAT3D vViewerZ( mViewer(3,1), mViewer(3,2), mViewer(3,3));
    // calculate x and z axis vectors to make object head towards viewer
    FLOAT3D vX = (-vViewerZ)*vY;
    vX.Normalize();
    FLOAT3D vZ = vY*vX;
    // compose the rotation matrix back from those angles
    m(1,1) = vX(1);  m(1,2) = vY(1);  m(1,3) = vZ(1);
    m(2,1) = vX(2);  m(2,2) = vY(2);  m(2,3) = vZ(2);
    m(3,1) = vX(3);  m(3,2) = vY(3);  m(3,3) = vZ(3);
    // add viewer rotation to that
    m = mViewer * m;
  } // if full face forward
  else if( rm.rm_pmdModelData->md_Flags&MF_FACE_FORWARD) {
    // use just object banking for rotation
    FLOAT fSinP = -rm.rm_mObjectRotation(2,3);
    FLOAT fCosP = Sqrt(1-fSinP*fSinP);
    FLOAT fSinB, fCosB;
    if( fCosP>0.001f) {
      const FLOAT f1oCosP = 1.0f/fCosP;
      fSinB = rm.rm_mObjectRotation(2,1)*f1oCosP;
      fCosB = rm.rm_mObjectRotation(2,2)*f1oCosP;
    } else {
      fSinB = 0.0f;
      fCosB = 1.0f;
    }
    m(1,1) = +fCosB;  m(1,2) = -fSinB;  m(1,3) = 0;
    m(2,1) = +fSinB;  m(2,2) = +fCosB;  m(2,3) = 0;
    m(3,1) =      0;  m(3,2) =      0;  m(3,3) = 1;
  } // if normal model
  else {
    // use viewer and object orientation
    m = mViewer * rm.rm_mObjectRotation;
  }
  // find translation vector
  rm.rm_vObjectToView  = rm.rm_vObjectPosition - vViewer;
  rm.rm_vObjectToView *= mViewer;
}
Exemplo n.º 3
0
/* Create angles in 3D from up vector (ignoring objects relative heading).
   (up vector must be normalized!)*/
void UpVectorToAngles(const FLOAT3D &vY, ANGLE3D &a3dAngles)
{
  // create any front vector
  FLOAT3D vZ;
  if (Abs(vY(2))>0.5f) {
    vZ = FLOAT3D(1,0,0)*vY;
  } else {
    vZ = FLOAT3D(0,1,0)*vY;
  }
  vZ.Normalize();
  // side vector is cross product
  FLOAT3D vX = vY*vZ;
  vX.Normalize();
  // create the rotation matrix
  FLOATmatrix3D m;
  m(1,1) = vX(1); m(1,2) = vY(1); m(1,3) = vZ(1);
  m(2,1) = vX(2); m(2,2) = vY(2); m(2,3) = vZ(2);
  m(3,1) = vX(3); m(3,2) = vY(3); m(3,3) = vZ(3);

  // decompose the matrix without snapping
  DecomposeRotationMatrixNoSnap(a3dAngles, m);
}
Exemplo n.º 4
0
// Create render model structure for rendering an attached model
BOOL CModelObject::CreateAttachment( CRenderModel &rmMain, CAttachmentModelObject &amo)
{
  _pfModelProfile.StartTimer( CModelProfile::PTI_CREATEATTACHMENT);
  _pfModelProfile.IncrementTimerAveragingCounter( CModelProfile::PTI_CREATEATTACHMENT);
  CRenderModel &rmAttached = *amo.amo_prm;
  rmAttached.rm_ulFlags = rmMain.rm_ulFlags&(RMF_FOG|RMF_HAZE|RMF_WEAPON) | RMF_ATTACHMENT;

  // get the position
  rmMain.rm_pmdModelData->md_aampAttachedPosition.Lock();
  const CAttachedModelPosition &amp = rmMain.rm_pmdModelData->md_aampAttachedPosition[amo.amo_iAttachedPosition];
  rmMain.rm_pmdModelData->md_aampAttachedPosition.Unlock();

  // copy common values
  rmAttached.rm_vLightDirection = rmMain.rm_vLightDirection;
  rmAttached.rm_fDistanceFactor = rmMain.rm_fDistanceFactor;
  rmAttached.rm_colLight   = rmMain.rm_colLight;
  rmAttached.rm_colAmbient = rmMain.rm_colAmbient;
  rmAttached.rm_colBlend   = rmMain.rm_colBlend;

  // unpack the reference vertices
  FLOAT3D vCenter, vFront, vUp;
  const INDEX iCenter = amp.amp_iCenterVertex;
  const INDEX iFront  = amp.amp_iFrontVertex;
  const INDEX iUp     = amp.amp_iUpVertex;
  UnpackVertex( rmMain, iCenter, vCenter);
  UnpackVertex( rmMain, iFront,  vFront);
  UnpackVertex( rmMain, iUp,     vUp);

  // create front and up direction vectors
  FLOAT3D vY = vUp - vCenter;
  FLOAT3D vZ = vCenter - vFront;
  // project center and directions from object to absolute space
  const FLOATmatrix3D &mO2A = rmMain.rm_mObjectRotation;
  const FLOAT3D &vO2A = rmMain.rm_vObjectPosition;
  vCenter = vCenter*mO2A +vO2A;
  vY = vY *mO2A;
  vZ = vZ *mO2A;

  // make a rotation matrix from the direction vectors
  FLOAT3D vX = vY*vZ;
  vY = vZ*vX;
  vX.Normalize();
  vY.Normalize();
  vZ.Normalize();
  FLOATmatrix3D mOrientation;
  mOrientation(1,1) = vX(1);  mOrientation(1,2) = vY(1);  mOrientation(1,3) = vZ(1);
  mOrientation(2,1) = vX(2);  mOrientation(2,2) = vY(2);  mOrientation(2,3) = vZ(2);
  mOrientation(3,1) = vX(3);  mOrientation(3,2) = vY(3);  mOrientation(3,3) = vZ(3);

  // adjust for relative placement of the attachment
  FLOAT3D vOffset;
  FLOATmatrix3D mRelative;
  MakeRotationMatrixFast( mRelative, amo.amo_plRelative.pl_OrientationAngle);
  vOffset(1) = amo.amo_plRelative.pl_PositionVector(1) * mo_Stretch(1);
  vOffset(2) = amo.amo_plRelative.pl_PositionVector(2) * mo_Stretch(2);
  vOffset(3) = amo.amo_plRelative.pl_PositionVector(3) * mo_Stretch(3);
  FLOAT3D vO = vCenter + vOffset * mOrientation;
  mOrientation *= mRelative; // convert absolute to relative orientation
  rmAttached.SetObjectPlacement( vO, mOrientation);

  // done here if clipping optimizations are not allowed
  extern INDEX gap_iOptimizeClipping;
  if( gap_iOptimizeClipping<1) { 
    gap_iOptimizeClipping = 0;
    _pfModelProfile.StopTimer( CModelProfile::PTI_CREATEATTACHMENT);
    return TRUE;
  }

  // test attachment to frustum and/or mirror
  FLOAT3D vHandle;
  _aprProjection->PreClip( vO, vHandle);
  CalculateBoundingBox( &amo.amo_moModelObject, rmAttached);

  // compose view-space bounding box and sphere of an attacment
  const FLOAT fR = Max( rmAttached.rm_vObjectMinBB.Length(), rmAttached.rm_vObjectMaxBB.Length());
  const FLOATobbox3D boxEntity( FLOATaabbox3D(rmAttached.rm_vObjectMinBB, rmAttached.rm_vObjectMaxBB),
                                vHandle, _aprProjection->pr_ViewerRotationMatrix*mOrientation);
  // frustum test?
  if( gap_iOptimizeClipping>1) {
    // test sphere against frustrum
    INDEX iFrustumTest = _aprProjection->TestSphereToFrustum(vHandle,fR);
    if( iFrustumTest==0) {
      // test box if sphere cut one of frustum planes
      iFrustumTest = _aprProjection->TestBoxToFrustum(boxEntity);
    }
    // mark if attachment is fully inside frustum
         if( iFrustumTest>0) rmAttached.rm_ulFlags |= RMF_INSIDE; 
    else if( iFrustumTest<0) { // if completely outside of frustum
      // signal skip rendering only if doesn't have any attachments
      _pfModelProfile.StopTimer( CModelProfile::PTI_CREATEATTACHMENT);
      return !amo.amo_moModelObject.mo_lhAttachments.IsEmpty(); 
    }
  }
  // test sphere against mirror/warp plane (if any)
  if( _aprProjection->pr_bMirror || _aprProjection->pr_bWarp) {
    INDEX iMirrorPlaneTest;
    const FLOAT fPlaneDistance = _aprProjection->pr_plMirrorView.PointDistance(vHandle);
         if( fPlaneDistance < -fR) iMirrorPlaneTest = -1;
    else if( fPlaneDistance > +fR) iMirrorPlaneTest = +1;
    else { // test box if sphere cut mirror plane
      iMirrorPlaneTest = boxEntity.TestAgainstPlane(_aprProjection->pr_plMirrorView);
    }
    // mark if attachment is fully inside mirror
         if( iMirrorPlaneTest>0) rmAttached.rm_ulFlags |= RMF_INMIRROR; 
    else if( iMirrorPlaneTest<0) { // if completely outside mirror
      // signal skip rendering only if doesn't have any attachments
      _pfModelProfile.StopTimer( CModelProfile::PTI_CREATEATTACHMENT);
      return !amo.amo_moModelObject.mo_lhAttachments.IsEmpty(); 
    }
  } 
  // all done
  _pfModelProfile.StopTimer( CModelProfile::PTI_CREATEATTACHMENT);
  return TRUE;
}
Exemplo n.º 5
0
CTString GetItemValue(CEntity *pen, INDEX iColumn, INDEX &iFormat)
{
  ASSERT(pen!=NULL);
  if(pen==NULL) return CTString("");
  CEntityClass *pecEntityClass = pen->GetClass();
  CDLLEntityClass *pdllecDllEntityClass = pecEntityClass->ec_pdecDLLClass;
  FLOAT3D vOrigin = pen->GetPlacement().pl_PositionVector;
  ANGLE3D vAngles = pen->GetPlacement().pl_OrientationAngle;
  CTString strResult="";
  iFormat=PDF_STRING;
  
  switch( iColumn)
  {
  case COLUMN_ID:
  {
    strResult.PrintF("%d", pen->en_ulID);
    iFormat=PDF_INDEX;
    break;
  }
  case COLUMN_CLASS:
  {
    strResult=pdllecDllEntityClass->dec_strName;
    break;
  }
  case COLUMN_NAME:
  {
    strResult=pen->GetName();
    break;
  }
  case COLUMN_DESCRIPTION:
  {
    strResult=pen->GetDescription();
    break;
  }
  case COLUMN_SECTOR_NAME:
  {
    CBrushSector *pbsc = pen->GetFirstSectorWithName();
    if( pbsc!=NULL)
    {
      strResult=pbsc->bsc_strName;
    }
    break;
  }
  case COLUMN_X:
  {
    strResult.PrintF("%g", vOrigin(1));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_Y:
  {
    strResult.PrintF("%g", vOrigin(2));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_Z:
  {
    strResult.PrintF("%g", vOrigin(3));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_H:
  {
    strResult.PrintF("%g", vAngles(1));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_P:
  {
    strResult.PrintF("%g", vAngles(2));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_B:
  {
    strResult.PrintF("%g", vAngles(3));
    iFormat=PDF_FLOAT;
    break;
  }
// 강동민 수정 시작
	case COLUMN_MOBINDEX:		
		{
			if(pen->IsEnemy())
			{	
				CEntityProperty &epPropertyMobType = *(pen->PropertyForTypeAndID(CEntityProperty::EPT_INDEX, 91));		// Zone Flag
				INDEX iEnemyType = ENTITYPROPERTY( &*pen, epPropertyMobType.ep_slOffset, INDEX);

				strResult.PrintF("%d", iEnemyType);
				iFormat=PDF_INDEX;
			}
			break;
		}
	case COLUMN_REGEN:
		{
			if(pen->IsEnemy())
			{
				CEntityProperty &epPropertyRegenTime = *(pen->PropertyForTypeAndID(CEntityProperty::EPT_INDEX, 21));		// Zone Flag
				INDEX iRegenSec = ENTITYPROPERTY( &*pen, epPropertyRegenTime.ep_slOffset, INDEX);

				strResult.PrintF("%d", iRegenSec);
				iFormat=PDF_INDEX;
			}
			break;
		}
// 강동민 수정 끝
	case COLUMN_RAIDOBJ:
		{
			if (pen->GetRaidObject())
			{
				strResult = CTString("RaidObject");
			}
			break;
		}
  case COLUMN_DISTANCE:
  {
    if( _penForDistanceSort != NULL)
    {
      FLOAT3D vSelectedOrigin = _penForDistanceSort->GetPlacement().pl_PositionVector;
      FLOAT3D fDistance = vOrigin-vSelectedOrigin;
      strResult.PrintF("%g", fDistance.Length());
      iFormat=PDF_FLOAT;
    }
    break;
  }
  case COLUMN_SPAWN_FLAGS:
  {
    strResult.PrintF("0x%08X", pen->GetSpawnFlags());
    break;
  }
  // entity properties
  default:
  {
    CDLLEntityClass *pdecDLLClass = pen->GetClass()->ec_pdecDLLClass;
    // for all classes in hierarchy of this entity
    INDEX iPropertyOrder=0;
    for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
    {
      // for all properties
      for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
      {
        CEntityProperty *pepProperty = &pdecDLLClass->dec_aepProperties[iProperty];
        if( pepProperty->ep_strName!=CTString(""))
        {
          if( iPropertyOrder==iColumn-COLUMN_PROPERTY_START)
          {
            strResult=GetPropertyValue(pen, pepProperty, iFormat);
            return strResult;
          }
          iPropertyOrder++;
        }
      }
    }
  }
  }
  return strResult;
}
/*
 * Prepare for projecting.
 */
void CPerspectiveProjection3D::Prepare(void)
{
  FLOATmatrix3D t3dObjectStretch;   // matrix for object stretch
  FLOATmatrix3D t3dObjectRotation;  // matrix for object angles

  // calc. matrices for viewer and object angles and stretch
  MakeRotationMatrixFast(
    t3dObjectRotation, pr_ObjectPlacement.pl_OrientationAngle);
  MakeInverseRotationMatrixFast(
    pr_ViewerRotationMatrix, pr_ViewerPlacement.pl_OrientationAngle);
  t3dObjectStretch.Diagonal(pr_ObjectStretch);
  pr_vViewerPosition = pr_ViewerPlacement.pl_PositionVector;
  BOOL bXInverted = pr_ObjectStretch(1)<0;
  BOOL bYInverted = pr_ObjectStretch(2)<0;
  BOOL bZInverted = pr_ObjectStretch(3)<0;

  pr_bInverted = (bXInverted != bYInverted) != bZInverted;

  // if the projection is mirrored
  if (pr_bMirror) {
    // reflect viewer
    ReflectPositionVectorByPlane(pr_plMirror, pr_vViewerPosition);
    ReflectRotationMatrixByPlane_rows(pr_plMirror, pr_ViewerRotationMatrix);
    // get mirror plane in view space
    pr_plMirrorView = pr_plMirror;
    pr_plMirrorView -= pr_vViewerPosition;
    pr_plMirrorView *= pr_ViewerRotationMatrix;
    // invert inversion
    pr_bInverted = !pr_bInverted;
  } else if (pr_bWarp) {
    // get mirror plane in view space
    pr_plMirrorView = pr_plMirror;
  }

  // if the object is face-forward
  if (pr_bFaceForward) {
    // if it turns only heading
    if (pr_bHalfFaceForward) {
      // get the y-axis vector of object rotation
      FLOAT3D vY(t3dObjectRotation(1,2), t3dObjectRotation(2,2), t3dObjectRotation(3,2));
      // find z axis of viewer
      FLOAT3D vViewerZ(
        pr_ViewerRotationMatrix(3,1),
        pr_ViewerRotationMatrix(3,2),
        pr_ViewerRotationMatrix(3,3));
      // calculate x and z axis vectors to make object head towards viewer
      FLOAT3D vX = (-vViewerZ)*vY;
      vX.Normalize();
      FLOAT3D vZ = vY*vX;
      // compose the rotation matrix back from those angles
      t3dObjectRotation(1,1) = vX(1); t3dObjectRotation(1,2) = vY(1); t3dObjectRotation(1,3) = vZ(1);
      t3dObjectRotation(2,1) = vX(2); t3dObjectRotation(2,2) = vY(2); t3dObjectRotation(2,3) = vZ(2);
      t3dObjectRotation(3,1) = vX(3); t3dObjectRotation(3,2) = vY(3); t3dObjectRotation(3,3) = vZ(3);

      // first apply object stretch then object rotation and then viewer rotation
      pr_mDirectionRotation = pr_ViewerRotationMatrix*t3dObjectRotation;
      pr_RotationMatrix = pr_mDirectionRotation*t3dObjectStretch;
    // if it is fully face forward
    } else {
      // apply object stretch and banking only
      FLOATmatrix3D mBanking;
      MakeRotationMatrixFast(
        mBanking, ANGLE3D(0,0, pr_ObjectPlacement.pl_OrientationAngle(3)));
      pr_mDirectionRotation = mBanking;
      pr_RotationMatrix = mBanking*t3dObjectStretch;
    }
  } else {
    // first apply object stretch then object rotation and then viewer rotation
    pr_mDirectionRotation = pr_ViewerRotationMatrix*t3dObjectRotation;
    pr_RotationMatrix = pr_mDirectionRotation*t3dObjectStretch;
  }

  // calc. offset of object from viewer
  pr_TranslationVector = pr_ObjectPlacement.pl_PositionVector - pr_vViewerPosition;
  // rotate offset only by viewer angles
  pr_TranslationVector = pr_TranslationVector*pr_ViewerRotationMatrix;
  // transform handle from object space to viewer space and add it to the offset
  pr_TranslationVector -= pr_vObjectHandle*pr_RotationMatrix;

  FLOAT2D vMin, vMax;
  // if using a shadow projection
  if (ppr_fMetersPerPixel>0) {
    // caclulate factors
    FLOAT fFactor = ppr_fViewerDistance/ppr_fMetersPerPixel;
    ppr_PerspectiveRatios(1) = -fFactor;
    ppr_PerspectiveRatios(2) = -fFactor;
    pr_ScreenCenter = -pr_ScreenBBox.Min();

    vMin = pr_ScreenBBox.Min();
    vMax = pr_ScreenBBox.Max();
  // if using normal projection
  } else if (ppr_boxSubScreen.IsEmpty()) {
    // calculate perspective constants
    FLOAT2D v2dScreenSize = pr_ScreenBBox.Size();
    pr_ScreenCenter = pr_ScreenBBox.Center();
    /* calculate FOVHeight from FOVWidth by formula:
       halfanglej = atan( tan(halfanglei)*jsize*aspect/isize ) */
    ANGLE aHalfI = ppr_FOVWidth/2;
    ANGLE aHalfJ = ATan(TanFast(aHalfI)*v2dScreenSize(2)*pr_AspectRatio/v2dScreenSize(1));

    /* calc. perspective ratios by formulae:
       xratio = isize/(2*tan(anglei/2))
       yratio = jsize/(2*tan(anglej/2))
      sign is negative since viewer is looking down the -z axis
    */
    ppr_PerspectiveRatios(1) = -v2dScreenSize(1)/(2.0f*TanFast(aHalfI))*pr_fViewStretch;
    ppr_PerspectiveRatios(2) = -v2dScreenSize(2)/(2.0f*TanFast(aHalfJ))*pr_fViewStretch;

    vMin = pr_ScreenBBox.Min()-pr_ScreenCenter;
    vMax = pr_ScreenBBox.Max()-pr_ScreenCenter;
  // if using sub-drawport projection
  } else {
    // calculate perspective constants
    FLOAT2D v2dScreenSize = pr_ScreenBBox.Size();
    pr_ScreenCenter = pr_ScreenBBox.Center();
    /* calculate FOVHeight from FOVWidth by formula:
       halfanglej = atan( tan(halfanglei)*jsize*aspect/isize ) */
    ANGLE aHalfI = ppr_FOVWidth/2;
    ANGLE aHalfJ = ATan(TanFast(aHalfI)*v2dScreenSize(2)*pr_AspectRatio/v2dScreenSize(1));

    /* calc. perspective ratios by formulae:
       xratio = isize/(2*tan(anglei/2))
       yratio = jsize/(2*tan(anglej/2))
      sign is negative since viewer is looking down the -z axis
    */
    ppr_PerspectiveRatios(1) = -v2dScreenSize(1)/(2.0f*TanFast(aHalfI))*pr_fViewStretch;
    ppr_PerspectiveRatios(2) = -v2dScreenSize(2)/(2.0f*TanFast(aHalfJ))*pr_fViewStretch;

    vMin = ppr_boxSubScreen.Min()-pr_ScreenCenter;
    vMax = ppr_boxSubScreen.Max()-pr_ScreenCenter;

    pr_ScreenCenter -= ppr_boxSubScreen.Min();
  }
  // find factors for left, right, up and down clipping

  FLOAT fMinI = vMin(1); FLOAT fMinJ = vMin(2);
  FLOAT fMaxI = vMax(1); FLOAT fMaxJ = vMax(2);
  FLOAT fRatioX = ppr_PerspectiveRatios(1);
  FLOAT fRatioY = ppr_PerspectiveRatios(2);

#define MySgn(x) ((x)>=0?1:-1)

  FLOAT fDZ = -1.0f;
  FLOAT fDXL = fDZ*fMinI/fRatioX;
  FLOAT fDXR = fDZ*fMaxI/fRatioX;
  FLOAT fDYU = -fDZ*fMinJ/fRatioY;
  FLOAT fDYD = -fDZ*fMaxJ/fRatioY;

  FLOAT fNLX = -fDZ;
  FLOAT fNLZ = +fDXL;
  FLOAT fOoNL = 1.0f/(FLOAT)sqrt(fNLX*fNLX+fNLZ*fNLZ);
  fNLX*=fOoNL; fNLZ*=fOoNL;

  FLOAT fNRX = +fDZ;
  FLOAT fNRZ = -fDXR;
  FLOAT fOoNR = 1.0f/(FLOAT)sqrt(fNRX*fNRX+fNRZ*fNRZ);
  fNRX*=fOoNR; fNRZ*=fOoNR;

  FLOAT fNDY = -fDZ;
  FLOAT fNDZ = +fDYD;
  FLOAT fOoND = 1.0f/(FLOAT)sqrt(fNDY*fNDY+fNDZ*fNDZ);
  fNDY*=fOoND; fNDZ*=fOoND;

  FLOAT fNUY = +fDZ;
  FLOAT fNUZ = -fDYU;
  FLOAT fOoNU = 1.0f/(FLOAT)sqrt(fNUY*fNUY+fNUZ*fNUZ);
  fNUY*=fOoNU; fNUZ*=fOoNU;

  // make clip planes
  pr_plClipU = FLOATplane3D(FLOAT3D(   0,fNUY,fNUZ), 0.0f);
  pr_plClipD = FLOATplane3D(FLOAT3D(   0,fNDY,fNDZ), 0.0f);
  pr_plClipL = FLOATplane3D(FLOAT3D(fNLX,   0,fNLZ), 0.0f);
  pr_plClipR = FLOATplane3D(FLOAT3D(fNRX,   0,fNRZ), 0.0f);

  // mark as prepared
  pr_Prepared = TRUE;

  // calculate constant value used for calculating z-buffer k-value from vertex's z coordinate
  pr_fDepthBufferFactor = -pr_NearClipDistance;
  pr_fDepthBufferMul = pr_fDepthBufferFar-pr_fDepthBufferNear;
  pr_fDepthBufferAdd = pr_fDepthBufferNear;

  // calculate ratio for mip factor calculation
  ppr_fMipRatio = pr_ScreenBBox.Size()(1)/(ppr_PerspectiveRatios(1)*640.0f);
}
CTString GetItemValue(CEntity *pen, INDEX iColumn, INDEX &iFormat)
{
  ASSERT(pen!=NULL);
  if(pen==NULL) return CTString("");
  CEntityClass *pecEntityClass = pen->GetClass();
  CDLLEntityClass *pdllecDllEntityClass = pecEntityClass->ec_pdecDLLClass;
  FLOAT3D vOrigin = pen->GetPlacement().pl_PositionVector;
  ANGLE3D vAngles = pen->GetPlacement().pl_OrientationAngle;
  CTString strResult="";
  iFormat=PDF_STRING;
  
  switch( iColumn)
  {
  case COLUMN_INDEX:
  {
    INDEX iIndex=dcEntities.GetIndex(pen);
    strResult.PrintF("%d", FLOAT(iIndex));
    iFormat=PDF_INDEX;
    break;
  }
  case COLUMN_CLASS:
  {
    strResult=pdllecDllEntityClass->dec_strName;
    break;
  }
  case COLUMN_NAME:
  {
    strResult=pen->GetName();
    break;
  }
  case COLUMN_DESCRIPTION:
  {
    strResult=pen->GetDescription();
    break;
  }
  case COLUMN_SECTOR_NAME:
  {
    CBrushSector *pbsc = pen->GetFirstSectorWithName();
    if( pbsc!=NULL)
    {
      strResult=pbsc->bsc_strName;
    }
    break;
  }
  case COLUMN_X:
  {
    strResult.PrintF("%g", vOrigin(1));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_Y:
  {
    strResult.PrintF("%g", vOrigin(2));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_Z:
  {
    strResult.PrintF("%g", vOrigin(3));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_H:
  {
    strResult.PrintF("%g", vAngles(1));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_P:
  {
    strResult.PrintF("%g", vAngles(2));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_B:
  {
    strResult.PrintF("%g", vAngles(3));
    iFormat=PDF_FLOAT;
    break;
  }
  case COLUMN_DISTANCE:
  {
    if( _penForDistanceSort != NULL)
    {
      FLOAT3D vSelectedOrigin = _penForDistanceSort->GetPlacement().pl_PositionVector;
      FLOAT3D fDistance = vOrigin-vSelectedOrigin;
      strResult.PrintF("%g", fDistance.Length());
      iFormat=PDF_FLOAT;
    }
    break;
  }
  case COLUMN_SPAWN_FLAGS:
  {
    strResult.PrintF("0x%08X", pen->GetSpawnFlags());
    break;
  }
  // entity properties
  default:
  {
    CDLLEntityClass *pdecDLLClass = pen->GetClass()->ec_pdecDLLClass;
    // for all classes in hierarchy of this entity
    INDEX iPropertyOrder=0;
    for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
    {
      // for all properties
      for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
      {
        CEntityProperty *pepProperty = &pdecDLLClass->dec_aepProperties[iProperty];
        if( pepProperty->ep_strName!=CTString(""))
        {
          if( iPropertyOrder==iColumn-COLUMN_PROPERTY_START)
          {
            strResult=GetPropertyValue(pen, pepProperty, iFormat);
            return strResult;
          }
          iPropertyOrder++;
        }
      }
    }
  }
  }
  return strResult;
}