Commits

Jason McKesson  committed 73614a0

glscene: Node layer parsing works. Fixed bug in scene node.

  • Participants
  • Parent commits 064b25b

Comments (0)

Files changed (8)

File docs/glscene_notepadpp.xml

             <Keywords name="Numbers, range"></Keywords>
             <Keywords name="Operators1"></Keywords>
             <Keywords name="Operators2"></Keywords>
-            <Keywords name="Folders in code1, open">resources sampler_res camera_res program_res scene</Keywords>
+            <Keywords name="Folders in code1, open">resources sampler_res camera_res program_res scene node</Keywords>
             <Keywords name="Folders in code1, middle"></Keywords>
             <Keywords name="Folders in code1, close">end</Keywords>
             <Keywords name="Folders in code2, open"></Keywords>
             <Keywords name="Folders in comment, open"></Keywords>
             <Keywords name="Folders in comment, middle"></Keywords>
             <Keywords name="Folders in comment, close"></Keywords>
-            <Keywords name="Keywords1">compare mag min aniso wrap_s wrap_t wrap_r target orient spin radius radius_delta pos_delta rotation_scale placeholder vert tess_ctrl tess_eval geom frag mtc nmtc nctm sampler image uniform_buffer storage_buffer layer_defs variant_check</Keywords>
+            <Keywords name="Keywords1">compare mag min aniso wrap_s wrap_t wrap_r target orient spin radius radius_delta pos_delta rotation_scale placeholder vert tess_ctrl tess_eval geom frag mtc nmtc nctm sampler image uniform_buffer storage_buffer layer_defs variant_check layers</Keywords>
             <Keywords name="Keywords2">uniform_res uniform_buffer_res storage_buffer_res texture_res mesh_res</Keywords>
             <Keywords name="Keywords3"></Keywords>
             <Keywords name="Keywords4"></Keywords>

File docs/sceneTest.glscene

 
 scene
 	//Defines all layers
-	layer_defs 'main' 'shadow1' 'shadow2'
+	layer_defs 'main' 'shadow1' 'shadow2' 'alt'
 	
 	//List of all legal variant names.
 	variant_check <test>
 
 	node <globals>
-		layer inherit 'main'	//Layer for the current node. All children will inherit these.
-		layer 'shadow1'			//Layer for the current node. Children will not inherit.
+		//Layer for the current node.
+		//Children will inherit 'main' and 'alt', but not 'shadow1'.
+		layers 'shadow1' +'main' +'alt'
 
 		local <matrices>
 			uniform_buffer 0 <projection_matrix>
 		end
 		
 		node <ship>
-			layer 'shadow1' -'main'	//Adds 'shadow1' layer and removes the inherited 'main' layer.
+			//Adds 'shadow1' layer.
+			//Removes the inherited 'main' and 'alt' layers.
+			//Children will still inherit 'main', but they will *not* inherit 'alt'.
+			//That is, they inherit the *lack* of alt.
+			layers 'shadow1' -'main' +-'alt'
 			
 			node_tm
 				quaternion (0 0.707 0 0.707)

File glscene/Test/test.glscene

 
 scene
 	layer_defs 'foo' 'bar'
-//	variant_check <bla> <blabal>
+	variant_check <bla> <blabal> <bol>
+	
+	node <foo>
+		layers 'foo' -'bar' +'bar' +-'foo'
+		node <ident>
+			
+		end
+	end
 end

File glscene/glscene.lua

 		"include/glscene/*.h",
 		"source/*.h",
 		"source/*.cpp",
+		"source/*.incl",
 	}
 
 	configuration "vs2008"

File glscene/glscene_format.doxy

 
 1. unsigned integer: an integer value without a leading "-" sign.
 2. signed integer: an integer value with a leading "-" sign.
-3. floating-point value: any number with a decimal.
+3. floating-point value: any number with a decimal, which may have a leading "-" or "+" sign. Note that scientific notation (1.0+e5) is not allowed. Also, note that there must be a digit before the decimal. `.5` is not a valid floating-point number; it must be `0.5`
 
 The types can be promoted from lower types to higher ones. So a command that expects you to provide a signed integer can also take an unsigned one. A command that takes a floating-point type will take any kind of number.
 
