Exemple #1
0
void Listener::initialize(const Misc::ConfigurationFileSection& configFileSection)
	{
	/* Read the listener's name: */
	std::string name=configFileSection.retrieveString("./name");
	listenerName=new char[name.size()+1];
	strcpy(listenerName,name.c_str());
	
	/* Determine whether the listener is head-tracked: */
	headTracked=configFileSection.retrieveValue<bool>("./headTracked",false);
	if(headTracked)
		{
		/* Retrieve head tracking device pointer: */
		headDevice=findInputDevice(configFileSection.retrieveString("./headDevice").c_str());
		if(headDevice==0)
			Misc::throwStdErr("Listener: Head device \"%s\" not found",configFileSection.retrieveString("./headDevice").c_str());
		}
	else
		{
		/* Retrieve fixed head position/orientation: */
		headDeviceTransformation=configFileSection.retrieveValue<TrackerState>("./headDeviceTransformation");
		}
	
	/* Get head position and listening and up directions in head device coordinates: */
	deviceHeadPosition=configFileSection.retrieveValue<Point>("./headPosition",Point::origin);
	deviceListenDirection=configFileSection.retrieveValue<Vector>("./listenDirection",Vector(0,1,0));
	deviceUpDirection=configFileSection.retrieveValue<Vector>("./upDirection",Vector(0,0,1));
	}
ToolKillZoneFrustum::ToolKillZoneFrustum(const Misc::ConfigurationFileSection& configFileSection)
	:ToolKillZone(configFileSection),
	 viewer(0),screen(0)
	{
	/* Get the viewer: */
	std::string viewerName=configFileSection.retrieveString("./killZoneViewerName");
	viewer=findViewer(viewerName.c_str());
	if(viewer==0)
		Misc::throwStdErr("ToolKillZoneFrustum::ToolKillZoneFrustum: Viewer %s not found",viewerName.c_str());
	
	/* Get the screen: */
	std::string screenName=configFileSection.retrieveString("./killZoneScreenName");
	screen=findScreen(screenName.c_str());
	if(screen==0)
		Misc::throwStdErr("ToolKillZoneFrustum::ToolKillZoneFrustum: Screen %s not found",screenName.c_str());
	
	/* Read box' center and size: */
	Point boxCenter=configFileSection.retrieveValue<Point>("./killZoneCenter");
	Vector boxSize=configFileSection.retrieveValue<Vector>("./killZoneSize");
	
	/* Transform box center and size to screen coordinates: */
	ONTransform screenT=screen->getScreenTransformation();
	boxCenter=screenT.inverseTransform(boxCenter);
	boxCenter[2]=Scalar(0);
	boxSize=screenT.inverseTransform(boxSize);
	boxSize[2]=Scalar(0);
	box=Box(boxCenter-boxSize*Scalar(0.5),boxCenter+boxSize*Scalar(0.5));
	}
Exemple #3
0
void Viewer::initialize(const Misc::ConfigurationFileSection& configFileSection)
	{
	/* Read the viewer's name: */
	std::string name=configFileSection.retrieveString("./name");
	viewerName=new char[name.size()+1];
	strcpy(viewerName,name.c_str());
	
	/* Determine whether the viewer is head-tracked: */
	headTracked=configFileSection.retrieveValue<bool>("./headTracked",false);
	if(headTracked)
		{
		/* Retrieve head tracking device pointer: */
		headDevice=findInputDevice(configFileSection.retrieveString("./headDevice").c_str());
		if(headDevice==0)
			Misc::throwStdErr("Viewer: Head device \"%s\" not found",configFileSection.retrieveString("./headDevice").c_str());
		}
	else
		{
		/* Retrieve fixed head position/orientation: */
		headDeviceTransformation=configFileSection.retrieveValue<TrackerState>("./headDeviceTransformation");
		}
	
	/* Get view direction and eye positions in head device coordinates: */
	deviceViewDirection=configFileSection.retrieveValue<Vector>("./viewDirection",Vector(0,1,0));
	deviceMonoEyePosition=configFileSection.retrieveValue<Point>("./monoEyePosition",Point::origin);
	deviceLeftEyePosition=configFileSection.retrieveValue<Point>("./leftEyePosition",Point::origin);
	deviceRightEyePosition=configFileSection.retrieveValue<Point>("./rightEyePosition",Point::origin);
	
	/* Create the viewer's light source: */
	lightsource=getLightsourceManager()->createLightsource(true);
	
	/* Get head light enable flag: */
	if(!configFileSection.retrieveValue<bool>("./headLightEnabled",true))
		lightsource->disable();
	
	/* Get head light position and direction in head device coordinates: */
	headLightDevicePosition=configFileSection.retrieveValue<Point>("./headLightPosition",Point::origin);
	headLightDeviceDirection=configFileSection.retrieveValue<Vector>("./headLightDirection",Vector(0,1,0));
	
	/* Retrieve head light settings: */
	GLLight::Color headLightColor=configFileSection.retrieveValue<GLLight::Color>("./headLightColor",GLLight::Color(1.0f,1.0f,1.0f));
	lightsource->getLight().diffuse=headLightColor;
	lightsource->getLight().specular=headLightColor;
	lightsource->getLight().spotCutoff=configFileSection.retrieveValue<GLfloat>("./headLightSpotCutoff",180.0f);
	lightsource->getLight().spotExponent=configFileSection.retrieveValue<GLfloat>("./headLightSpotExponent",0.0f);
	
	/* Initialize transient state if head tracking is disabled: */
	if(!headTracked)
		{
		/* Initialize transient state: */
		Point hlp=headDeviceTransformation.transform(headLightDevicePosition);
		lightsource->getLight().position=GLLight::Position(GLfloat(hlp[0]),GLfloat(hlp[1]),GLfloat(hlp[2]),1.0f);
		Vector hld=headDeviceTransformation.transform(headLightDeviceDirection);
		hld.normalize();
		lightsource->getLight().spotDirection=GLLight::SpotDirection(GLfloat(hld[0]),GLfloat(hld[1]),GLfloat(hld[2]));
		}
	}
Exemple #4
0
void ViewpointFileNavigationTool::configure(Misc::ConfigurationFileSection& configFileSection)
	{
	/* Override per-class configuration settings: */
	viewpointFileName=configFileSection.retrieveString("./viewpointFileName",viewpointFileName);
	showGui=configFileSection.retrieveValue<bool>("./showGui",showGui);
	showKeyframes=configFileSection.retrieveValue<bool>("./showKeyframes",showKeyframes);
	pauseFileName=configFileSection.retrieveString("./pauseFileName",pauseFileName);
	autostart=configFileSection.retrieveValue<bool>("./autostart",autostart);
	}
