//////////////////////////////////////////////////////////////////////////////////////////////// // // Make vert buffers // //////////////////////////////////////////////////////////////////////////////////////////////// #include "RenderPCH.h" #include "MeshIdx.h" #include "float.h" #include "i3dengine.h" #include #include CLeafBuffer CLeafBuffer::m_Root("Root"); CLeafBuffer CLeafBuffer::m_RootGlobal("RootGlobal"); void CLeafBuffer::CopyTo(CLeafBuffer *pDst, bool bUseSysBuf) { list2& arrSrcMats = *(m_pMats); list2& arrNewMats = *(pDst->m_pMats = new list2); pDst->m_bMaterialsWasCreatedInRenderer = true; arrNewMats.resize (arrSrcMats.Size()); unsigned i; for (i = 0; i < arrSrcMats.size(); ++i) { CMatInfo& rSrcMat = arrSrcMats[i]; CMatInfo& rNewMat = arrNewMats[i]; rNewMat = rSrcMat; SShaderItem Sh = rNewMat.GetShaderItem(); if (Sh.m_pShader) Sh.m_pShader->AddRef(); if (Sh.m_pShaderResources) Sh.m_pShaderResources->AddRef(); rNewMat.m_pPrimitiveGroups = NULL; CREOcLeaf *re = rSrcMat.pRE; if (re) { rNewMat.pRE = (CREOcLeaf *)gRenDev->EF_CreateRE(eDATA_OcLeaf); CRendElement *pNext = rNewMat.pRE->m_NextGlobal; CRendElement *pPrev = rNewMat.pRE->m_PrevGlobal; *rNewMat.pRE = *re; rNewMat.pRE->m_NextGlobal = pNext; rNewMat.pRE->m_PrevGlobal = pPrev; rNewMat.pRE->m_LIndicies = NULL; rNewMat.pRE->m_Faces = NULL; rNewMat.pRE->m_pBuffer = pDst; } } pDst->m_Indices.Reset(); pDst->m_SecIndices.Copy(m_SecIndices); pDst->m_NumIndices = m_NumIndices; pDst->InvalidateVideoBuffer(-1); pDst->m_SecVertCount = m_SecVertCount; if (!bUseSysBuf) pDst->m_bOnlyVideoBuffer=true; else { pDst->AllocateSystemBuffer(m_SecVertCount); CVertexBuffer* pSecVertBuffer = pDst->m_pSecVertBuffer; void * pTmp = pSecVertBuffer->m_VS[VSF_GENERAL].m_VData; void * pTmpTangs = pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData; cryMemcpy(pSecVertBuffer, m_pSecVertBuffer, sizeof(*pSecVertBuffer)); pSecVertBuffer->m_VS[VSF_GENERAL].m_VData=pTmp; pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData=pTmpTangs; cryMemcpy(pSecVertBuffer->m_VS[VSF_GENERAL].m_VData, m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData, m_VertexSize[m_pSecVertBuffer->m_vertexformat]*m_SecVertCount); pDst->CalcFaceNormals(); } if (CRenderer::CV_r_precachemesh) { int nVertFormat = -1; int Flags = 0; for (int i=0; i<(*pDst->m_pMats).Count(); i++) { CMatInfo *mi = &(*pDst->m_pMats)[i]; if (!mi->pRE) continue; SShaderItem Sh = mi->GetShaderItem(); if (Sh.m_pShader) { IShader *pSH = Sh.m_pShader->GetTemplate(-1); int nShVertFormat = pSH->GetVertexFormat(); if (nVertFormat < 0) nVertFormat = nShVertFormat; else nVertFormat = gRenDev->m_RP.m_VFormatsMerge[nShVertFormat][nVertFormat]; if (pSH->GetFlags() & EF_NEEDTANGENTS) Flags |= SHPF_TANGENTS; } } if (nVertFormat >= 0) pDst->CheckUpdate(nVertFormat, Flags, false); } } void CLeafBuffer::AllocateSystemBuffer( int nVertCount ) { m_pSecVertBuffer = new CVertexBuffer; m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[nVertCount]; } bool CLeafBuffer::UpdateTangBuffer(SPipTangents *pBasis) { SAFE_DELETE_ARRAY(m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData); if (!pBasis) 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 { bool operator() ( const Vec3 &a, const Vec3 &b ) const { // first sort by x if(a.xb.x) return(false); // then by y if(a.yb.y) return(false); // then by z if(a.zb.z) return(false); return(false); } }; public: //! constructor //! /param inpMesh must not be 0 CMeshInputProxy(CIndexedMesh &inData) { m_pData = &inData; // remap the normals (weld them) DWORD dwFaceCount = GetTriangleCount(); m_NormIndx.reserve(dwFaceCount); std::map mapNormalsToNumber; DWORD dwmapSize=0; // for every triangle for(DWORD i=0;im_pFaces[i].n[e]; Vec3 &vNorm = m_pData->m_pNorms[iNorm]; std::map::iterator iFind = mapNormalsToNumber.find(vNorm); if(iFind == mapNormalsToNumber.end()) // not found { idx.p[e] = dwmapSize; mapNormalsToNumber[vNorm] = dwmapSize; dwmapSize++; } else idx.p[e] = (*iFind).second; } m_NormIndx.push_back(idx); } } //! /return 0.. DWORD GetTriangleCount( void ) const { return m_pData->m_nFaceCount; } //! /param indwTriNo 0.. //! /param outdwPos //! /param outdwNorm //! /param outdwUV void GetTriangleIndices( const DWORD indwTriNo, DWORD outdwPos[3], DWORD outdwNorm[3], DWORD outdwUV[3] ) const { const ushort *pIndsP = &m_pData->m_pFaces[indwTriNo].v[0]; const ushort *pIndsUV = &m_pData->m_pFaces[indwTriNo].t[0]; const CTriNormIndex &norm = m_NormIndx[indwTriNo]; for(int i=0; i<3; i++) { outdwPos[i] = pIndsP[i]; outdwUV[i] = pIndsUV[i]; outdwNorm[i] = norm.p[i]; } } //! /param indwPos 0.. //! /param outfPos void GetPos( const DWORD indwPos, float outfPos[3] ) const { assert(indwPos < m_pData->m_nVertCount); Vec3 &ref = m_pData->m_pVerts[indwPos]; outfPos[0] = ref.x; outfPos[1] = ref.y; outfPos[2] = ref.z; } //! /param indwPos 0.. //! /param outfUV void GetUV( const DWORD indwPos, float outfUV[2] ) const { assert(indwPos < m_pData->m_nCoorCount); if(indwPos < m_pData->m_nCoorCount) { TexCoord &ref = m_pData->m_pCoors[indwPos]; outfUV[0] = ref.s; outfUV[1] = ref.t; } else { outfUV[0] = 0; outfUV[1] = 0; } } private: class CTriNormIndex { public: DWORD p[3]; //!< index in m_BaseVectors }; std::vector m_NormIndx; //!< normal indices for each triangle CIndexedMesh *m_pData; //!< must not be 0 }; struct SBasisFace { ushort v[3]; }; ////////////////////////////////////////////////////////////////////////// // Creates the leaf buffer out of the given indexed mesh. // IMPLEMENTATION: // . Sort|Group faces by materials // . Create vertex buffer with sequence of (possibly non-unique) vertices, 3 verts per face // . Make Render ELements for each material // . For each (non-unique) vertex calculate the tangent base // . Index the mesh (Compact Vertices): detect and delete duplicate vertices // . Remove degenerated triangles in the generated mesh (GetIndices()) // . Sort vertices and indices for GPU cache void CLeafBuffer::CreateBuffer( CIndexedMesh * pTriData, bool bStripifyAndShareVerts, bool bRemoveNoDrawFaces, bool bKeepRemapTable) { int max_vert_num = pTriData->m_nFaceCount*3; //bStripifyAndShareVerts = true; int i; struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F * pVBuff = new struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F[max_vert_num]; SPipTangents *pTBuff = new SPipTangents[max_vert_num]; int buff_vert_count = 0; uint *uiInfo = new uint[max_vert_num]; m_nVertexFormat = VERTEX_FORMAT_P3F_N_COL4UB_TEX2F; 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. In this list, there will be a sorted // array of faces belonging to this shader list2 _vhash_table[512]; list2 _thash_table[512]; bool bShareVertsArr[512]; SPipTangents *pBasises = NULL; ushort *pBasisIndices = NULL; { // Generate tangent basis vectors before indexing per-material CMeshInputProxy Input(*pTriData); CTangentSpaceCalculation tangents; // calculate the base matrices tangents.CalculateTangentSpace(Input); DWORD dwCnt = tangents.GetBaseCount(); // for every triangle DWORD dwTris = Input.GetTriangleCount(); pBasises = new SPipTangents[dwCnt]; pBasisIndices = new ushort[dwTris*3]; for(DWORD dwTri=0; dwTrim_nFaceCount; i++) { CObjFace *pFace = &pTriData->m_pFaces[i]; IShader *ef = (m_pMats->GetAt(pFace->shader_id).shaderItem.m_pShader)->GetTemplate(-1); a++; if(ef->GetFlags3() & EF3_NODRAW) { b++; if(bRemoveNoDrawFaces) continue; } assert(pFace->shader_id>=0 && pFace->shader_id<512); if(pFace->shader_id>=m_pMats->Count()) { pFace->shader_id=0; iLog->Log("CLeafBuffer::CreateBuffer shader_id of face is out of range"); } SBasisFace fc; ushort *v = &pBasisIndices[i*3]; fc.v[0] = v[0]; fc.v[1] = v[1]; fc.v[2] = v[2]; _vhash_table[pFace->shader_id].Add(pFace); _thash_table[pFace->shader_id].Add(fc); } } // m_pDoubleSideLighting = new uchar[max_vert_num]; // . Create vertex buffer with sequence of (possibly non-unique) vertices, 3 verts per face // for each shader.. for (int t=0; tCount(); 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<_vhash_table[t].Count(); ++i) { CObjFace *pFace = _vhash_table[t][i]; SBasisFace *pTFace = &_thash_table[t][i]; assert(pFace->shader_id == t); for (int v=0; v<3; ++v) { pTBuff[buff_vert_count] = pBasises[pTFace->v[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] = pTriData->m_pColor[pFace->v[v]].a; } 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 assert(pTriData->m_pNorms); 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]]; // store shader id to prevent vertex sharing between materials during recompacting uiInfo[buff_vert_count] |= pFace->shader_id; // [Anton] keep index list to build mapping table later if (piVtxIdx) piVtxIdx[buff_vert_count] = pFace->v[v]; // store cull flag for UpdateCustomLighting() // removed to make it work as in resource compiler /* IShader * ef = (m_pMats->GetAt(pFace->shader_id).shaderItem.m_pShader)->GetTemplate(-1); bool bTwoSided = ef && (ef->GetCull() == e CULL_None); uiInfo[buff_vert_count] |= bTwoSided << 8; bShareVertsArr[pFace->shader_id] = ((ef->GetFlags3() & EF3_SHAREVERTS) != 0); if (!bShareVertsArr[pFace->shader_id])*/ bShareVertsArr[pFace->shader_id] = bStripifyAndShareVerts; 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; _vhash_table[t].Reset(); _thash_table[t].Reset(); } // make REs for (i=0; i<(*m_pMats).Count(); i++) { if((*m_pMats)[i].nNumIndices) { CREOcLeaf *re = (CREOcLeaf *)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 = re; // always enable sharing if there is 'flareproc' in shader/material name if (!bShareVertsArr[i] && (*m_pMats)[i].nNumIndices == 6) { IShader * ef = (*m_pMats)[i].shaderItem.m_pShader->GetTemplate(-1); char nameSh[128]; strncpy(nameSh, ef->GetTemplate(-1)->GetName(),sizeof(nameSh)); strlwr(nameSh); bShareVertsArr[i] = strstr(nameSh, "flareproc")!=0; } // IShader * ef = (*m_pMats)[i].shaderItem.m_pShader->GetTemplate(-1); // bool bTwoSided = ef && (ef->GetCull() == eCULL_None); bool bTwoSided = ((*m_pMats)[i].shaderItem.m_pShaderResources->m_ResFlags & MTLFLAG_2SIDED)!=0; re->m_SortId = i + 2*(!bTwoSided); // render double sided leafs last } } // Index the mesh (Compact Vertices): detect and delete duplicate vertices CompactBuffer(pVBuff, pTBuff, &buff_vert_count, &m_SecIndices, bShareVertsArr, uiInfo); SAFE_DELETE_ARRAY (uiInfo); SAFE_DELETE_ARRAY (pBasises); SAFE_DELETE_ARRAY (pBasisIndices); /*if (buff_vert_count == 12288) { FILE *fp = fopen("verts.fur", "r"); int nVerts = 0; while (true) { Vec3 pos, norm; float tc[2]; int n = fscanf(fp, "%f %f %f %f %f %f %f %f\n", &pos.x, &pos.y, &pos.z, &norm.x, &norm.y, &norm.z, &tc[0], &tc[1]); if (n != 8) break; pVBuff[nVerts].xyz = pos; pVBuff[nVerts].normal = norm; pVBuff[nVerts].st[0] = tc[0]; pVBuff[nVerts].st[1] = tc[1]; nVerts++; } fclose(fp); buff_vert_count = nVerts; fp = fopen("inds.fur", "r"); int nInds = 0; m_SecIndices.Free(); while (true) { int ind; int n = fscanf(fp, "%d\n", &ind); if (n != 1) break; m_SecIndices.AddElem(ind); nInds++; } fclose(fp); CMatInfo *mi = &(*m_pMats)[0]; mi->nFirstIndexId = 0; mi->nNumIndices = nInds; mi->nFirstVertId = 0; mi->nNumVerts = nVerts; }*/ for( i=0; iExit("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) iConsole->Exit("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 TArray NewIndexes; for (i=0; i<(*m_pMats).Count(); i++) // each material.. { CMatInfo *mi = &(*m_pMats)[i]; if (!mi->pRE) continue; int nFirstInd = NewIndexes.Num(); for (int j=mi->nFirstIndexId; jnFirstIndexId+mi->nNumIndices; j+=3) { // the face in material #i consists of vertices i0,i1,i2: int i0 = m_SecIndices[j+0]; int i1 = m_SecIndices[j+1]; int i2 = m_SecIndices[j+2]; assert (i0<65536 && i1<65536 && i2<65536); // 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.AddElem(i0); NewIndexes.AddElem(i1); NewIndexes.AddElem(i2); } } mi->nFirstIndexId = nFirstInd; mi->nNumIndices = NewIndexes.Num() - nFirstInd; if (!mi->nNumIndices) { mi->pRE->Release(); mi->pRE = NULL; } } m_SecIndices.Free(); m_SecIndices.Copy(NewIndexes); m_NumIndices = m_SecIndices.Num(); NewIndexes.Free(); } else m_NumIndices = m_SecIndices.Num(); InvalidateVideoBuffer(-1); // Lock the index buffer and get the pointer ushort *pInds = GetIndices(NULL); int nVertFormat = -1; int nFlags = 0; // . 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 > m_NumIndices) { assert(0); continue; } SShaderItem Sh = mi->GetShaderItem(); if (Sh.m_pShader) { IShader *pSH = Sh.m_pShader->GetTemplate(-1); int nShVertFormat = pSH->GetVertexFormat(); if (nVertFormat < 0) nVertFormat = nShVertFormat; else nVertFormat = gRenDev->m_RP.m_VFormatsMerge[nShVertFormat][nVertFormat]; if ((pSH->GetFlags() & EF_NEEDTANGENTS) && !(pSH->GetFlags3() & EF3_HASVCOLORS)) nFlags |= SHPF_TANGENTS; } 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 = pInds[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).GetLength(); mi->nFirstVertId = nMin; mi->nNumVerts = nMax-nMin+1; if (mi->nNumVerts <= 1000 && !m_bOnlyVideoBuffer) { mi->pRE->mfUpdateFlags(FCEF_MERGABLE); } } { m_fMinU = m_fMinV = 9999; m_fMaxU = m_fMaxV = -9999; for (int i=0; i m_fMaxU) m_fMaxU = pVBuff[i].st[0]; if (pVBuff[i].st[1] < m_fMinV) m_fMinV = pVBuff[i].st[1]; if (pVBuff[i].st[1] > m_fMaxV) m_fMaxV = pVBuff[i].st[1]; } } /*if (bStripifyAndShareVerts) { FILE *fp = fopen("vertanim.txt", "w"); for (i=0; i<(*m_pMats).Count(); i++) // each material.. { CMatInfo *mi = &(*m_pMats)[i]; if (!mi->pRE) continue; fprintf(fp, "\nMaterial: %s\n", mi->shaderItem.m_pShader->GetName()); for (int j=0; jnNumVerts; j++) { int ind = j+mi->nFirstVertId; struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *pV = &pVBuff[ind]; fprintf(fp, "%.3f, %.3f, %.3f (%.3f, %.3f, %.3f) (%.3f, %.3f)\n", pV->x, pV->y, pV->z, pV->nx, pV->ny, pV->nz, pV->s, pV->t); for (int n=j+1; nnNumVerts; n++) { int ind = n+mi->nFirstVertId; struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *pV1 = &pVBuff[ind]; if (*pV1 == *pV) { int nnn = 0; } } } } fclose(fp); }*/ // 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; m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData = new struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F[m_SecVertCount]; cryMemcpy(m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData, pVBuff, m_SecVertCount*sizeof(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F)); m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData = new SPipTangents[m_SecVertCount]; cryMemcpy(m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData, pTBuff, m_SecVertCount*sizeof(SPipTangents)); SAFE_DELETE_ARRAY (pVBuff); SAFE_DELETE_ARRAY (pTBuff); SAFE_DELETE(m_pIndicesPreStrip); m_pIndicesPreStrip = new list2; m_pIndicesPreStrip->AddList((ushort *)&m_SecIndices[0], m_SecIndices.Num()); // . Stripify the indices #if !defined(LINUX) #if !defined(_DEBUG) if (bStripifyAndShareVerts && !bKeepRemapTable) StripifyMesh(STRIPTYPE_ONLYLISTS); #endif #endif//LINUX CalcFaceNormals(); //CreateTangBuffer(); // 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= 0 && CRenderer::CV_r_precachemesh) CheckUpdate(nVertFormat, nFlags, false); m_vBoxMin = pTriData->m_vBoxMin; m_vBoxMax = pTriData->m_vBoxMax; } //================================================================ class CTriangleInputProxyLB { // helper to get order for CVertexLoadHelper struct NormalCompare: public std::binary_function { bool operator() ( const Vec3 &a, const Vec3 &b ) const { // first sort by x if(a.xb.x) return(false); // then by y if(a.yb.y) return(false); // then by z if(a.zb.z) return(false); return(false); } }; public: //! constructor //! /param inpMesh must not be 0 CTriangleInputProxyLB(CLeafBuffer &inData) { m_pLB = &inData; byte *pD = (byte *)inData.m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData; SBufInfoTable *pOffs = &gBufInfoTable[inData.m_pSecVertBuffer->m_vertexformat]; int Stride = m_VertexSize[inData.m_pSecVertBuffer->m_vertexformat]; // position stride // Get pointers to positions, TexCoords and Normals m_pInPos = (Vec3 *)pD; m_nStridePos = Stride; if (pOffs->OffsNormal) { m_pInN = (Vec3 *)&pD[pOffs->OffsNormal]; m_nStrideN = Stride; } else { m_pInN = inData.m_TempNormals; m_nStrideN = sizeof(Vec3); } if (pOffs->OffsTC) { m_pInUV = (Vec2 *)&pD[pOffs->OffsTC]; m_nStrideUV = Stride; } else { m_pInUV = (Vec2 *)inData.m_TempTexCoords; m_nStrideUV = sizeof(Vec2); } m_pInds = inData.GetIndices(&m_nInds); // remap the normals (weld them) DWORD dwFaceCount=GetTriangleCount(); m_NormIndx.reserve(dwFaceCount); std::map mapNormalsToNumber; DWORD dwmapSize=0; // for every triangle for(DWORD i=0;i::iterator iFind = mapNormalsToNumber.find(vNorm); if(iFind==mapNormalsToNumber.end()) // not found { idx.p[e] = dwmapSize; mapNormalsToNumber[vNorm] = dwmapSize; dwmapSize++; } else idx.p[e] = (*iFind).second; } m_NormIndx.push_back(idx); } } //! /return 0.. DWORD GetTriangleCount( void ) const { return m_nInds / 3; } //! /param indwTriNo 0.. //! /param outdwPos //! /param outdwNorm //! /param outdwUV void GetTriangleIndices( const DWORD indwTriNo, DWORD outdwPos[3], DWORD outdwNorm[3], DWORD outdwUV[3] ) const { ushort *pInds = &m_pInds[indwTriNo*3]; const CTriNormIndex &norm = m_NormIndx[indwTriNo]; for(int i=0;i<3;i++) { outdwPos[i] = pInds[i]; outdwUV[i] = pInds[i]; outdwNorm[i] = norm.p[i]; } } //! /param indwPos 0.. //! /param outfPos void GetPos( const DWORD indwPos, float outfPos[3] ) const { assert(indwPos < m_pLB->m_SecVertCount); byte *b = (byte *)m_pInPos+indwPos*m_nStridePos; Vec3 *ref = (Vec3 *)b; outfPos[0] = ref->x; outfPos[1] = ref->y; outfPos[2] = ref->z; } //! /param indwPos 0.. //! /param outfUV void GetUV( const DWORD indwPos, float outfUV[2] ) const { assert(indwPos < m_pLB->m_SecVertCount); byte *b = (byte *)m_pInUV+indwPos*m_nStrideUV; Vec2 *ref = (Vec2 *)b; outfUV[0] = ref->x; outfUV[1] = ref->y; } private: class CTriNormIndex { public: DWORD p[3]; //!< index in m_BaseVectors }; std::vector m_NormIndx; //!< normal indices for each triangle CLeafBuffer *m_pLB; //!< must not be 0 int m_nStrideN; int m_nStridePos; Vec3 *m_pInPos; int m_nStrideUV; int m_nInds; public: Vec3 *m_pInN; Vec2 *m_pInUV; ushort *m_pInds; }; bool CLeafBuffer::CreateTangBuffer() { return false; assert(m_pSecVertBuffer); if (!m_pSecVertBuffer) return false; assert(m_SecIndices.Num()); if (!m_SecIndices.Num()) return false; int i; struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *p = (struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F *)m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData; CTangentSpaceCalculation tangents; CTriangleInputProxyLB Input(*this); if (!Input.m_pInUV) return false; if (!Input.m_pInN) return false; if (!Input.m_pInds) return false; // calculate the base matrices tangents.CalculateTangentSpace(Input); DWORD dwCnt = tangents.GetBaseCount(); // for every triangle DWORD dwTris = Input.GetTriangleCount(); SPipTangents *pBasises = new SPipTangents[dwCnt]; ushort *pBasisIndices = new ushort[dwTris*3]; for(DWORD dwTri=0; dwTrim_VS[VSF_TANGENTS].m_VData); m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData = new SPipTangents[m_SecVertCount]; SPipTangents *tn = (SPipTangents *)m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData; for (i=0; inumVertices]; //memset (pVBuff, 0, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F)*pSource->numVertices); if (!m_pMats) { if (pSource->pMats) { m_pMats = pSource->pMats; pSource->pMats = NULL; } else { m_pMats = new list2; m_pMats->resize(pSource->numPrimGroups); memset (&(*m_pMats)[0], 0, pSource->numPrimGroups*sizeof(CMatInfo)); } } else assert (0); // this means we already have someone allocated the materials for us - not good! bool bBoxInited = false; for (unsigned t = 0; t < pSource->numPrimGroups; ++t) { const CCFMaterialGroup& pg = pSource->pPrimGroups[t]; assert (pg.nMaterial < pSource->numMaterials); CMatInfo& mi = (*m_pMats)[pg.nMaterial]; mi.nFirstIndexId = pg.nIndexBase; mi.nNumIndices = pg.numIndices; CREOcLeaf *re = (CREOcLeaf *)gRenDev->EF_CreateRE(eDATA_OcLeaf); re->m_pBuffer = this; re->m_pChunk = &mi; mi.pRE = re; // fast creation of placeholder for the normal/centroid info /* if (!re->m_Faces) re->m_Faces = new TArray; re->m_Faces->Free(); re->m_Faces->Alloc (pg.numIndices / 3); */ mi.m_Id = pg.nMaterial; if (pSource->pShaders) mi.shaderItem = pSource->pShaders[pg.nMaterial]; re->m_Flags |= pSource->nREFlags; // correct the material flags according to incoming correction arrays if (pSource->pOrFlags) mi.m_Flags |= pSource->pOrFlags[pg.nMaterial]; if (pSource->pAndFlags) mi.m_Flags &= pSource->pAndFlags[pg.nMaterial]; // calculate the vertex index and coordinate ranges for this material unsigned nIndexEnd = pg.nIndexBase+pg.numIndices; if (pg.numIndices) { Vec3d vMinVtx = pSource->pVertices[pSource->pIndices[pg.nIndexBase]]; Vec3d vMaxVtx = vMinVtx; if (!bBoxInited) { m_vBoxMin = vMinVtx; m_vBoxMax = vMaxVtx; bBoxInited = true; } else { m_vBoxMin.CheckMin(vMinVtx); m_vBoxMax.CheckMax(vMaxVtx); } unsigned short nMinVtx = pSource->pIndices[pg.nIndexBase]; unsigned short nMaxVtx = nMinVtx; for (unsigned nIndex = pg.nIndexBase+1; nIndex < nIndexEnd; ++nIndex) { unsigned short nVertex = pSource->pIndices[nIndex]; const Vec3d& vVertex = pSource->pVertices[nVertex]; vMinVtx.CheckMin(vVertex); vMaxVtx.CheckMax(vVertex); nMinVtx = min (nMinVtx, nVertex); nMaxVtx = max (nMaxVtx, nVertex); } mi.m_vCenter = (vMinVtx+vMaxVtx) * 0.5f; mi.m_fRadius = (vMinVtx - mi.m_vCenter).GetLength(); mi.nFirstVertId = nMinVtx; mi.nNumVerts = nMaxVtx-nMinVtx+1; } else { mi.m_vCenter = Vec3d(0,0,0); mi.m_fRadius = 0; mi.nFirstVertId = 0; mi.nNumVerts = 0; } } UpdateSysIndices(pSource->pIndices, pSource->numIndices); m_SecVertCount = pSource->numVertices; // TODO: get rid of the following /* m_pSecVertBuffer = new CVertexBuffer; m_pSecVertBuffer->m_vertexformat = VERTEX_FORMAT_P3F_COL4UB_TEX2F; struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F* pVBuf = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[m_SecVertCount]; m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData = pVBuf; for (unsigned i = 0; i < m_SecVertCount; ++i) { *(Vec3d*)(&pVBuf[i].x) = pSource->pVertices[i]; *(CryUV*)(&pVBuf[i].s) = pSource->pUVs[i]; } CalcFaceNormals(); CreateTangBuffer(); */ return false; } #include "NvTriStrip/NVTriStrip.h" void CLeafBuffer::StripifyMesh(int StripType) { int i; unsigned int n; //iLog->Log("Stripify mesh..."); //////////////////////////////////////////////////////////////////////////////////////// // Stripping stuff if (StripType == STRIPTYPE_DEFAULT) StripType = CRenderer::CV_r_stripmesh; if (StripType == STRIPTYPE_NONE) return; CryLogComment(" Sorting vertices for GPU cache ... "); int nGPU = gRenDev->GetFeatures() & RFT_HW_MASK; if (nGPU == RFT_HW_GF3 || nGPU == RFT_HW_GFFX || nGPU == RFT_HW_NV4X) 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]; m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData = pVBNew; SPipTangents *pTBOld = (SPipTangents *)m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData; SPipTangents *pTBNew = new SPipTangents [m_SecVertCount]; m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData = pTBNew; // 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(NULL)[mi->nFirstIndexId], mi->nNumIndices, &pOldPG, (unsigned short*)&mi->m_dwNumSections); //remap! PrimitiveGroup *pg; if ((int)mi->m_dwNumSections < 0) iLog->Log("\001CLeafBuffer::CreateBuffer m_dwNumSections out of range (%d), crash is very likely", mi->m_dwNumSections); 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)); memcpy(&pTBNew[newVertex], &pTBOld[oldVertex], sizeof(SPipTangents)); // 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; UpdateSysIndices(NewIndexes.GetElements(), NewIndexes.Count()); SAFE_DELETE_ARRAY(pVBOld); SAFE_DELETE_ARRAY(pTBOld); //iLog->LogPlus("Ok"); } void CLeafBuffer::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; ushort *pInds = GetIndices(NULL); if (m_nPrimetiveType != R_PRIMV_MULTI_GROUPS) { for (i=0; iCount(); i++) { CMatInfo *mi = m_pMats->Get(i); CREOcLeaf *re = 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 = &pInds[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 { unsigned int n; for (i=0; iCount(); i++) { CMatInfo *mi = m_pMats->Get(i); CREOcLeaf *re = 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 = pInds[offs+n]; i1 = pInds[offs+n+1]; i2 = pInds[offs+n+2]; break; case PT_STRIP: i0 = pInds[offs+n]; i1 = pInds[offs+n+1]; i2 = pInds[offs+n+2]; break; case PT_FAN: i0 = pInds[offs+0]; i1 = pInds[offs+n+1]; i2 = pInds[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); } } } } } void CLeafBuffer::SaveColors(byte *pD, SBufInfoTable *pOffs, int Size) { if (!pOffs->OffsColor) return; if (!m_TempColors) { m_TempColors = new UCol[m_SecVertCount]; for (int i=0; iOffsColor]; } } } void CLeafBuffer::SaveSecColors(byte *pD, SBufInfoTable *pOffs, int Size) { if (!pOffs->OffsSecColor) return; if (!m_TempSecColors) { m_TempSecColors = new UCol[m_SecVertCount]; for (int i=0; iOffsSecColor]; } } } void CLeafBuffer::SaveTexCoords(byte *pD, SBufInfoTable *pOffs, int Size) { if (!pOffs->OffsTC) return; if (!m_TempTexCoords) { m_TempTexCoords = new SMRendTexVert[m_SecVertCount]; for (int i=0; iOffsTC]; m_TempTexCoords[i].vert[1] = *(float *)&pD[pOffs->OffsTC+4]; } } } void CLeafBuffer::SaveNormals(byte *pD, SBufInfoTable *pOffs, int Size) { if (!pOffs->OffsNormal) return; if (!m_TempNormals) { m_TempNormals = new Vec3d[m_SecVertCount]; for (int i=0; iOffsNormal]; m_TempNormals[i].y = *(float *)&pD[pOffs->OffsNormal+4]; m_TempNormals[i].z = *(float *)&pD[pOffs->OffsNormal+8]; } } } bool CLeafBuffer::ReCreateSystemBuffer(int VertFormat) { SBufInfoTable *pOffsOld, *pOffsNew; byte *pOld = (byte *)m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData; int nFormatOld = m_pSecVertBuffer->m_vertexformat; pOffsOld = &gBufInfoTable[nFormatOld]; int SizeOld = m_VertexSize[nFormatOld]; byte *pNew = NULL; m_pSecVertBuffer->m_vertexformat = VertFormat; pOffsNew = &gBufInfoTable[VertFormat]; int SizeNew = m_VertexSize[VertFormat]; bool bRes = true; if (pOld) { byte *p = (byte *)CreateVertexBuffer(VertFormat, m_SecVertCount); pNew = (byte *)p; byte *pS = pOld; byte *pD = pNew; for (int i=0; iOffsColor) { // Restore colors pD = &pNew[pOffsNew->OffsColor]; if (pOffsOld->OffsColor) { pS = &pOld[pOffsOld->OffsColor]; for (int i=0; im_RP.m_pShader) iLog->Log("Warning: we lost colors for shader '%s'\n", gRenDev->m_RP.m_pShader->m_Name.c_str()); bRes = false; } } else SaveColors(pOld, pOffsOld, SizeOld); if (pOffsNew->OffsSecColor) { // Restore colors pD = &pNew[pOffsNew->OffsSecColor]; if (pOffsOld->OffsSecColor) { pS = &pOld[pOffsOld->OffsSecColor]; for (int i=0; im_RP.m_pShader) iLog->Log("Warning: we lost secondary colors for shader '%s'\n", gRenDev->m_RP.m_pShader->m_Name.c_str()); bRes = false; } } else SaveSecColors(pOld, pOffsOld, SizeOld); if (pOffsNew->OffsTC) { // Restore colors pD = &pNew[pOffsNew->OffsTC]; if (pOffsOld->OffsTC) { pS = &pOld[pOffsOld->OffsTC]; for (int i=0; im_RP.m_pShader) iLog->Log("Warning: we lost texture coords for shader '%s'\n", gRenDev->m_RP.m_pShader->m_Name.c_str()); bRes = false; } } else SaveTexCoords(pOld, pOffsOld, SizeOld); if (pOffsNew->OffsNormal) { // Restore colors pD = &pNew[pOffsNew->OffsNormal]; if (pOffsOld->OffsNormal) { pS = &pOld[pOffsOld->OffsNormal]; for (int i=0; im_RP.m_pShader) iLog->Log("Warning: we lost normals for shader '%s'\n", gRenDev->m_RP.m_pShader->m_Name.c_str()); bRes = false; } } else SaveNormals(pOld, pOffsOld, SizeOld); } delete [] pOld; m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData = pNew; if (!pNew) return false; return bRes; } void CLeafBuffer::Unload() { Unlink(); if (gRenDev) { assert(!m_pVertexBuffer || m_pVertexBuffer->m_NumVerts == m_SecVertCount); if (m_pVertexBuffer) gRenDev->ReleaseBuffer(m_pVertexBuffer); gRenDev->ReleaseIndexBuffer(&m_Indices); } m_pVertexBuffer = NULL; } void CLeafBuffer::UpdateDynBufPtr(int VertFormat) { if (m_pVertexBuffer && !m_pVertexBuffer->m_bFenceSet) { gRenDev->ReleaseBuffer(m_pVertexBuffer); m_pVertexBuffer = NULL; } if (!m_pVertexBuffer) m_pVertexBuffer = new CVertexBuffer; if (m_pVertexBuffer) { void *vBufTangs, *vBufGen; int nOffsTangs, nOffsGen; vBufGen = gRenDev->GetDynVBPtr(m_SecVertCount, nOffsGen, 1); vBufTangs = gRenDev->GetDynVBPtr(m_SecVertCount, nOffsTangs, 2); assert (vBufTangs && vBufGen && nOffsTangs == nOffsGen); m_pVertexBuffer->m_fence = nOffsTangs; m_pVertexBuffer->m_bFenceSet = true; m_pVertexBuffer->m_VS[VSF_GENERAL].m_VData = vBufGen; m_pVertexBuffer->m_VS[VSF_TANGENTS].m_VData = vBufTangs; m_pVertexBuffer->m_NumVerts = m_SecVertCount; m_pVertexBuffer->m_VS[VSF_GENERAL].m_nItems = m_SecVertCount; m_pVertexBuffer->m_VS[VSF_TANGENTS].m_nItems = m_SecVertCount; m_pVertexBuffer->m_VS[VSF_GENERAL].m_bLocked = true; m_pVertexBuffer->m_VS[VSF_TANGENTS].m_bLocked = true; m_pVertexBuffer->m_vertexformat = VERTEX_FORMAT_P3F_TEX2F; Unlink(); } } struct SSortTri { int nTri; float fDist; }; static TArray sSortTris; static _inline int Compare(SSortTri &a, SSortTri &b) { float fDistA = a.fDist; float fDistB = b.fDist; if (fDistA+0.01f < fDistB) return 1; else if (fDistA > fDistB+0.01f) return -1; else return 0; } void CLeafBuffer::SortTris() { int i, n; CRenderer *rd = gRenDev; if (m_SortFrame == rd->m_RP.m_TransformFrame) return; m_SortFrame = rd->m_RP.m_TransformFrame; ushort *pInds = GetIndices(NULL); CCObject *pObj = rd->m_RP.m_pCurObject; Vec3d vCam = pObj->GetInvMatrix().TransformPointOLD(rd->m_RP.m_ViewOrg); ushort *pDst = NULL; int nPosPtr; byte *pPosPtr = GetPosPtr(nPosPtr); bool bGlobalTransp = false; if (rd->m_RP.m_pShaderResources && rd->m_RP.m_pShaderResources->m_Opacity != 1.0f) bGlobalTransp = true; for(i=0; iCount(); i++) { CMatInfo *pMI = m_pMats->Get(i); if (!pMI->pRE) continue; IShader *pSH = pMI->shaderItem.m_pShader->GetTemplate(-1); if (!bGlobalTransp) { if (!(pSH->GetFlags3() & EF3_HASALPHATEST)) { if (!pMI->shaderItem.IsTransparent()) continue; } } if (!m_Indices.m_bLocked) { rd->UpdateIndexBuffer(&m_Indices, NULL, 0, false); pDst = (ushort *)m_Indices.m_VData; } if (m_nPrimetiveType != R_PRIMV_MULTI_GROUPS) { int nStart = pMI->nFirstIndexId; int nEnd = nStart + pMI->nNumIndices; int nTris = pMI->nNumIndices/3; assert(nEnd <= m_NumIndices); sSortTris.SetUse(nStart); for(n=nStart; nUpdateIndexBuffer(&m_Indices, NULL, 0, true); } bool CLeafBuffer::CheckUpdate(int VertFormat, int Flags, bool bNeedAddNormals) { CLeafBuffer *lb = GetVertexContainer(); lb->Unlink(); lb->Link(&CLeafBuffer::m_Root); bool bWasReleased = false; if (lb->m_sSource) { /*if (!stricmp(lb->m_sSource, "WaterVolume")) { int nnn = 0; }*/ } /*if (Flags & FHF_FORANIM) { int RequestedVertFormat = VertFormat; if (lb->m_pVertexBuffer) RequestedVertFormat = gRenDev->m_RP.m_VFormatsMerge[lb->m_pVertexBuffer->m_vertexformat][RequestedVertFormat]; if (RequestedVertFormat == VERTEX_FORMAT_P3F_TEX2F && (Flags & FHF_TANGENTSUSED)) { lb->UpdateDynBufPtr(RequestedVertFormat); } else { int nnn = 0; } }*/ CRenderer *rd = gRenDev; if (bNeedAddNormals || !lb->m_pVertexBuffer || (lb->m_UpdateVBufferMask & 0x101) || lb->m_pVertexBuffer->m_vertexformat != VertFormat) { int RequestedVertFormat; RequestedVertFormat = VertFormat; if (bNeedAddNormals) { SVertBufComps Comps; GetVertBufComps(&Comps, RequestedVertFormat); RequestedVertFormat = VertFormatForComponents(Comps.m_bHasColors, Comps.m_bHasSecColors, true, Comps.m_bHasTC); } // Create the video buffer bool bCreate = true; if (lb->m_pVertexBuffer) { RequestedVertFormat = rd->m_RP.m_VFormatsMerge[lb->m_pVertexBuffer->m_vertexformat][RequestedVertFormat]; if (lb->m_pVertexBuffer->m_vertexformat == RequestedVertFormat) bCreate = false; else { rd->ReleaseBuffer(lb->m_pVertexBuffer); bWasReleased = true; lb->m_pVertexBuffer = 0; // M.M. test } } if (bCreate || (lb->m_UpdateVBufferMask & 0x101)) { lb->m_UpdateFrame = gRenDev->GetFrameID(); if (bCreate) lb->m_UpdateVBufferMask |= 1; if (lb->PrepareBufferCallback) { int nnn = 0; } if (!lb->m_pVertexBuffer) { PROFILE_FRAME(Mesh_CheckUpdateCreateGBuf); lb->CreateVidVertices(lb->m_SecVertCount, RequestedVertFormat); lb->m_nVertexFormat = RequestedVertFormat; } if (lb->PrepareBufferCallback) { PROFILE_FRAME(Mesh_CheckUpdateCallback); if (!lb->PrepareBufferCallback(lb, (Flags & SHPF_TANGENTS) != 0)) return false; bWasReleased = true; lb->m_UpdateVBufferMask &= ~0x100; } else if (!lb->m_bOnlyVideoBuffer) { assert(lb->m_pSecVertBuffer); if (lb->m_pSecVertBuffer->m_vertexformat != RequestedVertFormat) { PROFILE_FRAME(Mesh_CheckUpdateRecreateSystem); lb->ReCreateSystemBuffer(RequestedVertFormat); } } if (!lb->m_pVertexBuffer) return false; } if ((lb->m_UpdateVBufferMask & 1) && lb->m_pSecVertBuffer && lb->m_pVertexBuffer) { PROFILE_FRAME(Mesh_CheckUpdateUpdateGBuf); rd->UpdateBuffer(lb->m_pVertexBuffer, lb->m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData, lb->m_SecVertCount, true, 0); } lb->m_UpdateVBufferMask &= ~1; } // If we need Tangent Vectors for shader and Tangents stream doesn't exist create and fill it if ((Flags & SHPF_TANGENTS) && (!lb->m_pVertexBuffer->GetStream(VSF_TANGENTS, NULL) || (lb->m_UpdateVBufferMask & 2))) { lb->m_UpdateFrame = gRenDev->GetFrameID(); lb->m_UpdateVBufferMask |= 2; if (!lb->m_bOnlyVideoBuffer && lb->m_pSecVertBuffer) { if (!lb->m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData) { PROFILE_FRAME(Mesh_CheckUpdateCreateSysTang); lb->CreateTangBuffer(); } assert(lb->m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData); if (lb->m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData) { if (!lb->m_pVertexBuffer->GetStream(VSF_TANGENTS, NULL)) { PROFILE_FRAME(Mesh_CheckUpdateCreateTBuf); gRenDev->CreateBuffer(lb->m_SecVertCount*sizeof(SPipTangents), 0, lb->m_pVertexBuffer, VSF_TANGENTS, "LeafBuffer tangents"); } } } else if (!lb->m_pVertexBuffer->GetStream(VSF_TANGENTS, NULL)) { PROFILE_FRAME(Mesh_CheckUpdateCreateTBuf); gRenDev->CreateBuffer(lb->m_SecVertCount*sizeof(SPipTangents), 0, lb->m_pVertexBuffer, VSF_TANGENTS, "LeafBuffer tangents"); } if (!lb->m_pVertexBuffer->GetStream(VSF_TANGENTS, NULL)) return false; if ((lb->m_UpdateVBufferMask & 2) && lb->m_pSecVertBuffer && lb->m_pVertexBuffer) { PROFILE_FRAME(Mesh_CheckUpdateUpdateTBuf); gRenDev->UpdateBuffer(lb->m_pVertexBuffer, lb->m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData, lb->m_SecVertCount, true, 0, VSF_TANGENTS); } lb->m_UpdateVBufferMask &= ~2; } if (!m_Indices.m_VData || (m_UpdateVBufferMask & 0x100)) { PROFILE_FRAME(Mesh_CheckUpdateUpdateInds); UpdateVidIndices(&m_SecIndices[0], m_NumIndices); } if (rd->m_RP.m_ObjFlags & FOB_SORTPOLYS) SortTris(); //else //if (rd->m_RP.m_pShaderResources && rd->m_RP.m_pShaderResources->m_Opacity != 1.0f) // SortTris(); return bWasReleased; } int CLeafBuffer::GetAllocatedBytes(bool bVideoBuf) { if (bVideoBuf) { int size = 0; if (m_pVertexBuffer) { size += m_VertexSize[m_pVertexBuffer->m_vertexformat]; if (m_pVertexBuffer->m_VS[VSF_TANGENTS].m_VData) size += m_SecVertCount * sizeof(SPipTangents); } return size; } int size = sizeof(*this); if(m_pSecVertBuffer) size += m_VertexSize[m_pSecVertBuffer->m_vertexformat]*m_SecVertCount; return size; } void CLeafBuffer::ReleaseShaders() { if(!m_pMats) return; for(int i=0; iCount(); i++) { if(m_pMats->Get(i)->shaderItem.m_pShader) { m_pMats->Get(i)->shaderItem.m_pShader->Release(); m_pMats->Get(i)->shaderItem.m_pShader = NULL; } } } CLeafBuffer::~CLeafBuffer() { UnlinkGlobal(); if(m_bMaterialsWasCreatedInRenderer && m_pMats) { for(int i=0; iCount(); i++) { CMatInfo *mi = m_pMats->Get(i); if(mi->pMatEnt) { // pMatEnt can present only if file was loaded from co delete mi->pMatEnt; mi->pMatEnt=0; if(mi->m_dwNumSections) delete [] mi->m_pPrimitiveGroups; mi->m_pPrimitiveGroups = 0; } if (mi->shaderItem.m_pShader) mi->shaderItem.m_pShader->Release(); if (mi->shaderItem.m_pShaderResources) mi->shaderItem.m_pShaderResources->Release(); if(m_pMats->Get(i)->pRE) { m_pMats->Get(i)->pRE->Release(); } } delete m_pMats; m_pMats=0; } FreeSystemBuffer(); if(m_pLoadedColors) delete [] m_pLoadedColors; m_pLoadedColors=0; Unload(); DestroyIndices(); SAFE_DELETE(m_pIndicesPreStrip); delete [] m_arrVertStripMap; m_arrVertStripMap=0; } void CLeafBuffer::FreeSystemBuffer() { if (m_pSecVertBuffer) { #ifdef PS2 SAFE_DELETE_ARRAY((PipVertex*)m_pSecVertBuffer->m_VData); #else SAFE_DELETE_ARRAY(m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData); #endif SAFE_DELETE_ARRAY(m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData); SAFE_DELETE(m_pSecVertBuffer); } SAFE_DELETE_ARRAY(m_TempNormals); SAFE_DELETE_ARRAY(m_TempTexCoords); SAFE_DELETE_ARRAY(m_TempColors); SAFE_DELETE_ARRAY(m_TempSecColors); SAFE_DELETE_ARRAY(m_arrVtxMap); } unsigned short *CLeafBuffer::GetIndices(int * pIndicesCount) { if (pIndicesCount) *pIndicesCount = m_NumIndices; return &m_SecIndices[0]; } void CLeafBuffer::DestroyIndices() { if (gRenDev) gRenDev->ReleaseIndexBuffer(&m_Indices); m_SecIndices.Free(); } void CLeafBuffer::UpdateVidIndices(const ushort *pNewInds, int nInds) { gRenDev->UpdateIndexBuffer(&m_Indices, pNewInds, nInds, true); m_UpdateVBufferMask &= ~0x100; } void CLeafBuffer::UpdateSysIndices(const ushort *pNewInds, int nInds) { m_NumIndices = nInds; if (m_SecIndices.Num() != nInds) { m_SecIndices.Free(); m_SecIndices.Reserve(nInds); } cryMemcpy(&m_SecIndices[0], pNewInds, nInds*2); InvalidateVideoBuffer(0x100); } void CLeafBuffer::UpdateSysVertices(void * pNewVertices, int nNewVerticesCount) { if (!m_pSecVertBuffer) CreateSysVertices(nNewVerticesCount, m_nVertexFormat); gRenDev->UpdateBuffer(m_pSecVertBuffer,pNewVertices, nNewVerticesCount,true); if(m_pVertexBuffer) { if (m_pVertexBuffer->m_NumVerts != m_pSecVertBuffer->m_NumVerts) { gRenDev->ReleaseBuffer(m_pVertexBuffer); m_pVertexBuffer = NULL; } } InvalidateVideoBuffer(1); } void CLeafBuffer::UpdateVidVertices(void * pNewVertices, int nNewVerticesCount) { if (!m_pVertexBuffer) CreateVidVertices(nNewVerticesCount, m_nVertexFormat); else if (m_pVertexBuffer->m_NumVerts != nNewVerticesCount) { gRenDev->ReleaseBuffer(m_pVertexBuffer); m_pVertexBuffer = NULL; m_SecVertCount = nNewVerticesCount; CreateVidVertices(nNewVerticesCount, m_nVertexFormat); } gRenDev->UpdateBuffer(m_pVertexBuffer,pNewVertices, nNewVerticesCount,true); } void CLeafBuffer::CreateVidVertices(int nVerts, int VertFormat) { // assert(!m_Next && !m_Prev); Unlink(); assert(!m_pVertexBuffer); m_pVertexBuffer = gRenDev->CreateBuffer(nVerts, VertFormat, "LeafBuffer", m_bDynamic); if (!m_pVertexBuffer) return; assert(m_SecVertCount == m_pVertexBuffer->m_NumVerts); Link(&m_Root); } bool CLeafBuffer::CreateSysVertices(int nVerts, int VertFormat) { if (!m_pSecVertBuffer) m_pSecVertBuffer = new CVertexBuffer; else if (m_SecVertCount != nVerts) { SAFE_DELETE(m_pSecVertBuffer); m_pSecVertBuffer = new CVertexBuffer; } m_SecVertCount = nVerts; m_pSecVertBuffer->m_vertexformat = VertFormat; int Size = m_VertexSize[VertFormat]; m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData = new byte[m_SecVertCount*Size]; memset(m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData, 0, m_SecVertCount*Size); return true; } void * CLeafBuffer::GetSecVerticesPtr(int * pVerticesCount) { *pVerticesCount = m_pSecVertBuffer->m_NumVerts; // return m_pSecVertBuffer->m_data; return m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData; } // add new chunk void CLeafBuffer::SetChunk( IShader * pShader, int nFirstVertId, int nVertCount, int nFirstIndexId, int nIndexCount, int nMatID, bool bForceInitChunk ) { if(!nIndexCount || !nVertCount) return; CMatInfo * pMat = 0; if(nMatID < 0 || nMatID >= m_pMats->Count()) { // add new chunk CMatInfo matinfo; m_pMats->Add(matinfo); pMat = &m_pMats->Last(); if(m_pMats->Count()>1 && !bForceInitChunk) { pMat->shaderItem.m_pShader = 0; pMat->pRE = 0; } else { pMat->shaderItem.m_pShader = pShader;//gRenDev->EF_LoadShader((char*)szEfName, -1, eEF_World, 0); pMat->pRE = (CREOcLeaf*)gRenDev->EF_CreateRE(eDATA_OcLeaf); pMat->pRE->m_CustomTexBind[0] = m_nClientTextureBindID; } } else { // use present chunk pMat = m_pMats->Get(nMatID); } // update chunk if(pMat->pRE) { pMat->pRE->m_pChunk = pMat; pMat->pRE->m_pBuffer = this; pMat->shaderItem.m_pShader = pShader; } assert(!pMat->pRE ||pMat->pRE->m_pChunk->nFirstIndexId<60000); pMat->nFirstIndexId = nFirstIndexId; pMat->nNumIndices = max(nIndexCount,0); pMat->nFirstVertId = nFirstVertId; pMat->nNumVerts = max(nVertCount,0); /*#ifdef _DEBUG ushort *pInds = (ushort *)m_Indices.m_VData; if (pInds) { for(int i=pMat->nFirstIndexId; inFirstIndexId+pMat->nNumIndices; i++) { int id = pInds[i]; assert(id>=pMat->nFirstVertId && id<(pMat->nFirstVertId+pMat->nNumVerts)); } } #endif // _DEBUG*/ } // set effector for all chunks void CLeafBuffer::SetShader( IShader * pShader, int nCustomTID ) { if (m_pMats->Count()) { CMatInfo *mi = m_pMats->Get(0); if (mi->shaderItem.m_pShader == pShader && mi->pRE && mi->pRE->m_CustomTexBind[0] == nCustomTID) return; } for(int i=0; iCount(); i++) { CMatInfo *mi = m_pMats->Get(i); mi->shaderItem.m_pShader = pShader; if(mi->pRE) mi->pRE->m_CustomTexBind[0] = nCustomTID; } } void CLeafBuffer::SetRECustomData(float * pfCustomData, float fFogScale, float fAlpha) { for(int i=0; iCount(); i++) { if(m_pMats->Get(i)->pRE) { m_pMats->Get(i)->pRE->m_CustomData = pfCustomData; m_pMats->Get(i)->pRE->m_fFogScale = fFogScale; m_pMats->Get(i)->pRE->m_Color.a = fAlpha; } } } int CVertexBuffer::Size(int Flags, int nVerts) { int nSize = sizeof(*this); if (m_VS[VSF_GENERAL].m_VData) nSize += nVerts * m_VertexSize[m_vertexformat]; if (m_VS[VSF_TANGENTS].m_VData) nSize += nVerts * sizeof(SPipTangents); return nSize; } int CMatInfo::Size() { int nSize = sizeof(*this); if (m_pPrimitiveGroups) nSize += sizeof(SPrimitiveGroup)*m_dwNumSections; return nSize; } int CLeafBuffer::Size(int Flags) { int nSize; if (!Flags) { nSize = sizeof(*this); if (m_pSecVertBuffer) nSize += m_pSecVertBuffer->Size(Flags, m_SecVertCount); if (m_TempNormals) nSize += sizeof(Vec3d) * m_SecVertCount; if (m_TempTexCoords) nSize += sizeof(SMRendTexVert) * m_SecVertCount; if (m_TempColors) nSize += sizeof(UCol) * m_SecVertCount; if (m_TempSecColors) nSize += sizeof(UCol) * m_SecVertCount; if (m_SecIndices.Num()) nSize += m_SecIndices.GetMemoryUsage(); if (m_pIndicesPreStrip && m_pIndicesPreStrip->Count()) nSize += m_pIndicesPreStrip->GetMemoryUsage(); if (m_pMats) { for (int i=0; i<(int)m_pMats->capacity(); i++) { if (i < m_pMats->Count()) nSize += m_pMats->Get(i)->Size(); else nSize += sizeof(CMatInfo); } } if (m_pLoadedColors) nSize += sizeof(Vec3d) * m_SecVertCount; } if (Flags & 1) { nSize = 0; if (m_pSecVertBuffer) nSize += m_pSecVertBuffer->Size(0, m_SecVertCount); } if (Flags & 2) { nSize = 0; if (m_SecIndices.Num()) nSize += m_SecIndices.GetMemoryUsage(); } return nSize; } CLeafBuffer::CLeafBuffer(const char *szSource) { m_Indices.Reset(); m_pIndicesPreStrip = NULL; m_sSource = (char *)szSource; m_SecVertCount=0; m_pSecVertBuffer=NULL; m_pVertexBuffer=NULL; m_pMats = NULL; m_nPrimetiveType = R_PRIMV_TRIANGLES; m_TempTexCoords = NULL; m_TempColors = NULL; m_TempSecColors = NULL; m_TempNormals = NULL; m_nClientTextureBindID = 0; m_bMaterialsWasCreatedInRenderer = 0; m_bOnlyVideoBuffer = 0; m_bDynamic = 0; m_Next = NULL; m_Prev = NULL; m_NextGlobal = NULL; m_PrevGlobal = NULL; m_pVertexContainer = NULL; m_UpdateVBufferMask = -1; m_UpdateFrame = 0; if (!m_Root.m_Next) { m_Root.m_Next = &m_Root; m_Root.m_Prev = &m_Root; } if (!m_RootGlobal.m_NextGlobal) { m_RootGlobal.m_NextGlobal = &m_RootGlobal; m_RootGlobal.m_PrevGlobal = &m_RootGlobal; } m_vBoxMin = m_vBoxMax = Vec3d(0,0,0);//used for hw occlusion test m_pLoadedColors = 0; m_arrVertStripMap = 0; PrepareBufferCallback = NULL; if (this != &m_RootGlobal && this != &m_Root) LinkGlobal(&m_RootGlobal); m_arrVtxMap = 0; }