//------------------------------------------------------ // ParseGroupFlags // Group flags are generic in nature, so we can easily // use a generic function to parse them in, then the // caller can shift them into the appropriate range. // // input: // string that contains the flag strings // *flags returns the set bit flags // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseGroupFlags( const gsl::cstring_view& val, int& flags ) { // For a sub group, really you probably only have one or two flags set std::array< gsl::cstring_view, 4 > flag; const auto availableFlag = scanStrings( val, flag ); // Clear out the flags field, then convert the flag string to an actual value ( use generic flags ) flags = 0; bool ok = true; for( auto& cur : availableFlag ) { static StringViewIMap< int > flagNames{ { CSTRING_VIEW( "linear" ), FX_LINEAR }, { CSTRING_VIEW( "nonlinear" ), FX_NONLINEAR }, { CSTRING_VIEW( "wave" ), FX_WAVE }, { CSTRING_VIEW( "random" ), FX_RAND }, { CSTRING_VIEW( "clamp" ), FX_CLAMP }, }; auto pos = flagNames.find( cur ); if( pos == flagNames.end() ) { ok = false; } else { flags |= pos->second; } } return ok; }
//------------------------------------------------------ // ParseLength // Takes a length group and chomps out any pairs contained // in it. // // input: // the parse group to process // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseLength( const CGPGroup& grp ) { static StringViewIMap< ParseMethod > parseMethods{ { CSTRING_VIEW( "start" ), &CPrimitiveTemplate::ParseLengthStart }, { CSTRING_VIEW( "end" ), &CPrimitiveTemplate::ParseLengthEnd }, { CSTRING_VIEW( "parm" ), &CPrimitiveTemplate::ParseLengthParm }, { CSTRING_VIEW( "parms" ), &CPrimitiveTemplate::ParseLengthParm }, { CSTRING_VIEW( "flag" ), &CPrimitiveTemplate::ParseLengthFlags }, { CSTRING_VIEW( "flags" ), &CPrimitiveTemplate::ParseLengthFlags }, }; return ParseGroup( grp, parseMethods, "Length" ); }
bool CGPGroup::Parse( gsl::cstring_view& data, const bool topLevel ) { while( true ) { gsl::cstring_view token = GetToken( data, true ); if( token.empty() ) { if ( topLevel ) { // top level parse; there was no opening "{", so there should be no closing one either. return true; } else { // end of data - error! return false; } } else if( token == CSTRING_VIEW( "}" ) ) { if( topLevel ) { // top-level group; there was no opening "{" so there should be no closing one, either. return false; } else { // ending brace for this group return true; } } gsl::cstring_view lastToken = token; // read ahead to see what we are doing token = GetToken( data, true, true ); if( token == CSTRING_VIEW( "{" ) ) { // new sub group mSubGroups.emplace_back( lastToken ); if( !mSubGroups.back().Parse( data, false ) ) { return false; } } else if( token == CSTRING_VIEW( "[" ) ) { // new list mProperties.emplace_back( lastToken ); CGPProperty& list = mProperties.back(); while( true ) { token = GetToken( data, true, true ); if( token.empty() ) { return false; } if( token == CSTRING_VIEW( "]" ) ) { break; } list.AddValue( token ); } } else { // new value mProperties.emplace_back( lastToken, token ); } } }
//------------------------------------------------------ // ParseSpawnFlags // These kinds of flags control how things spawn. They // never get passed on to a primitive. // // input: // string that contains the flag strings // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseSpawnFlags( const gsl::cstring_view& val ) { std::array< gsl::cstring_view, 7 > flag; // For a primitive, really you probably only have two or less flags set const auto availableFlag = scanStrings( val, flag ); bool ok = true; for( auto& cur : availableFlag ) { static StringViewIMap< int > flagNames{ { CSTRING_VIEW( "org2fromTrace" ), FX_ORG2_FROM_TRACE }, { CSTRING_VIEW( "traceImpactFx" ), FX_TRACE_IMPACT_FX }, { CSTRING_VIEW( "org2isOffset" ), FX_ORG2_IS_OFFSET }, { CSTRING_VIEW( "cheapOrgCalc" ), FX_CHEAP_ORG_CALC }, { CSTRING_VIEW( "cheapOrg2Calc" ), FX_CHEAP_ORG2_CALC }, { CSTRING_VIEW( "absoluteVel" ), FX_VEL_IS_ABSOLUTE }, { CSTRING_VIEW( "absoluteAccel" ), FX_ACCEL_IS_ABSOLUTE }, { CSTRING_VIEW( "orgOnSphere" ), FX_ORG_ON_SPHERE }, { CSTRING_VIEW( "orgOnCylinder" ), FX_ORG_ON_CYLINDER }, { CSTRING_VIEW( "axisFromSphere" ), FX_AXIS_FROM_SPHERE }, { CSTRING_VIEW( "randrotaroundfwd" ), FX_RAND_ROT_AROUND_FWD }, { CSTRING_VIEW( "evenDistribution" ), FX_EVEN_DISTRIBUTION }, { CSTRING_VIEW( "rgbComponentInterpolation" ), FX_RGB_COMPONENT_INTERP }, { CSTRING_VIEW( "lessAttenuation" ), FX_SND_LESS_ATTENUATION }, }; auto pos = flagNames.find( cur ); if( pos == flagNames.end() ) { ok = false; } else { mSpawnFlags |= pos->second; } } return ok; }
//------------------------------------------------------ // ParseFlags // These are flags that are not specific to a group, // rather, they are specific to the whole primitive. // // input: // string that contains the flag strings // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseFlags( const gsl::cstring_view& val ) { // For a primitive, really you probably only have two or less flags set std::array< gsl::cstring_view, 7 > flag; const auto availableFlag = scanStrings( val, flag ); bool ok = true; for( auto& cur : availableFlag ) { static StringViewIMap< int > flagNames{ { CSTRING_VIEW( "useModel" ), FX_ATTACHED_MODEL }, { CSTRING_VIEW( "useBBox" ), FX_USE_BBOX }, { CSTRING_VIEW( "usePhysics" ), FX_APPLY_PHYSICS }, { CSTRING_VIEW( "expensivePhysics" ), FX_EXPENSIVE_PHYSICS }, //rww - begin g2 stuff { CSTRING_VIEW( "ghoul2Collision" ), ( FX_GHOUL2_TRACE | FX_APPLY_PHYSICS | FX_EXPENSIVE_PHYSICS ) }, { CSTRING_VIEW( "ghoul2Decals" ), FX_GHOUL2_DECALS }, //rww - end { CSTRING_VIEW( "impactKills" ), FX_KILL_ON_IMPACT }, { CSTRING_VIEW( "impactFx" ), FX_IMPACT_RUNS_FX }, { CSTRING_VIEW( "deathFx" ), FX_DEATH_RUNS_FX }, { CSTRING_VIEW( "useAlpha" ), FX_CLAMP }, { CSTRING_VIEW( "emitFx" ), FX_EMIT_FX }, { CSTRING_VIEW( "depthHack" ), FX_DEPTH_HACK }, { CSTRING_VIEW( "setShaderTime" ), FX_SET_SHADER_TIME }, }; auto pos = flagNames.find( cur ); if( pos == flagNames.end() ) { // we have badness going on, but continue on in case there are any valid fields in here ok = false; } else { mFlags |= pos->second; } } return ok; }
// 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; }