void CMFXLibrary::LoadFromXml( SLoadingEnvironment& loadingEnvironment ) { CryLogAlways("[MFX] Loading FXLib '%s' ...", loadingEnvironment.libraryName.c_str()); INDENT_LOG_DURING_SCOPE(); for (int i = 0; i < loadingEnvironment.libraryParamsNode->getChildCount(); ++i) { XmlNodeRef currentEffectNode = loadingEnvironment.libraryParamsNode->getChild(i); if (!currentEffectNode) continue; TMFXContainerPtr pContainer = MaterialEffectsUtils::CreateContainer(); pContainer->BuildFromXML(currentEffectNode); const TMFXNameId& effectName = pContainer->GetParams().name; const bool effectAdded = AddContainer(effectName, pContainer); if (effectAdded) { loadingEnvironment.AddLibraryContainer(loadingEnvironment.libraryName, pContainer); } else { GameWarning("[MFX] Effect (at line %d) '%s:%s' already present, skipping redefinition!", currentEffectNode->getLine(), loadingEnvironment.libraryName.c_str(), effectName.c_str()); } } }
SMFXResourceListPtr CMaterialEffects::GetResources(TMFXEffectId effectId) const { SMFXResourceListPtr pResourceList = SMFXResourceList::Create(); TMFXContainerPtr pEffectContainer = InternalGetEffect(effectId); if (pEffectContainer) { pEffectContainer->GetResources(*pResourceList); } return pResourceList; }
TMFXEffectId CMaterialEffects::GetEffectIdByName(const char* libName, const char* effectName) { if (!CMaterialEffectsCVars::Get().mfx_Enable) return InvalidEffectId; const TMFXContainerPtr pEffectContainer = InternalGetEffect(libName, effectName); if (pEffectContainer) { return pEffectContainer->GetParams().effectId; } return InvalidEffectId; }
void CMaterialEffects::SetCustomParameter(TMFXEffectId effectId, const char* customParameter, const SMFXCustomParamValue& customParameterValue) { FUNCTION_PROFILER(gEnv->pSystem, PROFILE_ACTION); if (!CMaterialEffectsCVars::Get().mfx_Enable) return; TMFXContainerPtr pEffect = InternalGetEffect(effectId); if (pEffect) { pEffect->SetCustomParameter(customParameter, customParameterValue); } }
void CMaterialEffects::StopEffect(TMFXEffectId effectId) { TMFXContainerPtr pEffectContainer = InternalGetEffect(effectId); if (pEffectContainer) { SMFXResourceListPtr resources = SMFXResourceList::Create(); pEffectContainer->GetResources(*resources); SMFXFlowGraphListNode *pNext=resources->m_flowGraphList; while (pNext) { GetFGManager()->EndFGEffect(pNext->m_flowGraphParams.name); pNext=pNext->pNext; } } }
bool CMaterialEffects::ExecuteEffect(TMFXEffectId effectId, SMFXRunTimeEffectParams& params) { FUNCTION_PROFILER(gEnv->pSystem, PROFILE_ACTION); if (!CMaterialEffectsCVars::Get().mfx_Enable) return false; bool success = false; TMFXContainerPtr pEffectContainer = InternalGetEffect(effectId); if (pEffectContainer) { const float delay = pEffectContainer->GetParams().delay; if ((delay > 0.0f) && !(params.playflags & eMFXPF_Disable_Delay)) { TimedEffect(pEffectContainer, params); } else { pEffectContainer->Execute(params); } success = true; #ifdef MATERIAL_EFFECTS_DEBUG if (CMaterialEffectsCVars::Get().mfx_DebugVisual) { if (effectId != InvalidEffectId) { m_pVisualDebug->AddEffectDebugVisual(effectId, params); } } #endif } return success; }
bool CMaterialEffects::PlayBreakageEffect(ISurfaceType* pSurfaceType, const char* breakageType, const SMFXBreakageParams& breakageParams) { if (pSurfaceType == 0) return false; CryFixedStringT<128> fxName ("Breakage:"); fxName+=breakageType; TMFXEffectId effectId = this->GetEffectId(fxName.c_str(), pSurfaceType->GetId()); if (effectId == InvalidEffectId) return false; // only play sound at the moment SMFXRunTimeEffectParams params; params.playflags = eMFXPF_Audio; // if hitpos is set, use it // otherwise use matrix (hopefully been set or 0,0,0) if (breakageParams.CheckFlag(SMFXBreakageParams::eBRF_HitPos) && breakageParams.GetHitPos().IsZero() == false) params.pos = breakageParams.GetHitPos(); else params.pos = breakageParams.GetMatrix().GetTranslation(); //params.soundSemantic = eSoundSemantic_Physics_General; const Vec3& hitImpulse = breakageParams.GetHitImpulse(); const float strength = hitImpulse.GetLengthFast(); params.AddAudioRtpc("strength", strength); const float mass = NormalizeMass(breakageParams.GetMass()); params.AddAudioRtpc("mass", mass); if (CMaterialEffectsCVars::Get().mfx_Debug & 2) { TMFXContainerPtr pEffectContainer = InternalGetEffect(effectId); if (pEffectContainer != NULL) { CryLogAlways("[MFX]: %s:%s FX=%s:%s Pos=%f,%f,%f NormMass=%f F=%f Imp=%f,%f,%f RealMass=%f Vel=%f,%f,%f", breakageType, pSurfaceType->GetName(), pEffectContainer->GetParams().libraryName.c_str(), pEffectContainer->GetParams().name.c_str(), params.pos[0],params.pos[1],params.pos[2], mass, strength, breakageParams.GetHitImpulse()[0], breakageParams.GetHitImpulse()[1], breakageParams.GetHitImpulse()[2], breakageParams.GetMass(), breakageParams.GetVelocity()[0], breakageParams.GetVelocity()[1], breakageParams.GetVelocity()[2] ); } } /* if (breakageParams.GetMass() == 0.0f) { int a = 0; } */ const bool bSuccess = ExecuteEffect(effectId, params); return bSuccess; }
void CMaterialEffects::LoadSpreadSheet() { m_bDataInitialized = true; Reset(false); CryComment("[MFX] Init"); IXmlTableReader* const pXmlTableReader = gEnv->pSystem->GetXmlUtils()->CreateXmlTableReader(); if (!pXmlTableReader) { GameWarning("[MFX] XML system failure"); return; } // The root node. XmlNodeRef root = gEnv->pSystem->LoadXmlFromFile( MATERIAL_EFFECTS_SPREADSHEET_FILE ); if (!root) { // The file wasn't found, or the wrong file format was used GameWarning("[MFX] File not found or wrong file type: %s", MATERIAL_EFFECTS_SPREADSHEET_FILE); pXmlTableReader->Release(); return; } CryComment("[MFX] Loaded: %s", MATERIAL_EFFECTS_SPREADSHEET_FILE); if (!pXmlTableReader->Begin(root)) { GameWarning("[MFX] Table not found"); pXmlTableReader->Release(); return; } // temporary multimap: we store effectstring -> [TIndexPairs]+ there typedef std::vector<TIndexPair> TIndexPairVec; typedef std::map<CConstCharArray, TIndexPairVec, less_CConstCharArray> TEffectStringToIndexPairVecMap; TEffectStringToIndexPairVecMap tmpEffectStringToIndexPairVecMap; int rowCount = 0; int warningCount = 0; CConstCharArray cell; string cellString; // temporary string // When we've gone down more rows than we have columns, we've entered special object space int maxCol = 0; std::vector<CConstCharArray> colOrder; std::vector<CConstCharArray> rowOrder; m_surfaceIdToMatrixEntry.resize(0); m_surfaceIdToMatrixEntry.resize(kMaxSurfaceCount, TIndex(0)); m_ptrToMatrixEntryMap.clear(); m_customConvert.clear(); // Iterate through the table's rows for (;;) { int nRowIndex = -1; if (!pXmlTableReader->ReadRow(nRowIndex)) break; // Iterate through the row's columns for (;;) { int colIndex = -1; if (!pXmlTableReader->ReadCell(colIndex, cell.ptr, cell.count)) break; if (cell.count <= 0) continue; cellString.assign(cell.ptr, cell.count); if (rowCount == 0 && colIndex > 0) { const int matId = gEnv->p3DEngine->GetMaterialManager()->GetSurfaceTypeManager()->GetSurfaceTypeByName(cellString.c_str(), "MFX", true)->GetId(); if (matId != 0 || /* matId == 0 && */ stricmp(cellString.c_str(), "mat_default") == 0) // if matId != 0 or it's the mat_default name { // CryLogAlways("[MFX] Material found: %s [ID=%d] [mapping to row/col=%d]", cellString.c_str(), matId, colCount); if (m_surfaceIdToMatrixEntry.size() < matId) { m_surfaceIdToMatrixEntry.resize(matId+1); if (matId >= kMaxSurfaceCount) { assert (false && "MaterialEffects.cpp: SurfaceTypes exceeds 256. Reconsider implementation."); CryLogAlways("MaterialEffects.cpp: SurfaceTypes exceeds %d. Reconsider implementation.", kMaxSurfaceCount); } } m_surfaceIdToMatrixEntry[matId] = colIndex; } else { GameWarning("MFX WARNING: Material not found: %s", cellString.c_str()); ++warningCount; } colOrder.push_back(cell); } else if (rowCount > 0 && colIndex > 0) { //CryLog("[MFX] Event found: %s", cellString.c_str()); tmpEffectStringToIndexPairVecMap[cell].push_back(TIndexPair(rowCount, colIndex)); } else if (rowCount > maxCol && colIndex == 0) { IEntityClass *pEntityClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(cellString.c_str()); //CryLog("[MFX] Object class ID: %d", (int)pEntityClass); if (pEntityClass) { // CryComment("[MFX] Found EntityClass based entry: %s [mapping to row/col=%d]", cellString.c_str(), rowCount); m_ptrToMatrixEntryMap[pEntityClass] = rowCount; } else { // CryComment("[MFX] Found Custom entry: %s [mapping to row/col=%d]", cellString.c_str(), rowCount); cellString.MakeLower(); m_customConvert[cellString] = rowCount; ++warningCount; } } else if (rowCount > 0 && colIndex == 0) { rowOrder.push_back(cell); } // Heavy-duty debug info //CryLog("[MFX] celldata = %s at (%d, %d) rowCount=%d colIndex=%d maxCol=%d", curCellData->getContent(), i, j, rowCount, colIndex, maxCol); // Check if this is the furthest column we've seen thus far if (colIndex > maxCol) maxCol = colIndex; SLICE_AND_SLEEP(); } // Increment row counter ++rowCount; } // now postprocess the tmpEffectStringIndexPairVecMap and generate the m_matmatArray { // create the matmat array. // +1, because index pairs are in range [1..rowCount][1..maxCol] m_surfacesLookupTable.Create(rowCount+1,maxCol+1); TEffectStringToIndexPairVecMap::const_iterator iter = tmpEffectStringToIndexPairVecMap.begin(); TEffectStringToIndexPairVecMap::const_iterator iterEnd = tmpEffectStringToIndexPairVecMap.end(); string libName; string effectName; string tmpString; while (iter != iterEnd) { // lookup effect tmpString.assign(iter->first.ptr, iter->first.count); ToEffectString(tmpString, libName, effectName); TMFXContainerPtr pEffectContainer = InternalGetEffect(libName, effectName); TMFXEffectId effectId = pEffectContainer ? pEffectContainer->GetParams().effectId : InvalidEffectId; TIndexPairVec::const_iterator vecIter = iter->second.begin(); TIndexPairVec::const_iterator vecIterEnd = iter->second.end(); while (vecIter != vecIterEnd) { const TIndexPair& indexPair = *vecIter; // CryLogAlways("[%d,%d]->%d '%s'", indexPair.first, indexPair.second, effectId, tmpString.c_str()); m_surfacesLookupTable(indexPair.first,indexPair.second) = effectId; ++vecIter; } ++iter; } } if (CMaterialEffectsCVars::Get().mfx_Debug > 0) { CryLogAlways("[MFX] RowCount=%d MaxCol=%d (*=%d)", rowCount, maxCol,rowCount*maxCol); for (int y=0; y<m_surfacesLookupTable.m_nRows; ++y) { for (int x=0; x<m_surfacesLookupTable.m_nCols; ++x) { TMFXEffectId idRowCol = m_surfacesLookupTable.GetValue(y,x, USHRT_MAX); assert (idRowCol != USHRT_MAX); TMFXContainerPtr pEffectRowCol = InternalGetEffect(idRowCol); if (pEffectRowCol) { CryLogAlways("[%d,%d] -> %d '%s:%s'", y, x, idRowCol, pEffectRowCol->GetParams().libraryName.c_str(), pEffectRowCol->GetParams().name.c_str()); if (y<m_surfacesLookupTable.m_nCols) { TMFXEffectId idColRow = m_surfacesLookupTable.GetValue(x,y, USHRT_MAX); assert (idColRow != USHRT_MAX); TMFXContainerPtr pEffectColRow = InternalGetEffect(idColRow); if (idRowCol != idColRow) { if (pEffectColRow) { GameWarning("[MFX] Identity mismatch: ExcelRowCol %d:%d: %s:%s != %s:%s", y+1, x+1, pEffectRowCol->GetParams().libraryName.c_str(), pEffectRowCol->GetParams().name.c_str(), pEffectColRow->GetParams().libraryName.c_str(), pEffectColRow->GetParams().name.c_str()); } else { GameWarning("[MFX] Identity mismatch: ExcelRowCol %d:%d: %s:%s != [not found]", y+1, x+1, pEffectRowCol->GetParams().libraryName.c_str(), pEffectRowCol->GetParams().name.c_str()); } } } } } } } // check that we have the same number of columns and rows if (colOrder.size() > rowOrder.size()) { GameWarning("[MFX] Found %d Columns, but not enough rows specified (%d)", (int32)colOrder.size(), (int32)rowOrder.size()); } // check that column order matches row order if (CMaterialEffectsCVars::Get().mfx_Debug > 0) { string colName; string rowName; for (int i=0;i<colOrder.size(); ++i) { colName.assign(colOrder[i].ptr, colOrder[i].count); if (i < rowOrder.size()) { rowName.assign(rowOrder[i].ptr, rowOrder[i].count); } else { rowName.clear(); } // CryLogAlways("ExcelColRow=%d col=%s row=%s", i+2, colName.c_str(), rowName.c_str()); if (colName != rowName) { GameWarning("ExcelColRow=%d: %s != %s", i+2, colName.c_str(), rowName.c_str()); } } } pXmlTableReader->Release(); }