Index: /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTree.h
===================================================================
--- /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTree.h	(revision 1202)
+++ /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTree.h	(revision 1204)
@@ -27,16 +27,16 @@
 public:
 
-	KdTreeApp()	
-	{ 
-		mFrameListener = 0; 
-		mRenderTargerListener = 0;
+	KdTreeApp() :
+	mFrameListener(0),
+	mRenderTargerListener(0)
+	{
+
 	}
 
-	KdTreeApp(const String& infile, const String& outfile)	
-	{ 
-		mFrameListener = 0; 
-		mRenderTargerListener = 0;
-		mDemoInfileName = infile;
-		mDemoOutfileName = outfile;
+	KdTreeApp(const KdTreeAppListener::Options& options) :
+	mFrameListener(0), 
+	mRenderTargerListener(0),
+	mOptions(options)
+	{
 	}
 
@@ -48,17 +48,15 @@
 
 protected:
-	SceneNode *mCamNode;
-	SceneNode *mDeathNode;
-	Camera *mTopCam;
-	Camera *mFollowCam;
 	KdTreeAppListener *mFrameListener;
 	KdTreeAppRenderTargetListener *mRenderTargerListener;
+	SceneNode *mCamNode;
+	SceneNode *mMoveNode;
+	Camera *mTopCam;
+	//Camera *mFollowCam;
 
+	// scene options
 	String  mSceneFiles;
 	String	mSelectedSceneManager;
-	Real	mMoveSpeed;
-	Real	mRotateSpeed;
 	Real	mRotationRadius;
-	Real	mRotationPeriod;
 	int		mModelSpacing;
 	int		mModelCount;
@@ -68,6 +66,6 @@
 	int		mSelectEntities;
 
-	String mDemoInfileName;
-	String mDemoOutfileName;
+	KdTreeAppListener::Options mOptions;
+
 
 	virtual void setupResources(void);
Index: /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTreeAppListener.h
===================================================================
--- /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTreeAppListener.h	(revision 1202)
+++ /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTreeAppListener.h	(revision 1204)
@@ -61,20 +61,127 @@
 class KdTreeAppListener: public FrameListener, public KeyListener
 {
+
+public:
+	// visualization modes for scene nodes
+	enum VizMode
+	{
+		NODEVIZ_NONE, 
+		NODEVIZ_RENDER_NODES, 
+		NODEVIZ_RENDER_NODES_AND_CONTENT, 
+		NODEVIZ_MODES_NUM
+	};
+
+	enum AppState
+	{
+		AS_NORMAL,
+		AS_RECORD,
+		AS_PLAYBACK
+	};
+
+	struct Options
+	{
+		Options():
+		mDemoMode(false),
+		mRotateSpeed(36.0f),
+		mMoveSpeed(100.0f),
+		mRotationPeriod(30.0f),
+		mMaxDepth(12),
+		mKT(2.0f),
+		mKI(1.0f),
+		mRenderMethod("CHC")
+		{
+
+		}
+
+		String mDemoInfileName;
+		String mDemoOutfileName;
+		String mDemoLogfileName;
+		bool mDemoMode;
+		Degree mRotateSpeed;
+		Real mMoveSpeed;
+		Real mRotationPeriod;
+		int mMaxDepth;
+		Real mKT;
+		Real mKI;
+		String mRenderMethod;
+	};
+
+    // Constructor takes a RenderWindow because it uses that to determine input context
+    KdTreeAppListener(RenderWindow* win, SceneManager* sm, const Options& options,  
+		bool useBufferedInputKeys = false, bool useBufferedInputMouse = false);
+
+    virtual ~KdTreeAppListener();
+
+	void initOverlayElement(OverlayElement **elInfo, String ext, 
+		String name, int top, String caption);
+
+	void initStatsOverlay();
+
+	void initKdTreeOverlay();
+
+	void showDebugOverlay(bool show);
+
+	void toggleVizCamera();
+
+    virtual bool processUnbufferedKeyInput(const FrameEvent& evt);
+
+    bool processUnbufferedMouseInput(const FrameEvent& evt);
+
+	void moveCamera();
+
+    // Override frameStarted event to process that (don't care about frameEnded)
+    bool frameStarted(const FrameEvent& evt);
+
+    bool frameEnded(const FrameEvent& evt);
+
+	void switchMouseMode();
+
+	void switchKeyMode();
+
+	void keyClicked(KeyEvent* e);
+
+	void keyPressed(KeyEvent* e) {};
+	void keyReleased(KeyEvent* e) {};
+
+
 protected:
-	int mSceneDetailIndex ;
-    Real mMoveSpeed;
-    Degree mRotateSpeed;
-	Real mRotationPeriod;
+	// basic
+	RenderWindow* mWindow;
+	SceneManager *mSceneMgr;
+	Options mOptions;
+	bool mUseBufferedInputKeys, mUseBufferedInputMouse, mInputTypeSwitchingOn;
+
+	// elements
+	SceneNode *mCamNode;
+	Camera* mCamera;
+	Camera* mTopCam;
+
+	// toggle
+	bool mStatsOn;
+
+	bool mVizCamera;
 	bool mShowTree;
 	bool mFreeMove;
 	bool mTopCamFollow;
 
+	// counters
+	int mSeqNum;
+	unsigned int mNumScreenShots;
+
+	// rendering/texture options
+	int mSceneDetailIndex;
+	TextureFilterOptions mFiltering;
+	int mAniso;
+
+	// chc stats
 	Real mDelayedQueriesIssued;
 	Real mDelayedTraversedNodes;
 
-	int mSeqNum;
-
-	Overlay* mDebugOverlay;
-	Overlay* mKdTreeOverlay;
+	// overlays
+	Overlay *mDemoOverlay;
+	Overlay *mDebugOverlay;
+	Overlay *mKdTreeOverlay;
+
+	OverlayElement *mDemoStatus;
 
 	OverlayElement *mKdTreeMaxDepthInfo;
@@ -95,50 +202,29 @@
 	OverlayElement *mQueriesIssuedInfo;
 
+	// input
 	EventProcessor* mEventProcessor;
 	InputReader* mInputDevice;
-	SceneNode *mCamNode;
-	Camera* mCamera;
-	Camera* mTopCam;
-	SceneManager *mSceneMgr;
-	Radian mDeathAngle;
-
+
+	// movement
 	Vector3 mTranslateVector;
-	RenderWindow* mWindow;
-	bool mStatsOn;
-	bool mUseBufferedInputKeys, mUseBufferedInputMouse, mInputTypeSwitchingOn;
-	unsigned int mNumScreenShots;
+	Vector3 mVizCamTransVect;
+	Radian mRotX, mRotY;
 	float mMoveScale;
 	Degree mRotScale;
+	Radian mDeathAngle;
+
 	// just to stop toggles flipping too fast
 	Real mTimeUntilNextToggle ;
-	Radian mRotX, mRotY;
-	TextureFilterOptions mFiltering;
-	int mAniso;
-
-	// stuff for the viz camera
-	bool mVizCamera;
-	Vector3 mVizCamTransVect;
-
-    void updateStats(void);
 
 	// stuff for walkthrough recording/playback
-	String mDemoInfileName;
-	String mDemoOutfileName;
-
-	enum AppState
-	{
-		AS_NORMAL,
-		AS_RECORD,
-		AS_PLAYBACK
-	};
-
+	//std::ofstream mDemoFramesLog;
+	std::list<Real> mDemoFPS;
+	Real mTimeUntilNextLogWrite;
 	FrameList mFrameList;
 	FrameList::iterator mCurrFrame;
 	Real mTimeRemaining;
+	Real mWaitBeforeDemoStart;
 
 	AppState mAppState;
-
-	Overlay * mDemoOverlay;
-	OverlayElement * mDemoStatus;
 
 	void setDemoOverlay();
@@ -148,5 +234,5 @@
 
 	void saveFrameInfo(Real elapsedTime);
-	
+
 	/** save demo frame data to file **/
 	static void saveFrames(const String& filename, FrameList& framelist);
@@ -159,51 +245,5 @@
 	static void loadFramesBinary(const String& filename, FrameList& framelist);
 
-public:
-	// visualization modes for scene nodes
-	enum 
-	{
-		NODEVIZ_NONE, 
-		NODEVIZ_RENDER_NODES, 
-		NODEVIZ_RENDER_NODES_AND_CONTENT, 
-		NODEVIZ_MODES_NUM
-	};
-
-    // Constructor takes a RenderWindow because it uses that to determine input context
-    KdTreeAppListener(RenderWindow* win, SceneManager* sm, Real rs, Real ms, Real rp, 
-		const String& infile, const String& outfile, 
-		bool useBufferedInputKeys = false, bool useBufferedInputMouse = false);
-
-    virtual ~KdTreeAppListener();
-
-	void initOverlayElement(OverlayElement **elInfo, String ext, 
-		String name, int top, String caption);
-
-	void initStatsOverlay();
-
-	void initKdTreeOverlay();
-
-	void showDebugOverlay(bool show);
-
-	void toggleVizCamera();
-
-    virtual bool processUnbufferedKeyInput(const FrameEvent& evt);
-
-    bool processUnbufferedMouseInput(const FrameEvent& evt);
-
-	void moveCamera();
-
-    // Override frameStarted event to process that (don't care about frameEnded)
-    bool frameStarted(const FrameEvent& evt);
-
-    bool frameEnded(const FrameEvent& evt);
-
-	void switchMouseMode();
-
-	void switchKeyMode();
-
-	void keyClicked(KeyEvent* e);
-
-	void keyPressed(KeyEvent* e) {};
-	void keyReleased(KeyEvent* e) {};
+	void updateStats(void);
 };
 
Index: /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/WinCmdLineParser.h
===================================================================
--- /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/WinCmdLineParser.h	(revision 1204)
+++ /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/WinCmdLineParser.h	(revision 1204)
@@ -0,0 +1,496 @@
+/**
+Utility class for parsing the commandline passed to WinMain and
+extracting options and option arguments
+
+Author: Martin Szydlowski
+*/
+
+#include <vector>
+#include <string>
+
+//using namespace std;
+
+static enum arg_types
+{
+	ARGUMENT_NONE,
+	ARGUMENT_REQUIRED,
+	ARGUMENT_OPTIONAL
+};
+
+class WinCmdLineParser
+{
+public:
+	// describes one option
+	struct option_info 
+	{
+		option_info():
+		shortname(""), longname(""), argtype(ARGUMENT_NONE)
+		{
+
+		}
+
+		option_info(const std::string& sname, const std::string& lname, arg_types atype):
+		shortname(sname), longname(lname), argtype(atype)
+		{
+
+		}
+
+		bool operator == (const option_info& rhs) const
+		{
+			if ((!(shortname.empty() || rhs.shortname.empty()) && shortname == rhs.shortname) ||
+				(!(longname.empty() || rhs.longname.empty()) && longname == rhs.longname))
+				return true;
+			else
+				return false;
+		}
+
+		std::string shortname;
+		std::string longname;
+		arg_types argtype;
+	};
+
+	struct option_found
+	{
+		option_found():
+		shortname(""), longname(""), optarg("")
+		{
+
+		}
+
+		option_found(const std::string& sname, const std::string& lname, const std::string& arg):
+		shortname(sname), longname(lname), optarg(arg)
+		{
+
+		}
+
+		bool operator == (const option_found& rhs) const
+		{
+			if ((!(shortname.empty() || rhs.shortname.empty()) && shortname == rhs.shortname) ||
+				(!(longname.empty() || rhs.longname.empty()) && longname == rhs.longname))
+				return true;
+			else
+				return false;
+		}
+
+		std::string shortname;
+		std::string longname;
+		std::string optarg;
+	};
+
+	WinCmdLineParser(const char * strCmdLine, bool caseSensitive = false):
+		case_sensitive(caseSensitive), reparse(true)
+	{
+		op_case_transform = tolower;
+		splitStrCmdLine(strCmdLine, m_argv);
+	}
+
+	~WinCmdLineParser()
+	{
+
+	}
+
+	String dumpOptSet()
+	{
+		std::string sDump;
+
+		for (std::vector<option_info>::iterator it = m_optset.begin(); it != m_optset.end(); it ++)
+		{
+			sDump += it->shortname + ", " + it->longname + "\n";
+		}
+
+		return sDump;
+	}
+
+	// add an option with short & long name (each optional, but one mandatory)
+	// only alphanumeric chars valid
+	WinCmdLineParser& addOpt(const std::string& sname, const std::string& lname, arg_types argtype)
+	{
+		std::string shortname = sname;
+		std::string longname = lname;
+
+		//bool invalid = false;
+		
+		// check sanity: presence & length
+		if (shortname.size() == 0 && longname.size() == 0)
+			throw std::string("Invalid option specification: Specify at least a short name or a long name");
+			//invalid = true;
+		if (shortname.size() > 1)
+			throw std::string("Invalid option specification: Short name too long, must be one character");
+		//invalid = true;
+		if (longname.size() == 1)
+			throw std::string("Invalid option specification: Long name too short, must be at least two characters");
+		//invalid = true;
+
+		// check sanity: valid characters
+		static std::string valid_chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
+
+		for (size_t i = 0; i < shortname.length(); i ++)
+			if (valid_chars.find(shortname[i]) == std::string::npos)
+				throw std::string("Invalid option specification: Invalid character in short name: " + shortname);
+				//invalid = true;
+
+		for (size_t i = 0; i < longname.length(); i ++)
+			if (valid_chars.find(longname[i]) == std::string::npos)
+				throw std::string("Invalid option specification: Invalid character in long name: " + longname);
+				//invalid = true;
+
+		// if all is well add option to list
+		//if (!invalid)
+		//{
+			// convert to all upper case when case-insensitive options
+			if (!case_sensitive)
+			{
+				std::transform(shortname.begin(), shortname.end(), shortname.begin(), op_case_transform);
+				std::transform(longname.begin(), longname.end(), longname.begin(), op_case_transform);
+			}
+
+			// try inserting
+			std::pair<option_info, bool> res = insertOpt(option_info(shortname, longname, argtype), m_optset);
+			if (!res.second)
+			{
+				throw std::string("Conflicting option specification: (" +
+					(shortname.empty() ? "" : " -" + shortname) +
+					(longname.empty() ? "" : " --" + longname) + 
+					") conflicts with (" + 
+					(res.first.shortname.empty() ? "" : " -" + res.first.shortname) +
+					(res.first.longname.empty() ? "" : " --" + res.first.longname) + ")");
+			}
+			else
+			{
+				reparse = true;
+			}
+		//}
+
+		return *this;
+	}
+
+	// returns true when option present, false otherwise
+	bool getOpt(const std::string& opt)
+	{
+		// dummy string
+		std::string optarg;
+		return getOpt(opt, optarg);
+	}
+
+
+	// returns true when option was present in the cmd-line and puts the argument
+	// in optarg, when present
+	bool getOpt(const std::string& opt, std::string& optarg)
+	{
+		if (reparse)
+		{
+			parseOpt(m_argv, m_optset, m_optfound, m_noopt);
+			reparse = false;
+		}
+
+		optarg.clear();
+
+		std::string option = opt;
+		option_found of;
+
+		if (!case_sensitive)
+			std::transform(option.begin(), option.end(), option.begin(), op_case_transform);
+
+		if (option.length() == 1) // short option
+			of.shortname = option;
+		else if (option.length() > 1) // long option
+			of.longname = option;
+		else // don't mess with me
+			return false;
+
+		if (findOptArg(m_optfound, of))
+		{
+			optarg = of.optarg;
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	// returns true when any non-option arguments were in the cmd line
+	// and places them in the arguments vector
+	bool getArgs(std::vector<std::string>& arguments)
+	{
+		if (reparse)
+		{
+			parseOpt(m_argv, m_optset, m_optfound, m_noopt);
+			reparse = false;
+		}
+
+		arguments.clear();
+
+		arguments = m_noopt;
+
+		if (m_noopt.size() > 0)
+			return true;
+		else
+			return false;
+	}
+
+protected:
+	// split a space-separated string argument in an array of strings
+	// sensitive to ", the only windows way to pass strings with embedded spaces
+	void splitStrCmdLine(const char *strCmdLine, std::vector<std::string>& argv)
+	{
+		std::string cmdline(strCmdLine);
+		argv.clear();
+
+		std::string tmp;
+		unsigned int strpos = 0;
+		bool skipspace = false;
+
+		while (strpos < cmdline.length())
+		{
+			while (strpos < cmdline.length() && cmdline[strpos] == ' ')
+				strpos++;
+			tmp.clear();
+			while (strpos < cmdline.length() && (cmdline[strpos] != ' ' || skipspace))
+			{
+				if (cmdline[strpos] == '"')
+				{
+					++ strpos;
+					skipspace = !skipspace;
+					if (!skipspace)
+						continue;
+				}
+
+				tmp += cmdline[strpos ++];
+			}
+			argv.push_back(tmp);
+		}
+
+		//std::ofstream testout("test.txt");
+
+		//testout << cmdline << "\n\n";
+
+		//std::vector<std::string>::iterator it = argv.begin();
+		//while (it != argv.end())
+		//{
+		//	testout << *it << "\n";
+		//	++ it;
+		//}
+
+		//testout.close();
+	}
+
+	void parseOpt(const std::vector<std::string>& argv, const std::vector<option_info>& optset, 
+		std::vector<option_found>& optfound, std::vector<std::string>& noopt)
+	{
+		// reset old options list
+		optfound.clear();
+
+		// bail out when nothing to parse
+		if (argv.empty() || optset.empty())
+			return;
+
+		// iterate through argv and create opt_founds
+		size_t item = 0;
+		while (item < argv.size())
+		{
+			// dummy info for lookup
+			std::string optstr;
+			option_info info;
+
+			// skip empty items, shold not happen actually ...
+			if (argv[item].length() > 0)
+			{
+				// check if item might be option (starts with /, - or --)
+				if (argv[item][0] == '-')
+				{
+					// unix-style option, one dash - long or short option
+					// two dashes - long option
+					optstr = argv[item].substr(1, argv[item].length());
+					if (optstr.length() > 1 && optstr[0] == '-') // long option
+					{
+						optstr = optstr.substr(1, optstr.length());
+						if (optstr.length() == 1) // invalid
+							optstr = "";
+					}
+				}
+				else if (argv[item][0] == '/')
+				{
+					// windows-style option, long or short
+					optstr = argv[item].substr(1, argv[item].length());
+				}
+				else
+				{
+					// no option and no option argument since these are skipped
+					// -> must be a program argument
+					noopt.push_back(argv[item]);
+					++ item;
+					continue;
+				}
+
+				if (!case_sensitive)
+					std::transform(optstr.begin(), optstr.end(), optstr.begin(), op_case_transform);
+
+				if (optstr.length() == 1) // short option
+					info.shortname = optstr;
+				else if (optstr.length() > 1) // long option
+					info.longname = optstr;
+
+				// lookup
+				if (findOpt(optset, info))
+				{
+					 // find optarg
+					std::string optarg;
+					if (item + 1 < argv.size())
+						optarg = argv[item + 1];
+
+					std::pair<option_found, bool> res;
+
+					switch (info.argtype)
+					{
+					case ARGUMENT_NONE:
+						res = insertOptArg(option_found(info.shortname, info.longname, ""), optfound);
+						if (!res.second)
+						{
+							throw std::string("Duplicate option: (" +
+								(res.first.shortname.empty() ? "" : " -" + res.first.shortname) +
+								(res.first.longname.empty() ? "" : " --" + res.first.longname) +
+								") allready specified");
+						}
+						break;
+					case ARGUMENT_REQUIRED:
+						if (optarg.length() > 0 && optarg[0] != '-' && optarg[0] != '/')
+						{
+							res = insertOptArg(option_found(info.shortname, info.longname, optarg), optfound);
+							if (!res.second)
+							{
+								throw std::string("Duplicate option: (" +
+									(res.first.shortname.empty() ? "" : " -" + res.first.shortname) +
+									(res.first.longname.empty() ? "" : " --" + res.first.longname) +
+									") allready specified with argument: " + res.first.optarg);
+							}
+							++ item;
+						}
+						else
+						{
+							throw std::string("Missing argument for option: " + argv[item]);
+						}
+						break;
+					case ARGUMENT_OPTIONAL:
+						if (optarg.length() > 0 && optarg[0] != '-' && optarg[0] != '/')
+						{
+							res = insertOptArg(option_found(info.shortname, info.longname, optarg), optfound);
+							if (!res.second)
+							{
+								throw std::string("Duplicate option: (" +
+									(res.first.shortname.empty() ? "" : " -" + res.first.shortname) +
+									(res.first.longname.empty() ? "" : " --" + res.first.longname) +
+									") allready specified with argument: " + res.first.optarg);
+							}
+							++ item;
+						}
+						else
+						{
+							res = insertOptArg(option_found(info.shortname, info.longname, ""), optfound);
+							if (!res.second)
+							{
+								throw std::string("Duplicate option: (" +
+									(res.first.shortname.empty() ? "" : " -" + res.first.shortname) +
+									(res.first.longname.empty() ? "" : " --" + res.first.longname) +
+									") allready specified");
+							}
+						}
+						break;
+					default:
+						break;
+					}
+				}
+				// otherwise panic
+				else
+				{
+					throw std::string("Invalid option: " + argv[item]);
+				}
+
+			}
+
+			++ item;
+		}
+	}
+
+	std::pair<option_info, bool> insertOpt(const option_info& optinfo, std::vector<option_info>& optset)
+	{
+		// check for conflicts
+		for (size_t i = 0; i < optset.size(); i ++)
+		{
+			if (optinfo == optset[i])
+			{
+				return std::pair<option_info, bool>(optset[i], false);
+			}
+		}
+		// no conflicts - insert
+		optset.push_back(optinfo);
+		return std::pair<option_info, bool>(optinfo, true);
+	}
+
+	bool findOpt(const std::vector<option_info>& optset, option_info& optinfo)
+	{
+		// find entry
+		for (size_t i = 0; i < optset.size(); i ++)
+		{
+			if (optinfo == optset[i])
+			{
+				optinfo = optset[i];
+				return true;
+			}
+		}
+		// not found - reset
+		return false;
+	}
+
+	std::pair<option_found, bool> insertOptArg(const option_found& of, std::vector<option_found>& optfound)
+	{
+		// check for conflicts
+		for (size_t i = 0; i < optfound.size(); i ++)
+		{
+			if (of == optfound[i])
+			{
+				return std::pair<option_found, bool>(optfound[i], false);
+			}
+		}
+		// no conflicts - insert
+		optfound.push_back(of);
+		return std::pair<option_found, bool>(of, true);
+	}
+
+	bool findOptArg(const std::vector<option_found>& optfound, option_found& of)
+	{
+		// find entry
+		for (size_t i = 0; i < optfound.size(); i ++)
+		{
+			if (of == optfound[i])
+			{
+				// found - set values
+				of = optfound[i];
+				return true;
+			}
+		}
+		// not found
+		return false;
+	}
+
+	// holds the elements of the command line
+	std::vector<std::string> m_argv;
+
+	// holds the elements of the command line which are not options or option arguments
+	std::vector<std::string> m_noopt;
+
+	// all options we recognize
+	std::vector<option_info> m_optset;
+
+	// all options we have found so far
+	std::vector<option_found> m_optfound;
+
+	// parse options case sensitive?
+	bool case_sensitive;
+
+	// reparse list for next getOpt
+	bool reparse;
+
+	// poiter to unary function for uppercase transform;
+	int (*op_case_transform)(int);
+};
Index: /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTree.cpp
===================================================================
--- /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTree.cpp	(revision 1203)
+++ /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTree.cpp	(revision 1204)
@@ -5,12 +5,9 @@
 
 #include "TestKdTree.h"
-//#include "WinCmdLineParser.h"
+#include "WinCmdLineParser.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
-
-void splitStrCmdLine(const char *strCmdLine, std::vector<std::string>& argv);
-bool getopt(const std::string& option, const std::vector<std::string>& argv, const std::string& optstring, std::string& optarg);
 
 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
@@ -22,23 +19,72 @@
 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
 		// parse windows-style command line
-		std::string optarg = "i:o:", infile, outfile;
-		std::vector<std::string> argv;
-
-		splitStrCmdLine(strCmdLine, argv);
-
-		getopt("i", argv, optarg, infile);
-		getopt("o", argv, optarg, outfile);
-
-		//WinCmdLineParser cmdparser(strCmdLine);
-
-		//cmdparser
-		//	.addOpt("o","",ARGUMENT_REQUIRED)
-		//	.addOpt("i","",ARGUMENT_REQUIRED);
-
-		//cmdparser.getOpt("o", outfile);
-		//cmdparser.getOpt("i", infile);
+
+		WinCmdLineParser cmdparser(strCmdLine);
+		KdTreeAppListener::Options options;
+
+		try
+		{
+			cmdparser
+				.addOpt("i","infile", ARGUMENT_REQUIRED)
+				.addOpt("o","outfile", ARGUMENT_REQUIRED)
+				.addOpt("l","logfile", ARGUMENT_REQUIRED)
+				.addOpt("d","demomode", ARGUMENT_NONE)
+				.addOpt("","maxdepth", ARGUMENT_REQUIRED)
+				.addOpt("","kt", ARGUMENT_REQUIRED)
+				.addOpt("","ki", ARGUMENT_REQUIRED)
+				.addOpt("r","rendermethod", ARGUMENT_REQUIRED);
+
+
+			cmdparser.getOpt("i", options.mDemoInfileName);
+			cmdparser.getOpt("o", options.mDemoOutfileName);
+			cmdparser.getOpt("l", options.mDemoLogfileName);
+			options.mDemoMode = cmdparser.getOpt("d");
+
+			std::string tmp;
+			std::stringstream s;
+
+			if (cmdparser.getOpt("maxdepth", tmp))
+			{
+				s << tmp;
+				s >> options.mMaxDepth;
+				s.clear();
+			}
+
+			if (cmdparser.getOpt("kt", tmp))
+			{
+				s << tmp;
+				s >> options.mKT;
+				s.clear();
+			}
+
+			if (cmdparser.getOpt("ki", tmp))
+			{
+				s << tmp;
+				s >> options.mKI;
+				s.clear();
+			}
+
+			if (cmdparser.getOpt("r",tmp))
+			{
+				if (tmp == "INT" || tmp == "VFC" || tmp == "SWC" || tmp == "CHC")
+				{
+					options.mRenderMethod = tmp;
+				}
+				else
+				{
+					MessageBox(NULL, ("Invalid argument for option --rendermethod: " + tmp).c_str(), "Error", MB_OK | MB_ICONERROR );
+					return -1;
+				}
+			}
+
+		}
+		catch (std::string s)
+		{
+			MessageBox(NULL, s.c_str(), "Error", MB_OK | MB_ICONERROR );
+			return -1;
+		}
 
 		// Create application object
-		KdTreeApp app(infile, outfile);
+		KdTreeApp app(options);
 #else
 		// TODO: unix-style getopt
@@ -70,126 +116,4 @@
 #endif
 
-// split a space-separated string argument in an array of strings
-// sensitive to "
-void splitStrCmdLine(const char *strCmdLine, std::vector<std::string>& argv)
-{
-	std::string cmdline(strCmdLine);
-	argv.clear();
-
-	std::string tmp;
-	unsigned int strpos = 0;
-	bool skipspace = false;
-
-	while (strpos < cmdline.length())
-	{
-		while (strpos < cmdline.length() && cmdline[strpos] == ' ')
-			strpos++;
-		tmp.clear();
-		while (strpos < cmdline.length() && (cmdline[strpos] != ' ' || skipspace))
-		{
-			if (cmdline[strpos] == '"')
-			{
-				++ strpos;
-				skipspace = !skipspace;
-				if (!skipspace)
-					continue;
-			}
-
-			tmp += cmdline[strpos ++];
-		}
-		argv.push_back(tmp);
-	}
-
-	//std::ofstream testout("test.txt");
-
-	//testout << cmdline << "\n\n";
-
-	//std::vector<std::string>::iterator it = argv.begin();
-	//while (it != argv.end())
-	//{
-	//	testout << *it << "\n";
-	//	++ it;
-	//}
-
-	//testout.close();
-}
-
-// simplified std::-based getopt (no long options)
-// does not provide options consecutively like POSIX getopt, it rather gives you the value of the option you ask for
-// or returns false if option not present or anything else went wrong
-bool getopt(const std::string& option, const std::vector<std::string>& argv, const std::string& optstring, std::string& optarg)
-{
-	static enum argtypes
-	{
-		no_argument,
-		required_argument,
-		optional_argument
-	};
-
-	// early terminate
-	if (option.empty() || argv.empty() || optstring.empty())
-		return false;
-
-	// verify presence of option
-	size_t iopt = optstring.find(option);
-	if (iopt == std::string::npos)
-		return false;
-
-	// check if mandatory or optional argument
-	int arg = no_argument;
-	if (++ iopt < optstring.size() && optstring[iopt] == ':')
-		arg = required_argument;
-	if (++ iopt < optstring.size() && optstring[iopt] == ':')
-		arg = optional_argument;
-
-
-	// find the arguments value
-	size_t item = 0;
-	std::string optstr = "-" + option;
-
-	while (item < argv.size())
-	{
-		if (argv[item] == optstr)
-		{
-			switch (arg)
-			{
-			case no_argument:
-				optarg.clear();
-				return true;
-				break;
-			case required_argument:
-				if (++ item < argv.size() && argv[item][0] != '-')
-				{
-					optarg = argv[item];
-					return true;
-				}
-				else
-				{
-					optarg.clear();
-					return false;
-				}
-				break;
-			case optional_argument:
-				if (++ item < argv.size() && argv[item][0] != '-')
-				{
-					optarg = argv[item];
-					return true;
-				}
-				else
-				{
-					optarg.clear();
-					return true;
-				}
-				break;
-			default:
-				return false;
-			}
-		}
-		++ item;
-	}
-
-	return false;
-}
-
 #define ENT_GRID	0x01
 #define ENT_RND		0x02
@@ -237,18 +161,29 @@
 	
 	tmp = cfDeath.getSetting("period");
-	mRotationPeriod = static_cast<Real>(strtod(tmp.c_str(), &errptr));
+	mOptions.mRotationPeriod = static_cast<Real>(strtod(tmp.c_str(), &errptr));
 
 	tmp = cfDeath.getSetting("movespeed");
-	mMoveSpeed = static_cast<Real>(strtod(tmp.c_str(), &errptr));
+	mOptions.mMoveSpeed = static_cast<Real>(strtod(tmp.c_str(), &errptr));
 
 	tmp = cfDeath.getSetting("rotatespeed");
-	mRotateSpeed = static_cast<Real>(strtod(tmp.c_str(), &errptr));
+	mOptions.mRotateSpeed = static_cast<Real>(strtod(tmp.c_str(), &errptr));
 
 	// command line has preference over config file
-	if (mDemoInfileName.empty())
-		mDemoInfileName = cfDeath.getSetting("demoinfile");
-
-	if (mDemoOutfileName.empty())
-		mDemoOutfileName = cfDeath.getSetting("demooutfile");
+	if (mOptions.mDemoInfileName.empty())
+		mOptions.mDemoInfileName = cfDeath.getSetting("demoinfile");
+
+	if (mOptions.mDemoOutfileName.empty())
+		mOptions.mDemoOutfileName = cfDeath.getSetting("demooutfile");
+
+	// set default demo output name to avoid SNAFUs
+	if (mOptions.mDemoOutfileName.empty())
+		mOptions.mDemoOutfileName = "demo.bin";
+
+	if (mOptions.mDemoLogfileName.empty())
+		mOptions.mDemoLogfileName = cfDeath.getSetting("demologfile");
+
+	// set default demo logfile name to avoid SNAFUs
+	if (mOptions.mDemoLogfileName.empty())
+		mOptions.mDemoLogfileName = "demo.csv";
 
 	ExampleApplication::setupResources();
@@ -357,10 +292,10 @@
 
 			SceneNode *deathPivotNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("deathPivotNode");
-			mDeathNode = deathPivotNode->createChildSceneNode("movingNode", Vector3(0, 0, mRotationRadius)/*,
+			mMoveNode = deathPivotNode->createChildSceneNode("movingNode", Vector3(0, 0, mRotationRadius)/*,
 				Quaternion(Radian(Math::HALF_PI), Vector3::UNIT_Y)*/);
-			mDeathNode->attachObject(movingDeath);
+			mMoveNode->attachObject(movingDeath);
 
 			Entity *ent_ball = mSceneMgr->createEntity("ball","sphere.mesh");
-			SceneNode *node_pivot = mDeathNode->createChildSceneNode("pivotNode");
+			SceneNode *node_pivot = mMoveNode->createChildSceneNode("pivotNode");
 			SceneNode *node_ball = node_pivot->createChildSceneNode("orbitNode", Vector3(120, 40, 0));
 			node_ball->attachObject(ent_ball);
@@ -368,5 +303,5 @@
 			
 
-			mFollowCam->setAutoTracking(true, mDeathNode);
+			//mFollowCam->setAutoTracking(true, mMoveNode);
 		}
 		
@@ -432,6 +367,6 @@
 void KdTreeApp::createFrameListener(void)
 {
-	mFrameListener = new KdTreeAppListener(mWindow, mSceneMgr, mRotateSpeed, mMoveSpeed, mRotationPeriod, mDemoInfileName, mDemoOutfileName);
-	mFrameListener->showDebugOverlay( true );
+	mFrameListener = new KdTreeAppListener(mWindow, mSceneMgr, mOptions);
+	//mFrameListener->showDebugOverlay( true );
 	mRoot->addFrameListener(mFrameListener);
 	mRenderTargerListener = new KdTreeAppRenderTargetListener(mSceneMgr);
@@ -443,4 +378,9 @@
 	// Get the SceneManager
 	mSceneMgr = mRoot->createSceneManager(mSelectedSceneManager,"MySceneManager");
+	// set params
+	mSceneMgr->setOption("KdTreeMaxDepth", &mOptions.mMaxDepth);
+	mSceneMgr->setOption("KT", &mOptions.mKT);
+	mSceneMgr->setOption("KI", &mOptions.mKI);
+	mSceneMgr->setOption("RenderMethod", &mOptions.mRenderMethod);
 }
 
Index: /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTreeAppListener.cpp
===================================================================
--- /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTreeAppListener.cpp	(revision 1202)
+++ /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTreeAppListener.cpp	(revision 1204)
@@ -70,14 +70,48 @@
 
 // Constructor takes a RenderWindow because it uses that to determine input context
-KdTreeAppListener::KdTreeAppListener(RenderWindow* win, SceneManager* sm, Real rs, Real ms, Real rp,
-									 const String& infile, const String& outfile,
-									 bool useBufferedInputKeys, bool useBufferedInputMouse)
-{
-	mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
-	mKdTreeOverlay = OverlayManager::getSingleton().getByName("KdTree/DebugOverlay");
-
-
-	mUseBufferedInputKeys = useBufferedInputKeys;
-	mUseBufferedInputMouse = useBufferedInputMouse;
+KdTreeAppListener::KdTreeAppListener(RenderWindow* win, SceneManager* sm, const Options& options, 
+									 bool useBufferedInputKeys, bool useBufferedInputMouse):
+// basic
+mWindow(win),
+mSceneMgr(sm),
+mOptions(options),
+mUseBufferedInputKeys(useBufferedInputKeys),
+mUseBufferedInputMouse(useBufferedInputMouse),
+// elements
+mCamNode(0),
+mCamera(0),
+mTopCam(0),
+// toggle
+mStatsOn(true),
+mVizCamera(false),
+mShowTree(false),
+mFreeMove(false),
+mTopCamFollow(true),
+//counters
+mSeqNum(0),
+mNumScreenShots(0),
+// rendering/texture options
+mSceneDetailIndex(PM_SOLID),
+mFiltering(TFO_ANISOTROPIC),
+mAniso(8),
+// chc stats
+mDelayedQueriesIssued(0.0f),
+mDelayedTraversedNodes(0.0f),
+// movement
+mTranslateVector(Vector3::ZERO),
+mVizCamTransVect(Vector3::ZERO),
+mRotX(0.0f), 
+mRotY(0.0f),
+mMoveScale(0.0f),
+mRotScale(0.0f),
+mDeathAngle(0.0f),
+// just to stop toggles flipping too fast
+mTimeUntilNextToggle(0.0f),
+// stuff for walkthrough recording/playback
+mTimeUntilNextLogWrite(0.0f),
+mTimeRemaining(0.0f),
+mWaitBeforeDemoStart(0.0f),
+mAppState(AS_NORMAL)
+{
 	mInputTypeSwitchingOn = mUseBufferedInputKeys || mUseBufferedInputMouse;
 
@@ -97,41 +131,13 @@
 	}
 
-	mTopCamFollow = true;
-	mFreeMove = false;
-	mShowTree = false;
-	mVizCamera = false;
-	mVizCamTransVect = Vector3::ZERO;
-	mSeqNum = 0;
-
-	mDemoInfileName = infile;
-	mDemoOutfileName = outfile;
-
-	mAppState = AS_NORMAL;
-
-	mDelayedQueriesIssued = 0.0;
-	mDelayedTraversedNodes = 0.0;
+	MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
+	MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);
 
 	mCamera = sm->getCamera("PlayerCam");
 	mTopCam = sm->getCamera("TopCam");
 	mCamNode = sm->getSceneNode("PlayerCamNode");
-	mSceneMgr = sm;
-	mWindow = win;
-	mRotateSpeed = rs;
-	mMoveSpeed = ms;
-	mRotationPeriod = rp;
-	mDeathAngle = 0;
-	mStatsOn = true;
-	mNumScreenShots = 0;
-	mTimeUntilNextToggle = 0;
-	mSceneDetailIndex = 0;
-	mMoveScale = 0.0f;
-	mRotScale = 0.0f;
-	mTranslateVector = Vector3::ZERO;
-	mAniso = 8;
-	mFiltering = TFO_ANISOTROPIC;
-
-	MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
-	MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);
-
+
+	mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
+	mKdTreeOverlay = OverlayManager::getSingleton().getByName("KdTree/DebugOverlay");
 	mDemoOverlay = 0;
 	mDemoStatus = 0;
@@ -140,10 +146,19 @@
 	initStatsOverlay();
 
-	showDebugOverlay(true);
-
+	if (!mOptions.mDemoInfileName.empty())
+		loadFrames(mOptions.mDemoInfileName, mFrameList);
+
+	if (!mOptions.mDemoInfileName.empty() && mOptions.mDemoMode)
+	{
+		// force 3 second wait when in demo mode - avoids initial low framerate due to loading delays
+		mWaitBeforeDemoStart = 3.0;
+		// set playback icon
+		togglePlayback();
+		// hide all other overlays
+		mStatsOn = false;
+	}
+
+	showDebugOverlay(mStatsOn);
 	setDemoOverlay();
-
-	if (!mDemoInfileName.empty())
-		loadFrames(mDemoInfileName, mFrameList);
 }
 //-----------------------------------------------------------------------
@@ -286,5 +301,5 @@
 void KdTreeAppListener::showDebugOverlay(bool show)
 {
-	if (mDebugOverlay)
+	if (mDebugOverlay && mKdTreeOverlay)
 	{
 		if (show)
@@ -339,4 +354,13 @@
 bool KdTreeAppListener::processUnbufferedKeyInput(const FrameEvent& evt)
 {
+	// ignore all keystrokes except escape when in demo mode
+	if (mOptions.mDemoMode)
+	{
+		if (mInputDevice->isKeyDown(KC_ESCAPE))
+			return false;
+		else
+			return true;
+	}
+
 	// demo recording stuff
 	if (mInputDevice->isKeyDown(KC_F5) && mTimeUntilNextToggle <= 0)
@@ -348,6 +372,6 @@
 	if (mInputDevice->isKeyDown(KC_F6) && mTimeUntilNextToggle <= 0)
 	{
-		if (!mDemoOutfileName.empty() && !mFrameList.empty())
-			saveFrames(mDemoOutfileName, mFrameList);
+		if (!mOptions.mDemoOutfileName.empty() && !mFrameList.empty())
+			saveFrames(mOptions.mDemoOutfileName, mFrameList);
 		mTimeUntilNextToggle = 0.5;
 	}
@@ -615,14 +639,14 @@
 	}
 
-	if (mInputDevice->isKeyDown(KC_O) && mTimeUntilNextToggle <= 0)
-	{
-		LogManager::getSingleton().logMessage("############## Camera Position:");
-		LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getPosition()));
-		LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getOrientation()));
-		LogManager::getSingleton().logMessage("############## Cull Camera Position:");
-		LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getPosition()));
-		LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getOrientation()));
-		mTimeUntilNextToggle = 1.0;
-	}
+	//if (mInputDevice->isKeyDown(KC_P) && mTimeUntilNextToggle <= 0)
+	//{
+	//	LogManager::getSingleton().logMessage("############## Camera Position:");
+	//	LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getPosition()));
+	//	LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getOrientation()));
+	//	LogManager::getSingleton().logMessage("############## Cull Camera Position:");
+	//	LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getPosition()));
+	//	LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getOrientation()));
+	//	mTimeUntilNextToggle = 1.0;
+	//}
 
 	if (mInputDevice->isKeyDown(KC_B) && mTimeUntilNextToggle <= 0)
