mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-11-23 10:50:26 +01:00
342 lines
13 KiB
C++
342 lines
13 KiB
C++
/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
|
|
|
|
#include "stdh.h"
|
|
|
|
#include <Engine/Models/ModelObject.h>
|
|
#include <Engine/Models/ModelData.h>
|
|
#include <Engine/Models/RenderModel.h>
|
|
#include <Engine/Models/Model_internal.h>
|
|
#include <Engine/Models/Normals.h>
|
|
#include <Engine/Base/Lists.inl>
|
|
|
|
#include <Engine/Base/ListIterator.inl>
|
|
#include <Engine/Templates/StaticStackArray.cpp>
|
|
|
|
#include <Engine/Templates/Stock_CModelData.h>
|
|
|
|
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<FLOAT3D> &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; iMipVx<pmmiMip->mmpi_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; iMipVx<pmmiMip->mmpi_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;
|
|
}
|
|
}
|