+Note that the leading "-" sign must be directly adjacent to the numeral. So "- 5" is not the number -5; it's a minus sign followed by the unsigned integer 5.
+
 ### Vectors and Matrices ### {#page_glscene_file_format_syntax_numbers_vectors}
 
 Some commands take vector or matrix types rather than a scalar. Such types must *always* be bounded by a pair of parenthesis, even if you are only passing one value.
 
 - `layer_defs`: Required. The parameters to this command are a series of graph names. These represent the names of the layers, as provided to glscene::SceneGraph::SceneGraph(), and the order you place them in the list is the order that they will be provided in.
 - `variant_check`: Optional. The parameters to this command are a series of identifier strings. If you provide this command, the use of any variant names not listed here will result in a parse error.
-- One or more `node` commands, as described below.
+- One or more `node` commands, [as described below](\ref page_glscene_file_format_syntax_scene_node).
 
 \par A Word on the Root Node
 The [GL Scene Graph](\ref module_glscene) has a root node. And glscene::SceneGraph freely allows you to fetch this node, add variants to it, change its transforms, and play with it as though it were any other node (mostly). However, the scene graph file format does not expose this functionality. You cannot set any of these things on the root node. This is quite deliberate.
 \par
-Becaue the root node is restricted in its functionality, such as re-parenting and deleting, the scene file format encourages you to create your own root. This makes it easier for you to move things around dynamically. It also makes it easier for you to change things later, since you can copy node definitions around more freely.
+Becaue the root node is restricted in its functionality, such as re-parenting, deleting, and querying-by-name, the scene file format encourages you to create your own root. This makes it easier for you to move things around dynamically. It also makes it easier for you to change things later, since you can copy node definitions around more freely.
 
-## Scene Node ## {#page_glscene_file_format_syntax_scene_node}
+## Node ## {#page_glscene_file_format_syntax_scene_node}
 
+\verbatim
+node <node_id>?
+//Commands
+end
+\endverbatim
+
+The `node` command defines a child node in the scene graph system. It is the child of whatever node it is defined in; if it is defined in the `scene` command, then it is a child of the root.
+
+`node_id` is optional. If a node does not have one, then you cannot query the node by name in the glscene::SceneGraph. If you do provide a `node_id` name, it *must* be unique; no other node can have the same identifier.
+
+The contents of a node are rigidly ordered. The sub-commands must be provided in the following order:
+
+- `layers`: Optional. This provides a list of layers that the node is a member of. This list has some complexities to it, so there is [a section dedicated to them](\ref page_glscene_file_format_syntax_scene_node_layers).
+
+### Node Layers ### {#page_glscene_file_format_syntax_scene_node_layers}
+
+~~~~
+layers 'layer_to_add' +'layer_to_inherit' -'layer_to_remove' +-'layer_to_remove_and_inherit_removal'
+~~~~
+
+The parameters of `layers` is a list of graph names that define which layers this node is associated with. They can also be inherited, such that child nodes will be members of those layers without a `layers` command mentioning that layer.
+
+It is an error to specify a layer name that is not mentioned in the `layer_defs` list in the `scene` node.
+
+Each layer name in the list can be prefixed. The prefixes mean the following:
+
+- No prefix: The current node will be a member of that layer. Child node layers are unaffected.
+- `+`: The current node will be a member of that layer. All child nodes will also be a member of that layer.
+- `-`: The current node will not be a member of that layer. Useful for removing an inherited layer. Child node layers are unaffected.
+- `+-`: The current node will not be a member of that layer. All child nodes will also *not* be a member of that layer.
+
+Note that `-+` is not a valid prefix. The `+` must always come first.
+
+All layer additions are processed in order, with latter commands overriding previous ones. For example:
+
+~~~~
+layers 'shadow' 'main' -'shadow'
+~~~~
+
+The node with this command will be a member of 'main' and any inherited layers. The `-'shadow'` layer overrides the first one because it came last. Similarly:
+
+~~~~
+layers -'shadow' 'main' 'shadow'
+~~~~
+
+This will put the node in 'main' and 'shadow', in addition to any inherited layers.
+
+You can do even more complex things through this with inheritance:
+
+~~~~
+layers 'main' +'shadow' -'shadow'
+~~~~
+
+The current node will only have 'main' (and any inherited). It's children will inherit 'shadow'. The `-'shadow'` parameter is what causes the current node to no longer be in 'shadow', but the `-` prefix *does not affect inheritance*.
+
+Similarly:
+
+~~~~
+layers +-'shadow' 'shadow'
+~~~~
+
+This will put the current node in 'shadow', but all child nodes will not be in 'shadow'.
 
 **/
 

File glscene/source/Parse.cpp

 		TOK_UNSIGNED_INTEGER,
 	};
 
