require 'core/appkit/lua/class' GoogleVRSystem = Appkit.class(GoogleVRSystem) local Application = stingray.Application local Viewport = stingray.Viewport local World = stingray.World local Unit = stingray.Unit local Vector2 = stingray.Vector2 local Vector2Box = stingray.Vector2Box local Vector3 = stingray.Vector3 local Vector3Box = stingray.Vector3Box local Quaternion = stingray.Quaternion local QuaternionBox = stingray.QuaternionBox local Camera = stingray.Camera local GoogleVR = stingray.GoogleVR local Sensor = stingray.Sensor function GoogleVRSystem:init(world) if not GoogleVR then return end self._world = world self._is_initialized = false self._controller_api_status = 0 self._controller_connection_status = 0 self._controller_button_state = {} for i=0,6 do self._controller_button_state[i] = false end self._controller_touch_position = Vector2Box(0, 0) self._controller_orientation = QuaternionBox(0, 0, 0, 0) self._controller_gyroscope = Vector3Box(0, 0, 0) self._controller_acceleration = Vector3Box(0, 0, 0) end function GoogleVRSystem:initialize(near, far) if not GoogleVR then return end if not self then return end -- Intialize VR system self._is_initialized = GoogleVR.initialize() -- Bail if there was an error on initialization if not self._is_initialized then return end self._left_eye_fov = GoogleVR.eye_fov(GoogleVR.LEFT_EYE) self._right_eye_fov = GoogleVR.eye_fov(GoogleVR.RIGHT_EYE) -- Create left, right and blit cameras self._left_camera_unit = World.spawn_unit(self._world, "core/units/camera") self._right_camera_unit = World.spawn_unit(self._world, "core/units/camera") self._left_camera = Unit.camera(self._left_camera_unit , "camera") self._right_camera = Unit.camera(self._right_camera_unit, "camera") -- Create left, right and blit viewports if Appkit.Util.is_ios() then -- On iOS Metal we use a single viewport for both eyes self._viewport_left = Application.create_viewport(self._world, "vr_main") self._viewport_right = Application.create_viewport(self._world, "vr_main") else -- On Android and iOS OpenGL we use one viewport per eye self._viewport_left = Application.create_viewport(self._world, "vr_left") self._viewport_right = Application.create_viewport(self._world, "vr_right") end -- Create VR working window local size_x, size_y = Application.render_setting("vr_hmd_eye_resolution") local scale = Application.render_setting("vr_target_scale") Sensor.set_performance_hint("fast") Sensor.set_magnetometer_frequency(60) -- Setup Render Targets GoogleVR.setup_render_targets("vr_left_target", "vr_right_target") -- Initialize cameras Camera.set_projection_type(self._left_camera, Camera.PERSPECTIVE) Camera.set_projection_type(self._right_camera, Camera.PERSPECTIVE) Camera.set_near_range(self._left_camera, near) Camera.set_near_range(self._right_camera, near) Camera.set_far_range(self._left_camera, far) Camera.set_far_range(self._right_camera, far) Camera.set_frustum_half_angles( self._left_camera, self._left_eye_fov.left, self._left_eye_fov.right, self._left_eye_fov.down, self._left_eye_fov.up) Camera.set_frustum_half_angles( self._right_camera, self._right_eye_fov.left, self._right_eye_fov.right, self._right_eye_fov.down, self._right_eye_fov.up) GoogleVR.link_node_to_eye( self._left_camera_unit, Unit.node(self._left_camera_unit, "rp_root"), GoogleVR.LEFT_EYE, self._world) GoogleVR.link_node_to_eye( self._right_camera_unit, Unit.node(self._right_camera_unit, "rp_root"), GoogleVR.RIGHT_EYE, self._world) Application.set_render_setting("vr_enabled", "true") GoogleVR.show_ui_overlay() self.mag_i = 0 self.mag_buffer = {} self.mag_buffer_l = 8 self.mag_down = false self.mag_click = false for i=0,self.mag_buffer_l do self.mag_buffer[i] = Vector3Box(Vector3(0, 0, 0)) end end function GoogleVRSystem:shutdown() if not GoogleVR then return end if not self or not self._is_initialized then return end GoogleVR.unlink_eye(GoogleVR.LEFT_EYE) GoogleVR.unlink_eye(GoogleVR.RIGHT_EYE) GoogleVR.hide_ui_overlay() GoogleVR.shutdown() Application.set_render_setting("vr_enabled", "false") if self._left_camera_unit then self._left_camera = nil World.destroy_unit(self._world, self._left_camera_unit) self._left_camera_unit = nil end if self._right_camera_unit then self._right_camera = nil World.destroy_unit(self._world, self._right_camera_unit) self._right_camera_unit = nil end if self._viewport_left then Application.destroy_viewport(self._world, self._viewport_left) self._viewport_left = nil end if self._viewport_right then Application.destroy_viewport(self._world, self._viewport_right) self._viewport_right = nil end end function GoogleVRSystem:check_controller_status() if not Appkit.Util.is_android() then return end if not GoogleVR then return end if not self or not self._is_initialized then return end local new_api_status = GoogleVR.controller_api_status() if new_api_status ~= self._controller_api_status then print(GoogleVR.controller_api_status_string(new_api_status)) self._controller_api_status = new_api_status end local new_connection_status = GoogleVR.controller_connection_status() if new_connection_status ~= self._controller_connection_status then print(GoogleVR.controller_connection_status_string(new_connection_status)) self._controller_connection_status = new_connection_status end return (self._controller_api_status == GoogleVR.STATUS_API_OK) and (self._controller_connection_status == GoogleVR.STATUS_CONNECTED) end function GoogleVRSystem:print_button_state(button) if not GoogleVR then return end if not self or not self._is_initialized then return end local new_button_state = GoogleVR.controller_held(button) if new_button_state ~= self._controller_button_state[button] then if new_button_state then print("Button ", button, " Pressed") else print("Button ", button, " Released") end self._controller_button_state[button] = new_button_state end end function GoogleVRSystem:print_buttons_state() if not GoogleVR then return end if not self or not self._is_initialized then return end self.print_button_state(self, GoogleVR.BUTTON_CLICK) self.print_button_state(self, GoogleVR.BUTTON_APP) self.print_button_state(self, GoogleVR.BUTTON_HOME) self.print_button_state(self, GoogleVR.BUTTON_VOLUME_UP) self.print_button_state(self, GoogleVR.BUTTON_VOLUME_DOWN) end function GoogleVRSystem:print_touch_position() if not GoogleVR then return end if not self or not self._is_initialized then return end local new_touch_position = GoogleVR.controller_touch_position() local old_touch_position = Vector2Box.unbox(self._controller_touch_position) if not Vector2.equal(new_touch_position, old_touch_position) then print("Touch Position: ", new_touch_position) Vector2Box.store(self._controller_touch_position, new_touch_position) end end function GoogleVRSystem:print_orientation() if not GoogleVR then return end if not self or not self._is_initialized then return end local new_orientation = GoogleVR.controller_orientation() local old_orientation = QuaternionBox.unbox(self._controller_orientation) if not Quaternion.equal(new_orientation, old_orientation) then print("Orientation: ", new_orientation) QuaternionBox.store(self._controller_orientation, new_orientation) end end function GoogleVRSystem:print_gyroscope() if not GoogleVR then return end if not self or not self._is_initialized then return end local new_gyroscope = GoogleVR.controller_gyroscope() local old_gyroscope = Vector3Box.unbox(self._controller_gyroscope) if not Vector3.equal(new_gyroscope, old_gyroscope) then print("Gyroscope: ", new_gyroscope) Vector3Box.store(self._controller_gyroscope, new_gyroscope) end end function GoogleVRSystem:print_acceleration() if not GoogleVR then return end if not self or not self._is_initialized then return end local new_acceleration = GoogleVR.controller_acceleration() local old_acceleration = Vector3Box.unbox(self._controller_acceleration) if not Vector3.equal(new_acceleration, old_acceleration) then print("Acceleration: ", new_acceleration) Vector3Box.store(self._controller_acceleration, new_acceleration) end end function GoogleVRSystem:update_magnet_clicker() if not GoogleVR then return end if not self or not self._is_initialized then return end local v = Sensor.magnetometer_magnetic_field() Vector3Box.store(self.mag_buffer[self.mag_i % self.mag_buffer_l], v) self.mag_i = self.mag_i+1 local old = Vector3Box.unbox(self.mag_buffer[self.mag_i % self.mag_buffer_l]) local new_mag_down = self.mag_down; if self.mag_i > self.mag_buffer_l+2 then local diff = old-v; local thres = 10 local x = 0 local y = 0 local z = 0 if diff.x < -thres then x = 1 elseif diff.x > thres then x = -1 end if diff.y < -thres then y = -1 elseif diff.y > thres then y = 1 end if diff.z < -thres then z = 1 elseif diff.z > thres then z = -1 end local total = x+y+z if total >= 2 then new_mag_down = true elseif total <= -2 then new_mag_down = false end end self.mag_click = new_mag_down and self.mag_down ~= new_mag_down self.mag_down = new_mag_down return self.mag_click end function GoogleVRSystem:magnet_clicker() return self.mag_click end function GoogleVRSystem:set_tracking_space_pose(pose) if not GoogleVR then return end if not self or not self._is_initialized then return end GoogleVR.set_tracking_space_pose(pose) end function GoogleVRSystem:render(shading_environment) if not GoogleVR then return end if not self or not self._is_initialized then return end Application.set_render_setting("vr_eye", "left") Application.render_world(self._world, self._left_camera, self._viewport_left, shading_environment) Application.set_render_setting("vr_eye", "right") Application.render_world(self._world, self._right_camera, self._viewport_right, shading_environment) Application.set_render_setting("vr_eye", "unknown") end return GoogleVRSystem