123
This commit is contained in:
40
ResourceCompilerPC/AutoFile.h
Normal file
40
ResourceCompilerPC/AutoFile.h
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
class CAutoFile
|
||||
{
|
||||
FILE* m_f;
|
||||
public:
|
||||
CAutoFile (const char* szName, const char* szMode)
|
||||
{
|
||||
m_f = fopen (szName, szMode);
|
||||
}
|
||||
~CAutoFile ()
|
||||
{
|
||||
if (m_f)
|
||||
fclose (m_f);
|
||||
}
|
||||
|
||||
long GetSize()
|
||||
{
|
||||
if (fseek (m_f, 0, SEEK_END))
|
||||
return -1;
|
||||
|
||||
long nSize = ftell (m_f);
|
||||
|
||||
if (fseek(m_f, 0, SEEK_SET))
|
||||
return -1;
|
||||
|
||||
return nSize;
|
||||
}
|
||||
|
||||
bool Read (void* pData, unsigned nSize)
|
||||
{
|
||||
return (1 == fread (pData, nSize, 1, m_f));
|
||||
}
|
||||
|
||||
bool isEof()
|
||||
{
|
||||
return feof(m_f)?true:false;
|
||||
}
|
||||
|
||||
operator FILE*() {return m_f;}
|
||||
};
|
||||
200
ResourceCompilerPC/BoneLightBindInfo.cpp
Normal file
200
ResourceCompilerPC/BoneLightBindInfo.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
#include "stdafx.h"
|
||||
#ifdef _CRY_ANIMATION_BASE_HEADER_
|
||||
#include "CVars.h"
|
||||
#endif
|
||||
#include "BoneLightBindInfo.h"
|
||||
|
||||
// initializes this from the structures found in the cgf file
|
||||
void CBoneLightBindInfo::load (const SBoneLightBind& bind, const LIGHT_CHUNK_DESC& light, const char* szLightName, float fScale)
|
||||
{
|
||||
// set up the flags that will be set to the DLight
|
||||
|
||||
m_nDLightFlags = 0;
|
||||
|
||||
// the light source must have a name with substrings _ls and/or _hs
|
||||
// _ls means a light source, _hs means a heat source
|
||||
// if none is present, then the heat source flag is automatically set up
|
||||
if (strstr(szLightName,"_ls"))
|
||||
m_nDLightFlags |= DLF_LIGHTSOURCE;
|
||||
if (strstr(szLightName, "_hs"))
|
||||
m_nDLightFlags |= DLF_HEATSOURCE;
|
||||
if (!(m_nDLightFlags & (DLF_HEATSOURCE|DLF_LIGHTSOURCE)))
|
||||
m_nDLightFlags |= DLF_HEATSOURCE;
|
||||
|
||||
if (strstr(szLightName, "local"))
|
||||
m_nDLightFlags |= DLF_LOCAL;
|
||||
|
||||
if (light.szLightImage[0])
|
||||
m_nDLightFlags |= DLF_PROJECT;
|
||||
else
|
||||
m_nDLightFlags |= DLF_POINT;
|
||||
|
||||
|
||||
m_nBone = bind.nBoneId;
|
||||
m_vPos = bind.vLightOffset;
|
||||
|
||||
m_qRot = exp( quaternionf(0,bind.vRotLightOrientation) );
|
||||
|
||||
constructMatLight();
|
||||
|
||||
m_nType = light.type;
|
||||
|
||||
m_rgbColor.r = light.color.r / 255.0f;
|
||||
m_rgbColor.g = light.color.g / 255.0f;
|
||||
m_rgbColor.b = light.color.b / 255.0f;
|
||||
m_rgbColor.a = 1.0f;
|
||||
|
||||
m_fIntensity = light.intens;
|
||||
m_fHotSpotSize = light.hotsize;
|
||||
m_fFalloffSize = light.fallsize;
|
||||
m_fNearAttenStart = light.nearAttenStart;
|
||||
m_fNearAttenEnd = light.nearAttenEnd;
|
||||
m_fFarAttenStart = light.attenStart;
|
||||
m_fFarAttenEnd = light.attenEnd;
|
||||
m_vDirection = light.vDirection;
|
||||
m_strLightImage = light.szLightImage;
|
||||
|
||||
m_bOn = light.on;
|
||||
m_bUseNearAtten = light.useNearAtten;
|
||||
m_bUseFarAtten = light.useAtten;
|
||||
m_bShadow = light.shadow;
|
||||
|
||||
if (!m_bUseFarAtten)
|
||||
{
|
||||
#ifdef _CRY_ANIMATION_BASE_HEADER_
|
||||
g_GetLog()->LogWarning ("\003no far attenuation in the heat source (bone) light, using default");
|
||||
#endif
|
||||
m_fFarAttenEnd = 40;
|
||||
}
|
||||
scale (fScale);
|
||||
}
|
||||
|
||||
void CBoneLightBindInfo::scale (float fScale)
|
||||
{
|
||||
m_vPos *= fScale;
|
||||
m_matLight.SetTranslationOLD (m_matLight.GetTranslationOLD()*fScale);
|
||||
|
||||
m_fNearAttenStart *= fScale;
|
||||
m_fNearAttenEnd *= fScale;
|
||||
m_fFarAttenStart *= fScale;
|
||||
m_fFarAttenEnd *= fScale;
|
||||
|
||||
if (!m_bUseFarAtten)
|
||||
m_fFarAttenEnd *= fScale;
|
||||
}
|
||||
|
||||
void CBoneLightBindInfo::constructMatLight()
|
||||
{
|
||||
m_matLight=Matrix44(m_qRot);
|
||||
m_matLight.SetTranslationOLD(m_vPos);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// initializes the given DLight structure out of the given bone instance
|
||||
// this is one-time call that is only required after construction of the DLight
|
||||
// to initialize its constant parameters
|
||||
void CBoneLightBindInfo::initDLight (CDLight& rDLight)
|
||||
{
|
||||
rDLight.m_Flags &= ~(DLF_LIGHTSOURCE|DLF_HEATSOURCE|DLF_PROJECT|DLF_POINT);
|
||||
rDLight.m_Flags |= m_nDLightFlags;
|
||||
rDLight.m_Flags |= DLF_LOCAL;
|
||||
rDLight.m_fDirectFactor = 0;
|
||||
rDLight.m_Color = m_rgbColor;
|
||||
rDLight.m_fRadius = m_fFarAttenEnd;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// per-frame update of the DLight structure. Updates the light position and radius
|
||||
// PARAMETERS:
|
||||
// matParentBone - the partent coordinate frame
|
||||
// fRadiusFactor - the multiplier for the original radius of the light
|
||||
// rDLight - the light to update
|
||||
void CBoneLightBindInfo::updateDLight (const Matrix44& matParentBone, float fRadiusMultiplier, CDLight& DLight)
|
||||
{
|
||||
DLight.m_Origin = matParentBone.TransformPointOLD(m_vPos);
|
||||
DLight.m_fRadius = m_fFarAttenEnd * fRadiusMultiplier;
|
||||
}
|
||||
|
||||
// returns true if this light source is local (affects only the character)
|
||||
bool CBoneLightBindInfo::isLocal()const
|
||||
{
|
||||
return (m_nDLightFlags & DLF_LOCAL) != 0;
|
||||
}
|
||||
|
||||
bool CBoneLightBindInfo::isHeatSource()const
|
||||
{
|
||||
return (m_nDLightFlags & DLF_HEATSOURCE) != 0;
|
||||
}
|
||||
|
||||
bool CBoneLightBindInfo::isLightSource()const
|
||||
{
|
||||
return (m_nDLightFlags & DLF_LIGHTSOURCE) != 0;
|
||||
}
|
||||
|
||||
|
||||
// returns the priority to sort
|
||||
int CBoneLightBindInfo::getPriority()const
|
||||
{
|
||||
int nPriority = isLocal()?0:1;
|
||||
nPriority <<= 1;
|
||||
nPriority |= isHeatSource()?0:1;
|
||||
nPriority <<= 1;
|
||||
return nPriority;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Serialization to/from memory buffer.
|
||||
// if the buffer is NULL, and bSave is true, returns the required buffer size
|
||||
// otherwise, tries to save/load from the buffer, returns the number of bytes written/read
|
||||
// or 0 if the buffer is too small or some error occured
|
||||
unsigned CBoneLightBindInfo::Serialize (bool bSave, void* pBuffer, unsigned nSize)
|
||||
{
|
||||
const int nVersion = 1;
|
||||
|
||||
typedef CBoneLightBindDesc Desc;
|
||||
if (bSave)
|
||||
{
|
||||
// calculate the required size
|
||||
unsigned nRequiredSize = unsigned(sizeof(nVersion) + sizeof(Desc) + m_strLightImage.length()+1);
|
||||
if (!pBuffer)
|
||||
return nRequiredSize;
|
||||
|
||||
if (nSize < nRequiredSize)
|
||||
return 0;
|
||||
|
||||
*(int*)pBuffer = 1;
|
||||
pBuffer = (int*)pBuffer+1;
|
||||
|
||||
*((Desc*)pBuffer) = *(Desc*)this;
|
||||
pBuffer = ((Desc*)pBuffer)+1;
|
||||
|
||||
memcpy (pBuffer, m_strLightImage.c_str(), m_strLightImage.length()+1);
|
||||
return nRequiredSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nSize < sizeof(nVersion) +sizeof(Desc))
|
||||
return 0;
|
||||
|
||||
const char* pBufEnd = (const char*)pBuffer + nSize;
|
||||
|
||||
int nRealVersion = *(int*)pBuffer;
|
||||
if (nRealVersion != nVersion)
|
||||
return 0;
|
||||
void* pRawData = (int*)pBuffer + 1;
|
||||
|
||||
*(Desc*)this = *(const Desc*)pRawData;
|
||||
pRawData = ((Desc*)pRawData)+1;
|
||||
|
||||
const char* pName = (const char*)pRawData;
|
||||
|
||||
m_strLightImage = "";
|
||||
for(;*pName && pName < pBufEnd;++pName)
|
||||
m_strLightImage += *pName;
|
||||
|
||||
constructMatLight();
|
||||
return (unsigned)(pName+1 - (const char*)pBuffer);
|
||||
}
|
||||
}
|
||||
89
ResourceCompilerPC/BoneLightBindInfo.h
Normal file
89
ResourceCompilerPC/BoneLightBindInfo.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef _BONELIGHTBIND_HDR_
|
||||
#define _BONELIGHTBIND_HDR_
|
||||
|
||||
// the storable in file structure for permanent data in CBoneLightBindInfo
|
||||
struct CBoneLightBindDesc
|
||||
{
|
||||
unsigned m_nDLightFlags; // additional flags that DLight receives (maybe light or heatsource)
|
||||
|
||||
unsigned m_nBone; // the bone to which the binding is made
|
||||
Vec3 m_vPos; // position of the light in the bone CS
|
||||
CryQuat m_qRot; // orientation of the light within the bone CS
|
||||
|
||||
LightTypes m_nType; // one of the LightTypes values
|
||||
CFColor m_rgbColor; // RGB color
|
||||
float m_fIntensity; // multiplier value
|
||||
|
||||
float m_fHotSpotSize; // for spot and direct lights hotspot value
|
||||
float m_fFalloffSize; // for spot and direct lights falloff value
|
||||
float m_fNearAttenStart; // near attenuation ranges
|
||||
float m_fNearAttenEnd;
|
||||
float m_fFarAttenStart; // far attenuation ranges
|
||||
float m_fFarAttenEnd;
|
||||
|
||||
Vec3 m_vDirection; //spot light direction
|
||||
|
||||
// for better alignment, these flags are at the end of the structure
|
||||
bool m_bOn; // light is on
|
||||
bool m_bUseNearAtten; // near atten. on
|
||||
bool m_bUseFarAtten; // far atteniation
|
||||
bool m_bShadow; // shadow is on
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// the structure describing binding of a light to a bone.
|
||||
// refers to the bone by the id, and contains the whole info about the ligtht
|
||||
class CBoneLightBindInfo: public CBoneLightBindDesc
|
||||
{
|
||||
public:
|
||||
CBoneLightBindInfo()
|
||||
{m_nBone = 0;}
|
||||
|
||||
// initializes this from the structures found in the cgf file
|
||||
void load (const SBoneLightBind&, const LIGHT_CHUNK_DESC&, const char* szLightName, float fScale);
|
||||
|
||||
void scale (float fScale);
|
||||
|
||||
// returns the index of the bone to which the light source is bound
|
||||
unsigned getBone() const {return m_nBone;}
|
||||
|
||||
// initializes the given DLight structure out of the given bone instance
|
||||
// this is one-time call that is only required after construction of the DLight to initialize its constant parameters
|
||||
void initDLight (CDLight& DLight);
|
||||
|
||||
// per-frame update of the DLight structure. Updates the light position and radius
|
||||
void updateDLight (const Matrix44& matParentBone, float fRadiusMultiplier, CDLight& DLight);
|
||||
|
||||
// returns true if this light source is local (affects only the character)
|
||||
bool isLocal()const;
|
||||
|
||||
bool isHeatSource()const;
|
||||
bool isLightSource()const;
|
||||
|
||||
// returns the priority to sort
|
||||
int getPriority()const;
|
||||
|
||||
bool operator < (const CBoneLightBindInfo& rRight)const
|
||||
{
|
||||
return getPriority() < rRight.getPriority();
|
||||
}
|
||||
|
||||
// Serialization to/from memory buffer.
|
||||
// if the buffer is NULL, and bSave is true, returns the required buffer size
|
||||
// otherwise, tries to save/load from the buffer, returns the number of bytes written/read
|
||||
// or 0 if the buffer is too small or some error occured
|
||||
unsigned Serialize (bool bSave, void* pBuffer, unsigned nSize);
|
||||
|
||||
const char* getLightImageCStr()const {return m_strLightImage.c_str();}
|
||||
protected:
|
||||
string m_strLightImage; //spot light texture
|
||||
|
||||
// the following members are not serialized:
|
||||
Matrix44 m_matLight; // transform matrix of the light in the bone CS
|
||||
|
||||
void constructMatLight();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
9
ResourceCompilerPC/CalConvertor.h
Normal file
9
ResourceCompilerPC/CalConvertor.h
Normal file
@@ -0,0 +1,9 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Declaration of convertor for CAL files that will compile them into easy-to-parse
|
||||
// and compact format which will contain the necessary information about the animation files.
|
||||
#ifndef _CAL_CONVERTOR_HDR_
|
||||
#define _CAL_CONVERTOR_HDR_
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
1533
ResourceCompilerPC/CgfConvertor.cpp
Normal file
1533
ResourceCompilerPC/CgfConvertor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
240
ResourceCompilerPC/CgfConvertor.h
Normal file
240
ResourceCompilerPC/CgfConvertor.h
Normal file
@@ -0,0 +1,240 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: cgfconvertor.h
|
||||
// Version: v1.00
|
||||
// Created: 5/11/2002 by Timur.
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __cgfconvertor_h__
|
||||
#define __cgfconvertor_h__
|
||||
#pragma once
|
||||
|
||||
#include "IRCLog.h"
|
||||
#include "IConvertor.h"
|
||||
#include "CryCompiledFile.h"
|
||||
#include "CryChunkedFile.h"
|
||||
#include "RenderMeshBuilder.h"
|
||||
|
||||
struct ConvertContext;
|
||||
|
||||
|
||||
/** Convertor implementation for CGF files.
|
||||
*/
|
||||
class CGFConvertor : public IConvertor
|
||||
{
|
||||
public:
|
||||
// this class will be thrown from the internal method during conversion
|
||||
// indicating some error that should abort conversion
|
||||
class Error
|
||||
{
|
||||
public:
|
||||
Error (int nCode);
|
||||
Error (const char* szFormat, ...);
|
||||
const char* c_str()const {return m_strReason.c_str();}
|
||||
protected:
|
||||
string m_strReason;
|
||||
};
|
||||
|
||||
CGFConvertor ();
|
||||
~CGFConvertor();
|
||||
|
||||
//! Release memory of interface.
|
||||
void Release() { delete this; };
|
||||
|
||||
//! Process file.
|
||||
virtual bool Process( ConvertContext &cc );
|
||||
|
||||
bool ProcessStatic( ConvertContext &cc );
|
||||
|
||||
//! Return name of output file that will be produced from this file.
|
||||
// @param sourceFileName File name plus extension of source file, must not contain path.
|
||||
virtual bool GetOutputFile( ConvertContext &cc );
|
||||
|
||||
//! Return platforms supported by this convertor.
|
||||
virtual int GetNumPlatforms() const;
|
||||
//! Get supported platform.
|
||||
//! @param index Index of platform must be in range 0 < index < GetNumPlatforms().
|
||||
virtual Platform GetPlatform( int index ) const;
|
||||
|
||||
//! Get number of supported extensions.
|
||||
virtual int GetNumExt() const { return 1+m_pStatCGFCompiler->GetNumExt(); };
|
||||
//! Get supported extension.
|
||||
//! @param index Index of extension must be in range 0 < index < GetNumExt().
|
||||
virtual const char* GetExt( int index ) const { return index?"cgf":m_pStatCGFCompiler->GetExt(index-1); };
|
||||
|
||||
// this should retrieve the timestamp of the convertor executable:
|
||||
// when it was created by the linker, normally. This date/time is used to
|
||||
// compare with the compiled file date/time and even if the compiled file
|
||||
// is not older than the source file, it will be recompiled if it's older than the
|
||||
// convertor
|
||||
virtual DWORD GetTimestamp() const ;
|
||||
protected:
|
||||
// internally used stuff
|
||||
// writes the data directly into the file
|
||||
void writeRaw (const void* pData, unsigned nSize);
|
||||
|
||||
template <class T>
|
||||
void write (const T& rData)
|
||||
{
|
||||
writeRaw (&rData, sizeof(T));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void write (const T* pData, size_t numElements)
|
||||
{
|
||||
writeRaw (pData, numElements * sizeof(T));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void writeArray (const std::vector<T>& arrData)
|
||||
{
|
||||
if (!arrData.empty())
|
||||
write (&arrData[0], arrData.size());
|
||||
}
|
||||
|
||||
// writes the 0-terminated string, returns the number of bytes (including the terminating 0) written
|
||||
size_t writeString (const char* szString)
|
||||
{
|
||||
size_t n = strlen(szString)+1;
|
||||
writeRaw (szString, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
// writes the 0-terminated string, returns the number of bytes (including the terminating 0) written
|
||||
size_t writeString (const string& strString)
|
||||
{
|
||||
size_t n = strString.length() + 1;
|
||||
writeRaw (strString.c_str(), n);
|
||||
return n;
|
||||
}
|
||||
|
||||
//void LogV (const char* szFormat, va_list args);
|
||||
//void Log (const char* szFormat, ...);
|
||||
|
||||
void WriteGeometryInfo (unsigned nLOD);
|
||||
void WriteHeader();
|
||||
void WriteBoneInfo();
|
||||
void WriteMaterials( const char *inszSrcFileName );
|
||||
void writeIntFaces(unsigned nLOD);
|
||||
void WriteVertices (CryChunkedFile* pSource);
|
||||
void WriteNormals (CryChunkedFile* pSource);
|
||||
|
||||
void writeShadowConnectivity (unsigned nLOD);
|
||||
void writeVertexSkin (unsigned nLOD);
|
||||
void writeNormalSkin (unsigned nLOD);
|
||||
void writeTangSkin (unsigned nLOD);
|
||||
void validateTangents (const TangData* pTangents, unsigned numTangents);
|
||||
|
||||
void WriteBoneGeometry (unsigned nLOD);
|
||||
|
||||
void writeBGBone(unsigned nLOD, unsigned nBone, CryChunkedFile::MeshDesc* pMesh);
|
||||
void WriteMorphTargetSet ();
|
||||
void writeMorphTargets (unsigned nLOD);
|
||||
void WriteLights();
|
||||
bool isAnimatedFastCheck( const char *filename );
|
||||
|
||||
string GetCalFilePath ();
|
||||
string GetSourceDir();
|
||||
|
||||
// loads the given animation info into the given structure
|
||||
// returns false upon failure
|
||||
bool LoadAnimInfo (const string& strFilePath, CCFAnimInfo &animInfo);
|
||||
protected:
|
||||
// loads the m_arrLODs
|
||||
bool LoadLODs();
|
||||
IConvertor* getStatCGFCompiler();
|
||||
|
||||
// builds the m_arrRenderMeshes array with the CRenderMeshBuilder
|
||||
// structures containing all the additional info required for leaf buffer creation
|
||||
void BuildRenderMeshes();
|
||||
|
||||
// Updates physics if needed (if there is LOD1, which contains physical data for LOD1 physics
|
||||
void UpdateDeadBodyPhysics();
|
||||
|
||||
|
||||
// remaps, if necessary, the bones from the LOD source to the Master source
|
||||
// and changes the links in the LOD source so that the boneid's there point to the indices (not IDs!)
|
||||
// of the bones in the Master Source, not LOD Source
|
||||
// This assumes that the bone information from the LOD source won't be used at all
|
||||
// throws an error if there's some unrecognized bone in the LOD source
|
||||
void RemapBones (unsigned nLOD);
|
||||
|
||||
// remaps the bone indices, throws error if some indices cannot be remapped for some reason
|
||||
// (e.g. mapping contains -1, i.e. no mapping)
|
||||
void RemapBoneIndices (CryChunkedFile* pLOD, const std::vector<int>& arrMap);
|
||||
|
||||
// releases all the resources
|
||||
void clear();
|
||||
|
||||
// !!!OBSOLETE!!!
|
||||
// calculates the number of materials used by the previous LODs (< than given)
|
||||
// this is to offset the mtl numbers of the nLOD to use the range of materials
|
||||
// belonging to that LOD
|
||||
// !!!OBSOLETE!!!
|
||||
unsigned getLODMtlOffset (unsigned nLOD);
|
||||
|
||||
// Reads the CAL file or the list of caf files in the same directory with the corresponding name,
|
||||
// and writes the animation list chunk with the animation names, file paths and compiled directives
|
||||
void WriteAnimListWithCAL (FILE* fCal);
|
||||
void WriteAnimListNoCAL ();
|
||||
void WriteAnimInfo (CCFFileWriter &rSubChunks, const char* szAnimName, const string& strFilePath, unsigned nFlag);
|
||||
|
||||
void WriteSceneProps();
|
||||
|
||||
void LogWarning (const char* szFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, szFormat);
|
||||
m_pContext->pLog->LogV (IMiniLog::eWarning, szFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void LogError (const char* szFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, szFormat);
|
||||
m_pContext->pLog->LogV (IMiniLog::eError, szFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Log (const char* szFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, szFormat);
|
||||
m_pContext->pLog->LogV (IMiniLog::eMessage, szFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
protected:
|
||||
ConvertContext* m_pContext;
|
||||
|
||||
// the source files: one file for each LOD. At least LOD 0 Must be present for conversion.
|
||||
CryChunkedFile_AutoArray m_arrLODs;
|
||||
|
||||
// the mapping from bone indices in Master (LOD0) to bone indices in LOD>0
|
||||
typedef std::vector<int> BoneMap;
|
||||
std::vector<BoneMap> m_arrLODBoneMaps;
|
||||
|
||||
typedef std::map<CString,int> PhysMatIDMap;
|
||||
PhysMatIDMap m_physMtlToFaceIdMap; // Map for every LOD (except first).
|
||||
|
||||
// the render meshes for each LOD
|
||||
std::vector<CRenderMeshBuilder> m_arrRenderMeshes;
|
||||
|
||||
CCFFileWriter m_Writer;
|
||||
|
||||
// the target file
|
||||
FILE* m_fTarget;
|
||||
|
||||
|
||||
IConvertor* m_pStatCGFCompiler;
|
||||
};
|
||||
|
||||
#endif // __cgfconvertor_h__
|
||||
542
ResourceCompilerPC/CgfUtils.cpp
Normal file
542
ResourceCompilerPC/CgfUtils.cpp
Normal file
@@ -0,0 +1,542 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Character Animation source code
|
||||
//
|
||||
// History:
|
||||
// Created by Sergiy Migdalskiy
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "stdafx.h"
|
||||
#include "StringUtils.h"
|
||||
#include "CgfUtils.h"
|
||||
|
||||
using namespace CryStringUtils;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// given the chunk, parses it and returns the array of pointers to the strings with the bone names
|
||||
// in the supplied array. Returns true when successful
|
||||
// PARAMETERS:
|
||||
// chunkHeader - the header of the chunk in the chunk table
|
||||
// pChunk - the raw chunk data in the file
|
||||
// nChunkSize - the size of the raw data piece in the file
|
||||
// arrNames - the array that will be resized according to the number of entries, and each element of this array
|
||||
// will be the pointer to the corresponding 0-terminated name string.
|
||||
bool LoadBoneNameList (const CHUNK_HEADER& chunkHeader, const void* pChunk, unsigned nChunkSize, std::vector<const char*>& arrNames)
|
||||
{
|
||||
switch (chunkHeader.ChunkVersion)
|
||||
{
|
||||
case BONENAMELIST_CHUNK_DESC_0744::VERSION:
|
||||
{
|
||||
// the old chunk version - fixed-size name list
|
||||
const BONENAMELIST_CHUNK_DESC_0744* pNameChunk = (const BONENAMELIST_CHUNK_DESC_0744*)(pChunk);
|
||||
|
||||
int nGeomBones = pNameChunk->nEntities;
|
||||
|
||||
// just fill in the pointers to the fixed-size string buffers
|
||||
const NAME_ENTITY* pGeomBoneNameTable = (const NAME_ENTITY*)(pNameChunk+1);
|
||||
if(nGeomBones < 0 || nGeomBones > 0x800)
|
||||
return false;
|
||||
arrNames.resize(nGeomBones);
|
||||
for (int i = 0; i < nGeomBones; ++i)
|
||||
arrNames[i] = pGeomBoneNameTable[i].name;
|
||||
}
|
||||
break;
|
||||
|
||||
case BONENAMELIST_CHUNK_DESC_0745::VERSION:
|
||||
{
|
||||
// the new memory-economizing chunk with variable-length packed strings following tightly each other
|
||||
const BONENAMELIST_CHUNK_DESC_0745* pNameChunk = (const BONENAMELIST_CHUNK_DESC_0745*)(pChunk);
|
||||
int nGeomBones = pNameChunk->numEntities;
|
||||
|
||||
// we know how many strings there are there; the whole bunch of strings may
|
||||
// be followed by pad zeros, to enable alignment
|
||||
arrNames.resize(nGeomBones, "");
|
||||
|
||||
// scan through all the strings, each string following immediately the 0 terminator of the previous one
|
||||
const char* pNameListEnd = ((const char*)pNameChunk) + nChunkSize;
|
||||
const char* pName = (const char*)(pNameChunk+1);
|
||||
int nName = 0;
|
||||
while (*pName && pName < pNameListEnd && nName < nGeomBones)
|
||||
{
|
||||
arrNames[nName] = pName;
|
||||
pName += strnlen(pName, pNameListEnd) + 1;
|
||||
++nName;
|
||||
}
|
||||
if (nName < nGeomBones)
|
||||
{
|
||||
// the chunk is truncated
|
||||
#ifdef _CRY_ANIMATION_BASE_HEADER_
|
||||
// if this is in the engine, log the error
|
||||
g_GetLog()->LogWarning ("\003inconsistent bone name list chunk: only %d out of %d bone names have been read.", nName, nGeomBones);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Attempts to load the material from the given material chunk to the "me" structure
|
||||
MatChunkLoadErrorEnum LoadMatEntity (const CHUNK_HEADER& chunkHeader, const void* pChunkData, unsigned nChunkSize, MAT_ENTITY& me)
|
||||
{
|
||||
memset(&me, 0, sizeof(MAT_ENTITY));
|
||||
|
||||
switch (chunkHeader.ChunkVersion)
|
||||
{
|
||||
case MTL_CHUNK_DESC_0746::VERSION:
|
||||
{
|
||||
const MTL_CHUNK_DESC_0746* pMatChunk = (const MTL_CHUNK_DESC_0746*)pChunkData;
|
||||
|
||||
me.m_New = 2;
|
||||
strcpy(me.name, pMatChunk->name);
|
||||
switch (pMatChunk->MtlType)
|
||||
{
|
||||
case MTL_STANDARD:
|
||||
{
|
||||
me.IsStdMat = true;
|
||||
me.col_d = pMatChunk->col_d;
|
||||
me.col_a = pMatChunk->col_a;
|
||||
//me.col_a.g=0;
|
||||
//me.col_a.b=0;
|
||||
me.col_s = pMatChunk->col_s;
|
||||
|
||||
me.specLevel = pMatChunk->specLevel;
|
||||
me.specShininess = pMatChunk->specShininess*100;
|
||||
me.opacity = pMatChunk->opacity;
|
||||
me.selfIllum = pMatChunk->selfIllum;
|
||||
me.flags = pMatChunk->flags;
|
||||
|
||||
me.Dyn_Bounce = pMatChunk->Dyn_Bounce;
|
||||
me.Dyn_StaticFriction = pMatChunk->Dyn_StaticFriction;
|
||||
me.Dyn_SlidingFriction = pMatChunk->Dyn_SlidingFriction;
|
||||
/* //Timur[10/24/2001]
|
||||
strcpy(me.map_a, pMatChunk->tex_a.name);
|
||||
strcpy(me.map_d, pMatChunk->tex_d.name);
|
||||
strcpy(me.map_o, pMatChunk->tex_o.name);
|
||||
strcpy(me.map_b, pMatChunk->tex_b.name);
|
||||
strcpy(me.map_s, pMatChunk->tex_s.name);
|
||||
strcpy(me.map_g, pMatChunk->tex_g.name);
|
||||
strcpy(me.map_c, pMatChunk->tex_c.name);
|
||||
strcpy(me.map_e, pMatChunk->tex_rl.name);
|
||||
strcpy(me.map_rr, pMatChunk->tex_rr.name);
|
||||
strcpy(me.map_det, pMatChunk->tex_det.name);
|
||||
*/
|
||||
me.map_a = pMatChunk->tex_a;
|
||||
me.map_d = pMatChunk->tex_d;
|
||||
me.map_o = pMatChunk->tex_o;
|
||||
me.map_b = pMatChunk->tex_b;
|
||||
me.map_s = pMatChunk->tex_s;
|
||||
me.map_g = pMatChunk->tex_g;
|
||||
me.map_detail = pMatChunk->tex_fl;
|
||||
me.map_e = pMatChunk->tex_rl;
|
||||
me.map_subsurf = pMatChunk->tex_subsurf;
|
||||
me.map_displ = pMatChunk->tex_det;
|
||||
|
||||
me.nChildren = pMatChunk->nChildren;
|
||||
|
||||
me.alpharef = pMatChunk->alphaTest;
|
||||
}
|
||||
return MCLE_Success;
|
||||
|
||||
default:
|
||||
return MCLE_IgnoredType;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MTL_CHUNK_DESC_0745::VERSION:
|
||||
{
|
||||
const MTL_CHUNK_DESC_0745* pMatChunk = (const MTL_CHUNK_DESC_0745*)pChunkData;
|
||||
|
||||
me.m_New = 1;
|
||||
strcpy(me.name, pMatChunk->name);
|
||||
switch (pMatChunk->MtlType)
|
||||
{
|
||||
case MTL_STANDARD:
|
||||
me.IsStdMat = true;
|
||||
me.col_d = pMatChunk->col_d;
|
||||
me.col_a = pMatChunk->col_a;
|
||||
//me.col_a.g=0;
|
||||
//me.col_a.b=0;
|
||||
me.col_s = pMatChunk->col_s;
|
||||
|
||||
me.specLevel = pMatChunk->specLevel;
|
||||
me.specShininess = pMatChunk->specShininess*100;
|
||||
me.opacity = pMatChunk->opacity;
|
||||
me.selfIllum = pMatChunk->selfIllum;
|
||||
me.flags = pMatChunk->flags;
|
||||
|
||||
me.Dyn_Bounce = pMatChunk->Dyn_Bounce;
|
||||
me.Dyn_StaticFriction = pMatChunk->Dyn_StaticFriction;
|
||||
me.Dyn_SlidingFriction = pMatChunk->Dyn_SlidingFriction;
|
||||
me.map_a = pMatChunk->tex_a;
|
||||
me.map_d = pMatChunk->tex_d;
|
||||
me.map_o = pMatChunk->tex_o;
|
||||
me.map_b = pMatChunk->tex_b;
|
||||
me.map_s = pMatChunk->tex_s;
|
||||
me.map_g = pMatChunk->tex_g;
|
||||
me.map_detail = pMatChunk->tex_c;
|
||||
me.map_e = pMatChunk->tex_rl;
|
||||
me.map_subsurf = pMatChunk->tex_subsurf;
|
||||
me.map_displ = pMatChunk->tex_det;
|
||||
|
||||
me.nChildren = pMatChunk->nChildren;
|
||||
|
||||
return MCLE_Success;
|
||||
|
||||
default:
|
||||
return MCLE_IgnoredType;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return MCLE_UnknownVersion;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if the given string is null, assigns the "" to the pointer
|
||||
void chkNullString (const char*&pszString)
|
||||
{
|
||||
if (!pszString)
|
||||
pszString = "";
|
||||
}
|
||||
|
||||
static void rtrim (char* szString)
|
||||
{
|
||||
for (char* p = szString + strlen (szString) - 1; p >= szString && isspace(*p); --p)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
static void ltrim (const char*& szString)
|
||||
{
|
||||
while (*szString && isspace(*szString))
|
||||
++szString;
|
||||
}
|
||||
|
||||
|
||||
CMatEntityNameTokenizer::CMatEntityNameTokenizer ():
|
||||
m_szMtlName (NULL),
|
||||
szName (""),
|
||||
szTemplate (""),
|
||||
szPhysMtl (""),
|
||||
nSortValue (0),
|
||||
bInvert (false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CMatEntityNameTokenizer::tokenize (const char* szMtlFullName)
|
||||
{
|
||||
if (m_szMtlName)
|
||||
{
|
||||
free (m_szMtlName);
|
||||
m_szMtlName = NULL;
|
||||
}
|
||||
if (!szMtlFullName)
|
||||
return;
|
||||
|
||||
int nLen = (int)strlen(szMtlFullName);
|
||||
m_szMtlName = (char*)malloc (nLen+1);
|
||||
memcpy (m_szMtlName, szMtlFullName, nLen + 1);
|
||||
|
||||
szName = NULL;
|
||||
szTemplate = NULL;
|
||||
szPhysMtl = NULL;
|
||||
nSortValue = 0;
|
||||
bInvert = false;
|
||||
|
||||
// the state machine will parse the whole string
|
||||
enum StateEnum
|
||||
{
|
||||
kUnknown,
|
||||
kName,
|
||||
kTemplate,
|
||||
kPhysMtl,
|
||||
kIndex
|
||||
};
|
||||
|
||||
StateEnum nState = kName; // by default, the string begins with name
|
||||
this->szName = m_szMtlName;
|
||||
|
||||
for (char* p = m_szMtlName; *p; ++p)
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case '(': // template name begins
|
||||
this->szTemplate = p+1;
|
||||
nState = kTemplate;
|
||||
*p = '\0';
|
||||
break;
|
||||
|
||||
case '[': // render priority number begins
|
||||
*p = '\0';
|
||||
nState = kIndex;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
this->szPhysMtl = p+1;
|
||||
*p = '\0';
|
||||
nState = kPhysMtl;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (nState)
|
||||
{
|
||||
case kName:
|
||||
switch (*p)
|
||||
{
|
||||
/*case ' ': // there are no spaces in the name
|
||||
*p = '\0';
|
||||
break;*/
|
||||
|
||||
case ')':
|
||||
case ']':
|
||||
#ifdef _CRY_ANIMATION_BASE_HEADER_
|
||||
g_GetLog()->LogError ("Invalid material name (unexpected closing bracket) \"%s\"", szMtlFullName);
|
||||
#endif
|
||||
break;
|
||||
};
|
||||
break;
|
||||
|
||||
case kTemplate:
|
||||
switch (*p)
|
||||
{
|
||||
case ')':
|
||||
nState = kUnknown;
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case kIndex:
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case ']':
|
||||
nState = kUnknown;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
this->nSortValue *= 10;
|
||||
this->nSortValue += *p - '0';
|
||||
break;
|
||||
|
||||
default:
|
||||
nState = kUnknown;
|
||||
#ifdef _CRY_ANIMATION_BASE_HEADER_
|
||||
g_GetLog()->LogError ("Invalid material name (unexpected symbol in index field) \"%s\"", szMtlFullName);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// take into account hte old form $s_... of setting the template name
|
||||
// if there was no () template, then use this one (after _)
|
||||
if ((!this->szTemplate || !this->szTemplate[0]) &&
|
||||
this->szName[0] == '$' && tolower(this->szName[1]) == 's' && this->szName[2] == '_')
|
||||
{
|
||||
this->szTemplate = this->szName + 3;
|
||||
}
|
||||
|
||||
// make sure all the strings get their pointers - if there's no name, then it will be an empty name
|
||||
chkNullString(this->szName);
|
||||
chkNullString(this->szTemplate);
|
||||
chkNullString(this->szPhysMtl);
|
||||
|
||||
// a special case (one more) - template name preceded by # means (or meant) the inverted template
|
||||
if (this->szTemplate[0] == '#')
|
||||
{
|
||||
this->szTemplate++;
|
||||
this->bInvert = true;
|
||||
}
|
||||
|
||||
// trim unneeded left and right leading spaces
|
||||
rtrim ((char*)this->szName);
|
||||
rtrim ((char*)this->szTemplate);
|
||||
rtrim ((char*)this->szPhysMtl);
|
||||
|
||||
ltrim (this->szName);
|
||||
ltrim (this->szTemplate);
|
||||
ltrim (this->szPhysMtl);
|
||||
}
|
||||
|
||||
CMatEntityNameTokenizer::~CMatEntityNameTokenizer ()
|
||||
{
|
||||
if (m_szMtlName)
|
||||
free (m_szMtlName);
|
||||
}
|
||||
|
||||
// operator that sorts the materials for rendering
|
||||
bool CMatEntityNameTokenizer::operator < (const CMatEntityNameTokenizer& right)const
|
||||
{
|
||||
if (this->nSortValue < right.nSortValue)
|
||||
return true;
|
||||
|
||||
if (this->nSortValue > right.nSortValue)
|
||||
return false;
|
||||
|
||||
int nComp = stricmp (this->szTemplate, right.szTemplate);
|
||||
|
||||
if (nComp < 0)
|
||||
return true;
|
||||
if (nComp > 0)
|
||||
return false;
|
||||
|
||||
nComp = stricmp (this->szName, right.szName);
|
||||
|
||||
if (nComp < 0)
|
||||
return true;
|
||||
if (nComp > 0)
|
||||
return false;
|
||||
|
||||
return false; // they're equal
|
||||
}
|
||||
|
||||
// given the in-permutation, constructs the inverse out-permutation, so that:
|
||||
// pOut[pIn[i]] == i
|
||||
// pIn[pOut[i]] == i
|
||||
void ConstructReversePermutation (const unsigned* pIn, unsigned* pOut, unsigned num)
|
||||
{
|
||||
unsigned i;
|
||||
#ifdef _DEBUG
|
||||
// we'll check the correctness of permutation by checking if there are duplicate entries in pIn
|
||||
// if there are no duplicate entries, according to Dirichle principle, there are no missed entries in pOut
|
||||
for (i = 0; i < num; ++i)
|
||||
pOut[i] = (unsigned)-1;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < num; ++i)
|
||||
{
|
||||
assert (pIn[i] < num);
|
||||
assert ((int)pOut[pIn[i]] ==(unsigned)-1);
|
||||
pOut[pIn[i]] = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Remaps the materials according to the given permutation
|
||||
// the permutation is perm[new index] == old index
|
||||
void RemapMatEntities (MAT_ENTITY* pMtls, unsigned numMtls, unsigned* pPerm)
|
||||
{
|
||||
MAT_ENTITY* pOldMtls = new MAT_ENTITY[numMtls];
|
||||
memcpy (pOldMtls, pMtls, sizeof(MAT_ENTITY)*numMtls);
|
||||
|
||||
for (unsigned nNewMtl = 0; nNewMtl < numMtls; ++nNewMtl)
|
||||
memcpy (pMtls + nNewMtl, pOldMtls + pPerm[nNewMtl], sizeof(MAT_ENTITY));
|
||||
|
||||
delete[]pOldMtls;
|
||||
}
|
||||
|
||||
// copies the matrix from SBoneInitPosMatrix to Matrix
|
||||
void copyMatrix (Matrix44& matDst, const SBoneInitPosMatrix& matSrc)
|
||||
{
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
{
|
||||
matDst(i,0) = matSrc[i][0];
|
||||
matDst(i,1) = matSrc[i][1];
|
||||
matDst(i,2) = matSrc[i][2];
|
||||
}
|
||||
matDst(0,3) = 0;
|
||||
matDst(1,3) = 0;
|
||||
matDst(2,3) = 0;
|
||||
matDst(3,3) = 1;
|
||||
}
|
||||
|
||||
const char* getMtlType (unsigned nMtlType)
|
||||
{
|
||||
switch (nMtlType)
|
||||
{
|
||||
case MTL_UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case MTL_STANDARD:
|
||||
return "STANDARD";
|
||||
case MTL_MULTI:
|
||||
return "MULTI";
|
||||
case MTL_2SIDED:
|
||||
return "2SIDED";
|
||||
default:
|
||||
return "#Unknown#";
|
||||
}
|
||||
}
|
||||
|
||||
const char* getTexType (unsigned char nTexType)
|
||||
{
|
||||
switch (nTexType)
|
||||
{
|
||||
case TEXMAP_AUTOCUBIC:
|
||||
return "TEXMAP_AUTOCUBIC";
|
||||
case TEXMAP_CUBIC:
|
||||
return "TEXMAP_CUBIC";
|
||||
case TEXMAP_ENVIRONMENT:
|
||||
return "TEXMAP_ENVIRONMENT";
|
||||
case TEXMAP_SCREENENVIRONMENT:
|
||||
return "!TEXMAP_SCREENENVIRONMENT(unsupported)!";
|
||||
default:
|
||||
return "#Unknown#";
|
||||
}
|
||||
}
|
||||
|
||||
string getLightType (LightTypes nType)
|
||||
{
|
||||
switch (nType)
|
||||
{
|
||||
case LT_OMNI:
|
||||
return "Omni";
|
||||
case LT_SPOT:
|
||||
return "Spot";
|
||||
case LT_DIRECT:
|
||||
return "Direct";
|
||||
case LT_AMBIENT:
|
||||
return "Ambient";
|
||||
default:
|
||||
{
|
||||
char szBuffer[32];
|
||||
printf (szBuffer, "Unknown(%d)", nType);
|
||||
return szBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string getMtlFlags (int nFlags)
|
||||
{
|
||||
string strResult;
|
||||
if (nFlags & MTLFLAG_WIRE)
|
||||
strResult += "MTLFLAG_WIRE|";
|
||||
if (nFlags & MTLFLAG_2SIDED)
|
||||
strResult += "MTLFLAG_2SIDED|";
|
||||
if (nFlags & MTLFLAG_FACEMAP)
|
||||
strResult += "MTLFLAG_FACEMAP|";
|
||||
if (nFlags & MTLFLAG_FACETED)
|
||||
strResult += "MTLFLAG_FACETED|";
|
||||
if (nFlags & MTLFLAG_ADDITIVE)
|
||||
strResult += "MTLFLAG_ADDITIVE|";
|
||||
if (nFlags & MTLFLAG_SUBTRACTIVE)
|
||||
strResult += "MTLFLAG_SUBTRACTIVE|";
|
||||
|
||||
if (!strResult.empty ())
|
||||
strResult.resize (strResult.length ()-1);
|
||||
|
||||
return strResult;
|
||||
}
|
||||
205
ResourceCompilerPC/ChunkFileReader.cpp
Normal file
205
ResourceCompilerPC/ChunkFileReader.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
#include "StdAfx.h"
|
||||
#include "FileMapping.h"
|
||||
#include "chunkfilereader.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#undef THIS_FILE
|
||||
static char THIS_FILE[] = __FILE__;
|
||||
#endif
|
||||
|
||||
const char* CChunkFileReader::gLastError = "";
|
||||
|
||||
CChunkFileReader::CChunkFileReader():
|
||||
m_pChunks(NULL)
|
||||
//,m_arrChunkSize ("CChunkFileReader.ChunkSize")
|
||||
{
|
||||
}
|
||||
|
||||
CChunkFileReader::~CChunkFileReader()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool CChunkFileReader::open (const string& strFileName, unsigned nFlags)
|
||||
{
|
||||
return open (strFileName.c_str(), nFlags);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// attaches the file mapping object to this file reader and checks
|
||||
// whether the file is a valid chunked file
|
||||
bool CChunkFileReader::open(CFileMapping* pFile)
|
||||
{
|
||||
close();
|
||||
m_pFile = pFile;
|
||||
|
||||
bool bSuccess = false;
|
||||
|
||||
if ( (m_pFile != (CFileMapping*)NULL) && (m_pFile->getData() != NULL) )
|
||||
{
|
||||
if (m_pFile->getSize() >= sizeof(FileHeader))
|
||||
{// the file must contain the header
|
||||
const FileHeader& fileHeader = getFileHeader();
|
||||
if (m_pFile->getSize() >= fileHeader.ChunkTableOffset + sizeof(int)
|
||||
&& (int)fileHeader.ChunkTableOffset > (int)sizeof(fileHeader)
|
||||
)
|
||||
{// there must be room for the chunk table header
|
||||
unsigned numChunks = *static_cast<const unsigned*>(m_pFile->getData(fileHeader.ChunkTableOffset));
|
||||
unsigned nChunk;
|
||||
if (m_pFile->getSize() >= fileHeader.ChunkTableOffset + sizeof(int) + numChunks*sizeof(ChunkHeader)
|
||||
&& numChunks <= (pFile->getSize () - fileHeader.ChunkTableOffset - sizeof(int)) / sizeof(ChunkHeader))
|
||||
{
|
||||
// the file must contain the full chunk table
|
||||
m_pChunks = (const ChunkHeader*)m_pFile->getData(fileHeader.ChunkTableOffset + sizeof(int));
|
||||
|
||||
bool bInvalidChunkOffsetsFound = false; // sets to true if there are chunks pointing outside the raw data section of the file
|
||||
|
||||
// step through all the chunks to fetch file offsets
|
||||
std::set<int> setOffsets;
|
||||
for (nChunk = 0; nChunk < numChunks; ++nChunk)
|
||||
{
|
||||
int nOffset = m_pChunks[nChunk].FileOffset;
|
||||
|
||||
if (nOffset < sizeof(FileHeader) || nOffset >= fileHeader.ChunkTableOffset)
|
||||
{
|
||||
gLastError = "CryFile is corrupted: chunk table is corrupted (invalid chunk offsets found)";
|
||||
bInvalidChunkOffsetsFound = true;
|
||||
}
|
||||
|
||||
setOffsets.insert(nOffset);
|
||||
}
|
||||
m_arrChunkSize.clear();
|
||||
m_arrChunkSize.resize (numChunks);
|
||||
for (nChunk = 0; nChunk < numChunks; ++nChunk)
|
||||
{
|
||||
int nOffset = m_pChunks[nChunk].FileOffset;
|
||||
int nSize = 0; // the size for invalid chunks (with invalid offsets)
|
||||
if (nOffset >= sizeof(FileHeader) && nOffset < fileHeader.ChunkTableOffset)
|
||||
{
|
||||
// find the next offset
|
||||
std::set<int>::const_iterator it = setOffsets.find (nOffset);
|
||||
assert (it != setOffsets.end());
|
||||
assert (*it == nOffset);
|
||||
++it;
|
||||
nSize = (it==setOffsets.end()?fileHeader.ChunkTableOffset:*it) - nOffset;
|
||||
}
|
||||
|
||||
assert (nSize >= 0);
|
||||
m_arrChunkSize[nChunk] = nSize;
|
||||
}
|
||||
|
||||
bSuccess = true;
|
||||
// don't let the files with invalid chunks..
|
||||
//bSuccess = !bInvalidChunkOffsetsFound;
|
||||
}
|
||||
else
|
||||
gLastError = "CryFile is corrupted: chunk table is corrupted or truncated (file too small)";
|
||||
}
|
||||
else
|
||||
gLastError = "CryFile is corrupted: chunk table is trucated (file header is probably corrupted)";
|
||||
}
|
||||
else
|
||||
gLastError = "CryFile is corrupted: header is truncated (file too small)";
|
||||
}
|
||||
else
|
||||
gLastError = "Invalid file mapping passed to CChunkFileReader::open";
|
||||
|
||||
|
||||
if (!bSuccess)
|
||||
close();
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// attaches a new file mapping object to this file reader and checks
|
||||
// whether the file is a valid chunked file
|
||||
bool CChunkFileReader::open(const char* szFileName, unsigned nFlags)
|
||||
{
|
||||
CFileMapping_AutoPtr pFileMapping = new CFileMapping(szFileName, nFlags);
|
||||
if (!pFileMapping->getData())
|
||||
{
|
||||
gLastError = "Cannot open file";
|
||||
return false;
|
||||
}
|
||||
return open (pFileMapping);
|
||||
}
|
||||
|
||||
void CChunkFileReader::close()
|
||||
{
|
||||
m_arrChunkSize.clear();
|
||||
m_pFile = NULL;
|
||||
m_pChunks = NULL;
|
||||
}
|
||||
|
||||
// returns the raw data of the file from the given offset
|
||||
const void* CChunkFileReader::getRawData(unsigned nOffset)const
|
||||
{
|
||||
if ((m_pFile != (CFileMapping*)NULL) && m_pFile->getData())
|
||||
return ((char*)m_pFile->getData())+nOffset;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// retrieves the raw chunk header, as it appears in the file
|
||||
const CChunkFileReader::ChunkHeader& CChunkFileReader::getChunkHeader(int nChunkIdx)const
|
||||
{
|
||||
return m_pChunks[nChunkIdx];
|
||||
}
|
||||
|
||||
|
||||
// returns the raw data of the i-th chunk
|
||||
const void* CChunkFileReader::getChunkData(int nChunkIdx)const
|
||||
{
|
||||
if (nChunkIdx>= 0 && nChunkIdx < numChunks())
|
||||
{
|
||||
int nOffset = m_pChunks[nChunkIdx].FileOffset;
|
||||
if (nOffset < sizeof(FileHeader) || nOffset >= getFileHeader().ChunkTableOffset)
|
||||
return 0;
|
||||
else
|
||||
return m_pFile->getData(nOffset);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// number of chunks
|
||||
int CChunkFileReader::numChunks()const
|
||||
{
|
||||
return (int)m_arrChunkSize.size();
|
||||
}
|
||||
|
||||
// number of chunks of the specified type
|
||||
int CChunkFileReader::numChunksOfType (ChunkTypes nChunkType)const
|
||||
{
|
||||
int nResult = 0;
|
||||
for (int i = 0; i < numChunks(); ++i)
|
||||
{
|
||||
if (m_pChunks[i].ChunkType == nChunkType)
|
||||
++nResult;
|
||||
}
|
||||
return nResult;
|
||||
}
|
||||
|
||||
|
||||
// returns the file headers
|
||||
const CChunkFileReader::FileHeader& CChunkFileReader::getFileHeader() const
|
||||
{
|
||||
return m_pFile?*((const FileHeader*)(m_pFile->getData())):*(const FileHeader*)NULL;
|
||||
}
|
||||
|
||||
bool CChunkFileReader::isValid () const
|
||||
{
|
||||
return m_pFile != (CFileMapping*)NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// calculates the chunk size, based on the very next chunk with greater offset
|
||||
// or the end of the raw data portion of the file
|
||||
int CChunkFileReader::getChunkSize(int nChunkIdx) const
|
||||
{
|
||||
assert (nChunkIdx >= 0 && nChunkIdx < numChunks());
|
||||
return m_arrChunkSize[nChunkIdx];
|
||||
}
|
||||
|
||||
186
ResourceCompilerPC/ChunkFileReader.h
Normal file
186
ResourceCompilerPC/ChunkFileReader.h
Normal file
@@ -0,0 +1,186 @@
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CryEngine Source code
|
||||
//
|
||||
// File:ChunkFileReader.h
|
||||
// Declaration of class CChunkFileReader
|
||||
//
|
||||
// History:
|
||||
// 06/26/2002 :Created by Sergiy Migdalskiy <sergiy@crytek.de>
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
#ifndef _CHUNK_FILE_READER_HDR_
|
||||
#define _CHUNK_FILE_READER_HDR_
|
||||
|
||||
#include "CryHeaders.h"
|
||||
#include "smartptr.h"
|
||||
|
||||
class CFileMapping;
|
||||
TYPEDEF_AUTOPTR(CFileMapping);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Chunk file reader.
|
||||
// Accesses a chunked file structure through file mapping object.
|
||||
// Opens a chunk file and checks for its validity.
|
||||
// If it's invalid, closes it as if there was no open operation.
|
||||
// Error handling is performed through the return value of open: it must
|
||||
// be true for successfully open files
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CChunkFileReader:
|
||||
public _reference_target_t
|
||||
{
|
||||
public:
|
||||
typedef FILE_HEADER FileHeader;
|
||||
typedef CHUNK_HEADER ChunkHeader;
|
||||
|
||||
CChunkFileReader();
|
||||
~CChunkFileReader();
|
||||
|
||||
// attaches the file mapping object to this file reader and checks
|
||||
// whether the file is a valid chunked file
|
||||
bool open(CFileMapping* pFile);
|
||||
|
||||
// attaches a new file mapping object to this file reader and checks
|
||||
// whether the file is a valid chunked file
|
||||
bool open(const char* szFileName, unsigned nFlags = 0);
|
||||
|
||||
bool open (const string& strFileName, unsigned nFlags = 0);
|
||||
|
||||
// closes the file mapping object and thus detaches the file from this reader
|
||||
void close();
|
||||
|
||||
// returns the raw data of the file from the given offset
|
||||
const void* getRawData(unsigned nOffset)const;
|
||||
|
||||
// returns the raw data of the i-th chunk
|
||||
const void* getChunkData(int nChunkIdx)const;
|
||||
|
||||
// retrieves the raw chunk header, as it appears in the file
|
||||
const ChunkHeader& getChunkHeader(int nChunkIdx)const;
|
||||
|
||||
// calculates the chunk size, based on the very next chunk with greater offset
|
||||
// or the end of the raw data portion of the file
|
||||
int getChunkSize(int nChunkIdx) const;
|
||||
|
||||
// number of chunks
|
||||
int numChunks()const;
|
||||
|
||||
// number of chunks of the specified type
|
||||
int numChunksOfType (ChunkTypes nChunkType) const;
|
||||
|
||||
// returns the file headers
|
||||
const FileHeader& getFileHeader() const;
|
||||
|
||||
bool isValid () const;
|
||||
|
||||
const char* getLastError()const {return gLastError;}
|
||||
protected:
|
||||
// this variable contains the last error occured in this class
|
||||
static const char* gLastError;
|
||||
|
||||
CFileMapping_AutoPtr m_pFile;
|
||||
// array of offsets used by the chunks
|
||||
typedef std::vector<int> ChunkSizeArray;
|
||||
ChunkSizeArray m_arrChunkSize;
|
||||
// pointer to the array of chunks in the m_pFile
|
||||
const ChunkHeader* m_pChunks;
|
||||
};
|
||||
|
||||
TYPEDEF_AUTOPTR(CChunkFileReader);
|
||||
|
||||
// this function eats the given number of elements from the raw data pointer pRawData
|
||||
// and increments the pRawData to point to the end of data just eaten
|
||||
template <typename T>
|
||||
void EatRawData (T*pArray, unsigned nSize, const void*&pRawData)
|
||||
{
|
||||
memcpy (pArray, pRawData, sizeof(T)*nSize);
|
||||
pRawData = static_cast<const T*>(pRawData) + nSize;
|
||||
}
|
||||
|
||||
// this function eats the given number of elements from the raw data pointer pRawData
|
||||
// and increments the pRawData to point to the end of data just eaten
|
||||
// RETURNS:
|
||||
// false if failed to read the data
|
||||
template <typename T>
|
||||
bool EatRawData (T*pArray, unsigned nSize, const void*&pRawData, unsigned& nDataSize)
|
||||
{
|
||||
if (sizeof(T)*nSize <= nDataSize)
|
||||
{
|
||||
memcpy (pArray, pRawData, sizeof(T)*nSize);
|
||||
pRawData = static_cast <const T*> (pRawData) + nSize;
|
||||
nDataSize -= sizeof(T)*nSize;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool EatRawData (T*pArray, unsigned nSize, const void*&pRawData, const void* pRawDataEnd)
|
||||
{
|
||||
if ((const char*)pRawData + sizeof(T)*nSize <= (const char*)pRawDataEnd)
|
||||
{
|
||||
memcpy (pArray, pRawData, sizeof(T)*nSize);
|
||||
pRawData = static_cast <const T*> (pRawData) + nSize;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// this function puts the pointer to the data to the given pointer, and moves
|
||||
// the raw data pointer further; if fails, nothing happens and false is returned
|
||||
// PARAMETERS:
|
||||
// pArray - reference to the (pointer) variable to which the pointer to the actual data will be stored
|
||||
// nSize - number of elements in the array (depending on this, the raw data pointer will be moved)
|
||||
// pRawData - reference to the actual raw data pointer, this will be incremented
|
||||
// nDataSize - reference to the data size counter, this will be decremented upon success
|
||||
// RETURNS:
|
||||
// false if failed to read the data
|
||||
template <typename T>
|
||||
bool EatRawDataPtr(const T*&pArray, unsigned nSize, const void*&pRawData, unsigned& nDataSize)
|
||||
{
|
||||
if (sizeof(T)*nSize <= nDataSize)
|
||||
{
|
||||
pArray = (const T*)pRawData;
|
||||
pRawData = static_cast <const T*> (pRawData) + nSize;
|
||||
nDataSize -= sizeof(T)*nSize;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool EatRawDataPtr(const T*&pArray, unsigned nSize, const void*&pRawData, const void* pRawDataEnd)
|
||||
{
|
||||
if ((const char*)pRawData + sizeof(T)*nSize <= (const char*)pRawDataEnd)
|
||||
{
|
||||
pArray = (const T*)pRawData;
|
||||
pRawData = static_cast <const T*> (pRawData) + nSize;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// ... non-const version, this will hardly be ever needed
|
||||
/*
|
||||
template <typename T>
|
||||
bool EatRawDataPtr(T*&pArray, unsigned nSize, void*&pRawData, unsigned& nDataSize)
|
||||
{
|
||||
if (sizeof(T)*nSize <= nDataSize)
|
||||
{
|
||||
pArray = (const T*)pRawData;
|
||||
pRawData = static_cast <const T*> (pRawData) + nSize;
|
||||
nDataSize -= sizeof(T)*nSize;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
129
ResourceCompilerPC/Controller.h
Normal file
129
ResourceCompilerPC/Controller.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Character Animation source code
|
||||
//
|
||||
// History:
|
||||
// Created by Sergiy Migdalskiy
|
||||
//
|
||||
// Notes:
|
||||
// IController interface declaration
|
||||
// See the IController comment for more info
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _CRYTEK_CONTROLLER_HEADER_
|
||||
#define _CRYTEK_CONTROLLER_HEADER_
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "CryHeaders.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// interface IController
|
||||
// Describes the position and orientation of an object, changing in time.
|
||||
// Responsible for loading itself from a binary file, calculations
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
class IController: public _reference_target_t
|
||||
{
|
||||
public:
|
||||
|
||||
// each controller has an ID, by which it is identifiable
|
||||
virtual unsigned GetID () const = 0;
|
||||
|
||||
// returns the orientation of the controller at the given time
|
||||
virtual CryQuat GetOrientation (float t) = 0;
|
||||
|
||||
// returns the orientation of the controller at the given time, in logarithmic space
|
||||
virtual Vec3 GetOrientation2 (float t) = 0;
|
||||
|
||||
// returns position of the controller at the given time
|
||||
virtual Vec3 GetPosition (float t) = 0;
|
||||
|
||||
// returns scale of the controller at the given time
|
||||
virtual Vec3 GetScale (float t) = 0;
|
||||
|
||||
// retrieves the position and orientation within one call
|
||||
// may be optimal in some applications
|
||||
virtual void GetValue (float t, CryQuat& q, Vec3 &p) = 0;
|
||||
|
||||
// retrieves the position and orientation (in the logarithmic space, i.e. instead of quaternion, its logarithm is returned)
|
||||
// may be optimal for motion interpolation
|
||||
struct PQLog
|
||||
{
|
||||
Vec3 vPos;
|
||||
Vec3 vRotLog; // logarithm of the rotation
|
||||
|
||||
string toString()const {return "{pos:" + CryStringUtils::toString(vPos)+", rot="+CryStringUtils::toString (vRotLog) + "}";}
|
||||
|
||||
// returns the rotation quaternion
|
||||
CryQuat getOrientation()const;
|
||||
// resets the state to zero
|
||||
void reset ();
|
||||
// blends the pqSource[0] and pqSource[1] with weights 1-fBlend and fBlend into pqResult
|
||||
void blendPQ (const PQLog* pqSource, float fBlend);
|
||||
// blends the pqFrom and pqTo with weights 1-fBlend and fBlend into pqResult
|
||||
void blendPQ (const PQLog& pqFrom, const PQLog& pqTo, float fBlend);
|
||||
// builds the matrix out of the position and orientation stored in this PQLog
|
||||
void buildMatrix(Matrix44& mat)const;
|
||||
// a special version of the buildMatrix that adds a rotation to the rotation of this PQLog
|
||||
void buildMatrixPlusRot(Matrix44& mat, const CryQuat& qRotPlus) const;
|
||||
// returns the equivalent rotation in logarithmic space (the quaternion of which is negative the original)
|
||||
Vec3 getComplementaryRotLog() const;
|
||||
// constructs the position/rotation from the given matrix
|
||||
void assignFromMatrix (const Matrix44& mat);
|
||||
|
||||
PQLog operator * (float f)const
|
||||
{
|
||||
PQLog res;
|
||||
res.vPos = this->vPos * f;
|
||||
res.vRotLog = this->vRotLog * f;
|
||||
return res;
|
||||
}
|
||||
|
||||
const PQLog& operator += (const PQLog& pq)
|
||||
{
|
||||
this->vPos += pq.vPos;
|
||||
this->vRotLog += pq.vRotLog;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
virtual void GetValue2 (float t, PQLog& pq) = 0;
|
||||
|
||||
// returns the start time
|
||||
virtual float GetTimeStart () = 0;
|
||||
|
||||
// returns the end time
|
||||
virtual float GetTimeEnd() = 0;
|
||||
|
||||
virtual size_t sizeofThis () const = 0;
|
||||
|
||||
virtual bool IsLooping() const { return false; };
|
||||
};
|
||||
|
||||
TYPEDEF_AUTOPTR(IController);
|
||||
//typedef IController*IController_AutoPtr;
|
||||
|
||||
// adjusts the rotation of these PQs: if necessary, flips them or one of them (effectively NOT changing the whole rotation,but
|
||||
// changing the rotation angle to Pi-X and flipping the rotation axis simultaneously)
|
||||
// this is needed for blending between animations represented by quaternions rotated by ~PI in quaternion space
|
||||
// (and thus ~2*PI in real space)
|
||||
extern void AdjustLogRotations (Vec3& vRotLog1, Vec3& vRotLog2);
|
||||
extern void AdjustLogRotationTo (const Vec3& vRotLog1, Vec3& vRotLog2);
|
||||
extern void AdjustLogRotation(Vec3& vRotLog);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// This class is a non-trivial predicate used for sorting an
|
||||
// ARRAY OF smart POINTERS to IController's. That's why I need a separate
|
||||
// predicate class for that. Also, to avoid multiplying predicate classes,
|
||||
// there are a couple of functions that are also used to find a IController
|
||||
// in a sorted by ID array of IController* pointers, passing only ID to the
|
||||
// lower_bound function instead of creating and passing a dummy IController*
|
||||
class AnimCtrlSortPred
|
||||
{
|
||||
public:
|
||||
bool operator() (const IController_AutoPtr& a, const IController_AutoPtr& b) {assert (a!=(IController*)NULL && b != (IController*)NULL); return a->GetID() < b->GetID();}
|
||||
bool operator() (const IController_AutoPtr& a, unsigned nID) {assert (a != (IController*)NULL);return a->GetID() < nID;}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
207
ResourceCompilerPC/CryAnimationInfo.h
Normal file
207
ResourceCompilerPC/CryAnimationInfo.h
Normal file
@@ -0,0 +1,207 @@
|
||||
#ifndef _CRY_ANIMATION_CRY_ANIMATION_INFO_HDR_
|
||||
#define _CRY_ANIMATION_CRY_ANIMATION_INFO_HDR_
|
||||
|
||||
struct AnimEvent { AnimSinkEventData UserData; float fTime; };
|
||||
inline bool operator < (const AnimEvent& left, const AnimEvent& right)
|
||||
{
|
||||
return left.fTime < right.fTime;
|
||||
}
|
||||
// returns true if the given events are equal with the given time tolerance
|
||||
inline bool isEqual (const AnimEvent& left, const AnimEvent& right, float fTolerance = 1e-3f)
|
||||
{
|
||||
return left.UserData == right.UserData
|
||||
&& fabs(left.fTime - right.fTime) < fTolerance;
|
||||
}
|
||||
|
||||
//! this structure contains info about loaded animations
|
||||
struct AnimData
|
||||
{
|
||||
string strName; // the name of the animation (not the name of the file) - unique per-model
|
||||
float fStart, fStop; // start and stop time, in seconds
|
||||
int nGlobalAnimId;
|
||||
bool bLoop;
|
||||
|
||||
AnimData():
|
||||
fStart(0), fStop(0), bLoop(false),
|
||||
nGlobalAnimId (-1)
|
||||
{
|
||||
}
|
||||
bool isStatic () const {return fStart == fStop;}
|
||||
float getLength() const {return fStop - fStart;}
|
||||
|
||||
size_t sizeofThis()const
|
||||
{
|
||||
return sizeof(*this) + strName.capacity();
|
||||
}
|
||||
};
|
||||
|
||||
struct MiniRangeEntity {
|
||||
int start;
|
||||
int end;
|
||||
MiniRangeEntity()
|
||||
{
|
||||
start = end = 0;
|
||||
}
|
||||
void operator = (const RANGE_ENTITY& right)
|
||||
{
|
||||
this->start = right.start;
|
||||
this->end = right.end;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// this is the animation information on the module level (not on the per-model level)
|
||||
// it doesn't know the name of the animation (which is model-specific), but does know the file name
|
||||
// Implements some services for bone binding and ref counting
|
||||
struct GlobalAnimation
|
||||
{
|
||||
// Since we know the number of controllers per animation from the beginning and don't
|
||||
// change it, we could use more econimical TFixedArray here instead of STL or other array.
|
||||
typedef IController_AutoArray ControllerArray;
|
||||
|
||||
// the flags used in the nFlags member
|
||||
enum
|
||||
{
|
||||
// if this is true, then the animation has valid info data (has been loaded at least once)
|
||||
FLAGS_INFO_LOADED = 1,
|
||||
// this doesn't allow the auto-unloading to happen
|
||||
FLAGS_DISABLE_AUTO_UNLOAD = 1 << 1,
|
||||
// this forces the animation to be loaded immediately
|
||||
FLAGS_DISABLE_DELAY_LOAD = 1 << 2,
|
||||
// this disables the error log in LoadAnimation() in case the animation wasn't found on disk
|
||||
FLAGS_DISABLE_LOAD_ERROR_LOG = 1 << 3,
|
||||
|
||||
// if this flag is set, it means that the animation is being loaded right now via asynchronous operation
|
||||
// and shouldn't be attempted to be played back or loaded
|
||||
FLAGS_LOAD_PENDING = 1 << 4,
|
||||
|
||||
// this is the flag combination that should be applied only to default animations
|
||||
FLAGS_DEFAULT_ANIMATION = FLAGS_DISABLE_DELAY_LOAD|FLAGS_DISABLE_LOAD_ERROR_LOG,
|
||||
|
||||
// combination of all possible flags
|
||||
FLAGS_ALL_FLAGS = (1<<5) - 1,
|
||||
|
||||
// the flags by default
|
||||
FLAGS_DEFAULT_FLAGS = 0
|
||||
};
|
||||
|
||||
GlobalAnimation ()
|
||||
{
|
||||
// some standard values to fill in before the animation will be loaded
|
||||
nRefCount = 0;
|
||||
nFlags = FLAGS_DEFAULT_FLAGS;
|
||||
fSecsPerTick = 0.000208f;
|
||||
nLastAccessFrameId = g_nFrameID;
|
||||
nTickCount = nStartCount = nApplyCount = 0;
|
||||
nTicksPerFrame = 160;
|
||||
// the defaults that are anyway immediately overridden
|
||||
fScale = 0.01f;
|
||||
rangeGlobal.end = 900; // this is in ticks, means 30 frames
|
||||
}
|
||||
|
||||
IController*GetController(unsigned nControllerID)
|
||||
{
|
||||
ControllerArray::iterator it = std::lower_bound(arrCtrls.begin(), arrCtrls.end(), nControllerID, AnimCtrlSortPred());
|
||||
if (it != arrCtrls.end() && (*it)->GetID() == nControllerID)
|
||||
{
|
||||
IController *c = *it;
|
||||
#ifdef _DEBUG
|
||||
// set this to true in the debugger to obtain the 0th frame p and q
|
||||
bool bCheck = false;
|
||||
if (bCheck)
|
||||
{
|
||||
CryQuat q; Vec3d p;
|
||||
c->GetValue(0, q, p);
|
||||
}
|
||||
#endif
|
||||
return c;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool IsLoaded()const {return !arrCtrls.empty();}
|
||||
|
||||
bool IsInfoLoaded()const {return (nFlags&FLAGS_INFO_LOADED) != 0;}
|
||||
void OnInfoLoaded() {nFlags |= FLAGS_INFO_LOADED;}
|
||||
bool IsAutoUnload()const {return (nFlags&FLAGS_DISABLE_AUTO_UNLOAD)== 0;}
|
||||
|
||||
void OnTick ()
|
||||
{
|
||||
++nTickCount;
|
||||
nLastAccessFrameId = g_nFrameID;
|
||||
}
|
||||
void OnStart()
|
||||
{
|
||||
++nStartCount;
|
||||
nLastAccessFrameId = g_nFrameID;
|
||||
}
|
||||
void OnApply()
|
||||
{
|
||||
++nApplyCount;
|
||||
nLastAccessFrameId = g_nFrameID;
|
||||
}
|
||||
|
||||
void AddRef()
|
||||
{
|
||||
++nRefCount;
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
if (!--nRefCount)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
for (ControllerArray::iterator it = arrCtrls.begin(); it!= arrCtrls.end(); ++it)
|
||||
assert ((*it)->NumRefs()==1); // only this object references the controllers now
|
||||
#endif
|
||||
arrCtrls.clear(); // nobody uses the controllers; clean them up. This makes the animation effectively unloaded
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
// returns the maximum reference counter from all controllers. 1 means that nobody but this animation
|
||||
// structure refers to them
|
||||
int MaxControllerRefCount()
|
||||
{
|
||||
if (arrCtrls.empty())
|
||||
return 0;
|
||||
int nMax = arrCtrls[0]->NumRefs();
|
||||
for (ControllerArray::iterator it = arrCtrls.begin()+1; it!= arrCtrls.end(); ++it)
|
||||
if((*it)->NumRefs() > nMax)
|
||||
nMax = (*it)->NumRefs();
|
||||
return nMax;
|
||||
}
|
||||
#endif
|
||||
size_t sizeofThis ()const;
|
||||
|
||||
|
||||
|
||||
// controllers comprising the animation; within the animation, they're sorted by ids
|
||||
ControllerArray arrCtrls;
|
||||
// timing data, retrieved from the timing_chunk_desc
|
||||
int nTicksPerFrame;
|
||||
float fSecsPerTick;
|
||||
float fScale; // the parameter from the initial load animation, used for reloadin
|
||||
|
||||
MiniRangeEntity rangeGlobal;
|
||||
|
||||
// the file name of the animation
|
||||
string strFileName;
|
||||
|
||||
// the number of times this animation has been accessed
|
||||
unsigned nTickCount;
|
||||
// the number of times this animation has been started
|
||||
unsigned nStartCount;
|
||||
// the number of times this animation has been applied to bones
|
||||
unsigned nApplyCount;
|
||||
// the last time the animation has been accessed
|
||||
int nLastAccessFrameId;
|
||||
// the number of referrers to this global animation record (doesn't matter if the controllers are currently loaded)
|
||||
int nRefCount;
|
||||
// the flags (see the enum in the top of the declaration)
|
||||
unsigned nFlags;
|
||||
};
|
||||
|
||||
#endif
|
||||
186
ResourceCompilerPC/CryBoneDesc.cpp
Normal file
186
ResourceCompilerPC/CryBoneDesc.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
#include "stdafx.h"
|
||||
#include "MathUtils.h"
|
||||
#include "CryBoneDesc.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
using namespace CryStringUtils;
|
||||
|
||||
CryBoneDesc::CryBoneDesc()
|
||||
{
|
||||
m_PhysInfo[0].pPhysGeom = m_PhysInfo[1].pPhysGeom = 0;
|
||||
m_matInvDefGlobal.SetIdentity();; // allows to get difference to def pose matrices
|
||||
}
|
||||
|
||||
CryBoneDesc::~CryBoneDesc()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// loads the bone from a raw chunk data (no header)
|
||||
// PARAMETERS:
|
||||
// pEntity - the chunk data to load the bone info from
|
||||
// RETURNS:
|
||||
// false if the bone couldn't be loaded
|
||||
bool CryBoneDesc::LoadRaw (const BONE_ENTITY* pEntity)
|
||||
{
|
||||
//read bone info
|
||||
assert(pEntity->nChildren<200);
|
||||
|
||||
// update the lod 0 physics of this bone
|
||||
UpdatePhysics (*pEntity, 0);
|
||||
|
||||
//get bone info
|
||||
m_nControllerID = pEntity->ControllerID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// updates this bone physics, from the given entity descriptor, and of the given lod
|
||||
void CryBoneDesc::UpdatePhysics (const BONE_ENTITY& entity, int nLod)
|
||||
{
|
||||
assert (nLod >= 0 && nLod < SIZEOF_ARRAY(m_PhysInfo));
|
||||
CopyPhysInfo(m_PhysInfo[nLod], entity.phys);
|
||||
|
||||
int nFlags = 0;
|
||||
if (entity.prop[0])
|
||||
{
|
||||
nFlags = joint_no_gravity|joint_isolated_accelerations;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!strnstr(entity.prop,"gravity", sizeof(entity.prop)))
|
||||
nFlags |= joint_no_gravity;
|
||||
|
||||
if (!strnstr(entity.prop,"physical",sizeof(entity.prop)))
|
||||
nFlags |= joint_isolated_accelerations;
|
||||
}
|
||||
|
||||
m_PhysInfo[nLod].flags |= nFlags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Performs post-initialization. This step is requred to initialize the pPhysGeom of the bones
|
||||
//! After the bone has been loaded but before it is first used. When the bone is first loaded, pPhysGeom
|
||||
//! is set to the value equal to the chunk id in the file where the physical geometry (BoneMesh) chunk is kept.
|
||||
//! After those chunks are loaded, and chunk ids are mapped to the registered physical geometry objects,
|
||||
//! call this function to replace pPhysGeom chunk ids with the actual physical geometry object pointers.
|
||||
//! RETURNS:
|
||||
// true if the corresponding physical geometry object has been found
|
||||
//! NOTE:
|
||||
//! The entries of the map that were used are deleted
|
||||
bool CryBoneDesc::PostInitPhysGeom (ChunkIdToPhysGeomMap& mapChunkIdToPhysGeom, int nLodLevel)
|
||||
{
|
||||
phys_geometry*& pPhysGeom = m_PhysInfo[nLodLevel].pPhysGeom;
|
||||
ChunkIdToPhysGeomMap::iterator it = mapChunkIdToPhysGeom.find ((INT_PTR)pPhysGeom);
|
||||
if (it != mapChunkIdToPhysGeom.end())
|
||||
{
|
||||
// remap the chunk id to the actual pointer to the geometry
|
||||
pPhysGeom = it->second;
|
||||
mapChunkIdToPhysGeom.erase (it);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPhysGeom = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// sets the name of the bone out of the given buffer of the given max size
|
||||
void CryBoneDesc::setName (const char* szName)
|
||||
{
|
||||
m_strName.assign (szName);
|
||||
|
||||
static const char *g_arrLimbNames[4] = { "L UpperArm","R UpperArm","L Thigh","R Thigh" };
|
||||
m_nLimbId = -1;
|
||||
for (int j=0; j < SIZEOF_ARRAY(g_arrLimbNames) ;j++)
|
||||
if (strstr(szName,g_arrLimbNames[j]))
|
||||
{
|
||||
m_nLimbId = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// returns the bone name, if available
|
||||
const char* CryBoneDesc::getNameCStr()const
|
||||
{
|
||||
return m_strName.c_str();
|
||||
}
|
||||
|
||||
const string& CryBoneDesc::getName()const
|
||||
{
|
||||
return m_strName;
|
||||
}
|
||||
|
||||
// compares two bone descriptions and returns true if they're the same bone
|
||||
// (the same name and the same position in the hierarchy)
|
||||
bool CryBoneDesc::isEqual (const CryBoneDesc& desc)const
|
||||
{
|
||||
return m_strName == desc.m_strName
|
||||
&& m_nControllerID == desc.m_nControllerID
|
||||
&& m_nOffsetParent == desc.m_nOffsetParent
|
||||
&& m_numChildren == desc.m_numChildren
|
||||
&& m_nOffsetChildren == desc.m_nOffsetChildren;
|
||||
}
|
||||
|
||||
|
||||
inline size_t align4 (size_t x)
|
||||
{
|
||||
return (x + 3)&~3;
|
||||
}
|
||||
|
||||
// Serializes the description:
|
||||
// returns the number of required bytes for serialization, if the data pointer is NULL
|
||||
// returns 0 (if the buffer size is not enough) or the number of bytes written, if the data pointer is given
|
||||
unsigned CryBoneDesc::Serialize (bool bSave, void *pStream, unsigned nSize)
|
||||
{
|
||||
if (bSave)
|
||||
{
|
||||
unsigned nSizeRequired = (unsigned)(sizeof(CryBoneDescData_Comp) + align4 (m_strName.length()+1));
|
||||
if (!pStream)
|
||||
return nSizeRequired;
|
||||
if (nSize < nSizeRequired)
|
||||
return 0;
|
||||
|
||||
CopyCryBone(*(CryBoneDescData_Comp*)pStream, *this);
|
||||
memcpy ((CryBoneDescData_Comp*)pStream+1,m_strName.c_str(),m_strName.length()+1);
|
||||
return nSizeRequired;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pStream)
|
||||
return 0;
|
||||
if (nSize < sizeof(CryBoneDescData_Comp)+1)
|
||||
return 0;
|
||||
if (nSize & 3)
|
||||
return 0; // alignment error
|
||||
CopyCryBone(*this, *(CryBoneDescData_Comp*)pStream);
|
||||
// end of the stream
|
||||
const char* pEnd = (const char*)pStream + nSize;
|
||||
// the start byte of the bone name
|
||||
const char* pName = (const char*)((CryBoneDescData_Comp*)pStream+1);
|
||||
|
||||
// scan until the end of the name (\0 char) or the stream (pEnd address)
|
||||
const char *pNameEnd;
|
||||
for (pNameEnd = pName; pNameEnd < pEnd && *pNameEnd; ++pNameEnd);
|
||||
m_strName.assign (pName, pNameEnd);
|
||||
// return aligned size of the chunk including the string 0 terminator, but
|
||||
// no more than the declared size of the stream
|
||||
return min(nSize, (unsigned)align4 (pNameEnd+1-(const char*)pStream));
|
||||
}
|
||||
}
|
||||
|
||||
void CryBoneDesc::setDefaultGlobal(const Matrix44& matDefault)
|
||||
{
|
||||
m_matInvDefGlobal=OrthoUniformGetInverted (matDefault);
|
||||
}
|
||||
|
||||
|
||||
// scales the bone with the given multiplier
|
||||
void CryBoneDesc::scale (float fScale)
|
||||
{
|
||||
m_matInvDefGlobal.SetTranslationOLD(m_matInvDefGlobal.GetTranslationOLD()*fScale);
|
||||
}
|
||||
170
ResourceCompilerPC/CryBoneDesc.h
Normal file
170
ResourceCompilerPC/CryBoneDesc.h
Normal file
@@ -0,0 +1,170 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Character Animation source code
|
||||
//
|
||||
// File:CryBoneDesc.h
|
||||
//
|
||||
// History:
|
||||
// Created by Sergiy Migdalskiy 01/14/2003
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _CRY_BONE_DESC_HDR_
|
||||
#define _CRY_BONE_DESC_HDR_
|
||||
|
||||
// this class contains the information that's common to all instances of bones
|
||||
// in the given model: like bone name, and misc. shared properties
|
||||
// We use a base structure to separate the bunch of parameters that get serialized
|
||||
// together
|
||||
#pragma pack(push,4)
|
||||
template <class TBonePhysics>
|
||||
struct TCryBoneDescData
|
||||
{
|
||||
unsigned int m_nControllerID; // unic id of bone (generated from bone name in the max)
|
||||
|
||||
// [Sergiy] physics info for different lods
|
||||
// lod 0 is the physics of alive body, lod 1 is the physics of a dead body
|
||||
TBonePhysics m_PhysInfo[2];
|
||||
float m_fMass;
|
||||
|
||||
Matrix44 m_matInvDefGlobal; // allows to get difference to def pose matrices
|
||||
|
||||
int m_nLimbId; // set by model state class
|
||||
|
||||
// this bone parent is this[m_nOffsetParent], 0 if the bone is root. Normally this is <= 0
|
||||
int m_nOffsetParent;
|
||||
|
||||
// The whole hierarchy of bones is kept in one big array that belongs to the ModelState
|
||||
// Each bone that has children has its own range of bone objects in that array,
|
||||
// and this points to the beginning of that range and defines the number of bones.
|
||||
unsigned m_numChildren;
|
||||
// the beginning of the subarray of children is at this[m_nOffsetChildren]
|
||||
// this is 0 if there are no children
|
||||
int m_nOffsetChildren;
|
||||
};
|
||||
|
||||
typedef TCryBoneDescData<BONE_PHYSICS> CryBoneDescData;
|
||||
// compatible structure
|
||||
typedef TCryBoneDescData<BONE_PHYSICS_COMP> CryBoneDescData_Comp;
|
||||
|
||||
#define __copy(x) left.x = right.x
|
||||
|
||||
inline void CopyCryBone (CryBoneDescData_Comp& left, const CryBoneDescData& right)
|
||||
{
|
||||
__copy(m_nControllerID);
|
||||
CopyPhysInfo (left.m_PhysInfo[0], right.m_PhysInfo[0]);
|
||||
CopyPhysInfo (left.m_PhysInfo[1], right.m_PhysInfo[1]);
|
||||
__copy(m_fMass);
|
||||
__copy(m_matInvDefGlobal);
|
||||
__copy(m_nLimbId);
|
||||
__copy(m_nOffsetParent);
|
||||
__copy(m_numChildren);
|
||||
__copy(m_nOffsetChildren);
|
||||
}
|
||||
|
||||
inline void CopyCryBone (CryBoneDescData& left, const CryBoneDescData_Comp& right)
|
||||
{
|
||||
__copy(m_nControllerID);
|
||||
CopyPhysInfo (left.m_PhysInfo[0], right.m_PhysInfo[0]);
|
||||
CopyPhysInfo (left.m_PhysInfo[1], right.m_PhysInfo[1]);
|
||||
__copy(m_fMass);
|
||||
__copy(m_matInvDefGlobal);
|
||||
__copy(m_nLimbId);
|
||||
__copy(m_nOffsetParent);
|
||||
__copy(m_numChildren);
|
||||
__copy(m_nOffsetChildren);
|
||||
}
|
||||
|
||||
#undef __copy
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
|
||||
class CryBoneDesc: public CryBoneDescData
|
||||
{
|
||||
public:
|
||||
CryBoneDesc ();
|
||||
~CryBoneDesc ();
|
||||
|
||||
// returns the bone name, if available
|
||||
const char* getNameCStr()const;
|
||||
const string& getName()const;
|
||||
|
||||
unsigned getControllerId()const {return m_nControllerID;}
|
||||
|
||||
// sets the name of the bone out of the given buffer of the given max size
|
||||
void setName (const char* szName);
|
||||
|
||||
unsigned numChildren ()const {return m_numChildren;}
|
||||
bool hasParent() const {return m_nOffsetParent != 0;}
|
||||
int getParentIndexOffset()const {return m_nOffsetParent;}
|
||||
int getFirstChildIndexOffset() const {return m_nOffsetChildren;}
|
||||
|
||||
const Matrix44& getInvDefGlobal() const {return m_matInvDefGlobal;}
|
||||
void setDefaultGlobal(const Matrix44& mxDefault);
|
||||
int getLimbId () const {return m_nLimbId;}
|
||||
|
||||
BONE_PHYSICS& getPhysInfo (int nLod) {return m_PhysInfo[nLod];}
|
||||
|
||||
// updates this bone physics, from the given entity descriptor, and of the given lod
|
||||
void UpdatePhysics (const BONE_ENTITY& entity, int nLod);
|
||||
void setPhysics (int nLod, const BONE_PHYSICS& BonePhysics)
|
||||
{
|
||||
assert (nLod >= 0 && nLod < sizeof(m_PhysInfo)/sizeof(m_PhysInfo[0]));
|
||||
m_PhysInfo[nLod] = BonePhysics;
|
||||
}
|
||||
// the physics for the given LOD is not available
|
||||
void resetPhysics (int nLod)
|
||||
{
|
||||
assert (nLod >= 0 && nLod < sizeof(m_PhysInfo)/sizeof(m_PhysInfo[0]));
|
||||
memset (&m_PhysInfo[nLod], 0, sizeof(m_PhysInfo[nLod]));
|
||||
}
|
||||
const BONE_PHYSICS& getPhysics (int nLod)const
|
||||
{
|
||||
assert (nLod >= 0 && nLod < sizeof(m_PhysInfo)/sizeof(m_PhysInfo[0]));
|
||||
return m_PhysInfo[nLod];
|
||||
}
|
||||
|
||||
// Returns the id of the bone mesh chunk from which the bone physical geometry
|
||||
// should be taken. The caller should take this id, find the corresponding chunk in the CCG/CGF file
|
||||
// and construct physical geometry using IGeomManager::CreateMesh.
|
||||
// Then, register it with RegisterGeometry(). It will return phys_geometry* that the caller
|
||||
// should put into the corresponding LOD m_PhysInfo.pPhysGeom
|
||||
// CryBoneInfo::PostInitPhysGeom uses this same id to find the physical geometry in the map
|
||||
INT_PTR getPhysGeomId (unsigned nLOD) {return (INT_PTR)m_PhysInfo[nLOD].pPhysGeom;}
|
||||
|
||||
// compares two bone descriptions and returns true if they're the same bone
|
||||
// (the same name and the same position in the hierarchy)
|
||||
bool isEqual(const CryBoneDesc& desc)const;
|
||||
|
||||
// Serializes the description:
|
||||
// returns the number of required bytes for serialization, if the data pointer is NULL
|
||||
// returns 0 (if the buffer size is not enough) or the number of bytes written, if the data pointer is given
|
||||
unsigned Serialize (bool bSave, void *pStream, unsigned nSize);
|
||||
|
||||
// scales the bone with the given multiplier
|
||||
void scale (float fScale);
|
||||
|
||||
protected:
|
||||
|
||||
// loads the bone from a raw chunk data (no header)
|
||||
// returns false if the bone couldn't be loaded
|
||||
bool LoadRaw (const BONE_ENTITY* pEntity);
|
||||
|
||||
//! Performs post-initialization. This step is requred to initialize the pPhysGeom of the bones
|
||||
//! After the bone has been loaded but before it is first used. When the bone is first loaded, pPhysGeom
|
||||
//! is set to the value equal to the chunk id in the file where the physical geometry (BoneMesh) chunk is kept.
|
||||
//! After those chunks are loaded, and chunk ids are mapped to the registered physical geometry objects,
|
||||
//! call this function to replace pPhysGeom chunk ids with the actual physical geometry object pointers.
|
||||
//! NOTE:
|
||||
//! The entries of the map that were used are deleted
|
||||
typedef std::map<INT_PTR, struct phys_geometry*> ChunkIdToPhysGeomMap;
|
||||
bool PostInitPhysGeom (ChunkIdToPhysGeomMap& mapChunkIdToPhysGeom, int nLodLevel);
|
||||
|
||||
friend class CryBoneHierarchyLoader;
|
||||
|
||||
protected:
|
||||
string m_strName;
|
||||
};
|
||||
|
||||
#endif
|
||||
366
ResourceCompilerPC/CrySkinAMD64.asm
Normal file
366
ResourceCompilerPC/CrySkinAMD64.asm
Normal file
@@ -0,0 +1,366 @@
|
||||
|
||||
;****************************************************************************
|
||||
;*
|
||||
;* This is the 64bit SSE-version of CrySkinFull.cpp.
|
||||
;* Rewritten by Ivo Herzeg
|
||||
;*
|
||||
;* Entry parameters:
|
||||
;*
|
||||
;* rcx = pAux
|
||||
;* rdx = pVertex
|
||||
;* r8 = pDest
|
||||
;* r9 = pBone
|
||||
;* [rSP+60] = pvMin ; After the call but before the push rbp
|
||||
;* [rSP+68] = pBoneEnd
|
||||
;*
|
||||
;****************************************************************************
|
||||
|
||||
|
||||
CRY_SKIN_AUX_INT_SIZE equ 2 ; This must match the define in CrySkinTypes.h
|
||||
|
||||
pvMin = 060h ; After the push rbp
|
||||
pBoneEnd = 068h ; "
|
||||
|
||||
|
||||
|
||||
X00 = 000h
|
||||
X10 = 004h
|
||||
X20 = 008h
|
||||
|
||||
Y01 = 010h
|
||||
Y11 = 014h
|
||||
Y21 = 018h
|
||||
|
||||
Z02 = 020h
|
||||
Z12 = 024h
|
||||
Z22 = 028h
|
||||
|
||||
TransX = 030h ; After the push rbp
|
||||
TransY = 034h ; After the push rbp
|
||||
TransZ = 038h ; After the push rbp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_data SEGMENT
|
||||
align 16
|
||||
var6 qword 0,0
|
||||
var7 qword 0,0
|
||||
var8 qword 0,0
|
||||
var9 qword 0,0
|
||||
var10 qword 0,0
|
||||
var11 qword 0,0
|
||||
var12 qword 0,0
|
||||
var13 qword 0,0
|
||||
var14 qword 0,0
|
||||
var15 qword 0,0
|
||||
|
||||
_text SEGMENT
|
||||
PUBLIC Amd64Skinner
|
||||
|
||||
|
||||
Amd64Skinner PROC FRAME
|
||||
|
||||
push rBP
|
||||
push rSI
|
||||
push rDI
|
||||
|
||||
push rAX
|
||||
push rBX
|
||||
push rCX
|
||||
push rDX
|
||||
|
||||
movdqa var6,xmm6
|
||||
movdqa var7,xmm7
|
||||
movdqa var8,xmm8
|
||||
movdqa var9,xmm9
|
||||
movdqa var10,xmm10
|
||||
movdqa var11,xmm11
|
||||
movdqa var12,xmm12
|
||||
movdqa var13,xmm13
|
||||
movdqa var14,xmm14
|
||||
movdqa var15,xmm15
|
||||
|
||||
|
||||
; For debug, I will copy the parameters into the same registers which Crytek used in the inline assembler.
|
||||
|
||||
mov rSI, rdx ;parameter 1
|
||||
mov rDX, rcx ;parameter 2
|
||||
mov rDI, r8 ;parameter 3
|
||||
; mov qqqqq, r9 ;parameter 4 //pointer to the matrix stack
|
||||
|
||||
|
||||
startLoop:
|
||||
cmp r9, pBoneEnd[rSP]
|
||||
jz endLoop
|
||||
|
||||
; load the current matrix; we don't need the move component
|
||||
movss xmm9, [r9+X00]
|
||||
movss xmm10, [r9+Y01]
|
||||
movss xmm11, [r9+X10]
|
||||
movss xmm12, [r9+Y11]
|
||||
movss xmm13, [r9+X20]
|
||||
movss xmm14, [r9+Y21]
|
||||
|
||||
; load the counter for the number of non-flipped tangets for this bone
|
||||
xor rCX,rCX
|
||||
mov CX, word ptr [rdx] ; Was mov CX, word ptr [EDX]
|
||||
add rDX, 2 ; add EDX, 2
|
||||
test eCX, eCX
|
||||
jz endLoopRigid
|
||||
|
||||
startLoopRigid:
|
||||
|
||||
; calculate the destination pointer
|
||||
mov rax, [rSI+0Ch]
|
||||
and rax, 0FFFFFFh
|
||||
add rax, rax
|
||||
|
||||
prefetch [rSI+140h]
|
||||
|
||||
movss xmm0, [rSI+00h] ;x
|
||||
movss xmm3, xmm0
|
||||
movss xmm1, [rSI+04h] ;y
|
||||
movss xmm4, xmm1
|
||||
movss xmm2, [rSI+08h] ;z
|
||||
movss xmm5, xmm2
|
||||
|
||||
prefetchw [rDI+rax*8+40h]
|
||||
|
||||
movss xmm6, xmm0
|
||||
movss xmm7, xmm1
|
||||
movss xmm8, xmm2
|
||||
|
||||
mulss xmm0, xmm13 ;x*M20
|
||||
mulss xmm1, xmm14 ;y*M21
|
||||
mulss xmm2, [r9+Z22] ;z*M22
|
||||
addss xmm0, [r9+TransZ]
|
||||
addss xmm1, xmm2
|
||||
addss xmm0, xmm1
|
||||
|
||||
|
||||
mulss xmm3, xmm9 ;x*M00
|
||||
mulss xmm4, xmm10 ;y*M01
|
||||
mulss xmm5, [r9+Z02] ;z*M02
|
||||
addss xmm3, [r9+TransX]
|
||||
addss xmm4, xmm5
|
||||
addss xmm3, xmm4
|
||||
|
||||
mulss xmm6, xmm11 ;x*M10
|
||||
mulss xmm7, xmm12 ;y*M11
|
||||
mulss xmm8, [r9+Z12] ;z*M12
|
||||
addss xmm6, [r9+TransY]
|
||||
addss xmm7, xmm8
|
||||
addss xmm6, xmm7
|
||||
|
||||
movss [rDI+rAX*8+08h], xmm0
|
||||
movss [rDI+rAX*8+00h], xmm3
|
||||
movss [rDI+rAX*8+04h], xmm6
|
||||
|
||||
add rSI, 010h ; rdi+rax*8 (EDI+EAX*8) points to the destination vector now
|
||||
dec eCX
|
||||
jnz startLoopRigid
|
||||
endLoopRigid:
|
||||
|
||||
|
||||
|
||||
;/////////////////////////////////////////////////////////
|
||||
;// Smooth-1 loop
|
||||
;/////////////////////////////////////////////////////////
|
||||
|
||||
movss xmm9, [r9+X00]
|
||||
movss xmm10, [r9+Y01]
|
||||
movss xmm11, [r9+X10]
|
||||
movss xmm12, [r9+Y11]
|
||||
movss xmm13, [r9+X20]
|
||||
movss xmm14, [r9+Y21]
|
||||
|
||||
|
||||
; load the counter for the number of smooth vertices met for the first time
|
||||
xor ECX,ECX
|
||||
mov CX, word ptr [rdx]
|
||||
add rDX, 2
|
||||
test ECX, ECX
|
||||
jz endLoopSmooth1
|
||||
|
||||
|
||||
startLoopSmooth1:
|
||||
|
||||
; calculate the destination pointer
|
||||
xor EAX,EAX
|
||||
mov AX, word ptr [rdx]
|
||||
add rDX, 2
|
||||
shl rAX,1
|
||||
|
||||
|
||||
prefetch [rSI+140h]
|
||||
|
||||
movss xmm0, [rSI+00h] ;x
|
||||
movss xmm3, xmm0
|
||||
movss xmm1, [rSI+04h] ;y
|
||||
movss xmm4, xmm1
|
||||
movss xmm2, [rSI+08h] ;z
|
||||
movss xmm5, xmm2
|
||||
movss xmm15, [rSI+0ch] ;w
|
||||
|
||||
prefetchw [rDI+rax*8+40h]
|
||||
|
||||
movss xmm6, xmm0
|
||||
movss xmm7, xmm1
|
||||
movss xmm8, xmm2
|
||||
|
||||
mulss xmm0, xmm13 ;x*M20
|
||||
mulss xmm1, xmm14 ;y*M21
|
||||
mulss xmm2, [r9+Z22] ;z*M22
|
||||
addss xmm0, [r9+TransZ]
|
||||
addss xmm1, xmm2
|
||||
addss xmm0, xmm1
|
||||
|
||||
mulss xmm3, xmm9 ;x*M00
|
||||
mulss xmm4, xmm10 ;y*M01
|
||||
mulss xmm5, [r9+Z02] ;z*M02
|
||||
addss xmm3, [r9+TransX]
|
||||
addss xmm4, xmm5
|
||||
addss xmm3, xmm4
|
||||
|
||||
mulss xmm6, xmm11 ;x*M10
|
||||
mulss xmm7, xmm12 ;y*M11
|
||||
mulss xmm8, [r9+Z12] ;z*M12
|
||||
addss xmm6, [r9+TransY]
|
||||
addss xmm7, xmm8
|
||||
addss xmm6, xmm7
|
||||
|
||||
mulss xmm0, xmm15 ;Z*weight
|
||||
mulss xmm3, xmm15 ;X*weight
|
||||
mulss xmm6, xmm15 ;Y*weight
|
||||
|
||||
add rSI, 010h
|
||||
dec eCX
|
||||
|
||||
movss [rDI+rAX*8+08h], xmm0
|
||||
movss [rDI+rAX*8+00h], xmm3
|
||||
movss [rDI+rAX*8+04h], xmm6
|
||||
|
||||
jnz startLoopSmooth1
|
||||
endLoopSmooth1:
|
||||
|
||||
|
||||
|
||||
|
||||
;//////////////////////////////////////////////////////////////////
|
||||
;// Smooth-2 loop
|
||||
;//////////////////////////////////////////////////////////////////
|
||||
|
||||
movss xmm9, [r9+X00]
|
||||
movss xmm10, [r9+Y01]
|
||||
movss xmm11, [r9+X10]
|
||||
movss xmm12, [r9+Y11]
|
||||
movss xmm13, [r9+X20]
|
||||
movss xmm14, [r9+Y21]
|
||||
|
||||
|
||||
;// load the counter for the number of smooth vertices met for the second time
|
||||
xor ECX,ECX
|
||||
mov CX, word ptr [rdx]
|
||||
add rdx, 2
|
||||
test ECX, ECX
|
||||
jz endLoopSmooth2
|
||||
|
||||
startLoopSmooth2:
|
||||
|
||||
; calculate the destination pointer
|
||||
xor EAX,EAX
|
||||
mov ax, word ptr [rdx]
|
||||
add rdx, 2
|
||||
shl rax, 4
|
||||
|
||||
prefetch [rSI+140h]
|
||||
|
||||
movss xmm0, [rSI+00h] ;x
|
||||
movss xmm3, xmm0
|
||||
movss xmm1, [rSI+04h] ;y
|
||||
movss xmm4, xmm1
|
||||
movss xmm2, [rSI+08h] ;z
|
||||
movss xmm5, xmm2
|
||||
movss xmm15, [rSI+0ch] ;w
|
||||
|
||||
prefetchw [rDI+rAX+40h]
|
||||
|
||||
movss xmm6, xmm0
|
||||
movss xmm7, xmm1
|
||||
movss xmm8, xmm2
|
||||
|
||||
mulss xmm0, xmm13 ;x*M20
|
||||
mulss xmm1, xmm14 ;y*M21
|
||||
mulss xmm2, [r9+Z22] ;z*M22
|
||||
addss xmm0, [r9+TransZ]
|
||||
addss xmm1, xmm2
|
||||
addss xmm0, xmm1
|
||||
|
||||
mulss xmm3, xmm9 ;x*M00
|
||||
mulss xmm4, xmm10 ;y*M01
|
||||
mulss xmm5, [r9+Z02] ;z*M02
|
||||
addss xmm3, [r9+TransX]
|
||||
addss xmm4, xmm5
|
||||
addss xmm3, xmm4
|
||||
|
||||
mulss xmm6, xmm11 ;x*M10
|
||||
mulss xmm7, xmm12 ;y*M11
|
||||
mulss xmm8, [r9+Z12] ;z*M12
|
||||
addss xmm6, [r9+TransY]
|
||||
addss xmm7, xmm8
|
||||
addss xmm6, xmm7
|
||||
|
||||
mulss xmm0, xmm15 ;Z*weight
|
||||
mulss xmm3, xmm15 ;X*weight
|
||||
mulss xmm6, xmm15 ;Y*weight
|
||||
|
||||
add rSI, 010h
|
||||
dec eCX
|
||||
|
||||
addss xmm0,[rDI+rAX+08h]
|
||||
addss xmm3,[rDI+rAX+00h]
|
||||
addss xmm6,[rDI+rAX+04h]
|
||||
|
||||
movss [rDI+rAX+08h], xmm0
|
||||
movss [rDI+rAX+00h], xmm3
|
||||
movss [rDI+rAX+04h], xmm6
|
||||
|
||||
jnz startLoopSmooth2
|
||||
|
||||
endLoopSmooth2:
|
||||
|
||||
add r9, 040h
|
||||
jmp startLoop
|
||||
endLoop:
|
||||
|
||||
|
||||
movdqa xmm6, var6
|
||||
movdqa xmm7, var7
|
||||
movdqa xmm8, var8
|
||||
movdqa xmm9, var9
|
||||
movdqa xmm10, var10
|
||||
movdqa xmm11, var11
|
||||
movdqa xmm12, var12
|
||||
movdqa xmm13, var13
|
||||
movdqa xmm14, var14
|
||||
movdqa xmm15, var15
|
||||
|
||||
pop rDX
|
||||
pop rCX
|
||||
pop rBX
|
||||
pop rAX
|
||||
pop rDI
|
||||
pop rSI
|
||||
pop rBP
|
||||
ret
|
||||
|
||||
Amd64Skinner ENDP
|
||||
|
||||
_text ENDS
|
||||
|
||||
.endprolog
|
||||
|
||||
END
|
||||
276
ResourceCompilerPC/CrySkinBase.cpp
Normal file
276
ResourceCompilerPC/CrySkinBase.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
#include "stdafx.h"
|
||||
#include <StlUtils.h>
|
||||
#include "CrySkinBase.h"
|
||||
|
||||
CrySkinBase::CrySkinBase():
|
||||
m_numBones(0),
|
||||
m_arrVertices ("CrySkin*.Vertices"),
|
||||
m_arrAux ("CrySkin*.Aux"),
|
||||
m_numSkipBones (0),
|
||||
m_numDests(0)
|
||||
{
|
||||
}
|
||||
|
||||
CrySkinBase::~CrySkinBase ()
|
||||
{
|
||||
}
|
||||
|
||||
void CrySkinBase::clear()
|
||||
{
|
||||
m_numBones = 0;
|
||||
m_numSkipBones = 0;
|
||||
m_arrVertices.clear();
|
||||
m_arrAux.clear();
|
||||
}
|
||||
|
||||
bool CrySkinBase::empty()const
|
||||
{
|
||||
return m_numBones == 0 || m_arrVertices.empty();
|
||||
}
|
||||
|
||||
void CrySkinBase::init (unsigned numVerts, unsigned numAux, unsigned numSkipBones, unsigned numBones)
|
||||
{
|
||||
m_numBones = numBones;
|
||||
m_numSkipBones = numSkipBones;
|
||||
// (re)allocate the memory
|
||||
m_arrVertices.reinit (numVerts);
|
||||
m_arrAux.reinit (numAux);
|
||||
}
|
||||
|
||||
// transforms the given smooth point into the destination with the matrix
|
||||
void CrySkinBase::transformWPoint (Vec3d& pDest, const Matrix44& matBone, const Vertex& rVtx)
|
||||
{
|
||||
//pDest = matBone.TransformPoint(rVtx) * rVtx.fWeight;
|
||||
|
||||
pDest.x = ((matBone[0][0] * rVtx.pt.x) + (matBone[1][0] * rVtx.pt.y) + (matBone[2][0] * rVtx.pt.z) + matBone[3][0]) * rVtx.fWeight;
|
||||
pDest.y = ((matBone[0][1] * rVtx.pt.x) + (matBone[1][1] * rVtx.pt.y) + (matBone[2][1] * rVtx.pt.z) + matBone[3][1]) * rVtx.fWeight;
|
||||
pDest.z = ((matBone[0][2] * rVtx.pt.x) + (matBone[1][2] * rVtx.pt.y) + (matBone[2][2] * rVtx.pt.z) + matBone[3][2]) * rVtx.fWeight;
|
||||
}
|
||||
|
||||
|
||||
// adds the given smooth point into the destination with the matrix
|
||||
void CrySkinBase::addWPoint (Vec3d& pDest, const Matrix44& matBone, const Vertex& rVtx)
|
||||
{
|
||||
//pDest += matBone.TransformPoint(rVtx) * rVtx.fWeight;
|
||||
|
||||
pDest.x += ((matBone[0][0] * rVtx.pt.x) + (matBone[1][0] * rVtx.pt.y) + (matBone[2][0] * rVtx.pt.z) + matBone[3][0]) * rVtx.fWeight;
|
||||
pDest.y += ((matBone[0][1] * rVtx.pt.x) + (matBone[1][1] * rVtx.pt.y) + (matBone[2][1] * rVtx.pt.z) + matBone[3][1]) * rVtx.fWeight;
|
||||
pDest.z += ((matBone[0][2] * rVtx.pt.x) + (matBone[1][2] * rVtx.pt.y) + (matBone[2][2] * rVtx.pt.z) + matBone[3][2]) * rVtx.fWeight;
|
||||
}
|
||||
|
||||
// transforms the given _vector_ without applying the transitional part
|
||||
/*
|
||||
void CrySkinBase::transformVectorNoTrans (Vec3d& pDest, const Vec3d& pSrc, const Matrix& matBone)
|
||||
{
|
||||
pDest.x = matBone[0][0] * pSrc.x + matBone[1][0] * pSrc.y + matBone[2][0] * pSrc.z;
|
||||
pDest.y = matBone[0][1] * pSrc.x + matBone[1][1] * pSrc.y + matBone[2][1] * pSrc.z;
|
||||
pDest.z = matBone[0][2] * pSrc.x + matBone[1][2] * pSrc.y + matBone[2][2] * pSrc.z;
|
||||
}
|
||||
*/
|
||||
|
||||
// transforms the given smooth point into the destination with the matrix
|
||||
void CrySkinBase::transformWVector (Vec3d& pDest, const Matrix44& matBone, const Vertex& rVtx)
|
||||
{
|
||||
//pDest = matBone.TransformPoint(rVtx) * rVtx.fWeight;
|
||||
|
||||
pDest.x = ((matBone[0][0] * rVtx.pt.x) + (matBone[1][0] * rVtx.pt.y) + (matBone[2][0] * rVtx.pt.z)) * rVtx.fWeight;
|
||||
pDest.y = ((matBone[0][1] * rVtx.pt.x) + (matBone[1][1] * rVtx.pt.y) + (matBone[2][1] * rVtx.pt.z)) * rVtx.fWeight;
|
||||
pDest.z = ((matBone[0][2] * rVtx.pt.x) + (matBone[1][2] * rVtx.pt.y) + (matBone[2][2] * rVtx.pt.z)) * rVtx.fWeight;
|
||||
}
|
||||
|
||||
|
||||
// adds the given smooth point into the destination with the matrix
|
||||
void CrySkinBase::addWVector (Vec3d& pDest, const Matrix44& matBone, const Vertex& rVtx)
|
||||
{
|
||||
//pDest += matBone.TransformPoint(rVtx) * rVtx.fWeight;
|
||||
|
||||
pDest.x += ((matBone[0][0] * rVtx.pt.x) + (matBone[1][0] * rVtx.pt.y) + (matBone[2][0] * rVtx.pt.z)) * rVtx.fWeight;
|
||||
pDest.y += ((matBone[0][1] * rVtx.pt.x) + (matBone[1][1] * rVtx.pt.y) + (matBone[2][1] * rVtx.pt.z)) * rVtx.fWeight;
|
||||
pDest.z += ((matBone[0][2] * rVtx.pt.x) + (matBone[1][2] * rVtx.pt.y) + (matBone[2][2] * rVtx.pt.z)) * rVtx.fWeight;
|
||||
}
|
||||
|
||||
// returns the number of bytes occupied by this structure and all its contained objects
|
||||
unsigned CrySkinBase::sizeofThis()const
|
||||
{
|
||||
return sizeof(*this) + sizeofArray (m_arrAux) + sizeofArray(m_arrVertices);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//----- this is the serialize version for little-endian CPUs -----
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned CrySkinBase::Serialize_PC (bool bSave, void* pStream, unsigned nBufSize)
|
||||
{
|
||||
SerialHeader Header;
|
||||
if (bSave)
|
||||
{
|
||||
Header.initFromSkin(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pStream)
|
||||
return 0;
|
||||
if (nBufSize < sizeof(Header))
|
||||
return 0;
|
||||
Header = *((SerialHeader*)pStream);
|
||||
}
|
||||
|
||||
unsigned nSizeAuxInts = ((sizeof(CrySkinAuxInt)*Header.numAuxInts+3)&~3);
|
||||
unsigned nSizeRequired =
|
||||
// the m_numBones, m_numSkipBones, m_numDests
|
||||
// m_arrAux.size(), m_arrVertices.size()
|
||||
sizeof(SerialHeader) +
|
||||
nSizeAuxInts +
|
||||
sizeof(Vertex) * Header.numVertices;
|
||||
|
||||
if (!pStream)
|
||||
return bSave?nSizeRequired:0;
|
||||
|
||||
if (nBufSize < nSizeRequired)
|
||||
return 0;
|
||||
|
||||
CrySkinAuxInt* pAuxInts = (CrySkinAuxInt*)(((SerialHeader*)pStream) + 1);
|
||||
Vertex* pVertices = (Vertex*)(((char*)pAuxInts) + nSizeAuxInts);
|
||||
|
||||
if (bSave)
|
||||
{
|
||||
//saving
|
||||
*((SerialHeader*)pStream) = Header;
|
||||
memcpy (pAuxInts, &m_arrAux[0], sizeof(CrySkinAuxInt)*m_arrAux.size());
|
||||
memcpy (pVertices, &m_arrVertices[0], sizeof(Vertex)*m_arrVertices.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
// loading
|
||||
m_arrAux.clear();
|
||||
m_arrAux.resize (Header.numAuxInts);
|
||||
m_arrVertices.clear();
|
||||
m_arrVertices.resize (Header.numVertices);
|
||||
m_numBones = Header.numBones;
|
||||
m_numSkipBones = Header.numSkipBones;
|
||||
m_numDests = Header.numDests;
|
||||
memcpy (&m_arrAux[0], pAuxInts, sizeof(CrySkinAuxInt)*m_arrAux.size());
|
||||
memcpy (&m_arrVertices[0], pVertices, sizeof(Vertex)*m_arrVertices.size());
|
||||
}
|
||||
return nSizeRequired;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//----- this is the serialize version for big-endian CPUs -----
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned CrySkinBase::Serialize_GC (bool bSave, void* pStream, unsigned nBufSize)
|
||||
{
|
||||
SerialHeader Header;
|
||||
if (bSave)
|
||||
{
|
||||
Header.initFromSkin(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pStream)
|
||||
return 0;
|
||||
if (nBufSize < sizeof(Header))
|
||||
return 0;
|
||||
Header = *((SerialHeader*)pStream);
|
||||
}
|
||||
|
||||
unsigned nSizeAuxInts = ((sizeof(CrySkinAuxInt)*Header.numAuxInts+3)&~3);
|
||||
unsigned nSizeRequired =
|
||||
// the m_numBones, m_numSkipBones, m_numDests
|
||||
// m_arrAux.size(), m_arrVertices.size()
|
||||
sizeof(SerialHeader) +
|
||||
nSizeAuxInts +
|
||||
sizeof(Vertex) * Header.numVertices;
|
||||
|
||||
if (!pStream)
|
||||
return bSave?nSizeRequired:0;
|
||||
|
||||
if (nBufSize < nSizeRequired)
|
||||
return 0;
|
||||
|
||||
CrySkinAuxInt* pAuxInts = (CrySkinAuxInt*)(((SerialHeader*)pStream) + 1);
|
||||
Vertex* pVertices = (Vertex*)(((char*)pAuxInts) + nSizeAuxInts);
|
||||
|
||||
if (bSave)
|
||||
{
|
||||
//saving
|
||||
Header.numBones = SWAP32(Header.numBones);
|
||||
Header.numSkipBones = SWAP32(Header.numSkipBones);
|
||||
Header.numDests = SWAP32(Header.numDests);
|
||||
Header.numAuxInts = SWAP32(Header.numAuxInts);
|
||||
Header.numVertices = SWAP32(Header.numVertices);
|
||||
*((SerialHeader*)pStream) = Header;
|
||||
|
||||
//swap data into big-endian-format
|
||||
unsigned sa = sizeof(CrySkinAuxInt);
|
||||
unsigned a = (unsigned)m_arrAux.size();
|
||||
unsigned x;
|
||||
for (x=0; x<a; x++) {
|
||||
pAuxInts[x]=SWAP16(pAuxInts[x]);
|
||||
}
|
||||
unsigned va = sizeof(m_arrVertices.size());
|
||||
unsigned v = (unsigned)m_arrVertices.size();
|
||||
for (x=0; x<(v); x++) {
|
||||
pVertices[x].nDest = SWAP32(pVertices[x].nDest);
|
||||
pVertices[x].pt.x = FSWAP32(pVertices[x].pt.x);
|
||||
pVertices[x].pt.y = FSWAP32(pVertices[x].pt.y);
|
||||
pVertices[x].pt.z = FSWAP32(pVertices[x].pt.z);
|
||||
}
|
||||
|
||||
//copy into stream
|
||||
memcpy (pAuxInts, &m_arrAux[0], sizeof(CrySkinAuxInt)*m_arrAux.size());
|
||||
memcpy (pVertices, &m_arrVertices[0], sizeof(Vertex)*m_arrVertices.size());
|
||||
|
||||
//..and new swap-back to little-endian,
|
||||
//because we need the original format for futher calculation on PC
|
||||
for (x=0; x<a; x++) {
|
||||
pAuxInts[x]=SWAP16(pAuxInts[x]);
|
||||
}
|
||||
for (x=0; x<(v); x++) {
|
||||
pVertices[x].nDest = SWAP32(pVertices[x].nDest);
|
||||
pVertices[x].pt.x = FSWAP32(pVertices[x].pt.x);
|
||||
pVertices[x].pt.y = FSWAP32(pVertices[x].pt.y);
|
||||
pVertices[x].pt.z = FSWAP32(pVertices[x].pt.z);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// loading
|
||||
m_arrAux.clear();
|
||||
m_arrAux.resize (Header.numAuxInts);
|
||||
m_arrVertices.clear();
|
||||
m_arrVertices.resize (Header.numVertices);
|
||||
m_numBones = Header.numBones;
|
||||
m_numSkipBones = Header.numSkipBones;
|
||||
m_numDests = Header.numDests;
|
||||
memcpy (&m_arrAux[0], pAuxInts, sizeof(CrySkinAuxInt)*m_arrAux.size());
|
||||
memcpy (&m_arrVertices[0], pVertices, sizeof(Vertex)*m_arrVertices.size());
|
||||
}
|
||||
return nSizeRequired;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CrySkinBase::CStatistics::CStatistics (const CrySkinBase*pSkin)
|
||||
{
|
||||
this->numBones = pSkin->m_numBones;
|
||||
this->numSkipBones = pSkin->m_numSkipBones;
|
||||
this->numAuxInts = (unsigned)pSkin->m_arrAux.size();
|
||||
this->numVertices = (unsigned)pSkin->m_arrVertices.size();
|
||||
|
||||
// construct the set of destination vertices
|
||||
for (unsigned nBone = numSkipBones; nBone < numBones; ++nBone)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void CrySkinBase::scaleVertices (float fScale)
|
||||
{
|
||||
// all we have to do is to scale all the offsets
|
||||
for (VertexArray::iterator it = m_arrVertices.begin(), itEnd = m_arrVertices.end(); it!= itEnd; ++it)
|
||||
it->pt *= fScale;
|
||||
}
|
||||
105
ResourceCompilerPC/CrySkinBase.h
Normal file
105
ResourceCompilerPC/CrySkinBase.h
Normal file
@@ -0,0 +1,105 @@
|
||||
#ifndef _CRY_ANIMATION_CRY_SKIN_BASE_HDR_
|
||||
#define _CRY_ANIMATION_CRY_SKIN_BASE_HDR_
|
||||
|
||||
#include "SSEUtils.h"
|
||||
#include "CrySkinTypes.h"
|
||||
|
||||
// this is the base for the actual skins
|
||||
// the actual skin does the validation and calculates the skin
|
||||
class CrySkinBase
|
||||
{
|
||||
public:
|
||||
void clear();
|
||||
bool empty()const;
|
||||
|
||||
void scaleVertices (float fScale);
|
||||
|
||||
//version for little-endian
|
||||
unsigned Serialize_PC (bool bSave, void* pBuffer, unsigned nBufSize);
|
||||
|
||||
//version for big-endian
|
||||
unsigned Serialize_GC (bool bSave, void* pBuffer, unsigned nBufSize);
|
||||
|
||||
// returns the number of bytes occupied by this structure and all its contained objects
|
||||
unsigned sizeofThis()const;
|
||||
|
||||
// this structure contains the statistical information about this skin; its calculation
|
||||
// may take significant time and should not be used in game run time (only for debugging purposes
|
||||
// and to output statistics in the tools)
|
||||
class CStatistics
|
||||
{
|
||||
public:
|
||||
CStatistics (const CrySkinBase*pSkin);
|
||||
|
||||
unsigned numBones;
|
||||
unsigned numSkipBones;
|
||||
unsigned numAuxInts;
|
||||
unsigned numVertices;
|
||||
};
|
||||
friend class CStatistics;
|
||||
|
||||
unsigned numBones() const {return m_numBones;}
|
||||
unsigned numSkipBones() const {return m_numSkipBones;}
|
||||
protected:
|
||||
CrySkinBase();
|
||||
~CrySkinBase ();
|
||||
void init (unsigned numVerts, unsigned numAux, unsigned numSkipBones, unsigned numBones);
|
||||
|
||||
typedef CrySkinVertexAligned Vertex;
|
||||
|
||||
// transforms the given _vector_ without applying the transitional part
|
||||
//void transformVectorNoTrans (Vec3& pDest, const Vec3& pSrc, const Matrix& matBone);
|
||||
|
||||
|
||||
// transforms the given smooth point into the destination with the matrix
|
||||
static void transformWPoint (Vec3& pDest, const Matrix44& matBone, const Vertex& rVtx);
|
||||
|
||||
// adds the given smooth point into the destination with the matrix
|
||||
static void addWPoint (Vec3& pDest, const Matrix44& matBone, const Vertex& rVtx);
|
||||
|
||||
// transforms the given smooth point into the destination with the matrix
|
||||
static void transformWVector (Vec3& pDest, const Matrix44& matBone, const Vertex& rVtx);
|
||||
|
||||
// adds the given smooth point into the destination with the matrix
|
||||
static void addWVector (Vec3& pDest, const Matrix44& matBone, const Vertex& rVtx);
|
||||
|
||||
//typedef TIncContAllocator<Vertex, &g_VectorAllocator> VertexAllocator;
|
||||
//typedef TIncContAllocator<CrySkinAuxInt, &g_VectorAllocator> AuxIntAllocator;
|
||||
typedef TAllocator16<Vertex> VertexAllocator;
|
||||
|
||||
// the vertex stream: contains the rigid and smooth vertex structures
|
||||
typedef TFixedArray<Vertex, VertexAllocator> VertexArray;
|
||||
VertexArray m_arrVertices;
|
||||
|
||||
// the auxiliary stream: contains the number of vertices in each group, and the group vertices' destination idices (for smooth vertices only)
|
||||
TFixedArray<CrySkinAuxInt> m_arrAux;
|
||||
// the total number of bones, NOT taking the m_numSkipBones into account
|
||||
unsigned m_numBones;
|
||||
// additional flexibility: skip m_numSkipBones bones before performing skinning;
|
||||
// useful for optimizing the skin which has only one or a few bones' influences
|
||||
unsigned m_numSkipBones;
|
||||
|
||||
// this is the header structure for serialization
|
||||
struct SerialHeader
|
||||
{
|
||||
void initFromSkin(const CrySkinBase* pSkin)
|
||||
{
|
||||
numBones = pSkin->m_numBones;
|
||||
numSkipBones = pSkin->m_numSkipBones;
|
||||
numDests = pSkin->m_numDests;
|
||||
numAuxInts = (unsigned)pSkin->m_arrAux.size();
|
||||
numVertices = (unsigned)pSkin->m_arrVertices.size();
|
||||
}
|
||||
|
||||
unsigned numBones;
|
||||
unsigned numSkipBones;
|
||||
unsigned numDests;
|
||||
unsigned numAuxInts;
|
||||
unsigned numVertices;
|
||||
};
|
||||
|
||||
// the total number of destination vertices
|
||||
unsigned m_numDests;
|
||||
};
|
||||
|
||||
#endif
|
||||
168
ResourceCompilerPC/CrySkinBasisBuilder.cpp
Normal file
168
ResourceCompilerPC/CrySkinBasisBuilder.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "stdafx.h"
|
||||
#include "CrySkinRigidBasis.h"
|
||||
#include "CrySkinBasisBuilder.h"
|
||||
|
||||
CrySkinBasisBuilder::CrySkinBasisBuilder (const ICrySkinSource* pGeometry, const Matrix44* pMatInvDef, unsigned numBoneInfos):
|
||||
CrySkinBuilderBase0 (pGeometry),
|
||||
m_pMatInvDef(pMatInvDef),
|
||||
m_numBoneInfos (numBoneInfos),
|
||||
m_nDestIntervalBegin (0),
|
||||
m_nDestIntervalEnd (0),
|
||||
m_numBones (0),
|
||||
m_nFirstBone (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// sets the destination vertex interval to operate on. Initially, this is infinity.
|
||||
// The destination vertex interval is the interval within which the destination vertex
|
||||
// index must lie in order to be skinned. The base of the interval is considered
|
||||
// vertex 0 in the produced skinner
|
||||
void CrySkinBasisBuilder::setDestinationInterval (unsigned nBegin, unsigned nEnd)
|
||||
{
|
||||
if (nEnd > m_pGeometry->numExtTangents())
|
||||
nEnd = m_pGeometry->numExtTangents();
|
||||
|
||||
if (nBegin < nEnd)
|
||||
{
|
||||
m_nDestIntervalBegin = nBegin;
|
||||
m_nDestIntervalEnd = nEnd;
|
||||
|
||||
preprocess();
|
||||
makeBoneBases ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nDestIntervalBegin = 0;
|
||||
m_nDestIntervalEnd = 0;
|
||||
m_numBones = 0;
|
||||
m_nFirstBone = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initializes the given rigid basis builder
|
||||
void CrySkinBasisBuilder::initRigidBasisSkin (CrySkinRigidBasis* pSkin)
|
||||
{
|
||||
assert (sizeof(SPipTangentsA16)==0x30);
|
||||
unsigned numAuxInts = 2 * (m_numBones-m_nFirstBone);
|
||||
unsigned numBases = m_nDestIntervalEnd-m_nDestIntervalBegin;
|
||||
pSkin->init (2 * numBases, numAuxInts, m_nFirstBone, m_numBones);
|
||||
|
||||
CrySkinStreams stream, streamBegin, streamEnd;
|
||||
streamBegin.pAux = pSkin->m_arrAux.begin();
|
||||
streamBegin.pVert = pSkin->m_arrVertices.begin();
|
||||
stream = streamBegin;
|
||||
streamEnd.pAux = streamBegin.pAux + numAuxInts;
|
||||
streamEnd.pVert = streamBegin.pVert + 2 * numBases;
|
||||
|
||||
for (unsigned nBone = m_nFirstBone; nBone < m_numBones; ++nBone)
|
||||
{
|
||||
// for each bone, fill the three groups
|
||||
// we fill the left and right vertices
|
||||
fillGroup (stream, m_arrBoneBases[nBone].arrRight);
|
||||
assert (stream.pAux <= streamEnd.pAux);
|
||||
assert (stream.pVert <= streamEnd.pVert);
|
||||
fillGroup (stream, m_arrBoneBases[nBone].arrLeft);
|
||||
// only when we processed the last bone, we should have the pAux pointing to the end
|
||||
assert (stream.pAux <= streamEnd.pAux);
|
||||
assert (stream.pVert <= streamEnd.pVert);
|
||||
}
|
||||
}
|
||||
|
||||
void clipDenormal (float& x)
|
||||
{
|
||||
if (x > -1e-4 && x < 1e-4)
|
||||
x = 0;
|
||||
}
|
||||
|
||||
void clipDenormals(Vec3d& v)
|
||||
{
|
||||
clipDenormal(v.x);
|
||||
clipDenormal(v.y);
|
||||
clipDenormal(v.z);
|
||||
}
|
||||
|
||||
// makes up the basis array
|
||||
void CrySkinBasisBuilder::makeBoneBases ()
|
||||
{
|
||||
const unsigned* pExtToInt = m_pGeometry->getExtToIntMapEntries();
|
||||
|
||||
m_arrBoneBases.clear();
|
||||
m_arrBoneBases.resize (m_numBones);
|
||||
|
||||
unsigned i;
|
||||
// preallocate for push_back
|
||||
for (i = 0; i < m_numBones; ++i)
|
||||
m_arrBoneBases[i].reserve (m_nDestIntervalEnd / m_numBones);
|
||||
|
||||
for (i = m_nDestIntervalBegin; i < m_nDestIntervalEnd; ++i)
|
||||
{
|
||||
unsigned nGeomVert = pExtToInt[i];
|
||||
|
||||
TangData rBasis = m_pGeometry->getExtTangent (i);
|
||||
clipDenormals(rBasis.binormal);
|
||||
clipDenormals(rBasis.tangent);
|
||||
const CryVertexBinding& rLink = m_pGeometry->getLink(nGeomVert);
|
||||
unsigned nBone = rLink[0].BoneID;
|
||||
assert (nBone < m_numBoneInfos);
|
||||
|
||||
CrySkinRigidBasisArray* pTargetArray;
|
||||
if ((rBasis.tangent ^ rBasis.binormal)*rBasis.tnormal > 0)
|
||||
pTargetArray = &m_arrBoneBases[nBone].arrRight;
|
||||
else
|
||||
pTargetArray = &m_arrBoneBases[nBone].arrLeft;
|
||||
|
||||
const Matrix44& matInvDef = m_pMatInvDef[nBone];
|
||||
|
||||
pTargetArray->push_back(CrySkinRigidBaseInfo (matInvDef,rBasis,i-m_nDestIntervalBegin));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// calculate the number of used bones and the skip-bone
|
||||
void CrySkinBasisBuilder::preprocess()
|
||||
{
|
||||
unsigned numTangents = m_pGeometry->numExtTangents();
|
||||
const unsigned* pExtToInt = m_pGeometry->getExtToIntMapEntries();
|
||||
|
||||
m_numBones = 0;
|
||||
m_nFirstBone = 0;
|
||||
bool bNotInited = true;
|
||||
|
||||
for (unsigned i = m_nDestIntervalBegin; i < min(m_nDestIntervalEnd,numTangents); ++i)
|
||||
{
|
||||
unsigned nGeomVert = pExtToInt[i];
|
||||
const CryVertexBinding& rLink = m_pGeometry->getLink(nGeomVert);
|
||||
unsigned nBone = rLink[0].BoneID;
|
||||
|
||||
if (bNotInited)
|
||||
{
|
||||
m_nFirstBone = nBone;
|
||||
m_numBones = nBone+1;
|
||||
bNotInited = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nFirstBone = min (m_nFirstBone, nBone);
|
||||
m_numBones = max (nBone+1, m_numBones);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fills the given bases to the simple stream
|
||||
typedef std::vector< CrySkinRigidBaseInfo > CrySkinRigidBasisArray;
|
||||
void CrySkinBasisBuilder::fillGroup (CrySkinStreams& streams, const CrySkinRigidBasisArray& arrBases)
|
||||
{
|
||||
// the group header is the number of vertices in the group
|
||||
*streams.pAux++ = (CrySkinAuxInt)arrBases.size();
|
||||
|
||||
CrySkinRigidBasisArray::const_iterator it = arrBases.begin(), itEnd = it + arrBases.size();
|
||||
for (; it != itEnd; ++it)
|
||||
{
|
||||
it->build(streams.pVert);
|
||||
streams.pVert += 2;
|
||||
}
|
||||
}
|
||||
67
ResourceCompilerPC/CrySkinBasisBuilder.h
Normal file
67
ResourceCompilerPC/CrySkinBasisBuilder.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef _CRY_ANIMATION_CRY_SKIN_BASIS_BUILDER_HDR_
|
||||
#define _CRY_ANIMATION_CRY_SKIN_BASIS_BUILDER_HDR_
|
||||
|
||||
#include "CrySkinBuilderBase.h"
|
||||
|
||||
class CrySkinBasisBuilder: public CrySkinBuilderBase0
|
||||
{
|
||||
public:
|
||||
CrySkinBasisBuilder (const ICrySkinSource* pGeometry, const Matrix44* pMatInvDef, unsigned numBones);
|
||||
|
||||
// sets the destination vertex interval to operate on. Initially, this is infinity.
|
||||
// The destination vertex interval is the interval within which the destination vertex
|
||||
// index must lie in order to be skinned. The base of the interval is considered
|
||||
// vertex 0 in the produced skinner
|
||||
void setDestinationInterval (unsigned nBegin, unsigned nEnd);
|
||||
|
||||
// initializes the given rigid basis builder
|
||||
void initRigidBasisSkin (class CrySkinRigidBasis* pSkin);
|
||||
protected:
|
||||
|
||||
// calculate the number of used bones and the skip-bone
|
||||
void preprocess();
|
||||
|
||||
// makes up the basis array
|
||||
void makeBoneBases ();
|
||||
|
||||
// fills the given bases to the simple stream
|
||||
typedef std::vector< CrySkinRigidBaseInfo > CrySkinRigidBasisArray;
|
||||
void fillGroup (CrySkinStreams& stream, const CrySkinRigidBasisArray& arrBases);
|
||||
protected:
|
||||
// the bone info, from which we'll extract the default position
|
||||
const Matrix44* m_pMatInvDef;
|
||||
unsigned m_numBoneInfos;
|
||||
|
||||
// this structure describes the flipped and unflipped bases belonging to the bone
|
||||
struct BoneBasisGroup
|
||||
{
|
||||
CrySkinRigidBasisArray arrRight;// unflipped, Normal = Tang ^ Binorm
|
||||
CrySkinRigidBasisArray arrLeft; // flipped, Normal = Binorm ^ Tang
|
||||
void reserve (unsigned numReserve)
|
||||
{
|
||||
arrRight.reserve (numReserve/2);
|
||||
arrLeft.reserve (numReserve/2);
|
||||
}
|
||||
};
|
||||
typedef std::vector<BoneBasisGroup> BoneBasisGroupArray;
|
||||
BoneBasisGroupArray m_arrBoneBases;
|
||||
|
||||
// total number of bones used (max bone + 1)
|
||||
unsigned m_numBones;
|
||||
unsigned m_nFirstBone;
|
||||
|
||||
// the destination interval: if the destination vertex is within this interval,
|
||||
// it is put into the skinner; the actual destination vertex index is dubtracted the interval begin
|
||||
unsigned m_nDestIntervalBegin, m_nDestIntervalEnd;
|
||||
|
||||
/*
|
||||
unsigned m_nFlags;
|
||||
|
||||
enum
|
||||
{
|
||||
flagForSSE = 1// if this is set, then the skin is constructed for SSE usage
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
#endif
|
||||
139
ResourceCompilerPC/CrySkinBuilder.cpp
Normal file
139
ResourceCompilerPC/CrySkinBuilder.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#include "stdafx.h"
|
||||
#include "CrySkinFull.h"
|
||||
#include "CrySkinBuilder.h"
|
||||
|
||||
|
||||
// initializes the builder for usage
|
||||
CrySkinBuilder::CrySkinBuilder (const ICrySkinSource*pGeometry):
|
||||
m_arrSmoothVertHitCount ("CrySkinBuilder.arrSmoothVertHitCount"),
|
||||
CrySkinBuilderBase (pGeometry)
|
||||
{
|
||||
makeFullBoneVertexArrays();
|
||||
|
||||
// skip the non-infuencing bones
|
||||
for (m_numSkipBones = 0; m_numSkipBones < m_numBones && m_arrBoneVerts[m_numSkipBones].empty(); ++m_numSkipBones)
|
||||
continue;
|
||||
|
||||
// we need the aux ints for:
|
||||
// 3 number per each bone to keep the number of groups
|
||||
// 0 numbers for the rigid vertices
|
||||
// 1 number for each smooth vertex
|
||||
// we don't count the bones that are skipped
|
||||
m_numAuxInts = 3 * (m_numBones-m_numSkipBones) + m_numSmoothLinks;
|
||||
}
|
||||
|
||||
// initializes a new skin
|
||||
void CrySkinBuilder::initSkinFull(CrySkinFull* pSkin)
|
||||
{
|
||||
pSkin->init(m_numLinks, m_numAuxInts, m_numSkipBones, m_numBones);
|
||||
pSkin->m_numDests = m_pGeometry->numVertices();
|
||||
|
||||
// this will hold the number of times a smooth vertex is hit
|
||||
m_arrSmoothVertHitCount.reinit (m_pGeometry->numVertices(), 0);
|
||||
|
||||
CrySkinStreams stream, streamBegin, streamEnd;
|
||||
streamBegin.pAux = pSkin->m_arrAux.begin();
|
||||
streamBegin.pVert = pSkin->m_arrVertices.begin();
|
||||
stream = streamBegin;
|
||||
streamEnd.pAux = streamBegin.pAux + m_numAuxInts;
|
||||
streamEnd.pVert = streamBegin.pVert + m_numLinks;
|
||||
|
||||
for (unsigned nBone = m_numSkipBones; nBone < m_numBones; ++nBone)
|
||||
{
|
||||
// for each bone, fill the three groups
|
||||
// we start from the rigid vertices
|
||||
fillRigidGroup (stream, nBone);
|
||||
assert (stream.pAux <= streamEnd.pAux);
|
||||
assert (stream.pVert <= streamEnd.pVert);
|
||||
fillSmoothGroups (stream, nBone);
|
||||
// only when we processed the last bone, we should have the pAux pointing to the end
|
||||
assert (stream.pAux <= streamEnd.pAux);
|
||||
assert (stream.pVert <= streamEnd.pVert);
|
||||
}
|
||||
m_arrSmoothVertHitCount.clear();
|
||||
assert (stream.pAux == streamEnd.pAux);
|
||||
assert (stream.pVert == streamEnd.pVert);
|
||||
#ifdef _DEBUG
|
||||
validate (pSkin);
|
||||
pSkin->validate (m_pGeometry);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// fills in 2 groups of aux ints for the given bone (the smooth vertex groups)
|
||||
// returns the pointer to the next available auxint after the groups
|
||||
// IMPLEMENTATION NOTE:
|
||||
// there are TWO groups filled in here
|
||||
void CrySkinBuilder::fillSmoothGroups (CrySkinStreams& streams, unsigned nBone)
|
||||
{
|
||||
// the group starts with the number of smooth vertices met the first time, belonging to this bone
|
||||
CrySkinAuxInt& numSmooth1Verts = *streams.pAux++;
|
||||
numSmooth1Verts = 0;
|
||||
|
||||
// the list of smooth vertices belonging to the bone
|
||||
CrySkinSmoothVertexArray& arrSmooth = m_arrBoneVerts[nBone].arrSmooth;
|
||||
CrySkinSmoothVertexArray::const_iterator itBegin = arrSmooth.begin(), itEnd = itBegin + arrSmooth.size(), it = itBegin;
|
||||
|
||||
// this will be the array of vertices met not for the first time -
|
||||
// we'll fill it in during processing of the Smooth1 group
|
||||
std::vector<CrySkinSmoothVertexArray::const_iterator> arrSmooth2Verts;
|
||||
arrSmooth2Verts.reserve (arrSmooth.size());
|
||||
|
||||
// iterate through the smooth vertices, picking up Smooth1 vertices and memorizing Smooth2 vertices
|
||||
// hit each vertex, either smooth1 or smooth2
|
||||
for (; it != itEnd; ++it)
|
||||
{
|
||||
unsigned& nVertHitCount = m_arrSmoothVertHitCount[it->nDest];
|
||||
#ifdef _DEBUG
|
||||
const CryVertexBinding& rLink = m_pGeometry->getLink(it->nDest);
|
||||
float fLegacyWeight = rLink.getBoneWeight(nBone);
|
||||
assert (rLink.hasBoneWeight(nBone, it->fWeight));
|
||||
#endif
|
||||
// check which time the vertex is met
|
||||
if (nVertHitCount == 0)
|
||||
{
|
||||
// this vertex is met for the first time
|
||||
*streams.pAux++ = it->nDest;
|
||||
it->build (*streams.pVert++);
|
||||
++numSmooth1Verts;
|
||||
}
|
||||
else
|
||||
// this vertex is met not for the first time - to be gone to the group Smooth2
|
||||
arrSmooth2Verts.push_back(it);
|
||||
|
||||
// hit the vertex anyway
|
||||
++nVertHitCount;
|
||||
}
|
||||
|
||||
CrySkinAuxInt& numSmooth2Verts = *streams.pAux++;
|
||||
// we already know the number of smooth2 group vertices
|
||||
numSmooth2Verts = (CrySkinAuxInt)arrSmooth2Verts.size();
|
||||
|
||||
// now iterate through the smooth2 vertices
|
||||
for (unsigned i = 0; i < arrSmooth2Verts.size(); ++i)
|
||||
{
|
||||
arrSmooth2Verts[i]->build (*streams.pVert++);
|
||||
*streams.pAux++ = arrSmooth2Verts[i]->nDest;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// validates the created skin
|
||||
void CrySkinBuilder::validate (CrySkinFull *pSkin)
|
||||
{
|
||||
CrySkinStreams stream;
|
||||
stream.pAux = &pSkin->m_arrAux[0];
|
||||
stream.pVert = &pSkin->m_arrVertices[0];
|
||||
|
||||
for (unsigned nBone = m_numSkipBones; nBone < pSkin->m_numBones; ++nBone)
|
||||
{
|
||||
/*
|
||||
BoneVertexGroup& rGroup = m_arrBoneVerts[nBone];
|
||||
assert (*stream.pAux++ == rGroup.arrRigid.size());
|
||||
|
||||
stream.pVert += rGroup.arrRigid.size();
|
||||
*/
|
||||
}
|
||||
}
|
||||
35
ResourceCompilerPC/CrySkinBuilder.h
Normal file
35
ResourceCompilerPC/CrySkinBuilder.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef _CRY_SKIN_BUIDLER_HDR_
|
||||
#define _CRY_SKIN_BUIDLER_HDR_
|
||||
|
||||
class CrySkinFull;
|
||||
#include "CrySkinBuilderBase.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Capable of building an optimized CrySkin class out of geometry info
|
||||
class CrySkinBuilder: public CrySkinBuilderBase
|
||||
{
|
||||
public:
|
||||
// initializes the builder for usage
|
||||
CrySkinBuilder (const ICrySkinSource* pGeometry);
|
||||
// creates a new skin, capable of skinning into a uninited mem, to be deleted by Release
|
||||
void initSkinFull(CrySkinFull*);
|
||||
|
||||
protected:
|
||||
|
||||
// fills in 2 groups of aux ints for the given bone (the smooth vertex groups)
|
||||
// returns the pointer to the next available auxint after the groups
|
||||
void fillSmoothGroups (CrySkinStreams& streams, unsigned nBone);
|
||||
|
||||
// validates the created skin
|
||||
void validate (CrySkinFull *pSkin);
|
||||
protected:
|
||||
unsigned m_numAuxInts; // number of aux ints required for the skin
|
||||
|
||||
// the number of times a vertex has been already met in the auxiliary stream
|
||||
TElementaryArray<unsigned> m_arrSmoothVertHitCount;
|
||||
|
||||
// number of bones to skip when skinning
|
||||
unsigned m_numSkipBones;
|
||||
};
|
||||
|
||||
#endif
|
||||
91
ResourceCompilerPC/CrySkinBuilderBase.cpp
Normal file
91
ResourceCompilerPC/CrySkinBuilderBase.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "stdafx.h"
|
||||
#include "CrySkinBuilderBase.h"
|
||||
|
||||
CrySkinBuilderBase::CrySkinBuilderBase(const ICrySkinSource* pGeometry):
|
||||
CrySkinBuilderBase0 (pGeometry)
|
||||
#ifdef DEBUG_STD_CONTAINERS
|
||||
,m_arrBoneVerts ("CrySkinBuilder.arrBoneVerts")
|
||||
#endif
|
||||
{
|
||||
preprocess();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// fills in the group of aux ints for the given bone (the rigid vertex group)
|
||||
// returns the pointer to the next available auxint after the group
|
||||
// IMPLEMENTATION NOTE:
|
||||
// actually, the rigid group is empty in the auxiliary stream, so we just set the number of vertices
|
||||
void CrySkinBuilderBase::fillRigidGroup (CrySkinStreams& streams, unsigned nBone)
|
||||
{
|
||||
CrySkinRigidVertexArray& arrRigid = m_arrBoneVerts[nBone].arrRigid;
|
||||
|
||||
// the group starts with the number of rigid vertices belonging to this bone
|
||||
*streams.pAux++ = (CrySkinAuxInt)arrRigid.size();
|
||||
|
||||
CrySkinRigidVertexArray::const_iterator it = arrRigid.begin(), itEnd = it + arrRigid.size();
|
||||
|
||||
for (; it != itEnd; ++it)
|
||||
it->build (*streams.pVert++);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// computes the max number of bone affecting a vertex + 1
|
||||
// and the total number of links to smooth vertices - the sum of numbers of links of all smooth vertices
|
||||
// the total number of links per all vertices. If the whole object is rigid,
|
||||
// this is the same as the number of vertices
|
||||
void CrySkinBuilderBase::preprocess()
|
||||
{
|
||||
// we need for each bone:
|
||||
// Vert:
|
||||
// RigidVertex for each rigid vertex, and SmoothVertex for each smooth vertex
|
||||
// Aux:
|
||||
// 3 counts of vertices in each group
|
||||
// index of target for each smooth vertex
|
||||
|
||||
m_numBones = 0;
|
||||
m_numSmoothLinks = 0;
|
||||
m_numLinks = 0;
|
||||
unsigned numVertices = m_pGeometry->numVertices();
|
||||
for (unsigned nVert = 0; nVert < numVertices; ++nVert)
|
||||
{
|
||||
// the number of links for this vertex
|
||||
unsigned numVertexLinks = (unsigned)m_pGeometry->getLink(nVert).size();
|
||||
if (numVertexLinks > 1)
|
||||
// if the vertex is smooth, we'll need to keep the weights and destination indices
|
||||
m_numSmoothLinks += numVertexLinks;
|
||||
|
||||
m_numBones = max(m_pGeometry->getLink(nVert).maxBoneID(), m_numBones);
|
||||
|
||||
m_numLinks += numVertexLinks;
|
||||
}
|
||||
++m_numBones;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// calculates the vertex list of each bone
|
||||
void CrySkinBuilderBase::makeFullBoneVertexArrays()
|
||||
{
|
||||
m_arrBoneVerts.clear();
|
||||
m_arrBoneVerts.resize (m_numBones);
|
||||
|
||||
unsigned numVertices = m_pGeometry->numVertices();
|
||||
// preallocate memory for the vertices in bones
|
||||
for (unsigned i = 0; i < m_numBones; ++i)
|
||||
// assume approximately uniform distribution
|
||||
m_arrBoneVerts[i].reserve (numVertices / m_numBones);
|
||||
|
||||
for (unsigned nVert = 0; nVert < numVertices; ++nVert)
|
||||
{
|
||||
// the number of links for this vertex
|
||||
const CryVertexBinding& rLinks = m_pGeometry->getLink (nVert);
|
||||
if (rLinks.size() == 1)
|
||||
m_arrBoneVerts[rLinks[0].BoneID].arrRigid.push_back(CrySkinRigidVertex (rLinks[0].offset, nVert));
|
||||
else
|
||||
for (unsigned i = 0; i < rLinks.size(); ++i)
|
||||
{
|
||||
m_arrBoneVerts[rLinks[i].BoneID].arrSmooth.push_back(CrySkinSmoothVertex (rLinks[i], nVert));
|
||||
}
|
||||
}
|
||||
}
|
||||
111
ResourceCompilerPC/CrySkinBuilderBase.h
Normal file
111
ResourceCompilerPC/CrySkinBuilderBase.h
Normal file
@@ -0,0 +1,111 @@
|
||||
#ifndef _CRY_ANIMATION_CRY_SKIN_BUILDER_BASE_HDR_
|
||||
#define _CRY_ANIMATION_CRY_SKIN_BUILDER_BASE_HDR_
|
||||
|
||||
#include "CrySkinTypes.h"
|
||||
#include "CryVertexBinding.h"
|
||||
|
||||
// This interface presents all the necessary information to the skin builders
|
||||
// the actual skinned info can actually be vertices or normals - doesn't really matter
|
||||
class ICrySkinSource
|
||||
{
|
||||
public:
|
||||
// this structure is initialized through the constructor
|
||||
ICrySkinSource (
|
||||
const CryVertexBinding* pLinks,
|
||||
unsigned numLinks,
|
||||
const Vec3* pVertices,
|
||||
unsigned numVertices,
|
||||
const TangData* pExtTangents,
|
||||
unsigned numExtTangents,
|
||||
const unsigned* pExtToIntMapping
|
||||
):
|
||||
m_pLinks (pLinks),
|
||||
m_numLinks (numLinks),
|
||||
m_pVertices (pVertices),
|
||||
m_numVertices (numVertices),
|
||||
m_pExtTangents (pExtTangents),
|
||||
m_numExtTangents (numExtTangents),
|
||||
m_pExtToIntMapping (pExtToIntMapping)
|
||||
{}
|
||||
unsigned numVertices()const {return m_numVertices;}
|
||||
const Vec3& getVertex (unsigned i)const {return m_pVertices[i];}
|
||||
unsigned numLinks() const {return m_numLinks;}
|
||||
const CryVertexBinding& getLink (unsigned i) const {return m_pLinks[i];}
|
||||
unsigned numExtTangents() const {return m_numExtTangents;}
|
||||
const unsigned *getExtToIntMapEntries()const {return m_pExtToIntMapping;}
|
||||
const TangData& getExtTangent(unsigned i)const {return m_pExtTangents[i];}
|
||||
protected:
|
||||
// this needs to be filled in by the derived class
|
||||
unsigned m_numLinks;
|
||||
const CryVertexBinding* m_pLinks;
|
||||
unsigned m_numVertices;
|
||||
const Vec3* m_pVertices;
|
||||
const TangData* m_pExtTangents;
|
||||
unsigned m_numExtTangents;
|
||||
const unsigned* m_pExtToIntMapping;
|
||||
};
|
||||
|
||||
class CrySkinBuilderBase0
|
||||
{
|
||||
public:
|
||||
CrySkinBuilderBase0(const class ICrySkinSource* pGeometry):
|
||||
m_pGeometry (pGeometry)
|
||||
{}
|
||||
|
||||
typedef CrySkinVertexAligned Vertex;
|
||||
|
||||
struct CrySkinStreams
|
||||
{
|
||||
CrySkinAuxInt* pAux;
|
||||
Vertex* pVert;
|
||||
};
|
||||
protected:
|
||||
const ICrySkinSource* m_pGeometry;
|
||||
};
|
||||
|
||||
class CrySkinBuilderBase: public CrySkinBuilderBase0
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
CrySkinBuilderBase(const class ICrySkinSource* pGeometry);
|
||||
|
||||
// Calculates the total number of links per all vertices. If the whole object is rigid,
|
||||
// the number of links is the same as the number of vertices.
|
||||
// Also calculates the sets of vertices belonging to each bone
|
||||
// calculates the max number of bone affecting a vertex + 1
|
||||
// and the total number of links to smooth vertices - the sum of numbers of links of all smooth vertices
|
||||
void preprocess();
|
||||
|
||||
// calculates the vertex list of each bone, for all vertices present in the geometry
|
||||
void makeFullBoneVertexArrays();
|
||||
|
||||
// fills in the group of aux ints for the given bone (the rigid vertex group)
|
||||
// returns the pointer to the next available auxint after the group
|
||||
void fillRigidGroup (CrySkinStreams& streams, unsigned nBone);
|
||||
|
||||
protected:
|
||||
|
||||
// precalculated numbers
|
||||
unsigned m_numLinks; // total number of links (number of aligned vertex structures)
|
||||
unsigned m_numBones; // number of bones affecting the skin, in the original array (max bone id + 1)
|
||||
unsigned m_numSmoothLinks; // number of smooth links
|
||||
|
||||
// the sets of vertices belonging to each bone
|
||||
typedef std::vector< CrySkinRigidVertex > CrySkinRigidVertexArray;
|
||||
typedef std::vector< CrySkinSmoothVertex > CrySkinSmoothVertexArray;
|
||||
struct BoneVertexGroup
|
||||
{
|
||||
CrySkinRigidVertexArray arrRigid;
|
||||
CrySkinSmoothVertexArray arrSmooth;
|
||||
bool empty() const{return arrRigid.empty() && arrSmooth.empty();}
|
||||
void reserve (unsigned numReserve)
|
||||
{
|
||||
arrRigid.reserve (numReserve/2);
|
||||
arrSmooth.reserve (numReserve/2);
|
||||
}
|
||||
};
|
||||
typedef std::vector< BoneVertexGroup > BoneVertexArray;
|
||||
BoneVertexArray m_arrBoneVerts;
|
||||
};
|
||||
|
||||
#endif
|
||||
515
ResourceCompilerPC/CrySkinFull.cpp
Normal file
515
ResourceCompilerPC/CrySkinFull.cpp
Normal file
@@ -0,0 +1,515 @@
|
||||
#include "stdafx.h"
|
||||
#include "MathUtils.h"
|
||||
#include "CrySkinBuilderBase.h"
|
||||
#include "CrySkinFull.h"
|
||||
#include "platform.h"
|
||||
|
||||
#define FOR_TEST 0
|
||||
|
||||
// takes each offset and includes it into the bbox of corresponding bone
|
||||
/*void CrySkinFull::computeBoneBBoxes(CryBBoxA16* pBBoxes)
|
||||
{
|
||||
CrySkinAuxInt* pAux = &m_arrAux[0];
|
||||
Vertex* pVertex = &m_arrVertices[0];
|
||||
CryBBoxA16* pBBox = pBBoxes + m_numSkipBones, *pBBoxEnd = pBBoxes + m_numBones;
|
||||
|
||||
for (; pBBox!= pBBoxEnd; ++pBBox)
|
||||
{
|
||||
// each bone has a group of vertices
|
||||
|
||||
// first process the rigid vertices
|
||||
Vertex* pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex)
|
||||
pBBox->include(pVertex->pt);
|
||||
|
||||
// process the smooth1 vertices that were the first time met
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
pBBox->include(pVertex->pt);
|
||||
|
||||
// process the smooth vertices that were the second time met
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
pBBox->include(pVertex->pt);
|
||||
}
|
||||
}*/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// does the skinning out of the given array of global matrices
|
||||
void CrySkinFull::skin (const Matrix44* pBones, Vec3d* pDest)
|
||||
{
|
||||
#ifdef DEFINE_PROFILER_FUNCTION
|
||||
DEFINE_PROFILER_FUNCTION();
|
||||
#endif
|
||||
|
||||
//PROFILE_FRAME_SELF(PureSkin);
|
||||
#if FOR_TEST
|
||||
for (int i = 0; i < g_GetCVars()->ca_TestSkinningRepeats(); ++i)
|
||||
#endif
|
||||
{
|
||||
|
||||
const Matrix44* pBone = pBones + m_numSkipBones;
|
||||
const Matrix44* pBonesEnd = pBones + m_numBones;
|
||||
|
||||
u32 s = 0;
|
||||
u32 t = 0;
|
||||
|
||||
#ifdef _DEBUG
|
||||
TFixedArray<float> arrW;
|
||||
arrW.reinit(m_numDests, 0);
|
||||
#endif
|
||||
|
||||
for (; pBone!= pBonesEnd; ++pBone)
|
||||
{
|
||||
|
||||
Matrix34 m34 = Matrix34( GetTransposed44(*pBone) );
|
||||
|
||||
// first process the rigid vertices
|
||||
u32 a0=m_arrAux[t];
|
||||
for (u32 i=0; i<a0; i++ )
|
||||
{
|
||||
//_mm_prefetch( (char*)&m_arrVertices[s+20].pt, _MM_HINT_T0 );
|
||||
pDest[m_arrVertices[s].nDest] = m34 * m_arrVertices[s].pt;
|
||||
|
||||
#ifdef _DEBUG
|
||||
assert (arrW[m_arrVertices[s].nDest] == 0);
|
||||
arrW[m_arrVertices[s].nDest] = 1;
|
||||
#endif
|
||||
s++;
|
||||
}
|
||||
t++;
|
||||
|
||||
// process the smooth1 vertices that were the first time met
|
||||
u32 a1=m_arrAux[t]; t++;
|
||||
for (u32 i=0; i<a1; i++ )
|
||||
{
|
||||
//_mm_prefetch( (char*)&m_arrVertices[s+20].pt, _MM_HINT_T0 );
|
||||
pDest[m_arrAux[t]]= (m34*m_arrVertices[s].pt) * m_arrVertices[s].fWeight;
|
||||
|
||||
#ifdef _DEBUG
|
||||
assert (arrW[m_arrAux[t]] == 0);
|
||||
arrW[m_arrAux[t]] = m_arrVertices[s].fWeight;
|
||||
#endif
|
||||
s++;
|
||||
t++;
|
||||
}
|
||||
|
||||
// process the smooth vertices that were the first time met
|
||||
u32 a2=m_arrAux[t]; t++;
|
||||
for (u32 i=0; i<a2; i++)
|
||||
{
|
||||
//_mm_prefetch( (char*)&m_arrVertices[s+20].pt, _MM_HINT_T0 );
|
||||
pDest[m_arrAux[t]] += (m34*m_arrVertices[s].pt) * m_arrVertices[s].fWeight;
|
||||
|
||||
#ifdef _DEBUG
|
||||
assert (arrW[m_arrAux[t]] > 0 && arrW[m_arrAux[t]] < 1.005f);
|
||||
arrW[m_arrAux[t]] += m_arrVertices[s].fWeight;
|
||||
assert (arrW[m_arrAux[t]] > 0 && arrW[m_arrAux[t]] < 1.005f);
|
||||
#endif
|
||||
s++;
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
/*#ifdef _DEBUG
|
||||
for (unsigned i = 0; i < m_numDests; ++i)
|
||||
assert (arrW[i] > 0.995f && arrW[i] < 1.005f);
|
||||
#endif
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// does the skinning out of the given array of global matrices
|
||||
void CrySkinFull::skinAsVec3d16 (const Matrix44* pBones, Vec3dA16* pDest)
|
||||
{
|
||||
//PROFILE_FRAME_SELF(PureSkin);
|
||||
#if FOR_TEST
|
||||
for (int i = 0; i < g_GetCVars()->ca_TestSkinningRepeats(); ++i)
|
||||
#endif
|
||||
{
|
||||
const Matrix44* pBone = pBones + m_numSkipBones, *pBonesEnd = pBones + m_numBones;
|
||||
CrySkinAuxInt* pAux = &m_arrAux[0];
|
||||
Vertex* pVertex = &m_arrVertices[0];
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
TFixedArray<float> arrW;
|
||||
arrW.reinit(m_numDests, 0);
|
||||
#endif
|
||||
|
||||
for (; pBone!= pBonesEnd; ++pBone)
|
||||
{
|
||||
// each bone has a group of vertices
|
||||
|
||||
// first process the rigid vertices
|
||||
Vertex* pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex)
|
||||
{
|
||||
//CHANGED_BY_IVO - INVALID CHANGE, PLEASE REVISE
|
||||
pDest[pVertex->nDest].v = pBone->TransformVectorOLD(pVertex->pt);
|
||||
// Temporary fixed by Sergiy. A new operation in the Matrix must be made
|
||||
//pDest[pVertex->nDest].v = GetTransposed44(*pBone) * (pVertex->pt);
|
||||
//transformVectorNoTrans (pDest[pVertex->nDest].v, pVertex->pt, *pBone);
|
||||
#ifdef _DEBUG
|
||||
assert (arrW[pVertex->nDest] == 0);
|
||||
arrW[pVertex->nDest] = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// process the smooth1 vertices that were the first time met
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
{
|
||||
transformWVector (pDest[*pAux].v, *pBone, *pVertex);
|
||||
#ifdef _DEBUG
|
||||
assert (arrW[*pAux] == 0);
|
||||
arrW[*pAux] = pVertex->fWeight;
|
||||
#endif
|
||||
}
|
||||
|
||||
// process the smooth vertices that were the first time met
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
{
|
||||
addWVector (pDest[*pAux].v, *pBone, *pVertex);
|
||||
#ifdef _DEBUG
|
||||
assert (arrW[*pAux] > 0 && arrW[*pAux] < 1.005f);
|
||||
arrW[*pAux] += pVertex->fWeight;
|
||||
assert (arrW[*pAux] > 0 && arrW[*pAux] < 1.005f);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
for (unsigned i = 0; i < m_numDests; ++i)
|
||||
assert (arrW[i] > 0.995f && arrW[i] < 1.005f);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void CrySkinFull::CStatistics::addDest(unsigned nDest)
|
||||
{
|
||||
if (arrNumLinks.size() < nDest+1)
|
||||
arrNumLinks.resize (nDest+1,0);
|
||||
++arrNumLinks[nDest];
|
||||
setDests.insert (nDest);
|
||||
}
|
||||
|
||||
void CrySkinFull::CStatistics::initSetDests (const CrySkinFull* pSkin)
|
||||
{
|
||||
const CrySkinAuxInt* pAux = &pSkin->m_arrAux[0];
|
||||
const Vertex* pVertex = &pSkin->m_arrVertices[0];
|
||||
|
||||
arrNumLinks.clear();
|
||||
|
||||
for (unsigned nBone = pSkin->m_numSkipBones; nBone < pSkin->m_numBones; ++nBone)
|
||||
{
|
||||
// each bone has a group of vertices
|
||||
|
||||
// first process the rigid vertices
|
||||
const Vertex* pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex)
|
||||
{
|
||||
unsigned nDest = pVertex->nDest;
|
||||
addDest (nDest);
|
||||
assert (arrNumLinks[nDest] == 1);
|
||||
}
|
||||
|
||||
// process the smooth1 vertices that were the first time met
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
{
|
||||
unsigned nDest = *pAux;
|
||||
addDest (nDest);
|
||||
assert (arrNumLinks[nDest] == 1);
|
||||
//pVertex->fWeight is the weight of the vertex
|
||||
}
|
||||
|
||||
// process the smooth vertices that were the second/etc time met
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
{
|
||||
unsigned nDest = *pAux;
|
||||
addDest (nDest);
|
||||
assert (arrNumLinks[nDest] > 1);
|
||||
// pVertex->fWeight contains the weight of the vertex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// validates the skin against the given geom info
|
||||
#if defined (_DEBUG)
|
||||
void CrySkinFull::validate (const ICrySkinSource* pGeometry)
|
||||
{
|
||||
TElementaryArray<unsigned> arrNumLinks ("CrySkinFull::validate.arrNumLinks");
|
||||
arrNumLinks.reinit (pGeometry->numVertices(), 0);
|
||||
|
||||
CrySkinAuxInt* pAux = &m_arrAux[0];
|
||||
Vertex* pVertex = &m_arrVertices[0];
|
||||
|
||||
for (unsigned nBone = m_numSkipBones; nBone < m_numBones; ++nBone)
|
||||
{
|
||||
// each bone has a group of vertices
|
||||
|
||||
// first process the rigid vertices
|
||||
Vertex* pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex)
|
||||
{
|
||||
unsigned nDest = pVertex->nDest;
|
||||
const CryVertexBinding& rLink = pGeometry->getLink(nDest);
|
||||
assert (arrNumLinks[nDest] == 0);
|
||||
arrNumLinks[nDest] = 1;
|
||||
assert (rLink.size()==1);
|
||||
assert (rLink[0].Blending == 1);
|
||||
assert (rLink[0].BoneID == nBone);
|
||||
}
|
||||
|
||||
// process the smooth1 vertices that were the first time met
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
{
|
||||
unsigned nDest = *pAux;
|
||||
const CryVertexBinding& rLink = pGeometry->getLink(nDest);
|
||||
assert (arrNumLinks[nDest]++ == 0);
|
||||
assert (rLink.size()>1);
|
||||
float fLegacyWeight = rLink.getBoneWeight(nBone);
|
||||
assert (pVertex->fWeight == fLegacyWeight);
|
||||
}
|
||||
|
||||
// process the smooth vertices that were the first time met
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
{
|
||||
unsigned nDest = *pAux;
|
||||
const CryVertexBinding& rLink = pGeometry->getLink(nDest);
|
||||
assert (arrNumLinks[nDest]++ > 0);
|
||||
assert (arrNumLinks[nDest] <= rLink.size());
|
||||
assert (rLink.size()>1);
|
||||
float fLegacyWeight = rLink.getBoneWeight(nBone);
|
||||
assert (rLink.hasBoneWeight(nBone,pVertex->fWeight));
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned nVert = 0; nVert < pGeometry->numVertices(); ++nVert)
|
||||
assert (arrNumLinks[nVert] == pGeometry->getLink(nVert).size());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( defined (_CPU_X86) || defined (_CPU_AMD64) ) & !defined(LINUX)
|
||||
|
||||
DEFINE_ALIGNED_DATA( CryBBoxA16, CrySkinFull::g_BBox, 32 ); // align by cache line boundaries
|
||||
|
||||
#if defined (_CPU_AMD64)
|
||||
extern "C" void Amd64Skinner(CrySkinAuxInt* pAux, CrySkinVertexAligned* pVertex, Vec3dA16* pDest, const Matrix44* pBone, Vec3dA16* pvMin,const Matrix44* pBoneEnd);
|
||||
#endif
|
||||
|
||||
|
||||
void CrySkinFull::skinSSE (const Matrix44* pBones, Vec3dA16* pDest)
|
||||
{
|
||||
|
||||
#ifdef DEFINE_PROFILER_FUNCTION
|
||||
DEFINE_PROFILER_FUNCTION();
|
||||
#endif
|
||||
|
||||
//PROFILE_FRAME_SELF(PureSkin);
|
||||
const Matrix44* pBone = pBones + m_numSkipBones, *pBoneEnd = pBones + m_numBones;
|
||||
CrySkinAuxInt* pAux = &m_arrAux[0];
|
||||
Vertex* pVertex = &m_arrVertices[0];
|
||||
|
||||
// set the bbox to the negative volume to make sure the bbox will calculate starting from the first vertex
|
||||
g_BBox.vMin.v = Vec3d(1e6,1e6,1e6);// = pBone->GetTranslation();
|
||||
g_BBox.vMax.v = Vec3d(-1e6,-1e6,-1e6);// = pBone->GetTranslation();
|
||||
|
||||
#if FOR_TEST
|
||||
for (int i = 0; i < g_GetCVars()->ca_TestSkinningRepeats(); ++i)
|
||||
#endif
|
||||
|
||||
#if defined(_CPU_AMD64)
|
||||
Amd64Skinner(pAux, pVertex, pDest, pBone, &g_BBox.vMin, pBoneEnd);
|
||||
#else
|
||||
_asm
|
||||
{
|
||||
mov EDX, pAux
|
||||
mov EBX, pVertex
|
||||
mov EDI, pDest
|
||||
mov ESI, pBone
|
||||
|
||||
// load the current matrix; we don't need the move component
|
||||
startLoop:
|
||||
cmp ESI, pBoneEnd
|
||||
jz endLoop
|
||||
movaps xmm0, [ESI]
|
||||
movaps xmm1, [ESI+0x10]
|
||||
movaps xmm2, [ESI+0x20]
|
||||
movaps xmm3, [ESI+0x30]
|
||||
add ESI, 0x40
|
||||
|
||||
// load the counter for the number of non-flipped tangets for this bone
|
||||
#if CRY_SKIN_AUX_INT_SIZE==2
|
||||
xor ECX,ECX
|
||||
mov CX, word ptr [EDX]
|
||||
add EDX, 2
|
||||
#else
|
||||
mov ECX, dword ptr [EDX]
|
||||
add EDX, 4
|
||||
#endif
|
||||
test ECX, ECX
|
||||
jz endLoopRigid
|
||||
|
||||
startLoopRigid:
|
||||
// load the offset
|
||||
movaps xmm7, [EBX]
|
||||
// calculate the destination pointer
|
||||
mov EAX, [EBX+0xC]
|
||||
and EAX, 0xFFFFFF
|
||||
add EAX, EAX
|
||||
// EDI+EAX*8 points to the destination vector now
|
||||
add EBX, 0x10
|
||||
|
||||
// transform the vertex
|
||||
movss xmm6, xmm7
|
||||
shufps xmm6, xmm6, 0 // xmm6 = 4 copies of offset.x
|
||||
mulps xmm6, xmm0
|
||||
movaps xmm5, xmm7
|
||||
shufps xmm5, xmm5, 0x55 // xmm5 = 4 copies of offset.y
|
||||
mulps xmm5, xmm1
|
||||
shufps xmm7, xmm7, 0xAA // xmm7 = 4 copies of offset.z
|
||||
mulps xmm7, xmm2
|
||||
addps xmm7, xmm5
|
||||
addps xmm7, xmm6
|
||||
addps xmm7, xmm3 // xmm7 = fully transformed vertex, store it
|
||||
// xmm7 = transformed vertex
|
||||
movaps [EDI+EAX*8], xmm7
|
||||
|
||||
//----------------------
|
||||
// Calculation of BBox
|
||||
// xmm5 will be the min, xmm6 will be the max of bbox
|
||||
movaps xmm5, xmm7
|
||||
movaps xmm6, xmm7
|
||||
minps xmm5, g_BBox.vMin
|
||||
maxps xmm6, g_BBox.vMax
|
||||
movaps g_BBox.vMin, xmm5
|
||||
movaps g_BBox.vMax, xmm6
|
||||
|
||||
loop startLoopRigid
|
||||
endLoopRigid:
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// Smooth-1 loop
|
||||
// load the counter for the number of smooth vertices met for the first time
|
||||
//////////////////////////////////////////////////////////
|
||||
#if CRY_SKIN_AUX_INT_SIZE==2
|
||||
xor ECX,ECX
|
||||
mov CX, word ptr [EDX]
|
||||
add EDX, 2
|
||||
#else
|
||||
mov ECX, dword ptr [EDX]
|
||||
add EDX, 4
|
||||
#endif
|
||||
test ECX, ECX
|
||||
jz endLoopSmooth1
|
||||
|
||||
startLoopSmooth1:
|
||||
// load the offset & blending
|
||||
movaps xmm7, [EBX]
|
||||
// calculate the destination pointer
|
||||
#if CRY_SKIN_AUX_INT_SIZE==2
|
||||
xor EAX,EAX
|
||||
mov AX, word ptr [EDX]
|
||||
add EDX, 2
|
||||
#else
|
||||
mov EAX, dword ptr [EDX]
|
||||
add EDX, 4
|
||||
#endif
|
||||
add EAX, EAX
|
||||
// EDI+EAX*8 points to the destination vector now
|
||||
add EBX, 0x10
|
||||
|
||||
// transform the vertex
|
||||
movss xmm6, xmm7
|
||||
shufps xmm6, xmm6, 0 // xmm6 = 4 copies of offset.x
|
||||
mulps xmm6, xmm0
|
||||
movaps xmm5, xmm7
|
||||
shufps xmm5, xmm5, 0x55 // xmm5 = 4 copies of offset.y
|
||||
mulps xmm5, xmm1
|
||||
movaps xmm4, xmm7
|
||||
shufps xmm4, xmm4, 0xAA // xmm4 = 4 copies of offset.z
|
||||
mulps xmm4, xmm2
|
||||
addps xmm4, xmm5
|
||||
addps xmm4, xmm6
|
||||
addps xmm4, xmm3 // xmm4 = fully transformed vertex, blend it
|
||||
shufps xmm7, xmm7, 0xFF // xmm7 = 4 copies of blending
|
||||
mulps xmm7, xmm4
|
||||
// xmm7 = transformed and blended vertex
|
||||
movaps [EDI+EAX*8], xmm7
|
||||
|
||||
loop startLoopSmooth1
|
||||
//loop startLoopNonflipped
|
||||
endLoopSmooth1:
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// Smooth-2 loop
|
||||
// load the counter for the number of smooth vertices met for the second time
|
||||
//////////////////////////////////////////////////////////
|
||||
#if CRY_SKIN_AUX_INT_SIZE==2
|
||||
xor ECX,ECX
|
||||
mov CX, word ptr [EDX]
|
||||
add EDX, 2
|
||||
#else
|
||||
mov ECX, dword ptr [EDX]
|
||||
add EDX, 4
|
||||
#endif
|
||||
test ECX, ECX
|
||||
jz endLoopSmooth2
|
||||
|
||||
startLoopSmooth2:
|
||||
// load the offset & blending
|
||||
movaps xmm7, [EBX]
|
||||
// calculate the destination pointer
|
||||
#if CRY_SKIN_AUX_INT_SIZE==2
|
||||
xor EAX,EAX
|
||||
mov AX, word ptr [EDX]
|
||||
add EDX, 2
|
||||
#else
|
||||
mov EAX, dword ptr [EDX]
|
||||
add EDX, 4
|
||||
#endif
|
||||
shl EAX, 4
|
||||
add EAX, EDI
|
||||
// EAX points to the destination vector now
|
||||
add EBX, 0x10
|
||||
|
||||
// transform the vertex
|
||||
movss xmm6, xmm7
|
||||
shufps xmm6, xmm6, 0 // xmm6 = 4 copies of offset.x
|
||||
mulps xmm6, xmm0
|
||||
movaps xmm5, xmm7
|
||||
shufps xmm5, xmm5, 0x55 // xmm5 = 4 copies of offset.y
|
||||
mulps xmm5, xmm1
|
||||
movaps xmm4, xmm7
|
||||
shufps xmm4, xmm4, 0xAA // xmm4 = 4 copies of offset.z
|
||||
mulps xmm4, xmm2
|
||||
addps xmm4, xmm5
|
||||
addps xmm4, xmm6
|
||||
addps xmm4, xmm3 // xmm4 = fully transformed vertex, blend it
|
||||
shufps xmm7, xmm7, 0xFF // xmm7 = 4 copies of blending
|
||||
mulps xmm7, xmm4
|
||||
// xmm7 = transformed and blended vertex
|
||||
addps xmm7, [EAX]
|
||||
movaps [EAX], xmm7
|
||||
|
||||
loop startLoopSmooth2
|
||||
//loop startLoopNonflipped
|
||||
endLoopSmooth2:
|
||||
|
||||
jmp startLoop
|
||||
endLoop:
|
||||
}
|
||||
#endif // _CPU_AMD64
|
||||
}
|
||||
#endif
|
||||
63
ResourceCompilerPC/CrySkinFull.h
Normal file
63
ResourceCompilerPC/CrySkinFull.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef _CRY_SKIN_HDR_
|
||||
#define _CRY_SKIN_HDR_
|
||||
|
||||
#include "CrySkinTypes.h"
|
||||
#include "CrySkinBase.h"
|
||||
#include "platform.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// the optimized skinner; built with the CrySkinBuilder class instance,
|
||||
// destroyed with the Release()
|
||||
// This is the full skinner: it skins into a memory with garbage in it
|
||||
class CrySkinFull: public CrySkinBase
|
||||
{
|
||||
public:
|
||||
friend class CrySkinBuilder;
|
||||
|
||||
// does the skinning out of the given array of global matrices
|
||||
void skin (const Matrix44* pBones, Vec3* pDest);
|
||||
// Skins skipping the translation components of bone matrices
|
||||
void skinAsVec3d16 (const Matrix44* pBones, Vec3dA16* pDest);
|
||||
#if ( defined (_CPU_X86) || defined (_CPU_AMD64) ) & !defined(LINUX)
|
||||
// skins using the given bone matrices, into the given destination array,
|
||||
// SIDE EFFECT: calculates the bounding box into the g_BBox
|
||||
void skinSSE (const Matrix44* pBones, Vec3dA16* pDest);
|
||||
DEFINE_ALIGNED_DATA_STATIC( CryBBoxA16, g_BBox, 32 ); // align by cache line boundaries
|
||||
#endif
|
||||
|
||||
// takes each offset and includes it into the bbox of corresponding bone
|
||||
void computeBoneBBoxes(CryBBoxA16* pBBox);
|
||||
|
||||
void scale (float fScale)
|
||||
{
|
||||
scaleVertices(fScale);
|
||||
}
|
||||
|
||||
// validates the skin against the given geom info
|
||||
void validate (const class ICrySkinSource* pGeometry);
|
||||
|
||||
// this structure contains the statistical information about this skin; its calculation
|
||||
// may take significant time and should not be used in game run time (only for debugging purposes
|
||||
// and to output statistics in the tools)
|
||||
class CStatistics: public CrySkinBase::CStatistics
|
||||
{
|
||||
public:
|
||||
CStatistics (const CrySkinFull* pSkin):
|
||||
CrySkinBase::CStatistics(pSkin)
|
||||
{
|
||||
initSetDests (pSkin);
|
||||
}
|
||||
|
||||
void initSetDests (const CrySkinFull* pSkin);
|
||||
void addDest(unsigned nDest);
|
||||
|
||||
// destination vertex set
|
||||
std::set<unsigned> setDests;
|
||||
// the number of links per each vertex
|
||||
std::vector<unsigned> arrNumLinks;
|
||||
};
|
||||
|
||||
friend class CStatistics;
|
||||
};
|
||||
|
||||
#endif
|
||||
154
ResourceCompilerPC/CrySkinMorph.cpp
Normal file
154
ResourceCompilerPC/CrySkinMorph.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "stdafx.h"
|
||||
#include "CrySkinMorph.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// does the skinning out of the given array of global matrices
|
||||
void CrySkinMorph::skin (const Matrix44* pBones, float fWeight, Vec3d* pDest)const
|
||||
{
|
||||
#ifdef PROFILE_FRAME_SELF
|
||||
//PROFILE_FRAME_SELF(PureSkin);
|
||||
#endif
|
||||
const Matrix44* pBone = pBones + m_numSkipBones, *pBonesEnd = pBones + m_numBones;
|
||||
const CrySkinAuxInt* pAux = &m_arrAux[0];
|
||||
const Vertex* pVertex = &m_arrVertices[0];
|
||||
|
||||
#ifdef _DEBUG
|
||||
TFixedArray<float> arrW;
|
||||
arrW.reinit(m_numDests, 0);
|
||||
#endif
|
||||
|
||||
for (; pBone!= pBonesEnd; ++pBone)
|
||||
{
|
||||
// each bone has a group of vertices
|
||||
|
||||
// first process the rigid vertices
|
||||
const Vertex* pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex)
|
||||
{
|
||||
//CHANGED_BY_IVO - INVALID CHANGE, PLEASE REVISE
|
||||
pDest[pVertex->nDest] += pBone->TransformVectorOLD(pVertex->pt) * fWeight;
|
||||
//pDest[pVertex->nDest] += (GetTransposed44(*pBone)*(pVertex->pt)) * fWeight;
|
||||
#ifdef _DEBUG
|
||||
assert (arrW[pVertex->nDest] == 0);
|
||||
arrW[pVertex->nDest] = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// then process the smooth vertices
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
{
|
||||
pDest[*pAux] += pBone->TransformVectorOLD(pVertex->pt) * (fWeight * pVertex->fWeight);
|
||||
// pDest[*pAux] += (GetTransposed44(*pBone)*pVertex->pt) * fWeight * pVertex->fWeight;
|
||||
|
||||
#ifdef _DEBUG
|
||||
assert (arrW[*pAux] >= 0 && arrW[*pAux] < 1.005f);
|
||||
arrW[*pAux] += pVertex->fWeight;
|
||||
assert (arrW[*pAux] >= 0 && arrW[*pAux] < 1.005f);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
for (unsigned i = 0; i < m_numDests; ++i)
|
||||
assert (arrW[i] == 0 || (arrW[i] > 0.995f && arrW[i] < 1.005f));
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// does the skinning out of the given array of global matrices,
|
||||
// tries to estimate the changes in normals
|
||||
void CrySkinMorph::skin (const Matrix44* pBones, float fWeight, Vec3d* pDest, Vec3dA16* pDestNormalsA16, float fAmplify)const
|
||||
{
|
||||
//PROFILE_FRAME_SELF(PureSkin);
|
||||
|
||||
const Matrix44* pBone = pBones + m_numSkipBones, *pBonesEnd = pBones + m_numBones;
|
||||
const CrySkinAuxInt* pAux = &m_arrAux[0];
|
||||
const Vertex* pVertex = &m_arrVertices[0];
|
||||
|
||||
#ifdef _DEBUG
|
||||
TFixedArray<float> arrW;
|
||||
arrW.reinit(m_numDests, 0);
|
||||
#endif
|
||||
|
||||
for (; pBone!= pBonesEnd; ++pBone)
|
||||
{
|
||||
// each bone has a group of vertices
|
||||
|
||||
// first process the rigid vertices
|
||||
const Vertex* pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex)
|
||||
{
|
||||
//CHANGED_BY_IVO - INVALID CHANGE, PLEASE REVISE
|
||||
Vec3d vOffset = pBone->TransformVectorOLD(pVertex->pt) * fWeight;
|
||||
pDest[pVertex->nDest] += vOffset;
|
||||
pDestNormalsA16[pVertex->nDest].v += vOffset * fAmplify;
|
||||
//pDest[pVertex->nDest] += (GetTransposed44(*pBone)*(pVertex->pt)) * fWeight;
|
||||
#ifdef _DEBUG
|
||||
assert (arrW[pVertex->nDest] == 0);
|
||||
arrW[pVertex->nDest] = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// then process the smooth vertices
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
{
|
||||
Vec3d vOffset = pBone->TransformVectorOLD(pVertex->pt) * (fWeight * pVertex->fWeight);
|
||||
pDest[*pAux] += vOffset;
|
||||
pDestNormalsA16[*pAux].v += vOffset * fAmplify;
|
||||
// pDest[*pAux] += (GetTransposed44(*pBone)*pVertex->pt) * fWeight * pVertex->fWeight;
|
||||
|
||||
#ifdef _DEBUG
|
||||
assert (arrW[*pAux] >= 0 && arrW[*pAux] < 1.005f);
|
||||
arrW[*pAux] += pVertex->fWeight;
|
||||
assert (arrW[*pAux] >= 0 && arrW[*pAux] < 1.005f);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
for (unsigned i = 0; i < m_numDests; ++i)
|
||||
assert (arrW[i] == 0 || (arrW[i] > 0.995f && arrW[i] < 1.005f));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CrySkinMorph::CStatistics::init (const CrySkinMorph* pSkin)
|
||||
{
|
||||
const CrySkinAuxInt* pAux = &pSkin->m_arrAux[0];
|
||||
const Vertex* pVertex = &pSkin->m_arrVertices[0];
|
||||
numRigid = numSmooth = 0;
|
||||
fMinOffset = fMaxOffset = -1;
|
||||
for (unsigned nBone = pSkin->m_numSkipBones; nBone < pSkin->m_numBones; ++nBone)
|
||||
{
|
||||
// each bone has a group of vertices
|
||||
|
||||
// first process the rigid vertices
|
||||
const Vertex* pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex)
|
||||
{
|
||||
//pDest[pVertex->nDest] += pBone->TransformVector(pVertex->pt) * fWeight;
|
||||
setDests.insert (pVertex->nDest);
|
||||
addOffset (pVertex->pt);
|
||||
++numRigid;
|
||||
}
|
||||
|
||||
// then process the smooth vertices
|
||||
pGroupEnd = pVertex + *pAux++;
|
||||
for (;pVertex < pGroupEnd; ++pVertex, ++pAux)
|
||||
{
|
||||
//pDest[*pAux] += pBone->TransformVector(pVertex->pt) * (fWeight * pVertex->fWeight);
|
||||
setDests.insert (*pAux);
|
||||
addOffset (pVertex->pt);
|
||||
++numSmooth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CrySkinMorph::CStatistics::addOffset (const Vec3d& v)
|
||||
{
|
||||
float d = v.Length();
|
||||
if (fMaxOffset < 0 || d > fMaxOffset)
|
||||
fMaxOffset = d;
|
||||
if (fMinOffset < 0 || d < fMinOffset)
|
||||
fMinOffset = d;
|
||||
}
|
||||
49
ResourceCompilerPC/CrySkinMorph.h
Normal file
49
ResourceCompilerPC/CrySkinMorph.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef _CRY_ANIMATION_CRY_SKIN_MORPH_HDR_
|
||||
#define _CRY_ANIMATION_CRY_SKIN_MORPH_HDR_
|
||||
|
||||
#include "CrySkinBase.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// This skinner is capable only of morphing a few vertices and adding their
|
||||
// displacements to the destination vertex array
|
||||
class CrySkinMorph: public CrySkinBase
|
||||
{
|
||||
public:
|
||||
// does the skinning out of the given array of global matrices:
|
||||
// adds the corresponding displacements with the given weight
|
||||
void skin (const Matrix44* pBones, float fWeight, Vec3d* pDest)const;
|
||||
|
||||
// does the skinning out of the given array of global matrices:
|
||||
// adds the corresponding displacements with the given weight
|
||||
// also tries to estimate the changes in normals
|
||||
void skin (const Matrix44* pBones, float fWeight, Vec3d* pDest, Vec3dA16* pDestNormalsA16, float fAmplify = 1) const;
|
||||
|
||||
void scale (float fScale)
|
||||
{
|
||||
// to scale it, we just need to proportionally scale each vertex x,y,z
|
||||
scaleVertices(fScale);
|
||||
}
|
||||
|
||||
friend class CrySkinMorphBuilder;
|
||||
|
||||
class CStatistics: public CrySkinBase::CStatistics
|
||||
{
|
||||
public:
|
||||
CStatistics (const CrySkinMorph* pSkin):
|
||||
CrySkinBase::CStatistics(pSkin)
|
||||
{
|
||||
init(pSkin);
|
||||
}
|
||||
void init(const CrySkinMorph* pSkin);
|
||||
void addOffset (const Vec3d& v);
|
||||
|
||||
// destination vertex set
|
||||
std::set<unsigned> setDests;
|
||||
// number of rigid and smooth vertices
|
||||
unsigned numRigid, numSmooth;
|
||||
// minimum and maximum offset length
|
||||
float fMinOffset, fMaxOffset;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
185
ResourceCompilerPC/CrySkinMorphBuilder.cpp
Normal file
185
ResourceCompilerPC/CrySkinMorphBuilder.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
#include "stdafx.h"
|
||||
#include "CrySkinMorphBuilder.h"
|
||||
#include "CrySkinMorph.h"
|
||||
|
||||
CrySkinMorphBuilder::CrySkinMorphBuilder(const ICrySkinSource* pGeometry, const Matrix44* pMatInvDef, unsigned numBones):
|
||||
CrySkinBuilderBase (pGeometry),
|
||||
m_pMatInvDef(pMatInvDef),
|
||||
m_numBones(numBones)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// initializes the given skin out of the given morph target
|
||||
void CrySkinMorphBuilder::initSkinMorph (const SMeshMorphTargetVertex* pMorphVerts, unsigned numMorphVerts, class CrySkinMorph* pSkin)
|
||||
{
|
||||
m_pMorphVerts = pMorphVerts;
|
||||
m_numMorphVerts = numMorphVerts;
|
||||
m_pSkinTarget = pSkin;
|
||||
pSkin->m_numDests = m_pGeometry->numVertices();
|
||||
|
||||
if (!numMorphVerts)
|
||||
{
|
||||
pSkin->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
findAffectingBoneRange();
|
||||
|
||||
makeMorphBoneVertexArray();
|
||||
|
||||
calculateNumMorphLinks();
|
||||
|
||||
validate();
|
||||
|
||||
// for aux ints, we need, for each bone:
|
||||
// 2 ints for group headers
|
||||
// for each smooth link,
|
||||
// 1 int for index of the target vertex
|
||||
unsigned numAuxInts = 2 * (m_numAffectingBones - m_nFirstAffectingBone) + m_numMorphSmoothLinks;
|
||||
|
||||
pSkin->init (m_numMorphRigidLinks + m_numMorphSmoothLinks,
|
||||
numAuxInts,
|
||||
m_nFirstAffectingBone,
|
||||
m_numAffectingBones);
|
||||
|
||||
CrySkinStreams stream, streamBegin, streamEnd;
|
||||
streamBegin.pAux = pSkin->m_arrAux.begin();
|
||||
streamBegin.pVert = pSkin->m_arrVertices.begin();
|
||||
stream = streamBegin;
|
||||
streamEnd.pAux = streamBegin.pAux + numAuxInts;
|
||||
streamEnd.pVert = streamBegin.pVert + m_numMorphRigidLinks + m_numMorphSmoothLinks;
|
||||
|
||||
for (unsigned nBone = m_nFirstAffectingBone; nBone < m_numAffectingBones; ++nBone)
|
||||
{
|
||||
// for each bone, fill the three groups
|
||||
// we start from the rigid vertices
|
||||
fillRigidGroup (stream, nBone);
|
||||
assert (stream.pAux <= streamEnd.pAux);
|
||||
assert (stream.pVert <= streamEnd.pVert);
|
||||
fillSmoothGroup (stream, nBone);
|
||||
// only when we processed the last bone, we should have the pAux pointing to the end
|
||||
assert (stream.pAux <= streamEnd.pAux);
|
||||
assert (stream.pVert <= streamEnd.pVert);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// for the given morph target(source) finds and initializes the
|
||||
// m_nFirstAffectingBone and m_numAffectingBones
|
||||
void CrySkinMorphBuilder::findAffectingBoneRange()
|
||||
{
|
||||
// init - find the first vertex binding info
|
||||
const CryVertexBinding* pLinks = &m_pGeometry->getLink(m_pMorphVerts[0].nVertexId);
|
||||
m_nFirstAffectingBone = pLinks->minBoneID();
|
||||
m_numAffectingBones = pLinks->maxBoneID()+1;
|
||||
|
||||
// find all the other vertex binding info and init the bone range
|
||||
for (unsigned nMorphVert = 1; nMorphVert < m_numMorphVerts; ++nMorphVert)
|
||||
{
|
||||
unsigned nGeomVert = m_pMorphVerts[nMorphVert].nVertexId;
|
||||
pLinks = &m_pGeometry->getLink(nGeomVert);
|
||||
m_nFirstAffectingBone = min (m_nFirstAffectingBone, pLinks->minBoneID());
|
||||
m_numAffectingBones = max(m_numAffectingBones, pLinks->maxBoneID()+1);
|
||||
}
|
||||
|
||||
assert (m_nFirstAffectingBone < m_numAffectingBones);
|
||||
assert (m_numAffectingBones <= m_numBones);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// calculates the number of rigid and smooth links
|
||||
// m_numMorphRigidLinks and m_numMorphSmoothLinks
|
||||
void CrySkinMorphBuilder::calculateNumMorphLinks()
|
||||
{
|
||||
m_numMorphRigidLinks = 0;
|
||||
m_numMorphSmoothLinks = 0;
|
||||
for (unsigned nMorphVert = 0; nMorphVert < m_numMorphVerts; ++nMorphVert)
|
||||
{
|
||||
unsigned nGeomVert = m_pMorphVerts[nMorphVert].nVertexId;
|
||||
const CryVertexBinding* pLinks = &m_pGeometry->getLink(nGeomVert);
|
||||
|
||||
if (pLinks->size() == 1)
|
||||
++m_numMorphRigidLinks;
|
||||
else
|
||||
m_numMorphSmoothLinks += (unsigned)pLinks->size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// calculates the vertex list of each bone, taking only those vertices
|
||||
// present in the morph vertex array
|
||||
void CrySkinMorphBuilder::makeMorphBoneVertexArray()
|
||||
{
|
||||
m_arrBoneVerts.clear();
|
||||
m_arrBoneVerts.resize (m_numAffectingBones);
|
||||
for (unsigned nMorphVert = 0; nMorphVert < m_numMorphVerts; ++nMorphVert)
|
||||
{
|
||||
unsigned nGeomVert = m_pMorphVerts[nMorphVert].nVertexId;
|
||||
const CryVertexBinding* pLinks = &m_pGeometry->getLink(nGeomVert);
|
||||
// the morph vertex target in the object coordinates
|
||||
Vec3d ptMorphOffset = m_pMorphVerts[nMorphVert].ptVertex - m_pGeometry->getVertex(nGeomVert);
|
||||
|
||||
if (pLinks->size() == 1)
|
||||
{
|
||||
unsigned nBone = (*pLinks)[0].BoneID;
|
||||
CrySkinRigidVertex v;
|
||||
v.nDest = nGeomVert;
|
||||
// transform the point into the bone coordinates
|
||||
|
||||
//CHANGED_BY_IVO - INVALID CHANGE, PLEASE REVISE
|
||||
v.pt = m_pMatInvDef[nBone].TransformVectorOLD (ptMorphOffset);
|
||||
//v.pt = GetTransposed44(m_pMatInvDef[nBone])*(ptMorphOffset);
|
||||
|
||||
m_arrBoneVerts[nBone].arrRigid.push_back(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned nLink = 0; nLink < pLinks->size(); ++nLink)
|
||||
{
|
||||
unsigned nBone = (*pLinks)[nLink].BoneID;
|
||||
CrySkinSmoothVertex v;
|
||||
v.fWeight = (*pLinks)[nLink].Blending;
|
||||
v.nDest = nGeomVert;
|
||||
|
||||
v.pt = m_pMatInvDef[nBone].TransformVectorOLD (ptMorphOffset);
|
||||
|
||||
m_arrBoneVerts[nBone].arrSmooth.push_back(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CrySkinMorphBuilder::validate()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
unsigned nBone;
|
||||
for (nBone = 0; nBone < m_nFirstAffectingBone;++nBone)
|
||||
assert (m_arrBoneVerts[nBone].empty());
|
||||
assert (!m_arrBoneVerts[m_nFirstAffectingBone].empty());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// fills in the group of aux ints for the given bone (the smooth vertex group)
|
||||
// returns the pointer to the next available auxint after the group
|
||||
void CrySkinMorphBuilder::fillSmoothGroup (CrySkinStreams& streams, unsigned nBone)
|
||||
{
|
||||
CrySkinSmoothVertexArray& arrSmooth = m_arrBoneVerts[nBone].arrSmooth;
|
||||
|
||||
// the group starts with the number of rigid vertices belonging to this bone
|
||||
*streams.pAux++ = (CrySkinAuxInt)arrSmooth.size();
|
||||
|
||||
CrySkinSmoothVertexArray::const_iterator it = arrSmooth.begin(), itEnd = it + arrSmooth.size();
|
||||
|
||||
for (; it != itEnd; ++it)
|
||||
{
|
||||
it->build (*streams.pVert++);
|
||||
*streams.pAux++ = it->nDest;
|
||||
}
|
||||
}
|
||||
57
ResourceCompilerPC/CrySkinMorphBuilder.h
Normal file
57
ResourceCompilerPC/CrySkinMorphBuilder.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef _CRY_ANIMATION_CRY_SKIN_MORPH_BUILDER_HDR_
|
||||
#define _CRY_ANIMATION_CRY_SKIN_MORPH_BUILDER_HDR_
|
||||
|
||||
#include "CrySkinBuilderBase.h"
|
||||
class CrySkinMorph;
|
||||
|
||||
// builds the skin morph
|
||||
class CrySkinMorphBuilder: public CrySkinBuilderBase
|
||||
{
|
||||
public:
|
||||
// Receives the geometry and the array of inverse-default-global matrices
|
||||
// 1 matrix per 1 bone
|
||||
CrySkinMorphBuilder(const ICrySkinSource* pGeometry, const Matrix44* pMatInvDef, unsigned numBones);
|
||||
|
||||
// initializes the given skin out of the given morph target
|
||||
void initSkinMorph (const SMeshMorphTargetVertex* pMorphVerts, unsigned numMorphVerts, class CrySkinMorph* pSkin);
|
||||
|
||||
protected:
|
||||
// for the given morph target(source) finds and initializes the m_nFirstAffectingBone and m_numAffectingBones
|
||||
void findAffectingBoneRange();
|
||||
|
||||
// calculates the number of rigid and smooth links
|
||||
void calculateNumMorphLinks();
|
||||
|
||||
// calculates the vertex list of each bone, taking only those vertices
|
||||
// present in the morph vertex array
|
||||
void makeMorphBoneVertexArray();
|
||||
|
||||
void validate();
|
||||
|
||||
|
||||
// fills in the group of aux ints for the given bone (the smooth vertex group)
|
||||
// returns the pointer to the next available auxint after the group
|
||||
void fillSmoothGroup (CrySkinStreams& streams, unsigned nBone);
|
||||
protected:
|
||||
// the bone info that's used to translate the
|
||||
// the matrices are from getInvDefGlobal() of each corresponding CryBoneInfo
|
||||
const Matrix44* m_pMatInvDef;
|
||||
unsigned m_numBones;
|
||||
|
||||
// this is set temporarily during initialization of the skin out of the morph target structure
|
||||
const SMeshMorphTargetVertex* m_pMorphVerts;
|
||||
unsigned m_numMorphVerts;
|
||||
CrySkinMorph* m_pSkinTarget;
|
||||
|
||||
// the first bone affecting the morph target
|
||||
unsigned m_nFirstAffectingBone;
|
||||
// the number of bones that are to be taken into account, does NOT depend on m_numFirstAffectingBone
|
||||
unsigned m_numAffectingBones;
|
||||
|
||||
// the total number of rigid links for the current morph target
|
||||
unsigned m_numMorphRigidLinks;
|
||||
// the total number of smooth links for the current morph target
|
||||
unsigned m_numMorphSmoothLinks;
|
||||
};
|
||||
|
||||
#endif
|
||||
460
ResourceCompilerPC/CrySkinRigidBasis.cpp
Normal file
460
ResourceCompilerPC/CrySkinRigidBasis.cpp
Normal file
@@ -0,0 +1,460 @@
|
||||
#include "stdafx.h"
|
||||
//#include "CryAnimationBase.h"
|
||||
#include "CrySkinRigidBasis.h"
|
||||
|
||||
#define FOR_TEST 0
|
||||
|
||||
#if FOR_TEST
|
||||
#include "CryAnimation.h"
|
||||
#include "CVars.h"
|
||||
#endif
|
||||
|
||||
// returns the size of the skin, the number of bases being calculated
|
||||
// by this skin. The bases are calculated into a 0-base continuous array
|
||||
// tangents may be divided into subskins, each having different number of bases
|
||||
// to skin, based on the performance consideration (strip mining)
|
||||
unsigned CrySkinRigidBasis::size()const
|
||||
{
|
||||
return m_numDestBases;
|
||||
}
|
||||
|
||||
// does the same as the base class init() but also remembers the number of bases (numVerts/2)
|
||||
// for future reference
|
||||
void CrySkinRigidBasis::init (unsigned numVerts, unsigned numAux, unsigned numSkipBones, unsigned numBones)
|
||||
{
|
||||
m_numDestBases = numVerts >> 1;
|
||||
CrySkinBase::init (numVerts, numAux, numSkipBones, numBones);
|
||||
}
|
||||
|
||||
|
||||
void CrySkinRigidBasis::CStatistics::initSetDests (const CrySkinRigidBasis* pSkin)
|
||||
{
|
||||
const CrySkinAuxInt* pAux = &pSkin->m_arrAux[0];
|
||||
const Vertex* pVertex = &pSkin->m_arrVertices[0];
|
||||
setDests.clear();
|
||||
arrNumLinks.clear();
|
||||
|
||||
for (unsigned nBone = pSkin->m_numSkipBones; nBone < pSkin->m_numBones; ++nBone)
|
||||
{
|
||||
// each bone has a group of (always rigid) vertices
|
||||
|
||||
// this is to take into account two groups: non-flipped and flipped tangents
|
||||
for (int t = 0; t < 2; ++t)
|
||||
{
|
||||
// for each actual basis, we have two vertices
|
||||
const Vertex* pGroupEnd = pVertex + (*pAux++<<1);
|
||||
for (;pVertex < pGroupEnd; pVertex+=2)
|
||||
{
|
||||
unsigned nDestOffset = pVertex[0].nDest & 0xFFFFFF;
|
||||
assert (nDestOffset < pSkin->m_numDestBases*sizeof(SPipTangentsA) && nDestOffset % sizeof(SPipTangentsA) == 0);
|
||||
unsigned nDest = nDestOffset / sizeof(SPipTangentsA);
|
||||
addDest(nDest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CrySkinRigidBasis::CStatistics::addDest(unsigned nDest)
|
||||
{
|
||||
if (arrNumLinks.size() < nDest+1)
|
||||
arrNumLinks.resize (nDest+1,0);
|
||||
++arrNumLinks[nDest];
|
||||
setDests.insert (nDest);
|
||||
}
|
||||
|
||||
|
||||
// does the skinning out of the given array of global matrices:
|
||||
// calculates the bases and fills the PipVertices in
|
||||
void CrySkinRigidBasis::skin (const Matrix44* pBones, SPipTangentsA* pDest)const
|
||||
{
|
||||
#ifdef DEFINE_PROFILER_FUNCTION
|
||||
DEFINE_PROFILER_FUNCTION();
|
||||
#endif
|
||||
|
||||
#if FOR_TEST
|
||||
for (int i = 0; i < g_GetCVars()->ca_TestSkinningRepeats(); ++i)
|
||||
#endif
|
||||
{
|
||||
const Matrix44* pBone = pBones + m_numSkipBones, *pBonesEnd = pBones + m_numBones;
|
||||
const CrySkinAuxInt* pAux = &m_arrAux[0];
|
||||
const Vertex* pVertex = &m_arrVertices[0];
|
||||
|
||||
for (; pBone!= pBonesEnd; ++pBone)
|
||||
{
|
||||
// each bone has a group of (always rigid) vertices
|
||||
|
||||
// for each actual basis, we have two vertices
|
||||
const Vertex* pGroupEnd = pVertex + (*pAux++<<1);
|
||||
for (;pVertex < pGroupEnd; pVertex+=2)
|
||||
{
|
||||
unsigned nDestOffset = pVertex[0].nDest & 0xFFFFFF;
|
||||
assert (nDestOffset < m_numDestBases*sizeof(SPipTangentsA));
|
||||
SPipTangentsA& rDest = *(SPipTangentsA*)(UINT_PTR(pDest) + nDestOffset);
|
||||
Vec3d vTang = pBone->TransformVectorOLD(pVertex[0].pt);
|
||||
Vec3d vBinorm = pBone->TransformVectorOLD(pVertex[1].pt);
|
||||
rDest.m_Tangent = vTang;
|
||||
rDest.m_Binormal = vBinorm;
|
||||
rDest.m_TNormal = vTang^vBinorm;
|
||||
}
|
||||
|
||||
// the flipped version
|
||||
pGroupEnd = pVertex + (*pAux++<<1);
|
||||
for (;pVertex < pGroupEnd; pVertex+=2)
|
||||
{
|
||||
unsigned nDestOffset = pVertex[0].nDest & 0xFFFFFF;
|
||||
assert (nDestOffset < m_numDestBases*sizeof(SPipTangentsA));
|
||||
SPipTangentsA& rDest = *(SPipTangentsA*)(UINT_PTR(pDest) + nDestOffset);
|
||||
Vec3d vTang = pBone->TransformVectorOLD(pVertex[0].pt);
|
||||
Vec3d vBinorm = pBone->TransformVectorOLD(pVertex[1].pt);
|
||||
|
||||
rDest.m_Tangent = vTang;
|
||||
rDest.m_Binormal = vBinorm;
|
||||
rDest.m_TNormal = vBinorm^vTang;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(_CPU_X86) && !defined(LINUX)
|
||||
// uses SSE for skinning; NOTE: EVERYTHING must be 16-aligned:
|
||||
// destination, bones, and the data in this object
|
||||
void CrySkinRigidBasis::skinSSE (const Matrix44* pBones, SPipTangentsA* pDest)const
|
||||
{
|
||||
#ifdef DEFINE_PROFILER_FUNCTION
|
||||
DEFINE_PROFILER_FUNCTION();
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG) && FOR_TEST
|
||||
TElementaryArray<SPipTangentsA> arrTest ("CrySkinRigidBasis::skinSSE");
|
||||
arrTest.reinit(size());
|
||||
skin (pBones, &arrTest[0]);
|
||||
#endif
|
||||
|
||||
#if FOR_TEST
|
||||
for (int i = 0; i < g_GetCVars()->ca_TestSkinningRepeats(); ++i)
|
||||
#endif
|
||||
{
|
||||
const Matrix44* pBone = pBones + m_numSkipBones, *pBoneEnd = pBones + m_numBones;
|
||||
const CrySkinAuxInt* pAux = &m_arrAux[0];
|
||||
const Vertex* pVertex = &m_arrVertices[0];
|
||||
|
||||
_asm
|
||||
{
|
||||
mov EDX, pAux
|
||||
mov EBX, pVertex
|
||||
mov EDI, pDest
|
||||
mov ESI, pBone
|
||||
|
||||
// load the current matrix; we don't need the move component
|
||||
startLoop:
|
||||
cmp ESI, pBoneEnd
|
||||
jz endLoop
|
||||
movaps xmm0, [ESI]
|
||||
movaps xmm1, [ESI+0x10]
|
||||
movaps xmm2, [ESI+0x20]
|
||||
add ESI, 0x40
|
||||
|
||||
// load the counter for the number of non-flipped tangets for this bone
|
||||
#if CRY_SKIN_AUX_INT_SIZE==2
|
||||
xor ECX,ECX
|
||||
mov CX, word ptr [EDX]
|
||||
add EDX, 2
|
||||
#else
|
||||
mov ECX, dword ptr [EDX]
|
||||
add EDX, 4
|
||||
#endif
|
||||
test ECX, ECX
|
||||
jz endLoopNonflipped
|
||||
|
||||
startLoopNonflipped:
|
||||
// load the tangent vector
|
||||
movaps xmm7, [EBX]
|
||||
// load the binormal
|
||||
// calculate the destination pointer
|
||||
mov EAX, [EBX+0xC]
|
||||
and EAX, 0xFFFFFF
|
||||
add EAX, EDI
|
||||
// EAX points to the destination triplet of vectors now
|
||||
movaps xmm6, [EBX+0x10]
|
||||
add EBX, 0x20
|
||||
//prefetchnta [EBX]
|
||||
|
||||
// calculate the transformed tangent and binormal
|
||||
movss xmm5, xmm7
|
||||
shufps xmm5, xmm5, 0 // xmm5 = 4 copies of tangent.x
|
||||
mulps xmm5, xmm0
|
||||
movaps xmm4, xmm7
|
||||
shufps xmm4, xmm4, 0x55 // xmm4 = 4 copies of tangent.y
|
||||
mulps xmm4, xmm1
|
||||
shufps xmm7, xmm7, 0xAA // xmm7 = 4 copies of tangent.z
|
||||
mulps xmm7, xmm2
|
||||
addps xmm7, xmm4
|
||||
addps xmm7, xmm5
|
||||
// xmm7 = transformed tangent
|
||||
#if sizeofSPipTangentsA == 0x30
|
||||
movaps [EAX], xmm7
|
||||
#else
|
||||
//SSE_MOVSS(EAX,xmm7)
|
||||
movss [EAX], xmm7
|
||||
shufps xmm7,xmm7, 0x39 // roll right
|
||||
movss [EAX+4], xmm7
|
||||
shufps xmm7,xmm7, 0x39 // roll right
|
||||
movss [EAX+8], xmm7
|
||||
shufps xmm7, xmm7, 0x4E // roll left twice
|
||||
#endif
|
||||
|
||||
// transform the binormal
|
||||
movss xmm5, xmm6
|
||||
shufps xmm5, xmm5, 0
|
||||
mulps xmm5, xmm0
|
||||
movaps xmm4, xmm6
|
||||
shufps xmm4, xmm4, 0x55
|
||||
mulps xmm4, xmm1
|
||||
shufps xmm6, xmm6, 0xAA
|
||||
mulps xmm6, xmm2
|
||||
addps xmm6, xmm4
|
||||
addps xmm6, xmm5
|
||||
// xmm6 = transformed binormal
|
||||
#if sizeofSPipTangentsA == 0x30
|
||||
movaps [EAX+0x10], xmm6
|
||||
#else
|
||||
//SSE_MOVSS(EAX+0xC,xmm7)
|
||||
movss [EAX+0xC], xmm6
|
||||
shufps xmm6,xmm6, 0x39
|
||||
movss [EAX+0xC+4], xmm6
|
||||
shufps xmm6,xmm6, 0x39
|
||||
movss [EAX+0xC+8], xmm6
|
||||
shufps xmm6, xmm6, 0x4E // roll left twice
|
||||
#endif
|
||||
|
||||
// calculate the cross product tangent (xmm7)^binormal (xmm6)
|
||||
movaps xmm5, xmm7
|
||||
shufps xmm5, xmm5, 0x09 // roll right 3-base
|
||||
movaps xmm4, xmm6
|
||||
shufps xmm4, xmm4, 0x12 // roll left 3-base
|
||||
//shufps xmm4, xmm4, 0x09 // roll right 3-base
|
||||
mulps xmm5, xmm4
|
||||
|
||||
shufps xmm7, xmm7, 0x12 // roll left 3-base
|
||||
shufps xmm6, xmm6, 0x09 // roll right 3-base
|
||||
//shufps xmm7, xmm7, 0x09 // roll right 3-base
|
||||
mulps xmm7, xmm6
|
||||
subps xmm5, xmm7
|
||||
//shufps xmm5,xmm5, 0x09
|
||||
#if sizeofSPipTangentsA == 0x30
|
||||
movaps [EAX+0x20], xmm5
|
||||
#else
|
||||
//SSE_MOVSS(EAX+0x18,xmm5)
|
||||
movss [EAX+0x18], xmm5
|
||||
shufps xmm5,xmm5, 0x39
|
||||
movss [EAX+0x18+4], xmm5
|
||||
shufps xmm5,xmm5, 0x39
|
||||
movss [EAX+0x18+8], xmm5
|
||||
shufps xmm5, xmm5, 0x4E // roll left twice
|
||||
#endif
|
||||
|
||||
dec ECX
|
||||
jnz startLoopNonflipped
|
||||
//loop startLoopNonflipped
|
||||
endLoopNonflipped:
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// Flipped loop
|
||||
|
||||
// load the counter for the number of flipped tangets for this bone
|
||||
#if CRY_SKIN_AUX_INT_SIZE==2
|
||||
xor ECX,ECX
|
||||
mov CX, word ptr [EDX]
|
||||
add EDX, 2
|
||||
#else
|
||||
mov ECX, dword ptr [EDX]
|
||||
add EDX, 4
|
||||
#endif
|
||||
test ECX, ECX
|
||||
jz endLoopFlipped
|
||||
|
||||
startLoopFlipped:
|
||||
// load the tangent vector
|
||||
movaps xmm7, [EBX]
|
||||
// load the binormal
|
||||
movaps xmm6, [EBX+0x10]
|
||||
// calculate the destination pointer
|
||||
mov EAX, [EBX+0xC]
|
||||
and EAX, 0xFFFFFF
|
||||
add EAX, EDI
|
||||
// EAX points to the destination triplet of vectors now
|
||||
add EBX, 0x20
|
||||
//prefetchnta [EBX]
|
||||
|
||||
// calculate the transformed tangent and binormal
|
||||
movss xmm5, xmm7
|
||||
shufps xmm5, xmm5, 0 // xmm5 = 4 copies of tangent.x
|
||||
mulps xmm5, xmm0
|
||||
movaps xmm4, xmm7
|
||||
shufps xmm4, xmm4, 0x55 // xmm4 = 4 copies of tangent.y
|
||||
mulps xmm4, xmm1
|
||||
shufps xmm7, xmm7, 0xAA // xmm7 = 4 copies of tangent.z
|
||||
mulps xmm7, xmm2
|
||||
addps xmm7, xmm4
|
||||
addps xmm7, xmm5
|
||||
// xmm7 = transformed tangent
|
||||
#if sizeofSPipTangentsA == 0x30
|
||||
movaps [EAX], xmm7
|
||||
#else
|
||||
//SSE_MOVSS(EAX,xmm7)
|
||||
movss [EAX], xmm7
|
||||
shufps xmm7,xmm7, 0x39
|
||||
movss [EAX+4], xmm7
|
||||
shufps xmm7,xmm7, 0x39
|
||||
movss [EAX+8], xmm7
|
||||
shufps xmm7, xmm7, 0x4E // roll left twice
|
||||
#endif
|
||||
|
||||
// transform the binormal
|
||||
movss xmm5, xmm6
|
||||
shufps xmm5, xmm5, 0
|
||||
mulps xmm5, xmm0
|
||||
movaps xmm4, xmm6
|
||||
shufps xmm4, xmm4, 0x55
|
||||
mulps xmm4, xmm1
|
||||
shufps xmm6, xmm6, 0xAA
|
||||
mulps xmm6, xmm2
|
||||
addps xmm6, xmm4
|
||||
addps xmm6, xmm5
|
||||
// xmm6 = transformed binormal
|
||||
#if sizeofSPipTangentsA == 0x30
|
||||
movaps [EAX+0x10], xmm6
|
||||
#else
|
||||
//SSE_MOVSS(EAX+0xC,xmm6)
|
||||
movss [EAX+0xC], xmm6
|
||||
shufps xmm6,xmm6, 0x39
|
||||
movss [EAX+0xC+4], xmm6
|
||||
shufps xmm6,xmm6, 0x39
|
||||
movss [EAX+0xC+8], xmm6
|
||||
shufps xmm6, xmm6, 0x4E // roll left twice
|
||||
#endif
|
||||
|
||||
// calculate the cross product binormal (xmm6)^tangent (xmm7)
|
||||
movaps xmm5, xmm7
|
||||
shufps xmm5, xmm5, 0x09 // roll right 3-base
|
||||
movaps xmm4, xmm6
|
||||
shufps xmm4, xmm4, 0x12 // roll left 3-base
|
||||
//shufps xmm4, xmm4, 0x09 // roll right 3-base
|
||||
mulps xmm5, xmm4
|
||||
|
||||
shufps xmm7, xmm7, 0x12 // roll left 3-base
|
||||
shufps xmm6, xmm6, 0x09 // roll right 3-base
|
||||
//shufps xmm7, xmm7, 0x09 // roll right 3-base
|
||||
mulps xmm7, xmm6
|
||||
subps xmm7, xmm5
|
||||
//shufps xmm7,xmm7, 9
|
||||
#if sizeofSPipTangentsA == 0x30
|
||||
movaps [EAX+0x20], xmm7
|
||||
#else
|
||||
//SSE_MOVSS(EAX+0x18,xmm7)
|
||||
movss [EAX+0x18], xmm7
|
||||
shufps xmm7,xmm7, 0x39
|
||||
movss [EAX+0x18+4], xmm7
|
||||
shufps xmm7,xmm7, 0x39
|
||||
movss [EAX+0x18+8], xmm7
|
||||
shufps xmm7, xmm7, 0x4E // roll left twice
|
||||
#endif
|
||||
|
||||
dec ECX
|
||||
jnz startLoopFlipped
|
||||
//loop startLoopFlipped
|
||||
endLoopFlipped:
|
||||
jmp startLoop
|
||||
endLoop:
|
||||
}
|
||||
}
|
||||
#if defined(_DEBUG) && FOR_TEST
|
||||
unsigned numBases = 0;
|
||||
|
||||
for (unsigned nBone = m_numSkipBones; nBone < m_numBones; ++nBone)
|
||||
{
|
||||
assert (numBases < size());
|
||||
const CrySkinAuxInt* pAux = &m_arrAux[(nBone-m_numSkipBones)*2];
|
||||
SPipTangentsA* pBTest;
|
||||
SPipTangentsA* pBDest;
|
||||
const Vertex*pVertex = &m_arrVertices[numBases*2];
|
||||
|
||||
// check the non-flipped bases
|
||||
unsigned i, j;
|
||||
float dT, dB, dN;
|
||||
for (i = 0; i < pAux[0]; ++i, ++numBases, pVertex+=2)
|
||||
{
|
||||
pBTest = (SPipTangentsA*)(((unsigned)&arrTest[0])+(pVertex->nDest&0xFFFFFF));
|
||||
pBDest = (SPipTangentsA*)(((unsigned)pDest)+(pVertex->nDest&0xFFFFFF));
|
||||
dT = Distance2(pBTest->m_Tangent,pBDest->m_Tangent);
|
||||
dB = Distance2(pBTest->m_Binormal,pBDest->m_Binormal);
|
||||
dN = Distance2(pBTest->m_TNormal,pBDest->m_TNormal);
|
||||
assert (dT < 1e-6 && dB < 1e-6 && dN < 1e-6);
|
||||
}
|
||||
for (j = 0; j < pAux[1]; ++j, ++numBases, pVertex+=2)
|
||||
{
|
||||
pBTest = (SPipTangentsA*)(((unsigned)&arrTest[0])+(pVertex->nDest&0xFFFFFF));
|
||||
pBDest = (SPipTangentsA*)(((unsigned)pDest)+(pVertex->nDest&0xFFFFFF));
|
||||
dT = Distance2(pBTest->m_Tangent,pBDest->m_Tangent);
|
||||
dB = Distance2(pBTest->m_Binormal,pBDest->m_Binormal);
|
||||
dN = Distance2(pBTest->m_TNormal,pBDest->m_TNormal);
|
||||
assert (dT < 1e-6 && dB < 1e-6 && dN < 1e-6);
|
||||
}
|
||||
}
|
||||
assert (numBases == size());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// returns the number of bytes occupied by this structure and all its contained objects
|
||||
unsigned CrySkinRigidBasis::sizeofThis()const
|
||||
{
|
||||
return CrySkinBase::sizeofThis() + sizeof(CrySkinRigidBasis) - sizeof(CrySkinBase);
|
||||
}
|
||||
|
||||
unsigned CrySkinRigidBasis::Serialize (bool bSave, void* pBuffer, unsigned nBufSize)
|
||||
{
|
||||
if (bSave)
|
||||
{
|
||||
unsigned nWrittenBytes = CrySkinBase::Serialize_PC(true, pBuffer, nBufSize);
|
||||
if (nWrittenBytes)
|
||||
{
|
||||
if (pBuffer)
|
||||
*(unsigned*)(((char*)pBuffer)+nWrittenBytes) = m_numDestBases;
|
||||
|
||||
return sizeof(unsigned) + nWrittenBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
// error
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned nReadBytes = CrySkinBase::Serialize_PC(false, pBuffer, nBufSize);
|
||||
if (nReadBytes)
|
||||
{
|
||||
if (nBufSize - nReadBytes >= sizeof(unsigned))
|
||||
{
|
||||
m_numDestBases = *(unsigned*)(((char*)pBuffer)+nReadBytes);
|
||||
return nReadBytes + sizeof(unsigned);
|
||||
}
|
||||
else
|
||||
{
|
||||
//error - perhaps not the tang stream
|
||||
m_numDestBases = 0;
|
||||
clear();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//error
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
ResourceCompilerPC/CrySkinRigidBasis.h
Normal file
72
ResourceCompilerPC/CrySkinRigidBasis.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef _CRY_ANIMATION_CRY_SKIN_RIGID_BASIS_HDR_
|
||||
#define _CRY_ANIMATION_CRY_SKIN_RIGID_BASIS_HDR_
|
||||
|
||||
#include "CrySkinBase.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// This is the skin that calculates the tangent bases
|
||||
// the skin is assumed to be rigid.
|
||||
// The basises can be flipped, but may not be non-normalized or non-orthogonal
|
||||
//
|
||||
// IMPLEMENTATION NOTES:
|
||||
// each base is represented by the first 2 vectors in the vertex array.
|
||||
// the 3rd one is the cross-product, optionally negated with the 0x80000000
|
||||
// flag in the 2nd vertex's nDest field. The 1st vertex contains the destination
|
||||
// vertex index itself
|
||||
class CrySkinRigidBasis: public CrySkinBase
|
||||
{
|
||||
public:
|
||||
// returns the size of the skin, the number of bases being calculated
|
||||
// by this skin. The bases are calculated into a 0-base continuous array
|
||||
// tangents may be divided into subskins, each having different number of bases
|
||||
// to skin, based on the performance consideration (strip mining)
|
||||
unsigned size()const;
|
||||
|
||||
// does the skinning out of the given array of global matrices:
|
||||
// calculates the bases and fills the PipVertices in
|
||||
void skin (const Matrix44* pBones, SPipTangentsA* pDest)const;
|
||||
#if defined(_CPU_X86) && !defined(LINUX)
|
||||
// uses SSE for skinning; NOTE: EVERYTHING must be 16-aligned:
|
||||
// destination, bones, and the data in this object
|
||||
void skinSSE (const Matrix44* pBones, SPipTangentsA* pDest)const;
|
||||
#endif
|
||||
friend class CrySkinBasisBuilder;
|
||||
|
||||
// does the same as the base class init() but also remembers the number of bases (numVerts/2)
|
||||
// for future reference
|
||||
void init (unsigned numVerts, unsigned numAux, unsigned numSkipBones, unsigned numBones);
|
||||
|
||||
// returns the number of bytes occupied by this structure and all its contained objects
|
||||
unsigned sizeofThis()const;
|
||||
|
||||
friend class CStatistics;
|
||||
// this structure contains the statistical information about this skin; its calculation
|
||||
// may take significant time and should not be used in game run time (only for debugging purposes
|
||||
// and to output statistics in the tools)
|
||||
class CStatistics: public CrySkinBase::CStatistics
|
||||
{
|
||||
public:
|
||||
CStatistics (const CrySkinRigidBasis* pSkin):
|
||||
CrySkinBase::CStatistics(pSkin)
|
||||
{
|
||||
initSetDests (pSkin);
|
||||
}
|
||||
|
||||
void initSetDests (const CrySkinRigidBasis* pSkin);
|
||||
void addDest(unsigned nDest);
|
||||
|
||||
// destination vertex set
|
||||
std::set<unsigned> setDests;
|
||||
// the number of links per each vertex
|
||||
std::vector<unsigned> arrNumLinks;
|
||||
};
|
||||
|
||||
unsigned Serialize (bool bSave, void* pBuffer, unsigned nBufSize);
|
||||
protected:
|
||||
// The size of the skin, the number of bases being calculated
|
||||
// by this skin. The bases are calculated into a 0-base continuous array
|
||||
unsigned m_numDestBases;
|
||||
};
|
||||
|
||||
#endif
|
||||
181
ResourceCompilerPC/CrySkinTypes.h
Normal file
181
ResourceCompilerPC/CrySkinTypes.h
Normal file
@@ -0,0 +1,181 @@
|
||||
#ifndef _CRY_ANIMATION_CRY_SKIN_TYPES_HDR_
|
||||
#define _CRY_ANIMATION_CRY_SKIN_TYPES_HDR_
|
||||
|
||||
#include "MathUtils.h"
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// the packed skin vertex structure: rigid or smooth, 16 byte
|
||||
// the point is the original point in the bone's CS
|
||||
struct CrySkinVertexAligned
|
||||
{
|
||||
Vec3 pt;
|
||||
|
||||
union
|
||||
{
|
||||
unsigned nDest; // the destination vertex index to store the transformed point
|
||||
float fWeight; // the weight of the point
|
||||
};
|
||||
};
|
||||
|
||||
// the way the packed indices/group headers are kept: short or int
|
||||
#define CRY_SKIN_AUX_INT_SIZE 2
|
||||
|
||||
#if CRY_SKIN_AUX_INT_SIZE==2
|
||||
typedef unsigned short CrySkinAuxInt;
|
||||
#elif CRY_SKIN_AUX_INT_SIZE==4
|
||||
typedef unsigned CrySkinAuxInt;
|
||||
#if defined _CPU_AMD64
|
||||
#error You will need to modify the file CrySkinAMD64.ASM to make this work!
|
||||
#endif // _CPU_AMD64
|
||||
#else
|
||||
#error CRY_SKIN_AUX_INT_SIZE must be defined and be 2 or 4
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Unpacked rigid vertex structure
|
||||
struct CrySkinRigidVertex
|
||||
{
|
||||
Vec3 pt;
|
||||
unsigned nDest; // the destination vertex index
|
||||
|
||||
CrySkinRigidVertex(){}
|
||||
|
||||
// initializes the structure given the offset from the bone and the destination vertex index
|
||||
CrySkinRigidVertex (const Vec3& _ptOffset, unsigned _nDest):
|
||||
pt (_ptOffset),
|
||||
nDest (_nDest)
|
||||
{
|
||||
}
|
||||
|
||||
// constructs the packed rigid vertex data from this structure
|
||||
void build (CrySkinVertexAligned& vDst)const
|
||||
{
|
||||
vDst.pt = pt;
|
||||
vDst.nDest = nDest;
|
||||
}
|
||||
};
|
||||
|
||||
// aligned by 16-byte boundary tangent vectors
|
||||
// if you don't want the padding to be used, just define it as
|
||||
// typedef SPipTangents SPipTangentsA16;
|
||||
struct SPipTangentsA16
|
||||
{
|
||||
Vec3 m_Tangent;
|
||||
unsigned int m_Pad0;
|
||||
Vec3 m_Binormal;
|
||||
unsigned int m_Pad1;
|
||||
Vec3 m_TNormal;
|
||||
unsigned int m_Pad2;
|
||||
|
||||
inline SPipTangentsA16& operator = (const SPipTangents& right)
|
||||
{
|
||||
m_Tangent = right.m_Tangent;
|
||||
m_Binormal = right.m_Binormal;
|
||||
m_TNormal = right.m_TNormal;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void copyTo (SPipTangents* right)
|
||||
{/*
|
||||
#ifdef DO_ASM
|
||||
_asm
|
||||
{
|
||||
mov EBX, this
|
||||
mov EDX, right
|
||||
|
||||
mov EAX, [EBX]
|
||||
mov [EDX], EAX
|
||||
mov EAX, [EBX+4]
|
||||
mov [EDX+4], EAX
|
||||
mov EAX, [EBX+8]
|
||||
mov [EDX+8], EAX
|
||||
|
||||
mov EAX, [EBX+0x10]
|
||||
mov [EDX+0xC], EAX
|
||||
mov EAX, [EBX+0x14]
|
||||
mov [EDX+0x10], EAX
|
||||
mov EAX, [EBX+0x18]
|
||||
mov [EDX+0x14], EAX
|
||||
|
||||
mov EAX, [EBX+0x20]
|
||||
mov [EDX+0x18], EAX
|
||||
mov EAX, [EBX+0x24]
|
||||
mov [EDX+0x1C], EAX
|
||||
mov EAX, [EBX+0x28]
|
||||
mov [EBX+0x20], EAX
|
||||
}
|
||||
#else
|
||||
*/
|
||||
right->m_Tangent = m_Tangent;
|
||||
right->m_Binormal = m_Binormal;
|
||||
right->m_TNormal = m_TNormal;
|
||||
//#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// the size of the SPipTangentsA: can be either 0x30 for aligned structure or
|
||||
// 0x24 for non-aligned
|
||||
#define sizeofSPipTangentsA 0x24
|
||||
|
||||
#if sizeofSPipTangentsA == 0x24
|
||||
// this is the actual structure that's to be used to store tangents
|
||||
typedef SPipTangents SPipTangentsA;
|
||||
#elif sizeofSPipTangentsA == 0x30
|
||||
typedef SPipTangentsA16 SPipTangentsA;
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Unpacked rigid basis structure
|
||||
struct CrySkinRigidBaseInfo
|
||||
{
|
||||
Vec3 ptTangent;
|
||||
Vec3 ptBinormal;
|
||||
unsigned nDest;
|
||||
|
||||
CrySkinRigidBaseInfo (){}
|
||||
CrySkinRigidBaseInfo (const Matrix44& matInvDef, const TangData& rBasis, unsigned _nDest):
|
||||
ptTangent (matInvDef.TransformVectorOLD(rBasis.tangent)),
|
||||
ptBinormal(matInvDef.TransformVectorOLD(rBasis.binormal)),
|
||||
nDest (_nDest)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// constructs the packed representation of the base: uses pDst[0] for tangent and destination
|
||||
// vertex, and pDst[1] for binormal. Does not set the additional field of the pDst[1]
|
||||
void build (CrySkinVertexAligned* pDst)const
|
||||
{
|
||||
pDst[0].pt = ptTangent;
|
||||
// we multiply to get the actual offset (to avoid multiplication in assembly)
|
||||
// and add the dummy bits that avoid denormalization assists in SSE
|
||||
pDst[0].nDest = nDest * sizeof(SPipTangentsA) + 0x40000000;
|
||||
pDst[1].pt = ptBinormal;
|
||||
pDst[1].fWeight = 0;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Unpacked smooth vertex structure
|
||||
struct CrySkinSmoothVertex: public CrySkinRigidVertex
|
||||
{
|
||||
float fWeight;// the weight of the point
|
||||
|
||||
CrySkinSmoothVertex(){}
|
||||
|
||||
// initializes this smooth vertex structure
|
||||
CrySkinSmoothVertex (const CryLink& rLink, unsigned _nDest):
|
||||
CrySkinRigidVertex(rLink.offset, _nDest),
|
||||
fWeight(rLink.Blending)
|
||||
{
|
||||
}
|
||||
|
||||
// constructs the packed rigid vertex data from this structure
|
||||
void build (CrySkinVertexAligned& vDst)const
|
||||
{
|
||||
vDst.pt = pt;
|
||||
vDst.fWeight = fWeight;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
128
ResourceCompilerPC/CryVertexBinding.cpp
Normal file
128
ResourceCompilerPC/CryVertexBinding.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "stdafx.h"
|
||||
#include "CryVertexBinding.h"
|
||||
|
||||
|
||||
CryVertexBinding::CryVertexBinding()
|
||||
#ifdef DEBUG_STD_CONTAINERS
|
||||
:std::vector<CryLink>("CryVertexBinding")
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
// normalizes the weights of links so that they sum up to 1
|
||||
void CryVertexBinding::normalizeBlendWeights()
|
||||
{
|
||||
// renormalize blending
|
||||
float fBlendSumm = 0;
|
||||
unsigned j;
|
||||
for (j = 0; j < size(); j++)
|
||||
fBlendSumm += (*this)[j].Blending;
|
||||
|
||||
assert (fBlendSumm > 0.1f && fBlendSumm <=1.001f);
|
||||
|
||||
for (j=0; j<size(); j++)
|
||||
(*this)[j].Blending /= fBlendSumm;
|
||||
}
|
||||
|
||||
|
||||
// prunes the weights that are less than the specified minimal blending factor
|
||||
// ASSUMES: that the links are already sorted by the blending factors in descending order
|
||||
void CryVertexBinding::pruneSmallWeights(float fMinBlending, unsigned numMinLinks)
|
||||
{
|
||||
// remove 0 blending links and merge the links to the same bones
|
||||
unsigned j;
|
||||
for (j = numMinLinks; j < size(); j++)
|
||||
{
|
||||
assert (j == 0 || (*this)[j].Blending <= (*this)[j-1].Blending);
|
||||
if((*this)[j].Blending <= fMinBlending)
|
||||
{
|
||||
resize(j);
|
||||
assert(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
// the links to delete
|
||||
std::set<unsigned> setToDel;
|
||||
for (i = 0; i < size()-1; ++i)
|
||||
for (j = i+1; j < size(); ++j)
|
||||
if ((*this)[i].BoneID == (*this)[j].BoneID)
|
||||
setToDel.insert (j);
|
||||
|
||||
// delete
|
||||
for (std::set<unsigned>::reverse_iterator it = setToDel.rbegin(); it != setToDel.rend(); ++it)
|
||||
this->erase (*it);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
// remaps the bone ids
|
||||
void CryVertexBinding::remapBoneIds (const unsigned* arrBoneIdMap, unsigned numBoneIds)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
// if you get this assert, most probably there is dissynchronization between different LODs of the same model
|
||||
// - all of them must be exported with exactly the same skeletons.
|
||||
if(it->BoneID >= 0 && it->BoneID < (int)numBoneIds)
|
||||
it->BoneID = arrBoneIdMap[it->BoneID];
|
||||
else
|
||||
{
|
||||
#ifdef _CRY_ANIMATION_BASE_HEADER_
|
||||
g_GetLog()->LogError ("\001bone index is out of range");
|
||||
#endif
|
||||
it->BoneID = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// scales all the link offsets multiplying the offset by the given scale
|
||||
void CryVertexBinding::scaleOffsets(float fScale)
|
||||
{
|
||||
for (iterator itLink = begin(); itLink != end(); ++itLink)
|
||||
itLink->offset *= fScale;
|
||||
}
|
||||
|
||||
|
||||
// sorts the links by the blending factor, descending order
|
||||
void CryVertexBinding::sortByBlendingDescending()
|
||||
{
|
||||
// sort the links by blend factor to allow skip unimportant ones
|
||||
std::sort (begin(), end(), CryLinkOrderByBlending());
|
||||
}
|
||||
|
||||
// returns the maximum BoneID in the array of links
|
||||
unsigned CryVertexBinding::maxBoneID ()const
|
||||
{
|
||||
unsigned nResult = 0;
|
||||
for (unsigned i = 0; i < this->size(); ++i)
|
||||
nResult = max((unsigned)(*this)[i].BoneID, nResult);
|
||||
return nResult;
|
||||
}
|
||||
|
||||
// returns the minimal BoneID in the array of links
|
||||
unsigned CryVertexBinding::minBoneID () const
|
||||
{
|
||||
unsigned nResult = (unsigned)(*this)[0].BoneID;
|
||||
for (unsigned i = 1; i < this->size(); ++i)
|
||||
nResult = min((unsigned)(*this)[i].BoneID, nResult);
|
||||
return nResult;
|
||||
}
|
||||
|
||||
// returns the link weight to the given bone
|
||||
float CryVertexBinding::getBoneWeight (int nBoneID)const
|
||||
{
|
||||
for (unsigned i = 0; i < this->size(); ++i)
|
||||
if ((*this)[i].BoneID == nBoneID)
|
||||
return (*this)[i].Blending;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns true if there is such bone weight
|
||||
bool CryVertexBinding::hasBoneWeight (int nBoneID, float fWeight) const
|
||||
{
|
||||
for (unsigned i = 0; i < this->size(); ++i)
|
||||
if ((*this)[i].BoneID == nBoneID && (*this)[i].Blending == fWeight)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
48
ResourceCompilerPC/CryVertexBinding.h
Normal file
48
ResourceCompilerPC/CryVertexBinding.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Character Animation source code
|
||||
//
|
||||
// History:
|
||||
// 11/05/2002 - Created by Sergiy Migdalskiy <sergiy@crytek.de>
|
||||
//
|
||||
// Contains:
|
||||
// Declaration of CryVertexBinding, a class incapsulating the array of links of a vertex to bone.
|
||||
// This class is only used during construction of the geometry, and shouldn't be used for
|
||||
// calculating the actual skin in the run time.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _CRY_VERTEX_BINDING_HDR_
|
||||
#define _CRY_VERTEX_BINDING_HDR_
|
||||
|
||||
// array of crylinks for one vertex
|
||||
class CryVertexBinding: public std::vector<CryLink>
|
||||
{
|
||||
public:
|
||||
CryVertexBinding ();
|
||||
// scales all the link offsets multiplying the offset by the given scale
|
||||
void scaleOffsets(float fScale);
|
||||
// sorts the links by the blending factor, descending order
|
||||
void sortByBlendingDescending();
|
||||
// normalizes the weights of links so that they sum up to 1
|
||||
void normalizeBlendWeights();
|
||||
// prunes the weights that are less than the specified minimal blending factor.
|
||||
// Leaves (unpruned) at least the first numMinLinks links
|
||||
// ASSUMES:that the links are already sorted by the blending factors in descending order
|
||||
void pruneSmallWeights(float fMinBlending, unsigned numMinLinks = 1);
|
||||
// remaps the bone ids
|
||||
void remapBoneIds (const unsigned* arrBoneIdMap, unsigned numBoneIds);
|
||||
|
||||
// returns the maximum BoneID in the array of links
|
||||
unsigned maxBoneID ()const;
|
||||
// returns the minimal BoneID in the array of links
|
||||
unsigned minBoneID () const;
|
||||
|
||||
// returns the link weight to the given bone
|
||||
float getBoneWeight (int nBoneID) const;
|
||||
|
||||
// returns true if there is such bone weight
|
||||
bool hasBoneWeight (int nBoneID, float fWeight) const;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
192
ResourceCompilerPC/FileMapping.cpp
Normal file
192
ResourceCompilerPC/FileMapping.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
#include "StdAfx.h"
|
||||
#include "FileMapping.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#undef THIS_FILE
|
||||
static char THIS_FILE[] = __FILE__;
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Initializes an empty file mapping object
|
||||
CFileMapping::CFileMapping():
|
||||
m_nSize(0)
|
||||
,m_pData(0)
|
||||
#ifdef USE_FILE_MAPPING
|
||||
,m_hFile (INVALID_HANDLE_VALUE)
|
||||
,m_hMapping (0)
|
||||
#endif
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// initializes the object and tries to open the given file mapping
|
||||
CFileMapping::CFileMapping (const char* szFileName, unsigned nFlags):
|
||||
m_nSize(0)
|
||||
,m_pData(0)
|
||||
#ifdef USE_FILE_MAPPING
|
||||
,m_hFile (INVALID_HANDLE_VALUE)
|
||||
,m_hMapping (0)
|
||||
#endif
|
||||
{
|
||||
open (szFileName, nFlags);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// closes file mapping
|
||||
CFileMapping::~CFileMapping()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Retuns the size of the mapped file, or 0 if no file was mapped or the file is empty
|
||||
unsigned CFileMapping::getSize()const
|
||||
{
|
||||
return m_nSize;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Returns the pointer to the mapped file start in memory, or NULL if the file
|
||||
// wasn't mapped
|
||||
CFileMapping::PData CFileMapping::getData() const
|
||||
{
|
||||
return m_pData;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Returns the file data at the given offset
|
||||
CFileMapping::PData CFileMapping::getData(unsigned nOffset) const
|
||||
{
|
||||
if (m_pData)
|
||||
return ((char*)m_pData)+nOffset;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef USE_FILE_MAPPING
|
||||
// sets the given (already allocated) buffer to this object
|
||||
// the memory must be allocated with malloc()
|
||||
void CFileMapping::attach (PData pData, unsigned nSize)
|
||||
{
|
||||
close();
|
||||
m_pData = pData;
|
||||
m_nSize = nSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// initializes the object, opening the given file
|
||||
// if file open has failed, subsequent getData() and
|
||||
// getSize() will return zeros
|
||||
// Returns true if open was successful
|
||||
bool CFileMapping::open (const char* szFileName, unsigned nFlags)
|
||||
{
|
||||
close();
|
||||
#ifdef USE_FILE_MAPPING
|
||||
m_hFile = CreateFile (szFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
|
||||
DWORD dwError = 0;
|
||||
if (m_hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
m_nSize = GetFileSize(m_hFile, NULL);
|
||||
m_hMapping = CreateFileMapping (m_hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (m_hMapping != NULL)
|
||||
{
|
||||
m_pData = MapViewOfFile (m_hMapping, FILE_MAP_READ, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dwError = GetLastError();
|
||||
}
|
||||
#elif defined(_CRY_ANIMATION_BASE_HEADER_)
|
||||
ICryPak* pPak = g_GetPak();
|
||||
FILE* f = pPak->FOpen (szFileName, "rb", nFlags);
|
||||
if (f != NULL)
|
||||
{
|
||||
if (0 == pPak->FSeek (f, 0, SEEK_END))
|
||||
{
|
||||
m_nSize = pPak->FTell (f);
|
||||
if ((int)m_nSize >= 0)
|
||||
{
|
||||
if (0 == pPak->FSeek (f, 0, SEEK_SET))
|
||||
{
|
||||
void* pData = malloc (m_nSize);
|
||||
if (pData != NULL && 1 != pPak->FRead (pData, m_nSize, 1, f))
|
||||
free (pData);
|
||||
else
|
||||
m_pData = pData;
|
||||
}
|
||||
}
|
||||
}
|
||||
pPak->FClose (f);
|
||||
}
|
||||
#else
|
||||
FILE* f = fxopen (szFileName, "rb");
|
||||
if (f != NULL)
|
||||
{
|
||||
if (0 == fseek (f, 0, SEEK_END))
|
||||
{
|
||||
m_nSize = ftell (f);
|
||||
if ((int)m_nSize >= 0)
|
||||
{
|
||||
if (0 == fseek (f, 0, SEEK_SET))
|
||||
{
|
||||
void* pData = malloc (m_nSize);
|
||||
if (pData != NULL && 1 != fread (pData, m_nSize, 1, f))
|
||||
free (pData);
|
||||
else
|
||||
m_pData = pData;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose (f);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_pData)
|
||||
{
|
||||
// we couldn't map the file
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// closes file mapping
|
||||
// NOTE:
|
||||
// this function can also be used for rollback of unsuccessful file mapping open
|
||||
// opration and thus must be able to close partially open file mapping object
|
||||
void CFileMapping::close()
|
||||
{
|
||||
#ifdef USE_FILE_MAPPING
|
||||
if (m_pData)
|
||||
{
|
||||
UnmapViewOfFile(m_pData);
|
||||
m_pData = NULL;
|
||||
}
|
||||
|
||||
if (m_hMapping != NULL)
|
||||
{
|
||||
CloseHandle (m_hMapping);
|
||||
m_hMapping = NULL;
|
||||
}
|
||||
|
||||
if (m_hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle (m_hFile);
|
||||
m_hFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
#else
|
||||
if (m_pData)
|
||||
{
|
||||
if (m_pData)
|
||||
free (m_pData);
|
||||
m_pData = NULL;
|
||||
}
|
||||
#endif
|
||||
m_nSize = 0;
|
||||
}
|
||||
86
ResourceCompilerPC/FileMapping.h
Normal file
86
ResourceCompilerPC/FileMapping.h
Normal file
@@ -0,0 +1,86 @@
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CryEngine Source code
|
||||
//
|
||||
// File:FileMapping
|
||||
// Declaration of class CFileMapping
|
||||
// USE_FILE_MAPPING must be defined in the project for this class to really
|
||||
// use the file mapping. Otherwise it just emulates it
|
||||
//
|
||||
// History:
|
||||
// 06/26/2002 :Created by Sergiy Migdalskiy <sergiy@crytek.de>
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// class CFileMapping
|
||||
// Generic file mapping object, is capable of mapping a file with
|
||||
// a simple call of a method.
|
||||
//
|
||||
// NOTES:
|
||||
//
|
||||
// Read-only file mapping is supported only.
|
||||
//
|
||||
// Error handing is performed through examining the getData()
|
||||
// address: NULL means that no file was open (no file or I/O error)
|
||||
//
|
||||
// No exceptions are thrown.
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class CFileMapping: public _reference_target_t
|
||||
{
|
||||
public:
|
||||
// Initializes an empty file mapping object
|
||||
CFileMapping();
|
||||
// initializes the object and tries to open the given file mapping
|
||||
CFileMapping (const char* szFileName, unsigned nFlags = 0);
|
||||
// closes file mapping
|
||||
~CFileMapping();
|
||||
|
||||
// Retuns the size of the mapped file, or 0 if no file was mapped or the file is empty
|
||||
unsigned getSize()const;
|
||||
|
||||
typedef
|
||||
#ifdef USE_FILE_MAPPING
|
||||
const
|
||||
#endif
|
||||
void * PData;
|
||||
|
||||
// Returns the pointer to the mapped file start in memory, or NULL if the file
|
||||
// wasn't mapped
|
||||
PData getData() const;
|
||||
|
||||
// Returns the file data at the given offset
|
||||
PData getData(unsigned nOffset) const;
|
||||
|
||||
#ifndef USE_FILE_MAPPING
|
||||
// sets the given (already allocated) buffer to this object
|
||||
// the memory must be allocated with malloc()
|
||||
void attach (PData pData, unsigned nSize);
|
||||
#endif
|
||||
|
||||
// initializes the object, opening the given file
|
||||
// if file open has failed, subsequent getData() and
|
||||
// getSize() will return zeros
|
||||
// Returns true if open was successful
|
||||
bool open (const char* szFileName, unsigned nFlags = 0);
|
||||
|
||||
// closes file mapping
|
||||
void close();
|
||||
|
||||
protected:
|
||||
// the data of the mapped file.
|
||||
PData m_pData;
|
||||
// the mapped file size
|
||||
unsigned m_nSize;
|
||||
|
||||
#ifdef USE_FILE_MAPPING
|
||||
// the mapped file handle
|
||||
HANDLE m_hFile;
|
||||
// the mapped file mapping handle
|
||||
HANDLE m_hMapping;
|
||||
#endif
|
||||
};
|
||||
|
||||
TYPEDEF_AUTOPTR(CFileMapping)
|
||||
1081
ResourceCompilerPC/GC_CgfConverter.cpp
Normal file
1081
ResourceCompilerPC/GC_CgfConverter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
322
ResourceCompilerPC/GC_CgfConverter.h
Normal file
322
ResourceCompilerPC/GC_CgfConverter.h
Normal file
@@ -0,0 +1,322 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: cgfconvertor.h
|
||||
// Version: v1.00
|
||||
// Created: 5/11/2002 by Timur.
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __GC_cgfconvertor_h__
|
||||
#define __GC_cgfconvertor_h__
|
||||
#pragma once
|
||||
|
||||
#include "IRCLog.h"
|
||||
#include "IConvertor.h"
|
||||
#include "CryCompiledFile.h"
|
||||
#include "CryChunkedFile.h"
|
||||
#include "RenderMeshBuilder.h"
|
||||
|
||||
struct ConvertContext;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// This is utility that can be used to easily write CCF format files
|
||||
// just open the file, create this object on stack and add the chunk with
|
||||
// AddChunk(nType)
|
||||
// Then write the chunk directly to the file, and then add new chunk,
|
||||
// repeat the process..
|
||||
// Destroy (or call CloseChunk()) this object before you close the file.
|
||||
// To have nested chunks, create another instance of CCFWriter and use it for some time.
|
||||
// When you destruct it, you can use the upper-level writer. And so on.
|
||||
class GC_CCFFileWriter
|
||||
{
|
||||
public:
|
||||
GC_CCFFileWriter (FILE* f):
|
||||
m_pFile (f), m_nLastChunk (-1)
|
||||
{
|
||||
}
|
||||
|
||||
GC_CCFFileWriter ():
|
||||
m_pFile(NULL), m_nLastChunk(-1)
|
||||
{
|
||||
}
|
||||
|
||||
~GC_CCFFileWriter()
|
||||
{
|
||||
CloseChunk();
|
||||
}
|
||||
|
||||
// changes the file handle
|
||||
void SetFile (FILE* f)
|
||||
{
|
||||
CloseChunk();
|
||||
m_pFile = f;
|
||||
}
|
||||
|
||||
// adds a new chunk of the specified type
|
||||
// returns 1 if successfully wrote the chunk header or 0 if an error occurred
|
||||
int AddChunk(CCFChunkTypeEnum nType)
|
||||
{
|
||||
// first, end the previous chunk
|
||||
CloseChunk();
|
||||
// remember the current position
|
||||
m_nLastChunk = ftell (m_pFile);
|
||||
|
||||
// write the chunk header
|
||||
CCFChunkHeader header;
|
||||
header.nSize = 0x58585858;
|
||||
header.nType = SWAP32(nType); //0x204f5649;
|
||||
return fwrite (&header, sizeof(header), 1, m_pFile);
|
||||
}
|
||||
|
||||
// Signals the end of the chunk that was added with AddChunk
|
||||
// Automatically aligns the chunk data by 4-byte boundary, if needed
|
||||
void CloseChunk()
|
||||
{
|
||||
if (m_nLastChunk < 0)
|
||||
return; // no last chunk, or the last chunk was closed
|
||||
|
||||
long nNewChunkPos = ftell (m_pFile);
|
||||
if (nNewChunkPos&3)
|
||||
{
|
||||
// align by 4-byte boundary
|
||||
int nPad = 0;
|
||||
fwrite (&nPad, 1, 4-(nNewChunkPos&3), m_pFile);
|
||||
nNewChunkPos = ftell (m_pFile);
|
||||
}
|
||||
|
||||
// write the size of the chunk to the chunk header
|
||||
fseek (m_pFile, (int)(&((CCFChunkHeader*)m_nLastChunk)->nSize), SEEK_SET);
|
||||
unsigned nSize = SWAP32(nNewChunkPos - m_nLastChunk);
|
||||
fwrite (&nSize, sizeof(nSize), 1, m_pFile);
|
||||
// set the file pointer back where it was
|
||||
fseek (m_pFile, nNewChunkPos, SEEK_SET);
|
||||
|
||||
// forget about the last chunk
|
||||
m_nLastChunk = -1;
|
||||
}
|
||||
|
||||
protected:
|
||||
// the file to which the chunks are written
|
||||
FILE* m_pFile;
|
||||
// the last chunk position within the file (used to update the chunk)
|
||||
long m_nLastChunk;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Convertor implementation for CGF files.
|
||||
*/
|
||||
class GC_CGFConvertor : public IConvertor
|
||||
{
|
||||
public:
|
||||
// this class will be thrown from the internal method during conversion
|
||||
// indicating some error that should abort conversion
|
||||
class Error
|
||||
{
|
||||
public:
|
||||
Error (int nCode);
|
||||
Error (const char* szFormat, ...);
|
||||
const char* c_str()const {return m_strReason.c_str();}
|
||||
protected:
|
||||
string m_strReason;
|
||||
};
|
||||
|
||||
GC_CGFConvertor ():
|
||||
m_fTarget(NULL),
|
||||
m_pStatCGFCompiler(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~GC_CGFConvertor()
|
||||
{
|
||||
clear();
|
||||
if (m_pStatCGFCompiler)
|
||||
m_pStatCGFCompiler->Release();
|
||||
}
|
||||
|
||||
//! Release memory of interface.
|
||||
void Release() { delete this; };
|
||||
|
||||
//! Process file.
|
||||
virtual bool Process( ConvertContext &cc );
|
||||
|
||||
//! Return name of output file that will be produced from this file.
|
||||
// @param sourceFileName File name plus extension of source file, must not contain path.
|
||||
virtual bool GetOutputFile( ConvertContext &cc );
|
||||
|
||||
//! Return platforms supported by this convertor.
|
||||
virtual int GetNumPlatforms() const;
|
||||
//! Get supported platform.
|
||||
//! @param index Index of platform must be in range 0 < index < GetNumPlatforms().
|
||||
virtual Platform GetPlatform( int index ) const;
|
||||
|
||||
//! Get number of supported extensions.
|
||||
virtual int GetNumExt() const { return 1; };
|
||||
//! Get supported extension.
|
||||
//! @param index Index of extension must be in range 0 < index < GetNumExt().
|
||||
virtual const char* GetExt( int index ) const { return "cgf"; };
|
||||
|
||||
// this should retrieve the timestamp of the convertor executable:
|
||||
// when it was created by the linker, normally. This date/time is used to
|
||||
// compare with the compiled file date/time and even if the compiled file
|
||||
// is not older than the source file, it will be recompiled if it's older than the
|
||||
// convertor
|
||||
virtual DWORD GetTimestamp() const ;
|
||||
protected:
|
||||
// internally used stuff
|
||||
// writes the data directly into the file
|
||||
void writeRaw (const void* pData, unsigned nSize);
|
||||
|
||||
template <class T>
|
||||
void write (const T& rData)
|
||||
{
|
||||
writeRaw (&rData, sizeof(T));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void write (const T* pData, unsigned numElements)
|
||||
{
|
||||
writeRaw (pData, numElements * sizeof(T));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void writeArray (const std::vector<T>& arrData)
|
||||
{
|
||||
if (!arrData.empty()){
|
||||
unsigned long a0=arrData.size();
|
||||
write (&arrData[0], arrData.size());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//void LogV (const char* szFormat, va_list args);
|
||||
//void Log (const char* szFormat, ...);
|
||||
|
||||
void WriteGeometryInfo (unsigned nLOD);
|
||||
void WriteHeader();
|
||||
void WriteBoneInfo();
|
||||
void WriteMaterials();
|
||||
void writeIntFaces(unsigned nLOD);
|
||||
void WriteVertices (CryChunkedFile* pSource);
|
||||
void WriteNormals (CryChunkedFile* pSource);
|
||||
|
||||
void writeShadowConnectivity (unsigned nLOD);
|
||||
void writeVertexSkin (unsigned nLOD);
|
||||
void writeNormalSkin (unsigned nLOD);
|
||||
void writeTangSkin (unsigned nLOD);
|
||||
|
||||
void WriteBoneGeometry (unsigned nLOD);
|
||||
|
||||
void writeBGBone(unsigned nLOD, unsigned nBone, CryChunkedFile::MeshDesc* pMesh);
|
||||
void WriteMorphTargetSet ();
|
||||
void writeMorphTargets (unsigned nLOD);
|
||||
void WriteLights();
|
||||
bool isAnimationFastCheck();
|
||||
protected:
|
||||
// loads the m_arrLODs
|
||||
bool LoadLODs();
|
||||
IConvertor* getStatCGFCompiler();
|
||||
|
||||
// builds the m_arrRenderMeshes array with the CRenderMeshBuilder
|
||||
// structures containing all the additional info required for leaf buffer creation
|
||||
void BuildRenderMeshes();
|
||||
|
||||
// Updates physics if needed (if there is LOD1, which contains physical data for LOD1 physics
|
||||
void UpdateDeadBodyPhysics();
|
||||
|
||||
|
||||
// remaps, if necessary, the bones from the LOD source to the Master source
|
||||
// and changes the links in the LOD source so that the boneid's there point to the indices (not IDs!)
|
||||
// of the bones in the Master Source, not LOD Source
|
||||
// This assumes that the bone information from the LOD source won't be used at all
|
||||
// throws an error if there's some unrecognized bone in the LOD source
|
||||
void RemapBones (unsigned nLOD);
|
||||
|
||||
// remaps the bone indices, throws error if some indices cannot be remapped for some reason
|
||||
// (e.g. mapping contains -1, i.e. no mapping)
|
||||
void RemapBoneIndices (CryChunkedFile* pLOD, const std::vector<int>& arrMap);
|
||||
|
||||
// releases all the resources
|
||||
void clear();
|
||||
|
||||
// calculates the number of materials used by the previous LODs (< than given)
|
||||
// this is to offset the mtl numbers of the nLOD to use the range of materials
|
||||
// belonging to that LOD
|
||||
unsigned getLODMtlOffset (unsigned nLOD);
|
||||
|
||||
void LogWarning (const char* szFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, szFormat);
|
||||
m_pContext->pLog->LogV (IMiniLog::eWarning, szFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void LogError (const char* szFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, szFormat);
|
||||
m_pContext->pLog->LogV (IMiniLog::eError, szFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Log (const char* szFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, szFormat);
|
||||
m_pContext->pLog->LogV (IMiniLog::eMessage, szFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
protected:
|
||||
ConvertContext* m_pContext;
|
||||
|
||||
// the source files: one file for each LOD. At least LOD 0 Must be present for conversion.
|
||||
CryChunkedFile_AutoArray m_arrLODs;
|
||||
|
||||
// the mapping from bone indices in Master (LOD0) to bone indices in LOD>0
|
||||
typedef std::vector<int> BoneMap;
|
||||
std::vector<BoneMap> m_arrLODBoneMaps;
|
||||
|
||||
// the render meshes for each LOD
|
||||
std::vector<CRenderMeshBuilder> m_arrRenderMeshes;
|
||||
|
||||
GC_CCFFileWriter m_Writer;
|
||||
|
||||
// the target file
|
||||
FILE* m_fTarget;
|
||||
|
||||
|
||||
IConvertor* m_pStatCGFCompiler;
|
||||
};
|
||||
|
||||
|
||||
#endif // __cgfconvertor_h__
|
||||
5
ResourceCompilerPC/MSSCCPRJ.SCC
Normal file
5
ResourceCompilerPC/MSSCCPRJ.SCC
Normal file
@@ -0,0 +1,5 @@
|
||||
SCC = This is a source code control file
|
||||
|
||||
[ResourceCompilerPC.vcproj]
|
||||
SCC_Aux_Path = "P4SCC#perforce:1666##marcoc_code##PC018"
|
||||
SCC_Project_Name = Perforce Project
|
||||
284
ResourceCompilerPC/MathUtils.h
Normal file
284
ResourceCompilerPC/MathUtils.h
Normal file
@@ -0,0 +1,284 @@
|
||||
#ifndef _CRY_ANIMATION_MATH_UTILS_HDR_
|
||||
#define _CRY_ANIMATION_MATH_UTILS_HDR_
|
||||
|
||||
#include "IBindable.h"
|
||||
#include "Cry_Geo.h"
|
||||
|
||||
// aligned on 16-byte boundary vector
|
||||
class Vec3dA16
|
||||
{
|
||||
public:
|
||||
Vec3 v;
|
||||
unsigned m_Pad;
|
||||
|
||||
Vec3dA16 () {}
|
||||
Vec3dA16 (float x, float y, float z):
|
||||
v(x,y,z)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
// for the given forward vector and position, builds up the right vector and up vector
|
||||
// and builds the corresponding matrix
|
||||
// Builds the right and up vector, given the forward vector, and initializes the matOut
|
||||
void BuildMatrixFromFwd (const Vec3& ptNormal, const Vec3& ptPosition, Matrix44& matOut);
|
||||
|
||||
// for the given forward vector and position, builds up the right vector and up vector
|
||||
// and builds the corresponding matrix
|
||||
// Builds the right and up vector, given the forward vector, and initializes the matOut
|
||||
void BuildMatrixFromFwdZRot (const Vec3& ptNormal, const Vec3& ptPosition, float fZRotate, Matrix44& matOut);
|
||||
|
||||
inline bool IsOrthoUniform (const Matrix44& b, float fTolerance = 0.01f)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (fabs(b.GetRow(i).GetLengthSquared()-1) > fTolerance)
|
||||
return false;
|
||||
if (fabs(b.GetColumn(i).GetLengthSquared()-1) > fTolerance)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void OrthoNormalize(Matrix44& m)
|
||||
{
|
||||
m.NoScale();
|
||||
}
|
||||
|
||||
// given the bone matrix, returns its inverted.
|
||||
// the bone matrices are orthounitary
|
||||
inline Matrix44 OrthoUniformGetInverted (const Matrix44& b)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
assert (fabs(b.GetRow(i).len2()-1) < 1e-2);
|
||||
assert (fabs(b.GetColumn(i).len2()-1) < 1e-2);
|
||||
}
|
||||
#endif
|
||||
return GetInverted44(b);
|
||||
Matrix44 m;
|
||||
m(0,0) = b(0,0); m(0,1) = b(1,0); m(0,2)= b(2,0); m(0,3) = 0;
|
||||
m(1,0) = b(0,1); m(1,1) = b(1,1); m(1,2)= b(2,1); m(1,3) = 0;
|
||||
m(2,0) = b(0,2); m(2,1) = b(1,2); m(2,2)= b(2,2); m(2,3) = 0;
|
||||
m.SetTranslationOLD(b.TransformVectorOLD(b.GetTranslationOLD())); m(3,3) = 1;
|
||||
|
||||
#ifdef _DEBUG
|
||||
Matrix44 e = b * m;
|
||||
assert (e.GetTranslationOLD().GetLengthSquared() < 0.01f);
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
|
||||
// rotates the matrix by the "Angles" used by the FarCry game
|
||||
void Rotate (Matrix44& matInOut, const Vec3& vAngles);
|
||||
|
||||
// rotates the matrix by the "Angles" used by the FarCry game,
|
||||
// but in inverse order and in opposite direction (effectively constructing the inverse matrix)
|
||||
void RotateInv (Matrix44& matInOut, const Vec3& vAngles);
|
||||
|
||||
// Smoothes linear blending into cubic (b-spline) with 0-derivatives
|
||||
// near 0 and 1
|
||||
extern float SmoothBlendValue (float fBlend);
|
||||
|
||||
template <typename T>
|
||||
T min2 (T a, T b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
template <typename T>
|
||||
T max2 (T a, T b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T max3(T val1, T val2, T val3)
|
||||
{
|
||||
return max2(max2(val1,val2),val3);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T min3(T val1, T val2, T val3)
|
||||
{
|
||||
return min2(min2(val1,val2),val3);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T min4 (T a, T b, T c, T d)
|
||||
{
|
||||
return min2(min2(a,b),min2(c,d));
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "QuaternionExponentX87.h"
|
||||
|
||||
// checks whether the quaternions are almost equal
|
||||
inline bool isEqual (const CryQuat& q, const CryQuat& p)
|
||||
{
|
||||
const float fEpsilon = 0.05f;
|
||||
if (fabs(q.w-p.w) > fEpsilon)
|
||||
return false;
|
||||
if (fabs(q.v.x-p.v.x) > fEpsilon)
|
||||
return false;
|
||||
if (fabs(q.v.y-p.v.y) > fEpsilon)
|
||||
return false;
|
||||
if (fabs(q.v.z-p.v.z) > fEpsilon)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
__inline void quaternionExponentOptimized(const Vec3& rSrcVector, CryQuat& rDstQuat)
|
||||
{
|
||||
#if DO_ASM && defined (_CPU_X86)
|
||||
float fResultWXYZ[4];
|
||||
quaternionExponent_x87 (&rSrcVector.x, fResultWXYZ);
|
||||
rDstQuat.w = fResultWXYZ[0];
|
||||
rDstQuat.v.x = fResultWXYZ[1];
|
||||
rDstQuat.v.y = fResultWXYZ[2];
|
||||
rDstQuat.v.z = fResultWXYZ[3];
|
||||
|
||||
assert (isEqual(rDstQuat,exp(quaternionf(0,rSrcVector))));
|
||||
#else
|
||||
CryQuat tmp;
|
||||
tmp.v = rSrcVector;
|
||||
tmp.w = 0;
|
||||
rDstQuat = exp(tmp);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct CryAABB
|
||||
{
|
||||
|
||||
Vec3 vMin;
|
||||
Vec3 vMax;
|
||||
|
||||
CryAABB() {}
|
||||
|
||||
/* CryAABB(struct IBindable* pObj) {
|
||||
pObj->GetBBox(vMin, vMax);
|
||||
}*/
|
||||
|
||||
CryAABB(const Vec3& a, const Vec3& b) {
|
||||
vMin = a;
|
||||
vMax = b;
|
||||
}
|
||||
|
||||
CryAABB(const CryAABB& right) {
|
||||
vMin = right.vMin;
|
||||
vMax = right.vMax;
|
||||
}
|
||||
|
||||
Vec3 getSize() const {return vMax-vMin;}
|
||||
Vec3 getCenter() const {return (vMin+vMax)*0.5f;}
|
||||
|
||||
bool empty() const {return vMin.x >= vMax.x || vMin.y >= vMax.y || vMin.z >= vMax.z;}
|
||||
|
||||
void include(const Vec3& v) { AddToBounds(v, vMin, vMax);}
|
||||
void include (const CryAABB& right) {
|
||||
include (right.vMin);
|
||||
include (right.vMax);
|
||||
}
|
||||
|
||||
|
||||
// static Vec3& toVec3d(Vec3&v) { return v; }
|
||||
// static const Vec3& toVec3d(const Vec3&v) {return v;}
|
||||
|
||||
// static Vec3& toVec3d(Vec3dA16&v){return v.v;}
|
||||
// static const Vec3& toVec3d(const Vec3dA16&v){return v.v;}
|
||||
// CryAABB& operator = (const Vec3& v) {vMin=vMax = v; return *this;}
|
||||
/*
|
||||
CryAABB(const Vec3& a) {
|
||||
toVec3d(vMin) = a;
|
||||
toVec3d(vMax) = a;
|
||||
}*/
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename TVec>
|
||||
class CryBBox_tpl
|
||||
{
|
||||
public:
|
||||
CryBBox_tpl(){}
|
||||
CryBBox_tpl(const Vec3& a)
|
||||
{
|
||||
toVec3d(vMin) = a;
|
||||
toVec3d(vMax) = a;
|
||||
}
|
||||
CryBBox_tpl(struct IBindable* pObj)
|
||||
{
|
||||
pObj->GetBBox(toVec3d(vMin), toVec3d(vMax));
|
||||
}
|
||||
CryBBox_tpl(const Vec3& a, const Vec3& b)
|
||||
{
|
||||
toVec3d(vMin) = a;
|
||||
toVec3d(vMax) = b;
|
||||
}
|
||||
template <typename T2>
|
||||
CryBBox_tpl(const CryBBox_tpl<T2>& right)
|
||||
{
|
||||
toVec3d(vMin) = toVec3d(right.vMin);
|
||||
toVec3d(vMax) = toVec3d(right.vMax);
|
||||
}
|
||||
|
||||
TVec vMin;
|
||||
TVec vMax;
|
||||
|
||||
bool empty()const {return vMin.x >= vMax.x || vMin.y >= vMax.y || vMin.z >= vMax.z;}
|
||||
|
||||
static Vec3& toVec3d(Vec3&v){return v;}
|
||||
static const Vec3& toVec3d(const Vec3&v){return v;}
|
||||
static Vec3& toVec3d(Vec3dA16&v){return v.v;}
|
||||
static const Vec3& toVec3d(const Vec3dA16&v){return v.v;}
|
||||
|
||||
Vec3 getSize() const {return toVec3d(vMax)-toVec3d(vMin);}
|
||||
Vec3 getCenter() const {return (toVec3d(vMin)+toVec3d(vMax))*0.5f;}
|
||||
CryBBox_tpl<TVec>& operator = (const Vec3& v) {toVec3d(vMin) = toVec3d(vMax) = v; return *this;}
|
||||
void include(const Vec3& v) { AddToBounds(v, toVec3d(vMin), toVec3d(vMax));}
|
||||
template <typename T3>
|
||||
void include (const CryBBox_tpl<T3>&right)
|
||||
{
|
||||
include (toVec3d(right.vMin));
|
||||
include (toVec3d(right.vMax));
|
||||
}
|
||||
};
|
||||
|
||||
//typedef CryBBox_tpl<Vec3> CryBBox;
|
||||
typedef CryBBox_tpl<Vec3dA16> CryBBoxA16;
|
||||
|
||||
|
||||
//extern Vec3 UntransformVector (const Matrix& m, const Vec3& v);
|
||||
inline bool isUnit (const Vec3& v, float fTolerance)
|
||||
{
|
||||
float fLen = v.GetLengthSquared();
|
||||
return fLen >= 1-fTolerance && fLen < 1+fTolerance;
|
||||
}
|
||||
|
||||
inline bool isSane(float x)
|
||||
{
|
||||
return x > -1e9 && x < 1e9;
|
||||
}
|
||||
|
||||
inline bool isSane (const Vec3& v)
|
||||
{
|
||||
return isSane(v.x) && isSane(v.y) && isSane(v.z);
|
||||
}
|
||||
|
||||
inline bool isUnit (const TangData& td, float fTolerance)
|
||||
{
|
||||
return isUnit(td.binormal, fTolerance) && isUnit(td.tangent, fTolerance) && isUnit(td.tnormal, fTolerance);
|
||||
}
|
||||
|
||||
#endif
|
||||
311
ResourceCompilerPC/NvTriStrip/NvTriStrip.cpp
Normal file
311
ResourceCompilerPC/NvTriStrip/NvTriStrip.cpp
Normal file
@@ -0,0 +1,311 @@
|
||||
#ifdef WIN64
|
||||
#include "WinDef.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "NvTriStripObjects.h"
|
||||
#include "NvTriStrip.h"
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4018) // signed/unsigned mismatch
|
||||
#ifdef WIN64 //AMD Port
|
||||
#pragma warning( disable : 4267 ) // conversion from 'size_t' to 'xxx', possible loss of data
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
//private data
|
||||
static unsigned int cacheSize = CACHESIZE_GEFORCE3;// CACHESIZE_GEFORCE1_2;
|
||||
static bool bStitchStrips = true;
|
||||
static unsigned int minStripSize = 0;
|
||||
static bool bListsOnly = false;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetListsOnly()
|
||||
//
|
||||
// If set to true, will return an optimized list, with no strips at all.
|
||||
//
|
||||
// Default value: false
|
||||
//
|
||||
void SetListsOnly(const bool _bListsOnly)
|
||||
{
|
||||
bListsOnly = _bListsOnly;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetCacheSize()
|
||||
//
|
||||
// Sets the cache size which the stripfier uses to optimize the data.
|
||||
// Controls the length of the generated individual strips.
|
||||
// This is the "actual" cache size, so 24 for GeForce3 and 16 for GeForce1/2
|
||||
// You may want to play around with this number to tweak performance.
|
||||
//
|
||||
// Default value: 16
|
||||
//
|
||||
void SetCacheSize(const unsigned int _cacheSize)
|
||||
{
|
||||
cacheSize = _cacheSize;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetStitchStrips()
|
||||
//
|
||||
// bool to indicate whether to stitch together strips into one huge strip or not.
|
||||
// If set to true, you'll get back one huge strip stitched together using degenerate
|
||||
// triangles.
|
||||
// If set to false, you'll get back a large number of separate strips.
|
||||
//
|
||||
// Default value: true
|
||||
//
|
||||
void SetStitchStrips(const bool _bStitchStrips)
|
||||
{
|
||||
bStitchStrips = _bStitchStrips;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetMinStripSize()
|
||||
//
|
||||
// Sets the minimum acceptable size for a strip, in triangles.
|
||||
// All strips generated which are shorter than this will be thrown into one big, separate list.
|
||||
//
|
||||
// Default value: 0
|
||||
//
|
||||
void SetMinStripSize(const unsigned int _minStripSize)
|
||||
{
|
||||
minStripSize = _minStripSize;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GenerateStrips()
|
||||
//
|
||||
// in_indices: input index list, the indices you would use to render
|
||||
// in_numIndices: number of entries in in_indices
|
||||
// primGroups: array of optimized/stripified PrimitiveGroups
|
||||
// numGroups: number of groups returned
|
||||
//
|
||||
// Be sure to call delete[] on the returned primGroups to avoid leaking mem
|
||||
//
|
||||
void GenerateStrips(const unsigned short* in_indices, const unsigned int in_numIndices,
|
||||
PrimitiveGroup** primGroups, unsigned short* numGroups)
|
||||
{
|
||||
//put data in format that the stripifier likes
|
||||
int i;
|
||||
WordVec tempIndices;
|
||||
tempIndices.resize(in_numIndices);
|
||||
unsigned short maxIndex = 0;
|
||||
for(i = 0; i < (int)in_numIndices; i++)
|
||||
{
|
||||
tempIndices[i] = in_indices[i];
|
||||
if(in_indices[i] > maxIndex)
|
||||
maxIndex = in_indices[i];
|
||||
}
|
||||
NvStripInfoVec tempStrips;
|
||||
NvFaceInfoVec tempFaces;
|
||||
|
||||
NvStripifier stripifier;
|
||||
|
||||
//do actual stripification
|
||||
stripifier.Stripify(tempIndices, cacheSize, minStripSize, maxIndex, tempStrips, tempFaces);
|
||||
|
||||
//stitch strips together
|
||||
IntVec stripIndices;
|
||||
unsigned int numSeparateStrips = 0;
|
||||
|
||||
if(bListsOnly)
|
||||
{
|
||||
//if we're outputting only lists, we're done
|
||||
*numGroups = 1;
|
||||
(*primGroups) = new PrimitiveGroup[*numGroups];
|
||||
PrimitiveGroup* primGroupArray = *primGroups;
|
||||
|
||||
//count the total number of indices
|
||||
unsigned int numIndices = 0;
|
||||
for(i = 0; i < tempStrips.size(); i++)
|
||||
{
|
||||
numIndices += tempStrips[i]->m_faces.size() * 3;
|
||||
}
|
||||
|
||||
//add in the list
|
||||
numIndices += tempFaces.size() * 3;
|
||||
|
||||
primGroupArray[0].type = PT_LIST;
|
||||
primGroupArray[0].numIndices = numIndices;
|
||||
primGroupArray[0].indices = new unsigned short[numIndices];
|
||||
|
||||
//do strips
|
||||
unsigned int indexCtr = 0;
|
||||
for(i = 0; i < tempStrips.size(); i++)
|
||||
{
|
||||
for(int j = 0; j < tempStrips[i]->m_faces.size(); j++)
|
||||
{
|
||||
//degenerates are of no use with lists
|
||||
if(!NvStripifier::IsDegenerate(tempStrips[i]->m_faces[j]))
|
||||
{
|
||||
primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v0;
|
||||
primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v1;
|
||||
primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
//we've removed a tri, reduce the number of indices
|
||||
primGroupArray[0].numIndices -= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//do lists
|
||||
for(i = 0; i < tempFaces.size(); i++)
|
||||
{
|
||||
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v0;
|
||||
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v1;
|
||||
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stripifier.CreateStrips(tempStrips, stripIndices, bStitchStrips, numSeparateStrips);
|
||||
|
||||
//if we're stitching strips together, we better get back only one strip from CreateStrips()
|
||||
assert( (bStitchStrips && (numSeparateStrips == 1)) || !bStitchStrips);
|
||||
|
||||
//convert to output format
|
||||
*numGroups = numSeparateStrips; //for the strips
|
||||
if(tempFaces.size() != 0)
|
||||
(*numGroups)++; //we've got a list as well, increment
|
||||
(*primGroups) = new PrimitiveGroup[*numGroups];
|
||||
|
||||
PrimitiveGroup* primGroupArray = *primGroups;
|
||||
|
||||
//first, the strips
|
||||
int startingLoc = 0;
|
||||
for(int stripCtr = 0; stripCtr < numSeparateStrips; stripCtr++)
|
||||
{
|
||||
int stripLength = 0;
|
||||
|
||||
if(!bStitchStrips)
|
||||
{
|
||||
//if we've got multiple strips, we need to figure out the correct length
|
||||
for(i = startingLoc; i < stripIndices.size(); i++)
|
||||
{
|
||||
if(stripIndices[i] == -1)
|
||||
break;
|
||||
}
|
||||
|
||||
stripLength = i - startingLoc;
|
||||
}
|
||||
else
|
||||
stripLength = stripIndices.size();
|
||||
|
||||
primGroupArray[stripCtr].type = PT_STRIP;
|
||||
primGroupArray[stripCtr].indices = new unsigned short[stripLength];
|
||||
primGroupArray[stripCtr].numIndices = stripLength;
|
||||
|
||||
int indexCtr = 0;
|
||||
for(int i = startingLoc; i < stripLength + startingLoc; i++)
|
||||
primGroupArray[stripCtr].indices[indexCtr++] = stripIndices[i];
|
||||
|
||||
//we add 1 to account for the -1 separating strips
|
||||
//this doesn't break the stitched case since we'll exit the loop
|
||||
startingLoc += stripLength + 1;
|
||||
}
|
||||
|
||||
//next, the list
|
||||
if(tempFaces.size() != 0)
|
||||
{
|
||||
int faceGroupLoc = (*numGroups) - 1; //the face group is the last one
|
||||
primGroupArray[faceGroupLoc].type = PT_LIST;
|
||||
primGroupArray[faceGroupLoc].indices = new unsigned short[tempFaces.size() * 3];
|
||||
primGroupArray[faceGroupLoc].numIndices = tempFaces.size() * 3;
|
||||
int indexCtr = 0;
|
||||
for(int i = 0; i < tempFaces.size(); i++)
|
||||
{
|
||||
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v0;
|
||||
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v1;
|
||||
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//clean up everything
|
||||
|
||||
//delete strips
|
||||
for(i = 0; i < tempStrips.size(); i++)
|
||||
{
|
||||
for(int j = 0; j < tempStrips[i]->m_faces.size(); j++)
|
||||
{
|
||||
delete tempStrips[i]->m_faces[j];
|
||||
tempStrips[i]->m_faces[j] = NULL;
|
||||
}
|
||||
tempStrips[i]->m_faces.resize(0);
|
||||
delete tempStrips[i];
|
||||
tempStrips[i] = NULL;
|
||||
}
|
||||
|
||||
//delete faces
|
||||
for(i = 0; i < tempFaces.size(); i++)
|
||||
{
|
||||
delete tempFaces[i];
|
||||
tempFaces[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RemapIndices()
|
||||
//
|
||||
// Function to remap your indices to improve spatial locality in your vertex buffer.
|
||||
//
|
||||
// in_primGroups: array of PrimitiveGroups you want remapped
|
||||
// numGroups: number of entries in in_primGroups
|
||||
// numVerts: number of vertices in your vertex buffer, also can be thought of as the range
|
||||
// of acceptable values for indices in your primitive groups.
|
||||
// remappedGroups: array of remapped PrimitiveGroups
|
||||
//
|
||||
// Note that, according to the remapping handed back to you, you must reorder your
|
||||
// vertex buffer.
|
||||
//
|
||||
void RemapIndices(const PrimitiveGroup* in_primGroups, const unsigned short numGroups,
|
||||
const unsigned short numVerts, PrimitiveGroup** remappedGroups)
|
||||
{
|
||||
(*remappedGroups) = new PrimitiveGroup[numGroups];
|
||||
|
||||
//caches oldIndex --> newIndex conversion
|
||||
int *indexCache;
|
||||
indexCache = new int[numVerts];
|
||||
memset(indexCache, -1, sizeof(int)*numVerts);
|
||||
|
||||
//loop over primitive groups
|
||||
unsigned int indexCtr = 0;
|
||||
for(int i = 0; i < numGroups; i++)
|
||||
{
|
||||
unsigned int numIndices = in_primGroups[i].numIndices;
|
||||
|
||||
//init remapped group
|
||||
(*remappedGroups)[i].type = in_primGroups[i].type;
|
||||
(*remappedGroups)[i].numIndices = numIndices;
|
||||
(*remappedGroups)[i].indices = new unsigned short[numIndices];
|
||||
|
||||
for(int j = 0; j < numIndices; j++)
|
||||
{
|
||||
int cachedIndex = indexCache[in_primGroups[i].indices[j]];
|
||||
if(cachedIndex == -1) //we haven't seen this index before
|
||||
{
|
||||
//point to "last" vertex in VB
|
||||
(*remappedGroups)[i].indices[j] = indexCtr;
|
||||
|
||||
//add to index cache, increment
|
||||
indexCache[in_primGroups[i].indices[j]] = indexCtr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//we've seen this index before
|
||||
(*remappedGroups)[i].indices[j] = cachedIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] indexCache;
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
131
ResourceCompilerPC/NvTriStrip/NvTriStrip.h
Normal file
131
ResourceCompilerPC/NvTriStrip/NvTriStrip.h
Normal file
@@ -0,0 +1,131 @@
|
||||
#ifndef NVTRISTRIP_H
|
||||
#define NVTRISTRIP_H
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public interface for stripifier
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//GeForce1 and 2 cache size
|
||||
#define CACHESIZE_GEFORCE1_2 16
|
||||
|
||||
//GeForce3 cache size
|
||||
#define CACHESIZE_GEFORCE3 24
|
||||
|
||||
enum PrimType
|
||||
{
|
||||
PT_LIST,
|
||||
PT_STRIP,
|
||||
PT_FAN
|
||||
};
|
||||
|
||||
struct SPrimitiveGroup
|
||||
{
|
||||
PrimType type;
|
||||
unsigned int numIndices;
|
||||
unsigned int offsIndex;
|
||||
unsigned int numTris;
|
||||
unsigned int nFirstFace;
|
||||
};
|
||||
|
||||
struct PrimitiveGroup
|
||||
{
|
||||
PrimType type;
|
||||
unsigned int numIndices;
|
||||
unsigned short* indices;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrimitiveGroup() : type(PT_STRIP), numIndices(0), indices(NULL) {}
|
||||
~PrimitiveGroup()
|
||||
{
|
||||
if(indices)
|
||||
delete[] indices;
|
||||
indices = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetCacheSize()
|
||||
//
|
||||
// Sets the cache size which the stripfier uses to optimize the data.
|
||||
// Controls the length of the generated individual strips.
|
||||
// This is the "actual" cache size, so 24 for GeForce3 and 16 for GeForce1/2
|
||||
// You may want to play around with this number to tweak performance.
|
||||
//
|
||||
// Default value: 16
|
||||
//
|
||||
void SetCacheSize(const unsigned int cacheSize);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetStitchStrips()
|
||||
//
|
||||
// bool to indicate whether to stitch together strips into one huge strip or not.
|
||||
// If set to true, you'll get back one huge strip stitched together using degenerate
|
||||
// triangles.
|
||||
// If set to false, you'll get back a large number of separate strips.
|
||||
//
|
||||
// Default value: true
|
||||
//
|
||||
void SetStitchStrips(const bool bStitchStrips);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetMinStripSize()
|
||||
//
|
||||
// Sets the minimum acceptable size for a strip, in triangles.
|
||||
// All strips generated which are shorter than this will be thrown into one big, separate list.
|
||||
//
|
||||
// Default value: 0
|
||||
//
|
||||
void SetMinStripSize(const unsigned int minSize);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetListsOnly()
|
||||
//
|
||||
// If set to true, will return an optimized list, with no strips at all.
|
||||
//
|
||||
// Default value: false
|
||||
//
|
||||
void SetListsOnly(const bool bListsOnly);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GenerateStrips()
|
||||
//
|
||||
// in_indices: input index list, the indices you would use to render
|
||||
// in_numIndices: number of entries in in_indices
|
||||
// primGroups: array of optimized/stripified PrimitiveGroups
|
||||
// numGroups: number of groups returned
|
||||
//
|
||||
// Be sure to call delete[] on the returned primGroups to avoid leaking mem
|
||||
//
|
||||
void GenerateStrips(const unsigned short* in_indices, const unsigned int in_numIndices,
|
||||
PrimitiveGroup** primGroups, unsigned short* numGroups);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RemapIndices()
|
||||
//
|
||||
// Function to remap your indices to improve spatial locality in your vertex buffer.
|
||||
//
|
||||
// in_primGroups: array of PrimitiveGroups you want remapped
|
||||
// numGroups: number of entries in in_primGroups
|
||||
// numVerts: number of vertices in your vertex buffer, also can be thought of as the range
|
||||
// of acceptable values for indices in your primitive groups.
|
||||
// remappedGroups: array of remapped PrimitiveGroups
|
||||
//
|
||||
// Note that, according to the remapping handed back to you, you must reorder your
|
||||
// vertex buffer.
|
||||
//
|
||||
// Credit goes to the MS Xbox crew for the idea for this interface.
|
||||
//
|
||||
void RemapIndices(const PrimitiveGroup* in_primGroups, const unsigned short numGroups,
|
||||
const unsigned short numVerts, PrimitiveGroup** remappedGroups);
|
||||
|
||||
#endif
|
||||
1798
ResourceCompilerPC/NvTriStrip/NvTriStripObjects.cpp
Normal file
1798
ResourceCompilerPC/NvTriStrip/NvTriStripObjects.cpp
Normal file
File diff suppressed because it is too large
Load Diff
244
ResourceCompilerPC/NvTriStrip/NvTriStripObjects.h
Normal file
244
ResourceCompilerPC/NvTriStrip/NvTriStripObjects.h
Normal file
@@ -0,0 +1,244 @@
|
||||
|
||||
#ifndef NV_TRISTRIP_OBJECTS_H
|
||||
#define NV_TRISTRIP_OBJECTS_H
|
||||
|
||||
#include <assert.h>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include "VertexCache.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Types defined for stripification
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct MyVertex {
|
||||
float x, y, z;
|
||||
float nx, ny, nz;
|
||||
};
|
||||
|
||||
typedef MyVertex MyVector;
|
||||
|
||||
struct MyFace {
|
||||
int v1, v2, v3;
|
||||
float nx, ny, nz;
|
||||
};
|
||||
|
||||
|
||||
class NvFaceInfo {
|
||||
public:
|
||||
|
||||
// vertex indices
|
||||
NvFaceInfo(int v0, int v1, int v2, bool bIsFake = false){
|
||||
m_v0 = v0; m_v1 = v1; m_v2 = v2;
|
||||
m_stripId = -1;
|
||||
m_testStripId = -1;
|
||||
m_experimentId = -1;
|
||||
m_bIsFake = bIsFake;
|
||||
}
|
||||
|
||||
// data members are left public
|
||||
int m_v0, m_v1, m_v2;
|
||||
int m_stripId; // real strip Id
|
||||
int m_testStripId; // strip Id in an experiment
|
||||
int m_experimentId; // in what experiment was it given an experiment Id?
|
||||
bool m_bIsFake; //if true, will be deleted when the strip it's in is deleted
|
||||
};
|
||||
|
||||
class NvEdgeInfo {
|
||||
public:
|
||||
|
||||
// constructor puts 1 ref on us
|
||||
NvEdgeInfo (int v0, int v1){
|
||||
m_v0 = v0;
|
||||
m_v1 = v1;
|
||||
m_face0 = NULL;
|
||||
m_face1 = NULL;
|
||||
m_nextV0 = NULL;
|
||||
m_nextV1 = NULL;
|
||||
|
||||
// we will appear in 2 lists. this is a good
|
||||
// way to make sure we delete it the second time
|
||||
// we hit it in the edge infos
|
||||
m_refCount = 2;
|
||||
|
||||
}
|
||||
|
||||
// ref and unref
|
||||
void Unref () { if (--m_refCount == 0) delete this; }
|
||||
|
||||
// data members are left public
|
||||
unsigned int m_refCount;
|
||||
NvFaceInfo *m_face0, *m_face1;
|
||||
int m_v0, m_v1;
|
||||
NvEdgeInfo *m_nextV0, *m_nextV1;
|
||||
};
|
||||
|
||||
|
||||
// This class is a quick summary of parameters used
|
||||
// to begin a triangle strip. Some operations may
|
||||
// want to create lists of such items, so they were
|
||||
// pulled out into a class
|
||||
class NvStripStartInfo {
|
||||
public:
|
||||
NvStripStartInfo(NvFaceInfo *startFace, NvEdgeInfo *startEdge, bool toV1){
|
||||
m_startFace = startFace;
|
||||
m_startEdge = startEdge;
|
||||
m_toV1 = toV1;
|
||||
}
|
||||
NvFaceInfo *m_startFace;
|
||||
NvEdgeInfo *m_startEdge;
|
||||
bool m_toV1;
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<NvFaceInfo*> NvFaceInfoVec;
|
||||
typedef std::list <NvFaceInfo*> NvFaceInfoList;
|
||||
typedef std::list <NvFaceInfoVec*> NvStripList;
|
||||
typedef std::vector<NvEdgeInfo*> NvEdgeInfoVec;
|
||||
|
||||
typedef std::vector<unsigned short> WordVec;
|
||||
typedef std::vector<int> IntVec;
|
||||
typedef std::vector<MyVertex> MyVertexVec;
|
||||
typedef std::vector<MyFace> MyFaceVec;
|
||||
|
||||
template<class T>
|
||||
inline void SWAP(T& first, T& second)
|
||||
{
|
||||
T temp = first;
|
||||
first = second;
|
||||
second = temp;
|
||||
}
|
||||
|
||||
// This is a summary of a strip that has been built
|
||||
class NvStripInfo {
|
||||
public:
|
||||
|
||||
// A little information about the creation of the triangle strips
|
||||
NvStripInfo(const NvStripStartInfo &startInfo, int stripId, int experimentId = -1) :
|
||||
m_startInfo(startInfo)
|
||||
{
|
||||
m_stripId = stripId;
|
||||
m_experimentId = experimentId;
|
||||
visited = false;
|
||||
m_numDegenerates = 0;
|
||||
}
|
||||
|
||||
// This is an experiment if the experiment id is >= 0
|
||||
inline bool IsExperiment () const { return m_experimentId >= 0; }
|
||||
|
||||
inline bool IsInStrip (const NvFaceInfo *faceInfo) const
|
||||
{
|
||||
if(faceInfo == NULL)
|
||||
return false;
|
||||
|
||||
return (m_experimentId >= 0 ? faceInfo->m_testStripId == m_stripId : faceInfo->m_stripId == m_stripId);
|
||||
}
|
||||
|
||||
bool SharesEdge(const NvFaceInfo* faceInfo, NvEdgeInfoVec &edgeInfos);
|
||||
|
||||
// take the given forward and backward strips and combine them together
|
||||
void Combine(const NvFaceInfoVec &forward, const NvFaceInfoVec &backward);
|
||||
|
||||
//returns true if the face is "unique", i.e. has a vertex which doesn't exist in the faceVec
|
||||
bool Unique(NvFaceInfoVec& faceVec, NvFaceInfo* face);
|
||||
|
||||
// mark the triangle as taken by this strip
|
||||
bool IsMarked (NvFaceInfo *faceInfo);
|
||||
void MarkTriangle(NvFaceInfo *faceInfo);
|
||||
|
||||
// build the strip
|
||||
void Build(NvEdgeInfoVec &edgeInfos, NvFaceInfoVec &faceInfos);
|
||||
|
||||
// public data members
|
||||
NvStripStartInfo m_startInfo;
|
||||
NvFaceInfoVec m_faces;
|
||||
int m_stripId;
|
||||
int m_experimentId;
|
||||
|
||||
bool visited;
|
||||
|
||||
int m_numDegenerates;
|
||||
};
|
||||
|
||||
typedef std::vector<NvStripInfo*> NvStripInfoVec;
|
||||
|
||||
|
||||
//The actual stripifier
|
||||
class NvStripifier {
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
NvStripifier();
|
||||
~NvStripifier();
|
||||
|
||||
//the target vertex cache size, the structure to place the strips in, and the input indices
|
||||
void Stripify(const WordVec &in_indices, const int in_cacheSize, const int in_minStripLength,
|
||||
const unsigned short maxIndex, NvStripInfoVec &allStrips, NvFaceInfoVec &allFaces);
|
||||
void CreateStrips(const NvStripInfoVec& allStrips, IntVec& stripIndices, const bool bStitchStrips, unsigned int& numSeparateStrips);
|
||||
|
||||
static int GetUniqueVertexInB(NvFaceInfo *faceA, NvFaceInfo *faceB);
|
||||
//static int GetSharedVertex(NvFaceInfo *faceA, NvFaceInfo *faceB);
|
||||
static void GetSharedVertices(NvFaceInfo *faceA, NvFaceInfo *faceB, int* vertex0, int* vertex1);
|
||||
|
||||
static bool IsDegenerate(const NvFaceInfo* face);
|
||||
|
||||
protected:
|
||||
|
||||
WordVec indices;
|
||||
int cacheSize;
|
||||
int minStripLength;
|
||||
float meshJump;
|
||||
bool bFirstTimeResetPoint;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Big mess of functions called during stripification
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//********************
|
||||
bool IsMoneyFace(const NvFaceInfo& face);
|
||||
bool FaceContainsIndex(const NvFaceInfo& face, const unsigned int index);
|
||||
|
||||
bool IsCW(NvFaceInfo *faceInfo, int v0, int v1);
|
||||
bool NextIsCW(const int numIndices);
|
||||
|
||||
bool IsDegenerate(const unsigned short v0, const unsigned short v1, const unsigned short v2);
|
||||
|
||||
static int GetNextIndex(const WordVec &indices, NvFaceInfo *face);
|
||||
static NvEdgeInfo *FindEdgeInfo(NvEdgeInfoVec &edgeInfos, int v0, int v1);
|
||||
static NvFaceInfo *FindOtherFace(NvEdgeInfoVec &edgeInfos, int v0, int v1, NvFaceInfo *faceInfo);
|
||||
NvFaceInfo *FindGoodResetPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
|
||||
|
||||
void FindAllStrips(NvStripInfoVec &allStrips, NvFaceInfoVec &allFaceInfos, NvEdgeInfoVec &allEdgeInfos, int numSamples);
|
||||
void SplitUpStripsAndOptimize(NvStripInfoVec &allStrips, NvStripInfoVec &outStrips, NvEdgeInfoVec& edgeInfos, NvFaceInfoVec& outFaceList);
|
||||
void RemoveSmallStrips(NvStripInfoVec& allStrips, NvStripInfoVec& allBigStrips, NvFaceInfoVec& faceList);
|
||||
|
||||
bool FindTraversal(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, NvStripInfo *strip, NvStripStartInfo &startInfo);
|
||||
int CountRemainingTris(std::list<NvStripInfo*>::iterator iter, std::list<NvStripInfo*>::iterator end);
|
||||
|
||||
void CommitStrips(NvStripInfoVec &allStrips, const NvStripInfoVec &strips);
|
||||
|
||||
float AvgStripSize(const NvStripInfoVec &strips);
|
||||
int FindStartPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
|
||||
|
||||
void UpdateCacheStrip(VertexCache* vcache, NvStripInfo* strip);
|
||||
void UpdateCacheFace(VertexCache* vcache, NvFaceInfo* face);
|
||||
float CalcNumHitsStrip(VertexCache* vcache, NvStripInfo* strip);
|
||||
int CalcNumHitsFace(VertexCache* vcache, NvFaceInfo* face);
|
||||
int NumNeighbors(NvFaceInfo* face, NvEdgeInfoVec& edgeInfoVec);
|
||||
|
||||
void BuildStripifyInfo(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, const unsigned short maxIndex);
|
||||
bool AlreadyExists(NvFaceInfo* faceInfo, NvFaceInfoVec& faceInfos);
|
||||
|
||||
// let our strip info classes and the other classes get
|
||||
// to these protected stripificaton methods if they want
|
||||
friend class NvStripInfo;
|
||||
};
|
||||
|
||||
#endif
|
||||
0
ResourceCompilerPC/NvTriStrip/RenderPCH.h
Normal file
0
ResourceCompilerPC/NvTriStrip/RenderPCH.h
Normal file
79
ResourceCompilerPC/NvTriStrip/VertexCache.h
Normal file
79
ResourceCompilerPC/NvTriStrip/VertexCache.h
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
#ifndef VERTEX_CACHE_H
|
||||
|
||||
#define VERTEX_CACHE_H
|
||||
|
||||
class VertexCache
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
VertexCache(int size)
|
||||
{
|
||||
numEntries = size;
|
||||
|
||||
entries = new int[numEntries];
|
||||
|
||||
for(int i = 0; i < numEntries; i++)
|
||||
entries[i] = -1;
|
||||
}
|
||||
|
||||
VertexCache() { VertexCache(16); }
|
||||
~VertexCache() { delete[] entries; entries = 0; }
|
||||
|
||||
bool InCache(int entry)
|
||||
{
|
||||
bool returnVal = false;
|
||||
for(int i = 0; i < numEntries; i++)
|
||||
{
|
||||
if(entries[i] == entry)
|
||||
{
|
||||
returnVal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
int AddEntry(int entry)
|
||||
{
|
||||
int removed;
|
||||
|
||||
removed = entries[numEntries - 1];
|
||||
|
||||
//push everything right one
|
||||
for(int i = numEntries - 2; i >= 0; i--)
|
||||
{
|
||||
entries[i + 1] = entries[i];
|
||||
}
|
||||
|
||||
entries[0] = entry;
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
memset(entries, -1, sizeof(int) * numEntries);
|
||||
}
|
||||
|
||||
void Copy(VertexCache* inVcache)
|
||||
{
|
||||
for(int i = 0; i < numEntries; i++)
|
||||
{
|
||||
inVcache->Set(i, entries[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int At(int index) { return entries[index]; }
|
||||
void Set(int index, int value) { entries[index] = value; }
|
||||
|
||||
private:
|
||||
|
||||
int *entries;
|
||||
int numEntries;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
44
ResourceCompilerPC/QuaternionExponentX87.h
Normal file
44
ResourceCompilerPC/QuaternionExponentX87.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef _CRY_ANIMATION_QUATERNION_EXPONENT_HDR_
|
||||
#define _CRY_ANIMATION_QUATERNION_EXPONENT_HDR_
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(_CPU_X86) && !defined(LINUX)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// x87 asm optimized quaternion exponent
|
||||
// Estimated runtime in good conditions: 315 cycles on P4
|
||||
// PARAMETERS:
|
||||
// pSrcVector[IN] - the vector to calculate the exponent for
|
||||
// pDstQuat [OUT]- the quaternion (exponent of the input)
|
||||
// NOTE:
|
||||
// The input vector mimics a quaternion with 0 real component (W)
|
||||
// This version uses FSINCOS, which takes ~70% of execution time
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void quaternionExponent_x87(const float* pSrc, float* pDst);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// x87 asm optimized quaternion exponent
|
||||
// Estimated runtime: 110 cycles on P4
|
||||
// PARAMETERS:
|
||||
// pSrcVector[IN] - the vector to calculate the exponent for
|
||||
// pDstQuat [OUT]- the quaternion (exponent of the input)
|
||||
// WARNING:
|
||||
// the source vector length should be no more than 3-4, otherwise the sin/cos
|
||||
// approximations won't work
|
||||
// NOTE:
|
||||
// The input vector mimics a quaternion with 0 real component (W)
|
||||
// This version uses approximation to FSINCOS (tailor series up to 9th magnitude)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void quaternionExponent_x87approx(const float* pSrc, float* pDst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
37
ResourceCompilerPC/ReadMe.txt
Normal file
37
ResourceCompilerPC/ReadMe.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
========================================================================
|
||||
DYNAMIC LINK LIBRARY : ResourceCompilerPC Project Overview
|
||||
========================================================================
|
||||
|
||||
AppWizard has created this ResourceCompilerPC DLL for you.
|
||||
This file contains a summary of what you will find in each of the files that
|
||||
make up your ResourceCompilerPC application.
|
||||
|
||||
|
||||
ResourceCompilerPC.vcproj
|
||||
This is the main project file for VC++ projects generated using an Application Wizard.
|
||||
It contains information about the version of Visual C++ that generated the file, and
|
||||
information about the platforms, configurations, and project features selected with the
|
||||
Application Wizard.
|
||||
|
||||
ResourceCompilerPC.cpp
|
||||
This is the main DLL source file.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other standard files:
|
||||
|
||||
StdAfx.h, StdAfx.cpp
|
||||
These files are used to build a precompiled header (PCH) file
|
||||
named ResourceCompilerPC.pch and a precompiled types file named StdAfx.obj.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other notes:
|
||||
|
||||
This is a resource compiler DLL, which contains the Convertors for PC platform.
|
||||
All the shared code (like CGF loading/processing, that is the same for all platforms)
|
||||
must reside in the resource compiler exe. All platform-specific code must be here.
|
||||
|
||||
|
||||
AppWizard uses "TODO:" comments to indicate parts of the source code you
|
||||
should add to or customize.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
459
ResourceCompilerPC/RenderMeshBuilder.cpp
Normal file
459
ResourceCompilerPC/RenderMeshBuilder.cpp
Normal file
@@ -0,0 +1,459 @@
|
||||
#include "stdafx.h"
|
||||
#include "RenderMeshBuilder.h"
|
||||
#include "StlUtils.h"
|
||||
#include "NvTriStrip/NvTriStrip.h"
|
||||
|
||||
// constructs everything for the render mesh out of the given mesh
|
||||
void CRenderMeshBuilder::build (const CryChunkedFile::MeshDesc* pMeshDesc)
|
||||
{
|
||||
clear();
|
||||
m_pMeshDesc = pMeshDesc;
|
||||
// build the tangent bases
|
||||
MeshProxy Proxy;
|
||||
Proxy.init(pMeshDesc);
|
||||
m_TangBaseBuilder.CalculateTangentSpace (Proxy);
|
||||
|
||||
buildExtToIntMaps();
|
||||
|
||||
// create the m_arrMtlFaces: the faces are sorted and perhaps
|
||||
// degraded faces are deleted
|
||||
buildMtlFaces();
|
||||
|
||||
// create the indices and the array m_arrMaterials
|
||||
buildIndexBuffer();
|
||||
|
||||
// optimize the final vertex buffer spacial locality
|
||||
remapIndicesForVBCache();
|
||||
|
||||
//selfValidate();
|
||||
}
|
||||
|
||||
// increases all indices of materials by the given offset
|
||||
void CRenderMeshBuilder::addMaterialOffset (unsigned nOffset)
|
||||
{
|
||||
for (MaterialGroupArray::iterator it = m_arrPrimGroups.begin(); it != m_arrPrimGroups.end(); ++it)
|
||||
it->nMaterial += nOffset;
|
||||
}
|
||||
|
||||
// cleans up the object
|
||||
void CRenderMeshBuilder::clear()
|
||||
{
|
||||
m_arrIndices.clear();
|
||||
m_arrPrimGroups.clear();
|
||||
m_arrExtTangMap.clear();
|
||||
m_arrExtUVMap.clear();
|
||||
m_arrExtTangents.clear();
|
||||
m_arrMtlFaces.clear();
|
||||
m_arrExtFaces.clear();
|
||||
m_mapVUVP.clear();
|
||||
m_arrExtToTBBMap.clear();
|
||||
m_pMeshDesc = NULL;
|
||||
}
|
||||
|
||||
|
||||
// returns the number of vertices in the resulting vertex buffer
|
||||
unsigned CRenderMeshBuilder::numVertices()const
|
||||
{
|
||||
// the number of external tangent bases determine this, because the
|
||||
// tangent base calculation algorithm completely splits all the necessary
|
||||
// vertices, so that the vertex buffer can be formed
|
||||
return m_arrExtTangents.size();
|
||||
}
|
||||
|
||||
// prepares the m_arrExtTangents, m_arrExtToTBBMap, m_arrExtTangMap and m_arrExtUVMap
|
||||
void CRenderMeshBuilder::prepareExtToIntMapping ()
|
||||
{
|
||||
unsigned numTBBTangents = m_TangBaseBuilder.GetBaseCount();
|
||||
unsigned numTBBTangents_Reserve = numTBBTangents*9/7;
|
||||
// prepare ext->TBB and the table of actual tangents
|
||||
m_arrExtToTBBMap.reserve (numTBBTangents_Reserve);
|
||||
//m_arrExtToTBBMap.resize (numTBBTangents);
|
||||
m_arrExtTangents.reserve (numTBBTangents_Reserve);
|
||||
//m_arrExtTangents.resize (numTBBTangents);
|
||||
//for (i = 0; i < numTBBTangents; ++i)
|
||||
//{
|
||||
// m_arrExtToTBBMap[i] = i;
|
||||
// TangData& rBase = m_arrExtTangents[i];
|
||||
// m_TangBaseBuilder.GetBase(i, &rBase.tangent.x, &rBase.binormal.x, &rBase.tnormal.x);
|
||||
//}
|
||||
|
||||
// create the indexation map new->old
|
||||
m_arrExtTangMap.reserve(numTBBTangents_Reserve);
|
||||
//m_arrExtTangMap.resize (numTBBTangents,-1);
|
||||
if (m_pMeshDesc->numTexFaces())
|
||||
{
|
||||
m_arrExtUVMap.reserve(numTBBTangents_Reserve);
|
||||
//m_arrExtUVMap.resize (numTBBTangents, -1);
|
||||
}
|
||||
|
||||
m_arrExtFaces.reserve (m_pMeshDesc->numFaces());
|
||||
}
|
||||
|
||||
|
||||
// adds an entry to all required maps - m_arrExtTangents, m_arrExtToTBBMap, m_arrExtTangMap and m_arrExtUVMap
|
||||
bool CRenderMeshBuilder::addExtToIntMapEntry (DWORD FaceExt[3], const CryFace& FaceInt, const CryTexFace& TexFaceInt)
|
||||
{
|
||||
unsigned numTBBTangents = m_TangBaseBuilder.GetBaseCount();
|
||||
assert (m_arrExtTangMap.size() == m_arrExtUVMap.size() || m_arrExtUVMap.empty());
|
||||
assert (m_arrExtTangMap.size() == m_arrExtTangents.size());
|
||||
|
||||
CryFace NewExtFace = FaceInt;
|
||||
|
||||
if (FaceExt[0] == FaceExt[1] || FaceExt[1] == FaceExt[2] || FaceExt[2] == FaceExt[0])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
{
|
||||
VertexUVPair VUVPair((ushort)FaceInt[i],(ushort)TexFaceInt[i], (ushort)FaceExt[i]);
|
||||
VertexUVPairMap::iterator itVUVPair = m_mapVUVP.find (VUVPair);
|
||||
unsigned nExtEntry;
|
||||
if (itVUVPair == m_mapVUVP.end())
|
||||
{
|
||||
// no such pair, add a new one.
|
||||
nExtEntry = m_arrExtTangents.size();
|
||||
TangData rBase;
|
||||
m_TangBaseBuilder.GetBase (FaceExt[i], &rBase.tangent.x, &rBase.binormal.x, &rBase.tnormal.x);
|
||||
AdjustBase(rBase);
|
||||
m_arrExtTangents.push_back (rBase);
|
||||
|
||||
m_arrExtTangMap.push_back(FaceInt[i]);
|
||||
m_arrExtToTBBMap.push_back((ushort)FaceExt[i]);
|
||||
if (m_pMeshDesc->numTexFaces())
|
||||
m_arrExtUVMap.push_back(TexFaceInt[i]);
|
||||
m_mapVUVP.insert (VertexUVPairMap::value_type(VUVPair, nExtEntry));
|
||||
}
|
||||
else
|
||||
{
|
||||
// there's already such a pair, use it
|
||||
nExtEntry = itVUVPair->second;
|
||||
}
|
||||
|
||||
NewExtFace[i] = nExtEntry;
|
||||
}
|
||||
|
||||
assert(!NewExtFace.isDegenerate());
|
||||
m_arrExtFaces.push_back(NewExtFace);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// creates the mapping from the external to internal indices
|
||||
void CRenderMeshBuilder::buildExtToIntMaps()
|
||||
{
|
||||
unsigned i,numTBBTangents = m_TangBaseBuilder.GetBaseCount();
|
||||
prepareExtToIntMapping();
|
||||
|
||||
unsigned numDegenerate = 0;
|
||||
|
||||
CryTexFace TexFaceInt (0,0,0);
|
||||
DWORD FaceExt[3];
|
||||
for (i = 0; i < m_pMeshDesc->numFaces(); ++i)
|
||||
{
|
||||
// internal indexation face
|
||||
const CryFace& FaceInt = m_pMeshDesc->pFaces[i];
|
||||
// external indexation face
|
||||
|
||||
m_TangBaseBuilder.GetTriangleBaseIndices(i, FaceExt);
|
||||
|
||||
if (m_pMeshDesc->numTexFaces())
|
||||
TexFaceInt = m_pMeshDesc->pTexFaces[i];
|
||||
|
||||
if (!addExtToIntMapEntry (FaceExt, FaceInt, TexFaceInt))
|
||||
{
|
||||
++numDegenerate;
|
||||
continue; // degenerate face
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
CryFace& NewExtFace = m_arrExtFaces.back();
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
assert (m_arrExtUVMap[NewExtFace[j]] == TexFaceInt[j]);
|
||||
assert (m_arrExtTangMap[NewExtFace[j]] == FaceInt[j]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (numDegenerate)
|
||||
LogWarning("%u degenerate faces (skipped)", numDegenerate);
|
||||
}
|
||||
|
||||
|
||||
// calculate the number of elements == nEl
|
||||
|
||||
|
||||
// create the indices and the array m_arrMaterials
|
||||
|
||||
// Create the m_arrMtlFaces
|
||||
// degraded faces are deleted
|
||||
void CRenderMeshBuilder::buildMtlFaces()
|
||||
{
|
||||
unsigned nFace, numExtFaces = m_arrExtFaces.size();
|
||||
// pass 1: calculate each material's number of faces, and the number of materials
|
||||
// SKIPPED NOW
|
||||
const unsigned nMaxMatID = 0x400;
|
||||
// pass 2: create the face groups and reserve space for the faces
|
||||
m_arrMtlFaces.reserve (nMaxMatID/4);
|
||||
|
||||
unsigned numSkippedFaces = 0;
|
||||
|
||||
// pass 3: create the faces in the face groups
|
||||
for (nFace = 0; nFace < numExtFaces; ++nFace)
|
||||
{
|
||||
// external indexation face
|
||||
const CryFace& rExtFace = m_arrExtFaces[nFace];
|
||||
|
||||
int nMatID = rExtFace.MatID;
|
||||
// material id of the face to count
|
||||
if (nMatID < 0 || nMatID > nMaxMatID)
|
||||
{
|
||||
++numSkippedFaces;
|
||||
continue;
|
||||
}
|
||||
assert (!rExtFace.isDegenerate());
|
||||
if (m_arrMtlFaces.size() <= (unsigned)nMatID)
|
||||
m_arrMtlFaces.resize (nMatID+1);
|
||||
m_arrMtlFaces[nMatID].push_back (Face(rExtFace));
|
||||
}
|
||||
|
||||
if (numSkippedFaces)
|
||||
LogWarning ("%d faces skipped: no material or material id is out of range", numSkippedFaces);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// create the indices and the array m_arrMaterials out of m_arrMtlFaces
|
||||
void CRenderMeshBuilder::buildIndexBuffer()
|
||||
{
|
||||
m_arrIndices.reserve (m_pMeshDesc->numFaces()*3);
|
||||
SetListsOnly (true);
|
||||
|
||||
for (unsigned nMaterial = 0; nMaterial < m_arrMtlFaces.size(); ++nMaterial)
|
||||
{
|
||||
const FaceArray& arrFaces = m_arrMtlFaces[nMaterial];
|
||||
if (arrFaces.empty())
|
||||
continue;
|
||||
|
||||
PrimitiveGroup* pGroup = NULL;
|
||||
unsigned short numGroups = 0;
|
||||
GenerateStrips((unsigned short*)&arrFaces[0], arrFaces.size() * 3, &pGroup, &numGroups);
|
||||
|
||||
for (unsigned nGroup = 0; nGroup < numGroups; ++nGroup)
|
||||
appendNvidiaStrip (pGroup[nGroup], nMaterial);
|
||||
|
||||
delete[numGroups] pGroup;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// remaps (transposes, permutates) the indices to improve spatial locality of the vertex buffer
|
||||
void CRenderMeshBuilder::remapIndicesForVBCache()
|
||||
{
|
||||
// this is the old->new indexation
|
||||
std::vector<unsigned> arrVCache;
|
||||
arrVCache.resize (m_arrExtTangents.size(), -1);
|
||||
unsigned nNextVertex = 0;
|
||||
for (unsigned i = 0; i < m_arrIndices.size(); ++i)
|
||||
{
|
||||
ushort nVertex = m_arrIndices[i];
|
||||
if (arrVCache[nVertex] == -1)
|
||||
// we've met this vertex for the first time
|
||||
arrVCache[nVertex] = nNextVertex++;
|
||||
}
|
||||
|
||||
remapExtIndices(&arrVCache[0], nNextVertex);
|
||||
}
|
||||
|
||||
// permutate the contents of the array with a permutation old->new
|
||||
template <class T>
|
||||
void Permutate (std::vector<T>& arrOld, unsigned* pPermutation, unsigned newSize)
|
||||
{
|
||||
assert (newSize <= arrOld.size());
|
||||
std::vector<T> arrNew;
|
||||
arrNew.resize (newSize);
|
||||
for (unsigned nEntry = 0; nEntry < arrOld.size(); ++nEntry)
|
||||
{
|
||||
if (pPermutation[nEntry] < arrNew.size())
|
||||
{
|
||||
arrNew[pPermutation[nEntry]] = arrOld[nEntry];
|
||||
}
|
||||
else
|
||||
assert (pPermutation[nEntry] == -1);
|
||||
}
|
||||
arrOld.swap(arrNew);
|
||||
}
|
||||
|
||||
|
||||
// remaps external indices according to the given permutation old->new
|
||||
void CRenderMeshBuilder::remapExtIndices (unsigned* pPermutation, unsigned numNewVertices)
|
||||
{
|
||||
unsigned numVertices = this->numVertices();
|
||||
// remap the indices
|
||||
for (unsigned nIndex = 0; nIndex < m_arrIndices.size(); ++nIndex)
|
||||
{
|
||||
assert (m_arrIndices[nIndex] < numVertices);
|
||||
m_arrIndices[nIndex] = pPermutation[m_arrIndices[nIndex]];
|
||||
assert (m_arrIndices[nIndex] < numNewVertices);
|
||||
}
|
||||
|
||||
for (unsigned nFace = 0; nFace < m_arrExtFaces.size(); ++nFace)
|
||||
{
|
||||
m_arrExtFaces[nFace].v0 = pPermutation[m_arrExtFaces[nFace].v0];
|
||||
m_arrExtFaces[nFace].v1 = pPermutation[m_arrExtFaces[nFace].v1];
|
||||
m_arrExtFaces[nFace].v2 = pPermutation[m_arrExtFaces[nFace].v2];
|
||||
}
|
||||
|
||||
// remap the ExtToInt mappings
|
||||
assert (m_arrExtTangMap.size() == numVertices);
|
||||
Permutate(m_arrExtTangMap, pPermutation, numNewVertices);
|
||||
|
||||
if (m_pMeshDesc->numTexFaces())
|
||||
{
|
||||
assert (m_arrExtUVMap.size() == numVertices);
|
||||
Permutate(m_arrExtUVMap, pPermutation, numNewVertices);
|
||||
}
|
||||
|
||||
assert (m_arrExtTangents.size() == numVertices);
|
||||
// remap the tangent bases
|
||||
Permutate(m_arrExtTangents, pPermutation, numNewVertices);
|
||||
assert (m_arrExtTangents.size() == numNewVertices);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// add the primitive group(s) and indices (m_arrPrimGroups and m_arrIndices)
|
||||
// from the given primitives generated by Nvidia Stripifier
|
||||
void CRenderMeshBuilder::appendNvidiaStrip (const struct PrimitiveGroup& rGroup, unsigned nMaterial)
|
||||
{
|
||||
int j;
|
||||
|
||||
// in case we'll add this material group, collect info in it
|
||||
MaterialGroup MatGroup;
|
||||
MatGroup.nMaterial = nMaterial;
|
||||
MatGroup.nIndexBase = m_arrIndices.size();
|
||||
MatGroup.numIndices = 0;
|
||||
|
||||
for (int nIndex = 0; nIndex < (int)rGroup.numIndices - 2; )
|
||||
{
|
||||
int v[3];
|
||||
unsigned short* src = rGroup.indices + nIndex;
|
||||
switch (rGroup.type)
|
||||
{
|
||||
case PT_LIST:
|
||||
v[0] = src[0];
|
||||
v[1] = src[1];
|
||||
v[2] = src[2];
|
||||
nIndex += 3;
|
||||
break;
|
||||
case PT_STRIP:
|
||||
if (nIndex&1)
|
||||
{
|
||||
v[0] = src[1];
|
||||
v[1] = src[0];
|
||||
v[2] = src[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
v[0] = src[0];
|
||||
v[1] = src[1];
|
||||
v[2] = src[2];
|
||||
}
|
||||
nIndex += 1;
|
||||
break;
|
||||
case PT_FAN:
|
||||
v[0] = rGroup.indices[0];
|
||||
v[1] = src[1];
|
||||
v[2] = src[2];
|
||||
break;
|
||||
}
|
||||
if (v[0] == v[1] || v[1] == v[2] || v[2] == v[0])
|
||||
continue;
|
||||
|
||||
MatGroup.numIndices += 3;
|
||||
for (j = 0; j < 3; ++j)
|
||||
m_arrIndices.push_back(v[j]);
|
||||
}
|
||||
|
||||
if (MatGroup.numIndices)
|
||||
{
|
||||
// there were some triangles - add a new group or append those triangles to the previous group
|
||||
if (!m_arrPrimGroups.empty() && m_arrPrimGroups.back().nMaterial == nMaterial)
|
||||
m_arrPrimGroups.back().numIndices += MatGroup.numIndices;
|
||||
else
|
||||
m_arrPrimGroups.push_back(MatGroup);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CRenderMeshBuilder::selfValidate()
|
||||
{
|
||||
assert (m_arrExtFaces.size() <= m_pMeshDesc->numFaces());
|
||||
unsigned numFaces = m_arrExtFaces.size();
|
||||
for (unsigned nFace = 0; nFace < numFaces; ++nFace)
|
||||
{
|
||||
CryFace ExtFace = m_arrExtFaces[nFace];
|
||||
CryFace IntFace = m_pMeshDesc->pFaces[nFace];
|
||||
CryTexFace TexFace = m_pMeshDesc->pTexFaces[nFace];
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
// this is only applicable to a normal manifold mesh
|
||||
assert (m_arrExtUVMap[ExtFace[i]] == TexFace[i]);
|
||||
assert (m_arrExtTangMap[ExtFace[i]] == IntFace[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjusts the base - converts from Martin's algorithm's requirements to the engine requirements
|
||||
void CRenderMeshBuilder::AdjustBase(TangData& rBase)
|
||||
{
|
||||
/*
|
||||
float fBinormal = rBase.binormal * rBase.tnormal;
|
||||
float fTangent = rBase.tangent * rBase.tnormal;
|
||||
assert (fabs(fBinormal) < 1e-2 && fabs(fTangent) < 1e-2);
|
||||
/* // normalize the normal
|
||||
float fEpsilon = 0.0005f;
|
||||
float fSqrt1_2 = 0.70710678118654752440084436210485f; // square root of 1/2
|
||||
float fNormalLen = rBase.tnormal.Length();
|
||||
if (fNormalLen < fEpsilon)
|
||||
rBase.tnormal /= fNormalLen;
|
||||
rBase.tnormal /= fNormalLen;
|
||||
|
||||
// make the bisect that
|
||||
Vec3d vBisect = rBase.binormal+rBase.tangent;
|
||||
vBisect -= (vBisect * rBase.tnormal) * rBase.tnormal; // make it orthogonal to the normal
|
||||
float fBisectLen = vBisect.Length();
|
||||
if (fBisectLen < fEpsilon)
|
||||
return;
|
||||
vBisect /= fBisectLen;
|
||||
|
||||
Vec3d vBase = vBisect ^ rBase.tnormal;
|
||||
|
||||
if (rBase.binormal * vBase > rBase.tangent * vBase)
|
||||
{
|
||||
assert (rBase.binormal * vBase > 0 && rBase.tangent * vBase < 0);
|
||||
rBase.binormal = (vBisect + vBase) * fSqrt1_2;
|
||||
rBase.tangent = (vBisect - vBase) * fSqrt1_2;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (rBase.binormal * vBase < 0 && rBase.tangent * vBase > 0);
|
||||
rBase.binormal = (vBisect - vBase) * fSqrt1_2;
|
||||
rBase.tangent = (vBisect + vBase) * fSqrt1_2;
|
||||
}
|
||||
*/
|
||||
//std::swap(rBase.binormal, rBase.tangent);
|
||||
rBase.binormal = -rBase.binormal;
|
||||
}
|
||||
|
||||
void CRenderMeshBuilder::MeshProxy::GetPos( const DWORD indwPos, float outfPos[3] ) const
|
||||
{
|
||||
const Vec3d ptPos = m_pMeshDesc->pVertices[indwPos].p;
|
||||
// unrotate the object
|
||||
for (int i = 0; i < 3; ++i)
|
||||
outfPos[i] = m_tm(0,i)*ptPos.x + m_tm(1,i)*ptPos.y + m_tm(2,i)*ptPos.z;
|
||||
}
|
||||
225
ResourceCompilerPC/RenderMeshBuilder.h
Normal file
225
ResourceCompilerPC/RenderMeshBuilder.h
Normal file
@@ -0,0 +1,225 @@
|
||||
// This is the class that makes a renderable (stripified) vertex/index buffers
|
||||
// and tangent bases out of a CGF mesh
|
||||
#ifndef _RC_RENDER_MESH_BUILDER_HDR_
|
||||
#define _RC_RENDER_MESH_BUILDER_HDR_
|
||||
|
||||
#include "CryChunkedFile.h"
|
||||
#include "TangentSpaceCalculation.h"
|
||||
#include "CryCompiledFile.h"
|
||||
|
||||
// Calculates tangent spaces
|
||||
// Builds index buffer (stripifies), material group array, ext-to-int map.
|
||||
class CRenderMeshBuilder
|
||||
{
|
||||
public:
|
||||
// constructs everything for the render mesh out of the given mesh
|
||||
void build (const CryChunkedFile::MeshDesc* pMeshDesc);
|
||||
// increases all indices of materials by the given offset
|
||||
void addMaterialOffset (unsigned nOffset);
|
||||
// cleans up the object
|
||||
void clear();
|
||||
|
||||
// this error class is thrown from the constructor when the object can't be constructed
|
||||
class Error
|
||||
{
|
||||
public:
|
||||
Error(const char* szDesc):m_szDesc(szDesc){}
|
||||
const char* c_str() const{return m_szDesc;}
|
||||
protected:
|
||||
const char* m_szDesc;
|
||||
};
|
||||
|
||||
// returns the number of vertices in the resulting vertex buffer
|
||||
unsigned numVertices()const;
|
||||
|
||||
// face/vertex index type
|
||||
typedef unsigned short ushort;
|
||||
|
||||
// this is the index buffer (external indexation)
|
||||
std::vector<ushort> m_arrIndices;
|
||||
|
||||
// this array represents the groups of indices in the index buffer:
|
||||
// each group has its own material id and number of elements (indices, i.e. number of faces * 3 in case of strip stripification)
|
||||
typedef CCFMaterialGroup MaterialGroup;
|
||||
typedef std::vector<MaterialGroup> MaterialGroupArray;
|
||||
MaterialGroupArray m_arrPrimGroups;
|
||||
|
||||
// this is the mapping from new indices to original
|
||||
std::vector<ushort> m_arrExtTangMap;
|
||||
|
||||
// this is the mapping from new indices to original UV indices
|
||||
// in the original CGF, texture and geometric mesh (faces/tex faces) are
|
||||
// different (tex face indices are not necessarily the same as face indices),
|
||||
// this is why the ExtToInt map doesn't coincide with this ExtUVMap
|
||||
std::vector<ushort> m_arrExtUVMap;
|
||||
|
||||
// these are the tangent bases (external indexation)
|
||||
std::vector<TangData> m_arrExtTangents;
|
||||
|
||||
#pragma pack(push,2)
|
||||
// this is a group of faces, as they will be inside a group (material)
|
||||
struct Face
|
||||
{
|
||||
ushort v[3];
|
||||
Face(){}
|
||||
Face(ushort v0, ushort v1, ushort v2)
|
||||
{
|
||||
v[0] = v0; v[1] = v1; v[2] = v2;
|
||||
}
|
||||
Face (const CryFace& rFace)
|
||||
{
|
||||
v[0] = rFace.v0; v[1] = rFace.v1; v[2] = rFace.v2;
|
||||
}
|
||||
Face (DWORD src[3])
|
||||
{
|
||||
v[0] = (ushort)src[0]; v[1] = (ushort)src[1]; v[2] = (ushort)src[2];
|
||||
}
|
||||
bool isDegenerate() const
|
||||
{
|
||||
return v[0] == v[1] || v[1] == v[2] || v[2] == v[0];
|
||||
}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// WARNING: this array must be binary-compatible with the array of unsigned shorts
|
||||
// passed to Nvidia Stripifier. external indexation
|
||||
typedef std::vector<Face> FaceArray;
|
||||
|
||||
// this is the array of faces for each material
|
||||
std::vector<FaceArray> m_arrMtlFaces;
|
||||
|
||||
// this is the actual array of faces, but in the final external indexation
|
||||
std::vector<CryFace> m_arrExtFaces;
|
||||
protected:
|
||||
// adjusts the base - converts from Martin's algorithm's requirements to the engine requirements
|
||||
static void AdjustBase(TangData& rBase);
|
||||
|
||||
// creates the mapping from the external to internal indices
|
||||
void buildExtToIntMaps();
|
||||
|
||||
// create m_arrMtlFaces; the degenerated faces are not included
|
||||
void buildMtlFaces();
|
||||
|
||||
// create the indices and the array m_arrMaterials out of m_arrMtlFaces
|
||||
void buildIndexBuffer();
|
||||
|
||||
// remaps (transposes, permutates) the indices to improve spatial locality of the vertex buffer
|
||||
void remapIndicesForVBCache();
|
||||
|
||||
// remaps external indices according to the given permutation old->new
|
||||
void remapExtIndices (unsigned* pPermutation, unsigned numNewTargets);
|
||||
|
||||
// prepares the m_arrExtTangents, m_arrExtToTBBMap, m_arrExtTangMap and m_arrExtUVMap
|
||||
void prepareExtToIntMapping();
|
||||
|
||||
// adds an entry to all required maps - m_arrExtTangents, m_arrExtToTBBMap, m_arrExtTangMap and m_arrExtUVMap
|
||||
bool addExtToIntMapEntry (DWORD FaceExt[3], const CryFace& FaceInt, const CryTexFace &TexFaceInt);
|
||||
|
||||
protected:
|
||||
// add the primitive group(s) and indices (m_arrPrimGroups and m_arrIndices)
|
||||
// from the given primitives generated by Nvidia Stripifier
|
||||
void appendNvidiaStrip (const struct PrimitiveGroup& Group, unsigned nMaterial);
|
||||
|
||||
void selfValidate();
|
||||
protected:
|
||||
|
||||
const CryChunkedFile::MeshDesc* m_pMeshDesc;
|
||||
|
||||
struct VertexUVPair
|
||||
{
|
||||
VertexUVPair(){}
|
||||
VertexUVPair(ushort _nVertex, ushort _nTexVertex, ushort _nExtTangent):
|
||||
nVertex(_nVertex), nTexVertex (_nTexVertex), nExtTangent(_nExtTangent){}
|
||||
|
||||
bool operator < (const VertexUVPair& right)const
|
||||
{
|
||||
return
|
||||
nVertex < right.nVertex ? true:
|
||||
nVertex > right.nVertex? false:
|
||||
nTexVertex < right.nTexVertex? true:
|
||||
nTexVertex > right.nTexVertex? false:
|
||||
nExtTangent < right.nExtTangent;
|
||||
}
|
||||
|
||||
ushort nVertex; // vertex in internal indexation
|
||||
ushort nTexVertex; // texture vertex (UV) in internal indexation
|
||||
ushort nExtTangent; // vertex in TBB indexation, or tangent in the array of tangents generated by TBB
|
||||
};
|
||||
|
||||
// this is the map from the vertex-uv pair to the index of the
|
||||
// temporary vertex mapping in this->arrVertMap;
|
||||
typedef std::map <VertexUVPair,ushort> VertexUVPairMap;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// a proxy structure that gets passed to the tangent space calculation algorithm
|
||||
struct MeshProxy
|
||||
{
|
||||
public:
|
||||
MeshProxy ()
|
||||
{
|
||||
m_pMeshDesc = NULL;
|
||||
}
|
||||
|
||||
// creates temporary mapping for splitting the vertices
|
||||
// with different UVs
|
||||
void init (const CryChunkedFile::MeshDesc* pMeshDesc)
|
||||
{
|
||||
m_pMeshDesc = pMeshDesc;
|
||||
m_tm = m_pMeshDesc->pNode->pDesc->tm;
|
||||
}
|
||||
|
||||
DWORD GetTriangleCount( void ) const
|
||||
{
|
||||
return m_pMeshDesc->numFaces();
|
||||
}
|
||||
|
||||
void GetTriangleIndices( const DWORD indwTriNo, DWORD outdwPos[3], DWORD outdwNorm[3], DWORD outdwUV[3] ) const
|
||||
{
|
||||
const CryFace& rFace = m_pMeshDesc->pFaces[indwTriNo];
|
||||
outdwNorm[0] = outdwPos[0] = rFace.v0;
|
||||
outdwNorm[1] = outdwPos[1] = rFace.v1;
|
||||
outdwNorm[2] = outdwPos[2] = rFace.v2;
|
||||
if (m_pMeshDesc->numTexFaces())
|
||||
{
|
||||
const CryTexFace& rTexFace = m_pMeshDesc->pTexFaces[indwTriNo];
|
||||
outdwUV[0] = rTexFace.t0;
|
||||
outdwUV[1] = rTexFace.t1;
|
||||
outdwUV[2] = rTexFace.t2;
|
||||
}
|
||||
else
|
||||
{
|
||||
outdwUV[0] = outdwUV[1] = outdwUV[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GetPos( const DWORD indwPos, float outfPos[3] ) const;
|
||||
|
||||
void GetUV ( const DWORD indwPos, float outfUV[2] ) const
|
||||
{
|
||||
const CryUV& uv = m_pMeshDesc->pUVs[indwPos];
|
||||
outfUV[0] = uv.u;
|
||||
outfUV[1] = uv.v;
|
||||
}
|
||||
|
||||
std::vector<VertexUVPair> arrVertMap;
|
||||
protected:
|
||||
const CryChunkedFile::MeshDesc* m_pMeshDesc;
|
||||
Matrix44 m_tm;
|
||||
};
|
||||
|
||||
CTangentSpaceCalculation<MeshProxy> m_TangBaseBuilder;
|
||||
|
||||
// this mapping gives the ext->tang ext mapping, i.e.
|
||||
// maps from the final external indexation (that's found in
|
||||
// m_arrExtTangMap, m_arrExtUVMap, m_arrExtTangents)
|
||||
// to the tangent base indexation in m_TangBaseBuilder
|
||||
// (GetBaseCount, GetTriangleBaseIndices, GetBase)
|
||||
std::vector<ushort> m_arrExtToTBBMap;
|
||||
|
||||
// this is used during construction of the external maps to quickly find
|
||||
// corresponding vertex-uv pairs and avoid collisions
|
||||
// the vertex-uv indices are in internal indexations of vertices and UVs
|
||||
VertexUVPairMap m_mapVUVP;
|
||||
};
|
||||
|
||||
#endif
|
||||
59
ResourceCompilerPC/ResourceCompilerPC.cpp
Normal file
59
ResourceCompilerPC/ResourceCompilerPC.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// ResourceCompilerPC.cpp : Defines the entry point for the DLL application.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "CgfConvertor.h"
|
||||
#include "GC_CgfConverter.h"
|
||||
#include "StatCGFCompiler\StatCGFCompiler.h"
|
||||
#include "ResourceCompilerPC.h"
|
||||
|
||||
IRCLog* g_pLog = NULL;
|
||||
|
||||
void LogWarning (const char* szFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, szFormat);
|
||||
if (g_pLog)
|
||||
g_pLog->LogV (IMiniLog::eWarning, szFormat, args);
|
||||
else
|
||||
vprintf (szFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
void Log (const char* szFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, szFormat);
|
||||
if (g_pLog)
|
||||
g_pLog->LogV (IMiniLog::eMessage, szFormat, args);
|
||||
else
|
||||
vprintf (szFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain( HANDLE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
g_hInst = (HMODULE)hModule;
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// This is an example of an exported function.
|
||||
void __stdcall RegisterConvertors(IResourceCompiler*pRC)
|
||||
{
|
||||
pRC->RegisterConvertor(new CGFConvertor());
|
||||
//pRC->RegisterConvertor(new GC_CGFConvertor());
|
||||
//pRC->RegisterConvertor(new CALConvertor());
|
||||
}
|
||||
|
||||
HMODULE g_hInst;
|
||||
8
ResourceCompilerPC/ResourceCompilerPC.h
Normal file
8
ResourceCompilerPC/ResourceCompilerPC.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "IRCLog.h"
|
||||
#include "IResCompiler.h"
|
||||
|
||||
extern HMODULE g_hInst;
|
||||
extern IRCLog* g_pLog;
|
||||
|
||||
extern void LogWarning (const char* szFormat, ...);
|
||||
extern void Log (const char* szFormat, ...);
|
||||
649
ResourceCompilerPC/ResourceCompilerPC.vcproj
Normal file
649
ResourceCompilerPC/ResourceCompilerPC.vcproj
Normal file
@@ -0,0 +1,649 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="ResourceCompilerPC"
|
||||
ProjectGUID="{43B9F5EF-C4FC-44FF-BEB0-70EFE792B6C0}"
|
||||
SccProjectName="SAK"
|
||||
SccAuxPath="SAK"
|
||||
SccLocalPath="SAK"
|
||||
SccProvider="SAK"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="D:\Games\FC\Bin32"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
OptimizeForProcessor="0"
|
||||
AdditionalIncludeDirectories="..\ResourceCompiler,..\CryCommon"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;RESOURCECOMPILERPC_EXPORTS"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
BufferSecurityCheck="FALSE"
|
||||
EnableFunctionLevelLinking="TRUE"
|
||||
UsePrecompiledHeader="3"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="dbghelp.lib"
|
||||
OutputFile="$(OutDir)/ResourceCompilerPC.dll"
|
||||
LinkIncremental="2"
|
||||
ModuleDefinitionFile="ResourceCompilerPlugin.def"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/ResourceCompilerPC.pdb"
|
||||
SubSystem="2"
|
||||
ImportLibrary="$(OutDir)/ResourceCompilerPC.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="D:\Games\FC\Bin32"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
GlobalOptimizations="TRUE"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="TRUE"
|
||||
FavorSizeOrSpeed="2"
|
||||
OmitFramePointers="TRUE"
|
||||
EnableFiberSafeOptimizations="FALSE"
|
||||
OptimizeForProcessor="2"
|
||||
AdditionalIncludeDirectories="..\ResourceCompiler,..\CryCommon"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;RESOURCECOMPILERPC_EXPORTS;_RELEASE"
|
||||
StringPooling="TRUE"
|
||||
RuntimeLibrary="2"
|
||||
BufferSecurityCheck="FALSE"
|
||||
EnableFunctionLevelLinking="FALSE"
|
||||
EnableEnhancedInstructionSet="0"
|
||||
UsePrecompiledHeader="3"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="dbghelp.lib"
|
||||
OutputFile="$(OutDir)/ResourceCompilerPC.dll"
|
||||
LinkIncremental="1"
|
||||
ModuleDefinitionFile="ResourceCompilerPlugin.def"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
ImportLibrary="$(OutDir)/ResourceCompilerPC.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug64|Win32"
|
||||
OutputDirectory="D:\Games\FC\Bin32"
|
||||
IntermediateDirectory="Debug64"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\ResourceCompiler,..\CryCommon"
|
||||
PreprocessorDefinitions="_AMD64_;WIN64;WIN32;_DEBUG;_WINDOWS;_USRDLL;RESOURCECOMPILERPC_EXPORTS"
|
||||
BasicRuntimeChecks="0"
|
||||
SmallerTypeCheck="FALSE"
|
||||
RuntimeLibrary="3"
|
||||
BufferSecurityCheck="FALSE"
|
||||
UsePrecompiledHeader="3"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalOptions="/MACHINE:AMD64"
|
||||
AdditionalDependencies="dbghelp.lib"
|
||||
OutputFile="$(OutDir)/$(ProjectName)64.dll"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
ModuleDefinitionFile="ResourceCompilerPlugin.def"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/$(TargetName).pdb"
|
||||
SubSystem="2"
|
||||
LargeAddressAware="2"
|
||||
ImportLibrary="$(OutDir)/$(ProjectName)64.lib"
|
||||
TargetMachine="0"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release64|Win32"
|
||||
OutputDirectory="D:\Games\FC\Bin32"
|
||||
IntermediateDirectory="Release64"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="TRUE">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
GlobalOptimizations="FALSE"
|
||||
InlineFunctionExpansion="0"
|
||||
EnableIntrinsicFunctions="FALSE"
|
||||
AdditionalIncludeDirectories="..\ResourceCompiler,..\CryCommon"
|
||||
PreprocessorDefinitions="_AMD64_;WIN64;WIN32;NDEBUG;_WINDOWS;_USRDLL;RESOURCECOMPILERPC_EXPORTS"
|
||||
StringPooling="TRUE"
|
||||
BasicRuntimeChecks="0"
|
||||
SmallerTypeCheck="FALSE"
|
||||
RuntimeLibrary="2"
|
||||
BufferSecurityCheck="FALSE"
|
||||
UsePrecompiledHeader="3"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalOptions="/MACHINE:AMD64"
|
||||
AdditionalDependencies="dbghelp.lib"
|
||||
OutputFile="$(OutDir)/$(ProjectName)64.dll"
|
||||
LinkIncremental="1"
|
||||
ModuleDefinitionFile="ResourceCompilerPlugin.def"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/$(TargetName).pdb"
|
||||
SubSystem="2"
|
||||
LargeAddressAware="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
ImportLibrary="$(OutDir)/$(ProjectName)64.lib"
|
||||
TargetMachine="0"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Skin"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="CrySkinAMD64.asm">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="TRUE">
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="TRUE">
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug64|Win32">
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Compiling $(InputName)"
|
||||
CommandLine="ml64 /c /Fl"$(OutDir)\$(InputName).cod" /Fo"$(OutDir)\$(InputName).obj" $(InputPath)
|
||||
"
|
||||
Outputs="$(OutDir)\$(InputName).obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release64|Win32">
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Compiling $(InputName)"
|
||||
CommandLine="ml64 /c /Fl"$(OutDir)\$(InputName).cod" /Fo"$(OutDir)\$(InputName).obj" $(InputPath)
|
||||
"
|
||||
Outputs="$(OutDir)\$(InputName).obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinBase.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinBase.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinBasisBuilder.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinBasisBuilder.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinBuilder.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinBuilder.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinBuilderBase.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinBuilderBase.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinFull.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinFull.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinMorph.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinMorph.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinMorphBuilder.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinMorphBuilder.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinRigidBasis.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinRigidBasis.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CrySkinTypes.h">
|
||||
</File>
|
||||
<Filter
|
||||
Name="DataSources"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="SkinDataSources.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="SkinDataSources.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Front-End"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;h;hpp;hxx;hm;inl;inc">
|
||||
<File
|
||||
RelativePath="CalConvertor.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CgfConvertor.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CgfConvertor.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CgfUtils.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GC_CgfConverter.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GC_CgfConverter.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="ResourceCompilerPC.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="ResourceCompilerPC.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="stdafx.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug64|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release64|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="stdafx.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
|
||||
<File
|
||||
RelativePath="ReadMe.txt">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="ResourceCompilerPlugin.def">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Support"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="AutoFile.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\GAME01\CryCommon\CryCompiledFile.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="MathUtils.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="RenderMeshBuilder.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="RenderMeshBuilder.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="TangentSpaceCalculation.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Shared with Animation"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="BoneLightBindInfo.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="BoneLightBindInfo.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="ChunkFileReader.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="ChunkFileReader.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="Controller.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CryAnimationInfo.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CryBoneDesc.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CryBoneDesc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CryVertexBinding.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CryVertexBinding.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="FileMapping.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="FileMapping.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="SSEUtils.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="SSEUtils.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="NvTriStrip"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="NvTriStrip\NvTriStrip.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug64|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release64|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="NvTriStrip\NvTriStrip.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="NvTriStrip\NvTriStripObjects.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug64|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release64|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="NvTriStrip\NvTriStripObjects.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="NvTriStrip\RenderPCH.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="NvTriStrip\VertexCache.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Stencil Shadows"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="StencilShadowConnectivity.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StencilShadowConnectivityBuilder.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StencilShadowConnectivityBuilder.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="StatCGFCompiler"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\BaseObj.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\CryStaticModel.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\CryStaticModel.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\File.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\File.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\Geom.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\Geom.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\Helper.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\Helper.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\Light.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\Light.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\Meshidx.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\CryCommon\MeshIdx.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\Node.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\Node.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\StatCGFCompiler.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\StatCGFCompiler.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\StatCGFCompilerLB.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\StatCGFCompilerLBSerialize.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\StatCGFShadowVolume.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\StatCGFShadVol.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="StatCGFCompiler\StatObjPhysics.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath="..\CryCommon\fSinCos64.lib">
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
10
ResourceCompilerPC/ResourceCompilerPC.vcproj.vspscc
Normal file
10
ResourceCompilerPC/ResourceCompilerPC.vcproj.vspscc
Normal file
@@ -0,0 +1,10 @@
|
||||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = "relative:ResourceCompilerPC"
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
||||
2
ResourceCompilerPC/ResourceCompilerPlugin.def
Normal file
2
ResourceCompilerPC/ResourceCompilerPlugin.def
Normal file
@@ -0,0 +1,2 @@
|
||||
EXPORTS
|
||||
RegisterConvertors @1
|
||||
456
ResourceCompilerPC/SSEUtils.cpp
Normal file
456
ResourceCompilerPC/SSEUtils.cpp
Normal file
@@ -0,0 +1,456 @@
|
||||
#include "stdafx.h"
|
||||
#include "SSEUtils.h"
|
||||
|
||||
namespace cpu
|
||||
{
|
||||
DWORD g_dwFeatures = 0;
|
||||
DWORD g_dwFeaturesEx = 0;
|
||||
|
||||
const char* g_arrCPUCaps[] = {
|
||||
"FPU", "VME", "DE", "PSE", "TSC", "MSR", "PAE", "MCE", "CX8", "APIC",
|
||||
"Unknown(10)", "SEP", "MTRR", "PGE", "MCA", "CMOV", "PAT", "PSE-36", "PSN", "CLFSH",
|
||||
"Unknown(20)", "DS", "ACPI", "MMX", "FXSR", "SSE", "SSE2", "SS", "HTT", "TM",
|
||||
"Unknown(30)", "PBE"
|
||||
};
|
||||
|
||||
const char* g_arrCPUCapsLong[] = {
|
||||
"Floating Point Unit On-Chip", "Virtual 8086 Mode Enhancements", "Debugging Extensions", "Page Size Extension", "Time Stamp Counter", "Model Specific Registers RDMSR and WRMSR Instructions", "Physical Address Extension", "Machine Check Exception", "CMPXCHG8B Instruction", "Advanced Programmable Interrupt Controller On-Chip",
|
||||
"Unknown(10)", "SYSENTER and SYSEXIT Instructions", "Memory Type Range Registers", "Page Directory Entries Global Bit", "Machine Check Architecture", "Conditional Move Instructions", "Page Attribute Table", "32-Bit Page Size Extension", "Processor Serial Number", "CLFLUSH Instruction",
|
||||
"Unknown(20)", "Debug Store", "Thermal Monitor and Software Controlled Clock Facilities", "MMX Technology", "FXSAVE and FXRSTOR Instructions", "SSE", "SSE2", "Self Snoop", "Hyper-Threading Technology", "Thermal Monitor",
|
||||
"Unknown(30)", "Pending Break Enable"
|
||||
};
|
||||
|
||||
void logCaps()
|
||||
{
|
||||
#ifdef _CRY_ANIMATION_BASE_HEADER_
|
||||
#ifdef _CPU_X86
|
||||
g_GetLog()->LogToFile ("CPU capabilities: ");
|
||||
for (unsigned nCap = 0; nCap < 32; ++nCap)
|
||||
if (g_dwFeatures&(1<<nCap))
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
g_GetLog()->LogToFilePlus(" %s.", g_arrCPUCapsLong[nCap]);
|
||||
#else
|
||||
g_GetLog()->LogToFilePlus(" %s", g_arrCPUCaps[nCap]);
|
||||
#endif
|
||||
}
|
||||
if (has3DNow())
|
||||
g_GetLog()->LogToFilePlus(" 3DNow!");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// detects CPU features (SSE) and perhaps sets up some
|
||||
// pointers to functions
|
||||
void detect ()
|
||||
{
|
||||
#if !defined(LINUX) && defined(_CPU_X86)
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// 386 processor check
|
||||
// The AC bit, bit #18, is a new bit introduced in the EFLAGS
|
||||
// register on the 486 processor to generate alignment
|
||||
// faults.
|
||||
// This bit cannot be set on the 386 processor.
|
||||
|
||||
pushfd // push original EFLAGS
|
||||
pop eax // get original EFLAGS
|
||||
mov ebx, eax // save original EFLAGS
|
||||
xor eax, 040000h // flip AC bit in EFLAGS
|
||||
push eax // save new EFLAGS value on stack
|
||||
popfd // replace current EFLAGS value
|
||||
pushfd // get new EFLAGS
|
||||
pop eax // store new EFLAGS in EAX
|
||||
cmp eax, ebx // can<61>t toggle AC bit, processor=80386
|
||||
jz label386 // jump if 80386 processor
|
||||
push ebx
|
||||
popfd // restore AC bit in EFLAGS
|
||||
|
||||
// Checking for ability to set/clear ID flag (Bit 21) in EFLAGS
|
||||
// which indicates the presence of a processor with the CPUID
|
||||
// instruction.
|
||||
pushfd // save EFLAGS to stack
|
||||
pop eax // store EFLAGS in EAX
|
||||
mov ebx, eax // save in EBX for testing later
|
||||
xor eax, 0200000h // flip bit 21 in EFLAGS
|
||||
push eax // save new EFLAGS value on stack
|
||||
popfd // replace current EFLAGS value
|
||||
pushfd // get new EFLAGS
|
||||
pop eax // store new EFLAGS in EAX
|
||||
cmp eax, ebx // see if bit 21 has changed
|
||||
jz labelNoCPUID // CPUID is not present
|
||||
|
||||
mov EAX, 1
|
||||
cpuid
|
||||
mov g_dwFeatures, EDX
|
||||
|
||||
// check for 3DNow!
|
||||
mov eax, 080000000h // query for extended functions
|
||||
cpuid // get extended function limit
|
||||
cmp eax, 080000001h /* functions up to 80000001h must be present */
|
||||
jb labelNoExtended /* 80000001h is not available */
|
||||
mov eax, 080000001h /* setup extended function 1 */
|
||||
cpuid /* call the function */
|
||||
mov g_dwFeaturesEx, edx /* bit 31 will be set for 3D Now! support*/
|
||||
|
||||
labelNoExtended:
|
||||
test g_dwFeatures, g_featureSSE
|
||||
jz labelNoSSE
|
||||
// SSE is present. to check for OS support...
|
||||
xorps xmm0, xmm0
|
||||
// if we got here safely after xorps, it only can mean we have SSE
|
||||
//or g_dwFeatures, g_featureSSE
|
||||
jmp labelEndDetect
|
||||
label386:
|
||||
labelNoCPUID:
|
||||
labelNoSSE:
|
||||
labelEndDetect:
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
// OS doesn't support some of the instructions we executed..
|
||||
|
||||
if(_exception_code () == STATUS_ILLEGAL_INSTRUCTION)
|
||||
g_dwFeatures &= ~g_featureSSE;
|
||||
}
|
||||
|
||||
if ((g_dwFeatures & (g_featureFXSR|g_featureSSE)) == (g_featureFXSR|g_featureSSE))
|
||||
{
|
||||
unsigned nMXCSR;
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
stmxcsr nMXCSR
|
||||
or nMXCSR, 0x8000
|
||||
ldmxcsr nMXCSR
|
||||
or nMXCSR, 0x40
|
||||
ldmxcsr nMXCSR
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if !defined(LINUX) && defined(_CPU_X86)
|
||||
// given the array of matrices, calculates the min/max
|
||||
// of their positions, and puts them into the min and max Vec3d
|
||||
// NOTE: the matrix array must be aligned on 16-byte boundary
|
||||
void getBBoxSSE (const Matrix44* pBones, unsigned numBones, CryAABB* pBBox)
|
||||
{
|
||||
assert (numBones > 0);
|
||||
_asm
|
||||
{
|
||||
mov EBX, pBones
|
||||
movaps xmm0, [EBX+0x30]
|
||||
movaps xmm1, xmm0
|
||||
mov EDX, pBBox
|
||||
add EBX, 0x70 // now EBX points to the next bone matrix
|
||||
mov ECX, numBones
|
||||
dec ECX
|
||||
jz label_End
|
||||
|
||||
label_Start:
|
||||
movaps xmm2, [EBX]
|
||||
minps xmm0, xmm2
|
||||
maxps xmm1, xmm2
|
||||
add EBX, 0x40
|
||||
loop label_Start
|
||||
|
||||
label_End:
|
||||
//SSE_MOVSS(EDX,xmm0)
|
||||
movss [EDX], xmm0
|
||||
shufps xmm0,xmm0, 0xE5
|
||||
movss [EDX+4], xmm0
|
||||
shufps xmm0,xmm0, 0xE6
|
||||
movss [EDX+8], xmm0
|
||||
//SSE_MOVSS(EDX+0x0C,xmm1)
|
||||
movss [EDX+0x0C], xmm1
|
||||
shufps xmm1,xmm1, 0xE5
|
||||
movss [EDX+0x0C+4], xmm1
|
||||
shufps xmm1,xmm1, 0xE6
|
||||
movss [EDX+0x0C+8], xmm1
|
||||
}
|
||||
}
|
||||
|
||||
// given the array of matrices, calculates the min/max
|
||||
// of their positions, and puts them into the min and max Vec3d
|
||||
// NOTE: the matrix array must be aligned on 16-byte boundary
|
||||
void getBBoxSSE (const Matrix44* pBones, const CryBBoxA16* pBoneBBox, unsigned numBones, CryAABB* pBBox)
|
||||
{
|
||||
assert (numBones > 0);
|
||||
_asm
|
||||
{
|
||||
mov EBX, pBones
|
||||
movaps xmm0, [EBX+0x30]
|
||||
movaps xmm1, xmm0
|
||||
mov EDX, pBBox
|
||||
add EBX, 0x70 // now EBX points to the next bone matrix
|
||||
mov ECX, numBones
|
||||
dec ECX
|
||||
jz label_End
|
||||
|
||||
label_Start:
|
||||
movaps xmm2, [EBX]
|
||||
minps xmm0, xmm2
|
||||
maxps xmm1, xmm2
|
||||
add EBX, 0x40
|
||||
loop label_Start
|
||||
|
||||
label_End:
|
||||
//SSE_MOVSS(EDX,xmm0)
|
||||
movss [EDX], xmm0
|
||||
shufps xmm0,xmm0, 0xE5
|
||||
movss [EDX+4], xmm0
|
||||
shufps xmm0,xmm0, 0xE6
|
||||
movss [EDX+8], xmm0
|
||||
//SSE_MOVSS(EDX+0x0C,xmm1)
|
||||
movss [EDX+0x0C], xmm1
|
||||
shufps xmm1,xmm1, 0xE5
|
||||
movss [EDX+0x0C+4], xmm1
|
||||
shufps xmm1,xmm1, 0xE6
|
||||
movss [EDX+0x0C+8], xmm1
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// packs the array of Vec3dA16 into Vec3d's
|
||||
// nCount - number of vertices
|
||||
// pData - [IN] Vec3dA16, [OUT] Vec3d
|
||||
void packVec3d16 (void* pData, unsigned nCount)
|
||||
{
|
||||
#if !defined(LINUX) && defined(_CPU_X86)
|
||||
_asm
|
||||
{
|
||||
mov ESI, pData
|
||||
mov EDI, ESI
|
||||
|
||||
add ESI, 0x10
|
||||
add EDI, 0xC
|
||||
|
||||
mov ECX, nCount
|
||||
dec ECX
|
||||
jz endLoop
|
||||
|
||||
startLoop:
|
||||
mov EAX, [ESI]
|
||||
mov [EDI], EAX
|
||||
mov EBX, [ESI+4]
|
||||
mov [EDI+4], EBX
|
||||
mov EDX, [ESI+8]
|
||||
mov [EDI+8], EDX
|
||||
|
||||
add ESI, 0x10
|
||||
add EDI, 0xC
|
||||
loop startLoop
|
||||
endLoop:
|
||||
}
|
||||
#else
|
||||
float* pTo = (float*)pData + 3;
|
||||
float* pFrom = (float*)pData + 4;
|
||||
for (unsigned i = 1; i < nCount; ++i)
|
||||
{
|
||||
pTo[0] = pFrom[0];
|
||||
pTo[1] = pFrom[1];
|
||||
pTo[2] = pFrom[2];
|
||||
pTo += 3;
|
||||
pFrom += 4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !defined(LINUX) && defined(_CPU_X86)
|
||||
__declspec(naked) void PIII_Mult00_4x4_4x4( float *src1, float *src2, float *dst)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov edx, dword ptr [esp+4] ; src1
|
||||
mov eax, dword ptr [esp+0Ch] ; dst
|
||||
mov ecx, dword ptr [esp+8] ; src2
|
||||
movss xmm0, dword ptr [edx]
|
||||
movaps xmm1, xmmword ptr [ecx]
|
||||
shufps xmm0, xmm0, 0
|
||||
movss xmm2, dword ptr [edx+4]
|
||||
mulps xmm0, xmm1
|
||||
shufps xmm2, xmm2, 0
|
||||
movaps xmm3, xmmword ptr [ecx+10h]
|
||||
movss xmm7, dword ptr [edx+8]
|
||||
mulps xmm2, xmm3
|
||||
shufps xmm7, xmm7, 0
|
||||
addps xmm0, xmm2
|
||||
movaps xmm4, xmmword ptr [ecx+20h]
|
||||
movss xmm2, dword ptr [edx+0Ch]
|
||||
mulps xmm7, xmm4
|
||||
shufps xmm2, xmm2, 0
|
||||
addps xmm0, xmm7
|
||||
movaps xmm5, xmmword ptr [ecx+30h]
|
||||
movss xmm6, dword ptr [edx+10h]
|
||||
mulps xmm2, xmm5
|
||||
movss xmm7, dword ptr [edx+14h]
|
||||
shufps xmm6, xmm6, 0
|
||||
addps xmm0, xmm2
|
||||
shufps xmm7, xmm7, 0
|
||||
movlps qword ptr [eax], xmm0
|
||||
movhps qword ptr [eax+8], xmm0
|
||||
mulps xmm7, xmm3
|
||||
movss xmm0, dword ptr [edx+18h]
|
||||
mulps xmm6, xmm1
|
||||
shufps xmm0, xmm0, 0
|
||||
addps xmm6, xmm7
|
||||
mulps xmm0, xmm4
|
||||
movss xmm2, dword ptr [edx+24h]
|
||||
addps xmm6, xmm0
|
||||
movss xmm0, dword ptr [edx+1Ch]
|
||||
movss xmm7, dword ptr [edx+20h]
|
||||
shufps xmm0, xmm0, 0
|
||||
shufps xmm7, xmm7, 0
|
||||
mulps xmm0, xmm5
|
||||
mulps xmm7, xmm1
|
||||
addps xmm6, xmm0
|
||||
shufps xmm2, xmm2, 0
|
||||
movlps qword ptr [eax+10h], xmm6
|
||||
movhps qword ptr [eax+18h], xmm6
|
||||
mulps xmm2, xmm3
|
||||
movss xmm6, dword ptr [edx+28h]
|
||||
addps xmm7, xmm2
|
||||
shufps xmm6, xmm6, 0
|
||||
movss xmm2, dword ptr [edx+2Ch]
|
||||
mulps xmm6, xmm4
|
||||
shufps xmm2, xmm2, 0
|
||||
addps xmm7, xmm6
|
||||
mulps xmm2, xmm5
|
||||
movss xmm0, dword ptr [edx+34h]
|
||||
addps xmm7, xmm2
|
||||
shufps xmm0, xmm0, 0
|
||||
movlps qword ptr [eax+20h], xmm7
|
||||
movss xmm2, dword ptr [edx+30h]
|
||||
movhps qword ptr [eax+28h], xmm7
|
||||
mulps xmm0, xmm3
|
||||
shufps xmm2, xmm2, 0
|
||||
movss xmm6, dword ptr [edx+38h]
|
||||
mulps xmm2, xmm1
|
||||
shufps xmm6, xmm6, 0
|
||||
addps xmm2, xmm0
|
||||
mulps xmm6, xmm4
|
||||
movss xmm7, dword ptr [edx+3Ch]
|
||||
shufps xmm7, xmm7, 0
|
||||
addps xmm2, xmm6
|
||||
mulps xmm7, xmm5
|
||||
addps xmm2, xmm7
|
||||
movaps xmmword ptr [eax+30h], xmm2
|
||||
ret
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void multMatrix(float *product, const float *m1, const float *m2)
|
||||
{
|
||||
#if defined(LINUX) || !defined(_CPU_X86)
|
||||
#define A(row,col) m1[(col<<2)+row]
|
||||
#define B(row,col) m2[(col<<2)+row]
|
||||
#define P(row,col) product[(col<<2)+row]
|
||||
|
||||
int i;
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
float ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3);
|
||||
P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
|
||||
P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
|
||||
P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
|
||||
P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
|
||||
}
|
||||
|
||||
|
||||
#undef A
|
||||
#undef B
|
||||
#undef P
|
||||
|
||||
#else
|
||||
__asm
|
||||
{
|
||||
mov eax, m2;
|
||||
mov ecx, m1;
|
||||
mov edx, product;
|
||||
movss xmm0,dword ptr [eax]
|
||||
movaps xmm1,xmmword ptr [ecx]
|
||||
shufps xmm0,xmm0,0
|
||||
movss xmm2,dword ptr [eax+4]
|
||||
mulps xmm0,xmm1
|
||||
shufps xmm2,xmm2,0
|
||||
movaps xmm3,xmmword ptr [ecx+10h]
|
||||
movss xmm4,dword ptr [eax+8]
|
||||
mulps xmm2,xmm3
|
||||
shufps xmm4,xmm4,0
|
||||
addps xmm0,xmm2
|
||||
movaps xmm2,xmmword ptr [ecx+20h]
|
||||
movss xmm5,dword ptr [eax+0Ch]
|
||||
mulps xmm4,xmm2
|
||||
shufps xmm5,xmm5,0
|
||||
movaps xmm6,xmmword ptr [ecx+30h]
|
||||
mulps xmm5,xmm6
|
||||
addps xmm4,xmm5
|
||||
addps xmm0,xmm4
|
||||
movaps xmmword ptr [edx],xmm0
|
||||
movss xmm0,dword ptr [eax+10h]
|
||||
movss xmm4,dword ptr [eax+14h]
|
||||
shufps xmm0,xmm0,0
|
||||
shufps xmm4,xmm4,0
|
||||
mulps xmm0,xmm1
|
||||
mulps xmm4,xmm3
|
||||
movss xmm5,dword ptr [eax+18h]
|
||||
addps xmm0,xmm4
|
||||
shufps xmm5,xmm5,0
|
||||
movss xmm4,dword ptr [eax+1Ch]
|
||||
mulps xmm5,xmm2
|
||||
shufps xmm4,xmm4,0
|
||||
mulps xmm4,xmm6
|
||||
addps xmm5,xmm4
|
||||
addps xmm0,xmm5
|
||||
movaps xmmword ptr [edx+10h],xmm0
|
||||
movss xmm0,dword ptr [eax+20h]
|
||||
movss xmm4,dword ptr [eax+24h]
|
||||
shufps xmm0,xmm0,0
|
||||
shufps xmm4,xmm4,0
|
||||
mulps xmm0,xmm1
|
||||
mulps xmm4,xmm3
|
||||
movss xmm5,dword ptr [eax+28h]
|
||||
addps xmm0,xmm4
|
||||
shufps xmm5,xmm5,0
|
||||
movss xmm4,dword ptr [eax+2Ch]
|
||||
mulps xmm5,xmm2
|
||||
shufps xmm4,xmm4,0
|
||||
mulps xmm4,xmm6
|
||||
addps xmm5,xmm4
|
||||
addps xmm0,xmm5
|
||||
movaps xmmword ptr [edx+20h],xmm0
|
||||
movss xmm0,dword ptr [eax+30h]
|
||||
movss xmm4,dword ptr [eax+34h]
|
||||
shufps xmm0,xmm0,0
|
||||
shufps xmm4,xmm4,0
|
||||
mulps xmm0,xmm1
|
||||
mulps xmm4,xmm3
|
||||
movss xmm1,dword ptr [eax+38h]
|
||||
addps xmm0,xmm4
|
||||
shufps xmm1,xmm1,0
|
||||
movss xmm3,dword ptr [eax+3Ch]
|
||||
mulps xmm1,xmm2
|
||||
shufps xmm3,xmm3,0
|
||||
mulps xmm3,xmm6
|
||||
addps xmm1,xmm3
|
||||
addps xmm0,xmm1
|
||||
movaps xmmword ptr [edx+30h],xmm0
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
212
ResourceCompilerPC/SSEUtils.h
Normal file
212
ResourceCompilerPC/SSEUtils.h
Normal file
@@ -0,0 +1,212 @@
|
||||
#ifndef _CRY_ANIMATION_SSE_UTILS_HDR_
|
||||
#define _CRY_ANIMATION_SSE_UTILS_HDR_
|
||||
|
||||
#include "MathUtils.h"
|
||||
|
||||
#ifdef _CPU_X86
|
||||
// given the array of matrices, calculates the min/max
|
||||
// of their positions, and puts them into the min and max Vec3d
|
||||
// NOTE: the matrix array must be aligned on 16-byte boundary
|
||||
extern void getBBoxSSE (const Matrix44* pBones, unsigned numBones, CryAABB* pBBox);
|
||||
extern void getBBoxSSE (const Matrix44* pBones, const CryBBoxA16* pBoneBBox, unsigned numBones, CryAABB* pBBox);
|
||||
#endif
|
||||
|
||||
// packs the array of Vec3dA16 into Vec3d's
|
||||
extern void packVec3d16 (void* pData, unsigned nCount);
|
||||
|
||||
namespace cpu
|
||||
{
|
||||
// detects CPU features (SSE) and perhaps sets up some
|
||||
// pointers to functions
|
||||
void detect ();
|
||||
|
||||
// the CPU feature set, as returned by CPUID(1):EDX
|
||||
extern DWORD g_dwFeatures;
|
||||
|
||||
// the extended feature set, as returned by CPUID(0x80000001):EDX
|
||||
extern DWORD g_dwFeaturesEx;
|
||||
|
||||
enum FeaturesEnum
|
||||
{
|
||||
// Floating Point Unit On-Chip. The processor contains an x87 FPU.
|
||||
g_featureFPU = 1,
|
||||
|
||||
// Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including
|
||||
// CR4.VME for controlling the feature, CR4.PVI for protected mode virtual
|
||||
// interrupts, software interrupt indirection, expansion of the TSS with the software
|
||||
// indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags.
|
||||
g_featureVME = 1 << 1,
|
||||
|
||||
|
||||
// Debugging Extensions. Support for I/O breakpoints, including CR4.DE for
|
||||
// controlling the feature, and optional trapping of accesses to DR4 and DR5.
|
||||
g_featureDE = 1 << 2,
|
||||
g_featureDebuggingExtensions = g_featureDE,
|
||||
|
||||
// Page Size Extension. Large pages of size 4Mbyte are supported, including
|
||||
// CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page Directory
|
||||
// Entries), optional reserved bit trapping in CR3, PDEs, and PTEs.
|
||||
g_featurePSE = 1 << 3,
|
||||
|
||||
// Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD
|
||||
// for controlling privilege.
|
||||
g_featureTSC = 1 << 4,
|
||||
|
||||
// Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and
|
||||
// WRMSR instructions are supported. Some of the MSRs are implementation
|
||||
// dependent.
|
||||
g_featureMSR = 1 << 5,
|
||||
|
||||
// PAE Physical Address Extension. Physical addresses greater than 32 bits are
|
||||
// supported: extended page table entry formats, an extra level in the page
|
||||
// translation tables is defined, 2 Mbyte pages are supported instead of 4 Mbyte
|
||||
// pages if PAE bit is 1. The actual number of address bits beyond 32 is not defined,
|
||||
// and is implementation specific.
|
||||
g_featurePAE = 1 << 6,
|
||||
|
||||
// MCE Machine Check Exception. Exception 18 is defined for Machine Checks,
|
||||
// including CR4.MCE for controlling the feature. This feature does not define the
|
||||
// model-specific implementations of machine-check error logging, reporting, and
|
||||
// processor shutdowns. Machine Check exception handlers may have to depend on
|
||||
// processor version to do model specific processing of the exception, or test for the
|
||||
// presence of the Machine Check feature.
|
||||
g_featureMCE = 1 << 7,
|
||||
|
||||
// CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits)
|
||||
// instruction is supported (implicitly locked and atomic).
|
||||
g_featureCX8 = 1 << 8,
|
||||
|
||||
// APIC On-Chip. The processor contains an Advanced Programmable Interrupt
|
||||
// Controller (APIC), responding to memory mapped commands in the physical
|
||||
// address range FFFE0000H to FFFE0FFFH (by default - some processors permit
|
||||
// the APIC to be relocated).
|
||||
g_featureAPIC = 1 << 9,
|
||||
|
||||
// SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and
|
||||
// associated MSRs are supported.
|
||||
g_featureSEP = 1 << 11,
|
||||
|
||||
// Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR
|
||||
// contains feature bits that describe what memory types are supported, how many
|
||||
// variable MTRRs are supported, and whether fixed MTRRs are supported.
|
||||
g_featureMTRR = 1 << 12,
|
||||
|
||||
// PTE Global Bit. The global bit in page directory entries (PDEs) and page table
|
||||
// entries (PTEs) is supported, indicating TLB entries that are common to different
|
||||
// processes and need not be flushed. The CR4.PGE bit controls this feature.
|
||||
g_featurePGE = 1 << 13,
|
||||
|
||||
// Machine Check Architecture. The Machine Check Architecture, which provides
|
||||
// a compatible mechanism for error reporting in P6 family, Pentium 4, and Intel
|
||||
// Xeon processors, and future processors, is supported. The MCG_CAP MSR
|
||||
// contains feature bits describing how many banks of error reporting MSRs are
|
||||
// supported.
|
||||
g_featureMCA = 1 << 14,
|
||||
|
||||
// Conditional Move Instructions. The conditional move instruction CMOV is
|
||||
// supported. In addition, if x87 FPU is present as indicated by the CPUID.FPU
|
||||
// feature bit, then the FCOMI and FCMOV instructions are supported
|
||||
g_featureCMOV = 1 << 15,
|
||||
|
||||
//Page Attribute Table. Page Attribute Table is supported. This feature augments
|
||||
//the Memory Type Range Registers (MTRRs), allowing an operating system to
|
||||
//specify attributes of memory on a 4K granularity through a linear address.
|
||||
g_featurePAT = 1 << 16,
|
||||
|
||||
//32-Bit Page Size Extension. Extended 4-MByte pages that are capable of
|
||||
//addressing physical memory beyond 4 GBytes are supported. This feature
|
||||
//indicates that the upper four bits of the physical address of the 4-MByte page is
|
||||
//encoded by bits 13-16 of the page directory entry.
|
||||
g_featurePSE36 = 1 << 17,
|
||||
|
||||
// PSN Processor Serial Number. The processor supports the 96-bit processor
|
||||
// identification number feature and the feature is enabled.
|
||||
g_featurePSN = 1 << 18,
|
||||
|
||||
// CLFLUSH Instruction. CLFLUSH Instruction is supported.
|
||||
g_featureCLFSH = 1 << 19,
|
||||
|
||||
// Reserved
|
||||
g_featureReserved = 1 << 20,
|
||||
|
||||
// DS Debug Store. The processor supports the ability to write debug information into a
|
||||
// memory resident buffer. This feature is used by the branch trace store (BTS) and
|
||||
// precise event-based sampling (PEBS) facilities (see Chapter 15, Debugging and
|
||||
// Performance Monitoring, in the IA-32 Intel Architecture Software Developer<65>s
|
||||
// Manual, Volume 3).
|
||||
g_featureDS = 1 << 21,
|
||||
|
||||
// Thermal Monitor and Software Controlled Clock Facilities. The processor
|
||||
// implements internal MSRs that allow processor temperature to be monitored and
|
||||
// processor performance to be modulated in predefined duty cycles under software
|
||||
// control.
|
||||
g_featureACPI = 1 << 22,
|
||||
|
||||
// Intel MMX Technology. The processor supports the Intel MMX technology.
|
||||
g_featureMMX = 1 << 23,
|
||||
|
||||
// FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions
|
||||
// are supported for fast save and restore of the floating point context. Presence of
|
||||
// this bit also indicates that CR4.OSFXSR is available for an operating system to
|
||||
// indicate that it supports the FXSAVE and FXRSTOR instructions
|
||||
g_featureFXSR = 1 << 24,
|
||||
|
||||
// SSE. The processor supports the SSE extensions.
|
||||
g_featureSSE = 1 << 25,
|
||||
|
||||
// SSE2. The processor supports the SSE2 extensions.
|
||||
g_featureSSE2 = 1 << 26,
|
||||
|
||||
// Self Snoop. The processor supports the management of conflicting memory
|
||||
// types by performing a snoop of its own cache structure for transactions issued to
|
||||
// the bus
|
||||
g_featureSS = 1 << 27,
|
||||
|
||||
// Hyper-Threading Technology. The processor implements Hyper-Threading
|
||||
// Technology.
|
||||
g_featureHTT = 1 << 28,
|
||||
|
||||
// TM Thermal Monitor. The processor implements the thermal monitor automatic
|
||||
// thermal control circuitry (TCC).
|
||||
g_featureTM = 1 << 29,
|
||||
|
||||
// Reserved
|
||||
g_featureReserved30 = 1 << 30,
|
||||
|
||||
// PBE Pending Break Enable. The processor supports the use of the FERR#/PBE# pin
|
||||
// when the processor is in the stop-clock state (STPCLK# is asserted) to signal the
|
||||
// processor that an interrupt is pending and that the processor should return to
|
||||
// normal operation to handle the interrupt. Bit 10 (PBE enable) in the
|
||||
// IA32_MISC_ENABLE MSR enables this capability.
|
||||
g_featurePBE = 1 << 31,
|
||||
|
||||
// this is 3D Now! instruction set bit
|
||||
g_featureEx3DNow = 0x80000000
|
||||
};
|
||||
|
||||
inline int hasSSE()
|
||||
{
|
||||
#ifdef _AMD64_
|
||||
return g_featureSSE;
|
||||
#else
|
||||
return (g_dwFeatures & g_featureSSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// does the machine have the RDTSC instruction?
|
||||
inline int hasRDTSC()
|
||||
{
|
||||
return (g_dwFeatures & g_featureTSC);
|
||||
}
|
||||
|
||||
// does the machine have 3D Now instruction set support?
|
||||
inline int has3DNow()
|
||||
{
|
||||
return (g_dwFeaturesEx & g_featureEx3DNow);
|
||||
}
|
||||
|
||||
extern void logCaps();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
124
ResourceCompilerPC/SkinDataSources.cpp
Normal file
124
ResourceCompilerPC/SkinDataSources.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "stdafx.h"
|
||||
#include "RenderMeshBuilder.h"
|
||||
#include "SkinDataSources.h"
|
||||
#include "CryBoneDesc.h"
|
||||
|
||||
// helper to get order for Vec3d
|
||||
struct CVec3dOrder: public std::binary_function< Vec3d, Vec3d, bool>
|
||||
{
|
||||
bool operator() ( const Vec3d &a, const Vec3d &b ) const
|
||||
{
|
||||
// first sort by x
|
||||
if(a.x<b.x)return(true);
|
||||
if(a.x>b.x)return(false);
|
||||
|
||||
// then by y
|
||||
if(a.y<b.y)return(true);
|
||||
if(a.y>b.y)return(false);
|
||||
|
||||
// then by z
|
||||
if(a.z<b.z)return(true);
|
||||
if(a.z>b.z)return(false);
|
||||
|
||||
return(false);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<Vec3d,unsigned,CVec3dOrder> VertexWelderMap;
|
||||
|
||||
|
||||
CRCSkinVertexSource::CRCSkinVertexSource (const CRenderMeshBuilder& rRendMesh, const CryChunkedFile::MeshDesc& rMeshDesc, Matrix44* pBones):
|
||||
ICrySkinSource(
|
||||
&rMeshDesc.arrVertBinds[0],
|
||||
rMeshDesc.arrVertBinds.size(),
|
||||
NULL, // m_pVertices
|
||||
0, // m_numVertices
|
||||
&rRendMesh.m_arrExtTangents[0],
|
||||
rRendMesh.m_arrExtTangents.size(),
|
||||
NULL // m_pExtToIntMapping
|
||||
)
|
||||
{
|
||||
// to get the vertices, we'll have to build the temp buffer holding unique vertices
|
||||
// this maps the vertex coordinates to the vertex index in the new buffer
|
||||
//VertexWelderMap mapVertices;
|
||||
|
||||
m_arrVerts.resize (rMeshDesc.numVertices());
|
||||
m_pVertices = &m_arrVerts[0];
|
||||
m_numVertices = m_arrVerts.size();
|
||||
|
||||
// skin the
|
||||
for (unsigned nVertex = 0; nVertex < rMeshDesc.numVertices(); ++nVertex)
|
||||
{
|
||||
Vec3d & p = m_arrVerts[nVertex];
|
||||
const CryVertexBinding& arrLinks = rMeshDesc.arrVertBinds[nVertex];
|
||||
|
||||
if (pBones && !arrLinks.empty())
|
||||
{
|
||||
p.x = p.y = p.z = 0;
|
||||
|
||||
for (CryVertexBinding::const_iterator itLink = arrLinks.begin(); itLink != arrLinks.end(); ++itLink)
|
||||
{
|
||||
Matrix44& matBoneGlobal = pBones[itLink->BoneID];
|
||||
p += matBoneGlobal.TransformPointOLD(itLink->offset) * itLink->Blending;
|
||||
}
|
||||
}
|
||||
else
|
||||
p = rMeshDesc.pVertices[nVertex].p;
|
||||
}
|
||||
|
||||
m_arrExtToIntMap.resize (rRendMesh.m_arrExtTangMap.size());
|
||||
unsigned i;
|
||||
for (i = 0; i < rRendMesh.m_arrExtTangMap.size(); ++i)
|
||||
m_arrExtToIntMap[i] = rRendMesh.m_arrExtTangMap[i];
|
||||
m_pExtToIntMapping = &m_arrExtToIntMap[0];
|
||||
}
|
||||
|
||||
CRCSkinVertexSource::~CRCSkinVertexSource ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
CRCSkinNormalSource::CRCSkinNormalSource (const CRenderMeshBuilder& rRendMesh, const CryChunkedFile::MeshDesc& rMeshDesc, const std::vector<CryBoneDesc>& arrBones):
|
||||
ICrySkinSource(
|
||||
NULL, // m_pLinks {&rMeshDesc.arrVertBinds[0]}
|
||||
0,// m_numLinks {rMeshDesc.arrVertBinds.size()}
|
||||
NULL, // m_pVertices
|
||||
0, // m_numVertices
|
||||
&rRendMesh.m_arrExtTangents[0],
|
||||
rRendMesh.m_arrExtTangents.size(),
|
||||
NULL // m_pExtToIntMapping
|
||||
)
|
||||
{
|
||||
// to get the vertices, we'll have to build the temp buffer holding unique vertices
|
||||
// this maps the vertex coordinates to the vertex index in the new buffer
|
||||
//VertexWelderMap mapVertices;
|
||||
|
||||
m_arrNormals.resize (rMeshDesc.numVertices());
|
||||
for (unsigned nVertex = 0; nVertex < rMeshDesc.numVertices(); ++nVertex)
|
||||
m_arrNormals[nVertex] = rMeshDesc.pVertices[nVertex].n;
|
||||
|
||||
m_pVertices = &m_arrNormals[0];
|
||||
m_numVertices = m_arrNormals.size();
|
||||
m_arrExtToIntMap.resize (rRendMesh.m_arrExtTangMap.size());
|
||||
unsigned i;
|
||||
for (i = 0; i < rRendMesh.m_arrExtTangMap.size(); ++i)
|
||||
m_arrExtToIntMap[i] = rRendMesh.m_arrExtTangMap[i];
|
||||
m_pExtToIntMapping = &m_arrExtToIntMap[0];
|
||||
|
||||
m_numLinks = rMeshDesc.arrVertBinds.size();
|
||||
m_arrLinks.resize (m_numLinks);
|
||||
for (unsigned i = 0; i < m_numVertices; ++i)
|
||||
{
|
||||
m_arrLinks[i].resize (1);
|
||||
unsigned nBone = m_arrLinks[i][0].BoneID = rMeshDesc.arrVertBinds[i][0].BoneID;
|
||||
m_arrLinks[i][0].Blending = 1;//getLink(0)[0].Blending;
|
||||
m_arrLinks[i][0].offset = arrBones[nBone].getInvDefGlobal().TransformVectorOLD(rMeshDesc.arrNormals[i]);
|
||||
}
|
||||
|
||||
m_pLinks = &m_arrLinks[0];
|
||||
}
|
||||
|
||||
CRCSkinNormalSource::~CRCSkinNormalSource()
|
||||
{
|
||||
}
|
||||
35
ResourceCompilerPC/SkinDataSources.h
Normal file
35
ResourceCompilerPC/SkinDataSources.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// These are the classes that supply information to the CrySkin builders
|
||||
#ifndef _SKIN_DATA_SOURCES_HDR_
|
||||
#define _SKIN_DATA_SOURCES_HDR_
|
||||
|
||||
#include "CryChunkedFile.h"
|
||||
#include "CrySkinBuilderBase.h"
|
||||
|
||||
class CRCSkinNormalSource: public ICrySkinSource
|
||||
{
|
||||
public:
|
||||
CRCSkinNormalSource (const class CRenderMeshBuilder& rRendMesh, const CryChunkedFile::MeshDesc& rMeshDesc, const std::vector<CryBoneDesc>& arrBones);
|
||||
~CRCSkinNormalSource ();
|
||||
|
||||
protected:
|
||||
std::vector<Vec3d> m_arrNormals;
|
||||
std::vector<unsigned> m_arrExtToIntMap;
|
||||
std::vector<CryVertexBinding> m_arrLinks;
|
||||
};
|
||||
|
||||
|
||||
class CRCSkinVertexSource: public ICrySkinSource
|
||||
{
|
||||
public:
|
||||
// constructs the vertex source recomputing the actual vertex coordinates with the bones given if any
|
||||
CRCSkinVertexSource (const class CRenderMeshBuilder& rRendMesh, const CryChunkedFile::MeshDesc& rMeshDesc, Matrix44* pBones = NULL);
|
||||
~CRCSkinVertexSource ();
|
||||
|
||||
protected:
|
||||
// the vertex buffer - initial pose, no duplicated vertices
|
||||
std::vector<Vec3d> m_arrVerts;
|
||||
std::vector<unsigned> m_arrExtToIntMap;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
42
ResourceCompilerPC/StatCGFCompiler/BaseObj.h
Normal file
42
ResourceCompilerPC/StatCGFCompiler/BaseObj.h
Normal file
@@ -0,0 +1,42 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: baseobj.h
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_BASEOBJ_H__2D817DB5_34FA_4C73_8588_867E88C9CFB3__INCLUDED_)
|
||||
#define AFX_BASEOBJ_H__2D817DB5_34FA_4C73_8588_867E88C9CFB3__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
class CBaseObj
|
||||
{
|
||||
public:
|
||||
CHUNK_HEADER m_ChunkHeader;
|
||||
bool m_bBinded;
|
||||
int m_nUsers;
|
||||
|
||||
CBaseObj()
|
||||
{
|
||||
memset(&m_ChunkHeader,0,sizeof(m_ChunkHeader));
|
||||
m_bBinded = false;
|
||||
m_nUsers = 0;
|
||||
}
|
||||
|
||||
virtual ~CBaseObj(){};
|
||||
virtual bool Load(class CXFile *f, int pos) { return false; }
|
||||
virtual void Bind(CBaseObj **all_objects, int n_obj){}
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_BASEOBJ_H__2D817DB5_34FA_4C73_8588_867E88C9CFB3__INCLUDED_)
|
||||
498
ResourceCompilerPC/StatCGFCompiler/CryStaticModel.cpp
Normal file
498
ResourceCompilerPC/StatCGFCompiler/CryStaticModel.cpp
Normal file
@@ -0,0 +1,498 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: crystaticmodel.cpp
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: load cgf file
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "CryStaticModel.h"
|
||||
|
||||
#include "baseobj.h"
|
||||
#include "node.h"
|
||||
#include "geom.h"
|
||||
#include "helper.h"
|
||||
#include "light.h"
|
||||
|
||||
#include "file.h"
|
||||
#include "IRCLog.h"
|
||||
|
||||
CryStaticModel::CryStaticModel()
|
||||
{
|
||||
memset( this,0,sizeof(*this) );
|
||||
}
|
||||
|
||||
CryStaticModel::~CryStaticModel()
|
||||
{
|
||||
for( int i=0; i<m_nNewObjs; i++)
|
||||
{
|
||||
CNodeCGF * pNode = (CNodeCGF*)m_ppNewObjs[i];
|
||||
delete pNode;
|
||||
}
|
||||
|
||||
if(m_ppNewObjs)
|
||||
free(m_ppNewObjs);
|
||||
m_ppNewObjs=0;
|
||||
}
|
||||
|
||||
void CryStaticModel::LoadMaterials(CXFile*f, int pos)
|
||||
{
|
||||
if(f->FSeek(pos,SEEK_SET))
|
||||
return;
|
||||
|
||||
CHUNK_HEADER ch;
|
||||
int res = f->FRead(&ch,1,sizeof(ch));
|
||||
if (ch.ChunkVersion == MTL_CHUNK_DESC_0746::VERSION)
|
||||
{
|
||||
f->FSeek(pos,SEEK_SET);
|
||||
MTL_CHUNK_DESC_0746 chunk;
|
||||
int res=f->FRead(&chunk,1,sizeof(chunk));
|
||||
if(res!=sizeof(chunk))
|
||||
return;
|
||||
|
||||
MAT_ENTITY me;
|
||||
memset(&me, 0, sizeof(MAT_ENTITY));
|
||||
me.opacity = 1.0f;
|
||||
me.alpharef = 0;
|
||||
me.m_New = 2;
|
||||
strcpy(me.name, chunk.name);
|
||||
switch (chunk.MtlType)
|
||||
{
|
||||
case MTL_STANDARD:
|
||||
me.IsStdMat = true;
|
||||
me.col_d = chunk.col_d;
|
||||
me.col_a = chunk.col_a;
|
||||
me.col_s = chunk.col_s;
|
||||
|
||||
me.specLevel = chunk.specLevel;
|
||||
me.specShininess = chunk.specShininess*100;
|
||||
me.opacity = chunk.opacity;
|
||||
me.selfIllum = chunk.selfIllum;
|
||||
me.flags = chunk.flags;
|
||||
if (me.flags & MTLFLAG_CRYSHADER)
|
||||
me.alpharef = chunk.alphaTest;
|
||||
|
||||
me.Dyn_Bounce = chunk.Dyn_Bounce;
|
||||
me.Dyn_StaticFriction = chunk.Dyn_StaticFriction;
|
||||
me.Dyn_SlidingFriction = chunk.Dyn_SlidingFriction;
|
||||
/* //Timur[10/24/2001]
|
||||
strcpy(me.map_a, chunk.tex_a.name);
|
||||
strcpy(me.map_d, chunk.tex_d.name);
|
||||
strcpy(me.map_o, chunk.tex_o.name);
|
||||
strcpy(me.map_b, chunk.tex_b.name);
|
||||
strcpy(me.map_s, chunk.tex_s.name);
|
||||
strcpy(me.map_g, chunk.tex_g.name);
|
||||
strcpy(me.map_c, chunk.tex_c.name);
|
||||
strcpy(me.map_e, chunk.tex_rl.name);
|
||||
strcpy(me.map_rr, chunk.tex_rr.name);
|
||||
strcpy(me.map_det, chunk.tex_det.name);
|
||||
*/
|
||||
me.map_a = chunk.tex_a;
|
||||
me.map_d = chunk.tex_d;
|
||||
me.map_o = chunk.tex_o;
|
||||
me.map_b = chunk.tex_b;
|
||||
me.map_s = chunk.tex_s;
|
||||
me.map_g = chunk.tex_g;
|
||||
me.map_detail = chunk.tex_fl;
|
||||
me.map_e = chunk.tex_rl;
|
||||
me.map_subsurf = chunk.tex_subsurf;
|
||||
me.map_displ = chunk.tex_det;
|
||||
|
||||
me.nChildren = chunk.nChildren;
|
||||
|
||||
m_lstMaterials.Add(me);
|
||||
break;
|
||||
|
||||
/* case MTL_MULTI:
|
||||
me.IsStdMat = 0;
|
||||
me.nChildren = chunk.nChildren;
|
||||
me.children = new int [chunk.nChildren];
|
||||
int res=f->FRead(me.children,sizeof(int),chunk.nChildren);
|
||||
if (res != chunk.nChildren)
|
||||
return;*/
|
||||
}
|
||||
}
|
||||
else
|
||||
if (ch.ChunkVersion == MTL_CHUNK_DESC_0745::VERSION)
|
||||
{
|
||||
f->FSeek(pos,SEEK_SET);
|
||||
MTL_CHUNK_DESC_0745 chunk;
|
||||
int res=f->FRead(&chunk,1,sizeof(chunk));
|
||||
if(res!=sizeof(chunk))
|
||||
return;
|
||||
|
||||
MAT_ENTITY me;
|
||||
memset(&me, 0, sizeof(MAT_ENTITY));
|
||||
me.opacity = 1.0f;
|
||||
me.alpharef = 0;
|
||||
me.m_New = 1;
|
||||
strcpy(me.name, chunk.name);
|
||||
switch (chunk.MtlType)
|
||||
{
|
||||
case MTL_STANDARD:
|
||||
me.IsStdMat = true;
|
||||
me.col_d = chunk.col_d;
|
||||
me.col_a = chunk.col_a;
|
||||
me.col_s = chunk.col_s;
|
||||
|
||||
me.specLevel = chunk.specLevel;
|
||||
me.specShininess = chunk.specShininess*100;
|
||||
me.opacity = chunk.opacity;
|
||||
me.selfIllum = chunk.selfIllum;
|
||||
me.flags = chunk.flags;
|
||||
|
||||
me.Dyn_Bounce = chunk.Dyn_Bounce;
|
||||
me.Dyn_StaticFriction = chunk.Dyn_StaticFriction;
|
||||
me.Dyn_SlidingFriction = chunk.Dyn_SlidingFriction;
|
||||
/* //Timur[10/24/2001]
|
||||
strcpy(me.map_a, chunk.tex_a.name);
|
||||
strcpy(me.map_d, chunk.tex_d.name);
|
||||
strcpy(me.map_o, chunk.tex_o.name);
|
||||
strcpy(me.map_b, chunk.tex_b.name);
|
||||
strcpy(me.map_s, chunk.tex_s.name);
|
||||
strcpy(me.map_g, chunk.tex_g.name);
|
||||
strcpy(me.map_c, chunk.tex_c.name);
|
||||
strcpy(me.map_e, chunk.tex_rl.name);
|
||||
strcpy(me.map_rr, chunk.tex_rr.name);
|
||||
strcpy(me.map_det, chunk.tex_det.name);
|
||||
*/
|
||||
me.map_a = chunk.tex_a;
|
||||
me.map_d = chunk.tex_d;
|
||||
me.map_o = chunk.tex_o;
|
||||
me.map_b = chunk.tex_b;
|
||||
me.map_s = chunk.tex_s;
|
||||
me.map_g = chunk.tex_g;
|
||||
me.map_detail = chunk.tex_c;
|
||||
me.map_e = chunk.tex_rl;
|
||||
me.map_subsurf = chunk.tex_subsurf;
|
||||
me.map_displ = chunk.tex_det;
|
||||
|
||||
me.nChildren = chunk.nChildren;
|
||||
|
||||
m_lstMaterials.Add(me);
|
||||
break;
|
||||
|
||||
/* case MTL_MULTI:
|
||||
me.IsStdMat = 0;
|
||||
me.nChildren = chunk.nChildren;
|
||||
me.children = new int [chunk.nChildren];
|
||||
int res=f->FRead(me.children,sizeof(int),chunk.nChildren);
|
||||
if (res != chunk.nChildren)
|
||||
return;*/
|
||||
}
|
||||
}
|
||||
else
|
||||
if (ch.ChunkVersion == MTL_CHUNK_DESC_0744::VERSION)
|
||||
{
|
||||
f->FSeek(pos,SEEK_SET);
|
||||
MTL_CHUNK_DESC_0744 chunk;
|
||||
int res=f->FRead(&chunk,1,sizeof(chunk));
|
||||
if(res!=sizeof(chunk))
|
||||
return;
|
||||
|
||||
MAT_ENTITY me;
|
||||
memset(&me, 0, sizeof(MAT_ENTITY));
|
||||
me.opacity = 1.0f;
|
||||
me.alpharef = 0;
|
||||
strcpy(me.name, chunk.name);
|
||||
switch (chunk.MtlType)
|
||||
{
|
||||
case MTL_STANDARD:
|
||||
me.IsStdMat = true;
|
||||
me.col_d = chunk.col_d;
|
||||
me.col_a = chunk.col_a;
|
||||
me.col_s = chunk.col_s;
|
||||
me.Dyn_Bounce = chunk.Dyn_Bounce;
|
||||
me.Dyn_StaticFriction = chunk.Dyn_StaticFriction;
|
||||
me.Dyn_SlidingFriction = chunk.Dyn_SlidingFriction;
|
||||
strcpy(me.map_d.name, chunk.tex_d.name);
|
||||
strcpy(me.map_o.name, chunk.tex_o.name);
|
||||
strcpy(me.map_b.name, chunk.tex_b.name);
|
||||
me.nChildren = chunk.nChildren;
|
||||
|
||||
m_lstMaterials.Add(me);
|
||||
break;
|
||||
|
||||
case MTL_MULTI:
|
||||
me.IsStdMat = 0;
|
||||
me.nChildren = chunk.nChildren;
|
||||
me.m_pMaterialChildren = new int [chunk.nChildren];//leak
|
||||
int res=f->FRead(me.m_pMaterialChildren,sizeof(int),chunk.nChildren);
|
||||
if (res != chunk.nChildren)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CryStaticModel::OnLoadgeom(char * FileName, const char * szGeomName, bool bLoadMats, bool bKeepInLocalSpace)
|
||||
{
|
||||
CXFile * f = new CXFile();
|
||||
|
||||
// preload all data
|
||||
if(!f->FLoad(FileName))
|
||||
{
|
||||
delete f; return 0;
|
||||
}
|
||||
|
||||
//read the file header
|
||||
FILE_HEADER fh;
|
||||
int res = f->FRead(&fh,sizeof(fh),1);
|
||||
if(res!=1)
|
||||
return 0;
|
||||
|
||||
if(fh.Version != GeomFileVersion)
|
||||
{
|
||||
f->FClose(); delete f; f=0;
|
||||
m_pLog->LogError("CryStaticModel::OnLoadgeom: CGF file version error: %s", FileName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(fh.FileType != FileType_Geom)
|
||||
{
|
||||
f->FClose(); delete f; f=0;
|
||||
m_pLog->LogError("OnLoadgeom: CGF file type error: %s", FileName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//read the chunk table
|
||||
f->FSeek(fh.ChunkTableOffset,SEEK_SET);
|
||||
int n_chunks=100000;
|
||||
res = f->FRead(&n_chunks,sizeof(n_chunks),1);
|
||||
if(res!=1)
|
||||
return 0;
|
||||
|
||||
if(n_chunks>=100000)
|
||||
{
|
||||
f->FClose(); delete f; f=0;
|
||||
m_pLog->LogError("CryStaticModel::OnLoadgeom: File corrupted: %s, (n_chunks>=100000)", FileName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CHUNK_HEADER * pChunks;
|
||||
pChunks=(CHUNK_HEADER *)malloc(sizeof(CHUNK_HEADER)*n_chunks);
|
||||
assert(pChunks);
|
||||
res = f->FRead(pChunks,sizeof(CHUNK_HEADER),n_chunks);
|
||||
if(res!=n_chunks)
|
||||
return 0;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Create and load objects
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
m_ppNewObjs = (CBaseObj **)malloc(n_chunks*sizeof(CBaseObj*));
|
||||
memset(m_ppNewObjs,0,n_chunks*sizeof(CBaseObj*));
|
||||
|
||||
assert(m_ppNewObjs);
|
||||
m_nNewObjs=0;
|
||||
|
||||
int nGeomToLoadID = -1;
|
||||
|
||||
int i;
|
||||
for(i=0;i<n_chunks;i++)
|
||||
{
|
||||
switch(pChunks[i].ChunkType)
|
||||
{
|
||||
case ChunkType_Node:
|
||||
m_ppNewObjs[m_nNewObjs]=new CNodeCGF();
|
||||
break;
|
||||
|
||||
case ChunkType_Mesh:
|
||||
if(!szGeomName || nGeomToLoadID == i)
|
||||
m_ppNewObjs[m_nNewObjs]=new CGeom();
|
||||
break;
|
||||
|
||||
case ChunkType_Helper:
|
||||
m_ppNewObjs[m_nNewObjs]=new CHelper();
|
||||
break;
|
||||
|
||||
case ChunkType_Light:
|
||||
m_ppNewObjs[m_nNewObjs]=new CLight();
|
||||
break;
|
||||
|
||||
case ChunkType_Mtl:
|
||||
if(bLoadMats)
|
||||
LoadMaterials(f,pChunks[i].FileOffset);
|
||||
break;
|
||||
}
|
||||
|
||||
if(m_ppNewObjs[m_nNewObjs])
|
||||
{
|
||||
m_ppNewObjs[m_nNewObjs]->Load(f,pChunks[i].FileOffset);
|
||||
|
||||
// find chunk id of needed geom
|
||||
if(pChunks[i].ChunkType == ChunkType_Node)
|
||||
if(szGeomName && strcmp(szGeomName,((CNodeCGF*)m_ppNewObjs[m_nNewObjs])->m_Chunk.name)==0)
|
||||
nGeomToLoadID = ((CNodeCGF*)m_ppNewObjs[m_nNewObjs])->m_Chunk.ObjectID;
|
||||
|
||||
m_nNewObjs++;
|
||||
}
|
||||
}
|
||||
|
||||
//Do pointer and name list bindings
|
||||
for(i=0;i<m_nNewObjs;i++)
|
||||
{
|
||||
if(!m_ppNewObjs[i])
|
||||
continue;
|
||||
m_ppNewObjs[i]->Bind(m_ppNewObjs, m_nNewObjs);
|
||||
}
|
||||
|
||||
f->FClose(); delete f; f=0;
|
||||
|
||||
if(pChunks)
|
||||
free(pChunks);
|
||||
pChunks=0;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Make objects
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
list2<NAME_ENTITY> lstOtherNames;
|
||||
|
||||
for( i=0; i<m_nNewObjs; i++)
|
||||
{
|
||||
CNodeCGF * pNode = (CNodeCGF*)m_ppNewObjs[i];
|
||||
|
||||
if(pNode->m_ChunkHeader.ChunkType != ChunkType_Node)
|
||||
continue;
|
||||
|
||||
// make list of mesh names
|
||||
NAME_ENTITY geomname;
|
||||
strcpy(geomname.name, pNode->m_Chunk.name);
|
||||
lstOtherNames.Add(geomname);
|
||||
|
||||
if(!pNode->m_pObj)
|
||||
continue;
|
||||
|
||||
if(pNode->m_pObj->m_nUsers>1)
|
||||
m_pLog->Log("WARNING: loading of instances from cgf not supported, geom skipped: %s, %s",FileName, pNode->GetName());
|
||||
|
||||
// Accumulate this and all parent nodes transformations
|
||||
// TODO: get rid of the obsolete CryMatrix here
|
||||
|
||||
//CHANGED_BY_IVO
|
||||
//CryMatrix matNodeMatrix = pNode->m_Chunk.tm;
|
||||
Matrix44 matNodeMatrix = pNode->m_Chunk.tm;
|
||||
|
||||
for(CNodeCGF * pCurNode = pNode->m_pParent; pCurNode; pCurNode = pCurNode->m_pParent)
|
||||
//CHANGED_BY_IVO
|
||||
//matNodeMatrix = matNodeMatrix * (CryMatrix&)(pCurNode->m_Chunk.tm);
|
||||
matNodeMatrix = matNodeMatrix * (pCurNode->m_Chunk.tm);
|
||||
|
||||
if(pNode->m_pObj->m_ChunkHeader.ChunkType == ChunkType_Mesh)
|
||||
if(pNode->m_pObj->m_nUsers<=1)
|
||||
{ // geoms
|
||||
// make list of mesh names
|
||||
NAME_ENTITY geomname;
|
||||
strcpy(geomname.name, pNode->m_Chunk.name);
|
||||
m_lstGeomNames.Add(geomname);
|
||||
lstOtherNames.DeleteLast();
|
||||
|
||||
CGeom * pGeom = (CGeom*)pNode->m_pObj;
|
||||
|
||||
// transform geometry from this node space into CGFs space
|
||||
if(!bKeepInLocalSpace)
|
||||
for(int v=0; v<pGeom->m_Chunk.nVerts; v++)
|
||||
{
|
||||
//CHANGED_BY_IVO
|
||||
//pGeom->m_pVertices[v].p = matNodeMatrix*pGeom->m_pVertices[v].p;
|
||||
//pGeom->m_pVertices[v].n = matNodeMatrix/pGeom->m_pVertices[v].n;
|
||||
pGeom->m_pVertices[v].p = matNodeMatrix.TransformPointOLD(pGeom->m_pVertices[v].p);
|
||||
pGeom->m_pVertices[v].n = matNodeMatrix.TransformVectorOLD(pGeom->m_pVertices[v].n);
|
||||
}
|
||||
|
||||
if(!szGeomName || strcmp(pNode->GetName(),szGeomName)==0)
|
||||
m_lstGeoms.Add(pGeom);
|
||||
}
|
||||
|
||||
if(pNode->m_pObj->m_ChunkHeader.ChunkType == ChunkType_Light)
|
||||
{ // make light
|
||||
CLight * pLight = (CLight*)pNode->m_pObj;
|
||||
|
||||
LightInstance inst;
|
||||
memcpy(&inst.Chunk,&pLight->m_Chunk,sizeof(LIGHT_CHUNK_DESC));
|
||||
inst.Chunk = pLight->m_Chunk;
|
||||
|
||||
if(bKeepInLocalSpace)
|
||||
|
||||
//inst.vPos.Set(&pNode->m_Chunk.pos.x);
|
||||
inst.vPos.Set(pNode->m_Chunk.pos[0],pNode->m_Chunk.pos[1],pNode->m_Chunk.pos[2]);
|
||||
|
||||
else
|
||||
//CHANGED_BY_IVO
|
||||
//inst.vPos = Vec3d(matNodeMatrix.data[3]);
|
||||
inst.vPos = matNodeMatrix.GetTranslationOLD();
|
||||
|
||||
if(!pNode->m_pParent)
|
||||
assert( IsEquivalent(pNode->m_Chunk.pos,inst.vPos,VEC_EPSILON) );
|
||||
|
||||
strncpy(inst.szName,pNode->m_Chunk.name, sizeof(inst.szName));
|
||||
|
||||
// load proj texture
|
||||
if(inst.Chunk.szLightImage[0])
|
||||
{
|
||||
assert(0);
|
||||
inst.pLightImage = 0;//GetRenderer()->EF_LoadTexture(inst.Chunk.szLightImage, FT_CLAMP, FT2_FORCECUBEMAP, eTT_Cubemap);
|
||||
if (!inst.pLightImage->IsTextureLoaded())
|
||||
inst.pLightImage = NULL;
|
||||
}
|
||||
else
|
||||
inst.pLightImage = NULL;
|
||||
|
||||
m_lstLights.Add(inst);
|
||||
}
|
||||
|
||||
if(pNode->m_pObj->m_ChunkHeader.ChunkType == ChunkType_Helper)
|
||||
{ // make helper
|
||||
CHelper * pHelper = (CHelper*)pNode->m_pObj;
|
||||
|
||||
HelperInstance inst;
|
||||
inst.Chunk = pHelper->m_Chunk;
|
||||
|
||||
if(bKeepInLocalSpace)
|
||||
inst.tMat.SetIdentity();
|
||||
else
|
||||
//CHANGED_BY_IVO
|
||||
//inst.tMat = Matrix(matNodeMatrix.matrix);
|
||||
inst.tMat = matNodeMatrix;
|
||||
|
||||
/*
|
||||
if(!pNode->m_pParent)
|
||||
{
|
||||
assert(inst.vPos == pNode->m_Chunk.pos);
|
||||
float dot = inst.qRot.Dot(pNode->m_Chunk.rot);
|
||||
dot=dot;
|
||||
}
|
||||
*/
|
||||
strncpy(inst.szName,pNode->m_Chunk.name, sizeof(inst.szName));
|
||||
m_lstHelpers.Add(inst);
|
||||
}
|
||||
}
|
||||
|
||||
m_lstGeomNames.AddList (lstOtherNames);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
CHelperInstance * CryStaticModel::GetHelper(const char * name)
|
||||
{
|
||||
for(int i=0; i<m_Helpers.Count(); i++)
|
||||
{
|
||||
if(!strcmp(m_Helpers[i].name,name))
|
||||
return &m_Helpers[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
// this timer measures the time spent in the CGF Loader
|
||||
//double g_dTimeLoadCGF;
|
||||
69
ResourceCompilerPC/StatCGFCompiler/CryStaticModel.h
Normal file
69
ResourceCompilerPC/StatCGFCompiler/CryStaticModel.h
Normal file
@@ -0,0 +1,69 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: crystaticmodel.h
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: cgf file loader
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef CryStaticModel_H
|
||||
#define CryStaticModel_H
|
||||
|
||||
class CBaseObj;
|
||||
class CGeom;
|
||||
|
||||
#include "list2.h"
|
||||
|
||||
struct LightInstance
|
||||
{
|
||||
LIGHT_CHUNK_DESC Chunk;
|
||||
Vec3d vPos;
|
||||
char szName[64];
|
||||
struct ITexPic * pLightImage;
|
||||
};
|
||||
|
||||
struct HelperInstance
|
||||
{
|
||||
HELPER_CHUNK_DESC Chunk;
|
||||
char szName[64];
|
||||
Matrix44 tMat;
|
||||
};
|
||||
|
||||
class CXFile;
|
||||
|
||||
struct CryStaticModel
|
||||
{
|
||||
CryStaticModel();
|
||||
~CryStaticModel();
|
||||
|
||||
char m_FileName[256];
|
||||
|
||||
list2<CGeom*> m_lstGeoms;
|
||||
list2<MAT_ENTITY> m_lstMaterials;
|
||||
list2<NAME_ENTITY> m_lstGeomNames;
|
||||
list2<LightInstance> m_lstLights;
|
||||
list2<HelperInstance> m_lstHelpers;
|
||||
|
||||
bool OnLoadgeom(char * filename, const char * geom_name, bool bLoadMats, bool bKeepInLocalSpace);
|
||||
|
||||
float m_fBoundingRadius;
|
||||
float m_fCenterZ;
|
||||
|
||||
void LoadMaterials(CXFile*f, int pos);
|
||||
int m_nNewObjs;
|
||||
CBaseObj ** m_ppNewObjs;
|
||||
ILog * m_pLog;
|
||||
};
|
||||
|
||||
// timers that are used for precision very low cost profiling of load times
|
||||
// this timer measures the time spent in the CGF Loader
|
||||
//extern double g_dTimeLoadCGF;
|
||||
|
||||
#endif // CryStaticModel_H
|
||||
306
ResourceCompilerPC/StatCGFCompiler/File.cpp
Normal file
306
ResourceCompilerPC/StatCGFCompiler/File.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: file.cpp
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: ceached file access
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#ifndef GAMECUBE
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifndef _XBOX
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "windows.h"
|
||||
#endif
|
||||
#else
|
||||
#include <xtl.h>
|
||||
#endif
|
||||
|
||||
#include "File.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
CXFile::CXFile()
|
||||
{
|
||||
m_szFileStart=NULL;
|
||||
m_nFileSize=0;
|
||||
m_pCurrPos=0;
|
||||
m_pEndOfFile=NULL;
|
||||
m_sLoadedFileName[0]=0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
int CXFile::FRead(void *pDest,int nSize,int nNumElems)
|
||||
{
|
||||
int nTotSize=nSize*nNumElems;
|
||||
char *pTest=m_pCurrPos+nTotSize;
|
||||
if (pTest>m_pEndOfFile)
|
||||
return (0);
|
||||
|
||||
memcpy(pDest,m_pCurrPos,nTotSize);
|
||||
m_pCurrPos+=nTotSize;
|
||||
return (nNumElems);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
int CXFile::FSeek(int nOff,int nFrom)
|
||||
{
|
||||
if (nFrom==SEEK_SET)
|
||||
{
|
||||
m_pCurrPos=m_szFileStart+nOff;
|
||||
if (m_pCurrPos>m_pEndOfFile)
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void CXFile::FClose()
|
||||
{
|
||||
if (m_szFileStart)
|
||||
{
|
||||
delete [] m_szFileStart;
|
||||
m_szFileStart=NULL;
|
||||
}
|
||||
|
||||
m_pCurrPos=NULL;
|
||||
m_nFileSize=0;
|
||||
m_pEndOfFile=NULL;
|
||||
m_sLoadedFileName[0]=0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
int CXFile::FLoad(const char * filename)
|
||||
{
|
||||
if(!m_szFileStart || strcmp(m_sLoadedFileName,filename)!=0)
|
||||
{
|
||||
FClose();
|
||||
m_nFileSize=LoadInMemory(filename,(void**)&m_szFileStart);
|
||||
strncpy(m_sLoadedFileName,filename,sizeof(m_sLoadedFileName));
|
||||
}
|
||||
|
||||
m_pCurrPos=m_szFileStart;
|
||||
m_pEndOfFile=m_szFileStart+m_nFileSize;
|
||||
return (m_nFileSize);
|
||||
}
|
||||
|
||||
//get filename's extension
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
char *CXFile::GetExtension(const char *filename)
|
||||
{
|
||||
char *src = (char *)filename+strlen(filename)-1;
|
||||
while (*src)
|
||||
{
|
||||
if (*src == '.')
|
||||
{
|
||||
return (++src);
|
||||
}
|
||||
src--;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
//remove extension from filename
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void CXFile::RemoveExtension(char *path)
|
||||
{
|
||||
char *src = path+strlen(path)-1;
|
||||
while (*src)
|
||||
{
|
||||
if (*src == '.')
|
||||
{
|
||||
*src = 0; // remove extension
|
||||
return;
|
||||
}
|
||||
src--;
|
||||
}
|
||||
}
|
||||
|
||||
//replace filename extension
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void CXFile::ReplaceExtension(char *path, const char *new_ext)
|
||||
{
|
||||
RemoveExtension(path);
|
||||
strcat(path,".");
|
||||
strcat(path,new_ext);
|
||||
}
|
||||
|
||||
//check if file exist
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
bool CXFile::IsFileExist(const char *filename)
|
||||
{
|
||||
return FileExist(filename);
|
||||
}
|
||||
|
||||
//check if file exist
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
bool CXFile::FileExist(const char *filename)
|
||||
{
|
||||
FILE *fp=fopen(filename,"rb");
|
||||
if (!fp) return (false);
|
||||
fclose(fp);
|
||||
return (true);
|
||||
}
|
||||
|
||||
//get length of the file
|
||||
//return (-1) if error
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
int CXFile::GetLength(const char *filename)
|
||||
{
|
||||
FILE *fp=fopen(filename,"rb");
|
||||
if (!fp) return (-1);
|
||||
|
||||
int pos;
|
||||
int end;
|
||||
|
||||
pos = ftell(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
end = ftell(fp);
|
||||
fseek(fp, pos, SEEK_SET);
|
||||
|
||||
fclose(fp);
|
||||
return (end);
|
||||
}
|
||||
|
||||
//tell if filename1 is older than masterfile
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
bool CXFile::IsOutOfDate(const char *pFileName1,const char *pMasterFile)
|
||||
{
|
||||
|
||||
FILE *f=fopen(pMasterFile,"rb");
|
||||
if (f)
|
||||
fclose(f);
|
||||
else
|
||||
return (false);
|
||||
|
||||
f=fopen(pFileName1,"rb");
|
||||
if (f)
|
||||
fclose(f);
|
||||
else
|
||||
return (true);
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
HANDLE status1 = CreateFile(pFileName1,GENERIC_READ,FILE_SHARE_READ,
|
||||
NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
||||
|
||||
HANDLE status2 = CreateFile(pMasterFile,GENERIC_READ,FILE_SHARE_READ,
|
||||
NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
||||
|
||||
FILETIME writetime1,writetime2;
|
||||
|
||||
GetFileTime(status1,NULL,NULL,&writetime1);
|
||||
GetFileTime(status2,NULL,NULL,&writetime2);
|
||||
|
||||
CloseHandle(status1);
|
||||
CloseHandle(status2);
|
||||
|
||||
if (CompareFileTime(&writetime1,&writetime2)==-1)
|
||||
return(true);
|
||||
|
||||
return (false);
|
||||
#else
|
||||
|
||||
return (false);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
int CXFile::GetWriteTime(const char *pFileName1)
|
||||
{
|
||||
FILE *f=fopen(pFileName1,"rb");
|
||||
if (f)
|
||||
fclose(f);
|
||||
else
|
||||
return (0);
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
HANDLE status1 = CreateFile(pFileName1,GENERIC_READ,FILE_SHARE_READ,
|
||||
NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
||||
|
||||
FILETIME writetime1;
|
||||
memset(&writetime1,0,sizeof(writetime1));
|
||||
|
||||
GetFileTime(status1,NULL,NULL,&writetime1);
|
||||
|
||||
CloseHandle(status1);
|
||||
|
||||
return (writetime1.dwHighDateTime + writetime1.dwLowDateTime);
|
||||
#else
|
||||
|
||||
return (0);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
int CXFile::GetLength(FILE *f)
|
||||
{
|
||||
int pos;
|
||||
int end;
|
||||
|
||||
pos = ftell(f);
|
||||
fseek(f, 0, SEEK_END);
|
||||
end = ftell(f);
|
||||
fseek(f, pos, SEEK_SET);
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void CXFile::SafeRead(FILE *f, void *buffer, int count)
|
||||
{
|
||||
(fread(buffer, 1, count, f) != (unsigned)count);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
int CXFile::LoadInMemory(const char *filename, void **bufferptr)
|
||||
{
|
||||
FILE *f = fopen(filename,"rb");
|
||||
if (!f)
|
||||
return (0);
|
||||
int length = CXFile::GetLength(f);
|
||||
void *buffer = new char[length+1];
|
||||
|
||||
SafeRead(f, buffer, length);
|
||||
fclose(f);
|
||||
|
||||
char *bbp=(char *)buffer;
|
||||
bbp[length]=0; //null terminated
|
||||
*bufferptr = buffer;
|
||||
return (length);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void CXFile::GetPath(char *path)
|
||||
{
|
||||
char *src = path+strlen(path)-1;
|
||||
while (*src)
|
||||
{
|
||||
if (*src == '\\')
|
||||
{
|
||||
src++;
|
||||
*src = 0; // remove extension
|
||||
return;
|
||||
}
|
||||
src--;
|
||||
}
|
||||
}
|
||||
68
ResourceCompilerPC/StatCGFCompiler/File.h
Normal file
68
ResourceCompilerPC/StatCGFCompiler/File.h
Normal file
@@ -0,0 +1,68 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: file.h
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: cecahed file access
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PS2
|
||||
#ifndef FILE_H
|
||||
#define FILE_H
|
||||
|
||||
#define MAX_PATH_LENGTH 512
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class CXFile
|
||||
{
|
||||
public:
|
||||
|
||||
CXFile();
|
||||
~CXFile() { FClose(); }
|
||||
|
||||
int FRead(void *pDest,int nSize,int nNumElems);
|
||||
static void SafeRead(FILE *f, void *buffer, int count);
|
||||
int FSeek(int nOff,int nFrom);
|
||||
int FLoad(const char *filename);
|
||||
void FClose();
|
||||
|
||||
static bool FileExist(const char *filename);
|
||||
static bool IsFileExist(const char *filename);
|
||||
//-1 if file does not exist
|
||||
static int GetLength(const char *filename);
|
||||
static int GetLength(FILE *f);
|
||||
static int LoadInMemory(const char *filename, void **bufferptr);
|
||||
|
||||
static bool IsOutOfDate(const char *pFileName1,const char *pMasterFile);
|
||||
static int GetWriteTime(const char *pFileName1);
|
||||
|
||||
//utils
|
||||
static void RemoveExtension (char *path);
|
||||
static void ReplaceExtension(char *path, const char *new_ext);
|
||||
static char *GetExtension (const char *filename);
|
||||
static char *GetString (FILE *fp,const char *key);
|
||||
static void GetPath(char *path);
|
||||
|
||||
//Tim code
|
||||
static void SetLanguage (const char *command=NULL);
|
||||
static char *ConvertFilename(const char *filename);
|
||||
|
||||
private:
|
||||
|
||||
char *m_szFileStart,*m_pCurrPos,*m_pEndOfFile;
|
||||
int m_nFileSize;
|
||||
char m_sLoadedFileName[512];
|
||||
};
|
||||
|
||||
#endif
|
||||
#else //PS2
|
||||
#include "..\CryCommon\File.h"
|
||||
#endif
|
||||
148
ResourceCompilerPC/StatCGFCompiler/Geom.cpp
Normal file
148
ResourceCompilerPC/StatCGFCompiler/Geom.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: geom.cpp
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: loading geometry from cgf
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Geom.h"
|
||||
#include "file.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CGeom::CGeom() : CBaseObj()
|
||||
{
|
||||
memset(&m_Chunk,0,sizeof(m_Chunk));
|
||||
m_pVertices =NULL;
|
||||
m_pFaces =NULL;
|
||||
// m_pLinks =NULL;
|
||||
m_pUVs =NULL;
|
||||
m_sPropstr =NULL;
|
||||
// bones =NULL;
|
||||
m_pTexFaces =NULL;
|
||||
// m_pNumLinks =NULL;
|
||||
// links =NULL;
|
||||
m_pVcols =NULL;
|
||||
// BoneNames =NULL;
|
||||
}
|
||||
|
||||
CGeom::~CGeom()
|
||||
{
|
||||
/* if(links)
|
||||
{
|
||||
for(int i=0;i<m_Chunk.nVerts;i++) if(links[i]) free(links[i]);
|
||||
free(links);
|
||||
}*/
|
||||
|
||||
// if(bones) free(bones);
|
||||
if(m_pFaces) free(m_pFaces);
|
||||
if(m_pVertices)free(m_pVertices);
|
||||
if(m_pUVs) free(m_pUVs);
|
||||
if(m_sPropstr) free(m_sPropstr);
|
||||
// if(nLinks) free(nLinks);
|
||||
if(m_pVcols) free(m_pVcols);
|
||||
if(m_pTexFaces)free(m_pTexFaces);
|
||||
}
|
||||
|
||||
bool CGeom::Load(CXFile *f, int pos)
|
||||
{
|
||||
if(f->FSeek(pos,SEEK_SET)) return true;
|
||||
|
||||
int res=f->FRead(&m_Chunk,sizeof(m_Chunk),1);
|
||||
if(res!=1) return true;
|
||||
|
||||
m_ChunkHeader=m_Chunk.chdr;
|
||||
|
||||
if(m_ChunkHeader.ChunkType != ChunkType_Mesh || m_ChunkHeader.ChunkVersion != MESH_CHUNK_DESC_VERSION)
|
||||
{
|
||||
memset(&m_Chunk,0,sizeof(m_Chunk));
|
||||
return true;
|
||||
}
|
||||
|
||||
//read verts
|
||||
m_pVertices=(CryVertex*)malloc(sizeof(CryVertex)*m_Chunk.nVerts);
|
||||
assert(m_pVertices);
|
||||
res=f->FRead(m_pVertices,sizeof(CryVertex),m_Chunk.nVerts);
|
||||
if(res!=m_Chunk.nVerts) return true;
|
||||
|
||||
//read m_pFaces
|
||||
m_pFaces=(CryFace*)malloc(sizeof(CryFace)*m_Chunk.nFaces);
|
||||
assert(m_pFaces);
|
||||
res=f->FRead(m_pFaces,sizeof(CryFace),m_Chunk.nFaces);
|
||||
if(res!=m_Chunk.nFaces) return true;
|
||||
|
||||
//read tverts
|
||||
if(m_Chunk.nTVerts)
|
||||
{
|
||||
m_pUVs=(CryUV*)malloc(sizeof(CryUV)*m_Chunk.nTVerts);
|
||||
assert(m_pUVs);
|
||||
res=f->FRead(m_pUVs,sizeof(CryUV),m_Chunk.nTVerts);
|
||||
if(res!=m_Chunk.nTVerts) return true;
|
||||
|
||||
// flip tex coords (since it was flipped in max?)
|
||||
for(int t=0; t<m_Chunk.nTVerts; t++)
|
||||
m_pUVs[t].v = 1.f-m_pUVs[t].v;
|
||||
|
||||
//read Tfaces
|
||||
//if(m_Chunk.nVerts != m_Chunk.nTVerts)
|
||||
if(m_Chunk.nVerts != 12 || pos != 692)//hack to make old grass objects working
|
||||
{
|
||||
m_pTexFaces=(CryTexFace*)malloc(sizeof(CryTexFace)*m_Chunk.nFaces);
|
||||
assert(m_pTexFaces);
|
||||
|
||||
res=f->FRead(m_pTexFaces,sizeof(CryTexFace),m_Chunk.nFaces);
|
||||
if(res!=m_Chunk.nFaces) return true;
|
||||
}
|
||||
}
|
||||
|
||||
//read Vertex Colors
|
||||
if(m_Chunk.HasVertexCol)
|
||||
{
|
||||
m_pVcols=(CryIRGB *)malloc(m_Chunk.nVerts*sizeof(CryIRGB));
|
||||
assert(m_pVcols);
|
||||
|
||||
int res=f->FRead(m_pVcols, sizeof(CryIRGB), m_Chunk.nVerts);
|
||||
|
||||
/*
|
||||
for (int k=0;k<m_Chunk.nVerts;k++)
|
||||
{
|
||||
m_pVcols[k].r=255;
|
||||
m_pVcols[k].g=0;
|
||||
m_pVcols[k].b=0;
|
||||
} //k
|
||||
*/
|
||||
|
||||
|
||||
if (res!=m_Chunk.nVerts)
|
||||
return (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pVcols=0;
|
||||
/*
|
||||
m_pVcols=(CryIRGB *)malloc(m_Chunk.nVerts*sizeof(CryIRGB));
|
||||
assert(m_pVcols);
|
||||
|
||||
for (int k=0;k<m_Chunk.nVerts;k++)
|
||||
{
|
||||
m_pVcols[k].r=255;
|
||||
m_pVcols[k].g=0;
|
||||
m_pVcols[k].b=0;
|
||||
} //k
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
return (false);
|
||||
}
|
||||
51
ResourceCompilerPC/StatCGFCompiler/Geom.h
Normal file
51
ResourceCompilerPC/StatCGFCompiler/Geom.h
Normal file
@@ -0,0 +1,51 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: geom.h
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_GEOM_H__D90B8CB0_DAA4_49C7_8D72_4A73FA38E640__INCLUDED_)
|
||||
#define AFX_GEOM_H__D90B8CB0_DAA4_49C7_8D72_4A73FA38E640__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#include "baseobj.h"
|
||||
|
||||
class CGeom : public CBaseObj
|
||||
{
|
||||
public:
|
||||
CryVertex *m_pVertices;
|
||||
CryFace *m_pFaces;
|
||||
CryUV *m_pUVs;
|
||||
CryTexFace *m_pTexFaces;
|
||||
CryIRGB *m_pVcols;
|
||||
// int *m_pNumLinks;
|
||||
// CryLink ** m_pLinks;
|
||||
|
||||
char * m_sPropstr;
|
||||
MESH_CHUNK_DESC m_Chunk;
|
||||
|
||||
CGeom();
|
||||
virtual ~CGeom();
|
||||
|
||||
//from BaseObj
|
||||
bool Load(CXFile *f, int pos);
|
||||
|
||||
MESH_CHUNK_DESC * GetChunk() { return &m_Chunk; }
|
||||
|
||||
//CGeom methods
|
||||
void Deform();
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_GEOM_H__D90B8CB0_DAA4_49C7_8D72_4A73FA38E640__INCLUDED_)
|
||||
49
ResourceCompilerPC/StatCGFCompiler/Helper.cpp
Normal file
49
ResourceCompilerPC/StatCGFCompiler/Helper.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: helper.cpp
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: loading helper from cgf
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Helper.h"
|
||||
#include "file.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CHelper::CHelper() : CBaseObj()
|
||||
{
|
||||
memset(&m_Chunk,0,sizeof(m_Chunk));
|
||||
}
|
||||
|
||||
CHelper::~CHelper()
|
||||
{
|
||||
}
|
||||
|
||||
bool CHelper::Load(CXFile *f, int pos)
|
||||
{
|
||||
if(f->FSeek(pos,SEEK_SET)) return true;
|
||||
|
||||
int res=f->FRead(&m_Chunk,sizeof(m_Chunk),1);
|
||||
if(res!=1) return true;
|
||||
|
||||
if(m_Chunk.chdr.ChunkType != ChunkType_Helper || m_Chunk.chdr.ChunkVersion != HELPER_CHUNK_DESC_VERSION)
|
||||
{
|
||||
memset(&m_Chunk,0,sizeof(m_Chunk));
|
||||
return true;
|
||||
}
|
||||
|
||||
m_ChunkHeader=m_Chunk.chdr;
|
||||
|
||||
return false;
|
||||
}
|
||||
36
ResourceCompilerPC/StatCGFCompiler/Helper.h
Normal file
36
ResourceCompilerPC/StatCGFCompiler/Helper.h
Normal file
@@ -0,0 +1,36 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: helper.h
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_HELPER_H__3A967DC3_988F_4A67_BC33_AC26573B86FA__INCLUDED_)
|
||||
#define AFX_HELPER_H__3A967DC3_988F_4A67_BC33_AC26573B86FA__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#include "BaseObj.h"
|
||||
|
||||
class CHelper : public CBaseObj
|
||||
{
|
||||
public:
|
||||
HELPER_CHUNK_DESC m_Chunk;
|
||||
|
||||
CHelper();
|
||||
virtual ~CHelper();
|
||||
|
||||
virtual bool Load(CXFile *f, int pos);
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_HELPER_H__3A967DC3_988F_4A67_BC33_AC26573B86FA__INCLUDED_)
|
||||
49
ResourceCompilerPC/StatCGFCompiler/Light.cpp
Normal file
49
ResourceCompilerPC/StatCGFCompiler/Light.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: light.cpp
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: loading light source from cgf
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Light.h"
|
||||
#include "file.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CLight::CLight()
|
||||
{
|
||||
memset(&m_Chunk,0,sizeof(m_Chunk));
|
||||
}
|
||||
|
||||
CLight::~CLight()
|
||||
{
|
||||
}
|
||||
|
||||
bool CLight::Load(CXFile *f, int pos)
|
||||
{
|
||||
if(f->FSeek(pos,SEEK_SET)) return true;
|
||||
|
||||
int res=f->FRead(&m_Chunk,sizeof(m_Chunk),1);
|
||||
if(res!=1) return true;
|
||||
|
||||
if(m_Chunk.chdr.ChunkType != ChunkType_Light || m_Chunk.chdr.ChunkVersion != LIGHT_CHUNK_DESC_VERSION)
|
||||
{
|
||||
memset(&m_Chunk,0,sizeof(m_Chunk));
|
||||
return true;
|
||||
}
|
||||
|
||||
m_ChunkHeader=m_Chunk.chdr;
|
||||
|
||||
return false;
|
||||
}
|
||||
36
ResourceCompilerPC/StatCGFCompiler/Light.h
Normal file
36
ResourceCompilerPC/StatCGFCompiler/Light.h
Normal file
@@ -0,0 +1,36 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: light.h
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_LIGHT_H__ACF97045_6471_4C13_BC9F_F26C16A0590E__INCLUDED_)
|
||||
#define AFX_LIGHT_H__ACF97045_6471_4C13_BC9F_F26C16A0590E__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#include "BaseObj.h"
|
||||
|
||||
class CLight : public CBaseObj
|
||||
{
|
||||
public:
|
||||
LIGHT_CHUNK_DESC m_Chunk;
|
||||
|
||||
CLight();
|
||||
virtual ~CLight();
|
||||
|
||||
virtual bool Load(CXFile *f, int pos);
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_LIGHT_H__ACF97045_6471_4C13_BC9F_F26C16A0590E__INCLUDED_)
|
||||
1224
ResourceCompilerPC/StatCGFCompiler/Meshidx.cpp
Normal file
1224
ResourceCompilerPC/StatCGFCompiler/Meshidx.cpp
Normal file
File diff suppressed because it is too large
Load Diff
125
ResourceCompilerPC/StatCGFCompiler/Node.cpp
Normal file
125
ResourceCompilerPC/StatCGFCompiler/Node.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: node.cpp
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: loading node info from cgf
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "Node.h"
|
||||
#include "Geom.h"
|
||||
#include "file.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CNodeCGF::CNodeCGF() : CBaseObj()
|
||||
{
|
||||
m_pObj = NULL;
|
||||
// m_sPropStr = NULL;
|
||||
// m_ppChildren = NULL;
|
||||
// m_pnChildrenIds= NULL;
|
||||
m_pParent = NULL;
|
||||
// m_pMtl = NULL;
|
||||
// m_pConRot = NULL;
|
||||
// m_pConPos = NULL;
|
||||
// m_pConScl = NULL;
|
||||
memset(&m_Chunk,0,sizeof(m_Chunk));
|
||||
}
|
||||
|
||||
CNodeCGF::~CNodeCGF()
|
||||
{
|
||||
// if(m_ppChildren) free(m_ppChildren);
|
||||
// if(m_pnChildrenIds) free(m_pnChildrenIds);
|
||||
// if(m_sPropStr) free(m_sPropStr);
|
||||
}
|
||||
|
||||
bool CNodeCGF::Load(CXFile *f, int pos)
|
||||
{
|
||||
if(f->FSeek(pos,SEEK_SET)) return true;
|
||||
|
||||
int res=f->FRead(&m_Chunk,sizeof(m_Chunk),1);
|
||||
if(res!=1) return true;
|
||||
|
||||
if(m_Chunk.chdr.ChunkType != ChunkType_Node || m_Chunk.chdr.ChunkVersion != NODE_CHUNK_DESC_VERSION)
|
||||
{
|
||||
memset(&m_Chunk,0,sizeof(m_Chunk));
|
||||
return true;
|
||||
}
|
||||
|
||||
m_ChunkHeader=m_Chunk.chdr;
|
||||
// m_NodeMatrix = m_Chunk.tm;
|
||||
|
||||
//read propstr
|
||||
/* if(m_Chunk.PropStrLen)
|
||||
{
|
||||
m_sPropStr=(char*)malloc(m_Chunk.PropStrLen+1);
|
||||
assert(m_sPropStr);
|
||||
res=f->FRead(m_sPropStr,m_Chunk.PropStrLen,1);
|
||||
m_sPropStr[m_Chunk.PropStrLen]=0;
|
||||
if(res!=1) return true;
|
||||
}*/
|
||||
|
||||
//read m_ppChildren
|
||||
/* if(m_Chunk.nChildren)
|
||||
{
|
||||
m_pnChildrenIds = (int*) malloc(m_Chunk.nChildren*sizeof(int));
|
||||
assert(m_pnChildrenIds);
|
||||
|
||||
m_ppChildren = (CNodeCGF **) malloc(m_Chunk.nChildren*sizeof(CNodeCGF*));
|
||||
assert(m_pnChildrenIds);
|
||||
memset(m_ppChildren,0,m_Chunk.nChildren*sizeof(CNodeCGF*));
|
||||
|
||||
int res=f->FRead(m_pnChildrenIds,sizeof(int),m_Chunk.nChildren);
|
||||
if(res!=m_Chunk.nChildren) return true;
|
||||
}*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CNodeCGF::Bind(CBaseObj ** all_objects, int n_obj)
|
||||
{
|
||||
if(m_bBinded)
|
||||
return;
|
||||
|
||||
for(int i=0;i<n_obj;i++)
|
||||
{
|
||||
CBaseObj * o = all_objects[i];
|
||||
if(!o || o->m_ChunkHeader.ChunkID == -1)
|
||||
continue;
|
||||
|
||||
if(o->m_ChunkHeader.ChunkID == m_Chunk.ObjectID)
|
||||
{
|
||||
m_pObj = o;
|
||||
o->m_nUsers++;
|
||||
}
|
||||
else if(o->m_ChunkHeader.ChunkID == m_Chunk.ParentID)
|
||||
m_pParent=(CNodeCGF *)o; /*
|
||||
else if(o->m_ChunkHeader.ChunkID == m_Chunk.MatID)
|
||||
m_pMtl=o;
|
||||
else if(o->m_ChunkHeader.ChunkID == m_Chunk.pos_cont_id)
|
||||
m_pConPos=(Controller *)o;
|
||||
else if(o->m_ChunkHeader.ChunkID == m_Chunk.rot_cont_id)
|
||||
m_pConRot=(Controller *)o;
|
||||
else if(o->m_ChunkHeader.ChunkID == m_Chunk.scl_cont_id)
|
||||
m_pConScl=(Controller *)o;
|
||||
|
||||
for(int j=0;j<m_Chunk.nChildren;j++)
|
||||
{
|
||||
if(o->m_ChunkHeader.ChunkID == m_pnChildrenIds[j])
|
||||
m_ppChildren[j]=(CNodeCGF *)o;
|
||||
}*/
|
||||
}
|
||||
|
||||
m_bBinded = true;
|
||||
}
|
||||
51
ResourceCompilerPC/StatCGFCompiler/Node.h
Normal file
51
ResourceCompilerPC/StatCGFCompiler/Node.h
Normal file
@@ -0,0 +1,51 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: node.h
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_NODE_H__8DFD8741_DBA1_4357_9F50_8E37EA039BCB__INCLUDED_)
|
||||
#define AFX_NODE_H__8DFD8741_DBA1_4357_9F50_8E37EA039BCB__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#include "BaseObj.h"
|
||||
|
||||
class Controller;
|
||||
|
||||
class CNodeCGF : public CBaseObj
|
||||
{
|
||||
public:
|
||||
NODE_CHUNK_DESC m_Chunk;
|
||||
// int *m_pnChildrenIds;
|
||||
|
||||
CBaseObj *m_pObj;
|
||||
/* char *m_sPropStr;
|
||||
CNodeCGF ** m_ppChildren;*/
|
||||
CNodeCGF *m_pParent;
|
||||
/*CBaseObj *m_pMtl;
|
||||
Controller *m_pConPos,*m_pConRot,*m_pConScl;*/
|
||||
// CryMatrix m_NodeMatrix;
|
||||
|
||||
CNodeCGF();
|
||||
virtual ~CNodeCGF();
|
||||
|
||||
virtual bool Load(CXFile *f, int pos);
|
||||
virtual void Bind(CBaseObj **all_objects, int n_obj);
|
||||
|
||||
char * GetName() { return m_Chunk.name; }
|
||||
float * GetMatrixData() { return m_Chunk.tm.GetData(); }
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_NODE_H__8DFD8741_DBA1_4357_9F50_8E37EA039BCB__INCLUDED_)
|
||||
362
ResourceCompilerPC/StatCGFCompiler/StatCGFCompiler.cpp
Normal file
362
ResourceCompilerPC/StatCGFCompiler/StatCGFCompiler.cpp
Normal file
@@ -0,0 +1,362 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: StatCGFCompiler.cpp
|
||||
// Version: v1.00
|
||||
// Created: 5/11/2002 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <DbgHelp.h>
|
||||
#include "ConvertContext.h"
|
||||
#include "iconfig.h"
|
||||
#include "StatCGFCompiler.h"
|
||||
#define ISystem IRCLog
|
||||
#include "meshidx.h"
|
||||
#include "statcgfshadvol.h"
|
||||
|
||||
CStatCFGCompiler::CStatCFGCompiler(void)
|
||||
{
|
||||
}
|
||||
|
||||
CStatCFGCompiler::~CStatCFGCompiler(void)
|
||||
{
|
||||
}
|
||||
|
||||
// function for creating this from outside (without including StatCGFCompiler.h)
|
||||
IConvertor* NewStatCGFCompiler()
|
||||
{
|
||||
return new CStatCFGCompiler();
|
||||
}
|
||||
|
||||
void CStatCFGCompiler::FindDependencies( CIndexedMesh * pIndexedMesh, ConvertContext &cc )
|
||||
{
|
||||
cc.pLog->Log("Finding dependencies");
|
||||
|
||||
for(int m=0; m<pIndexedMesh->m_lstMatTable.Count(); m++)
|
||||
{
|
||||
CMatInfo &ref=pIndexedMesh->m_lstMatTable[m];
|
||||
|
||||
const char *szMatName=ref.GetName();
|
||||
const char *szScriptName=ref.sScriptMaterial;
|
||||
|
||||
CString sourceFile = cc.getSourcePath();
|
||||
|
||||
cc.pRC->AddDependencyMaterial(sourceFile.GetString(),szMatName,szScriptName); // material name
|
||||
|
||||
if(!ref.pMatEnt)continue;
|
||||
|
||||
// texture path names
|
||||
#define ADD_MAP(MAP) if (ref.pMatEnt->map_##MAP.name[0]) cc.pRC->AddDependencyFile(sourceFile.GetString(),ref.pMatEnt->map_##MAP.name);
|
||||
ADD_MAP(a);
|
||||
ADD_MAP(d);
|
||||
ADD_MAP(o);
|
||||
ADD_MAP(b);
|
||||
ADD_MAP(s);
|
||||
ADD_MAP(g);
|
||||
ADD_MAP(detail);
|
||||
ADD_MAP(e);
|
||||
ADD_MAP(subsurf);
|
||||
ADD_MAP(displ);
|
||||
#undef ADD_MAP
|
||||
}
|
||||
}
|
||||
|
||||
FILETIME UnixTimeToFileTime(time_t t)
|
||||
{
|
||||
// Note that LONGLONG is a 64-bit value
|
||||
LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
|
||||
return (FILETIME&)ll;
|
||||
}
|
||||
|
||||
|
||||
// returns the file modification time
|
||||
FILETIME GetModificationTime(FILE* hFile)
|
||||
{
|
||||
struct _stat st;
|
||||
_fstat(_fileno(hFile), &st);
|
||||
#ifdef _DEBUG
|
||||
const char* szTest = ctime (&st.st_mtime);
|
||||
#endif
|
||||
return UnixTimeToFileTime (st.st_mtime);
|
||||
}
|
||||
|
||||
|
||||
bool CStatCFGCompiler::GetSourceFileTime(const char * szFileName, FILETIME & fileTime)
|
||||
{
|
||||
FILE* f = fopen (szFileName, "rb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
fileTime = GetModificationTime(f);
|
||||
fclose (f);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CStatCFGCompiler::GetFileParams( ConvertContext &cc, CString & sGeomName,
|
||||
bool & bStripify, bool & bLoadAdditinalInfo, bool & bKeepInLocalSpace)
|
||||
{
|
||||
cc.config->Get("GeomName",sGeomName); // subobject name
|
||||
cc.config->Get("Stripify",bStripify); // sort for vertex ceache
|
||||
cc.config->Get("LoadAdditinalInfo",bLoadAdditinalInfo); // load geom names, helpers, lightsources
|
||||
cc.config->Get("KeepInLocalSpace",bKeepInLocalSpace); // do not transform vertices by node matrix
|
||||
}
|
||||
|
||||
bool CStatCFGCompiler::Process( ConvertContext &cc )
|
||||
{
|
||||
try
|
||||
{
|
||||
CString sGeomName;
|
||||
bool bStripify=0, bLoadAdditinalInfo=0, bKeepInLocalSpace=0;
|
||||
GetFileParams( cc, sGeomName, bStripify, bLoadAdditinalInfo, bKeepInLocalSpace);
|
||||
if (!cc.bQuiet)
|
||||
{
|
||||
cc.pLog->Log("Conversion params:");
|
||||
cc.pLog->Log(" GeomName = %s", sGeomName[0] ? sGeomName : "None");
|
||||
cc.pLog->Log(" Stripify = %s", bStripify ? "Yes" : "No");
|
||||
cc.pLog->Log(" LoadAdditinalInfo = %s", bLoadAdditinalInfo ? "Yes" : "No");
|
||||
cc.pLog->Log(" KeepInLocalSpace = %s", bKeepInLocalSpace ? "Yes" : "No");
|
||||
}
|
||||
|
||||
CString sourceFile = cc.getSourcePath();
|
||||
CString outputFile = cc.getOutputPath();
|
||||
|
||||
const char *sInFile = sourceFile.GetString();
|
||||
|
||||
FILETIME fileTime;
|
||||
if(!GetSourceFileTime( sourceFile.GetString(), fileTime))
|
||||
{
|
||||
remove( outputFile.GetString() );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if .cga.
|
||||
if (stricmp(Path::GetExt(cc.sourceFile).GetString(),"cga") == 0)
|
||||
{
|
||||
// Load CGA.
|
||||
ProcessCGA( cc,sourceFile,outputFile,fileTime,bStripify );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load Normal CGF.
|
||||
ProcessCGF( cc,sourceFile,outputFile,fileTime,sGeomName,bStripify,bLoadAdditinalInfo,bKeepInLocalSpace );
|
||||
}
|
||||
}
|
||||
catch(char*)
|
||||
{
|
||||
Beep(1000,1000);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStatCFGCompiler::ProcessCGA( ConvertContext &cc,CString &sourceFile,CString &outputFile,FILETIME fileTime,bool bStripify )
|
||||
{
|
||||
CString outputFileNoExt = Path::RemoveExtension(cc.sourceFile);
|
||||
CString outputGeomFile;
|
||||
|
||||
int nLoadedTrisCount=0;
|
||||
CIndexedMesh * pIndexedMesh = new CIndexedMesh( cc.pLog,sourceFile.GetString(),0,&nLoadedTrisCount,true,true );
|
||||
if (pIndexedMesh)
|
||||
{
|
||||
for (int i = 0; i < (int)pIndexedMesh->m_lstGeomNames.size(); i++)
|
||||
{
|
||||
CString sOrgGeomName = pIndexedMesh->m_lstGeomNames[i];
|
||||
CString sGeomName = sOrgGeomName;
|
||||
sGeomName.Replace( '\\','_' );
|
||||
sGeomName.Replace( '/','_' );
|
||||
outputGeomFile.Format( "%s_%s_%d_%d_%d.ccgf",outputFileNoExt.GetString(), sGeomName.GetString(),(int)bStripify,1,1 );
|
||||
cc.outputFile = outputGeomFile;
|
||||
outputGeomFile = cc.getOutputPath();
|
||||
const char *sgeom = outputGeomFile.GetString();
|
||||
ProcessCGF( cc,sourceFile,outputGeomFile,fileTime,sOrgGeomName,bStripify,true,true );
|
||||
}
|
||||
}
|
||||
delete pIndexedMesh;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStatCFGCompiler::ProcessCGF( ConvertContext &cc,CString &sourceFile,CString &outputFile,FILETIME fileTime,CString sGeomName,
|
||||
bool bStripify, bool bLoadAdditinalInfo, bool bKeepInLocalSpace )
|
||||
{
|
||||
// load source cgf
|
||||
int nLoadedTrisCount=0;
|
||||
CIndexedMesh * pIndexedMesh = new CIndexedMesh( cc.pLog, sourceFile.GetString(), sGeomName[0] ? sGeomName.GetString() : 0,
|
||||
&nLoadedTrisCount, bLoadAdditinalInfo, bKeepInLocalSpace);
|
||||
pIndexedMesh->CalcTangentSpace();
|
||||
|
||||
// if geom name was specified - save empty file to let the engine know that this geom does not exits
|
||||
// since passing wrong geom name is valid operation
|
||||
if(!nLoadedTrisCount && !sGeomName[0])
|
||||
cc.pLog->ThrowError(" No faces found");
|
||||
|
||||
// find dependencies (material names, texture path names)
|
||||
FindDependencies( pIndexedMesh, cc );
|
||||
|
||||
// compile data
|
||||
CSimpleStatObj StatObj( cc.pLog, pIndexedMesh, sourceFile.GetString() );
|
||||
CSimpleLeafBuffer LeafBuffer(cc.pLog, pIndexedMesh, bStripify,
|
||||
pIndexedMesh->m_lstGeomNames.Count()>0 && strstr(pIndexedMesh->m_lstGeomNames[0],"cloth")!=0);
|
||||
CStatCGFShadVol StatCGFShadVol(cc.pLog, pIndexedMesh);
|
||||
|
||||
int nPos = 0;
|
||||
|
||||
// get data size
|
||||
if(nLoadedTrisCount)
|
||||
{
|
||||
StatObj.Serialize(nPos, 0, true);
|
||||
LeafBuffer.Serialize(nPos, 0, true, outputFile.GetString() );
|
||||
StatCGFShadVol.Serialize(nPos, 0, true);
|
||||
}
|
||||
|
||||
// allocate mem buffer
|
||||
uchar * pData = new uchar[nPos+sizeof(CCGFHeader)];
|
||||
|
||||
// make header
|
||||
CCGFHeader fileHeader;
|
||||
fileHeader.nDataSize = nPos;
|
||||
fileHeader.nFacesInCGFNum = nLoadedTrisCount;
|
||||
fileHeader.SourceFileTime = fileTime;
|
||||
fileHeader.vBoxMin = pIndexedMesh->m_vBoxMin;
|
||||
fileHeader.vBoxMax = pIndexedMesh->m_vBoxMax;
|
||||
strcpy(fileHeader.szVersion,CCGF_FILE_VERSION);
|
||||
if(StatObj.IsPhysicsExist())
|
||||
fileHeader.dwFlags |= CCGFHF_PHYSICS_EXIST;
|
||||
|
||||
memcpy(pData,&fileHeader,sizeof(CCGFHeader));
|
||||
|
||||
nPos = sizeof(fileHeader);
|
||||
|
||||
// save to new file
|
||||
if(nLoadedTrisCount)
|
||||
{
|
||||
StatObj.Serialize(nPos, pData, true);
|
||||
LeafBuffer.Serialize(nPos, pData, true, outputFile.GetString() );
|
||||
StatCGFShadVol.Serialize(nPos, pData, true);
|
||||
}
|
||||
|
||||
// create folder for object
|
||||
CString srtDirName = cc.getOutputFolderPath();
|
||||
int nFind = -1;
|
||||
while(1)
|
||||
{
|
||||
nFind = srtDirName.Find('\\', nFind+1);
|
||||
if(nFind<0)
|
||||
break;
|
||||
|
||||
CString strSubDirName = srtDirName.Left(nFind);
|
||||
CreateDirectory(strSubDirName.GetString(),NULL);
|
||||
}
|
||||
|
||||
cc.pLog->Log("Writing CCGF: %s", outputFile.GetString() );
|
||||
FILE * f = fopen(outputFile.GetString(),"wb");
|
||||
if(f)
|
||||
{
|
||||
size_t nWriten = fwrite(pData,1,nPos,f);
|
||||
fclose(f);
|
||||
if(nWriten == nPos)
|
||||
cc.pLog->Log(" %d bytes saved", nPos);
|
||||
else
|
||||
cc.pLog->ThrowError(" Error writing output file");
|
||||
}
|
||||
else
|
||||
cc.pLog->ThrowError(" Error opening output file");
|
||||
|
||||
delete pIndexedMesh;
|
||||
delete pData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// !!! PLZ NEVER CHANGE THIS FILE WITHOUT ASKING VLAD !!!
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
bool CStatCFGCompiler::GetOutputFile( ConvertContext &cc )
|
||||
{
|
||||
bool bStripify=0, bLoadAdditinalInfo=0, bKeepInLocalSpace=0; CString sGeomName;
|
||||
GetFileParams( cc, sGeomName, bStripify, bLoadAdditinalInfo, bKeepInLocalSpace);
|
||||
|
||||
CString outputFileNoExt = Path::ReplaceExtension( cc.sourceFile, "" );
|
||||
|
||||
char szCurDir[MAX_PATH]="";
|
||||
GetCurrentDirectory(MAX_PATH,szCurDir);
|
||||
CString curFolderName = szCurDir;
|
||||
|
||||
cc.outputFolder = cc.masterFolder + CString(CCGF_CACHE_DIR_NAME) + "\\" + cc.outputFolder;
|
||||
//CString outputDirName=Path::ReplacePath(curFolderName, curFolderName + "\\" + CCGF_CACHE_DIR_NAME, outputFileNoExt);
|
||||
|
||||
char szOutputFileName[1024];
|
||||
sprintf(szOutputFileName,
|
||||
"%s_%s_%d_%d_%d.ccgf",
|
||||
outputFileNoExt.GetString(), sGeomName.GetString(),
|
||||
(int)bStripify, (int)bLoadAdditinalInfo, (int)bKeepInLocalSpace);
|
||||
|
||||
//specify output path
|
||||
cc.outputFile = szOutputFileName;
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
int CStatCFGCompiler::GetNumPlatforms() const
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
Platform CStatCFGCompiler::GetPlatform( int index ) const
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return PLATFORM_PC;
|
||||
case 1: return PLATFORM_XBOX;
|
||||
//case 2: return PLATFORM_PS2;
|
||||
//case 3: return PLATFORM_GAMECUBE;
|
||||
};
|
||||
//assert(0);
|
||||
return PLATFORM_UNKNOWN;
|
||||
}
|
||||
|
||||
DWORD CStatCFGCompiler::GetTimestamp() const
|
||||
{
|
||||
return GetTimestampForLoadedLibrary(g_hInst);
|
||||
}
|
||||
|
||||
CStatCFGCompiler::Error::Error (const char* szFormat, ...)
|
||||
{
|
||||
char szBuffer[0x800];
|
||||
va_list arg;
|
||||
va_start(arg,szFormat);
|
||||
_vsnprintf (szBuffer, sizeof(szBuffer), szFormat, arg);
|
||||
va_end(arg);
|
||||
this->m_strReason = szBuffer;
|
||||
}
|
||||
|
||||
CStatCFGCompiler::Error::Error (int nCode)
|
||||
{
|
||||
char szBuffer[36];
|
||||
sprintf (szBuffer, "Generic Error #%d", nCode);
|
||||
this->m_strReason = szBuffer;
|
||||
}
|
||||
|
||||
int CStatCFGCompiler::SetTexType(TextureMap3 *tm)
|
||||
{
|
||||
if (tm->type == TEXMAP_CUBIC)
|
||||
return eTT_Cubemap;
|
||||
else
|
||||
if (tm->type == TEXMAP_AUTOCUBIC)
|
||||
return eTT_AutoCubemap;
|
||||
return eTT_Base;
|
||||
}
|
||||
299
ResourceCompilerPC/StatCGFCompiler/StatCGFCompiler.h
Normal file
299
ResourceCompilerPC/StatCGFCompiler/StatCGFCompiler.h
Normal file
@@ -0,0 +1,299 @@
|
||||
#ifndef STAT_CGF_COMPILER
|
||||
#define STAT_CGF_COMPILER
|
||||
|
||||
#include "IConvertor.h"
|
||||
|
||||
struct ConvertContext;
|
||||
class CStatCFGCompiler : public IConvertor
|
||||
{
|
||||
public:
|
||||
class Error
|
||||
{
|
||||
public:
|
||||
Error (int nCode);
|
||||
Error (const char* szFormat, ...);
|
||||
const char* c_str()const {return m_strReason.c_str();}
|
||||
protected:
|
||||
string m_strReason;
|
||||
};
|
||||
|
||||
CStatCFGCompiler(void);
|
||||
~CStatCFGCompiler(void);
|
||||
bool Process( ConvertContext &cc );
|
||||
void Release() { delete this; };
|
||||
bool GetOutputFile( ConvertContext &cc );
|
||||
int GetNumPlatforms() const;
|
||||
Platform GetPlatform( int index ) const;
|
||||
virtual int GetNumExt() const { return 2; };
|
||||
virtual const char* GetExt( int index ) const { return index ? "cga" : "cgf"; };
|
||||
DWORD GetTimestamp() const;
|
||||
bool GetSourceFileTime(const char * szFileName, FILETIME & fileTime);
|
||||
|
||||
protected:
|
||||
int SetTexType(struct TextureMap3 *tm);
|
||||
bool PrepareTexSpaceBasis();
|
||||
void FindDependencies( CIndexedMesh * pIndexedMesh, ConvertContext &cc );
|
||||
void GetFileParams( ConvertContext &cc, CString & sGeomName,
|
||||
bool & bStripify, bool & bLoadAdditinalInfo, bool & bKeepInLocalSpace);
|
||||
void ProcessCGA( ConvertContext &cc,CString &sourceFile,CString &outputFile,FILETIME fileTime,bool bStripify );
|
||||
void ProcessCGF( ConvertContext &cc,CString &sourceFile,CString &outputFile,FILETIME fileTime,CString sGeomName,
|
||||
bool bStripify, bool bLoadAdditinalInfo, bool bKeepInLocalSpace );
|
||||
};
|
||||
|
||||
struct CSimpleREOcLeaf
|
||||
{
|
||||
TArray<SMeshFace> * m_Faces;
|
||||
CMatInfo * m_pChunk;
|
||||
class CSimpleLeafBuffer * m_pBuffer;
|
||||
|
||||
CSimpleREOcLeaf() {memset(this,0,sizeof(CSimpleREOcLeaf));}
|
||||
~CSimpleREOcLeaf()
|
||||
{
|
||||
delete m_Faces;
|
||||
}
|
||||
};
|
||||
|
||||
struct CBasis
|
||||
{
|
||||
CBasis()
|
||||
{
|
||||
tangent(0,0,0);
|
||||
binormal(0,0,0);
|
||||
tnormal(0,0,0);
|
||||
}
|
||||
Vec3d tangent, binormal, tnormal;
|
||||
};
|
||||
|
||||
class CSimpleLeafBuffer
|
||||
{
|
||||
public:
|
||||
CSimpleLeafBuffer(IRCLog * pLog, CIndexedMesh * pIndexedMesh, bool bStripifyAndShareVerts, bool bKeepRemapTable=false);
|
||||
~CSimpleLeafBuffer();
|
||||
bool Serialize(int & nPos, uchar * pSerBuf, bool bSave, const char * szFolderName);
|
||||
// CBasis * m_pBasises;
|
||||
|
||||
protected:
|
||||
void CreateLeafBuffer( CIndexedMesh * pTriData, int Stripify, bool bShareVerts, bool bKeepRemapTable=false );
|
||||
Vec3d *m_TempNormals;
|
||||
SMRendTexVert *m_TempTexCoords;
|
||||
UCol *m_TempColors;
|
||||
int m_SecVertCount;
|
||||
list2<CMatInfo> * m_pMats;
|
||||
|
||||
IRCLog * m_pLog;
|
||||
|
||||
bool compute_tangent( const float * v0, const float * v1, const float * v2,
|
||||
const float * t0, const float * t1, const float * t2,
|
||||
Vec3d & tangent, Vec3d & binormal, Vec3d & tnormal, Vec3d & face_normal);
|
||||
|
||||
void CompactBuffer(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F * _vbuff, int * _vcount,
|
||||
list2<unsigned short> * pindices, bool bShareVerts[128], uint *uiInfo, CBasis * pBasises);
|
||||
|
||||
list2<unsigned short> *m_pIndices, *m_pIndicesPreStrip;
|
||||
void *m_pD3DIndBuf;
|
||||
list2<unsigned short> & GetIndices() { return *m_pIndices; }
|
||||
CVertexBuffer * m_pSecVertBuffer;
|
||||
void StripifyMesh(int StripType, CBasis *pTangNonStrip);
|
||||
void CalcFaceNormals();
|
||||
bool CreateTangBuffer(CBasis * pBasises);
|
||||
Vec3d * m_pLoadedColors;
|
||||
Vec3d m_vBoxMin, m_vBoxMax;
|
||||
int FindInBuffer(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F &opt, CBasis &origBasis, uint nMatInfo, uint *uiInfo, struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F* _vbuff, CBasis *_vbasis, int _vcount, list2<unsigned short> * pHash, TArray<uint>& ShareNewInfo);
|
||||
uint * m_arrVertStripMap;
|
||||
int m_nPrimetiveType;
|
||||
bool PrepareTexSpaceBasis();
|
||||
void CorrectTangentBasisesForPolyBump( TangData * pDuplTangData = 0);
|
||||
|
||||
CSimpleLeafBuffer *m_pVertexContainer;
|
||||
CVertexBuffer * m_pVertexBuffer;
|
||||
uint * m_arrVtxMap; //!< [Anton] mapping table leaf buffer vertex idx->original vertex idx
|
||||
|
||||
_inline CSimpleLeafBuffer *GetVertexContainer(void)
|
||||
{
|
||||
if (m_pVertexContainer)
|
||||
return m_pVertexContainer;
|
||||
return this;
|
||||
}
|
||||
|
||||
byte *GetNormalPtr(int& Stride, int Id=0, bool bSys=true)
|
||||
{
|
||||
CSimpleLeafBuffer *lb = GetVertexContainer();
|
||||
byte *pData;
|
||||
SBufInfoTable * pOffs;
|
||||
if (bSys)
|
||||
{
|
||||
pData = (byte *)lb->m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
pOffs = &gBufInfoTable[lb->m_pSecVertBuffer->m_vertexformat];
|
||||
Stride = m_VertexSize[lb->m_pSecVertBuffer->m_vertexformat];
|
||||
}
|
||||
else
|
||||
{
|
||||
pData = (byte *)lb->m_pVertexBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
pOffs = &gBufInfoTable[lb->m_pVertexBuffer->m_vertexformat];
|
||||
Stride = m_VertexSize[lb->m_pVertexBuffer->m_vertexformat];
|
||||
}
|
||||
if (pOffs->OffsNormal)
|
||||
{
|
||||
return &pData[Id*Stride+pOffs->OffsNormal];
|
||||
}
|
||||
|
||||
Stride = sizeof(Vec3d);
|
||||
return (byte*)&lb->m_TempNormals[Id];
|
||||
}
|
||||
|
||||
byte *GetPosPtr(int& Stride, int Id=0, bool bSys=true)
|
||||
{
|
||||
CSimpleLeafBuffer *lb = GetVertexContainer();
|
||||
byte *pData;
|
||||
if (bSys)
|
||||
{
|
||||
pData = (byte *)lb->m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
Stride = m_VertexSize[lb->m_pSecVertBuffer->m_vertexformat];
|
||||
}
|
||||
else
|
||||
{
|
||||
pData = (byte *)lb->m_pVertexBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
Stride = m_VertexSize[lb->m_pVertexBuffer->m_vertexformat];
|
||||
}
|
||||
return &pData[Id*Stride];
|
||||
}
|
||||
|
||||
byte *GetBinormalPtr(int& Stride, int Id=0, bool bSys=true)
|
||||
{
|
||||
CSimpleLeafBuffer *lb = GetVertexContainer();
|
||||
byte *pData;
|
||||
if (bSys)
|
||||
{
|
||||
pData = (byte *)lb->m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData;
|
||||
}
|
||||
else
|
||||
{
|
||||
pData = (byte *)lb->m_pVertexBuffer->m_VS[VSF_TANGENTS].m_VData;
|
||||
}
|
||||
Stride = sizeof(SPipTangents);
|
||||
return &pData[Id*Stride+12];
|
||||
}
|
||||
byte *GetTangentPtr(int& Stride, int Id=0, bool bSys=true)
|
||||
{
|
||||
CSimpleLeafBuffer *lb = GetVertexContainer();
|
||||
byte *pData;
|
||||
if (bSys)
|
||||
{
|
||||
pData = (byte *)lb->m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData;
|
||||
}
|
||||
else
|
||||
{
|
||||
pData = (byte *)lb->m_pVertexBuffer->m_VS[VSF_TANGENTS].m_VData;
|
||||
}
|
||||
Stride = sizeof(SPipTangents);
|
||||
return &pData[Id*Stride];
|
||||
}
|
||||
byte *GetTNormalPtr(int& Stride, int Id=0, bool bSys=true)
|
||||
{
|
||||
CSimpleLeafBuffer *lb = GetVertexContainer();
|
||||
byte *pData;
|
||||
if (bSys)
|
||||
{
|
||||
pData = (byte *)lb->m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData;
|
||||
}
|
||||
else
|
||||
{
|
||||
pData = (byte *)lb->m_pVertexBuffer->m_VS[VSF_TANGENTS].m_VData;
|
||||
}
|
||||
Stride = sizeof(SPipTangents);
|
||||
return &pData[Id*Stride+24];
|
||||
}
|
||||
|
||||
byte *GetColorPtr(int & Stride, int Id=0, bool bSys=true)
|
||||
{
|
||||
CSimpleLeafBuffer *lb = GetVertexContainer();
|
||||
SBufInfoTable * pOffs;
|
||||
byte *pData;
|
||||
if (bSys)
|
||||
{
|
||||
pData = (byte *)lb->m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
pOffs = &gBufInfoTable[lb->m_pSecVertBuffer->m_vertexformat];
|
||||
Stride = m_VertexSize[lb->m_pSecVertBuffer->m_vertexformat];
|
||||
}
|
||||
else
|
||||
{
|
||||
pData = (byte *)lb->m_pVertexBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
pOffs = &gBufInfoTable[lb->m_pVertexBuffer->m_vertexformat];
|
||||
Stride = m_VertexSize[lb->m_pVertexBuffer->m_vertexformat];
|
||||
}
|
||||
if (pOffs->OffsColor)
|
||||
{
|
||||
return &pData[Id*Stride+pOffs->OffsColor];
|
||||
}
|
||||
|
||||
Stride = sizeof(UCol);
|
||||
return (byte*)&lb->m_TempColors[Id];
|
||||
}
|
||||
|
||||
byte *GetUVPtr(int & Stride, int Id=0, bool bSys=true)
|
||||
{
|
||||
CSimpleLeafBuffer *lb = GetVertexContainer();
|
||||
SBufInfoTable * pOffs;
|
||||
byte *pData;
|
||||
if (bSys)
|
||||
{
|
||||
pData = (byte *)lb->m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
pOffs = &gBufInfoTable[lb->m_pSecVertBuffer->m_vertexformat];
|
||||
Stride = m_VertexSize[m_pSecVertBuffer->m_vertexformat];
|
||||
}
|
||||
else
|
||||
{
|
||||
pData = (byte *)lb->m_pVertexBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
pOffs = &gBufInfoTable[lb->m_pVertexBuffer->m_vertexformat];
|
||||
Stride = m_VertexSize[m_pVertexBuffer->m_vertexformat];
|
||||
}
|
||||
if (pOffs->OffsTC)
|
||||
{
|
||||
return &pData[Id*Stride+pOffs->OffsTC];
|
||||
}
|
||||
|
||||
Stride = sizeof(SMRendTexVert);
|
||||
return (byte*)&lb->m_TempTexCoords[Id];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CSimpleStatObj
|
||||
{
|
||||
public:
|
||||
CSimpleStatObj(IRCLog * pLog, CIndexedMesh * pTriData, const char*pGeomName)
|
||||
{
|
||||
memset(this,0,sizeof(CSimpleStatObj));
|
||||
m_pLog = pLog;
|
||||
m_pTriData = pTriData;
|
||||
m_pGeomName = (char *)pGeomName;
|
||||
Physicalize();
|
||||
InitGeometry();
|
||||
}
|
||||
void Serialize(int & nPos, uchar * pSerBuf, bool bSave);
|
||||
bool IsPhysicsExist();
|
||||
|
||||
protected:
|
||||
int FindInPosBuffer(const Vec3d & opt, Vec3d * _vbuff, int _vcount, list2<int> * pHash);
|
||||
void CompactPosBuffer(Vec3d * _vbuff, int * _vcount, list2<int> * pindices);
|
||||
|
||||
void Physicalize();
|
||||
void InitGeometry();
|
||||
IRCLog * m_pLog;
|
||||
CIndexedMesh * m_pTriData;
|
||||
char * m_pGeomName;
|
||||
|
||||
// output
|
||||
list2<Vec3d> m_lstProxyVerts[3];
|
||||
list2<int> m_lstProxyInds[3];
|
||||
Vec3d m_vProxyBoxMin[3];
|
||||
Vec3d m_vProxyBoxMax[3];
|
||||
list2<unsigned char> m_lstProxyFaceMaterials[3];
|
||||
|
||||
Vec3d m_vBoxMin, m_vBoxMax;
|
||||
|
||||
list2<struct StatHelperInfo> m_lstHelpers;
|
||||
list2<CDLight> m_lstLSources;
|
||||
};
|
||||
|
||||
#endif
|
||||
913
ResourceCompilerPC/StatCGFCompiler/StatCGFCompilerLB.cpp
Normal file
913
ResourceCompilerPC/StatCGFCompiler/StatCGFCompilerLB.cpp
Normal file
@@ -0,0 +1,913 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: StatCGFCompiler.cpp
|
||||
// Version: v1.00
|
||||
// Created: 5/11/2002 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Dbghelp.h"
|
||||
#include "FileUtil.h"
|
||||
#include "PathUtil.h"
|
||||
#include "..\ResourceCompilerPC.h"
|
||||
|
||||
#include "StatCGFCompiler.h"
|
||||
#include "CryChunkedFile.h"
|
||||
#include "CryHeaders.h"
|
||||
|
||||
#include "NvTriStrip\NvTriStrip.h"
|
||||
|
||||
#include "meshidx.h"
|
||||
#include <IShader.h>
|
||||
#include "Cry_Geo.h"
|
||||
|
||||
CSimpleLeafBuffer::CSimpleLeafBuffer(IRCLog * pLog, CIndexedMesh * pIndexedMesh, bool bStripifyAndShareVerts,bool bKeepRemapTable)
|
||||
{
|
||||
memset(this,0,sizeof(CSimpleLeafBuffer));
|
||||
m_pIndices = new list2<unsigned short>;
|
||||
m_pIndicesPreStrip = new list2<unsigned short>;
|
||||
m_pLog = pLog;
|
||||
|
||||
CreateLeafBuffer(pIndexedMesh,bStripifyAndShareVerts,bStripifyAndShareVerts,bKeepRemapTable);
|
||||
}
|
||||
|
||||
CSimpleLeafBuffer::~CSimpleLeafBuffer()
|
||||
{
|
||||
for (int i=0; m_pMats && i<m_pMats->Count(); i++)
|
||||
{
|
||||
delete (CSimpleREOcLeaf*)(m_pMats->Get(i)->pRE);
|
||||
m_pMats->Get(i)->pRE = 0;
|
||||
delete m_pMats->Get(i)->pMatEnt;
|
||||
m_pMats->Get(i)->pMatEnt=0;
|
||||
delete [] m_pMats->Get(i)->m_pPrimitiveGroups;
|
||||
m_pMats->Get(i)->m_pPrimitiveGroups=0;
|
||||
}
|
||||
|
||||
delete m_pIndices;
|
||||
delete m_pIndicesPreStrip;
|
||||
|
||||
delete m_TempNormals;
|
||||
delete m_TempTexCoords;
|
||||
delete m_TempColors;
|
||||
delete m_pMats;
|
||||
|
||||
delete m_pD3DIndBuf;
|
||||
delete m_pLoadedColors;
|
||||
delete m_arrVertStripMap;
|
||||
|
||||
if (m_pVertexBuffer)
|
||||
{
|
||||
delete m_pVertexBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
delete m_pVertexBuffer->m_VS[VSF_TANGENTS].m_VData;
|
||||
}
|
||||
|
||||
if (m_pSecVertBuffer)
|
||||
{
|
||||
delete m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
delete m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData;
|
||||
}
|
||||
|
||||
delete m_pVertexContainer;
|
||||
delete m_pVertexBuffer;
|
||||
delete m_pSecVertBuffer;
|
||||
|
||||
if (m_arrVtxMap)
|
||||
delete[] m_arrVtxMap;
|
||||
}
|
||||
|
||||
|
||||
void CSimpleLeafBuffer::CreateLeafBuffer( CIndexedMesh * pTriData, int Stripify, bool bShareVerts, bool bKeepRemapTable )
|
||||
{
|
||||
m_pLog->Log("Processing geometry");
|
||||
|
||||
int max_vert_num = pTriData->m_nFaceCount*3;
|
||||
|
||||
int i;
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F * pVBuff = new struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F[max_vert_num];
|
||||
CBasis * pTmpTangBasis = new CBasis[max_vert_num];
|
||||
|
||||
int buff_vert_count = 0;
|
||||
uint *uiInfo = new uint[max_vert_num];
|
||||
|
||||
uint *piVtxIdx = 0; // [Anton] need this to build the mapping table leafbuffer vtx idx->original vtx idx
|
||||
if (bKeepRemapTable)
|
||||
piVtxIdx = new uint[max_vert_num];
|
||||
m_arrVtxMap = 0;
|
||||
|
||||
// . Sort|Group faces by materials
|
||||
// For each shader (designated by shader_id of an element of m_pFaces)
|
||||
// there is one list2 in this table. Each list will contain
|
||||
// set of faces belonging to this shader.
|
||||
list2<CObjFace*> _hash_table[512];
|
||||
bool bShareVertsArr[512];
|
||||
|
||||
m_pMats = new list2<CMatInfo>;
|
||||
m_pMats->PreAllocate(pTriData->m_lstMatTable.Count(),pTriData->m_lstMatTable.Count());
|
||||
*m_pMats = pTriData->m_lstMatTable;
|
||||
|
||||
{ // fill the table: one list of faces per one shader
|
||||
for(int i=0; i<pTriData->m_nFaceCount; i++)
|
||||
{
|
||||
CObjFace * pFace = &pTriData->m_pFaces[i];
|
||||
|
||||
char szMatName[128];
|
||||
strncpy(szMatName, m_pMats->GetAt(pFace->shader_id).pMatEnt->name, 128);
|
||||
strlwr(szMatName);
|
||||
if(strstr(szMatName,"(nodraw)") || strstr(szMatName,"(no_draw)"))
|
||||
continue;
|
||||
|
||||
assert(pFace->shader_id>=0 && pFace->shader_id<512);
|
||||
|
||||
if(pFace->shader_id>=m_pMats->Count())
|
||||
{
|
||||
pFace->shader_id=0;
|
||||
m_pLog->Log("CLeafBuffer::CreateBuffer shader_id of face is out of range");
|
||||
}
|
||||
|
||||
_hash_table[pFace->shader_id].Add(pFace);
|
||||
}
|
||||
}
|
||||
|
||||
// . Create vertex buffer with sequence of (possibly non-unique) vertices, 3 verts per face
|
||||
// for each shader..
|
||||
for (int t = 0; t < m_pMats->Count(); t++)
|
||||
{
|
||||
// memorize the starting index of this material's face range
|
||||
(*m_pMats)[t].nFirstIndexId = buff_vert_count;
|
||||
|
||||
// scan through all the faces using the shader #t
|
||||
for(int i=0; i<_hash_table[t].Count(); ++i)
|
||||
{
|
||||
CObjFace * pFace = _hash_table[t][i];
|
||||
|
||||
assert(pFace->shader_id == t);
|
||||
|
||||
for (int v = 0; v < 3; ++v)
|
||||
{
|
||||
if(pTriData->m_pColor)
|
||||
{ // if color exported - copy from pTriData
|
||||
pVBuff[buff_vert_count].color.bcolor[0] = pTriData->m_pColor[pFace->v[v]].r;
|
||||
pVBuff[buff_vert_count].color.bcolor[1] = pTriData->m_pColor[pFace->v[v]].g;
|
||||
pVBuff[buff_vert_count].color.bcolor[2] = pTriData->m_pColor[pFace->v[v]].b;
|
||||
pVBuff[buff_vert_count].color.bcolor[3] = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
pVBuff[buff_vert_count].color.dcolor = -1;
|
||||
}
|
||||
|
||||
// base tex coord
|
||||
int tid = pFace->t[v];
|
||||
if(tid>=0 && tid<pTriData->m_nCoorCount)
|
||||
{
|
||||
pVBuff[buff_vert_count].st[0] = pTriData->m_pCoors[pFace->t[v]].s;
|
||||
pVBuff[buff_vert_count].st[1] = pTriData->m_pCoors[pFace->t[v]].t;
|
||||
}
|
||||
else
|
||||
{
|
||||
pVBuff[buff_vert_count].st[0] = 0;
|
||||
pVBuff[buff_vert_count].st[1] = 0;
|
||||
}
|
||||
|
||||
// normal
|
||||
pVBuff[buff_vert_count].normal = pTriData->m_pNorms[pFace->n[v]];
|
||||
uiInfo[buff_vert_count] = 0;
|
||||
|
||||
// position
|
||||
pVBuff[buff_vert_count].xyz = pTriData->m_pVerts[pFace->v[v]];
|
||||
|
||||
// remember shader id per face to prevent vertex sharing between materials during recompacting
|
||||
uiInfo[buff_vert_count] |= pFace->shader_id;
|
||||
bShareVertsArr[pFace->shader_id] = bShareVerts;
|
||||
|
||||
// [Anton] keep index list to build mapping table later
|
||||
if (piVtxIdx)
|
||||
piVtxIdx[buff_vert_count] = pFace->v[v];
|
||||
|
||||
// tang basis
|
||||
pTmpTangBasis[buff_vert_count] = pTriData->m_pTangBasis[pFace->b[v]];
|
||||
|
||||
buff_vert_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// there are faces belonging to this material(shader) #t, if number of indices > 0
|
||||
(*m_pMats)[t].nNumIndices = buff_vert_count - (*m_pMats)[t].nFirstIndexId;
|
||||
_hash_table[t].Reset();
|
||||
}
|
||||
|
||||
// make REs
|
||||
for (i=0; i<(*m_pMats).Count(); i++)
|
||||
{
|
||||
if((*m_pMats)[i].nNumIndices)
|
||||
{
|
||||
CSimpleREOcLeaf *re = new CSimpleREOcLeaf; // (CRE OcLeaf *)gRenDev->EF_CreateRE(eDATA_OcLeaf);
|
||||
re->m_pChunk = &(*m_pMats)[i];
|
||||
re->m_pBuffer = this;
|
||||
assert (re->m_pChunk->nNumIndices < 60000);
|
||||
re->m_pChunk->pRE = (CREOcLeaf*)re;
|
||||
|
||||
// always enable sharing if there is 'flareproc' in shader/material name
|
||||
if (!bShareVertsArr[i] && (*m_pMats)[i].nNumIndices == 6)
|
||||
{
|
||||
char nameSh[128];
|
||||
strncpy(nameSh, (*m_pMats)[i].pMatEnt->name,sizeof(nameSh));
|
||||
strlwr(nameSh);
|
||||
bShareVertsArr[i] = strstr(nameSh, "flareproc")!=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// . For each (non-unique) vertex calculate the tangent base
|
||||
/* m_pBasises = buff_vert_count ? new CBasis[buff_vert_count] : 0;
|
||||
for (int n=0; n<buff_vert_count; n+=3)
|
||||
{
|
||||
Vec3d *vN0 = (Vec3d *)(&pVBuff[n+0].nx);
|
||||
Vec3d *vN1 = (Vec3d *)(&pVBuff[n+1].nx);
|
||||
Vec3d *vN2 = (Vec3d *)(&pVBuff[n+2].nx);
|
||||
Vec3d vFaceNormal = *vN0 + *vN1 + *vN2;
|
||||
vFaceNormal.Normalize();
|
||||
|
||||
float *v[3] =
|
||||
{
|
||||
(float *)&pVBuff[n+0].x,
|
||||
(float *)&pVBuff[n+1].x,
|
||||
(float *)&pVBuff[n+2].x,
|
||||
};
|
||||
|
||||
float *tc[3] =
|
||||
{
|
||||
(float *)&pVBuff[n+0].s,
|
||||
(float *)&pVBuff[n+1].s,
|
||||
(float *)&pVBuff[n+2].s,
|
||||
};
|
||||
|
||||
compute_tangent(v[0], v[1], v[2], tc[0], tc[1], tc[2], m_pBasises[n+0].tangent, m_pBasises[n+0].binormal, m_pBasises[n+0].tnormal, vFaceNormal);
|
||||
compute_tangent(v[1], v[2], v[0], tc[1], tc[2], tc[0], m_pBasises[n+1].tangent, m_pBasises[n+1].binormal, m_pBasises[n+1].tnormal, vFaceNormal);
|
||||
compute_tangent(v[2], v[0], v[1], tc[2], tc[0], tc[1], m_pBasises[n+2].tangent, m_pBasises[n+2].binormal, m_pBasises[n+2].tnormal, vFaceNormal);
|
||||
}*/
|
||||
|
||||
// . Index the mesh (Compact Vertices): detect and delete duplicate vertices
|
||||
// remove duplicates
|
||||
if(buff_vert_count)
|
||||
CompactBuffer(pVBuff, &buff_vert_count, &GetIndices(), bShareVertsArr, uiInfo, pTmpTangBasis );
|
||||
|
||||
delete [] uiInfo;
|
||||
uiInfo=0;
|
||||
|
||||
for( i=0; i<GetIndices().Count(); i++ )
|
||||
{
|
||||
if(GetIndices()[i]<buff_vert_count)
|
||||
continue;
|
||||
|
||||
m_pLog->ThrowError("CLeafBuffer::CreateBuffer: Indices out of range");
|
||||
}
|
||||
|
||||
if (bKeepRemapTable) // [Anton] build the mapping table leaf buffer vertex index -> original vertex index
|
||||
{
|
||||
m_arrVtxMap = new uint[buff_vert_count];
|
||||
for( i=0; i<GetIndices().Count(); i++ )
|
||||
m_arrVtxMap[GetIndices()[i]] = piVtxIdx[i];
|
||||
delete[] piVtxIdx;
|
||||
}
|
||||
|
||||
if(buff_vert_count>65535)
|
||||
m_pLog->ThrowError("CLeafBuffer::CreateBuffer: Number of vertices in object is more than 65535");
|
||||
|
||||
// . Remove degenerated triangles in the generated mesh (GetIndices())
|
||||
// FIXME: For some reason this optimization doesn't work for Animated objects (Assertion in CryModelState::GenerateRenderArrays)
|
||||
/*if (!m_sSource || strcmp(m_sSource, "CryModelArray") != 0)
|
||||
{
|
||||
// Remove degenerated triangles
|
||||
list2<ushort> NewIndexes;
|
||||
for (i=0; i<(*m_pMats).Count(); i++) // each material..
|
||||
{
|
||||
CMatInfo *mi = &(*m_pMats)[i];
|
||||
if (!mi->pRE)
|
||||
continue;
|
||||
int nFirstInd = NewIndexes.Count();
|
||||
for (int j=mi->nFirstIndexId; j<mi->nFirstIndexId+mi->nNumIndices; j+=3)
|
||||
{
|
||||
// the face in material #i consists of vertices i0,i1,i2:
|
||||
int i0 = GetIndices()[j+0];
|
||||
int i1 = GetIndices()[j+1];
|
||||
int i2 = GetIndices()[j+2];
|
||||
// if the face is not degenerated, then add it; otherwise skip and finally it'll be deleted
|
||||
if (i0!=i1 && i0!=i2 && i1!=i2)
|
||||
{
|
||||
NewIndexes.Add(i0);
|
||||
NewIndexes.Add(i1);
|
||||
NewIndexes.Add(i2);
|
||||
}
|
||||
}
|
||||
mi->nFirstIndexId = nFirstInd;
|
||||
mi->nNumIndices = NewIndexes.Count() - nFirstInd;
|
||||
if (!mi->nNumIndices)
|
||||
{
|
||||
mi->pRE->Release();
|
||||
mi->pRE = NULL;
|
||||
}
|
||||
}
|
||||
GetIndices().Free();
|
||||
GetIndices().AddList(NewIndexes);
|
||||
NewIndexes.Free();
|
||||
}*/
|
||||
|
||||
// . Find vertex range (both index and spacial ranges) for each material (needed for rendering)
|
||||
for (i=0; i<(*m_pMats).Count(); i++)
|
||||
{
|
||||
CMatInfo *mi = &(*m_pMats)[i];
|
||||
if (!mi->pRE)
|
||||
continue;
|
||||
if (mi->nNumIndices+mi->nFirstIndexId > GetIndices().Count())
|
||||
{ assert(0); continue; }
|
||||
int nMin = 999999;
|
||||
int nMax = -999999;
|
||||
Vec3d vMin;
|
||||
Vec3d vMax;
|
||||
vMin=SetMaxBB();
|
||||
vMax=SetMinBB();
|
||||
for (int j=mi->nFirstIndexId; j<mi->nNumIndices+mi->nFirstIndexId; j++)
|
||||
{
|
||||
int ind = GetIndices()[j];
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *pV = &pVBuff[ind];
|
||||
Vec3d v = pV->xyz;
|
||||
vMin.CheckMin(v);
|
||||
vMax.CheckMax(v);
|
||||
nMin = min(nMin, ind);
|
||||
nMax = max(nMax, ind);
|
||||
}
|
||||
mi->m_vCenter = (vMin + vMax) * 0.5f;
|
||||
mi->m_fRadius = (vMin - mi->m_vCenter).Length();
|
||||
mi->nFirstVertId = nMin;
|
||||
mi->nNumVerts = nMax-nMin+1;
|
||||
}
|
||||
|
||||
// store resulting vertex buffer in system memory
|
||||
m_SecVertCount = buff_vert_count;
|
||||
m_pSecVertBuffer = new CVertexBuffer;
|
||||
m_pSecVertBuffer->m_vertexformat = VERTEX_FORMAT_P3F_N_COL4UB_TEX2F;
|
||||
if(m_SecVertCount)
|
||||
m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData = new struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F[m_SecVertCount];
|
||||
memcpy(m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData, pVBuff, m_SecVertCount*sizeof(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F));
|
||||
|
||||
delete [] pVBuff;
|
||||
pVBuff=0;
|
||||
|
||||
*m_pIndicesPreStrip = GetIndices();
|
||||
|
||||
if(m_SecVertCount)
|
||||
{
|
||||
if (Stripify!=STRIPTYPE_NONE && !bKeepRemapTable)
|
||||
StripifyMesh(Stripify,pTmpTangBasis);
|
||||
CalcFaceNormals();
|
||||
CreateTangBuffer(pTmpTangBasis);
|
||||
}
|
||||
|
||||
delete [] pTmpTangBasis;
|
||||
pTmpTangBasis=0;
|
||||
|
||||
// if colors was loaded - remember for later use
|
||||
if(pTriData->m_pColor)
|
||||
{
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F * pSecBuff = (struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *)m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
m_pLoadedColors = new Vec3d[m_SecVertCount];
|
||||
for(int i=0; i<m_SecVertCount; i++)
|
||||
{
|
||||
m_pLoadedColors[i].x = pSecBuff[i].color.bcolor[0];
|
||||
m_pLoadedColors[i].y = pSecBuff[i].color.bcolor[1];
|
||||
m_pLoadedColors[i].z = pSecBuff[i].color.bcolor[2];
|
||||
}
|
||||
}
|
||||
m_vBoxMin = pTriData->m_vBoxMin;
|
||||
m_vBoxMax = pTriData->m_vBoxMax;
|
||||
}
|
||||
|
||||
|
||||
void CSimpleLeafBuffer::CompactBuffer(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F * _vbuff, int * _vcount,
|
||||
list2<unsigned short> * pindices, bool bShareVerts[128], uint *uiInfo,
|
||||
CBasis * pBasises)
|
||||
{
|
||||
assert(*_vcount);
|
||||
if(!*_vcount)
|
||||
m_pLog->ThrowError("CLeafBuffer::CompactBuffer error");
|
||||
|
||||
int vert_num_before = *_vcount;
|
||||
|
||||
CBasis *tmp_basis = new CBasis[*_vcount];
|
||||
SMRendTexVert *tmp_lmtc = NULL;
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F * tmp_buff = new struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F[*_vcount];
|
||||
unsigned int tmp_count = 0;
|
||||
pindices->Clear();
|
||||
TArray<uint> ShareNewInfo;
|
||||
|
||||
list2<unsigned short> hash_table[256];//[256];
|
||||
|
||||
for(unsigned int v=0; v<(unsigned int)(*_vcount); v++)
|
||||
{
|
||||
int nHashInd = (unsigned char)(_vbuff[v].xyz.x*100);
|
||||
uint nMInfo = uiInfo[v];
|
||||
uint nMatId = nMInfo & 255;
|
||||
int find = bShareVerts[nMatId] ? FindInBuffer( _vbuff[v], pBasises[v], nMInfo, uiInfo, tmp_buff, tmp_basis, tmp_count, &hash_table[nHashInd], ShareNewInfo/*[(unsigned char)(_vbuff[v].pos.y*100)]*/) : -1;
|
||||
if(find<0)
|
||||
{ // not found
|
||||
tmp_buff[tmp_count] = _vbuff[v];
|
||||
tmp_basis[tmp_count] = pBasises[v];
|
||||
pindices->Add(tmp_count);
|
||||
ShareNewInfo.AddElem(uiInfo[v]);
|
||||
|
||||
hash_table[(unsigned char)(_vbuff[v].xyz.x*100)]/*[(unsigned char)(_vbuff[v].pos.y*100)]*/.Add(tmp_count);
|
||||
|
||||
tmp_count++;
|
||||
}
|
||||
else
|
||||
{ // found
|
||||
pindices->Add(find);
|
||||
}
|
||||
}
|
||||
|
||||
* _vcount = tmp_count;
|
||||
memcpy( _vbuff, tmp_buff, tmp_count*sizeof(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F));
|
||||
delete [] tmp_buff;
|
||||
|
||||
// pBasises will contain recompacted tangents now
|
||||
memcpy( pBasises, tmp_basis, tmp_count*sizeof(CBasis) );
|
||||
delete [] tmp_basis;
|
||||
|
||||
// SAFE_DELETE_ARRAY(pBasises);
|
||||
|
||||
int ratio = 100*(*_vcount)/vert_num_before;
|
||||
m_pLog->Log(" Vert buffer size after compression = %d %s ( %d -> %d )", ratio, "%", vert_num_before, *_vcount);
|
||||
}
|
||||
|
||||
#include "NvTriStrip/NVTriStrip.h"
|
||||
|
||||
void CSimpleLeafBuffer::StripifyMesh(int StripType, CBasis *pTangNonStrip)
|
||||
{
|
||||
int i;
|
||||
unsigned int n;
|
||||
|
||||
//Log("Stripify mesh...");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Stripping stuff
|
||||
|
||||
if (StripType == STRIPTYPE_DEFAULT)
|
||||
StripType = STRIPTYPE_ONLYLISTS;//CRenderer::CV_r_stripmesh;
|
||||
|
||||
if (StripType == STRIPTYPE_NONE)
|
||||
return;
|
||||
|
||||
m_pLog->Log(" Sorting vertices for GPU cache");
|
||||
|
||||
// if (gRenDev->GetFeatures() & RFT_HW_GF3)
|
||||
SetCacheSize(CACHESIZE_GEFORCE3);
|
||||
// else
|
||||
// SetCacheSize(CACHESIZE_GEFORCE1_2);
|
||||
if (StripType == STRIPTYPE_SINGLESTRIP)
|
||||
SetStitchStrips(true);
|
||||
else
|
||||
SetStitchStrips(false);
|
||||
SetMinStripSize(0);
|
||||
if (StripType == STRIPTYPE_ONLYLISTS)
|
||||
{
|
||||
SetListsOnly(true);
|
||||
SetStitchStrips(false);
|
||||
}
|
||||
else
|
||||
SetListsOnly(false);
|
||||
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *pVBOld = (struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *)m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *pVBNew = new struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F [m_SecVertCount];
|
||||
|
||||
CBasis *pTangOld = pTangNonStrip;
|
||||
CBasis *pTangNew = new CBasis[m_SecVertCount];
|
||||
|
||||
m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData = pVBNew;
|
||||
|
||||
// remember remapping
|
||||
m_arrVertStripMap = new uint [m_SecVertCount];
|
||||
memset(m_arrVertStripMap,256,sizeof(uint)*m_SecVertCount);
|
||||
|
||||
int vertFirst = 0;
|
||||
|
||||
list2<ushort> NewIndexes;
|
||||
|
||||
//stripify!
|
||||
for (i=0; i<(*m_pMats).Count(); i++)
|
||||
{
|
||||
CMatInfo *mi = &(*m_pMats)[i];
|
||||
if (!mi->pRE)
|
||||
continue;
|
||||
PrimitiveGroup* pOldPG;
|
||||
GenerateStrips(&GetIndices()[mi->nFirstIndexId], mi->nNumIndices, &pOldPG, (unsigned short*)&mi->m_dwNumSections);
|
||||
|
||||
//remap!
|
||||
PrimitiveGroup *pg;
|
||||
RemapIndices(pOldPG, mi->m_dwNumSections, m_SecVertCount, &pg);
|
||||
mi->m_pPrimitiveGroups = new SPrimitiveGroup[mi->m_dwNumSections];
|
||||
|
||||
int nMin = 999999;
|
||||
int nMax = -999999;
|
||||
|
||||
//loop through all indices, copying from oldVB -> newVB
|
||||
//note that this will do numIndices copies, instead of numVerts copies,
|
||||
// which is extraneous. Deal with it! ;-)
|
||||
int nFirstIndex = 0;
|
||||
mi->nFirstIndexId = NewIndexes.Count();
|
||||
for(int groupCtr = 0; groupCtr < mi->m_dwNumSections; groupCtr++)
|
||||
{
|
||||
mi->m_pPrimitiveGroups[groupCtr].type = pg[groupCtr].type;
|
||||
mi->m_pPrimitiveGroups[groupCtr].numIndices = pg[groupCtr].numIndices;
|
||||
mi->m_pPrimitiveGroups[groupCtr].offsIndex = nFirstIndex;
|
||||
mi->m_pPrimitiveGroups[groupCtr].numTris = 0;
|
||||
for(unsigned int indexCtr = 0; indexCtr < mi->m_pPrimitiveGroups[groupCtr].numIndices; indexCtr++)
|
||||
{
|
||||
//grab old index
|
||||
int oldVertex = pOldPG[groupCtr].indices[indexCtr];
|
||||
|
||||
//grab new index
|
||||
int newVertex = pg[groupCtr].indices[indexCtr] + vertFirst;
|
||||
NewIndexes.Add(newVertex);
|
||||
|
||||
nMin = min(nMin, newVertex);
|
||||
nMax = max(nMax, newVertex);
|
||||
|
||||
//copy from old -> new vertex buffer
|
||||
memcpy(&pVBNew[newVertex], &pVBOld[oldVertex], sizeof(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F));
|
||||
|
||||
//copy from old -> new tang buffer
|
||||
memcpy(&pTangNew[newVertex], &pTangOld[oldVertex], sizeof(CBasis));
|
||||
// if (pVBLMOld)
|
||||
// memcpy(&pVBLMNew[newVertex], &pVBLMOld[oldVertex], sizeof(SMRendTexVert));
|
||||
|
||||
// remember remaping
|
||||
m_arrVertStripMap[oldVertex] = newVertex;
|
||||
}
|
||||
nFirstIndex += mi->m_pPrimitiveGroups[groupCtr].numIndices;
|
||||
|
||||
SPrimitiveGroup *pgn = &mi->m_pPrimitiveGroups[groupCtr];
|
||||
int incr;
|
||||
switch (pgn->type)
|
||||
{
|
||||
case PT_LIST:
|
||||
incr = 3;
|
||||
break;
|
||||
case PT_STRIP:
|
||||
case PT_FAN:
|
||||
incr = 1;
|
||||
break;
|
||||
}
|
||||
int offs = pgn->offsIndex;
|
||||
for (n=0; n<pgn->numIndices-2; n+=incr)
|
||||
{
|
||||
int i0, i1, i2;
|
||||
switch (pgn->type)
|
||||
{
|
||||
case PT_LIST:
|
||||
i0 = pg[groupCtr].indices[offs+n];
|
||||
i1 = pg[groupCtr].indices[offs+n+1];
|
||||
i2 = pg[groupCtr].indices[offs+n+2];
|
||||
break;
|
||||
case PT_STRIP:
|
||||
i0 = pg[groupCtr].indices[offs+n];
|
||||
i1 = pg[groupCtr].indices[offs+n+1];
|
||||
i2 = pg[groupCtr].indices[offs+n+2];
|
||||
break;
|
||||
case PT_FAN:
|
||||
i0 = pg[groupCtr].indices[offs+0];
|
||||
i1 = pg[groupCtr].indices[offs+n+1];
|
||||
i2 = pg[groupCtr].indices[offs+n+2];
|
||||
break;
|
||||
}
|
||||
// ignore degenerate triangle
|
||||
if (i0==i1 || i0==i2 || i1==i2)
|
||||
continue;
|
||||
pgn->numTris++;
|
||||
}
|
||||
}
|
||||
mi->nNumIndices = nFirstIndex;
|
||||
mi->nFirstVertId = nMin;
|
||||
mi->nNumVerts = nMax-nMin+1;
|
||||
vertFirst += mi->nNumVerts;
|
||||
}
|
||||
m_nPrimetiveType = R_PRIMV_MULTI_GROUPS;
|
||||
|
||||
GetIndices().Free();
|
||||
GetIndices().AddList(NewIndexes);
|
||||
|
||||
delete [] pVBOld;
|
||||
|
||||
memcpy(pTangOld,pTangNew,sizeof(CBasis)*m_SecVertCount);
|
||||
delete [] pTangNew;
|
||||
}
|
||||
|
||||
void CSimpleLeafBuffer::CalcFaceNormals()
|
||||
{
|
||||
int i, j;
|
||||
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *pV = (struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *)m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
|
||||
if (m_nPrimetiveType != R_PRIMV_MULTI_GROUPS)
|
||||
{
|
||||
for (i=0; i<m_pMats->Count(); i++)
|
||||
{
|
||||
CMatInfo *mi = m_pMats->Get(i);
|
||||
CSimpleREOcLeaf * re = (CSimpleREOcLeaf *)mi->pRE;
|
||||
if (!re)
|
||||
continue;
|
||||
if (!re->m_Faces)
|
||||
re->m_Faces = new TArray<SMeshFace>;
|
||||
re->m_Faces->Free();
|
||||
int nOffs = mi->nFirstIndexId;
|
||||
for(j=0; j<mi->nNumIndices-2; j+=3)
|
||||
{
|
||||
unsigned short * face = &GetIndices()[j+nOffs];
|
||||
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *p0 = &pV[face[0]];
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *p1 = &pV[face[1]];
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *p2 = &pV[face[2]];
|
||||
Vec3d v0 = p0->xyz;
|
||||
Vec3d v1 = p1->xyz;
|
||||
Vec3d v2 = p2->xyz;
|
||||
Vec3d face_normal = (v0-v1) ^ (v0-v2);
|
||||
face_normal.Normalize();
|
||||
SMeshFace fn;
|
||||
fn.m_Normal = face_normal;
|
||||
fn.m_Middle = (v0 + v1 + v2) / 3.0f;
|
||||
re->m_Faces->AddElem(fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// assert(0);
|
||||
|
||||
unsigned int n;
|
||||
for (i=0; i<m_pMats->Count(); i++)
|
||||
{
|
||||
CMatInfo *mi = m_pMats->Get(i);
|
||||
CSimpleREOcLeaf *re = (CSimpleREOcLeaf*)mi->pRE;
|
||||
if (!re)
|
||||
continue;
|
||||
if (!re->m_Faces)
|
||||
re->m_Faces = new TArray<SMeshFace>;
|
||||
re->m_Faces->Free();
|
||||
int nOffs = mi->nFirstIndexId;
|
||||
for (j=0; j<mi->m_dwNumSections; j++)
|
||||
{
|
||||
SPrimitiveGroup *g = &mi->m_pPrimitiveGroups[j];
|
||||
g->nFirstFace = re->m_Faces->Num();
|
||||
int incr;
|
||||
switch (g->type)
|
||||
{
|
||||
case PT_LIST:
|
||||
incr = 3;
|
||||
break;
|
||||
case PT_STRIP:
|
||||
case PT_FAN:
|
||||
incr = 1;
|
||||
break;
|
||||
}
|
||||
int offs = g->offsIndex + nOffs;
|
||||
for (n=0; n<g->numIndices-2; n+=incr)
|
||||
{
|
||||
int i0, i1, i2;
|
||||
switch (g->type)
|
||||
{
|
||||
case PT_LIST:
|
||||
i0 = GetIndices()[offs+n];
|
||||
i1 = GetIndices()[offs+n+1];
|
||||
i2 = GetIndices()[offs+n+2];
|
||||
break;
|
||||
case PT_STRIP:
|
||||
i0 = GetIndices()[offs+n];
|
||||
i1 = GetIndices()[offs+n+1];
|
||||
i2 = GetIndices()[offs+n+2];
|
||||
break;
|
||||
case PT_FAN:
|
||||
i0 = GetIndices()[offs+0];
|
||||
i1 = GetIndices()[offs+n+1];
|
||||
i2 = GetIndices()[offs+n+2];
|
||||
break;
|
||||
}
|
||||
// ignore degenerate triangle
|
||||
if (i0==i1 || i0==i2 || i1==i2)
|
||||
continue;
|
||||
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *p0 = &pV[i0];
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *p1 = &pV[i1];
|
||||
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *p2 = &pV[i2];
|
||||
Vec3d v0 = p0->xyz;
|
||||
Vec3d v1 = p1->xyz;
|
||||
Vec3d v2 = p2->xyz;
|
||||
Vec3d face_normal = (v0-v1) ^ (v0-v2);
|
||||
face_normal.Normalize();
|
||||
|
||||
SMeshFace fn;
|
||||
fn.m_Normal = face_normal;
|
||||
fn.m_Middle = (v0 + v1 + v2) / 3.0f;
|
||||
re->m_Faces->AddElem(fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CSimpleLeafBuffer::CreateTangBuffer(CBasis * pBasises)
|
||||
{
|
||||
// if (!m_pBasises)
|
||||
// PrepareTexSpaceBasis();
|
||||
assert(pBasises);
|
||||
|
||||
SAFE_DELETE_ARRAY(m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData);
|
||||
// if (!m_pBasises)
|
||||
// return false;
|
||||
m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData = new SPipTangents[m_SecVertCount];
|
||||
SPipTangents *tn = (SPipTangents *)m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData;
|
||||
for (int i=0; i<m_SecVertCount; i++)
|
||||
{
|
||||
tn[i].m_Tangent[0] = pBasises[i].tangent[0];
|
||||
tn[i].m_Tangent[1] = pBasises[i].tangent[1];
|
||||
tn[i].m_Tangent[2] = pBasises[i].tangent[2];
|
||||
|
||||
tn[i].m_Binormal[0] = pBasises[i].binormal[0];
|
||||
tn[i].m_Binormal[1] = pBasises[i].binormal[1];
|
||||
tn[i].m_Binormal[2] = pBasises[i].binormal[2];
|
||||
|
||||
tn[i].m_TNormal[0] = pBasises[i].tnormal[0];
|
||||
tn[i].m_TNormal[1] = pBasises[i].tnormal[1];
|
||||
tn[i].m_TNormal[2] = pBasises[i].tnormal[2];
|
||||
}
|
||||
|
||||
// CorrectTangentBasisesForPolyBump();
|
||||
|
||||
// Temporary basis vectors
|
||||
// delete [] m_pBasises;
|
||||
// m_pBasises = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define PIP_TEX_EPS 0.001f
|
||||
#define PIP_VER_EPS 0.001f
|
||||
|
||||
bool struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F::operator == (struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F & other)
|
||||
{
|
||||
assert(this != &other);
|
||||
|
||||
return fabs(xyz.x-other.xyz.x)<PIP_VER_EPS && fabs(xyz.y-other.xyz.y)<PIP_VER_EPS && fabs(xyz.z-other.xyz.z)<PIP_VER_EPS &&
|
||||
fabs(normal.x-other.normal.x)<PIP_VER_EPS && fabs(normal.y-other.normal.y)<PIP_VER_EPS && fabs(normal.z-other.normal.z)<PIP_VER_EPS &&
|
||||
fabs(st[0]-other.st[0])<PIP_TEX_EPS && fabs(st[1]-other.st[1])<PIP_TEX_EPS &&
|
||||
(color.dcolor&0xffffff) == (other.color.dcolor&0xffffff);
|
||||
}
|
||||
|
||||
int CSimpleLeafBuffer::FindInBuffer(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F &opt, CBasis &origBasis, uint nMatInfo, uint *uiInfo, struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F* _vbuff, CBasis *_vbasis, int _vcount, list2<unsigned short> * pHash, TArray<uint>& ShareNewInfo)
|
||||
{
|
||||
for(int i=0; i<pHash->Count(); i++)
|
||||
{
|
||||
int id = (*pHash)[i];
|
||||
if(_vbuff[id] == opt)
|
||||
{
|
||||
if (ShareNewInfo[id] != nMatInfo)
|
||||
continue;
|
||||
if (origBasis.binormal.Dot(_vbasis[id].binormal) > 0.5f && origBasis.tangent.Dot(_vbasis[id].tangent) > 0.5f)
|
||||
return (*pHash)[i];
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CSimpleLeafBuffer::CorrectTangentBasisesForPolyBump( TangData * pDuplTangData )
|
||||
{
|
||||
TArray <bool> bUsedVerts;
|
||||
|
||||
int nBinormalStride=0, nTangentStride=0, nTNormalStride=0;
|
||||
byte * pBinormal = GetBinormalPtr(nBinormalStride, 0, true);
|
||||
byte * pTangent = GetTangentPtr(nTangentStride, 0, true);
|
||||
byte * pTNormal = GetTNormalPtr(nTNormalStride, 0, true);
|
||||
|
||||
bUsedVerts.Reserve(GetIndices().Count());
|
||||
|
||||
for(int m=0; m<m_pMats->Count(); m++)
|
||||
{
|
||||
CMatInfo *pMI = m_pMats->Get(m);
|
||||
if(!(pMI->m_Flags & MIF_POLYBUMP))
|
||||
continue; // not polybump
|
||||
|
||||
bool bCloneSpace = false;
|
||||
if (pMI->shaderItem.m_pShaderResources)
|
||||
{
|
||||
SRenderShaderResources *sr = pMI->shaderItem.m_pShaderResources;
|
||||
if (sr->m_Textures[EFTT_BUMP] && sr->m_Textures[EFTT_BUMP]->m_TU.m_ITexPic && bCloneSpace)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_nPrimetiveType != R_PRIMV_MULTI_GROUPS)
|
||||
{
|
||||
int nStart = pMI->nFirstIndexId;
|
||||
int nEnd = nStart + pMI->nNumIndices;
|
||||
|
||||
assert(nEnd <= GetIndices().Count());
|
||||
|
||||
for( int i = nStart; i<nEnd; i++ )
|
||||
{
|
||||
int nVertId = GetIndices()[i];
|
||||
if (bUsedVerts[nVertId])
|
||||
continue;
|
||||
bUsedVerts[nVertId] = true;
|
||||
|
||||
Vec3d vBin, vTan, vTnor;
|
||||
if(pMI->m_Flags & MIF_INVPOLYBUMP)
|
||||
{
|
||||
vTan = Vec3d(1,0,0);
|
||||
vBin = Vec3d(0,1,0);
|
||||
vTnor = vTan.Cross(vBin);
|
||||
}
|
||||
else
|
||||
{
|
||||
vTan = Vec3d(-1,0,0);
|
||||
vBin = Vec3d(0,1,0);
|
||||
vTnor = vBin.Cross(vTan);
|
||||
}
|
||||
if ((UINT_PTR)pBinormal>256 && (UINT_PTR)pTangent>256)
|
||||
{
|
||||
Vec3d * vBinorm = (Vec3d *)&pBinormal[nBinormalStride*nVertId];
|
||||
Vec3d * vTang = (Vec3d *)&pTangent [nTangentStride*nVertId];
|
||||
Vec3d * vTNormal = (Vec3d *)&pTNormal [nTNormalStride*nVertId];
|
||||
|
||||
*vBinorm = vBin;
|
||||
*vTang = vTan;
|
||||
*vTNormal = vTnor;
|
||||
}
|
||||
|
||||
if (pDuplTangData)
|
||||
{
|
||||
// int sn = pGeomInfo->m_rDupVertToNorVert[nVertId];
|
||||
// assert(nVertId<pGeomInfo->m_nAllocatedTangNum);
|
||||
pDuplTangData[nVertId].binormal = vBin;
|
||||
pDuplTangData[nVertId].tangent = vTan;
|
||||
pDuplTangData[nVertId].tnormal = vTnor;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j=0; j<pMI->m_dwNumSections; j++)
|
||||
{
|
||||
SPrimitiveGroup *g = &pMI->m_pPrimitiveGroups[j];
|
||||
int offs = g->offsIndex+pMI->nFirstIndexId;
|
||||
for (uint n=0; n<g->numIndices; n++)
|
||||
{
|
||||
int nVertId = GetIndices()[n+offs];
|
||||
if (bUsedVerts[nVertId])
|
||||
continue;
|
||||
bUsedVerts[nVertId] = true;
|
||||
|
||||
Vec3d vBin, vTan, vTnor;
|
||||
if(pMI->m_Flags & MIF_INVPOLYBUMP)
|
||||
{
|
||||
vTan = Vec3d(1,0,0);
|
||||
vBin = Vec3d(0,1,0);
|
||||
vTnor = vTan.Cross(vBin);
|
||||
}
|
||||
else
|
||||
{
|
||||
vTan = Vec3d(-1,0,0);
|
||||
vBin = Vec3d(0,1,0);
|
||||
vTnor = vBin.Cross(vTan);
|
||||
}
|
||||
if ((UINT_PTR)pBinormal>256 && (UINT_PTR)pTangent>256)
|
||||
{
|
||||
Vec3d * vBinorm = (Vec3d *)&pBinormal[nBinormalStride*nVertId];
|
||||
Vec3d * vTang = (Vec3d *)&pTangent [nTangentStride*nVertId];
|
||||
Vec3d * vTNormal = (Vec3d *)&pTNormal [nTNormalStride*nVertId];
|
||||
|
||||
*vBinorm = vBin;
|
||||
*vTang = vTan;
|
||||
*vTNormal = vTnor;
|
||||
}
|
||||
|
||||
if (pDuplTangData)
|
||||
{
|
||||
// int sn = pGeomInfo->m_rDupVertToNorVert[nVertId];
|
||||
// assert(nVertId<pGeomInfo->m_nAllocatedTangNum);
|
||||
pDuplTangData[nVertId].binormal = vBin;
|
||||
pDuplTangData[nVertId].tangent = vTan;
|
||||
pDuplTangData[nVertId].tnormal = vTnor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bUsedVerts.Free();
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: LeafBufferSerialize.cpp
|
||||
// Version: v1.00
|
||||
// Created: 28/8/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: LeafBuffer serialization
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Dbghelp.h"
|
||||
#include "FileUtil.h"
|
||||
#include "PathUtil.h"
|
||||
#include "..\ResourceCompilerPC.h"
|
||||
|
||||
#include "StatCGFCompiler.h"
|
||||
#include "CryChunkedFile.h"
|
||||
#include "CryHeaders.h"
|
||||
|
||||
#include "meshidx.h"
|
||||
#include "IShader.h"
|
||||
#include "NvTriStrip\NvTriStrip.h"
|
||||
|
||||
#include "SerializeBuffer.h"
|
||||
|
||||
CryIRGB CF2IRGB(CFColor in)
|
||||
{
|
||||
CryIRGB out;
|
||||
out.r = uchar(in.r*255);
|
||||
out.g = uchar(in.g*255);
|
||||
out.b = uchar(in.b*255);
|
||||
return out;
|
||||
}
|
||||
|
||||
char *SkipPath (char *pathname)
|
||||
{
|
||||
char *last;
|
||||
|
||||
last = pathname;
|
||||
while (*pathname)
|
||||
{
|
||||
if (*pathname=='/' || *pathname=='\\')
|
||||
last = pathname+1;
|
||||
pathname++;
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
int CSimpleLeafBuffer__SetTexType(TextureMap3 *tm)
|
||||
{
|
||||
if (tm->type == TEXMAP_CUBIC)
|
||||
return eTT_Cubemap;
|
||||
else
|
||||
if (tm->type == TEXMAP_AUTOCUBIC)
|
||||
return eTT_AutoCubemap;
|
||||
return eTT_Base;
|
||||
}
|
||||
|
||||
bool CSimpleLeafBuffer::Serialize(int & nPos, uchar * pSerBuf, bool bSave, const char * szFolderName)
|
||||
{
|
||||
assert(bSave);
|
||||
|
||||
SaveBuffer("LeafBuffer", 11, pSerBuf, nPos);
|
||||
|
||||
SaveBuffer(&m_SecVertCount, sizeof(m_SecVertCount), pSerBuf, nPos);
|
||||
|
||||
SaveBuffer( m_arrVertStripMap, m_SecVertCount*sizeof(m_arrVertStripMap[0]), pSerBuf, nPos);
|
||||
GetIndices().SaveToBuffer(pSerBuf, nPos);
|
||||
m_pIndicesPreStrip->SaveToBuffer(pSerBuf, nPos);
|
||||
SaveBuffer(&m_nPrimetiveType, sizeof(m_nPrimetiveType), pSerBuf, nPos);
|
||||
// assert(m_pBasises==0); // not needed
|
||||
SaveBuffer( m_pLoadedColors, m_SecVertCount*sizeof(m_pLoadedColors[0]), pSerBuf, nPos);
|
||||
m_pMats->SaveToBuffer(pSerBuf, nPos); // need to restore
|
||||
|
||||
// save shader info
|
||||
for (int i=0; i<m_pMats->Count(); i++)
|
||||
{
|
||||
MAT_ENTITY * pMatEnt = m_pMats->Get(i)->pMatEnt;
|
||||
SaveBuffer(pMatEnt, sizeof(*pMatEnt), pSerBuf, nPos);
|
||||
|
||||
if(m_pMats->GetAt(i).pRE)
|
||||
{
|
||||
assert(((CSimpleREOcLeaf*)m_pMats->GetAt(i).pRE)->m_pChunk->nNumIndices);
|
||||
assert(((CSimpleREOcLeaf*)m_pMats->GetAt(i).pRE)->m_pChunk == m_pMats->Get(i));
|
||||
}
|
||||
|
||||
// save primitive groups
|
||||
if(m_pMats->GetAt(i).m_dwNumSections)
|
||||
SaveBuffer((void*)m_pMats->GetAt(i).m_pPrimitiveGroups,
|
||||
sizeof(SPrimitiveGroup)*m_pMats->GetAt(i).m_dwNumSections,
|
||||
pSerBuf, nPos);
|
||||
}
|
||||
|
||||
SaveBuffer( m_pSecVertBuffer, sizeof(*m_pSecVertBuffer), pSerBuf, nPos); // need to restore
|
||||
SaveBuffer( m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData, m_SecVertCount*m_VertexSize[m_pSecVertBuffer->m_vertexformat], pSerBuf, nPos);
|
||||
SaveBuffer( m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData, m_SecVertCount*sizeof(SPipTangents), pSerBuf, nPos);
|
||||
|
||||
assert(!m_pVertexBuffer); // not needed
|
||||
SaveBuffer(&m_vBoxMax, sizeof(m_vBoxMax), pSerBuf, nPos);
|
||||
SaveBuffer(&m_vBoxMin, sizeof(m_vBoxMin), pSerBuf, nPos);
|
||||
|
||||
// [Anton] m_arrVtxMap serialization
|
||||
int bHasVtxMap;
|
||||
if (m_arrVtxMap)
|
||||
{
|
||||
SaveBuffer(&(bHasVtxMap=1),sizeof(bHasVtxMap), pSerBuf,nPos);
|
||||
SaveBuffer(m_arrVtxMap,sizeof(uint)*m_SecVertCount, pSerBuf,nPos);
|
||||
}
|
||||
else
|
||||
SaveBuffer(&(bHasVtxMap=0),sizeof(bHasVtxMap), pSerBuf,nPos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
100
ResourceCompilerPC/StatCGFCompiler/StatCGFShadVol.cpp
Normal file
100
ResourceCompilerPC/StatCGFCompiler/StatCGFShadVol.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "StdAfx.h"
|
||||
#include "statcgfshadvol.h"
|
||||
|
||||
#include "meshidx.h"
|
||||
#include "IEdgeConnectivityBuilder.h"
|
||||
#include "..\StencilShadowConnectivity.h"
|
||||
#include "..\StencilShadowConnectivityBuilder.h"
|
||||
|
||||
CStatCGFShadVol::CStatCGFShadVol(ILog * pLog, CIndexedMesh * pIndexedMesh)
|
||||
{
|
||||
m_pShadowVolObject = new CShadowVolObject( pLog );
|
||||
|
||||
for (int i=0; i<pIndexedMesh->m_nFaceCount; i++)
|
||||
{
|
||||
CObjFace *cf=&pIndexedMesh->m_pFaces[i];
|
||||
|
||||
for (int v=0; v<3; v++)
|
||||
{
|
||||
cf->m_Vecs[v].x=pIndexedMesh->m_pVerts[pIndexedMesh->m_pFaces[i].v[v]].x;
|
||||
cf->m_Vecs[v].y=pIndexedMesh->m_pVerts[pIndexedMesh->m_pFaces[i].v[v]].y;
|
||||
cf->m_Vecs[v].z=pIndexedMesh->m_pVerts[pIndexedMesh->m_pFaces[i].v[v]].z;
|
||||
} //v
|
||||
|
||||
//calc plane equation
|
||||
cf->m_Plane.CalcPlane(cf->m_Vecs[2],cf->m_Vecs[1],cf->m_Vecs[0]);
|
||||
} //i
|
||||
|
||||
//precalc edges
|
||||
m_pShadowVolObject->CreateConnectivityInfo(pIndexedMesh, pLog);
|
||||
}
|
||||
|
||||
CStatCGFShadVol::~CStatCGFShadVol()
|
||||
{
|
||||
delete m_pShadowVolObject;
|
||||
}
|
||||
|
||||
#define FLAG_SKIP_SHADOWVOLUME 1 // todo: share this flag
|
||||
|
||||
void CShadowVolObject::CreateConnectivityInfo( CIndexedMesh * pIndexedMesh, ILog * pLog )
|
||||
{
|
||||
//list of faces is shared from statobj
|
||||
m_pFaceList = pIndexedMesh->m_pFaces;
|
||||
m_nNumFaces = pIndexedMesh->m_nFaceCount;
|
||||
Vec3d *pVert = pIndexedMesh->m_pVerts;
|
||||
|
||||
IEdgeConnectivityBuilder * iBuilder = new CStencilShadowStaticConnectivityBuilder();
|
||||
iBuilder->Reinit();
|
||||
|
||||
assert(iBuilder);
|
||||
|
||||
iBuilder->ReserveForTriangles(m_nNumFaces,pIndexedMesh->m_nVertCount);
|
||||
|
||||
for(int i=0;i<m_nNumFaces;i++)
|
||||
{
|
||||
CObjFace *cf = &m_pFaceList[i];
|
||||
|
||||
if(cf->m_dwFlags & FLAG_SKIP_SHADOWVOLUME)
|
||||
continue;
|
||||
|
||||
// with welding
|
||||
unsigned short a=cf->v[0],b=cf->v[1],c=cf->v[2];
|
||||
iBuilder->AddTriangleWelded(a,b,c,pVert[a],pVert[b],pVert[c]);
|
||||
}
|
||||
|
||||
m_pEdgeConnectivity = iBuilder->ConstructConnectivity();
|
||||
|
||||
#ifdef _DEBUG
|
||||
if(m_pEdgeConnectivity)
|
||||
{
|
||||
DWORD dwVertCount,dwTriCount;
|
||||
|
||||
m_pEdgeConnectivity->GetStats(dwVertCount,dwTriCount);
|
||||
|
||||
pLog->Log(" StencilEdgeConnectivity Stats:");
|
||||
pLog->Log(" %d/%d Vertices %d/%d Faces",dwVertCount,pIndexedMesh->m_nVertCount,dwTriCount,m_nNumFaces);
|
||||
}
|
||||
#endif
|
||||
|
||||
delete iBuilder;
|
||||
}
|
||||
|
||||
CShadowVolObject::~CShadowVolObject()
|
||||
{
|
||||
if(m_pEdgeConnectivity)
|
||||
{
|
||||
m_pEdgeConnectivity->Release();
|
||||
m_pEdgeConnectivity=0;
|
||||
}
|
||||
}
|
||||
|
||||
void CStatCGFShadVol::Serialize(int & nPos, void * pStream, bool bSave)
|
||||
{
|
||||
byte* pTarget = pStream ? (byte*)pStream+nPos : NULL;
|
||||
IStencilShadowConnectivity* pConnectivity = m_pShadowVolObject->GetEdgeConnectivity();
|
||||
// NOTE: passing a big number is not a good practice here, because in debug mode
|
||||
// it validates the buffers size and can detect buffer overruns early and painlessly.
|
||||
// a good practice is passing the actual number of bytes available in ths target buffer
|
||||
|
||||
nPos += pConnectivity->Serialize(bSave, pTarget, 100000000);
|
||||
}
|
||||
81
ResourceCompilerPC/StatCGFCompiler/StatCGFShadVol.h
Normal file
81
ResourceCompilerPC/StatCGFCompiler/StatCGFShadVol.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
class CShadowVolObject //: public CVolume
|
||||
{
|
||||
public:
|
||||
|
||||
// constructor
|
||||
CShadowVolObject(ILog * pSystem)
|
||||
{
|
||||
m_pFaceList=NULL;
|
||||
m_pReMeshShadow=NULL;
|
||||
m_pSystemVertexBuffer=NULL;
|
||||
m_pEdgeConnectivity=0;
|
||||
m_nNumVertices=0;
|
||||
m_nNumFaces=0;
|
||||
m_pSystem = pSystem;
|
||||
};
|
||||
|
||||
ILog * m_pSystem;
|
||||
|
||||
//! destructor
|
||||
~CShadowVolObject();
|
||||
|
||||
//!
|
||||
bool CheckInside(const Vec3d &pos,bool bWorldSpace=true)
|
||||
{
|
||||
//temporary return false...will be a cool AI game play feature to know
|
||||
//if we are in shadows
|
||||
return (false);
|
||||
}
|
||||
|
||||
//! precalculate the connectivity infos to build the object silouhette
|
||||
void CreateConnectivityInfo( CIndexedMesh * pIndexedMesh, ILog * pLog );
|
||||
|
||||
//! create/update a vertex buffer containing the shadow volume (for static lights)
|
||||
void RebuildDynamicShadowVolumeBuffer( const CDLight &lSource, struct IVisArea * pVisArea );// lSource has to be object relative
|
||||
|
||||
Vec3d * GetSysVertBufer() { return m_pSystemVertexBuffer; }
|
||||
|
||||
int GetNumVertices() { return(m_nNumVertices); }
|
||||
int GetNumFaces() { return(m_nNumFaces); }
|
||||
|
||||
// Shader RenderElements for stencil
|
||||
CRETriMeshShadow * m_pReMeshShadow; //!<
|
||||
|
||||
void CheckUnload();
|
||||
|
||||
class IStencilShadowConnectivity * GetEdgeConnectivity() { return m_pEdgeConnectivity; }
|
||||
|
||||
protected:
|
||||
|
||||
//! free the shadow volume buffers
|
||||
void FreeVertexBuffers();
|
||||
|
||||
//list of faces from source objects, its always shared from the stat obj
|
||||
int m_nNumFaces; //
|
||||
CObjFace *m_pFaceList; // pointer to MeshIdx faces [0..m_nNumFaces-1]
|
||||
|
||||
//list of edges...can be shared from another shadow vol object
|
||||
IStencilShadowConnectivity *m_pEdgeConnectivity; //!< stored edge connectivity for fast shadow edge extraction, could be 0, call ->Release() to free it
|
||||
|
||||
TFixedArray<unsigned short> m_arrIndices; //!<
|
||||
unsigned m_nNumVertices; //!< number of vertices in SystemBuffer
|
||||
|
||||
//!
|
||||
//! /param nNumIndices
|
||||
//! /param nNumVertices
|
||||
void PrepareShadowVolumeVertexBuffer( unsigned nNumIndices, unsigned nNumVertices );
|
||||
|
||||
//shadow volume renderer vertex buffer
|
||||
Vec3d * m_pSystemVertexBuffer;
|
||||
};
|
||||
|
||||
class CStatCGFShadVol
|
||||
{
|
||||
public:
|
||||
CStatCGFShadVol(ILog * pSystem, CIndexedMesh * pMesh);
|
||||
~CStatCGFShadVol(void);
|
||||
CShadowVolObject * m_pShadowVolObject;
|
||||
void Serialize(int & nPos, void * pStream, bool bSave);
|
||||
};
|
||||
8
ResourceCompilerPC/StatCGFCompiler/StatCGFShadowVolume.h
Normal file
8
ResourceCompilerPC/StatCGFCompiler/StatCGFShadowVolume.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
class StatCGFShadowVolume
|
||||
{
|
||||
public:
|
||||
StatCGFShadowVolume(void);
|
||||
~StatCGFShadowVolume(void);
|
||||
};
|
||||
245
ResourceCompilerPC/StatCGFCompiler/StatObj.h
Normal file
245
ResourceCompilerPC/StatCGFCompiler/StatObj.h
Normal file
@@ -0,0 +1,245 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: statobj.h
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef STAT_OBJ_H
|
||||
#define STAT_OBJ_H
|
||||
|
||||
const int FAR_TEX_COUNT = 24; // number of sprites per object
|
||||
const int FAR_TEX_ANGLE = (360/FAR_TEX_COUNT);
|
||||
const int FAR_TEX_SIZE = 64;
|
||||
|
||||
const int SHADOW_TEX_SIZE = 256;
|
||||
|
||||
class CIndexedMesh;
|
||||
class CCObject;
|
||||
|
||||
#include "../Cry3DEngine/Cry3DEngineBase.h"
|
||||
#include "list2.h"
|
||||
|
||||
struct CStatObjSV;
|
||||
struct ItShadowVolume;
|
||||
|
||||
#include "istatobj.h"
|
||||
|
||||
#define STATOBJ_EFT_PLANT (EFT_USER_FIRST+1)
|
||||
#define STATOBJ_EFT_PLANT_IN_SHADOW (EFT_USER_FIRST+2)
|
||||
|
||||
struct CStatObj : public Cry3DEngineBase, IStatObj
|
||||
{
|
||||
CStatObj(ISystem * pSystem);
|
||||
~CStatObj();
|
||||
|
||||
CIndexedMesh * m_pTriData;
|
||||
CIndexedMesh * GetTriData() { return m_pTriData; }
|
||||
|
||||
int m_nLoadedTrisCount;
|
||||
float GetCenterZ() { return m_vBoxMax.z*0.5f; }
|
||||
const Vec3d GetCenter() { return (m_vBoxMax+m_vBoxMin)*0.5f; }
|
||||
inline float GetRadius() { return m_fObjectRadius; }
|
||||
|
||||
char m_szFolderName[256];
|
||||
char m_szFileName [256];
|
||||
char m_szGeomName [256];
|
||||
|
||||
bool m_bDefaultObject;
|
||||
|
||||
TArray<int> m_lstShaderTemplates;
|
||||
TArray <SShaderParam> m_ShaderParams;
|
||||
|
||||
uint m_arrSpriteTexID[FAR_TEX_COUNT];
|
||||
|
||||
float m_fObjectRadius;
|
||||
|
||||
void InitParams(float sizeZ);
|
||||
|
||||
public:
|
||||
|
||||
// Loader
|
||||
bool LoadObject(const char * szFileName, const char * szGeomName, int Stripify, bool bLoadAdditinalInfo, bool bKeepInLocalSpace, bool bLoadLater = false);
|
||||
|
||||
//! Returns script material name
|
||||
virtual const char * GetScriptMaterialName(int Id=-1);
|
||||
|
||||
virtual void Render(const SRendParams & rParams, int nLodLevel=0);
|
||||
|
||||
//virtual void RenderModel(const RenderParams *pParams);
|
||||
virtual void RenderShadowVolumes(const SRendParams *pParams);
|
||||
|
||||
//! Refresh object ( reload shaders or/and object geometry )
|
||||
virtual void Refresh(int nFlags);
|
||||
|
||||
virtual bool SetShaderTemplate(int nTemplate, const char *TemplName, const char *ShaderName, bool bOnlyRegister=false);
|
||||
virtual void SetShaderFloat(const char *Name, float Val);
|
||||
//virtual void SetRefractFactor(float fRefr) { m_fRefractFactor = fRefr; }
|
||||
|
||||
//! set shadow volume
|
||||
ItShadowVolume *GetShadowVolume() { return (m_pSvObj);}
|
||||
|
||||
//! get shadow volume
|
||||
void SetShadowVolume(ItShadowVolume *pSvObj) { m_pSvObj=pSvObj;}
|
||||
|
||||
//Marco's NOTE: NEVER OVERRIDE THESE FLAGS!
|
||||
//! get flags
|
||||
int GetFlags() { return (m_dwFlags); }
|
||||
|
||||
//! set flags
|
||||
void SetFlags(int dwFlags) { m_dwFlags=dwFlags; }
|
||||
|
||||
//Marco's NOTE: NEVER OVERRIDE THESE FLAGS!
|
||||
//! get flags
|
||||
int GetFlags2() { return (m_dwFlags); }
|
||||
|
||||
//! set flags
|
||||
void SetFlags2(int dwFlags) { m_dwFlags2=dwFlags; }
|
||||
|
||||
|
||||
protected:
|
||||
void Physicalize();
|
||||
|
||||
void CreateModelFarImages(int nTexRes);
|
||||
|
||||
CLeafBuffer * m_pLeafBuffer;
|
||||
ItShadowVolume *m_pSvObj;
|
||||
int m_dwFlags,m_dwFlags2;
|
||||
|
||||
public:
|
||||
|
||||
CLeafBuffer * GetLeafBuffer() { return m_pLeafBuffer; };
|
||||
void SetLeafBuffer( CLeafBuffer *buf ) { m_pLeafBuffer = buf; };
|
||||
|
||||
Vec3d m_vBoxMin, m_vBoxMax, m_vBoxCenter;//, m_vGeometryAngles;
|
||||
phys_geometry * m_arrPhysGeomInfo[2];
|
||||
phys_geometry * GetPhysGeom(int n = 0) { return m_arrPhysGeomInfo[n]; }
|
||||
|
||||
const char *GetFolderName() { return (m_szFolderName); }
|
||||
const char *GetFileName() { return (m_szFileName); }
|
||||
const char *GetGeoName() { return (m_szGeomName); }
|
||||
bool IsSameObject(const char * szFileName, const char * szGeomName);
|
||||
|
||||
//set object's min/max bbox
|
||||
void SetBBoxMin(const Vec3d &vBBoxMin) { m_vBoxMin=vBBoxMin; }
|
||||
void SetBBoxMax(const Vec3d &vBBoxMax) { m_vBoxMax=vBBoxMax; }
|
||||
Vec3d & GetBoxMin() { return m_vBoxMin; }
|
||||
Vec3d & GetBoxMax() { return m_vBoxMax; }
|
||||
|
||||
int m_nUsers; // reference counter
|
||||
|
||||
ShadowMapLightSource * m_pSMLSource;
|
||||
|
||||
void MakeShadowMaps(const Vec3d vSunPos);
|
||||
|
||||
protected:
|
||||
void MakeBuffers(bool make_tree, int Stripify, char * szCompiledFileName);
|
||||
void MakeLeafBuffer( CIndexedMesh *mesh,bool bStripify=false );
|
||||
|
||||
void PrepareShadowMaps(const Vec3d & obj_pos, ShadowMapLightSource * pLSource);
|
||||
|
||||
public:
|
||||
// void DrawShadowMapOnTerrain(const Vec3d & pos, const float fScale, float fAlpha, struct IndexedVertexBuffer ** ppShadowGridBuffer, CTerrain * pTerrain, bool bLMapsGeneration);
|
||||
|
||||
int GetAllocatedBytes();
|
||||
// IndexedVertexBuffer * MakeShadowGridBuffer(const Vec3d & pos, const float fScale, ShadowMapFrustum*lf, bool translate_projection, CTerrain * pTerrain);
|
||||
void AddShadowPoint(int x, int y, list2<struct_VERTEX_FORMAT_P3F> * pList, CTerrain * pTerrain);
|
||||
|
||||
void SetCurDynMask(int nCurDynMask);
|
||||
|
||||
int FindInPosBuffer(const Vec3d & opt, Vec3d * _vbuff, int _vcount, list2<int> * pHash);
|
||||
void CompactPosBuffer(Vec3d * _vbuff, int * _vcount, list2<int> * pindices);
|
||||
|
||||
virtual Vec3d GetHelperPos(const char * szHelperName);
|
||||
virtual const char *GetHelperById(int nId, Vec3d & vPos, Matrix * pMat, int * pnType);
|
||||
virtual const Matrix * GetHelperMatrixByName(const char * szHelperName);
|
||||
|
||||
virtual void UpdateCustomLightingSpritesAndShadowMaps(float fStatObjAmbientLevel, int nTexRes);
|
||||
|
||||
//float m_fRefractFactor;
|
||||
float m_fRadiusHors;
|
||||
float m_fRadiusVert;
|
||||
// float m_fBending;
|
||||
// int m_nHideability;
|
||||
|
||||
float & GetRadiusVert() { return m_fRadiusVert; }
|
||||
float & GetRadiusHors() { return m_fRadiusHors; }
|
||||
|
||||
virtual void RegisterUser();
|
||||
virtual void UnregisterUser();
|
||||
|
||||
virtual bool IsDefaultObject() { return (m_bDefaultObject); }
|
||||
virtual bool MakeObjectPicture(UCHAR * pRGBAData, int nWidth);
|
||||
|
||||
#define MAX_STATOBJ_LODS_NUM 3
|
||||
CStatObj * m_arrpLowLODs[MAX_STATOBJ_LODS_NUM];
|
||||
void LoadLowLODs(int nStripify,bool bLoadAdditinalInfo,bool bKeepInLocalSpace);
|
||||
int m_nLoadedLodsNum;
|
||||
|
||||
// virtual int GetHideability() { return m_nHideability; }
|
||||
// virtual void SetHideability(int hideability);
|
||||
bool IsSpritesCreated() { return m_arrSpriteTexID[0]>0; }
|
||||
float GetDistFromPoint(const Vec3d & vPoint);
|
||||
int GetLoadedTrisCount() { return m_nLoadedTrisCount; }
|
||||
|
||||
list2<Vec3d> m_lstOcclVolVerts;
|
||||
list2<int> m_lstOcclVolInds;
|
||||
|
||||
virtual bool GetOcclusionVolume(list2<Vec3d> * & plstOcclVolVerts, list2<int> * & plstOcclVolInds)
|
||||
{
|
||||
plstOcclVolVerts = &m_lstOcclVolVerts;
|
||||
plstOcclVolInds = &m_lstOcclVolInds;
|
||||
|
||||
return m_lstOcclVolInds.Count() >= 3;
|
||||
}
|
||||
list2<struct HelperInfo> m_lstHelpers;
|
||||
list2<CDLight> m_lstLSources;
|
||||
bool Serialize(int & nPos, uchar * pSerBuf, bool bSave, char * szFolderName);
|
||||
|
||||
virtual void FreeTriData();
|
||||
// virtual void SetBending(float fBending);
|
||||
virtual const CDLight * GetLightSources(int nId);
|
||||
void RenderDebugInfo(const SRendParams & rParams, const class CCObject * pObj);
|
||||
void DrawMatrix(const Matrix & pMat);
|
||||
|
||||
//! Release method.
|
||||
void Release() { delete this; }
|
||||
void GetMemoryUsage(class ICrySizer* pSizer);
|
||||
int GetMemoryUsage();
|
||||
void SpawnParticles( ParticleParams & SpawnParticleParams, const Matrix & matWorldSpace, bool bOnlyUpLookingFaces );
|
||||
|
||||
// connectivity object that gets pre-computed for each model once and then
|
||||
// used to extract edge topology by the stencil shadowing module
|
||||
class IStencilShadowConnectivity* m_pStencilShadowConnectivity;
|
||||
// returns the cached connectivity object for stencil shadows
|
||||
class IStencilShadowConnectivity* getStencilShadowConnectivity( );
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// builds the connectivity object for stencil shadows
|
||||
// PARAMETERS:
|
||||
// iEdgeBuilder - the builder to use to create the connectivity info
|
||||
// pbCastShadow - the array of flags, 1 flag per 1 material, if the flag is true, then this material casts shadow, otherwise not
|
||||
// numMaterials - number of items in the pbCastShadow array
|
||||
void buildStencilShadowConnectivity (class IEdgeConnectivityBuilder *inpEdgeCon, const bool* pbCastShadow, unsigned numMaterials);
|
||||
void RenderShadowVolumes (const SRendParams *rParams, int nLimitLOD);
|
||||
void ShutDown();
|
||||
void Init();
|
||||
|
||||
// loading state
|
||||
int m_nStripify;
|
||||
bool m_bLoadAdditinalInfo;
|
||||
bool m_bKeepInLocalSpace;
|
||||
int m_nLastRendFrameId;
|
||||
bool m_bStreamable;
|
||||
static float m_fStreamingTimePerFrame;
|
||||
int m_nSpriteTexRes;
|
||||
};
|
||||
|
||||
#endif // STAT_OBJ_H
|
||||
768
ResourceCompilerPC/StatCGFCompiler/StatObjConstr.cpp
Normal file
768
ResourceCompilerPC/StatCGFCompiler/StatObjConstr.cpp
Normal file
@@ -0,0 +1,768 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: statobjconstr.cpp
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: loading
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "StatObj.h"
|
||||
#include "MeshIdx.h"
|
||||
#include "../RenderDll/Common/shadow_renderer.h"
|
||||
#include <irenderer.h>
|
||||
#include <I3dIndoorEngine.h>
|
||||
#include <CrySizer.h>
|
||||
|
||||
//#define USE_CCGF
|
||||
|
||||
float CStatObj::m_fStreamingTimePerFrame=0;
|
||||
|
||||
void CStatObj::Refresh(int nFlags)
|
||||
{
|
||||
if(nFlags & FRO_GEOMETRY)
|
||||
{
|
||||
bool bSpritesWasCreated = IsSpritesCreated();
|
||||
ShutDown();
|
||||
Init();
|
||||
bool bRes = LoadObject(m_szFileName, m_szGeomName[0] ? m_szGeomName : 0, m_nStripify, m_bLoadAdditinalInfo, m_bKeepInLocalSpace);
|
||||
if(bRes && bSpritesWasCreated)
|
||||
{
|
||||
Vec3d vColor = Get3DEngine()->GetAmbientColorFromPosition(Vec3d(-1000,-1000,-1000));
|
||||
UpdateCustomLightingSpritesAndShadowMaps(vColor.x, m_nSpriteTexRes);
|
||||
}
|
||||
|
||||
if(!bRes)
|
||||
{ // load default in case of error
|
||||
ShutDown();
|
||||
Init();
|
||||
LoadObject("Objects\\default.cgf", 0, m_nStripify, m_bLoadAdditinalInfo, m_bKeepInLocalSpace);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (nFlags & (FRO_TEXTURES | FRO_SHADERS))
|
||||
{
|
||||
CLeafBuffer *lb = m_pLeafBuffer;
|
||||
|
||||
for (int i=0; i<lb->m_pMats->Count(); i++)
|
||||
{
|
||||
IShader *e = (*lb->m_pMats)[i].shaderItem.m_pShader;
|
||||
if (e && (*lb->m_pMats)[i].pRE && (*lb->m_pMats)[i].nNumIndices)
|
||||
e->Reload(nFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CStatObj::LoadObject(const char * szFileName,
|
||||
const char*szGeomName,
|
||||
int nStripify,
|
||||
bool bLoadAdditinalInfo,
|
||||
bool bKeepInLocalSpace,
|
||||
bool bLoadLater)
|
||||
{
|
||||
if(!szFileName[0])
|
||||
{
|
||||
GetLog()->Log("Error: CStatObj::LoadObject: szFileName not specified");
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_nStripify = nStripify;
|
||||
m_bLoadAdditinalInfo = bLoadAdditinalInfo;
|
||||
m_bKeepInLocalSpace = bKeepInLocalSpace;
|
||||
m_bStreamable = bLoadLater;
|
||||
|
||||
if(bLoadLater)
|
||||
{ // define fake bbox
|
||||
Init();
|
||||
|
||||
m_vBoxMin = Vec3d(-1.f,-1.f,-1.f);
|
||||
m_vBoxMax = Vec3d( 1.f, 1.f, 1.f);
|
||||
m_vBoxCenter = Vec3d(0,0,0);
|
||||
m_fRadiusHors = m_fRadiusVert = 1.f;
|
||||
|
||||
// remember names
|
||||
strcpy(m_szFileName,szFileName);
|
||||
|
||||
if(szGeomName)
|
||||
strcpy(m_szGeomName,szGeomName);
|
||||
else
|
||||
m_szGeomName[0]=0;
|
||||
|
||||
strcpy(m_szFolderName,szFileName);
|
||||
while(m_szFolderName[0])
|
||||
{ // make folder name
|
||||
if(m_szFolderName[strlen(m_szFolderName)-1] == '\\' || m_szFolderName[strlen(m_szFolderName)-1] == '/')
|
||||
{ m_szFolderName[strlen(m_szFolderName)-1]=0; break; }
|
||||
m_szFolderName[strlen(m_szFolderName)-1]=0;
|
||||
}
|
||||
|
||||
m_nLoadedTrisCount = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FILE * f = 0;
|
||||
|
||||
#ifdef USE_CCGF
|
||||
|
||||
char szCompiledFileNameFull[512];
|
||||
{
|
||||
char szCompiledFileName[512]="";
|
||||
strcpy(szCompiledFileName,szFileName);
|
||||
|
||||
while(strstr(szCompiledFileName,"\\") || strstr(szCompiledFileName,"/"))
|
||||
strcpy(szCompiledFileName,szCompiledFileName+1);
|
||||
|
||||
while(strstr(szCompiledFileName,"."))
|
||||
szCompiledFileName[strlen(szCompiledFileName)-1]=0;
|
||||
|
||||
strcat( szCompiledFileName, "_" );
|
||||
strcat( szCompiledFileName, szGeomName ? szGeomName : "NoGeom" );
|
||||
strcat( szCompiledFileName, ".ccgf" );
|
||||
|
||||
snprintf(szCompiledFileNameFull, "CCGF\\%s", szCompiledFileName);
|
||||
}
|
||||
|
||||
f = fopen(szCompiledFileNameFull, "rb");
|
||||
|
||||
#endif // USE_CCGF
|
||||
|
||||
if(!f || szGeomName)
|
||||
{ // compile object and save to disk
|
||||
strcpy(m_szFileName,szFileName);
|
||||
|
||||
if(szGeomName)
|
||||
strcpy(m_szGeomName,szGeomName);
|
||||
else
|
||||
m_szGeomName[0]=0;
|
||||
|
||||
strcpy(m_szFolderName,szFileName);
|
||||
while(m_szFolderName[0])
|
||||
{ // make folder name
|
||||
if(m_szFolderName[strlen(m_szFolderName)-1] == '\\' || m_szFolderName[strlen(m_szFolderName)-1] == '/')
|
||||
{ m_szFolderName[strlen(m_szFolderName)-1]=0; break; }
|
||||
m_szFolderName[strlen(m_szFolderName)-1]=0;
|
||||
}
|
||||
|
||||
m_nLoadedTrisCount = 0;
|
||||
m_pTriData = new CIndexedMesh( m_pSystem, szFileName, szGeomName, &m_nLoadedTrisCount, bLoadAdditinalInfo, bKeepInLocalSpace );
|
||||
if(!m_nLoadedTrisCount)
|
||||
{
|
||||
if(!szGeomName)
|
||||
return false;
|
||||
|
||||
int i;
|
||||
for(i=0; i<m_pTriData->m_lstGeomNames.Count(); i++)
|
||||
if(strcmp(m_pTriData->m_lstGeomNames[i],szGeomName)==0)
|
||||
break;
|
||||
|
||||
if(i>=m_pTriData->m_lstGeomNames.Count())
|
||||
return false;
|
||||
}
|
||||
|
||||
m_vBoxMin = m_pTriData->m_vBoxMin;
|
||||
m_vBoxMax = m_pTriData->m_vBoxMax;
|
||||
m_vBoxCenter = (m_vBoxMax+m_vBoxMin)/2;
|
||||
|
||||
// copy helpers
|
||||
m_lstHelpers.AddList(*m_pTriData->GetHelpers());
|
||||
|
||||
// copy lsources
|
||||
for(int i=0; i<m_pTriData->GetLightSourcesList()->Count(); i++)
|
||||
m_lstLSources.Add(*m_pTriData->GetLightSourcesList()->GetAt(i));
|
||||
|
||||
InitParams(m_pTriData->m_vBoxMax.z - m_pTriData->m_vBoxMin.z);
|
||||
|
||||
Physicalize(); // can change some indices/faces
|
||||
|
||||
// create vert buffers
|
||||
if(m_nLoadedTrisCount>30000)
|
||||
GetLog()->UpdateLoadingScreen(" Indexing huge vertex buffer ...");
|
||||
|
||||
MakeBuffers(szGeomName!=0, nStripify, 0);
|
||||
|
||||
for (int i=0; m_pLeafBuffer && m_pLeafBuffer->m_pMats && i<m_pLeafBuffer->m_pMats->Count(); i++)
|
||||
m_lstShaderTemplates.Add(-1);
|
||||
|
||||
if(m_nLoadedTrisCount>30000)
|
||||
GetLog()->UpdateLoadingScreen(" Indexed OK");
|
||||
|
||||
#ifdef USE_CCGF
|
||||
|
||||
delete m_pTriData;
|
||||
m_pTriData=0;
|
||||
|
||||
CreateDirectory("CCGF", 0);
|
||||
|
||||
// Save to file
|
||||
int nPos = 0;
|
||||
Serialize(nPos, 0, true, m_szFolderName);
|
||||
|
||||
uchar * pData = new uchar[nPos];
|
||||
nPos=0;
|
||||
Serialize(nPos, pData, true, m_szFolderName);
|
||||
|
||||
f = fopen(szCompiledFileNameFull,"wb");
|
||||
if(f)
|
||||
fwrite(pData,1,nPos,f);
|
||||
delete pData;
|
||||
|
||||
}
|
||||
else
|
||||
{ // load ready object from disk
|
||||
GetLog()->UpdateLoadingScreen("Loading compiled object: %s", szCompiledFileNameFull);
|
||||
|
||||
fseek(f,0,SEEK_END);
|
||||
int nSize = ftell(f);
|
||||
fseek(f,0,SEEK_SET);
|
||||
|
||||
uchar * pData = new uchar[nSize];
|
||||
int nReadedBytes = fread(pData,1,nSize,f);
|
||||
if(nReadedBytes != nSize)
|
||||
GetConsole()->Exit("Error: CStatObj::LoadObject: Error reading ccfg: %s", szCompiledFileNameFull);
|
||||
|
||||
nSize=0;
|
||||
Serialize(nSize, pData, false, m_szFolderName);
|
||||
assert(nReadedBytes == nSize);
|
||||
|
||||
delete pData;
|
||||
|
||||
#endif // USE_CCGF
|
||||
}
|
||||
|
||||
if(f)
|
||||
fclose(f);
|
||||
|
||||
// if(!szGeomName) // m_pTriData is needed only for indoors
|
||||
// FreeTriData();
|
||||
|
||||
// buildStencilShadowConnectivity (Get3DEngine()->GetNewStaticConnectivityBuilder(), 0, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CStatObj::FreeTriData()
|
||||
{
|
||||
delete m_pTriData;
|
||||
m_pTriData=0;
|
||||
}
|
||||
|
||||
const char * CStatObj::GetScriptMaterialName(int Id)
|
||||
{
|
||||
CLeafBuffer *lb = m_pLeafBuffer;
|
||||
if (Id < 0)
|
||||
{
|
||||
for (int i=0; i<lb->m_pMats->Count(); i++)
|
||||
{
|
||||
if ((*lb->m_pMats)[i].sScriptMaterial[0])
|
||||
return (*lb->m_pMats)[i].sScriptMaterial;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
if (Id < lb->m_pMats->Count() && (*lb->m_pMats)[Id].sScriptMaterial[0])
|
||||
return (*lb->m_pMats)[Id].sScriptMaterial;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CStatObj::InitParams(float sizeZ)
|
||||
{
|
||||
m_fObjectRadius = GetDistance(m_vBoxMin, m_vBoxMax)/2;
|
||||
|
||||
// calc vert/horis radiuses
|
||||
/* float dxh = GetBoxMax().x - GetBoxMin().x;
|
||||
float dyh = GetBoxMax().y - GetBoxMin().y;
|
||||
m_fRadiusHors = sqrtf(dxh*dxh+dyh*dyh)/2;
|
||||
m_fRadiusVert = GetBoxMax().z/2;*/
|
||||
|
||||
float dxh = (float)max( fabs(GetBoxMax().x), fabs(GetBoxMin().x));
|
||||
float dyh = (float)max( fabs(GetBoxMax().y), fabs(GetBoxMin().y));
|
||||
m_fRadiusHors = (float)sqrt(dxh*dxh+dyh*dyh);
|
||||
m_fRadiusVert = 0.01f + (GetBoxMax().z - GetBoxMin().z)*0.5f;
|
||||
}
|
||||
|
||||
CStatObj::CStatObj(ISystem * pSystem)
|
||||
{
|
||||
m_pSystem = pSystem;
|
||||
m_nUsers = 0; // referense counter
|
||||
|
||||
m_nStripify=0;
|
||||
m_bLoadAdditinalInfo=false;
|
||||
m_bKeepInLocalSpace=false;
|
||||
m_bStreamable=false;
|
||||
m_nSpriteTexRes=0;
|
||||
|
||||
ZeroStruct( m_szFolderName );
|
||||
ZeroStruct( m_szFileName );
|
||||
ZeroStruct( m_szGeomName );
|
||||
|
||||
m_pStencilShadowConnectivity=0;
|
||||
|
||||
m_nLastRendFrameId = 0;
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
void CStatObj::Init()
|
||||
{
|
||||
m_pTriData = 0;
|
||||
m_nLoadedTrisCount = 0;
|
||||
m_fObjectRadius = 0;
|
||||
m_pSvObj=NULL;
|
||||
m_dwFlags=m_dwFlags2=0;
|
||||
|
||||
ZeroStruct( m_arrSpriteTexID );
|
||||
|
||||
m_vBoxMin.Set(0,0,0);
|
||||
m_vBoxMax.Set(0,0,0);
|
||||
m_vBoxCenter.Set(0,0,0);
|
||||
memset(m_arrPhysGeomInfo, 0, sizeof(m_arrPhysGeomInfo));
|
||||
|
||||
m_pSMLSource = 0;
|
||||
|
||||
m_pLeafBuffer = 0;//GetRenderer()->CreateLe afBuffer("StatObj");
|
||||
|
||||
m_bDefaultObject=false;
|
||||
|
||||
memset(m_arrpLowLODs,0,sizeof(m_arrpLowLODs));
|
||||
|
||||
m_nLoadedLodsNum=1;
|
||||
}
|
||||
|
||||
CStatObj::~CStatObj()
|
||||
{
|
||||
ShutDown();
|
||||
}
|
||||
|
||||
void CStatObj::ShutDown()
|
||||
{
|
||||
if(!m_pSystem)
|
||||
return;
|
||||
|
||||
if(m_pTriData)
|
||||
m_pTriData->FreeLMInfo();
|
||||
delete m_pTriData;
|
||||
m_pTriData = 0;
|
||||
|
||||
for(int n=0; n<2; n++)
|
||||
if(m_arrPhysGeomInfo[n])
|
||||
GetPhysicalWorld()->GetGeomManager()->UnregisterGeometry(m_arrPhysGeomInfo[n]);
|
||||
|
||||
if(m_pSMLSource && m_pSMLSource->m_LightFrustums.Count() && m_pSMLSource->m_LightFrustums[0].pModelsList)
|
||||
delete m_pSMLSource->m_LightFrustums[0].pModelsList;
|
||||
delete m_pSMLSource;
|
||||
|
||||
if(m_pLeafBuffer && !m_pLeafBuffer->m_bMaterialsWasCreatedInRenderer)
|
||||
{
|
||||
for (int i=0; i<(*m_pLeafBuffer->m_pMats).Count(); i++)
|
||||
{
|
||||
if((*m_pLeafBuffer->m_pMats)[i].pRE)
|
||||
(*m_pLeafBuffer->m_pMats)[i].pRE->Release();
|
||||
}
|
||||
delete m_pLeafBuffer->m_pMats;
|
||||
m_pLeafBuffer->m_pMats=0;
|
||||
}
|
||||
|
||||
GetRenderer()->DeleteLeafBuffer(m_pLeafBuffer);
|
||||
m_pLeafBuffer=0;
|
||||
|
||||
for(int i=0; i<FAR_TEX_COUNT; i++)
|
||||
if(m_arrSpriteTexID[i])
|
||||
GetRenderer()->RemoveTexture(m_arrSpriteTexID[i]);
|
||||
|
||||
if (m_pSvObj)
|
||||
{
|
||||
m_pSvObj->Release();
|
||||
m_pSvObj=NULL;
|
||||
}
|
||||
|
||||
for(int i=0; i<MAX_STATOBJ_LODS_NUM; i++)
|
||||
delete m_arrpLowLODs[i];
|
||||
|
||||
m_ShaderParams.Free();
|
||||
}
|
||||
|
||||
/*
|
||||
void CStatObj::BuildOcTree()
|
||||
{
|
||||
if(!m_pTriData->m_nFaceCount || m_pTriData->m_nFaceCount<=2)
|
||||
return;
|
||||
|
||||
CBox parent_box( m_pTriData->m_vBoxMin, m_pTriData->m_vBoxMax );
|
||||
parent_box.max += 0.01f;
|
||||
parent_box.min +=-0.01f;
|
||||
|
||||
CObjFace ** allFaces = new CObjFace *[m_pTriData->m_nFaceCount];
|
||||
|
||||
for(int f=0; f<m_pTriData->m_nFaceCount; f++)
|
||||
{
|
||||
m_pTriData->m_pFaces[f].m_vCenter =
|
||||
(Vec3d(&m_pTriData->m_pVerts[m_pTriData->m_pFaces[f].v[0]].x) +
|
||||
Vec3d(&m_pTriData->m_pVerts[m_pTriData->m_pFaces[f].v[1]].x) +
|
||||
Vec3d(&m_pTriData->m_pVerts[m_pTriData->m_pFaces[f].v[2]].x))/3.f;
|
||||
|
||||
allFaces[f] = &m_pTriData->m_pFaces[f];
|
||||
}
|
||||
|
||||
const int max_tris_in_leaf = 2000;
|
||||
const float leaf_min_size = stricmp(m_szGeomName,"sector_0") ? 16.f : 32.f;
|
||||
|
||||
text_to_log(" Generating octree ... ");
|
||||
m_pOcTree = new octree_node( &parent_box, allFaces, triData->m_nFaceCount, triData, leaf_min_size, max_tris_in_leaf, 2);
|
||||
text_to_log_plus("%d leafs created", octree_node::static_current_leaf_id);
|
||||
m_pOcTree->update_bbox(triData);
|
||||
|
||||
delete [] allFaces;
|
||||
}*/
|
||||
|
||||
//float MakeBuffersTime = 0;
|
||||
|
||||
void CStatObj::MakeBuffers(bool make_tree, int nStripify, char * szCompiledFileName)
|
||||
{
|
||||
// float fTimeStart = GetTimer()->GetAsyncCurTime();
|
||||
/*
|
||||
FILE * f = fopen(szCompiledFileName,"rb");
|
||||
|
||||
if(f)
|
||||
{
|
||||
fseek(f,0,SEEK_END);
|
||||
int nSize = ftell(f);
|
||||
fseek(f,0,SEEK_SET);
|
||||
|
||||
uchar * pData = new uchar[nSize];
|
||||
int nReadedBytes = fread(pData,1,nSize,f);
|
||||
m_pLeafBuffer->Serialize(nSize, pData, false, m_szFolderName, m_nEFT_Flags);
|
||||
|
||||
delete pData;
|
||||
}
|
||||
else*/
|
||||
{
|
||||
assert(!m_pLeafBuffer);
|
||||
m_pLeafBuffer = GetRenderer()->CreateLeafBuffer(eBT_Static,"StatObj");
|
||||
|
||||
m_pLeafBuffer->m_pMats = new list2<CMatInfo>;
|
||||
m_pLeafBuffer->m_pMats->AddList(m_pTriData->m_lstMatTable);
|
||||
|
||||
if(m_pTriData->m_nFaceCount)
|
||||
{
|
||||
// m_pLeafBuffer->CreateBuffer(m_pTriData, nStripify, true);
|
||||
m_pLeafBuffer->CreateBuffer(m_pTriData, STRIPTYPE_NONE, false ); // no sorting for lightmaps
|
||||
}
|
||||
|
||||
/*
|
||||
int nSize = 0;
|
||||
m_pLeafBuffer->Serialize(nSize, 0, true, m_szFolderName, m_nEFT_Flags);
|
||||
|
||||
uchar * pData = new uchar[nSize];
|
||||
m_pLeafBuffer->Serialize(nSize, pData, true, m_szFolderName, m_nEFT_Flags);
|
||||
|
||||
f = fopen(szCompiledFileName,"wb");
|
||||
fwrite(pData,1,nSize,f);
|
||||
delete pData;*/
|
||||
}
|
||||
|
||||
//fclose(f);
|
||||
|
||||
// MakeBuffersTime += (GetTimer()->GetAsyncCurTime() - fTimeStart);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CStatObj::MakeLeafBuffer( CIndexedMesh *mesh,bool bStripify )
|
||||
{
|
||||
m_pTriData = mesh;
|
||||
if (m_pLeafBuffer)
|
||||
{
|
||||
// Delete old leaf buffer.
|
||||
GetRenderer()->DeleteLeafBuffer(m_pLeafBuffer);
|
||||
}
|
||||
m_pLeafBuffer = GetRenderer()->CreateLeafBuffer(eBT_Static,"StatObj");
|
||||
|
||||
m_pLeafBuffer->m_pMats = new list2<CMatInfo>;
|
||||
m_pLeafBuffer->m_pMats->AddList(m_pTriData->m_lstMatTable);
|
||||
|
||||
if(m_pTriData->m_nFaceCount)
|
||||
{
|
||||
// m_pLeafBuffer->CreateBuffer(m_pTriData, (bStripify)?1:0, true );
|
||||
m_pLeafBuffer->CreateBuffer(m_pTriData, STRIPTYPE_NONE, false ); // no sorting for lightmaps
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CStatObj::GetAllocatedBytes()
|
||||
{
|
||||
int size = sizeof(*this) + m_pTriData ? m_pTriData->GetAllocatedBytes() : 0;
|
||||
|
||||
// for(int i=0; i<MAX_TREE_LEAFS_NUM; i++)
|
||||
{
|
||||
size += m_pLeafBuffer->GetAllocatedBytes(false);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
Vec3d CStatObj::GetHelperPos(const char * szHelperName)
|
||||
{
|
||||
for(int i=0; i<m_lstHelpers.Count(); i++)
|
||||
if(!strcmp(m_lstHelpers[i].sName,szHelperName))
|
||||
return m_lstHelpers[i].tMat.GetTranslation();
|
||||
|
||||
return Vec3d(0,0,0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
const Matrix * CStatObj::GetHelperMatrixByName(const char * szHelperName)
|
||||
{
|
||||
for(int i=0; i<m_lstHelpers.Count(); i++)
|
||||
if(!strcmp(m_lstHelpers[i].sName,szHelperName))
|
||||
return &(m_lstHelpers[i].tMat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
const char *CStatObj::GetHelperById(int nId, Vec3d & vPos, Matrix * pMat, int * pnType)
|
||||
{
|
||||
if ( nId >= m_lstHelpers.Count() || nId<0 )
|
||||
return (NULL);
|
||||
|
||||
vPos = m_lstHelpers[nId].tMat.GetTranslation();
|
||||
|
||||
if(pnType)
|
||||
*pnType = m_lstHelpers[nId].nType;
|
||||
|
||||
if(pMat)
|
||||
*pMat = m_lstHelpers[nId].tMat;
|
||||
|
||||
return (m_lstHelpers[nId].sName);
|
||||
}
|
||||
|
||||
/*
|
||||
bool CStatObj::GetHelper(int id, char * szHelperName, int nMaxHelperNameSize, Vec3d * pPos, Vec3d * pRot)
|
||||
{
|
||||
if(id<0 || id>=triData->m_Helpers.Count())
|
||||
return false;
|
||||
|
||||
strncpy(szHelperName, triData->m_Helpers[id].name, nMaxHelperNameSize);
|
||||
*pPos = triData->m_Helpers[id].pos;
|
||||
*pRot = triData->m_Helpers[id].rot;
|
||||
return true;
|
||||
} */
|
||||
|
||||
void CStatObj::UpdateCustomLightingSpritesAndShadowMaps(float fStatObjAmbientLevel, int nTexRes)
|
||||
{
|
||||
m_nSpriteTexRes = nTexRes;
|
||||
Vec3d vLight = m_pSystem->GetI3DEngine()->GetSunPosition();
|
||||
vLight.Normalize();
|
||||
// Vec3d vColor = m_pSystem->GetI3DEngine()->GetWorldColor();
|
||||
float fSize = m_vBoxMax.z - m_vBoxMin.z;
|
||||
|
||||
// update lighting for full lod and lower lods
|
||||
m_pLeafBuffer->UpdateCustomLighting( vLight, fSize, fStatObjAmbientLevel );
|
||||
int nLowestLod=0;
|
||||
for(int nLodLevel=1; nLodLevel<MAX_STATOBJ_LODS_NUM; nLodLevel++)
|
||||
if(m_arrpLowLODs[nLodLevel])
|
||||
{
|
||||
m_arrpLowLODs[nLodLevel]->GetLeafBuffer()->UpdateCustomLighting( vLight, fSize, fStatObjAmbientLevel );
|
||||
nLowestLod = nLodLevel;
|
||||
}
|
||||
|
||||
// make sprites
|
||||
if(nLowestLod)
|
||||
{
|
||||
// clear sprites in full lod
|
||||
for(int i=0; i<FAR_TEX_COUNT; i++)
|
||||
if(m_arrSpriteTexID[i])
|
||||
{
|
||||
GetRenderer()->RemoveTexture(m_arrSpriteTexID[i]);
|
||||
m_arrSpriteTexID[i]=0;
|
||||
}
|
||||
|
||||
// make new sprites in low lod
|
||||
m_arrpLowLODs[nLowestLod]->CreateModelFarImages(nTexRes); // use lowest lod if present
|
||||
|
||||
// move sprite id from low inro into full lod
|
||||
memcpy(m_arrSpriteTexID, m_arrpLowLODs[nLowestLod]->m_arrSpriteTexID, sizeof(m_arrSpriteTexID));
|
||||
memset(m_arrpLowLODs[nLowestLod]->m_arrSpriteTexID, 0, sizeof(m_arrpLowLODs[nLowestLod]->m_arrSpriteTexID));
|
||||
}
|
||||
else
|
||||
CreateModelFarImages(nTexRes);
|
||||
|
||||
MakeShadowMaps(vLight);
|
||||
|
||||
// if(m_pTriData && !m_pTriData->m_lstLSources.Count())
|
||||
// FreeTriData();
|
||||
}
|
||||
|
||||
/*
|
||||
const char * CStatObj::GetPhysMaterialName(int nMatID)
|
||||
{
|
||||
if(m_pLeafBuffer && m_pLeafBuffer->m_pMats && nMatID < m_pLeafBuffer->m_pMats->Count())
|
||||
return m_pLeafBuffer->m_pMats->Get(nMatID)->szPhysMat;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CStatObj::SetPhysMaterialName(int nMatID, const char * szPhysMatName)
|
||||
{
|
||||
if(m_pLeafBuffer && m_pLeafBuffer->m_pMats && nMatID < m_pLeafBuffer->m_pMats->Count())
|
||||
{
|
||||
strncpy(m_pLeafBuffer->m_pMats->Get(nMatID)->szPhysMat, szPhysMatName, sizeof(m_pLeafBuffer->m_pMats->Get(nMatID)->szPhysMat));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
void CStatObj::RegisterUser()
|
||||
{
|
||||
m_nUsers++;
|
||||
}
|
||||
|
||||
void CStatObj::UnregisterUser()
|
||||
{
|
||||
m_nUsers--;
|
||||
}
|
||||
|
||||
void CStatObj::LoadLowLODs(int nStripify,bool bLoadAdditinalInfo,bool bKeepInLocalSpace)
|
||||
{
|
||||
if(m_szGeomName[0])
|
||||
return;
|
||||
|
||||
m_nLoadedLodsNum = 1;
|
||||
|
||||
for(int nLodLevel=1; nLodLevel<MAX_STATOBJ_LODS_NUM; nLodLevel++)
|
||||
{
|
||||
// make lod file name
|
||||
char sLodFileName[512];
|
||||
strncpy(sLodFileName, m_szFileName, sizeof(m_szFileName));
|
||||
sLodFileName[strlen(sLodFileName)-4]=0;
|
||||
strcat(sLodFileName,"_lod");
|
||||
char sLodNum[8];
|
||||
ltoa(nLodLevel,sLodNum,10);
|
||||
strcat(sLodFileName,sLodNum);
|
||||
strcat(sLodFileName,".cgf");
|
||||
|
||||
// try to load
|
||||
m_arrpLowLODs[nLodLevel] = new CStatObj(m_pSystem);
|
||||
bool bRes = fxopen(sLodFileName,"r") &&
|
||||
m_arrpLowLODs[nLodLevel]->LoadObject(sLodFileName, 0, nStripify, bLoadAdditinalInfo, bKeepInLocalSpace);
|
||||
|
||||
if(!bRes || m_arrpLowLODs[nLodLevel]->m_nLoadedTrisCount > m_nLoadedTrisCount / 1.8f)
|
||||
{
|
||||
if(bRes)
|
||||
GetLog()->Log("Error: CStatObj::LoadLowLODs: Low lod model contains too many polygons (more than half of original model, loading skipped): %s", sLodFileName);
|
||||
|
||||
delete m_arrpLowLODs[nLodLevel];
|
||||
m_arrpLowLODs[nLodLevel]=0;
|
||||
break;
|
||||
}
|
||||
m_nLoadedLodsNum++;
|
||||
}
|
||||
}
|
||||
|
||||
float CStatObj::GetDistFromPoint(const Vec3d & vPoint)
|
||||
{
|
||||
float fMinDist = 4096;
|
||||
for(int v=0; v<m_pTriData->m_nVertCount; v++)
|
||||
{
|
||||
float fDist = GetDistance(m_pTriData->m_pVerts[v],vPoint);
|
||||
if(fDist < fMinDist)
|
||||
fMinDist = fDist;
|
||||
}
|
||||
|
||||
return fMinDist;
|
||||
}
|
||||
|
||||
bool CStatObj::IsSameObject(const char * szFileName, const char * szGeomName)
|
||||
{
|
||||
// cmp object names
|
||||
if (szGeomName)
|
||||
{
|
||||
if(stricmp(szGeomName,m_szGeomName)!=0)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normilize file name
|
||||
char szFileNameNorm[MAX_PATH_LENGTH]="";
|
||||
char *pszDest = szFileNameNorm;
|
||||
const char *pszSource = szFileName;
|
||||
while (*pszSource)
|
||||
{
|
||||
if (*pszSource=='/')
|
||||
*pszDest++='\\';
|
||||
else
|
||||
*pszDest++=*pszSource;
|
||||
pszSource++;
|
||||
}
|
||||
*pszDest=0;
|
||||
|
||||
// cmp file names
|
||||
if(stricmp(szFileNameNorm,m_szFileName)!=0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
// SetHideability and SetBending will be removed from here
|
||||
#include "objman.h"
|
||||
#include "3dengine.h"
|
||||
|
||||
void CStatObj::SetHideability(int nHideability)
|
||||
{
|
||||
m_nHideability = nHideability;
|
||||
|
||||
list2<StatInstGroup> & TypeList = ((C3DEngine*)Get3DEngine())->GetObjManager()->m_lstStaticTypes;
|
||||
for(int i=0; i<TypeList.Count(); i++)
|
||||
if(TypeList[i].pStatObj == this)
|
||||
TypeList[i].bHideability = (nHideability!=0);
|
||||
}
|
||||
|
||||
void CStatObj::SetBending(float fBending)
|
||||
{
|
||||
m_fBending = fBending;
|
||||
|
||||
list2<StatInstGroup> & TypeList = ((C3DEngine*)Get3DEngine())->GetObjManager()->m_lstStaticTypes;
|
||||
for(int i=0; i<TypeList.Count(); i++)
|
||||
if(TypeList[i].pStatObj == this)
|
||||
TypeList[i].fBending = fBending;
|
||||
}
|
||||
*/
|
||||
|
||||
void CStatObj::GetMemoryUsage(ICrySizer* pSizer)
|
||||
{
|
||||
pSizer->AddObject(this,GetMemoryUsage());
|
||||
}
|
||||
|
||||
int CStatObj::GetMemoryUsage()
|
||||
{
|
||||
int nSize=0;
|
||||
|
||||
for(int i=0; i<MAX_STATOBJ_LODS_NUM; i++)
|
||||
if(m_arrpLowLODs[i])
|
||||
nSize += m_arrpLowLODs[i]->GetMemoryUsage();
|
||||
|
||||
nSize += m_lstHelpers.GetMemoryUsage();
|
||||
nSize += m_lstLSources.GetMemoryUsage();
|
||||
nSize += m_lstOcclVolInds.GetMemoryUsage();
|
||||
nSize += m_lstOcclVolVerts.GetMemoryUsage();
|
||||
nSize += m_lstShaderTemplates.GetMemoryUsage();
|
||||
nSize += m_pSMLSource ? sizeof(*m_pSMLSource) : 0;
|
||||
nSize += m_pSvObj ? m_pSvObj->GetMemoryUsage() : 0;
|
||||
nSize += m_pTriData ? m_pTriData->GetMemoryUsage() : 0;
|
||||
nSize += m_ShaderParams.GetMemoryUsage() + m_ShaderParams.Num()*sizeof(SShaderParam);
|
||||
|
||||
return nSize;
|
||||
}
|
||||
265
ResourceCompilerPC/StatCGFCompiler/StatObjPhys.cpp
Normal file
265
ResourceCompilerPC/StatCGFCompiler/StatObjPhys.cpp
Normal file
@@ -0,0 +1,265 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: statobjphys.cpp
|
||||
// Version: v1.00
|
||||
// Created: 28/5/2001 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description: make physical representation
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "StatObj.h"
|
||||
#include "MeshIdx.h"
|
||||
#include "3dengine.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// Buffer optimizer
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int CStatObj::FindInPosBuffer(const Vec3d & opt, Vec3d * _vbuff, int _vcount, list2<int> * pHash)
|
||||
{
|
||||
for(int i=0; i<pHash->Count(); i++)
|
||||
{
|
||||
if(
|
||||
IsEquivalent(*((Vec3d*)(&_vbuff[(*pHash)[i]].x)), *((Vec3d*)(&opt.x)), VEC_EPSILON)
|
||||
)
|
||||
return (*pHash)[i];
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CStatObj::CompactPosBuffer(Vec3d * _vbuff, int * _vcount, list2<int> * pindices)
|
||||
{
|
||||
int before = *_vcount; assert(before);
|
||||
if(!before)
|
||||
GetConsole()->Exit("Error: CStatObj::CompactPosBuffer: Input vertex count is zero");
|
||||
|
||||
Vec3d * tmp_buff = new Vec3d[*_vcount];
|
||||
int tmp_count = 0;
|
||||
|
||||
pindices->Clear();
|
||||
|
||||
list2<int> pos_hash_table[256];//[256];
|
||||
|
||||
for(uint v=0; v<(uint)(*_vcount); v++)
|
||||
{
|
||||
list2<int> * pHash = &pos_hash_table[(unsigned char)(_vbuff[v].x*100)];//[(unsigned char)(_vbuff[v].y*100)];
|
||||
int find = FindInPosBuffer( _vbuff[v], tmp_buff, tmp_count, pHash);
|
||||
if(find<0)
|
||||
{
|
||||
tmp_buff[tmp_count] = _vbuff[v];
|
||||
pindices->Add(tmp_count);
|
||||
|
||||
pos_hash_table[(unsigned char)(_vbuff[v].x*100)]/*[(unsigned char)(_vbuff[v].y*100)]*/.Add(tmp_count);
|
||||
|
||||
tmp_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int u = (uint)find;
|
||||
pindices->Add(u);
|
||||
}
|
||||
}
|
||||
|
||||
* _vcount = tmp_count;
|
||||
memcpy( _vbuff, tmp_buff, tmp_count*sizeof(Vec3d));
|
||||
|
||||
delete [] tmp_buff;
|
||||
}
|
||||
|
||||
// This function prepares 3 additional meshes:
|
||||
// usual physical representation(mat_phys or bounce koeff),
|
||||
// obstruct physical representation(mat_obstruct)
|
||||
// and occlusion volume(mat_occl).
|
||||
// Register physical stuff in physics engine.
|
||||
void CStatObj::Physicalize()
|
||||
{
|
||||
bool bShowINfo = (m_pTriData->m_nFaceCount>10000);
|
||||
|
||||
if(bShowINfo)
|
||||
GetLog()->UpdateLoadingScreen(" Creating buffer for physics ...");
|
||||
|
||||
// get phys material id's from game code
|
||||
IPhysMaterialEnumerator * pPhysMaterialEnumerator = ((C3DEngine*)Get3DEngine())->m_pPhysMaterialEnumerator;
|
||||
int i=0;
|
||||
for(i=0; pPhysMaterialEnumerator && i<m_pTriData->m_lstMatTable.Count(); i++)
|
||||
m_pTriData->m_lstMatTable[i].nGamePhysMatId = pPhysMaterialEnumerator->EnumPhysMaterial(m_pTriData->m_lstMatTable[i].sScriptMaterial);
|
||||
|
||||
// find mat id's
|
||||
int nPhysMatID = -1;
|
||||
int nObstrMatID = -1;
|
||||
int nOcclMatID = -1;
|
||||
|
||||
{
|
||||
// find phys material id
|
||||
for(int m=0; m<m_pTriData->m_lstMatTable.Count(); m++)
|
||||
if(strstr(m_pTriData->m_lstMatTable[m].sScriptMaterial,"mat_phys"))
|
||||
{
|
||||
nPhysMatID = m;
|
||||
break;
|
||||
}
|
||||
|
||||
// find obstruct material id
|
||||
for(int m=0; m<m_pTriData->m_lstMatTable.Count(); m++)
|
||||
if(strstr(m_pTriData->m_lstMatTable[m].sScriptMaterial,"mat_obstruct"))
|
||||
{
|
||||
nObstrMatID = m;
|
||||
break;
|
||||
}
|
||||
|
||||
// find occlusion material id
|
||||
for(int m=0; m<m_pTriData->m_lstMatTable.Count(); m++)
|
||||
if(strstr(m_pTriData->m_lstMatTable[m].sScriptMaterial,"mat_occl"))
|
||||
{
|
||||
nOcclMatID = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define MESH_PHYSIC 0
|
||||
#define MESH_OBSTRUCT 1
|
||||
#define MESH_OCCLUSION 2
|
||||
|
||||
for(int nMesh = 0; nMesh<=2; nMesh++)
|
||||
{ // fill physics indices
|
||||
list2<int> lstPhysIndices;
|
||||
list2<unsigned char> lstFaceMaterials;
|
||||
|
||||
if(nMesh == MESH_PHYSIC)
|
||||
{ // find all physicalized faces
|
||||
for(i=0; i<m_pTriData->m_nFaceCount; i++)
|
||||
{
|
||||
if( ((m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].m_Flags & MIF_PHYSIC) && nPhysMatID<0) ||
|
||||
m_pTriData->m_pFaces[i].shader_id == nPhysMatID )
|
||||
{
|
||||
for(int v=0; v<3; v++)
|
||||
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
|
||||
|
||||
lstFaceMaterials.Add(m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].nGamePhysMatId);
|
||||
|
||||
if(m_pTriData->m_pFaces[i].shader_id == nPhysMatID)
|
||||
{ // remove face from list (it's not needed for rendering)
|
||||
if(m_pTriData->m_nFaceCount>1)
|
||||
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
|
||||
m_pTriData->m_nFaceCount--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(nMesh == MESH_OBSTRUCT)
|
||||
{ // find all obstruct faces
|
||||
if(nObstrMatID>=0)
|
||||
{ // find all obstruct faces
|
||||
for(i=0; i<m_pTriData->m_nFaceCount; i++)
|
||||
{
|
||||
if(m_pTriData->m_pFaces[i].shader_id == nObstrMatID)
|
||||
{
|
||||
for(int v=0; v<3; v++)
|
||||
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
|
||||
|
||||
lstFaceMaterials.Add(m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].nGamePhysMatId);
|
||||
|
||||
// remove face from list (it's not needed for rendering)
|
||||
if(m_pTriData->m_nFaceCount>1)
|
||||
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
|
||||
m_pTriData->m_nFaceCount--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(nMesh == MESH_OCCLUSION)
|
||||
{
|
||||
if(nOcclMatID>=0)
|
||||
{ // find all occlusion faces
|
||||
for(i=0; i<m_pTriData->m_nFaceCount; i++)
|
||||
{
|
||||
if(m_pTriData->m_pFaces[i].shader_id == nOcclMatID)
|
||||
{
|
||||
for(int v=0; v<3; v++)
|
||||
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
|
||||
|
||||
lstFaceMaterials.Add(m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].nGamePhysMatId);
|
||||
|
||||
// remove face from list (it's not needed for rendering)
|
||||
if(m_pTriData->m_nFaceCount>1)
|
||||
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
|
||||
m_pTriData->m_nFaceCount--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(lstPhysIndices.Count())
|
||||
{
|
||||
Vec3d * pExVerts = new Vec3d[lstPhysIndices.Count()];
|
||||
|
||||
for(i=0; i<lstPhysIndices.Count();i++)
|
||||
pExVerts[i] = m_pTriData->m_pVerts[lstPhysIndices[i]];
|
||||
|
||||
if(bShowINfo)
|
||||
GetLog()->UpdateLoadingScreen(" Compacting buffer ...");
|
||||
|
||||
int init_count = lstPhysIndices.Count();
|
||||
CompactPosBuffer(pExVerts, &init_count, &lstPhysIndices);
|
||||
|
||||
if(bShowINfo)
|
||||
GetLog()->UpdateLoadingScreen(" Creating OBB tree ...");
|
||||
|
||||
if(GetPhysicalWorld() && (nMesh==MESH_PHYSIC || nMesh==MESH_OBSTRUCT))
|
||||
{
|
||||
IGeomManager *pGeoman = GetPhysicalWorld()->GetGeomManager();
|
||||
Vec3d ptmin=pExVerts[0],ptmax=pExVerts[0],sz;
|
||||
for(int i=1;i<lstPhysIndices.Count();i++)
|
||||
{
|
||||
ptmin.x = min(ptmin.x,pExVerts[i].x);
|
||||
ptmax.x = max(ptmax.x,pExVerts[i].x);
|
||||
ptmin.y = min(ptmin.y,pExVerts[i].y);
|
||||
ptmax.y = max(ptmax.y,pExVerts[i].y);
|
||||
ptmin.z = min(ptmin.z,pExVerts[i].z);
|
||||
ptmax.z = max(ptmax.z,pExVerts[i].z);
|
||||
}
|
||||
int nMinTrisPerNode=2, nMaxTrisPerNode=4;
|
||||
sz = ptmax-ptmin;
|
||||
int flags = mesh_multicontact1 | mesh_uchar_ids;
|
||||
float tol = 0.05f;
|
||||
flags |= lstPhysIndices.Count()<=60 ? mesh_SingleBB : mesh_OBB|mesh_AABB;
|
||||
if (strstr(m_szGeomName,"wheel"))
|
||||
{
|
||||
flags |= mesh_approx_cylinder;
|
||||
tol = 1.0f;
|
||||
} //else
|
||||
//flags |= mesh_approx_box;
|
||||
if (lstPhysIndices.Count()<600 && max(max(sz.x,sz.y),sz.z)>6) // make more dense OBBs for large (wrt terrain grid) objects
|
||||
nMinTrisPerNode = nMaxTrisPerNode = 1;
|
||||
m_arrPhysGeomInfo[nMesh] = pGeoman->RegisterGeometry(pGeoman->CreateMesh((vectorf*)&pExVerts[0], &lstPhysIndices[0],
|
||||
(short*)&lstFaceMaterials[0], lstPhysIndices.Count()/3, flags, true, true, tol, nMinTrisPerNode,nMaxTrisPerNode, 2.5f));
|
||||
}
|
||||
|
||||
if(nOcclMatID>=0 && nMesh==MESH_OCCLUSION)
|
||||
{
|
||||
m_lstOcclVolVerts.AddList(pExVerts,init_count);
|
||||
m_lstOcclVolInds.AddList(lstPhysIndices);
|
||||
}
|
||||
|
||||
delete [] pExVerts;
|
||||
}
|
||||
}
|
||||
|
||||
if(bShowINfo)
|
||||
GetLog()->UpdateLoadingScreenPlus("ok");
|
||||
|
||||
#undef MESH_PHYSIC
|
||||
#undef MESH_OBSTRUCT
|
||||
#undef MESH_OCCLUSION
|
||||
}
|
||||
353
ResourceCompilerPC/StatCGFCompiler/StatObjPhysics.cpp
Normal file
353
ResourceCompilerPC/StatCGFCompiler/StatObjPhysics.cpp
Normal file
@@ -0,0 +1,353 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Engine Source File.
|
||||
// Copyright (C), Crytek Studios, 2002.
|
||||
// -------------------------------------------------------------------------
|
||||
// File name: StatCGFCompiler.cpp
|
||||
// Version: v1.00
|
||||
// Created: 5/11/2002 by Vladimir Kajalin
|
||||
// Compilers: Visual Studio.NET
|
||||
// Description:
|
||||
// -------------------------------------------------------------------------
|
||||
// History:
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "StatCGFCompiler.h"
|
||||
|
||||
#include "MeshIdx.h"
|
||||
|
||||
#include "SerializeBuffer.h"
|
||||
|
||||
#define MESH_PHYSIC 0
|
||||
#define MESH_OBSTRUCT 1
|
||||
#define MESH_OCCLUSION 2
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// Buffer optimizer
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int CSimpleStatObj::FindInPosBuffer(const Vec3d & opt, Vec3d * _vbuff, int _vcount, list2<int> * pHash)
|
||||
{
|
||||
for(int i=0; i<pHash->Count(); i++)
|
||||
{
|
||||
if(
|
||||
IsEquivalent(*((Vec3d*)(&_vbuff[(*pHash)[i]].x)), *((Vec3d*)(&opt.x)), VEC_EPSILON)
|
||||
)
|
||||
return (*pHash)[i];
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CSimpleStatObj::CompactPosBuffer(Vec3d * _vbuff, int * _vcount, list2<int> * pindices)
|
||||
{
|
||||
int before = *_vcount; assert(before);
|
||||
if(!before)
|
||||
m_pLog->ThrowError("Error: CSimpleStatObj::CompactPosBuffer: Input vertex count is zero");
|
||||
|
||||
Vec3d * tmp_buff = new Vec3d[*_vcount];
|
||||
int tmp_count = 0;
|
||||
|
||||
pindices->Clear();
|
||||
|
||||
list2<int> pos_hash_table[256];//[256];
|
||||
|
||||
for(uint v=0; v<(uint)(*_vcount); v++)
|
||||
{
|
||||
list2<int> * pHash = &pos_hash_table[(unsigned char)(_vbuff[v].x*100)];//[(unsigned char)(_vbuff[v].y*100)];
|
||||
int find = FindInPosBuffer( _vbuff[v], tmp_buff, tmp_count, pHash);
|
||||
if(find<0)
|
||||
{
|
||||
tmp_buff[tmp_count] = _vbuff[v];
|
||||
pindices->Add(tmp_count);
|
||||
|
||||
pos_hash_table[(unsigned char)(_vbuff[v].x*100)]/*[(unsigned char)(_vbuff[v].y*100)]*/.Add(tmp_count);
|
||||
|
||||
tmp_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int u = (uint)find;
|
||||
pindices->Add(u);
|
||||
}
|
||||
}
|
||||
|
||||
* _vcount = tmp_count;
|
||||
memcpy( _vbuff, tmp_buff, tmp_count*sizeof(Vec3d));
|
||||
|
||||
delete [] tmp_buff;
|
||||
}
|
||||
|
||||
// This function prepares 3 additional meshes:
|
||||
// usual physical representation(mat_phys or bounce koeff),
|
||||
// obstruct physical representation(mat_obstruct)
|
||||
// and occlusion volume(mat_occl).
|
||||
// Register physical stuff in physics engine.
|
||||
void CSimpleStatObj::Physicalize()
|
||||
{
|
||||
bool bShowINfo = (m_pTriData->m_nFaceCount>10000);
|
||||
|
||||
if(bShowINfo)
|
||||
m_pLog->Log(" Creating buffer for physics ...");
|
||||
|
||||
// get phys material id's from game code
|
||||
/* IPhysMaterialEnumerator * pPhysMaterialEnumerator = ((C3DEngine*)Get3DEngine())->m_pPhysMaterialEnumerator;
|
||||
int i=0;
|
||||
for(i=0; pPhysMaterialEnumerator && i<m_pTriData->m_lstMatTable.Count(); i++)
|
||||
m_pTriData->m_lstMatTable[i].nGamePhysMatId = pPhysMaterialEnumerator->EnumPhysMaterial(m_pTriData->m_lstMatTable[i].sScriptMaterial);
|
||||
*/
|
||||
// find mat id's
|
||||
int nPhysMatID = -1;
|
||||
int nObstrMatID = -1;
|
||||
int nOcclMatID = -1;
|
||||
int nLeavesMatID= -1;
|
||||
|
||||
{
|
||||
// find phys material id
|
||||
for(int m=0; m<m_pTriData->m_lstMatTable.Count(); m++)
|
||||
if(strstr(m_pTriData->m_lstMatTable[m].sScriptMaterial,"mat_phys"))
|
||||
{
|
||||
nPhysMatID = m;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// find obstruct material id
|
||||
for(int m=0; m<m_pTriData->m_lstMatTable.Count(); m++)
|
||||
if(strstr(m_pTriData->m_lstMatTable[m].sScriptMaterial,"mat_obstruct"))
|
||||
{
|
||||
nObstrMatID = m;
|
||||
break;
|
||||
}
|
||||
|
||||
// find leaves material id
|
||||
for(int m=0; m<m_pTriData->m_lstMatTable.Count(); m++)
|
||||
if(strstr(m_pTriData->m_lstMatTable[m].sScriptMaterial,"mat_leaves"))
|
||||
{
|
||||
nLeavesMatID = m;
|
||||
break;
|
||||
}
|
||||
|
||||
// find occlusion material id
|
||||
for(int m=0; m<m_pTriData->m_lstMatTable.Count(); m++)
|
||||
if(strstr(m_pTriData->m_lstMatTable[m].sScriptMaterial,"mat_occl"))
|
||||
{
|
||||
nOcclMatID = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(int nMesh = 0; nMesh<=2; nMesh++)
|
||||
{ // fill physics indices
|
||||
list2<int> lstPhysIndices;
|
||||
list2<unsigned char> lstFaceMaterials;
|
||||
|
||||
if(nMesh == MESH_PHYSIC)
|
||||
{ // find all physicalized faces
|
||||
for(int i=0; i<m_pTriData->m_nFaceCount; i++)
|
||||
{
|
||||
if( ((m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].m_Flags & MIF_PHYSIC) && nPhysMatID<0) ||
|
||||
m_pTriData->m_pFaces[i].shader_id == nPhysMatID )
|
||||
{
|
||||
for(int v=0; v<3; v++)
|
||||
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
|
||||
|
||||
lstFaceMaterials.Add((unsigned char)m_pTriData->m_pFaces[i].shader_id);
|
||||
|
||||
if(m_pTriData->m_pFaces[i].shader_id == nPhysMatID)
|
||||
{ // remove face from list (it's not needed for rendering)
|
||||
if(m_pTriData->m_nFaceCount>1)
|
||||
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
|
||||
m_pTriData->m_nFaceCount--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(nMesh == MESH_OBSTRUCT)
|
||||
{ // find all obstruct faces
|
||||
if(nObstrMatID>=0 || nLeavesMatID>=0)
|
||||
{ // find all obstruct faces
|
||||
for(int i=0; i<m_pTriData->m_nFaceCount; i++)
|
||||
{
|
||||
if( m_pTriData->m_pFaces[i].shader_id == nObstrMatID ||
|
||||
m_pTriData->m_pFaces[i].shader_id == nLeavesMatID )
|
||||
{
|
||||
for(int v=0; v<3; v++)
|
||||
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
|
||||
|
||||
lstFaceMaterials.Add((unsigned char)m_pTriData->m_pFaces[i].shader_id);
|
||||
|
||||
if(m_pTriData->m_pFaces[i].shader_id == nObstrMatID)
|
||||
{ // remove face from list (it's not needed for rendering)
|
||||
if(m_pTriData->m_nFaceCount>1)
|
||||
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
|
||||
m_pTriData->m_nFaceCount--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(nMesh == MESH_OCCLUSION)
|
||||
{
|
||||
if(nOcclMatID>=0)
|
||||
{ // find all occlusion faces
|
||||
for(int i=0; i<m_pTriData->m_nFaceCount; i++)
|
||||
{
|
||||
if(m_pTriData->m_pFaces[i].shader_id == nOcclMatID)
|
||||
{
|
||||
for(int v=0; v<3; v++)
|
||||
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
|
||||
|
||||
lstFaceMaterials.Add((unsigned char)m_pTriData->m_pFaces[i].shader_id);
|
||||
|
||||
// remove face from list (it's not needed for rendering)
|
||||
if(m_pTriData->m_nFaceCount>1)
|
||||
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
|
||||
m_pTriData->m_nFaceCount--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(lstPhysIndices.Count())// && lstPhysIndices.Count()<600) // 200 tris limit for physics set by Cevat
|
||||
{
|
||||
Vec3d * pExVerts;
|
||||
int init_count;
|
||||
|
||||
if (m_pTriData->m_lstGeomNames.Count()>0 && strstr(m_pTriData->m_lstGeomNames[0],"cloth")!=0)
|
||||
{
|
||||
pExVerts = m_pTriData->m_pVerts;
|
||||
init_count = m_pTriData->m_nVertCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
pExVerts = new Vec3d[lstPhysIndices.Count()];
|
||||
|
||||
for(int i=0; i<lstPhysIndices.Count();i++)
|
||||
pExVerts[i] = m_pTriData->m_pVerts[lstPhysIndices[i]];
|
||||
|
||||
if(bShowINfo)
|
||||
m_pLog->Log(" Compacting buffer ...");
|
||||
|
||||
init_count = lstPhysIndices.Count();
|
||||
CompactPosBuffer(pExVerts, &init_count, &lstPhysIndices);
|
||||
}
|
||||
|
||||
if(bShowINfo)
|
||||
m_pLog->Log(" Creating OBB tree ...");
|
||||
|
||||
if(/*GetPhysicalWorld() && */(nMesh==MESH_PHYSIC || nMesh==MESH_OBSTRUCT))
|
||||
{
|
||||
// IGeomManager *pGeoman = GetPhysicalWorld()->GetGeomManager();
|
||||
Vec3d ptmin=pExVerts[0],ptmax=pExVerts[0],sz;
|
||||
for(int i=1;i<init_count;i++)
|
||||
{
|
||||
ptmin.x = min(ptmin.x,pExVerts[i].x);
|
||||
ptmax.x = max(ptmax.x,pExVerts[i].x);
|
||||
ptmin.y = min(ptmin.y,pExVerts[i].y);
|
||||
ptmax.y = max(ptmax.y,pExVerts[i].y);
|
||||
ptmin.z = min(ptmin.z,pExVerts[i].z);
|
||||
ptmax.z = max(ptmax.z,pExVerts[i].z);
|
||||
}
|
||||
int nMinTrisPerNode=2, nMaxTrisPerNode=4;
|
||||
sz = ptmax-ptmin;
|
||||
int flags = mesh_multicontact1 | mesh_uchar_ids;
|
||||
float tol = 0.05f;
|
||||
flags |= lstPhysIndices.Count()<=60 ? mesh_SingleBB : mesh_OBB|mesh_AABB;
|
||||
if (strstr(m_pGeomName,"wheel"))
|
||||
{
|
||||
flags |= mesh_approx_cylinder;
|
||||
tol = 1.0f;
|
||||
} else
|
||||
flags |= mesh_approx_box | mesh_approx_sphere;
|
||||
if (lstPhysIndices.Count()<600 && max(max(sz.x,sz.y),sz.z)>6) // make more dense OBBs for large (wrt terrain grid) objects
|
||||
nMinTrisPerNode = nMaxTrisPerNode = 1;
|
||||
|
||||
// assert(0);
|
||||
// serialize data here
|
||||
|
||||
///// m_arrPhysGeomInfo[nMesh] = pGeoman->RegisterGeometry(pGeoman->CreateMesh((vectorf*)
|
||||
// &pExVerts[0], &lstPhysIndices[0],
|
||||
///// (short*)&lstFaceMaterials[0],
|
||||
// lstPhysIndices.Count()/3,
|
||||
// flags,
|
||||
// true,
|
||||
// true,
|
||||
// tol,
|
||||
// nMinTrisPerNode,
|
||||
// nMaxTrisPerNode,
|
||||
///// 2.5f));
|
||||
|
||||
m_lstProxyVerts[nMesh].AddList(pExVerts,init_count);
|
||||
m_lstProxyInds[nMesh].AddList(lstPhysIndices);
|
||||
m_vProxyBoxMin[nMesh] = ptmin;
|
||||
m_vProxyBoxMax[nMesh] = ptmax;
|
||||
m_lstProxyFaceMaterials[nMesh].AddList(lstFaceMaterials);
|
||||
}
|
||||
|
||||
if(nOcclMatID>=0 && nMesh==MESH_OCCLUSION)
|
||||
{
|
||||
m_lstProxyVerts[MESH_OCCLUSION].AddList(pExVerts,init_count);
|
||||
m_lstProxyInds[MESH_OCCLUSION].AddList(lstPhysIndices);
|
||||
}
|
||||
|
||||
if (pExVerts!=m_pTriData->m_pVerts)
|
||||
delete [] pExVerts;
|
||||
}
|
||||
else if(lstPhysIndices.Count())
|
||||
{
|
||||
m_pLog->Log("Error: CSimpleStatObj::Physicalize: proxy geometry contains more than 200 polygons - skipped");
|
||||
}
|
||||
}
|
||||
|
||||
if(bShowINfo)
|
||||
m_pLog->LogPlus("ok");
|
||||
}
|
||||
|
||||
void CSimpleStatObj::InitGeometry()
|
||||
{
|
||||
// copy helpers
|
||||
m_lstHelpers.AddList(*m_pTriData->GetHelpers());
|
||||
|
||||
// copy lsources
|
||||
for(int i=0; i<m_pTriData->GetLightSourcesList()->Count(); i++)
|
||||
m_lstLSources.Add(*m_pTriData->GetLightSourcesList()->GetAt(i));
|
||||
|
||||
m_vBoxMin = m_pTriData->m_vBoxMin;
|
||||
m_vBoxMax = m_pTriData->m_vBoxMax;
|
||||
}
|
||||
|
||||
void CSimpleStatObj::Serialize(int & nPos, uchar * pSerBuf, bool bSave)
|
||||
{
|
||||
assert(bSave);
|
||||
|
||||
SaveBuffer("StatObj", 8, pSerBuf, nPos);
|
||||
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
m_lstProxyVerts[i].SaveToBuffer(pSerBuf,nPos);
|
||||
m_lstProxyInds[i].SaveToBuffer(pSerBuf,nPos);
|
||||
SaveBuffer(m_vProxyBoxMin[i], sizeof(m_vProxyBoxMin[i]), pSerBuf, nPos);
|
||||
SaveBuffer(m_vProxyBoxMax[i], sizeof(m_vProxyBoxMax[i]), pSerBuf, nPos);
|
||||
m_lstProxyFaceMaterials[i].SaveToBuffer(pSerBuf,nPos);
|
||||
}
|
||||
|
||||
SaveBuffer(&m_vBoxMin, sizeof(m_vBoxMin), pSerBuf, nPos);
|
||||
SaveBuffer(&m_vBoxMax, sizeof(m_vBoxMax), pSerBuf, nPos);
|
||||
|
||||
m_lstHelpers.SaveToBuffer(pSerBuf,nPos);
|
||||
m_lstLSources.SaveToBuffer(pSerBuf,nPos);
|
||||
}
|
||||
|
||||
bool CSimpleStatObj::IsPhysicsExist()
|
||||
{
|
||||
return (m_lstProxyInds[MESH_PHYSIC].Count() || m_lstProxyInds[MESH_OBSTRUCT].Count());
|
||||
}
|
||||
|
||||
//"Objects\Natural\Bushes\beach_bush_yellow.cgf" /GeomName= /Stripify=1 /LoadAdditinalInfo=0 /KeepInLocalSpace=0 /StaticCGF=1 /refresh
|
||||
680
ResourceCompilerPC/StatCGFCompiler/tang_basis.cpp
Normal file
680
ResourceCompilerPC/StatCGFCompiler/tang_basis.cpp
Normal file
@@ -0,0 +1,680 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// bm
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "StatCGFCompiler.h"
|
||||
|
||||
#define EPS 0.00001f
|
||||
|
||||
// from nvidia kitchen
|
||||
bool CSimpleLeafBuffer::compute_tangent( const float * v0, const float * v1, const float * v2,
|
||||
const float * t0, const float * t1, const float * t2,
|
||||
Vec3d & tangent, Vec3d & binormal, Vec3d & tnormal, Vec3d & face_normal)
|
||||
{
|
||||
Vec3d cp;
|
||||
Vec3d e0;
|
||||
Vec3d e1;
|
||||
|
||||
tangent = Vec3d(0,0,1);
|
||||
binormal = Vec3d(0,1,0);
|
||||
tnormal = Vec3d(1,0,0);
|
||||
|
||||
// x
|
||||
e0[0] = v1[0] - v0[0];
|
||||
e0[1] = t1[0] - t0[0];
|
||||
e0[2] = t1[1] - t0[1];
|
||||
|
||||
e1[0] = v2[0] - v0[0];
|
||||
e1[1] = t2[0] - t0[0];
|
||||
e1[2] = t2[1] - t0[1];
|
||||
|
||||
|
||||
cp = e0.Cross(e1);
|
||||
|
||||
if ( fabs(cp[0]) > EPS )
|
||||
{
|
||||
tangent[0] = -cp[1] / cp[0];
|
||||
binormal[0] = -cp[2] / cp[0];
|
||||
}
|
||||
|
||||
// y
|
||||
e0[0] = v1[1] - v0[1];
|
||||
e0[1] = t1[0] - t0[0];
|
||||
e0[2] = t1[1] - t0[1];
|
||||
|
||||
e1[0] = v2[1] - v0[1];
|
||||
e1[1] = t2[0] - t0[0];
|
||||
e1[2] = t2[1] - t0[1];
|
||||
|
||||
cp = e0.Cross(e1);
|
||||
|
||||
if ( fabs(cp[0]) > EPS )
|
||||
{
|
||||
tangent[1] = -cp[1] / cp[0];
|
||||
binormal[1] = -cp[2] / cp[0];
|
||||
}
|
||||
|
||||
// z
|
||||
e0[0] = v1[2] - v0[2];
|
||||
e0[1] = t1[0] - t0[0];
|
||||
e0[2] = t1[1] - t0[1];
|
||||
|
||||
e1[0] = v2[2] - v0[2];
|
||||
e1[1] = t2[0] - t0[0];
|
||||
e1[2] = t2[1] - t0[1];
|
||||
|
||||
cp = e0.Cross(e1);
|
||||
|
||||
if ( fabs(cp[0]) > EPS )
|
||||
{
|
||||
tangent[2] = -cp[1] / cp[0];
|
||||
binormal[2] = -cp[2] / cp[0];
|
||||
}
|
||||
|
||||
tangent.Normalize();
|
||||
binormal.Normalize();
|
||||
|
||||
tnormal = tangent.Cross(binormal);
|
||||
tnormal.Normalize();
|
||||
|
||||
// Gram-Schmidt orthogonalization process for B
|
||||
// compute the cross product B=NxT to obtain
|
||||
// an orthogonal basis
|
||||
//binormal = tnormal.Cross(tangent);
|
||||
|
||||
if (tnormal.Dot(face_normal) < 0)
|
||||
tnormal = -tnormal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#include "NvTriStrip/NVTriStrip.h"
|
||||
|
||||
static _inline int sGetHash(float *v, float *n)
|
||||
{
|
||||
return (int)(v[0]*64.0f+v[1]*64.0f+v[2]*64.0f+n[0]*2.0f+n[1]*2.0f+n[2]*2.0f) & 511;
|
||||
}
|
||||
|
||||
static _inline void sAddToHash(TArray<unsigned short>& hash, unsigned short ind)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<hash.Num(); i++)
|
||||
{
|
||||
if (hash[i] == ind)
|
||||
return;
|
||||
}
|
||||
hash.AddElem(ind);
|
||||
}
|
||||
|
||||
static void sGetObjectSpaceVectors( Vec3d &outvA, Vec3d &outvB, Vec3d &outvC )
|
||||
{
|
||||
outvA = Vec3d(1,0,0);
|
||||
outvB = Vec3d(0,1,0);
|
||||
outvC = Vec3d(0,0,1);
|
||||
}
|
||||
/*
|
||||
float sCalcAngle( Vec3d &invA, Vec3d &invB )
|
||||
{
|
||||
float LengthQ = invA.Length() * invB.Length();
|
||||
|
||||
if(LengthQ < 0.01f)
|
||||
LengthQ = 0.01f;
|
||||
|
||||
return acosf(invA.Dot(invB) / LengthQ);
|
||||
}
|
||||
*/
|
||||
|
||||
// orthogonalize the base vectors
|
||||
//! /param v0 input [0..2] position vertex 1
|
||||
//! /param v1 input [0..2] position vertex 2
|
||||
//! /param v2 input [0..2] position vertex 3
|
||||
//! /param t0 input [0..1] texture coordinate vertex 1
|
||||
//! /param t1 input [0..1] texture coordinate vertex 2
|
||||
//! /param t2 input [0..1] texture coordinate vertex 3
|
||||
//! /param tangent output vector 1
|
||||
//! /param binormal output vector 2
|
||||
//! /param tnormal output vector 3
|
||||
/*void CSimpleLeafBuffer::compute_tangent_base_CS( const float *v0, const float *v1, const float *v2,
|
||||
const float *t0, const float *t1, const float *t2,
|
||||
Vec3d &tangent, Vec3d &binormal, Vec3d &tnormal )
|
||||
{
|
||||
float fA[2]={ t1[0]-t0[0], t1[1]-t0[1] }, fB[2]={ t2[0]-t0[0], t2[1]-t0[1] };
|
||||
|
||||
float fOrientation = fA[0]*fB[1]-fA[1]*fB[0];
|
||||
|
||||
Vec3d vfNormal = Vec3d(0,0,1);
|
||||
compute_tangent_CS(v0,v1,v2,t0,t1,t2,tangent,binormal,tnormal,vfNormal);
|
||||
|
||||
// make sure they are orthogonal
|
||||
tnormal = tangent.Cross(binormal);
|
||||
tnormal.Normalize();
|
||||
binormal = tnormal.Cross(tangent);
|
||||
binormal.Normalize();
|
||||
if(fOrientation < 0)
|
||||
tnormal = -tnormal;
|
||||
} */
|
||||
|
||||
#define TV_EPS 0.001f
|
||||
#define TN_EPS 0.0001f
|
||||
|
||||
bool CSimpleLeafBuffer::PrepareTexSpaceBasis()
|
||||
{
|
||||
int hash;
|
||||
int i, j;
|
||||
|
||||
// allocate if not ready
|
||||
// process faces
|
||||
byte *pD = (byte *)m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
|
||||
SBufInfoTable *pOffs = &gBufInfoTable[m_pSecVertBuffer->m_vertexformat];
|
||||
int Stride = m_VertexSize[m_pSecVertBuffer->m_vertexformat]; // position stride
|
||||
|
||||
// Get pointers to positions, TexCoords and Normals
|
||||
byte *verts = pD;
|
||||
int StrN; // Normals Stride
|
||||
byte *norms;
|
||||
int StrTC; // Tex coords stride
|
||||
byte *tc0;
|
||||
if (pOffs->OffsNormal)
|
||||
{
|
||||
norms = &pD[pOffs->OffsNormal];
|
||||
StrN = Stride;
|
||||
}
|
||||
else
|
||||
{
|
||||
norms = (byte *)this->m_TempNormals;
|
||||
StrN = sizeof(Vec3d);
|
||||
}
|
||||
|
||||
if (pOffs->OffsTC)
|
||||
{
|
||||
tc0 = &pD[pOffs->OffsTC];
|
||||
StrTC = Stride;
|
||||
}
|
||||
else
|
||||
{
|
||||
tc0 = (byte *)this->m_TempTexCoords;
|
||||
StrTC = sizeof(SMRendTexVert);
|
||||
}
|
||||
// If there is no tex coords or normals ignore this mesh
|
||||
if (!tc0 || !norms)
|
||||
return false;
|
||||
|
||||
if(!m_pBasises)
|
||||
m_pBasises = new CBasis[m_SecVertCount];
|
||||
memset(m_pBasises, 0, sizeof(CBasis)*m_SecVertCount);
|
||||
|
||||
// Indices hash table for smoothing of vectors between different materials
|
||||
TArray<unsigned short> hash_table[2][512]; // 0. for TS; 1. for CS
|
||||
|
||||
// array for avoid smooothing multiple times
|
||||
TArray<bool> bUsed;
|
||||
bUsed.Create(m_SecVertCount);
|
||||
|
||||
// Clone space map
|
||||
/* CPBCloneMapDest *pCM = NULL;
|
||||
bool bCM = false;*/
|
||||
bool bSpace[2];
|
||||
|
||||
// Init hash tables
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
bSpace[i] = false;
|
||||
for (j=0; j<512; j++)
|
||||
{
|
||||
hash_table[i][j].Free();
|
||||
}
|
||||
}
|
||||
|
||||
// Non-optimized geometry case (usually in Debug mode)
|
||||
if (m_nPrimetiveType != R_PRIMV_MULTI_GROUPS)
|
||||
{
|
||||
// All materials
|
||||
for (int nm=0; nm<m_pMats->Count(); nm++)
|
||||
{
|
||||
CMatInfo *mi = m_pMats->Get(nm);
|
||||
/* if (pCM)
|
||||
{
|
||||
delete pCM;
|
||||
pCM = NULL;
|
||||
}
|
||||
*/ /*
|
||||
if (mi->shaderItem.m_pShaderResources)
|
||||
{
|
||||
STexPic *pBumpTex = mi->shaderItem.m_pShaderResources->m_Textures[EFTT_BUMP].m_TU.m_TexPic;
|
||||
|
||||
// If clone space texture is present
|
||||
if (pBumpTex && (pBumpTex->m_Flags2 & FT2_CLONESPACE))
|
||||
{
|
||||
char name[128];
|
||||
strcpy(name, pBumpTex->m_SourceName.c_str());
|
||||
StripExtension(name, name);
|
||||
AddExtension(name, ".cln");
|
||||
FILE *fp = iSystem->GetIPak()->FOpen (name, "rb");
|
||||
if (fp)
|
||||
{
|
||||
iSystem->GetIPak()->FClose(fp);
|
||||
pCM = new CPBCloneMapDest;
|
||||
pCM->LoadCloneMap(name);
|
||||
bCM = true;
|
||||
}
|
||||
}
|
||||
else // otherwise if it's object-space polybump ignore this material
|
||||
if (pBumpTex && (pBumpTex->m_Flags2 & FT2_POLYBUMP))
|
||||
continue;
|
||||
}*/
|
||||
// For clone-space - another hash index for smoothing
|
||||
int nIndHash = 0;//(pCM != 0) ? 1 : 0;
|
||||
if (mi->nNumIndices)
|
||||
bSpace[nIndHash] = true;
|
||||
|
||||
for(i=0; i<mi->nNumIndices-2; i+=3)
|
||||
{
|
||||
unsigned short * face = &GetIndices()[i+mi->nFirstIndexId];
|
||||
|
||||
float *n[3] =
|
||||
{
|
||||
(float *)&norms[face[0]*StrN],
|
||||
(float *)&norms[face[1]*StrN],
|
||||
(float *)&norms[face[2]*StrN],
|
||||
};
|
||||
|
||||
float *v[3] =
|
||||
{
|
||||
(float *)&verts[face[0]*Stride],
|
||||
(float *)&verts[face[1]*Stride],
|
||||
(float *)&verts[face[2]*Stride],
|
||||
};
|
||||
|
||||
float *tc[3] =
|
||||
{
|
||||
(float *)&tc0[face[0]*StrTC],
|
||||
(float *)&tc0[face[1]*StrTC],
|
||||
(float *)&tc0[face[2]*StrTC],
|
||||
};
|
||||
// Place indices to hash (for future smoothing)
|
||||
hash = sGetHash(v[0], n[0]);
|
||||
sAddToHash(hash_table[nIndHash][hash], face[0]);
|
||||
hash = sGetHash(v[1], n[1]);
|
||||
sAddToHash(hash_table[nIndHash][hash], face[1]);
|
||||
hash = sGetHash(v[2], n[2]);
|
||||
sAddToHash(hash_table[nIndHash][hash], face[2]);
|
||||
|
||||
// Compute the face normal based on vertex normals
|
||||
Vec3d face_normal;
|
||||
face_normal.x = n[0][0] + n[1][0] + n[2][0];
|
||||
face_normal.y = n[0][1] + n[1][1] + n[2][1];
|
||||
face_normal.z = n[0][2] + n[1][2] + n[2][2];
|
||||
|
||||
face_normal.Normalize();
|
||||
|
||||
// If we have clone-space
|
||||
{
|
||||
Vec3d tangents[3];
|
||||
Vec3d binormals[3];
|
||||
Vec3d tnormals[3];
|
||||
|
||||
// compute tangent vectors
|
||||
compute_tangent(v[0], v[1], v[2], tc[0], tc[1], tc[2], tangents[0], binormals[0], tnormals[0], face_normal);
|
||||
compute_tangent(v[1], v[2], v[0], tc[1], tc[2], tc[0], tangents[1], binormals[1], tnormals[1], face_normal);
|
||||
compute_tangent(v[2], v[0], v[1], tc[2], tc[0], tc[1], tangents[2], binormals[2], tnormals[2], face_normal);
|
||||
|
||||
// accumulate
|
||||
for(j=0; j<3; j++)
|
||||
{
|
||||
m_pBasises[face[j]].tangent += tangents [j];
|
||||
m_pBasises[face[j]].binormal += binormals[j];
|
||||
m_pBasises[face[j]].tnormal += tnormals[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// smooth tangent vectors between different materials with the same positions and normals
|
||||
if (1)//CRenderer::CV_r_smoothtangents)
|
||||
{
|
||||
// Shared indices array for smoothing
|
||||
TArray<int> Inds;
|
||||
Inds.Create(32);
|
||||
// Smooth separatelly for tangent-space and clone-space
|
||||
for (int nn=0; nn<2; nn++)
|
||||
{
|
||||
// If this space wasn't used ignore it
|
||||
if (!bSpace[nn])
|
||||
continue;
|
||||
for (i=0; i<m_SecVertCount; i++)
|
||||
{
|
||||
// if this vertex was already used ignore it
|
||||
if (bUsed[i])
|
||||
continue;
|
||||
bUsed[i] = true;
|
||||
Inds.SetUse(0);
|
||||
Inds.AddElem(i);
|
||||
// Get position and normal for the current index i
|
||||
float *v = (float *)&verts[i*Stride];
|
||||
float *n = (float *)&norms[i*StrN];
|
||||
hash = sGetHash(v, n);
|
||||
for (j=0; j<hash_table[nn][hash].Num(); j++)
|
||||
{
|
||||
int m = hash_table[nn][hash][j];
|
||||
if (m == i)
|
||||
continue;
|
||||
// Get position and normal for the new index m
|
||||
float *v1 = (float *)&verts[m*Stride];
|
||||
float *n1 = (float *)&norms[m*StrN];
|
||||
// If position and normal are the same take this index int account
|
||||
if (fabs(v1[0]-v[0])<TV_EPS && fabs(v1[1]-v[1])<TV_EPS && fabs(v1[2]-v[2])<TV_EPS && fabs(n1[0]-n[0])<TN_EPS && fabs(n1[1]-n[1])<TN_EPS && fabs(n1[2]-n[2])<TN_EPS)
|
||||
{
|
||||
// Check angle between tangent vectors to avoid degenerated tangent vectors
|
||||
Vec3d tang, tang1;
|
||||
tang = m_pBasises[m].binormal;
|
||||
tang.NormalizeFast();
|
||||
tang1 = m_pBasises[i].binormal;
|
||||
tang1.NormalizeFast();
|
||||
float dot = tang.Dot(tang1);
|
||||
if (dot > 0.5f)
|
||||
{
|
||||
tang = m_pBasises[m].tangent;
|
||||
tang.NormalizeFast();
|
||||
tang1 = m_pBasises[i].tangent;
|
||||
tang1.NormalizeFast();
|
||||
dot = tang.Dot(tang1);
|
||||
if (dot > 0.5f)
|
||||
{
|
||||
tang = m_pBasises[m].tnormal;
|
||||
tang.NormalizeFast();
|
||||
tang1 = m_pBasises[i].tnormal;
|
||||
tang1.NormalizeFast();
|
||||
float dot = tang.Dot(tang1);
|
||||
if (dot > 0.5f)
|
||||
Inds.AddElem(m); // Add the new index to the shared indices list
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we have more then one shared index smooth vectors between them
|
||||
if (Inds.Num() > 1)
|
||||
{
|
||||
Vec3d tang = m_pBasises[Inds[0]].tangent;
|
||||
Vec3d binorm = m_pBasises[Inds[0]].binormal;
|
||||
Vec3d tnorm = m_pBasises[Inds[0]].tnormal;
|
||||
for (j=1; j<Inds.Num(); j++)
|
||||
{
|
||||
int m = Inds[j];
|
||||
bUsed[m] = true;
|
||||
tang += m_pBasises[m].tangent;
|
||||
binorm += m_pBasises[m].binormal;
|
||||
tnorm += m_pBasises[m].tnormal;
|
||||
}
|
||||
for (j=0; j<Inds.Num(); j++)
|
||||
{
|
||||
int m = Inds[j];
|
||||
m_pBasises[m].tangent = tang;
|
||||
m_pBasises[m].binormal = binorm;
|
||||
m_pBasises[m].tnormal = tnorm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Optimized geometry (Stripified)
|
||||
{
|
||||
unsigned int n;
|
||||
for (int nm=0; nm<m_pMats->Count(); nm++)
|
||||
{
|
||||
CMatInfo *mi = m_pMats->Get(nm);
|
||||
/* if (pCM)
|
||||
{
|
||||
delete pCM;
|
||||
pCM = NULL;
|
||||
}*//*
|
||||
if (mi->shaderItem.m_pShaderResources)
|
||||
{
|
||||
STexPic *pBumpTex = mi->shaderItem.m_pShaderResources->m_Textures[EFTT_BUMP].m_TU.m_TexPic;
|
||||
|
||||
// If we have clone-space texture
|
||||
if (pBumpTex && (pBumpTex->m_Flags2 & FT2_CLONESPACE))
|
||||
{
|
||||
char name[128];
|
||||
strcpy(name, pBumpTex->m_SourceName.c_str());
|
||||
StripExtension(name, name);
|
||||
AddExtension(name, ".cln");
|
||||
FILE *fp = iSystem->GetIPak()->FOpen (name, "rb");
|
||||
if (fp)
|
||||
{
|
||||
iSystem->GetIPak()->FClose(fp);
|
||||
pCM = new CPBCloneMapDest;
|
||||
pCM->LoadCloneMap(name);
|
||||
bCM = true;
|
||||
}
|
||||
}
|
||||
else // if it's object-space bump ignore this material
|
||||
if (pBumpTex && (pBumpTex->m_Flags2 & FT2_POLYBUMP))
|
||||
continue;
|
||||
} */
|
||||
// For clone-space - another hash index for smoothing
|
||||
int nIndHash = 0;//(pCM != 0) ? 1 : 0;
|
||||
if (mi->nNumIndices)
|
||||
bSpace[nIndHash] = true;
|
||||
|
||||
int nOffs = mi->nFirstIndexId;
|
||||
for (j=0; j<mi->m_dwNumSections; j++)
|
||||
{
|
||||
SPrimitiveGroup *g = &mi->m_pPrimitiveGroups[j];
|
||||
int incr;
|
||||
switch (g->type)
|
||||
{
|
||||
case PT_LIST:
|
||||
incr = 3;
|
||||
break;
|
||||
case PT_STRIP:
|
||||
case PT_FAN:
|
||||
incr = 1;
|
||||
break;
|
||||
}
|
||||
int offs = g->offsIndex + nOffs;
|
||||
for (n=0; n<g->numIndices-2; n+=incr)
|
||||
{
|
||||
int i0, i1, i2;
|
||||
switch (g->type)
|
||||
{
|
||||
case PT_LIST:
|
||||
i0 = GetIndices()[offs+n];
|
||||
i1 = GetIndices()[offs+n+1];
|
||||
i2 = GetIndices()[offs+n+2];
|
||||
break;
|
||||
case PT_STRIP:
|
||||
i0 = GetIndices()[offs+n];
|
||||
i1 = GetIndices()[offs+n+1];
|
||||
i2 = GetIndices()[offs+n+2];
|
||||
break;
|
||||
case PT_FAN:
|
||||
i0 = GetIndices()[offs+0];
|
||||
i1 = GetIndices()[offs+n+1];
|
||||
i2 = GetIndices()[offs+n+2];
|
||||
break;
|
||||
}
|
||||
// ignore degenerate triangle
|
||||
if (i0==i1 || i0==i2 || i1==i2)
|
||||
continue;
|
||||
|
||||
float *n[3] =
|
||||
{
|
||||
(float *)&norms[i0*StrN],
|
||||
(float *)&norms[i1*StrN],
|
||||
(float *)&norms[i2*StrN],
|
||||
};
|
||||
|
||||
float *v[3] =
|
||||
{
|
||||
(float *)&verts[i0*Stride],
|
||||
(float *)&verts[i1*Stride],
|
||||
(float *)&verts[i2*Stride],
|
||||
};
|
||||
|
||||
float *tc[3] =
|
||||
{
|
||||
(float *)&tc0[i0*StrTC],
|
||||
(float *)&tc0[i1*StrTC],
|
||||
(float *)&tc0[i2*StrTC],
|
||||
};
|
||||
|
||||
// Place indices to hash (for future smoothing)
|
||||
hash = sGetHash(v[0], n[0]);
|
||||
sAddToHash(hash_table[nIndHash][hash], i0);
|
||||
hash = sGetHash(v[1], n[1]);
|
||||
sAddToHash(hash_table[nIndHash][hash], i1);
|
||||
hash = sGetHash(v[2], n[2]);
|
||||
sAddToHash(hash_table[nIndHash][hash], i2);
|
||||
|
||||
// Compute the face normal based on vertex normals
|
||||
Vec3d face_normal;
|
||||
face_normal.x = n[0][0] + n[1][0] + n[2][0];
|
||||
face_normal.y = n[0][1] + n[1][1] + n[2][1];
|
||||
face_normal.z = n[0][2] + n[1][2] + n[2][2];
|
||||
|
||||
//Vec3d::Normalize(face_normal);
|
||||
face_normal.Normalize();
|
||||
|
||||
{
|
||||
Vec3d tangents[3];
|
||||
Vec3d binormals[3];
|
||||
Vec3d tnormals[3];
|
||||
|
||||
compute_tangent(v[0], v[1], v[2], tc[0], tc[1], tc[2], tangents[0], binormals[0], tnormals[0], face_normal);
|
||||
compute_tangent(v[1], v[2], v[0], tc[1], tc[2], tc[0], tangents[1], binormals[1], tnormals[1], face_normal);
|
||||
compute_tangent(v[2], v[0], v[1], tc[2], tc[0], tc[1], tangents[2], binormals[2], tnormals[2], face_normal);
|
||||
|
||||
// accumulate
|
||||
m_pBasises[i0].tangent += tangents [0];
|
||||
m_pBasises[i0].binormal += binormals[0];
|
||||
m_pBasises[i0].tnormal += tnormals[0];
|
||||
m_pBasises[i1].tangent += tangents [1];
|
||||
m_pBasises[i1].binormal += binormals[1];
|
||||
m_pBasises[i1].tnormal += tnormals[1];
|
||||
m_pBasises[i2].tangent += tangents [2];
|
||||
m_pBasises[i2].binormal += binormals[2];
|
||||
m_pBasises[i2].tnormal += tnormals[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// smooth tangent vectors between different materials with the same positions and normals
|
||||
if (1)//CRenderer::CV_r_smoothtangents)
|
||||
{
|
||||
// Shared indices array for smoothing
|
||||
TArray<int> Inds;
|
||||
Inds.Create(32);
|
||||
// Smooth separatelly for tangent-space and clone-space
|
||||
for (int nn=0; nn<2; nn++)
|
||||
{
|
||||
// If this space wasn't used ignore it
|
||||
if (!bSpace[nn])
|
||||
continue;
|
||||
for (i=0; i<m_SecVertCount; i++)
|
||||
{
|
||||
// if this vertex was already used ignore it
|
||||
if (bUsed[i])
|
||||
continue;
|
||||
bUsed[i] = true;
|
||||
Inds.SetUse(0);
|
||||
Inds.AddElem(i);
|
||||
// Get position and normal for the current index i
|
||||
float *v = (float *)&verts[i*Stride];
|
||||
float *n = (float *)&norms[i*StrN];
|
||||
hash = sGetHash(v, n);
|
||||
for (j=0; j<hash_table[nn][hash].Num(); j++)
|
||||
{
|
||||
int m = hash_table[nn][hash][j];
|
||||
// If it's the same index ignore it
|
||||
if (m == i)
|
||||
continue;
|
||||
// Get position and normal for the tested index m
|
||||
float *v1 = (float *)&verts[m*Stride];
|
||||
float *n1 = (float *)&norms[m*StrN];
|
||||
// If position and normal are the same take this index int account
|
||||
if (fabs(v1[0]-v[0])<TV_EPS && fabs(v1[1]-v[1])<TV_EPS && fabs(v1[2]-v[2])<TV_EPS && fabs(n1[0]-n[0])<TN_EPS && fabs(n1[1]-n[1])<TN_EPS && fabs(n1[2]-n[2])<TN_EPS)
|
||||
{
|
||||
// Check angle between tangent vectors to avoid degenerated tangent vectors
|
||||
Vec3d tang, tang1;
|
||||
tang = m_pBasises[m].binormal;
|
||||
tang.NormalizeFast();
|
||||
tang1 = m_pBasises[i].binormal;
|
||||
tang1.NormalizeFast();
|
||||
if (tang.Dot(tang1) > 0.5f)
|
||||
{
|
||||
tang = m_pBasises[m].tangent;
|
||||
tang.NormalizeFast();
|
||||
tang1 = m_pBasises[i].tangent;
|
||||
tang1.NormalizeFast();
|
||||
if (tang.Dot(tang1) > 0.5f)
|
||||
{
|
||||
tang = m_pBasises[m].tnormal;
|
||||
tang.NormalizeFast();
|
||||
tang1 = m_pBasises[i].tnormal;
|
||||
tang1.NormalizeFast();
|
||||
if (tang.Dot(tang1) > 0.5f)
|
||||
Inds.AddElem(m); // Add the new index to the shared indices list
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we have more then one shared index smooth vectors between them
|
||||
if (Inds.Num() > 1)
|
||||
{
|
||||
Vec3d tang = m_pBasises[Inds[0]].tangent;
|
||||
Vec3d binorm = m_pBasises[Inds[0]].binormal;
|
||||
Vec3d tnorm = m_pBasises[Inds[0]].tnormal;
|
||||
for (j=1; j<Inds.Num(); j++)
|
||||
{
|
||||
int m = Inds[j];
|
||||
bUsed[m] = true;
|
||||
tang += m_pBasises[m].tangent;
|
||||
binorm += m_pBasises[m].binormal;
|
||||
tnorm += m_pBasises[m].tnormal;
|
||||
}
|
||||
for (j=0; j<Inds.Num(); j++)
|
||||
{
|
||||
int m = Inds[j];
|
||||
m_pBasises[m].tangent = tang;
|
||||
m_pBasises[m].binormal = binorm;
|
||||
m_pBasises[m].tnormal = tnorm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normalize
|
||||
for(int v=0; v<m_SecVertCount; v++)
|
||||
{
|
||||
m_pBasises[v].tangent.Normalize();
|
||||
m_pBasises[v].binormal.Normalize();
|
||||
m_pBasises[v].tnormal.Normalize();
|
||||
// if we have CV_r_unifytangentnormals (set by default) use Normals from vertex normal as Tangent normal
|
||||
// and orthonormalize tangent vectors
|
||||
if (1)//CRenderer::CV_r_unifytangentnormals && !bCM)
|
||||
{
|
||||
Vec3d *n = (Vec3d *)&norms[v*StrN];
|
||||
m_pBasises[v].tnormal = *n;
|
||||
Vec3d bin = m_pBasises[v].binormal;
|
||||
Vec3d tan = m_pBasises[v].tangent;
|
||||
m_pBasises[v].tangent = m_pBasises[v].tnormal.Cross(m_pBasises[v].binormal);
|
||||
if (m_pBasises[v].tangent.Dot(tan) < 0.0f)
|
||||
m_pBasises[v].tangent = -m_pBasises[v].tangent;
|
||||
m_pBasises[v].binormal = m_pBasises[v].tnormal.Cross(m_pBasises[v].tangent);
|
||||
if (m_pBasises[v].binormal.Dot(bin) < 0.0f)
|
||||
m_pBasises[v].binormal = -m_pBasises[v].binormal;
|
||||
m_pBasises[v].tangent.Normalize();
|
||||
m_pBasises[v].binormal.Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
805
ResourceCompilerPC/StencilShadowConnectivity.h
Normal file
805
ResourceCompilerPC/StencilShadowConnectivity.h
Normal file
@@ -0,0 +1,805 @@
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CryEngine Source code
|
||||
//
|
||||
// File:StencilShadowConnectivity.h
|
||||
// Declaration of class CStencilShadowConnectivity
|
||||
//
|
||||
// History:
|
||||
// -:Created by Sergiy Migdalskiy <sergiy@crytek.de>
|
||||
// 08/30/2002 include .cpp in header files, move to CryCommon, use in Cry3DEngine (Martin Mittring)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// class CStencilShadowConnectivity
|
||||
//
|
||||
// This is pre-computed data for a model that's gonna cast stencil
|
||||
// shadows, and whose vertices may change position ****, but the topology
|
||||
// cannot change.
|
||||
//
|
||||
// Ok, to put it clear: for each model, you need one instance of this
|
||||
// class initialized once. The model is allowed to deform, but is not
|
||||
// allowed to change topology (add or remove faces as well as re-assign
|
||||
// face vertices or even change face orientation).
|
||||
//
|
||||
// NOTE: The class is optimized for use with manifold geometry.
|
||||
// This means you have to provide a model with unified normals and non-
|
||||
// exploded triangles.
|
||||
//
|
||||
//
|
||||
// IMPLEMENTATION NOTES should be in
|
||||
// StencilShadowConnectivity.cpp
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef _STENCIL_SHADOW_CONNECTIVITY_HDR_
|
||||
#define _STENCIL_SHADOW_CONNECTIVITY_HDR_
|
||||
|
||||
#include <IEdgeConnectivityBuilder.h> // IStencilShadowConnectivity
|
||||
|
||||
// the empty connectivity info:
|
||||
class CStencilShadowConnectivityNull:public IStencilShadowConnectivity
|
||||
{
|
||||
public:
|
||||
|
||||
//! don't forget to call Release for freeing the memory resources
|
||||
virtual void Release( void ) {delete this;}
|
||||
|
||||
//! to keep the interface small and the access fast
|
||||
//! /return pointer to the internal memory representation (only used within module 3DEngine)
|
||||
const virtual CStencilShadowConnectivity *GetInternalRepresentation( void ) const {return NULL;}
|
||||
|
||||
//! for debugging and profiling
|
||||
//! /param outVertexCount
|
||||
//! /param outTriangleCount
|
||||
virtual void GetStats( DWORD &outVertexCount, DWORD &outTriangleCount ) {outVertexCount = outTriangleCount = 0;}
|
||||
|
||||
//! Memorize the vertex buffer in this connectivity object. This is needed if a static object doesn't need this info
|
||||
virtual void SetVertices(const Vec3d* pVertices, unsigned numVertices) {assert(0);}
|
||||
|
||||
//! Serializes this object to the given memory block; if it's NULL, only returns
|
||||
//! the number of bytes required. If it's not NULL, returns the number of bytes written
|
||||
//! (0 means error, insufficient space)
|
||||
virtual unsigned Serialize (bool bSave, void* pStream, unsigned nSize, IMiniLog* pWarningLog = NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Calculates the size of this object
|
||||
virtual void GetMemoryUsage (ICrySizer* pSizer) {}
|
||||
|
||||
#ifdef WIN32
|
||||
//! /param szFilename filename with path (or relative) and extension
|
||||
//! /return true=success, false otherwise
|
||||
virtual bool DebugConnectivityInfo( const char *szFilename ){}
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef WIN64
|
||||
#pragma warning( push ) //AMD Port
|
||||
#pragma warning( disable : 4267 )
|
||||
#endif
|
||||
|
||||
class CStencilShadowConnectivity : public IStencilShadowConnectivity
|
||||
{
|
||||
public:
|
||||
|
||||
//! number of vertices in the array referenced by the mesh
|
||||
//! /return vertex count
|
||||
unsigned numVertices() const
|
||||
{
|
||||
return m_numVertices;
|
||||
}
|
||||
|
||||
//! number of edges in the array of edges
|
||||
//! /return edge count
|
||||
unsigned numEdges() const
|
||||
{
|
||||
return m_numEdges;
|
||||
}
|
||||
|
||||
//! number of orphaned (open) edges
|
||||
//! /return orphaned (open) count
|
||||
virtual unsigned numOrphanEdges() const
|
||||
{
|
||||
return m_numOrphanEdges;
|
||||
}
|
||||
|
||||
//! total number of faces
|
||||
//! /return face count
|
||||
unsigned numFaces ()const
|
||||
{
|
||||
return m_numFaces;
|
||||
}
|
||||
|
||||
// -----------------
|
||||
|
||||
// This is the basic edge representation: two vertex indices.
|
||||
// This is capable of being sorted.
|
||||
struct BasicEdge
|
||||
{
|
||||
//! default constructor
|
||||
BasicEdge () {}
|
||||
|
||||
//! constructor
|
||||
//! /param nV0 start vertex index
|
||||
//! /param nV1 end vertex index
|
||||
BasicEdge (vindex nV0, vindex nV1)
|
||||
{
|
||||
m_nVertex[0] = nV0;
|
||||
m_nVertex[1] = nV1;
|
||||
}
|
||||
|
||||
//! start and end vertex index of the edge
|
||||
vindex m_nVertex[2];
|
||||
|
||||
// alphabet sorting implementation
|
||||
//! /param rEdge right side of the operator term
|
||||
inline bool operator < (const BasicEdge& rEdge)const
|
||||
{
|
||||
if (m_nVertex[0] < rEdge.m_nVertex[0])
|
||||
return true;
|
||||
else
|
||||
if (m_nVertex[0] == rEdge.m_nVertex[0])
|
||||
return m_nVertex[1] < rEdge.m_nVertex[1];
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
//! get teh start or end vertex index
|
||||
//! /param nIndex 0/1
|
||||
inline unsigned operator [] (int nIndex)const
|
||||
{
|
||||
assert(nIndex==0 || nIndex==1);
|
||||
return m_nVertex[nIndex];
|
||||
}
|
||||
|
||||
//! copy the basic edge, designed for ancestors
|
||||
//! /param beEdge
|
||||
void setBasicEdge (const BasicEdge& beEdge)
|
||||
{
|
||||
m_nVertex[0] = beEdge.m_nVertex[0];
|
||||
m_nVertex[1] = beEdge.m_nVertex[1];
|
||||
}
|
||||
};
|
||||
|
||||
// -----------------
|
||||
|
||||
// connection of the edge to the face: may contain, depending on the implementation,
|
||||
// the face index, pointer to it, vertex, pointer to it
|
||||
struct EdgeFace
|
||||
{
|
||||
//! default constructor
|
||||
EdgeFace (){}
|
||||
|
||||
//! constructor
|
||||
//! /param nFace face index
|
||||
//! /param nVertex vertex index
|
||||
EdgeFace (vindex nFace, vindex nVertex): m_nFace(nFace), m_nVertex(nVertex) {}
|
||||
|
||||
//! /return face index
|
||||
inline vindex getFaceIndex ()const {return m_nFace;}
|
||||
|
||||
//! /return vertex index
|
||||
inline vindex getVertexIndex() const {return m_nVertex;}
|
||||
|
||||
vindex m_nFace; //!< face index
|
||||
vindex m_nVertex; //!< face vertex
|
||||
};
|
||||
|
||||
// -----------------
|
||||
|
||||
// This is a primary connectivity edge data structure:
|
||||
// the basic edge (start and end vertices, inherited from BasicEdge)
|
||||
// and the opposite face edges
|
||||
class Edge: public BasicEdge
|
||||
{
|
||||
//! this and opposite face 3rd vertex.
|
||||
//! in "this" face, the edge goes CCW (natural) direction [0],
|
||||
//! and in "opposite" face it goes CW (reverse) direction [1]
|
||||
EdgeFace m_Face[2];
|
||||
|
||||
public:
|
||||
|
||||
//! default constructor
|
||||
Edge () {}
|
||||
|
||||
//! constructor
|
||||
//! /param be edge datastructure
|
||||
//! /param ef0 in this triangle the edge goes CCW (natural) direction
|
||||
//! /param ef1 in this triangle the edge goes CW (reverse) direction
|
||||
Edge (const BasicEdge& be, const EdgeFace& ef0, const EdgeFace& ef1):
|
||||
BasicEdge(be)
|
||||
{
|
||||
m_Face[0] = ef0;
|
||||
m_Face[1] = ef1;
|
||||
}
|
||||
|
||||
//! /param nFace 0/1
|
||||
//! /return reference to the face data structure
|
||||
const EdgeFace& getFace(int nFace) const
|
||||
{
|
||||
assert(nFace==0 || nFace==1);
|
||||
|
||||
return m_Face[nFace];
|
||||
}
|
||||
|
||||
//! /param nFace 0/1
|
||||
//! /param ef reference to the edge datastructure
|
||||
void setFace (int nFace, const EdgeFace& ef)
|
||||
{
|
||||
assert(nFace==0 || nFace==1);
|
||||
|
||||
m_Face[nFace] = ef;
|
||||
}
|
||||
};
|
||||
|
||||
// -----------------
|
||||
|
||||
// orphan edge - an edge with only one face attached to it (boundary)
|
||||
class OrphanEdge: public BasicEdge
|
||||
{
|
||||
EdgeFace m_Face; //!<
|
||||
|
||||
public:
|
||||
//! default constructor
|
||||
OrphanEdge () {}
|
||||
|
||||
// constructor
|
||||
OrphanEdge (const BasicEdge& be, const EdgeFace& ef):
|
||||
BasicEdge (be),
|
||||
m_Face (ef)
|
||||
{}
|
||||
|
||||
const EdgeFace& getFace()const {return m_Face;}
|
||||
void setFace (const EdgeFace& ef) {m_Face = ef;}
|
||||
};
|
||||
|
||||
// -----------------
|
||||
|
||||
// face - 3 vertices
|
||||
class Face
|
||||
{
|
||||
public:
|
||||
vindex m_nVertex[3]; //!<
|
||||
|
||||
//! default constructur
|
||||
Face () {}
|
||||
|
||||
//! constructor
|
||||
//! /param nV0 first vertex index
|
||||
//! /param nV1 second vertex index
|
||||
//! /param nV2 thired vertex index
|
||||
Face (vindex nV0, vindex nV1, vindex nV2)
|
||||
{
|
||||
m_nVertex[0] = nV0;
|
||||
m_nVertex[1] = nV1;
|
||||
m_nVertex[2] = nV2;
|
||||
}
|
||||
|
||||
//! get the index of one triangle vertex
|
||||
//! /param nVtx 0/1/2
|
||||
//! /return index of that triangle vertex
|
||||
const vindex getVertex (int nVtx) const
|
||||
{
|
||||
assert(nVtx==0 || nVtx==1 || nVtx==2);
|
||||
|
||||
return m_nVertex[nVtx];
|
||||
}
|
||||
|
||||
//! set the index of one triangle vertex
|
||||
//! /param nVtx 0/1/2
|
||||
//! /param nIndex index of the triangle vertex no <nVtx>
|
||||
void setVertex (int nVtx, vindex nIndex)
|
||||
{
|
||||
assert(nVtx==0 || nVtx==1 || nVtx==2);
|
||||
|
||||
m_nVertex[nVtx] = nIndex;
|
||||
}
|
||||
};
|
||||
|
||||
// -----------------
|
||||
|
||||
//! /aparam nEdge 0..m_numEdges-1
|
||||
//! /return the nEdge'th edge
|
||||
const Edge& getEdge (int nEdge)const
|
||||
{
|
||||
assert(m_pEdges);
|
||||
assert(nEdge>=0);
|
||||
assert((unsigned)nEdge<m_numEdges);
|
||||
|
||||
return m_pEdges[nEdge];
|
||||
}
|
||||
|
||||
// returns the nEdge's orphaned edge
|
||||
//! /param nEdge 0..m_numOrphanEdges-1
|
||||
//! /return
|
||||
const OrphanEdge& getOrphanEdge(int nEdge)const
|
||||
{
|
||||
assert(m_pOrphanEdges);
|
||||
assert(nEdge>=0);
|
||||
assert((unsigned)nEdge<m_numOrphanEdges);
|
||||
|
||||
return m_pOrphanEdges[nEdge];
|
||||
}
|
||||
|
||||
//! returns the nFace's face
|
||||
//! /param 0..m_numFaces-1
|
||||
//! /return reference to the face
|
||||
const Face& getFace (int nFace) const
|
||||
{
|
||||
assert(m_pFaces);
|
||||
assert(nFace>=0);
|
||||
assert((unsigned)nFace<m_numFaces);
|
||||
|
||||
return m_pFaces[nFace];
|
||||
}
|
||||
|
||||
// copies the array of referred faces into internal array
|
||||
// this is specially optimized for faster cooperation with the Builder
|
||||
// The number of faces is determined from the earlier given edges, so
|
||||
// NOTE: becareful to call the SetOrphanEdges BEFORE THIS FUNCTION
|
||||
// DO NOT call twice, this is only designed to be called once after construction
|
||||
void SetFaces (const std::vector<Face>& arrFaces)
|
||||
{
|
||||
assert (!m_pFaces && m_numFaces <= arrFaces.size());
|
||||
if (!arrFaces.empty())
|
||||
{
|
||||
m_pFaces = new Face[m_numFaces = arrFaces.size()];
|
||||
for (unsigned i = 0; i < m_numFaces; ++i)
|
||||
m_pFaces[i] = arrFaces[i];
|
||||
}
|
||||
}
|
||||
|
||||
// destruct the object (it's only constructed by the Builder)
|
||||
// the virtual ensures that the function releases the object in the same module where it was allocated:
|
||||
// because the VTable was also allocated in the same module
|
||||
virtual void Release ()
|
||||
{
|
||||
assert(this);
|
||||
// this is a counterpart to the new that's called within the
|
||||
// CStencilShadowConnectivityBuilder::ConstructConnectivity() method
|
||||
delete this;
|
||||
}
|
||||
|
||||
const virtual CStencilShadowConnectivity *GetInternalRepresentation( void ) const
|
||||
{
|
||||
return(this);
|
||||
}
|
||||
|
||||
|
||||
// from IStencilShadowConnectivity
|
||||
virtual bool DebugConnectivityInfo( const char *szFilename )
|
||||
{
|
||||
// used only for debugging
|
||||
FILE *out=fopen(szFilename,"w");
|
||||
if(!out)return(false);
|
||||
|
||||
fprintf(out,"%d Edges:\n",m_numEdges);
|
||||
for(unsigned i=0;i<m_numEdges;i++)
|
||||
{
|
||||
fprintf(out," face={%d,%d}, vertex={%d,%d}\n",
|
||||
(m_pEdges[i].getFace(0)).getFaceIndex(),
|
||||
(m_pEdges[i].getFace(1)).getFaceIndex(),
|
||||
m_pEdges[i].m_nVertex[0],
|
||||
m_pEdges[i].m_nVertex[1]);
|
||||
}
|
||||
|
||||
fprintf(out,"%d OrphanEdges:\n",m_numOrphanEdges);
|
||||
for(unsigned i=0;i<m_numOrphanEdges;i++)
|
||||
#if !defined(LINUX)
|
||||
fprintf(out," face={%d}, vertex={%d,%d}\n",m_pOrphanEdges[i].getFace(),m_pOrphanEdges[i].m_nVertex[0],m_pOrphanEdges[i].m_nVertex[1]);
|
||||
#else
|
||||
fprintf(out,", vertex={%d,%d}\n",m_pOrphanEdges[i].m_nVertex[0],m_pOrphanEdges[i].m_nVertex[1]);//face info does not compile, no time to make it more correct here
|
||||
#endif//LINUX
|
||||
|
||||
fprintf(out,"%d Vertices:\n",m_numVertices);
|
||||
|
||||
fprintf(out,"Faces:\n",m_numFaces);
|
||||
for(unsigned i=0;i<m_numFaces;i++)
|
||||
fprintf(out," vertex indices={%d,%d,%d}\n",m_pFaces[i].getVertex(0),m_pFaces[i].getVertex(1),m_pFaces[i].getVertex(2));
|
||||
|
||||
fclose(out);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
//! constructor, only makes an empty object that's good for deserializing only
|
||||
CStencilShadowConnectivity ()
|
||||
{
|
||||
m_numEdges = m_numOrphanEdges = m_numVertices = m_numFaces = 0;
|
||||
m_pOrphanEdges = NULL;
|
||||
m_pFaces = NULL;
|
||||
m_pEdges = NULL;
|
||||
m_pPlanes = NULL;
|
||||
m_pVertices = NULL;
|
||||
}
|
||||
|
||||
struct Plane
|
||||
{
|
||||
Vec3d vNormal;
|
||||
float fDistance;
|
||||
|
||||
Plane(){}
|
||||
Plane (const Vec3d& v0, const Vec3d& v1, const Vec3d& v2)
|
||||
{
|
||||
vNormal = (v1-v0)^(v2-v0);
|
||||
fDistance = (v0*vNormal);
|
||||
}
|
||||
float apply (const Vec3d& v)const
|
||||
{
|
||||
return vNormal * v - fDistance;
|
||||
}
|
||||
};
|
||||
|
||||
//! Calculates the size of this object
|
||||
void GetMemoryUsage(ICrySizer* pSizer)
|
||||
{
|
||||
pSizer->AddObject(this,Serialize (true, NULL,0));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//! constructor is only called within 3DEngine
|
||||
//! /param pEdges - array of nNumEdges edges
|
||||
//! /param nNumEdges
|
||||
CStencilShadowConnectivity( const std::vector<Edge>& arrEdges)
|
||||
{
|
||||
m_pOrphanEdges=NULL;
|
||||
m_pFaces=NULL;
|
||||
m_numOrphanEdges=0;
|
||||
|
||||
// find the max vertex index to put it into m_nVertices
|
||||
m_numVertices = 0;
|
||||
m_numFaces = 0;
|
||||
for (std::vector<Edge>::const_iterator it = arrEdges.begin(); it != arrEdges.end(); ++it)
|
||||
{
|
||||
UseBasicEdge (*it);
|
||||
UseEdgeFace (it->getFace(0));
|
||||
UseEdgeFace (it->getFace(1));
|
||||
}
|
||||
|
||||
m_numEdges = arrEdges.size();
|
||||
if(m_numEdges)
|
||||
{
|
||||
m_pEdges = new Edge[m_numEdges];
|
||||
for (unsigned i = 0; i < m_numEdges; ++i)
|
||||
m_pEdges[i] = arrEdges[i];
|
||||
}
|
||||
else
|
||||
m_pEdges=0;
|
||||
|
||||
m_pPlanes = NULL;
|
||||
m_pVertices = NULL;
|
||||
}
|
||||
|
||||
void SetPlanes (const Plane* pPlanes, unsigned numPlanes)
|
||||
{
|
||||
if (m_pPlanes)
|
||||
delete [] m_pPlanes;
|
||||
if (pPlanes)
|
||||
{
|
||||
assert (numPlanes >= m_numFaces);
|
||||
m_pPlanes = new Plane[m_numFaces];
|
||||
memcpy (m_pPlanes, pPlanes, sizeof(Plane) * m_numFaces);
|
||||
}
|
||||
else
|
||||
m_pPlanes = NULL;
|
||||
}
|
||||
|
||||
void SetVertices(const Vec3d* pVertices, unsigned numVertices)
|
||||
{
|
||||
if (m_pVertices)
|
||||
delete[]m_pVertices;
|
||||
if (pVertices)
|
||||
{
|
||||
assert (numVertices >= m_numVertices);
|
||||
m_pVertices = new Vec3d[m_numVertices];
|
||||
memcpy (m_pVertices, pVertices, sizeof(Vec3d)*m_numVertices);
|
||||
}
|
||||
else
|
||||
m_pVertices = NULL;
|
||||
}
|
||||
|
||||
// remaps all vertex indices and memorizes the passed "new" vertex array (in new indexation)
|
||||
void SetRemapVertices (const vindex*pMap, unsigned numMapEntries, const Vec3d* pNewVertices, unsigned numNewVertices)
|
||||
{
|
||||
if (m_pVertices)
|
||||
delete[]m_pVertices;
|
||||
assert (pNewVertices);
|
||||
// we collected information about the vertices before . The number of used vertices is in
|
||||
// m_numVertices. We assume the passed new vertex map can not make this number larger, because
|
||||
// its sole purpose is optimization of number of vertex indices used (for storing the vertex info inside)
|
||||
assert (numNewVertices <= m_numVertices);
|
||||
m_numVertices = numNewVertices;
|
||||
m_pVertices = new Vec3d[numNewVertices];
|
||||
memcpy (m_pVertices, pNewVertices, sizeof(Vec3d)*numNewVertices);
|
||||
|
||||
remapVertexIndices (pMap, numMapEntries);
|
||||
}
|
||||
|
||||
|
||||
// can be destructed only from within Release()
|
||||
virtual ~CStencilShadowConnectivity(void)
|
||||
{
|
||||
if (m_pEdges) delete[] m_pEdges;
|
||||
if (m_pOrphanEdges) delete[] m_pOrphanEdges;
|
||||
if (m_pFaces) delete[] m_pFaces;
|
||||
if (m_pPlanes) delete[] m_pPlanes;
|
||||
if (m_pVertices) delete[] m_pVertices;
|
||||
}
|
||||
|
||||
|
||||
// makes sure that the given vertex index fits into the range 0..m_nVertices
|
||||
// by expanding (increasing) m_nVertices
|
||||
void UseVertex(vindex nVertex)
|
||||
{
|
||||
if (nVertex >= m_numVertices)
|
||||
m_numVertices = nVertex + 1;
|
||||
}
|
||||
|
||||
// makes sure that the given face index fits into the range 0..m_nFaces
|
||||
// by expanding (increasing) m_nFaces
|
||||
void UseFace (vindex nFace)
|
||||
{
|
||||
if (nFace >= m_numFaces)
|
||||
m_numFaces = nFace + 1;
|
||||
}
|
||||
|
||||
// copies the list of orphaned edges into internal array
|
||||
// this is specially optimized for faster cooperation with the Builder
|
||||
// DO NOT call twice, this is only designed to be called once after construction
|
||||
typedef std::map<BasicEdge, EdgeFace> OrphanEdgeMap;
|
||||
|
||||
|
||||
// copies the list of orphaned edges into internal array
|
||||
// this is specially optimized for faster cooperation with the Builder
|
||||
// DO NOT call twice, this is only designed to be called once after construction
|
||||
void SetOrphanEdges (const OrphanEdgeMap& mapOrphanEdge)
|
||||
{
|
||||
m_numOrphanEdges = mapOrphanEdge.size();
|
||||
|
||||
m_pOrphanEdges = new OrphanEdge[m_numOrphanEdges];
|
||||
|
||||
OrphanEdge* pEdge = m_pOrphanEdges;
|
||||
|
||||
// copy the content of the orphan edge map into the array
|
||||
for (OrphanEdgeMap::const_iterator it = mapOrphanEdge.begin(); it != mapOrphanEdge.end(); ++it)
|
||||
{
|
||||
pEdge->setBasicEdge (it->first);
|
||||
pEdge->setFace (it->second);
|
||||
|
||||
UseBasicEdge (*pEdge);
|
||||
UseEdgeFace (pEdge->getFace());
|
||||
|
||||
++pEdge;
|
||||
}
|
||||
}
|
||||
|
||||
// makes sure that the vertices/faces referenced by the edge are in account by the m_numFaces and m_numVertices
|
||||
void UseBasicEdge (const BasicEdge& beEdge)
|
||||
{
|
||||
UseVertex(beEdge[0]);
|
||||
UseVertex(beEdge[1]);
|
||||
}
|
||||
|
||||
// makes sure that the vertices/faces referenced by the edge are in account by the m_numFaces and m_numVertices
|
||||
void UseEdgeFace (const EdgeFace& efEdge)
|
||||
{
|
||||
UseFace (efEdge.getFaceIndex());
|
||||
UseVertex(efEdge.getVertexIndex());
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! for debugging and profiling
|
||||
//! /param outVertexCount
|
||||
//! /param outTriangleCount
|
||||
virtual void GetStats( DWORD &outVertexCount, DWORD &outTriangleCount )
|
||||
{
|
||||
outVertexCount=m_numVertices;
|
||||
outTriangleCount=m_numFaces;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// the version of the stream
|
||||
enum {g_nSerialVersion = 2};
|
||||
|
||||
//! Deserializes this object. Returns the number of bytes read. 0 means error
|
||||
//! pWarningLog is used to put warnings about deserialized connectivity
|
||||
unsigned Deserialize (void *pStream, unsigned nSize, IMiniLog* pWarningLog = NULL)
|
||||
{
|
||||
unsigned* pHeader = (unsigned*)pStream;
|
||||
|
||||
if (nSize < 5 * sizeof(unsigned))
|
||||
return 0; // we should have the header in place
|
||||
|
||||
if (*(pHeader++) != g_nSerialVersion) // version is incompatible
|
||||
return 0;
|
||||
|
||||
m_numEdges = *(pHeader++);
|
||||
m_numOrphanEdges = *(pHeader++);
|
||||
m_numVertices = *(pHeader++);
|
||||
m_numFaces = *(pHeader++);
|
||||
unsigned numPlanes = *(pHeader++);
|
||||
assert (numPlanes == 0 || numPlanes == m_numFaces);
|
||||
unsigned numVertices = *(pHeader++);
|
||||
assert (numVertices == 0 || numVertices == m_numVertices);
|
||||
|
||||
unsigned nRequiredSize =
|
||||
sizeof(unsigned) +
|
||||
sizeof(m_numEdges) + m_numEdges * sizeof(Edge) +
|
||||
sizeof(m_numOrphanEdges) + m_numOrphanEdges * sizeof(OrphanEdge) +
|
||||
sizeof(m_numVertices) +
|
||||
sizeof(m_numFaces) + m_numFaces * sizeof(Face) +
|
||||
sizeof(numPlanes) + numPlanes * sizeof(Plane)+
|
||||
sizeof(numVertices) + numVertices * sizeof(Vec3d);
|
||||
|
||||
if(m_pEdges) delete[] m_pEdges;
|
||||
if(m_pOrphanEdges) delete[] m_pOrphanEdges;
|
||||
if(m_pFaces) delete[] m_pFaces;
|
||||
if(m_pPlanes) delete[] m_pPlanes;
|
||||
if (m_pVertices) delete []m_pVertices;
|
||||
|
||||
if (nSize < nRequiredSize)
|
||||
{
|
||||
m_pEdges = NULL;
|
||||
m_pOrphanEdges = NULL;
|
||||
m_pFaces = NULL;
|
||||
|
||||
m_numEdges = 0;
|
||||
m_numOrphanEdges = 0;
|
||||
m_numVertices = 0;
|
||||
m_numFaces = 0;
|
||||
|
||||
// incompatible stream
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_pEdges = new Edge [m_numEdges];
|
||||
m_pOrphanEdges = new OrphanEdge [m_numOrphanEdges];
|
||||
m_pFaces = new Face [m_numFaces];
|
||||
m_pPlanes = numPlanes?new Plane[numPlanes]:NULL;
|
||||
m_pVertices = numVertices?new Vec3d[numVertices]:NULL;
|
||||
|
||||
Edge* pEdgeData = (Edge*)pHeader;
|
||||
memcpy (m_pEdges, pEdgeData, m_numEdges*sizeof(Edge));
|
||||
OrphanEdge* pOrphanEdgeData = (OrphanEdge*)(pEdgeData + m_numEdges);
|
||||
memcpy (m_pOrphanEdges, pOrphanEdgeData, m_numOrphanEdges*sizeof(OrphanEdge));
|
||||
Face* pFaceData = (Face*)(pOrphanEdgeData + m_numOrphanEdges);
|
||||
memcpy (m_pFaces, pFaceData, m_numFaces * sizeof(Face));
|
||||
|
||||
Plane* pPlanes = (Plane*)(pFaceData+m_numFaces);
|
||||
if (numPlanes)
|
||||
memcpy (m_pPlanes, pPlanes, numPlanes* sizeof(Plane));
|
||||
|
||||
Vec3d* pVertices = (Vec3d*)(pPlanes + numPlanes);
|
||||
if (numVertices)
|
||||
memcpy (m_pVertices, pVertices, sizeof(Vec3d)*numVertices);
|
||||
|
||||
#if !defined(LINUX)
|
||||
if (m_numOrphanEdges && pWarningLog)
|
||||
pWarningLog->LogWarning("Connectivity warning: there are %d open edges (%d closed, %d faces, %d planes, %d vertices)", m_numOrphanEdges, m_numEdges, m_numFaces, numPlanes, numVertices);
|
||||
#endif
|
||||
return nRequiredSize;
|
||||
}
|
||||
|
||||
|
||||
//! Serializes this object to the given memory block; if it's NULL, only returns
|
||||
//! the number of bytes required. If it's not NULL, returns the number of bytes written
|
||||
//! (0 means error, insufficient space)
|
||||
unsigned Serialize (bool bSave, void* pStream, unsigned nSize, IMiniLog* pWarningLog = NULL)
|
||||
{
|
||||
if (!bSave)
|
||||
return Deserialize (pStream, nSize, pWarningLog);
|
||||
|
||||
// calculate the required size of the buffer
|
||||
unsigned
|
||||
numPlanes = m_pPlanes?m_numFaces:0,
|
||||
numVertices = m_pVertices?m_numVertices:0,
|
||||
nRequiredSize =
|
||||
sizeof(unsigned) +
|
||||
sizeof(m_numEdges) + m_numEdges * sizeof(Edge) +
|
||||
sizeof(m_numOrphanEdges) + m_numOrphanEdges * sizeof(OrphanEdge) +
|
||||
sizeof(m_numVertices) +
|
||||
sizeof(m_numFaces) + m_numFaces * sizeof(Face) +
|
||||
sizeof(numPlanes) + numPlanes * sizeof(Plane)+
|
||||
sizeof(numVertices) + numVertices * sizeof(Vec3d);
|
||||
|
||||
if (pStream)
|
||||
{
|
||||
if (nSize < nRequiredSize)
|
||||
return 0; // insufficient space in the pStream buffer
|
||||
|
||||
unsigned* pHeader = (unsigned*)pStream;
|
||||
*(pHeader++) = g_nSerialVersion; // version of the stream
|
||||
*(pHeader++) = m_numEdges;
|
||||
*(pHeader++) = m_numOrphanEdges;
|
||||
*(pHeader++) = m_numVertices;
|
||||
*(pHeader++) = m_numFaces;
|
||||
*(pHeader++) = numPlanes;
|
||||
*(pHeader++) = numVertices;
|
||||
|
||||
Edge* pEdgeData = (Edge*)pHeader;
|
||||
memcpy (pEdgeData, m_pEdges, m_numEdges*sizeof(Edge));
|
||||
OrphanEdge* pOrphanEdgeData = (OrphanEdge*)(pEdgeData + m_numEdges);
|
||||
memcpy (pOrphanEdgeData, m_pOrphanEdges, m_numOrphanEdges*sizeof(OrphanEdge));
|
||||
Face* pFaceData = (Face*)(pOrphanEdgeData + m_numOrphanEdges);
|
||||
memcpy (pFaceData, m_pFaces, m_numFaces * sizeof(Face));
|
||||
Plane* pPlanes = (Plane*)(pFaceData+m_numFaces);
|
||||
if (m_pPlanes)
|
||||
memcpy (pPlanes, m_pPlanes, numPlanes * sizeof(Plane));
|
||||
Vec3d* pVertices = (Vec3d*)(pPlanes+numPlanes);
|
||||
if (m_pVertices)
|
||||
memcpy (pVertices, m_pVertices, numVertices * sizeof(Vec3d));
|
||||
}
|
||||
|
||||
return nRequiredSize;
|
||||
}
|
||||
|
||||
// the plane equation, x*n+d == 0
|
||||
bool hasPlanes() const {return m_pPlanes != NULL;}
|
||||
const Plane&getPlane (unsigned i)const {assert(i<m_numFaces && m_pPlanes);return m_pPlanes[i];}
|
||||
|
||||
const Vec3d* getVertices() const {return m_pVertices;}
|
||||
|
||||
bool IsStandalone() const {return m_pPlanes != NULL && m_pVertices!= NULL;}
|
||||
|
||||
void remapVertexIndices(const vindex*pMap, unsigned nMapSize)
|
||||
{
|
||||
unsigned i;
|
||||
#define REMAP(X) assert((X) < nMapSize);\
|
||||
(X) = pMap[X];\
|
||||
assert ((vindex)(X) != (vindex)-1 && (X) < m_numVertices)
|
||||
|
||||
for(i=0;i<m_numEdges;i++)
|
||||
{
|
||||
REMAP(m_pEdges[i].m_nVertex[0]);
|
||||
REMAP(m_pEdges[i].m_nVertex[1]);
|
||||
}
|
||||
for(i=0;i<m_numOrphanEdges;i++)
|
||||
{
|
||||
REMAP(m_pOrphanEdges[i].m_nVertex[0]);
|
||||
REMAP(m_pOrphanEdges[i].m_nVertex[1]);
|
||||
}
|
||||
for(i=0;i<m_numFaces;i++)
|
||||
{
|
||||
REMAP(m_pFaces[i].m_nVertex[0]);
|
||||
REMAP(m_pFaces[i].m_nVertex[1]);
|
||||
REMAP(m_pFaces[i].m_nVertex[2]);
|
||||
}
|
||||
#undef REMAP
|
||||
}
|
||||
private:
|
||||
|
||||
|
||||
friend class CStencilShadowConnectivityBuilder;
|
||||
friend class CStencilShadowStaticConnectivityBuilder;
|
||||
|
||||
// the array of normal edges (with two adjacent faces)
|
||||
unsigned m_numEdges; //!<
|
||||
Edge* m_pEdges; //!<
|
||||
|
||||
// the array of orphaned edges (with only one face attached)
|
||||
unsigned m_numOrphanEdges; //!<
|
||||
OrphanEdge* m_pOrphanEdges; //!<
|
||||
|
||||
|
||||
private:
|
||||
// number of vertices in the array referenced by the mesh
|
||||
unsigned m_numVertices; //!<
|
||||
|
||||
// the faces
|
||||
unsigned m_numFaces; //!< number of faces in the array referenced by the mesh
|
||||
Face* m_pFaces; //!<
|
||||
Plane* m_pPlanes; //!< if not NULL, then use these normals instead of computing them on the fly; 1 face - 1 normal
|
||||
Vec3d* m_pVertices;
|
||||
};
|
||||
|
||||
#ifdef WIN64
|
||||
#pragma warning( pop ) //AMD Port
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _STENCIL_SHADOW_CONNECTIVITY_HDR_
|
||||
279
ResourceCompilerPC/StencilShadowConnectivityBuilder.cpp
Normal file
279
ResourceCompilerPC/StencilShadowConnectivityBuilder.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
#include "stdafx.h" // precompiled header
|
||||
#include "StencilShadowConnectivity.h"
|
||||
#include "StencilShadowConnectivityBuilder.h"
|
||||
|
||||
#ifdef WIN64
|
||||
#pragma warning( push ) //AMD Port
|
||||
#pragma warning( disable : 4267 )
|
||||
#endif
|
||||
|
||||
// creates an empty mesh connectivity
|
||||
CStencilShadowConnectivityBuilder::CStencilShadowConnectivityBuilder( void )
|
||||
#ifdef DEBUG_STD_CONTAINERS
|
||||
:m_mapSingleEdges("CStencilShadowConnectivityBuilder.SingleEdges")
|
||||
,m_vDoubleEdges ("CStencilShadowConnectivityBuilder.DoubleEdges")
|
||||
,m_vFaces("CStencilShadowConnectivityBuilder.Faces")
|
||||
,m_mVertexWelder("CStencilShadowConnectivityBuilder.VertexWelder")
|
||||
#endif
|
||||
{
|
||||
Reinit();
|
||||
}
|
||||
|
||||
CStencilShadowConnectivityBuilder::~CStencilShadowConnectivityBuilder( void )
|
||||
{
|
||||
}
|
||||
|
||||
void CStencilShadowConnectivityBuilder::Reinit( void )
|
||||
{
|
||||
m_mapSingleEdges.clear();
|
||||
m_vDoubleEdges.clear();
|
||||
m_vFaces.clear();
|
||||
m_mVertexWelder.clear();
|
||||
m_dwNumUncompressedVertices=0;
|
||||
// m_fWeldTolerance = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// adds a single triangle to the mesh
|
||||
// the tirangle is defined by three vertices, in counter-clockwise order
|
||||
// these vertex indices will be used later when accessing the array of
|
||||
// deformed character/model vertices to determine the shadow volume boundary
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
void CStencilShadowConnectivityBuilder::AddTriangle( unsigned short nV0, unsigned short nV1, unsigned short nV2 )
|
||||
{
|
||||
unsigned nNumFaces = m_vFaces.size();
|
||||
AddNewEdge (BasicEdge(nV0, nV1), EdgeFace(nNumFaces, nV2));
|
||||
AddNewEdge (BasicEdge(nV1, nV2), EdgeFace(nNumFaces, nV0));
|
||||
AddNewEdge (BasicEdge(nV2, nV0), EdgeFace(nNumFaces, nV1));
|
||||
m_vFaces.push_back(Face (nV0, nV1, nV2));
|
||||
}
|
||||
|
||||
|
||||
// this will try to find a close match to the given vertex, and
|
||||
// if found, return its index (the actual index of the vertex that's very close or
|
||||
// coincide with v in space). Otherwise, creates a new vertex reference in the map
|
||||
// and returns the index nNewVertex
|
||||
unsigned CStencilShadowConnectivityBuilder::WeldVertex (const Vec3d& v, unsigned nNewVertex)
|
||||
{
|
||||
// The easiest way: just find it directly
|
||||
VertexWelderMap::iterator it;
|
||||
it = m_mVertexWelder.find(v);
|
||||
if (it != m_mVertexWelder.end())
|
||||
return it->second;
|
||||
else
|
||||
{
|
||||
/*
|
||||
// scan and find some very close vertex
|
||||
if (m_fWeldTolerance > 0)
|
||||
for (it = m_mVertexWelder.begin(); it != m_mVertexWelder.end(); ++it)
|
||||
{
|
||||
if ((it->first-v).len2() < m_fWeldTolerance)
|
||||
return it->second;
|
||||
}
|
||||
*/
|
||||
m_mVertexWelder.insert (VertexWelderMap::value_type(v, nNewVertex));
|
||||
return nNewVertex;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Adds the triangle with the given vertex indices and vertex coordinates
|
||||
// to the list of triangles that will cast shadows. Welds the vertices based on their
|
||||
// coordinates
|
||||
void CStencilShadowConnectivityBuilder::AddTriangleWelded(
|
||||
unsigned short nV0, unsigned short nV1, unsigned short nV2,
|
||||
const Vec3d &vV0, const Vec3d &vV1, const Vec3d &vV2 )
|
||||
{
|
||||
nV0=WeldVertex(vV0,nV0);
|
||||
nV1=WeldVertex(vV1,nV1);
|
||||
nV2=WeldVertex(vV2,nV2);
|
||||
|
||||
AddTriangle(nV0,nV1,nV2);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// add a new edge, if there is no complementary single edge;
|
||||
// otherwise, withdraw the edge from the list of single edges and add to double edges
|
||||
// PARAMETERS:
|
||||
// edge - start and end vertices of the edge going CCW along the face
|
||||
// efFace - the opposite vertex/face the edge belongs to
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
void CStencilShadowConnectivityBuilder::AddNewEdge (BasicEdge eEdge, EdgeFace efFace)
|
||||
{
|
||||
// first, try to find the complementary
|
||||
BasicEdge eComplementary (eEdge[1], eEdge[0]);
|
||||
|
||||
SingleEdgeMap::iterator itComplementary = m_mapSingleEdges.find (eComplementary);
|
||||
|
||||
if (itComplementary == m_mapSingleEdges.end())
|
||||
{
|
||||
// complementeary edge not found. Add a new single edge
|
||||
|
||||
m_mapSingleEdges.insert (SingleEdgeMap::value_type(eEdge, efFace));
|
||||
|
||||
// nVEdgeG for nFaceVertex[1] is unknown and doesn't matter at the moment
|
||||
}
|
||||
else
|
||||
{
|
||||
// we found the complementary edge
|
||||
Edge edgeNewDouble (eComplementary, itComplementary->second, efFace);
|
||||
|
||||
m_vDoubleEdges.push_back (edgeNewDouble);
|
||||
|
||||
m_mapSingleEdges.erase (itComplementary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// constructs/compiles the optimum representation of the connectivity
|
||||
// to be used in run-time
|
||||
// WARNING: use Release method to dispose the connectivity object
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
IStencilShadowConnectivity *CStencilShadowConnectivityBuilder::ConstructConnectivity( void )
|
||||
{
|
||||
CStencilShadowConnectivity* pConnectivity = new CStencilShadowConnectivity(m_vDoubleEdges);
|
||||
|
||||
assert(pConnectivity); // low memeory?
|
||||
|
||||
pConnectivity->SetOrphanEdges(m_mapSingleEdges);
|
||||
pConnectivity->SetFaces(m_vFaces);
|
||||
|
||||
// find all the used vertices
|
||||
FaceArray::const_iterator pFace = m_vFaces.begin();
|
||||
DWORD nFaceCount = m_vFaces.size();
|
||||
|
||||
#if 0
|
||||
// test for serialization function
|
||||
unsigned nBufSize = pConnectivity->Serialize(true, NULL, 0);
|
||||
void* pBuf = malloc (nBufSize);
|
||||
unsigned nSaved = pConnectivity->Serialize(true, pBuf, nBufSize);
|
||||
assert (nSaved == nBufSize);
|
||||
pConnectivity->Release();
|
||||
pConnectivity = new CStencilShadowConnectivity ();
|
||||
unsigned nLoaded = pConnectivity->Serialize(false, pBuf, nBufSize);
|
||||
assert (nLoaded == nBufSize);
|
||||
free (pBuf);
|
||||
#endif
|
||||
|
||||
return((IStencilShadowConnectivity *)pConnectivity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// returns the number of single (with no pair faces found) or orphaned edges
|
||||
unsigned CStencilShadowConnectivityBuilder::numOrphanedEdges ()const
|
||||
{
|
||||
return(m_mapSingleEdges.size());
|
||||
}
|
||||
|
||||
//! Returns the list of faces for orphaned edges into the given buffer;
|
||||
//! For each orphaned edge, one face will be returned; some faces may be duplicated
|
||||
void CStencilShadowConnectivityBuilder::getOrphanedEdgeFaces (unsigned* pBuffer)
|
||||
{
|
||||
for (SingleEdgeMap::iterator it = m_mapSingleEdges.begin(); it != m_mapSingleEdges.end(); ++it)
|
||||
*(pBuffer++) = it->second.m_nFace;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// reserves space for the given number of triangles that are to be added
|
||||
void CStencilShadowConnectivityBuilder::ReserveForTriangles( unsigned nNumTriangles, unsigned innNumVertices )
|
||||
{
|
||||
m_vDoubleEdges.reserve(nNumTriangles*3/2);
|
||||
m_vFaces.reserve(nNumTriangles);
|
||||
|
||||
m_dwNumUncompressedVertices=innNumVertices;
|
||||
}
|
||||
|
||||
|
||||
CStencilShadowStaticConnectivityBuilder::CStencilShadowStaticConnectivityBuilder()
|
||||
#ifdef DEBUG_STD_CONTAINERS
|
||||
: m_vPlanes("CStencilShadowStaticConnectivityBuilder.Planes")
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
CStencilShadowStaticConnectivityBuilder::~CStencilShadowStaticConnectivityBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
// reserves space for the given number of triangles that are to be added
|
||||
void CStencilShadowStaticConnectivityBuilder::ReserveForTriangles( unsigned nNumTriangles, unsigned innNumVertices )
|
||||
{
|
||||
CStencilShadowConnectivityBuilder::ReserveForTriangles (nNumTriangles, innNumVertices);
|
||||
m_vPlanes.reserve (nNumTriangles);
|
||||
}
|
||||
|
||||
//! return to the state right after construction
|
||||
void CStencilShadowStaticConnectivityBuilder::Reinit( void )
|
||||
{
|
||||
CStencilShadowConnectivityBuilder::Reinit();
|
||||
m_vPlanes.clear();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Adds the triangle with the given vertex indices and vertex coordinates
|
||||
// to the list of triangles that will cast shadows. Welds the vertices based on their
|
||||
// coordinates. Calculates and remembers the normals for each triangle
|
||||
void CStencilShadowStaticConnectivityBuilder::AddTriangleWelded(
|
||||
vindex nV0, vindex nV1, vindex nV2,
|
||||
const Vec3d &vV0, const Vec3d &vV1, const Vec3d &vV2 )
|
||||
{
|
||||
CStencilShadowConnectivityBuilder::AddTriangleWelded (nV0, nV1, nV2, vV0, vV1, vV2);
|
||||
m_vPlanes.push_back(Plane (vV0,vV1,vV2));
|
||||
}
|
||||
|
||||
// constructs/compiles the optimum representation of the connectivity
|
||||
// to be used in run-time
|
||||
// WARNING: use Release method to dispose the connectivity object
|
||||
//! /param inpVertexBuf vertex position buffer to check for solvable open edges (2 vertices with same position)
|
||||
//! /return interface pointer, could be 0
|
||||
class IStencilShadowConnectivity *CStencilShadowStaticConnectivityBuilder::ConstructConnectivity ()
|
||||
{
|
||||
if (m_vPlanes.empty())
|
||||
return new CStencilShadowConnectivity();
|
||||
|
||||
CStencilShadowConnectivity * pConnectivity = (CStencilShadowConnectivity *)CStencilShadowConnectivityBuilder::ConstructConnectivity()->GetInternalRepresentation();
|
||||
pConnectivity->SetPlanes(&m_vPlanes[0], m_vPlanes.size());
|
||||
|
||||
SetVertices (pConnectivity);
|
||||
return pConnectivity;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// WARNING: This is only to be called when the whole construction process
|
||||
// is finished, to modify already created connectivity
|
||||
// Goes through all vertices used by the connectivity and constructs a continuous
|
||||
// array out of them; reindexes the vertices in the connectivity object
|
||||
// to use these vertices; puts the new vertex array into the connectivity object
|
||||
void CStencilShadowStaticConnectivityBuilder::SetVertices (CStencilShadowConnectivity * pConnectivity)
|
||||
{
|
||||
// scan through all used vertices and put them into continuous array
|
||||
std::vector<Vec3d> arrNewVertices; // the vertices array in new indexation
|
||||
std::vector<CStencilShadowConnectivity::vindex> arrOldToNewMap; // the mapping old->new indexation
|
||||
arrNewVertices.reserve (pConnectivity->numVertices());
|
||||
arrOldToNewMap.resize (pConnectivity->numVertices(),-1);
|
||||
for (VertexWelderMap::const_iterator it = m_mVertexWelder.begin(); it != m_mVertexWelder.end(); ++it)
|
||||
{
|
||||
#if 1
|
||||
// this will remap the vertex indices
|
||||
arrOldToNewMap[it->second] = arrNewVertices.size();
|
||||
arrNewVertices.push_back(it->first);
|
||||
#else
|
||||
// this will not change indexation
|
||||
arrOldToNewMap[it->second] = it->second;
|
||||
if (arrNewVertices.size() <= it->second)
|
||||
arrNewVertices.resize (it->second+1, Vec3d(0,0,0));
|
||||
arrNewVertices[it->second] = it->first;
|
||||
#endif
|
||||
}
|
||||
|
||||
// now renumber the vertices
|
||||
pConnectivity->SetRemapVertices(&arrOldToNewMap[0], arrOldToNewMap.size(), &arrNewVertices[0], arrNewVertices.size());
|
||||
}
|
||||
|
||||
#ifdef WIN64
|
||||
#pragma warning( pop ) //AMD Port
|
||||
#endif
|
||||
210
ResourceCompilerPC/StencilShadowConnectivityBuilder.h
Normal file
210
ResourceCompilerPC/StencilShadowConnectivityBuilder.h
Normal file
@@ -0,0 +1,210 @@
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CryEngine Source code
|
||||
//
|
||||
// File:StencilShadowConnectivityBuilder.h
|
||||
// Declaration of class CStencilShadowConnectivityBuilder
|
||||
//
|
||||
// History:
|
||||
// -:Created by Sergiy Migdalskiy <sergiy@crytek.de>
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// class CStencilShadowConnectivityBuilder
|
||||
//
|
||||
// This class is used to pre-compute the data for a model that's gonna cast stencil
|
||||
// shadows, and whose vertices may change position, but the topology
|
||||
// cannot change.
|
||||
//
|
||||
// Ok, to put it clear: for each model, you need one instance of
|
||||
// class CStencilShadowConnectivity. To create that instance, use
|
||||
// this class: create an object, push the mesh of the model into it,
|
||||
// then ask this class to give out the CStencilShadowConnectivity.
|
||||
//
|
||||
// CStencilShadowConnectivity is build for maximum run-time performance and
|
||||
// minimal memory footprint, whilst this class is build for convenient
|
||||
// pre-calculations and flexibility.
|
||||
//
|
||||
// The model is allowed to deform, but is not
|
||||
// allowed to change topology (add or remove faces as well as re-assign
|
||||
// face vertices or even change face orientation).
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION NOTES should be in
|
||||
// StencilShadowConnectivityBuilder.cpp
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef _STENCIL_SHADOW_CONNECTIVITY_BUILDER_HDR_
|
||||
#define _STENCIL_SHADOW_CONNECTIVITY_BUILDER_HDR_
|
||||
|
||||
// the connectivity class is required for the declarations
|
||||
// of the Face, Edge, EdgeFace and BasicEdge structures which are common for both
|
||||
// the builder and the built class
|
||||
#include "IEdgeConnectivityBuilder.h" // IEdgeConnectivityBuilder
|
||||
#include "StencilShadowConnectivity.h" // CStencilShadowConnectivity
|
||||
|
||||
#include <map> // STL map<>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
class CStencilShadowConnectivityBuilder : public IEdgeConnectivityBuilder
|
||||
{
|
||||
public:
|
||||
typedef IStencilShadowConnectivity::vindex vindex;
|
||||
//! default constructor
|
||||
//! creates an empty mesh connectivity
|
||||
CStencilShadowConnectivityBuilder(void);
|
||||
|
||||
//! destructor
|
||||
virtual ~CStencilShadowConnectivityBuilder(void);
|
||||
|
||||
//! return to the state right after construction
|
||||
virtual void Reinit( void );
|
||||
|
||||
// sets the maximum distance between two points that are allowed to be welded
|
||||
//virtual void SetWeldTolerance (float fTolerance) {m_fWeldTolerance = fTolerance*fTolerance;}
|
||||
|
||||
// reserves space for the given number of triangles that are to be added
|
||||
//! /param nNumTriangles 0..
|
||||
//! /param innNumVertices 0..
|
||||
virtual void ReserveForTriangles( unsigned nNumTriangles, unsigned innNumVertices );
|
||||
|
||||
// adds a single triangle to the mesh
|
||||
// the triangle is defined by three vertices, in counter-clockwise order
|
||||
// these vertex indices will be used later when accessing the array of
|
||||
// deformed character/model vertices to determine the shadow volume boundary
|
||||
//! /param nV0 vertex index one 0..0xffff
|
||||
//! /param nV1 vertex index two 0..0xffff
|
||||
//! /param nV2 vertex index three 0..0xffff
|
||||
//! /param inpVertexPos pointer to the vertex array (to remove vertices on same position)
|
||||
virtual void AddTriangle( vindex nV0, vindex nV1, vindex nV2 );
|
||||
|
||||
//!
|
||||
//! /param nV0 vertex index one 0..0xffff
|
||||
//! /param nV1 vertex index two 0..0xffff
|
||||
//! /param nV2 vertex index three 0..0xffff
|
||||
//! /param vV0 original vertex one position
|
||||
//! /param vV1 original vertex two position
|
||||
//! /param vV2 original vertex three position
|
||||
//! slower but with the auto weld feature (if there are vertices with the same position your result is smaller and therefore faster)
|
||||
virtual void AddTriangleWelded( vindex nV0, vindex nV1, vindex nV2, const Vec3d &vV0, const Vec3d &vV1, const Vec3d &vV2 );
|
||||
|
||||
// constructs/compiles the optimum representation of the connectivity
|
||||
// to be used in run-time
|
||||
// WARNING: use Release method to dispose the connectivity object
|
||||
//! /param inpVertexBuf vertex position buffer to check for solvable open edges (2 vertices with same position)
|
||||
//! /return interface pointer, could be 0
|
||||
virtual class IStencilShadowConnectivity *ConstructConnectivity( void );
|
||||
|
||||
// returns the number of single (with no pair faces found) or orphaned edges
|
||||
// /return 0..
|
||||
virtual unsigned numOrphanedEdges ()const;
|
||||
|
||||
//! Returns the list of faces for orphaned edges into the given buffer;
|
||||
//! For each orphaned edge, one face will be returned; some faces may be duplicated
|
||||
virtual void getOrphanedEdgeFaces (unsigned* pBuffer);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// for the descriptions of the following shared structures, refer to
|
||||
// File:StencilShadowConnectivity.h
|
||||
typedef CStencilShadowConnectivity::BasicEdge BasicEdge;
|
||||
typedef CStencilShadowConnectivity::Edge Edge;
|
||||
typedef CStencilShadowConnectivity::EdgeFace EdgeFace;
|
||||
typedef CStencilShadowConnectivity::Face Face;
|
||||
|
||||
// map of single edges - edge with only one face attached
|
||||
typedef std::map<BasicEdge, EdgeFace> SingleEdgeMap;
|
||||
SingleEdgeMap m_mapSingleEdges; //!<
|
||||
|
||||
// array of double-edges - edges with both faces attached/found
|
||||
typedef std::vector<Edge> DoubleEdgeArray;
|
||||
DoubleEdgeArray m_vDoubleEdges; //!<
|
||||
|
||||
// triangles added (used to extract index to reference edge to faces, and keep the topology)
|
||||
typedef std::vector<Face> FaceArray;
|
||||
FaceArray m_vFaces; //!<
|
||||
DWORD m_dwNumUncompressedVertices; //!<
|
||||
|
||||
// helper to get order for Vec3d
|
||||
struct CVec3dOrder: public std::binary_function< Vec3d, Vec3d, bool>
|
||||
{
|
||||
bool operator() ( const Vec3d &a, const Vec3d &b ) const
|
||||
{
|
||||
// first sort by x
|
||||
if(a.x<b.x)return(true);
|
||||
if(a.x>b.x)return(false);
|
||||
|
||||
// then by y
|
||||
if(a.y<b.y)return(true);
|
||||
if(a.y>b.y)return(false);
|
||||
|
||||
// then by z
|
||||
if(a.z<b.z)return(true);
|
||||
if(a.z>b.z)return(false);
|
||||
|
||||
return(false);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<Vec3d,unsigned,CVec3dOrder> VertexWelderMap;
|
||||
VertexWelderMap m_mVertexWelder; //!< used for AddTriangleWelded
|
||||
|
||||
// this will try to find a close match to the given vertex, and
|
||||
// if found, return its index (the actual index of the vertex that's very close or
|
||||
// coincide with v in space). Otherwise, creates a new vertex reference in the map
|
||||
// and returns the index nNewVertex
|
||||
unsigned WeldVertex (const Vec3d& v, unsigned nNewVertex);
|
||||
|
||||
//float m_fWeldTolerance;
|
||||
// this is 1 + the max index of the vertex in the original mesh vertex array, that
|
||||
// is used by the currently being built connectivity
|
||||
//unsigned m_numOrigMeshVerticesUsed; // this is unneeded because connectivity calculates this itself
|
||||
protected:
|
||||
|
||||
// adds a new single edge, or finds an adjacent edge and puts the double-edge on record
|
||||
// add a new edge, if there is no complementary single edge;
|
||||
// otherwise, withdraw the edge from the list of single edges and add to double edges
|
||||
//! /param eEdge
|
||||
//! /param efFace
|
||||
void AddNewEdge (BasicEdge eEdge, EdgeFace efFace);
|
||||
};
|
||||
|
||||
// this is the builder of connectivity that can be used for static objects
|
||||
// (with non-changing face normals)
|
||||
class CStencilShadowStaticConnectivityBuilder :public CStencilShadowConnectivityBuilder
|
||||
{
|
||||
public:
|
||||
CStencilShadowStaticConnectivityBuilder();
|
||||
virtual ~CStencilShadowStaticConnectivityBuilder();
|
||||
void AddTriangleWelded( vindex nV0, vindex nV1, vindex nV2, const Vec3d &vV0, const Vec3d &vV1, const Vec3d &vV2 );
|
||||
//! return to the state right after construction
|
||||
virtual void Reinit( void );
|
||||
|
||||
// reserves space for the given number of triangles that are to be added
|
||||
//! /param nNumTriangles 0..
|
||||
//! /param innNumVertices 0..
|
||||
virtual void ReserveForTriangles( unsigned nNumTriangles, unsigned innNumVertices );
|
||||
|
||||
// constructs/compiles the optimum representation of the connectivity
|
||||
// to be used in run-time
|
||||
// WARNING: use Release method to dispose the connectivity object
|
||||
//! /param inpVertexBuf vertex position buffer to check for solvable open edges (2 vertices with same position)
|
||||
//! /return interface pointer, could be 0
|
||||
virtual class IStencilShadowConnectivity *ConstructConnectivity( void );
|
||||
protected:
|
||||
// WARNING: This is only to be called when the whole construction process
|
||||
// is finished, to modify already created connectivity
|
||||
// Goes through all vertices used by the connectivity and constructs a continuous
|
||||
// array out of them; reindexes the vertices in the connectivity object
|
||||
// to use these vertices; puts the new vertex array into the connectivity object
|
||||
void SetVertices (CStencilShadowConnectivity * pConnectivity);
|
||||
|
||||
typedef CStencilShadowConnectivity::Plane Plane;
|
||||
std::vector<Plane> m_vPlanes;
|
||||
};
|
||||
|
||||
#endif // _STENCIL_SHADOW_CONNECTIVITY_BUILDER_HDR_
|
||||
612
ResourceCompilerPC/TangentSpaceCalculation.h
Normal file
612
ResourceCompilerPC/TangentSpaceCalculation.h
Normal file
@@ -0,0 +1,612 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek SuperFramework Source code
|
||||
//
|
||||
// (c) by Crytek GmbH 2003. All rights reserved.
|
||||
// Used with permission to distribute for non-commercial purposes.
|
||||
//
|
||||
//
|
||||
// File:TangentSpaceCalculation.h
|
||||
// Description: calculated the tangent space base vector for a given mesh
|
||||
// Dependencies: none
|
||||
// Documentation: "How to calculate tangent base vectors.doc"
|
||||
//
|
||||
// Usage:
|
||||
// implement the proxy class: CTriangleInputProxy
|
||||
// instance the proxy class: CTriangleInputProxy MyProxy(MyData);
|
||||
// instance the calculation helper: CTangentSpaceCalculation<MyProxy> MyTangent;
|
||||
// do the calculation: MyTangent.CalculateTangentSpace(MyProxy);
|
||||
// get the data back: MyTangent.GetTriangleIndices(), MyTangent.GetBase()
|
||||
//
|
||||
// History:
|
||||
// - 12/07/2002: Created by Martin Mittring as part of CryEngine
|
||||
// - 08/18/2003: MM improved stability (no illegal floats) with bad input data
|
||||
// - 08/19/2003: MM added check for input data problems (DebugMesh() is deactivated by default)
|
||||
// - 10/02/2003: MM removed rundundant code
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector> // STL vector<>
|
||||
#include <map> // STL map<,,> multimap<>
|
||||
|
||||
#define BASEMATRIXMERGEBIAS 0.9f
|
||||
|
||||
/* // use this as reference
|
||||
class CTriangleInputProxy
|
||||
{
|
||||
public:
|
||||
|
||||
//! /return 0..
|
||||
DWORD GetTriangleCount( void ) const;
|
||||
|
||||
//! /param indwTriNo 0..
|
||||
//! /param outdwPos
|
||||
//! /param outdwNorm
|
||||
//! /param outdwUV
|
||||
void GetTriangleIndices( const DWORD indwTriNo, DWORD outdwPos[3], DWORD outdwNorm[3], DWORD outdwUV[3] ) const;
|
||||
|
||||
//! /param indwPos 0..
|
||||
//! /param outfPos
|
||||
void GetPos( const DWORD indwPos, float outfPos[3] ) const;
|
||||
|
||||
//! /param indwPos 0..
|
||||
//! /param outfUV
|
||||
void GetUV( const DWORD indwPos, float outfUV[2] ) const;
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// InputProxy - use CTriangleInputProxy as reference
|
||||
template <class InputProxy>
|
||||
class CTangentSpaceCalculation
|
||||
{
|
||||
public:
|
||||
|
||||
// IN ------------------------------------------------
|
||||
|
||||
//! /param inInput - the normals are only used as smoothing input - we calculate the normals ourself
|
||||
void CalculateTangentSpace( const InputProxy &inInput );
|
||||
|
||||
// OUT -----------------------------------------------
|
||||
|
||||
//! /return the number of base vectors that are stored 0..
|
||||
size_t GetBaseCount( void );
|
||||
|
||||
//!
|
||||
//! /param indwTriNo 0..
|
||||
//! /param outdwBase
|
||||
void GetTriangleBaseIndices( const DWORD indwTriNo, DWORD outdwBase[3] );
|
||||
|
||||
//! returns a orthogonal base (perpendicular and normalized)
|
||||
//! /param indwPos 0..
|
||||
//! /param outU in object/worldspace
|
||||
//! /param outV in object/worldspace
|
||||
//! /param outN in object/worldspace
|
||||
void GetBase( const DWORD indwPos, float outU[3], float outV[3], float outN[3] );
|
||||
|
||||
private: // -----------------------------------------------------------------
|
||||
|
||||
class CVec2
|
||||
{
|
||||
public:
|
||||
float x,y;
|
||||
|
||||
CVec2(){}
|
||||
CVec2(float fXval, float fYval) { x=fXval; y=fYval; }
|
||||
friend CVec2 operator - (const CVec2 &vec1, const CVec2 &vec2) { return CVec2(vec1.x-vec2.x, vec1.y-vec2.y); }
|
||||
operator float * () { return((float *)this); }
|
||||
};
|
||||
|
||||
class CVec3
|
||||
{
|
||||
public:
|
||||
float x,y,z;
|
||||
|
||||
CVec3(){}
|
||||
CVec3(float fXval, float fYval, float fZval) { x=fXval; y=fYval; z=fZval; }
|
||||
friend CVec3 operator - (const CVec3 &vec1, const CVec3 &vec2) { return CVec3(vec1.x-vec2.x, vec1.y-vec2.y, vec1.z-vec2.z); }
|
||||
friend CVec3 operator - (const CVec3 &vec1) { return CVec3(-vec1.x, -vec1.y, -vec1.z); }
|
||||
friend CVec3 operator + (const CVec3 &vec1, const CVec3 &vec2) { return CVec3(vec1.x+vec2.x, vec1.y+vec2.y, vec1.z+vec2.z); }
|
||||
friend CVec3 operator * (const CVec3 &vec1, const float fVal) { return CVec3(vec1.x*fVal, vec1.y*fVal, vec1.z*fVal); }
|
||||
friend float operator * (const CVec3 &vec1, const CVec3 &vec2) { return( vec1.x*vec2.x + vec1.y*vec2.y + vec1.z*vec2.z); }
|
||||
operator float * () { return((float *)this); }
|
||||
void Negate() { x=-x;y=-y;z=-z; }
|
||||
friend CVec3 normalize( const CVec3 &vec ) { CVec3 ret; float fLen=length(vec); if(fLen<0.00001f)return(vec); fLen=1.0f/fLen;ret.x=vec.x*fLen;ret.y=vec.y*fLen;ret.z=vec.z*fLen;return(ret); }
|
||||
friend CVec3 cross( const CVec3 &vec1, const CVec3 &vec2 ) { return CVec3(vec1.y*vec2.z-vec1.z*vec2.y, vec1.z*vec2.x-vec1.x*vec2.z, vec1.x*vec2.y-vec1.y*vec2.x); }
|
||||
friend float length( const CVec3 &invA ) { return (float)sqrt(invA.x*invA.x+invA.y*invA.y+invA.z*invA.z); }
|
||||
friend float CalcAngleBetween( const CVec3 &invA, const CVec3 &invB )
|
||||
{
|
||||
float LengthQ=length(invA)*length(invB);
|
||||
|
||||
if(LengthQ<0.0001f)LengthQ=0.0001f; // to prevent division by zero
|
||||
|
||||
float f=(invA*invB)/LengthQ;
|
||||
|
||||
if(f>1.0f)f=1.0f; // acos need input in the range [-1..1]
|
||||
else if(f<-1.0f)f=-1.0f; //
|
||||
|
||||
float fRet=(float)acos(f); // cosf is not avaiable on every plattform
|
||||
|
||||
return(fRet);
|
||||
}
|
||||
friend bool IsZero( const CVec3 &invA ) { return(invA.x==0.0f && invA.y==0.0f && invA.z==0.0f); }
|
||||
friend bool IsNormalized( const CVec3 &invA ) { float f=length(invA);return(f>=0.95f && f<=1.05f); }
|
||||
};
|
||||
|
||||
class CBaseIndex
|
||||
{
|
||||
public:
|
||||
DWORD m_dwPosNo; //!< 0..
|
||||
DWORD m_dwNormNo; //!< 0..
|
||||
};
|
||||
|
||||
// helper to get order for CVertexLoadHelper
|
||||
struct CBaseIndexOrder: public std::binary_function< CBaseIndex, CBaseIndex, bool>
|
||||
{
|
||||
bool operator() ( const CBaseIndex &a, const CBaseIndex &b ) const
|
||||
{
|
||||
// first sort by position
|
||||
if(a.m_dwPosNo<b.m_dwPosNo)return(true);
|
||||
if(a.m_dwPosNo>b.m_dwPosNo)return(false);
|
||||
|
||||
// then by normal
|
||||
if(a.m_dwNormNo<b.m_dwNormNo)return(true);
|
||||
if(a.m_dwNormNo>b.m_dwNormNo)return(false);
|
||||
|
||||
return(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CBase33
|
||||
{
|
||||
public:
|
||||
|
||||
CBase33() { }
|
||||
CBase33(CVec3 Uval, CVec3 Vval, CVec3 Nval) { u=Uval; v=Vval; n=Nval; }
|
||||
|
||||
CVec3 u; //!<
|
||||
CVec3 v; //!<
|
||||
CVec3 n; //!< is part of the tangent base but can be used also as vertex normal
|
||||
};
|
||||
|
||||
class CTriBaseIndex
|
||||
{
|
||||
public:
|
||||
DWORD p[3]; //!< index in m_BaseVectors
|
||||
};
|
||||
|
||||
// output data -----------------------------------------------------------------------------------
|
||||
|
||||
std::vector<CTriBaseIndex> m_TriBaseAssigment; //!< [0..dwTriangleCount]
|
||||
std::vector<CBase33> m_BaseVectors; //!< [0..] generated output data
|
||||
|
||||
//! /param indwPosNo
|
||||
//! /param indwNormNo
|
||||
CBase33 &GetBase( std::multimap<CBaseIndex,DWORD,CBaseIndexOrder> &inMap, const DWORD indwPosNo, const DWORD indwNormNo );
|
||||
|
||||
private:
|
||||
//! creates, copies or returns a reference
|
||||
//! /param inMap
|
||||
//! /param indwPosNo
|
||||
//! /param indwNormNo
|
||||
//! /param inU weighted
|
||||
//! /param inV weighted
|
||||
//! /param inN normalized
|
||||
DWORD AddUV2Base( std::multimap<CBaseIndex,DWORD,CBaseIndexOrder> &inMap, const DWORD indwPosNo, const DWORD indwNormNo, const CVec3 &inU, const CVec3 &inV, const CVec3 &inNormN );
|
||||
|
||||
//! /param inMap
|
||||
//! /param indwPosNo
|
||||
//! /param indwNormNo
|
||||
//! /param inNormal weighted normal
|
||||
void AddNormal2Base( std::multimap<CBaseIndex,DWORD,CBaseIndexOrder> &inMap, const DWORD indwPosNo, const DWORD indwNormNo, const CVec3 &inNormal );
|
||||
|
||||
//! this code was heavly tested with external test app by SergiyM and MartinM
|
||||
//! rotates the input vector with the rotation to-from
|
||||
//! /param vFrom has to be normalized
|
||||
//! /param vTo has to be normalized
|
||||
//! /param vInput
|
||||
static CVec3 Rotate( const CVec3 &vFrom, const CVec3 &vTo, const CVec3 &vInput )
|
||||
{
|
||||
// no mesh is perfect
|
||||
// assert(IsNormalized(vFrom));
|
||||
// no mesh is perfect
|
||||
// assert(IsNormalized(vTo));
|
||||
|
||||
CVec3 vRotAxis=cross(vFrom,vTo); // rotation axis
|
||||
|
||||
float fSin=length(vRotAxis);
|
||||
float fCos=vFrom*vTo;
|
||||
|
||||
if(fSin<0.00001f) // no rotation
|
||||
return(vInput);
|
||||
|
||||
vRotAxis=vRotAxis*(1.0f/fSin); // normalize
|
||||
|
||||
CVec3 vFrom90deg=normalize(cross(vRotAxis,vFrom)); // perpendicular to vRotAxis and vFrom90deg
|
||||
|
||||
// Base is vFrom,vFrom90deg,vRotAxis
|
||||
|
||||
float fXInPlane=vFrom*vInput;
|
||||
float fYInPlane=vFrom90deg*vInput;
|
||||
|
||||
CVec3 a=vFrom*(fXInPlane*fCos-fYInPlane*fSin);
|
||||
CVec3 b=vFrom90deg*(fXInPlane*fSin+fYInPlane*fCos);
|
||||
CVec3 c=vRotAxis*(vRotAxis*vInput);
|
||||
|
||||
return( a + b + c );
|
||||
}
|
||||
|
||||
void DebugMesh( const InputProxy &inInput ) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <class InputProxy>
|
||||
void CTangentSpaceCalculation<InputProxy>::DebugMesh( const InputProxy &inInput ) const
|
||||
{
|
||||
DWORD dwTriCount=inInput.GetTriangleCount();
|
||||
|
||||
// search for polygons that use the same indices (input data problems)
|
||||
for(DWORD a=0;a<dwTriCount;a++)
|
||||
{
|
||||
DWORD dwAPos[3],dwANorm[3],dwAUV[3];
|
||||
|
||||
inInput.GetTriangleIndices(a,dwAPos,dwANorm,dwAUV);
|
||||
|
||||
for(DWORD b=a+1;b<dwTriCount;b++)
|
||||
{
|
||||
DWORD dwBPos[3],dwBNorm[3],dwBUV[3];
|
||||
|
||||
inInput.GetTriangleIndices(b,dwBPos,dwBNorm,dwBUV);
|
||||
|
||||
assert(!( dwAPos[0]==dwBPos[0] && dwAPos[1]==dwBPos[1] && dwAPos[2]==dwBPos[2] ));
|
||||
assert(!( dwAPos[1]==dwBPos[0] && dwAPos[2]==dwBPos[1] && dwAPos[0]==dwBPos[2] ));
|
||||
assert(!( dwAPos[2]==dwBPos[0] && dwAPos[0]==dwBPos[1] && dwAPos[1]==dwBPos[2] ));
|
||||
|
||||
assert(!( dwAPos[1]==dwBPos[0] && dwAPos[0]==dwBPos[1] && dwAPos[2]==dwBPos[2] ));
|
||||
assert(!( dwAPos[2]==dwBPos[0] && dwAPos[1]==dwBPos[1] && dwAPos[0]==dwBPos[2] ));
|
||||
assert(!( dwAPos[0]==dwBPos[0] && dwAPos[2]==dwBPos[1] && dwAPos[1]==dwBPos[2] ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <class InputProxy>
|
||||
void CTangentSpaceCalculation<InputProxy>::CalculateTangentSpace( const InputProxy &inInput )
|
||||
{
|
||||
DWORD dwTriCount=inInput.GetTriangleCount();
|
||||
|
||||
// clear result
|
||||
m_BaseVectors.clear();
|
||||
m_TriBaseAssigment.clear();
|
||||
m_TriBaseAssigment.reserve(dwTriCount);
|
||||
assert(m_BaseVectors.size()==0);
|
||||
assert(m_TriBaseAssigment.size()==0);
|
||||
|
||||
std::multimap<CBaseIndex,DWORD,CBaseIndexOrder> mBaseMap; // second=index into m_BaseVectors, generated output data
|
||||
std::vector<CBase33> vTriangleBase; // base vectors per triangle
|
||||
|
||||
// DebugMesh(inInput); // only for debugging - slow
|
||||
|
||||
// calculate the base vectors per triangle -------------------------------------------
|
||||
{
|
||||
for(DWORD i=0;i<dwTriCount;i++)
|
||||
{
|
||||
// get data from caller ---------------------------
|
||||
DWORD dwPos[3],dwNorm[3],dwUV[3];
|
||||
|
||||
inInput.GetTriangleIndices(i,dwPos,dwNorm,dwUV);
|
||||
|
||||
CVec3 vPos[3];
|
||||
CVec2 vUV[3];
|
||||
|
||||
for(int e=0;e<3;e++)
|
||||
{
|
||||
inInput.GetPos(dwPos[e],vPos[e]);
|
||||
inInput.GetUV(dwUV[e],vUV[e]);
|
||||
}
|
||||
|
||||
// calculate tangent vectors ---------------------------
|
||||
|
||||
CVec3 vA=vPos[1]-vPos[0];
|
||||
CVec3 vB=vPos[2]-vPos[0];
|
||||
|
||||
/*
|
||||
char str[2024];
|
||||
|
||||
sprintf(str,"in: vA=(%.3f %.3f %.3f) vB=(%.3f %.3f %.3f)\n",vA.x,vA.y,vA.z,vA.x,vA.y,vA.z);
|
||||
OutputDebugString(str);
|
||||
*/
|
||||
|
||||
float fDeltaU1=vUV[1].x-vUV[0].x;
|
||||
float fDeltaU2=vUV[2].x-vUV[0].x;
|
||||
float fDeltaV1=vUV[1].y-vUV[0].y;
|
||||
float fDeltaV2=vUV[2].y-vUV[0].y;
|
||||
|
||||
float div =(fDeltaU1*fDeltaV2-fDeltaU2*fDeltaV1);
|
||||
|
||||
CVec3 vU,vV,vN=normalize(cross(vA,vB));
|
||||
|
||||
|
||||
if(div!=0.0)
|
||||
{
|
||||
// area(u1*v2-u2*v1)/2
|
||||
float fAreaMul2=fabsf(fDeltaU1*fDeltaV2-fDeltaU2*fDeltaV1); // weight the tangent vectors by the UV triangles area size (fix problems with base UV assignment)
|
||||
|
||||
float a = fDeltaV2/div;
|
||||
float b = -fDeltaV1/div;
|
||||
float c = -fDeltaU2/div;
|
||||
float d = fDeltaU1/div;
|
||||
|
||||
vU=normalize(vA*a+vB*b)*fAreaMul2;
|
||||
vV=normalize(vA*c+vB*d)*fAreaMul2;
|
||||
}
|
||||
else { vU=CVec3(0,0,0);vV=CVec3(0,0,0); }
|
||||
|
||||
vTriangleBase.push_back(CBase33(vU,vV,vN));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// distribute the normals to the vertices
|
||||
{
|
||||
// we create a new tangent base for every vertex index that has a different normal (later we split further for mirrored use)
|
||||
// and sum the base vectors (weighted by angle and mirrored if necessary)
|
||||
for(DWORD i=0;i<dwTriCount;i++)
|
||||
{
|
||||
DWORD e;
|
||||
|
||||
// get data from caller ---------------------------
|
||||
DWORD dwPos[3],dwNorm[3],dwUV[3];
|
||||
|
||||
inInput.GetTriangleIndices(i,dwPos,dwNorm,dwUV);
|
||||
CBase33 TriBase=vTriangleBase[i];
|
||||
CVec3 vPos[3];
|
||||
|
||||
for(e=0;e<3;e++) inInput.GetPos(dwPos[e],vPos[e]);
|
||||
|
||||
// for each triangle vertex
|
||||
for(e=0;e<3;e++)
|
||||
{
|
||||
float fWeight=CalcAngleBetween( vPos[(e+2)%3]-vPos[e],vPos[(e+1)%3]-vPos[e] ); // weight by angle to fix the L-Shape problem
|
||||
// float fWeight=length(cross( vPos[(e+2)%3]-vPos[e],vPos[(e+1)%3]-vPos[e] )); // weight by area, that does not fix the L-Shape problem 100%
|
||||
|
||||
if(fWeight<=0.0f)
|
||||
fWeight=0.0001f;
|
||||
|
||||
AddNormal2Base(mBaseMap,dwPos[e],dwNorm[e],TriBase.n*fWeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// distribute the uv vectors to the vertices
|
||||
{
|
||||
// we create a new tangent base for every vertex index that has a different normal
|
||||
// if the base vectors does'nt fit we split as well
|
||||
for(DWORD i=0;i<dwTriCount;i++)
|
||||
{
|
||||
DWORD e;
|
||||
|
||||
// get data from caller ---------------------------
|
||||
DWORD dwPos[3],dwNorm[3],dwUV[3];
|
||||
|
||||
CTriBaseIndex Indx;
|
||||
inInput.GetTriangleIndices(i,dwPos,dwNorm,dwUV);
|
||||
CBase33 TriBase=vTriangleBase[i];
|
||||
CVec3 vPos[3];
|
||||
|
||||
for(e=0;e<3;e++) inInput.GetPos(dwPos[e],vPos[e]);
|
||||
|
||||
// for each triangle vertex
|
||||
for(e=0;e<3;e++)
|
||||
{
|
||||
float fWeight=CalcAngleBetween( vPos[(e+2)%3]-vPos[e],vPos[(e+1)%3]-vPos[e] ); // weight by angle to fix the L-Shape problem
|
||||
// float fWeight=length(cross( vPos[(e+2)%3]-vPos[e],vPos[(e+1)%3]-vPos[e] )); // weight by area, that does not fix the L-Shape problem 100%
|
||||
|
||||
Indx.p[e]=AddUV2Base(mBaseMap,dwPos[e],dwNorm[e],TriBase.u*fWeight,TriBase.v*fWeight,normalize(TriBase.n));
|
||||
}
|
||||
|
||||
m_TriBaseAssigment.push_back(Indx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// orthogonalize the base vectors per vertex -------------------------------------------
|
||||
{
|
||||
std::vector<CBase33>::iterator it;
|
||||
|
||||
for(it=m_BaseVectors.begin();it!=m_BaseVectors.end();++it)
|
||||
{
|
||||
CBase33 &ref=(*it);
|
||||
|
||||
// rotate u and v in n plane
|
||||
{
|
||||
// (N is dominating, U and V equal weighted)
|
||||
CVec3 vUout,vVout,vNout;
|
||||
|
||||
vNout=normalize(ref.n);
|
||||
|
||||
vUout = ref.u - vNout * (vNout*ref.u); // project u in n plane
|
||||
vVout = ref.v - vNout * (vNout*ref.v); // project v in n plane
|
||||
|
||||
ref.u=normalize(vUout);ref.v=normalize(vVout);ref.n=vNout;
|
||||
|
||||
assert(ref.u.x>=-1 && ref.u.x<=1);
|
||||
assert(ref.u.y>=-1 && ref.u.y<=1);
|
||||
assert(ref.u.z>=-1 && ref.u.z<=1);
|
||||
assert(ref.v.x>=-1 && ref.v.x<=1);
|
||||
assert(ref.v.y>=-1 && ref.v.y<=1);
|
||||
assert(ref.v.z>=-1 && ref.v.z<=1);
|
||||
assert(ref.n.x>=-1 && ref.n.x<=1);
|
||||
assert(ref.n.y>=-1 && ref.n.y<=1);
|
||||
assert(ref.n.z>=-1 && ref.n.z<=1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class InputProxy>
|
||||
DWORD CTangentSpaceCalculation<InputProxy>::AddUV2Base( std::multimap<CBaseIndex,DWORD,CBaseIndexOrder> &inMap,
|
||||
const DWORD indwPosNo, const DWORD indwNormNo, const CVec3 &inU, const CVec3 &inV, const CVec3 &inNormN )
|
||||
{
|
||||
// no mesh is perfect
|
||||
// assert(IsNormalized(inNormN));
|
||||
|
||||
CBaseIndex Indx;
|
||||
|
||||
Indx.m_dwPosNo=indwPosNo;
|
||||
Indx.m_dwNormNo=indwNormNo;
|
||||
|
||||
std::multimap<CBaseIndex,DWORD,CBaseIndexOrder>::iterator iFind,iFindEnd;
|
||||
|
||||
iFind = inMap.lower_bound(Indx);
|
||||
|
||||
assert(iFind!=inMap.end());
|
||||
|
||||
CVec3 vNormal=m_BaseVectors[(*iFind).second].n;
|
||||
|
||||
iFindEnd = inMap.upper_bound(Indx);
|
||||
|
||||
DWORD dwBaseUVIndex=0xffffffff; // init with not found
|
||||
|
||||
bool bParity=(cross(inU,inV)*inNormN>0.0f);
|
||||
|
||||
for(;iFind!=iFindEnd;++iFind)
|
||||
{
|
||||
CBase33 &refFound=m_BaseVectors[(*iFind).second];
|
||||
|
||||
if(!IsZero(refFound.u))
|
||||
{
|
||||
bool bParityRef=(cross(refFound.u,refFound.v)*refFound.n>0.0f);
|
||||
bool bParityCheck=(bParityRef==bParity);
|
||||
|
||||
if(!bParityCheck)continue;
|
||||
|
||||
// bool bHalfAngleCheck=normalize(inU+inV) * normalize(refFound.u+refFound.v) > 0.0f;
|
||||
|
||||
|
||||
CVec3 vRotHalf=Rotate(normalize(refFound.n),inNormN,normalize(refFound.u+refFound.v));
|
||||
|
||||
bool bHalfAngleCheck=normalize(inU+inV) * vRotHalf > 0.0f;
|
||||
// // bool bHalfAngleCheck=normalize(normalize(inU)+normalize(inV)) * normalize(normalize(refFound.u)+normalize(refFound.v)) > 0.0f;
|
||||
|
||||
if(!bHalfAngleCheck)continue;
|
||||
}
|
||||
|
||||
dwBaseUVIndex=(*iFind).second;break;
|
||||
}
|
||||
|
||||
if(dwBaseUVIndex==0xffffffff) // not found
|
||||
{
|
||||
// otherwise create a new base
|
||||
|
||||
CBase33 Base( CVec3(0,0,0), CVec3(0,0,0), vNormal );
|
||||
|
||||
dwBaseUVIndex = m_BaseVectors.size();
|
||||
|
||||
inMap.insert( std::pair<CBaseIndex,DWORD>(Indx,dwBaseUVIndex) );
|
||||
m_BaseVectors.push_back(Base);
|
||||
}
|
||||
|
||||
CBase33 &refBaseUV=m_BaseVectors[dwBaseUVIndex];
|
||||
|
||||
refBaseUV.u=refBaseUV.u+inU;
|
||||
refBaseUV.v=refBaseUV.v+inV;
|
||||
|
||||
//no mesh is perfect
|
||||
if(inU.x!=0.0f || inU.y!=0.0f || inU.z!=0.0f)
|
||||
assert(refBaseUV.u.x!=0.0f || refBaseUV.u.y!=0.0f || refBaseUV.u.z!=0.0f);
|
||||
// no mesh is perfect
|
||||
if(inV.x!=0.0f || inV.y!=0.0f || inV.z!=0.0f)
|
||||
assert(refBaseUV.v.x!=0.0f || refBaseUV.v.y!=0.0f || refBaseUV.v.z!=0.0f);
|
||||
|
||||
return(dwBaseUVIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <class InputProxy>
|
||||
void CTangentSpaceCalculation<InputProxy>::AddNormal2Base( std::multimap<CBaseIndex,DWORD,CBaseIndexOrder> &inMap,
|
||||
const DWORD indwPosNo, const DWORD indwNormNo, const CVec3 &inNormal )
|
||||
{
|
||||
CBaseIndex Indx;
|
||||
|
||||
Indx.m_dwPosNo=indwPosNo;
|
||||
Indx.m_dwNormNo=indwNormNo;
|
||||
|
||||
std::multimap<CBaseIndex,DWORD,CBaseIndexOrder>::iterator iFind = inMap.find(Indx);
|
||||
|
||||
DWORD dwBaseNIndex;
|
||||
|
||||
if(iFind!=inMap.end()) // found
|
||||
{
|
||||
// resuse the existing one
|
||||
|
||||
dwBaseNIndex=(*iFind).second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise create a new base
|
||||
|
||||
CBase33 Base( CVec3(0,0,0), CVec3(0,0,0), CVec3(0,0,0) );
|
||||
|
||||
dwBaseNIndex=m_BaseVectors.size();
|
||||
inMap.insert( std::pair<CBaseIndex,DWORD>(Indx,dwBaseNIndex) );
|
||||
m_BaseVectors.push_back(Base);
|
||||
}
|
||||
|
||||
CBase33 &refBaseN=m_BaseVectors[dwBaseNIndex];
|
||||
|
||||
refBaseN.n=refBaseN.n+inNormal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class InputProxy>
|
||||
void CTangentSpaceCalculation<InputProxy>::GetBase( const DWORD indwPos, float outU[3], float outV[3], float outN[3] )
|
||||
{
|
||||
CBase33 &base=m_BaseVectors[indwPos];
|
||||
|
||||
outU[0]=base.u.x;
|
||||
outV[0]=base.v.x;
|
||||
outN[0]=base.n.x;
|
||||
outU[1]=base.u.y;
|
||||
outV[1]=base.v.y;
|
||||
outN[1]=base.n.y;
|
||||
outU[2]=base.u.z;
|
||||
outV[2]=base.v.z;
|
||||
outN[2]=base.n.z;
|
||||
}
|
||||
|
||||
|
||||
template <class InputProxy>
|
||||
void CTangentSpaceCalculation<InputProxy>::GetTriangleBaseIndices( const DWORD indwTriNo, DWORD outdwBase[3] )
|
||||
{
|
||||
assert(indwTriNo<m_TriBaseAssigment.size());
|
||||
CTriBaseIndex &indx=m_TriBaseAssigment[indwTriNo];
|
||||
|
||||
for(DWORD i=0;i<3;i++) outdwBase[i]=indx.p[i];
|
||||
}
|
||||
|
||||
|
||||
template <class InputProxy>
|
||||
size_t CTangentSpaceCalculation<InputProxy>::GetBaseCount( void )
|
||||
{
|
||||
return(m_BaseVectors.size());
|
||||
}
|
||||
8
ResourceCompilerPC/stdafx.cpp
Normal file
8
ResourceCompilerPC/stdafx.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// ResourceCompilerPC.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
58
ResourceCompilerPC/stdafx.h
Normal file
58
ResourceCompilerPC/stdafx.h
Normal file
@@ -0,0 +1,58 @@
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#define NOT_USE_CRY_MEMORY_MANAGER
|
||||
#include <platform.h>
|
||||
// Windows Header Files:
|
||||
#ifdef WIN64
|
||||
#include "PortableString.h"
|
||||
typedef CPortableString CString;
|
||||
#else
|
||||
#include <atlbase.h>
|
||||
#include <atlstr.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
|
||||
|
||||
#include <Cry_Math.h>
|
||||
#include <IRenderer.h>
|
||||
#include <LeafBuffer.h>
|
||||
#include <RendElement.h>
|
||||
#include <IShader.h>
|
||||
#include <VertexFormats.h>
|
||||
#include <CryHeaders.h>
|
||||
#include <TArrays.h>
|
||||
#include <primitives.h>
|
||||
#include <physinterface.h>
|
||||
#include <CrySizer.h>
|
||||
// TODO: reference additional headers your program requires here
|
||||
#ifndef SIZEOF_ARRAY
|
||||
#define SIZEOF_ARRAY(arr) (sizeof(arr)/sizeof((arr)[0]))
|
||||
|
||||
#include "ResourceCompilerPC.h"
|
||||
#include "float.h"
|
||||
#include "list2.h"
|
||||
|
||||
#ifndef WIN64
|
||||
#include "Dbghelp.h"
|
||||
#endif
|
||||
|
||||
#include "FileUtil.h"
|
||||
#include "PathUtil.h"
|
||||
#include "IRCLog.h"
|
||||
#include "CryChunkedFile.h"
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user