Interactive/WebPageCustom.py

# (C) Copyright 2010 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.

# If objects have web pages as textures, go into this mode to interact
# with the pages.

# Unique ID, menu title, URL, resolution
kWhatToShow = (
    ("3d1", "Google", "http://www.google.com/", (1024,1024)),
    ("3d2", "Local", "http://localhost:5555/example.html", (256,256)),
    ("3d3", "Severin", "http://severin.wille.net/", (1024,1024)),
    ("3d4", "Autodesk", "http://www.autodesk.com/", (1024,1024)),
)

__all__ = ['WebPageCustom', 'instantiate']

from RTFapi              import Event, Appearance, Parameter, WebContainer
from SceneGraphUtilities import GetTextureIntersect
from awSupportUtilities  import StringToAffineMatrix
from awSupportApi        import Point
from MessageInterpreter  import MessageInterpreter
from ActionRegistry      import theActionRegistry
from ParameterConstant   import ParameterConstant
from RTFapi              import Id
from UserCustomization   import UserCustomBase, CustomInfo
from Application         import theApplication


kWebKeyMappingId = 'WebKeys'

class WebPageCustom (UserCustomBase):
    def __init__(self):
        self.__myWebMenu = None
        self.__myWebId = None
        self.__myMenus = {}
        self.__myInterpreter = LocalInterpreter()


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


    def appendMenuItems(self,id,menu):
        if "Appearance" == id:
            self.__myWebMenu = menu

            for (name,title,url,sz) in kWhatToShow:
                id = menu.appendItem( title, self.__onPageHit )
                self.__myMenus[id] = (name,url,sz)

            self.__myWebId = \
                        menu.appendCheckItem(_( 'Interact with page\tCtrl+Q' ),
                                             self.__onWebedObject )
            theActionRegistry.register( Event.BUTTON_q,
                                        (Event.BUTTON_Control, ),
                                        True,
                                        Event.BUTTONUP,
                                        'WebMode',
                                        'Global' )


    def enableMenuStates(self,id,enableStates):
        if "Appearance" == id:
            if self.__myInterpreter:
                enabled = self.__myInterpreter.Enabled()
            else:
                enabled = False
            for each in self.__myMenus.keys():
                enableStates[each] = enabled
            enableStates[self.__myWebId] = True


    def resetMenuStates(self, id):
        if "Appearance" == id:
            menuItemStates = {}
            menuItemStates[self.__myWebId] = False
            self.__myWebMenu.checkMenuItems(menuItemStates)

    # ------------------------------------------------
    def __onPageHit( self, event ):
        if self.__myInterpreter:
            (name,url,sz) = self.__myMenus[event.GetId()]
            self.__myInterpreter.PageHit(name,url,sz)

    def __onWebedObject( self, event ):
        isOn = bool(self.__myWebMenu.IsChecked(self.__myWebId))
        self.__myInterpreter.WebMode( isOn )


# -----------------------------------------------------------------------

