wxBlenderPlayer a player for wxPython

Game Engine, Players & Web Plug-in, Virtual Reality, support for other engines

Moderators: jesterKing, stiv

M.E.Farmer
Posts: 3
Joined: Fri Mar 14, 2003 5:02 am
Location: USA

wxBlenderPlayer a player for wxPython

Postby M.E.Farmer » Sun Mar 16, 2003 10:11 am

Hello all.
I am releasing a script I have had for a while, it shows how to integrate the ActiveX web plugin into a wxPython program (Windows only).
Fairly simple and straight forward, more of an example how to do it than anything . That said, it is pretty darn fast ..faster than the web browser for sure but no hyperlinking ...Oh yea it is fairly trivial to make this fullscreen too .
wxPython comes with joystick support so I am going to try to interface it with the plugin...Just dont know how yet! Hope this helps someone.
:wink:

Code: Select all

#wxBlenderPlayer.py
##################################################################################################
# Windows only! Sorry Linux!
"""wxBlenderPlayer by M.E.Farmer Jr. 2002
   This is the begining of a Blender 3D Plug-in ActiveX Control
   module\widget for wxPython so it can easily be used in your own wxPython programs.
   Originally written in 2002 it has sat dormant on my hard drive forgotten for a year.
   When I annonced it on the old website someone asked me
   if I was trying to make Nan go bankcrupt.
   Although they said it jokingly I figured I would not release it ...
   But they did go bankcrupt and it wasn't even my fault!
   So here it is, hope you find it useful.
   I have stalled on it and never finished it, so much work left to do....
   but I only program in my _spare time_ so bills come first ;)
   Released to the public 03/2003 M.E.Farmer
"""
##################################################################################################
# Can view local and internet based .Blend files
#
# Requirements:
#  Either:
#      ActivePython                            (http://www.activestate.com/Products/ActivePython/)
#  Or:
#      Python 2.0 or higher :                  (http://www.Python.org)
#      Mark Hammonds win32 extensions          (http://starship.python.net/crew/mhammond/)
#  Also:
#      wxPython : a cross platform gui toolkit (http://www.wxPython.org)
#      BlenderPlugin  : ActiveX version        (http://www.blender.org)
#      Windows 95 or higher:                   (http://Microsoft.com)
##################################################################################################

#This section is sensitive only change values if you know what your doing.
#If you want to tweak things and change up stuff goto the GUI section below.

##################################################################################################
# This section created by makepy.py version 0.4.0
# By python version 2.1.1 (#20, Jul 26 2001, 11:38:51) [MSC 32 bit (Intel)]
# From type library 'BLENDER3DPLUGIN.OCX'
# On Sat May 25 02:52:04 2002

makepy_version = '0.4.0'
python_version = 0x20101f0

import win32com.client.CLSIDToClass, pythoncom

# The following 3 lines may need tweaking for the particular server
# Candidates are pythoncom.Missing and pythoncom.Empty
defaultNamedOptArg=pythoncom.Missing
defaultNamedNotOptArg=pythoncom.Missing
defaultUnnamedArg=pythoncom.Missing

CLSID = pythoncom.MakeIID('{B7A2076C-3DD8-4F9D-9D76-5FE71ECC0EF1}')
MajorVersion = 1
MinorVersion = 0
LibraryFlags = 10
LCID = 0x0

from win32com.client import DispatchBaseClass

