218 lines
6.4 KiB
C
218 lines
6.4 KiB
C
// this is mostly copied / inspired by this: https://gist.github.com/cnlohr/6e452dc6cc2df7f48d5ade66059358d9
|
|
// made for this video: https://www.youtube.com/watch?v=r6kM3tR03g4
|
|
// thanks @cnlohr for rawdraw, alot of other functions, my motivation and the idea
|
|
|
|
|
|
#include <time.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
#define CNFG_IMPLEMENTATION
|
|
#define CNFGOGL
|
|
#include "os_generic.h"
|
|
#include "CNFG.h"
|
|
|
|
#undef EXTERN_C
|
|
#include "openvr_capi.h"
|
|
|
|
intptr_t VR_InitInternal( EVRInitError *peError, EVRApplicationType eType );
|
|
void VR_ShutdownInternal();
|
|
bool VR_IsHmdPresent();
|
|
intptr_t VR_GetGenericInterface( const char *pchInterfaceVersion, EVRInitError *peError );
|
|
bool VR_IsRuntimeInstalled();
|
|
const char * VR_GetVRInitErrorAsSymbol( EVRInitError error );
|
|
const char * VR_GetVRInitErrorAsEnglishDescription( EVRInitError error );
|
|
|
|
//rawdraw callbacks
|
|
void HandleKey( int keycode, int bDown ) { }
|
|
void HandleButton( int x, int y, int button, int bDown ) { }
|
|
void HandleMotion( int x, int y, int mask ) { }
|
|
void HandleDestroy() {
|
|
exit(0);
|
|
}
|
|
|
|
// This function was copy-pasted from cnovr.
|
|
void* CNOVRGetOpenVRFunctionTable( const char * interfacename ) {
|
|
EVRInitError e;
|
|
char fnTableName[128];
|
|
int result1 = snprintf( fnTableName, 128, "FnTable:%s", interfacename );
|
|
void* ret = (void *)VR_GetGenericInterface( fnTableName, &e );
|
|
printf( "Getting System FnTable: %s = %p (%d)\n", fnTableName, ret, e );
|
|
if( !ret ) {
|
|
exit( 1 );
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// These are interfaces into OpenVR, they are basically function call tables.
|
|
struct VR_IVRSystem_FnTable* oSystem;
|
|
struct VR_IVROverlay_FnTable* oOverlay;
|
|
|
|
// The OpenVR Overlay handle.
|
|
VROverlayHandle_t overlayID;
|
|
|
|
const uint32_t WIDTH = 120, HEIGHT = 24;
|
|
|
|
int initVR() {
|
|
EVRInitError ierr;
|
|
uint32_t token = VR_InitInternal( &ierr, EVRApplicationType_VRApplication_Overlay );
|
|
if( !token ) {
|
|
printf( "Error!!!! Could not initialize OpenVR\n" );
|
|
return 1;
|
|
}
|
|
|
|
// Get the system and overlay interfaces. We pass in the version of these
|
|
// interfaces that we wish to use, in case the runtime is newer, we can still
|
|
// get the interfaces we expect.
|
|
oSystem = CNOVRGetOpenVRFunctionTable( IVRSystem_Version );
|
|
oOverlay = CNOVRGetOpenVRFunctionTable( IVROverlay_Version );
|
|
|
|
|
|
oOverlay->CreateOverlay( "controlerhandmountedclock", "Controller Hand Mounted Clock", &overlayID );
|
|
oOverlay->SetOverlayWidthInMeters( overlayID, .2 );
|
|
oOverlay->SetOverlayColor( overlayID, 1., .8, .7 );
|
|
|
|
// Control texture bounds to control the way the texture is mapped to the overlay.
|
|
VRTextureBounds_t bounds;
|
|
bounds.uMin = 0;
|
|
bounds.uMax = 1;
|
|
bounds.vMin = 0;
|
|
bounds.vMax = 1;
|
|
oOverlay->SetOverlayTextureBounds( overlayID, &bounds );
|
|
|
|
return 0;
|
|
}
|
|
|
|
GLuint initOverlayTexture() {
|
|
// Initialize the texture with junk data.
|
|
uint8_t * myjunkdata = malloc( 128 * 128 * 4 );
|
|
int x, y;
|
|
for( y = 0; y < 128; y++ )
|
|
for( x = 0; x < 128; x++ )
|
|
{
|
|
myjunkdata[ ( x + y * 128 ) * 4 + 0 ] = x * 2;
|
|
myjunkdata[ ( x + y * 128 ) * 4 + 1 ] = y * 2;
|
|
myjunkdata[ ( x + y * 128 ) * 4 + 2 ] = 0;
|
|
myjunkdata[ ( x + y * 128 ) * 4 + 3 ] = 255;
|
|
}
|
|
|
|
// We aren't doing it, but we could write directly into the overlay.
|
|
//err = oOverlay->SetOverlayRaw( overlayID, myjunkdata, 128, 128, 4 );
|
|
|
|
// Generate the texture.
|
|
GLuint textureid;
|
|
glGenTextures( 1, &textureid );
|
|
glBindTexture( GL_TEXTURE_2D, textureid );
|
|
|
|
// It is required to setup the min and mag filter of the texture.
|
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
|
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
|
|
|
|
// Load the texture with our dummy data. Optionally we could pass 0 in where we are
|
|
// passing in myjunkdata. That would allocate the RAM on the GPU but not do anything with it.
|
|
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, myjunkdata);
|
|
|
|
free(myjunkdata);
|
|
|
|
return textureid;
|
|
}
|
|
|
|
bool attach() {
|
|
TrackedDeviceIndex_t index;
|
|
index = oSystem->GetTrackedDeviceIndexForControllerRole( ETrackedControllerRole_TrackedControllerRole_LeftHand );
|
|
|
|
if( index == k_unTrackedDeviceIndexInvalid || index == k_unTrackedDeviceIndex_Hmd ) {
|
|
printf( "Couldn't find your controller to attach our overlay to (%d)\n", index );
|
|
return false;
|
|
} else {
|
|
// We have a ETrackedControllerRole_TrackedControllerRole_LeftHand. Associate it.
|
|
EVROverlayError err;
|
|
|
|
// Transform that puts the text somewhere reasonable.
|
|
HmdMatrix34_t transform = { 0 };
|
|
|
|
//rotation
|
|
transform.m[0][0] = -1;
|
|
transform.m[1][2] = -1;
|
|
transform.m[2][1] = -1;
|
|
|
|
//offset
|
|
transform.m[0][3] = 0;
|
|
transform.m[1][3] = -0.05;
|
|
transform.m[2][3] = 0.15;
|
|
|
|
// Apply the transform and attach the overlay to that tracked device object.
|
|
err = oOverlay->SetOverlayTransformTrackedDeviceRelative( overlayID, index, &transform );
|
|
|
|
// Notify the terminal that this was associated.
|
|
printf( "Successfully associated your clock to the tracked device (%d %d %08x).\n",
|
|
err, index, overlayID );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
CNFGSetup( "CHAC", -WIDTH, -HEIGHT );
|
|
|
|
while(initVR()) {
|
|
OGUSleep( (int)( 1000000 ) );
|
|
}
|
|
|
|
oOverlay->ShowOverlay( overlayID );
|
|
GLuint texture = initOverlayTexture();
|
|
|
|
bool isAttached = false;
|
|
|
|
CNFGBGColor = 0x00000000; //Background
|
|
while(1) {
|
|
if(!isAttached) {
|
|
isAttached = attach();
|
|
OGUSleep( (int)( 1000000 ) ); //wait one sec
|
|
continue;
|
|
}
|
|
|
|
CNFGClearFrame();
|
|
|
|
//Change color to white.
|
|
CNFGColor( 0xffffffff );
|
|
|
|
CNFGPenX = 1; CNFGPenY = 1;
|
|
//draw clock
|
|
char clock[9];
|
|
time_t curr = time(NULL);
|
|
struct tm * formtime = localtime(&curr);
|
|
strftime(clock, 9, "%H:%M:%S", formtime);
|
|
CNFGDrawText( clock, 5 );
|
|
|
|
// Finish rendering any pending draw operations.
|
|
CNFGFlushRender();
|
|
|
|
// Bind the texture we will be sending to OpenVR.
|
|
glBindTexture( GL_TEXTURE_2D, texture );
|
|
|
|
// Copy the current framebuffer into that texture.
|
|
glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, WIDTH, HEIGHT, 0 );
|
|
|
|
{
|
|
// Setup a Texture_t object to send in the texture.
|
|
struct Texture_t tex;
|
|
tex.eColorSpace = EColorSpace_ColorSpace_Auto;
|
|
tex.eType = ETextureType_TextureType_OpenGL;
|
|
tex.handle = (void*)(intptr_t)texture;
|
|
|
|
// Send texture into OpenVR as the overlay.
|
|
oOverlay->SetOverlayTexture( overlayID, &tex );
|
|
}
|
|
|
|
|
|
// We have to process through texture events.
|
|
{
|
|
struct VREvent_t nEvent;
|
|
oOverlay->PollNextOverlayEvent( overlayID, &nEvent, 0xffffff );
|
|
}
|
|
|
|
// Display the image and wait for time to display next frame.
|
|
CNFGSwapBuffers();
|
|
OGUSleep( (int)( 0.1 * 1000000 ) );
|
|
}
|
|
} |