@@ -687,5 +711,5 @@
 	}
 
-	if (mInputDevice->isKeyDown(KC_P))
+	if (mInputDevice->isKeyDown(KC_O))
 	{
 		mWindow->writeContentsToTimestampedFile("Screenshot",".jpg");
@@ -921,7 +945,7 @@
 		{
 			// Move about 100 units per second,
-			mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
+			mMoveScale = mOptions.mMoveSpeed * evt.timeSinceLastFrame;
 			// Take about 10 seconds for full rotation
-			mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
+			mRotScale = mOptions.mRotateSpeed * evt.timeSinceLastFrame;
 		}
 		mRotX = 0;
@@ -955,4 +979,9 @@
 		}
 	}
+	
+	// do nothing until delay passes to stabilize frame rate
+	mWaitBeforeDemoStart -= evt.timeSinceLastFrame;
+	if (mWaitBeforeDemoStart > 0.0)
+		return true;
 
 	// demo playback - replace position with stored one
@@ -961,4 +990,17 @@
 		// update time
 		mTimeRemaining -= evt.timeSinceLastFrame;
+
+		// store fps when in demo mode
+		if (mOptions.mDemoMode)
+		{
+			// save FPS
+			mTimeUntilNextLogWrite -= evt.timeSinceLastFrame;
+			if (mTimeUntilNextLogWrite <= 0.0)
+			{
+				const RenderTarget::FrameStats& stats = mWindow->getStatistics();
+				mTimeUntilNextLogWrite += 1.0;
+				mDemoFPS.push_back(stats.lastFPS);
+			}
+		}
 
 		static FrameList::iterator lastFrame;
