소스 검색

Added GUI constructing from GUIObjects
Added mutex-free execution synchronization between GUI Object and GUI Rendering Pass using atomic_flag
Added a way to set variables in lua from pmap file
Added more GUI functions for lua scripts

Paul A 4 년 전
부모
커밋
ad9aa2f9df

+ 12 - 1
Praxis3D/Data/Maps/componentTest.pmap

@@ -211,7 +211,18 @@
 			{
 				"Lua":
 				{
-					"Filename": "Camera_free.lua"
+					"Filename": "Camera_free.lua",
+					"Variables":
+					[
+						{
+							"Name": "cameraSpeed",
+							"Value": "10.0f"
+						},
+						{
+							"Name": "cameraSpeedMultiplier",
+							"Value": "2.0f"
+						}
+					]
 				}
 			}
 		},

+ 5 - 1
Praxis3D/Data/Scripts/Camera_free.lua

@@ -24,7 +24,11 @@ function init ()
 	mouseLeftKey:bindByName('Mouse_left')
 	
 	-- Get the camera movement speed
-	movementSpeedF = gameplayVariables.camera_freelook_speed
+	if cameraSpeed then 
+		movementSpeedF = cameraSpeed
+	else
+		movementSpeedF = gameplayVariables.camera_freelook_speed
+	end
 	
 	print('Camera_free.lua script initialized.')
 end

+ 18 - 13
Praxis3D/Data/Scripts/GUI_test.lua

@@ -5,28 +5,33 @@ function init ()
 	create(Types.InputVariables, 'inputVariables');
 	create(Types.WindowVariables, 'windowVariables');
 	
-	-- Create key commands, used to track pressed keys
-	create(Types.KeyCommand, 'closeKey')
-	create(Types.KeyCommand, 'fullscreenKey')
-	create(Types.KeyCommand, 'mouseCaptureKey')
-	create(Types.KeyCommand, 'vsyncKey')
-	
-	-- Bind keys to their corresponding buttons on the keyboard
-	closeKey:bind(inputVariables.close_window_key)
-	fullscreenKey:bind(inputVariables.fullscreen_key)
-	mouseCaptureKey:bind(inputVariables.clip_mouse_key)
-	vsyncKey:bind(inputVariables.vsync_key)
-		
+	create(Types.Conditional, 'button1')
+	create(Types.Conditional, 'checkbox1')
+	button1:check()
+	
 	print('GUI_test.lua script initialized.')
 end
-
+	
 function update (p_deltaTime)
 	
 	GUI.Begin('Test window')
 	
 	GUI.Text('SAMPLE TEXT M8', 10.0)
 	
+	GUI.Button('Button Test', button1)
+	
+	GUI.Checkbox('Checkbox Test', checkbox1)
+	
 	GUI.End()
+		
+	if button1:isChecked() then
+		print('Button pressed')
+		button1:uncheck()
+	end
+	
+	if checkbox1:isChecked() then
+		print('Checkbox pressed')
+	end
 	
 	--print('test')
 	

+ 4 - 0
Praxis3D/Source/Config.h

@@ -198,6 +198,8 @@ namespace Properties
 	Code(Scene,) \
 	Code(Systems,) \
 	Code(Type,) \
+	Code(Value,) \
+	Code(Variables,) \
 	/* Geometry */ \
 	Code(OffsetPosition,) \
 	Code(OffsetRotation,) \
@@ -359,6 +361,8 @@ namespace Properties
 		GetString(Scene),
 		GetString(Systems),
 		GetString(Type),
+		GetString(Value),
+		GetString(Variables),
 		GetString(OffsetPosition),
 		GetString(OffsetRotation),
 		GetString(LocalPosition),

+ 11 - 3
Praxis3D/Source/GUIHandler.cpp

@@ -17,11 +17,19 @@ void GUIHandler::render()
 	//ImGui::Text("Hello, world");
 	//ImGui::End();
 
-	//ImGui::Render();
 	//glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
 	//glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
 	//glClear(GL_COLOR_BUFFER_BIT);
-	//ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
 
-	m_frameReady = false;
+	// Create draw data from GUI elements
+	ImGui::Render();
+
+	// Render the draw data to a framebuffer
+	ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
+
+	// Prepare OpenGL states for a new frame here, since the "render" method can only be called from the rendering thread
+	ImGui_ImplOpenGL3_NewFrame();
+
+	// Frame is no longer ready to be rendered
+	m_frameReady.clear();
 }

