Interactive/RegionEnterCustom.py

##
# (C) Copyright 2012 Autodesk, Inc.  All rights reserved.
##
## Use of this software is subject to the terms of the Autodesk license
## agreement provided at the time of installation or download, or which
## otherwise accompanies this software in either electronic or hard copy
## form.
##

# You will need Autodesk Project Newport 0.46 or later.
#
 
#
# You will get a custom menu item in the context menu for the
# storyboard slides.  This will create a "enter region" trigger
# which will activate that slide whenever a camera enters the
# defined region.  If an object is selected at the time of creation
# the bounding box of that object will be used to define a region.
# Otherwise, a 10m x 10m x (-10m -> 100m) region will be defined
# centered at the current camera position.

__all__ = ['RegionEnterCustom', 'instantiate']

from MessageInterpreter        import MessageInterpreter
from UserCustomization         import UserCustomBase, CustomInfo
from GenericPopupMenu          import GenericPopupMenuItem

from SceneGraphUtilities       import ComputeBoundingBox, GetNodesFromIds
from awSupportApi              import Point, BoundingBox
from RTFapi                    import Id
from Trigger                   import Trigger

from XMLSaxData                import Data
from RtfXMLTags                import *

import ModelIO, NavigationIO


# Debugging only...
# from Utilities import __FILE__, __LINE__


class RegionEnter( UserCustomBase ):
    def __init__( self ):
        #UserCustomBase.__init__(self)
        self.__myInterpreter = LocalInterpreter()


    def getInterpreter( self, isInteractive ):
        return (self.__myInterpreter if isInteractive else None)


    def appendPopupMenuItems( self, id, popupMenu, item ):
        menuItem = None
        if "StoryboardSelector" == id:
            menuItem = GenericPopupMenuItem(_( 'Create region trigger'),
                                            self.__cbCustomStoryboard,
                                            item )

        if menuItem is not None:
            popupMenu.append( menuItem )


    def __cbCustomStoryboard( self, item ):
        if self.__myInterpreter:
            self.__myInterpreter.regionCreate( item.getId() )


class LocalInterpreter( MessageInterpreter ):

    def __init__( self ):
        MessageInterpreter.__init__( self )
        self.__myModels = None
        self.__myNavigators = None
        self.__myDocument = None


    def SET_DOCUMENT( self, message ):
        self.__myDocument, = message.data
        self.__myModels = self.__myDocument.get( ModelIO.id )
        self.__myNavigators = self.__myDocument.get( NavigationIO.id )


    def APPLICATION_CLOSE_SCENE( self, message ):
        self.__myModels = None
        self.__myNavigators = None
        self.__myDocument = None


    def regionCreate( self, slideId ):
        if self.__myModels is None or \
           self.__myNavigators is None:
            print "Invalid model or navigators"
            return

        if self.__myModels.selected:
            nodes = GetNodesFromIds( self.__myModels.selected )
            bb = ComputeBoundingBox( nodes )
        else:
            position = Point()
            self.__myNavigators.current.getPosition(position)
            minPos = Point( position[0] - 5.0, position[1] - 5.0, -10.0 )
            maxPos = Point( position[0] + 5.0, position[1] + 5.0,  100.0 )
            bb = BoundingBox( minPos, maxPos )

        minCorner = bb.getCorner(0)
        maxCorner = bb.getCorner(7)

        # Make it at least 50cm high...
        if (maxCorner[2] - minCorner[2]) < 0.5:
            maxCorner[2] = minCorner[2] + 0.5

        # Now, make a trigger:
        trigger = Trigger.createFromFile("RegionEnter",
                                         Id("Example") )
        value = "%f %f %f %f %f %f" % (minCorner[0], maxCorner[0],
                                       minCorner[1], maxCorner[1],
                                       minCorner[2], maxCorner[2])

        parData = Data( kTriggerParameterTag, () )
        parData.setAttribute( kTriggerParameterNameAttr, 'region' )
        parData.setAttribute( kTriggerParameterTypeAttr, 'string' )
        parData.setAttribute( kTriggerParameterValueAttr, value )
        trigger.addParameter( parData )

        targetInfo = { kTriggerTargetSlideNameAttr:slideId,
                       kTriggerTargetSlideActionAttr:'play' }
        trigger.addTargetSlide( targetInfo )

        trigger.initParameters()
        self.sendMessage( "ADD_TRIGGER", (trigger,) )


def instantiate():
    return RegionEnter()


def info():
    customInfo = CustomInfo()
    customInfo.vendor = 'Autodesk'
    customInfo.version = '1.0'
    customInfo.api = '2013'
    customInfo.shortInfo = "Create an enter-region trigger to activate a slide."
    customInfo.longInfo = \
"""A custom menu item is added in the context menu for the storyboard slides, which will \
create an "enter region" trigger which will activate that slide whenever a camera enters \
the defined region. If an object is selected at the time of creation the bounding box of \
that object will be used to define a region. Otherwise, a 10m x 10m x (-10m -> 100m) \
region will be defined centered at the current camera position.
"""
    return customInfo