+	const size_t g_layersTokens[] =
+	{
+		TOK_MINUS_SIGN,
+		TOK_PLUS_SIGN,
+		TOK_GRAPH_NAME,
+	};
+
 	//////////////////////////////////////////////////////////////////////////
 	// The lexer.
 	template <typename Lexer>
 	};
 
 	template<typename Def>
-	FilePosition GetPosFromDef(const Def &def) {return def.pos;}
+	FilePosition GetFilePosition(const Def &def) {return def.pos;}
+	FilePosition GetFilePosition(const FilePosition &pos) {return pos;}
+
+	template<typename Key, typename Def>
+	FilePosition GetPosFromDef(const std::pair<Key, Def> &pairDef) {return GetFilePosition(pairDef.second);}
 
 	typedef boost::container::flat_map<IdString, ParsedUniformDef> ParsedUniformMap;
 	typedef boost::container::flat_map<IdString, ParsedSamplerDef> ParsedSamplerMap;
 		ParsedTextureMap textures;
 	};
 
+	typedef boost::container::flat_set<std::string> LayerSet;
+
+	struct ParsedNodeDef
+	{
+		FilePosition pos;
+		boost::optional<IdString> name;
+		LayerSet layers;
+		std::vector<int> childIndices;
+		int parentIx;
+
+		ParsedNodeDef& operator=(const ParsedNodeDef &other)
+		{
+			pos = other.pos;
+			name = other.name;
+			layers = other.layers;
+			return *this;
+		}
+	};
+
+	struct InheritedNodeData
+	{
+		int parentIx;
+		LayerSet layers;
+
+		InheritedNodeData() : parentIx(-1) {}
+	};
+
 	struct ParsedSceneGraphDef
 	{
 		FilePosition pos;
-		std::vector<std::string> layers;
-		std::vector<IdString> variantChecks;
+		LayerSet layers;
+		std::vector<std::string> layerOrder;
+		boost::container::flat_set<IdString> variantChecks;
+		boost::container::flat_map<IdString, FilePosition> nodeNamePositions;
+		std::vector<ParsedNodeDef> nodes;
 	};
 
 	template<typename Range>
 				ExpectAndEatToken(TOK_LAYER_DEFS);
 				while(IsCurrToken(TOK_GRAPH_NAME))
 				{
-					m_scene.layers.push_back(ParseGraphName());
+					std::string layerName = GetStringTokenData();
+					if(m_scene.layers.find(layerName) != m_scene.layers.end())
+						ThrowParseError("The layer '" + layerName + "' has already been defined.", curr_throw);
+					m_scene.layers.insert(layerName);
+					m_scene.layerOrder.push_back(layerName);
+					EatOneToken();
 				}
 				if(m_scene.layers.empty())
 					ThrowParseError("You must provide at least one layer name in a `layer_defs`.");
 				EatOneToken();
 				while(IsCurrToken(TOK_IDENTIFIER))
 				{
+					std::string variantName = GetStringTokenData();
+					IdString variantId = variantName;
+					if(m_scene.variantChecks.find(variantId) != m_scene.variantChecks.end())
+						ThrowParseError("The variant check '" + variantName + "' has already been defined.", curr_throw);
+					m_scene.variantChecks.insert(variantId);
 					EatOneToken();
 				}
 				if(!IsCurrTokenCategory(KEYWORD_ID_PREFIX))
 					ThrowParseError("`variant_check` members must be identifier strings.", curr_throw);
 			}
 
+			if(!IsCurrToken(TOK_NODE))
+				ThrowParseError("The `scene` command must have at least 1 `node` sub-command.");
+
+			do
+			{
+				ParseNode(InheritedNodeData());
+			} while (IsCurrToken(TOK_NODE));
+
 			ExpectAndEatEndToken();
 		}
 
