/************************************************************************************************ * CRMInstanceFile::Open * Opens the given instance file and prepares it for use in instance creation * * inputs: * instance: Name of instance to open. Note that the root path will be automatically * added and shouldnt be included in the given name * * return: * true: instance file successfully loaded * false: instance file could not be loaded for some reason * ************************************************************************************************/ bool CRMInstanceFile::Open ( const char* instance ) { char instanceDef[MAX_QPATH]; CGPGroup *basegroup; // Build the filename Com_sprintf(instanceDef, MAX_QPATH, "ext_data/rmg/%s.instance", instance ); #ifndef FINAL_BUILD // Debug message Com_Printf("CM_Terrain: Loading and parsing instanceDef %s.....\n", instance); #endif // Parse the text file using the generic parser if(!Com_ParseTextFile(instanceDef, mParser )) { Com_sprintf(instanceDef, MAX_QPATH, "ext_data/arioche/%s.instance", instance ); if(!Com_ParseTextFile(instanceDef, mParser )) { Com_Printf(va("CM_Terrain: Could not open instance file '%s'\n", instanceDef)); return false; } } // The whole file.... basegroup = mParser.GetBaseParseGroup(); // The root { } struct mInstances = basegroup->GetSubGroups(); // The "instances" { } structure mInstances = mInstances->GetSubGroups ( ); return true; }
static LPCSTR Skins_Parse(string strThisSkinFileName, CGPGroup *pFileGroup, CGPGroup *pParseGroup_Prefs) { LPCSTR psError = NULL; // read any optional surface on/off blocks... // for (int iSurfaceOnOffType = 0; iSurfaceOnOffType<3; iSurfaceOnOffType++) { CGPGroup *pSurfaceParseGroup = NULL; switch (iSurfaceOnOffType) { case 0: pSurfaceParseGroup = pParseGroup_Prefs->FindSubGroup(sSKINKEYWORD_SURFACES_ON); break; case 1: pSurfaceParseGroup = pParseGroup_Prefs->FindSubGroup(sSKINKEYWORD_SURFACES_OFF); break; case 2: pSurfaceParseGroup = pParseGroup_Prefs->FindSubGroup(sSKINKEYWORD_SURFACES_OFFNOCHILDREN); break; default: assert(0); break; } if (pSurfaceParseGroup) { CGPValue *pValue = pSurfaceParseGroup->GetPairs(); while (pValue) { // string str1 = (*it).first; // junk, eg "name1" string str2 = pValue->GetTopValue(); switch (iSurfaceOnOffType) { case 0: CurrentSkinsSurfacePrefs[strThisSkinFileName].vSurfacesOn.push_back(str2); break; case 1: CurrentSkinsSurfacePrefs[strThisSkinFileName].vSurfacesOff.push_back(str2); break; case 2: CurrentSkinsSurfacePrefs[strThisSkinFileName].vSurfacesOffNoChildren.push_back(str2); break; default: assert(0); break; } pValue = pValue->GetNext(); } } } // find all the materials and add them to the skin set... // int iMaterialDeclarationIndex = 0; for (CGPGroup *pMaterialGroup = pFileGroup->GetSubGroups(); pMaterialGroup; pMaterialGroup = pMaterialGroup->GetNext(), iMaterialDeclarationIndex++) { string strKeyWord = pMaterialGroup->GetName(); if (strKeyWord == sSKINKEYWORD_MATERIAL) { string strMaterialName(pMaterialGroup->FindPairValue(sSKINKEYWORD_NAME,"")); if (strMaterialName == "") { psError = va("%s[%d] had no \"%s\" field!\n",sSKINKEYWORD_MATERIAL, iMaterialDeclarationIndex, sSKINKEYWORD_NAME); return psError; } // now iterate through the ethnic group variants of this material... // int iEthnicGroupIndex = 0; for (CGPGroup *pEthnicGroup = pMaterialGroup->GetSubGroups(); pEthnicGroup; pEthnicGroup = pEthnicGroup->GetNext(), iEthnicGroupIndex++) { strKeyWord = pEthnicGroup->GetName(); if (strKeyWord == sSKINKEYWORD_GROUP) { string strEthnicGroupName(pEthnicGroup->FindPairValue(sSKINKEYWORD_NAME,"")); if (strEthnicGroupName == "") { psError = va("%s[%d] %s[%d] had no \"%s\" field!\n",sSKINKEYWORD_MATERIAL, iMaterialDeclarationIndex, sSKINKEYWORD_GROUP, iEthnicGroupIndex, sSKINKEYWORD_NAME); return psError; } // now iterate through the shader variants for this ethnic version of this material... (is anyone reading this...?) // int iAlternateShaderIndex = 0; for (CGPValue *pValue = pEthnicGroup->GetPairs(); pValue; pValue = pValue->GetNext()) { string strField(pValue->GetName()); if (strField != sSKINKEYWORD_NAME) { // ... then it should be a shader... // string strShader(pValue->GetTopValue()); CurrentSkins[strThisSkinFileName][strEthnicGroupName][strMaterialName].push_back(strShader); } } } } } } return psError; }
static sboolean Music_ParseMusic(CGenericParser2 &Parser, MusicData_t *MusicData, CGPGroup *pgMusicFiles, LPCSTR psMusicName, LPCSTR psMusicNameKey, MusicState_e eMusicState) { sboolean bReturn = qfalse; #ifdef _XBOX Z_SetNewDeleteTemporary(true); #endif MusicFile_t MusicFile; #ifdef _XBOX Z_SetNewDeleteTemporary(false); #endif CGPGroup *pgMusicFile = pgMusicFiles->FindSubGroup(psMusicName); if (pgMusicFile) { // read subgroups... // sboolean bEntryFound = qfalse; sboolean bExitFound = qfalse; // // (read entry points first, so I can check exit points aren't too close in time) // CGPGroup *pEntryGroup = pgMusicFile->FindSubGroup(sKEY_ENTRY); if (pEntryGroup) { // read entry points... // for (CGPValue *pValue = pEntryGroup->GetPairs(); pValue; pValue = pValue->GetNext()) { LPCSTR psKey = pValue->GetName(); LPCSTR psValue = pValue->GetTopValue(); //if (!strncmp(psKey,sKEY_MARKER,strlen(sKEY_MARKER))) // for now, assume anything is a marker { MusicFile.MusicEntryTimes[psKey] = atof(psValue); bEntryFound = qtrue; // harmless to keep setting } } } for (CGPGroup *pGroup = pgMusicFile->GetSubGroups(); pGroup; pGroup = pGroup->GetNext()) { LPCSTR psGroupName = pGroup->GetName(); if (!strcmp(psGroupName,sKEY_ENTRY)) { // skip entry points, I've already read them in above // } else if (!strcmp(psGroupName,sKEY_EXIT)) { int iThisExitPointIndex = MusicFile.MusicExitPoints.size(); // must eval this first, so unaffected by push_back etc // // read this set of exit points... // MusicExitPoint_t MusicExitPoint; for (CGPValue *pValue = pGroup->GetPairs(); pValue; pValue = pValue->GetNext()) { LPCSTR psKey = pValue->GetName(); LPCSTR psValue = pValue->GetTopValue(); if (!strcmp(psKey,sKEY_NEXTFILE)) { MusicExitPoint.sNextFile = psValue; bExitFound = qtrue; // harmless to keep setting } else if (!strcmp(psKey,sKEY_NEXTMARK)) { MusicExitPoint.sNextMark = psValue; } else if (!strncmp(psKey,sKEY_TIME,strlen(sKEY_TIME))) { MusicExitTime_t MusicExitTime; MusicExitTime.fTime = atof(psValue); MusicExitTime.iExitPoint= iThisExitPointIndex; // new check, don't keep this this exit point if it's within 1.5 seconds either way of an entry point... // sboolean bTooCloseToEntryPoint = qfalse; for (MusicEntryTimes_t::iterator itEntryTimes = MusicFile.MusicEntryTimes.begin(); itEntryTimes != MusicFile.MusicEntryTimes.end(); ++itEntryTimes) { float fThisEntryTime = (*itEntryTimes).second; if (Q_fabs(fThisEntryTime - MusicExitTime.fTime) < 1.5f) { // bTooCloseToEntryPoint = qtrue; // not sure about this, ignore for now break; } } if (!bTooCloseToEntryPoint) { #ifdef _XBOX Z_SetNewDeleteTemporary(true); #endif MusicFile.MusicExitTimes.push_back(MusicExitTime); #ifdef _XBOX Z_SetNewDeleteTemporary(false); #endif } } } #ifdef _XBOX Z_SetNewDeleteTemporary(true); #endif MusicFile.MusicExitPoints.push_back(MusicExitPoint); #ifdef _XBOX Z_SetNewDeleteTemporary(false); #endif int iNumExitPoints = MusicFile.MusicExitPoints.size(); // error checking... // switch (eMusicState) { case eBGRNDTRACK_EXPLORE: if (iNumExitPoints > iMAX_EXPLORE_TRANSITIONS) { MUSIC_PARSE_ERROR( va("\"%s\" has > %d %s transitions defined!\n",psMusicName,iMAX_EXPLORE_TRANSITIONS,psMusicNameKey) ); return qfalse; } break; case eBGRNDTRACK_ACTION: if (iNumExitPoints > iMAX_ACTION_TRANSITIONS) { MUSIC_PARSE_ERROR( va("\"%s\" has > %d %s transitions defined!\n",psMusicName,iMAX_ACTION_TRANSITIONS,psMusicNameKey) ); return qfalse; } break; case eBGRNDTRACK_BOSS: case eBGRNDTRACK_DEATH: MUSIC_PARSE_ERROR( va("\"%s\" has %s transitions defined, this is not allowed!\n",psMusicName,psMusicNameKey) ); break; } } } // for now, assume everything was ok unless some obvious things are missing... // bReturn = qtrue; if (eMusicState != eBGRNDTRACK_BOSS && eMusicState != eBGRNDTRACK_DEATH) // boss & death pieces can omit entry/exit stuff { if (!bEntryFound) { MUSIC_PARSE_ERROR(va("Unable to find subgroup \"%s\" in group \"%s\"\n",sKEY_ENTRY,psMusicName)); bReturn = qfalse; } if (!bExitFound) { MUSIC_PARSE_ERROR(va("Unable to find subgroup \"%s\" in group \"%s\"\n",sKEY_EXIT,psMusicName)); bReturn = qfalse; } } } else { MUSIC_PARSE_ERROR(va("Unable to find musicfiles entry \"%s\"\n",psMusicName)); } if (bReturn) { MusicFile.sFileNameBase = psMusicName; (*MusicData)[ psMusicNameKey ] = MusicFile; } return bReturn; }
// Parse a primitive, apply defaults first, grab any base level // key pairs, then process any sub groups we may contain. //------------------------------------------------------ bool CPrimitiveTemplate::ParsePrimitive( const CGPGroup& grp ) { // Property for( auto& prop : grp.GetProperties() ) { // Single Value Parsing { static StringViewIMap< ParseMethod > parseMethods{ { CSTRING_VIEW( "count" ), &CPrimitiveTemplate::ParseCount }, { CSTRING_VIEW( "life" ), &CPrimitiveTemplate::ParseLife }, { CSTRING_VIEW( "delay" ), &CPrimitiveTemplate::ParseDelay }, { CSTRING_VIEW( "bounce" ), &CPrimitiveTemplate::ParseElasticity }, { CSTRING_VIEW( "intensity" ), &CPrimitiveTemplate::ParseElasticity }, { CSTRING_VIEW( "min" ), &CPrimitiveTemplate::ParseMin }, { CSTRING_VIEW( "max" ), &CPrimitiveTemplate::ParseMax }, { CSTRING_VIEW( "angle" ), &CPrimitiveTemplate::ParseAngle }, { CSTRING_VIEW( "angles" ), &CPrimitiveTemplate::ParseAngle }, { CSTRING_VIEW( "angleDelta" ), &CPrimitiveTemplate::ParseAngleDelta }, { CSTRING_VIEW( "velocity" ), &CPrimitiveTemplate::ParseVelocity }, { CSTRING_VIEW( "vel" ), &CPrimitiveTemplate::ParseVelocity }, { CSTRING_VIEW( "acceleration" ), &CPrimitiveTemplate::ParseAcceleration }, { CSTRING_VIEW( "accel" ), &CPrimitiveTemplate::ParseAcceleration }, { CSTRING_VIEW( "gravity" ), &CPrimitiveTemplate::ParseGravity }, { CSTRING_VIEW( "density" ), &CPrimitiveTemplate::ParseDensity }, { CSTRING_VIEW( "variance" ), &CPrimitiveTemplate::ParseVariance }, { CSTRING_VIEW( "origin" ), &CPrimitiveTemplate::ParseOrigin1 }, { CSTRING_VIEW( "origin2" ), &CPrimitiveTemplate::ParseOrigin2 }, { CSTRING_VIEW( "radius" ), &CPrimitiveTemplate::ParseRadius }, { CSTRING_VIEW( "height" ), &CPrimitiveTemplate::ParseHeight }, { CSTRING_VIEW( "wind" ), &CPrimitiveTemplate::ParseWindModifier }, { CSTRING_VIEW( "rotation" ), &CPrimitiveTemplate::ParseRotation }, { CSTRING_VIEW( "rotationDelta" ), &CPrimitiveTemplate::ParseRotationDelta }, { CSTRING_VIEW( "flags" ), &CPrimitiveTemplate::ParseFlags }, { CSTRING_VIEW( "flag" ), &CPrimitiveTemplate::ParseFlags }, { CSTRING_VIEW( "spawnFlags" ), &CPrimitiveTemplate::ParseSpawnFlags }, { CSTRING_VIEW( "spawnFlag" ), &CPrimitiveTemplate::ParseSpawnFlags }, }; auto pos = parseMethods.find( prop.GetName() ); if( pos != parseMethods.end() ) { ParseMethod method = pos->second; ( this->*method )( prop.GetTopValue() ); continue; } } // Property Parsing { using PropertyParseMethod = bool( CPrimitiveTemplate::* )( const CGPProperty& ); static StringViewIMap< PropertyParseMethod > parseMethods{ { CSTRING_VIEW( "shaders" ), &CPrimitiveTemplate::ParseShaders }, { CSTRING_VIEW( "shader" ), &CPrimitiveTemplate::ParseShaders }, { CSTRING_VIEW( "models" ), &CPrimitiveTemplate::ParseModels }, { CSTRING_VIEW( "model" ), &CPrimitiveTemplate::ParseModels }, { CSTRING_VIEW( "sounds" ), &CPrimitiveTemplate::ParseSounds }, { CSTRING_VIEW( "sound" ), &CPrimitiveTemplate::ParseSounds }, { CSTRING_VIEW( "impactfx" ), &CPrimitiveTemplate::ParseImpactFxStrings }, { CSTRING_VIEW( "deathfx" ), &CPrimitiveTemplate::ParseDeathFxStrings }, { CSTRING_VIEW( "emitfx" ), &CPrimitiveTemplate::ParseEmitterFxStrings }, { CSTRING_VIEW( "playfx" ), &CPrimitiveTemplate::ParsePlayFxStrings }, }; auto pos = parseMethods.find( prop.GetName() ); if( pos != parseMethods.end() ) { PropertyParseMethod method = pos->second; ( this->*method )( prop ); continue; } } // Special Cases if( Q::stricmp( prop.GetName(), CSTRING_VIEW( "cullrange" ) ) == Q::Ordering::EQ ) { mCullRange = Q::svtoi( prop.GetTopValue() ); mCullRange *= mCullRange; // Square } else if( Q::stricmp( prop.GetName(), CSTRING_VIEW( "name" ) ) == Q::Ordering::EQ ) { if( !prop.GetTopValue().empty() ) { // just stash the descriptive name of the primitive std::size_t len = std::min< std::size_t >( prop.GetTopValue().size(), FX_MAX_PRIM_NAME - 1 ); auto begin = prop.GetTopValue().begin(); std::copy( begin, begin + len, &mName[ 0 ] ); mName[ len ] = '\0'; } } // Error else { theFxHelper.Print( "Unknown key parsing an effect primitive!\n" ); } } for( auto& subGrp : grp.GetSubGroups() ) { using GroupParseMethod = bool ( CPrimitiveTemplate::* )( const CGPGroup& ); static StringViewIMap< GroupParseMethod > parseMethods{ { CSTRING_VIEW( "rgb" ), &CPrimitiveTemplate::ParseRGB }, { CSTRING_VIEW( "alpha" ), &CPrimitiveTemplate::ParseAlpha }, { CSTRING_VIEW( "size" ), &CPrimitiveTemplate::ParseSize }, { CSTRING_VIEW( "width" ), &CPrimitiveTemplate::ParseSize }, { CSTRING_VIEW( "size2" ), &CPrimitiveTemplate::ParseSize2 }, { CSTRING_VIEW( "width2" ), &CPrimitiveTemplate::ParseSize2 }, { CSTRING_VIEW( "length" ), &CPrimitiveTemplate::ParseLength }, { CSTRING_VIEW( "height" ), &CPrimitiveTemplate::ParseLength }, }; auto pos = parseMethods.find( subGrp.GetName() ); if( pos == parseMethods.end() ) { theFxHelper.Print( "Unknown group key parsing a particle!\n" ); } else { GroupParseMethod method = pos->second; ( this->*method )( subGrp ); } } return true; }