chac/src/main.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 ) );
}
}