TheoraMovieSaver::TheoraMovieSaver(const Misc::ConfigurationFileSection& configFileSection)
	:MovieSaver(configFileSection),
	 movieFile(IO::openFile(configFileSection.retrieveString("./movieFileName").c_str(),IO::File::WriteOnly)),
	 oggStream(1),
	 theoraBitrate(0),theoraQuality(32),theoraGopSize(32),
	 imageExtractor(0)
	{
	movieFile->setEndianness(Misc::LittleEndian);
	
	/* Read the encoder parameters: */
	theoraBitrate=configFileSection.retrieveValue<int>("./movieBitrate",theoraBitrate);
	if(theoraBitrate<0)
		theoraBitrate=0;
	theoraQuality=configFileSection.retrieveValue<int>("./movieQuality",theoraQuality);
	if(theoraQuality<0)
		theoraQuality=0;
	if(theoraQuality>63)
		theoraQuality=63;
	theoraGopSize=configFileSection.retrieveValue<int>("./movieGopSize",theoraGopSize);
	if(theoraGopSize<1)
		theoraGopSize=1;
	
	/* Set the Theora frame rate and adjust the initially configured frame rate: */
	theoraFrameRate=int(frameRate+0.5);
	frameRate=theoraFrameRate;
	frameInterval=Misc::Time(1.0/frameRate);
	}
Exemple #6
0
ImageSequenceMovieSaver::ImageSequenceMovieSaver(const Misc::ConfigurationFileSection& configFileSection)
	:MovieSaver(configFileSection),
	 frameNameTemplate(configFileSection.retrieveString("./movieFrameNameTemplate")),
	 done(false)
	{
	/* Check if the frame name template has the correct format: */
	int numConversions=0;
	bool hasIntConversion=false;
	for(std::string::const_iterator fntIt=frameNameTemplate.begin();fntIt!=frameNameTemplate.end();++fntIt)
		{
		if(*fntIt=='%')
			{
			++fntIt;
			if(*fntIt!='%')
				{
				++numConversions;
				
				/* Skip width modifiers: */
				while(isdigit(*fntIt))
					++fntIt;
				
				/* Check for unsigned integer conversion: */
				if(*fntIt=='u')
					hasIntConversion=true;
				}
			}
		else if(*fntIt=='/') // Only accept conversions in the file name part
			hasIntConversion=false;
		}
	if(numConversions!=1||!hasIntConversion)
		Misc::throwStdErr("MovieSaver::MovieSaver: movie frame name template \"%s\" does not have exactly one %%u conversion",frameNameTemplate.c_str());
	
	/* Start the image writing thread: */
	frameSavingThread.start(this,&ImageSequenceMovieSaver::frameSavingThreadMethod);
	}
Exemple #7
0
VRDeviceClient::VRDeviceClient(const Misc::ConfigurationFileSection& configFileSection)
	:pipe(Comm::TCPSocket(configFileSection.retrieveString("./serverName"),configFileSection.retrieveValue<int>("./serverPort"))),
	 active(false),streaming(false),
	 packetNotificationCB(0),packetNotificationCBData(0)
	{
	initClient();
	}
InputDeviceAdapterVisBox::InputDeviceAdapterVisBox(InputDeviceManager* sInputDeviceManager,const Misc::ConfigurationFileSection& configFileSection)
	:InputDeviceAdapter(sInputDeviceManager),
	 xyzhpr((const float*)-1)
	{
	/* Retrieve the shared memory key from the configuration file: */
	key_t sharedMemoryKey=key_t(configFileSection.retrieveValue<int>("./sharedMemoryKey",0xDEAD));
	
	/* Try attaching to the shared memory segment: */
	int sharedMemoryID=shmget(sharedMemoryKey,6*sizeof(float),0777);
	if(sharedMemoryID<0)
		Misc::throwStdErr("InputDeviceAdapterVisBox::InputDeviceAdapterVisBox: Could not attach to shared memory segment using key %x",int(sharedMemoryKey));
	
	/* Get the pointer to the tracker state variables: */
	xyzhpr=reinterpret_cast<const float*>(shmat(sharedMemoryID,0,SHM_RDONLY));
	if(xyzhpr==(const float*)-1)
		Misc::throwStdErr("InputDeviceAdapterVisBox::InputDeviceAdapterVisBox: Could not map shared memory segment using key %x",int(sharedMemoryKey));
	
	/* Allocate new adapter state arrays: */
	numInputDevices=1;
	inputDevices=new InputDevice*[numInputDevices];
	
	/* Create new input device: */
	std::string deviceName=configFileSection.retrieveString("./name");
	inputDevices[0]=inputDeviceManager->createInputDevice(deviceName.c_str(),InputDevice::TRACK_POS|InputDevice::TRACK_DIR|InputDevice::TRACK_ORIENT,0,0,true);
	inputDevices[0]->setDeviceRayDirection(configFileSection.retrieveValue<Vector>("./deviceRayDirection",Vector(0,1,0)));
	
	/* Initialize the new device's glyph from the current configuration file section: */
	Glyph& deviceGlyph=inputDeviceManager->getInputGraphManager()->getInputDeviceGlyph(inputDevices[0]);
	deviceGlyph.configure(configFileSection,"./deviceGlyphType","./deviceGlyphMaterial");
	
	/* Set device's linear and angular velocities to zero, because we don't know any better: */
	inputDevices[0]->setLinearVelocity(Vector::zero);
	inputDevices[0]->setAngularVelocity(Vector::zero);
	}
void Glyph::configure(const Misc::ConfigurationFileSection& configFileSection,const char* glyphTypeTagName,const char* glyphMaterialTagName)
	{
	/* Retrieve glyph type as string: */
	std::string glyphTypeName=configFileSection.retrieveString(glyphTypeTagName,"None");
	if(glyphTypeName!="None")
		{
		if(glyphTypeName=="Cone")
			glyphType=CONE;
		else if(glyphTypeName=="Cube")
			glyphType=CUBE;
		else if(glyphTypeName=="Sphere")
			glyphType=SPHERE;
		else if(glyphTypeName=="Crossball")
			glyphType=CROSSBALL;
		else if(glyphTypeName=="Box")
			glyphType=BOX;
		else if(glyphTypeName=="Cursor")
			glyphType=CURSOR;
		else
			Misc::throwStdErr("GlyphRenderer::Glyph: Invalid glyph type %s",glyphTypeName.c_str());
		enabled=true;
		glyphMaterial=configFileSection.retrieveValue<GLMaterial>(glyphMaterialTagName,glyphMaterial);
		}
	else
		enabled=false;
	}
Exemple #10
0
SoundContext::SoundContext(const Misc::ConfigurationFileSection& configFileSection,VruiState* sVruiState)
    :vruiState(sVruiState),
#ifdef VRUI_USE_OPENAL
     alDevice(0),alContext(0),