class _DBlenderPlayer(DispatchBaseClass):
    """Dispatch interface for Blender 3D Plug-in Active X Control"""
    CLSID = pythoncom.MakeIID('{75BE7171-64C0-4125-99A8-1AE50EA49D6C}')

    def AboutBox(self):
        return self._oleobj_.InvokeTypes(0xfffffdd8, LCID, 1, (24, 0), (),)

    def Rewind(self):
        return self._oleobj_.InvokeTypes(0x8, LCID, 1, (24, 0), (),)

    def SendMessage(self, to=defaultNamedNotOptArg,
                      From=defaultNamedNotOptArg,
                      subject=defaultNamedNotOptArg,
                      message=defaultNamedNotOptArg):

        return self._oleobj_.InvokeTypes(0x9, LCID, 1, (11, 0),
                                         ((8, 0), (8, 0), (8, 0), (8, 0)),
                                         to, From, subject, message)

    _prop_map_get_ = {
            "BackColor": (-501, 2, (19, 0), (), "BackColor", None),
            "ForeColor": (-513, 2, (19, 0), (), "ForeColor", None),
            "blenderURL": (3, 2, (8, 0), (), "blenderURL", None),
            "frameRate": (6, 2, (2, 0), (), "frameRate", None),
            "loadingURL": (5, 2, (8, 0), (), "loadingURL", None),
            "showFrameCount": (1, 2, (11, 0), (), "showFrameCount", None),
            "showProfileInfo": (2, 2, (11, 0), (), "showProfileInfo", None),
            "showProperties": (4, 2, (11, 0), (), "showProperties", None),
            "useFileBackColor": (7, 2, (11, 0), (), "useFileBackColor", None),
    }
    _prop_map_put_ = {
            "BackColor" : ((-501, LCID, 4, 0),()),
            "ForeColor" : ((-513, LCID, 4, 0),()),
            "blenderURL" : ((3, LCID, 4, 0),()),
            "frameRate" : ((6, LCID, 4, 0),()),
            "loadingURL" : ((5, LCID, 4, 0),()),
            "showFrameCount" : ((1, LCID, 4, 0),()),
            "showProfileInfo" : ((2, LCID, 4, 0),()),
            "showProperties" : ((4, LCID, 4, 0),()),
            "useFileBackColor" : ((7, LCID, 4, 0),()),
    }

class _DBlenderPlayerEvents:
    "Event interface for Blender 3D Plug-in Active X Control"
    CLSID = CLSID_Sink = pythoncom.MakeIID('{7990FCE5-09A6-4E39-94B6-3E470ED5C22A}')
    _public_methods_ = [] # For COM Server support
    _dispid_to_func_ = {
            }

    def __init__(self, oobj = None):
        if oobj is None:
            self._olecp = None
        else:
            import win32com.server.util
            from win32com.server.policy import EventHandlerPolicy
            cpc=oobj._oleobj_.QueryInterface(pythoncom.IID_IConnectionPointContainer)
            cp=cpc.FindConnectionPoint(self.CLSID_Sink)
            cookie=cp.Advise(win32com.server.util.wrap(self, usePolicy=EventHandlerPolicy))
            self._olecp,self._olecp_cookie = cp,cookie
    def __del__(self):
        try:
            self.close()
        except pythoncom.com_error:
            pass
    def close(self):
        if self._olecp is not None:
            cp,cookie,self._olecp,self._olecp_cookie = self._olecp,self._olecp_cookie,None,None
            cp.Unadvise(cookie)
    def _query_interface_(self, iid):
        import win32com.server.util
        if iid==self.CLSID_Sink: return win32com.server.util.wrap(self)

    # Handlers for the control
    # If you create handlers, they should have the following prototypes:

class CoClassBaseClass:
    def __init__(self, oobj=None):
        if oobj is None: oobj = pythoncom.new(self.CLSID)
        self.__dict__["_dispobj_"] = self.default_interface(oobj)
    def __repr__(self):
        return "<win32com.gen_py.%s.%s>" % (__doc__, self.__class__.__name__)

    def __getattr__(self, attr):
        d=self.__dict__["_dispobj_"]
        if d is not None: return getattr(d, attr)
        raise AttributeError, attr
    def __setattr__(self, attr, value):
        if self.__dict__.has_key(attr): self.__dict__[attr] = value; return
        try:
            d=self.__dict__["_dispobj_"]
            if d is not None:
                d.__setattr__(attr, value)
                return
        except AttributeError:
            pass
        self.__dict__[attr] = value