class LocalInterpreter( MessageInterpreter ):

    def __init__( self ):
        MessageInterpreter.__init__( self )
        self.__myDisplay = None
        self.__myIsWebMode = False
        self.__myBrowserId = None

        #   Web key mappings.
        #
        keyMappings = (
          (Event.BUTTON_LMB,  (Event.BUTTON_Control,),
           True,  Event.BUTTONDOWN, "MyWebStart"),
          (Event.BUTTON_MMB,  (Event.BUTTON_Control,),
           True,  Event.BUTTONDOWN, "MyWebStop"),
          (Event.BUTTON_RMB,  (Event.BUTTON_Control,),
           True,  Event.BUTTONDOWN, "MyWebReset"),
        )
        theActionRegistry.registerList(kWebKeyMappingId, keyMappings)


    def __getMaterial( self, path ):
        material = None
        if path and len(path) > 0:
            node = path[0]
            if node is not None:
                app = node.getAppearance()
                if app is not None and app.get() is not None:
                    material = app.getMaterial()
        return material


    def __normalize(self, val):
        val0 = val.p[0]
        while (val0 > 1.0):
            val0 -= 1.0
        while (val0 < 0.0):
            val0 += 1.0
        val1 = val.p[1]
        while (val1 > 1.0):
            val1 -= 1.0
        while (val1 < 0.0):
            val1 += 1.0
        return val0,val1


    def __convertForParametric( self, material, uv ):
        p = material.getParameterByName( "diffuseUVMatrix" )
        if p is not None and p.get() is not None:
            st = p.getValueAsString()
            ms = StringToAffineMatrix(st)
            pnt = Point(uv[0],uv[1],0)
            res = Point(0,0,0)
            ms.preMult(res,pnt)
            (uv[0], uv[1]) = self.__normalize( res )
        return uv


    def __convertForProjected( self, material, point, proj ):
        p = material.getParameterByName( "diffuseProjMatrix" )
        if p is not None and p.get() is not None:
            st = p.getValueAsString()
            ms = StringToAffineMatrix(st)
            res = Point(0,0,0)
            ms.preMult(res,point)
            (u, v) = self.__normalize( res )
        return (u,v)


    def __getHit( self, event, modelRoot, display ) :
        '''
        Returns a list of nodes from the node that was clicked on,
        to the root node of the model.  Any one of these nodes
        could be associated with a light.
        '''
        x = event.getValue( Event.kNormalizedWinX )
        y = event.getValue( Event.kNormalizedWinY )
        intersector = display.createIntersector()
        intersector.intersect( x, y )

        return GetTextureIntersect( "diffuse", intersector, modelRoot )


    def MyWebStart(self, event ):
        self.MyWebDo(event, 1)


    def MyWebStop(self, event ):
        self.MyWebDo(event, 0)


    def MyWebReset(self, event ):
        self.MyWebDo(event, -1)


    def MyWebDo(self, event, startOrStopOrReset):
        '''
        Clicking on a web page
        '''
        if self.__myDisplay is None or \
           theApplication.getCurrentDocument().getModels() is None:
            return False

        # Find out which node (and its parents) was clicked on
        #
        uv, tex = self.__getHit(event, theApplication.getCurrentDocument().getModels().root, self.__myDisplay)
        if uv is not None:
            wc = WebContainer.instance()
            if tex is not None:
                id = Id(tex)
                br = wc.browser(id)
            if br is None:
                if self.__myBrowserId is not None:
                    br = wc.browser(self.__myBrowserId)
            if br is not None:
                br.mouseDownRel(uv[0],uv[1])
                br.mouseUpRel(uv[0],uv[1])

        return True


    def WebMode( self, isOn ):
        if self.__myDisplay and theApplication.getCurrentDocument().getModels() :
            if isOn != self.__myIsWebMode:
                self.__myIsWebMode = isOn
                if isOn :
                    theActionRegistry.addSetToStack(kWebKeyMappingId)
                else:
                    theActionRegistry.removeSetFromStack(kWebKeyMappingId)
            # Push key mappings to take over click
            theActionRegistry.activateSet( kWebKeyMappingId,
                                           self.__myIsWebMode )


    def APPLICATION_CLOSE_SCENE( self, message ) :
        self.WebMode( False )


    def SET_DOCUMENT( self, message ) :
        self.WebMode( False )


    def SET_DISPLAY( self, message ):
        ( self.__myDisplay, ) = message.data

    def PageHit( self, name, url, sz ):
        if theApplication.getCurrentDocument().getModels() is not None:
            self.Web( theApplication.getCurrentDocument().getModels().selected,
                      "mem:WEB:%s" % (name), url, sz )

    def Enabled( self ):
        return theApplication.getCurrentDocument().getModels() is not None \
           and not theApplication.getCurrentDocument().getModels().selected.empty()

    def Web( self, objects, name, web, sz ):
        wc = WebContainer.instance()
        br = None
        id = Id(name)
        br = wc.browser(id)
        if br is None:
            id = wc.createBrowser( name, sz[0], sz[1] )
        br = wc.browser(id)
        if br is not None:
            br.navigate( web )
            self.sendMessage( "APPEARANCE_PARAMETER_CHANGE",
                              (tuple(objects),
                               Appearance.kParameterCategoryMaterial,
                               ParameterConstant.kDiffuseTexture,
                               br.id().getFullId(), True, Parameter.kString) )

# --------------------------------------------------------------------

def instantiate():
    return WebPageCustom()

def info():
    customInfo = CustomInfo()
    customInfo.vendor = 'Autodesk'
    customInfo.version = '2.0'
    customInfo.api = '2013'
    customInfo.shortInfo = "Web textures manipulation."
    customInfo.longInfo = \
"""If objects have web pages as textures, go into this mode to interact with the pages.
"""
    return customInfo