#endif
     contextData(0),
     listener(findListener(configFileSection.retrieveString("./listenerName").c_str()))
{
#ifdef VRUI_USE_OPENAL
    /* Open the OpenAL device: */
    std::string alDeviceName=configFileSection.retrieveValue<std::string>("./deviceName","Default");
    alDevice=alcOpenDevice(alDeviceName!="Default"?alDeviceName.c_str():0);
    if(alDevice==0)
        Misc::throwStdErr("SoundContext::SoundContext: Could not open OpenAL sound device %s",alDeviceName.c_str());

    /* Create an OpenAL context: */
    alContext=alcCreateContext(alDevice,0);
    if(alContext==0)
    {
        alcCloseDevice(alDevice);
        Misc::throwStdErr("SoundContext::SoundContext: Could not create OpenAL context for sound device %s",alDeviceName.c_str());
    }
#endif

    /* Create an AL context data object: */
    contextData=new ALContextData(101);

    /* Initialize the sound context's OpenAL context: */
    makeCurrent();

    /* Initialize application sound state: */
    if(vruiState->perSoundInitFunction!=0)
        vruiState->perSoundInitFunction(*contextData,vruiState->perSoundInitFunctionData);
}
Exemple #11
0
void Glyph::configure(const Misc::ConfigurationFileSection& configFileSection,const char* glyphTypeTagName,const char* glyphMaterialTagName)
	{
	/* Retrieve glyph type as string and set it: */
	setGlyphType(configFileSection.retrieveString(glyphTypeTagName,"None").c_str());
	
	/* Retrieve the glyph material: */
	glyphMaterial=configFileSection.retrieveValue<GLMaterial>(glyphMaterialTagName,glyphMaterial);
	}
std::string InputDeviceDataSaver::getInputDeviceDataFileName(const Misc::ConfigurationFileSection& configFileSection)
	{
	/* Retrieve the base file name: */
	std::string inputDeviceDataFileName=configFileSection.retrieveString("./inputDeviceDataFileName");
	
	/* Make the file name unique: */
	char numberedFileName[1024];
	Misc::createNumberedFileName(inputDeviceDataFileName.c_str(),4,numberedFileName);
	return numberedFileName;
	}
InputDeviceDataSaver::InputDeviceDataSaver(const Misc::ConfigurationFileSection& configFileSection,InputDeviceManager& inputDeviceManager)
	:inputDeviceDataFile(getInputDeviceDataFileName(configFileSection).c_str(),"wb",Misc::File::LittleEndian),
	 numInputDevices(inputDeviceManager.getNumInputDevices()),
	 inputDevices(new InputDevice*[numInputDevices]),
	 soundRecorder(0),
	 firstFrame(true)
	{
	/* Save number of input devices: */
	inputDeviceDataFile.write<int>(numInputDevices);
	
	/* Save layout of all input devices in the input device manager: */
	for(int i=0;i<numInputDevices;++i)
		{
		/* Get pointer to the input device: */
		inputDevices[i]=inputDeviceManager.getInputDevice(i);
		
		/* Save input device's layout: */
		char name[40];
		strncpy(name,inputDevices[i]->getDeviceName(),40);
		name[39]='\0';
		inputDeviceDataFile.write(name,40);
		inputDeviceDataFile.write<int>(inputDevices[i]->getTrackType());
		inputDeviceDataFile.write<int>(inputDevices[i]->getNumButtons());
		inputDeviceDataFile.write<int>(inputDevices[i]->getNumValuators());
		inputDeviceDataFile.write(inputDevices[i]->getDeviceRayDirection().getComponents(),3);
		}
	
	/* Check if the user wants to record a commentary track: */
	std::string soundFileName=configFileSection.retrieveString("./soundFileName","");
	if(soundFileName!="")
		{
		try
			{
			/* Create a sound data format for recording: */
			Sound::SoundDataFormat soundFormat;
			soundFormat.bitsPerSample=configFileSection.retrieveValue<int>("./sampleResolution",soundFormat.bitsPerSample);
			soundFormat.samplesPerFrame=configFileSection.retrieveValue<int>("./numChannels",soundFormat.samplesPerFrame);
			soundFormat.framesPerSecond=configFileSection.retrieveValue<int>("./sampleRate",soundFormat.framesPerSecond);
			
			/* Create a sound recorder for the given sound file name: */
			char numberedFileName[1024];
			soundRecorder=new Sound::SoundRecorder(soundFormat,Misc::createNumberedFileName(soundFileName.c_str(),4,numberedFileName));
			}
		catch(std::runtime_error error)
			{
			/* Print a message, but carry on: */
			std::cerr<<"InputDeviceDataSaver: Disabling sound recording due to exception "<<error.what()<<std::endl;
			}
		}
	}
Exemple #14
0
VisletManager::VisletManager(const Misc::ConfigurationFileSection& sConfigFileSection)
	:Plugins::FactoryManager<VisletFactory>(sConfigFileSection.retrieveString("./visletDsoNameTemplate",SYSVISLETDSONAMETEMPLATE)),
	 configFileSection(sConfigFileSection)
	{
	typedef std::vector<std::string> StringList;
	
	/* Get additional search paths from configuration file section and add them to the factory manager: */
	StringList visletSearchPaths=configFileSection.retrieveValue<StringList>("./visletSearchPaths",StringList());
	for(StringList::const_iterator vspIt=visletSearchPaths.begin();vspIt!=visletSearchPaths.end();++vspIt)
		{
		/* Add the path: */
		getDsoLocator().addPath(*vspIt);
		}
	}
void InputDeviceAdapter::createInputDevice(int deviceIndex,const Misc::ConfigurationFileSection& configFileSection)
	{
	/* Read input device name: */
	std::string name=configFileSection.retrieveString("./name");
	
	/* Determine input device type: */
	int trackType=InputDevice::TRACK_NONE;
	std::string trackTypeString=configFileSection.retrieveString("./trackType","None");
	if(trackTypeString=="None")
		trackType=InputDevice::TRACK_NONE;
	else if(trackTypeString=="3D")
		trackType=InputDevice::TRACK_POS;
	else if(trackTypeString=="Ray")
		trackType=InputDevice::TRACK_POS|InputDevice::TRACK_DIR;
	else if(trackTypeString=="6D")
		trackType=InputDevice::TRACK_POS|InputDevice::TRACK_DIR|InputDevice::TRACK_ORIENT;
	else
		Misc::throwStdErr("InputDeviceAdapter: Unknown tracking type \"%s\"",trackTypeString.c_str());
	
	/* Determine numbers of buttons and valuators: */
	int numButtons=configFileSection.retrieveValue<int>("./numButtons",0);
	int numValuators=configFileSection.retrieveValue<int>("./numValuators",0);
	
	/* Create new input device as a physical device: */
	InputDevice* newDevice=inputDeviceManager->createInputDevice(name.c_str(),trackType,numButtons,numValuators,true);
	Vector deviceRayDirection=configFileSection.retrieveValue<Vector>("./deviceRayDirection",Vector(0,1,0));
	Scalar deviceRayStart=configFileSection.retrieveValue<Scalar>("./deviceRayStart",-getInchFactor());
	newDevice->setDeviceRay(deviceRayDirection,deviceRayStart);
	
	/* Initialize the new device's glyph from the current configuration file section: */
	Glyph& deviceGlyph=inputDeviceManager->getInputGraphManager()->getInputDeviceGlyph(newDevice);
	deviceGlyph.configure(configFileSection,"./deviceGlyphType","./deviceGlyphMaterial");
	
	/* Save the new input device: */
	inputDevices[deviceIndex]=newDevice;
	}