+ 31 - 9
Praxis3D/Source/GUIHandler.h

@@ -15,7 +15,10 @@ class GUIHandlerBase
 	friend class GUISystem;
 	friend class GUITask;
 public:
-	GUIHandlerBase() : m_initialized(false), m_frameReady(false) { }
+	GUIHandlerBase() : m_initialized(false) 
+	{
+		m_frameReady.clear();
+	}
 
 	// Let the GUI process an SDL even so it can be registered
 	virtual void processSDLEvent(const SDL_Event &p_SDLEvent) { }
@@ -23,18 +26,26 @@ public:
 	// Has the GUI Handle been initialized
 	const inline bool isInitialized() const { return m_initialized; }
 
-	// Is the GUI frame ready to be rendered
-	const inline bool isFrameReady() const { return m_frameReady; }
+	// Get an atomic flag that marks when the GUI frame is ready to be rendered
+	inline std::atomic_flag &getFrameReadyFlag()  { return m_frameReady; }
 
 protected:
 	virtual ErrorCode init() { return ErrorCode::Success; }
 
+	// Must be called ONCE upon startup, and only from the rendering thread
+	virtual void initRendering() { }
+
+	// Begin GUI frame; can be called from any thread
 	virtual void beginFrame() { }
+
+	// Render the GUI; must be called from the rendering thread
 	virtual void render() { }
+
+	// End GUI frame; can be called from any thread
 	virtual void endFrame() { }
 
 	bool m_initialized;
-	std::atomic_bool m_frameReady;
+	std::atomic_flag m_frameReady;
 };
 
 class GUIHandlerNull : public GUIHandlerBase
