Beispiel #1
0
//-----------------------------------------------------------------------------
// Render the number from the given item into a string.
static char* PrintNumber(double d)
{
    char *str;
    //double d=item->valuedouble;
    int valueint = (int)d;
    if (fabs(((double)valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
    {
        str=(char*)OVR_ALLOC(21);   // 2^64+1 can be represented in 21 chars.
        if (str)
            OVR_sprintf(str, 21, "%d", valueint);
    }
    else
    {
        str=(char*)OVR_ALLOC(64);   // This is a nice tradeoff.
        if (str)
        {
            if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)
                OVR_sprintf(str, 64, "%.0f", d);
            else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)
                OVR_sprintf(str, 64, "%e", d);
            else
                OVR_sprintf(str, 64, "%f", d);
        }
    }
    return str;
}
Beispiel #2
0
//-----------------------------------------------------------------------------
// Render the number from the given item into a string.
static char* PrintNumber(double d)
{
    char *str;
    int valueint = (int)d;

    if ((fabs(((double)valueint)-d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN))
    {
        return PrintInt(valueint);
    }
    else
    {
        const size_t kCapacity = 64;

        str=(char*)OVR_ALLOC(kCapacity);    // This is a nice tradeoff.
        if (str)
        {
            // The JSON Standard, section 7.8.3, specifies that decimals are always expressed with '.' and 
            // not some locale-specific decimal such as ',' or ' '. However, since we are using the C standard
            // library below to write a floating point number, we need to make sure that it's writing a '.' 
            // and not something else. We can't change the locale (even temporarily) here, as it will affect 
            // the whole process by default. That are compiler-specific ways to change this per-thread, but 
            // below we implement the simple solution of simply fixing the decimal after the string was written.

            if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60))
            {
                // Write integral values with no decimals
                OVR_sprintf(str, kCapacity, "%.0f", d);
            }
            else if ((fabs(d) < 1.0) || (fabs(d) > 1.0e9))
            {
                // Write numbers < 1 or larger than 1e9 with 7 significant digits
                OVR_sprintf(str, kCapacity, "%.7g", d);
            }
            else
            {
                // Write numbers >= 1 and <= 1e9 with 6 decimals (7 to 15 sig digits)
                OVR_sprintf(str, kCapacity, "%.6f", d);
            }

            // Convert any found ',' or ''' char to '.'. This will happen only if the locale was set to write a ',' 
            // instead of a '.' for the decimal point. Decimal points are represented only by one of these
            // three characters in practice.
            for(char* p = str; *p; p++)
            {
                if((*p == ',') || (*p == '\''))
                {
                    *p = '.';
                    break;
                }
            }
        }
    }
    return str;
}
Beispiel #3
0
void MakePath( const char * dirPath, mode_t mode )
{
	char path[ 256 ];
	char * currentChar = NULL;

	OVR_sprintf( path, sizeof( path ), "%s", dirPath );
	
	for ( currentChar = path + 1; *currentChar; ++currentChar )
	{
		if ( *currentChar == '/' ) 
		{
			*currentChar = 0;
			DIR * checkDir = opendir( path );
			if ( checkDir == NULL )
			{
				mkdir( path, mode );
			}
			else
			{
				closedir( checkDir );
			}
			*currentChar = '/';
		}
	}
}
void FormatLatencyReading(char* buff, UPInt size, float val)
{    
    if (val < 0.000001f)
        OVR_strcpy(buff, size, "N/A   ");
    else
        OVR_sprintf(buff, size, "%4.2fms", val * 1000.0f);    
}
static String FormatMaxFromSideTan(OptionVar* var)
{
    char   buff[64];
    float  degrees = 2.0f * atan(*var->AsFloat()) * (180.0f / Math<float>::Pi);
    OVR_sprintf(buff, sizeof(buff), "%.1f Degrees", degrees);
    return String(buff);
}
Beispiel #6
0
bool SearchPaths::ToRelativePath( char const * fullPath, char * outPath, const int outMaxLen ) const
{
	// check if the path starts with any of the search paths
	const int n = Paths.GetSizeI();
	for ( int i = 0; i < n; ++i )
	{
		char const * path = Paths[i].ToCStr();
		if ( strstr( fullPath, path ) == fullPath )
		{
			size_t len = OVR_strlen( path );
			OVR_sprintf( outPath, outMaxLen, "%s", fullPath + len );
			return true;
		}
	}
	OVR_sprintf( outPath, outMaxLen, "%s", fullPath );
	return false;
}
Beispiel #7
0
CFStringRef HIDDevice::generateRunLoopModeString(IOHIDDeviceRef device)
{
    const UInt32 safeBuffSize = 256;
    char nameBuff[safeBuffSize];
    OVR_sprintf(nameBuff, safeBuffSize, "%016lX", device);
  
    return CFStringCreateWithCString(NULL, nameBuff, kCFStringEncodingASCII);
}
//-----------------------------------------------------------------------------
// Render the string provided to an escaped version that can be printed.
char* PrintString(const char* str)
{
	const char *ptr;
    char *ptr2,*out;
    int len=0;
    unsigned char token;
	
	if (!str)
        return JSON_strdup("");
	ptr=str;
    
    token=*ptr;
    while (token && ++len)\
    {
        if (strchr("\"\\\b\f\n\r\t",token))
            len++;
        else if (token<32) 
            len+=5;
        ptr++;
        token=*ptr;
    }
	
	int buff_size = len+3;
    out=(char*)OVR_ALLOC(buff_size);
	if (!out)
        return 0;

	ptr2 = out;
    ptr  = str;
	*ptr2++ = '\"';

	while (*ptr)
	{
		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') 
            *ptr2++=*ptr++;
		else
		{
			*ptr2++='\\';
			switch (token=*ptr++)
			{
				case '\\':	*ptr2++='\\';	break;
				case '\"':	*ptr2++='\"';	break;
				case '\b':	*ptr2++='b';	break;
				case '\f':	*ptr2++='f';	break;
				case '\n':	*ptr2++='n';	break;
				case '\r':	*ptr2++='r';	break;
				case '\t':	*ptr2++='t';	break;
				default: 
                    OVR_sprintf(ptr2, buff_size - (ptr2-out), "u%04x",token);
                    ptr2+=5;
                    break;	// Escape and print.
			}
		}
	}
	*ptr2++='\"';
    *ptr2++=0;
	return out;
}
// Custom formatter for Timewarp interval message.
static String FormatTimewarp(OptionVar* var)
{    
    char    buff[64];
    float   timewarpInterval = *var->AsFloat();
    OVR_sprintf(buff, sizeof(buff), "%.1fms, %.1ffps",
                timewarpInterval * 1000.0f,
                ( timewarpInterval > 0.000001f ) ? 1.0f / timewarpInterval : 10000.0f);
    return String(buff);
}
//-----------------------------------------------------------------------------
// Render the number from the given item into a string.
static char* PrintInt(int valueint)
{
    char *str;
    str = (char*)OVR_ALLOC(21);	// 2^64+1 can be represented in 21 chars.
    if (str)
    {
        OVR_sprintf(str, 21, "%d", valueint);
    }
    return str;
}
String GetImage( eScrollBarImage const type, const bool vertical )
{
	static char const * images[ SCROLLBAR_IMAGE_MAX ] =
	{
		"res/raw/scrollbar_base_%s.png",
		"res/raw/scrollbar_thumb_%s.png",
	};

	char buff[ 256 ];
	OVR_sprintf( buff, sizeof( buff ), images[ type ], vertical ? "vert" : "horz" );
	return String( buff );
}
Beispiel #12
0
static void AddRelativePathToHost( ovrUriScheme_File * scheme, char const * hostName, char const * baseDir, char const * relativePath )
{
	char rebasedPath[MAX_PATH];
	OVR_sprintf( rebasedPath, sizeof( rebasedPath ), "%s/%s", baseDir, relativePath );

	// collapse the path -- fopen() was not working with relative paths, though it should?
	char rebasedPathCanonical[MAX_PATH];
	ovrPathUtils::CollapsePath( rebasedPath, rebasedPathCanonical, sizeof( rebasedPathCanonical ) );

	char uri[ovrFileSysLocal::OVR_MAX_PATH_LEN];
	OVR_sprintf( uri, sizeof( uri ), "file:///%s", rebasedPathCanonical );	

	if ( !scheme->HostExists( hostName ) )
	{
		scheme->OpenHost( hostName, uri );
	}
	else
	{
		scheme->AddHostSourceUri( hostName, uri);	
	}
}
Beispiel #13
0
bool SearchPaths::GetFullPath( char const * relativePath, char * outPath, const int outMaxLen ) const
{
	OVR_ASSERT( outPath != NULL && outMaxLen >= 1 );

	if ( FileExists( relativePath ) )
	{
		OVR_sprintf( outPath, OVR_strlen( relativePath ) + 1, "%s", relativePath );
		return true;
	}

	for ( int i = 0; i < Paths.GetSizeI(); ++i )
	{
		OVR_sprintf( outPath, outMaxLen, "%s%s", Paths[i].ToCStr(), relativePath );
		if ( FileExists( outPath ) )
		{
			return true;	// outpath is now set to the full path
		}
	}
	// just return the relative path if we never found the file
	OVR_sprintf( outPath, outMaxLen, "%s", relativePath );
	return false;
}
//-----------------------------------------------------------------------------
// Render the number from the given item into a string.
static char* PrintNumber(double d)
{
    char *str;
    int valueint = (int)d;
	if (fabs(((double)valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
	{
        return PrintInt(valueint);
	}
	else
	{
		str=(char*)OVR_ALLOC(64);	// This is a nice tradeoff.
		if (str)
		{
			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)
                OVR_sprintf(str, 64, "%.0f", d);
			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)
                OVR_sprintf(str, 64, "%e", d);
			else
                OVR_sprintf(str, 64, "%f", d);
		}
	}
	return str;
}
Beispiel #15
0
void ovrSoundLimiter::PlayMenuSound( OvrGuiSys & guiSys, char const * appendKey, char const * soundName, double const limitSeconds )
{
	char overrideSound[ 1024 ];
	OVR_sprintf( overrideSound, 1024, "%s_%s", appendKey, soundName );

	if ( guiSys.GetSoundEffectPlayer().Has( overrideSound ) )
	{
		PlaySoundEffect( guiSys, overrideSound, limitSeconds );
	}
	else
	{
		PlaySoundEffect( guiSys, soundName, limitSeconds );
	}
}
String GetSliderImage( eSliderImage const type, bool vertical )
{
	static char const * images[SLIDER_IMAGE_MAX] =
	{
		"res/raw/slider_base_%s.png",
		"res/raw/slider_track_%s.png",
		"res/raw/slider_track_full_%s.png",
		"res/raw/slider_scrubber.png",
		"res/raw/slider_bubble_%s.png"
	};

	char buff[256];
	OVR_sprintf( buff, sizeof( buff ), images[type], vertical ? "vert" : "horz" );
	return String( buff );
}
Beispiel #17
0
void ovrJobManagerImpl::Init( JavaVM & javaVM )
{
	Jvm = &javaVM;

	// signal must be created before any job threads are created
	NewJobSignal = ovrSignal::Create( true );

	// create all threads... they will end up waiting on a new job signal
	for ( int i = 0; i < MAX_THREADS; ++i )
	{
		char threadName[16];
		OVR_sprintf( threadName, sizeof( threadName ), "ovrJobThread_%i", i );

		ovrJobThread * jt = ovrJobThread::Create( this, i, threadName );
		Threads.PushBack( jt );
	}

	Initialized = true;
}
//==============================
// LogEventType
static inline void LogEventType( VRMenuEvent const & event, char const * fmt, ... )
{
#if defined( OVR_OS_ANDROID )
	if ( event.EventType != VRMENU_EVENT_TOUCH_RELATIVE )
	{
		return;
	}

	char fmtBuff[256];
	va_list args;
	va_start( args, fmt );
	vsnprintf( fmtBuff, sizeof( fmtBuff ), fmt, args );
	va_end( args );

	char buffer[512];
	OVR_sprintf( buffer, sizeof( buffer ), "%s: %s", VRMenuEvent::EventTypeNames[event.EventType], fmtBuff );

	__android_log_write( ANDROID_LOG_WARN, "VrMenu", buffer );
#endif
}
String GetSliderImage( OvrSliderComponent::imageInfo_t const & info, bool vertical )
{
	char buff[256];
	OVR_sprintf( buff, sizeof( buff ), info.ImageName, vertical ? "vert" : "horz" );
	return String( buff );
}
//==============================
// OvrSliderComponent::GetStringValue
void OvrSliderComponent::GetStringValue( char * valueStr, int maxLen ) const
{
	int curValue = (int)floor( ( MaxValue - MinValue ) * SliderFrac + MinValue );
	OVR_sprintf( valueStr, maxLen, "%i", curValue );
}
bool XmlHandler::ReadFile(const char* fileName, OVR::Render::RenderDevice* pRender,
	                      OVR::Render::Scene* pScene,
                          OVR::Array<Ptr<CollisionModel> >* pCollisions,
	                      OVR::Array<Ptr<CollisionModel> >* pGroundCollisions,
                          bool srgbAware /*= false*/,
                          bool anisotropic /*= false*/)
{
    if(pXmlDocument->LoadFile(fileName) != 0)
    {
        return false;
    }

    // Extract the relative path to our working directory for loading textures
    filePath[0] = 0;
    intptr_t pos = 0;
	intptr_t len = strlen(fileName);
    for(intptr_t i = len; i > 0; i--)
    {
        if (fileName[i-1]=='\\' || fileName[i-1]=='/')
        {
            memcpy(filePath, fileName, i);
            filePath[i] = 0;
            break;
        }        
    }    

    // Load the textures
	OVR_DEBUG_LOG_TEXT(("Loading textures..."));
    XMLElement* pXmlTexture = pXmlDocument->FirstChildElement("scene")->FirstChildElement("textures");
    OVR_ASSERT(pXmlTexture);
    if (pXmlTexture)
    {
        pXmlTexture->QueryIntAttribute("count", &textureCount);
        pXmlTexture = pXmlTexture->FirstChildElement("texture");
    }

    for(int i = 0; i < textureCount; ++i)
    {
        const char* textureName = pXmlTexture->Attribute("fileName");
		intptr_t    dotpos = strcspn(textureName, ".");
        char        fname[300];

		if (pos == len)
		{            
			OVR_sprintf(fname, 300, "%s", textureName);
		}
		else
		{
			OVR_sprintf(fname, 300, "%s%s", filePath, textureName);
		}

        int textureLoadFlags = 0;
        textureLoadFlags |= srgbAware ? TextureLoad_SrgbAware : 0;
        textureLoadFlags |= anisotropic ? TextureLoad_Anisotropic : 0;

        SysFile* pFile = new SysFile(fname);
		Ptr<Texture> texture;
		if (textureName[dotpos + 1] == 'd' || textureName[dotpos + 1] == 'D')
		{
			// DDS file
            Texture* tmp_ptr = LoadTextureDDSTopDown(pRender, pFile, textureLoadFlags);
			if(tmp_ptr)
			{
				texture.SetPtr(*tmp_ptr);
			}
		}
		else
		{
            Texture* tmp_ptr = LoadTextureTgaTopDown(pRender, pFile, textureLoadFlags, 255);
			if(tmp_ptr)
			{
				texture.SetPtr(*tmp_ptr);
			}
		}

        Textures.PushBack(texture);
		pFile->Close();
		pFile->Release();
        pXmlTexture = pXmlTexture->NextSiblingElement("texture");
    }
	OVR_DEBUG_LOG_TEXT(("Done.\n"));

    // Load the models
	pXmlDocument->FirstChildElement("scene")->FirstChildElement("models")->
		          QueryIntAttribute("count", &modelCount);
	
		OVR_DEBUG_LOG(("Loading models... %i models to load...", modelCount));
    XMLElement* pXmlModel = pXmlDocument->FirstChildElement("scene")->
		                                  FirstChildElement("models")->FirstChildElement("model");
    for(int i = 0; i < modelCount; ++i)
    {
		if (i % 15 == 0)
		{
			OVR_DEBUG_LOG_TEXT(("%i models remaining...", modelCount - i));
		}
        const char* name = pXmlModel->Attribute("name");
        Models.PushBack(*new Model(Prim_Triangles, name));
        bool isCollisionModel = false;
        pXmlModel->QueryBoolAttribute("isCollisionModel", &isCollisionModel);
        Models[i]->IsCollisionModel = isCollisionModel;
		if (isCollisionModel)
		{
			Models[i]->Visible = false;
		}

        bool tree_c = (strcmp(name, "tree_C") == 0) || (strcmp(name, "Object03") == 0);

        //read the vertices
        OVR::Array<Vector3f> *vertices = new OVR::Array<Vector3f>();
        ParseVectorString(pXmlModel->FirstChildElement("vertices")->FirstChild()->
			              ToText()->Value(), vertices);

		for (unsigned int vertexIndex = 0; vertexIndex < vertices->GetSize(); ++vertexIndex)
		{
			vertices->At(vertexIndex).x *= -1.0f;

            if (tree_c)
            {   // Move the terrace tree closer to the house
                vertices->At(vertexIndex).z += 0.5;
            }
		}

        //read the normals
        OVR::Array<Vector3f> *normals = new OVR::Array<Vector3f>();
        ParseVectorString(pXmlModel->FirstChildElement("normals")->FirstChild()->
			              ToText()->Value(), normals);

		for (unsigned int normalIndex = 0; normalIndex < normals->GetSize(); ++normalIndex)
		{
			normals->At(normalIndex).z *= -1.0f;
		}

        //read the textures
        OVR::Array<Vector3f> *diffuseUVs = new OVR::Array<Vector3f>();
        OVR::Array<Vector3f> *lightmapUVs = new OVR::Array<Vector3f>();
        int         diffuseTextureIndex = -1;
        int         lightmapTextureIndex = -1;
        XMLElement* pXmlCurMaterial = pXmlModel->FirstChildElement("material");

        while(pXmlCurMaterial != NULL)
        {
            if(pXmlCurMaterial->Attribute("name", "diffuse"))
            {
                pXmlCurMaterial->FirstChildElement("texture")->
					             QueryIntAttribute("index", &diffuseTextureIndex);
                if(diffuseTextureIndex > -1)
                {
                    ParseVectorString(pXmlCurMaterial->FirstChildElement("texture")->
						              FirstChild()->ToText()->Value(), diffuseUVs, true);
                }
            }
            else if(pXmlCurMaterial->Attribute("name", "lightmap"))
            {
                pXmlCurMaterial->FirstChildElement("texture")->
					                               QueryIntAttribute("index", &lightmapTextureIndex);
                if(lightmapTextureIndex > -1)
                {
                    XMLElement* firstChildElement = pXmlCurMaterial->FirstChildElement("texture");
                    XMLNode* firstChild = firstChildElement->FirstChild();
                    XMLText* text = firstChild->ToText();
                    const char* value = text->Value();
                    ParseVectorString(value, lightmapUVs, true);
                }
            }

            pXmlCurMaterial = pXmlCurMaterial->NextSiblingElement("material");
        }

        //set up the shader
        Ptr<ShaderFill> shader = *new ShaderFill(*pRender->CreateShaderSet());
        shader->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Vertex, VShader_MVP));
        if(diffuseTextureIndex > -1)
        {
            shader->SetTexture(0, Textures[diffuseTextureIndex]);
            if(lightmapTextureIndex > -1)
            {
                shader->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Fragment, FShader_MultiTexture));
                shader->SetTexture(1, Textures[lightmapTextureIndex]);
            }
            else
            {
                shader->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Fragment, FShader_Texture));
            }
        }
        else
        {
            shader->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Fragment, FShader_LitGouraud));
        }
        Models[i]->Fill = shader;

        //add all the vertices to the model
        const size_t numVerts = vertices->GetSize();
        for(size_t v = 0; v < numVerts; ++v)
        {
            if(diffuseTextureIndex > -1)
            {
                if(lightmapTextureIndex > -1)
                {
                    Models[i]->AddVertex(vertices->At(v).z, vertices->At(v).y, vertices->At(v).x, Color(255, 255, 255),
                                          diffuseUVs->At(v).x, diffuseUVs->At(v).y, lightmapUVs->At(v).x, lightmapUVs->At(v).y,
                                          normals->At(v).x, normals->At(v).y, normals->At(v).z);
                }
                else
                {
                    Models[i]->AddVertex(vertices->At(v).z, vertices->At(v).y, vertices->At(v).x, Color(255, 255, 255),
                                          diffuseUVs->At(v).x, diffuseUVs->At(v).y, 0, 0,
                                          normals->At(v).x, normals->At(v).y, normals->At(v).z);
                }
            }
            else
            {
                Models[i]->AddVertex(vertices->At(v).z, vertices->At(v).y, vertices->At(v).x, Color(255, 255, 255, 255),
                                      0, 0, 0, 0,
                                      normals->At(v).x, normals->At(v).y, normals->At(v).z);
            }
        }

        // Read the vertex indices for the triangles
        const char* indexStr = pXmlModel->FirstChildElement("indices")->
                                          FirstChild()->ToText()->Value();
        
        size_t stringLength = strlen(indexStr);

        for(size_t j = 0; j < stringLength; )
        {
            size_t k = j + 1;
            for(; k < stringLength; ++k)
            {
                if (indexStr[k] == ' ')
                    break;                
            }
            char text[20];
            for(size_t l = 0; l < k - j; ++l)
            {
                text[l] = indexStr[j + l];
            }
            text[k - j] = '\0';

            Models[i]->Indices.PushBack((unsigned short)atoi(text));
            j = k + 1;
        }

        // Reverse index order to match original expected orientation
        Array<uint16_t>& indices    = Models[i]->Indices;
        size_t         indexCount = indices.GetSize();         

        for (size_t revIndex = 0; revIndex < indexCount/2; revIndex++)
        {
            unsigned short itemp               = indices[revIndex];
            indices[revIndex]                  = indices[indexCount - revIndex - 1];
            indices[indexCount - revIndex - 1] = itemp;            
        }

        delete vertices;
        delete normals;
        delete diffuseUVs;
        delete lightmapUVs;

        pScene->World.Add(Models[i]);
        pScene->Models.PushBack(Models[i]);
        pXmlModel = pXmlModel->NextSiblingElement("model");
    }
	OVR_DEBUG_LOG(("Done."));

    //load the collision models
	OVR_DEBUG_LOG(("Loading collision models... "));
    XMLElement* pXmlCollisionModel = pXmlDocument->FirstChildElement("scene")->FirstChildElement("collisionModels");
    if (pXmlCollisionModel)
    {
		pXmlCollisionModel->QueryIntAttribute("count", &collisionModelCount);
        pXmlCollisionModel = pXmlCollisionModel->FirstChildElement("collisionModel");
    }

    XMLElement* pXmlPlane = NULL;
    for(int i = 0; i < collisionModelCount; ++i)
    {
        Ptr<CollisionModel> cm = *new CollisionModel();
        int planeCount = 0;
        
        OVR_ASSERT(pXmlCollisionModel != NULL); // collisionModelCount should guarantee this.
        if (pXmlCollisionModel)
        {
        pXmlCollisionModel->QueryIntAttribute("planeCount", &planeCount);

        pXmlPlane = pXmlCollisionModel->FirstChildElement("plane");
        for(int j = 0; j < planeCount; ++j)
        {
            Vector3f norm;
            pXmlPlane->QueryFloatAttribute("nx", &norm.x);
            pXmlPlane->QueryFloatAttribute("ny", &norm.y);
            pXmlPlane->QueryFloatAttribute("nz", &norm.z);
            float D;
            pXmlPlane->QueryFloatAttribute("d", &D);
            D -= 0.5f;
            if (i == 26)
                D += 0.5f;  // tighten the terrace collision so player can move right up to rail
            Planef p(norm.z, norm.y, norm.x * -1.0f, D);
            cm->Add(p);
            pXmlPlane = pXmlPlane->NextSiblingElement("plane");
        }

        if (pCollisions)
        pCollisions->PushBack(cm);
        pXmlCollisionModel = pXmlCollisionModel->NextSiblingElement("collisionModel");
    }
    }
	OVR_DEBUG_LOG(("done."));

    //load the ground collision models
	OVR_DEBUG_LOG(("Loading ground collision models..."));
    pXmlCollisionModel = pXmlDocument->FirstChildElement("scene")->FirstChildElement("groundCollisionModels");
    OVR_ASSERT(pXmlCollisionModel);
    if (pXmlCollisionModel)
    {
		pXmlCollisionModel->QueryIntAttribute("count", &groundCollisionModelCount);
        pXmlCollisionModel = pXmlCollisionModel->FirstChildElement("collisionModel");

    pXmlPlane = NULL;
    for(int i = 0; i < groundCollisionModelCount; ++i)
    {
        Ptr<CollisionModel> cm = *new CollisionModel();
        int planeCount = 0;
        pXmlCollisionModel->QueryIntAttribute("planeCount", &planeCount);

        pXmlPlane = pXmlCollisionModel->FirstChildElement("plane");
        for(int j = 0; j < planeCount; ++j)
        {
            Vector3f norm;
            pXmlPlane->QueryFloatAttribute("nx", &norm.x);
            pXmlPlane->QueryFloatAttribute("ny", &norm.y);
            pXmlPlane->QueryFloatAttribute("nz", &norm.z);
                float D = 0.f;
            pXmlPlane->QueryFloatAttribute("d", &D);
            Planef p(norm.z, norm.y, norm.x * -1.0f, D);
            cm->Add(p);
            pXmlPlane = pXmlPlane->NextSiblingElement("plane");
        }

        if (pGroundCollisions)
        pGroundCollisions->PushBack(cm);
        pXmlCollisionModel = pXmlCollisionModel->NextSiblingElement("collisionModel");
    }
    }
	OVR_DEBUG_LOG(("done."));
	return true;
}
Beispiel #22
0
bool ShaderSet::Link()
{
    glLinkProgram(Prog);
    GLint r;
    glGetProgramiv(Prog, GL_LINK_STATUS, &r);
    if (!r)
    {
        GLchar msg[1024];
        glGetProgramInfoLog(Prog, sizeof(msg), 0, msg);
        OVR_DEBUG_LOG(("Linking shaders failed: %s\n", msg));
        if (!r)
            return 0;
    }
    glUseProgram(Prog);

    UniformInfo.Clear();
    LightingVer = 0;
    UsesLighting = 0;

	GLint uniformCount = 0;
	glGetProgramiv(Prog, GL_ACTIVE_UNIFORMS, &uniformCount);
	OVR_ASSERT(uniformCount >= 0);

    for(GLuint i = 0; i < (GLuint)uniformCount; i++)
    {
        GLsizei namelen;
        GLint size = 0;
        GLenum type;
        GLchar name[32];
        glGetActiveUniform(Prog, i, sizeof(name), &namelen, &size, &type, name);

        if (size)
        {
            int l = glGetUniformLocation(Prog, name);
            char *np = name;
            while (*np)
            {
                if (*np == '[')
                    *np = 0;
                np++;
            }
            Uniform u;
            u.Name = name;
            u.Location = l;
            u.Size = size;
            switch (type)
            {
            case GL_FLOAT:      u.Type = 1; break;
            case GL_FLOAT_VEC2: u.Type = 2; break;
            case GL_FLOAT_VEC3: u.Type = 3; break;
            case GL_FLOAT_VEC4: u.Type = 4; break;
            case GL_FLOAT_MAT3: u.Type = 12; break;
            case GL_FLOAT_MAT4: u.Type = 16; break;
            default:
                continue;
            }
            UniformInfo.PushBack(u);
            if (!strcmp(name, "LightCount"))
                UsesLighting = 1;
        }
        else
            break;
    }

    ProjLoc = glGetUniformLocation(Prog, "Proj");
    ViewLoc = glGetUniformLocation(Prog, "View");
    for (int i = 0; i < 8; i++)
    {
        char texv[32];
        OVR_sprintf(texv, 10, "Texture%d", i);
        TexLoc[i] = glGetUniformLocation(Prog, texv);
        if (TexLoc[i] < 0)
            break;

        glUniform1i(TexLoc[i], i);
    }
    if (UsesLighting)
        OVR_ASSERT(ProjLoc >= 0 && ViewLoc >= 0);
    return 1;
}
String OptionVar::FormatInt(OptionVar* var)
{
    char buff[64];
    OVR_sprintf(buff, sizeof(buff), var->FormatString, *var->AsInt());
    return String(buff);
}
static int discoverExtendedRifts(OVR::DisplayDesc* descriptorArray, int inputArraySize, bool /*edidInfo*/)
{
    int result = 0;

    if (X11Display == NULL)
    {
        OVR::LogError("[Linux Display] Unable to open X Display!");
        return 0;
    }

    Atom EDIDAtom = XInternAtom(X11Display, RR_PROPERTY_RANDR_EDID, False);
    int numScreens = XScreenCount(X11Display);
    for (int i = 0; i < numScreens; ++i)
    {
        Window sr                       = XRootWindow(X11Display, i);
        XRRScreenResources* screen      = XRRGetScreenResources(X11Display, sr);

        for (int ii = 0; ii < screen->ncrtc; ++ii)
        {
            XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(X11Display, screen, screen->crtcs[ii]);

            if (0 == crtcInfo->noutput)
            {
                XRRFreeCrtcInfo(crtcInfo);
                continue;
            }

            bool foundOutput = false;
            RROutput output = crtcInfo->outputs[0];
            for (int k = 0; k < crtcInfo->noutput; ++k)
            {
                XRROutputInfo* outputInfo =
                    XRRGetOutputInfo(X11Display, screen, crtcInfo->outputs[k]);

                for (int kk = 0; kk < outputInfo->nmode; ++kk)
                {
                    if (outputInfo->modes[kk] == crtcInfo->mode)
                    {
                        output = crtcInfo->outputs[k];
                        foundOutput = true;
                        break;
                    }
                }
                XRRFreeOutputInfo(outputInfo);
                if (foundOutput)
                {
                    break;
                }
            }

            if (!foundOutput)
            {
                XRRFreeCrtcInfo(crtcInfo);
                continue;
            }

            XRROutputInfo* outputInfo = XRRGetOutputInfo(X11Display, screen, output);
            if (RR_Connected != outputInfo->connection)
            {
                XRRFreeOutputInfo(outputInfo);
                XRRFreeCrtcInfo(crtcInfo);
                continue;
            }

            // Read EDID associated with crtc.
            uint8_t* data    = NULL;
            int      dataLen = 0;
            if (getXRRProperty(X11Display, output, EDIDAtom, &data, &dataLen) != 0)
            {
                // Identify rifts based on EDID.
                Linux::DisplayEDID edid;
                parseEdid(data, edid);
                XFree(data);
                data = NULL;

                // TODO: Remove either this 3rdParty call to read EDID data
                //       or remove our own parsing of the EDID. Probably opt
                //       to remove our parsing.
                MonitorInfo* mi = read_edid_data(X11Display, output);
                if (mi == NULL)
                {
                    XRRFreeOutputInfo(outputInfo);
                    XRRFreeCrtcInfo(crtcInfo);
                    continue;
                }

                if (edid.VendorName == "OVR")
                {
                    if( result >= inputArraySize )
                    {
                        delete mi;
                        XRRFreeOutputInfo(outputInfo);
                        XRRFreeCrtcInfo(crtcInfo);
                        return result;
                    }

                    XRRModeInfo* modeInfo = findModeByXID(screen, crtcInfo->mode);

                    int width = modeInfo->width;
                    int height = modeInfo->height;

                    int x = crtcInfo->x;
                    int y = crtcInfo->y;

                    // Generate a device ID string similar Windows does it
                    char device_id[32];
                    OVR_sprintf(device_id, 32, "%s%04d-%d",
                                mi->manufacturer_code, mi->product_code,
                                screen->crtcs[ii]);

                    OVR::DisplayDesc& desc         = descriptorArray[result++];
                    desc.ResolutionInPixels        = Sizei(width, height);
                    desc.DesktopDisplayOffset      = Vector2i(x, y);
                    strncpy(desc.DisplayID, device_id, sizeof(desc.DisplayID)-1);
                    desc.DisplayID[sizeof(desc.DisplayID)-1] = 0;
                    strncpy(desc.ModelName, edid.MonitorName, sizeof(desc.ModelName)-1);
                    desc.ModelName[sizeof(desc.ModelName)-1] = 0;
                    strncpy(desc.EdidSerialNumber, edid.SerialNumber, sizeof(desc.EdidSerialNumber)-1);
                    desc.EdidSerialNumber[sizeof(desc.EdidSerialNumber)-1] = 0;

                    bool tallScreen = (height > width);
                    switch (crtcInfo->rotation)
                    {
                        default:
                            desc.Rotation = tallScreen ? 270 : 0;
                            break;
                        case RR_Rotate_90:
                            desc.Rotation = tallScreen ? 0 : 90;
                            break;
                        case RR_Rotate_180:
                            desc.Rotation = tallScreen ? 90 : 180;
                            break;
                        case RR_Rotate_270:
                            desc.Rotation = tallScreen ? 180 : 270;
                            break;
                    }

                    switch (mi->product_code)
                    {
                        case 3: desc.DeviceTypeGuess = HmdType_DK2;       break;
                        case 2: desc.DeviceTypeGuess = HmdType_DKHDProto; break;
                        case 1: desc.DeviceTypeGuess = HmdType_DK1;       break;

                        default:
                        case 0: desc.DeviceTypeGuess = HmdType_Unknown;   break;
                    }

                    // Hard-coded defaults in case the device doesn't have the
                    // data itself. DK2 prototypes (0003) or DK HD Prototypes (0002).
                    if (   desc.DeviceTypeGuess == HmdType_DK2
                        || desc.DeviceTypeGuess == HmdType_DKHDProto)
                    {
                        desc.ResolutionInPixels = Sizei(1920, 1080);
                    }
                    else
                    {
                        desc.ResolutionInPixels = Sizei(width, height);
                    }
                }

                delete mi;
                mi = NULL;
            }
            else
            {
                XFree(data);
            }

            XRRFreeOutputInfo(outputInfo);
            XRRFreeCrtcInfo(crtcInfo);
        }

        XRRFreeScreenResources(screen);
    }

    return result;
}
Beispiel #25
0
//==============================
// ovrFileSysLocal::ovrFileSysLocal
ovrFileSysLocal::ovrFileSysLocal( ovrJava const & javaContext )
{
	// always do unit tests on startup to assure nothing has been broken
	ovrUri::DoUnitTest();

#if defined( OVR_OS_ANDROID )
	// add the apk scheme 
	ovrUriScheme_Apk * scheme = new ovrUriScheme_Apk( "apk" );

	// add a host for the executing application's scheme
	char curPackageName[OVR_MAX_PATH_LEN];
	ovr_GetCurrentPackageName( javaContext.Env, javaContext.ActivityObject, curPackageName, sizeof( curPackageName ) );
	char curPackageCodePath[OVR_MAX_PATH_LEN];
	ovr_GetPackageCodePath( javaContext.Env, javaContext.ActivityObject, curPackageCodePath, sizeof( curPackageCodePath ) );

	// not sure if this is necessary... shouldn't the application always have permission to open its own scheme?
/*
	String outPath;
	const bool validCacheDir = StoragePaths->GetPathIfValidPermission(
			EST_INTERNAL_STORAGE, EFT_CACHE, "", permissionFlags_t( PERMISSION_WRITE ) | PERMISSION_READ, outPath );
	ovr_OpenApplicationPackage( temp, validCacheDir ? outPath.ToCStr() : NULL );
*/
	char curPackageUri[OVR_MAX_URI_LEN];
	OVR_sprintf( curPackageUri, sizeof( curPackageUri ), "file://%s", curPackageCodePath );
	if ( !scheme->OpenHost( "localhost", curPackageUri ) )
	{
		LOG( "Failed to OpenHost for host '%s', uri '%s'", "localhost", curPackageUri );
		OVR_ASSERT( false );
	}

	// add the hosts for the system activities apk

	/// FIXME: why do we try to add the PUI_PACKAGE_NAME package and then curPackageName? Shouldn't
	/// the PUI_PACKAGE_NAME (i.e. System Activities) always exist and shouldn't we always add
	/// the current package as a valid host name anyway?

	// NOTE: we do not add a "com.<company>.<appname>" ( i.e. the Android app's package name ) host 
	// for Windows because we don't really have a good way of knowing what the Android package name
	// on Windows without parsing the AndroidManifest.xml explicitly for that reason. This means
	// using apk://com.<company>.<appname> for the scheme and host will fail on non-Android builds.
	// This, in turn, means that any access to the apps own assets should just be done with 
	// apk://localhost/ in order to be cross-platform compatible. Because of that, we do not add
	// "com.<company>.<appname>" as a host on Android, either (since it would just fail on Windows).

	{
		for ( int i = 0; i < 2; ++i )
		{
			char const * packageName = ( i == 0 ) ? PUI_PACKAGE_NAME : curPackageName;
			char packagePath[OVR_MAX_PATH_LEN];
			packagePath[0] = '\0';
			if ( ovr_GetInstalledPackagePath( javaContext.Env, javaContext.ActivityObject, packageName, packagePath, sizeof( packagePath ) ) )
			{
				char packageUri[sizeof( packagePath ) + 7 ];
				OVR_sprintf( packageUri, sizeof( packageUri ), "file://%s", packagePath );

				scheme->OpenHost( packageName, packageUri );
				break;
			}
		}
	}

	Schemes.PushBack( scheme );

	// add the host for font assets by opening a stream and trying to load res/raw/font_location.txt from the System Activites apk.
	// If this file exists then
	{
		MemBufferT< uint8_t > buffer;
		char fileName[256];
		OVR::OVR_sprintf( fileName, sizeof( fileName ), "apk://%s/res/raw/font_location.txt", PUI_PACKAGE_NAME );
		char fontPackageName[1024];		
		bool success = ReadFile( fileName, buffer );
		if ( success && buffer.GetSize() > 0 )
		{
			OVR::OVR_strncpy( fontPackageName, sizeof( fontPackageName ), ( char const * )( static_cast< uint8_t const * >( buffer ) ), buffer.GetSize() );
			LOG( "Found font package name '%s'", fontPackageName );
		} else {
			// default to the SystemActivities apk.
			OVR::OVR_strcpy( fontPackageName, sizeof( fontPackageName ), PUI_PACKAGE_NAME );
		}

		char packagePath[OVR_MAX_PATH_LEN];
		packagePath[0] = '\0';
		if ( ovr_GetInstalledPackagePath( javaContext.Env, javaContext.ActivityObject, fontPackageName, packagePath, sizeof( packagePath ) ) )
		{
			// add this package to our scheme as a host so that fonts can be loaded from it
			char packageUri[sizeof( packagePath ) + 7 ];
			OVR_sprintf( packageUri, sizeof( packageUri ), "file://%s", packagePath );				

			// add the package name as an explict host if it doesn't already exists -- it will already exist if the package name
			// is not overrloaded by font_location.txt (i.e. the fontPackageName will have defaulted to PUI_PACKAGE_NAME )
			if ( !scheme->HostExists( fontPackageName ) ) {
				scheme->OpenHost( fontPackageName, packageUri );
			}
			scheme->OpenHost( "font", packageUri );

			LOG( "Added host '%s' for fonts @'%s'", fontPackageName, packageUri );
		}
	}
#elif defined( OVR_OS_WIN32 )
	ovrPathUtils::DoUnitTests();

	// Assume the working dir has an assets/ and res/ folder in it as is common on Android. Normally
	// the working folder would be Projects/Android.
	char curWorkingDir[MAX_PATH];
	_getcwd( curWorkingDir, sizeof( curWorkingDir ) );
	char uriWorkingDir[MAX_PATH];
	ovrPathUtils::FixSlashesForUri( curWorkingDir, uriWorkingDir, sizeof( uriWorkingDir ) );

	// if the asset package exists in the current working dir, add it as an apk scheme instead of using
	// raw files
	const char * const PACKAGE_EXTENSION = "pak";
	char packagePath[MAX_PATH];
	OVR_sprintf( packagePath, sizeof( packagePath ), "%s\\%s.%s", curWorkingDir, "assets", PACKAGE_EXTENSION );
	if ( _access( packagePath, 04 ) == 0 )
	{
		// package exists
		ovrUriScheme_Apk * scheme = new ovrUriScheme_Apk( "apk" );
		
		char packageUri[OVR_MAX_URI_LEN];
		OVR_sprintf( packageUri, sizeof( packageUri ), "file://%s", packagePath );
		ovrPathUtils::FixSlashesForUriInPlace( packageUri );
		if ( !scheme->OpenHost( "localhost", packageUri ) )
		{
			LOG( "Failed to OpenHost for host '%s', uri '%s'", "localhost", packageUri );
			OVR_ASSERT( false );
		}

		// NOTE: we do not add a "com.<company>.<appname>" ( i.e. the Android app's package name ) host 
		// for Windows because we don't really have a good way of knowing what the Android package name
		// on Windows without parsing the AndroidManifest.xml explicitly for that reason. This means
		// using apk://com.<company>.<appname> for the scheme and host will fail on non-Android builds.
		// This, in turn, means that any access to the apps own assets should just be done with 
		// apk://localhost/ in order to be cross-platform compatible. Because of that, we do not add
		// "com.<company>.<appname>" as a host on Android, either (since it would just fail on Windows).
		
		// Currently "com.oculus.systemactivities" and "font" hosts assume the SA assets are simply 
		// packed into the application's asset package.
		if ( !scheme->OpenHost( PUI_PACKAGE_NAME, packageUri ) )
		{
			LOG( "Failed to OpenHost for host '%s', uri '%s'", PUI_PACKAGE_NAME, packageUri );
			OVR_ASSERT( false );
		}
		if ( !scheme->OpenHost( "font", packageUri ) )
		{
			LOG( "Failed to OpenHost for host '%s', uri '%s'", "font", packageUri );
			OVR_ASSERT( false );
		}

        Schemes.PushBack(scheme);
    }
    else
    {
		// add the apk scheme for the working path
		ovrUriScheme_File * scheme = new ovrUriScheme_File("apk");

		// On Android we have several different APK hosts:
		// - apk://com.oculus.systemactivities/ : this may hold vrapi.so, font_location.txt, or font data.
		// - apk://font/ : this may hold font data, if font data has been moved out of SystemActivities apk, 
		//   so all fonts should be loaded via this host.
		// - apk://localhost/ : the default host that maps to the application's own apk.
		char dataUri[OVR_MAX_PATH_LEN];
		OVR_sprintf( dataUri, sizeof( dataUri ), "file:///%s", uriWorkingDir );
          
		// HACK: this is currently relying on the relative path to VrAppFramework being the same for all projects, which it's not.
		// FIXME: change this to use command line parameters that specify additional paths.
		AddRelativePathToHost( scheme, "localhost", curWorkingDir, "../../../VrAppFramework" );
		AddRelativePathToHost( scheme, "localhost", curWorkingDir, "../../../VrAppSupport/VrGUI" );
		AddRelativePathToHost( scheme, "localhost", curWorkingDir, "../../../VrAppSupport/Net" );
		AddRelativePathToHost( scheme, "localhost", curWorkingDir, "../Libraries/ovr_sdks/ovr_sdk_mobile/VrAppFramework" );
		AddRelativePathToHost( scheme, "localhost", curWorkingDir, "../Libraries/ovr_sdks/ovr_sdk_mobile/VrAppSupport/VrGUI" );
		AddRelativePathToHost( scheme, "localhost", curWorkingDir, "../Libraries/AppSupport/Net" );
		scheme->AddHostSourceUri( "localhost", dataUri );

		AddRelativePathToHost( scheme, PUI_PACKAGE_NAME, curWorkingDir, "../../../VrAppFramework" );
		AddRelativePathToHost( scheme, PUI_PACKAGE_NAME, curWorkingDir, "../../../VrAppSupport/VrGUI" );
		// MA: This path works if target is within Projects
		AddRelativePathToHost( scheme, PUI_PACKAGE_NAME, curWorkingDir, "../../../../../../VrAppFramework" );
		AddRelativePathToHost( scheme, PUI_PACKAGE_NAME, curWorkingDir, "../../../../../../VrAppSupport/VrGUI" );        
		AddRelativePathToHost( scheme, PUI_PACKAGE_NAME, curWorkingDir, "../Libraries/ovr_sdks/ovr_sdk_mobile/VrAppFramework" );
		AddRelativePathToHost( scheme, PUI_PACKAGE_NAME, curWorkingDir, "../Libraries/ovr_sdks/ovr_sdk_mobile/VrAppSupport/VrGUI" );
		scheme->AddHostSourceUri( PUI_PACKAGE_NAME, dataUri );

		AddRelativePathToHost( scheme, "font", curWorkingDir, "../../../VrAppFramework" );
		AddRelativePathToHost( scheme, "font", curWorkingDir, "../../../VrAppSupport/VrGUI" );
		// MA: This path works if target is within Projects
		AddRelativePathToHost( scheme, "font", curWorkingDir, "../../../../../../VrAppFramework");
		AddRelativePathToHost( scheme, "font", curWorkingDir, "../../../../../../VrAppSupport/VrGUI");
		AddRelativePathToHost( scheme, "font", curWorkingDir, "../Libraries/ovr_sdks/ovr_sdk_mobile/VrAppFramework" );
		AddRelativePathToHost( scheme, "font", curWorkingDir, "../Libraries/ovr_sdks/ovr_sdk_mobile/VrAppSupport/VrGUI" );
		scheme->AddHostSourceUri( "font", dataUri );

		Schemes.PushBack( scheme );	
	}
#else
#error Unsupported platform!
#endif
}
void OculusWorldDemoApp::RenderTextInfoHud(float textHeight)
{
    // View port & 2D ortho projection must be set before call.
    
    float hmdYaw, hmdPitch, hmdRoll;
    switch(TextScreen)
    {
    case Text_Info:
    {
        char buf[512], gpustat[256];

        // Average FOVs.
        FovPort leftFov  = EyeRenderDesc[0].Fov;
        FovPort rightFov = EyeRenderDesc[1].Fov;
        
        // Rendered size changes based on selected options & dynamic rendering.
        int pixelSizeWidth = EyeTexture[0].Header.RenderViewport.Size.w +
                             ((!ForceZeroIpd) ?
                               EyeTexture[1].Header.RenderViewport.Size.w : 0);
        int pixelSizeHeight = ( EyeTexture[0].Header.RenderViewport.Size.h +
                                EyeTexture[1].Header.RenderViewport.Size.h ) / 2;

        // No DK2, no message.
        char latency2Text[128] = "";
        {
            //float latency2 = ovrHmd_GetMeasuredLatencyTest2(Hmd) * 1000.0f; // show it in ms
            //if (latency2 > 0)
            //    OVR_sprintf(latency2Text, sizeof(latency2Text), "%.2fms", latency2);

            float latencies[3] = { 0.0f, 0.0f, 0.0f };
            if (ovrHmd_GetFloatArray(Hmd, "DK2Latency", latencies, 3) == 3)
            {
                char latencyText0[32], latencyText1[32], latencyText2[32];
                FormatLatencyReading(latencyText0, sizeof(latencyText0), latencies[0]);
                FormatLatencyReading(latencyText1, sizeof(latencyText1), latencies[1]);
                FormatLatencyReading(latencyText2, sizeof(latencyText2), latencies[2]);

                OVR_sprintf(latency2Text, sizeof(latency2Text),
                            " DK2 Latency  Ren: %s  TWrp: %s\n"
                            " PostPresent: %s  ",
                            latencyText0, latencyText1, latencyText2);
            }
        }

        ThePlayer.HeadPose.Rotation.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(&hmdYaw, &hmdPitch, &hmdRoll);
        OVR_sprintf(buf, sizeof(buf),
                    " HMD YPR:%4.0f %4.0f %4.0f   Player Yaw: %4.0f\n"
                    " FPS: %.1f  ms/frame: %.1f Frame: %d\n"
                    " Pos: %3.2f, %3.2f, %3.2f  HMD: %s\n"
                    " EyeHeight: %3.2f, IPD: %3.1fmm\n" //", Lens: %s\n"
                    " FOV %3.1fx%3.1f, Resolution: %ix%i\n"
                    "%s",
                    RadToDegree(hmdYaw), RadToDegree(hmdPitch), RadToDegree(hmdRoll),
                    RadToDegree(ThePlayer.BodyYaw.Get()),
                    FPS, SecondsPerFrame * 1000.0f, FrameCounter,
                    ThePlayer.BodyPos.x, ThePlayer.BodyPos.y, ThePlayer.BodyPos.z,
                    //GetDebugNameHmdType ( TheHmdRenderInfo.HmdType ),
                    HmdDesc.ProductName,
                    ThePlayer.UserEyeHeight,
                    ovrHmd_GetFloat(Hmd, OVR_KEY_IPD, 0) * 1000.0f,
                    //( EyeOffsetFromNoseLeft + EyeOffsetFromNoseRight ) * 1000.0f,
                    //GetDebugNameEyeCupType ( TheHmdRenderInfo.EyeCups ),  // Lens/EyeCup not exposed
                    
                    (leftFov.GetHorizontalFovDegrees() + rightFov.GetHorizontalFovDegrees()) * 0.5f,
                    (leftFov.GetVerticalFovDegrees() + rightFov.GetVerticalFovDegrees()) * 0.5f,

                    pixelSizeWidth, pixelSizeHeight,

                    latency2Text
                    );

        size_t texMemInMB = pRender->GetTotalTextureMemoryUsage() / 1058576;
        if (texMemInMB)
        {
            OVR_sprintf(gpustat, sizeof(gpustat), " GPU Tex: %u MB", texMemInMB);
            OVR_strcat(buf, sizeof(buf), gpustat);
        }
        
        DrawTextBox(pRender, 0.0f, 0.0f, textHeight, buf, DrawText_Center);
    }
    break;
    
    case Text_Timing:    
        Profiler.DrawOverlay(pRender);    
    break;
    
    case Text_Help1:
        DrawTextBox(pRender, 0.0f, 0.0f, textHeight, HelpText1, DrawText_Center);
        break;
    case Text_Help2:
        DrawTextBox(pRender, 0.0f, 0.0f, textHeight, HelpText2, DrawText_Center);
        break;
    
    case Text_None:
        break;

    default:
        OVR_ASSERT ( !"Missing text screen" );
        break;    
    }
}
String OptionVar::FormatFloat(OptionVar* var)
{
    char buff[64];
    OVR_sprintf(buff, sizeof(buff), var->FormatString, *var->AsFloat() * var->FormatScale);
    return String(buff);
}