Exemple #16
0
ToolKillZone::ToolKillZone(const Misc::ConfigurationFileSection& configFileSection)
	:baseDevice(0),
	 render(true),
	 material(getWidgetMaterial()),
	 modelVersion(1)
	{
	/* Retrieve the name of the base device (if any) from the configuration file: */
	std::string baseDeviceName=configFileSection.retrieveString("./killZoneBaseDevice","");
	if(baseDeviceName!="")
		{
		/* Attach the kill zone to the base device: */
		baseDevice=getInputDeviceManager()->findInputDevice(baseDeviceName.c_str());
		if(baseDevice==0)
			Misc::throwStdErr("ToolKillZone: Unknown base input device \"%s\"",baseDeviceName.c_str());
		}
	
	/* Retrieve the render flag: */
	render=configFileSection.retrieveValue<bool>("./killZoneRender",render);
	
	/* Retrieve the model material: */
	material=configFileSection.retrieveValue<GLMaterial>("./killZoneMaterial",material);
	}
Exemple #17
0
InputDeviceAdapterPlayback::InputDeviceAdapterPlayback(InputDeviceManager* sInputDeviceManager,const Misc::ConfigurationFileSection& configFileSection)
	:InputDeviceAdapter(sInputDeviceManager),
	 inputDeviceDataFile(configFileSection.retrieveString("./inputDeviceDataFileName").c_str(),"rb",Misc::File::LittleEndian),
	 mouseCursorFaker(0),
	 synchronizePlayback(configFileSection.retrieveValue<bool>("./synchronizePlayback",false)),
	 quitWhenDone(configFileSection.retrieveValue<bool>("./quitWhenDone",false)),
	 soundPlayer(0),
	 saveMovie(configFileSection.retrieveValue<bool>("./saveMovie",false)),
	 movieWindowIndex(0),movieWindow(0),
	 firstFrame(true),timeStamp(0.0),
	 done(false)
	{
	/* Read file header: */
	static const char* fileHeader="Vrui Input Device Data File v2.0\n";
	char header[34];
	inputDeviceDataFile.read<char>(header,34);
	bool haveFeatureNames=strncmp(header,fileHeader,34)==0;
	if(!haveFeatureNames)
		{
		/* Old file format doesn't have the header text: */
		inputDeviceDataFile.rewind();
		}
	
	/* Read random seed value: */
	unsigned int randomSeed=inputDeviceDataFile.read<unsigned int>();
	setRandomSeed(randomSeed);
	
	/* Read number of saved input devices: */
	numInputDevices=inputDeviceDataFile.read<int>();
	inputDevices=new InputDevice*[numInputDevices];
	deviceFeatureBaseIndices=new int[numInputDevices];
	
	/* Initialize devices: */
	for(int i=0;i<numInputDevices;++i)
		{
		/* Read device's name and layout from file: */
		std::string name=Misc::readCppString(inputDeviceDataFile);
		int trackType=inputDeviceDataFile.read<int>();
		int numButtons=inputDeviceDataFile.read<int>();
		int numValuators=inputDeviceDataFile.read<int>();
		Vector deviceRayDirection;
		inputDeviceDataFile.read<Scalar>(deviceRayDirection.getComponents(),3);
		
		/* Create new input device: */
		InputDevice* newDevice=inputDeviceManager->createInputDevice(name.c_str(),trackType,numButtons,numValuators,true);
		newDevice->setDeviceRayDirection(deviceRayDirection);
		
		/* Initialize the new device's glyph from the current configuration file section: */
		Glyph& deviceGlyph=inputDeviceManager->getInputGraphManager()->getInputDeviceGlyph(newDevice);
		char deviceGlyphTypeTag[20];
		snprintf(deviceGlyphTypeTag,sizeof(deviceGlyphTypeTag),"./device%dGlyphType",i);
		char deviceGlyphMaterialTag[20];
		snprintf(deviceGlyphMaterialTag,sizeof(deviceGlyphMaterialTag),"./device%dGlyphMaterial",i);
		deviceGlyph.configure(configFileSection,deviceGlyphTypeTag,deviceGlyphMaterialTag);
		
		/* Store the input device: */
		inputDevices[i]=newDevice;
		
		/* Read or create the device's feature names: */
		deviceFeatureBaseIndices[i]=int(deviceFeatureNames.size());
		if(haveFeatureNames)
			{
			/* Read feature names from file: */
			for(int j=0;j<newDevice->getNumFeatures();++j)
				deviceFeatureNames.push_back(Misc::readCppString(inputDeviceDataFile));
			}
		else
			{
			/* Create default feature names: */
			for(int j=0;j<newDevice->getNumFeatures();++j)
				deviceFeatureNames.push_back(getDefaultFeatureName(InputDeviceFeature(newDevice,j)));
			}
		}
	
	/* Check if the user wants to use a fake mouse cursor: */
	int fakeMouseCursorDevice=configFileSection.retrieveValue<int>("./fakeMouseCursorDevice",-1);
	if(fakeMouseCursorDevice>=0)
		{
		/* Read the cursor file name and nominal size: */
		std::string mouseCursorImageFileName=configFileSection.retrieveString("./mouseCursorImageFileName",DEFAULTMOUSECURSORIMAGEFILENAME);
		unsigned int mouseCursorNominalSize=configFileSection.retrieveValue<unsigned int>("./mouseCursorNominalSize",24);
		
		/* Create the mouse cursor faker: */
		mouseCursorFaker=new MouseCursorFaker(inputDevices[fakeMouseCursorDevice],mouseCursorImageFileName.c_str(),mouseCursorNominalSize);
		mouseCursorFaker->setCursorSize(configFileSection.retrieveValue<Size>("./mouseCursorSize",mouseCursorFaker->getCursorSize()));
		mouseCursorFaker->setCursorHotspot(configFileSection.retrieveValue<Vector>("./mouseCursorHotspot",mouseCursorFaker->getCursorHotspot()));
		}
	
	/* Read time stamp of first data frame: */
	try
		{
		nextTimeStamp=inputDeviceDataFile.read<double>();
		
		/* Request an update for the next frame: */
		requestUpdate();
		}
	catch(Misc::File::ReadError)
		{
		done=true;
		nextTimeStamp=Math::Constants<double>::max;
		
		if(quitWhenDone)
			{
			/* Request exiting the program: */
			shutdown();
			}
		}
	
	/* Check if the user wants to play back a commentary sound track: */
	std::string soundFileName=configFileSection.retrieveString("./soundFileName","");
	if(soundFileName!="")
		{
		try
			{
			/* Create a sound player for the given sound file name: */
			soundPlayer=new Sound::SoundPlayer(soundFileName.c_str());
			}
		catch(std::runtime_error error)
			{
			/* Print a message, but carry on: */
			std::cerr<<"InputDeviceAdapterPlayback: Disabling sound playback due to exception "<<error.what()<<std::endl;
			}
		}
	
	/* Check if the user wants to save a movie: */
	if(saveMovie)
		{
		/* Read the movie image file name template: */
		movieFileNameTemplate=configFileSection.retrieveString("./movieFileNameTemplate");
		
		/* Check if the name template has the correct format: */
		int numConversions=0;
		bool hasIntConversion=false;
		for(std::string::const_iterator mfntIt=movieFileNameTemplate.begin();mfntIt!=movieFileNameTemplate.end();++mfntIt)
			{
			if(*mfntIt=='%')
				{
				++mfntIt;
				if(*mfntIt!='%')
					{
					++numConversions;
					
					/* Skip width modifiers: */
					while(isdigit(*mfntIt))
						++mfntIt;
					
					/* Check for integer conversion: */
					if(*mfntIt=='d')
						hasIntConversion=true;
					}
				}
			else if(*mfntIt=='/') // Only accept conversions in the file name part
				hasIntConversion=false;
			}
		if(numConversions!=1||!hasIntConversion)
			Misc::throwStdErr("InputDeviceAdapterPlayback::InputDeviceAdapterPlayback: movie file name template \"%s\" does not have exactly one %%d conversion",movieFileNameTemplate.c_str());
		
		/* Get the index of the window from which to save the frames: */
		movieWindowIndex=configFileSection.retrieveValue<int>("./movieWindowIndex",movieWindowIndex);
		
		/* Get the intended frame rate for the movie: */
		double frameRate=configFileSection.retrieveValue<double>("./movieFrameRate",30.0);
		movieFrameTimeInterval=1.0/frameRate;
		
		/* Calculate the first time at which to save a frame: */
		nextMovieFrameTime=nextTimeStamp+movieFrameTimeInterval*0.5;
		nextMovieFrameCounter=0;
		}
	}
