void CheckboardTexture::Deserialization( tinyxml2::XMLElement* RootElement ) { Spectrum value; ParseVector( RootElement->Attribute( "value1" ) , value.GetDataPtr() ); texture1 = new ConstantTexture( value ); ParseVector( RootElement->Attribute( "value2" ) , value.GetDataPtr() ); texture2 = new ConstantTexture( value ); }
void CheckboardTexture::Deserialization( tinyxml2::XMLElement* RootElement ) { Vector3f value; ParseVector( RootElement->Attribute( "value1" ) , &value[0] ); texture1 = new ConstantTexture( value ); ParseVector( RootElement->Attribute( "value2" ) , &value[0] ); texture2 = new ConstantTexture( value ); }
bool CRainSystem::Command(const char *command) { char *token; if (CWorldEffectsSystem::Command(command)) { return true; } token = COM_ParseExt(&command, false); if (strcmpi(token, "fog") == 0) { // rain fog AddWorldEffect(new CMistyFog2); mWindChange = 0; return true; } else if (strcmpi(token, "fall") == 0) { // rain fall ( minVelocity maxVelocity ) default: ( -60 -50 ) float data[2]; if (ParseVector(&command, 2, data)) { mMinVelocity[2] = data[0]; mMaxVelocity[2] = data[1]; } return true; } else if (strcmpi(token, "spread") == 0) { // rain spread ( radius height ) default: ( 20 20 ) ParseVector(&command, 2, &mSpread[1]); return true; } else if (strcmpi(token, "alpha") == 0) { // rain alpha <float> default: 0.15 token = COM_ParseExt(&command, false); mAlpha = atof(token); return true; } else if (strcmpi(token, "height") == 0) { // rain height <float> default: 1.5 token = COM_ParseExt(&command, false); mRainHeight = atof(token); return true; } else if (strcmpi(token, "angle") == 0) { // rain angle <float> default: 1.0 token = COM_ParseExt(&command, false); mWindAngle = atof(token); return true; } return false; }
bool FDefaultValueHelper::ParseRotator(const FString& Source, FRotator& OutVal) { FVector Vector; if( ParseVector( Source, Vector ) ) { OutVal = FRotator(Vector.X, Vector.Y, Vector.Z); return true; } return false; }
void Sphere::Deserialization( tinyxml2::XMLElement* ShapeRootElement ) { ShapeRootElement->QueryFloatAttribute( "radius" , &m_Radius ); ParseVector( std::string( ShapeRootElement->FirstChildElement( "transform" )->Attribute( "position" ) ) , &mWorldPos[0] ); *mObjectToWorld = Translate( Vector3f( mWorldPos ) ); *mWorldToObject = Inverse( *mObjectToWorld ); BBoxLocal = Bound3f( Point3f( -m_Radius , -m_Radius , -m_Radius ) , Point3f( m_Radius , m_Radius , m_Radius ) ); BBoxWorld = ( *mObjectToWorld )( BBoxLocal ); }
//------------------------------------------------------ // ParseVelocity // Reads in a ranged velocity field in vector format // // input: // string that contains one or two vectors // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseVelocity( const gsl::cstring_view& val ) { vec3_t min, max; if ( ParseVector( val, min, max ) == true ) { mVelX.SetRange( min[0], max[0] ); mVelY.SetRange( min[1], max[1] ); mVelZ.SetRange( min[2], max[2] ); return true; } return false; }
//------------------------------------------------------ // ParseOrigin2 // Reads in an origin field in vector format // // input: // string that contains three float values // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseOrigin2( const char *val ) { vec3_t min, max; if ( ParseVector( val, min, max ) == true ) { mOrigin2X.SetRange( min[0], max[0] ); mOrigin2Y.SetRange( min[1], max[1] ); mOrigin2Z.SetRange( min[2], max[2] ); return true; } return false; }
//------------------------------------------------------ // ParseAngleDelta // Reads in a ranged angleDelta field in vector format // // input: // string that contains one or two vectors // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseAngleDelta( const char *val ) { vec3_t min, max; if ( ParseVector( val, min, max ) == true ) { mAngle1Delta.SetRange( min[0], max[0] ); mAngle2Delta.SetRange( min[1], max[1] ); mAngle3Delta.SetRange( min[2], max[2] ); return true; } return false; }
//------------------------------------------------------ // ParseAcceleration // Reads in a ranged acceleration field in vector format // // input: // string that contains one or two vectors // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseAcceleration( const char *val ) { vec3_t min, max; if ( ParseVector( val, min, max ) == true ) { mAccelX.SetRange( min[0], max[0] ); mAccelY.SetRange( min[1], max[1] ); mAccelZ.SetRange( min[2], max[2] ); return true; } return false; }
//------------------------------------------------------ // ParseRGBEnd // Reads in a ranged rgbEnd field in vector format // // input: // string that contains one or two vectors // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseRGBEnd( const char *val ) { vec3_t min, max; if ( ParseVector( val, min, max ) == true ) { mRedEnd.SetRange( min[0], max[0] ); mGreenEnd.SetRange( min[1], max[1] ); mBlueEnd.SetRange( min[2], max[2] ); return true; } return false; }
//------------------------------------------------------ // ParseRGBStart // Reads in a ranged rgbStart field in vector format // // input: // string that contains one or two vectors // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseRGBStart( const gsl::cstring_view& val ) { vec3_t min, max; if ( ParseVector( val, min, max ) == true ) { mRedStart.SetRange( min[0], max[0] ); mGreenStart.SetRange( min[1], max[1] ); mBlueStart.SetRange( min[2], max[2] ); return true; } return false; }
//------------------------------------------------------ // ParseAngle // Reads in a ranged angle field in vector format // // input: // string that contains one or two vectors // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseAngle( const gsl::cstring_view& val ) { vec3_t min, max; if ( ParseVector( val, min, max ) == true ) { mAngle1.SetRange( min[0], max[0] ); mAngle2.SetRange( min[1], max[1] ); mAngle3.SetRange( min[2], max[2] ); return true; } return false; }
//------------------------------------------------------ // ParseMin // Reads in a min bounding box field in vector format // // input: // string that contains three float values // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseMin( const gsl::cstring_view& val ) { vec3_t min; if ( ParseVector( val, min, min ) == true ) { VectorCopy( min, mMin ); // We assume that if a min is being set that we are using physics and a bounding box mFlags |= (FX_USE_BBOX | FX_APPLY_PHYSICS); return true; } return false; }
//------------------------------------------------------ // ParseMax // Reads in a max bounding box field in vector format // // input: // string that contains three float values // // return: // success of parse operation. //------------------------------------------------------ bool CPrimitiveTemplate::ParseMax( const char *val ) { vec3_t max; if ( ParseVector( val, max, max ) == true ) { VectorCopy( max, mMax ); // We assume that if a max is being set that we are using physics and a bounding box mFlags |= (FX_USE_BBOX | FX_APPLY_PHYSICS); return true; } return false; }
Vector2 ParseVertex(const picojson::value& vertices, const picojson::value& id) { const auto& vertex = vertices.get(id.to_str()); const auto& position = vertex.get("Position"); return ParseVector(position); }
void AreaLight::Deserialization( tinyxml2::XMLElement* LightRootElement ) { ParseVector( LightRootElement->Attribute( "Le" ) , Lemission.GetDataPtr() ); }
bool CSnowSystem::Command(const char *command) { char *token; if (CWorldEffectsSystem::Command(command)) { return true; } token = COM_ParseExt(&command, false); if (strcmpi(token, "wind") == 0) { // snow wind ( windOriginX windOriginY windOriginZ ) ( windVelocityX windVelocityY windVelocityZ ) ( sizeX sizeY sizeZ ) vec3_t origin, velocity, size; ParseVector(&command, 3, origin); ParseVector(&command, 3, velocity); ParseVector(&command, 3, size); AddWorldEffect(new CWind(origin, velocity, size, 0)); return true; } else if (strcmpi(token, "fog") == 0) { // snow fog AddWorldEffect(new CMistyFog2); mWindChange = 0; return true; } else if (strcmpi(token, "alpha") == 0) { // snow alpha <float> default: 0.09 token = COM_ParseExt(&command, false); mAlpha = atof(token); return true; } else if (strcmpi(token, "spread") == 0) { // snow spread ( minX minY minZ ) ( maxX maxY maxZ ) default: ( -600 -600 -200 ) ( 600 600 250 ) ParseVector(&command, 3, mMinSpread); ParseVector(&command, 3, mMaxSpread); return true; } else if (strcmpi(token, "velocity") == 0) { // snow velocity ( minX minY minZ ) ( maxX maxY maxZ ) default: ( -15 -15 -20 ) ( 15 15 -70 ) ParseVector(&command, 3, mMinSpread); ParseVector(&command, 3, mMaxSpread); return true; } else if (strcmpi(token, "blowing") == 0) { token = COM_ParseExt(&command, false); if (strcmpi(token, "duration") == 0) { // snow blowing duration <int> default: 2 token = COM_ParseExt(&command, false); mWindDuration = atol(token); return true; } else if (strcmpi(token, "low") == 0) { // snow blowing low <int> default: 3 token = COM_ParseExt(&command, false); mWindLow = atol(token); return true; } else if (strcmpi(token, "velocity") == 0) { // snow blowing velocity ( min max ) default: ( 30 70 ) float data[2]; ParseVector(&command, 2, data); mWindMin = data[0]; mWindMax = data[1]; return true; } else if (strcmpi(token, "size") == 0) { // snow blowing size ( minX minY minZ ) default: ( 1000 300 300 ) ParseVector(&command, 3, mWindSize); return true; } } return false; }
void Sphere::Deserialization( tinyxml2::XMLElement* ShapeRootElement ) { ShapeRootElement->QueryFloatAttribute( "radius" , &mRadius ); ParseVector( std::string( ShapeRootElement->FirstChildElement( "transform" )->Attribute( "position" ) ) , &mWorldPos[0] ); }
/* ================ Model::ImportMD5 ================ */ Model *Model::ImportMD5( const char *filename, const char *filenameAnim ) { Lexer lexer(LEXER_NO_BOM_WARNING); if ( !lexer.LoadFile( filename ) ) return NULL; Model *model = new Model(true); int numJoints = -1; try { // MD5Version must be the first keyword lexer.ExpectToken( "MD5Version" ); int fileVersion = lexer.ReadInt(); if ( fileVersion != MD5_VERSION_DOOM3 && fileVersion != MD5_VERSION_QUAKEWARS ) lexer.Error( Format( "MD5Version is $*, should be $* or $*") << fileVersion << MD5_VERSION_DOOM3 << MD5_VERSION_QUAKEWARS ); const Token *token; String key; const char *p; bool inJointGroup = false; bool inMeshGroup = false; bool readMeshVerts = false; bool readMeshTris = false; int numMeshes = -1; int numVerts, vertIndex; int triCounter, indexCounter; int numWeights; MeshAnimated *mesh = NULL; int i, j, num; Vec3 vTemp; bool noAnimate = false; bool readVertexColor = false; Color vertexColor; ListEx<MD5Vertex> vertexList; ListEx<MD5Weight> weightList; while ( (token = lexer.ReadToken()) != NULL ) { p = token->GetString(); if ( !p || !*p ) continue; if ( inJointGroup ) { if ( *p == '}' ) { inJointGroup = false; continue; } lexer.ReadInt(); // unused ParseVector( lexer, &vTemp.x, 3 ); ParseVector( lexer, &vTemp.x, 3 ); } else if ( inMeshGroup ) { lexer.UnreadToken(); if ( readMeshVerts ) { if ( lexer.CheckToken( "numtris" ) ) { if ( numVerts != vertexList.Num() ) lexer.Error( Format("numVerts don't match: $*") << vertexList.Num() ); InitIndices( mesh, lexer.ReadInt() * 3 ); // numtris * 3 triCounter = 0; indexCounter = 0; readMeshVerts = false; readMeshTris = true; continue; } lexer.ExpectToken( "vert" ); vertIndex = lexer.ReadInt(); if ( vertIndex != vertexList.Num() ) lexer.Error( Format("Bad Vert Index, should be $*") << vertexList.Num() ); MD5Vertex &vertex = vertexList.Alloc(); ParseVector( lexer, &vertex.texCoord.x, 2 ); vertex.firstWeight = lexer.ReadInt(); vertex.lastWeight = lexer.ReadInt() + vertex.firstWeight - 1; if ( readVertexColor ) { // Currently we don't have use for vertex color.. // I haven't seen md5meshes with other values than ( 1 1 1 1 ) for vertexColor anyway.. ParseVector( lexer, &vertexColor.r, 4 ); } } else if ( readMeshTris ) { if ( lexer.CheckToken( "numweights" ) ) { numWeights = lexer.ReadInt(); weightList.CheckSize( numWeights ); readMeshTris = false; continue; } lexer.ExpectToken( "tri" ); if ( lexer.ReadInt() != triCounter ) lexer.Error( Format("Bad Tri Index, should be $*") << triCounter ); mesh->indices[indexCounter++] = lexer.ReadInt(); mesh->indices[indexCounter++] = lexer.ReadInt(); mesh->indices[indexCounter++] = lexer.ReadInt(); triCounter++; } else { if ( lexer.CheckToken( "}" ) ) { if ( numWeights != weightList.Num() ) lexer.Error( Format("numWeights doesn't match $*") << weightList.Num() ); // Convert vertices: num = vertexList.Num(); for( i=0; i<num; i++ ) { if ( i >= vertexList.Num() ) lexer.Error( "Vertex index out of range" ); const MD5Vertex &md5Vert = vertexList[i]; mesh->texCoords[i] = md5Vert.texCoord; Vertex &vInfo = mesh->vertices[i]; InitVertex( &vInfo, 1 + md5Vert.lastWeight - md5Vert.firstWeight ); vInfo.numWeights = 0; for ( j=md5Vert.firstWeight; j<=md5Vert.lastWeight; j++ ) { if ( j >= weightList.Num() ) lexer.Error( "Weight index out of range" ); const MD5Weight &md5Weight = weightList[j]; if ( md5Weight.jointIndex >= numJoints ) lexer.Error( "Weight joint index out of range" ); if ( md5Weight.bias == 0.0f ) continue; VertexWeight &weight = vInfo.weights[vInfo.numWeights++]; weight.boneId = md5Weight.jointIndex; weight.origin = md5Weight.origin; //weight.normal = md5Weight.normal; //! @todo calculate normal weight.influence = md5Weight.bias; } } inMeshGroup = false; continue; } lexer.ExpectToken( "weight" ); if ( lexer.ReadInt() != weightList.Num() ) lexer.Error( Format("Bad VertexWeight Index, should be $*") << weightList.Num() ); MD5Weight &weight = weightList.Alloc(); weight.jointIndex = lexer.ReadInt(); weight.bias = lexer.ReadFloat(); ParseVector( lexer, &weight.origin.x, 3 ); weight.origin *= MD5_MODEL_SCALE; } } else { if ( String::Icmp( p, "commandline" ) == 0 ) { // Skip value, we don't need it lexer.ReadToken(); } else if ( String::Icmp( p, "numJoints" ) == 0 ) { numJoints = lexer.ReadInt(); if ( numJoints > 0 ) { model->bones.SetGranularity( numJoints ); model->bones.CheckSize( numJoints ); } } else if ( String::Icmp( p, "numMeshes" ) == 0 ) { numMeshes = lexer.ReadInt(); if ( numMeshes <= 0 ) lexer.Error("Zero meshes"); model->meshes.SetGranularity( numMeshes ); model->meshes.CheckSize( numMeshes ); } else if ( String::Icmp( p, "joints" ) == 0 ) { if ( numJoints == -1 ) lexer.Error( "numJoins not set!" ); lexer.ExpectToken( "{" ); inJointGroup = true; } else if ( String::Icmp( p, "mesh" ) == 0 ) { if ( numMeshes == -1 ) lexer.Error( "numMeshes not set!" ); lexer.ExpectToken( "{" ); mesh = new MeshAnimated; model->meshes.Append(mesh); if ( fileVersion != MD5_VERSION_QUAKEWARS ) mesh->name = Format("mesh $*") << model->meshes.Num(); else { lexer.ExpectToken( "name" ); mesh->name = lexer.ReadString(); } lexer.ExpectToken( "shader" ); mesh->material = lexer.ReadString(); noAnimate = false; readVertexColor = false; if ( fileVersion == MD5_VERSION_QUAKEWARS ) { lexer.ExpectToken( "flags" ); lexer.ExpectToken( "{" ); while( !lexer.CheckToken("}") ) { if ( lexer.CheckToken("noAnimate") ) noAnimate = true; else if ( lexer.CheckToken("vertexColor") ) readVertexColor = true; else lexer.Error( Format("Unknown flag: '$*'") << lexer.ReadString() ); } } lexer.ExpectToken( "numverts" ); numVerts = lexer.ReadInt(); vertexList.Clear(); vertexList.CheckSize( numVerts ); weightList.Clear(); InitVertices( mesh, numVerts ); inMeshGroup = true; readMeshVerts = true; } else { lexer.Error( Format("Unexpected '$*'") << p ); } } } if ( inJointGroup || inMeshGroup || numJoints == -1 || numMeshes == -1 ) throw LexerError( LexerError::END_OF_FILE ); } catch( LexerError err ) { delete model; String errStr; err.ToString( errStr ); User::Error( ERR_LEXER_FAILURE, errStr.c_str(), filename ); return NULL; } if ( !ImportMD5AnimBaseFrame( filenameAnim, model ) ) return NULL; if ( numJoints != model->bones.Num() ) { delete model; User::Error( ERR_FILE_CORRUPT, "Number of Joints do not match", filename ); return NULL; } return model; }
/* ============ 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; }
/* ================ ImportMD5AnimBaseFrame ================ */ bool ImportMD5AnimBaseFrame( const char *filename, Model *model ) { Lexer lexer(LEXER_NO_BOM_WARNING); if ( !lexer.LoadFile( filename ) ) { delete model; return false; } try { // MD5Version must be the first keyword lexer.ExpectToken( "MD5Version" ); int fileVersion = lexer.ReadInt(); if ( fileVersion != MD5_VERSION_DOOM3 && fileVersion != MD5_VERSION_QUAKEWARS ) lexer.Error( Format("MD5Version is $*, should be $* or $*") << fileVersion << MD5_VERSION_DOOM3 << MD5_VERSION_QUAKEWARS ); const Token *token; String key; const char *p; bool inHierarchyGroup = false; bool inBoundsGroup = false; bool inBaseFrameGroup = false; bool inFrameGroup = false; int numJoints = -1; int frameRate, numFrames, currentFrame; bool noAnimate = false; bool readVertexColor = false; Color vertexColor; ListEx<MD5Vertex> vertexList; ListEx<MD5Weight> weightList; Vec3 vTemp; int boneIndex = 0; while ( (token = lexer.ReadToken()) != NULL ) { p = token->GetString(); if ( !p || !*p ) continue; if ( inHierarchyGroup ) { if ( *p == '}' ) { inHierarchyGroup = false; continue; } Bone &bone = model->bones.Alloc(); bone.name = p; bone.idParent = lexer.ReadInt(); bone.flags = lexer.ReadInt(); lexer.ReadInt(); // start index ? } else if ( inBaseFrameGroup ) { if ( *p == '}' ) { inBaseFrameGroup = false; break; //! @todo should be continue when loading all frames. } lexer.UnreadToken(); Bone &bone = model->bones[boneIndex++]; ParseVector( lexer, &bone.origin.x, 3 ); ParseVector( lexer, &bone.quat.x, 3 ); bone.origin *= MD5_MODEL_SCALE; // Compute w bone.quat.w = 1.0f - (bone.quat.x * bone.quat.x) - (bone.quat.y * bone.quat.y) - (bone.quat.z * bone.quat.z); bone.quat.w = ( bone.quat.w <= 0.0f ) ? 0.0f : -Math::Sqrt( bone.quat.w ); } else if ( inBoundsGroup ) { if ( *p == '}' ) { inBoundsGroup = false; continue; } lexer.UnreadToken(); ParseVector( lexer, &vTemp.x, 3 ); ParseVector( lexer, &vTemp.x, 3 ); } else if ( inFrameGroup ) { if ( *p == '}' ) { inFrameGroup = false; continue; } //! @todo why was here a fixme ? } else { if ( String::Icmp( p, "commandline" ) == 0 ) { // Skip value, we don't need it lexer.ReadToken(); } else if ( String::Icmp( p, "frameRate" ) == 0 ) { frameRate = lexer.ReadInt(); } else if ( String::Icmp( p, "numAnimatedComponents" ) == 0 ) { // Skip value, we don't need it lexer.ReadToken(); } else if ( String::Icmp( p, "numJoints" ) == 0 ) { numJoints = lexer.ReadInt(); if ( numJoints > 0 ) { model->bones.SetGranularity( numJoints ); model->bones.CheckSize( numJoints ); } } else if ( String::Icmp( p, "numFrames" ) == 0 ) { numFrames = lexer.ReadInt(); if ( numFrames <= 0 ) lexer.Error("Zero frames on model"); //! @todo why was here a fixme ? } else if ( String::Icmp( p, "hierarchy" ) == 0 ) { if ( numJoints == -1 ) lexer.Error("numJoins not set!"); lexer.ExpectToken( "{" ); inHierarchyGroup = true; } else if ( String::Icmp( p, "bounds" ) == 0 ) { lexer.ExpectToken( "{" ); inBoundsGroup = true; } else if ( String::Icmp( p, "baseframe" ) == 0 ) { lexer.ExpectToken( "{" ); inBaseFrameGroup = true; } else if ( String::Icmp( p, "frame" ) == 0 ) { currentFrame = lexer.ReadInt(); lexer.ExpectToken( "{" ); inFrameGroup = true; } else { lexer.Error( Format("Unexpected '$*'") << p ); } } } if ( inHierarchyGroup || inBoundsGroup || inFrameGroup || numJoints == -1 ) throw LexerError( LexerError::END_OF_FILE ); return true; } catch( LexerError err ) { delete model; String errStr; err.ToString( errStr ); User::Error( ERR_LEXER_FAILURE, errStr.c_str(), filename ); return false; } }
/** * @brief The current text pointer is at the explicit text definition of the * shader. Parse it into the global shader variable. Later functions * will optimize it. * @param[in,out] _text * @return */ qboolean ParseShaderR1(char *_text) { char **text = &_text; char *token; int s = 0; shader.explicitlyDefined = qtrue; token = COM_ParseExt2(text, qtrue); if (token[0] != '{') { Ren_Warning("WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name); return qfalse; } while (1) { token = COM_ParseExt2(text, qtrue); if (!token[0]) { Ren_Warning("WARNING: no concluding '}' in shader %s\n", shader.name); return qfalse; } // end of shader definition if (token[0] == '}') { break; } // stage definition else if (token[0] == '{') { if (s >= MAX_SHADER_STAGES) { Ren_Warning("WARNING: too many stages in shader %s (max is %i)\n", shader.name, MAX_SHADER_STAGES); return qfalse; } if (!ParseStage(&stages[s], text)) { Ren_Warning("WARNING: can't parse stages of shader %s @[%.50s ...]\n", shader.name, _text); return qfalse; } stages[s].active = qtrue; s++; continue; } // skip stuff that only the QuakeEdRadient needs else if (!Q_stricmpn(token, "qer", 3)) { SkipRestOfLine(text); continue; } // skip description else if (!Q_stricmp(token, "description")) { SkipRestOfLine(text); continue; } // skip renderbump else if (!Q_stricmp(token, "renderbump")) { SkipRestOfLine(text); continue; } // skip unsmoothedTangents else if (!Q_stricmp(token, "unsmoothedTangents")) { Ren_Warning("WARNING: unsmoothedTangents keyword not supported in shader '%s'\n", shader.name); continue; } // skip guiSurf else if (!Q_stricmp(token, "guiSurf")) { SkipRestOfLine(text); continue; } // skip decalInfo else if (!Q_stricmp(token, "decalInfo")) { Ren_Warning("WARNING: decalInfo keyword not supported in shader '%s'\n", shader.name); SkipRestOfLine(text); continue; } // skip Quake4's extra material types else if (!Q_stricmp(token, "materialType")) { Ren_Warning("WARNING: materialType keyword not supported in shader '%s'\n", shader.name); SkipRestOfLine(text); continue; } // skip Prey's extra material types else if (!Q_stricmpn(token, "matter", 6)) { //Ren_Warning( "WARNING: materialType keyword not supported in shader '%s'\n", shader.name); SkipRestOfLine(text); continue; } // sun parms else if (!Q_stricmp(token, "xmap_sun") || !Q_stricmp(token, "q3map_sun")) { float a, b; token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } tr.sunLight[0] = atof(token); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } tr.sunLight[1] = atof(token); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } tr.sunLight[2] = atof(token); VectorNormalize(tr.sunLight); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } a = atof(token); VectorScale(tr.sunLight, a, tr.sunLight); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } a = atof(token); a = a / 180 * M_PI; token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } b = atof(token); b = b / 180 * M_PI; tr.sunDirection[0] = cos(a) * cos(b); tr.sunDirection[1] = sin(a) * cos(b); tr.sunDirection[2] = sin(b); continue; } // noShadows else if (!Q_stricmp(token, "noShadows")) { shader.noShadows = qtrue; continue; } // noSelfShadow else if (!Q_stricmp(token, "noSelfShadow")) { Ren_Warning("WARNING: noSelfShadow keyword not supported in shader '%s'\n", shader.name); continue; } // forceShadows else if (!Q_stricmp(token, "forceShadows")) { Ren_Warning("WARNING: forceShadows keyword not supported in shader '%s'\n", shader.name); continue; } // forceOverlays else if (!Q_stricmp(token, "forceOverlays")) { Ren_Warning("WARNING: forceOverlays keyword not supported in shader '%s'\n", shader.name); continue; } // noPortalFog else if (!Q_stricmp(token, "noPortalFog")) { Ren_Warning("WARNING: noPortalFog keyword not supported in shader '%s'\n", shader.name); continue; } // fogLight else if (!Q_stricmp(token, "fogLight")) { Ren_Warning("WARNING: fogLight keyword not supported in shader '%s'\n", shader.name); shader.fogLight = qtrue; continue; } // blendLight else if (!Q_stricmp(token, "blendLight")) { Ren_Warning("WARNING: blendLight keyword not supported in shader '%s'\n", shader.name); shader.blendLight = qtrue; continue; } // ambientLight else if (!Q_stricmp(token, "ambientLight")) { Ren_Warning("WARNING: ambientLight keyword not supported in shader '%s'\n", shader.name); shader.ambientLight = qtrue; continue; } // volumetricLight else if (!Q_stricmp(token, "volumetricLight")) { shader.volumetricLight = qtrue; continue; } // translucent else if (!Q_stricmp(token, "translucent")) { shader.translucent = qtrue; continue; } // forceOpaque else if (!Q_stricmp(token, "forceOpaque")) { shader.forceOpaque = qtrue; continue; } // forceSolid else if (!Q_stricmp(token, "forceSolid") || !Q_stricmp(token, "solid")) { continue; } else if (!Q_stricmp(token, "deformVertexes") || !Q_stricmp(token, "deform")) { ParseDeform(text); continue; } else if (!Q_stricmp(token, "tesssize")) { SkipRestOfLine(text); continue; } // skip noFragment if (!Q_stricmp(token, "noFragment")) { continue; } // skip stuff that only the xmap needs else if (!Q_stricmpn(token, "xmap", 4) || !Q_stricmpn(token, "q3map", 5)) { SkipRestOfLine(text); continue; } // skip stuff that only xmap or the server needs else if (!Q_stricmp(token, "surfaceParm")) { ParseSurfaceParm(text); continue; } // no mip maps else if (!Q_stricmp(token, "nomipmap") || !Q_stricmp(token, "nomipmaps")) { shader.filterType = FT_LINEAR; shader.noPicMip = qtrue; continue; } // no picmip adjustment else if (!Q_stricmp(token, "nopicmip")) { shader.noPicMip = qtrue; continue; } // RF, allow each shader to permit compression if available else if (!Q_stricmp(token, "allowcompress")) { shader.uncompressed = qfalse; continue; } else if (!Q_stricmp(token, "nocompress")) { shader.uncompressed = qtrue; continue; } // polygonOffset else if (!Q_stricmp(token, "polygonOffset")) { shader.polygonOffset = qtrue; continue; } // parallax mapping else if (!Q_stricmp(token, "parallax")) { shader.parallax = qtrue; continue; } // entityMergable, allowing sprite surfaces from multiple entities // to be merged into one batch. This is a savings for smoke // puffs and blood, but can't be used for anything where the // shader calcs (not the surface function) reference the entity color or scroll else if (!Q_stricmp(token, "entityMergable")) { shader.entityMergable = qtrue; continue; } // fogParms else if (!Q_stricmp(token, "fogParms")) { if (!ParseVector(text, 3, shader.fogParms.color)) { return qfalse; } //shader.fogParms.colorInt = ColorBytes4(shader.fogParms.color[0] * tr.identityLight, // shader.fogParms.color[1] * tr.identityLight, // shader.fogParms.color[2] * tr.identityLight, 1.0); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: 'fogParms' incomplete - missing opacity value in shader '%s' set to 1\n", shader.name); shader.fogParms.depthForOpaque = 1; } else { shader.fogParms.depthForOpaque = atof(token); shader.fogParms.depthForOpaque = shader.fogParms.depthForOpaque < 1 ? 1 : shader.fogParms.depthForOpaque; } //shader.fogParms.tcScale = 1.0f / shader.fogParms.depthForOpaque; shader.fogVolume = qtrue; shader.sort = SS_FOG; // skip any old gradient directions SkipRestOfLine(text); continue; } // noFog else if (!Q_stricmp(token, "noFog")) { shader.noFog = qtrue; continue; } // portal else if (!Q_stricmp(token, "portal")) { shader.sort = SS_PORTAL; shader.isPortal = qtrue; token = COM_ParseExt2(text, qfalse); if (token[0]) { shader.portalRange = atof(token); } else { shader.portalRange = 256; } continue; } // portal or mirror else if (!Q_stricmp(token, "mirror")) { shader.sort = SS_PORTAL; shader.isPortal = qtrue; continue; } // skyparms <cloudheight> <outerbox> <innerbox> else if (!Q_stricmp(token, "skyparms")) { ParseSkyParms(text); continue; } // This is fixed fog for the skybox/clouds determined solely by the shader // it will not change in a level and will not be necessary // to force clients to use a sky fog the server says to. // skyfogvars <(r,g,b)> <dist> else if (!Q_stricmp(token, "skyfogvars")) { vec3_t fogColor; if (!ParseVector(text, 3, fogColor)) { return qfalse; } token = COM_ParseExt(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing density value for sky fog\n"); continue; } if (atof(token) > 1) { Ren_Warning("WARNING: last value for skyfogvars is 'density' which needs to be 0.0-1.0\n"); continue; } RE_SetFog(FOG_SKY, 0, 5, fogColor[0], fogColor[1], fogColor[2], atof(token)); continue; } // ET waterfogvars else if (!Q_stricmp(token, "waterfogvars")) { vec3_t watercolor; float fogvar; if (!ParseVector(text, 3, watercolor)) { return qfalse; } token = COM_ParseExt(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing density/distance value for water fog\n"); continue; } fogvar = atof(token); // right now allow one water color per map. I'm sure this will need // to change at some point, but I'm not sure how to track fog parameters // on a "per-water volume" basis yet. if (fogvar == 0) { // '0' specifies "use the map values for everything except the fog color // TODO } else if (fogvar > 1) { // distance "linear" fog RE_SetFog(FOG_WATER, 0, fogvar, watercolor[0], watercolor[1], watercolor[2], 1.1); } else { // density "exp" fog RE_SetFog(FOG_WATER, 0, 5, watercolor[0], watercolor[1], watercolor[2], fogvar); } continue; } // ET fogvars else if (!Q_stricmp(token, "fogvars")) { vec3_t fogColor; float fogDensity; int fogFar; if (!ParseVector(text, 3, fogColor)) { return qfalse; } token = COM_ParseExt(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing density value for the fog\n"); continue; } // NOTE: fogFar > 1 means the shader is setting the farclip, < 1 means setting // density (so old maps or maps that just need softening fog don't have to care about farclip) fogDensity = atof(token); if (fogDensity > 1) { // linear fogFar = fogDensity; } else { fogFar = 5; } RE_SetFog(FOG_MAP, 0, fogFar, fogColor[0], fogColor[1], fogColor[2], fogDensity); RE_SetFog(FOG_CMD_SWITCHFOG, FOG_MAP, 50, 0, 0, 0, 0); continue; } // ET sunshader <name> else if (!Q_stricmp(token, "sunshader")) { size_t tokenLen; token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing shader name for 'sunshader'\n"); continue; } // Don't call tr.sunShader = R_FindShader(token, SHADER_3D_STATIC, qtrue); // because it breaks the computation of the current shader tokenLen = strlen(token) + 1; tr.sunShaderName = (char *)ri.Hunk_Alloc(sizeof(char) * tokenLen, h_low); Q_strncpyz(tr.sunShaderName, token, tokenLen); } else if (!Q_stricmp(token, "lightgridmulamb")) { // ambient multiplier for lightgrid token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing value for 'lightgrid ambient multiplier'\n"); continue; } if (atof(token) > 0) { tr.lightGridMulAmbient = atof(token); } } else if (!Q_stricmp(token, "lightgridmuldir")) { // directional multiplier for lightgrid token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing value for 'lightgrid directional multiplier'\n"); continue; } if (atof(token) > 0) { tr.lightGridMulDirected = atof(token); } } // light <value> determines flaring in xmap, not needed here else if (!Q_stricmp(token, "light")) { (void) COM_ParseExt2(text, qfalse); continue; } // cull <face> else if (!Q_stricmp(token, "cull")) { token = COM_ParseExt2(text, qfalse); if (token[0] == 0) { Ren_Warning("WARNING: missing cull parms in shader '%s'\n", shader.name); continue; } if (!Q_stricmp(token, "none") || !Q_stricmp(token, "twoSided") || !Q_stricmp(token, "disable")) { shader.cullType = CT_TWO_SIDED; } else if (!Q_stricmp(token, "back") || !Q_stricmp(token, "backside") || !Q_stricmp(token, "backsided")) { shader.cullType = CT_BACK_SIDED; } else if (!Q_stricmp(token, "front")) { // CT_FRONT_SIDED is set per default see R_FindShader - nothing to do just don't throw a warning } else { Ren_Warning("WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name); } continue; } // distancecull <opaque distance> <transparent distance> <alpha threshold> else if (!Q_stricmp(token, "distancecull")) { int i; for (i = 0; i < 3; i++) { token = COM_ParseExt(text, qfalse); if (token[0] == 0) { Ren_Warning("WARNING: missing distancecull parms in shader '%s'\n", shader.name); } else { shader.distanceCull[i] = atof(token); } } if (shader.distanceCull[1] - shader.distanceCull[0] > 0) { // distanceCull[ 3 ] is an optimization shader.distanceCull[3] = 1.0f / (shader.distanceCull[1] - shader.distanceCull[0]); } else { shader.distanceCull[0] = 0; shader.distanceCull[1] = 0; shader.distanceCull[2] = 0; shader.distanceCull[3] = 0; } continue; } // twoSided else if (!Q_stricmp(token, "twoSided")) { shader.cullType = CT_TWO_SIDED; continue; } // backSided else if (!Q_stricmp(token, "backSided")) { shader.cullType = CT_BACK_SIDED; continue; } // clamp else if (!Q_stricmp(token, "clamp")) { shader.wrapType = WT_CLAMP; continue; } // edgeClamp else if (!Q_stricmp(token, "edgeClamp")) { shader.wrapType = WT_EDGE_CLAMP; continue; } // zeroClamp else if (!Q_stricmp(token, "zeroclamp")) { shader.wrapType = WT_ZERO_CLAMP; continue; } // alphaZeroClamp else if (!Q_stricmp(token, "alphaZeroClamp")) { shader.wrapType = WT_ALPHA_ZERO_CLAMP; continue; } // sort else if (!Q_stricmp(token, "sort")) { ParseSort(text); continue; } // implicit default mapping to eliminate redundant/incorrect explicit shader stages else if (!Q_stricmpn(token, "implicit", 8)) { //Ren_Warning( "WARNING: keyword '%s' not supported in shader '%s'\n", token, shader.name); //SkipRestOfLine(text); // set implicit mapping state if (!Q_stricmp(token, "implicitBlend")) { implicitStateBits = GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; implicitCullType = CT_TWO_SIDED; } else if (!Q_stricmp(token, "implicitMask")) { implicitStateBits = GLS_DEPTHMASK_TRUE | GLS_ATEST_GE_128; implicitCullType = CT_TWO_SIDED; } else // "implicitMap" { implicitStateBits = GLS_DEPTHMASK_TRUE; implicitCullType = CT_FRONT_SIDED; } // get image token = COM_ParseExt(text, qfalse); if (token[0] != '\0') { Q_strncpyz(implicitMap, token, sizeof(implicitMap)); } else { implicitMap[0] = '-'; implicitMap[1] = '\0'; } continue; } // spectrum else if (!Q_stricmp(token, "spectrum")) { Ren_Warning("WARNING: spectrum keyword not supported in shader '%s'\n", shader.name); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'spectrum' keyword in shader '%s'\n", shader.name); continue; } shader.spectrum = qtrue; shader.spectrumValue = atoi(token); continue; } // diffuseMap <image> else if (!Q_stricmp(token, "diffuseMap")) { ParseDiffuseMap(&stages[s], text); s++; continue; } // normalMap <image> else if (!Q_stricmp(token, "normalMap") || !Q_stricmp(token, "bumpMap")) { ParseNormalMap(&stages[s], text); s++; continue; } // specularMap <image> else if (!Q_stricmp(token, "specularMap")) { ParseSpecularMap(&stages[s], text); s++; continue; } // glowMap <image> else if (!Q_stricmp(token, "glowMap")) { ParseGlowMap(&stages[s], text); s++; continue; } // reflectionMap <image> else if (!Q_stricmp(token, "reflectionMap")) { ParseReflectionMap(&stages[s], text); s++; continue; } // reflectionMapBlended <image> else if (!Q_stricmp(token, "reflectionMapBlended")) { ParseReflectionMapBlended(&stages[s], text); s++; continue; } // lightMap <image> else if (!Q_stricmp(token, "lightMap")) { Ren_Warning("WARNING: obsolete lightMap keyword not supported in shader '%s'\n", shader.name); SkipRestOfLine(text); continue; } // lightFalloffImage <image> else if (!Q_stricmp(token, "lightFalloffImage")) { ParseLightFalloffImage(&stages[s], text); s++; continue; } // Doom 3 DECAL_MACRO else if (!Q_stricmp(token, "DECAL_MACRO")) { shader.polygonOffset = qtrue; shader.sort = SS_DECAL; SurfaceParm("discrete"); SurfaceParm("noShadows"); continue; } // Prey DECAL_ALPHATEST_MACRO else if (!Q_stricmp(token, "DECAL_ALPHATEST_MACRO")) { // what's different? shader.polygonOffset = qtrue; shader.sort = SS_DECAL; SurfaceParm("discrete"); SurfaceParm("noShadows"); continue; } else if (SurfaceParm(token)) { continue; } else { Ren_Warning("WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name); SkipRestOfLine(text); continue; } } // ignore shaders that don't have any stages, unless it is a sky or fog if (s == 0 && !shader.forceOpaque && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG) && implicitMap[0] == '\0') { return qfalse; } return qtrue; }