@@ -99,7 +110,7 @@ protected:
 		{
 			if(glContextHandle != nullptr)
 			{
-				auto glslVersionString = "#version " + Utilities::toString(Config::engineVar().glsl_version);
+				std::string glslVersionString = "#version " + Utilities::toString(Config::engineVar().glsl_version);
 				const char *glsl_version = glslVersionString.c_str();
 
 				// Setup Platform/Renderer backends
@@ -117,18 +128,29 @@ protected:
 		return returnError;
 	}
 
+	void initRendering() 
+	{
+		ImGui_ImplOpenGL3_NewFrame();
+	}
+
 	void beginFrame() 
 	{
-		//ImGui_ImplOpenGL3_NewFrame();
-		//ImGui_ImplSDL2_NewFrame();
-		//ImGui::NewFrame();
+		// Begin new SDL frame (get windows data from SDL)
+		ImGui_ImplSDL2_NewFrame();
+
+		// Begin new GUI frame (prepares frame to receive new GUI calls)
+		ImGui::NewFrame();
 	}
 
 	void render();
 
 	void endFrame() 
 	{
-		m_frameReady = true;
+		// Mark the frame as ready to be rendered
+		m_frameReady.test_and_set();
+
+		// Notify any waiting threads that the frame is ready
+		m_frameReady.notify_all();
 	}
 
 private:

+ 9 - 0
Praxis3D/Source/GUIObject.h

@@ -111,8 +111,17 @@ public:
 
 		// If the change type is GUI, send the change to the GUI Data Manager
 		if(CheckBitmask(p_changeType, Systems::Changes::Type::GUI))
+		{
 			m_GUIData.changeOccurred(p_subject, p_changeType);
 
+			// If GUI Sequence has been changed, and GUISequenceComponent is present, 
+			// notify the component about the change separately, as it has to make a copy of the sequence for later use
+			// (the Functors sequence in GUIDataManager only stores a pointer to it and not a copy)
+			if(CheckBitmask(p_changeType, Systems::Changes::GUI::Sequence))
+				if(GUISequenceComponentPresent())
+					m_GUISequenceComponent->changeOccurred(p_subject, Systems::Changes::GUI::Sequence);
+		}
+
 		// If any data has been updated, post the changes to listeners
 		if(newChanges != Systems::Changes::None)
 		{

+ 6 - 0
Praxis3D/Source/GUIPass.h

@@ -26,11 +26,17 @@ public:
 		else
 			ErrHandlerLoc::get().log(ErrorCode::Initialize_failure, ErrorSource::Source_FinalPass);
 
+		GUIHandlerLocator::get().initRendering();
+
 		return returnError;
 	}
 
 	void update(RenderPassData &p_renderPassData, const SceneObjects &p_sceneObjects, const float p_deltaTime)
 	{
+		// If the GUI frame is not ready yet, wait for it to become ready
+		if(!GUIHandlerLocator::get().getFrameReadyFlag().test())
+			GUIHandlerLocator::get().getFrameReadyFlag().wait(false);
+
 		// Render the GUI
 		GUIHandlerLocator::get().render();
 	}

+ 4 - 0
Praxis3D/Source/LuaComponent.h

@@ -69,6 +69,7 @@ public:
 			if(p_properties.getPropertyID() == Properties::Lua)
 			{
 				auto const &luaFilenameProperty = p_properties.getPropertyByID(Properties::Filename);
+				auto const &luaVariablesProperty = p_properties.getPropertySetByID(Properties::Variables);
 
 				if(luaFilenameProperty)
 				{
@@ -80,6 +81,9 @@ public:
 						{
 							m_luaScript.setScriptFilename(luaFilename);
 
+							if(luaVariablesProperty)
+								m_luaScript.setVariables(luaVariablesProperty);
+
 							importError = ErrorCode::Success;
 							ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_LuaComponent, m_name + " - Script loaded");
 						}

+ 139 - 24
Praxis3D/Source/LuaScript.h

@@ -15,13 +15,15 @@
 namespace LuaDefinitions
 {
 #define LUA_USER_TYPES(Code) \
-    Code(MouseInfo,) \
-    Code(KeyCommand,) \
+	Code(Test, ) \
+	Code(Conditional, ) \
 	Code(EngineVariables, ) \
 	Code(GameplayVariables,) \
 	Code(InputVariables,) \
-	Code(WindowVariables,) \
+    Code(KeyCommand,) \
+    Code(MouseInfo,) \
 	Code(SpatialDataManager,) \
+	Code(WindowVariables,) \
 	Code(NumOfTypes, )
 	DECLARE_ENUM(UserTypes, LUA_USER_TYPES)
 
@@ -42,17 +44,32 @@ namespace LuaDefinitions
 	DECLARE_ENUM(SpatialChanges, LUA_SPATIAL_CHANGES)
 }
 
+struct Conditional
+{
+	Conditional() { m_flag = false; }
+
+	inline bool isChecked() const { return m_flag; }
+
+	inline void check() { m_flag = true; }
+	inline void uncheck() { m_flag = false; }
+	inline void set(const bool p_flag) { m_flag = p_flag; }
+
+	bool m_flag;
+};
+
 class LuaScript
 {
 public:
 	LuaScript(SpatialDataManager &p_spatialData, GUIDataManager &p_GUIData) : m_spatialData(p_spatialData), m_GUIData(p_GUIData)
 	{ 
 		m_keyCommands.reserve(10);
+		m_conditionals.reserve(10);
 		m_currentChanges = Systems::Changes::None;
 	}
 	LuaScript(SpatialDataManager &p_spatialData, GUIDataManager &p_GUIData, std::string &p_scriptFilename) : m_spatialData(p_spatialData), m_GUIData(p_GUIData), m_luaScriptFilename(p_scriptFilename)
 	{
 		m_keyCommands.reserve(10);
+		m_conditionals.reserve(10);
 		m_currentChanges = Systems::Changes::None;
 	}
 	~LuaScript() 
@@ -66,6 +83,12 @@ public:
 				delete m_keyCommands[i];
 			}
 		}
+
+		// Delete all created conditionals
+		for(decltype(m_conditionals.size()) i = 0; i < m_conditionals.size(); i++)
+		{
+			delete m_conditionals[i];
+		}
 	}
 
 	ErrorCode init()
@@ -115,6 +138,22 @@ public:
 	// Set the filename of the script that should be loaded
 	inline void setScriptFilename(std::string &p_filename) { m_luaScriptFilename = p_filename; }
 
+	// Set the variables so they can be accessed from inside the lua script
+	inline void setVariables(const PropertySet &p_properties)
+	{
+		if(p_properties && p_properties.getPropertyID() == Properties::Variables)
+		{
+			// Loop over each variable entry in the node
+			for(decltype(p_properties.getNumPropertySets()) iVariable = 0, numVariables = p_properties.getNumPropertySets(); iVariable < numVariables; iVariable++)
+			{
+				// Add the variable
+				m_variables.emplace_back(
+					p_properties.getPropertySet(iVariable).getPropertyByID(Properties::Name).getString(),
+					p_properties.getPropertySet(iVariable).getPropertyByID(Properties::Value));
+			}
+		}
+	}
+
 	// Get sequences of function calls so that they can be passed to other objects and executed later
 	// They are also cleared at the beginning of each update call, so a copy must be made if there are intentions to store them for later
 	inline const Functors &getFunctors() { return m_GUIData.getGUIData().m_functors; }
