diff --git a/CAVE/NOMADCaveT/CMakeLists.txt b/CAVE/NOMADCaveT/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..456aede07a5af75203ceb0b9b47494b75c3b4114
--- /dev/null
+++ b/CAVE/NOMADCaveT/CMakeLists.txt
@@ -0,0 +1,93 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+
+# Project Name
+PROJECT(NOMADCaveT)
+include(CheckCXXCompilerFlag)
+CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
+if(COMPILER_SUPPORTS_CXX11)
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")        
+else()
+	MESSAGE(FATAL_ERROR "C++ 11 is required")
+endif()
+
+set(project_LIBRARIES)
+set(project_INCLUDES)
+set(project_DEFINITIONS -DCAVE -DINDICESGL32)
+
+#########################################################
+# ADD PTHREAD
+#########################################################
+list(APPEND project_LIBRARIES pthread)
+find_package(synch REQUIRED)
+#list(APPEND project_INCLUDES ${SYNCH_INCLUDE_DIRS})
+list(APPEND project_LIBRARIES synch)
+
+find_package(screen REQUIRED )
+
+#plib
+#find_library (PLIB_UL plibul HINTS $ENV{PLIBDIR} PATH_SUFFIXES lib REQUIRED)
+#find_library (PLIB_FNT plibfnt HINTS $ENV{PLIBDIR} PATH_SUFFIXES lib REQUIRED)
+#set (PLIB_LIBRARIES ${PLIB_FNT} ${PLIB_UL})
+#message ("plib_libraries = ${PLIB_LIBRARIES} ")
+#find_path (PLIB_INCLUDE_DIR plib/fnt.h HINTS $ENV{PLIBDIR} PATH_SUFFIXES include REQUIRED)
+#message ("plib_include = ${PLIB_INCLUDE_DIR} ")
+
+#freetype2
+INCLUDE (FindPkgConfig)
+pkg_search_module(FREETYPE REQUIRED freetype2)
+message ("freetype LDFLAGS ${FREETYPE_LDFLAGS}")
+message ("freetype CFLAGS ${FREETYPE_CFLAGS}")
+#target_link_libraries(demoCO2CaO PUBLIC screen)
+#target_link_libraries(demoCO2CaO_server PUBLIC screen)
+#list(APPEND project_INCLUDES ${SCREEN_INCLUDE_DIRS})
+list(APPEND project_LIBRARIES screen)
+
+
+
+#########################################################
+# Include Files
+#########################################################
+include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src)
+include_directories(${project_INCLUDES})
+include_directories(${FREETYPE_INCLUDE_DIRS})
+set(HEADERS
+
+)
+set(SOURCES
+       src/main.cpp src/textRendering.cpp
+	src/NOMADVRLib/atoms.cpp	src/NOMADVRLib/CompileGLShader.cpp	
+	src/NOMADVRLib/polyhedron.cpp   src/NOMADVRLib/UnitCellShaders.cpp
+	src/NOMADVRLib/atomsGL.cpp	src/NOMADVRLib/ConfigFile.cpp	
+	src/NOMADVRLib/TessShaders.cpp	
+	src/happyhttp/happyhttp.cpp
+)
+
+
+
+set(HEADERS_SERVER
+)
+
+set(SOURCES_SERVER
+	src/main_server.cpp src/textRendering.cpp
+)
+
+
+
+########################################################
+# Add definitions
+#########################################################
+add_definitions(${project_DEFINITIONS})
+
+########################################################
+# Linking & stuff
+#########################################################
+
+
+add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
+target_link_libraries(${PROJECT_NAME} ${project_LIBRARIES} ${FREETYPE_LDFLAGS})
+add_executable(${PROJECT_NAME}_server ${SOURCES_SERVER} ${HEADERS_SERVER})
+target_link_libraries(${PROJECT_NAME}_server ${project_LIBRARIES} ${FREETYPE_LIBRARIES})
+
+
diff --git a/CAVE/NOMADCaveT/clean.sh b/CAVE/NOMADCaveT/clean.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4349eabc9946a2a4f536d392a088431d931a01c5
--- /dev/null
+++ b/CAVE/NOMADCaveT/clean.sh
@@ -0,0 +1 @@
+for i in `seq -w 1 10`; do ssh caverender${i}-lnx killall demoCO2CaO; done
diff --git a/CAVE/NOMADCaveT/readme.txt b/CAVE/NOMADCaveT/readme.txt
new file mode 100644
index 0000000000000000000000000000000000000000..74c6b86239d7c00b97d2515ff34730c67d8c6645
--- /dev/null
+++ b/CAVE/NOMADCaveT/readme.txt
@@ -0,0 +1,28 @@
+This demo is based on 
+https://svn.lrz.de/repos/v2t/projects/demos/demoBunge/
+Revision 1538
+
+For use in LRZ CAVE and Powerwall.
+
+Use in suse:
+Run once:
+/sw/bin/remove_cursor
+On CAVE Master 1 (linux)
+/sw/DTrack2/2.8.1/bin/DTrack2.bin
+	(connect, activate, close, do not stop measurement)
+/sw/equalizer/1.8.0/bin/vrpn_server -v -f /sw/config/vrpn-lrz-cave.cfg
+On CAVE Master 1 (windows)
+Dtrack2 icon on the desktop
+	(connect, activate, close, do not stop measurement)
+vrpn: startvrpn in the desktop complains that vrpn_server.exe does not exist. Check this.
+
+use in ubuntu:
+/sw/vrpn/latest/bin/vrpn_server -v -f  /sw/config/vrpn/lrz_cave.cfg 
+
+
+Run demo (on cavemaster 2): 
+./demoBunge_server /sw/config/mlib/cave_2.conf
+Run demo (on cavemaster 1):
+./demoBunge_server /sw/config/mlib/cave_1.conf
+
+WAIT 5 minutes
diff --git a/CAVE/NOMADCaveT/src/defines.h b/CAVE/NOMADCaveT/src/defines.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba5c426b1ddd21307505003dc6271a7a80e9e451
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/defines.h
@@ -0,0 +1,10 @@
+#ifndef __DEFINES_H
+#define __DEFINES_H
+
+#define FONT "/usr/share/fonts/truetype/freefont/FreeSans.ttf"
+//#define FONT "/usr/share/fonts/truetype/DejaVuSans.ttf"
+#define SHADERPATH "/home/demos/nomad_rgarcia/m3d/"
+
+#define PATHSIZE 256
+
+#endif
diff --git a/CAVE/NOMADCaveT/src/main.cpp b/CAVE/NOMADCaveT/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4718435d00a20978c77d3698fc2ba9c8450a8de8
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/main.cpp
@@ -0,0 +1,802 @@
+#include <string>
+
+#include <m3drenderer.h>
+#include <functional>
+#include <iostream>
+#include <m3dtextureHandler.h>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/transform.hpp>
+#include <glm/gtx/matrix_decompose.hpp>
+#include <glm/gtx/string_cast.hpp>
+#include <glm/gtx/vector_angle.hpp> 
+#include <m3dnode.h>
+#include <chrono>
+#include <renderNode.h>
+#include <synchObject.h>
+#include <m3dFileIO.h>
+#include <m3dtextureHandler.h>
+#include <m3dmeshHandler.h>
+#include <m3duploadingInterface.h>
+#include <m3ddefaultShader.h>
+
+#include "textRendering.hpp"
+#include "selectedPoints.hpp"
+
+#include "NOMADVRLib/ConfigFile.h"
+#include "NOMADVRLib/atoms.hpp"
+#include "NOMADVRLib/atomsGL.h"
+
+#include "NOMADVRLib/TessShaders.h"
+#include "NOMADVRLib/UnitCellShaders.h"
+
+#include "NOMADVRLib/CompileGLShader.h"
+
+#include "defines.h"
+
+#define TESSSUB 16
+
+void eprintf( const char *fmt, ... )
+{
+	va_list args;
+	char buffer[ 2048 ];
+
+	va_start( args, fmt );
+	vsprintf( buffer, fmt, args );
+	va_end( args );
+
+	fprintf(stderr, "%s\n", buffer );
+}
+
+typedef std::chrono::high_resolution_clock Clock;
+ using namespace m3d;
+
+class sceneManager{
+public:
+    sceneManager(m3d::Renderer* ren, synchlib::renderNode* node, const char *NOMADconfigFile);
+    ~sceneManager();
+    void displayFunction();
+    void keyboardFunction(char key, int x, int y);
+    void keyReleaseFunction(char key, int x, int y);
+    void setCDPSyncher(std::shared_ptr<synchlib::SynchObject<int> > sy){m_pCurrentDataPosSyncher = sy; m_pCurrentDataPosSyncher->setData(0);}
+    void setCDTPSyncher(std::shared_ptr<synchlib::SynchObject<int> > sy){m_pCurrentDataTimeSyncher = sy; m_pCurrentDataTimeSyncher->setData(0);}
+    void setCDPtSyncher(std::shared_ptr<synchlib::SynchObject<SelectedPoints> > sy)
+	{
+	m_pCurrentDataPointSyncher = sy; 
+	SelectedPoints p={0};
+	m_pCurrentDataPointSyncher->setData(p);
+	}
+
+private:
+    m3d::Renderer* m_ren;
+    synchlib::renderNode* m_node;
+
+    int counter = 0;
+    Clock::time_point t1 = Clock::now();
+
+
+
+
+    glm::mat4 m_preMat;
+    glm::mat4 m_scalemat;
+    glm::mat4 m_scalematSky;
+    std::shared_ptr<UploadingInterface> m_uploading;
+
+TextRendering::Text text;
+
+GLuint PointVAO, PointVBO;
+
+std::shared_ptr<synchlib::SynchObject<int> > m_pCurrentDataPosSyncher;
+std::shared_ptr<synchlib::SynchObject<int> > m_pCurrentDataTimeSyncher;
+std::shared_ptr<synchlib::SynchObject<SelectedPoints> > m_pCurrentDataPointSyncher;
+
+int m_oldDataPos = 0;
+int m_oldTime = 0;
+
+void glDraw(glm::mat4 pvmat, glm::mat4 viewmat, int curDataPos, 
+	const SelectedPoints& sp);
+
+const char * configFile="/home/demos/nomad_rgarcia-ubuntu/shell.ncfg";
+void SetConfigFile (const char * f) {
+configFile=f;
+}
+int error=0;
+GLuint textures[2]; // white, atoms
+	//if no tesselation is available, we still need the tess atoms for the trajectories!
+	GLuint *AtomTVAO=0, *AtomTBuffer=0, *AtomVAO=0, *AtomBuffer=0, *AtomIndices=0,//[2], atoms, extraatoms
+		UnitCellVAO, UnitCellBuffer, UnitCellIndexBuffer;
+GLuint			AtomsP, UnitCellP; // framework does not provide support for tesselation and provides many things we don't need.
+	GLint		AtomMatrixLoc, UnitCellMatrixLoc, UnitCellColourLoc;
+bool hasTess=true;
+
+void RenderAtoms(const float *m);
+void RenderUnitCell(const glm::mat4 eyeViewProjection);
+void RenderAtomTrajectoriesUnitCell();
+void RenderAtomTrajectories(const glm::mat4 eyeViewProjection);
+};
+
+
+sceneManager::sceneManager(m3d::Renderer* ren, synchlib::renderNode* node,
+	const char *c){
+GLenum err;
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor 0: "<<__FUNCTION__<<" OpenGL error " << err << std::endl;
+	}
+
+     m_ren = ren;// m_th = th;
+    m_node = node;
+	if (c)
+		SetConfigFile (c);
+
+    m_preMat = glm::mat4_cast(glm::rotation(glm::vec3(0.,0.,1.),glm::vec3(0.,1.,0.)));
+   m_scalemat = glm::scale(m_scalemat,glm::vec3(0.1,0.1,0.1));
+   m_scalematSky = glm::scale(m_scalematSky,glm::vec3(0.05,0.05,0.05));
+	
+	std::string s(configFile);
+	chdir(s.substr(0, s.find_last_of("\\/")).c_str());
+
+	if ((error=loadConfigFile(configFile))<0) {
+		if (-100<error) {
+			fprintf (stderr, "%s", loadConfigFileErrors[-error]);
+			fprintf (stderr, "Config file reading error");
+		}else if (-200<error) {
+			fprintf (stderr, "%s", readAtomsXYZErrors[-error-100]);
+			fprintf (stderr, "XYZ file reading error");
+		}else if (-300<error) {
+			fprintf (stderr, "%s", readAtomsCubeErrors[-error-200]);
+			fprintf (stderr, "Cube file reading error");
+		}else {fprintf (stderr, "%s", readAtomsJsonErrors[-error-300]);
+			fprintf (stderr, "Json reading error");
+		}
+	}
+
+glGenTextures(2, textures);
+    //white
+    unsigned char data2[4]={255,255,255,255}; //white texture for non-textured meshes
+    glBindTexture(GL_TEXTURE_2D, textures[0]);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
+
+    // Create the programs
+	if (!PrepareUnitCellShader (&UnitCellP, &UnitCellMatrixLoc, &UnitCellColourLoc)) {
+		eprintf("OneTimeInit, failure compiling Unit Cell Shader");
+		error=-401;
+		return ;
+	}
+	
+	if (!PrepareAtomShader(&AtomsP, &AtomMatrixLoc)) {
+		hasTess=false;
+		if (!solid)
+			solid=new Solid(Solid::Type::Icosahedron);
+		if (!PrepareAtomShaderNoTess(&AtomsP, &AtomMatrixLoc)) {
+			error=-402;
+			eprintf ("PrepareAtomShaderNoTess failed");
+		}
+	};
+
+	//atom texture
+	int e;
+	
+	e=atomTexture(textures[1]);
+	if (e!=GL_NO_ERROR) {
+		eprintf ("atomTexture error %d", e);
+		error=-403;
+	}
+
+	e=SetupAtoms(&AtomTVAO, &AtomTBuffer);
+	if (e!=GL_NO_ERROR) {
+		eprintf ("SetupAtoms error %d", e);
+		error=-404;
+	}
+
+	if (!hasTess)
+		e=SetupAtomsNoTess(&AtomVAO, &AtomBuffer, &AtomIndices);
+
+	if (e!=GL_NO_ERROR) {
+		eprintf ("SetupAtomsNoTess error %d, tess=%d", e, hasTess);
+		error=-405;
+	}
+	e=SetupUnitCell(&UnitCellVAO, &UnitCellBuffer, &UnitCellIndexBuffer);
+	if (e!=GL_NO_ERROR) {
+		eprintf ("SetupUnitCell error %d", e);
+		error=-406;
+	}
+
+//for painting selected points 
+	glGenVertexArrays(1, &PointVAO);
+	glGenBuffers(1, &PointVBO);
+glBindVertexArray(PointVAO);
+glBindBuffer(GL_ARRAY_BUFFER, PointVBO);
+//x y z r g b (6), 5 points (wand + 4 selected points)
+glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 5, NULL, GL_DYNAMIC_DRAW);
+glEnableVertexAttribArray(0);
+glEnableVertexAttribArray(1);
+glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);
+glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 
+	(char*)0+3*sizeof(float));
+glBindBuffer(GL_ARRAY_BUFFER, 0);
+glBindVertexArray(0);      
+
+//end for painting selected points
+
+	M3DFileIO fileio;
+	std::shared_ptr<Node> UploadingRoot = Node::create();
+
+
+	
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor 1: "<<__FUNCTION__<<" OpenGL error " << err << std::endl;
+	}
+
+	if (!text.init(FONT))
+		std::cerr << "Font loading error " << FONT << std::endl;
+
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor nach shader zeug: "<<__FUNCTION__<<
+			" OpenGL error" << err << std::endl;
+	}
+
+    std::shared_ptr<m3d::MeshHandler> mHandler = std::make_shared<MeshHandler>(ren->getDisplay(),*(ren->getContext()),true,false);
+    std::shared_ptr<TextureHandler> tHandler = std::make_shared<TextureHandler>((ren->getDisplay()),*(ren->getContext()),true);
+    mHandler->start();
+    tHandler->start();
+
+
+
+    m_uploading = std::make_shared<UploadingInterface>(mHandler,tHandler);
+    m_uploading->setRootNode(UploadingRoot);
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor nach set root: "<<__FUNCTION__<<" OpenGL error " << err << std::endl;
+	}
+    std::cout<<"start"<<std::endl;
+    m_uploading->start();
+    std::cout<<"started"<<std::endl;
+    sleep(2);
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor nach start: "<<__FUNCTION__<<" OpenGL error " << err << std::endl;
+	}
+}
+
+sceneManager::~sceneManager(){
+m_uploading->quit();
+
+}
+
+void sceneManager::glDraw(glm::mat4 pvmat, glm::mat4 viewMat, int curDataPos,
+	const SelectedPoints& selectedPoints) {
+
+	GLenum err;
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+   	while ((err = glGetError()) != GL_NO_ERROR) {
+   		std::cerr << "disp vor draw: "<<__FUNCTION__<<" OpenGL error " << err << std::endl;
+   	}
+
+
+//here the low-level gl code can be added
+glm::mat4 wand;
+m_node->getWandTrafo(wand);
+//rgh FIXME this should be done only once.
+glm::vec3 scale;
+glm::quat rotation;
+glm::vec3 translation;
+glm::vec3 skew;
+glm::vec4 perspective;
+glm::decompose(wand, scale, rotation, translation, skew, perspective);
+
+glm::mat4 st;
+m_node->getSceneTrafo(st);
+//fprintf (stderr, "st = ");
+//for (int i=0;i<4;i++)
+//	for (int j=0;j<4;j++)
+//		fprintf (stderr, "%f ", st[i][j]);
+//fprintf(stderr, "\n");
+//rgh FIXME: cache these numbers, do not calculate twice per frame
+if(error)
+	return;
+if (has_abc) {
+	RenderUnitCell(pvmat*st);
+} else {
+	//atom trajectories
+	RenderAtomTrajectories(pvmat*st);
+}
+
+}
+
+void sceneManager::displayFunction(){
+	GLenum err;
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "disp 1: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+	bool ttt = false;
+    glm::mat4 pvmatL, pvmatR;
+
+    m_node->getProjectionMatrices(pvmatL,pvmatR);
+    glm::mat4 viewMat;
+    m_node->getSceneTrafo(viewMat);
+    int curDataPos;
+    m_pCurrentDataPosSyncher->getData(curDataPos);
+    int timePos;
+    m_pCurrentDataTimeSyncher->getData(timePos);
+    if(m_oldTime != timePos){
+    	m_oldTime = timePos%TIMESTEPS;
+	if (m_oldTime<0)
+		m_oldTime+=TIMESTEPS;
+	//eprintf ("m_oldtime=%d", m_oldTime);
+    }
+	SelectedPoints selectedPoints;
+	m_pCurrentDataPointSyncher->getData(selectedPoints);
+
+    auto t2 = Clock::now();
+    auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count();
+    if(dur > 1000){
+        std::cout<<"################################ fps: "<<(double)counter/((double) dur / (double) 1000)<<std::endl;
+        counter = 0;
+        t1 = Clock::now();
+        std::cout<<"time: "<<timePos<<" iso: "<<curDataPos<<std::endl;
+    }
+
+
+    if(m_oldDataPos != curDataPos){
+    	//rgh: no lods in this demo //m_posData->setLOD(curDataPos[0]);
+    	m_oldDataPos = curDataPos;
+    }
+    glm::mat4 user; m_node->getUserTrafo(user);
+
+//rgh: parameter not needed in this demo
+//    m_posData->getShader()->setUserPos(glm::vec3(user[3]));
+//    m_NegData->getShader()->setUserPos(glm::vec3(user[3]));
+
+
+    glm::mat4 viewRotOnly = viewMat;
+    viewRotOnly[3] = glm::vec4(0.,0.,0.,1.);
+
+
+
+    glDrawBuffer(GL_BACK_LEFT);
+    {
+	glDraw(pvmatL, viewMat, curDataPos, selectedPoints);
+    }
+
+    glDrawBuffer(GL_BACK_RIGHT);
+   {
+	glDraw(pvmatR, viewMat, curDataPos, selectedPoints);
+    }
+   GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE,0);
+   glClientWaitSync(fence,GL_SYNC_FLUSH_COMMANDS_BIT,GL_TIMEOUT_IGNORED);
+
+
+    if(!m_node->synchFrame()){
+
+       m_ren->stopMainLoop();
+       return;
+    }
+
+    m_ren->swapBuffer();
+
+
+    ++counter;
+
+}
+
+
+void sceneManager::keyboardFunction(char key, int x, int y){
+
+switch(key){
+
+
+case 27:
+    m_ren->stopMainLoop();
+    break;
+}
+}
+
+void sceneManager::keyReleaseFunction(char key, int x, int y){
+    switch(key){
+
+    }
+}
+
+
+
+void InitGraphics(void)
+{
+	glClearColor (BACKGROUND[0], BACKGROUND[1], BACKGROUND[2], 1.0);
+	glClearDepth(1.0f);				// Depth Buffer Setup
+	glEnable(GL_DEPTH_TEST);		// Enables Depth Testing
+	glDepthFunc(GL_LEQUAL);			// The Type Of Depth Test To Do
+	glDisable(GL_BLEND);
+
+}
+
+
+
+
+
+int main(int argc, char** argv){
+	if(argc < 4){
+		std::cout<<"Not enough arguments! Start with "<<argv[0]<<" <own hostname/IP> <path to mlib configfile> <path to ncfg configfile>"<<std::endl;
+		exit(0);
+	}
+
+	TMPDIR="/tmp/"; //needs to be a non-shared directory, as we have 
+	//concurrent loading from the web
+
+    bool stereo = true;
+    bool debug = true;
+    m3d::Renderer* ren = new m3d::Renderer(stereo,debug);
+
+    std::string file =argv[2];
+    synchlib::caveConfig conf(file);
+    std::stringstream ownIP;
+    ownIP<< argv[1];
+    if(argc > 3){
+    	ownIP<<"_"<<argv[3];
+    }
+
+	synchlib::renderNode* node = new synchlib::renderNode(file,argc, argv);
+
+    std::cout<<conf.m_wall_conf[ownIP.str()].wall_geo[0]<<"    "<<conf.m_wall_conf[ownIP.str()].wall_geo[1]<<std::endl;
+    ren->createWindow("NOMADCaveT",conf.m_wall_conf[ownIP.str()].wall_geo[0],conf.m_wall_conf[ownIP.str()].wall_geo[1]);
+//http://stackoverflow.com/questions/8302625/segmentation-fault-at-glgenvertexarrays-1-vao
+	glewExperimental = GL_TRUE; 
+    GLenum err = glewInit();
+    if (GLEW_OK != err)
+    {
+      /* Problem: glewInit failed, something is seriously wrong. */
+      fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
+
+    }
+
+
+
+	{
+		sceneManager sceneM(ren,node, argv[4]);
+
+
+		std::shared_ptr<synchlib::SynchObject<int> > currentDataPosSyncher = synchlib::SynchObject<int>::create();
+		sceneM.setCDPSyncher(currentDataPosSyncher);
+		node->addSynchObject(currentDataPosSyncher,synchlib::renderNode::RECEIVER,0);
+
+		std::shared_ptr<synchlib::SynchObject<int> > currentDataTimeSyncher = synchlib::SynchObject<int>::create();
+		sceneM.setCDTPSyncher(currentDataTimeSyncher);
+		node->addSynchObject(currentDataTimeSyncher,synchlib::renderNode::RECEIVER,0);
+
+		std::shared_ptr<synchlib::SynchObject<SelectedPoints> > 
+			currentDataPointsSyncher = synchlib::SynchObject<SelectedPoints>::create();
+		sceneM.setCDPtSyncher(currentDataPointsSyncher);
+		node->addSynchObject(currentDataPointsSyncher,synchlib::renderNode::RECEIVER,0);
+
+		std::function<void(void)> dispFunc = std::bind(&sceneManager::displayFunction,&sceneM);
+		std::function<void(char,int,int)>  keyFunc = std::bind(&sceneManager::keyboardFunction,&sceneM,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
+		std::function<void(char,int,int)>  keyRFunc = std::bind(&sceneManager::keyReleaseFunction,&sceneM,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
+		ren->setDisplayFunction(dispFunc);
+		ren->setIdleFunction(dispFunc);
+		ren->setKeyPressFunction(keyFunc);
+		ren->setAllowKeyboardAutoRepressing(false);
+		ren->setKeyReleaseFunction(keyRFunc);
+//		ren->toggleFullscreen();
+		node->init();
+
+		node->startSynching();
+		while ((err = glGetError()) != GL_NO_ERROR) {
+			std::cerr <<" vor init: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+		}
+		InitGraphics();
+		while ((err = glGetError()) != GL_NO_ERROR) {
+			std::cerr << "initGraphics: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+		}
+		ren->mainLoop();
+	}
+    delete ren;
+
+    node->stopSynching();
+    delete node;
+
+}
+
+void sceneManager::RenderAtoms(const float *m) //m[16]
+{
+	//return;
+	//eprintf ("RenderAtoms start numatoms %d, timestep %d", numAtoms[m_oldTime], m_oldTime);
+	if (solid)
+		eprintf ("solid nfaces %d", solid->nFaces);
+	int e;
+	if (numAtoms==0)
+		return;
+	
+	if (hasTess) {
+		glBindTexture(GL_TEXTURE_2D, textures[1]);
+		glUseProgram(AtomsP);
+		//eprintf ("1");
+		float levelso[4] = { TESSSUB, TESSSUB, TESSSUB, TESSSUB };
+		float levelsi[2] = { TESSSUB, TESSSUB};
+		//eprintf ("2");
+		glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL,levelso);
+		glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL,levelsi);
+		glPatchParameteri(GL_PATCH_VERTICES, 1);
+		//eprintf ("3");
+		glBindVertexArray(AtomTVAO[0]);
+		glEnableVertexAttribArray(0);
+		glEnableVertexAttribArray(1);
+		//eprintf ("4");
+		glBindBuffer(GL_ARRAY_BUFFER, AtomTBuffer[0]);
+		//eprintf ("5");
+		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 
+			4 * sizeof(float), (const void *)(0));
+		//eprintf ("6");
+		glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 
+			4 * sizeof(float), (const void *)(3 * sizeof(float)));
+		//eprintf ("7");
+		//trans.translate(iPos).rotateX(-90).translate(UserPosition);
+		//Matrix4 transform = GetCurrentViewProjectionMatrix(nEye)*trans;
+		//Matrix4 mv=GetCurrentViewMatrix(nEye)*trans;
+
+		glUniformMatrix4fv(AtomMatrixLoc, 1, GL_FALSE, m);
+
+		//glUniformMatrix4fv(m_nAtomMVLocation, 1, GL_FALSE, mv.get());
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("Gl error 4 timestep =%d: %d, %s\n", m_oldTime, 
+				e, gluErrorString(e));
+		//eprintf ("8");
+		if (m_oldTime==0)
+			glDrawArrays(GL_PATCHES, 0, numAtoms[0]);
+		else
+			glDrawArrays(GL_PATCHES, numAtoms[m_oldTime-1], 
+				numAtoms[m_oldTime]-numAtoms[m_oldTime-1]);
+		//eprintf ("9");
+	
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("Gl error after RenderAtoms timestep =%d: %d, %s\n", 
+				m_oldTime, e, gluErrorString(e));
+
+		//now cloned atoms
+		if (numClonedAtoms!=0 && m_oldTime==0) {
+			//eprintf ("10");
+			glBindVertexArray(AtomTVAO[1]);
+			//eprintf ("11");
+			glDrawArrays(GL_PATCHES, 0, numClonedAtoms);
+			//eprintf ("12");
+			if ((e = glGetError()) != GL_NO_ERROR)
+				eprintf("Gl error after Render cloned Atom timestep =%d: %d, %s\n", 
+					m_oldTime, e, gluErrorString(e));
+		}
+
+	} else { //no tess
+		glBindVertexArray(AtomVAO[0]);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, AtomIndices[0]);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("1 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+	glBindBuffer(GL_ARRAY_BUFFER, AtomBuffer[0]);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("2 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+
+	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (const void *)0);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("3 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+
+	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(3*sizeof(float)));
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("4 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+
+	glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(6 * sizeof(float)));
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("5 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+
+		glBindTexture(GL_TEXTURE_2D, textures[1]);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("6 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+
+		glUseProgram(AtomsP);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("7 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+
+		glUniformMatrix4fv(AtomMatrixLoc, 1, GL_FALSE, m);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("8 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+
+		if (m_oldTime==0) {
+			glDrawElements(GL_TRIANGLES, numAtoms[m_oldTime]* 3 * solid->nFaces, 
+#ifndef INDICESGL32				
+				GL_UNSIGNED_SHORT,
+#else
+				GL_UNSIGNED_INT,
+#endif	
+				0);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("9 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+
+		} else {
+			glDrawElements(GL_TRIANGLES, (numAtoms[m_oldTime]-numAtoms[m_oldTime-1]) * 3 * solid->nFaces,
+#ifndef INDICESGL32				
+				GL_UNSIGNED_SHORT, (void*)(numAtoms[m_oldTime-1]*sizeof(unsigned short)*3*solid->nFaces)
+#else
+				GL_UNSIGNED_INT, (void*)(numAtoms[m_oldTime-1]*sizeof(unsigned int)*3*solid->nFaces)
+#endif
+				);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("10 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+
+		} //if (m_oldTime==0) 
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("Gl error after Render  Atom timestep =%d: %d\n", m_oldTime, e);
+		//now cloned atoms
+		if (numClonedAtoms!=0 && m_oldTime==0) {
+			glBindVertexArray(AtomVAO[1]);
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, AtomIndices[1]);
+			glBindBuffer(GL_ARRAY_BUFFER, AtomBuffer[1]);
+	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (const void *)0);
+	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(3*sizeof(float)));
+	glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(6 * sizeof(float)));
+
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("5 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+			glDrawElements(GL_TRIANGLES, numClonedAtoms* 3 * solid->nFaces, 
+#ifndef INDICESGL32				
+				GL_UNSIGNED_SHORT,
+#else
+				GL_UNSIGNED_INT,
+#endif	
+				0);			
+			
+			
+			if ((e = glGetError()) != GL_NO_ERROR)
+				eprintf("Gl error after Render cloned Atom timestep =%d: %d\n", m_oldTime, e);
+		} // painting cloned atoms
+	} // no tess
+
+//eprintf ("RenderAtoms, end");
+} // render atoms
+
+void sceneManager::RenderAtomTrajectories(const glm::mat4 eyeViewProjection)
+{
+int e;
+if (!numAtoms)
+	return;
+eprintf ("RenderAtomTrajectories start");
+/*glm::mat4 trans={1,0,0,UserTranslation[0],
+		0,1,0,UserTranslation[1],
+		0,0,1,UserTranslation[2],
+		0,0,0,1};
+*/					
+//trans.translate(iPos).rotateX(-90).translate(UserPosition);
+glm::mat4 transform = eyeViewProjection; //MatrixMul(eyeViewProjection,trans);
+//gvr::Mat4f transform=eyeViewProjection;					
+float t[16];
+for (int i=0;i<4;i++)
+	for (int j=0;j<4;j++)
+		t[j*4+i]=transform[j][i];
+glUseProgram(UnitCellP);
+glUniformMatrix4fv(UnitCellMatrixLoc, 1, GL_FALSE, t);
+if ((e = glGetError()) != GL_NO_ERROR)
+	eprintf("Gl error after glUniform4fv 1 RenderAtomTrajectories: %d\n", e);
+RenderAtomTrajectoriesUnitCell();
+RenderAtoms(t);
+} //RenderAtomTrajectories
+
+void sceneManager::RenderAtomTrajectoriesUnitCell()
+{
+//eprintf ("RenderAtomTrajectoriesUnitCell start");
+	//now trajectories
+if (!showTrajectories)
+	return;
+
+int e;
+if (!AtomTVAO) {
+	eprintf("RenderAtomTrajectoriesUnitCell, no atoms");
+	return;
+}
+glBindVertexArray(AtomTVAO[0]);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("1 Gl error RenderAtomTrajectoriesUnitCell: %d\n", e);
+//glUseProgram(UnitCellP);
+//glUniformMatrix4fv(m_nUnitCellMatrixLocation, 1, GL_FALSE, matrix);
+float color[4]={1,0,0,1};
+glUniform4fv(UnitCellColourLoc, 1, color);
+if ((e = glGetError()) != GL_NO_ERROR)
+	eprintf("Gl error after glUniform4fv 2 RenderAtomTrajectoriesUnitCell: %d\n", e);
+//glEnableVertexAttribArray(0);
+//glDisableVertexAttribArray(1);
+
+//LOG("atomtrajectories.size()=%d", atomtrajectories.size());
+glBindBuffer(GL_ARRAY_BUFFER, AtomTBuffer[0]);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("3 Gl error RenderAtomTrajectoriesUnitCell: %d\n", e);
+
+for (unsigned int i=0;i<atomtrajectories.size();i++) {
+	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4 * sizeof(float)*numAtoms[0], 
+		(const void *)(0+4*sizeof(float)*atomtrajectories[i]));
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("4 Gl error RenderAtomTrajectoriesUnitCell: %d\n", e);
+
+		//LOG("atomtrajectoryrestarts[%d].size()=%d", i, atomtrajectoryrestarts[i].size());
+	for (unsigned int j=1;j<atomtrajectoryrestarts[i].size();j++) {
+		int orig=atomtrajectoryrestarts[i][j-1];
+		int count=atomtrajectoryrestarts[i][j]-atomtrajectoryrestarts[i][j-1];
+		glDrawArrays(GL_LINE_STRIP, orig, count);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("5 Gl error RenderAtomTrajectoriesUnitCell: %d, orig=%d, count=%d\n", e, orig, count);
+
+	} //j
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("Gl error after Render Atom trajectories: %d\n", e);
+} //i
+
+} //sceneManager::RenderAtomTrajectoriesUnitCell()
+
+
+void sceneManager::RenderUnitCell(const glm::mat4 eyeViewProjection)
+{
+	//eprintf ("eyeViewProjection");
+	//for (int i=0;i<4;i++)
+	//	for (int j=0;j<4;j++)
+	//		eprintf ("%d %d = %f", i, j, eyeViewProjection.m[i][j]);
+	//eprintf ("RenderUnitCell, has_abc=%d", has_abc);
+	if (!has_abc)
+		return;
+	if (UnitCellVAO==0)
+		eprintf ("Error, Unit Cell VAO not loaded");
+	int e;
+	
+	int p[3];
+
+	for (p[0]=0;p[0]<repetitions[0];(p[0])++)
+		for (p[1]=0;p[1]<repetitions[1];(p[1])++)
+			for (p[2]=0;p[2]<repetitions[2];(p[2])++)
+				{
+					float delta[3];
+					GetDisplacement(p, delta);
+					//eprintf ("delta %f %f %f", delta[0], delta[1], delta[2]);
+					glm::mat4 scale={5,0,0,1,  
+						0,5,0,1,
+						0,0,5,1,
+						0,0,0,1};
+					glm::mat4 trans= glm::mat4(1.0f);
+					trans=glm::translate(trans,glm::vec3(delta[0]*5, delta[1]*5, delta[2]*5));
+					trans=glm::scale(trans, glm::vec3(5,5,5));
+//						={1,0,0,delta[0]/*+UserTranslation[0]*/,
+//						0,1,0,delta[1]/*+UserTranslation[1]*/,
+//						0,0,1,delta[2]/*+UserTranslation[2]*/,
+//						0,0,0,1};
+					
+					//trans.translate(iPos).rotateX(-90).translate(UserPosition);
+					glm::mat4 transform = eyeViewProjection*trans;
+					//gvr::Mat4f transform=eyeViewProjection;					
+					float t[16];
+					for (int i=0;i<4;i++)
+						for (int j=0;j<4;j++)
+							t[j*4+i]=transform[j][i];
+					glUseProgram(UnitCellP);
+					glUniformMatrix4fv(UnitCellMatrixLoc, 1, GL_FALSE, t);
+					if ((e = glGetError()) != GL_NO_ERROR)
+						eprintf("Gl error after glUniform4fv 1 RenderUnitCell: %d\n", e);
+					float color[4]={1,1,1,1};
+					glUniform4fv(UnitCellColourLoc, 1, color);
+					if ((e = glGetError()) != GL_NO_ERROR)
+						eprintf("Gl error after glUniform4fv 2 RenderUnitCell: %d\n", e);
+					glBindVertexArray(UnitCellVAO);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, UnitCellIndexBuffer);
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("1 Gl error RenderAtom timestep =%d: %d\n", m_oldTime, e);
+	glBindBuffer(GL_ARRAY_BUFFER, UnitCellBuffer);
+	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (const void *)(0));
+	glEnableVertexAttribArray(0);
+	glDisableVertexAttribArray(1);
+	glDisableVertexAttribArray(2);
+	glDisableVertexAttribArray(3);
+					if ((e = glGetError()) != GL_NO_ERROR)
+						eprintf("Gl error after glBindVertexArray RenderUnitCell: %d\n", e);
+					glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0);
+					//glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, 0);
+					if ((e = glGetError()) != GL_NO_ERROR)
+						eprintf("Gl error after RenderUnitCell: %d\n", e);
+					//atom trajectories
+					//rgh: disable for now
+					RenderAtomTrajectoriesUnitCell();
+					RenderAtoms(t);
+				}
+}
diff --git a/CAVE/NOMADCaveT/src/main.cpp.mono b/CAVE/NOMADCaveT/src/main.cpp.mono
new file mode 100644
index 0000000000000000000000000000000000000000..2259b271aea78745acd0283c811255281a21682c
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/main.cpp.mono
@@ -0,0 +1,400 @@
+#include <m3drenderer.h>
+#include <functional>
+#include <iostream>
+#include <m3dtextureHandler.h>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/transform.hpp>
+#include <m3dnode.h>
+#include <chrono>
+#include <renderNode.h>
+#include <m3dshader.h>
+//#include <syncher.h>
+//#include <synchType.h>
+#include <synchObject.h>
+#include <m3dFileIO.h>
+#include <m3dtextureHandler.h>
+#include <m3dmeshHandler.h>
+#include <m3duploadingInterface.h>
+
+typedef std::chrono::high_resolution_clock Clock;
+ using namespace m3d;
+
+class sceneManager{
+public:
+    sceneManager(m3d::Renderer* ren, synchlib::renderNode* node);
+    ~sceneManager();
+    void displayFunction();
+    void keyboardFunction(char key, int x, int y);
+    void keyReleaseFunction(char key, int x, int y);
+    void setCDPSyncher(std::shared_ptr<synchlib::SynchObject<glm::ivec2> > sy){m_pCurrentDataPosSyncher = sy; m_pCurrentDataPosSyncher->setData(glm::ivec2(0,0));}
+    void setCDTPSyncher(std::shared_ptr<synchlib::SynchObject<int> > sy){m_pCurrentDataTimeSyncher = sy; m_pCurrentDataTimeSyncher->setData(0);}
+
+
+private:
+    m3d::Renderer* m_ren;
+    synchlib::renderNode* m_node;
+
+    std::shared_ptr<Node> m_world;
+    std::shared_ptr<Node> m_core;
+//    std::shared_ptr<Node> m_border410;
+    std::shared_ptr<Node> m_border660;
+    std::shared_ptr<Node> m_skydome;
+    std::shared_ptr<Node> m_dataGroup;
+    std::shared_ptr<Node> m_posData;
+    std::shared_ptr<Node> m_NegData;
+
+
+    GLuint m_worldTexId;
+//    std::vector<std::shared_ptr<Node> > m_dataNegVec;
+//    std::vector<std::shared_ptr<Node> > m_dataPosVec;
+
+    int counter = 0;
+    Clock::time_point t1 = Clock::now();
+
+
+//
+//    cwc::glShaderManager sm;
+//    cwc::glShader* m_pCoreShader;
+//    cwc::glShader* m_pPhongSecondShader;
+//    cwc::glShader* m_pPhongShader;
+
+
+    glm::mat4 m_preMat;
+    glm::mat4 m_scalemat;
+    glm::mat4 m_scalematSky;
+    std::shared_ptr<UploadingInterface> m_uploading;
+
+
+
+GLUquadric* qobj;
+std::shared_ptr<synchlib::SynchObject<glm::ivec2> > m_pCurrentDataPosSyncher;
+std::shared_ptr<synchlib::SynchObject<int> > m_pCurrentDataTimeSyncher;
+
+
+glm::ivec2 m_oldDataPos = glm::ivec2(0,0);
+int m_oldTime = 0;
+};
+
+
+sceneManager::sceneManager(m3d::Renderer* ren, synchlib::renderNode* node){
+
+
+     m_ren = ren;// m_th = th;
+    m_node = node;
+
+    m_preMat = glm::mat4_cast(glm::rotation(glm::vec3(0.,0.,1.),glm::vec3(0.,1.,0.)));
+//    m_preMat = glm::translate(glm::vec3(0.,0.,-13000.)) * m_preMat;
+   m_scalemat = glm::scale(m_scalemat,glm::vec3(0.1,0.1,0.1));
+   m_scalematSky = glm::scale(m_scalematSky,glm::vec3(0.05,0.05,0.05));
+
+qobj = gluNewQuadric();
+GLenum err;
+
+
+
+//	std::vector<Object*> dataVec;
+//	m_dataPosVec.resize(64);
+//	m_dataNegVec.resize(64);
+
+
+	M3DFileIO fileio;
+	std::shared_ptr<Node> UploadingRoot = Node::create();
+
+	if(!fileio.load(m_world,"/home/demos/m_demos/demoBunge2/datasets/world_plus0.m3d",false))
+		std::cout<<"world loading failed"<<std::endl;
+	fileio.load(m_skydome,"/home/demos/m_demos/demoBunge2/datasets/skydome_stars.m3d",false);
+	fileio.load(m_core,"/home/demos/m_demos/demoBunge2/datasets/earth_core.m3d",false);
+	fileio.load(m_border660,"/home/demos/m_demos/demoBunge2/datasets/660km_border.m3d",false);
+
+	std::cout<<"loading allpos"<<std::endl;
+	fileio.load(m_posData,"/home/demos/m_demos/demoBunge2/datasets/smallDataPos.m3d",false);
+	std::cout<<"loading allneg"<<std::endl;
+	fileio.load(m_NegData,"/home/demos/m_demos/demoBunge2/datasets/smallDataNeg.m3d",false);
+
+//	fileio.load(m_posData,"/home/demos/m_demos/demoBunge2/datasets/10lowPos.m3d",false);
+//	fileio.load(m_NegData,"/home/demos/m_demos/demoBunge2/datasets/10lowNeg.m3d",false);
+
+
+	UploadingRoot->addChild(m_posData);
+	UploadingRoot->addChild(m_NegData);
+
+	UploadingRoot->addChild(m_skydome);
+	UploadingRoot->addChild(m_world);
+	UploadingRoot->addChild(m_core);
+	UploadingRoot->addChild(m_border660);
+
+
+	float scale = 630.;
+	(*m_posData->getSceneMat()) = glm::scale(glm::vec3(scale,scale,scale)) * m_preMat;
+	(*m_NegData->getSceneMat()) = glm::scale(glm::vec3(scale,scale,scale)) * m_preMat;
+
+	(*m_world->getSceneMat()) = m_scalemat * m_preMat;
+	(*m_core->getSceneMat()) = m_scalemat * m_preMat;
+	(*m_border660->getSceneMat()) = m_scalemat * m_preMat;
+	(*m_skydome->getSceneMat()) = m_scalematSky;
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor 1: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+
+//
+	if(!m_posData->initDefaultShader(2,false))
+		std::cout<<"shader pos failed"<<std::endl;
+	if(!m_NegData->initDefaultShader(2,false))
+		std::cout<<"shader neg failed"<<std::endl;
+
+	m_NegData->setShininess(100.,true);
+	m_NegData->setSpecular(glm::vec4(1.f,1.f,1.0f,1.f),true);
+	m_NegData->setLightPos(0,glm::vec4(0.f,3000.f,0.0f,1.f),true);
+	m_NegData->setLightPos(1,glm::vec4(0.f,-3000.f,.0f,1.f),true);
+	m_posData->setShininess(100.,true);
+	m_posData->setSpecular(glm::vec4(1.f,1.f,1.0f,1.f),true);
+//	m_posData->setDiffuse(glm::vec4(0.2f,.2f,.2f,1.f),true);
+//	m_posData->setAmbient(glm::vec4(0.8f,.8f,.8f,1.f),true);
+	m_posData->setLightPos(0,glm::vec4(0.f,3000.f,0.0f,1.f),true);
+	m_posData->setLightPos(1,glm::vec4(0.f,-3000.f,.0f,1.f),true);
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor nach shader zeug: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+	if(!m_world->initDefaultShader(0))
+		std::cout<<"m_world failed"<<std::endl;
+	if(!m_core->initDefaultShader(0,false))
+		std::cout<<"m_core failed"<<std::endl;
+	if(!m_border660->initDefaultShader(0))
+		std::cout<<"m_border660 failed"<<std::endl;
+	if(!m_skydome->initDefaultShader(0))
+		std::cout<<"m_skydome failed"<<std::endl;
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor 2: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+    std::shared_ptr<m3d::MeshHandler> mHandler = std::make_shared<MeshHandler>(ren->getDisplay(),*(ren->getContext()),true,false);
+    std::shared_ptr<TextureHandler> tHandler = std::make_shared<TextureHandler>((ren->getDisplay()),*(ren->getContext()),true);
+    mHandler->start();
+    tHandler->start();
+
+
+
+    m_uploading = std::make_shared<UploadingInterface>(mHandler,tHandler);
+    m_uploading->setRootNode(UploadingRoot);
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor nach set root: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+    std::cout<<"start"<<std::endl;
+    m_uploading->start();
+    std::cout<<"started"<<std::endl;
+    sleep(2);
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor nach start: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+
+}
+
+sceneManager::~sceneManager(){
+m_uploading->quit();
+
+}
+
+
+
+void sceneManager::displayFunction(){
+	GLenum err;
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "disp 1: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+	bool ttt = false;
+    glm::mat4 pvmatL, pvmatR;
+    m_node->getProjectionMatrices(pvmatL,pvmatR);
+    glm::mat4 viewMat;
+    m_node->getSceneTrafo(viewMat);
+    glm::ivec2 curDataPos;
+    m_pCurrentDataPosSyncher->getData(curDataPos);
+    int timePos;
+    m_pCurrentDataTimeSyncher->getData(timePos);
+    if(m_oldTime != timePos){
+    	m_oldTime = timePos;
+    }
+    auto t2 = Clock::now();
+    auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count();
+    if(dur > 1000){
+        std::cout<<"################################ fps: "<<(double)counter/((double) dur / (double) 1000)<<std::endl;
+        counter = 0;
+        t1 = Clock::now();
+        std::cout<<"time: "<<timePos<<" lod: "<<curDataPos[0]<<" , "<<curDataPos[1]<<std::endl;
+    }
+
+    m_posData->setTimeStep(timePos);
+    m_NegData->setTimeStep(timePos);
+    if(m_oldDataPos[0] != curDataPos[0]){
+    	m_posData->setLOD(curDataPos[0]);
+    	m_oldDataPos[0] = curDataPos[0];
+    }
+    if(m_oldDataPos[1] != curDataPos[1]){
+    	m_NegData->setLOD(curDataPos[1]);
+    	m_oldDataPos[1] = curDataPos[1];
+    }
+    glm::mat4 user; m_node->getUserTrafo(user);
+    m_posData->getShader()->setUserPos(glm::vec3(user[3]));
+    m_NegData->getShader()->setUserPos(glm::vec3(user[3]));
+
+
+    glm::mat4 viewRotOnly = viewMat;
+    viewRotOnly[3] = glm::vec4(0.,0.,0.,1.);
+
+
+    glDrawBuffer(GL_BACK_LEFT);
+    {
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+   	while ((err = glGetError()) != GL_NO_ERROR) {
+   		std::cerr << "disp vor draw: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+   	}
+       m_posData->draw(pvmatL, viewMat, glm::mat4(1));
+       m_NegData->draw(pvmatL, viewMat, glm::mat4(1));
+       m_world->draw(pvmatL, viewMat, glm::mat4(1));
+//       m_border660->draw(pvmatL, viewMat, glm::mat4(1));
+       m_skydome->draw(pvmatL, viewRotOnly, glm::mat4(1));
+       m_core->draw(pvmatL, viewMat, glm::mat4(1));
+    }
+
+    glDrawBuffer(GL_BACK_RIGHT);
+    {
+// Aenderung durch Jutta Dreer fuer mono
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+       m_posData->draw(pvmatL, viewMat, glm::mat4(1));
+       m_NegData->draw(pvmatL, viewMat, glm::mat4(1));
+       m_world->draw(pvmatL, viewMat, glm::mat4(1));
+//       m_border660->draw(pvmatR, viewMat, glm::mat4(1));
+       m_skydome->draw(pvmatL, viewRotOnly, glm::mat4(1));
+       m_core->draw(pvmatL, viewMat, glm::mat4(1));
+    }
+   GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE,0);
+   glClientWaitSync(fence,GL_SYNC_FLUSH_COMMANDS_BIT,GL_TIMEOUT_IGNORED);
+
+
+    if(!m_node->synchFrame()){
+
+       m_ren->stopMainLoop();
+       return;
+    }
+
+    m_ren->swapBuffer();
+
+
+    ++counter;
+
+}
+
+
+void sceneManager::keyboardFunction(char key, int x, int y){
+
+switch(key){
+
+
+case 27:
+    m_ren->stopMainLoop();
+    break;
+}
+}
+
+void sceneManager::keyReleaseFunction(char key, int x, int y){
+    switch(key){
+
+    }
+}
+
+
+
+void InitGraphics(void)
+{
+
+	    glClearColor (1.0, 1.0, 1.0, 1.0);
+	    glClearDepth(1.0f);				// Depth Buffer Setup
+	    glEnable(GL_DEPTH_TEST);		// Enables Depth Testing
+	    glDepthFunc(GL_LEQUAL);			// The Type Of Depth Test To Do
+	    glDisable(GL_BLEND);
+		glEnable(GL_SMOOTH);
+//		glEnable(GL_MULTISAMPLE);
+//		glShadeModel(GL_SMOOTH);
+
+
+}
+
+
+
+
+
+int main(int argc, char** argv){
+	if(argc < 3){
+		std::cout<<"Not enough arguments! Start with "<<argv[0]<<" <own hostname/IP> <path to configfile>"<<std::endl;
+		exit(0);
+	}
+
+
+    bool stereo = true;
+    bool debug = false;
+    m3d::Renderer* ren = new m3d::Renderer(stereo,debug);
+
+    std::string file =argv[2];
+    synchlib::caveConfig conf(file);
+    std::stringstream ownIP;
+    ownIP<< argv[1];
+    if(argc > 3){
+    	ownIP<<"_"<<argv[3];
+    }
+
+    synchlib::renderNode* node = new synchlib::renderNode(file,ownIP.str());
+    std::cout<<conf.m_wall_conf[ownIP.str()].wall_geo[0]<<"    "<<conf.m_wall_conf[ownIP.str()].wall_geo[1]<<std::endl;
+    ren->createWindow("demoBunge",conf.m_wall_conf[ownIP.str()].wall_geo[0],conf.m_wall_conf[ownIP.str()].wall_geo[1]);
+    GLenum err = glewInit();
+    if (GLEW_OK != err)
+    {
+      /* Problem: glewInit failed, something is seriously wrong. */
+      fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
+
+    }
+
+
+
+	{
+		sceneManager sceneM(ren,node);
+
+
+		std::shared_ptr<synchlib::SynchObject<glm::ivec2> > currentDataPosSyncher = synchlib::SynchObject<glm::ivec2>::create();
+		sceneM.setCDPSyncher(currentDataPosSyncher);
+		node->addSynchObject(currentDataPosSyncher,synchlib::renderNode::RECEIVER,50000);
+
+		std::shared_ptr<synchlib::SynchObject<int> > currentDataTimeSyncher = synchlib::SynchObject<int>::create();
+		sceneM.setCDTPSyncher(currentDataTimeSyncher);
+		node->addSynchObject(currentDataTimeSyncher,synchlib::renderNode::RECEIVER,50001);
+
+
+
+		std::function<void(void)> dispFunc = std::bind(&sceneManager::displayFunction,&sceneM);
+		std::function<void(char,int,int)>  keyFunc = std::bind(&sceneManager::keyboardFunction,&sceneM,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
+		std::function<void(char,int,int)>  keyRFunc = std::bind(&sceneManager::keyReleaseFunction,&sceneM,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
+		ren->setDisplayFunction(dispFunc);
+		ren->setIdleFunction(dispFunc);
+		ren->setKeyPressFunction(keyFunc);
+		ren->setAllowKeyboardAutoRepressing(false);
+		ren->setKeyReleaseFunction(keyRFunc);
+		ren->toggleFullscreen();
+		node->init();
+
+		node->startSynching();
+		while ((err = glGetError()) != GL_NO_ERROR) {
+			std::cerr <<" vor init: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+		}
+		InitGraphics();
+		while ((err = glGetError()) != GL_NO_ERROR) {
+			std::cerr << "initGraphics: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+		}
+		ren->mainLoop();
+	}
+    delete ren;
+
+    node->stopSynching();
+    delete node;
+
+}
diff --git a/CAVE/NOMADCaveT/src/main.cpp.stereo b/CAVE/NOMADCaveT/src/main.cpp.stereo
new file mode 100644
index 0000000000000000000000000000000000000000..5d0f5c65390788d83859bf9c3dca9e5c58da7c72
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/main.cpp.stereo
@@ -0,0 +1,399 @@
+#include <m3drenderer.h>
+#include <functional>
+#include <iostream>
+#include <m3dtextureHandler.h>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/transform.hpp>
+#include <m3dnode.h>
+#include <chrono>
+#include <renderNode.h>
+#include <m3dshader.h>
+//#include <syncher.h>
+//#include <synchType.h>
+#include <synchObject.h>
+#include <m3dFileIO.h>
+#include <m3dtextureHandler.h>
+#include <m3dmeshHandler.h>
+#include <m3duploadingInterface.h>
+
+typedef std::chrono::high_resolution_clock Clock;
+ using namespace m3d;
+
+class sceneManager{
+public:
+    sceneManager(m3d::Renderer* ren, synchlib::renderNode* node);
+    ~sceneManager();
+    void displayFunction();
+    void keyboardFunction(char key, int x, int y);
+    void keyReleaseFunction(char key, int x, int y);
+    void setCDPSyncher(std::shared_ptr<synchlib::SynchObject<glm::ivec2> > sy){m_pCurrentDataPosSyncher = sy; m_pCurrentDataPosSyncher->setData(glm::ivec2(0,0));}
+    void setCDTPSyncher(std::shared_ptr<synchlib::SynchObject<int> > sy){m_pCurrentDataTimeSyncher = sy; m_pCurrentDataTimeSyncher->setData(0);}
+
+
+private:
+    m3d::Renderer* m_ren;
+    synchlib::renderNode* m_node;
+
+    std::shared_ptr<Node> m_world;
+    std::shared_ptr<Node> m_core;
+//    std::shared_ptr<Node> m_border410;
+    std::shared_ptr<Node> m_border660;
+    std::shared_ptr<Node> m_skydome;
+    std::shared_ptr<Node> m_dataGroup;
+    std::shared_ptr<Node> m_posData;
+    std::shared_ptr<Node> m_NegData;
+
+
+    GLuint m_worldTexId;
+//    std::vector<std::shared_ptr<Node> > m_dataNegVec;
+//    std::vector<std::shared_ptr<Node> > m_dataPosVec;
+
+    int counter = 0;
+    Clock::time_point t1 = Clock::now();
+
+
+//
+//    cwc::glShaderManager sm;
+//    cwc::glShader* m_pCoreShader;
+//    cwc::glShader* m_pPhongSecondShader;
+//    cwc::glShader* m_pPhongShader;
+
+
+    glm::mat4 m_preMat;
+    glm::mat4 m_scalemat;
+    glm::mat4 m_scalematSky;
+    std::shared_ptr<UploadingInterface> m_uploading;
+
+
+
+GLUquadric* qobj;
+std::shared_ptr<synchlib::SynchObject<glm::ivec2> > m_pCurrentDataPosSyncher;
+std::shared_ptr<synchlib::SynchObject<int> > m_pCurrentDataTimeSyncher;
+
+
+glm::ivec2 m_oldDataPos = glm::ivec2(0,0);
+int m_oldTime = 0;
+};
+
+
+sceneManager::sceneManager(m3d::Renderer* ren, synchlib::renderNode* node){
+
+
+     m_ren = ren;// m_th = th;
+    m_node = node;
+
+    m_preMat = glm::mat4_cast(glm::rotation(glm::vec3(0.,0.,1.),glm::vec3(0.,1.,0.)));
+//    m_preMat = glm::translate(glm::vec3(0.,0.,-13000.)) * m_preMat;
+   m_scalemat = glm::scale(m_scalemat,glm::vec3(0.1,0.1,0.1));
+   m_scalematSky = glm::scale(m_scalematSky,glm::vec3(0.05,0.05,0.05));
+
+qobj = gluNewQuadric();
+GLenum err;
+
+
+
+//	std::vector<Object*> dataVec;
+//	m_dataPosVec.resize(64);
+//	m_dataNegVec.resize(64);
+
+
+	M3DFileIO fileio;
+	std::shared_ptr<Node> UploadingRoot = Node::create();
+
+	if(!fileio.load(m_world,"/home/demos/m_demos/demoBunge2/datasets/world_plus0.m3d",false))
+		std::cout<<"world loading failed"<<std::endl;
+	fileio.load(m_skydome,"/home/demos/m_demos/demoBunge2/datasets/skydome_stars.m3d",false);
+	fileio.load(m_core,"/home/demos/m_demos/demoBunge2/datasets/earth_core.m3d",false);
+	fileio.load(m_border660,"/home/demos/m_demos/demoBunge2/datasets/660km_border.m3d",false);
+
+	std::cout<<"loading allpos"<<std::endl;
+	fileio.load(m_posData,"/home/demos/m_demos/demoBunge2/datasets/smallDataPos.m3d",false);
+	std::cout<<"loading allneg"<<std::endl;
+	fileio.load(m_NegData,"/home/demos/m_demos/demoBunge2/datasets/smallDataNeg.m3d",false);
+
+//	fileio.load(m_posData,"/home/demos/m_demos/demoBunge2/datasets/10lowPos.m3d",false);
+//	fileio.load(m_NegData,"/home/demos/m_demos/demoBunge2/datasets/10lowNeg.m3d",false);
+
+
+	UploadingRoot->addChild(m_posData);
+	UploadingRoot->addChild(m_NegData);
+
+	UploadingRoot->addChild(m_skydome);
+	UploadingRoot->addChild(m_world);
+	UploadingRoot->addChild(m_core);
+	UploadingRoot->addChild(m_border660);
+
+
+	float scale = 630.;
+	(*m_posData->getSceneMat()) = glm::scale(glm::vec3(scale,scale,scale)) * m_preMat;
+	(*m_NegData->getSceneMat()) = glm::scale(glm::vec3(scale,scale,scale)) * m_preMat;
+
+	(*m_world->getSceneMat()) = m_scalemat * m_preMat;
+	(*m_core->getSceneMat()) = m_scalemat * m_preMat;
+	(*m_border660->getSceneMat()) = m_scalemat * m_preMat;
+	(*m_skydome->getSceneMat()) = m_scalematSky;
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor 1: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+
+//
+	if(!m_posData->initDefaultShader(2,false))
+		std::cout<<"shader pos failed"<<std::endl;
+	if(!m_NegData->initDefaultShader(2,false))
+		std::cout<<"shader neg failed"<<std::endl;
+
+	m_NegData->setShininess(100.,true);
+	m_NegData->setSpecular(glm::vec4(1.f,1.f,1.0f,1.f),true);
+	m_NegData->setLightPos(0,glm::vec4(0.f,3000.f,0.0f,1.f),true);
+	m_NegData->setLightPos(1,glm::vec4(0.f,-3000.f,.0f,1.f),true);
+	m_posData->setShininess(100.,true);
+	m_posData->setSpecular(glm::vec4(1.f,1.f,1.0f,1.f),true);
+//	m_posData->setDiffuse(glm::vec4(0.2f,.2f,.2f,1.f),true);
+//	m_posData->setAmbient(glm::vec4(0.8f,.8f,.8f,1.f),true);
+	m_posData->setLightPos(0,glm::vec4(0.f,3000.f,0.0f,1.f),true);
+	m_posData->setLightPos(1,glm::vec4(0.f,-3000.f,.0f,1.f),true);
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor nach shader zeug: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+	if(!m_world->initDefaultShader(0))
+		std::cout<<"m_world failed"<<std::endl;
+	if(!m_core->initDefaultShader(0,false))
+		std::cout<<"m_core failed"<<std::endl;
+	if(!m_border660->initDefaultShader(0))
+		std::cout<<"m_border660 failed"<<std::endl;
+	if(!m_skydome->initDefaultShader(0))
+		std::cout<<"m_skydome failed"<<std::endl;
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor 2: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+    std::shared_ptr<m3d::MeshHandler> mHandler = std::make_shared<MeshHandler>(ren->getDisplay(),*(ren->getContext()),true,false);
+    std::shared_ptr<TextureHandler> tHandler = std::make_shared<TextureHandler>((ren->getDisplay()),*(ren->getContext()),true);
+    mHandler->start();
+    tHandler->start();
+
+
+
+    m_uploading = std::make_shared<UploadingInterface>(mHandler,tHandler);
+    m_uploading->setRootNode(UploadingRoot);
+
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor nach set root: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+    std::cout<<"start"<<std::endl;
+    m_uploading->start();
+    std::cout<<"started"<<std::endl;
+    sleep(2);
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "construktor nach start: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+
+}
+
+sceneManager::~sceneManager(){
+m_uploading->quit();
+
+}
+
+
+
+void sceneManager::displayFunction(){
+	GLenum err;
+	while ((err = glGetError()) != GL_NO_ERROR) {
+		std::cerr << "disp 1: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+	}
+	bool ttt = false;
+    glm::mat4 pvmatL, pvmatR;
+    m_node->getProjectionMatrices(pvmatL,pvmatR);
+    glm::mat4 viewMat;
+    m_node->getSceneTrafo(viewMat);
+    glm::ivec2 curDataPos;
+    m_pCurrentDataPosSyncher->getData(curDataPos);
+    int timePos;
+    m_pCurrentDataTimeSyncher->getData(timePos);
+    if(m_oldTime != timePos){
+    	m_oldTime = timePos;
+    }
+    auto t2 = Clock::now();
+    auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count();
+    if(dur > 1000){
+        std::cout<<"################################ fps: "<<(double)counter/((double) dur / (double) 1000)<<std::endl;
+        counter = 0;
+        t1 = Clock::now();
+        std::cout<<"time: "<<timePos<<" lod: "<<curDataPos[0]<<" , "<<curDataPos[1]<<std::endl;
+    }
+
+    m_posData->setTimeStep(timePos);
+    m_NegData->setTimeStep(timePos);
+    if(m_oldDataPos[0] != curDataPos[0]){
+    	m_posData->setLOD(curDataPos[0]);
+    	m_oldDataPos[0] = curDataPos[0];
+    }
+    if(m_oldDataPos[1] != curDataPos[1]){
+    	m_NegData->setLOD(curDataPos[1]);
+    	m_oldDataPos[1] = curDataPos[1];
+    }
+    glm::mat4 user; m_node->getUserTrafo(user);
+    m_posData->getShader()->setUserPos(glm::vec3(user[3]));
+    m_NegData->getShader()->setUserPos(glm::vec3(user[3]));
+
+
+    glm::mat4 viewRotOnly = viewMat;
+    viewRotOnly[3] = glm::vec4(0.,0.,0.,1.);
+
+
+    glDrawBuffer(GL_BACK_LEFT);
+    {
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+   	while ((err = glGetError()) != GL_NO_ERROR) {
+   		std::cerr << "disp vor draw: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+   	}
+       m_posData->draw(pvmatL, viewMat, glm::mat4(1));
+       m_NegData->draw(pvmatL, viewMat, glm::mat4(1));
+       m_world->draw(pvmatL, viewMat, glm::mat4(1));
+//       m_border660->draw(pvmatL, viewMat, glm::mat4(1));
+       m_skydome->draw(pvmatL, viewRotOnly, glm::mat4(1));
+       m_core->draw(pvmatL, viewMat, glm::mat4(1));
+    }
+
+    glDrawBuffer(GL_BACK_RIGHT);
+    {
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+       m_posData->draw(pvmatR, viewMat, glm::mat4(1));
+       m_NegData->draw(pvmatR, viewMat, glm::mat4(1));
+       m_world->draw(pvmatR, viewMat, glm::mat4(1));
+//       m_border660->draw(pvmatR, viewMat, glm::mat4(1));
+       m_skydome->draw(pvmatR, viewRotOnly, glm::mat4(1));
+       m_core->draw(pvmatR, viewMat, glm::mat4(1));
+    }
+   GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE,0);
+   glClientWaitSync(fence,GL_SYNC_FLUSH_COMMANDS_BIT,GL_TIMEOUT_IGNORED);
+
+
+    if(!m_node->synchFrame()){
+
+       m_ren->stopMainLoop();
+       return;
+    }
+
+    m_ren->swapBuffer();
+
+
+    ++counter;
+
+}
+
+
+void sceneManager::keyboardFunction(char key, int x, int y){
+
+switch(key){
+
+
+case 27:
+    m_ren->stopMainLoop();
+    break;
+}
+}
+
+void sceneManager::keyReleaseFunction(char key, int x, int y){
+    switch(key){
+
+    }
+}
+
+
+
+void InitGraphics(void)
+{
+
+	    glClearColor (1.0, 1.0, 1.0, 1.0);
+	    glClearDepth(1.0f);				// Depth Buffer Setup
+	    glEnable(GL_DEPTH_TEST);		// Enables Depth Testing
+	    glDepthFunc(GL_LEQUAL);			// The Type Of Depth Test To Do
+	    glDisable(GL_BLEND);
+		glEnable(GL_SMOOTH);
+//		glEnable(GL_MULTISAMPLE);
+//		glShadeModel(GL_SMOOTH);
+
+
+}
+
+
+
+
+
+int main(int argc, char** argv){
+	if(argc < 3){
+		std::cout<<"Not enough arguments! Start with "<<argv[0]<<" <own hostname/IP> <path to configfile>"<<std::endl;
+		exit(0);
+	}
+
+
+    bool stereo = true;
+    bool debug = true;
+    m3d::Renderer* ren = new m3d::Renderer(stereo,debug);
+
+    std::string file =argv[2];
+    synchlib::caveConfig conf(file);
+    std::stringstream ownIP;
+    ownIP<< argv[1];
+    if(argc > 3){
+    	ownIP<<"_"<<argv[3];
+    }
+
+    synchlib::renderNode* node = new synchlib::renderNode(file,ownIP.str());
+    std::cout<<conf.m_wall_conf[ownIP.str()].wall_geo[0]<<"    "<<conf.m_wall_conf[ownIP.str()].wall_geo[1]<<std::endl;
+    ren->createWindow("demoBunge",conf.m_wall_conf[ownIP.str()].wall_geo[0],conf.m_wall_conf[ownIP.str()].wall_geo[1]);
+    GLenum err = glewInit();
+    if (GLEW_OK != err)
+    {
+      /* Problem: glewInit failed, something is seriously wrong. */
+      fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
+
+    }
+
+
+
+	{
+		sceneManager sceneM(ren,node);
+
+
+		std::shared_ptr<synchlib::SynchObject<glm::ivec2> > currentDataPosSyncher = synchlib::SynchObject<glm::ivec2>::create();
+		sceneM.setCDPSyncher(currentDataPosSyncher);
+		node->addSynchObject(currentDataPosSyncher,synchlib::renderNode::RECEIVER,50000);
+
+		std::shared_ptr<synchlib::SynchObject<int> > currentDataTimeSyncher = synchlib::SynchObject<int>::create();
+		sceneM.setCDTPSyncher(currentDataTimeSyncher);
+		node->addSynchObject(currentDataTimeSyncher,synchlib::renderNode::RECEIVER,50001);
+
+
+
+		std::function<void(void)> dispFunc = std::bind(&sceneManager::displayFunction,&sceneM);
+		std::function<void(char,int,int)>  keyFunc = std::bind(&sceneManager::keyboardFunction,&sceneM,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
+		std::function<void(char,int,int)>  keyRFunc = std::bind(&sceneManager::keyReleaseFunction,&sceneM,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
+		ren->setDisplayFunction(dispFunc);
+		ren->setIdleFunction(dispFunc);
+		ren->setKeyPressFunction(keyFunc);
+		ren->setAllowKeyboardAutoRepressing(false);
+		ren->setKeyReleaseFunction(keyRFunc);
+		ren->toggleFullscreen();
+		node->init();
+
+		node->startSynching();
+		while ((err = glGetError()) != GL_NO_ERROR) {
+			std::cerr <<" vor init: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+		}
+		InitGraphics();
+		while ((err = glGetError()) != GL_NO_ERROR) {
+			std::cerr << "initGraphics: "<<__FUNCTION__<<" OpenGL error" << err << std::endl;
+		}
+		ren->mainLoop();
+	}
+    delete ren;
+
+    node->stopSynching();
+    delete node;
+
+}
diff --git a/CAVE/NOMADCaveT/src/main_server.cpp b/CAVE/NOMADCaveT/src/main_server.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f5aff004c24f1ab88be6de3f7886c32b52c2b5da
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/main_server.cpp
@@ -0,0 +1,357 @@
+#define GLM_SWIZZLE
+#include <glm/gtx/matrix_decompose.hpp>
+#include <m3drenderer.h>
+#include <functional>
+#include <iostream>
+#include <chrono>
+#include <renderNode.h>
+#include <renderServer.h>
+
+#include <synchObject.h>
+//#include <m3dshader.h>
+#include <future>
+#include <iostream>
+#include <string>
+#include <cstdlib>
+#include <stdio.h>
+#include <m3dutils.h>
+#include <ctime>
+
+#include "selectedPoints.hpp"
+
+typedef std::chrono::high_resolution_clock Clock;
+
+#include "defines.h"
+
+
+#define bunge_maxSurfaces 1
+//#define bunge_maxTimeSteps TIMESTEPS
+
+
+class sceneManager{
+public:
+    sceneManager(m3d::Renderer* ren,  synchlib::renderServer* serv) {
+    	m_ren = ren;
+    	m_serv = serv;
+    	cameraFile.open("/home/di73yad/demos/demoBunge/cameraTrafos.txt",std::fstream::out | std::fstream::app);
+    	std::time_t curTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+    	cameraFile<<std::ctime(&curTime)<<std::endl;
+    }
+    ~sceneManager();
+    void displayFunction();
+    void keyboardFunction(char key, int x, int y);
+  //  void keyReleaseFunction(char key, int x, int y);
+
+    void startThreads();
+    std::shared_ptr<synchlib::SynchObject<int> > m_pCurrentDataPosSyncher;
+    std::shared_ptr<synchlib::SynchObject<int> > m_pCurrentDataTimeSyncher;
+	std::shared_ptr<synchlib::SynchObject<SelectedPoints> >
+		m_pCurrentDataPointSyncher;
+
+private:
+    void updateButtonActions();
+    void buttonEval();
+	void synch();
+
+    m3d::Renderer* m_ren;
+    synchlib::renderServer* m_serv;
+
+
+    Clock::time_point m_oldTimeForSwap = Clock::now();
+    float m_maxAnimTime;
+
+    bool m_stop = false;
+    int m_swapIsoSurface = 0;
+    int m_curData = 0; //ISOS;
+    std::thread* m_updateButtonsThread;
+    int m_mode = 0; //0 both, 1 negative and 2 positive iso swap
+    bool m_pressB0 = false;
+    bool m_pressB2 = false;
+    int m_curTime = 0;
+	SelectedPoints selectedPoints={0};
+    std::fstream cameraFile;
+ 	int TIMESTEPS=1;
+
+};
+
+
+sceneManager::~sceneManager(){
+	cameraFile.close();
+    m_updateButtonsThread->join();
+
+}
+
+
+
+void sceneManager::startThreads(){
+    //initialize first data as zero
+    m_pCurrentDataPosSyncher->setData(m_curData);
+    m_pCurrentDataPosSyncher->send();
+    m_pCurrentDataTimeSyncher->setData(0);
+    m_pCurrentDataTimeSyncher->send();
+	SelectedPoints p={0};
+    m_pCurrentDataPointSyncher->setData(p);
+    m_pCurrentDataPointSyncher->send();
+
+
+    m_updateButtonsThread  = new std::thread( std::bind(&sceneManager::updateButtonActions,this));
+}
+
+void sceneManager::synch()
+{
+	m_pCurrentDataPosSyncher->setData(m_curData);
+	m_pCurrentDataPosSyncher->send();
+	m_pCurrentDataTimeSyncher->setData(m_curTime);
+	m_pCurrentDataTimeSyncher->send();
+	m_pCurrentDataPointSyncher->setData(selectedPoints);
+	m_pCurrentDataPointSyncher->send();
+	m_oldTimeForSwap = Clock::now();
+}
+
+void sceneManager::updateButtonActions()
+{
+bool longpress=false;
+    while (!m_stop) {
+        buttonEval();
+         auto t2 = Clock::now();
+	int dur;
+        if(abs(m_swapIsoSurface) > 0 || m_pressB0 || m_pressB2)
+             dur = std::chrono::duration_cast<std::chrono::milliseconds>(t2-m_oldTimeForSwap).count();
+	else {
+		longpress=false;
+		}
+        if(abs(m_swapIsoSurface) > 0){
+              	 if(!m_pressB2){
+			if (dur>100) {//ms
+					//make modulo in client; avoids having to read the file here.
+					std::cout << "Current timestep " << m_curTime << std::endl;
+					 m_curTime += m_swapIsoSurface;
+					 synch();
+			}
+            	 }else {
+			if ((!longpress && dur>100) || (longpress && dur>500)) 
+			{//ms //rgh: change isos in a more discrete manner.
+					std::cout << "Changing iso!!\n";
+					 m_curData += m_swapIsoSurface;
+//rgh: unused for now
+//					 m_curData = (m_curData > ISOS) ? 0 : m_curData;
+//					 m_curData = (m_curData < 0) ? ISOS : m_curData;
+					 synch();
+					 longpress=true;
+			std::cout << "longpress true in B2\n";
+			}
+
+
+
+             }//m_pressB2
+        } 
+	if (m_pressB0){
+		if ((!longpress & dur>100) ||(longpress && dur>500)) {
+			selectedPoints.number++;
+
+
+			glm::vec3 scale;
+			glm::quat rotation;
+			glm::vec3 translation;
+			glm::vec3 skew;
+			glm::vec4 perspective;
+			glm::decompose(m_serv->getWandTransform(), 
+				scale, rotation, translation, skew, perspective);
+			glm::mat4 st;
+			m_serv->getSceneTransform(st);
+			st=glm::inverse(st);
+			translation=(st*glm::vec4(translation, 1)).xyz();
+			if (selectedPoints.number>4)
+				selectedPoints.number=0;
+			else
+				selectedPoints.p[selectedPoints.number-1]=translation;
+			synch();
+			longpress=true;
+			std::cout << "longpress true in B0\n";
+		}//dur
+	}//m_pressB0
+	
+        //wait 5 ms
+        usleep(5000);
+
+    }
+
+}
+
+
+void sceneManager::buttonEval(){
+    std::list<glm::ivec2> queue;
+    m_serv->getButtonQueue(queue);
+    for(std::list<glm::ivec2>::iterator it = queue.begin(); it != queue.end();++it){
+	if ((*it)[1]==1)
+		std::cout << "button " << (*it)[0] << "pressed\n";
+        if((*it)[0] == 1){ // if button 1
+            if((*it)[1] == 1){ //if pressed
+                m_swapIsoSurface = +1;
+                m_oldTimeForSwap = Clock::now();
+
+            } else {
+                m_swapIsoSurface = 0;
+            }
+        }
+        if((*it)[0] == 3){ // if button 3
+            if((*it)[1] == 1){ //if pressed
+                m_swapIsoSurface = -1;
+                m_oldTimeForSwap = Clock::now();
+
+            } else {
+                m_swapIsoSurface = 0;
+            }
+        }
+        if((*it)[0] == 2){ // if button 2 (mode for isosurfaces: both, negative, positive)
+            if((*it)[1] == 1){ //if pressed
+                m_oldTimeForSwap = Clock::now();
+            	m_pressB0 = true;
+            } else {
+            	if(m_pressB0){
+			std::cout << " B0 true\n";
+            		m_mode = (m_mode +1) % 3;
+            		m_pressB0 = false;
+            	}
+
+            }
+        }
+        if((*it)[0] == 0){ // if button 0 (switch time on/off)
+            if((*it)[1] == 1){ //if pressed
+            	m_pressB2 = true;
+
+            } else {
+            	if(m_pressB2){
+			std::cout << "b2 true\n";
+            		m_pressB2 = false;
+            	}
+
+            }
+        }
+    }
+
+}
+
+
+
+
+
+
+void sceneManager::keyboardFunction(char key, int x, int y){
+    switch(key){
+    case 27:
+        m_stop = true;
+        m_ren->stopMainLoop();
+
+        break;
+    case 'c':
+    case 'C':
+//    	if(cameraFile.is_open())
+//    		cameraFile<<glm::transpose(m_serv->getSceneTrafo())<<std::endl;
+//    	std::cout<<glm::transpose(m_serv->getSceneTrafo())<<std::endl;
+//    	break;
+    default:
+        std::cout<<"got key: "<<key<<std::endl;
+        break;
+
+
+    }
+}
+
+void sceneManager::displayFunction(){
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	m_ren->swapBuffer();
+
+}
+
+
+void InitGraphics(void)
+{
+
+
+    GLfloat LightAmbient[]= { 0.f, 0.0f, 0.0f, 1.0f };
+    GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
+    GLfloat LightSpecular[]= { 1.0f, 1.0f, 1.0f, 1.0f };
+    GLfloat LightPosition[]= { 0.0f, 20.0f, 0.0f};
+
+    glEnable(GL_TEXTURE_2D);
+
+    glClearColor (0.0, 0.0, 0.0, 1.0);
+    glClearDepth(1.0f);				// Depth Buffer Setup
+    glEnable(GL_DEPTH_TEST);		// Enables Depth Testing
+    glDepthFunc(GL_LESS);			// The Type Of Depth Test To Do
+
+    glDisable(GL_CULL_FACE);
+    glEnable (GL_BLEND);
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+
+}
+
+
+int main( int argc, char **argv )
+{
+	if(argc < 3){
+		std::cout<<"Not enough arguments! Start with "<<argv[0]<<
+			" <path to mlib configfile> <path to NOMAD configfile"<<std::endl;
+		exit(0);
+	}
+    std::string file =argv[1];
+    synchlib::caveConfig conf(file);
+    m3d::Renderer* ren = new m3d::Renderer(false,true);
+    ren->createWindow("demoServer",800,600,false,false);
+    GLenum err = glewInit();
+    if (GLEW_OK != err)
+    {
+      /* Problem: glewInit failed, something is seriously wrong. */
+      fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
+
+    }
+
+    synchlib::renderServer server(file,argc,argv);
+    {
+        sceneManager sceneM(ren,&server);
+
+        std::shared_ptr<synchlib::SynchObject<int> > currentDataPosSyncher = synchlib::SynchObject<int>::create();
+        sceneM.m_pCurrentDataPosSyncher = currentDataPosSyncher;
+        server.addSynchObject(currentDataPosSyncher,synchlib::renderServer::SENDER,0,0); //manual sending
+
+        std::shared_ptr<synchlib::SynchObject<int> > currentDataTimeSyncher = synchlib::SynchObject<int>::create();
+        sceneM.m_pCurrentDataTimeSyncher = currentDataTimeSyncher;
+        server.addSynchObject(currentDataTimeSyncher,synchlib::renderServer::SENDER,0,0); //manual sending
+
+	std::shared_ptr<synchlib::SynchObject<SelectedPoints> > 
+		currentDataPointsSyncher = 
+			synchlib::SynchObject<SelectedPoints>::create();
+
+	sceneM.m_pCurrentDataPointSyncher=currentDataPointsSyncher;
+	server.addSynchObject(currentDataPointsSyncher, synchlib::renderServer::SENDER,0,0); //manual sending
+
+
+        std::function<void(void)> dispFunc = std::bind(&sceneManager::displayFunction,&sceneM);
+        std::function<void(char,int,int)>  keyFunc = std::bind(&sceneManager::keyboardFunction,&sceneM,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
+
+        ren->setDisplayFunction(dispFunc);
+        ren->setIdleFunction(dispFunc);
+        ren->setKeyPressFunction(keyFunc);
+        ren->setAllowKeyboardAutoRepressing(false);
+
+
+        server.init();
+
+        server.startSynching();
+
+
+        sceneM.startThreads();
+
+        ren->mainLoop();
+    }
+    server.stopSynching();
+    delete ren;
+
+
+
+        return 0;
+}
+
+
diff --git a/CAVE/NOMADCaveT/src/points.frag b/CAVE/NOMADCaveT/src/points.frag
new file mode 100644
index 0000000000000000000000000000000000000000..a7c85144e5094541024b39d631986c551054b0c5
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/points.frag
@@ -0,0 +1,8 @@
+#version 330 core
+in vec3 col;
+out vec4 color;
+
+void main()
+{    
+    color = vec4(col, 1);
+}  
diff --git a/CAVE/NOMADCaveT/src/points.vert b/CAVE/NOMADCaveT/src/points.vert
new file mode 100644
index 0000000000000000000000000000000000000000..1e80909a93777a7ae87aaf3313931090e9a2c587
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/points.vert
@@ -0,0 +1,12 @@
+#version 330 core
+layout (location = 0) in vec3 pos; 
+layout (location = 1) in vec3 colin;
+out vec3 col;
+
+uniform mat4 projection;
+
+void main()
+{
+    gl_Position = projection * vec4(pos, 1.0);
+    col=colin;
+}  
diff --git a/CAVE/NOMADCaveT/src/selectedPoints.hpp b/CAVE/NOMADCaveT/src/selectedPoints.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..36a78a22361ebf913a448ebeead04b05cb93bc38
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/selectedPoints.hpp
@@ -0,0 +1,7 @@
+#include <glm/vec3.hpp>
+/// for measuring length (2 points), angle (3 points), 
+/// and dihedral angle (4 points)
+struct SelectedPoints {
+	int number;
+	glm::vec3 p[4];
+};
diff --git a/CAVE/NOMADCaveT/src/text.frag b/CAVE/NOMADCaveT/src/text.frag
new file mode 100644
index 0000000000000000000000000000000000000000..cdb8fff6af337a4972d30fd2a0fe604383064b62
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/text.frag
@@ -0,0 +1,12 @@
+#version 330 core
+in vec2 TexCoords;
+out vec4 color;
+
+uniform sampler2D text;
+uniform vec3 textColor;
+
+void main()
+{    
+    vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
+    color = vec4(textColor, 1.0) * sampled;
+}  
diff --git a/CAVE/NOMADCaveT/src/text.vert b/CAVE/NOMADCaveT/src/text.vert
new file mode 100644
index 0000000000000000000000000000000000000000..5985616a12342cdafd9d5b1f8d33468e5959058f
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/text.vert
@@ -0,0 +1,11 @@
+#version 330 core
+layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>
+out vec2 TexCoords;
+
+uniform mat4 projection;
+
+void main()
+{
+    gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
+    TexCoords = vertex.zw;
+}  
diff --git a/CAVE/NOMADCaveT/src/textRendering.cpp b/CAVE/NOMADCaveT/src/textRendering.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5b7f4712c0932c8a68204c2030bd56994306a848
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/textRendering.cpp
@@ -0,0 +1,170 @@
+#include <iostream>
+#include <glm/vec2.hpp>
+#include <glm/vec3.hpp>
+#include <GL/glew.h>
+#include <m3dshaderLoader.h>
+#include "textRendering.hpp"
+
+#include "defines.h"
+
+namespace TextRendering {
+
+Text::Text()
+{
+}
+
+bool Text::init(std::string font) 
+{
+GLenum err;
+//initialization
+FT_Library ft;
+FT_Face face;
+
+if (FT_Init_FreeType(&ft)) {
+    std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;
+	return false;
+}
+
+if (FT_New_Face(ft, font.c_str(), 0, &face)) {
+    std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;  
+	return false;
+}
+
+FT_Set_Pixel_Sizes(face, 0, 96);  
+
+while ((err = glGetError()) != GL_NO_ERROR) 
+	std::cerr <<__FUNCTION__<<"line" << __LINE__<< " OpenGL error " << err << std::endl;
+
+glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Disable byte-alignment restriction
+
+//load of glyphs
+for (GLubyte c = 0; c < 128; c++)
+{
+    // Load character glyph 
+    if (FT_Load_Char(face, c, FT_LOAD_RENDER))
+    {
+        std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << c <<std::endl;
+        continue;
+    }
+    // Generate texture
+    GLuint texture;
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glTexImage2D(
+        GL_TEXTURE_2D,
+        0,
+        GL_RED,
+        face->glyph->bitmap.width,
+        face->glyph->bitmap.rows,
+        0,
+        GL_RED,
+        GL_UNSIGNED_BYTE,
+        face->glyph->bitmap.buffer
+    );
+    // Set texture options
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    // Now store character for later use
+    Character character = {
+        texture, 
+        glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
+        glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
+        face->glyph->advance.x
+    };
+    Characters.insert(std::pair<GLchar, Character>(c, character));
+	while ((err = glGetError()) != GL_NO_ERROR) 
+		std::cerr <<__FUNCTION__<<"line" << __LINE__<< " OpenGL error " << err << std::endl;
+} //for
+
+//cleanup
+FT_Done_Face(face);
+FT_Done_FreeType(ft);
+
+while ((err = glGetError()) != GL_NO_ERROR) 
+	std::cerr <<__FUNCTION__<<"line" << __LINE__<< " OpenGL error " << err << std::endl;
+
+//vaos
+glGenVertexArrays(1, &VAO);
+glGenBuffers(1, &VBO);
+glBindVertexArray(VAO);
+glBindBuffer(GL_ARRAY_BUFFER, VBO);
+glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
+glEnableVertexAttribArray(0);
+glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
+glBindBuffer(GL_ARRAY_BUFFER, 0);
+glBindVertexArray(0);      
+
+while ((err = glGetError()) != GL_NO_ERROR) 
+	std::cerr <<__FUNCTION__<<"line" << __LINE__<< " OpenGL error " << err << std::endl;
+
+//loading of shaders
+if (!s.loadShadersFromFiles(SHADERPATH "text.vert", SHADERPATH "text.frag"))
+	return false;
+
+while ((err = glGetError()) != GL_NO_ERROR) 
+	std::cerr <<__FUNCTION__<<"line" << __LINE__<< " OpenGL error " << err << std::endl;
+
+return err== GL_NO_ERROR;
+} //bool Text::init(std::string font) 
+
+bool Text::render(std::string text, GLfloat ix, GLfloat iy, GLfloat scale, 
+	glm::vec3 color, glm::mat4 proj)
+{
+GLfloat x=ix, y=iy;
+glEnable(GL_BLEND);
+glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  
+  // Activate corresponding render state	
+    s.begin();
+    s.setUniform("textColor", color);
+    s.setUniformMatrix("projection", false, proj);
+    glActiveTexture(GL_TEXTURE0);
+    glBindVertexArray(VAO);
+
+    // Iterate through all characters
+    std::string::const_iterator c;
+    for (c = text.begin(); c != text.end(); c++)
+    {
+	if (*c=='\n') {
+		x=ix;
+		y-=Characters[*c].Size.y * scale;
+		continue;
+	}
+        Character ch = Characters[*c];
+
+        GLfloat xpos = x + ch.Bearing.x * scale;
+        GLfloat ypos = y - (ch.Size.y - ch.Bearing.y) * scale;
+
+        GLfloat w = ch.Size.x * scale;
+        GLfloat h = ch.Size.y * scale;
+        // Update VBO for each character
+        GLfloat vertices[6][4] = {
+            { xpos,     ypos + h,   0.0, 0.0 },            
+            { xpos,     ypos,       0.0, 1.0 },
+            { xpos + w, ypos,       1.0, 1.0 },
+
+            { xpos,     ypos + h,   0.0, 0.0 },
+            { xpos + w, ypos,       1.0, 1.0 },
+            { xpos + w, ypos + h,   1.0, 0.0 }           
+        };
+        // Render glyph texture over quad
+        glBindTexture(GL_TEXTURE_2D, ch.TextureID);
+        // Update content of VBO memory
+        glBindBuffer(GL_ARRAY_BUFFER, VBO);
+        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); 
+        glBindBuffer(GL_ARRAY_BUFFER, 0);
+        // Render quad
+        glDrawArrays(GL_TRIANGLES, 0, 6);
+        // Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
+        x += (ch.Advance >> 6) * scale; // Bitshift by 6 to get value in pixels (2^6 = 64)
+    }
+    glBindVertexArray(0);
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+	s.end();
+	return true;
+} // render
+
+} // namespace TextRendering
+
diff --git a/CAVE/NOMADCaveT/src/textRendering.hpp b/CAVE/NOMADCaveT/src/textRendering.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..dbfec764750f4298f63da79a2667951281b7a703
--- /dev/null
+++ b/CAVE/NOMADCaveT/src/textRendering.hpp
@@ -0,0 +1,53 @@
+#ifndef TEXT_RENDERING_HPP
+#define TEXT_RENDERING_HPP
+
+#include <map>
+#include <ft2build.h>
+#include FT_FREETYPE_H 
+
+#include <m3dshaderLoader.h>
+
+///Text rendering class for OpenGL 4 and Freetype 2
+///Compatible with libsynch
+
+///Based on http://learnopengl.com/#!In-Practice/Text-Rendering
+///License of original work: CC0 1.0 Universal
+///https://creativecommons.org/publicdomain/zero/1.0/legalcode
+
+///Adapted by Ruben Garcia (garcia@lrz.de) for use within NOMAD and
+///libSynch
+///License: Apache 2.0 (as required by NOMAD)
+
+namespace TextRendering {
+
+struct Character {
+    GLuint     TextureID;  // ID handle of the glyph texture
+    glm::ivec2 Size;       // Size of glyph
+    glm::ivec2 Bearing;    // Offset from baseline to left/top of glyph
+    GLuint     Advance;    // Offset to advance to next glyph
+};
+
+class Text {
+///use within synchlib: call init in SceneManager constructor and 
+///render in displayFunction. use pvmat*wand as proj parameter for wand-aligned
+///use glm::decompose to use axis-aligned, wand-centred
+///Warning, this code uses glgenvertexarrays and requires
+///glewExperimental = GL_TRUE; GLenum err = glewInit(); 
+///for glew under 1.20
+private:
+std::map<GLchar, Character> Characters;
+GLuint VAO, VBO;
+m3d::ShaderLoader s;
+public:
+Text();
+bool init(std::string font);
+///This function may only be used with a correctly setup OpenGL environment
+///@arg font: The path to a ttf font in disk to load
+bool render(std::string text, GLfloat x, GLfloat y, GLfloat scale, 
+	glm::vec3 color, glm::mat4 proj);
+///This function may only be used with a correctly setup OpenGL environment
+///Carriage return is not supported for now
+};
+
+}
+#endif
diff --git a/NOMADVRLib/ConfigFile.cpp b/NOMADVRLib/ConfigFile.cpp
index 51ca86e8fd903dcbab1af0bdbab64f2e92d3d3aa..7e3c1eb3b053af4d113c75f7ebb5149849ca8564 100644
--- a/NOMADVRLib/ConfigFile.cpp
+++ b/NOMADVRLib/ConfigFile.cpp
@@ -1,5 +1,6 @@
 #include <algorithm>
 #include <errno.h>
+#include <string.h>
 
 #include "ConfigFile.h"
 #include "atoms.hpp"
diff --git a/NOMADVRLib/MyGL.h b/NOMADVRLib/MyGL.h
index 5687278bafb037d96f4987a1a96e00d45dcc86a1..fcd3a8cf0ba79ae3bf36c5684d1d840ebd36a400 100644
--- a/NOMADVRLib/MyGL.h
+++ b/NOMADVRLib/MyGL.h
@@ -2,20 +2,20 @@
 #define __MYGL_H
 
 //FIXME, support more platforms in the future
-#ifdef WIN32
+#if defined(WIN32) || defined(CAVE)
 	#include <GL/glew.h>
 #else // Samsung GearVR + Oculus Mobile
 	#ifdef OCULUSMOBILE
 		#include "Kernel/OVR_GlUtils.h"
 	#else
-	#include <GLES3/gl31.h>
+		#include <GLES3/gl31.h>
 	//google cardboard, gvr
 	#endif //OCULUSMOBILE
 	#include "GLES2/gl2ext.h"
 //ndk r10e does not provide opengles 3.2
 	#ifndef GL_TESS_EVALUATION_SHADER
-	#define GL_TESS_EVALUATION_SHADER GL_TESS_EVALUATION_SHADER_EXT
+		#define GL_TESS_EVALUATION_SHADER GL_TESS_EVALUATION_SHADER_EXT
 	#endif //GL_TESS_EVALUATION_SHADER
 #endif //WIN32
 
-#endif //__MYGL_H
\ No newline at end of file
+#endif //__MYGL_H
diff --git a/NOMADVRLib/TessShaders.cpp b/NOMADVRLib/TessShaders.cpp
index 866964f3d1cc869a9a8efca69eed73f3112bfd47..cabc18b4ef466b24aea6f8eb6506ab82bfa1cf59 100644
--- a/NOMADVRLib/TessShaders.cpp
+++ b/NOMADVRLib/TessShaders.cpp
@@ -10,7 +10,7 @@ const char * const AtomShaders [] = {
 
 	// vertex shader
 //Android 21 gives error: only supports up to '310 es'
-#ifdef WIN32
+#if defined(WIN32) || defined(CAVE)
 	"#version 410\n"
 #else
 "#version 310 es\n"
@@ -30,7 +30,7 @@ const char * const AtomShaders [] = {
 	"}\n",
 
 	//fragment shader
-#ifdef WIN32
+#if defined(WIN32) || defined(CAVE)
 	"#version 410 core\n"
 #else
 "#version 310 es\n"
@@ -52,7 +52,7 @@ const char * const AtomShaders [] = {
 	"}\n",
 
 	//tess eval
-#ifdef WIN32
+#if defined(WIN32) || defined(CAVE)
 	"#version 400\n"
 #else
 "#version 320 es\n"
@@ -87,7 +87,7 @@ const char * const AtomShadersNoTess [] = {
 	//No Tess means smooth shading looks very strange. Better use per-face lighting
 		// vertex shader
 //Android 21 gives error: only supports up to '310 es'
-#ifdef WIN32
+#if defined(WIN32) || defined(CAVE)
 	"#version 410\n"
 #else
 "#version 310 es\n"
@@ -111,7 +111,7 @@ const char * const AtomShadersNoTess [] = {
 	"}\n",
 
 	//fragment shader
-#ifdef WIN32
+#if defined(WIN32) || defined(CAVE)
 	"#version 410 core\n"
 #else
 "#version 310 es\n"
@@ -133,4 +133,4 @@ const char * const AtomShadersNoTess [] = {
 	"}\n",
 	//tess eval
 	nullptr
-};
\ No newline at end of file
+};
diff --git a/NOMADVRLib/UnitCellShaders.cpp b/NOMADVRLib/UnitCellShaders.cpp
index 05dc426898a86b8ddd3e760d73ca72697c87baab..b60f4cfad271924922499acd814547210735583e 100644
--- a/NOMADVRLib/UnitCellShaders.cpp
+++ b/NOMADVRLib/UnitCellShaders.cpp
@@ -2,7 +2,7 @@
 
 const char * const UnitCellShaders [] = {"Unit Cell Renderer",
 	//vertex
-	#ifdef WIN32
+#if defined(WIN32) || defined(CAVE)
 	"#version 410\n"
 #else
 	"#version 300 es\n"
@@ -15,7 +15,7 @@ const char * const UnitCellShaders [] = {"Unit Cell Renderer",
 	"}\n"
 	,
 	//fragment
-	#ifdef WIN32
+#if defined(WIN32) || defined(CAVE)
 	"#version 410\n"
 #else
 	"#version 300 es\n"
diff --git a/NOMADVRLib/atoms.cpp b/NOMADVRLib/atoms.cpp
index e79c3ac5d6e7ed245bc131022b576167cccfd947..cfdb1101d0801bdc67cd237fdc24a26e2afa430f 100644
--- a/NOMADVRLib/atoms.cpp
+++ b/NOMADVRLib/atoms.cpp
@@ -358,7 +358,6 @@ if (out==nullptr) {
 conn.request( "GET", url, 0, 0,0 );
 while( conn.outstanding() )
 	conn.pump();
-fclose(out);
 } catch (const happyhttp::Wobbly& w) {
 #ifdef _MSC_VER
 	int e=	WSAGetLastError();
@@ -366,7 +365,7 @@ fclose(out);
 #else
 	eprintf( "error %s\n", w.what());
 #endif
-
+	fclose(out);
 	return -3;
 }
 fclose(out);
diff --git a/NOMADVRLib/atomsGL.cpp b/NOMADVRLib/atomsGL.cpp
index 1fb3f7db1e456c051b00a23d9bd811b42fb074d7..88b9162653a7d42bf6c12e98417bcb89444e0243 100644
--- a/NOMADVRLib/atomsGL.cpp
+++ b/NOMADVRLib/atomsGL.cpp
@@ -45,6 +45,11 @@ GLenum SetupAtomsNoTess (GLuint **AtomVAO, GLuint **AtomVertBuffer, GLuint **Ato
 if (!numAtoms)
 		return 0;
 
+if (!solid) {
+	eprintf ("SetupAtomsNoTess, error: no solid defined");
+	return 0;
+}
+
 //eprintf ("SetupAtomsNoTess 2");
 	//for now, render an icosahedron
 	//http://prideout.net/blog/?p=48 //public domain code
diff --git a/README.md b/README.md
index b5d540f3c09ad4ccb67856e80ed0e953eeb99bb8..15bff9267de4fa5d6a80f182d5ed79cfe09fc56d 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,10 @@ Subdirectories:
 	OpenVR: Demos for HTC Vive.
 	OculusMobile: Demos for GearVR.
 	GoogleCardboardAndroid: Demos for Google Cardboard (android)
+	CAVE: Demos for LRZ CAVE-like environment (linux)
 	
 	NOMADVRLib: Shared code between HTC Vive and GearVR demos related to NOMAD.
-	libs: Other (external) supporting libs shared by HTC Vive and GearVR demos
+	libs: Other (external) supporting libs shared by HTC Vive, GearVR, Cardboard and CAVE demos
 	
 	webserver: 
 		htdocs: Web pages containing the VR software and documentation.