void InputDeviceAdapterHID::createInputDevice(int deviceIndex,const Misc::ConfigurationFileSection& configFileSection)
	{
	/* Read input device name: */
	std::string name=configFileSection.retrieveString("./name");
	
	/* Read HID's vendor / product IDs: */
	std::string deviceVendorProductId=configFileSection.retrieveString("./deviceVendorProductId");
	
	/* Split ID string into vendor ID / product ID: */
	char* colonPtr;
	unsigned int vendorId=strtoul(deviceVendorProductId.c_str(),&colonPtr,16);
	char* endPtr;
	unsigned int productId=strtoul(colonPtr+1,&endPtr,16);
	if(*colonPtr!=':'||*endPtr!='\0')
		Misc::throwStdErr("InputDeviceAdapterHID::InputDeviceAdapterHID: Malformed vendorId:productId string \"%s\" for device %s",deviceVendorProductId.c_str(),name.c_str());
	
	/* Get the device index: */
	int matchingDeviceIndex=configFileSection.retrieveValue<int>("./deviceIndex",0);
	
	/* Create list of all available /dev/input/eventX devices, in numerical order: */
	struct dirent** eventFiles=0;
	int numEventFiles=scandir("/dev/input",&eventFiles,isEventFile,versionsort);
	
	/* Check all event files for the wanted device: */
	int deviceFd=-1;
	for(int eventFileIndex=0;eventFileIndex<numEventFiles;++eventFileIndex)
		{
		/* Open the event file: */
		char eventFileName[256];
		snprintf(eventFileName,sizeof(eventFileName),"/dev/input/%s",eventFiles[eventFileIndex]->d_name);
		int eventFd=open(eventFileName,O_RDONLY);
		if(eventFd>=0)
			{
			/* Get device information: */
			input_id deviceInformation;
			if(ioctl(eventFd,EVIOCGID,&deviceInformation)>=0)
				{
				if(deviceInformation.vendor==vendorId&&deviceInformation.product==productId)
					{
					/* We have a match: */
					if(matchingDeviceIndex==0)
						{
						/* We have a winner! */
						deviceFd=eventFd;
						break;
						}
					
					/* Try again on the next matching device: */
					--matchingDeviceIndex;
					}
				}
			
			/* This is not the device you are looking for, go to the next: */
			close(eventFd);
			}
		}
	
	/* Destroy list of event files: */
	for(int i=0;i<numEventFiles;++i)
		free(eventFiles[i]);
	free(eventFiles);
	
	/* Check if a matching device was found: */
	if(deviceFd<0)
		Misc::throwStdErr("InputDeviceAdapterHID::InputDeviceAdapterHID: No match for vendorId:productId \"%s\" for device %s",deviceVendorProductId.c_str(),name.c_str());
	
	/* Create a new device structure: */
	Device newDevice;
	newDevice.deviceFd=deviceFd;
	
	/* Query all feature types of the device: */
	unsigned char featureTypeBits[EV_MAX/8+1];
	memset(featureTypeBits,0,EV_MAX/8+1);
	if(ioctl(deviceFd,EVIOCGBIT(0,sizeof(featureTypeBits)),featureTypeBits)<0)
		Misc::throwStdErr("InputDeviceAdapterHID::InputDeviceAdapterHID: Unable to query device feature types for device %s",name.c_str());
	
	/* Count the number of keys: */
	newDevice.numButtons=0;
	
	/* Query the number of keys/buttons on the device: */
	if(featureTypeBits[EV_KEY/8]&(1<<(EV_KEY%8)))
		{
		/* Query key features: */
		unsigned char keyBits[KEY_MAX/8+1];
		memset(keyBits,0,KEY_MAX/8+1);
		if(ioctl(deviceFd,EVIOCGBIT(EV_KEY,sizeof(keyBits)),keyBits)<0)
			Misc::throwStdErr("InputDeviceAdapterHID::InputDeviceAdapterHID: Unable to query keys for device %s",name.c_str());
		
		/* Initialize the key translation array: */
		newDevice.keyMap.reserve(KEY_MAX+1);
		for(int i=0;i<=KEY_MAX;++i)
			{
			if(keyBits[i/8]&(1<<(i%8)))
				{
				newDevice.keyMap.push_back(newDevice.numButtons);
				++newDevice.numButtons;
				}
			else
				newDevice.keyMap.push_back(-1);
			}
		}
	
	/* Count the number of absolute and relative axes: */
	newDevice.numValuators=0;
	
	/* Query the number of absolute axes on the device: */
	if(featureTypeBits[EV_ABS/8]&(1<<(EV_ABS%8)))
		{
		/* Query absolute axis features: */
		unsigned char absAxisBits[ABS_MAX/8+1];
		memset(absAxisBits,0,ABS_MAX/8+1);
		if(ioctl(deviceFd,EVIOCGBIT(EV_ABS,sizeof(absAxisBits)),absAxisBits)<0)
			Misc::throwStdErr("InputDeviceAdapterHID::InputDeviceAdapterHID: Unable to query absolute axes for device %s",name.c_str());
		
		/* Initialize the axis translation array: */
		newDevice.absAxisMap.reserve(ABS_MAX+1);
		for(int i=0;i<=ABS_MAX;++i)
			{
			if(absAxisBits[i/8]&(1<<(i%8)))
				{
				/* Enter the next valuator index into the axis map: */
				newDevice.absAxisMap.push_back(newDevice.numValuators);
				
				/* Query the configuration of this axis: */
				input_absinfo absAxisConf;
				if(ioctl(deviceFd,EVIOCGABS(i),&absAxisConf)<0)
					Misc::throwStdErr("InputDeviceAdapterHID::InputDeviceAdapterHID: Unable to query absolute axis configuration for device %s",name.c_str());
				
				/* Create an absolute axis value mapper: */
				Device::AxisValueMapper avm;
				avm.min=double(absAxisConf.minimum);
				double mid=Math::mid(double(absAxisConf.minimum),double(absAxisConf.maximum));
				avm.deadMin=mid-double(absAxisConf.flat);
				avm.deadMax=mid+double(absAxisConf.flat);
				avm.max=double(absAxisConf.maximum);
				
				/* Override axis value mapper from configuration file: */
				char axisSettingsTag[20];
				snprintf(axisSettingsTag,sizeof(axisSettingsTag),"axis%dSettings",newDevice.numValuators);
				avm=configFileSection.retrieveValue<Device::AxisValueMapper>(axisSettingsTag,avm);
				
				/* Store the axis value mapper: */
				newDevice.axisValueMappers.push_back(avm);
				
				++newDevice.numValuators;
				}
			else
				newDevice.absAxisMap.push_back(-1);
			}
		}
	
	/* Query the number of relative axes on the device: */
	if(featureTypeBits[EV_REL/8]&(1<<(EV_REL%8)))
		{
		/* Query relative axis features: */
		unsigned char relAxisBits[REL_MAX/8+1];
		memset(relAxisBits,0,REL_MAX/8+1);
		if(ioctl(deviceFd,EVIOCGBIT(EV_REL,sizeof(relAxisBits)),relAxisBits)<0)
			Misc::throwStdErr("InputDeviceAdapterHID::InputDeviceAdapterHID: Unable to query relative axes for device %s",name.c_str());
		
		/* Initialize the axis translation array: */
		newDevice.relAxisMap.reserve(REL_MAX+1);
		for(int i=0;i<=REL_MAX;++i)
			{
			if(relAxisBits[i/8]&(1<<(i%8)))
				{
				/* Enter the next valuator index into the axis map: */
				newDevice.relAxisMap.push_back(newDevice.numValuators);
				
				/* Create a relative axis value mapper: */
				Device::AxisValueMapper avm;
				avm.min=-1.0;
				avm.deadMin=0.0;
				avm.deadMax=0.0;
				avm.max=1.0;
				
				/* Override axis value mapper from configuration file: */
				char axisSettingsTag[20];
				snprintf(axisSettingsTag,sizeof(axisSettingsTag),"axis%dSettings",newDevice.numValuators);
				avm=configFileSection.retrieveValue<Device::AxisValueMapper>(axisSettingsTag,avm);
				
				/* Store the axis value mapper: */
				newDevice.axisValueMappers.push_back(avm);
				
				++newDevice.numValuators;
				}
			else
				newDevice.relAxisMap.push_back(-1);
			}
		}
	
	/* Create new input device as a physical device: */
	newDevice.device=inputDeviceManager->createInputDevice(name.c_str(),InputDevice::TRACK_NONE,newDevice.numButtons,newDevice.numValuators,true);
	
	/* Store the new device structure: */
	devices.push_back(newDevice);
	}