@@ -143,6 +182,44 @@ private:
 
 		// Create entries for GUI changes
 		m_changeTypesTable[sol::update_if_empty]["GUI"]["Sequence"] = Int64Packer(Systems::Changes::GUI::Sequence);
+
+		// Iterate over variables array and set each variable depending on its type
+		for(decltype(m_variables.size()) i = 0, size = m_variables.size(); i < size; i++)
+		{
+			switch(m_variables[i].second.getVariableType())
+			{
+			case Property::Type_bool:
+				m_luaState.set(m_variables[i].first, m_variables[i].second.getBool());
+				break;
+			case Property::Type_int:
+				m_luaState.set(m_variables[i].first, m_variables[i].second.getInt());
+				break;
+			case Property::Type_float:
+				m_luaState.set(m_variables[i].first, m_variables[i].second.getFloat());
+				break;
+			case Property::Type_double:
+				m_luaState.set(m_variables[i].first, m_variables[i].second.getDouble());
+				break;
+			case Property::Type_vec2i:
+				m_luaState.set(m_variables[i].first, m_variables[i].second.getVec2i());
+				break;
+			case Property::Type_vec2f:
+				m_luaState.set(m_variables[i].first, m_variables[i].second.getVec2f());
+				break;
+			case Property::Type_vec3f:
+				m_luaState.set(m_variables[i].first, m_variables[i].second.getVec3f());
+				break;
+			case Property::Type_vec4f:
+				m_luaState.set(m_variables[i].first, m_variables[i].second.getVec4f());
+				break;
+			case Property::Type_string:
+				m_luaState.set(m_variables[i].first, m_variables[i].second.getString());
+				break;
+			case Property::Type_propertyID:
+				m_luaState.set(m_variables[i].first, GetString(m_variables[i].second.getID()));
+				break;
+			}
+		}
 	}
 	// Binds functions, so that they can be called from the lua script
 	void setFunctions()
@@ -170,15 +247,26 @@ private:
 		// GUI functions
 		auto GUITable = m_luaState.create_table("GUI");
 		GUITable.set_function("Begin", [this](const std::string &p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::Begin(p_v1.c_str()); }); });
+		GUITable.set_function("BeginChild", [this](const std::string &p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::BeginChild(p_v1.c_str()); }); });
+		GUITable.set_function("BeginMenu", [this](const std::string &p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::BeginMenu(p_v1.c_str()); }); });
+		GUITable.set_function("Button", [this](const std::string &p_v1, Conditional *p_v2) -> void { m_GUIData.addFunctor([=] { p_v2->m_flag = ImGui::Button(p_v1.c_str()); }); });
+		GUITable.set_function("Checkbox", [this](const std::string &p_v1, Conditional *p_v2) -> void { m_GUIData.addFunctor([=] { ImGui::Checkbox(p_v1.c_str(), &p_v2->m_flag); }); });
+		GUITable.set_function("ColorEdit3", [this](const std::string &p_v1, glm::vec3 *p_v2) -> void { m_GUIData.addFunctor([=] { ImGui::ColorEdit3(p_v1.c_str(), &(p_v2->x)); }); });
+		GUITable.set_function("ColorEdit4", [this](const std::string &p_v1, glm::vec4 *p_v2) -> void { m_GUIData.addFunctor([=] { ImGui::ColorEdit4(p_v1.c_str(), &(p_v2->x)); }); });
 		GUITable.set_function("End", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::End(); }); });
+		GUITable.set_function("EndChild", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::EndChild(); }); });
+		GUITable.set_function("EndMenu", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::EndMenu(); }); });
+		GUITable.set_function("EndMenuBar", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::EndMenuBar(); }); });
+		GUITable.set_function("MenuItem", [this](const std::string &p_v1, const std::string &p_v2, Conditional *p_v3) -> void { m_GUIData.addFunctor([=] { p_v3->m_flag = ImGui::MenuItem(p_v1.c_str(), p_v2.c_str()); }); });
+		GUITable.set_function("PlotLines", [this](const std::string &p_v1, const float *p_v2, int p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::PlotLines(p_v1.c_str(), p_v2, p_v3); }); });
+		GUITable.set_function("SliderFloat", [this](const std::string &p_v1, float *p_v2, const float p_v3, const float p_v4) -> const void { m_GUIData.addFunctor([=] { ImGui::SliderFloat(p_v1.c_str(), p_v2, p_v3, p_v4); }); });
 		GUITable.set_function("SameLine", [this]() -> const void { m_GUIData.addFunctor([=] { ImGui::SameLine(); }); });
 		GUITable.set_function("Text", sol::overload([this](const std::string &p_v1) -> const void { m_GUIData.addFunctor([=] { ImGui::Text(p_v1.c_str()); }); },
 			[this](const std::string &p_v1, const float p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::Text(p_v1.c_str(), p_v2); }); },
 			[this](const std::string &p_v1, const float p_v2, const float p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::Text(p_v1.c_str(), p_v2, p_v3); }); }));
