Beispiel #1
0
/*
================
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 ) );
	}

}
Beispiel #2
0
/*
====================
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;
}
Beispiel #3
0
/*
================
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;
}
Beispiel #4
0
/*
====================
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();
}
Beispiel #5
0
/*
================
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;
}
Beispiel #6
0
/*
================
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;
}
Beispiel #7
0
/*
================
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;
}
Beispiel #8
0
/*
================
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;
}
Beispiel #9
0
/*
================
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++;
	}
}
Beispiel #10
0
/*
================
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;
}
Beispiel #11
0
/*
================
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;
}
Beispiel #12
0
/*
================
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;
}
Beispiel #13
0
/*
====================
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 );
}
Beispiel #14
0
/*
====================
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() );
}
Beispiel #15
0
/*
============
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;
}
Beispiel #16
0
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;
}