123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- /* Copyright (c) 2002-2012 Croteam Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as published by
- the Free Software Foundation
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
- #include "StdAfx.h"
- #include "WorldEditor.h"
-
- /////////////////////////////////////////////////////////////////////
- // CSlaveViewer
- #define MIN_TARGET_DISTANCE 0.1f
- #define MAX_TARGET_DISTANCE 640000.0f
- extern FLOAT wed_fFrontClipDistance;
- /*
- * Default constructor
- */
- CMasterViewer::CMasterViewer(void)
- {
- // set initial viewer variables, viewing tovards origin from ten meters distance
- mv_plViewer.pl_PositionVector = FLOAT3D(3.0f, 4.0f, 10.0f);
- mv_plViewer.pl_OrientationAngle = ANGLE3D(AngleDeg( 20.0f), AngleDeg( -20.0f), 0);
- mv_fTargetDistance = 10.0f; // this must never be very small!
- }
- // get placement of the virtual target
- CPlacement3D CMasterViewer::GetTargetPlacement(void) const
- {
- CPlacement3D plTarget;
- // copy viewer to target
- plTarget = mv_plViewer;
- // get the direction vector of viewer's sight
- FLOAT3D vDirection;
- AnglesToDirectionVector(mv_plViewer.pl_OrientationAngle, vDirection);
- // offset the target placement by target distance along the vector
- plTarget.pl_PositionVector += vDirection*mv_fTargetDistance;
- // return the target placement
- return plTarget;
- }
- // set placement of the virtual target
- void CMasterViewer::SetTargetPlacement(FLOAT3D f3dTarget)
- {
- CPlacement3D plViewer;
- // copy the viewer's orientation, it will stay the same
- plViewer.pl_OrientationAngle = mv_plViewer.pl_OrientationAngle;
- // set position vector of new target
- plViewer.pl_PositionVector = f3dTarget;
- // translate viewer back from target for their distance
- plViewer.Translate_OwnSystem( FLOAT3D( 0.0f, 0.0f, mv_fTargetDistance) );
- // set new viewer's pacement
- mv_plViewer = plViewer;
- }
- /*
- * Convert from slave.
- */
- void CMasterViewer::operator=(const CSlaveViewer &svSlave)
- {
- // copy target distance
- mv_fTargetDistance = svSlave.sv_fTargetDistance;
- // if is perspective
- if( svSlave.IsPerspective())
- {
- // copy viewer placement
- mv_plViewer = svSlave.sv_plViewer;
- }
- // if is isometric
- else
- {
- // copy slave viewer position to master viewer position
- mv_plViewer.pl_PositionVector = svSlave.sv_plViewer.pl_PositionVector;
- // get the ray of the slave viewing direction
- FLOAT3D vSlaveDirection;
- AnglesToDirectionVector(svSlave.sv_plViewer.pl_OrientationAngle, vSlaveDirection);
- // offset the viewer forward by target distance along the slave direction vector
- mv_plViewer.pl_PositionVector += vSlaveDirection*mv_fTargetDistance;
- // get the ray of the master viewing direction
- FLOAT3D vMasterDirection;
- AnglesToDirectionVector(mv_plViewer.pl_OrientationAngle, vMasterDirection);
- // offset the viewer backward by target distance along the slave direction vector
- mv_plViewer.pl_PositionVector -= vMasterDirection*mv_fTargetDistance;
- }
- }
- /////////////////////////////////////////////////////////////////////
- // CSlaveViewer
- // get orientation angles for type of isometric viewer
- ANGLE3D CSlaveViewer::GetAngleForIsometricType(void) const
- {
- // depending on the projection type, return angles
- switch (sv_ProjectionType) {
- case PT_ISOMETRIC_FRONT:
- return ANGLE3D((ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 );
- case PT_ISOMETRIC_RIGHT:
- return ANGLE3D((ANGLE)ANGLE_90 ,(ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 );
- case PT_ISOMETRIC_TOP:
- return ANGLE3D((ANGLE)ANGLE_0 ,(ANGLE)ANGLE_270,(ANGLE)ANGLE_0 );
- case PT_ISOMETRIC_BACK:
- return ANGLE3D((ANGLE)ANGLE_180,(ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 );
- case PT_ISOMETRIC_LEFT:
- return ANGLE3D((ANGLE)ANGLE_270,(ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 );
- case PT_ISOMETRIC_BOTTOM:
- return ANGLE3D((ANGLE)ANGLE_0 ,(ANGLE)ANGLE_90 ,(ANGLE)ANGLE_0 );
- default:
- ASSERT(FALSE);
- return ANGLE3D((ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 );
- }
- }
-
- /*
- * Get zoom factor for the viewer.
- */
- FLOAT CSlaveViewer::GetZoomFactor(void)
- {
- // calculate the zoom factor that as ratio of size in pixels and size in meters
- // for target object
- FLOAT fScreenX = (float)sv_pdpDrawPort->GetWidth();
- ANGLE aHalfI = AngleDeg(90.0f)/2; // assume FOV of 90 degrees for perspective
- FLOAT fPerspectiveRatio = fScreenX/(2.0f*Tan(aHalfI));
- FLOAT fZoomFactor = fPerspectiveRatio/sv_fTargetDistance;
- ASSERT( fZoomFactor > 0);
- return fZoomFactor;
- }
- /*
- * Get distance for wanted zoom factor for the viewer.
- */
- FLOAT CSlaveViewer::GetDistanceForZoom(FLOAT fZoom)
- {
- // calculate the zoom factor that as ratio of size in pixels and size in meters
- // for target object
- FLOAT fScreenX = (float)sv_pdpDrawPort->GetWidth();
- ANGLE aHalfI = AngleDeg(90.0f)/2; // assume FOV of 90 degrees for perspective
- FLOAT fPerspectiveRatio = fScreenX/(2.0f*Tan(aHalfI));
- FLOAT fDistance = fPerspectiveRatio / fZoom;
- ASSERT( fDistance > 0);
- return fDistance;
- }
- // get placement of the virtual target
- CPlacement3D CSlaveViewer::GetTargetPlacement(void) const
- {
- CPlacement3D plTarget;
- // copy viewer to target
- plTarget = sv_plViewer;
- // get the direction vector of viewer's sight
- FLOAT3D vDirection;
- AnglesToDirectionVector(sv_plViewer.pl_OrientationAngle, vDirection);
- // offset the target placement by target distance along the vector
- plTarget.pl_PositionVector += vDirection*sv_fTargetDistance;
- // return the target placement
- return plTarget;
- }
- /*
- * Default constructor
- */
- CSlaveViewer::CSlaveViewer(const CMasterViewer &mvMaster,
- enum ProjectionType ptProjectionType,
- const CPlacement3D &plGrid,
- CDrawPort *pdpDrawPort)
- {
- // remember the drawport
- sv_pdpDrawPort = pdpDrawPort;
- // set projection type
- sv_ProjectionType = ptProjectionType;
- // set grid placement
- sv_plGrid = plGrid;
- // copy target distance
- sv_fTargetDistance = mvMaster.mv_fTargetDistance;
- // if is perspective
- if( IsPerspective())
- {
- // copy viewer placement
- sv_plViewer = mvMaster.mv_plViewer;
- }
- // if is isometric
- else
- {
- // copy target position to slave viewer position
- sv_plViewer.pl_PositionVector = mvMaster.GetTargetPlacement().pl_PositionVector;
- // get the orientation depending on the isometry type
- sv_plViewer.pl_OrientationAngle = GetAngleForIsometricType();
- // transform to grid system
- sv_plViewer.AbsoluteToRelative(sv_plGrid);
- // get the ray of the viewing direction
- FLOAT3D vDirection;
- AnglesToDirectionVector(sv_plViewer.pl_OrientationAngle, vDirection);
- // offset the viewer backward by target distance along the vector
- sv_plViewer.pl_PositionVector -= vDirection*sv_fTargetDistance;
- // transform back from grid system
- sv_plViewer.RelativeToAbsolute(sv_plGrid);
- }
- }
- /*
- * create a perspective projection for this viewer
- */
- void CSlaveViewer::MakePerspectiveProjection(CPerspectiveProjection3D &prPerspectiveProjection)
- {
- // if is perspective
- ASSERT( IsPerspective());
- // init projection parameters
- prPerspectiveProjection.FOVL() = AngleDeg(90.0f);
- prPerspectiveProjection.ScreenBBoxL() = FLOATaabbox2D(
- FLOAT2D(0.0f, 0.0f),
- FLOAT2D((float)sv_pdpDrawPort->GetWidth(), (float)sv_pdpDrawPort->GetHeight())
- );
- wed_fFrontClipDistance = Clamp( wed_fFrontClipDistance, 0.02f, 2.00f);
- prPerspectiveProjection.FrontClipDistanceL() = wed_fFrontClipDistance;
- prPerspectiveProjection.AspectRatioL() = 1.0f;
- prPerspectiveProjection.ObjectStretchL() = FLOAT3D(1.0f, 1.0f, 1.0f);
- // set up viewer position and placement
- prPerspectiveProjection.ViewerPlacementL() = sv_plViewer;
- prPerspectiveProjection.ObjectPlacementL().pl_PositionVector = FLOAT3D(0.0f, 0.0f, 0.0f);
- prPerspectiveProjection.ObjectPlacementL().pl_OrientationAngle = ANGLE3D(0, 0, 0);
- }
- /*
- * create a projection for this viewer
- */
- void CSlaveViewer::MakeProjection(CAnyProjection3D &prProjection)
- {
- // if is perspective
- if( IsPerspective()) {
- // use perspective projection
- CPerspectiveProjection3D prPerspectiveProjection;
- // make perspective projection
- MakePerspectiveProjection( prPerspectiveProjection);
- // return the result
- prProjection = prPerspectiveProjection;
- // if is isometric
- } else {
- // use isometric projection
- CIsometricProjection3D prIsometricProjection;
-
- // init projection parameters
- prIsometricProjection.ZoomFactorL() = GetZoomFactor();
- prIsometricProjection.ScreenBBoxL() = FLOATaabbox2D(
- FLOAT2D(0.0f, 0.0f),
- FLOAT2D((float)sv_pdpDrawPort->GetWidth(), (float)sv_pdpDrawPort->GetHeight())
- );
- wed_fFrontClipDistance = Clamp( wed_fFrontClipDistance, 0.02f, 2.00f);
- prIsometricProjection.AspectRatioL() = 1.0f;
- prIsometricProjection.FrontClipDistanceL() = wed_fFrontClipDistance;
- prIsometricProjection.ObjectStretchL() = FLOAT3D(1.0f, 1.0f, 1.0f);
- // set up viewer position and placement
- prIsometricProjection.ViewerPlacementL() = sv_plViewer;
- prIsometricProjection.ObjectPlacementL().pl_PositionVector = FLOAT3D(0.0f, 0.0f, 0.0f);
- prIsometricProjection.ObjectPlacementL().pl_OrientationAngle = ANGLE3D(0, 0, 0);
- // return the result
- prProjection = prIsometricProjection;
- }
- }
- /*
- * Translate slave viewer in his own system
- */
- void CSlaveViewer::Translate_OwnSystem( PIX pixDI, PIX pixDJ, PIX pixDK)
- {
- FLOAT fZoom = GetZoomFactor();
- sv_fTargetDistance += pixDK/fZoom;
- if( sv_fTargetDistance < MIN_TARGET_DISTANCE)
- {
- sv_fTargetDistance = MIN_TARGET_DISTANCE;
- return;
- }
- if( sv_fTargetDistance > MAX_TARGET_DISTANCE)
- {
- sv_fTargetDistance = MAX_TARGET_DISTANCE;
- return;
- }
- ASSERT( sv_fTargetDistance > 0);
- sv_plViewer.Translate_OwnSystem( FLOAT3D(-pixDI/fZoom, pixDJ/fZoom, pixDK/fZoom));
- }
- /*
- * Translate slave viewer without stretching zoom factor
- */
- void CSlaveViewer::Translate_Local_OwnSystem(FLOAT fdX, FLOAT fdY, FLOAT fdZ)
- {
- sv_plViewer.Translate_OwnSystem( FLOAT3D(fdX, fdY, fdZ));
- }
- /*
- * Scales target distance using given factor
- */
- void CSlaveViewer::ScaleTargetDistance( FLOAT fFactor)
- {
- // if very close to the target, and trying to go even closer or
- // if very far away and trying to move further away
- if( (sv_fTargetDistance <MIN_TARGET_DISTANCE && fFactor<1.0f) ||
- (sv_fTargetDistance >MAX_TARGET_DISTANCE && fFactor>1.0f) )
- {
- // don't do anything
- return;
- }
- // change along z axis
- FLOAT dz = sv_fTargetDistance * fFactor;
- sv_plViewer.Translate_OwnSystem( FLOAT3D( 0.0f, 0.0f, dz));
- sv_fTargetDistance += dz;
- }
- /*
- * Rotate slave viewer arround target using HPB method
- */
- void CSlaveViewer::Rotate_HPB( PIX pixDI, PIX pixDJ, PIX pixDK)
- {
- // if is perspective
- if( IsPerspective())
- {
- // get target placement
- CPlacement3D plTarget = GetTargetPlacement();
- // project viewer placement to the target placement
- sv_plViewer.AbsoluteToRelative(plTarget);
- // rotate the target
- plTarget.Rotate_HPB( ANGLE3D( AngleDeg((FLOAT)-pixDI),
- AngleDeg((FLOAT)-pixDJ),
- AngleDeg((FLOAT)-pixDK)));
- // project viewer placement back from the target placement
- sv_plViewer.RelativeToAbsolute(plTarget);
- }
- // if is isometric
- else
- {
- // can't rotate isometric projections
- }
- }
- /*
- * Rotate slave viewer in his own system using HPB method
- */
- void CSlaveViewer::Rotate_Local_HPB( FLOAT fdX, FLOAT fdY, FLOAT fdZ)
- {
- // if is perspective
- if( IsPerspective())
- {
- // rotate the viewer
- sv_plViewer.Rotate_HPB( ANGLE3D( AngleDeg(-fdX), AngleDeg(-fdY), AngleDeg(-fdZ)));
- }
- // if is isometric
- else
- {
- // can't rotate isometric projections
- }
- }
- // translate a placement in given system
- void CSlaveViewer::TranslatePlacement_OtherSystem(CPlacement3D &plToTranslate,
- CPlacement3D &plOtherSystem,
- PIX pixDI, PIX pixDJ, PIX pixDK)
- {
- FLOAT fZoom = GetZoomFactor();
- // project the placement to the viewer's system
- plToTranslate.AbsoluteToRelative(sv_plViewer);
- // project the placement to the given system
- plToTranslate.AbsoluteToRelative(plOtherSystem);
- // translate it
- plToTranslate.Translate_AbsoluteSystem( FLOAT3D(pixDI/fZoom, -pixDJ/fZoom, pixDK/fZoom));
- // project the placement back from given system
- plToTranslate.RelativeToAbsolute(plOtherSystem);
- // project the placement back from viewer's system
- plToTranslate.RelativeToAbsolute(sv_plViewer);
- }
- // translate a placement in viewer's system
- void CSlaveViewer::TranslatePlacement_OwnSystem(CPlacement3D &plToTranslate,
- PIX pixDI, PIX pixDJ, PIX pixDK)
- {
- FLOAT fZoom = GetZoomFactor();
- // project the placement to the viewer's system
- plToTranslate.AbsoluteToRelative(sv_plViewer);
- // translate it
- plToTranslate.Translate_AbsoluteSystem( FLOAT3D(pixDI/fZoom, -pixDJ/fZoom, pixDK/fZoom));
- // project the placement back from viewer's system
- plToTranslate.RelativeToAbsolute(sv_plViewer);
- }
- // convert offset from pixels to meters
- FLOAT CSlaveViewer::PixelsToMeters(PIX pix)
- {
- FLOAT fZoom = GetZoomFactor();
- return pix/fZoom;
- }
- // translate a placement in viewer's system
- void CSlaveViewer::RotatePlacement_HPB(CPlacement3D &plToRotate,
- PIX pixDI, PIX pixDJ, PIX pixDK)
- {
- // project the placement to the viewer's system
- plToRotate.AbsoluteToRelative(sv_plViewer);
- // rotate it
- plToRotate.Rotate_HPB( ANGLE3D( AngleDeg((FLOAT)-pixDI),
- AngleDeg((FLOAT)-pixDJ),
- AngleDeg((FLOAT)-pixDK)));
- // project the placement back from viewer's system
- plToRotate.RelativeToAbsolute(sv_plViewer);
- }
- // translate a placement in viewer's system
- void CSlaveViewer::RotatePlacement_TrackBall(CPlacement3D &plToRotate,
- PIX pixDI, PIX pixDJ, PIX pixDK)
- {
- // if viewer is perspective
- if( IsPerspective()) {
- // project the placement to the viewer's system
- plToRotate.AbsoluteToRelative(sv_plViewer);
- // rotate it
- plToRotate.Rotate_TrackBall( ANGLE3D( AngleDeg((FLOAT)-pixDI),
- AngleDeg((FLOAT)-pixDJ),
- AngleDeg((FLOAT)-pixDK)));
- // project the placement back from viewer's system
- plToRotate.RelativeToAbsolute(sv_plViewer);
- // if viewer is isometric
- } else {
- // project the placement to the viewer's system
- plToRotate.AbsoluteToRelative(sv_plViewer);
- // rotate it only around banking axis
- plToRotate.Rotate_TrackBall( ANGLE3D( 0,0, AngleDeg((FLOAT)-pixDI)));
- // project the placement back from viewer's system
- plToRotate.RelativeToAbsolute(sv_plViewer);
- }
- }
|