Appkit: /camera_wrapper.lua — code sample - Stingray Lua API Reference

Appkit: /camera_wrapper.lua — code sample

Code

--[[

`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.

]]--

require 'core/appkit/lua/class'
require 'core/appkit/lua/app'
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