/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: b3dtrans.cxx,v $ * * $Revision: 1.5 $ * * last change: $Author: rt $ $Date: 2005-09-09 02:27:50 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ************************************************************************/ #ifndef _B3D_B3DTRANS_HXX #include "b3dtrans.hxx" #endif #ifndef _B3D_BASE3D_HXX #include "base3d.hxx" #endif #ifndef _B3D_VOLUM_HXX #include "b3dvolum.hxx" #endif /************************************************************************* |* |* Transformationen fuer alle 3D Ausgaben |* \************************************************************************/ B3dTransformationSet::B3dTransformationSet() { Reset(); } /************************************************************************* |* |* Reset der Werte |* \************************************************************************/ void B3dTransformationSet::Reset() { // Matritzen auf Einheitsmatritzen aObjectTrans.Identity(); PostSetObjectTrans(); aOrientation.Orientation(); PostSetOrientation(); aTexture.Identity(); fLeftBound = fBottomBound = -1.0; fRightBound = fTopBound = 1.0; fNearBound = 0.001; fFarBound = 1.001; eRatio = Base3DRatioGrow; fRatio = 0.0; aViewportRectangle = Rectangle(-1, -1, 2, 2); aVisibleRectangle = aViewportRectangle; bPerspective = TRUE; bProjectionValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; CalcViewport(); } /************************************************************************* |* |* Objekttransformation |* \************************************************************************/ void B3dTransformationSet::SetObjectTrans(Matrix4D& rObj) { aObjectTrans = rObj; bObjectToDeviceValid = FALSE; bInvTransObjectToEyeValid = FALSE; PostSetObjectTrans(); } void B3dTransformationSet::PostSetObjectTrans() { // Zuweisen und Inverse bestimmen aInvObjectTrans = aObjectTrans; aInvObjectTrans.Invert(); } /************************************************************************* |* |* Orientierungstransformation |* \************************************************************************/ #if ! defined ICC && ! defined __GNUC__ void B3dTransformationSet::SetOrientation( Vector3D& aVRP, Vector3D& aVPN, Vector3D& aVUP) #else void B3dTransformationSet::SetOrientation( Vector3D aVRP, Vector3D aVPN, Vector3D aVUP) #endif { aOrientation.Identity(); aOrientation.Orientation(Point4D(aVRP), aVPN, aVUP); bInvTransObjectToEyeValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; PostSetOrientation(); } void B3dTransformationSet::SetOrientation(Matrix4D& mOrient) { aOrientation = mOrient; bInvTransObjectToEyeValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; PostSetOrientation(); } void B3dTransformationSet::PostSetOrientation() { // Zuweisen und Inverse bestimmen aInvOrientation = aOrientation; aInvOrientation.Invert(); } /************************************************************************* |* |* Projektionstransformation |* \************************************************************************/ void B3dTransformationSet::SetProjection(Matrix4D& mProject) { aProjection = mProject; PostSetProjection(); } const Matrix4D& B3dTransformationSet::GetProjection() { if(!bProjectionValid) CalcViewport(); return aProjection; } const Matrix4D& B3dTransformationSet::GetInvProjection() { if(!bProjectionValid) CalcViewport(); return aInvProjection; } void B3dTransformationSet::PostSetProjection() { // Zuweisen und Inverse bestimmen aInvProjection = GetProjection(); aInvProjection.Invert(); // Abhaengige Matritzen invalidieren bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; } /************************************************************************* |* |* Texturtransformation |* \************************************************************************/ void B3dTransformationSet::SetTexture(Matrix4D& rTxt) { aTexture = rTxt; PostSetTexture(); } void B3dTransformationSet::PostSetTexture() { } /************************************************************************* |* |* Viewport-Transformation |* \************************************************************************/ void B3dTransformationSet::CalcViewport() { // Faktoren fuer die Projektion double fLeft = fLeftBound; double fRight = fRightBound; double fBottom = fBottomBound; double fTop = fTopBound; // Soll das Seitenverhaeltnis Beachtung finden? // Falls ja, Bereich der Projektion an Seitenverhaeltnis anpassen if(GetRatio() != 0.0) { // Berechne aktuelles Seitenverhaeltnis der Bounds double fBoundWidth = (double)(aViewportRectangle.GetWidth() + 1); double fBoundHeight = (double)(aViewportRectangle.GetHeight() + 1); double fActRatio = 1; double fFactor; if(fBoundWidth != 0.0) fActRatio = fBoundHeight / fBoundWidth; // FIXME else in this case has a lot of problems, should this return. switch(eRatio) { case Base3DRatioShrink : { // Kleineren Teil vergroessern if(fActRatio > fRatio) { // X vergroessern fFactor = 1.0 / fActRatio; fRight *= fFactor; fLeft *= fFactor; } else { // Y vergroessern fFactor = fActRatio; fTop *= fFactor; fBottom *= fFactor; } break; } case Base3DRatioGrow : { // GroesserenTeil verkleinern if(fActRatio > fRatio) { // Y verkleinern fFactor = fActRatio; fTop *= fFactor; fBottom *= fFactor; } else { // X verkleinern fFactor = 1.0 / fActRatio; fRight *= fFactor; fLeft *= fFactor; } break; } case Base3DRatioMiddle : { // Mitteln fFactor = ((1.0 / fActRatio) + 1.0) / 2.0; fRight *= fFactor; fLeft *= fFactor; fFactor = (fActRatio + 1.0) / 2.0; fTop *= fFactor; fBottom *= fFactor; break; } } } // Ueberschneiden sich Darstellungsflaeche und Objektflaeche? aSetBound = aViewportRectangle; // Mit den neuen Werten Projektion und ViewPort setzen Matrix4D aNewProjection; // #i36281# // OpenGL needs a little more rough additional size to not let // the front face vanish. Changed from SMALL_DVALUE to 0.000001, // which is 1/10000th, comared with 1/tenth of a million from SMALL_DVALUE. const double fDistPart((fFarBound - fNearBound) * 0.0001); // Near, Far etwas grosszuegiger setzen, um falsches, // zu kritisches clippen zu verhindern if(bPerspective) aNewProjection.Frustum(fLeft, fRight, fBottom, fTop, fNearBound - fDistPart, fFarBound + fDistPart); else aNewProjection.Ortho(fLeft, fRight, fBottom, fTop, fNearBound - fDistPart, fFarBound + fDistPart); // jetzt schon auf gueltig setzen um Endlosschleife zu vermeiden bProjectionValid = TRUE; // Neue Projektion setzen SetProjection(aNewProjection); // fill parameters for ViewportTransformation // Translation aTranslate[0] = (double)aSetBound.Left() + ((aSetBound.GetWidth() - 1L) / 2.0); aTranslate[1] = (double)aSetBound.Top() + ((aSetBound.GetHeight() - 1L) / 2.0); aTranslate[2] = ZBUFFER_DEPTH_RANGE / 2.0; // Skalierung aScale[0] = (aSetBound.GetWidth() - 1L) / 2.0; aScale[1] = (aSetBound.GetHeight() - 1L) / -2.0; aScale[2] = ZBUFFER_DEPTH_RANGE / 2.0; // Auf Veraenderung des ViewPorts reagieren PostSetViewport(); } void B3dTransformationSet::SetRatio(double fNew) { if(fRatio != fNew) { fRatio = fNew; bProjectionValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; } } void B3dTransformationSet::SetRatioMode(Base3DRatio eNew) { if(eRatio != eNew) { eRatio = eNew; bProjectionValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; } } void B3dTransformationSet::SetDeviceRectangle(double fL, double fR, double fB, double fT, BOOL bBroadCastChange) { if(fL != fLeftBound || fR != fRightBound || fB != fBottomBound || fT != fTopBound) { fLeftBound = fL; fRightBound = fR; fBottomBound = fB; fTopBound = fT; bProjectionValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; // Aenderung bekanntmachen if(bBroadCastChange) DeviceRectangleChange(); } } void B3dTransformationSet::SetDeviceVolume(const B3dVolume& rVol, BOOL bBroadCastChange) { SetDeviceRectangle(rVol.MinVec().X(), rVol.MaxVec().X(), rVol.MinVec().Y(), rVol.MaxVec().Y(), bBroadCastChange); SetFrontClippingPlane(rVol.MinVec().Z()); SetBackClippingPlane(rVol.MaxVec().Z()); } void B3dTransformationSet::DeviceRectangleChange() { } void B3dTransformationSet::GetDeviceRectangle(double &fL, double &fR, double& fB, double& fT) { fL = fLeftBound; fR = fRightBound; fB = fBottomBound; fT = fTopBound; bProjectionValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; } B3dVolume B3dTransformationSet::GetDeviceVolume() { B3dVolume aRet; aRet.MinVec() = Vector3D(fLeftBound, fBottomBound, fNearBound); aRet.MaxVec() = Vector3D(fRightBound, fTopBound, fFarBound); return aRet; } void B3dTransformationSet::SetFrontClippingPlane(double fF) { if(fNearBound != fF) { fNearBound = fF; bProjectionValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; } } void B3dTransformationSet::SetBackClippingPlane(double fB) { if(fFarBound != fB) { fFarBound = fB; bProjectionValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; } } void B3dTransformationSet::SetPerspective(BOOL bNew) { if(bPerspective != bNew) { bPerspective = bNew; bProjectionValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; } } void B3dTransformationSet::SetViewportRectangle(Rectangle& rRect, Rectangle& rVisible) { if(rRect != aViewportRectangle || rVisible != aVisibleRectangle) { aViewportRectangle = rRect; aVisibleRectangle = rVisible; bProjectionValid = FALSE; bObjectToDeviceValid = FALSE; bWorldToViewValid = FALSE; } } void B3dTransformationSet::PostSetViewport() { } const Rectangle& B3dTransformationSet::GetLogicalViewportBounds() { if(!bProjectionValid) CalcViewport(); return aSetBound; } const Vector3D& B3dTransformationSet::GetScale() { if(!bProjectionValid) CalcViewport(); return aScale; } const Vector3D& B3dTransformationSet::GetTranslate() { if(!bProjectionValid) CalcViewport(); return aTranslate; } /************************************************************************* |* |* Hilfsmatrixberechnungsroutinen |* \************************************************************************/ void B3dTransformationSet::CalcMatObjectToDevice() { // ObjectToDevice berechnen (Orientation * Projection * Object) aObjectToDevice = aObjectTrans; aObjectToDevice *= aOrientation; aObjectToDevice *= GetProjection(); // auf gueltig setzen bObjectToDeviceValid = TRUE; } const Matrix4D& B3dTransformationSet::GetObjectToDevice() { if(!bObjectToDeviceValid) CalcMatObjectToDevice(); return aObjectToDevice; } void B3dTransformationSet::CalcMatInvTransObjectToEye() { aInvTransObjectToEye = aObjectTrans; aInvTransObjectToEye *= aOrientation; aInvTransObjectToEye.Invert(); aInvTransObjectToEye.Transpose(); // eventuelle Translationen rausschmeissen, da diese // Matrix nur zur Transformation von Vektoren gedacht ist aInvTransObjectToEye[3] = Point4D(0.0, 0.0, 0.0, 1.0); // auf gueltig setzen bInvTransObjectToEyeValid = TRUE; } const Matrix4D& B3dTransformationSet::GetInvTransObjectToEye() { if(!bInvTransObjectToEyeValid) CalcMatInvTransObjectToEye(); return aInvTransObjectToEye; } Matrix4D B3dTransformationSet::GetMatFromObjectToView() { Matrix4D aFromObjectToView = GetObjectToDevice(); aFromObjectToView.Scale(GetScale()); aFromObjectToView.Translate(GetTranslate()); return aFromObjectToView; } void B3dTransformationSet::CalcMatFromWorldToView() { aMatFromWorldToView = aOrientation; aMatFromWorldToView *= GetProjection(); aMatFromWorldToView.Scale(GetScale()); aMatFromWorldToView.Translate(GetTranslate()); aInvMatFromWorldToView = aMatFromWorldToView; aInvMatFromWorldToView.Invert(); // gueltig setzen bWorldToViewValid = TRUE; } const Matrix4D& B3dTransformationSet::GetMatFromWorldToView() { if(!bWorldToViewValid) CalcMatFromWorldToView(); return aMatFromWorldToView; } const Matrix4D& B3dTransformationSet::GetInvMatFromWorldToView() { if(!bWorldToViewValid) CalcMatFromWorldToView(); return aInvMatFromWorldToView; } /************************************************************************* |* |* Direkter Zugriff auf verschiedene Transformationen |* \************************************************************************/ const Vector3D B3dTransformationSet::WorldToEyeCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetOrientation(); return aVec; } const Vector3D B3dTransformationSet::EyeToWorldCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetInvOrientation(); return aVec; } const Vector3D B3dTransformationSet::EyeToViewCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetProjection(); aVec *= GetScale(); aVec += GetTranslate(); return aVec; } const Vector3D B3dTransformationSet::ViewToEyeCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec -= GetTranslate(); aVec = aVec / GetScale(); aVec *= GetInvProjection(); return aVec; } const Vector3D B3dTransformationSet::WorldToViewCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetMatFromWorldToView(); return aVec; } const Vector3D B3dTransformationSet::ViewToWorldCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetInvMatFromWorldToView(); return aVec; } const Vector3D B3dTransformationSet::DeviceToViewCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetScale(); aVec += GetTranslate(); return aVec; } const Vector3D B3dTransformationSet::ViewToDeviceCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec -= GetTranslate(); aVec = aVec / GetScale(); return aVec; } const Vector3D B3dTransformationSet::ObjectToWorldCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetObjectTrans(); return aVec; } const Vector3D B3dTransformationSet::WorldToObjectCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetInvObjectTrans(); return aVec; } const Vector3D B3dTransformationSet::ObjectToViewCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetObjectTrans(); aVec *= GetMatFromWorldToView(); return aVec; } const Vector3D B3dTransformationSet::ViewToObjectCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetInvMatFromWorldToView(); aVec *= GetInvObjectTrans(); return aVec; } const Vector3D B3dTransformationSet::ObjectToEyeCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetObjectTrans(); aVec *= GetOrientation(); return aVec; } const Vector3D B3dTransformationSet::EyeToObjectCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetInvOrientation(); aVec *= GetInvObjectTrans(); return aVec; } const Vector3D B3dTransformationSet::DeviceToEyeCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetInvProjection(); return aVec; } const Vector3D B3dTransformationSet::EyeToDeviceCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetProjection(); return aVec; } const Vector3D B3dTransformationSet::InvTransObjectToEye(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetInvTransObjectToEye(); return aVec; } const Vector3D B3dTransformationSet::TransTextureCoor(const Vector3D& rVec) { Vector3D aVec(rVec); aVec *= GetTexture(); return aVec; } /************************************************************************* |* |* Konstruktor B3dViewport |* \************************************************************************/ B3dViewport::B3dViewport() : B3dTransformationSet(), aVRP(0, 0, 0), aVPN(0, 0, 1), aVUV(0, 1, 0) { CalcOrientation(); } void B3dViewport::SetVRP(const Vector3D& rNewVRP) { aVRP = rNewVRP; CalcOrientation(); } void B3dViewport::SetVPN(const Vector3D& rNewVPN) { aVPN = rNewVPN; CalcOrientation(); } void B3dViewport::SetVUV(const Vector3D& rNewVUV) { aVUV = rNewVUV; CalcOrientation(); } void B3dViewport::SetViewportValues( const Vector3D& rNewVRP, const Vector3D& rNewVPN, const Vector3D& rNewVUV) { aVRP = rNewVRP; aVPN = rNewVPN; aVUV = rNewVUV; CalcOrientation(); } void B3dViewport::CalcOrientation() { SetOrientation(aVRP, aVPN, aVUV); } /************************************************************************* |* |* Konstruktor B3dViewport |* \************************************************************************/ B3dCamera::B3dCamera(const Vector3D& rPos, const Vector3D& rLkAt, double fFocLen, double fBnkAng, BOOL bUseFocLen) : B3dViewport(), aPosition(rPos), aCorrectedPosition(rPos), aLookAt(rLkAt), fFocalLength(fFocLen), fBankAngle(fBnkAng), bUseFocalLength(bUseFocLen) { CalcNewViewportValues(); } void B3dCamera::SetPosition(const Vector3D& rNewPos) { if(rNewPos != aPosition) { // Zuweisen aCorrectedPosition = aPosition = rNewPos; // Neuberechnung CalcNewViewportValues(); } } void B3dCamera::SetLookAt(const Vector3D& rNewLookAt) { if(rNewLookAt != aLookAt) { // Zuweisen aLookAt = rNewLookAt; // Neuberechnung CalcNewViewportValues(); } } void B3dCamera::SetPositionAndLookAt(const Vector3D& rNewPos, const Vector3D& rNewLookAt) { if(rNewPos != aPosition || rNewLookAt != aLookAt) { // Zuweisen aPosition = rNewPos; aLookAt = rNewLookAt; // Neuberechnung CalcNewViewportValues(); } } void B3dCamera::SetFocalLength(double fLen) { if(fLen != fFocalLength) { // Zuweisen if(fLen < 5.0) fLen = 5.0; fFocalLength = fLen; // Neuberechnung CalcNewViewportValues(); } } void B3dCamera::SetBankAngle(double fAngle) { if(fAngle != fBankAngle) { // Zuweisen fBankAngle = fAngle; // Neuberechnung CalcNewViewportValues(); } } void B3dCamera::SetUseFocalLength(BOOL bNew) { if(bNew != (BOOL)bUseFocalLength) { // Zuweisen bUseFocalLength = bNew; // Neuberechnung CalcNewViewportValues(); } } void B3dCamera::DeviceRectangleChange() { // call parent B3dViewport::DeviceRectangleChange(); // Auf Aenderung reagieren CalcNewViewportValues(); } void B3dCamera::CalcNewViewportValues() { Vector3D aViewVector = aPosition - aLookAt; Vector3D aNewVPN = aViewVector; Vector3D aNewVUV(0.0, 1.0, 0.0); if(aNewVPN.GetLength() < aNewVPN.Y()) aNewVUV.X() = 0.5; aNewVUV.Normalize(); aNewVPN.Normalize(); Vector3D aNewToTheRight = aNewVPN; aNewToTheRight |= aNewVUV; aNewToTheRight.Normalize(); aNewVUV = aNewToTheRight | aNewVPN; aNewVUV.Normalize(); SetViewportValues(aPosition, aNewVPN, aNewVUV); if(CalcFocalLength()) SetViewportValues(aCorrectedPosition, aNewVPN, aNewVUV); if(fBankAngle != 0.0) { Matrix4D aRotMat; aRotMat.RotateZ(fBankAngle); Vector3D aUp(0.0, 1.0, 0.0); aUp *= aRotMat; aUp = EyeToWorldCoor(aUp); aUp.Normalize(); SetVUV(aUp); } } BOOL B3dCamera::CalcFocalLength() { double fWidth = GetDeviceRectangleWidth(); BOOL bRetval = FALSE; if(bUseFocalLength) { // Position aufgrund der FocalLength korrigieren aCorrectedPosition = Vector3D(0.0, 0.0, fFocalLength * fWidth / 35.0); aCorrectedPosition = EyeToWorldCoor(aCorrectedPosition); bRetval = TRUE; } else { // FocalLength anhand der Position anpassen Vector3D aOldPosition; aOldPosition = WorldToEyeCoor(aOldPosition); if(fWidth != 0.0) fFocalLength = aOldPosition.Z() / fWidth * 35.0; if(fFocalLength < 5.0) fFocalLength = 5.0; } return bRetval; }