SoundContext::SoundContext(const Misc::ConfigurationFileSection& configFileSection,VruiState* sVruiState)
	:vruiState(sVruiState),
	 #if ALSUPPORT_CONFIG_HAVE_OPENAL
	 alDevice(0),alContext(0),
	 #endif
	 contextData(0),
	 listener(findListener(configFileSection.retrieveString("./listenerName").c_str())),
	 speedOfSound(float(getMeterFactor())*343.0f),
	 dopplerFactor(1.0f),
	 distanceAttenuationModel(CONSTANT)
	{
	/* Set sound context parameters from configuration file: */
	speedOfSound=configFileSection.retrieveValue<float>("./speedOfSound",speedOfSound);
	dopplerFactor=configFileSection.retrieveValue<float>("./dopplerFactor",dopplerFactor);
	distanceAttenuationModel=configFileSection.retrieveValue<DistanceAttenuationModel>("./distanceAttenuationModel",distanceAttenuationModel);
	
	#if ALSUPPORT_CONFIG_HAVE_OPENAL
	/* Open the OpenAL device: */
	std::string alDeviceName=configFileSection.retrieveValue<std::string>("./deviceName","Default");
	alDevice=alcOpenDevice(alDeviceName!="Default"?alDeviceName.c_str():0);
	if(alDevice==0)
		Misc::throwStdErr("SoundContext::SoundContext: Could not open OpenAL sound device \"%s\"",alDeviceName.c_str());
	
	/* Create a list of context attributes: */
	ALCint alContextAttributes[9];
	ALCint* attPtr=alContextAttributes;
	if(configFileSection.hasTag("./mixerFrequency"))
		{
		*(attPtr++)=ALC_FREQUENCY;
		*(attPtr++)=configFileSection.retrieveValue<ALCint>("./mixerFrequency");
		}
	if(configFileSection.hasTag("./refreshFrequency"))
		{
		*(attPtr++)=ALC_REFRESH;
		*(attPtr++)=configFileSection.retrieveValue<ALCint>("./refreshFrequency");
		}
	if(configFileSection.hasTag("./numMonoSources"))
		{
		*(attPtr++)=ALC_MONO_SOURCES;
		*(attPtr++)=configFileSection.retrieveValue<ALCint>("./numMonoSources");
		}
	if(configFileSection.hasTag("./numStereoSources"))
		{
		*(attPtr++)=ALC_STEREO_SOURCES;
		*(attPtr++)=configFileSection.retrieveValue<ALCint>("./numStereoSources");
		}
	*(attPtr++)=ALC_INVALID;
	
	/* Create an OpenAL context: */
	alContext=alcCreateContext(alDevice,alContextAttributes);
	if(alContext==0)
		{
		alcCloseDevice(alDevice);
		Misc::throwStdErr("SoundContext::SoundContext: Could not create OpenAL context for sound device %s",alDeviceName.c_str());
		}
	#endif
	
	/* Create an AL context data object: */
	contextData=new ALContextData(101);
	
	/* Initialize the sound context's OpenAL context: */
	makeCurrent();
	
	#if ALSUPPORT_CONFIG_HAVE_OPENAL
	/* Set global OpenAL parameters: */
	alSpeedOfSound(speedOfSound);
	alDopplerFactor(dopplerFactor);
	switch(distanceAttenuationModel)
		{
		case CONSTANT:
			alDistanceModel(AL_NONE);
			break;
		
		case INVERSE:
			alDistanceModel(AL_INVERSE_DISTANCE);
			break;
		
		case INVERSE_CLAMPED:
			alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
			break;
		
		case LINEAR:
			alDistanceModel(AL_LINEAR_DISTANCE);
			break;
		
		case LINEAR_CLAMPED:
			alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
			break;
		
		case EXPONENTIAL:
			alDistanceModel(AL_EXPONENT_DISTANCE);
			break;
		
		case EXPONENTIAL_CLAMPED:
			alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
			break;
		}
	#endif
	}