@@ -978,4 +1020,33 @@
 		{
 			togglePlayback();
+			// exit app when in demo mode
+			if (mOptions.mDemoMode)
+			{
+				// write FPS log
+				Real minFPS = Math::POS_INFINITY, maxFPS = 0.0, avgFPS = 0.0;
+				std::ofstream demolog(mOptions.mDemoLogfileName.c_str());
+				if (demolog)
+				{
+					for (std::list<Real>::iterator it = mDemoFPS.begin(); it != mDemoFPS.end(); it ++)
+					{
+						demolog << (int)*it << "\n";
+
+						if (*it < minFPS)
+							minFPS = *it;
+
+						if (*it > maxFPS)
+							maxFPS = *it;
+
+						avgFPS += *it;
+					}
+
+					avgFPS /= mDemoFPS.size();
+
+					demolog << "\n" << (int)minFPS << "\n" << (int)avgFPS << "\n" << (int)maxFPS << "\n";
+
+					demolog.close();
+				}
+				return false;
+			}
 		}
 		// interpolate position & orientation and modify move vectors
@@ -1060,5 +1131,7 @@
 bool KdTreeAppListener::frameEnded(const FrameEvent& evt)
 {
-	updateStats();
+	if (!mOptions.mDemoMode)
+		updateStats();
+
 	return true;
 }
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneManager.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneManager.cpp	(revision 1195)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneManager.cpp	(revision 1204)
@@ -57,8 +57,4 @@
 
 mHierarchyInterface = new KdTreeHierarchyInterface(this, mDestRenderSystem);
-
-// test
-String chc = "CHC";
-setOption("RenderMethod", &chc);
 }
 
