Index: GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTree.h
===================================================================
--- GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTree.h	(revision 1200)
+++ GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTree.h	(revision 1202)
@@ -27,5 +27,17 @@
 public:
 
-	KdTreeApp()	{ mFrameListener = 0; }
+	KdTreeApp()	
+	{ 
+		mFrameListener = 0; 
+		mRenderTargerListener = 0;
+	}
+
+	KdTreeApp(const String& infile, const String& outfile)	
+	{ 
+		mFrameListener = 0; 
+		mRenderTargerListener = 0;
+		mDemoInfileName = infile;
+		mDemoOutfileName = outfile;
+	}
 
 	~KdTreeApp()
@@ -56,4 +68,7 @@
 	int		mSelectEntities;
 
+	String mDemoInfileName;
+	String mDemoOutfileName;
+
 	virtual void setupResources(void);
 
@@ -71,8 +86,10 @@
     virtual bool configure(void);
 
+	/** load scene from file **/
 	bool loadScene(const String& filename);
 	bool loadSceneIV(const String &filename, SceneNode *root, const int index);
+
+	void createMaterials(void);
 private:
-	void createMaterials(void);
 	std::string cat(std::string name, int x, int z)
 	{
Index: GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTreeAppListener.h
===================================================================
--- GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTreeAppListener.h	(revision 1200)
+++ GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTreeAppListener.h	(revision 1202)
@@ -46,4 +46,17 @@
 using namespace Ogre;
 
+struct FrameInfo
+{
+	FrameInfo(Vector3 pos, Quaternion or, Real time):
+	mPosition(pos), mOrientation(or), mElapsedTime(time)
+	{ }
+
+	Vector3 mPosition;
+	Quaternion mOrientation;
+	Real	mElapsedTime;
+};
+
+typedef std::list<FrameInfo> FrameList;
+
 class KdTreeAppListener: public FrameListener, public KeyListener
 {
@@ -110,16 +123,6 @@
 
 	// stuff for walkthrough recording/playback
-	struct FrameInfo
-	{
-		FrameInfo(Vector3 pos, Quaternion or, Real time):
-		mPosition(pos), mOrientation(or), mElapsedTime(time)
-		{ }
-
-		Vector3 mPosition;
-		Quaternion mOrientation;
-		Real	mElapsedTime;
-	};
-
-	typedef std::list<FrameInfo> FrameList;
+	String mDemoInfileName;
+	String mDemoOutfileName;
 
 	enum AppState
@@ -139,18 +142,22 @@
 	OverlayElement * mDemoStatus;
 
+	void setDemoOverlay();
+
 	void toggleRecord();
 	void togglePlayback();
-//	void resetPlayback();
 
 	void saveFrameInfo(Real elapsedTime);
-
-	void setDemoOverlay();
-
-	void saveFramesBinary(const String& filename);
-	void loadFramesBinary(const String& filename);
+	
+	/** save demo frame data to file **/
+	static void saveFrames(const String& filename, FrameList& framelist);
+	static void saveFramesAscii(const String& filename, FrameList& framelist);
+	static void saveFramesBinary(const String& filename, FrameList& framelist);
+
+	/** load demo frame data from file **/
+	static void loadFrames(const String& filename, FrameList& framelist);
+	static void loadFramesAscii(const String& filename, FrameList& framelist);
+	static void loadFramesBinary(const String& filename, FrameList& framelist);
+
 public:
-	void loadFrames(const String& filename);
-	void saveFrames(const String& filename);
-
 	// visualization modes for scene nodes
 	enum 
@@ -163,5 +170,6 @@
 
     // Constructor takes a RenderWindow because it uses that to determine input context
-    KdTreeAppListener(RenderWindow* win, SceneManager* sm, Real rs, Real ms, Real rp,
+    KdTreeAppListener(RenderWindow* win, SceneManager* sm, Real rs, Real ms, Real rp, 
+		const String& infile, const String& outfile, 
 		bool useBufferedInputKeys = false, bool useBufferedInputMouse = false);
 
Index: GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/scripts/TestKdTree.vcproj
===================================================================
--- GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/scripts/TestKdTree.vcproj	(revision 1187)
+++ GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/scripts/TestKdTree.vcproj	(revision 1202)
@@ -22,5 +22,5 @@
 				ImproveFloatingPointConsistency="TRUE"
 				AdditionalIncludeDirectories="..\include;&quot;$(OGRE_PATH)\Samples\Common\include&quot;;&quot;$(OGRE_PATH)\OgreMain\include&quot;;..\..\..\..\..\..\Lib\Vis\OnlineCullingCHC\IVReader\include"
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;GTP_VISIBILITY_MODIFIED_OGRE;KDTREE_FASTSTART"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;GTP_VISIBILITY_MODIFIED_OGRE"
 				MinimalRebuild="TRUE"
 				BasicRuntimeChecks="3"
@@ -85,5 +85,5 @@
 				OptimizeForWindowsApplication="TRUE"
 				AdditionalIncludeDirectories="..\include;&quot;$(OGRE_PATH)\Samples\Common\include&quot;;&quot;$(OGRE_PATH)\OgreMain\include&quot;;..\..\..\..\..\..\Lib\Vis\OnlineCullingCHC\IVReader\include"
-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GTP_VISIBILITY_MODIFIED_OGRE;KDTREE_FASTSTART"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GTP_VISIBILITY_MODIFIED_OGRE"
 				StringPooling="TRUE"
 				MinimalRebuild="TRUE"
Index: GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTree.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTree.cpp	(revision 1200)
+++ GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTree.cpp	(revision 1202)
@@ -9,4 +9,7 @@
 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
@@ -16,6 +19,21 @@
 #endif
 	{
+#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);
+
+		// Create application object
+		KdTreeApp app(infile, outfile);
+#else
+		// TODO: unix-style getopt
 		// Create application object
 		KdTreeApp app;
+#endif
 
 		SET_TERM_HANDLER;
@@ -42,4 +60,126 @@
 #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
@@ -94,4 +234,11 @@
 	tmp = cfDeath.getSetting("rotatespeed");
 	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");
 
 	ExampleApplication::setupResources();
@@ -275,5 +422,5 @@
 void KdTreeApp::createFrameListener(void)
 {
-	mFrameListener = new KdTreeAppListener(mWindow, mSceneMgr, mRotateSpeed, mMoveSpeed, mRotationPeriod);
+	mFrameListener = new KdTreeAppListener(mWindow, mSceneMgr, mRotateSpeed, mMoveSpeed, mRotationPeriod, mDemoInfileName, mDemoOutfileName);
 	mFrameListener->showDebugOverlay( true );
 	mRoot->addFrameListener(mFrameListener);
Index: GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTreeAppListener.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTreeAppListener.cpp	(revision 1200)
+++ GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTreeAppListener.cpp	(revision 1202)
@@ -71,5 +71,6 @@
 // Constructor takes a RenderWindow because it uses that to determine input context
 KdTreeAppListener::KdTreeAppListener(RenderWindow* win, SceneManager* sm, Real rs, Real ms, Real rp,
-	bool useBufferedInputKeys, bool useBufferedInputMouse)
+									 const String& infile, const String& outfile,
+									 bool useBufferedInputKeys, bool useBufferedInputMouse)
 {
 	mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
@@ -102,4 +103,7 @@
 	mVizCamTransVect = Vector3::ZERO;
 	mSeqNum = 0;
+
+	mDemoInfileName = infile;
+	mDemoOutfileName = outfile;
 
 	mAppState = AS_NORMAL;
@@ -140,6 +144,6 @@
 	setDemoOverlay();
 
-	//loadFrames("demo-in.txt");
-	loadFramesBinary("demo-in.bin");
+	if (!mDemoInfileName.empty())
+		loadFrames(mDemoInfileName, mFrameList);
 }
 //-----------------------------------------------------------------------
@@ -153,11 +157,4 @@
 	{
 		PlatformManager::getSingleton().destroyInputReader( mInputDevice );
-	}
-
-	// save demo
-	if (!mFrameList.empty())
-	{
-		//saveFrames("demo-out.txt");
-		saveFramesBinary("demo-out.bin");
 	}
 }
@@ -346,4 +343,11 @@
 	{
 		toggleRecord();
+		mTimeUntilNextToggle = 0.5;
+	}
+
+	if (mInputDevice->isKeyDown(KC_F6) && mTimeUntilNextToggle <= 0)
+	{
+		if (!mDemoOutfileName.empty() && !mFrameList.empty())
+			saveFrames(mDemoOutfileName, mFrameList);
 		mTimeUntilNextToggle = 0.5;
 	}
@@ -1146,22 +1150,20 @@
 }
 
+
 //-----------------------------------------------------------------------------
-//void KdTreeAppListener::resetPlayback()
-//{
-//	if (!mFrameList.empty())
-//	{
-//		mCurrFrame = mFrameList.begin();
-//		mTimeRemaining = mCurrFrame->mElapsedTime;
-//	}
-//}
+void KdTreeAppListener::saveFrames(const String& filename, FrameList& framelist)
+{
+	size_t dot = filename.find_last_of(".");
+	String ext = filename.substr(dot + 1, filename.length());
+	if (ext == "txt")
+		saveFramesAscii(filename, framelist);
+	else if (ext == "bin")
+		saveFramesBinary(filename, framelist);
+	else
+		OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid extension for demo file: " + ext, "KdTreeApp::loadFrames");
+}
 
 //-----------------------------------------------------------------------------
-void KdTreeAppListener::saveFrameInfo(Real elapsedTime)
-{
-	mFrameList.push_back(FrameInfo(mCamNode->getPosition(), mCamNode->getOrientation(), elapsedTime));
-}
-
-//-----------------------------------------------------------------------------
-void KdTreeAppListener::saveFrames(const String& filename)
+void KdTreeAppListener::saveFramesAscii(const String& filename, FrameList& framelist)
 {
 	// open file
@@ -1173,6 +1175,6 @@
 	}
 
-	FrameList::iterator it = mFrameList.begin();
-	FrameList::iterator end = mFrameList.end();
+	FrameList::iterator it = framelist.begin();
+	FrameList::iterator end = framelist.end();
 
 	// dump values
@@ -1190,5 +1192,5 @@
 
 //-----------------------------------------------------------------------------
-void KdTreeAppListener::saveFramesBinary(const String& filename)
+void KdTreeAppListener::saveFramesBinary(const String& filename, FrameList& framelist)
 {
 	std::ofstream dest(filename.c_str(), std::ios_base::out | std::ios_base::binary);
@@ -1200,8 +1202,8 @@
 	}
 
-	FrameList::iterator it = mFrameList.begin();
-	FrameList::iterator end = mFrameList.end();
-
-	size_t size = sizeof(Real);
+	FrameList::iterator it = framelist.begin();
+	FrameList::iterator end = framelist.end();
+
+	int size = sizeof(Real);
 
 	// dump values
@@ -1223,5 +1225,18 @@
 
 //-----------------------------------------------------------------------------
-void KdTreeAppListener::loadFrames(const String& filename)
+void KdTreeAppListener::loadFrames(const String& filename, FrameList& framelist)
+{
+	size_t dot = filename.find_last_of(".");
+	String ext = filename.substr(dot + 1, filename.length());
+	if (ext == "txt")
+		loadFramesAscii(filename, framelist);
+	else if (ext == "bin")
+		loadFramesBinary(filename, framelist);
+	else
+		OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid extension for demo file: " + ext, "KdTreeApp::loadFrames");
+}
+
+//-----------------------------------------------------------------------------
+void KdTreeAppListener::loadFramesAscii(const String& filename, FrameList& framelist)
 {
 	// open file
@@ -1234,5 +1249,5 @@
 
 	// clear the list
-	mFrameList.clear();
+	framelist.clear();
 
 	Vector3 pos;
@@ -1253,9 +1268,9 @@
 		src >> time;
 
-		mFrameList.push_back(FrameInfo(pos, or, time));
+		framelist.push_back(FrameInfo(pos, or, time));
 	}
 
 	// HACK pop last frame, was doubled while reading
-	mFrameList.pop_back();
+	framelist.pop_back();
 
 	src.close();
@@ -1263,5 +1278,5 @@
 
 //-----------------------------------------------------------------------------
-void KdTreeAppListener::loadFramesBinary(const String& filename)
+void KdTreeAppListener::loadFramesBinary(const String& filename, FrameList& framelist)
 {
 	// open file
@@ -1274,7 +1289,7 @@
 
 	// clear the list
-	mFrameList.clear();
-
-	size_t size = sizeof(Real);
+	framelist.clear();
+
+	int size = sizeof(Real);
 
 	Vector3 pos;
@@ -1293,12 +1308,19 @@
 		src.read((char *)&time, size);
 
-		mFrameList.push_back(FrameInfo(pos, or, time));
+		framelist.push_back(FrameInfo(pos, or, time));
 	}
 
 	// HACK pop last frame, was doubled while reading
-	mFrameList.pop_back();
+	framelist.pop_back();
 
 	src.close();
 }
+
+//-----------------------------------------------------------------------------
+void KdTreeAppListener::saveFrameInfo(Real elapsedTime)
+{
+	mFrameList.push_back(FrameInfo(mCamNode->getPosition(), mCamNode->getOrientation(), elapsedTime));
+}
+
 //-----------------------------------------------------------------------------
 void KdTreeAppListener::setDemoOverlay()