+		int ParseNode(const InheritedNodeData &inherit)
+		{
+			ExpectToken(TOK_NODE);
+			PosStackPusher push(*this);
+			EatOneToken();
+
+			m_scene.nodes.push_back(ParsedNodeDef());
+			const int nodeIx = int(m_scene.nodes.size());
+			InheritedNodeData myData = inherit;
+			myData.parentIx = nodeIx;
+
+			{
+
+				ParsedNodeDef &node = m_scene.nodes.back();
+				node.layers = inherit.layers;
+				node.parentIx = inherit.parentIx;
+
+				if(IsCurrToken(TOK_IDENTIFIER))
+				{
+					IdString nodeId = ParseIdentifier(m_scene.nodeNamePositions, false, TOK_NODE);
+					m_scene.nodeNamePositions[nodeId] = m_posStack.top();
+					node.name = nodeId;
+				}
+
+				ExpectCategory(KEYWORD_ID_PREFIX);
+
+				if(IsCurrToken(TOK_LAYERS))
+				{
+					PosStackPusher push(*this);
+					EatOneToken();
+
+					while(!IsCurrTokenCategory(KEYWORD_ID_PREFIX))
+					{
+						bool layerInherit = false;
+						bool layerRemove = false;
+
+						if(IsCurrToken(TOK_PLUS_SIGN))
+						{
+							EatOneToken();
+							layerInherit = true;
+						}
+
+						if(IsCurrToken(TOK_MINUS_SIGN))
+						{
+							EatOneToken();
+							layerRemove = true;
+						}
+
+						try
+						{
+							ExpectToken(TOK_GRAPH_NAME);
+						}
+						catch(BaseParseError &)
+						{
+							if(IsCurrToken(TOK_PLUS_SIGN))
+								ThrowParseError("The `+` sign must always come before the `-` sign.", curr_throw);
+							else
+								ThrowParseError("Members of a `layers` list must be graph names, `+`, or `-`", curr_throw);
+						}
+						std::string layerName = GetStringTokenData();
+						if(m_scene.layers.find(layerName) == m_scene.layers.end())
+							ThrowParseError("The layer '" + layerName + "' was not listed in the scene graph `layer_defs`.", curr_throw);
+						EatOneToken();
+
+						if(layerRemove)
+							node.layers.erase(layerName);
+						else
+							node.layers.insert(layerName);
+
+						if(layerInherit)
+						{
+							if(layerRemove)
+								myData.layers.erase(layerName);
+							else
+								myData.layers.insert(layerName);
+						}
+					}
+				}
+
+				ExpectCategory(KEYWORD_ID_PREFIX);
+			}
+
+			while(IsCurrToken(TOK_NODE))
+			{
+				int childIx = ParseNode(myData);
+				m_scene.nodes[nodeIx].childIndices.push_back(childIx);
+			}
+
+			try
+			{
+				ExpectAndEatEndToken();
+			}
+			catch(BaseParseError &)
+			{
+				if(IsCurrTokenCategory(KEYWORD_ID_PREFIX))
+					ThrowParseError("Incorrect command or command out of order in `node`.\n`layers` comes first, then transforms, `local`s, `variant`s, and lastly `node`s.", curr_throw);
+				else
+					throw;
+			}
+
+			return nodeIx;
+		}
+
 		template<typename MapType>
 		IdString ParseIdentifier(const MapType &search, bool mustFind, size_t currentCmd)
 		{
 			ExpectToken(TOK_IDENTIFIER);
-			std::string idToken = GetTokenString();
+			std::string idToken = GetTokenText();
 			IdString ident(string_ref(&idToken[0] + 1, idToken.size() - 2));
 
 			if(mustFind)
 			{
 				MapType::const_iterator foundIt = search.find(ident);
 				if(foundIt != search.end())
-					MultipleIdentifierOfSameType(idToken, currentCmd, GetPosFromDef(foundIt->second));
+					MultipleIdentifierOfSameType(idToken, currentCmd, GetPosFromDef(*foundIt));
 			}
 
 			EatOneToken();
 				str << std::setw(earlyDefPos.columnNumber - 1) << " ";
 			str << "^- here" << std::endl;
 
-			ThrowParseError(str.str(), curr_throw);			
+			ThrowParseError(str.str(), curr_throw);
 		}
 
 		//Expects the top of the stack to be the position of the containing command.
 				case TOK_ANISO:
 					{
 						ExpectCategory(NUMBER_ID_PREFIX);
-						samplerData.sampler.maxAniso = boost::lexical_cast<float>(GetTokenString());
+						samplerData.sampler.maxAniso = boost::lexical_cast<float>(GetTokenText());
 						if(samplerData.sampler.maxAniso < 1.0f)
 						{
 							std::string msg = "The maximum anisotropic filtering value must be 1.0 or greater.";
 					if(IsUnifTypeUnsigned(typeIx) && HasTokenNoEmpty(TOK_SIGNED_INTEGER))
 						throw UniformTypeMismatchError(m_rng.front(), g_uniformTypeList[typeIx], unf_type_unsigned);
 
-					std::string theInt(GetTokenString());
+					std::string theInt(GetTokenText());
 					EatOneToken();
 
 					if(theInt[0] == '-')
 						throw UniformTypeMismatchError(m_rng.front(),
 						g_uniformTypeList[typeIx], unf_type_float);
 
-					std::string theFloat(GetTokenString());
+					std::string theFloat(GetTokenText());
 
 					EatOneToken();
 					float val = boost::lexical_cast<float>(theFloat);
 						throw UniformTypeMismatchError(m_rng.front(),
 						g_uniformTypeList[typeIx], unf_type_unsigned);
 
-					std::string theInt(GetTokenString());
+					std::string theInt(GetTokenText());
 
 					if(theInt[0] == '-')
 						ret.push_back(boost::lexical_cast<int>(theInt));
 						throw UniformTypeMismatchError(m_rng.front(),
 						g_uniformTypeList[typeIx], unf_type_float);
 
-					std::string theFloat(GetTokenString());
+					std::string theFloat(GetTokenText());
 
 					ret.push_back(boost::lexical_cast<float>(theFloat));
 				}
 		std::string ParseFilename()
 		{
 			ExpectToken(TOK_FILENAME);
-			std::string rawToken = GetTokenString();
+			std::string rawToken = GetTokenText();
 			EatOneToken();
 
 			return std::string(rawToken.begin() + 1, rawToken.end() - 1);
 		std::string ParseGlslIdentifier(const Token &owningTok)
 		{
 			ExpectToken(TOK_GLSL_IDENT);
-			std::string rawToken = GetTokenString();
+			std::string rawToken = GetTokenText();
 			EatOneToken();
 
 			return std::string(rawToken.begin() + 1, rawToken.end() - 1);
 		std::string ParseGraphName()
 		{
 			ExpectToken(TOK_GRAPH_NAME);
-			std::string rawToken = GetTokenString();
+			std::string rawToken = GetTokenText();
 			EatOneToken();
 
 			return std::string(rawToken.begin() + 1, rawToken.end() - 1);
 					ThrowParseError(msg, curr_throw);
 				}
 
-				ret[count] = boost::lexical_cast<float>(GetTokenString());
+				ret[count] = boost::lexical_cast<float>(GetTokenText());
 			}
 
 			ExpectToken(TOK_CLOSE_PAREN);
 					ThrowParseError(msg, curr_throw);
 				}
 
-				inputQuat[count] = boost::lexical_cast<float>(GetTokenString());
+				inputQuat[count] = boost::lexical_cast<float>(GetTokenText());
 			}
 
 			ExpectToken(TOK_CLOSE_PAREN);
 			}
 
 			ExpectCategory(NUMBER_ID_PREFIX);