# This CoClass is known by the name 'BLENDERPLAYER.BlenderPlayerCtrl.1'
class BlenderPlayer(CoClassBaseClass): # A CoClass
    # Blender 3D Plug-in Active X Control
    CLSID = pythoncom.MakeIID("{5DB05CB8-7751-469D-A1DD-45C8C201C013}")
    coclass_sources = [
            _DBlenderPlayerEvents,
    ]
    default_source = _DBlenderPlayerEvents
    coclass_interfaces = [
            _DBlenderPlayer,
    ]
    default_interface = _DBlenderPlayer

RecordMap = {
}

CLSIDToClassMap = {
        '{7990FCE5-09A6-4E39-94B6-3E470ED5C22A}' : _DBlenderPlayerEvents,
        '{5DB05CB8-7751-469D-A1DD-45C8C201C013}' : BlenderPlayer,
        '{75BE7171-64C0-4125-99A8-1AE50EA49D6C}' : _DBlenderPlayer,
}
CLSIDToPackageMap = {}
win32com.client.CLSIDToClass.RegisterCLSIDsFromDict( CLSIDToClassMap )
VTablesToPackageMap = {}
VTablesToClassMap = {
}


VTablesNamesToCLSIDMap = {
}
######################################################################################
#GUI code for the player.Change at will..... :)
######################################################################################
from wxPython.wx import *
from wxPython.lib.activexwrapper import MakeActiveXClass

class PlayerPanel(wxWindow):
    def __init__(self, parent, frame=None):
        wxWindow.__init__(self, parent, -1, style=wxCLIP_CHILDREN)
        self.Plug = None
        self.frame = frame
        sizer = wxBoxSizer(wxVERTICAL)
        btnSizer = wxBoxSizer(wxHORIZONTAL)

        # old sample area No longer exist but left for historical purposes.
        #http://www.blender3d.com/3DInAction/gallery/plugins/XXXX.blend

        # new sample area
        #http://www.blender3d.org/_media/gallery/3dwebplugin/XXXX.blend
        # If you want to add more or change the list do it here.
        Location = ['http://www.blender3d.org/_media/gallery/3dwebplugin/Radiosity.blend',
                    'http://www.blender3d.org/_media/gallery/3dwebplugin/skategirl.blend',
                    'http://www.blender3d.org/_media/gallery/3dwebplugin/haloparty.blend',
                    'http://www.blender3d.org/_media/gallery/3dwebplugin/Nevaeh.blend',
                    'http://www.blender3d.org/_media/gallery/3dwebplugin/SkategirlMovie.blend',
                    'http://www.blender3d.org/_media/gallery/3dwebplugin/Colorcubes.blend']
        # Make a new class that derives from the BlenderPlayer class in the
        # COM module imported above.  This class also derives from wxWindow and
        # implements the machinery needed to integrate the two worlds.
        theXClass = MakeActiveXClass(BlenderPlayer, eventObj = self)
        # Create an instance of that class
        self.Plug = theXClass(self, -1, style=wxSUNKEN_BORDER)
        # Code for the buttons on the player
        btn = wxButton(self, wxNewId(), "About")
        EVT_BUTTON(self, btn.GetId(), self.OnAboutBox)
        btnSizer.Add(btn, 0, wxEXPAND|wxALL, 5)

        btn = wxButton(self, wxNewId(), "Restart")
        EVT_BUTTON(self, btn.GetId(), self.OnRewind)
        btnSizer.Add(btn, 0, wxEXPAND|wxALL, 5)

        btn = wxButton(self, wxNewId(), "Properties")
        EVT_BUTTON(self, btn.GetId(), self.OnProperties)
        btnSizer.Add(btn, 0, wxEXPAND|wxALL, 5)

        txt = wxStaticText(self, -1, "Location:")
        btnSizer.Add(txt, 0, wxCENTER|wxALL, 5)
        self.location = wxComboBox(self, wxNewId(),
                               "Select an URL from the drop down list, or type in one here->",
                                wxPoint(-1,-1), wxSize(-1,-1), Location, style=wxCB_DROPDOWN)
        EVT_COMBOBOX(self, self.location.GetId(), self.OnLocationSelect)
        EVT_KEY_UP(self.location, self.OnLocationKey)
        btnSizer.Add(self.location, 1, wxEXPAND|wxALL, 5)
        #Player layout code. used to position buttons on top
        #and the activex control in the bottom.
        sizer.Add(btnSizer, 0, wxEXPAND)
        sizer.Add(self.Plug, 1, wxEXPAND)
        self.SetSizer(sizer)
        self.SetAutoLayout(true)
        #Sets an event handler for resizing the window when needed
        EVT_SIZE(self, self.OnSize)

    def OnSize(self, event):
        self.Layout()

    def OnLocationSelect(self, evt):
        """Gets the location fron the address bar
           when a selection is made in drop down list,
           and sends it to the control for loading.
        """
        url = self.location.GetStringSelection()
        self.Plug.blenderURL = url
        self.Plug.loadingURL = ""
        self.Plug.useFileBackColor = 1

    def OnLocationKey(self, evt):
        """Gets the location when entered,
           appends it to the drop down list,
           and then sends the URL to the
           control for loading.
           Skips if no enter is pressed.
        """
        if evt.KeyCode() == WXK_RETURN:
            URL = self.location.GetValue()
            self.location.Append(URL)
            self.Plug.blenderURL = URL
            self.Plug.useFileBackColor = 1
            self.Plug.loadingURL = ""
        else:
            evt.Skip()

    def OnAboutBox(self,event):
        """It even says Nan ;)"""
        self.Plug.AboutBox()

    def OnRewind(self, event):
        """Restart.....Rewind"""
        self.Plug.Rewind()

    def OnProperties(self, event):
        """Really just an example of how to do it
           this function acts like a toggle on or off
           for the values below"""
        if self.Plug.showProperties:
            self.Plug.showProperties = 0
            self.Plug.showFrameCount = 0
            self.Plug.showProfileInfo = 0
        else:
            self.Plug.showProperties = 1
            self.Plug.showFrameCount = 1
            #If you want to see it make it eqaul one not zero
            self.Plug.showProfileInfo = 0

