/* ================ idDeclParticle::ParseParametric ================ */ void idDeclParticle::ParseParametric( idLexer &src, idParticleParm *parm ) { idToken token; parm->table = NULL; parm->from = parm->to = 0.0f; if ( !src.ReadToken( &token ) ) { src.Error( "not enough parameters" ); return; } if ( token.IsNumeric() ) { // can have a to + 2nd parm parm->from = parm->to = atof( token ); if ( src.ReadToken( &token ) ) { if ( !token.Icmp( "to" ) ) { if ( !src.ReadToken( &token ) ) { src.Error( "missing second parameter" ); return; } parm->to = atof( token ); } else { src.UnreadToken( &token ); } } } else { // table parm->table = static_cast<const idDeclTable *>( declManager->FindType( DECL_TABLE, token, false ) ); } }
/* ==================== idModelExport::ParseOptions ==================== */ bool idModelExport::ParseOptions( idLexer &lex ) { idToken token; idStr destdir; idStr sourcedir; if ( !lex.ReadToken( &token ) ) { lex.Error( "Expected filename" ); return false; } src = token; dest = token; while( lex.ReadToken( &token ) ) { if ( token == "-" ) { if ( !lex.ReadToken( &token ) ) { lex.Error( "Expecting option" ); return false; } if ( token == "sourcedir" ) { if ( !lex.ReadToken( &token ) ) { lex.Error( "Missing pathname after -sourcedir" ); return false; } sourcedir = token; } else if ( token == "destdir" ) { if ( !lex.ReadToken( &token ) ) { lex.Error( "Missing pathname after -destdir" ); return false; } destdir = token; } else if ( token == "dest" ) { if ( !lex.ReadToken( &token ) ) { lex.Error( "Missing filename after -dest" ); return false; } dest = token; } else { commandLine += va( " -%s", token.c_str() ); } } else { commandLine += va( " %s", token.c_str() ); } } if ( sourcedir.Length() ) { src.StripPath(); sourcedir.BackSlashesToSlashes(); sprintf( src, "%s/%s", sourcedir.c_str(), src.c_str() ); } if ( destdir.Length() ) { dest.StripPath(); destdir.BackSlashesToSlashes(); sprintf( dest, "%s/%s", destdir.c_str(), dest.c_str() ); } return true; }
/* ================ idAFVector::Parse ================ */ bool idAFVector::Parse( idLexer &src ) { idToken token; if ( !src.ReadToken( &token ) ) { return false; } if ( token == "-" ) { negate = true; if ( !src.ReadToken( &token ) ) { return false; } } else { negate = false; } if ( token == "(" ) { type = idAFVector::VEC_COORDS; vec.x = src.ParseFloat(); src.ExpectTokenString( "," ); vec.y = src.ParseFloat(); src.ExpectTokenString( "," ); vec.z = src.ParseFloat(); src.ExpectTokenString( ")" ); } else if ( token == "joint" ) { type = idAFVector::VEC_JOINT; src.ExpectTokenString( "(" ); src.ReadToken( &token ); joint1 = token; src.ExpectTokenString( ")" ); } else if ( token == "bonecenter" ) { type = idAFVector::VEC_BONECENTER; src.ExpectTokenString( "(" ); src.ReadToken( &token ); joint1 = token; src.ExpectTokenString( "," ); src.ReadToken( &token ); joint2 = token; src.ExpectTokenString( ")" ); } else if ( token == "bonedir" ) { type = idAFVector::VEC_BONEDIR; src.ExpectTokenString( "(" ); src.ReadToken( &token ); joint1 = token; src.ExpectTokenString( "," ); src.ReadToken( &token ); joint2 = token; src.ExpectTokenString( ")" ); } else { src.Error( "unknown token %s in vector", token.c_str() ); return false; } return true; }
/* ==================== idRenderModelMD5::ParseJoint ==================== */ void idRenderModelMD5::ParseJoint( idLexer& parser, idMD5Joint* joint, idJointQuat* defaultPose ) { // // parse name // idToken token; parser.ReadToken( &token ); joint->name = token; // // parse parent // int num = parser.ParseInt(); if( num < 0 ) { joint->parent = NULL; } else { if( num >= joints.Num() - 1 ) { parser.Error( "Invalid parent for joint '%s'", joint->name.c_str() ); } joint->parent = &joints[ num ]; } // // parse default pose // parser.Parse1DMatrix( 3, defaultPose->t.ToFloatPtr() ); parser.Parse1DMatrix( 3, defaultPose->q.ToFloatPtr() ); defaultPose->q.w = defaultPose->q.CalcW(); }
/* ================ idDeclAF::ParseFixed ================ */ bool idDeclAF::ParseFixed( idLexer &src ) { idToken token; idDeclAF_Constraint *constraint = new idDeclAF_Constraint; constraint->SetDefault( this ); constraints.Alloc() = constraint; if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || !src.ExpectTokenString( "{" ) ) { return false; } constraint->type = DECLAF_CONSTRAINT_FIXED; constraint->name = token; while( src.ReadToken( &token ) ) { if ( !token.Icmp( "body1" ) ) { src.ExpectTokenType( TT_STRING, 0, &token ); constraint->body1 = token; } else if ( !token.Icmp( "body2" ) ) { src.ExpectTokenType( TT_STRING, 0, &token ); constraint->body2 = token; } else if ( token == "}" ) { break; } else { src.Error( "unknown token %s in ball and socket joint", token.c_str() ); return false; } } return true; }
/* ================ idDeclAF::ParseHinge ================ */ bool idDeclAF::ParseHinge( idLexer &src ) { idToken token; idDeclAF_Constraint *constraint = new idDeclAF_Constraint; constraint->SetDefault( this ); constraints.Alloc() = constraint; if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || !src.ExpectTokenString( "{" ) ) { return false; } constraint->type = DECLAF_CONSTRAINT_HINGE; constraint->limit = idDeclAF_Constraint::LIMIT_NONE; constraint->name = token; constraint->friction = 0.5f; constraint->anchor.ToVec3().Zero(); constraint->axis.ToVec3().Zero(); while( src.ReadToken( &token ) ) { if ( !token.Icmp( "body1" ) ) { src.ExpectTokenType( TT_STRING, 0, &token ); constraint->body1 = token; } else if ( !token.Icmp( "body2" ) ) { src.ExpectTokenType( TT_STRING, 0, &token ); constraint->body2 = token; } else if ( !token.Icmp( "anchor" ) ) { if ( !constraint->anchor.Parse( src ) ) { return false; } } else if ( !token.Icmp( "axis" ) ) { if ( !constraint->axis.Parse( src ) ) { return false; } } else if ( !token.Icmp( "limit" ) ) { constraint->limitAngles[0] = src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { return false; } constraint->limitAngles[1] = src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { return false; } constraint->limitAngles[2] = src.ParseFloat(); constraint->limit = idDeclAF_Constraint::LIMIT_CONE; } else if ( !token.Icmp( "friction" ) ) { constraint->friction = src.ParseFloat(); } else if ( token == "}" ) { break; } else { src.Error( "unknown token %s in hinge", token.c_str() ); return false; } } return true; }
/* ================ idDeclAF::ParseSpring ================ */ bool idDeclAF::ParseSpring( idLexer &src ) { idToken token; idDeclAF_Constraint *constraint = new idDeclAF_Constraint; constraint->SetDefault( this ); constraints.Alloc() = constraint; if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || !src.ExpectTokenString( "{" ) ) { return false; } constraint->type = DECLAF_CONSTRAINT_SPRING; constraint->limit = idDeclAF_Constraint::LIMIT_NONE; constraint->name = token; constraint->friction = 0.5f; while( src.ReadToken( &token ) ) { if ( !token.Icmp( "body1" ) ) { src.ExpectTokenType( TT_STRING, 0, &token ); constraint->body1 = token; } else if ( !token.Icmp( "body2" ) ) { src.ExpectTokenType( TT_STRING, 0, &token ); constraint->body2 = token; } else if ( !token.Icmp( "anchor1" ) ) { if ( !constraint->anchor.Parse( src ) ) { return false; } } else if ( !token.Icmp( "anchor2" ) ) { if ( !constraint->anchor2.Parse( src ) ) { return false; } } else if ( !token.Icmp( "friction" ) ) { constraint->friction = src.ParseFloat(); } else if ( !token.Icmp( "stretch" ) ) { constraint->stretch = src.ParseFloat(); } else if ( !token.Icmp( "compress" ) ) { constraint->compress = src.ParseFloat(); } else if ( !token.Icmp( "damping" ) ) { constraint->damping = src.ParseFloat(); } else if ( !token.Icmp( "restLength" ) ) { constraint->restLength = src.ParseFloat(); } else if ( !token.Icmp( "minLength" ) ) { constraint->minLength = src.ParseFloat(); } else if ( !token.Icmp( "maxLength" ) ) { constraint->maxLength = src.ParseFloat(); } else if ( token == "}" ) { break; } else { src.Error( "unknown token %s in spring", token.c_str() ); return false; } } return true; }
/* ================ idDeclAF::ParseSlider ================ */ bool idDeclAF::ParseSlider( idLexer& src ) { idToken token; idDeclAF_Constraint* constraint = new( TAG_DECL ) idDeclAF_Constraint; constraint->SetDefault( this ); constraints.Alloc() = constraint; if( !src.ExpectTokenType( TT_STRING, 0, &token ) || !src.ExpectTokenString( "{" ) ) { return false; } constraint->type = DECLAF_CONSTRAINT_SLIDER; constraint->limit = idDeclAF_Constraint::LIMIT_NONE; constraint->name = token; constraint->friction = 0.5f; while( src.ReadToken( &token ) ) { if( !token.Icmp( "body1" ) ) { src.ExpectTokenType( TT_STRING, 0, &token ); constraint->body1 = token; } else if( !token.Icmp( "body2" ) ) { src.ExpectTokenType( TT_STRING, 0, &token ); constraint->body2 = token; } else if( !token.Icmp( "axis" ) ) { if( !constraint->axis.Parse( src ) ) { return false; } } else if( !token.Icmp( "friction" ) ) { constraint->friction = src.ParseFloat(); } else if( token == "}" ) { break; } else { src.Error( "unknown token %s in slider", token.c_str() ); return false; } } return true; }
/* ================ idDeclParticle::ParseParms Parses a variable length list of parms on one line ================ */ void idDeclParticle::ParseParms( idLexer &src, float *parms, int maxParms ) { idToken token; memset( parms, 0, maxParms * sizeof( *parms ) ); int count = 0; while( 1 ) { if ( !src.ReadTokenOnLine( &token ) ) { return; } if ( count == maxParms ) { src.Error( "too many parms on line" ); return; } token.StripQuotes(); parms[count] = atof( token ); count++; } }
/* ================ idDeclAF::ParseBody ================ */ bool idDeclAF::ParseBody( idLexer &src ) { bool hasJoint = false; idToken token; idAFVector angles; idDeclAF_Body *body = new idDeclAF_Body; bodies.Alloc() = body; body->SetDefault( this ); if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || !src.ExpectTokenString( "{" ) ) { return false; } body->name = token; if ( !body->name.Icmp( "origin" ) || !body->name.Icmp( "world" ) ) { src.Error( "a body may not be named \"origin\" or \"world\"" ); return false; } while( src.ReadToken( &token ) ) { if ( !token.Icmp( "model" ) ) { if ( !src.ExpectTokenType( TT_NAME, 0, &token ) ) { return false; } if ( !token.Icmp( "box" ) ) { body->modelType = TRM_BOX; if ( !src.ExpectTokenString( "(" ) || !body->v1.Parse( src ) || !src.ExpectTokenString( "," ) || !body->v2.Parse( src ) || !src.ExpectTokenString( ")" ) ) { return false; } } else if ( !token.Icmp( "octahedron" ) ) { body->modelType = TRM_OCTAHEDRON; if ( !src.ExpectTokenString( "(" ) || !body->v1.Parse( src ) || !src.ExpectTokenString( "," ) || !body->v2.Parse( src ) || !src.ExpectTokenString( ")" ) ) { return false; } } else if ( !token.Icmp( "dodecahedron" ) ) { body->modelType = TRM_DODECAHEDRON; if ( !src.ExpectTokenString( "(" ) || !body->v1.Parse( src ) || !src.ExpectTokenString( "," ) || !body->v2.Parse( src ) || !src.ExpectTokenString( ")" ) ) { return false; } } else if ( !token.Icmp( "cylinder" ) ) { body->modelType = TRM_CYLINDER; if ( !src.ExpectTokenString( "(" ) || !body->v1.Parse( src ) || !src.ExpectTokenString( "," ) || !body->v2.Parse( src ) || !src.ExpectTokenString( "," ) ) { return false; } body->numSides = src.ParseInt(); if ( !src.ExpectTokenString( ")" ) ) { return false; } } else if ( !token.Icmp( "cone" ) ) { body->modelType = TRM_CONE; if ( !src.ExpectTokenString( "(" ) || !body->v1.Parse( src ) || !src.ExpectTokenString( "," ) || !body->v2.Parse( src ) || !src.ExpectTokenString( "," ) ) { return false; } body->numSides = src.ParseInt(); if ( !src.ExpectTokenString( ")" ) ) { return false; } } else if ( !token.Icmp( "bone" ) ) { body->modelType = TRM_BONE; if ( !src.ExpectTokenString( "(" ) || !body->v1.Parse( src ) || !src.ExpectTokenString( "," ) || !body->v2.Parse( src ) || !src.ExpectTokenString( "," ) ) { return false; } body->width = src.ParseFloat(); if ( !src.ExpectTokenString( ")" ) ) { return false; } } else if ( !token.Icmp( "custom" ) ) { src.Error( "custom models not yet implemented" ); return false; } else { src.Error( "unkown model type %s", token.c_str() ); return false; } } else if ( !token.Icmp( "origin" ) ) { if ( !body->origin.Parse( src ) ) { return false; } } else if ( !token.Icmp( "angles" ) ) { if ( !angles.Parse( src ) ) { return false; } body->angles = idAngles( angles.ToVec3().x, angles.ToVec3().y, angles.ToVec3().z ); } else if ( !token.Icmp( "joint" ) ) { if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { return false; } body->jointName = token; hasJoint = true; } else if ( !token.Icmp( "mod" ) ) { if ( !src.ExpectAnyToken( &token ) ) { return false; } body->jointMod = JointModFromString( token.c_str() ); } else if ( !token.Icmp( "density" ) ) { body->density = src.ParseFloat(); } else if ( !token.Icmp( "inertiaScale" ) ) { src.Parse1DMatrix( 9, body->inertiaScale[0].ToFloatPtr() ); } else if ( !token.Icmp( "friction" ) ) { body->linearFriction = src.ParseFloat(); src.ExpectTokenString( "," ); body->angularFriction = src.ParseFloat(); src.ExpectTokenString( "," ); body->contactFriction = src.ParseFloat(); } else if ( !token.Icmp( "contents" ) ) { ParseContents( src, body->contents ); } else if ( !token.Icmp( "clipMask" ) ) { ParseContents( src, body->clipMask ); } else if ( !token.Icmp( "selfCollision" ) ) { body->selfCollision = src.ParseBool(); } else if ( !token.Icmp( "containedjoints" ) ) { if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { return false; } body->containedJoints = token; } else if ( !token.Icmp( "frictionDirection" ) ) { if ( !body->frictionDirection.Parse( src ) ) { return false; } } else if ( !token.Icmp( "contactMotorDirection" ) ) { if ( !body->contactMotorDirection.Parse( src ) ) { return false; } } else if ( token == "}" ) { break; } else { src.Error( "unknown token %s in body", token.c_str() ); return false; } } if ( body->modelType == TRM_INVALID ) { src.Error( "no model set for body" ); return false; } if ( !hasJoint ) { src.Error( "no joint set for body" ); return false; } body->clipMask |= CONTENTS_MOVEABLECLIP; return true; }
/* ================ idDeclAF::ParseSettings ================ */ bool idDeclAF::ParseSettings( idLexer &src ) { idToken token; if ( !src.ExpectTokenString( "{" ) ) { return false; } while( src.ReadToken( &token ) ) { if ( !token.Icmp( "mesh" ) ) { if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { return false; } } else if ( !token.Icmp( "anim" ) ) { if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { return false; } } else if ( !token.Icmp( "model" ) ) { if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { return false; } model = token; } else if ( !token.Icmp( "skin" ) ) { if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { return false; } skin = token; } else if ( !token.Icmp( "friction" ) ) { defaultLinearFriction = src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { return false; } defaultAngularFriction = src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { return false; } defaultContactFriction = src.ParseFloat(); if ( src.CheckTokenString( "," ) ) { defaultConstraintFriction = src.ParseFloat(); } } else if ( !token.Icmp( "totalMass" ) ) { totalMass = src.ParseFloat(); } else if ( !token.Icmp( "suspendSpeed" ) ) { suspendVelocity[0] = src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { return false; } suspendVelocity[1] = src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { return false; } suspendAcceleration[0] = src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { return false; } suspendAcceleration[1] = src.ParseFloat(); } else if ( !token.Icmp( "noMoveTime" ) ) { noMoveTime = src.ParseFloat(); } else if ( !token.Icmp( "noMoveTranslation" ) ) { noMoveTranslation = src.ParseFloat(); } else if ( !token.Icmp( "noMoveRotation" ) ) { noMoveRotation = src.ParseFloat(); } else if ( !token.Icmp( "minMoveTime" ) ) { minMoveTime = src.ParseFloat(); } else if ( !token.Icmp( "maxMoveTime" ) ) { maxMoveTime = src.ParseFloat(); } else if ( !token.Icmp( "contents" ) ) { ParseContents( src, contents ); } else if ( !token.Icmp( "clipMask" ) ) { ParseContents( src, clipMask ); } else if ( !token.Icmp( "selfCollision" ) ) { selfCollision = src.ParseBool(); } else if ( token == "}" ) { break; } else { src.Error( "unknown token %s in settings", token.c_str() ); return false; } } return true; }
/* ================ idDeclAF::ParseUniversalJoint ================ */ bool idDeclAF::ParseUniversalJoint( idLexer &src ) { idToken token; idDeclAF_Constraint *constraint = new idDeclAF_Constraint; constraint->SetDefault( this ); constraints.Alloc() = constraint; if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || !src.ExpectTokenString( "{" ) ) { return false; } constraint->type = DECLAF_CONSTRAINT_UNIVERSALJOINT; constraint->limit = idDeclAF_Constraint::LIMIT_NONE; constraint->name = token; constraint->friction = 0.5f; constraint->anchor.ToVec3().Zero(); constraint->shaft[0].ToVec3().Zero(); constraint->shaft[1].ToVec3().Zero(); while( src.ReadToken( &token ) ) { if ( !token.Icmp( "body1" ) ) { src.ExpectTokenType( TT_STRING, 0, &token ); constraint->body1 = token; } else if ( !token.Icmp( "body2" ) ) { src.ExpectTokenType( TT_STRING, 0, &token ); constraint->body2 = token; } else if ( !token.Icmp( "anchor" ) ) { if ( !constraint->anchor.Parse( src ) ) { return false; } } else if ( !token.Icmp( "shafts" ) ) { if ( !constraint->shaft[0].Parse( src ) || !src.ExpectTokenString( "," ) || !constraint->shaft[1].Parse( src ) ) { return false; } } else if ( !token.Icmp( "conelimit" ) ) { if ( !constraint->limitAxis.Parse( src ) || !src.ExpectTokenString( "," ) ) { return false; } constraint->limitAngles[0] = src.ParseFloat(); constraint->limit = idDeclAF_Constraint::LIMIT_CONE; } else if ( !token.Icmp( "pyramidlimit" ) ) { if ( !constraint->limitAxis.Parse( src ) || !src.ExpectTokenString( "," ) ) { return false; } constraint->limitAngles[0] = src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { return false; } constraint->limitAngles[1] = src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { return false; } constraint->limitAngles[2] = src.ParseFloat(); constraint->limit = idDeclAF_Constraint::LIMIT_PYRAMID; } else if ( !token.Icmp( "friction" ) ) { constraint->friction = src.ParseFloat(); } else if ( token == "}" ) { break; } else { src.Error( "unknown token %s in universal joint", token.c_str() ); return false; } } 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 ); }
/* ==================== 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() ); }
/* ============ idAASSettings::FromParser ============ */ bool idAASSettings::FromParser( idLexer &src ) { idToken token; if ( !src.ExpectTokenString( "{" ) ) { return false; } // parse the file while ( 1 ) { if ( !src.ReadToken( &token ) ) { break; } if ( token == "}" ) { break; } if ( token == "bboxes" ) { if ( !ParseBBoxes( src ) ) { return false; } } else if ( token == "usePatches" ) { if ( !ParseBool( src, usePatches ) ) { return false; } } else if ( token == "writeBrushMap" ) { if ( !ParseBool( src, writeBrushMap ) ) { return false; } } else if ( token == "playerFlood" ) { if ( !ParseBool( src, playerFlood ) ) { return false; } } else if ( token == "allowSwimReachabilities" ) { if ( !ParseBool( src, allowSwimReachabilities ) ) { return false; } } else if ( token == "allowFlyReachabilities" ) { if ( !ParseBool( src, allowFlyReachabilities ) ) { return false; } } else if ( token == "fileExtension" ) { src.ExpectTokenString( "=" ); src.ExpectTokenType( TT_STRING, 0, &token ); fileExtension = token; } else if ( token == "gravity" ) { ParseVector( src, gravity ); gravityDir = gravity; gravityValue = gravityDir.Normalize(); invGravityDir = -gravityDir; } else if ( token == "maxStepHeight" ) { if ( !ParseFloat( src, maxStepHeight ) ) { return false; } } else if ( token == "maxBarrierHeight" ) { if ( !ParseFloat( src, maxBarrierHeight ) ) { return false; } } else if ( token == "maxWaterJumpHeight" ) { if ( !ParseFloat( src, maxWaterJumpHeight ) ) { return false; } } else if ( token == "maxFallHeight" ) { if ( !ParseFloat( src, maxFallHeight ) ) { return false; } } else if ( token == "minFloorCos" ) { if ( !ParseFloat( src, minFloorCos ) ) { return false; } } else if ( token == "tt_barrierJump" ) { if ( !ParseInt( src, tt_barrierJump ) ) { return false; } } else if ( token == "tt_startCrouching" ) { if ( !ParseInt( src, tt_startCrouching ) ) { return false; } } else if ( token == "tt_waterJump" ) { if ( !ParseInt( src, tt_waterJump ) ) { return false; } } else if ( token == "tt_startWalkOffLedge" ) { if ( !ParseInt( src, tt_startWalkOffLedge ) ) { return false; } } else { src.Error( "invalid token '%s'", token.c_str() ); } } if ( numBoundingBoxes <= 0 ) { src.Error( "no valid bounding box" ); } return true; }
bool idEFXFile::ReadEffect( idLexer &src, idSoundEffect *effect ) { idToken name, token; if ( !src.ReadToken( &token ) ) return false; // reverb effect if ( token != "reverb" ) { // other effect (not supported at the moment) src.Error( "idEFXFile::ReadEffect: Unknown effect definition" ); return false; } src.ReadTokenOnLine( &token ); name = token; if ( !src.ReadToken( &token ) ) return false; if ( token != "{" ) { src.Error( "idEFXFile::ReadEffect: { not found, found %s", token.c_str() ); return false; } ALenum err; alGetError(); EFXprintf("Loading EFX effect '%s' (#%u)\n", name.c_str(), effect->effect); do { if ( !src.ReadToken( &token ) ) { src.Error( "idEFXFile::ReadEffect: EOF without closing brace" ); return false; } if ( token == "}" ) { effect->name = name; break; } if ( token == "environment" ) { // <+KittyCat> the "environment" token should be ignored (efx has nothing equatable to it) src.ParseInt(); } else if ( token == "environment size" ) { float size = src.ParseFloat(); efxf(AL_EAXREVERB_DENSITY, (size < 2.0f) ? (size - 1.0f) : 1.0f); } else if ( token == "environment diffusion" ) { efxf(AL_EAXREVERB_DIFFUSION, src.ParseFloat()); } else if ( token == "room" ) { efxf(AL_EAXREVERB_GAIN, mB_to_gain(src.ParseInt(), GAIN)); } else if ( token == "room hf" ) { efxf(AL_EAXREVERB_GAINHF, mB_to_gain(src.ParseInt(), GAINHF)); } else if ( token == "room lf" ) { efxf(AL_EAXREVERB_GAINLF, mB_to_gain(src.ParseInt(), GAINLF)); } else if ( token == "decay time" ) { efxf(AL_EAXREVERB_DECAY_TIME, src.ParseFloat()); } else if ( token == "decay hf ratio" ) { efxf(AL_EAXREVERB_DECAY_HFRATIO, src.ParseFloat()); } else if ( token == "decay lf ratio" ) { efxf(AL_EAXREVERB_DECAY_LFRATIO, src.ParseFloat()); } else if ( token == "reflections" ) { efxf(AL_EAXREVERB_REFLECTIONS_GAIN, mB_to_gain(src.ParseInt(), REFLECTIONS_GAIN)); } else if ( token == "reflections delay" ) { efxf(AL_EAXREVERB_REFLECTIONS_DELAY, src.ParseFloat()); } else if ( token == "reflections pan" ) { efxfv(AL_EAXREVERB_REFLECTIONS_PAN, src.ParseFloat(), src.ParseFloat(), src.ParseFloat()); } else if ( token == "reverb" ) { efxf(AL_EAXREVERB_LATE_REVERB_GAIN, mB_to_gain(src.ParseInt(), LATE_REVERB_GAIN)); } else if ( token == "reverb delay" ) { efxf(AL_EAXREVERB_LATE_REVERB_DELAY, src.ParseFloat()); } else if ( token == "reverb pan" ) { efxfv(AL_EAXREVERB_LATE_REVERB_PAN, src.ParseFloat(), src.ParseFloat(), src.ParseFloat()); } else if ( token == "echo time" ) { efxf(AL_EAXREVERB_ECHO_TIME, src.ParseFloat()); } else if ( token == "echo depth" ) { efxf(AL_EAXREVERB_ECHO_DEPTH, src.ParseFloat()); } else if ( token == "modulation time" ) { efxf(AL_EAXREVERB_MODULATION_TIME, src.ParseFloat()); } else if ( token == "modulation depth" ) { efxf(AL_EAXREVERB_MODULATION_DEPTH, src.ParseFloat()); } else if ( token == "air absorption hf" ) { efxf(AL_EAXREVERB_AIR_ABSORPTION_GAINHF, mB_to_gain(src.ParseFloat(), AIR_ABSORPTION_GAINHF)); } else if ( token == "hf reference" ) { efxf(AL_EAXREVERB_HFREFERENCE, src.ParseFloat()); } else if ( token == "lf reference" ) { efxf(AL_EAXREVERB_LFREFERENCE, src.ParseFloat()); } else if ( token == "room rolloff factor" ) { efxf(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, src.ParseFloat()); } else if ( token == "flags" ) { src.ReadTokenOnLine( &token ); unsigned int flags = token.GetUnsignedLongValue(); efxi(AL_EAXREVERB_DECAY_HFLIMIT, (flags & 0x20) ? AL_TRUE : AL_FALSE); // the other SCALE flags have no equivalent in efx } else { src.ReadTokenOnLine( &token ); src.Error( "idEFXFile::ReadEffect: Invalid parameter in reverb definition" ); } } while ( 1 ); return true; }
/* =============== idEFXFile::ReadEffect =============== */ bool idEFXFile::ReadEffect( idLexer &src, idSoundEffect *effect ) { idToken name, token; if ( !src.ReadToken( &token ) ) return false; // reverb effect if ( token == "reverb" ) { EAXREVERBPROPERTIES *reverb = ( EAXREVERBPROPERTIES * )Mem_Alloc( sizeof( EAXREVERBPROPERTIES ) ); if ( reverb ) { src.ReadTokenOnLine( &token ); name = token; if ( !src.ReadToken( &token ) ) { Mem_Free( reverb ); return false; } if ( token != "{" ) { src.Error( "idEFXFile::ReadEffect: { not found, found %s", token.c_str() ); Mem_Free( reverb ); return false; } do { if ( !src.ReadToken( &token ) ) { src.Error( "idEFXFile::ReadEffect: EOF without closing brace" ); Mem_Free( reverb ); return false; } if ( token == "}" ) { effect->name = name; effect->data = ( void * )reverb; effect->datasize = sizeof( EAXREVERBPROPERTIES ); break; } if ( token == "environment" ) { src.ReadTokenOnLine( &token ); reverb->ulEnvironment = token.GetUnsignedIntValue(); } else if ( token == "environment size" ) { reverb->flEnvironmentSize = src.ParseFloat(); } else if ( token == "environment diffusion" ) { reverb->flEnvironmentDiffusion = src.ParseFloat(); } else if ( token == "room" ) { reverb->lRoom = src.ParseInt(); } else if ( token == "room hf" ) { reverb->lRoomHF = src.ParseInt(); } else if ( token == "room lf" ) { reverb->lRoomLF = src.ParseInt(); } else if ( token == "decay time" ) { reverb->flDecayTime = src.ParseFloat(); } else if ( token == "decay hf ratio" ) { reverb->flDecayHFRatio = src.ParseFloat(); } else if ( token == "decay lf ratio" ) { reverb->flDecayLFRatio = src.ParseFloat(); } else if ( token == "reflections" ) { reverb->lReflections = src.ParseInt(); } else if ( token == "reflections delay" ) { reverb->flReflectionsDelay = src.ParseFloat(); } else if ( token == "reflections pan" ) { reverb->vReflectionsPan.x = src.ParseFloat(); reverb->vReflectionsPan.y = src.ParseFloat(); reverb->vReflectionsPan.z = src.ParseFloat(); } else if ( token == "reverb" ) { reverb->lReverb = src.ParseInt(); } else if ( token == "reverb delay" ) { reverb->flReverbDelay = src.ParseFloat(); } else if ( token == "reverb pan" ) { reverb->vReverbPan.x = src.ParseFloat(); reverb->vReverbPan.y = src.ParseFloat(); reverb->vReverbPan.z = src.ParseFloat(); } else if ( token == "echo time" ) { reverb->flEchoTime = src.ParseFloat(); } else if ( token == "echo depth" ) { reverb->flEchoDepth = src.ParseFloat(); } else if ( token == "modulation time" ) { reverb->flModulationTime = src.ParseFloat(); } else if ( token == "modulation depth" ) { reverb->flModulationDepth = src.ParseFloat(); } else if ( token == "air absorption hf" ) { reverb->flAirAbsorptionHF = src.ParseFloat(); } else if ( token == "hf reference" ) { reverb->flHFReference = src.ParseFloat(); } else if ( token == "lf reference" ) { reverb->flLFReference = src.ParseFloat(); } else if ( token == "room rolloff factor" ) { reverb->flRoomRolloffFactor = src.ParseFloat(); } else if ( token == "flags" ) { src.ReadTokenOnLine( &token ); reverb->ulFlags = token.GetUnsignedIntValue(); } else { src.ReadTokenOnLine( &token ); src.Error( "idEFXFile::ReadEffect: Invalid parameter in reverb definition" ); Mem_Free( reverb ); } } while ( 1 ); return true; } } else { // other effect (not supported at the moment) src.Error( "idEFXFile::ReadEffect: Unknown effect definition" ); } return false; }