-			float ret = boost::lexical_cast<float>(GetTokenString());
+			float ret = boost::lexical_cast<float>(GetTokenText());
 			EatOneToken();
 
 			if(paren)
 			}
 
 			ExpectToken(TOK_UNSIGNED_INTEGER);
-			unsigned int ret = boost::lexical_cast<unsigned int>(GetTokenString());
+			unsigned int ret = boost::lexical_cast<unsigned int>(GetTokenText());
 			EatOneToken();
 
 			if(paren)
 		}
 
 		//Gets the current token as a std::string.
-		std::string GetTokenString() const
+		std::string GetTokenText() const
 		{
 			return std::string(m_rng.front().value().begin(), m_rng.front().value().end());
 		}
 
+		//Assuming the current token is a string token, constructs a std::string from the contents.
+		std::string GetStringTokenData() const
+		{
+			std::string rawToken = GetTokenText();
+			return std::string(++rawToken.begin(), --rawToken.end());
+		}
+
 		void ThrowParseError(const std::string &msg) const
 		{
 			throw BaseParseError(msg, m_posStack.top());

File glscene/source/keywords.incl

 	MAC(TEXTURE_RES,	"texture_res",	"texture resource",			"mesh resource")
 	MAC(SCENE,			"scene",		"scene graph",				"scene graph")
 	MAC(LAYER_DEFS,		"layer_defs",	"layer definition",			"layer definition")
-	MAC(VARIANT_CHECK,	"variant_check",	"variant checking",		"variant checking")
+	MAC(VARIANT_CHECK,	"variant_check",	"variant checking",		"variant checking")
+	MAC(NODE,			"node",			"scene graph node",			"scene graph node")
+	MAC(LAYERS,			"layers",		"layer declaration",		"layer declaration")
+	

File glscene/source/symbols.incl

 //	MAC(Enum suffix,		Pattern,	Debug name,			Display name)
 	MAC(OPEN_PAREN,			"\\(",		"Open Paren",		"(")
 	MAC(CLOSE_PAREN,		"\\)",		"Close Paren",		")")
+	MAC(MINUS_SIGN,			"\\-",		"Minus Sign",		"-")
+	MAC(PLUS_SIGN,			"\\+",		"Plus Sign",		"+")