Python-Ogre Web Browser Plugin

dermont

22-02-2011 03:29:57

I was looking at implementing a web plugin for python-ogre, I see that Panda3D already has one.

As a first step I created a simple web plugin in C++ (Linux only) using firebreath to test whether it was feasible. It appears to work (most of the time), see the attached screen shot.

[attachment=0]Ogrefbreath.jpeg[/attachment]

http://code.google.com/p/firebreath/

It should therefore be feasible to run python scripts via either boost python / Python C. Since I probably won't be able to look at updating this till next week, does anyone have anything similar they are working on or better alternatives?

SirGolan

23-02-2011 16:31:28

That looks like a great start!

I was able to get Python-Ogre running in browser a while back using a pretty horrible hack. Basically, I used Panda3D's web plugin and handed Ogre its window handle. It actually worked pretty well, but it is definitely a hack.

I'd love to see something similar to Panda3D's plugin for Python-Ogre. That would be awesome!

Mike

dermont

24-02-2011 14:05:18

That looks like a great start!

I was able to get Python-Ogre running in browser a while back using a pretty horrible hack. Basically, I used Panda3D's web plugin and handed Ogre its window handle. It actually worked pretty well, but it is definitely a hack.
Mike

That's may not be as horrible a hack as you think and probably the way to go. Did your Python-Ogre application work as expected? Maybe you could post a simple demo for others?. It looks as if they put quite a bit of work into their plugin.

http://www.zixin.us/blog/game/41

Panda3D appears to have a vibrant community with a large number of active users/developers, whilst this forum is dead. I guess not too many people use Python-Ogre.

andrewmac

25-02-2011 02:57:31

I use it :) and I'm enjoying it very much. My guess is that most people don't post here because python-ogre is a wrapper, and it wraps up ogre so well that if you have any issues they are likely issues with using ogre not with python-ogre and those questions should be directed to the ogre community itself if I understand correctly.

SirGolan

25-02-2011 03:37:39

Did your Python-Ogre application work as expected?

Mostly. I had to do a lot of faking out mouse/keyboard events to get CEGUI and keyboard input to work, but it had the nice side effect of not locking the cursor to the Ogre window. :)

I also get the feeling that not a ton of people use Python-Ogre. Personally, I think more binary packages for various OSes would probably make it more accessible to people. It's really a great package, especially with all the extra wrapped libraries.

Here's what I have. It's very rough and hacky. I think it's hardcoded to 640x480, too. It is meant to work within MV3D, so the OgreWebRenderer class inherits from OgreRenderer, which is MV3D's wrapper to Ogre. Basically, I made this as a proof of concept to see that it could be done. But in the end, I decided to add Panda3D support to MV3D instead for cases where you wanted to play in a browser. One of the main reasons behind that was that the download for Ogre was too big for a casual in browser game.

Anyway, here's the code:


from ogre.renderer import OGRE as ogre
from ogre.io import OIS
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import WindowProperties
from mv3d.client.ui.ogre3d import OgreRenderer


class KeyEvent:
keyMap = {}

for letter in "abcdefghijklmnopqrstuvwxyz1234567890":
oiskey = getattr(OIS, "KC_%s" % letter.upper())
keyMap[letter] = oiskey
skeys = ["up", "down", "left", "right", "tab", "f1", "f2", "f3", "f4", "f5",
"f6", "f7", "f8", "f9", "f10", "f11", "f12", "escape", "minus",
"equals", "back", "tab", "lbracket", "rbracket", "return", "lcontrol",
"lshift", "rcontrol", "rshift", "semicolon", "apostrophe", "grave",
"backslash", "comma", "period", "slash", "multiply", "lmenu", "rmenu",
"space", "capital", "numlock", "scroll", "numpad0", "numpad1",
"numpad2", "numpad3", "numpad4", "numpad5", "numpad6", "numpad7",
"numpad8", "numpad9", "add", "decimal", "sysrq", "pause", "home",
"pgup", "pgdown", "delete", "insert", "lwin", "rwin", "end"]
for skey in skeys:
oiskey = getattr(OIS, "KC_%s" % skey.upper())
keyMap[skey] = oiskey

converter = dict(arrow_up="up", arrow_left="left", arrow_right="right",
arrow_down="down", print_screen="sysrq", page_up="pgup",
page_down="pgdown", num_lock="numlock", backspace="back")
converter["/"] = "slash"
converter[","] = "comma"
converter["."] = "period"
converter[";"] = "semicolon"
converter["'"] = "apostrophe"
converter["`"] = "grave"
converter["-"] = "minus"
converter["*"] = "multiply"
converter["="] = "equals"
converter[" "] = "space"

def __init__(self, key):
if len(key) == 1:
self.text = ord(key)
else:
self.text = 0
self.key = self.keyMap.get(key, self.keyMap.get(
self.converter.get(key, ""), None))
if self.key is None:
print "Unknown key", key


class KeyCatcher(DirectObject):
callback = None
singleKeys = "abcdefghijklmnopqrstuvwxyz1234567890`-=[]\;',./ "
multiKeys = ("escape", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
"f10", "f11", "f12", "print_screen" "scroll_lock", "backspace",
"insert", "home", "page_up", "num_lock", "tab", "delete", "end",
"page_down", "caps_lock", "enter", "arrow_left", "arrow_up",
"arrow_down", "arrow_right", "shift", "lshift", "rshift", "control",
"alt", "lcontrol", "lalt", "space", "ralt", "rcontrol")
allKeys = list(singleKeys) + list(multiKeys)


