/* 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 "stdh.h" #include #include #include #include #include #include #include #include #include extern FLOAT mdl_fLODMul; extern FLOAT mdl_fLODAdd; extern const FLOAT *pfSinTable; extern const FLOAT *pfCosTable; static BOOL _b16Bit; static FLOAT _fRatio; static FLOAT3D _vStretch; static FLOAT3D _vOffset; static struct ModelFrameVertex8 *_pFrame8_0; // ptr to last frame static struct ModelFrameVertex16 *_pFrame16_0; static struct ModelFrameVertex8 *_pFrame8_1; // ptr to next frame static struct ModelFrameVertex16 *_pFrame16_1; void UnpackVertex( const INDEX iVertex, FLOAT3D &vVertex) { if( _b16Bit ) { // get 16 bit packed vertices const SWPOINT3D &vsw0 = _pFrame16_0[iVertex].mfv_SWPoint; const SWPOINT3D &vsw1 = _pFrame16_1[iVertex].mfv_SWPoint; // convert them to float and lerp between them vVertex(1) = (Lerp( (FLOAT)vsw0(1), (FLOAT)vsw1(1), _fRatio) -_vOffset(1)) * _vStretch(1); vVertex(2) = (Lerp( (FLOAT)vsw0(2), (FLOAT)vsw1(2), _fRatio) -_vOffset(2)) * _vStretch(2); vVertex(3) = (Lerp( (FLOAT)vsw0(3), (FLOAT)vsw1(3), _fRatio) -_vOffset(3)) * _vStretch(3); } else { // get 8 bit packed vertices const SBPOINT3D &vsb0 = _pFrame8_0[iVertex].mfv_SBPoint; const SBPOINT3D &vsb1 = _pFrame8_1[iVertex].mfv_SBPoint; // convert them to float and lerp between them vVertex(1) = (Lerp( (FLOAT)vsb0(1), (FLOAT)vsb1(1), _fRatio) -_vOffset(1)) * _vStretch(1); vVertex(2) = (Lerp( (FLOAT)vsb0(2), (FLOAT)vsb1(2), _fRatio) -_vOffset(2)) * _vStretch(2); vVertex(3) = (Lerp( (FLOAT)vsb0(3), (FLOAT)vsb1(3), _fRatio) -_vOffset(3)) * _vStretch(3); } } void CModelObject::GetModelVertices( CStaticStackArray &avVertices, FLOATmatrix3D &mRotation, FLOAT3D &vPosition, FLOAT fNormalOffset, FLOAT fMipFactor) { FLOAT3D f3dVertex; INDEX iFrame0, iFrame1; FLOAT fLerpRatio; CModelData *pmd = GetData(); struct ModelFrameVertex16 *pFrame16_0, *pFrame16_1; struct ModelFrameVertex8 *pFrame8_0, *pFrame8_1; // get lerp information GetFrame( iFrame0, iFrame1, fLerpRatio); // set pFrame to point to last and next frames' vertices if( pmd->md_Flags & MF_COMPRESSED_16BIT) { pFrame16_0 = &pmd->md_FrameVertices16[ iFrame0 * pmd->md_VerticesCt]; pFrame16_1 = &pmd->md_FrameVertices16[ iFrame1 * pmd->md_VerticesCt]; } else { pFrame8_0 = &pmd->md_FrameVertices8[ iFrame0 * pmd->md_VerticesCt]; pFrame8_1 = &pmd->md_FrameVertices8[ iFrame1 * pmd->md_VerticesCt]; } // Apply stretch factors FLOAT3D &vDataStretch = pmd->md_Stretch; FLOAT3D &vObjectStretch = mo_Stretch; FLOAT3D vStretch, vOffset; vStretch(1) = vDataStretch(1)*vObjectStretch(1); vStretch(2) = vDataStretch(2)*vObjectStretch(2); vStretch(3) = vDataStretch(3)*vObjectStretch(3); _vStretch = vStretch; _vOffset = vOffset = pmd->md_vCompressedCenter; // check if object is inverted (in mirror) BOOL bXInverted = vStretch(1)<0; BOOL bYInverted = vStretch(2)<0; BOOL bZInverted = vStretch(3)<0; BOOL bInverted = bXInverted!=bYInverted!=bZInverted; // if dynamic stretch factor should be applied if( mo_Stretch != FLOAT3D( 1.0f, 1.0f, 1.0f)) { fMipFactor -= Log2(Max(mo_Stretch(1),Max(mo_Stretch(2),mo_Stretch(3)))); } // adjust mip factor by custom settings fMipFactor = fMipFactor*mdl_fLODMul+mdl_fLODAdd; // get current mip model using mip factor INDEX iMipLevel = GetMipModel( fMipFactor); // get current vertices mask ULONG ulVtxMask = (1L) << iMipLevel; struct ModelMipInfo *pmmiMip = &pmd->md_MipInfos[iMipLevel]; // allocate space for vertices FLOAT3D *pvFirstVtx = avVertices.Push( pmmiMip->mmpi_ctMipVx); // Transform a vertex in model with lerping if( pmd->md_Flags & MF_COMPRESSED_16BIT) { // for each vertex in mip for( INDEX iMipVx=0; iMipVxmmpi_ctMipVx; iMipVx++) { // get destination for unpacking INDEX iMdlVx = pmmiMip->mmpi_auwMipToMdl[iMipVx]; ModelFrameVertex16 &mfv0 = pFrame16_0[iMdlVx]; ModelFrameVertex16 &mfv1 = pFrame16_1[iMdlVx]; FLOAT3D &v = *pvFirstVtx; v(1) = (Lerp((FLOAT)mfv0.mfv_SWPoint(1), (FLOAT)mfv1.mfv_SWPoint(1), fLerpRatio)-vOffset(1))*vStretch(1); v(2) = (Lerp((FLOAT)mfv0.mfv_SWPoint(2), (FLOAT)mfv1.mfv_SWPoint(2), fLerpRatio)-vOffset(2))*vStretch(2); v(3) = (Lerp((FLOAT)mfv0.mfv_SWPoint(3), (FLOAT)mfv1.mfv_SWPoint(3), fLerpRatio)-vOffset(3))*vStretch(3); FLOAT fSinH = pfSinTable[mfv0.mfv_ubNormH]; FLOAT fCosH = pfCosTable[mfv0.mfv_ubNormH]; FLOAT fSinP = pfSinTable[mfv0.mfv_ubNormP]; FLOAT fCosP = pfCosTable[mfv0.mfv_ubNormP]; FLOAT fX0 = -fSinH*fCosP; FLOAT fY0 = +fSinP; FLOAT fZ0 = -fCosH*fCosP; fSinH = pfSinTable[mfv1.mfv_ubNormH]; fCosH = pfCosTable[mfv1.mfv_ubNormH]; fSinP = pfSinTable[mfv1.mfv_ubNormP]; fCosP = pfCosTable[mfv1.mfv_ubNormP]; FLOAT fX1 = -fSinH*fCosP; FLOAT fY1 = +fSinP; FLOAT fZ1 = -fCosH*fCosP; FLOAT3D vNor; vNor(1) = Lerp(fX0, fX1, fLerpRatio); vNor(2) = Lerp(fY0, fY1, fLerpRatio); vNor(3) = Lerp(fZ0, fZ1, fLerpRatio); v=(v+vNor*fNormalOffset)*mRotation+vPosition; pvFirstVtx++; } } else { // for each vertex in mip for( INDEX iMipVx=0; iMipVxmmpi_ctMipVx; iMipVx++) { // get destination for unpacking INDEX iMdlVx = pmmiMip->mmpi_auwMipToMdl[iMipVx]; // get 16 bit packed vertices ModelFrameVertex8 &mfv0 = pFrame8_0[iMdlVx]; ModelFrameVertex8 &mfv1 = pFrame8_1[iMdlVx]; FLOAT3D &v = *pvFirstVtx; // convert them to float and lerp between them v(1) = (Lerp((FLOAT)mfv0.mfv_SBPoint(1), (FLOAT)mfv1.mfv_SBPoint(1), fLerpRatio)-vOffset(1))*vStretch(1); v(2) = (Lerp((FLOAT)mfv0.mfv_SBPoint(2), (FLOAT)mfv1.mfv_SBPoint(2), fLerpRatio)-vOffset(2))*vStretch(2); v(3) = (Lerp((FLOAT)mfv0.mfv_SBPoint(3), (FLOAT)mfv1.mfv_SBPoint(3), fLerpRatio)-vOffset(3))*vStretch(3); FLOAT3D vNor; const FLOAT3D &vNormal0 = avGouraudNormals[mfv0.mfv_NormIndex]; const FLOAT3D &vNormal1 = avGouraudNormals[mfv1.mfv_NormIndex]; vNor(1) = Lerp((FLOAT)vNormal0(1), (FLOAT)vNormal1(1), fLerpRatio); vNor(2) = Lerp((FLOAT)vNormal0(2), (FLOAT)vNormal1(2), fLerpRatio); vNor(3) = Lerp((FLOAT)vNormal0(3), (FLOAT)vNormal1(3), fLerpRatio); v=(v+vNor*fNormalOffset)*mRotation+vPosition; pvFirstVtx++; } } // for each attachment on this model object FOREACHINLIST( CAttachmentModelObject, amo_lnInMain, mo_lhAttachments, itamo) { CAttachmentModelObject *pamo = itamo; CModelData *pmd=pamo->amo_moModelObject.GetData(); ASSERT(pmd!=NULL); if(pmd==NULL || pmd->md_Flags&(MF_FACE_FORWARD|MF_HALF_FACE_FORWARD)) continue; FLOATmatrix3D mNew = mRotation; FLOAT3D vNew = vPosition; // get new rotation and position matrices GetAttachmentMatrices(pamo, mNew, vNew); // recursion will concate attached model's vertices in absolute space to array pamo->amo_moModelObject.GetModelVertices(avVertices, mNew, vNew, fNormalOffset, fMipFactor); } } void CModelObject::GetAttachmentMatrices( CAttachmentModelObject *pamo, FLOATmatrix3D &mRotation, FLOAT3D &vPosition) { // get the position CModelData *pmdMain = (CModelData *)GetData(); pmdMain ->md_aampAttachedPosition.Lock(); const CAttachedModelPosition & = pmdMain->md_aampAttachedPosition[pamo->amo_iAttachedPosition]; pmdMain ->md_aampAttachedPosition.Unlock(); FLOAT3D &vDataStretch = pmdMain->md_Stretch; FLOAT3D &vObjectStretch = mo_Stretch; _vStretch(1) = vDataStretch(1)*vObjectStretch(1); _vStretch(2) = vDataStretch(2)*vObjectStretch(2); _vStretch(3) = vDataStretch(3)*vObjectStretch(3); _vOffset = pmdMain->md_vCompressedCenter; INDEX iFrame0, iFrame1; GetFrame( iFrame0, iFrame1, _fRatio); const INDEX ctVertices = pmdMain->md_VerticesCt; if( pmdMain->md_Flags & MF_COMPRESSED_16BIT) { _b16Bit = TRUE; // set pFrame to point to last and next frames' vertices _pFrame16_0 = &pmdMain->md_FrameVertices16[iFrame0 *ctVertices]; _pFrame16_1 = &pmdMain->md_FrameVertices16[iFrame1 *ctVertices]; } else { _b16Bit = FALSE; // set pFrame to point to last and next frames' vertices _pFrame8_0 = &pmdMain->md_FrameVertices8[iFrame0 *ctVertices]; _pFrame8_1 = &pmdMain->md_FrameVertices8[iFrame1 *ctVertices]; } // 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( iCenter, vCenter); ::UnpackVertex( iFront, vFront); ::UnpackVertex( 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 = mRotation; const FLOAT3D &vO2A = vPosition; 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, pamo->amo_plRelative.pl_OrientationAngle); vOffset(1) = pamo->amo_plRelative.pl_PositionVector(1) * mo_Stretch(1); vOffset(2) = pamo->amo_plRelative.pl_PositionVector(2) * mo_Stretch(2); vOffset(3) = pamo->amo_plRelative.pl_PositionVector(3) * mo_Stretch(3); const FLOAT3D vO = vCenter + vOffset * mOrientation; mRotation = mOrientation*mRelative; vPosition = vO; } void CModelObject::GetAttachmentTransformations( INDEX iAttachment, FLOATmatrix3D &mRotation, FLOAT3D &vPosition, BOOL bDummyAttachment) { // get the position CModelData *pmdMain = (CModelData *)GetData(); pmdMain ->md_aampAttachedPosition.Lock(); const CAttachedModelPosition & = pmdMain->md_aampAttachedPosition[iAttachment]; pmdMain ->md_aampAttachedPosition.Unlock(); // Apply stretch factors FLOAT3D &vDataStretch = pmdMain->md_Stretch; FLOAT3D &vObjectStretch = mo_Stretch; FLOAT3D vStretch, vOffset; vStretch(1) = vDataStretch(1)*vObjectStretch(1); vStretch(2) = vDataStretch(2)*vObjectStretch(2); vStretch(3) = vDataStretch(3)*vObjectStretch(3); _vStretch = vStretch; _vOffset = vOffset = pmdMain->md_vCompressedCenter; INDEX iFrame0, iFrame1; GetFrame( iFrame0, iFrame1, _fRatio); const INDEX ctVertices = pmdMain->md_VerticesCt; if( pmdMain->md_Flags & MF_COMPRESSED_16BIT) { _b16Bit = TRUE; // set pFrame to point to last and next frames' vertices _pFrame16_0 = &pmdMain->md_FrameVertices16[iFrame0 *ctVertices]; _pFrame16_1 = &pmdMain->md_FrameVertices16[iFrame1 *ctVertices]; } else { _b16Bit = FALSE; // set pFrame to point to last and next frames' vertices _pFrame8_0 = &pmdMain->md_FrameVertices8[iFrame0 *ctVertices]; _pFrame8_1 = &pmdMain->md_FrameVertices8[iFrame1 *ctVertices]; } // 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( iCenter, vCenter); ::UnpackVertex( iFront, vFront); ::UnpackVertex( 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 = mRotation; const FLOAT3D &vO2A = vPosition; 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 if (!bDummyAttachment) { CAttachmentModelObject *amo = GetAttachmentModel(iAttachment); ASSERT(amo!=NULL); 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); const FLOAT3D vO = vCenter + vOffset * mOrientation; mRotation = mOrientation*mRelative; vPosition = vO; } else { mRotation = mOrientation; vPosition = vCenter; } }