Hacking around with Google Blockly and Blender. Blockly inside of Blender could be useful for game play scripting and other things. At the moment this is just a proof of concept how to get WebKit and Blockly to load inside of Blender and have simple two-way communication.
This hack is standalone, and already includes Blender2.63 compiled by natewiebe13 from Graphicall.org. To get this running, all you need to do is: "sudo apt-get install libwebkitgtk-3.0-dev" download hereHello World Source Code
import bpy
def myprocedure():
'''
user defined function, in blockly just define an empty function,
and give it the name "myprocedure"
'''
bpy.ops.mesh.primitive_monkey_add()
###############################################
import os, sys, time, ctypes
sys.path.append( os.path.abspath('.') )
import webkitgtk as webkit
import Blender # brett's ctypes wrapper to libblender
gtk = glib = webkit # webkit links to gtk and glib
gtk.init()
def get_html():
dom = view.get_dom_document()
html = webkit.dom_html_element_get_inner_html( dom )
return html
def call_javascript( script ):
'''
this won't work because it kills newlines!
view.execute_script('document.title=%s;' %script)
'''
view.execute_script(
"document.getElementsByTagName('text_hack')[0].setAttribute('x',%s);"%script
)
result = get_html()
result = result.split('text_hack x="')[-1]
result = result.split('"')[0]
return result
def hack_code( script ):
'''
need to hack the script a bit, blockly generates python2,
and blender needs python3!
'''
a = []
for line in script.splitlines():
if "print '" in line:
line = line.replace("print '", "print('") + ')'
if line == 'null': continue # blockly bug?
elif line.strip() == 'passnull': # check for an undefined function and remove it
a.pop()
continue
a.append(line)
script = '\n'.join(a)
print('----------- python code -------------')
print(script)
return script
def execute_python( script ):
script = hack_code( script )
print('----------- exec python code -------------')
exec( script )
################### WebKitGTK ####################
view = webkit.webkit_web_view_new()
print(view)
settings = webkit.web_settings_new()
for prop in 'enable-webaudio enable-file-access-from-file-uris enable-universal-access-from-file-uris enable-developer-extras enable-accelerated-compositing enable-webgl'.split():
gval = glib.GValue(True)
glib.g_object_set_property( settings, prop, gval )
view.set_settings( settings )
view.load_uri( 'file://%s/test-blockly.html'%os.path.abspath('.'))
win = gtk.Window()
root = gtk.VBox()
win.add( root )
header = gtk.HBox()
root.pack_start( header, expand=False )
button = gtk.Button('print html')
button.connect('clicked', lambda b: get_html() )
header.pack_start( button, expand=False )
header.pack_start( gtk.Label() )
button = gtk.Button('print python')
button.connect('clicked', lambda b: hack_code(call_javascript("Blockly.Generator.workspaceToCode('Python')")) )
header.pack_start( button, expand=False )
button = gtk.Button('run python')
button.connect('clicked', lambda b: execute_python(call_javascript("Blockly.Generator.workspaceToCode('Python')")) )
header.pack_start( button, expand=False )
root.pack_start( view, expand=True )
win.set_default_size( 800, 600 )
win.show_all()
class BlenderHack(object):
def update_gtk(self, region):
while gtk.gtk_events_pending():
gtk.gtk_main_iteration()
def setup_blender_hack(self, context):
self._sync_hack_handles = {} # region : handle
self.default_blender_screen = context.screen.name
self.evil_C = Blender.Context( context )
for area in context.screen.areas:
if area.type == 'VIEW_3D':
for reg in area.regions:
if reg.type == 'WINDOW':
handle = reg.callback_add( self.update_gtk, (reg,), 'POST_PIXEL' )
self._sync_hack_handles[ reg ] = handle
return self._sync_hack_handles
def mainloop(self):
self.active = True
while self.active:
screen = bpy.data.screens[ self.default_blender_screen ]
## force a redraw on the 3d view
for area in screen.areas:
if area.type == 'VIEW_3D':
for reg in area.regions:
if reg.type == 'WINDOW':
reg.tag_redraw()
break
## iterate blender's mainloop from ctypes
Blender.iterate( self.evil_C )
time.sleep(0.01)
hack = BlenderHack()
hack.setup_blender_hack( bpy.context )
hack.mainloop()
print('exit to normal blender mainloop')