-		GUITable.set_function("Checkbox", [this](const std::string &p_v1, bool *p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::Checkbox(p_v1.c_str(), p_v2); }); });
-		GUITable.set_function("SliderFloat", [this](const std::string &p_v1, float *p_v2, const float p_v3, const float p_v4) -> const void { m_GUIData.addFunctor([=] { ImGui::SliderFloat(p_v1.c_str(), p_v2, p_v3, p_v4); }); });
-		GUITable.set_function("ColorEdit3", [this](const std::string &p_v1, const float p_v2, const float p_v3, const float p_v4) -> const void { m_GUIData.addFunctor([=] { float color[3] = { p_v2, p_v3, p_v4 }; ImGui::ColorEdit3(p_v1.c_str(), color); }); });
-		GUITable.set_function("Button", [this](const std::string &p_v1, bool *p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::Checkbox(p_v1.c_str(), p_v2); }); });
+		GUITable.set_function("TextColored", sol::overload([this](const glm::vec4 p_v1, const std::string &p_v2) -> const void { m_GUIData.addFunctor([=] { ImGui::TextColored(ImVec4(p_v1.x, p_v1.y, p_v1.z, p_v1.w), p_v2.c_str()); }); },
+			[this](const glm::vec4 p_v1, const std::string &p_v2, const float p_v3) -> const void { m_GUIData.addFunctor([=] { ImGui::TextColored(ImVec4(p_v1.x, p_v1.y, p_v1.z, p_v1.w), p_v2.c_str(), p_v3); }); },
+			[this](const glm::vec4 p_v1, const std::string &p_v2, const float p_v3, const float p_v4) -> const void { m_GUIData.addFunctor([=] { ImGui::TextColored(ImVec4(p_v1.x, p_v1.y, p_v1.z, p_v1.w), p_v2.c_str(), p_v3, p_v4); }); }));
 
 		// LuaScript callbacks
 		m_luaState.set_function("postChanges", &LuaScript::registerChange, this);
@@ -384,6 +472,13 @@ private:
 			"bindByName", sol::resolve<void(const std::string&)>(&KeyCommand::bind),
 			"unbind", &KeyCommand::unbind,
 			"unbindAll", &KeyCommand::unbindAll);
+
+		// Misc types
+		m_luaState.new_usertype<Conditional>("Conditional",
+			"isChecked", &Conditional::isChecked,
+			"check", &Conditional::check,
+			"uncheck", &Conditional::uncheck,
+			"set", &Conditional::set);
 	}
 
 	// Creates and assigns objects to be used in the lua script
