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.

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()
