//////////////////////////////////////////////////////////////////////////// // // 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 #include "Cry_Geo.h" CSimpleLeafBuffer::CSimpleLeafBuffer(IRCLog * pLog, CIndexedMesh * pIndexedMesh, bool bStripifyAndShareVerts,bool bKeepRemapTable) { memset(this,0,sizeof(CSimpleLeafBuffer)); m_pIndices = new list2; m_pIndicesPreStrip = new list2; m_pLog = pLog; CreateLeafBuffer(pIndexedMesh,bStripifyAndShareVerts,bStripifyAndShareVerts,bKeepRemapTable); } CSimpleLeafBuffer::~CSimpleLeafBuffer() { for (int i=0; m_pMats && iCount(); 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 _hash_table[512]; bool bShareVertsArr[512]; m_pMats = new list2; 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; im_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 && tidm_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; nThrowError("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; i65535) 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 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; jnFirstIndexId+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; jnNumIndices+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; im_vBoxMin; m_vBoxMax = pTriData->m_vBoxMax; } void CSimpleLeafBuffer::CompactBuffer(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F * _vbuff, int * _vcount, list2 * 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 ShareNewInfo; list2 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 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; nnumIndices-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; iCount(); i++) { CMatInfo *mi = m_pMats->Get(i); CSimpleREOcLeaf * re = (CSimpleREOcLeaf *)mi->pRE; if (!re) continue; if (!re->m_Faces) re->m_Faces = new TArray; re->m_Faces->Free(); int nOffs = mi->nFirstIndexId; for(j=0; jnNumIndices-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; iCount(); i++) { CMatInfo *mi = m_pMats->Get(i); CSimpleREOcLeaf *re = (CSimpleREOcLeaf*)mi->pRE; if (!re) continue; if (!re->m_Faces) re->m_Faces = new TArray; re->m_Faces->Free(); int nOffs = mi->nFirstIndexId; for (j=0; jm_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; nnumIndices-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 * pHash, TArray& ShareNewInfo) { for(int i=0; iCount(); 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 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; mCount(); 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; im_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(nVertIdm_nAllocatedTangNum); pDuplTangData[nVertId].binormal = vBin; pDuplTangData[nVertId].tangent = vTan; pDuplTangData[nVertId].tnormal = vTnor; } } } else { for (int j=0; jm_dwNumSections; j++) { SPrimitiveGroup *g = &pMI->m_pPrimitiveGroups[j]; int offs = g->offsIndex+pMI->nFirstIndexId; for (uint n=0; nnumIndices; 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(nVertIdm_nAllocatedTangNum); pDuplTangData[nVertId].binormal = vBin; pDuplTangData[nVertId].tangent = vTan; pDuplTangData[nVertId].tnormal = vTnor; } } } } } bUsedVerts.Free(); }