if __name__ == '__main__':
    #All the top level code is here.
    class PlayerFrame(wxFrame):
        def __init__(self):
            wxFrame.__init__(self, None, -1, "wxBlenderPlayer--by M.E.Farmer Jr.",
                             size=(800, 600),
                             style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
            #self.CreateStatusBar()
            self.tp = PlayerPanel(self)
            self.SetBackgroundColour(wxBLACK)
           
            EVT_CLOSE(self, self.OnCloseWindow)

        def OnCloseWindow(self, event):
            self.Destroy()

    app = wxPySimpleApp()
    frame = PlayerFrame()
    frame.Show(true)
    app.MainLoop()

If you have everything in palce just cut copy and paste this into a text document and rename save as wxBlenderPlayer.py then click to run. :D

datura
Posts: 8
Joined: Sun Oct 13, 2002 7:41 pm
Location: Berlin
Contact:

Postby datura » Tue Mar 18, 2003 12:09 pm

hello !

that's a very nice script ! thank you very much.
i've got a questions about the eventhandling :

at the moment you can send messages to the
activeX-plugin (restart, properties, ...).

but i think, you can send messages
or events from the plugin to the GUI with the message-actuator
(host_application, load_url) too.

do you know, how to catch these events in the GUI ?

M.E.Farmer
Posts: 3
Joined: Fri Mar 14, 2003 5:02 am
Location: USA

Postby M.E.Farmer » Wed Mar 19, 2003 3:41 am

Hello all,
Datura thanks for your response!
The short answer is no.
I have not worked on that yet, and this is all I have right now.
The top part of the script with all the COM\win32 stuff is where you should probably look for inspiration, it is probably already thereI just dont know how to get at it yet.
I did not write that part it was automatically generated by makepy/pythonwin.
Your best bet would be to study Mark Hammonds documentation to learn what is wrapping the events and how to get at them.
Once you know that it should be easy. This is something I will read up on and try to help(if I can).
I would very interested to hear from you if you make any progress.
I could make joysticks and such work if I knew that.
I will post updates here. :P
Any COM/win32 pros out there?


Return to “Interactive 3d”

Who is online

Users browsing this forum: No registered users and 1 guest