def __init__(self):
for key in self.allKeys:
self.addKey(key)


def addKey(self, key):
self.accept(key, lambda: self.gotKey(key, True))
self.accept(key + "-up", lambda: self.gotKey(key, False))


def setEventCallback(self, callback):
self.callback = callback


def capture(self):
pass


def gotKey(self, key, isKeyDown):
event = KeyEvent(key)
if event.key is None or self.callback is None:
return
if isKeyDown:
self.callback.keyPressed(event)
else:
self.callback.keyReleased(event)


def isModifierDown(self, *_args):
return False



class Position:
def __init__(self, abs_, rel):
self.abs = abs_
self.rel = rel


def __str__(self):
return "a: %d r: %d" % (self.abs, self.rel)



class MouseEvent:
def __init__(self, lastPos=None, buttons=0):
mpos = base.win.getPointer(0) # get the mouse position
if lastPos is None:
self.X = Position(mpos.getX(), mpos.getX() - 320)
self.Y = Position(mpos.getY(), mpos.getY() - 240)
else:
self.X = Position(mpos.getX(), mpos.getX() - lastPos.getX())
self.Y = Position(mpos.getY(), mpos.getY() - lastPos.getY())
self.Z = Position(0, 0)
self.modifiers = (False, False, False)
self.width = 640
self.height = 480


def get_state(self):
return self



class MouseCatcher(DirectObject):
lastPos = None
callback = None

def __init__(self, *args, **kw):
DirectObject.__init__(self, *args, **kw)
self.accept("mouse1", lambda: self.mouse(0, True))
self.accept("mouse1-up", lambda: self.mouse(0, False))
self.accept("mouse2", lambda: self.mouse(1, True))
self.accept("mouse2-up", lambda: self.mouse(1, False))
self.accept("mouse3", lambda: self.mouse(2, True))
self.accept("mouse3-up", lambda: self.mouse(2, False))
self.buttons = 0


def setEventCallback(self, callback):
self.callback = callback
self.lastPos = None


def capture(self):
if base.win.getPointer(0).getInWindow():
event = MouseEvent(self.lastPos)
self.callback.mouseMoved(event)
self.lastPos = base.win.getPointer(0)


def mouse(self, button, direction):
if self.callback is None:
return
buttonbit = 2 ** button
if direction:
self.buttons += buttonbit
else:
self.buttons -= buttonbit
event = MouseEvent(self.lastPos, self.buttons)
if direction:
self.callback.mousePressed(event, button)
else:
self.callback.mouseReleased(event, button)


def getMouseState(self):
return self #exceptions.AttributeError: MouseCatcher instance has no attribute 'getMouseState'



class OgreWebRenderer(OgreRenderer):

def initialize(self, displayconfig=None, openwindow=True, logPath=""):
"""
Initialize the renderer.
"""
OgreRenderer.initialize(self, displayconfig, False, logPath)
dims = self.config.get("Graphics", "resolution")
width = int(dims.split("x")[0])
height = int(dims.split("x")[1])

renderParameters = ogre.NameValuePairList()
win = base.win.getWindowHandle().getOsHandle().getIntHandle()
parentWin = WindowProperties.getDefault().getParentWindow()
renderParameters['externalWindowHandle'] = str(win)
renderParameters["externalGLControl"] = "true"
renderWindow = self.root.createRenderWindow(
'wxPython render window %s' % self, width, height, False,
renderParameters)
renderWindow.active = True
self.renderWindow = renderWindow
self.camera = self.sceneManager.createCamera(
'PlayerCam')
self.camera.setPosition (0, 0, 500)
self.camera.lookAt((0, 0, -300))
self.camera.setNearClipDistance(0.01)
self.viewport = self.renderWindow.addViewport(
self.camera)
self.viewport.backgroundColour = ogre.ColourValue(0, 0, 0)
self.imsys = OIS.createPythonInputSystem(
[("WINDOW", str(int(str(parentWin), 16))),
("w32_mouse", "DISCL_FOREGROUND"),
("w32_mouse", "DISCL_NONEXCLUSIVE"),
("w32_keyboard", "DISCL_FOREGROUND"),
("w32_keyboard", "DISCL_NONEXCLUSIVE")])
try:
self.keyboard = self.imsys.createInputObjectKeyboard(
OIS.OISKeyboard, True)
except RuntimeError:
self.keyboard = KeyCatcher()
try:
self.mouse = self.imsys.createInputObjectMouse(
OIS.OISMouse, True)
mstate = self.mouse.getMouseState()
ss = self.getScreenDimensions()
mstate.width = ss[0]
mstate.height = ss[1]
mstate.X.abs = ss[0] / 2
mstate.Y.abs = ss[1] / 2
except RuntimeError:
self.mouse = MouseCatcher()

ogre.WindowEventUtilities.addWindowEventListener(self.renderWindow,
self)
self.run = True
return True

andrewmac

25-02-2011 03:55:38

I also get the feeling that not a ton of people use Python-Ogre. Personally, I think more binary packages for various OSes would probably make it more accessible to people. It's really a great package, especially with all the extra wrapped libraries.

It could have something to with the fact that most game programmers use windows and the .NET languages are more popular in windows than python is. So the python-ogre wrapper appeals a lot more to linux users, however if you're a programmer and you use linux more often than not you're experienced in C++.