/* ================ idTypeInfoTools::VerifyVariable ================ */ void idTypeInfoTools::VerifyVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) { idToken token; if ( typeError ) { return; } src->SkipUntilString( "=" ); src->ExpectTokenType( TT_STRING, 0, &token ); if ( token.Cmp( value ) != 0 ) { // NOTE: skip several things if ( IsRenderHandleVariable( varName, varType, scope, prefix, postfix, value ) ) { return; } if ( IsAllowedToChangedFromSaveGames( varName, varType, scope, prefix, postfix, value ) ) { return; } src->Warning( "state diff for %s%s::%s%s\n%s\n%s", prefix, scope, varName, postfix, token.c_str(), value ); typeError = true; } }
/* ============ sdGUIDFile::ParseEntry ============ */ bool sdGUIDFile::ParseEntry( idLexer& src ) { // parse entry sdGUIDInfo newInfo; idDict data; if ( !data.Parse( src ) ) { return false; } idStr tempString; if ( data.GetString( "ip", "", tempString ) ) { int ip; if ( !IPForString( tempString.c_str(), ip ) ) { return false; } newInfo.SetIP( ip ); } else if ( data.GetString( "pbid", "", tempString ) ) { int pbguid; if ( !PBGUIDForString( tempString.c_str(), pbguid ) ) { return false; } newInfo.SetPBID( pbguid ); } else if ( data.GetString( "guid", "", tempString ) ) { sdNetClientId id; if ( !GUIDForString( tempString.c_str(), id ) ) { return false; } newInfo.SetGUID( id ); } newInfo.SetAuthGroup( data.GetString( "auth_group" ) ); const char* banText = data.GetString( "ban_time" ); if ( *banText != '\0' ) { if ( !idStr::Icmp( banText, "forever" ) ) { newInfo.BanForever(); } else { int t; sdProperties::sdFromString( t, banText ); newInfo.SetBanTime( t ); } } const char* userName = data.GetString( "user_name" ); if ( *userName != '\0' ) { newInfo.SetUserName( userName ); } if ( newInfo.GetMatchType() == sdGUIDInfo::MT_INVALID ) { src.Warning( "No match type specified" ); return true; } info.Alloc() = newInfo; return true; }
/* =============== idSoundShader::ParseShader =============== */ bool idSoundShader::ParseShader( idLexer &src ) { int i; idToken token; parms.minDistance = 1; parms.maxDistance = 10; parms.volume = 1; parms.shakes = 0; parms.soundShaderFlags = 0; parms.soundClass = 0; speakerMask = 0; altSound = NULL; for( i = 0; i < SOUND_MAX_LIST_WAVS; i++ ) { leadins[i] = NULL; entries[i] = NULL; } numEntries = 0; numLeadins = 0; int maxSamples = idSoundSystemLocal::s_maxSoundsPerShader.GetInteger(); if ( com_makingBuild.GetBool() || maxSamples <= 0 || maxSamples > SOUND_MAX_LIST_WAVS ) { maxSamples = SOUND_MAX_LIST_WAVS; } while ( 1 ) { if ( !src.ExpectAnyToken( &token ) ) { return false; } // end of definition else if ( token == "}" ) { break; } // minimum number of sounds else if ( !token.Icmp( "minSamples" ) ) { maxSamples = idMath::ClampInt( src.ParseInt(), SOUND_MAX_LIST_WAVS, maxSamples ); } // description else if ( !token.Icmp( "description" ) ) { src.ReadTokenOnLine( &token ); desc = token.c_str(); } // mindistance else if ( !token.Icmp( "mindistance" ) ) { parms.minDistance = src.ParseFloat(); } // maxdistance else if ( !token.Icmp( "maxdistance" ) ) { parms.maxDistance = src.ParseFloat(); } // shakes screen else if ( !token.Icmp( "shakes" ) ) { src.ExpectAnyToken( &token ); if ( token.type == TT_NUMBER ) { parms.shakes = token.GetFloatValue(); } else { src.UnreadToken( &token ); parms.shakes = 1.0f; } } // reverb else if ( !token.Icmp( "reverb" ) ) { int reg0 = src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { src.FreeSource(); return false; } int reg1 = src.ParseFloat(); // no longer supported } // volume else if ( !token.Icmp( "volume" ) ) { parms.volume = src.ParseFloat(); } // leadinVolume is used to allow light breaking leadin sounds to be much louder than the broken loop else if ( !token.Icmp( "leadinVolume" ) ) { leadinVolume = src.ParseFloat(); } // speaker mask else if ( !token.Icmp( "mask_center" ) ) { speakerMask |= 1<<SPEAKER_CENTER; } // speaker mask else if ( !token.Icmp( "mask_left" ) ) { speakerMask |= 1<<SPEAKER_LEFT; } // speaker mask else if ( !token.Icmp( "mask_right" ) ) { speakerMask |= 1<<SPEAKER_RIGHT; } // speaker mask else if ( !token.Icmp( "mask_backright" ) ) { speakerMask |= 1<<SPEAKER_BACKRIGHT; } // speaker mask else if ( !token.Icmp( "mask_backleft" ) ) { speakerMask |= 1<<SPEAKER_BACKLEFT; } // speaker mask else if ( !token.Icmp( "mask_lfe" ) ) { speakerMask |= 1<<SPEAKER_LFE; } // soundClass else if ( !token.Icmp( "soundClass" ) ) { parms.soundClass = src.ParseInt(); if ( parms.soundClass < 0 || parms.soundClass >= SOUND_MAX_CLASSES ) { src.Warning( "SoundClass out of range" ); return false; } } // altSound else if ( !token.Icmp( "altSound" ) ) { if ( !src.ExpectAnyToken( &token ) ) { return false; } altSound = declManager->FindSound( token.c_str() ); } // ordered else if ( !token.Icmp( "ordered" ) ) { // no longer supported } // no_dups else if ( !token.Icmp( "no_dups" ) ) { parms.soundShaderFlags |= SSF_NO_DUPS; } // no_flicker else if ( !token.Icmp( "no_flicker" ) ) { parms.soundShaderFlags |= SSF_NO_FLICKER; } // plain else if ( !token.Icmp( "plain" ) ) { // no longer supported } // looping else if ( !token.Icmp( "looping" ) ) { parms.soundShaderFlags |= SSF_LOOPING; } // no occlusion else if ( !token.Icmp( "no_occlusion" ) ) { parms.soundShaderFlags |= SSF_NO_OCCLUSION; } // private else if ( !token.Icmp( "private" ) ) { parms.soundShaderFlags |= SSF_PRIVATE_SOUND; } // antiPrivate else if ( !token.Icmp( "antiPrivate" ) ) { parms.soundShaderFlags |= SSF_ANTI_PRIVATE_SOUND; } // once else if ( !token.Icmp( "playonce" ) ) { parms.soundShaderFlags |= SSF_PLAY_ONCE; } // global else if ( !token.Icmp( "global" ) ) { parms.soundShaderFlags |= SSF_GLOBAL; } // unclamped else if ( !token.Icmp( "unclamped" ) ) { parms.soundShaderFlags |= SSF_UNCLAMPED; } // omnidirectional else if ( !token.Icmp( "omnidirectional" ) ) { parms.soundShaderFlags |= SSF_OMNIDIRECTIONAL; } // onDemand can't be a parms, because we must track all references and overrides would confuse it else if ( !token.Icmp( "onDemand" ) ) { // no longer loading sounds on demand //onDemand = true; } // the wave files else if ( !token.Icmp( "leadin" ) ) { // add to the leadin list if ( !src.ReadToken( &token ) ) { src.Warning( "Expected sound after leadin" ); return false; } if ( soundSystemLocal.soundCache && numLeadins < maxSamples ) { leadins[ numLeadins ] = soundSystemLocal.soundCache->FindSound( token.c_str(), onDemand ); numLeadins++; } } else if ( token.Find( ".wav", false ) != -1 || token.Find( ".ogg", false ) != -1 ) { // add to the wav list if ( soundSystemLocal.soundCache && numEntries < maxSamples ) { token.BackSlashesToSlashes(); idStr lang = cvarSystem->GetCVarString( "sys_lang" ); if ( lang.Icmp( "english" ) != 0 && token.Find( "sound/vo/", false ) >= 0 ) { idStr work = token; work.ToLower(); work.StripLeading( "sound/vo/" ); work = va( "sound/vo/%s/%s", lang.c_str(), work.c_str() ); if ( fileSystem->ReadFile( work, NULL, NULL ) > 0 ) { token = work; } else { // also try to find it with the .ogg extension work.SetFileExtension( ".ogg" ); if ( fileSystem->ReadFile( work, NULL, NULL ) > 0 ) { token = work; } } } entries[ numEntries ] = soundSystemLocal.soundCache->FindSound( token.c_str(), onDemand ); numEntries++; } } else { src.Warning( "unknown token '%s'", token.c_str() ); return false; } } if ( parms.shakes > 0.0f ) { CheckShakesAndOgg(); } return true; }
/* ==================== idMD5Mesh::ParseMesh ==================== */ void idMD5Mesh::ParseMesh( idLexer& parser, int numJoints, const idJointMat* joints ) { idToken token; idToken name; parser.ExpectTokenString( "{" ); // // parse name // if( parser.CheckTokenString( "name" ) ) { parser.ReadToken( &name ); } // // parse shader // parser.ExpectTokenString( "shader" ); parser.ReadToken( &token ); idStr shaderName = token; shader = declManager->FindMaterial( shaderName ); // // parse texture coordinates // parser.ExpectTokenString( "numverts" ); int count = parser.ParseInt(); if( count < 0 ) { parser.Error( "Invalid size: %s", token.c_str() ); } this->numVerts = count; idList<idVec2> texCoords; idList<int> firstWeightForVertex; idList<int> numWeightsForVertex; texCoords.SetNum( count ); firstWeightForVertex.SetNum( count ); numWeightsForVertex.SetNum( count ); int numWeights = 0; int maxweight = 0; for( int i = 0; i < texCoords.Num(); i++ ) { parser.ExpectTokenString( "vert" ); parser.ParseInt(); parser.Parse1DMatrix( 2, texCoords[ i ].ToFloatPtr() ); firstWeightForVertex[ i ] = parser.ParseInt(); numWeightsForVertex[ i ] = parser.ParseInt(); if( !numWeightsForVertex[ i ] ) { parser.Error( "Vertex without any joint weights." ); } numWeights += numWeightsForVertex[ i ]; if( numWeightsForVertex[ i ] + firstWeightForVertex[ i ] > maxweight ) { maxweight = numWeightsForVertex[ i ] + firstWeightForVertex[ i ]; } } // // parse tris // parser.ExpectTokenString( "numtris" ); count = parser.ParseInt(); if( count < 0 ) { parser.Error( "Invalid size: %d", count ); } idList<int> tris; tris.SetNum( count * 3 ); numTris = count; for( int i = 0; i < count; i++ ) { parser.ExpectTokenString( "tri" ); parser.ParseInt(); tris[ i * 3 + 0 ] = parser.ParseInt(); tris[ i * 3 + 1 ] = parser.ParseInt(); tris[ i * 3 + 2 ] = parser.ParseInt(); } // // parse weights // parser.ExpectTokenString( "numweights" ); count = parser.ParseInt(); if( count < 0 ) { parser.Error( "Invalid size: %d", count ); } if( maxweight > count ) { parser.Warning( "Vertices reference out of range weights in model (%d of %d weights).", maxweight, count ); } idList<vertexWeight_t> tempWeights; tempWeights.SetNum( count ); assert( numJoints < 256 ); // so we can pack into bytes for( int i = 0; i < count; i++ ) { parser.ExpectTokenString( "weight" ); parser.ParseInt(); int jointnum = parser.ParseInt(); if( ( jointnum < 0 ) || ( jointnum >= numJoints ) ) { parser.Error( "Joint Index out of range(%d): %d", numJoints, jointnum ); } tempWeights[ i ].joint = jointnum; tempWeights[ i ].jointWeight = parser.ParseFloat(); parser.Parse1DMatrix( 3, tempWeights[ i ].offset.ToFloatPtr() ); } // create pre-scaled weights and an index for the vertex/joint lookup idVec4* scaledWeights = ( idVec4* ) Mem_Alloc16( numWeights * sizeof( scaledWeights[0] ), TAG_MD5_WEIGHT ); int* weightIndex = ( int* ) Mem_Alloc16( numWeights * 2 * sizeof( weightIndex[0] ), TAG_MD5_INDEX ); memset( weightIndex, 0, numWeights * 2 * sizeof( weightIndex[0] ) ); count = 0; for( int i = 0; i < texCoords.Num(); i++ ) { int num = firstWeightForVertex[i]; for( int j = 0; j < numWeightsForVertex[i]; j++, num++, count++ ) { scaledWeights[count].ToVec3() = tempWeights[num].offset * tempWeights[num].jointWeight; scaledWeights[count].w = tempWeights[num].jointWeight; weightIndex[count * 2 + 0] = tempWeights[num].joint * sizeof( idJointMat ); } weightIndex[count * 2 - 1] = 1; } parser.ExpectTokenString( "}" ); // update counters c_numVerts += texCoords.Num(); c_numWeights += numWeights; c_numWeightJoints++; for( int i = 0; i < numWeights; i++ ) { c_numWeightJoints += weightIndex[i * 2 + 1]; } // // build a base pose that can be used for skinning // idDrawVert* basePose = ( idDrawVert* )Mem_ClearedAlloc( texCoords.Num() * sizeof( *basePose ), TAG_MD5_BASE ); for( int j = 0, i = 0; i < texCoords.Num(); i++ ) { idVec3 v = ( *( idJointMat* )( ( byte* )joints + weightIndex[j * 2 + 0] ) ) * scaledWeights[j]; while( weightIndex[j * 2 + 1] == 0 ) { j++; v += ( *( idJointMat* )( ( byte* )joints + weightIndex[j * 2 + 0] ) ) * scaledWeights[j]; } j++; basePose[i].Clear(); basePose[i].xyz = v; basePose[i].SetTexCoord( texCoords[i] ); } // build the weights and bone indexes into the verts, so they will be duplicated // as necessary at mirror seems static int maxWeightsPerVert; static float maxResidualWeight; const int MAX_VERTEX_WEIGHTS = 4; idList< bool > jointIsUsed; jointIsUsed.SetNum( numJoints ); for( int i = 0; i < jointIsUsed.Num(); i++ ) { jointIsUsed[i] = false; } numMeshJoints = 0; maxJointVertDist = 0.0f; //----------------------------------------- // new-style setup for fixed four weights and normal / tangent deformation // // Several important models have >25% residual weight in joints after the // first four, which is worrisome for using a fixed four joint deformation. //----------------------------------------- for( int i = 0; i < texCoords.Num(); i++ ) { idDrawVert& dv = basePose[i]; // some models do have >4 joint weights, so it is necessary to sort and renormalize // sort the weights and take the four largest int weights[256]; const int numWeights = numWeightsForVertex[ i ]; for( int j = 0; j < numWeights; j++ ) { weights[j] = firstWeightForVertex[i] + j; } // bubble sort for( int j = 0; j < numWeights; j++ ) { for( int k = 0; k < numWeights - 1 - j; k++ ) { if( tempWeights[weights[k]].jointWeight < tempWeights[weights[k + 1]].jointWeight ) { SwapValues( weights[k], weights[k + 1] ); } } } if( numWeights > maxWeightsPerVert ) { maxWeightsPerVert = numWeights; } const int usedWeights = Min( MAX_VERTEX_WEIGHTS, numWeights ); float totalWeight = 0; for( int j = 0; j < numWeights; j++ ) { totalWeight += tempWeights[weights[j]].jointWeight; } assert( totalWeight > 0.999f && totalWeight < 1.001f ); float usedWeight = 0; for( int j = 0; j < usedWeights; j++ ) { usedWeight += tempWeights[weights[j]].jointWeight; } const float residualWeight = totalWeight - usedWeight; if( residualWeight > maxResidualWeight ) { maxResidualWeight = residualWeight; } byte finalWeights[MAX_VERTEX_WEIGHTS] = { 0 }; byte finalJointIndecies[MAX_VERTEX_WEIGHTS] = { 0 }; for( int j = 0; j < usedWeights; j++ ) { const vertexWeight_t& weight = tempWeights[weights[j]]; const int jointIndex = weight.joint; const float fw = weight.jointWeight; assert( fw >= 0.0f && fw <= 1.0f ); const float normalizedWeight = fw / usedWeight; finalWeights[j] = idMath::Ftob( normalizedWeight * 255.0f ); finalJointIndecies[j] = jointIndex; } // Sort the weights and indices for hardware skinning for( int k = 0; k < 3; ++k ) { for( int l = k + 1; l < 4; ++l ) { if( finalWeights[l] > finalWeights[k] ) { SwapValues( finalWeights[k], finalWeights[l] ); SwapValues( finalJointIndecies[k], finalJointIndecies[l] ); } } } // Give any left over to the biggest weight finalWeights[0] += Max( 255 - finalWeights[0] - finalWeights[1] - finalWeights[2] - finalWeights[3], 0 ); dv.color[0] = finalJointIndecies[0]; dv.color[1] = finalJointIndecies[1]; dv.color[2] = finalJointIndecies[2]; dv.color[3] = finalJointIndecies[3]; dv.color2[0] = finalWeights[0]; dv.color2[1] = finalWeights[1]; dv.color2[2] = finalWeights[2]; dv.color2[3] = finalWeights[3]; for( int j = usedWeights; j < 4; j++ ) { assert( dv.color2[j] == 0 ); } for( int j = 0; j < usedWeights; j++ ) { if( !jointIsUsed[finalJointIndecies[j]] ) { jointIsUsed[finalJointIndecies[j]] = true; numMeshJoints++; } const idJointMat& joint = joints[finalJointIndecies[j]]; float dist = ( dv.xyz - joint.GetTranslation() ).Length(); if( dist > maxJointVertDist ) { maxJointVertDist = dist; } } } meshJoints = ( byte* ) Mem_Alloc( numMeshJoints * sizeof( meshJoints[0] ), TAG_MODEL ); numMeshJoints = 0; for( int i = 0; i < numJoints; i++ ) { if( jointIsUsed[i] ) { meshJoints[numMeshJoints++] = i; } } // build the deformInfo and collect a final base pose with the mirror // seam verts properly including the bone weights deformInfo = R_BuildDeformInfo( texCoords.Num(), basePose, tris.Num(), tris.Ptr(), shader->UseUnsmoothedTangents() ); for( int i = 0; i < deformInfo->numOutputVerts; i++ ) { for( int j = 0; j < 4; j++ ) { if( deformInfo->verts[i].color[j] >= numJoints ) { idLib::FatalError( "Bad joint index" ); } } } Mem_Free( basePose ); }
/* ================ idDeclFX::ParseSingleFXAction ================ */ void idDeclFX::ParseSingleFXAction( idLexer &src, idFXSingleAction& FXAction ) { idToken token; FXAction.type = -1; FXAction.sibling = -1; FXAction.data = "<none>"; FXAction.name = "<none>"; FXAction.fire = "<none>"; FXAction.delay = 0.0f; FXAction.duration = 0.0f; FXAction.restart = 0.0f; FXAction.size = 0.0f; FXAction.fadeInTime = 0.0f; FXAction.fadeOutTime = 0.0f; FXAction.shakeTime = 0.0f; FXAction.shakeAmplitude = 0.0f; FXAction.shakeDistance = 0.0f; FXAction.shakeFalloff = false; FXAction.shakeImpulse = 0.0f; FXAction.shakeIgnoreMaster = false; FXAction.lightRadius = 0.0f; FXAction.rotate = 0.0f; FXAction.random1 = 0.0f; FXAction.random2 = 0.0f; FXAction.lightColor = vec3_origin; FXAction.offset = vec3_origin; FXAction.axis = mat3_identity; FXAction.bindParticles = false; FXAction.explicitAxis = false; FXAction.noshadows = false; FXAction.particleTrackVelocity = false; FXAction.trackOrigin = false; FXAction.soundStarted = false; while (1) { if ( !src.ReadToken( &token ) ) { break; } if ( !token.Icmp( "}" ) ) { break; } if ( !token.Icmp( "shake" ) ) { FXAction.type = FX_SHAKE; FXAction.shakeTime = src.ParseFloat(); src.ExpectTokenString(","); FXAction.shakeAmplitude = src.ParseFloat(); src.ExpectTokenString(","); FXAction.shakeDistance = src.ParseFloat(); src.ExpectTokenString(","); FXAction.shakeFalloff = src.ParseBool(); src.ExpectTokenString(","); FXAction.shakeImpulse = src.ParseFloat(); continue; } if ( !token.Icmp( "noshadows" ) ) { FXAction.noshadows = true; continue; } if ( !token.Icmp( "name" ) ) { src.ReadToken( &token ); FXAction.name = token; continue; } if ( !token.Icmp( "fire") ) { src.ReadToken( &token ); FXAction.fire = token; continue; } if ( !token.Icmp( "random" ) ) { FXAction.random1 = src.ParseFloat(); src.ExpectTokenString( "," ); FXAction.random2 = src.ParseFloat(); FXAction.delay = 0.0f; // check random continue; } if ( !token.Icmp( "delay" ) ) { FXAction.delay = src.ParseFloat(); continue; } if ( !token.Icmp( "rotate" ) ) { FXAction.rotate = src.ParseFloat(); continue; } if ( !token.Icmp( "duration" ) ) { FXAction.duration = src.ParseFloat(); continue; } if ( !token.Icmp( "trackorigin" ) ) { FXAction.trackOrigin = src.ParseBool(); continue; } if (!token.Icmp("restart")) { FXAction.restart = src.ParseFloat(); continue; } if ( !token.Icmp( "fadeIn" ) ) { FXAction.fadeInTime = src.ParseFloat(); continue; } if ( !token.Icmp( "fadeOut" ) ) { FXAction.fadeOutTime = src.ParseFloat(); continue; } if ( !token.Icmp( "size" ) ) { FXAction.size = src.ParseFloat(); continue; } if ( !token.Icmp( "offset" ) ) { FXAction.offset.x = src.ParseFloat(); src.ExpectTokenString( "," ); FXAction.offset.y = src.ParseFloat(); src.ExpectTokenString( "," ); FXAction.offset.z = src.ParseFloat(); continue; } if ( !token.Icmp( "axis" ) ) { idVec3 v; v.x = src.ParseFloat(); src.ExpectTokenString( "," ); v.y = src.ParseFloat(); src.ExpectTokenString( "," ); v.z = src.ParseFloat(); v.Normalize(); FXAction.axis = v.ToMat3(); FXAction.explicitAxis = true; continue; } if ( !token.Icmp( "angle" ) ) { idAngles a; a[0] = src.ParseFloat(); src.ExpectTokenString( "," ); a[1] = src.ParseFloat(); src.ExpectTokenString( "," ); a[2] = src.ParseFloat(); FXAction.axis = a.ToMat3(); FXAction.explicitAxis = true; continue; } if ( !token.Icmp( "uselight" ) ) { src.ReadToken( &token ); FXAction.data = token; for( int i = 0; i < events.Num(); i++ ) { if ( events[i].name.Icmp( FXAction.data ) == 0 ) { FXAction.sibling = i; FXAction.lightColor = events[i].lightColor; FXAction.lightRadius = events[i].lightRadius; } } FXAction.type = FX_LIGHT; // precache the light material declManager->FindMaterial( FXAction.data ); continue; } if ( !token.Icmp( "attachlight" ) ) { src.ReadToken( &token ); FXAction.data = token; FXAction.type = FX_ATTACHLIGHT; // precache it declManager->FindMaterial( FXAction.data ); continue; } if ( !token.Icmp( "attachentity" ) ) { src.ReadToken( &token ); FXAction.data = token; FXAction.type = FX_ATTACHENTITY; // precache the model renderModelManager->FindModel( FXAction.data ); continue; } if ( !token.Icmp( "launch" ) ) { src.ReadToken( &token ); FXAction.data = token; FXAction.type = FX_LAUNCH; // precache the entity def declManager->FindType( DECL_ENTITYDEF, FXAction.data ); continue; } if ( !token.Icmp( "useModel" ) ) { src.ReadToken( &token ); FXAction.data = token; for( int i = 0; i < events.Num(); i++ ) { if ( events[i].name.Icmp( FXAction.data ) == 0 ) { FXAction.sibling = i; } } FXAction.type = FX_MODEL; // precache the model renderModelManager->FindModel( FXAction.data ); continue; } if ( !token.Icmp( "light" ) ) { src.ReadToken( &token ); FXAction.data = token; src.ExpectTokenString( "," ); FXAction.lightColor[0] = src.ParseFloat(); src.ExpectTokenString( "," ); FXAction.lightColor[1] = src.ParseFloat(); src.ExpectTokenString( "," ); FXAction.lightColor[2] = src.ParseFloat(); src.ExpectTokenString( "," ); FXAction.lightRadius = src.ParseFloat(); FXAction.type = FX_LIGHT; // precache the light material declManager->FindMaterial( FXAction.data ); continue; } if ( !token.Icmp( "model" ) ) { src.ReadToken( &token ); FXAction.data = token; FXAction.type = FX_MODEL; // precache it renderModelManager->FindModel( FXAction.data ); continue; } if ( !token.Icmp( "particle" ) ) { // FIXME: now the same as model src.ReadToken( &token ); FXAction.data = token; FXAction.type = FX_PARTICLE; // precache it renderModelManager->FindModel( FXAction.data ); continue; } if ( !token.Icmp( "decal" ) ) { src.ReadToken( &token ); FXAction.data = token; FXAction.type = FX_DECAL; // precache it declManager->FindMaterial( FXAction.data ); continue; } if ( !token.Icmp( "particleTrackVelocity" ) ) { FXAction.particleTrackVelocity = true; continue; } if ( !token.Icmp( "sound" ) ) { src.ReadToken( &token ); FXAction.data = token; FXAction.type = FX_SOUND; // precache it declManager->FindSound( FXAction.data ); continue; } if ( !token.Icmp( "ignoreMaster" ) ) { FXAction.shakeIgnoreMaster = true; continue; } if ( !token.Icmp( "shockwave" ) ) { src.ReadToken( &token ); FXAction.data = token; FXAction.type = FX_SHOCKWAVE; // precache the entity def declManager->FindType( DECL_ENTITYDEF, FXAction.data ); continue; } src.Warning( "FX File: bad token" ); continue; } }
/* ==================== idMD5Mesh::ParseMesh ==================== */ void idMD5Mesh::ParseMesh( idLexer &parser, int numJoints, const idJointMat *joints ) { idToken token; idToken name; int num; int count; int jointnum; idStr shaderName; int i, j; idList<int> tris; idList<int> firstWeightForVertex; idList<int> numWeightsForVertex; int maxweight; idList<vertexWeight_t> tempWeights; parser.ExpectTokenString( "{" ); // // parse name // if ( parser.CheckTokenString( "name" ) ) { parser.ReadToken( &name ); } // // parse shader // parser.ExpectTokenString( "shader" ); parser.ReadToken( &token ); shaderName = token; shader = declManager->FindMaterial( shaderName ); // // parse texture coordinates // parser.ExpectTokenString( "numverts" ); count = parser.ParseInt(); if ( count < 0 ) { parser.Error( "Invalid size: %s", token.c_str() ); } texCoords.SetNum( count ); firstWeightForVertex.SetNum( count ); numWeightsForVertex.SetNum( count ); numWeights = 0; maxweight = 0; for( i = 0; i < texCoords.Num(); i++ ) { parser.ExpectTokenString( "vert" ); parser.ParseInt(); parser.Parse1DMatrix( 2, texCoords[ i ].ToFloatPtr() ); firstWeightForVertex[ i ] = parser.ParseInt(); numWeightsForVertex[ i ] = parser.ParseInt(); if ( !numWeightsForVertex[ i ] ) { parser.Error( "Vertex without any joint weights." ); } numWeights += numWeightsForVertex[ i ]; if ( numWeightsForVertex[ i ] + firstWeightForVertex[ i ] > maxweight ) { maxweight = numWeightsForVertex[ i ] + firstWeightForVertex[ i ]; } } // // parse tris // parser.ExpectTokenString( "numtris" ); count = parser.ParseInt(); if ( count < 0 ) { parser.Error( "Invalid size: %d", count ); } tris.SetNum( count * 3 ); numTris = count; for( i = 0; i < count; i++ ) { parser.ExpectTokenString( "tri" ); parser.ParseInt(); tris[ i * 3 + 0 ] = parser.ParseInt(); tris[ i * 3 + 1 ] = parser.ParseInt(); tris[ i * 3 + 2 ] = parser.ParseInt(); } // // parse weights // parser.ExpectTokenString( "numweights" ); count = parser.ParseInt(); if ( count < 0 ) { parser.Error( "Invalid size: %d", count ); } if ( maxweight > count ) { parser.Warning( "Vertices reference out of range weights in model (%d of %d weights).", maxweight, count ); } tempWeights.SetNum( count ); for( i = 0; i < count; i++ ) { parser.ExpectTokenString( "weight" ); parser.ParseInt(); jointnum = parser.ParseInt(); if ( ( jointnum < 0 ) || ( jointnum >= numJoints ) ) { parser.Error( "Joint Index out of range(%d): %d", numJoints, jointnum ); } tempWeights[ i ].joint = jointnum; tempWeights[ i ].jointWeight = parser.ParseFloat(); parser.Parse1DMatrix( 3, tempWeights[ i ].offset.ToFloatPtr() ); } // create pre-scaled weights and an index for the vertex/joint lookup scaledWeights = (idVec4 *) Mem_Alloc16( numWeights * sizeof( scaledWeights[0] ) ); weightIndex = (int *) Mem_Alloc16( numWeights * 2 * sizeof( weightIndex[0] ) ); memset( weightIndex, 0, numWeights * 2 * sizeof( weightIndex[0] ) ); count = 0; for( i = 0; i < texCoords.Num(); i++ ) { num = firstWeightForVertex[i]; for( j = 0; j < numWeightsForVertex[i]; j++, num++, count++ ) { scaledWeights[count].ToVec3() = tempWeights[num].offset * tempWeights[num].jointWeight; scaledWeights[count].w = tempWeights[num].jointWeight; weightIndex[count * 2 + 0] = tempWeights[num].joint * sizeof( idJointMat ); } weightIndex[count * 2 - 1] = 1; } tempWeights.Clear(); numWeightsForVertex.Clear(); firstWeightForVertex.Clear(); parser.ExpectTokenString( "}" ); // update counters c_numVerts += texCoords.Num(); c_numWeights += numWeights; c_numWeightJoints++; for ( i = 0; i < numWeights; i++ ) { c_numWeightJoints += weightIndex[i*2+1]; } // // build the information that will be common to all animations of this mesh: // silhouette edge connectivity and normal / tangent generation information // idDrawVert *verts = (idDrawVert *) _alloca16( texCoords.Num() * sizeof( idDrawVert ) ); for ( i = 0; i < texCoords.Num(); i++ ) { verts[i].Clear(); verts[i].st = texCoords[i]; } TransformVerts( verts, joints ); deformInfo = R_BuildDeformInfo( texCoords.Num(), verts, tris.Num(), tris.Ptr(), shader->UseUnsmoothedTangents() ); }
/* =============== idSoundShader::ParseShader =============== */ bool idSoundShader::ParseShader( idLexer &src ) { idToken token; parms.minDistance = 1; parms.maxDistance = 10; parms.volume = 1; parms.shakes = 0; parms.soundShaderFlags = 0; parms.soundClass = 0; speakerMask = 0; altSound = NULL; entries.Clear(); while ( 1 ) { if ( !src.ExpectAnyToken( &token ) ) { return false; } // end of definition else if ( token == "}" ) { break; } // minimum number of sounds else if ( !token.Icmp( "minSamples" ) ) { src.ParseInt(); } // description else if ( !token.Icmp( "description" ) ) { src.ReadTokenOnLine( &token ); } // mindistance else if ( !token.Icmp( "mindistance" ) ) { parms.minDistance = src.ParseFloat(); } // maxdistance else if ( !token.Icmp( "maxdistance" ) ) { parms.maxDistance = src.ParseFloat(); } // shakes screen else if ( !token.Icmp( "shakes" ) ) { src.ExpectAnyToken( &token ); if ( token.type == TT_NUMBER ) { parms.shakes = token.GetFloatValue(); } else { src.UnreadToken( &token ); parms.shakes = 1.0f; } } // reverb else if ( !token.Icmp( "reverb" ) ) { src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { src.FreeSource(); return false; } src.ParseFloat(); // no longer supported } // volume else if ( !token.Icmp( "volume" ) ) { parms.volume = src.ParseFloat(); } // leadinVolume is used to allow light breaking leadin sounds to be much louder than the broken loop else if ( !token.Icmp( "leadinVolume" ) ) { leadinVolume = src.ParseFloat(); leadin = true; } // speaker mask else if ( !token.Icmp( "mask_center" ) ) { speakerMask |= 1<<SPEAKER_CENTER; } // speaker mask else if ( !token.Icmp( "mask_left" ) ) { speakerMask |= 1<<SPEAKER_LEFT; } // speaker mask else if ( !token.Icmp( "mask_right" ) ) { speakerMask |= 1<<SPEAKER_RIGHT; } // speaker mask else if ( !token.Icmp( "mask_backright" ) ) { speakerMask |= 1<<SPEAKER_BACKRIGHT; } // speaker mask else if ( !token.Icmp( "mask_backleft" ) ) { speakerMask |= 1<<SPEAKER_BACKLEFT; } // speaker mask else if ( !token.Icmp( "mask_lfe" ) ) { speakerMask |= 1<<SPEAKER_LFE; } // soundClass else if ( !token.Icmp( "soundClass" ) ) { parms.soundClass = src.ParseInt(); if ( parms.soundClass < 0 || parms.soundClass >= SOUND_MAX_CLASSES ) { src.Warning( "SoundClass out of range" ); return false; } } // altSound else if ( !token.Icmp( "altSound" ) ) { if ( !src.ExpectAnyToken( &token ) ) { return false; } altSound = declManager->FindSound( token.c_str() ); } // ordered else if ( !token.Icmp( "ordered" ) ) { // no longer supported } // no_dups else if ( !token.Icmp( "no_dups" ) ) { parms.soundShaderFlags |= SSF_NO_DUPS; } // no_flicker else if ( !token.Icmp( "no_flicker" ) ) { parms.soundShaderFlags |= SSF_NO_FLICKER; } // plain else if ( !token.Icmp( "plain" ) ) { // no longer supported } // looping else if ( !token.Icmp( "looping" ) ) { parms.soundShaderFlags |= SSF_LOOPING; } // no occlusion else if ( !token.Icmp( "no_occlusion" ) ) { parms.soundShaderFlags |= SSF_NO_OCCLUSION; } // private else if ( !token.Icmp( "private" ) ) { parms.soundShaderFlags |= SSF_PRIVATE_SOUND; } // antiPrivate else if ( !token.Icmp( "antiPrivate" ) ) { parms.soundShaderFlags |= SSF_ANTI_PRIVATE_SOUND; } // once else if ( !token.Icmp( "playonce" ) ) { parms.soundShaderFlags |= SSF_PLAY_ONCE; } // global else if ( !token.Icmp( "global" ) ) { parms.soundShaderFlags |= SSF_GLOBAL; } // unclamped else if ( !token.Icmp( "unclamped" ) ) { parms.soundShaderFlags |= SSF_UNCLAMPED; } // omnidirectional else if ( !token.Icmp( "omnidirectional" ) ) { parms.soundShaderFlags |= SSF_OMNIDIRECTIONAL; } else if ( !token.Icmp( "onDemand" ) ) { // no longer loading sounds on demand } // the wave files else if ( !token.Icmp( "leadin" ) ) { leadin = true; } else if ( token.Find( ".wav", false ) != -1 || token.Find( ".ogg", false ) != -1 ) { if ( token.IcmpPrefixPath( "sound/vo/" ) == 0 || token.IcmpPrefixPath( "sound/guis/" ) == 0 ) { parms.soundShaderFlags |= SSF_VO; } if ( token.IcmpPrefixPath( "sound/musical/" ) == 0 ) { parms.soundShaderFlags |= SSF_MUSIC; } // add to the wav list if ( s_maxSamples.GetInteger() == 0 || ( s_maxSamples.GetInteger() > 0 && entries.Num() < s_maxSamples.GetInteger() ) ) { entries.Append( soundSystemLocal.LoadSample( token.c_str() ) ); } } else { src.Warning( "unknown token '%s'", token.c_str() ); return false; } } return true; }
/* ================ idTypeInfoTools::CompareGameState ================ */ void idTypeInfoTools::CompareGameState( const char *fileName ) { int entityNum; idToken token; src = new idLexer(); src->SetFlags( LEXFL_NOSTRINGESCAPECHARS ); if ( !src->LoadFile( fileName ) ) { common->Warning( "couldn't load %s", fileName ); delete src; src = NULL; return; } fp = NULL; Write = VerifyVariable; #ifdef DUMP_GAMELOCAL if ( !src->ExpectTokenString( "gameLocal" ) || !src->ExpectTokenString( "{" ) ) { delete src; src = NULL; return; } WriteClass_r( (void *)&gameLocal, "", "idGameLocal", "idGameLocal", "", 0 ); if ( !src->ExpectTokenString( "}" ) ) { delete src; src = NULL; return; } #endif while( src->ReadToken( &token ) ) { if ( token != "entity" ) { break; } if ( !src->ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) { break; } entityNum = token.GetIntValue(); if ( entityNum < 0 || entityNum >= gameLocal.num_entities ) { src->Warning( "entity number %d out of range", entityNum ); break; } typeError = false; idEntity *ent = gameLocal.entities[entityNum]; if ( !ent ) { src->Warning( "entity %d is not spawned", entityNum ); src->SkipBracedSection( true ); continue; } if ( !src->ExpectTokenType( TT_NAME, 0, &token ) ) { break; } if ( token.Cmp( ent->GetType()->classname ) != 0 ) { src->Warning( "entity %d has wrong type", entityNum ); src->SkipBracedSection( true ); continue; } if ( !src->ExpectTokenString( "{" ) ) { src->Warning( "entity %d missing leading {", entityNum ); break; } WriteClass_r( (void *)ent, "", ent->GetType()->classname, ent->GetType()->classname, "", 0 ); if ( !src->SkipBracedSection( false ) ) { src->Warning( "entity %d missing trailing }", entityNum ); break; } } delete src; src = NULL; }