mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-11-24 19:30:26 +01:00
466 lines
15 KiB
C++
466 lines
15 KiB
C++
/* 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);
|
|
}
|
|
}
|