This commit is contained in:
romkazvo
2023-08-07 19:29:24 +08:00
commit 34d6c5d489
4832 changed files with 1389451 additions and 0 deletions

View 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_)

View 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;

View 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

View 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--;
}
}

View 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

View 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);
}

View 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_)

View 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;
}

View 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_)

View 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;
}

View 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_)

File diff suppressed because it is too large Load Diff

View 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;
}

View 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_)

View 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;
}

View 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

View 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();
}

View File

@@ -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;
}

View 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);
}

View 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);
};

View File

@@ -0,0 +1,8 @@
#pragma once
class StatCGFShadowVolume
{
public:
StatCGFShadowVolume(void);
~StatCGFShadowVolume(void);
};

View 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

View 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;
}

View 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
}

View 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

View 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;
}