void OvrGazeCursorLocal::UpdateCursorGeometry() const { ASSERT_WITH_TAG( CursorDynamicVBO != 0, "DrawCursorGeometry" ); const size_t numQuadsPerDraw = TRAIL_GHOSTS; const size_t numVertsPerQuad = 4; const size_t bufferSize = numQuadsPerDraw * numVertsPerQuad * sizeof( Vector4f ); // We pack two buffers into one... one for scattered trails, one for normal. const size_t numBuffers = 2; glBindBuffer( GL_ARRAY_BUFFER, CursorDynamicVBO ); Vector4f * positions = ( Vector4f * )glMapBufferRange( GL_ARRAY_BUFFER, 0, bufferSize * numBuffers, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ); if ( positions == NULL ) { // we have logs of glMapBufferRange() apparently returning NULL here after the GPU resets. OVR_ASSERT( positions != NULL ); return; } // Z-pass positions... UpdateCursorPositions( &positions[ 0 ], CursorTransform ); // Z-fail positions... UpdateCursorPositions( &positions[ numQuadsPerDraw * numVertsPerQuad ], CursorScatterTransform ); glUnmapBuffer( GL_ARRAY_BUFFER ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); }
//============================== // OvrGazeCursorLocal:: void OvrGazeCursorLocal::Shutdown() { LOG( "OvrGazeCursorLocal::Shutdown" ); ASSERT_WITH_TAG( Initialized == true, "GazeCursor" ); ReleaseCursorGeometry(); for ( int i = 0; i < CURSOR_STATE_MAX; ++i ) { if ( CursorTextureHandle[i] != 0 ) { glDeleteTextures( 1, &CursorTextureHandle[i] ); CursorTextureHandle[i] = 0; } } if ( TimerTextureHandle != 0 ) { glDeleteTextures( 1, & TimerTextureHandle ); TimerTextureHandle = 0; } if ( ColorTableHandle != 0 ) { glDeleteTextures( 1, &ColorTableHandle ); ColorTableHandle = 0; } DeleteProgram( CursorProgram ); DeleteProgram( TimerProgram ); Initialized = false; }
void OvrGazeCursorLocal::DrawCursorWithTrail( unsigned int bufferIndex ) const { ASSERT_WITH_TAG( CursorVAO != 0, "DrawCursorWithTrail" ); const GLvoid * offset = reinterpret_cast<const GLvoid *>( bufferIndex * TRAIL_GHOSTS * 6 * sizeof( GLushort ) ); glBindVertexArray( CursorVAO ); glDrawElements( GL_TRIANGLES, TRAIL_GHOSTS * 6, GL_UNSIGNED_SHORT, offset ); }
//============================== // OvrGazeCursorLocal:: void OvrGazeCursorLocal::Init() { LOG( "OvrGazeCursorLocal::Init" ); ASSERT_WITH_TAG( Initialized == false, "GazeCursor" ); if ( Initialized ) { LOG( "OvrGazeCursorLocal::Init - already initialized!" ); return; } CreateCursorGeometry(); TimerGeometry = BuildTesselatedQuad( 1, 1 ); int w = 0; int h = 0; char const * const cursorStateNames[ CURSOR_STATE_MAX ] = { //"res/raw/color_ramp_test.tga", //"res/raw/color_ramp_test.tga", //"res/raw/gaze_cursor_dot.tga", //"res/raw/gaze_cursor_dot_hi.tga" //"res/raw/gaze_cursor_cross.tga", //"res/raw/gaze_cursor_cross_hi.tga" "res/raw/gaze_cursor_cross.tga", "res/raw/gaze_cursor_cross.tga", // for now, hilight is the same because the graphic needs work "res/raw/gaze_cursor_cross.tga", "res/raw/gaze_cursor_hand.tga" }; for ( int i = 0; i < CURSOR_STATE_MAX; ++i ) { CursorTextureHandle[i] = LoadTextureFromApplicationPackage( cursorStateNames[i], TextureFlags_t(), w, h ); } TimerTextureHandle = LoadTextureFromApplicationPackage( "res/raw/gaze_cursor_timer.tga", TextureFlags_t(), w, h ); ColorTableHandle = LoadTextureFromApplicationPackage( "res/raw/color_ramp_timer.tga", TextureFlags_t(), w, h ); CursorProgram = BuildProgram( GazeCursorVertexSrc, GazeCursorFragmentSrc ); TimerProgram = BuildProgram( GazeCursorTimerVertexSrc, GazeCursorColorTableFragmentSrc );//GazeCursorFragmentSrc ); Initialized = true; }
//============================== // VRMenuEventHandler::DispatchToComponents bool VRMenuEventHandler::DispatchToComponents( OvrGuiSys & guiSys, VrFrame const & vrFrame, VRMenuEvent const & event, VRMenuObject * receiver ) const { ASSERT_WITH_TAG( receiver != NULL, "VrMenu" ); Array< VRMenuComponent* > const & list = receiver->GetComponentList(); int numComps = list.GetSizeI(); for ( int i = 0; i < numComps; ++i ) { VRMenuComponent * item = list[i]; if ( item->HandlesEvent( VRMenuEventFlags_t( event.EventType ) ) ) { LogEventType( event, "DispatchEvent: to '%s'", receiver->GetText().ToCStr() ); if ( item->OnEvent( guiSys, vrFrame, receiver, event ) == MSG_STATUS_CONSUMED ) { LogEventType( event, "DispatchEvent: receiver '%s', component %i consumed event.", receiver->GetText().ToCStr(), i ); return true; // consumed by component } } } return false; }
//============================== // VRMenuEventHandler::BroadcastEvent bool VRMenuEventHandler::BroadcastEvent( OvrGuiSys & guiSys, VrFrame const & vrFrame, VRMenuEvent const & event, VRMenuObject * receiver ) const { ASSERT_WITH_TAG( receiver != NULL, "VrMenu" ); // allow parent components to handle first if ( DispatchToComponents( guiSys, vrFrame, event, receiver ) ) { return true; } // if the parent did not consume, dispatch to children int numChildren = receiver->NumChildren(); for ( int i = 0; i < numChildren; ++i ) { menuHandle_t childHandle = receiver->GetChildHandleForIndex( i ); VRMenuObject * child = guiSys.GetVRMenuMgr().ToObject( childHandle ); if ( child != NULL && BroadcastEvent( guiSys, vrFrame, event, child ) ) { return true; // consumed by child } } return false; }
//========================== // KeyState::HandleEvent void KeyState::HandleEvent( double const time, bool const down, int const repeatCount ) { LOG_WITH_TAG( "KeyState", "(%.4f) HandleEvent: %s, NumEvents %i, RepeatCount %i", vrapi_GetTimeInSeconds(), down ? "DOWN" : "UP", NumEvents, repeatCount ); bool wasDown = this->Down; this->Down = down; if ( NumEvents <= 0 && !down ) { // we ignore up events if we aren't currently tracking from a down -- this let's us exclude the up // event after a long press because we Reset() as soon as we fire the long-press event. PendingEvent = KEY_EVENT_NONE; return; } if ( repeatCount > 0 ) { ASSERT_WITH_TAG( down == true, "KeyState" ); // only a hold should have a repeat count // key is held PendingEvent = KEY_EVENT_NONE; return; } if ( wasDown == down ) { LOG_WITH_TAG( "KeyState", "wasDown != down" ); // this should always be a toggle unless we've missed an event, right? PendingEvent = KEY_EVENT_NONE; return; } // record the event times if ( NumEvents < MAX_EVENTS ) { EventTimes[NumEvents++] = time; } if ( !down ) { if ( NumEvents == 2 ) { // the button was held longer than a double-tap time, but came up before the long-press time if ( time - EventTimes[0] > DoubleTapTime ) { // returning a short-press here allows a kinda-long-press to act as a short press, which // is fairly annoying if the user is just trying to abort a long press before the menu appears. //PendingEvent = KEY_EVENT_SHORT_PRESS; PendingEvent = KEY_EVENT_UP; return; } else { // coming up for the first time PendingEvent = KEY_EVENT_UP; return; } } } else { // key going down if ( NumEvents == 1 && repeatCount == 0 ) { PendingEvent = KEY_EVENT_DOWN; // initial down event return; } if ( NumEvents == 3 ) // second down event { if ( time - EventTimes[0] <= DoubleTapTime ) { Reset(); PendingEvent = KEY_EVENT_DOUBLE_TAP; return; } } } PendingEvent = KEY_EVENT_NONE; }