//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2002. // ------------------------------------------------------------------------- // File name: brush.cpp // Version: v1.00 // Created: 28/5/2001 by Vladimir Kajalin // Compilers: Visual Studio.NET // Description: // ------------------------------------------------------------------------- // History: // //////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include "StatObj.h" #include "objman.h" #include "visareas.h" #include "terrain_sector.h" #include "cbuffer.h" #include "3DEngine.h" #include "meshidx.h" #include "watervolumes.h" #include "LMCompStructures.h" #include "brush.h" ////////////////////////////////////////////////////////////////////////// // Brush Export structures. ////////////////////////////////////////////////////////////////////////// #define BRUSH_FILE_TYPE 1 #define BRUSH_FILE_VERSION 3 #define BRUSH_FILE_SIGNATURE "CRY" list2 CBrush::m_lstBrushTypes; list2 CBrush::m_lstSExportedBrushMaterials; #pragma pack(push,1) struct SExportedBrushHeader { char signature[3]; // File signature. int filetype; // File type. int version; // File version. }; struct SExportedBrushGeom { enum EFlags { SUPPORT_LIGHTMAP = 0x01, NO_PHYSICS = 0x02, }; int size; // Size of this sructure. char filename[128]; int flags; //! @see EFlags Vec3 m_minBBox; Vec3 m_maxBBox; }; struct SExportedBrush { int size; // Size of this sructure. int id; int geometry; int material; int flags; int mergeId; Matrix34 matrix; uchar ratioLod; uchar ratioViewDist; uchar reserved1; uchar reserved2; }; #pragma pack(pop) ////////////////////////////////////////////////////////////////////////// const char * CBrush::GetEntityClassName() const { return "Brush"; } const Vec3d & CBrush::GetPos(bool bWorldOnly) const { assert(bWorldOnly); return m_vPos; } const Vec3d & CBrush::GetAngles(int realA) const { assert(0); return m_vAngles; } float CBrush::GetScale() const { return 1.f; // assert(0); //return m_fScale; } const char *CBrush::GetName() const { return m_nObjectTypeID>=0 ? m_lstBrushTypes[m_nObjectTypeID]->GetFileName() : "StatObjNotSet"; } void CBrush::GetRenderBBox( Vec3d &mins,Vec3d &maxs ) { mins = m_vWSBoxMin; maxs = m_vWSBoxMax; } float CBrush::GetRenderRadius() const { return m_fWSRadius; } bool CBrush::HasChanged() { return false; } #ifdef WIN64 #pragma warning( push ) //AMD Port #pragma warning( disable : 4311 ) #endif bool CBrush::DrawEntity(const struct SRendParams & _EntDrawParams) { FUNCTION_PROFILER_FAST( GetSystem(),PROFILE_3DENGINE,m_bProfilerEnabled ); assert(m_nObjectTypeID>=0 && m_nObjectTypeIDe_brushes_onlymerged && !(m_dwRndFlags & ERF_MERGED_NEW)) return false; //Matrix44 mat; //mat.SetIdentity(); //IStatObj * pStatObj = GetEntityStatObj(0,&mat); //if (strcmp(pStatObj->GetFileName(), "")) // return false; // if(!m_pStatObj || !((CStatObj*)m_pStatObj)->m_bStreamable) // return false; // if(m_arrPhysGeomId[0]<0 && m_arrPhysGeomId[1]<0) // return false; // if(!strstr(m_pStatObj->GetFileName(),"SWR_MP_PumpB.cgf")) // return false; int nRecursionLevel = (int)GetRenderer()->EF_Query(EFQ_RecurseLevel) - 1; // some parameters will be modified SRendParams rParms = _EntDrawParams; int nLod; if (m_dwRndFlags & ERF_USELIGHTMAPS) nLod = 0; // disable since low lods has no lmaps calculated else // lod depends on distance and size nLod = max(0,(int)(rParms.fDistance*GetLodRatioNormilized()/(GetCVars()->e_obj_lod_ratio*GetRenderRadius()))); // enable lightmaps if alowed if(m_dwRndFlags&ERF_USELIGHTMAPS && HasLightmap(nLod) && GetCVars()->e_light_maps && _EntDrawParams.nShaderTemplate != EFT_INVLIGHT && // !(_EntDrawParams.dwFlags & RPF_LIGHTPASS) && !(_EntDrawParams.dwFObjFlags & FOB_FOGPASS)) { rParms.pLightMapInfo = GetLightmap(nLod); rParms.pLMTCBuffer = GetLightmapTexCoord(nLod); if(GetCVars()->e_light_maps_occlusion) if( m_arrOcclusionLightOwners[0] || m_arrOcclusionLightOwners[1] || m_arrOcclusionLightOwners[2] || m_arrOcclusionLightOwners[3]) { list2 * pSources = ((C3DEngine*)m_p3DEngine)->GetDynamicLightSources(); *(DWORD*)rParms.arrOcclusionLightIds = 0; for(int i=0; iCount(); i++) { CDLight * pDynLight = pSources->Get(i); if(pDynLight->m_Flags & DLF_SUN) { for(int k=0; m_arrOcclusionLightOwners[k] && k<4; k++) if((IEntityRender*)-1 == m_arrOcclusionLightOwners[k]) { assert(k>=0 && k<4); rParms.arrOcclusionLightIds[k] = pDynLight->m_Id+1; } } else { for(int k=0; m_arrOcclusionLightOwners[k] && k<4; k++) if(pDynLight->m_pOwner == m_arrOcclusionLightOwners[k]) { assert(k>=0 && k<4); rParms.arrOcclusionLightIds[k] = pDynLight->m_Id+1; } } } } } else { rParms.pLightMapInfo = 0; rParms.pLMTCBuffer = 0; } // remember last rendered frames if(nRecursionLevel>=0 && nRecursionLevel<=1) SetDrawFrame( GetFrameID(), nRecursionLevel ); if (m_nObjectTypeID<0 || !m_lstBrushTypes[m_nObjectTypeID]) return false; Matrix44 tmpMatrix = m_Matrix; if(rParms.dwFObjFlags & FOB_RENDER_INTO_SHADOWMAP) { // modify position tmpMatrix.SetTranslationOLD(rParms.vPos); rParms.pMatrix = &tmpMatrix; } else rParms.pMatrix = &m_Matrix; rParms.pMaterial = m_pMaterial; rParms.pCaller = this; // if(m_dwRndFlags & ERF_SELECTED) // rParms.dwFObjFlags |= FOB_SELECTED; // render if (!rParms.pShadowVolumeLightSource) m_lstBrushTypes[m_nObjectTypeID]->Render(rParms,Vec3(zero),nLod); else if(m_dwRndFlags&ERF_CASTSHADOWVOLUME) m_lstBrushTypes[m_nObjectTypeID]->RenderShadowVolumes(&rParms); /* if (GetCVars()->e_brush_bboxes && !rParms.bRenderShadowVolumes) { Vec3d mins,maxs; GetRenderBBox(mins,maxs); GetRenderer()->Draw3dBBox(mins,maxs); } */ return true; } #ifdef WIN64 #pragma warning( pop ) //AMD Port #endif bool CBrush::IsStatic() const { return true; } struct IStatObj * CBrush::GetEntityStatObj( unsigned int nSlot, Matrix44* pMatrix, bool bReturnOnlyVisible ) { if(nSlot != 0 || m_nObjectTypeID<0) return 0; if(pMatrix) *pMatrix = m_Matrix; return m_lstBrushTypes[m_nObjectTypeID]; } struct ICryCharInstance* CBrush::GetEntityCharacter( unsigned int nSlot, Matrix44* pMatrix ) { return 0; } void CBrush::SetMatrix( Matrix44* pMatrix ) { Get3DEngine()->UnRegisterEntity(this); if(pMatrix) { if(!IsMatrixValid(*pMatrix)) { Warning( 0,0,"Error: IEntityRender::SetMatrix: Invalid matrix passed from the editor - ignored, reset to identity: %s", GetName()); m_Matrix.SetIdentity(); } else m_Matrix = *pMatrix; m_vPos = m_Matrix.GetTranslationOLD(); CalcWholeBBox(); /* if ((m_vWSBoxMin-m_vPos).Length() > (m_vWSBoxMax-m_vPos).Length()) m_fWSRadius = (m_vWSBoxMin-m_vPos).Length(); else m_fWSRadius = (m_vWSBoxMax-m_vPos).Length();*/ m_fWSRadius = (m_vWSBoxMax-m_vWSBoxMin).Length()*0.5f; } if(!m_pEntityRenderState) m_pEntityRenderState = Get3DEngine()->MakeEntityRenderState(); Get3DEngine()->RegisterEntity(this); Physicalize( ); } void CBrush::CalcWholeBBox() { m_vWSBoxMin = SetMaxBB(); m_vWSBoxMax = SetMinBB(); m_fWSRadius = 0; { if (m_nObjectTypeID<0 || !m_lstBrushTypes[m_nObjectTypeID]) return; // get object space bbox Vec3d mins,maxs; mins = m_lstBrushTypes[m_nObjectTypeID]->GetBoxMin(); maxs = m_lstBrushTypes[m_nObjectTypeID]->GetBoxMax(); /* // transform all 8 vertices into world space Vec3d verts[8] = { m_Matrix.TransformPoint(Vec3d(mins.x,mins.y,mins.z)), m_Matrix.TransformPoint(Vec3d(mins.x,maxs.y,mins.z)), m_Matrix.TransformPoint(Vec3d(maxs.x,mins.y,mins.z)), m_Matrix.TransformPoint(Vec3d(maxs.x,maxs.y,mins.z)), m_Matrix.TransformPoint(Vec3d(mins.x,mins.y,maxs.z)), m_Matrix.TransformPoint(Vec3d(mins.x,maxs.y,maxs.z)), m_Matrix.TransformPoint(Vec3d(maxs.x,mins.y,maxs.z)), m_Matrix.TransformPoint(Vec3d(maxs.x,maxs.y,maxs.z)) }; // find new min/max values for(int i=0; i<8; i++) { m_vBoxMin.CheckMin(verts[i]); m_vBoxMax.CheckMax(verts[i]); } */ // Fast AABB transformation. Matrix44 &tm = m_Matrix; Vec3d m = tm.TransformPointOLD( mins ); Vec3d vx = Vec3d(tm[0][0],tm[0][1],tm[0][2])*(maxs.x-mins.x); Vec3d vy = Vec3d(tm[1][0],tm[1][1],tm[1][2])*(maxs.y-mins.y); Vec3d vz = Vec3d(tm[2][0],tm[2][1],tm[2][2])*(maxs.z-mins.z); mins = m; maxs = m; if (vx.x < 0) mins.x += vx.x; else maxs.x += vx.x; if (vx.y < 0) mins.y += vx.y; else maxs.y += vx.y; if (vx.z < 0) mins.z += vx.z; else maxs.z += vx.z; if (vy.x < 0) mins.x += vy.x; else maxs.x += vy.x; if (vy.y < 0) mins.y += vy.y; else maxs.y += vy.y; if (vy.z < 0) mins.z += vy.z; else maxs.z += vy.z; if (vz.x < 0) mins.x += vz.x; else maxs.x += vz.x; if (vz.y < 0) mins.y += vz.y; else maxs.y += vz.y; if (vz.z < 0) mins.z += vz.z; else maxs.z += vz.z; m_vWSBoxMin.CheckMin( mins ); m_vWSBoxMax.CheckMax( maxs ); } } CBrush::CBrush() { m_vPos=m_vAngles=m_vWSBoxMin=m_vWSBoxMax=Vec3d(0,0,0); m_fScale=m_fWSRadius=0; // m_pStatObj=0; m_dwRndFlags=0; m_Matrix.SetIdentity(); m_narrDrawFrames[0]=m_narrDrawFrames[1]=0; m_pEntityRenderState=0; m_pPhysEnt=0; m_Matrix.SetIdentity(); // m_pLMTCBuffer = NULL; m_pMaterial = 0; m_nEditorObjectId = 0; // m_arrPhysGeomId[0] = m_arrPhysGeomId[1] = -1; m_nObjectTypeID = -1; m_nMaterialId = -1; m_arrOcclusionLightOwners[0]=m_arrOcclusionLightOwners[1]=m_arrOcclusionLightOwners[2]=m_arrOcclusionLightOwners[3]=0; } void CBrush::DeleteLMTC() { for(int nLod=0; nLodGetIRenderer()->DeleteLeafBuffer(m_arrLMData[nLod].m_pLMTCBuffer); m_arrLMData[nLod].m_pLMTCBuffer = NULL; } } } CBrush::~CBrush() { Dephysicalize( ); // Get3DEngine()->UnRegisterEntity(this); Get3DEngine()->FreeEntityRenderState(this); //m_pLMData = NULL; /* if(GetRndFlags()&ERF_MERGED_NEW && m_nObjectTypeID>=0) { CStatObj * pBody = (CStatObj*)m_lstBrushTypes[m_nObjectTypeID]; assert(pBody->m_nUsers==1); delete pBody; m_lstBrushTypes[m_nObjectTypeID] = NULL; m_nObjectTypeID=-1; } */ DeleteLMTC(); } void CBrush::Physicalize(bool bInstant) { assert(m_nObjectTypeID>=0); CStatObj * pBody = (CStatObj*)m_lstBrushTypes[m_nObjectTypeID]; float fScaleX = m_Matrix.GetOrtX().len(); float fScaleY = m_Matrix.GetOrtY().len(); float fScaleZ = m_Matrix.GetOrtZ().len(); if( fabs(fScaleX - fScaleY)>0.01f || fabs(fScaleX - fScaleZ)>0.01f || !pBody->IsPhysicsExist() ) { // scip non uniform scaled object and object without physics Dephysicalize(); return; } if (!GetCVars()->e_on_demand_physics) bInstant = true; if (!bInstant) { pe_status_placeholder spc; if (m_pPhysEnt && m_pPhysEnt->GetStatus(&spc) && spc.pFullEntity) GetSystem()->GetIPhysicalWorld()->DestroyPhysicalEntity(spc.pFullEntity); pe_params_bbox pbb; pbb.BBox[0] = m_vWSBoxMin; pbb.BBox[1] = m_vWSBoxMax; pe_params_foreign_data pfd; pfd.pForeignData = this; pfd.iForeignData = 1; if (!m_pPhysEnt) m_pPhysEnt = GetSystem()->GetIPhysicalWorld()->CreatePhysicalPlaceholder(PE_STATIC,&pbb); else m_pPhysEnt->SetParams(&pbb); m_pPhysEnt->SetParams(&pfd); return; } // CStatObj * pBody = (CStatObj*)m_lstBrushTypes[m_nObjectTypeID]; pBody->CheckLoaded(); // if(!(pBody && (pBody->m_arrPhysGeomInfo[0] || pBody->m_arrPhysGeomInfo[1]))) // return; //Dephysicalize( ); // create new // pe_params_pos par_pos; if (!m_pPhysEnt) { m_pPhysEnt = GetSystem()->GetIPhysicalWorld()->CreatePhysicalEntity(PE_STATIC,NULL,this,1); if(!m_pPhysEnt) return; } else if (!bInstant) { // this is on-demand creation, so entity pointer is automatically put into the placeholder GetSystem()->GetIPhysicalWorld()->CreatePhysicalEntity(PE_STATIC,5.0f); } pe_action_remove_all_parts remove_all; m_pPhysEnt->Action(&remove_all); pe_geomparams params; if(pBody->m_arrPhysGeomInfo[0]) { // if(m_arrPhysGeomId[0]>=0) // m_pPhysEnt->RemoveGeometry(m_arrPhysGeomId[0]); /*m_arrPhysGeomId[0] =*/ m_pPhysEnt->AddGeometry(pBody->m_arrPhysGeomInfo[0], ¶ms); } // else // m_arrPhysGeomId[0] = -1; params.flags = geom_colltype_ray; if(pBody->m_arrPhysGeomInfo[1]) { // if(m_arrPhysGeomId[1]>=0) // m_pPhysEnt->RemoveGeometry(m_arrPhysGeomId[1]); /*m_arrPhysGeomId[1] =*/ m_pPhysEnt->AddGeometry(pBody->m_arrPhysGeomInfo[1], ¶ms); } // else // m_arrPhysGeomId[1] = -1; if(m_dwRndFlags & (ERF_HIDABLE|ERF_EXCLUDE_FROM_TRIANGULATION)) { pe_params_foreign_data foreignData; m_pPhysEnt->GetParams(&foreignData); if (m_dwRndFlags & ERF_HIDABLE) foreignData.iForeignFlags |= PFF_HIDABLE; //[PETAR] new flag to exclude from triangulation if (m_dwRndFlags & ERF_EXCLUDE_FROM_TRIANGULATION) foreignData.iForeignFlags |= PFF_EXCLUDE_FROM_STATIC; m_pPhysEnt->SetParams(&foreignData); } pe_params_flags par_flags; par_flags.flagsOR = pef_never_affect_triggers; m_pPhysEnt->SetParams(&par_flags); pe_params_pos par_pos; par_pos.pMtx4x4T = m_Matrix.GetData(); m_pPhysEnt->SetParams(&par_pos); } void CBrush::Dephysicalize( ) { // delete old physics if(m_pPhysEnt) GetSystem()->GetIPhysicalWorld()->DestroyPhysicalEntity(m_pPhysEnt); m_pPhysEnt=0; } void CBrush::Dematerialize( ) { if(m_pMaterial) m_pMaterial = 0; } int __cdecl CBrush__Cmp_MergeID(const void* v1, const void* v2) { CBrush ** pBr1 = (CBrush**)v1; CBrush ** pBr2 = (CBrush**)v2; // shader if(pBr1[0]->GetMergeId() > pBr2[0]->GetMergeId()) return 1; else if(pBr1[0]->GetMergeId() < pBr2[0]->GetMergeId()) return -1; return 0; } struct LMTexCoord { float s,t; }; int __cdecl CBrush__Cmp_MatChunks(const void* v1, const void* v2) { CMatInfo * pMat1 = (CMatInfo*)v1; CMatInfo * pMat2 = (CMatInfo*)v2; // shader if(pMat1->shaderItem.m_pShader->GetTemplate(-1) > pMat2->shaderItem.m_pShader->GetTemplate(-1)) return 1; else if(pMat1->shaderItem.m_pShader->GetTemplate(-1) < pMat2->shaderItem.m_pShader->GetTemplate(-1)) return -1; // shader resources if(pMat1->shaderItem.m_pShaderResources > pMat2->shaderItem.m_pShaderResources) return 1; else if(pMat1->shaderItem.m_pShaderResources < pMat2->shaderItem.m_pShaderResources) return -1; // lm tex id if(pMat1->m_Id > pMat2->m_Id) return 1; else if(pMat1->m_Id < pMat2->m_Id) return -1; return 0; } struct SBrushM { int Id; int nNumMats; }; struct SMatGroup { SShaderItem sh; int nLMId; int nNumVerts; TArray Owners; }; void CObjManager::MergeBrushes() { if (!GetCVars()->e_brushes_merging || !m_lstBrushContainer.Count()) return; int nEntityId=0; int nNextStartId=-1; list2 newBrushes; int nMergeId = -1; qsort(&m_lstBrushContainer[0], m_lstBrushContainer.Count(), sizeof(m_lstBrushContainer[0]), CBrush__Cmp_MergeID); list2 lstVerts; list2 lstLMTexCoords; list2 lstIndices; list2 lstChunks; list2 lstChunksMerged; list2 lstTangBasises; int i, j; int nNumGroups = 0; TArray *groupBrushes; for(i=0; iGetMergeId(); if (nMergeId <= 0) continue; //nMergeId = 1; //pBrush->SetMergeId(nMergeId); if (nMergeId > nNumGroups) nNumGroups = nMergeId; } if (!nNumGroups) return; nMergeId = -1; GetLog()->UpdateLoadingScreen("\003---Merge brushes ... "); FILE *fp = NULL; if (GetCVars()->e_brushes_merging_debug) { fp = fopen("Brushes.txt", "w"); int nLastMergedId = -1; for(i=0; iGetMergeId(); if (nMergeId <= 0) continue; if (nLastMergedId != nMergeId) { nLastMergedId = nMergeId; fprintf(fp, "\n"); } Matrix44 mat; mat.SetIdentity(); IStatObj * pStatObj = pBrush->GetEntityStatObj(0,&mat); if(!pStatObj) continue; int nLMTexId = pBrush->GetLightmap(0) ? pBrush->GetLightmap(0)->GetColorLerpTex() : 0; int nLMHDRTexId = pBrush->GetLightmap(0) ? pBrush->GetLightmap(0)->GetHDRColorLerpTex() : 0; CLeafBuffer * pLB = pStatObj->GetLeafBuffer(); fprintf(fp, "Brush: %d, MergeId: %d, LMId: %d, Mats: %d (%s)\n", i, nMergeId, nLMTexId, pLB->m_pMats->Count(), pStatObj->GetFileName()); } fclose(fp); fp = fopen("BrushesMerged.txt", "w"); } groupBrushes = new TArray[nNumGroups]; for(i=0; iGetMergeId(); if (nMergeId <= 0) continue; nMergeId--; if(pBrush->m_dwRndFlags & ERF_CASTSHADOWVOLUME || pBrush->m_dwRndFlags & ERF_CASTSHADOWMAPS) continue; Matrix44 mat; mat.SetIdentity(); int nLMTexId = pBrush->GetLightmap(0) ? pBrush->GetLightmap(0)->GetColorLerpTex() : 0; int nHDRLMTexId = pBrush->GetLightmap(0) ? pBrush->GetLightmap(0)->GetHDRColorLerpTex() : 0; IStatObj * pStatObj = pBrush->GetEntityStatObj(0,&mat); if(!pStatObj) continue; CLeafBuffer * pLB = pStatObj->GetLeafBuffer(); if(!pLB || !pLB->m_SecVertCount) continue; for(int m=0; mm_pMats->Count(); m++) { CMatInfo newMatInfo = *pLB->m_pMats->Get(m); if(GetCVars()->e_materials) { // Override default material CMatInfo * pCustMat = (CMatInfo *)pBrush->GetMaterial(); if (pCustMat) { int nMatId = newMatInfo.m_nCGFMaterialID; if(nMatId<0) continue; if (nMatId == 0) pCustMat = (CMatInfo*)pCustMat; else if (nMatId-1 < pCustMat->GetSubMtlCount()) pCustMat = (CMatInfo*)pCustMat->GetSubMtl(nMatId-1); newMatInfo.shaderItem = pCustMat->shaderItem; } } SMatGroup *mg; for (j=0; jGetTemplate(-1); if (shm == mg->sh.m_pShader && newMatInfo.shaderItem.m_pShaderResources == mg->sh.m_pShaderResources && nLMTexId == mg->nLMId) break; } if (j == groupBrushes[nMergeId].Num()) { mg = new SMatGroup; mg->sh.m_pShader = newMatInfo.shaderItem.m_pShader->GetTemplate(-1); mg->sh.m_pShaderResources = newMatInfo.shaderItem.m_pShaderResources; mg->nLMId = nLMTexId; mg->nNumVerts = 0; groupBrushes[nMergeId].AddElem(mg); } for (j=0; jOwners.Num(); j++) { if (mg->Owners[j].Id == i) break; } if (j == mg->Owners.Num()) { SBrushM bm; bm.Id = i; bm.nNumMats = pLB->m_pMats->Count(); mg->Owners.AddElem(bm); } mg->nNumVerts += newMatInfo.nNumVerts; } } TArray Enabled; TArray maxMergedMats; maxMergedMats.Reserve(m_lstBrushContainer.Count()); Enabled.Reserve(m_lstBrushContainer.Count()); for (i=0; iOwners.Num(); m++) { int nId = mg->Owners[m].Id; maxMergedMats[nId] = max(mg->Owners.Num(), maxMergedMats[nId]); } } } int nRejected = 0; int nRequested = 0; for(j=0; jm_dwRndFlags & ERF_CASTSHADOWVOLUME || pBrush->m_dwRndFlags & ERF_CASTSHADOWMAPS) continue; nMergeId = pBrush->GetMergeId(); if (nMergeId <= 0) continue; nRequested++; if (maxMergedMats[j] >= 3) Enabled[j] = true; else { nRejected++; Enabled[j] = false; } } while(nEntityId=0) { Vec3d vBoxMax(-10000,-10000,-10000); Vec3d vBoxMin( 10000, 10000, 10000); int nLMTexId=-1; int nHDRLMTexId=-1; int nLMDirTexId=-1; int nCurVertsNum=0; if(nNextStartId>=0) nEntityId = nNextStartId; nNextStartId=-1; int nMergeID = -1; lstVerts.Clear(); lstLMTexCoords.Clear(); lstIndices.Clear(); list2 lstIndicesSorted; lstIndicesSorted.Clear(); lstChunks.Clear(); lstChunksMerged.Clear(); lstTangBasises.Clear(); TArray brMerged; brMerged.Free(); int dwResRndFlags = ERF_RECVSHADOWMAPS; for( ;nEntityIdGetMergeId() <= 0) continue; if( pBrush->m_dwRndFlags & ERF_MERGED || pBrush->m_dwRndFlags & ERF_CASTSHADOWVOLUME || pBrush->m_dwRndFlags & ERF_CASTSHADOWMAPS) continue; if (!Enabled[nEntityId]) continue; if (nMergeID != pBrush->GetMergeId() && nCurVertsNum) break; nMergeID = pBrush->GetMergeId(); if(nLMTexId<0) { nLMTexId = pBrush->GetLightmap(0) ? pBrush->GetLightmap(0)->GetColorLerpTex() : 0; nHDRLMTexId = pBrush->GetLightmap(0) ? pBrush->GetLightmap(0)->GetHDRColorLerpTex() : 0; nLMDirTexId = pBrush->GetLightmap(0) ? pBrush->GetLightmap(0)->GetDomDirectionTex() : 0; } else { if(nLMTexId != (pBrush->GetLightmap(0) ? pBrush->GetLightmap(0)->GetColorLerpTex() : 0) || nHDRLMTexId != (pBrush->GetLightmap(0) ? pBrush->GetLightmap(0)->GetHDRColorLerpTex() : 0) || nLMDirTexId != (pBrush->GetLightmap(0) ? pBrush->GetLightmap(0)->GetDomDirectionTex() : 0)) { if(nNextStartId<0) nNextStartId = nEntityId; continue; } } Matrix44 mat; mat.SetIdentity(); IStatObj * pStatObj = pBrush->GetEntityStatObj(0,&mat); if(!pStatObj) continue; EERType eType = pBrush->GetEntityRenderType(); assert(eType == eERType_Brush); if (eType != eERType_Brush) continue; if(!CBrush::IsMatrixValid(mat)) continue; CLeafBuffer * pLMLB = pBrush->GetLightmapTexCoord(0); CLeafBuffer * pLB = pStatObj->GetLeafBuffer(); if(!pLB->m_SecVertCount) continue; if(nCurVertsNum + pLB->m_SecVertCount>65535) break; int nIndCount=0; pLB->GetIndices(&nIndCount); brMerged.AddElem(nEntityId); int nInitVertCout = lstVerts.Count(); for(int m=0; mm_pMats->Count(); m++) { CMatInfo newMatInfo = *pLB->m_pMats->Get(m); if(GetCVars()->e_materials) { // Override default material CMatInfo * pCustMat = (CMatInfo *)pBrush->GetMaterial(); if (pCustMat) { int nMatId = newMatInfo.m_nCGFMaterialID; if(nMatId<0) continue; if (nMatId == 0) pCustMat = (CMatInfo*)pCustMat; else if (nMatId-1 < pCustMat->GetSubMtlCount()) pCustMat = (CMatInfo*)pCustMat->GetSubMtl(nMatId-1); newMatInfo.shaderItem = pCustMat->shaderItem; } } // copy indices ushort *pSrcInds = pLB->GetIndices(0); for(int i=newMatInfo.nFirstIndexId; iGetPosPtr(nPosStride,0,true); int nTexStride=0; const byte * pTex = pLB->GetUVPtr(nTexStride,0,true); int nNormStride=0; const byte * pNorm = pLB->GetNormalPtr(nNormStride,0,true); // get tangent basis int nTangStride=0; const byte * pTang = pLB->GetTangentPtr(nTangStride,0,true); int nTnormStride=0; const byte * pTNorm = pLB->GetTNormalPtr(nTnormStride,0,true); int nBNormStride=0; const byte * pBNorm = pLB->GetBinormalPtr(nBNormStride,0,true); int nColorStride=0; const byte * pColor = pLB->GetColorPtr(nColorStride,0,true); // get LM TexCoords int nLMStride=0; const byte * pLMTexCoords = pLMLB ? pLMLB->GetPosPtr(nLMStride,0,true) : 0; for(int v=newMatInfo.nFirstVertId; vGetLightmap(0) ? pBrush->GetLightmap(0)->GetColorLerpTex() : 0; if(newMatInfo.nNumIndices) { lstChunks.Add(newMatInfo); } else assert(!newMatInfo.nNumVerts); } nCurVertsNum += pLB->m_SecVertCount; pBrush->m_dwRndFlags |= ERF_MERGED; dwResRndFlags &= pBrush->m_dwRndFlags; } CBrush * pNewBrush = 0; if(!lstVerts.Count()) continue; // sort if(lstChunks.Count()) qsort(lstChunks.GetElements(), lstChunks.Count(), sizeof(lstChunks[0]), CBrush__Cmp_MatChunks); // merge chunks for(int nChunk=0; nChunkCreateLeafBufferInitialized( lstVerts.GetElements(), lstVerts.Count(), VERTEX_FORMAT_P3F_N_COL4UB_TEX2F, lstIndices.GetElements(), lstIndices.Count(), R_PRIMV_TRIANGLES, "MergedLB", eBT_Static, lstChunks.Count()); pNewLB->UpdateTangBuffer(lstTangBasises.GetElements()); for(int i=0; iSetChunk(lstChunks[i].GetShaderItem().m_pShader, lstChunks[i].nFirstVertId, lstChunks[i].nNumVerts, lstChunks[i].nFirstIndexId, lstChunks[i].nNumIndices, i, true); assert(lstChunks[i].GetShaderItem().m_pShaderResources); assert(lstChunks[i].GetShaderItem().m_pShader); pNewLB->m_pMats->Get(i)->shaderItem = lstChunks[i].GetShaderItem(); pNewLB->m_pMats->Get(i)->shaderItem.m_pShader->AddRef(); pNewLB->m_pMats->Get(i)->shaderItem.m_pShaderResources->AddRef(); } // make statobj CStatObj * pNewStatObj = MakeObject("NOFILE"); pNewStatObj->m_nLoadedTrisCount = lstIndices.Count()/3; pNewStatObj->SetLeafBuffer(pNewLB); pNewStatObj->SetBBoxMin(vBoxMin); pNewStatObj->SetBBoxMax(vBoxMax); sprintf(pNewStatObj->m_szFileName,"nMergeID=%d",nMergeID); // make brush pNewBrush = new CBrush(); if (fp) { fprintf(fp, "\n\nMerged Brush: %d, GroupID: %d\n", newBrushes.Count(), nMergeID); for (int i=0; iSetEntityStatObj(0,pNewStatObj,&mat); pNewBrush->m_vWSBoxMin = vBoxMin; pNewBrush->m_vWSBoxMax = vBoxMax; pNewBrush->m_fWSRadius = vBoxMin.GetDistance(vBoxMax)*0.5f; pNewBrush->m_dwRndFlags |= ERF_MERGED_NEW; pNewBrush->m_dwRndFlags |= ERF_NOTRANS_MASK; pNewBrush->m_dwRndFlags |= dwResRndFlags; // Make leafbuffer and fill it with texture coordinates if(nLMTexId && (nLMDirTexId || (GetCVars()->e_light_maps_quality==0))) { RenderLMData * pLMData = new RenderLMData(GetRenderer(), nLMTexId, nHDRLMTexId, nLMDirTexId); pNewBrush->SetLightmap(pLMData, (float*)lstLMTexCoords.GetElements(), lstLMTexCoords.Count(), 0); pLMData->AddRef(); pNewBrush->SetRndFlags(ERF_USELIGHTMAPS,true); } //Get3DEngine()->UnRegisterEntity(pNewBrush); //Get3DEngine()->RegisterEntity(pNewBrush); // find distance to the camera const Vec3d vCamPos = GetViewCamera().GetPos(); Vec3d vCenter = (pNewBrush->m_vWSBoxMin+pNewBrush->m_vWSBoxMax)*0.5f; float fEntDistance = GetDist2D( vCamPos.x, vCamPos.y, vCenter.x, vCenter.y ); assert(fEntDistance>=0); assert(_finite(fEntDistance)); newBrushes.Add(pNewBrush); } int nOldBrushes = m_lstBrushContainer.Count(); int nNewBrushes = newBrushes.Count(); int nMergedBrushes = nNewBrushes; for (i=0; im_dwRndFlags & ERF_MERGED) { pBrush->DeleteLMTC(); } else nMergedBrushes++; newBrushes.Add(m_lstBrushContainer[i]); } } m_lstBrushContainer.Free(); m_lstBrushContainer.AddList(newBrushes); for (i=0; iUpdateLoadingScreen("\003---%d groups, %d brushes requested, %d brushes rejected", nNumGroups, nRequested, nRejected); GetLog()->UpdateLoadingScreen("\003---%d additional brushes, %d new brushes: %d old brushes (%.3f perc)", nNewBrushes, nMergedBrushes, nOldBrushes, (float)nMergedBrushes/(float)nOldBrushes*100.0f); } void CObjManager::LoadBrushes() { GetLog()->UpdateLoadingScreen("\003Loading brushes ... "); assert(!m_lstBrushContainer.Count()); for(int i=0; i */CBrush::m_lstSExportedBrushMaterials.Reset(); list2 lstSExportedBrushGeom; list2 lstSExportedBrush; char szName[512]=""; strncpy(szName, Get3DEngine()->GetLevelFilePath("brush.lst"), sizeof(szName)); FILE * f = GetSystem()->GetIPak()->FOpen(szName, "rb"); if(!f) return; GetSystem()->GetIPak()->FRead( &header,sizeof(header),1,f ); if ((strncmp(header.signature,BRUSH_FILE_SIGNATURE,3) != 0) || (header.filetype != BRUSH_FILE_TYPE) || (header.version != BRUSH_FILE_VERSION)) { // Not Cry file. Warning(0,szName,"CObjManager::LoadBrushes: File %s is not a valid brush list file or wrong version, Reexport you level in Editor",szName ); GetSystem()->GetIPak()->FClose(f); return; } int nCount = 0; GetSystem()->GetIPak()->FRead(&nCount, 4, 1, f); int numMaterials = nCount; if(nCount<0 || nCount>100000) { GetSystem()->Warning(VALIDATOR_MODULE_3DENGINE,VALIDATOR_ERROR,0,szName, "CObjManager::LoadBrushes: invalid brush.lst file, Reexport the level from Editor again"); return; } if (numMaterials > 0) { CBrush::m_lstSExportedBrushMaterials.PreAllocate(nCount,nCount); GetSystem()->GetIPak()->FRead(&CBrush::m_lstSExportedBrushMaterials[0], sizeof(SExportedBrushMaterial), nCount, f); } GetSystem()->GetIPak()->FRead(&nCount, 4, 1, f); if(nCount<=0 || nCount>100000) { GetSystem()->Warning(VALIDATOR_MODULE_3DENGINE,VALIDATOR_ERROR,0,szName, "CObjManager::LoadBrushes: invalid brush.lst file, Reexport the level from Editor again"); return; } lstSExportedBrushGeom.PreAllocate(nCount,nCount); GetSystem()->GetIPak()->FRead(&lstSExportedBrushGeom[0], sizeof(SExportedBrushGeom), nCount, f); nCount = 0; GetSystem()->GetIPak()->FRead(&nCount, 4, 1, f); if(nCount<=0 || nCount>100000) { GetSystem()->Warning(VALIDATOR_MODULE_3DENGINE,VALIDATOR_ERROR,0,szName, "CObjManager::LoadBrushes: invalid brush.lst file, Reexport the level from Editor again"); return; } lstSExportedBrush.PreAllocate(nCount,nCount); GetSystem()->GetIPak()->FRead(&lstSExportedBrush[0], sizeof(SExportedBrush), nCount, f); GetSystem()->GetIPak()->FClose(f); std::vector vGLMs; // load instances for(int i=0; i=lstSExportedBrushGeom.Count() || GetDistance(lstSExportedBrushGeom[lstSExportedBrush[i].geometry].m_minBBox, lstSExportedBrushGeom[lstSExportedBrush[i].geometry].m_maxBBox)>256) { GetSystem()->Warning(VALIDATOR_MODULE_3DENGINE,VALIDATOR_ERROR,0,szName, "CObjManager::LoadBrushes: invalid brush.lst file, Reexport the level from Editor again"); continue; } CBrush * pEnt = (CBrush *)Get3DEngine()->CreateEntityRender(); const char * szFileName = lstSExportedBrushGeom[lstSExportedBrush[i].geometry].filename; IStatObj * pStatObj = MakeObject(szFileName, NULL, (lstSExportedBrush[i].flags&ERF_USELIGHTMAPS) ? evs_NoSharing : evs_ShareAndSortForCache, true, false, GetCVars()->e_stream_cgf==1); // Find or allocate slot containing pointer to this StatObj int nBrushGeomId = CBrush::m_lstBrushTypes.Find(pStatObj); if(nBrushGeomId<0) { // make new slot CBrush::m_lstBrushTypes.Add(pStatObj); nBrushGeomId = CBrush::m_lstBrushTypes.Count()-1; } assert(nBrushGeomId>=0); if(GetCVars()->e_stream_cgf) { pStatObj->SetBBoxMin(lstSExportedBrushGeom[lstSExportedBrush[i].geometry].m_minBBox); pStatObj->SetBBoxMax(lstSExportedBrushGeom[lstSExportedBrush[i].geometry].m_maxBBox); } pEnt->SetStatObjGroupId(nBrushGeomId); pEnt->SetMergeId(lstSExportedBrush[i].mergeId); pEnt->SetMatrix( &mat44 ); pEnt->SetRndFlags(lstSExportedBrush[i].flags & ~(ERF_SELECTED | ERF_HIDDEN)); pEnt->SetEditorObjectId(lstSExportedBrush[i].id); pEnt->SetViewDistRatio(lstSExportedBrush[i].ratioViewDist); pEnt->SetLodRatio(lstSExportedBrush[i].ratioLod); if (pEnt->GetRndFlags() & ERF_USELIGHTMAPS) vGLMs.push_back(pEnt); // Find material. if (numMaterials > 0) { int mtlid = lstSExportedBrush[i].material; if (mtlid >= 0 && mtlid < numMaterials) { const char *sMtlName = CBrush::m_lstSExportedBrushMaterials[mtlid].material; IMatInfo *pMtl = Get3DEngine()->FindMaterial( sMtlName ); if (pMtl) { pEnt->SetMaterial( pMtl ); pEnt->SetMaterialId( mtlid ); } } } } GetLog()->UpdateLoadingScreen("\003Brushes loaded: %d models, %d instances, %d custom materials", lstSExportedBrushGeom.Count(), lstSExportedBrush.Count(), CBrush::m_lstSExportedBrushMaterials.Count()); if(GetCVars()->e_light_maps) { ILMSerializationManager *pILMSerialization = Get3DEngine()->CreateLMSerializationManager(); pILMSerialization->ApplyLightmapfile(Get3DEngine()->GetLevelFilePath(LM_EXPORT_FILE_NAME), vGLMs); pILMSerialization->Release(); pILMSerialization = NULL; } } bool CBrush::IsEntityHasSomethingToRender() { return m_nObjectTypeID>=0 && m_lstBrushTypes[m_nObjectTypeID] && !(m_dwRndFlags & ERF_HIDDEN); } bool CBrush::IsEntityAreasVisible() { if(!GetEntityRS()) return false; // test last render frame id if(m_pVisArea) if(abs(m_pVisArea->m_nRndFrameId - GetFrameID())<=2) return true; return false; } IPhysicalEntity* CBrush::GetPhysics() const { return m_pPhysEnt; } void CBrush::SetPhysics( IPhysicalEntity* pPhys ) { m_pPhysEnt = pPhys; } bool CBrush::IsMatrixValid(const Matrix44 & mat) { Vec3d vScaleTest = mat.TransformVectorOLD(Vec3d(0,0,1)); float fDist = GetDistance(mat.GetTranslationOLD(),Vec3d(0,0,0)); if( vScaleTest.Length()>100.f || vScaleTest.Length()<0.01f || fDist > 64000 || !_finite(vScaleTest.x) || !_finite(vScaleTest.y) || !_finite(vScaleTest.z) ) return false; return true; } void CBrush::SetMaterial( IMatInfo *pMatInfo ) { m_pMaterial = pMatInfo; if(m_pMaterial) m_pMaterial->SetFlags(m_pMaterial->GetFlags()|MIF_WASUSED); } IMatInfo* CBrush::GetMaterial() const { return m_pMaterial; } void CBrush::CheckPhysicalized() { // if(GetEntityStatObj(0)) // ((CStatObj*)GetEntityStatObj(0))->CheckLoaded(true); if(!m_pPhysEnt) Physicalize(); } int CBrush::DestroyPhysicalEntityCallback(IPhysicalEntity *pent) { // assert(pent == m_pPhysEnt); /* for(int i=0; i<2; i++) { if(m_arrPhysGeomId[i]>=0) pent->RemoveGeometry(m_arrPhysGeomId[i]); // m_arrPhysGeomId[i] = -1; } */ for(int i=0; i<2; i++) { // if(m_arrPhysGeomId[i]>=0) // m_pPhysEnt->RemoveGeometry(m_arrPhysGeomId[i]); // m_arrPhysGeomId[i] = -1; } return 1; } float CBrush::GetMaxViewDist() { return max(GetCVars()->e_obj_min_view_dist, m_fWSRadius*GetCVars()->e_obj_view_dist_ratio*GetViewDistRatioNormilized()); } void CBrush::Serialize(bool bSave, ICryPak * pPak, FILE * f) { #if 0 if(bSave) { pPak->FWrite(this,sizeof(*this),1,f); if(0 && m_pLMTCBuffer) { /* int nPos=0; m_pLMTCBuffer->Serialize(nPos,0,true,0,0); uchar * pLMLBuffer = new uchar[nPos]; pPak->FWrite(&nPos,sizeof(nPos),1,f); nPos=0; m_pLMTCBuffer->Serialize(nPos,pLMLBuffer,true,0,0);*/ // Make leafbuffer and fill it with texture coordinates // m_pLMTCBuffer = GetRenderer()->CreateLeafBufferInitialized( // &vTexCoord3[0], pLeafBuffer->m_SecVertCount, VERTEX_FORMAT_P3F, // pLeafBuffer->GetIndices(0), pLeafBuffer->m_Indices.m_nItems, R_PRIMV_TRIANGLES, "LMapTexCoords", eBT_Static); pPak->FWrite(&m_pLMTCBuffer->m_SecVertCount,sizeof(m_pLMTCBuffer->m_SecVertCount),1,f); byte * pData = (byte *)m_pLMTCBuffer->m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData; assert(m_VertexSize[m_pLMTCBuffer->m_pSecVertBuffer->m_vertexformat] == 12); int nSize = m_VertexSize[m_pLMTCBuffer->m_pSecVertBuffer->m_vertexformat]*m_pLMTCBuffer->m_SecVertCount; pPak->FWrite(&m_pLMTCBuffer->m_SecVertCount,sizeof(m_pLMTCBuffer->m_SecVertCount),1,f); } else { int nPos=0; pPak->FWrite(&nPos,sizeof(nPos),1,f); } } else { pPak->FRead(this,sizeof(*this),1,f); if(m_nMaterialId>=0) { // restore material const char * sMtlName = CBrush::m_lstSExportedBrushMaterials[m_nMaterialId].material; m_pMaterial = Get3DEngine()->FindMaterial( sMtlName ); } else m_pMaterial = 0; int nSize=0; pPak->FRead(&nSize,sizeof(nSize),1,f); if(nSize) { assert(0); int nVertCount = 0; pPak->FRead(&nVertCount,sizeof(nVertCount),1,f); byte * pData = new byte[nVertCount*12]; pPak->FRead(pData,nVertCount*12,1,f); // Make leafbuffer and fill it with texture coordinates m_pLMTCBuffer = GetRenderer()->CreateLeafBufferInitialized( pData, nVertCount, VERTEX_FORMAT_P3F, 0, 0, R_PRIMV_TRIANGLES, "LMapTexCoordsStreamed", eBT_Static); assert(m_VertexSize[m_pLMTCBuffer->m_pSecVertBuffer->m_vertexformat] == 12); } else { m_pLMTCBuffer = 0; m_pLMData = NULL; } } #endif } int CBrush::GetMemoryUsage() { return sizeof(*this) + m_pEntityRenderState ? sizeof(*m_pEntityRenderState) : 0; } void CBrush::SetEntityStatObj( unsigned int nSlot, IStatObj * pStatObj, Matrix44 * pMatrix ) { if(!pStatObj) { m_nObjectTypeID = -1; return; } int nFind = CBrush::m_lstBrushTypes.Find(pStatObj); if(nFind>=0) { // found m_nObjectTypeID = nFind; } else { m_nObjectTypeID = CBrush::m_lstBrushTypes.Count(); CBrush::m_lstBrushTypes.Add(pStatObj); } if(pMatrix) SetMatrix(pMatrix); } void CBrush::PreloadInstanceResources(Vec3d vPrevPortalPos, float fPrevPortalDistance, float fTime) { if(!GetEntityStatObj(0)) return; if(GetCVars()->e_stream_cgf) ((CStatObj*)GetEntityStatObj(0))->StreamCCGF(false); if(!GetEntityStatObj(0)->GetLeafBuffer()) return; float fDist = fPrevPortalDistance + m_vPos.GetDistance(vPrevPortalPos); float fMaxViewDist = GetMaxViewDist(); if(fDistPreloadResources(fDist,fTime,0); for(int nLod=0; nLodGetColorLerpTex() && m_arrLMData[nLod].m_pLMData->GetDomDirectionTex()) #else if(m_arrLMData[nLod].m_pLMData != 0 && m_arrLMData[nLod].m_pLMData->GetColorLerpTex() && m_arrLMData[nLod].m_pLMData->GetDomDirectionTex()) #endif { { ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(m_arrLMData[nLod].m_pLMData->GetColorLerpTex()); if(pTexPic) GetRenderer()->EF_PrecacheResource(pTexPic, 0, 1.f, 0); } { ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(m_arrLMData[nLod].m_pLMData->GetDomDirectionTex()); if(pTexPic) GetRenderer()->EF_PrecacheResource(pTexPic, 0, 1.f, 0); } } }