void VRScreen::initialize(const Misc::ConfigurationFileSection& configFileSection)
	{
	/* Read the screen's name: */
	std::string name=configFileSection.retrieveString("./name");
	screenName=new char[name.size()+1];
	strcpy(screenName,name.c_str());
	
	/* Determine whether screen is device-mounted: */
	deviceMounted=configFileSection.retrieveValue<bool>("./deviceMounted",false);
	if(deviceMounted)
		{
		/* Retrieve the input device this screen is attached to: */
		std::string deviceName=configFileSection.retrieveString("./deviceName");
		device=findInputDevice(deviceName.c_str());
		if(device==0)
			Misc::throwStdErr("VRScreen: Mounting device \"%s\" not found",deviceName.c_str());
		}
	
	/* Retrieve screen position/orientation in physical or device coordinates: */
	try
		{
		/* Try reading the screen transformation directly: */
		transform=configFileSection.retrieveValue<ONTransform>("./transform");
		}
	catch(std::runtime_error)
		{
		/* Fall back to reading the screen's origin and axis directions: */
		Point origin=configFileSection.retrieveValue<Point>("./origin");
		Vector horizontalAxis=configFileSection.retrieveValue<Vector>("./horizontalAxis");
		Vector verticalAxis=configFileSection.retrieveValue<Vector>("./verticalAxis");
		ONTransform::Rotation rot=ONTransform::Rotation::fromBaseVectors(horizontalAxis,verticalAxis);
		transform=ONTransform(origin-Point::origin,rot);
		}
	
	/* Read the screen's size: */
	screenSize[0]=configFileSection.retrieveValue<Scalar>("./width");
	screenSize[1]=configFileSection.retrieveValue<Scalar>("./height");
	
	/* Apply a rotation around a single axis: */
	Point rotateCenter=configFileSection.retrieveValue<Point>("./rotateCenter",Point::origin);
	Vector rotateAxis=configFileSection.retrieveValue<Vector>("./rotateAxis",Vector(1,0,0));
	Scalar rotateAngle=configFileSection.retrieveValue<Scalar>("./rotateAngle",Scalar(0));
	if(rotateAngle!=Scalar(0))
		{
		ONTransform screenRotation=ONTransform::translateFromOriginTo(rotateCenter);
		screenRotation*=ONTransform::rotate(ONTransform::Rotation::rotateAxis(rotateAxis,Math::rad(rotateAngle)));
		screenRotation*=ONTransform::translateToOriginFrom(rotateCenter);
		transform.leftMultiply(screenRotation);
		}
	
	/* Apply an arbitrary pre-transformation: */
	ONTransform preTransform=configFileSection.retrieveValue<ONTransform>("./preTransform",ONTransform::identity);
	transform.leftMultiply(preTransform);
	
	/* Finalize the screen transformation: */
	transform.renormalize();
	inverseTransform=Geometry::invert(transform);
	
	/* Check if the screen is projected off-axis: */
	offAxis=configFileSection.retrieveValue<bool>("./offAxis",offAxis);
	if(offAxis)
		{
		/* Create the inverse of the 2D homography from clip space to rectified screen space in screen coordinates: */
		PTransform2 sHomInv=PTransform2::identity;
		sHomInv.getMatrix()(0,0)=Scalar(2)/screenSize[0];
		sHomInv.getMatrix()(0,2)=Scalar(-1);
		sHomInv.getMatrix()(1,1)=Scalar(2)/screenSize[1];
		sHomInv.getMatrix()(1,2)=Scalar(-1);
		sHomInv.getMatrix()(2,2)=Scalar(1);
		
		/* Retrieve the 2D homography from clip space to projected screen space in screen coordinates: */
		PTransform2 pHom=configFileSection.retrieveValue<PTransform2>("./homography");
		
		/* Calculate the screen space homography: */
		screenHomography=pHom*sHomInv;
		
		/* Calculate the clip space homography: */
		PTransform2 hom=sHomInv*pHom;
		for(int i=0;i<3;++i)
			for(int j=0;j<3;++j)
				inverseClipHomography.getMatrix()(i<2?i:3,j<2?j:3)=hom.getMatrix()(i,j);
		
		/* Put in correction factors to keep the frustum's far plane in the same position: */
		inverseClipHomography.getMatrix()(2,0)=inverseClipHomography.getMatrix()(3,0);
		inverseClipHomography.getMatrix()(2,1)=inverseClipHomography.getMatrix()(3,1);
		
		inverseClipHomography.doInvert();
		}
	}
