--[[
`CameraWrapper` notifies the Wwise Audio, Scatter and Terrain systems of the Camera's
location, and is used in conjunction with the `WorldWrapper` and `LevelWrapper`
to allow for automatic rendering of active cameras and the `Get Active Camera` and
`Set Active Camera` flow nodes.
]]--
Appkit = Appkit or {}
require 'core/appkit/lua/class'
local ComponentManager = require 'core/appkit/lua/component_manager'
Appkit.CameraWrapper = Appkit.class(Appkit.CameraWrapper)
local CameraWrapper = Appkit.CameraWrapper
local CameraModule = stingray.Camera
local Unit = stingray.Unit
local Matrix4x4 = stingray.Matrix4x4
local Vector3 = stingray.Vector3
local Level = stingray.Level
-- Check if listeners/observers are available
local USE_TIMPANI = false
if stingray.World.timpani_world then USE_TIMPANI = true end
local USE_WWISE = false
if stingray.Wwise then USE_WWISE = true end
local USE_SCATTER_SYSTEM = false
if stingray.ScatterSystem then USE_SCATTER_SYSTEM = true end
local USE_TERRAIN_DECORATOR = false
if stingray.TerrainDecoration then USE_TERRAIN_DECORATOR = true end
ComponentManager.give_manager(CameraWrapper, ComponentManager.update_post_world)
function CameraWrapper.refresh_enabled_cameras()
-- making use of component manager list.
local manager = CameraWrapper.manager
for _, component_wrapper in pairs(manager.components) do
local camera_wrapper = component_wrapper[1]
if camera_wrapper.is_enabled == true then
local world_wrapper = Appkit.managed_world
if world_wrapper and world_wrapper.world == camera_wrapper.world then
world_wrapper:set_camera_enabled(camera_wrapper.camera, camera_wrapper.unit, true)
end
end
end
end
function CameraWrapper:init(entity, unit, camera_index)
self.entity = entity -- object this component is associated with, can be used to access other components
self.unit = unit
self.camera = Unit.camera(unit, camera_index)
self.world = Unit.world(unit)
self.is_enabled = false
self.is_wwise_listener_enabled = true
if USE_TERRAIN_DECORATOR then
self.terrain_decorator = nil
if self.world then
self.terrain_decorator = stingray.TerrainDecoration.create_observer(self.world, stingray.Vector3(0,0,0))
end
end
if USE_SCATTER_SYSTEM then
self.scatter_system = stingray.World.scatter_system(self.world)
self.scatter_observer = nil
if self.scatter_system then
self.scatter_observer = stingray.ScatterSystem.make_observer(self.scatter_system, stingray.Vector3(0,0,0))
end
end
CameraWrapper.manager:add_component(entity, self, Unit.level(unit))
end
function CameraWrapper:enable()
if self.enabled == true then return end
local world_wrapper = Appkit.managed_world
if world_wrapper and world_wrapper.world == self.world then
world_wrapper:set_camera_enabled(self.camera, self.unit, true)
self.is_enabled = true
end
end
function CameraWrapper:disable()
if self.enabled == false then return end
local world_wrapper = Appkit.managed_world
if world_wrapper and world_wrapper.world == self.world then
world_wrapper:set_camera_enabled(self.camera, self.unit, false)
end
self.is_enabled = false
end
function CameraWrapper:set_wwise_listener_enabled(enabled)
self.is_wwise_listener_enabled = enabled
end
function CameraWrapper:get_camera()
return self.camera
end
function CameraWrapper:world_pose()
return CameraModule.world_pose(self.camera, self.unit)
end
function CameraWrapper:world_position()
return CameraModule.world_position(self.camera, self.unit)
end
function CameraWrapper:world_rotation()
return CameraModule.world_rotation(self.camera, self.unit)
end
function CameraWrapper:set_local_pose(pose)
Unit.set_local_pose(self.unit, 1, pose)
CameraModule.set_local_pose(self.camera, self.unit, pose)
end
function CameraWrapper:set_local_position(position)
Unit.set_local_position(self.unit, 1, position)
CameraModule.set_local_position(self.camera, self.unit, position)
end
function CameraWrapper:set_local_rotation(rotation)
CameraModule.set_local_rotation(self.camera, self.unit, rotation)
end
function CameraWrapper:local_pose()
return CameraModule.local_pose(self.camera, self.unit)
end
function CameraWrapper:local_position()
return CameraModule.local_position(self.camera, self.unit)
end
function CameraWrapper:local_rotation()
return CameraModule.local_rotation(self.camera, self.unit)
end
local function update_observers(self, pose)
if USE_TIMPANI then
local tw = stingray.Unit.world(self.unit):timpani_world()
tw:set_listener(1, pose)
tw:set_listener_mode(1, stingray.TimpaniWorld.LISTENER_3D)
end
if self.is_wwise_listener_enabled and USE_WWISE then
local wwise_world = stingray.Wwise.wwise_world(self.world)
stingray.WwiseWorld.set_listener(wwise_world, stingray.Wwise.LISTENER_0, pose)
end
local pos = Matrix4x4.translation(pose)
if USE_TERRAIN_DECORATOR and self.terrain_decorator then
stingray.TerrainDecoration.move_observer(self.world, self.terrain_decorator, pos)
end
if USE_SCATTER_SYSTEM and self.scatter_observer then
stingray.ScatterSystem.move_observer(self.scatter_system, self.scatter_observer, pos)
end
end
-- component callback
function CameraWrapper:update(dt)
if not self.is_enabled then return end
-- Do not update if not an active world render camera
local world_wrapper = Appkit.managed_world
if world_wrapper then
camera, unit = world_wrapper:get_enabled_camera() -- Only 1 active camera supported at the moment in Appkit.
if camera ~= self.camera and unit ~= self.unit then
return
end
end
CameraModule.set_local_pose(self.camera, self.unit, Unit.local_pose(self.unit, 1))
update_observers(self, Unit.world_pose(self.unit, 1))
end
local function destroy(self)
if USE_TERRAIN_DECORATOR and self.terrain_decorator then
stingray.TerrainDecoration.destroy_observer(self.world, self.terrain_decorator)
self.terrain_decorator = nil
end
if USE_SCATTER_SYSTEM and self.scatter_observer then
stingray.ScatterSystem.destroy_observer(self.scatter_system, self.scatter_observer)
self.scatter_observer = nil
end
end
-- component callback
function CameraWrapper:on_level_shutdown()
end
-- component callback
function CameraWrapper:shutdown()
destroy(self)
end
return CameraWrapper