@@ -395,25 +490,19 @@ private:
 		{
 			switch(p_objectType)
 			{
-			case LuaDefinitions::MouseInfo:
-
-				// Set the given variable name in Lua to point to the MouseInfo object
-				m_luaState.set(p_variableName, WindowLocator::get().getMouseInfo());
-
-				break;
-			case LuaDefinitions::KeyCommand:
+			case LuaDefinitions::Conditional:
 			{
-				// Create new key command
-				KeyCommand *keyCommand = new KeyCommand();
+				// Create a new Conditional
+				Conditional *newConditional = new Conditional();
 
-				// Set the given variable name in Lua to point to the created key command
-				m_luaState.set(p_variableName, keyCommand);
+				// Set the given variable name in Lua to point to the created Conditional
+				m_luaState.set(p_variableName, newConditional);
 
-				// Add key command pointer to an array so it is not lost
-				m_keyCommands.push_back(keyCommand);
+				// Add the conditional pointer to an array so it is not lost
+				m_conditionals.push_back(newConditional);
 			}
 				break;
-				
+
 			case LuaDefinitions::EngineVariables:
 
 				// Set the given variable name in Lua to point to the EngineVariables object
@@ -435,10 +524,23 @@ private:
 
 				break;
 
-			case LuaDefinitions::WindowVariables:
+			case LuaDefinitions::KeyCommand:
+			{
+				// Create new key command
+				KeyCommand *keyCommand = new KeyCommand();
 
-				// Set the given variable name in Lua to point to the WindowVariables object
-				m_luaState.set(p_variableName, Config::windowVar());
+				// Set the given variable name in Lua to point to the created key command
+				m_luaState.set(p_variableName, keyCommand);
+
+				// Add key command pointer to an array so it is not lost
+				m_keyCommands.push_back(keyCommand);
+			}
+				break;
+
+			case LuaDefinitions::MouseInfo:
+
+				// Set the given variable name in Lua to point to the MouseInfo object
+				m_luaState.set(p_variableName, WindowLocator::get().getMouseInfo());
 
 				break;
 
@@ -447,6 +549,13 @@ private:
 				// Set the given variable name in Lua to point to the Spatial Data Manager object
 				m_luaState.set(p_variableName, &m_spatialData);
 
+				break;
+
+			case LuaDefinitions::WindowVariables:
+
+				// Set the given variable name in Lua to point to the WindowVariables object
+				m_luaState.set(p_variableName, Config::windowVar());
+
 				break;
 			default:
 				break;
@@ -473,6 +582,9 @@ private:
 	sol::table m_userTypesTable;
 	sol::table m_changeTypesTable;
 
+	// An array of variable names and their value, that get additionally defined in the lua script
+	std::vector<std::pair<std::string, Property>> m_variables;
+
 	// Contains all spatial data
 	SpatialDataManager &m_spatialData;
 
@@ -482,6 +594,9 @@ private:
 	// Keeps all created key commands, so they can be unbound and deleted when cleaning up
 	std::vector<KeyCommand*> m_keyCommands;
 
+	// Keeps all created conditional objects, so they can be deleted when cleaning up
+	std::vector<Conditional*> m_conditionals;
+
 	// Contains sequences of function calls that can be passed to other SystemObjects
 	//Functors m_functors;
 

+ 20 - 15
Praxis3D/Source/PropertySet.h

@@ -17,6 +17,21 @@ class Property
 {
 	friend class PropertySet;
 public:
+	enum PropertyVariableType : unsigned int
+	{
+		Type_null,
+		Type_bool,
+		Type_int,
+		Type_float,
+		Type_double,
+		Type_vec2i,
+		Type_vec2f,
+		Type_vec3f,
+		Type_vec4f,
+		Type_string,
+		Type_propertyID
+	};
+
 	// Type can be determined by overloaded constructor call
 	Property() : m_propertyID(Properties::Null), m_variableType(Type_null) { }
 	Property(const Properties::PropertyID p_propertyID) : m_propertyID(p_propertyID), m_variableType(Type_null) { }
@@ -475,6 +490,9 @@ public:
 			return Properties::Null;
 	}
 
+	// Get the type of the native value stored inside the Property
+	const inline PropertyVariableType getVariableType() const { return m_variableType; }
+
 	// Returns the property ID of Property class, NOT the property ID stored in enum (as property value)
 	const inline Properties::PropertyID getPropertyID() const				{ return m_propertyID;			}
 	const inline void setPropertyID(Properties::PropertyID &p_propertyID)	{ m_propertyID = p_propertyID;	}
@@ -534,25 +552,12 @@ public:
 	inline explicit operator bool() const { return m_propertyID != Properties::Null; }
 
 	// Returns true if the native variable type of the property is string (meaning the string that was retrieved from the property is
-	const inline bool isVariableTypeString() const { return (m_variableType == VariableType::Type_string); }
+	const inline bool isVariableTypeString() const { return (m_variableType == PropertyVariableType::Type_string); }
 
 	// Converts the property to text (used for saving properties to text files)
 	const inline std::string toString() { return "\"" + std::string(GetString(m_propertyID)) + "\": \"" + getString() + "\""; }
 private:
-	enum VariableType
-	{
-		Type_null,
-		Type_bool,
-		Type_int,
-		Type_float,
-		Type_double,
-		Type_vec2i,
-		Type_vec2f,
-		Type_vec3f,
-		Type_vec4f,
-		Type_string,
-		Type_propertyID
-	} m_variableType;
+	PropertyVariableType m_variableType;
 	union VariableUnion
 	{
 		VariableUnion() { }