void InputDeviceAdapterDeviceDaemon::createInputDevice(int deviceIndex,const Misc::ConfigurationFileSection& configFileSection)
	{
	/* Check if the device client has a virtual device of the same name as this configuration file section: */
	for(int vdIndex=0;vdIndex<deviceClient.getNumVirtualDevices();++vdIndex)
		{
		const VRDeviceDescriptor& vd=deviceClient.getVirtualDevice(vdIndex);
		if(vd.name==configFileSection.getName())
			{
			/* Ensure that the index mapping tables exist: */
			createIndexMappings();
			
			/* Create an input device from the virtual input device descriptor: */
			int trackType=InputDevice::TRACK_NONE;
			if(vd.trackType&VRDeviceDescriptor::TRACK_POS)
				trackType|=InputDevice::TRACK_POS;
			if(vd.trackType&VRDeviceDescriptor::TRACK_DIR)
				trackType|=InputDevice::TRACK_DIR;
			if(vd.trackType&VRDeviceDescriptor::TRACK_ORIENT)
				trackType|=InputDevice::TRACK_ORIENT;
			
			/* Create new input device as a physical device: */
			std::string deviceName=configFileSection.retrieveString("./name",vd.name);
			InputDevice* newDevice=inputDeviceManager->createInputDevice(deviceName.c_str(),trackType,vd.numButtons,vd.numValuators,true);
			newDevice->setDeviceRay(vd.rayDirection,vd.rayStart);
	
			/* Initialize the new device's glyph from the current configuration file section: */
			Glyph& deviceGlyph=inputDeviceManager->getInputGraphManager()->getInputDeviceGlyph(newDevice);
			deviceGlyph.configure(configFileSection,"./deviceGlyphType","./deviceGlyphMaterial");
			
			/* Save the new input device: */
			inputDevices[deviceIndex]=newDevice;
			
			/* Assign the new device's tracker index: */
			trackerIndexMapping[deviceIndex]=vd.trackerIndex;
			
			/* Assign the new device's button indices: */
			if(vd.numButtons>0)
				{
				buttonIndexMapping[deviceIndex]=new int[vd.numButtons];
				for(int i=0;i<vd.numButtons;++i)
					buttonIndexMapping[deviceIndex][i]=vd.buttonIndices[i];
				}
			else
				buttonIndexMapping[deviceIndex]=0;
			
			/* Store the virtual input device's button names: */
			for(int i=0;i<vd.numButtons;++i)
				buttonNames.push_back(vd.buttonNames[i]);
			
			/* Assign the new device's valuator indices: */
			if(vd.numValuators>0)
				{
				valuatorIndexMapping[deviceIndex]=new int[vd.numValuators];
				for(int i=0;i<vd.numValuators;++i)
					valuatorIndexMapping[deviceIndex][i]=vd.valuatorIndices[i];
				}
			else
				valuatorIndexMapping[deviceIndex]=0;
			
			/* Store the virtual input device's valuator names: */
			for(int i=0;i<vd.numValuators;++i)
				valuatorNames.push_back(vd.valuatorNames[i]);
			
			/* Skip the usual device creation procedure: */
			return;
			}
		}
	
	/* Call base class method to initialize the input device: */
	InputDeviceAdapterIndexMap::createInputDevice(deviceIndex,configFileSection);
	
	/* Read the list of button names for this device: */
	/* Read the names of all button features: */
	typedef std::vector<std::string> StringList;
	StringList tempButtonNames=configFileSection.retrieveValue<StringList>("./buttonNames",StringList());
	int buttonIndex=0;
	for(StringList::iterator bnIt=tempButtonNames.begin();bnIt!=tempButtonNames.end()&&buttonIndex<inputDevices[deviceIndex]->getNumButtons();++bnIt,++buttonIndex)
		{
		/* Store the button name: */
		buttonNames.push_back(*bnIt);
		}
	for(;buttonIndex<inputDevices[deviceIndex]->getNumButtons();++buttonIndex)
		{
		char buttonName[40];
		snprintf(buttonName,sizeof(buttonName),"Button%d",buttonIndex);
		buttonNames.push_back(buttonName);
		}
	
	/* Read the names of all valuator features: */
	StringList tempValuatorNames=configFileSection.retrieveValue<StringList>("./valuatorNames",StringList());
	int valuatorIndex=0;
	for(StringList::iterator vnIt=tempValuatorNames.begin();vnIt!=tempValuatorNames.end()&&valuatorIndex<inputDevices[deviceIndex]->getNumValuators();++vnIt,++valuatorIndex)
		{
		/* Store the valuator name: */
		valuatorNames.push_back(*vnIt);
		}
	for(;valuatorIndex<inputDevices[deviceIndex]->getNumValuators();++valuatorIndex)
		{
		char valuatorName[40];
		snprintf(valuatorName,sizeof(valuatorName),"Valuator%d",valuatorIndex);
		valuatorNames.push_back(valuatorName);
		}
	}
Exemple #22
0
void VideoDevice::configure(const Misc::ConfigurationFileSection& cfg)
	{
	/* Check which components of the video format are stored in the configuration file section: */
	unsigned int frameSize[2]={0,0};
	bool haveFrameSize=false;
	if(cfg.hasTag("./width")&&cfg.hasTag("./height"))
		{
		/* Read the requested frame size as width and height: */
		frameSize[0]=cfg.retrieveValue<unsigned int>("./width");
		frameSize[1]=cfg.retrieveValue<unsigned int>("./height");
		
		haveFrameSize=true;
		}
	if(cfg.hasTag("./frameSize"))
		{
		/* Read the requested frame size as a two-element array: */
		Misc::CFixedArrayValueCoder<unsigned int,2> valueCoder(frameSize);
		cfg.retrieveValueWC<unsigned int*>("./frameSize",valueCoder);
		
		haveFrameSize=true;
		}
	
	double frameRate=0.0;
	bool haveFrameRate=false;
	if(cfg.hasTag("./frameRate"))
		{
		/* Read the requested frame rate as a double: */
		frameRate=cfg.retrieveValue<double>("./frameRate");
		
		haveFrameRate=true;
		}
	
	unsigned int pixelFormat=0;
	bool havePixelFormat=false;
	if(cfg.hasTag("./pixelFormat"))
		{
		/* Read a pixel format as a FourCC code: */
		std::string fourCC=cfg.retrieveValue<std::string>("./pixelFormat");
		if(fourCC.size()!=4)
			Misc::throwStdErr("Video::VideoDevice::configure: Invalid pixel format code \"%s\"",fourCC.c_str());
		
		/* Convert the FourCC code to a pixel format: */
		VideoDataFormat temp;
		temp.setPixelFormat(fourCC.c_str());
		pixelFormat=temp.pixelFormat;
		
		havePixelFormat=true;
		}
	if(cfg.hasTag("./pixelFormatHex"))
		{
		/* Read a pixel format as a hexadecimal number: */
		std::string hex=cfg.retrieveString("./pixelFormatHex");
		if(hex.size()!=8)
			Misc::throwStdErr("Video::VideoDevice::configure: Invalid hexadecimal pixel format code \"%s\"",hex.c_str());
		for(int i=0;i<8;++i)
			{
			if(hex[i]>='0'&&hex[i]<='9')
				pixelFormat=(pixelFormat<<4)|(hex[i]-'0');
			else if(hex[i]>='A'&&hex[i]<='F')
				pixelFormat=(pixelFormat<<4)|(hex[i]-'A'+10);
			else if(hex[i]>='a'&&hex[i]<='f')
				pixelFormat=(pixelFormat<<4)|(hex[i]-'a'+10);
			else
				Misc::throwStdErr("Video::VideoDevice::configure: Invalid hexadecimal pixel format code \"%s\"",hex.c_str());
			}
		
		havePixelFormat=true;
		}
	
	/* Get the list of the device's supported video formats: */
	std::vector<VideoDataFormat> deviceFormats=getVideoFormatList();
	
	/* Find the best-matching video format among the device's advertised formats: */
	std::vector<VideoDataFormat>::iterator bestFormat=deviceFormats.end();
	double bestMatch=0.0;
	for(std::vector<VideoDataFormat>::iterator dfIt=deviceFormats.begin();dfIt!=deviceFormats.end();++dfIt)
		{
		double match=1.0;
		if(haveFrameSize)
			for(int i=0;i<2;++i)
				match*=dfIt->size[i]>=frameSize[i]?double(frameSize[i])/double(dfIt->size[i]):double(dfIt->size[i])/double(frameSize[i]);
		if(haveFrameRate)
			{
			double dfRate=double(dfIt->frameIntervalDenominator)/double(dfIt->frameIntervalCounter);
			match*=dfRate>=frameRate?frameRate/dfRate:dfRate/frameRate;
			}
		if(havePixelFormat&&dfIt->pixelFormat!=pixelFormat)
			match*=0.75;
		
		if(bestMatch<match)
			{
			bestFormat=dfIt;
			bestMatch=match;
			}
		}
	if(bestFormat==deviceFormats.end()) // Can only happen if there are no device formats
		throw std::runtime_error("Video::VideoDevice::configure: No matching video formats found");
	
	/* Set the selected video format: */
	setVideoFormat(*bestFormat);
	}