commit
19eceac3f9
44 changed files with 5846 additions and 0 deletions
@ -0,0 +1,152 @@ |
|||||||
|
|
||||||
|
SERVER_URL="http://volta:8080/do_request"; |
||||||
|
UPLOAD_URL="http://volta:8080/do_upload"; |
||||||
|
|
||||||
|
function refreshStatus() { |
||||||
|
|
||||||
|
$.ajax({ |
||||||
|
url: SERVER_URL, |
||||||
|
dataType: "json", |
||||||
|
type: "POST", |
||||||
|
data: JSON.stringify({"cmd": "getcurrentfilename"}), |
||||||
|
success: function(data) { |
||||||
|
$.blayerwebif.newFilename = data.currentfilename; |
||||||
|
if($.blayerwebif.oldFilename == $.blayerwebif.newFilename) |
||||||
|
return; |
||||||
|
$.blayerwebif.oldFilename = $.blayerwebif.newFilename; |
||||||
|
|
||||||
|
$("#tagtable").empty(); |
||||||
|
$("#tagtable").append("<tr><td>filename</td><td>"+$.blayerwebif.newFilename+"</td></tr"); |
||||||
|
$.ajax({ |
||||||
|
url: SERVER_URL, |
||||||
|
dataType: "json", |
||||||
|
type: "POST", |
||||||
|
data: JSON.stringify({"cmd": "getcurrentfileinfo"}), |
||||||
|
success: function(data) { |
||||||
|
$.each(data.currentfileinfo, function(key, value) { |
||||||
|
$("#tagtable").append("<tr><td>"+key+"</td><td>"+value+"</td></tr"); |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
function refreshFilenames() { |
||||||
|
$.ajax({ |
||||||
|
url: SERVER_URL, |
||||||
|
dataType: "json", |
||||||
|
type: "POST", |
||||||
|
data: JSON.stringify({"cmd": "getallfilenames"}), |
||||||
|
success: function(data) { |
||||||
|
$("#filenames").empty(); |
||||||
|
$.each(data.allfilenames, function(key, value) { |
||||||
|
//alert("<li><a href=\"#\" onClick=\"playNext(\\\""+value+"\\\")\">"+value+"</a></li>");
|
||||||
|
$("#filenames").append("<li><a href=\"#\" class=\"playNextLink\">"+value+"</a></li>"); |
||||||
|
|
||||||
|
}); |
||||||
|
$("#animationcount").text(data.allfilenames.length); |
||||||
|
$(".playNextLink").click(function() { |
||||||
|
linkNode = this; |
||||||
|
$.ajax({ |
||||||
|
url: SERVER_URL, |
||||||
|
dataType: "json", |
||||||
|
type: "POST", |
||||||
|
data: JSON.stringify({"cmd": "playnext", "filename": $(this).text()}), |
||||||
|
success: function(data) { |
||||||
|
if(data.playnext == "ok") |
||||||
|
item = $("<span class=\"notificationtext\">queued...</span>"); |
||||||
|
else |
||||||
|
item = $("<span class=\"notificationtext\">queue full :(</span>"); |
||||||
|
|
||||||
|
$(linkNode).after(item); |
||||||
|
$(item).delay(1000).fadeOut("slow"); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
function refreshStatusPeriodic() { |
||||||
|
refreshStatus(); |
||||||
|
setTimeout(refreshStatusPeriodic, 1000); |
||||||
|
} |
||||||
|
|
||||||
|
$(document).ready(function() { |
||||||
|
$.blayerwebif = {}; |
||||||
|
$.blayerwebif.oldFilename = ""; |
||||||
|
|
||||||
|
setTimeout(refreshStatusPeriodic, 1000); |
||||||
|
refreshFilenames(); |
||||||
|
refreshStatus(); |
||||||
|
|
||||||
|
$("#uploadbutton").click(function() { |
||||||
|
$.ajax({ |
||||||
|
url: UPLOAD_URL, |
||||||
|
type: "POST", |
||||||
|
beforeSend: function() { |
||||||
|
$("#uploadform").after("<span class=\"notificationtext\" id=\"uploadingnotification\">uploading...</span>"); |
||||||
|
}, |
||||||
|
success: function() { |
||||||
|
$("#uploadingnotification").text("done! :)").delay(1000).fadeOut("slow"); |
||||||
|
refreshFilenames(); |
||||||
|
}, |
||||||
|
error: function() { |
||||||
|
$("#uploadingnotification").text("failed! :(").delay(1000).fadeOut("slow"); |
||||||
|
}, |
||||||
|
contentType: false, |
||||||
|
cache: false, |
||||||
|
processData: false, |
||||||
|
data: new FormData($("#uploadform")[0]) |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
$("#next").click(function() { |
||||||
|
$.ajax({ |
||||||
|
url: SERVER_URL, |
||||||
|
dataType: "json", |
||||||
|
type: "POST", |
||||||
|
data: JSON.stringify({"cmd": "next"}), |
||||||
|
success: function() { |
||||||
|
refreshStatus(); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
$("#pause").click(function() { |
||||||
|
button = this; |
||||||
|
$.ajax({ |
||||||
|
url: SERVER_URL, |
||||||
|
dataType: "json", |
||||||
|
type: "POST", |
||||||
|
data: JSON.stringify({"cmd": "togglepaused"}), |
||||||
|
success: function(data) { |
||||||
|
refreshStatus(); |
||||||
|
|
||||||
|
if(data.paused) |
||||||
|
$(button).text("play"); |
||||||
|
else |
||||||
|
$(button).text("pause"); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
$("#filtertext").keyup(function() { |
||||||
|
keyword = $("#filtertext").val().toLowerCase(); |
||||||
|
$("#filenames li").each(function(key, value) { |
||||||
|
|
||||||
|
if($(value).children("a").text().toLowerCase().indexOf(keyword) >= 0) |
||||||
|
$(value).show(); |
||||||
|
else |
||||||
|
$(value).hide(); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
|
@ -0,0 +1,53 @@ |
|||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>blayer web interface</title> |
||||||
|
<script src="jquery.js" type="text/javascript"></script> |
||||||
|
<script src="blayerwebif.js" type="text/javascript"></script> |
||||||
|
|
||||||
|
<link rel="stylesheet" href="style.css" /> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
|
||||||
|
<div id="containerleft"> |
||||||
|
<div class="box"> |
||||||
|
<p class="boxhead">control</p> |
||||||
|
|
||||||
|
<p class="controlbuttons"> |
||||||
|
<a href="#" id="next">next</a> |
||||||
|
<a href="#" id="pause">play / pause</a> |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="box"> |
||||||
|
<p class="boxhead">upload</p> |
||||||
|
<form action="#" method="post" id="uploadform"> |
||||||
|
<input type="file" name="file" /> |
||||||
|
<input type="button" value="upload" id="uploadbutton" /> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="box"> |
||||||
|
<p class="boxhead">current animation</p> |
||||||
|
|
||||||
|
<!--<p><span class="label">Filename:</span><span id="filename"></span></p>--> |
||||||
|
|
||||||
|
<table id="tagtable"> |
||||||
|
</table> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div id="containerleft"> |
||||||
|
<div class="box"> |
||||||
|
<p class="boxhead">animation database</p> |
||||||
|
<p><span id="animationcount">###</span> animations in total</p> |
||||||
|
|
||||||
|
<p>filter: <input type="text" id="filtertext" /></p> |
||||||
|
|
||||||
|
<ul id="filenames"> |
||||||
|
</ul> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
</body></html> |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,87 @@ |
|||||||
|
body { |
||||||
|
background-color: #2f2f2f; |
||||||
|
font-family: "lucida grande",tahoma, verdana, sans-serif; |
||||||
|
font-size: 0.8em; |
||||||
|
color: #cccccc; |
||||||
|
} |
||||||
|
|
||||||
|
h1 { |
||||||
|
font-size: 1.5em; |
||||||
|
} |
||||||
|
|
||||||
|
#containerleft { |
||||||
|
width: 46%; |
||||||
|
margin-left: auto; |
||||||
|
padding: 20px; |
||||||
|
float: left; |
||||||
|
} |
||||||
|
#containerright { |
||||||
|
width: 46%; |
||||||
|
padding: 20px; |
||||||
|
float: left; |
||||||
|
} |
||||||
|
|
||||||
|
div.box { |
||||||
|
border-radius: 10px; |
||||||
|
border-color: #000000; |
||||||
|
border-width: 1px; |
||||||
|
border-style: solid; |
||||||
|
/*width: 50%;*/ |
||||||
|
background-color: #3d3d3d; |
||||||
|
margin: auto; |
||||||
|
margin-bottom: 30px; |
||||||
|
padding: 10px; |
||||||
|
box-shadow: 3px 3px 3px 3px #272727; |
||||||
|
} |
||||||
|
|
||||||
|
p.boxhead { |
||||||
|
color: #006483; |
||||||
|
font-weight: bold; |
||||||
|
margin-top: 0px; |
||||||
|
} |
||||||
|
|
||||||
|
#tagtable td:first-child { |
||||||
|
font-style: italic; |
||||||
|
padding-right: 30px; |
||||||
|
} |
||||||
|
#tagtable td { |
||||||
|
font-size: 0.8em; |
||||||
|
} |
||||||
|
|
||||||
|
#filenames a, #filenames a:visited { |
||||||
|
text-decoration: none; |
||||||
|
color: #cccccc; |
||||||
|
} |
||||||
|
|
||||||
|
.notificationtext { |
||||||
|
padding-left: 20px; |
||||||
|
color: #ffffff; |
||||||
|
font-size: 0.7em; |
||||||
|
} |
||||||
|
|
||||||
|
.controlbuttons { |
||||||
|
padding: 10px; |
||||||
|
} |
||||||
|
.controlbuttons a, .controlbutton a:visited { |
||||||
|
padding: 5px; |
||||||
|
border: 1px solid #cccccc; |
||||||
|
border-radius: 4px; |
||||||
|
color: #cccccc; |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
|
||||||
|
.controlbuttons a:hover { |
||||||
|
background: #006483; |
||||||
|
} |
||||||
|
|
||||||
|
.label { |
||||||
|
font-style: italic; |
||||||
|
} |
||||||
|
|
||||||
|
.clear { |
||||||
|
clear:both; |
||||||
|
width: 0px; |
||||||
|
height: 0px; |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@ |
|||||||
|
[control] |
||||||
|
bind_host = 0.0.0.0 |
||||||
|
bind_port = 4243 |
||||||
|
|
||||||
|
[player] |
||||||
|
animation_dir = /var/tmp/blup2/ |
||||||
|
playlist = /var/tmp/blup2/playlist.txt |
||||||
|
shuffle = true |
||||||
|
autorefresh = true |
||||||
|
looptime = 3 |
||||||
|
maxplaynext = 3 |
||||||
|
|
||||||
|
[output] |
||||||
|
output = blp:localhost:4242 |
||||||
|
#output = blp:bastel0:4242 |
||||||
|
#output = 'shell' |
||||||
|
|
@ -0,0 +1,428 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import threading |
||||||
|
import random |
||||||
|
import os.path |
||||||
|
import os |
||||||
|
import time |
||||||
|
import socket |
||||||
|
import asyncore |
||||||
|
import asynchat |
||||||
|
import cmd |
||||||
|
import ConfigParser |
||||||
|
import sys |
||||||
|
import json |
||||||
|
|
||||||
|
import blup.animation as Animation |
||||||
|
import blup.output as BlupOutput |
||||||
|
import blup.frame as Frame |
||||||
|
|
||||||
|
|
||||||
|
CONFIG_DEFAULTS = { |
||||||
|
'output': 'shell', |
||||||
|
'playlist': '', |
||||||
|
'animation_dir': '.', |
||||||
|
'enabled': False, |
||||||
|
'shuffle': False, |
||||||
|
'autorefresh': False |
||||||
|
} |
||||||
|
|
||||||
|
def find(f, list): |
||||||
|
for x in list: |
||||||
|
if f(x): |
||||||
|
return x |
||||||
|
|
||||||
|
class AnimationInfo(): |
||||||
|
def __init__(self, filename): |
||||||
|
self.__filename = filename |
||||||
|
self.__tags = None |
||||||
|
self.__valid = None |
||||||
|
|
||||||
|
@property |
||||||
|
def filesize(self): |
||||||
|
try: |
||||||
|
statinfo = os.stat(self.__filename) |
||||||
|
return statinfo.st_size |
||||||
|
except OSError: |
||||||
|
return -1 |
||||||
|
|
||||||
|
@property |
||||||
|
def mtime(self): |
||||||
|
try: |
||||||
|
statinfo = os.stat(self.__filename) |
||||||
|
return statinfo.st_mtime |
||||||
|
except OSError: |
||||||
|
return -1 |
||||||
|
|
||||||
|
@property |
||||||
|
def tags(self): |
||||||
|
return self.__tags |
||||||
|
|
||||||
|
@property |
||||||
|
def valid(self): |
||||||
|
if self.__valid == None: |
||||||
|
try: |
||||||
|
self.check() |
||||||
|
except Animation.AnimationFileError: |
||||||
|
pass |
||||||
|
return self.__valid |
||||||
|
|
||||||
|
@property |
||||||
|
def filename(self): |
||||||
|
return self.__filename |
||||||
|
|
||||||
|
def check(self): |
||||||
|
self.__valid = False |
||||||
|
self.__tags = None |
||||||
|
|
||||||
|
anim = Animation.load(self.__filename) |
||||||
|
|
||||||
|
self.__valid = True |
||||||
|
self.__tags = anim.tags |
||||||
|
|
||||||
|
|
||||||
|
class AnimationDatabase(): |
||||||
|
def __init__(self, animDir): |
||||||
|
self.__animDir = animDir |
||||||
|
self.__animInfos = [] |
||||||
|
self.__lock = threading.Lock() |
||||||
|
|
||||||
|
def update(self): |
||||||
|
with self.__lock: |
||||||
|
oldAnimInfos = self.__animInfos |
||||||
|
animInfos = [] |
||||||
|
|
||||||
|
for (dirpath, dirnames, filenames) in os.walk(self.__animDir): |
||||||
|
files = map(lambda f: os.path.join(dirpath, f), filenames) |
||||||
|
files = map(lambda f: os.path.relpath(os.path.join(dirpath, f), self.__animDir), filenames) |
||||||
|
animInfos.extend(map(lambda f: AnimationInfo(f), files)) |
||||||
|
#animInfos = filter(lambda a: a.valid, animInfos) |
||||||
|
|
||||||
|
newAnimInfos = [] |
||||||
|
for animInfo in animInfos: |
||||||
|
oldAnimInfo = find(lambda a: a.filename == animInfo.filename, oldAnimInfos) |
||||||
|
if oldAnimInfo is not None and oldAnimInfo.mtime == animInfo.mtime: |
||||||
|
newAnimInfos.append(oldAnimInfo) |
||||||
|
else: |
||||||
|
if animInfo.valid: |
||||||
|
newAnimInfos.append(animInfo) |
||||||
|
|
||||||
|
self.__animInfos = newAnimInfos |
||||||
|
|
||||||
|
def findAnimation(self, filename): |
||||||
|
with self.__lock: |
||||||
|
animInfo = find(lambda a: a.filename == filename, self.__animInfos) |
||||||
|
if animInfo is not None: |
||||||
|
return animInfo |
||||||
|
else: |
||||||
|
raise Exception('animation not found!') |
||||||
|
|
||||||
|
def containsAnimation(self, filename): |
||||||
|
with self.__lock: |
||||||
|
animInfo = find(lambda a: a.filename == filename, self.__animInfos) |
||||||
|
return (animInfo is not None) |
||||||
|
|
||||||
|
def getAllFilenames(self): |
||||||
|
with self.__lock: |
||||||
|
return map(lambda a: a.filename, self.__animInfos) |
||||||
|
|
||||||
|
|
||||||
|
#class Playlist(list): |
||||||
|
# def __init__(self, animationDatabase, filename=None): |
||||||
|
# self.__animDb = animationDatabase |
||||||
|
# self.__filename = filename |
||||||
|
# if filename == None: |
||||||
|
# self.append(self.__animDb.getAllFilenames()) |
||||||
|
# else: |
||||||
|
# f = open(filename, 'r') |
||||||
|
# lines = f.read().split('\n') |
||||||
|
# f.close() |
||||||
|
# |
||||||
|
# for line in lines: |
||||||
|
# if self.__animDb.containsAnimation(line): |
||||||
|
# self.append(line) |
||||||
|
# |
||||||
|
# def refresh(self): |
||||||
|
# #f = open(filename, 'r') |
||||||
|
# #lines = f.read().split('\n') |
||||||
|
# #f.close() |
||||||
|
# pass |
||||||
|
# |
||||||
|
# #for line in lines: |
||||||
|
# # if self.__animDb.containsAnimation(line): |
||||||
|
# # self.append(line) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerThread(threading.Thread): |
||||||
|
def __init__(self, database, output): |
||||||
|
threading.Thread.__init__(self) |
||||||
|
self.__playlist = [] |
||||||
|
self.database = database |
||||||
|
self.__playNext = [] |
||||||
|
self.maxPlayNext = 3 |
||||||
|
self.__output = output |
||||||
|
self.shuffle = False |
||||||
|
self.autoRefresh = True |
||||||
|
self.loopTime = 10 |
||||||
|
self.gap = 800 |
||||||
|
self.__running = False |
||||||
|
self.__player = Animation.AnimationPlayer() |
||||||
|
self.__currentIndex = 0 |
||||||
|
self.__currentFile = '' |
||||||
|
self.__paused = False |
||||||
|
|
||||||
|
@property |
||||||
|
def currentFile(self): |
||||||
|
if not self.__paused: |
||||||
|
return self.__currentFile |
||||||
|
else: |
||||||
|
return "" |
||||||
|
|
||||||
|
@property |
||||||
|
def currentFileInfo(self): |
||||||
|
if not self.__paused: |
||||||
|
return self.database.findAnimation(self.__currentFile) |
||||||
|
else: |
||||||
|
# TODO: mhh... |
||||||
|
return None |
||||||
|
|
||||||
|
@property |
||||||
|
def paused(self): |
||||||
|
return self.__paused |
||||||
|
|
||||||
|
def playNext(self, next): |
||||||
|
if len(self.__playNext) < self.maxPlayNext: |
||||||
|
self.__playNext.append(next) |
||||||
|
else: |
||||||
|
raise Exception |
||||||
|
|
||||||
|
def next(self): |
||||||
|
self.__player.stop() |
||||||
|
|
||||||
|
def togglePaused(self): |
||||||
|
self.__paused = not self.__paused |
||||||
|
if self.__paused: |
||||||
|
self.__player.stop() |
||||||
|
|
||||||
|
def refreshPlaylist(self): |
||||||
|
self.database.update() |
||||||
|
self.__playlist = self.database.getAllFilenames() |
||||||
|
|
||||||
|
def loadPlaylistFile(self): |
||||||
|
raise Exception('not yet implemented :(') |
||||||
|
|
||||||
|
def terminate(self): |
||||||
|
self.__player.stop() |
||||||
|
self.__running = False |
||||||
|
|
||||||
|
def run(self): |
||||||
|
self.__running = True |
||||||
|
while self.__running: |
||||||
|
anim = None |
||||||
|
if self.autoRefresh: # and self.__currentIndex == len(self.__playlist) - 1: |
||||||
|
self.refreshPlaylist() |
||||||
|
|
||||||
|
if len(self.__playNext) == 0: |
||||||
|
if len(self.__playlist) == 0: |
||||||
|
print 'busywait!!' |
||||||
|
continue |
||||||
|
|
||||||
|
if self.shuffle: |
||||||
|
self.__currentFile = self.__playlist[random.randint(0, len(self.__playlist) - 1)] |
||||||
|
else: |
||||||
|
if self.__currentIndex >= len(self.__playlist): |
||||||
|
self.__currentIndex = 0 |
||||||
|
self.__currentFile = self.__playlist[self.__currentIndex] |
||||||
|
self.__currentIndex += 1 |
||||||
|
else: |
||||||
|
self.__currentFile = self.__playNext.pop(0) |
||||||
|
anim = Animation.load(self.__currentFile) |
||||||
|
|
||||||
|
count = 1 |
||||||
|
if anim.tags.has_key('loop') and anim.tags['loop'].lower() in ['yes', 'true']: |
||||||
|
if anim.duration < self.loopTime * 1000: |
||||||
|
count = (self.loopTime * 1000) / anim.duration |
||||||
|
|
||||||
|
|
||||||
|
print 'playing:', anim |
||||||
|
print 'tags:', anim.tags |
||||||
|
self.__player.play(anim, self.__output, count=count) |
||||||
|
print 'elapsed: ', self.__player.elapsed |
||||||
|
|
||||||
|
if self.__paused: |
||||||
|
# TODO: use correct frame size |
||||||
|
self.__output.sendFrame(Frame.Frame(18,8)) |
||||||
|
while self.__paused: |
||||||
|
time.sleep(1) |
||||||
|
print 'busywait!!' |
||||||
|
|
||||||
|
if self.gap > 0 and self.__running: |
||||||
|
# TODO: use correct frame size |
||||||
|
self.__output.sendFrame(Frame.Frame(18,8)) |
||||||
|
time.sleep(self.gap / 1000.0) |
||||||
|
|
||||||
|
|
||||||
|
class PlayerControlClientHandler(asynchat.async_chat): |
||||||
|
def __init__(self, sock, player): |
||||||
|
asynchat.async_chat.__init__(self, sock=sock) |
||||||
|
self.set_terminator('\n') |
||||||
|
self.__buffer = '' |
||||||
|
self.__player = player |
||||||
|
|
||||||
|
def collect_incoming_data(self, data): |
||||||
|
self.__buffer += data |
||||||
|
|
||||||
|
def sendPacket(self, data): |
||||||
|
self.send(json.dumps(data) + '\n') |
||||||
|
|
||||||
|
def found_terminator(self): |
||||||
|
try: |
||||||
|
data = json.loads(self.__buffer) |
||||||
|
except ValueError: |
||||||
|
self.sendPacket({'error': 'invalid json'}) |
||||||
|
return |
||||||
|
finally: |
||||||
|
self.__buffer = '' |
||||||
|
|
||||||
|
try: |
||||||
|
cmd = data['cmd'] |
||||||
|
except (TypeError, KeyError): |
||||||
|
self.sendPacket({'error': 'no command given'}) |
||||||
|
return |
||||||
|
|
||||||
|
if cmd == 'refresh': |
||||||
|
self.__player.refreshPlaylist() |
||||||
|
self.sendPacket({'refresh': 'ok'}) |
||||||
|
elif cmd == 'next': |
||||||
|
self.__player.next() |
||||||
|
self.sendPacket({'next': 'ok'}) |
||||||
|
elif cmd == 'togglepaused': |
||||||
|
self.__player.togglePaused() |
||||||
|
self.sendPacket({'togglepaused': 'ok', 'paused': self.__player.paused}) |
||||||
|
elif cmd == 'getpaused': |
||||||
|
self.sendPacket({'paused': self.__player.paused}) |
||||||
|
elif cmd == 'playnext': |
||||||
|
if data.has_key('filename') and type(data['filename']) in [str, unicode]: |
||||||
|
try: |
||||||
|
self.__player.playNext(data['filename']) |
||||||
|
except Exception: |
||||||
|
self.sendPacket({'error':'too many animations queued'}) |
||||||
|
else: |
||||||
|
self.sendPacket({'playnext':'ok'}) |
||||||
|
else: |
||||||
|
self.sendPacket({'error': 'no or invalid animation file'}) |
||||||
|
elif cmd == 'getallfilenames': |
||||||
|
self.sendPacket({'allfilenames': self.__player.database.getAllFilenames()}) |
||||||
|
elif cmd == 'getcurrentfileinfo': |
||||||
|
if not self.__player.paused: |
||||||
|
info = self.__player.currentFileInfo.tags |
||||||
|
else: |
||||||
|
info = {} |
||||||
|
self.sendPacket({'currentfileinfo': info}) |
||||||
|
elif cmd == 'getcurrentfilename': |
||||||
|
self.sendPacket({'currentfilename': self.__player.currentFile}) |
||||||
|
else: |
||||||
|
self.sendPacket({'error': 'unknown command'}) |
||||||
|
|
||||||
|
|
||||||
|
class PlayerControlServer(asyncore.dispatcher): |
||||||
|
def __init__(self, host, port, player): |
||||||
|
asyncore.dispatcher.__init__(self) |
||||||
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM) |
||||||
|
self.set_reuse_addr() |
||||||
|
self.bind((host, port)) |
||||||
|
self.listen(5) |
||||||
|
self.__player = player |
||||||
|
|
||||||
|
def handle_accept(self): |
||||||
|
pair = self.accept() |
||||||
|
if pair is not None: |
||||||
|
sock, addr = pair |
||||||
|
print 'control connetcion from', addr |
||||||
|
PlayerControlClientHandler(sock, self.__player) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# |
||||||
|
# main |
||||||
|
# |
||||||
|
|
||||||
|
cfg = ConfigParser.SafeConfigParser(CONFIG_DEFAULTS) |
||||||
|
cfg.read('/var/tmp/blup2/blayer.cfg') |
||||||
|
|
||||||
|
try: |
||||||
|
out = BlupOutput.getOutput(cfg.get('output', 'output')) |
||||||
|
except ConfigParser.NoSectionError: |
||||||
|
sys.err.write('config error: missing \'output\' section') |
||||||
|
except ConfigParser.NoOptionError: |
||||||
|
sys.err.write('config error: missing \'output\' option in \'output\' section') |
||||||
|
|
||||||
|
try: |
||||||
|
animation_dir = cfg.get('player', 'animation_dir') |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
animation_dir = '.' |
||||||
|
|
||||||
|
db = AnimationDatabase(animation_dir) |
||||||
|
|
||||||
|
print 'updating database...' |
||||||
|
db.update() |
||||||
|
print 'done with updating database...' |
||||||
|
print 'updating database (again)...' |
||||||
|
db.update() |
||||||
|
print 'done with updating database...' |
||||||
|
#print db.getAllFilenames() |
||||||
|
|
||||||
|
#try: |
||||||
|
# playlist = Playlist(db, cfg.get('player', 'playlist')) |
||||||
|
# print 'file-playluist:', playlist |
||||||
|
#except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
# playlist = Playlist(db) |
||||||
|
# print 'db-playluist:', playlist |
||||||
|
|
||||||
|
blayer = PlayerThread(db, out) |
||||||
|
blayer.refreshPlaylist() |
||||||
|
#sys.exit(0) |
||||||
|
|
||||||
|
try: |
||||||
|
blayer.loopTime = cfg.getint('player', 'looptime') |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
pass |
||||||
|
|
||||||
|
try: |
||||||
|
blayer.shuffle = cfg.getboolean('player', 'shuffle') |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
pass |
||||||
|
|
||||||
|
try: |
||||||
|
blayer.autoRefresh = cfg.getboolean('player', 'autorefresh') |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
pass |
||||||
|
|
||||||
|
try: |
||||||
|
blayer.maxPlayNext = cfg.getint('player', 'maxplaynext') |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
pass |
||||||
|
|
||||||
|
blayer.start() |
||||||
|
|
||||||
|
try: |
||||||
|
cser = PlayerControlServer(cfg.get('control', 'bind_host'), cfg.getint('control', 'bind_port'), blayer) |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
cser = None |
||||||
|
|
||||||
|
|
||||||
|
try: |
||||||
|
|
||||||
|
if cser is not None: |
||||||
|
asyncore.loop() |
||||||
|
else: |
||||||
|
blayer.join() |
||||||
|
except KeyboardInterrupt: |
||||||
|
print 'nawk!!' |
||||||
|
blayer.terminate() |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,379 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import threading |
||||||
|
import random |
||||||
|
import os.path |
||||||
|
import os |
||||||
|
import time |
||||||
|
import socket |
||||||
|
import asyncore |
||||||
|
import asynchat |
||||||
|
import cmd |
||||||
|
import ConfigParser |
||||||
|
import sys |
||||||
|
|
||||||
|
import blup.animation as Animation |
||||||
|
import blup.output as BlupOutput |
||||||
|
import blup.frame as Frame |
||||||
|
|
||||||
|
|
||||||
|
CONFIG_DEFAULTS = { |
||||||
|
'output': 'shell', |
||||||
|
'playlist': '', |
||||||
|
'animation_dir': '.', |
||||||
|
'enabled': False, |
||||||
|
'shuffle': False, |
||||||
|
'autorefresh': False |
||||||
|
} |
||||||
|
|
||||||
|
def find(f, list): |
||||||
|
for x in list: |
||||||
|
if f(x): |
||||||
|
return x |
||||||
|
|
||||||
|
class AnimationInfo(): |
||||||
|
def __init__(self, filename): |
||||||
|
self.__filename = filename |
||||||
|
self.__tags = None |
||||||
|
self.__valid = None |
||||||
|
|
||||||
|
@property |
||||||
|
def filesize(self): |
||||||
|
try: |
||||||
|
statinfo = os.stat(self.__filename) |
||||||
|
return statinfo.st_size |
||||||
|
except OSError: |
||||||
|
return -1 |
||||||
|
|
||||||
|
@property |
||||||
|
def mtime(self): |
||||||
|
try: |
||||||
|
statinfo = os.stat(self.__filename) |
||||||
|
return statinfo.st_mtime |
||||||
|
except OSError: |
||||||
|
return -1 |
||||||
|
|
||||||
|
@property |
||||||
|
def tags(self): |
||||||
|
return self.__tags |
||||||
|
|
||||||
|
@property |
||||||
|
def valid(self): |
||||||
|
if self.__valid == None: |
||||||
|
try: |
||||||
|
self.check() |
||||||
|
except Animation.AnimationFileError: |
||||||
|
pass |
||||||
|
return self.__valid |
||||||
|
|
||||||
|
@property |
||||||
|
def filename(self): |
||||||
|
return self.__filename |
||||||
|
|
||||||
|
def check(self): |
||||||
|
self.__valid = False |
||||||
|
self.__tags = None |
||||||
|
|
||||||
|
anim = Animation.load(self.__filename) |
||||||
|
|
||||||
|
self.__valid = True |
||||||
|
self.__tags = anim.tags |
||||||
|
|
||||||
|
|
||||||
|
class AnimationDatabase(): |
||||||
|
def __init__(self, animDir): |
||||||
|
self.__animDir = animDir |
||||||
|
self.__animInfos = [] |
||||||
|
self.__lock = threading.Lock() |
||||||
|
|
||||||
|
def update(self): |
||||||
|
with self.__lock: |
||||||
|
oldAnimInfos = self.__animInfos |
||||||
|
animInfos = [] |
||||||
|
|
||||||
|
for (dirpath, dirnames, filenames) in os.walk(self.__animDir): |
||||||
|
files = map(lambda f: os.path.join(dirpath, f), filenames) |
||||||
|
files = map(lambda f: os.path.relpath(os.path.join(dirpath, f), self.__animDir), filenames) |
||||||
|
animInfos.extend(map(lambda f: AnimationInfo(f), files)) |
||||||
|
#animInfos = filter(lambda a: a.valid, animInfos) |
||||||
|
|
||||||
|
newAnimInfos = [] |
||||||
|
for animInfo in animInfos: |
||||||
|
oldAnimInfo = find(lambda a: a.filename == animInfo.filename, oldAnimInfos) |
||||||
|
if oldAnimInfo is not None and oldAnimInfo.mtime == animInfo.mtime: |
||||||
|
newAnimInfos.append(oldAnimInfo) |
||||||
|
else: |
||||||
|
if animInfo.valid: |
||||||
|
newAnimInfos.append(animInfo) |
||||||
|
|
||||||
|
self.__animInfos = newAnimInfos |
||||||
|
|
||||||
|
def findAnimation(self, filename): |
||||||
|
with self.__lock: |
||||||
|
animInfo = find(lambda a: a.filename == filename, self.__animInfos) |
||||||
|
if animInfo is not None: |
||||||
|
return animInfo |
||||||
|
else: |
||||||
|
raise Exception('animation not found!') |
||||||
|
|
||||||
|
def containsAnimation(self, filename): |
||||||
|
with self.__lock: |
||||||
|
animInfo = find(lambda a: a.filename == filename, self.__animInfos) |
||||||
|
return (animInfo is not None) |
||||||
|
|
||||||
|
def getAllFilenames(self): |
||||||
|
with self.__lock: |
||||||
|
return map(lambda a: a.filename, self.__animInfos) |
||||||
|
|
||||||
|
|
||||||
|
#class Playlist(list): |
||||||
|
# def __init__(self, animationDatabase, filename=None): |
||||||
|
# self.__animDb = animationDatabase |
||||||
|
# self.__filename = filename |
||||||
|
# if filename == None: |
||||||
|
# self.append(self.__animDb.getAllFilenames()) |
||||||
|
# else: |
||||||
|
# f = open(filename, 'r') |
||||||
|
# lines = f.read().split('\n') |
||||||
|
# f.close() |
||||||
|
# |
||||||
|
# for line in lines: |
||||||
|
# if self.__animDb.containsAnimation(line): |
||||||
|
# self.append(line) |
||||||
|
# |
||||||
|
# def refresh(self): |
||||||
|
# #f = open(filename, 'r') |
||||||
|
# #lines = f.read().split('\n') |
||||||
|
# #f.close() |
||||||
|
# pass |
||||||
|
# |
||||||
|
# #for line in lines: |
||||||
|
# # if self.__animDb.containsAnimation(line): |
||||||
|
# # self.append(line) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerThread(threading.Thread): |
||||||
|
def __init__(self, database, playlist, output): |
||||||
|
threading.Thread.__init__(self) |
||||||
|
self.__playlist = playlist |
||||||
|
self.__database = database |
||||||
|
self.__playNext = [] |
||||||
|
self.maxPlayNext = 3 |
||||||
|
self.__output = output |
||||||
|
self.shuffle = False |
||||||
|
self.autoRefresh = True |
||||||
|
self.loopTime = 10 |
||||||
|
self.gap = 800 |
||||||
|
self.__running = False |
||||||
|
self.__player = Animation.AnimationPlayer() |
||||||
|
self.__currentIndex = 0 |
||||||
|
self.__currentFile = '' |
||||||
|
|
||||||
|
@property |
||||||
|
def currentFile(self): |
||||||
|
return self.__currentFile |
||||||
|
|
||||||
|
def playNext(self, next): |
||||||
|
if len(self.__playNext) < self.__maxPlayNext: |
||||||
|
self.__playNext.append(next) |
||||||
|
else: |
||||||
|
raise Exception |
||||||
|
|
||||||
|
def refreshPlaylist(self): |
||||||
|
self.__database.update() |
||||||
|
self.__playlist = self.__database.getAllFilenames() |
||||||
|
|
||||||
|
def loadPlaylistFile(self): |
||||||
|
raise Exception('not yet implemented :(') |
||||||
|
|
||||||
|
def terminate(self): |
||||||
|
self.__player.stop() |
||||||
|
self.__running = False |
||||||
|
|
||||||
|
def run(self): |
||||||
|
self.__running = True |
||||||
|
while self.__running: |
||||||
|
anim = None |
||||||
|
if self.autoRefresh: # and self.__currentIndex == len(self.__playlist) - 1: |
||||||
|
self.refreshPlaylist() |
||||||
|
|
||||||
|
if len(self.__playNext) == 0: |
||||||
|
if len(self.__playlist) == 0: |
||||||
|
print 'busywait!!' |
||||||
|
continue |
||||||
|
|
||||||
|
if self.shuffle: |
||||||
|
self.__currentFile = self.__playlist[random.randint(0, len(self.__playlist) - 1)] |
||||||
|
else: |
||||||
|
if self.__currentIndex >= len(self.__playlist): |
||||||
|
self.__currentIndex = 0 |
||||||
|
self.__currentFile = self.__playlist[self.__currentIndex] |
||||||
|
self.__currentIndex += 1 |
||||||
|
else: |
||||||
|
self.__currentFile = self.__playNext.pop(0) |
||||||
|
anim = Animation.load(self.__currentFile) |
||||||
|
|
||||||
|
count = 1 |
||||||
|
if anim.tags.has_key('loop') and anim.tags['loop'].lower() in ['yes', 'true']: |
||||||
|
if anim.duration < self.loopTime * 1000: |
||||||
|
count = (self.loopTime * 1000) / anim.duration |
||||||
|
|
||||||
|
|
||||||
|
print 'playing:', anim |
||||||
|
print 'tags:', anim.tags |
||||||
|
self.__player.play(anim, self.__output, count=count) |
||||||
|
|
||||||
|
if self.gap > 0 and self.__running: |
||||||
|
self.__output.sendFrame(Frame.Frame(18,8)) |
||||||
|
time.sleep(self.gap / 1000.0) |
||||||
|
|
||||||
|
|
||||||
|
class PlayerControlClientHandler(asynchat.async_chat): |
||||||
|
def __init__(self, sock, player): |
||||||
|
asynchat.async_chat.__init__(self, sock=sock) |
||||||
|
self.set_terminator('\n') |
||||||
|
self.__buffer = '' |
||||||
|
self.__player = player |
||||||
|
|
||||||
|
def collect_incoming_data(self, data): |
||||||
|
self.__buffer += data |
||||||
|
|
||||||
|
def found_terminator(self): |
||||||
|
args = self.__buffer.split(' ') |
||||||
|
args = filter(lambda a: len(a) > 0, args) |
||||||
|
if len(args) == 0: |
||||||
|
return |
||||||
|
self.__buffer = '' |
||||||
|
cmd = args.pop(0) |
||||||
|
|
||||||
|
if cmd == 'refresh': |
||||||
|
self.__playlist.refresh() |
||||||
|
self.send('ok\n') |
||||||
|
elif cmd == 'status': |
||||||
|
self.send('playing %s\n' % (self.__player.getCurrentFile())) |
||||||
|
elif cmd == 'getplaylist': |
||||||
|
plist = '\n'.join(self.__playlist.getPlaylist()) |
||||||
|
self.send(plist + '\n') |
||||||
|
elif cmd == 'playnext' and len(args) == 1: |
||||||
|
try: |
||||||
|
self.__player.playNext(args[0]) |
||||||
|
self.send('ok\n') |
||||||
|
except Exception: |
||||||
|
self.send('error\n') |
||||||
|
elif cmd == 'loadplaylist' and len(args) == 1: |
||||||
|
try: |
||||||
|
if args[0] == '.': |
||||||
|
self.__playlist.loadDir() |
||||||
|
else: |
||||||
|
self.__playlist.loadFile(args[0]) |
||||||
|
self.send('ok\n') |
||||||
|
except: |
||||||
|
self.send('error\n') |
||||||
|
elif cmd == 'quit': |
||||||
|
self.send('bye\n') |
||||||
|
self.close() |
||||||
|
else: |
||||||
|
self.send('unknown command\n') |
||||||
|
|
||||||
|
|
||||||
|
class PlayerControlServer(asyncore.dispatcher): |
||||||
|
def __init__(self, host, port, player, playlist): |
||||||
|
asyncore.dispatcher.__init__(self) |
||||||
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM) |
||||||
|
self.set_reuse_addr() |
||||||
|
self.bind((host, port)) |
||||||
|
self.listen(5) |
||||||
|
self.__player = player |
||||||
|
self.__playlist = playlist |
||||||
|
|
||||||
|
def handle_accept(self): |
||||||
|
pair = self.accept() |
||||||
|
if pair is not None: |
||||||
|
sock, addr = pair |
||||||
|
print 'control connetcion from', addr |
||||||
|
PlayerControlClientHandler(sock, self.__player, self.__playlist) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# |
||||||
|
# main |
||||||
|
# |
||||||
|
|
||||||
|
cfg = ConfigParser.SafeConfigParser(CONFIG_DEFAULTS) |
||||||
|
cfg.read('/var/tmp/blup2/blayer.cfg') |
||||||
|
|
||||||
|
try: |
||||||
|
out = BlupOutput.getOutput(cfg.get('output', 'output')) |
||||||
|
except ConfigParser.NoSectionError: |
||||||
|
sys.err.write('config error: missing \'output\' section') |
||||||
|
except ConfigParser.NoOptionError: |
||||||
|
sys.err.write('config error: missing \'output\' option in \'output\' section') |
||||||
|
|
||||||
|
try: |
||||||
|
animation_dir = cfg.get('player', 'animation_dir') |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
animation_dir = '.' |
||||||
|
|
||||||
|
db = AnimationDatabase(animation_dir) |
||||||
|
|
||||||
|
print 'updating database...' |
||||||
|
db.update() |
||||||
|
print 'done with updating database...' |
||||||
|
print 'updating database (again)...' |
||||||
|
db.update() |
||||||
|
print 'done with updating database...' |
||||||
|
#print db.getAllFilenames() |
||||||
|
|
||||||
|
try: |
||||||
|
playlist = Playlist(db, cfg.get('player', 'playlist')) |
||||||
|
print 'file-playluist:', playlist |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
playlist = Playlist(db) |
||||||
|
print 'db-playluist:', playlist |
||||||
|
|
||||||
|
blayer = PlayerThread(db, playlist, out) |
||||||
|
#sys.exit(0) |
||||||
|
|
||||||
|
try: |
||||||
|
blayer.setLoopTime(cfg.getint('player', 'looptime')) |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
pass |
||||||
|
|
||||||
|
try: |
||||||
|
blayer.setShuffle(cfg.getboolean('player', 'shuffle')) |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
pass |
||||||
|
|
||||||
|
try: |
||||||
|
blayer.setAutoRefresh(cfg.getboolean('player', 'autorefresh')) |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
pass |
||||||
|
|
||||||
|
try: |
||||||
|
blayer.setMaxPlayNext(cfg.getint('player', 'maxplaynext')) |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
pass |
||||||
|
|
||||||
|
blayer.start() |
||||||
|
|
||||||
|
try: |
||||||
|
cser = PlayerControlServer(cfg.get('control', 'bind_host'), cfg.getint('control', 'bind_port'), blayer, playlist) |
||||||
|
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
||||||
|
cser = None |
||||||
|
|
||||||
|
|
||||||
|
try: |
||||||
|
|
||||||
|
if cser is not None: |
||||||
|
asyncore.loop() |
||||||
|
else: |
||||||
|
blayer.join() |
||||||
|
except KeyboardInterrupt: |
||||||
|
print 'nawk!!' |
||||||
|
blayer.terminate() |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,68 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import sys |
||||||
|
import getopt |
||||||
|
|
||||||
|
import blup.animation |
||||||
|
import blup.output |
||||||
|
|
||||||
|
def printUsage(errMsg=None): |
||||||
|
if errMsg is not None: |
||||||
|
print 'error: %s\n' % (errMsg) |
||||||
|
print 'usage: %s [OPTIONS] FILENAME' % (sys.argv[0]) |
||||||
|
print 'supported options:' |
||||||
|
print ' -o OUTPUT where to output the frames (default: shell)' |
||||||
|
print ' --output OUTPUT\n' |
||||||
|
print ' -h print this text' |
||||||
|
print ' --help' |
||||||
|
|
||||||
|
def main(): |
||||||
|
try: |
||||||
|
(opts, args) = getopt.gnu_getopt(sys.argv, 'ho:', ['help', 'output=']) |
||||||
|
opts = dict(opts) |
||||||
|
except getopt.GetoptError as e: |
||||||
|
printUsage(e.msg) |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
if opts.has_key('--help'): |
||||||
|
printUsage() |
||||||
|
sys.exit(0) |
||||||
|
|
||||||
|
if opts.has_key('-o'): |
||||||
|
output = opts['-o'] |
||||||
|
elif opts.has_key('--output'): |
||||||
|
output = opts['--output'] |
||||||
|
else: |
||||||
|
output = 'shell' |
||||||
|
|
||||||
|
try: |
||||||
|
out = blup.output.getOutput(output) |
||||||
|
except blup.output.IllegalOutputSpecificationError: |
||||||
|
print 'illegal output specification' |
||||||
|
print 'available outputs:' |
||||||
|
print blup.output.getOutputDescriptions() |
||||||
|
sys.exit(1) |
||||||
|
except Exception as e: |
||||||
|
print 'could not initialize output: %s' % (str(e)) |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
if len(args) != 2: |
||||||
|
printUsage() |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
try: |
||||||
|
anim = blup.animation.load(args[1]) |
||||||
|
except blup.animation.AnimationFileError: |
||||||
|
print 'could not load animation' |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
player = blup.animation.AnimationPlayer() |
||||||
|
try: |
||||||
|
while True: |
||||||
|
player.play(anim, out) |
||||||
|
except KeyboardInterrupt: |
||||||
|
sys.exit(0) |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main() |
||||||
|
|
@ -0,0 +1,167 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
|
||||||
|
import threading |
||||||
|
import socket |
||||||
|
import time |
||||||
|
import getopt |
||||||
|
import sys |
||||||
|
|
||||||
|
import blup.BLP |
||||||
|
import blup.output |
||||||
|
|
||||||
|
|
||||||
|
class BLPStreamReceiverThread(threading.Thread): |
||||||
|
def __init__(self, addr, port, hub, protocol=blup.BLP.PROTO_BLP): |
||||||
|
threading.Thread.__init__(self) |
||||||
|
self.__addr = addr |
||||||
|
self.__port = port |
||||||
|
self.__hub = hub |
||||||
|
self.__protocol = protocol |
||||||
|
self.__running = False |
||||||
|
|
||||||
|
def run(self): |
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
||||||
|
sock.bind((self.__addr, self.__port)) |
||||||
|
sock.settimeout(1) |
||||||
|
|
||||||
|
self.__running = True |
||||||
|
while self.__running: |
||||||
|
try: |
||||||
|
data, addr = sock.recvfrom(2048) |
||||||
|
except socket.timeout: |
||||||
|
continue |
||||||
|
|
||||||
|
try: |
||||||
|
frame = blup.BLP.blp2frame(data, protocol=self.__protocol) |
||||||
|
except ValueError: |
||||||
|
print('got an invalid frame from', addr) |
||||||
|
else: |
||||||
|
self.__hub.sendFrame(frame, self) |
||||||
|
|
||||||
|
def terminate(self): |
||||||
|
self.__running = False |
||||||
|
|
||||||
|
class BLPHub(): |
||||||
|
def __init__(self, output): |
||||||
|
self.__output = output |
||||||
|
self.__streams = {} |
||||||
|
self.__lock = threading.Lock() |
||||||
|
self.__lastFrameTimeout = -1 |
||||||
|
self.__lastFramePriority = -1 |
||||||
|
|
||||||
|
def sendFrame(self, frame, stream): |
||||||
|
with self.__lock: |
||||||
|
if stream not in self.__streams.keys(): |
||||||
|
return False |
||||||
|
|
||||||
|
priority = self.__streams[stream]['priority'] |
||||||
|
currentTime = int(time.time() * 1000) |
||||||
|
|
||||||
|
accept = False |
||||||
|
if priority >= self.__lastFramePriority: |
||||||
|
accept = True |
||||||
|
else: |
||||||
|
if currentTime > self.__lastFrameTimeout: |
||||||
|
accept = True |
||||||
|
|
||||||
|
if accept: |
||||||
|
self.__lastFramePriority = priority |
||||||
|
self.__lastFrameTimeout = ( |
||||||
|
currentTime + self.__streams[stream]['timeout'] |
||||||
|
) |
||||||
|
self.__output.sendFrame(frame) |
||||||
|
return True |
||||||
|
|
||||||
|
return False |
||||||
|
|
||||||
|
def addStream(self, stream, priority, timeout): |
||||||
|
if stream not in self.__streams.keys(): |
||||||
|
self.__streams[stream] = {'priority': priority, 'timeout': timeout} |
||||||
|
|
||||||
|
def printUsage(errMsg=None): |
||||||
|
if errMsg is not None: |
||||||
|
print('error: %s\n' % (errMsg)) |
||||||
|
print('usage: %s [OPTIONS] INPUTSTREAM ...' % (sys.argv[0])) |
||||||
|
print('where INPUTSTREAM is given as HOST:PORT:PRIORITY:TIMEOUT') |
||||||
|
print('supported options:') |
||||||
|
print(' -o OUTPUT where to put the received frames') |
||||||
|
print(' --eblp use EBLP instead of BLP') |
||||||
|
print(' --e3blp use E3BLP instead of BLP') |
||||||
|
print(' -h print this text') |
||||||
|
print(' --help') |
||||||
|
|
||||||
|
def main(): |
||||||
|
(opts, args) = getopt.gnu_getopt(sys.argv, 'hs:o:', |
||||||
|
['help', 'eblp', 'e3blp']) |
||||||
|
opts = dict(opts) |
||||||
|
|
||||||
|
if '--help' in opts or '-h' in opts: |
||||||
|
printUsage() |
||||||
|
sys.exit(0) |
||||||
|
|
||||||
|
if '-o' in opts: |
||||||
|
output = opts['-o'] |
||||||
|
else: |
||||||
|
output = 'shell' |
||||||
|
|
||||||
|
if '--eblp' in opts: |
||||||
|
protocol = blup.BLP.PROTO_EBLP |
||||||
|
elif '--e3blp' in opts: |
||||||
|
protocol = blup.BLP.PROTO_E3BLP |
||||||
|
else: |
||||||
|
protocol = blup.BLP.PROTO_BLP |
||||||
|
|
||||||
|
if '--eblp' in opts and '--e3blp' in opts: |
||||||
|
printUsage('please only specify one of --eblp or --e3blp') |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
streams = [] |
||||||
|
for arg in args[1:]: |
||||||
|
try: |
||||||
|
(host, port, priority, timeout) = arg.split(':') |
||||||
|
port = int(port) |
||||||
|
priority = int(priority) |
||||||
|
timeout = int(timeout) |
||||||
|
if port <= 0 or timeout < 0: |
||||||
|
raise ValueError |
||||||
|
except ValueError as e: |
||||||
|
printUsage('illegal stream specification') |
||||||
|
sys.exit(1) |
||||||
|
streams.append((host, port, priority, timeout)) |
||||||
|
|
||||||
|
if len(streams) == 0: |
||||||
|
printUsage('please specify at least one stream') |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
try: |
||||||
|
out = blup.output.getOutput(output) |
||||||
|
except ValueError: |
||||||
|
printUsage('could not initialize output') |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
hub = BLPHub(out) |
||||||
|
|
||||||
|
streamThreads = [] |
||||||
|
firstThread = None |
||||||
|
for (host, port, priority, timeout) in streams: |
||||||
|
stream = BLPStreamReceiverThread(host, port, hub, protocol) |
||||||
|
hub.addStream(stream, priority, timeout) |
||||||
|
if firstThread is None: |
||||||
|
firstThread = stream |
||||||
|
else: |
||||||
|
streamThreads.append(stream) |
||||||
|
stream.start() |
||||||
|
|
||||||
|
try: |
||||||
|
firstThread.run() |
||||||
|
except KeyboardInterrupt: |
||||||
|
if len(streamThreads) > 0: |
||||||
|
print('waiting for listeners to terminate...') |
||||||
|
for stream in streamThreads: |
||||||
|
stream.terminate() |
||||||
|
for stream in streamThreads: |
||||||
|
stream.join() |
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
main() |
||||||
|
|
@ -0,0 +1,4 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
python blphub.py -o blp:bastel0:4242 localhost:4242:1:1000 localhost:42421:2:3500 |
||||||
|
|
@ -0,0 +1,88 @@ |
|||||||
|
|
||||||
|
import socket |
||||||
|
import getopt |
||||||
|
import sys |
||||||
|
|
||||||
|
from blup.BLP import BLPServer |
||||||
|
import blup.BLP |
||||||
|
import blup.output |
||||||
|
|
||||||
|
|
||||||
|
def printUsage(errMsg=None): |
||||||
|
if errMsg is not None: |
||||||
|
print 'error: %s\n' % (errMsg) |
||||||
|
print 'usage: %s [OPTIONS]' % (sys.argv[0]) |
||||||
|
print 'supported options:' |
||||||
|
print ' -a ADDR address to listen for packets (default: 127.0.0.1)' |
||||||
|
print ' --address ADDR\n' |
||||||
|
print ' -p PORT port to listen for packets (default: 4242)' |
||||||
|
print ' --port PORT\n' |
||||||
|
print ' -o OUTPUT where to put the recieved frames (default: shell)' |
||||||
|
print ' --output OUTPUT\n' |
||||||
|
print ' --eblp use EBLP instead of BLP\n' |
||||||
|
print ' --e3blp use E3BLP instead of BLP\n' |
||||||
|
print ' -h print this text' |
||||||
|
print ' --help' |
||||||
|
|
||||||
|
|
||||||
|
def main(): |
||||||
|
try: |
||||||
|
(opts, args) = getopt.gnu_getopt(sys.argv, 'ha:p:o:', ['help', 'address=', 'port=', 'output=', 'eblp', 'e3blp']) |
||||||
|
opts = dict(opts) |
||||||
|
except getopt.GetoptError as e: |
||||||
|
printUsage(e.msg) |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
if opts.has_key('--help'): |
||||||
|
printUsage() |
||||||
|
sys.exit(0) |
||||||
|
|
||||||
|
if opts.has_key('-a'): |
||||||
|
addr = opts['-a'] |
||||||
|
elif opts.has_key('--address'): |
||||||
|
addr = opts['--address'] |
||||||
|
else: |
||||||
|
addr = '127.0.0.1' |
||||||
|
|
||||||
|
if opts.has_key('-p'): |
||||||
|
port = opts['-p'] |
||||||
|
elif opts.has_key('--port'): |
||||||
|
port = opts['--port'] |
||||||
|
else: |
||||||
|
port = 4242 |
||||||
|
|
||||||
|
if opts.has_key('-o'): |
||||||
|
output = opts['-o'] |
||||||
|
elif opts.has_key('--output'): |
||||||
|
output = opts['--output'] |
||||||
|
else: |
||||||
|
output = 'shell' |
||||||
|
|
||||||
|
if opts.has_key('--eblp'): |
||||||
|
protocol = blup.BLP.PROTO_EBLP |
||||||
|
elif opts.has_key('--e3blp'): |
||||||
|
protocol = blup.BLP.PROTO_E3BLP |
||||||
|
else: |
||||||
|
protocol = blup.BLP.PROTO_BLP |
||||||
|
|
||||||
|
if opts.has_key('--eblp') and opts.has_key('--e3blp'): |
||||||
|
printUsage('please only specify one of --eblp or --e3blp') |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
try: |
||||||
|
port = int(port) |
||||||
|
except ValueError: |
||||||
|
printUsage('invalid port specified') |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
out = blup.output.getOutput(output) |
||||||
|
srv = BLPServer(output=out, addr=addr, port=port, protocol=protocol) |
||||||
|
|
||||||
|
try: |
||||||
|
srv.serve() |
||||||
|
except KeyboardInterrupt: |
||||||
|
pass |
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
main() |
||||||
|
|
@ -0,0 +1,174 @@ |
|||||||
|
""" |
||||||
|
This is a BLP and EBLP implementation as described here: |
||||||
|
https://wiki.blinkenarea.org/index.php/BlinkenlightsProtocolEnglish |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
import threading |
||||||
|
import socket |
||||||
|
import struct |
||||||
|
|
||||||
|
from .frame import Frame |
||||||
|
from .frame import FrameDimension |
||||||
|
|
||||||
|
BLP_MAGIC = b'\xde\xad\xbe\xef' |
||||||
|
EBLP_MAGIC = b'\xfe\xed\xbe\xef' |
||||||
|
E3BLP_MAGIC = b'\xca\xfe\xbe\xef' |
||||||
|
|
||||||
|
PROTO_BLP = 0 |
||||||
|
PROTO_EBLP = 1 |
||||||
|
PROTO_E3BLP = 2 |
||||||
|
PROTOCOLS = [PROTO_BLP, PROTO_EBLP, PROTO_E3BLP] |
||||||
|
|
||||||
|
def frame2blp(frame, protocol=PROTO_BLP, depth=16): |
||||||
|
if protocol not in PROTOCOLS: |
||||||
|
raise ValueError('Unknown protocol: %d' % (protocol)) |
||||||
|
if frame.depth != 2 and protocol == PROTO_BLP: |
||||||
|
raise ValueError('BLP does not support greyscale.') |
||||||
|
if frame.channels != 3 and protocol == PROTO_E3BLP: |
||||||
|
raise ValueError('E3BLP does only support 3-channel frames.') |
||||||
|
|
||||||
|
(w, h) = frame.size |
||||||
|
|
||||||
|
# magic value |
||||||
|
if protocol == PROTO_BLP: |
||||||
|
packet = BLP_MAGIC |
||||||
|
elif protocol == PROTO_EBLP: |
||||||
|
packet = EBLP_MAGIC |
||||||
|
elif protocol == PROTO_E3BLP: |
||||||
|
packet = E3BLP_MAGIC |
||||||
|
|
||||||
|
# frame number, not yet implemented |
||||||
|
packet += b'\x00\x00\x00\x00' |
||||||
|
|
||||||
|
# frame dimension |
||||||
|
packet += struct.pack('>HH', w, h) |
||||||
|
|
||||||
|
for y in range(h): |
||||||
|
for x in range(w): |
||||||
|
if protocol == PROTO_BLP: |
||||||
|
if frame.getPixel(x, y) == 1: |
||||||
|
packet += b'\x01' |
||||||
|
else: |
||||||
|
packet += b'\x00' |
||||||
|
elif protocol == PROTO_EBLP: |
||||||
|
packet += struct.pack('B', frame.getPixel(x, y)) |
||||||
|
elif protocol == PROTO_E3BLP: |
||||||
|
(r,g,b) = frame.getPixel(x, y) |
||||||
|
packet += struct.pack('BBB', r, g, b) |
||||||
|
|
||||||
|
return packet |
||||||
|
|
||||||
|
def blp2frame(packet, protocol=PROTO_BLP, depth=None): |
||||||
|
if protocol not in PROTOCOLS: |
||||||
|
raise ValueError('Unknown protocol: %d' % (protocol)) |
||||||
|
if len(packet) < 13: |
||||||
|
raise ValueError('packet is too short') |
||||||
|
if ( (packet[0:4] != BLP_MAGIC and protocol == PROTO_BLP) or |
||||||
|
(packet[0:4] != EBLP_MAGIC and protocol == PROTO_EBLP) or |
||||||
|
(packet[0:4] != E3BLP_MAGIC and protocol == PROTO_E3BLP) ): |
||||||
|
raise ValueError('MAGIC does not match') |
||||||
|
|
||||||
|
w = (packet[8]<<8) + packet[9] |
||||||
|
h = (packet[10]<<8) + packet[11] |
||||||
|
|
||||||
|
if ( (protocol == PROTO_E3BLP and len(packet) != (w*h*3 + 12)) or |
||||||
|
(protocol in [PROTO_BLP, PROTO_EBLP] and len(packet) != (w*h + 12)) ): |
||||||
|
print(len(packet)) |
||||||
|
raise ValueError('packet size does not match') |
||||||
|
|
||||||
|
if protocol == PROTO_BLP: |
||||||
|
frm = Frame(FrameDimension(w, h, 2, 1)) |
||||||
|
elif protocol == PROTO_EBLP: |
||||||
|
if depth is None: |
||||||
|
depth = 16 |
||||||
|
frm = Frame(FrameDimension(w, h, depth, 1)) |
||||||
|
elif protocol == PROTO_E3BLP: |
||||||
|
if depth is None: |
||||||
|
depth = 8 |
||||||
|
frm = Frame(FrameDimension(w, h, depth, 3)) |
||||||
|
|
||||||
|
pixels = [] |
||||||
|
for y in range(h): |
||||||
|
row = [] |
||||||
|
for x in range(w): |
||||||
|
if protocol == PROTO_BLP: |
||||||
|
if packet[12 + y*w + x] == '\x01': |
||||||
|
#frm.setPixel(x, y, 1) |
||||||
|
row.append(1) |
||||||
|
else: |
||||||
|
#frm.setPixel(x, y, 0) |
||||||
|
row.append(0) |
||||||
|
elif protocol == PROTO_EBLP: |
||||||
|
row.append(packet[12 + y*w + x]) |
||||||
|
elif protocol == PROTO_E3BLP: |
||||||
|
pos = 12 + (y*w + x) * 3 |
||||||
|
r = packet[pos] |
||||||
|
g = packet[pos + 1] |
||||||
|
b = packet[pos + 2] |
||||||
|
row.append((r,g,b)) |
||||||
|
pixels.append(row) |
||||||
|
frm.pixels = pixels |
||||||
|
|
||||||
|
return frm |
||||||
|
|
||||||
|
class BLPServer: |
||||||
|
def __init__(self, addr='127.0.0.1', port=4242, output=None, |
||||||
|
protocol=PROTO_BLP): |
||||||
|
if protocol not in PROTOCOLS: |
||||||
|
raise ValueError('Unknown protocol: %d' % (protocol)) |
||||||
|
|
||||||
|
self.__addr = addr |
||||||
|
self.__port = port |
||||||
|
self.__output = output |
||||||
|
self.__sock = None |
||||||
|
self.__protocol = protocol |
||||||
|
|
||||||
|
if not output: |
||||||
|
raise ValueError('serving without output isn\'t supported, yet') |
||||||
|
|
||||||
|
def bind(self): |
||||||
|
self.__sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
||||||
|
self.__sock.bind((self.__addr, self.__port)) |
||||||
|
|
||||||
|
def handle(self): |
||||||
|
if self.__sock is None: |
||||||
|
return |
||||||
|
|
||||||
|
data, addr = self.__sock.recvfrom(1024) |
||||||
|
try: |
||||||
|
frame = blp2frame(data, protocol=self.__protocol) |
||||||
|
except ValueError as e: |
||||||
|
print('got an invalid frame from', addr) |
||||||
|
print(e) |
||||||
|
return |
||||||
|
else: |
||||||
|
self.__output.sendFrame(frame) |
||||||
|
|
||||||
|
def serve(self): |
||||||
|
self.bind() |
||||||
|
while True: |
||||||
|
self.handle() |
||||||
|
|
||||||
|
class BLPServerThread(threading.Thread, BLPServer): |
||||||
|
def __init__(self, addr, port, output, protocol=PROTO_BLP): |
||||||
|
if protocol not in PROTOCOLS: |
||||||
|
raise ValueError('Unknown protocol: %d' % (protocol)) |
||||||
|
|
||||||
|
threading.Thread.__init__(self) |
||||||
|
BLPServer.__init__(self, addr, port, output, protocol) |
||||||
|
self.__running = False |
||||||
|
|
||||||
|
def run(self): |
||||||
|
self.bind() |
||||||
|
self.__running = True |
||||||
|
while self.__running: self.handle() |
||||||
|
|
||||||
|
def serve(self): |
||||||
|
self.start() |
||||||
|
|
||||||
|
def terminate(self): |
||||||
|
self.__running = False |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,344 @@ |
|||||||
|
""" |
||||||
|
This module is part of the 'blup' package and defines an animation class along |
||||||
|
with the necessary functions to read animations from files. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
import re |
||||||
|
import time |
||||||
|
import xml.etree.ElementTree as ET |
||||||
|
|
||||||
|
from frame import Frame |
||||||
|
from frame import FrameDimension |
||||||
|
|
||||||
|
|
||||||
|
class AnimationFileError(Exception): |
||||||
|
def __init__(self, value): |
||||||
|
self.__value = value |
||||||
|
def __str__(self): |
||||||
|
return repr(self.__value) |
||||||
|
|
||||||
|
class AnimationFrame(Frame): |
||||||
|
""" This class constitutes a single frame of an animation. """ |
||||||
|
|
||||||
|
def __init__(self, dimension, delay=100): |
||||||
|
""" Initialize the frame with given dimension and delay. """ |
||||||
|
Frame.__init__(self, dimension) |
||||||
|
self.delay = int(delay) |
||||||
|
|
||||||
|
class AnimationIterator(object): |
||||||
|
""" |
||||||
|
This iterator can be used to loop over the animation's frames using |
||||||
|
python's 'for' statement. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
def __init__(self, animation): |
||||||
|
""" Initialize the iterator. """ |
||||||
|
self.__animation = animation |
||||||
|
self.__pos = 0 |
||||||
|
|
||||||
|
def next(self): |
||||||
|
""" Return the next frame (if available). """ |
||||||
|
if self.__pos >= len(self.__animation): |
||||||
|
raise StopIteration |
||||||
|
else: |
||||||
|
self.__pos += 1 |
||||||
|
return self.__animation[self.__pos - 1] |
||||||
|
|
||||||
|
class Animation(object): |
||||||
|
""" This class constitutes an animation. """ |
||||||
|
|
||||||
|
def __init__(self, dimension): |
||||||
|
""" Initialize the animation (without frames). """ |
||||||
|
self.__dimension = dimension |
||||||
|
self.__frames = [] |
||||||
|
self.tags = {} |
||||||
|
|
||||||
|
|
||||||
|
@property |
||||||
|
def dimension(self): |
||||||
|
return self.__dimension |
||||||
|
|
||||||
|
@property |
||||||
|
def width(self): |
||||||
|
return self.__dimension.width |
||||||
|
@property |
||||||
|
def height(self): |
||||||
|
return self.__dimension.height |
||||||
|
@property |
||||||
|
def depth(self): |
||||||
|
return self.__dimension.depth |
||||||
|
@property |
||||||
|
def channels(self): |
||||||
|
return self.__dimension.channels |
||||||
|
|
||||||
|
@property |
||||||
|
def duration(self): |
||||||
|
""" Compute the duration of the animation. """ |
||||||
|
return sum(map(lambda f: f.delay, self.__frames)) |
||||||
|
|
||||||
|
def addFrame(self, frame): |
||||||
|
""" Append a frame to the animation. """ |
||||||
|
if not isinstance(frame, Frame): |
||||||
|
raise ValueError('frame is no \'Frame\' instance') |
||||||
|
|
||||||
|
if self.dimension != frame.dimension: |
||||||
|
raise ValueError(('frame dimension %s does not match animation ' + |
||||||
|
'dimension %s' ) |
||||||
|
% (str(self.dimension), str(frame.dimension))) |
||||||
|
|
||||||
|
self.__frames.append(frame) |
||||||
|
|
||||||
|
def __iter__(self): |
||||||
|
""" Return an iterator to loop over the animation's frames. """ |
||||||
|
return AnimationIterator(self) |
||||||
|
|
||||||
|
def __len__(self): |
||||||
|
""" Return the number of frames. """ |
||||||
|
return len(self.__frames) |
||||||
|
|
||||||
|
def __getitem__(self, i): |
||||||
|
""" Retrieve a certain frame from the animation. """ |
||||||
|
if i < 0 or i >= len(self): |
||||||
|
raise IndexError('frame index out of bounds') |
||||||
|
return self.__frames[i] |
||||||
|
|
||||||
|
def __delitem__(self, i): |
||||||
|
""" Delete a certain frame from the animation. """ |
||||||
|
if i < 0 or i >= len(self): |
||||||
|
raise IndexError('frame index out of bounds') |
||||||
|
del self.__frames[i] |
||||||
|
|
||||||
|
|
||||||
|
class AnimationPlayer(object): |
||||||
|
""" |
||||||
|
This class can be used to play an Animation using an output class that |
||||||
|
implements the 'sendFrame()' function. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
def __init__(self): |
||||||
|
""" Initialize the player. """ |
||||||
|
self.__playing = False |
||||||
|
self.__elapsed = 0 |
||||||
|
|
||||||
|
@property |
||||||
|
def elapsed(self): |
||||||
|
return self.__elapsed |
||||||
|
|
||||||
|
def play(self, animation, output, count=1): |
||||||
|
""" Play the animation 'count' times on 'output'. """ |
||||||
|
self.__playing = True |
||||||
|
self.__elapsed = 0 |
||||||
|
for i in range(count): |
||||||
|
for frame in animation: |
||||||
|
output.sendFrame(frame) |
||||||
|
|
||||||
|
delay = frame.delay / 1000.0 |
||||||
|
time.sleep(delay) |
||||||
|
self.__elapsed += delay |
||||||
|
if not self.__playing: |
||||||
|
break |
||||||
|
if not self.__playing: |
||||||
|
break |
||||||
|
|
||||||
|
def stop(self): |
||||||
|
""" Stop the player, if playing. """ |
||||||
|
self.__playing = False |
||||||
|
|
||||||
|
def loadBlm(filename): |
||||||
|
""" Parse a blm file and return an Animation object. """ |
||||||
|
|
||||||
|
f = open(filename, 'r') |
||||||
|
|
||||||
|
w = h = 0 |
||||||
|
tags = {} |
||||||
|
|
||||||
|
header = True |
||||||
|
framedelay = 100 |
||||||
|
frame = [] |
||||||
|
animframes = [] |
||||||
|
for line in f: |
||||||
|
if header: |
||||||
|
m = re.match('^\s*#\s+BlinkenLights Movie (\d+)x(\d+)', line) |
||||||
|
if m: |
||||||
|
w = int(m.group(1)) |
||||||
|
h = int(m.group(2)) |
||||||
|
continue |
||||||
|
|
||||||
|
m = re.match('^\s*#\s+(.+)\s+=\s+(.+)\s+$', line) |
||||||
|
if m: |
||||||
|
key = m.group(1) |
||||||
|
val = m.group(2) |
||||||
|
tags[key] = val |
||||||
|
continue |
||||||
|
|
||||||
|
m = re.match('^@(\d+)\s+$', line) |
||||||
|
if m: |
||||||
|
if header: |
||||||
|
header = False |
||||||
|
framedelay = int(m.group(1)) |
||||||
|
if len(frame) > 0: |
||||||
|
if h == 0: |
||||||
|
h = len(frame) |
||||||
|
else: |
||||||
|
if len(frame) != h: |
||||||
|
raise AnimationFileError( |
||||||
|
'frame height does not match specified or ' + |
||||||
|
'previous height') |
||||||
|
|
||||||
|
frm = AnimationFrame(FrameDimension(w, h, 2, 1), |
||||||
|
delay=framedelay) |
||||||
|
frm.pixels = frame |
||||||
|
print frame.pixels |
||||||
|
animframes.append(frm) |
||||||
|
frame = [] |
||||||
|
continue |
||||||
|
|
||||||
|
if not header: |
||||||
|
if line.strip() == '' or line.strip().startswith('#'): |
||||||
|
continue |
||||||
|
|
||||||
|
if re.match('^(0|1)+$', line): |
||||||
|
line = line.strip() |
||||||
|
if w == 0: |
||||||
|
w = len(line) |
||||||
|
else: |
||||||
|
if len(line) != w: |
||||||
|
raise AnimationFileError( |
||||||
|
'frame width does not match specified or ' + |
||||||
|
'previous width') |
||||||
|
row = map(lambda c: int(c), list(line)) |
||||||
|
frame.append(row) |
||||||
|
|
||||||
|
if h != 0 and len(frame) == h: |
||||||
|
frm = AnimationFrame(FrameDimension(w, h, 2, 1), |
||||||
|
delay=framedelay) |
||||||
|
frm.pixels = frame |
||||||
|
animframes.append(frm) |
||||||
|
frame = [] |
||||||
|
|
||||||
|
continue |
||||||
|
|
||||||
|
f.close() |
||||||
|
|
||||||
|
if len(frame) > 0: |
||||||
|
frm = AnimationFrame(FrameDimension(w, h, 2, 1), delay=framedelay) |
||||||
|
frm.pixels = frame |
||||||
|
animframes.append(frm) |
||||||
|
|
||||||
|
if len(animframes) == 0: |
||||||
|
raise AnimationFileError('no frames found in this file') |
||||||
|
|
||||||
|
|
||||||
|
a = Animation(FrameDimension(w, h, 2, 1)) |
||||||
|
a.tags = tags |
||||||
|
for f in animframes: |
||||||
|
a.addFrame(f) |
||||||
|
|
||||||
|
return a |
||||||
|
|
||||||
|
|
||||||
|
def loadBml(filename): |
||||||
|
""" Parse a bml file and return an Animation object. """ |
||||||
|
|
||||||
|
try: |
||||||
|
tree = ET.parse(filename) |
||||||
|
except ET.ParseError: |
||||||
|
raise AnimationFileError('invalid xml') |
||||||
|
root = tree.getroot() |
||||||
|
|
||||||
|
if root.tag != 'blm': |
||||||
|
raise AnimationFileError('the root tag needs to be a \'blm\' tag') |
||||||
|
|
||||||
|
try: |
||||||
|
width = int(root.attrib['width']) |
||||||
|
height = int(root.attrib['height']) |
||||||
|
bits = int(root.attrib['bits']) |
||||||
|
channels = int(root.attrib['channels']) |
||||||
|
|
||||||
|
dim = FrameDimension(width, height, 2**bits, channels) |
||||||
|
except KeyError as e: |
||||||
|
raise AnimationFileError('the root tag does not contain a ' + |
||||||
|
'\'%s\' attribute.' % (e[0])) |
||||||
|
|
||||||
|
if channels not in [1, 3]: |
||||||
|
raise AnimationFileError('unsupported channel count') |
||||||
|
|
||||||
|
tags = {} |
||||||
|
frames = [] |
||||||
|
|
||||||
|
for child in root: |
||||||
|
if child.tag == 'header': |
||||||
|
for headerchild in child: |
||||||
|
tags[headerchild.tag] = headerchild.text |
||||||
|
# TODO (maybe) raise an exception in case no 'title' is given |
||||||
|
|
||||||
|
elif child.tag == 'frame': |
||||||
|
delay = int(child.attrib['duration']) |
||||||
|
currentframe = AnimationFrame(dim, delay) |
||||||
|
rows = [] |
||||||
|
for row in child: |
||||||
|
charsPerPixel = channels |
||||||
|
if bits > 4: |
||||||
|
charsPerPixel *= 2 |
||||||
|
|
||||||
|
rowPixels = [] |
||||||
|
for i in xrange(0, width * charsPerPixel, charsPerPixel): |
||||||
|
if channels == 1: |
||||||
|
pixel = row.text[i:(i + charsPerPixel)] |
||||||
|
rowPixels.append(int(pixel, 16)) |
||||||
|
elif channels == 3: |
||||||
|
charsPerColor = charsPerPixel / 3 |
||||||
|
r = row.text[i:(i + charsPerColor)] |
||||||
|
g = row.text[(i + charsPerColor):(i + 2*charsPerColor)] |
||||||
|
b = row.text[(i + 2*charsPerColor):(i + charsPerPixel)] |
||||||
|
rowPixels.append((int(r, 16), int(g, 16), int(b, 16))) |
||||||
|
rows.append(rowPixels) |
||||||
|
currentframe.pixels = rows |
||||||
|
frames.append(currentframe) |
||||||
|
|
||||||
|
a = Animation(dim) |
||||||
|
a.tags = tags |
||||||
|
for f in frames: |
||||||
|
a.addFrame(f) |
||||||
|
|
||||||
|
return a |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def load(filename): |
||||||
|
""" |
||||||
|
(Try to) parse the given file using all available parser functions and |
||||||
|
return the Animation afterwards. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
loaders = [ loadBlm, loadBml ] |
||||||
|
|
||||||
|
anim = None |
||||||
|
for loader in loaders: |
||||||
|
try: |
||||||
|
anim = loader(filename) |
||||||
|
except AnimationFileError as e: |
||||||
|
pass |
||||||
|
if anim: |
||||||
|
break |
||||||
|
|
||||||
|
if not anim: |
||||||
|
raise AnimationFileError('file could not be read') |
||||||
|
|
||||||
|
return anim |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,97 @@ |
|||||||
|
""" |
||||||
|
This module is part of the 'blup' package and defines a font class as well as |
||||||
|
some methods to load fonts from files and draw text on frames. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
import re |
||||||
|
|
||||||
|
class FontFileError(Exception): |
||||||
|
def __init__(self, value): |
||||||
|
self.__value = value |
||||||
|
def __str__(self): |
||||||
|
return repr(self.__value) |
||||||
|
|
||||||
|
class Font(object): |
||||||
|
|
||||||
|
def __init__(self): |
||||||
|
self.__chars = {} |
||||||
|
self.__spacing = 1 |
||||||
|
self.__height = -1 |
||||||
|
|
||||||
|
@property |
||||||
|
def spacing(self): |
||||||
|
return self.__spacing |
||||||
|
|
||||||
|
@spacing.setter |
||||||
|
def spacing(self, value): |
||||||
|
if type(self.value) == int and self.value > 0: |
||||||
|
self.__spacing = value |
||||||
|
else: |
||||||
|
raise ValueError('illegal spacing given') |
||||||
|
|
||||||
|
@property |
||||||
|
def height(self): |
||||||
|
if self.__height == -1: |
||||||
|
raise ValueError('this font does not contain any characters') |
||||||
|
else: |
||||||
|
return self.__height |
||||||
|
|
||||||
|
def __setitem__(self, item, value): |
||||||
|
height = len(value) |
||||||
|
if self.__height == -1: |
||||||
|
self.__height = height |
||||||
|
elif height != self.__height: |
||||||
|
raise ValueError('character height does not match font height') |
||||||
|
|
||||||
|
if len(set(map(len, value))) != 1: |
||||||
|
raise ValueError('character lines differ in width') |
||||||
|
|
||||||
|
allowedValues = set([0,1]) |
||||||
|
for line in value: |
||||||
|
if set(line) != allowedValues: |
||||||
|
raise ValueError('character contains invalid pixel value') |
||||||
|
|
||||||
|
self.__chars[item] = value |
||||||
|
|
||||||
|
def __getitem__(self, item): |
||||||
|
return self.__chars[item] |
||||||
|
|
||||||
|
|
||||||
|
charPixels = None |
||||||
|
def load(filename): |
||||||
|
f = open(filename, 'r') |
||||||
|
data = f.read() |
||||||
|
|
||||||
|
f = Font() |
||||||
|
for line in f: |
||||||
|
m = re.match('^\s*§(\d+)\s*$', line) |
||||||
|
if m: |
||||||
|
f.spacing = int(m.group(1)) |
||||||
|
continue |
||||||
|
|
||||||
|
m = re.match('^\s*@(\d+)\|(\d+)\s*$', line): |
||||||
|
if m: |
||||||
|
charCode = int(m.group(1)) |
||||||
|
charWidth = int(m.group(2)) |
||||||
|
charPixels = [] |
||||||
|
continue |
||||||
|
|
||||||
|
m = re.match('^\s*([01]+)\s*$', line): |
||||||
|
if m and charPixels != None: |
||||||
|
charRow = m.group(1) |
||||||
|
if len(charRow) < charWidth: |
||||||
|
raise FontFileError('char row does not contain enough pixels') |
||||||
|
row = [] |
||||||
|
for i in xrange(charWidth): |
||||||
|
row.append(int(charRow[i])) |
||||||
|
charPixels.append(row) |
||||||
|
|
||||||
|
continue |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,152 @@ |
|||||||
|
""" |
||||||
|
This module is part of the 'blup' package and contains the definition of a |
||||||
|
basic Frame class. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
class FrameDimension(object): |
||||||
|
""" This class serves as container for the dimensions of a frame. """ |
||||||
|
|
||||||
|
def __init__(self, width=18, height=8, depth=2, channels=1): |
||||||
|
self.width = width |
||||||
|
self.height = height |
||||||
|
self.depth = depth |
||||||
|
self.channels = channels |
||||||
|
|
||||||
|
def size(self): |
||||||
|
return (self.width, self.height) |
||||||
|
|
||||||
|
def depth(self): |
||||||
|
return self.depth |
||||||
|
|
||||||
|
def channels(self): |
||||||
|
return self.channels |
||||||
|
|
||||||
|
def __eq__(self, other): |
||||||
|
if ( self.width == other.width and self.height == other.height and |
||||||
|
self.depth == other.depth and self.channels == other.channels ): |
||||||
|
return True |
||||||
|
else: |
||||||
|
return False |
||||||
|
|
||||||
|
def __ne__(self, other): |
||||||
|
return not self.__eq__(other) |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
return "(%d, %d, %d, %d)" % (self.width, self.height, self.depth, |
||||||
|
self.channels) |
||||||
|
|
||||||
|
class Frame(object): |
||||||
|
""" This class describes a single frame. """ |
||||||
|
|
||||||
|
def __init__(self, dimension): |
||||||
|
""" |
||||||
|
Initialize the frame with the given dimensions. The 'depth' parameter |
||||||
|
describes, how many different values a single pixel can have. |
||||||
|
|
||||||
|
""" |
||||||
|
self.__dimension = dimension |
||||||
|
width = dimension.width |
||||||
|
height = dimension.height |
||||||
|
if dimension.channels == 1: |
||||||
|
self.__pixels = [ [ 0 ] * width for i in range(height) ] |
||||||
|
else: |
||||||
|
self.__pixels = [ [ tuple([0]*dimension.channels) ] * width for i in range(height) ] |
||||||
|
|
||||||
|
@property |
||||||
|
def dimension(self): |
||||||
|
return self.__dimension |
||||||
|
|
||||||
|
@property |
||||||
|
def size(self): |
||||||
|
return (self.__dimension.width, self.__dimension.height) |
||||||
|
@property |
||||||
|
def depth(self): |
||||||
|
return self.__dimension.depth |
||||||
|
@property |
||||||
|
def channels(self): |
||||||
|
return self.__dimension.channels |
||||||
|
|
||||||
|
@property |
||||||
|
def pixels(self): |
||||||
|
return self.__pixels |
||||||
|
|
||||||
|
@pixels.setter |
||||||
|
def pixels(self, pixels): |
||||||
|
if len(pixels) != self.__dimension.height: |
||||||
|
raise ValueError('not enough rows given') |
||||||
|
widths = set(map(lambda r: len(r), pixels)) |
||||||
|
if len(widths) != 1: |
||||||
|
raise ValueError('rows are not of the same length') |
||||||
|
if widths.pop() != self.__dimension.width: |
||||||
|
raise ValueError('rows are too short') |
||||||
|
|
||||||
|
# TODO check depth |
||||||
|
# TODO check number of channels |
||||||
|
|
||||||
|
self.__pixels = pixels |
||||||
|
|
||||||
|
def transform(self, depth): |
||||||
|
""" Transform the frame to a frame with a different depth. """ |
||||||
|
oldmaxval = self.__dimension.depth - 1 |
||||||
|
newmaxval = depth - 1 |
||||||
|
factor = (newmaxval*1.0) / (oldmaxval*1.0) |
||||||
|
newdim = FrameDimension(self.__dimension.width, |
||||||
|
self.__dimension.height, |
||||||
|
depth, |
||||||
|
self.__dimension.channels) |
||||||
|
newframe = Frame(newdim) |
||||||
|
|
||||||
|
transformfkt = lambda p: int(round(p * factor)) |
||||||
|
for y in range(self.__dimension.height): |
||||||
|
if self.__dimension.channels == 1: |
||||||
|
newframe.__pixels[y] = map(transformfkt, self.__pixels[y]) |
||||||
|
else: |
||||||
|
for x in range(self.__dimension.width): |
||||||
|
newframe.__pixels[y][x] = tuple(map(transformfkt, p)) |
||||||
|
|
||||||
|
return newframe |
||||||
|
|
||||||
|
def getPixel(self, x, y): |
||||||
|
""" Return the pixel value at (x, y). """ |
||||||
|
return self.__pixels[y][x] |
||||||
|
|
||||||
|
def setPixel(self, x, y, value): |
||||||
|
""" Set the pixel value at (x, y). """ |
||||||
|
if self.__dimension.channels == 1: |
||||||
|
if value < 0 or value >= self.__dimension.depth: |
||||||
|
raise ValueError('pixel value not in depth range') |
||||||
|
else: |
||||||
|
if len(value) != self.__dimension.channels: |
||||||
|
raise ValueError('channel count does not match') |
||||||
|
for v in value: |
||||||
|
if v < 0 or v >= self.__dimension.depth: |
||||||
|
raise ValueError('pixel value not in depth range') |
||||||
|
self.__pixels[y][x] = value |
||||||
|
|
||||||
|
|
||||||
|
def getPixelsAsBytes(self): |
||||||
|
""" Return the frame as a byte string. """ |
||||||
|
if self.__dimension.channels != 1: |
||||||
|
raise Exception('cannot convert a multi-channel frame') |
||||||
|
|
||||||
|
bytes = '' |
||||||
|
for y in range(self.__dimension.width): |
||||||
|
for x in range(self.__dimension.height): |
||||||
|
bytes += chr(self.__pixels[x][y]) |
||||||
|
return bytes |
||||||
|
|
||||||
|
def invert(self): |
||||||
|
""" Ivert the frame. """ |
||||||
|
for y in range(self.__dimension.height): |
||||||
|
for x in range(self.__dimension.width): |
||||||
|
if self.__dimension.channels == 1: |
||||||
|
self.__pixels[x][y] = ((self.__dimension.depth - 1) - |
||||||
|
self.__pixels[x][y]) |
||||||
|
else: |
||||||
|
self.__pixels[y][x] = tuple(map( |
||||||
|
lambda x: ((self.depth - 1) - x), |
||||||
|
self.__pixels[y][x])) |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,444 @@ |
|||||||
|
""" |
||||||
|
This module is part of the 'blup' package and provides several output modules |
||||||
|
to send frames as well as a mechanism to create them from a string |
||||||
|
specification. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
import re |
||||||
|
import serial |
||||||
|
import socket |
||||||
|
|
||||||
|
from blup import BLP |
||||||
|
|
||||||
|
|
||||||
|
# |
||||||
|
# ---- exceptions ---- |
||||||
|
# |
||||||
|
|
||||||
|
class IllegalOutputSpecificationError(Exception): |
||||||
|
""" |
||||||
|
Will be thrown when a string is given to getOutput (see below) that is not |
||||||
|
matched by any output modules regex. |
||||||
|
|
||||||
|
""" |
||||||
|
def __str__(self): |
||||||
|
return __class__.__name__ |
||||||
|
|
||||||
|
|
||||||
|
# |
||||||
|
# ---- generic output class to be subclassed ---- |
||||||
|
# |
||||||
|
|
||||||
|
class Output(object): |
||||||
|
def sendFrame(self, frame): |
||||||
|
raise Exception('not implemented - just a dummy class') |
||||||
|
|
||||||
|
|
||||||
|
# |
||||||
|
# ---- MCUFOutput (MicroController Unit Frame) ---- |
||||||
|
# |
||||||
|
|
||||||
|
class MCUFOutput(Output): |
||||||
|
""" |
||||||
|
This output module allows to send frames to blinkendevices over a serial |
||||||
|
line using the MCUF protocol. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
moduleRegexDesc = 'mcuf:DEVICE:BAUDRATE[:DEPTH]' |
||||||
|
moduleRegex = '^mcuf:([^:]+):(\d+)(:(\d+))?$' |
||||||
|
|
||||||
|
def __init__(self, port, baudrate, depth=0): |
||||||
|
""" |
||||||
|
Initialize the module with given port and baudrate. If depth is |
||||||
|
specified, every frame will be transformed, if it not already has the |
||||||
|
correct depth. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
self.__port = port |
||||||
|
self.__baudrate = baudrate |
||||||
|
self.__ser = serial.Serial(port=port, baudrate=baudrate) |
||||||
|
self.__depth = depth |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def fromRegexMatch(cls, regexMatch): |
||||||
|
""" Create an instance from a RegexMatch (matched with moduleRegex) """ |
||||||
|
port = regexMatch.group(1) |
||||||
|
baudrate = int(regexMatch.group(2)) |
||||||
|
if regexMatch.group(4): |
||||||
|
depth = int(regexMatch.group(4)) |
||||||
|
else: |
||||||
|
depth = 0 |
||||||
|
return cls(port, baudrate, depth) |
||||||
|
|
||||||
|
def sendFrame(self, frame): |
||||||
|
""" Pass a frame to the module. """ |
||||||
|
(w, h) = frame.size |
||||||
|
|
||||||
|
if self.__depth != 0: |
||||||
|
if frame.depth != self.__depth: |
||||||
|
frame = frame.transform(self.__depth) |
||||||
|
maxval = frame.depth - 1 |
||||||
|
|
||||||
|
framedata = '' |
||||||
|
for y in range(h): |
||||||
|
for x in range(w): |
||||||
|
framedata += chr(frame.getPixel(x, y)) |
||||||
|
|
||||||
|
packet = '\x23\x54\x26\x66' |
||||||
|
packet += '%s%s%s%s' % (chr(h>>8), chr(h & 0xff), |
||||||
|
chr(w>>8), chr(w & 0xff)) |
||||||
|
packet += '\x00\x01\x00%s' % (chr(maxval)) |
||||||
|
packet += framedata |
||||||
|
|
||||||
|
self.__ser.write(packet) |
||||||
|
|
||||||
|
return True |
||||||
|
|
||||||
|
|
||||||
|
# |
||||||
|
# ---- SerialBlupOutput ---- |
||||||
|
# |
||||||
|
|
||||||
|
class SerialBlupOutput(Output): |
||||||
|
""" |
||||||
|
This output module allows sending frames to 18x8 blinkendevices with |
||||||
|
depth 2 over a serial line, by sending every column as a byte. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
moduleRegexDesc = 'serialblup:DEVICE:BAUDRATE' |
||||||
|
moduleRegex = '^serialblup:([^:]+):(\d+)$' |
||||||
|
|
||||||
|
def __init__(self, port, baudrate): |
||||||
|
""" Initialize the output module with the given port. """ |
||||||
|
self.__port = port |
||||||
|
self.__baudrate = baudrate |
||||||
|
self.__ser = serial.Serial(port=port, baudrate=baudrate) |
||||||
|
self.__stx2 = 'a' |
||||||
|
self.__etx2 = 'b' |
||||||
|
self.__stx8 = 'q' |
||||||
|
self.__etx8 = 'b' |
||||||
|
self.__stxRGB = chr(0xca) |
||||||
|
self.__etxRGB = chr(0xfe) |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def fromRegexMatch(cls, regexMatch): |
||||||
|
""" Create an instance from a RegexMatch (matched with moduleRegex) """ |
||||||
|
port = regexMatch.group(1) |
||||||
|
baudrate = int(regexMatch.group(2)) |
||||||
|
return cls(port, baudrate) |
||||||
|
|
||||||
|
def sendFrame(self, frame): |
||||||
|
""" Pass a frame to the module. """ |
||||||
|
if frame.depth not in [2, 16] and frame.channels == 1: |
||||||
|
raise ValueError('%s only supports frames of depth 2 or 16' % |
||||||
|
(self.__class__.__name__)) |
||||||
|
|
||||||
|
if frame.channels not in [1, 3]: |
||||||
|
raise ValueError('%s only supports frames with 1 or 3 channels' % |
||||||
|
(self.__class__.__name__)) |
||||||
|
|
||||||
|
if frame.size != (18, 8): |
||||||
|
raise ValueError('%s currently only supports 18x8 frames' % |
||||||
|
(self.__class__.__name__)) |
||||||
|
|
||||||
|
if frame.channels == 1 and frame.depth == 2: |
||||||
|
bytes = [ 0 ] * 18 |
||||||
|
for x in range(18): |
||||||
|
for y in range(8): |
||||||
|
if frame.getPixel(x, y) == 1: |
||||||
|
bytes[x] += 2**(7 - y) |
||||||
|
|
||||||
|
packet = self.__stx2 + ''.join(map(lambda b: chr(b), bytes)) + self.__etx2 |
||||||
|
elif frame.channels == 1 and frame.depth == 16: |
||||||
|
bytes = [ 0 ] * (18*4) |
||||||
|
for x in range(18): |
||||||
|
for y in range(8): |
||||||
|
pixelval = frame.getPixel(x, y) |
||||||
|
pixelnum = y*18 + x |
||||||
|
bytes[pixelnum/2] += (pixelval << ((pixelnum % 2) * 4)) |
||||||
|
|
||||||
|
packet = self.__stx8 + ''.join(map(lambda b: chr(b), bytes)) + self.__etx8 |
||||||
|
elif frame.channels == 3: |
||||||
|
bytes = [ 0 ] * (18*8*3) |
||||||
|
for y in range(8): |
||||||
|
for x in range(18): |
||||||
|
(r,g,b) = frame.getPixel(x, y) |
||||||
|
pixelnum = y*18 + x |
||||||
|
bytes[3*pixelnum] = r |
||||||
|
bytes[3*pixelnum + 1] = g |
||||||
|
bytes[3*pixelnum + 2] = b |
||||||
|
packet = self.__stxRGB + ''.join(map(lambda b: chr(b), bytes)) + self.__etxRGB |
||||||
|
|
||||||
|
self.__ser.write(packet) |
||||||
|
|
||||||
|
return True |
||||||
|
|
||||||
|
# |
||||||
|
# ---- ShellOuput ---- |
||||||
|
# |
||||||
|
|
||||||
|
class ShellOutput(Output): |
||||||
|
""" This output module prints frames with depth 2 on the terminal. """ |
||||||
|
|
||||||
|
moduleRegexDesc = 'shell[:ON_CHAR:OFF_CHAR]' |
||||||
|
moduleRegex = '^shell(:(.):(.))?$' |
||||||
|
|
||||||
|
def __init__(self, onChar='#', offChar=' '): |
||||||
|
""" Initialize the output. """ |
||||||
|
self.__onChar = onChar |
||||||
|
self.__offChar = offChar |
||||||
|
self.__initialized = False |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def fromRegexMatch(cls, regexMatch): |
||||||
|
""" Create an instance from a RegexMatch (matched with moduleRegex) """ |
||||||
|
if regexMatch.group(2) is not None: |
||||||
|
return cls(regexMatch.group(2), regexMatch.group(3)) |
||||||
|
else: |
||||||
|
return cls() |
||||||
|
|
||||||
|
def sendFrame(self, frame): |
||||||
|
""" Pass a frame to the module. """ |
||||||
|
if frame.depth != 2: |
||||||
|
raise ValueError('%s only supports frames of depth 2' % |
||||||
|
(self.__class__.__name__)) |
||||||
|
|
||||||
|
(width, height) = frame.size |
||||||
|
|
||||||
|
if not self.__initialized: |
||||||
|
self.__initialized = True |
||||||
|
print('\n' * height) |
||||||
|
|
||||||
|
print('\x1b[%dA' % (height + 2)) |
||||||
|
for y in range(height): |
||||||
|
line = '' |
||||||
|
for x in range(width): |
||||||
|
if frame.getPixel(x, y) == 1: |
||||||
|
line += self.__onChar |
||||||
|
else: |
||||||
|
line += self.__offChar |
||||||
|
print(line) |
||||||
|
print('') |
||||||
|
|
||||||
|
return True |
||||||
|
|
||||||
|
# |
||||||
|
# ---- ColorfulShellOuput ---- |
||||||
|
# |
||||||
|
|
||||||
|
class ColorfulShellOutput(Output): |
||||||
|
""" This output module prints frames on the terminal, using colors. """ |
||||||
|
|
||||||
|
moduleRegexDesc = 'colorfulshell' |
||||||
|
moduleRegex = '^colorfulshell?$' |
||||||
|
|
||||||
|
def __init__(self): |
||||||
|
""" Initialize the output. """ |
||||||
|
self.__initialized = False |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def fromRegexMatch(cls, regexMatch): |
||||||
|
""" Create an instance from a RegexMatch (matched with moduleRegex) """ |
||||||
|
return cls() |
||||||
|
|
||||||
|
def sendFrame(self, frame): |
||||||
|
""" Pass a frame to the module. """ |
||||||
|
if frame.channels not in [1, 3]: |
||||||
|
raise ValueError('%s only supports frames with 1 or 3 channels' % |
||||||
|
(self.__class__.__name__)) |
||||||
|
|
||||||
|
(width, height) = frame.size |
||||||
|
|
||||||
|
if not self.__initialized: |
||||||
|
self.__initialized = True |
||||||
|
print('\n' * height) |
||||||
|
|
||||||
|
print('\x1b[%dA' % (height + 2)) |
||||||
|
for y in range(height): |
||||||
|
line = '' |
||||||
|
for x in range(width): |
||||||
|
if frame.channels == 3: |
||||||
|
(r,g,b) = frame.getPixel(x, y) |
||||||
|
if frame.depth != 5: |
||||||
|
factor = 5 / ((frame.depth - 1) * 1.0) |
||||||
|
r = round(r*factor) |
||||||
|
g = round(g*factor) |
||||||
|
b = round(b*factor) |
||||||
|
colorval = 36*r + 6*g + b + 16 |
||||||
|
|
||||||
|
line += '\033[48;05;%dm ' % (colorval) |
||||||
|
elif frame.channels == 1: |
||||||
|
colorval = frame.getPixel(x, y) |
||||||
|
if frame.depth != 24: |
||||||
|
factor = (23 / ((frame.depth - 1) * 1.0)) |
||||||
|
colorval = 232 + colorval * factor |
||||||
|
|
||||||
|
line += '\033[48;05;%dm ' % (colorval) |
||||||
|
print(line) |
||||||
|
print('') |
||||||
|
|
||||||
|
return True |
||||||
|
# |
||||||
|
# ---- BLPOutput ---- |
||||||
|
# |
||||||
|
|
||||||
|
class BLPOutput(Output): |
||||||
|
""" |
||||||
|
This output module sends frames over the network using the UDP-based BLP |
||||||
|
protocol. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
moduleRegexDesc = 'blp[:HOST:PORT]' |
||||||
|
moduleRegex = '^(blp|eblp|e3blp)(:(.+):(\d+))?$' |
||||||
|
|
||||||
|
def __init__(self, host='127.0.0.1', port=4242, protocol=BLP.PROTO_BLP): |
||||||
|
""" Initialize the output. Frames are sent to host:port. """ |
||||||
|
self.__host = host |
||||||
|
self.__port = port |
||||||
|
self.__sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
||||||
|
self.__protocol = protocol |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def fromRegexMatch(cls, regexMatch): |
||||||
|
""" Create an instance from a RegexMatch (matched with moduleRegex) """ |
||||||
|
if regexMatch.group(1) == 'blp': |
||||||
|
protocol = BLP.PROTO_BLP |
||||||
|
elif regexMatch.group(1) == 'eblp': |
||||||
|
protocol = BLP.PROTO_EBLP |
||||||
|
elif regexMatch.group(1) == 'e3blp': |
||||||
|
protocol = BLP.PROTO_E3BLP |
||||||
|
|
||||||
|
if regexMatch.group(3) and regexMatch.group(4): |
||||||
|
host = regexMatch.group(3) |
||||||
|
port = int(regexMatch.group(4)) |
||||||
|
return cls(host, port, protocol) |
||||||
|
else: |
||||||
|
return cls(protocol=protocol) |
||||||
|
|
||||||
|
def sendFrame(self, frame): |
||||||
|
""" Pass a frame to the module. """ |
||||||
|
packet = BLP.frame2blp(frame, protocol=self.__protocol) |
||||||
|
self.__sock.sendto(packet, (self.__host, self.__port)) |
||||||
|
return True |
||||||
|
|
||||||
|
# |
||||||
|
# ---- BlinkenbuntHDOutput ---- |
||||||
|
# |
||||||
|
|
||||||
|
class BlinkenbuntHDOutput(Output): |
||||||
|
moduleRegexDesc = 'bbunthd' |
||||||
|
moduleRegex = '^bbunthd$' |
||||||
|
|
||||||
|
def __init__(self): |
||||||
|
import neopixel |
||||||
|
self.w = 22 |
||||||
|
self.h = 16 |
||||||
|
LED_COUNT = self.w * self.h |
||||||
|
LED_PIN = 13 |
||||||
|
LED_FREQ_HZ = 800000 |
||||||
|
LED_DMA = 5 |
||||||
|
LED_BRIGHTNESS = 50 |
||||||
|
LED_INVERT = False |
||||||
|
LED_PWM = 1 |
||||||
|
|
||||||
|
self.strip = neopixel.Adafruit_NeoPixel( |
||||||
|
LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, |
||||||
|
LED_BRIGHTNESS, LED_PWM |
||||||
|
) |
||||||
|
self.strip.begin() |
||||||
|
self._color_cls = neopixel.Color |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def fromRegexMatch(cls, regexMatch): |
||||||
|
return cls() |
||||||
|
|
||||||
|
def sendFrame(self, frame): |
||||||
|
for y in range(self.h): |
||||||
|
for x in range(self.w): |
||||||
|
if x%2 == 0: |
||||||
|
lednum = x*self.h + y |
||||||
|
else: |
||||||
|
lednum = x*self.h - y + 15 |
||||||
|
pix = frame.getPixel(x, y) |
||||||
|
print(pix) |
||||||
|
self.strip.setPixelColor(lednum, self._color_cls(*pix)) |
||||||
|
self.strip.show() |
||||||
|
|
||||||
|
# |
||||||
|
# ---- PygameOutput ---- |
||||||
|
# |
||||||
|
|
||||||
|
class PygameOutput(Output): |
||||||
|
moduleRegexDesc = 'pygame' |
||||||
|
moduleRegex = '^pygame$' |
||||||
|
|
||||||
|
def __init__(self, width=22, height=16, scalex=8, scaley=8): |
||||||
|
self.width = width |
||||||
|
self.height = height |
||||||
|
self.scalex = scalex |
||||||
|
self.scaley = scaley |
||||||
|
import pygame |
||||||
|
self.__pygame = pygame |
||||||
|
self.screen = pygame.display.set_mode((width*scalex, height*scaley)) |
||||||
|
pygame.display.update() |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def fromRegexMatch(cls, regexMatch): |
||||||
|
return cls() |
||||||
|
|
||||||
|
def sendFrame(self, frame): |
||||||
|
pygame = self.__pygame |
||||||
|
for y in range(self.height): |
||||||
|
for x in range(self.width): |
||||||
|
rect = (x*self.scalex, y*self.scaley, self.scalex, self.scaley) |
||||||
|
pygame.draw.rect(self.screen, frame.getPixel(x, y), rect, 0) |
||||||
|
pygame.display.update() |
||||||
|
#import time |
||||||
|
#time.sleep(0.1) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# |
||||||
|
# ---- output creator ;) ---- |
||||||
|
# |
||||||
|
|
||||||
|
__outputModules = { |
||||||
|
SerialBlupOutput.moduleRegex: SerialBlupOutput, |
||||||
|
MCUFOutput.moduleRegex: MCUFOutput, |
||||||
|
ShellOutput.moduleRegex: ShellOutput, |
||||||
|
ColorfulShellOutput.moduleRegex: ColorfulShellOutput, |
||||||
|
BLPOutput.moduleRegex: BLPOutput, |
||||||
|
BlinkenbuntHDOutput.moduleRegex: BlinkenbuntHDOutput, |
||||||
|
PygameOutput.moduleRegex: PygameOutput, |
||||||
|
} |
||||||
|
|
||||||
|
def getOutput(outputSpec): |
||||||
|
""" |
||||||
|
Return an output module instance described by the given specification. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
for regex in __outputModules.keys(): |
||||||
|
m = re.match(regex, outputSpec) |
||||||
|
if m: |
||||||
|
return __outputModules[regex].fromRegexMatch(regexMatch=m) |
||||||
|
|
||||||
|
raise IllegalOutputSpecificationError() |
||||||
|
|
||||||
|
def getOutputDescriptions(): |
||||||
|
""" |
||||||
|
Return a string containing the moduleRegexDesc of every available output |
||||||
|
module. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
s = "" |
||||||
|
for outputModule in __outputModules.values(): |
||||||
|
s += " %s\n" % (outputModule.moduleRegexDesc) |
||||||
|
return s |
||||||
|
|
@ -0,0 +1,24 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import sys |
||||||
|
|
||||||
|
import blup.animation |
||||||
|
import writebml |
||||||
|
|
||||||
|
anim = blup.animation.load(sys.argv[1]) |
||||||
|
plasmaanim = blup.animation.load('/tmp/plasma.bml') |
||||||
|
newanim = blup.animation.Animation(anim.dimension) |
||||||
|
|
||||||
|
plasmaFrame = 0 |
||||||
|
for f in anim: |
||||||
|
newframe = blup.animation.AnimationFrame(f.dimension, f.delay) |
||||||
|
for x in range(anim.dimension.width): |
||||||
|
for y in range(anim.dimension.height): |
||||||
|
p = f.getPixel(x,y) |
||||||
|
if max(p) > 14: |
||||||
|
newframe.setPixel(x,y, plasmaanim[plasmaFrame].getPixel(x,y)) |
||||||
|
newanim.addFrame(newframe) |
||||||
|
plasmaFrame += 1 |
||||||
|
|
||||||
|
writebml.writeBml(newanim, '/tmp/colormarq.bml') |
||||||
|
|
@ -0,0 +1,44 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import colorsys |
||||||
|
import time |
||||||
|
|
||||||
|
import blup.output |
||||||
|
import blup.frame |
||||||
|
|
||||||
|
dim = blup.frame.FrameDimension(18,8,16,3) |
||||||
|
frame = blup.frame.Frame(dim) |
||||||
|
|
||||||
|
HEIGHT = 8 |
||||||
|
WIDTH = 18 |
||||||
|
|
||||||
|
#h = 0.0 |
||||||
|
#for y in range(HEIGHT): |
||||||
|
# h += 1.0 / (HEIGHT * 1.0) |
||||||
|
# v = 0 |
||||||
|
# s = 0.7 |
||||||
|
# for x in range(WIDTH): |
||||||
|
# v += 1.0 / (WIDTH * 1.0) |
||||||
|
# print s |
||||||
|
# color = colorsys.hsv_to_rgb(h, s, v) |
||||||
|
# color = tuple(map(lambda c: int(round(c * 15)), color)) |
||||||
|
# print color |
||||||
|
# frame.setPixel(x, y, color) |
||||||
|
|
||||||
|
for y in range(HEIGHT): |
||||||
|
for x in range(WIDTH): |
||||||
|
h = (x * 1.0) / (WIDTH - 1.0) |
||||||
|
s = 1.0 - (y * 1.0) / (HEIGHT - 0.0) |
||||||
|
v = 1.0 - (y * 1.0) / (HEIGHT - 0.0) |
||||||
|
color = colorsys.hsv_to_rgb(h, s, v) |
||||||
|
color = tuple(map(lambda c: int(round(c * 15)), color)) |
||||||
|
frame.setPixel(x, y, color) |
||||||
|
|
||||||
|
out = blup.output.getOutput('e3blp') |
||||||
|
while True: |
||||||
|
out.sendFrame(frame) |
||||||
|
time.sleep(0.4) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,34 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import sys |
||||||
|
|
||||||
|
import blup.animation |
||||||
|
import blup.frame |
||||||
|
import writebml |
||||||
|
import random |
||||||
|
|
||||||
|
dim = blup.frame.FrameDimension(18, 8, 16, 3) |
||||||
|
newanim = blup.animation.Animation(dim) |
||||||
|
|
||||||
|
|
||||||
|
num = 10 |
||||||
|
horiz = True |
||||||
|
delay = 100 |
||||||
|
for i in range(num): |
||||||
|
newcolor = (random.randint(0, 15), random.randint(0, 15), random.randint(0, 15)) |
||||||
|
horiz = not horiz |
||||||
|
newframe = blup.animation.AnimationFrame(dim, delay) |
||||||
|
if horiz: |
||||||
|
for x in range(dim.size()[0]): |
||||||
|
for y in range(dim.size()[1]): |
||||||
|
newframe.setPixel(x, y, newcolor) |
||||||
|
newanim.addFrame(newframe) |
||||||
|
else: |
||||||
|
for y in range(dim.size()[1]): |
||||||
|
for x in range(dim.size()[0]): |
||||||
|
newframe.setPixel(x, y, newcolor) |
||||||
|
newanim.addFrame(newframe) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
writebml.writeBml(newanim, '/tmp/colorwischer.bml') |
@ -0,0 +1,104 @@ |
|||||||
|
# Major library imports |
||||||
|
import atexit |
||||||
|
import pyaudio |
||||||
|
from numpy import zeros, short, fromstring, array |
||||||
|
from numpy.fft import fft |
||||||
|
|
||||||
|
import colorsys |
||||||
|
import time |
||||||
|
import blup.frame |
||||||
|
import blup.output |
||||||
|
|
||||||
|
#NUM_SAMPLES = 512 |
||||||
|
NUM_SAMPLES = 36 |
||||||
|
#NUM_SAMPLES = 18 |
||||||
|
#NUM_SAMPLES = 16 |
||||||
|
#SAMPLING_RATE = 11025 |
||||||
|
#SAMPLING_RATE = 11024 / 2 |
||||||
|
SAMPLING_RATE = 1100 |
||||||
|
|
||||||
|
_stream = None |
||||||
|
|
||||||
|
def read_fft(): |
||||||
|
global _stream |
||||||
|
pa = None |
||||||
|
|
||||||
|
def cleanup_audio(): |
||||||
|
if _stream: |
||||||
|
_stream.stop_stream() |
||||||
|
_stream.close() |
||||||
|
pa.terminate() |
||||||
|
|
||||||
|
if _stream is None: |
||||||
|
pa = pyaudio.PyAudio() |
||||||
|
_stream = pa.open(format=pyaudio.paInt16, channels=1, |
||||||
|
rate=SAMPLING_RATE, |
||||||
|
input=True, frames_per_buffer=NUM_SAMPLES) |
||||||
|
atexit.register(cleanup_audio) |
||||||
|
|
||||||
|
audio_data = fromstring(_stream.read(NUM_SAMPLES), dtype=short) |
||||||
|
normalized_data = audio_data / 32768.0 |
||||||
|
|
||||||
|
return fft(normalized_data)[1:1+NUM_SAMPLES/2] |
||||||
|
|
||||||
|
def flatten_fft(scale = 1.0): |
||||||
|
""" |
||||||
|
Produces a nicer graph, I'm not sure if this is correct |
||||||
|
""" |
||||||
|
for i, v in enumerate(read_fft()): |
||||||
|
yield scale * (i * v) / NUM_SAMPLES |
||||||
|
|
||||||
|
|
||||||
|
def makeColor(x): |
||||||
|
hue = (7-x) / 7.0 / 3.0 -0.1 |
||||||
|
if hue < 0: |
||||||
|
hue += 1 |
||||||
|
rgb = map(lambda x: int(round(x*7)), colorsys.hsv_to_rgb(hue, 1, 1)) |
||||||
|
return rgb |
||||||
|
def makeSpectrumFrame(spectrum): |
||||||
|
f = blup.frame.Frame(blup.frame.FrameDimension(18,8,8,3)) |
||||||
|
for x, y in enumerate(spectrum): |
||||||
|
if y > 7: |
||||||
|
y = 7 |
||||||
|
y = int(y) |
||||||
|
for i in range(y): |
||||||
|
#val = (7,7,7) |
||||||
|
val = makeColor(i) |
||||||
|
f.setPixel(x, 7-i, val) |
||||||
|
return f |
||||||
|
|
||||||
|
def draw(): |
||||||
|
'''Draw 3 different colour graphs''' |
||||||
|
global NUM_SAMPLES |
||||||
|
audio = array(list(flatten_fft(scale = 80))) |
||||||
|
freqs = len(audio) |
||||||
|
bass, mid, treble = triple(audio) |
||||||
|
|
||||||
|
colours = (0.5, 1.0, 0.5), (1, 1, 0), (1, 0.2, 0.5) |
||||||
|
|
||||||
|
fill(0, 0, 1) |
||||||
|
rect(0, 0, WIDTH, 400) |
||||||
|
translate(50, 200) |
||||||
|
|
||||||
|
for spectrum, col in zip((bass, mid, treble), colours): |
||||||
|
fill(col) |
||||||
|
for i, s in enumerate(spectrum): |
||||||
|
rect(i, 0, 1, -abs(s)) |
||||||
|
else: |
||||||
|
translate(i, 0) |
||||||
|
|
||||||
|
audio = array(list(flatten_fft(scale = 80))) |
||||||
|
|
||||||
|
|
||||||
|
out = blup.output.getOutput('colorfulshell') |
||||||
|
while True: |
||||||
|
audio = array(list(flatten_fft(scale=80))) |
||||||
|
#audio = map(abs, audio) |
||||||
|
#print len(audio) |
||||||
|
frame = makeSpectrumFrame([ int((x/18.0)*8) for x in range(18)]) |
||||||
|
frame = makeSpectrumFrame(audio) |
||||||
|
#print map(int,audio) |
||||||
|
out.sendFrame(frame) |
||||||
|
#time.sleep(0.1) |
||||||
|
|
||||||
|
|
@ -0,0 +1,63 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import colorsys |
||||||
|
import random |
||||||
|
|
||||||
|
import blup.frame |
||||||
|
import blup.output |
||||||
|
import blup.animation |
||||||
|
|
||||||
|
# thanks to |
||||||
|
# http://quiteuseful.co.uk/post/96424751/beautiful-algorithms-1-fire-part-2 |
||||||
|
|
||||||
|
|
||||||
|
dim = blup.frame.FrameDimension(18,8,16,3) |
||||||
|
anim = blup.animation.Animation(dim) |
||||||
|
|
||||||
|
def getRandomColor(maxval): |
||||||
|
return mmeap(lambda x: int(round(x*maxval)), colorsys.hsv_to_rgb(random.random() % 0.16666666, 1, 1)) |
||||||
|
|
||||||
|
def colorAvg(colors): |
||||||
|
r = 0 |
||||||
|
g = 0 |
||||||
|
b = 0 |
||||||
|
for c in colors: |
||||||
|
r += c[0] |
||||||
|
g += c[1] |
||||||
|
b += c[2] |
||||||
|
avg = (r,g,b) |
||||||
|
avg = map(lambda x: int(round(x / (len(colors) * 1.0))), avg) |
||||||
|
return avg |
||||||
|
|
||||||
|
|
||||||
|
for i in range(100): |
||||||
|
randRow = [ getRandomColor(dim.depth - 1) for i in range(dim.width) ] |
||||||
|
print randRow |
||||||
|
|
||||||
|
f = blup.animation.AnimationFrame(dim, 60) |
||||||
|
|
||||||
|
for y in range(dim.height - 1, -1, -1): |
||||||
|
for x in range(dim.width): |
||||||
|
colors = [] |
||||||
|
if x >=1 : |
||||||
|
colors.append(f.getPixel(x-1,y)) |
||||||
|
if x < dim.width - 1: |
||||||
|
pass |
||||||
|
colors.append(f.getPixel(x+1,y)) |
||||||
|
if y < dim.height - 1: |
||||||
|
colors.append(f.getPixel(x, y+1)) |
||||||
|
else: |
||||||
|
#colors.append(randRow[y]) |
||||||
|
colors.append(getRandomColor(dim.depth - 1)) |
||||||
|
#colors = [randRow[x]] |
||||||
|
c = colorAvg(colors) |
||||||
|
f.setPixel(x, y, c) |
||||||
|
anim.addFrame(f) |
||||||
|
|
||||||
|
#out = blup.output.getOutput('e3blp:bbunt:4242') |
||||||
|
out = blup.output.getOutput('colorfulshell') |
||||||
|
player = blup.animation.AnimationPlayer() |
||||||
|
player.play(anim, out) |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,84 @@ |
|||||||
|
|
||||||
|
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler |
||||||
|
import socket |
||||||
|
import cgi |
||||||
|
import json |
||||||
|
import time |
||||||
|
import os.path |
||||||
|
import threading |
||||||
|
|
||||||
|
TELNET_HOST = 'localhost' |
||||||
|
TELNET_PORT = 4243 |
||||||
|
|
||||||
|
DOCROOT = '/var/tmp/blup2/blayer-webif' |
||||||
|
UPLOAD_DIR = '/var/tmp/blup2/blm/incoming' |
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||||
|
sock.connect((TELNET_HOST, TELNET_PORT)) |
||||||
|
socklock = threading.Lock() |
||||||
|
|
||||||
|
class HTTPRequestHandler(BaseHTTPRequestHandler): |
||||||
|
def do_GET(self): |
||||||
|
self.send_response(200) |
||||||
|
self.send_header('Content-type', 'text/html') |
||||||
|
self.end_headers() |
||||||
|
print self.path |
||||||
|
#self.wfile.write('<form action="bla" method="post"><input type="text" name="text" /><input type="submit" value="ok" /></form>') |
||||||
|
|
||||||
|
p = os.path.join(DOCROOT, self.path[1:]) |
||||||
|
print p |
||||||
|
if os.path.isfile(p): |
||||||
|
f = open(p, 'r') |
||||||
|
data = f.read() |
||||||
|
f.close() |
||||||
|
self.wfile.write(data) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def do_POST(self): |
||||||
|
|
||||||
|
if self.path == '/do_upload': |
||||||
|
formdata = cgi.FieldStorage( |
||||||
|
fp=self.rfile, headers=self.headers, |
||||||
|
environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers['Content-Type']}) |
||||||
|
|
||||||
|
fileField = formdata['file'] |
||||||
|
|
||||||
|
f = open(os.path.join(UPLOAD_DIR, fileField.filename), 'w') |
||||||
|
f.write(fileField.file.read()) |
||||||
|
f.close() |
||||||
|
|
||||||
|
sock.send(json.dumps({"cmd": "refresh"}) + '\n') |
||||||
|
print 'server answer to refresh cmd: ', sock.recv(1024) |
||||||
|
|
||||||
|
self.send_response(200); |
||||||
|
self.end_headers(); |
||||||
|
|
||||||
|
return |
||||||
|
|
||||||
|
postdata = self.rfile.read(int(self.headers.getheader('content-length'))) |
||||||
|
#self.wfile.write('test') |
||||||
|
|
||||||
|
if postdata[-1:] != '\n': |
||||||
|
postdata += '\n' |
||||||
|
print 'postdata:', postdata |
||||||
|
|
||||||
|
with socklock: |
||||||
|
sock.send(postdata) |
||||||
|
time.sleep(0.1) |
||||||
|
resp = sock.recv(1024 * 10) |
||||||
|
#sock.shutdown(socket.SHUT_RDWR) |
||||||
|
#sock.close() |
||||||
|
|
||||||
|
self.send_response(200) |
||||||
|
self.send_header('Content-type', 'text/html') |
||||||
|
self.send_header('Content-length', len(resp)) |
||||||
|
self.end_headers() |
||||||
|
print 'resp:', resp |
||||||
|
self.wfile.write(resp) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
server = HTTPServer(('0.0.0.0',8080), HTTPRequestHandler) |
||||||
|
server.serve_forever() |
||||||
|
|
@ -0,0 +1,43 @@ |
|||||||
|
|
||||||
|
def loadBbm(filename): |
||||||
|
""" Parse a bbm file and return an Animation object. """ |
||||||
|
|
||||||
|
def getint16(vals): |
||||||
|
return (cals[2]>>8) + vals[3] |
||||||
|
def getint32(vals): |
||||||
|
return (vals[0]>>24) + (vals[1]>>16) + (cals[2]>>8) + vals[3] |
||||||
|
|
||||||
|
f = open(filename, 'r') |
||||||
|
rawdata = f.read() |
||||||
|
f.close() |
||||||
|
|
||||||
|
data = [ ord(x) for x in rawdata ] |
||||||
|
|
||||||
|
if getint32(data[0:4]) != 0x23542666: |
||||||
|
raise ValueError('magic does not match') |
||||||
|
|
||||||
|
height = getint16(data[4:6]) |
||||||
|
width = getint16(data[6:8]) |
||||||
|
channels = getint16(data[8:10]) |
||||||
|
maxval = getint16(data[10:12]) |
||||||
|
|
||||||
|
framecnt = getint32(data[10:14]) |
||||||
|
duration = getint32(data[14:18]) |
||||||
|
frameptr = getint32(data[18:22]) |
||||||
|
|
||||||
|
# TODO: parse additional headers |
||||||
|
|
||||||
|
if rawdata[frameptr:(frameptr+4)] != 'frms': |
||||||
|
raise ValueError('frame pointer does not point to frame start marker') |
||||||
|
|
||||||
|
framedata = data[frameptr + 4:] |
||||||
|
framesize = width*height*channels |
||||||
|
|
||||||
|
frames = [] |
||||||
|
while True: |
||||||
|
pass |
||||||
|
|
||||||
|
raise Exception('uarrgh!!') |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,23 @@ |
|||||||
|
# BlinkenLights Movie 18x8 |
||||||
|
# loop = yes |
||||||
|
|
||||||
|
@200 |
||||||
|
000000000000000000 |
||||||
|
000011100011100000 |
||||||
|
000111110111110000 |
||||||
|
000111111111110000 |
||||||
|
000011111111100000 |
||||||
|
000000111110000000 |
||||||
|
000000001000000000 |
||||||
|
000000000000000000 |
||||||
|
|
||||||
|
@800 |
||||||
|
000011100011100000 |
||||||
|
000111110111110000 |
||||||
|
001111111111111000 |
||||||
|
001111111111111000 |
||||||
|
000111111111110000 |
||||||
|
000011111111100000 |
||||||
|
000000111110000000 |
||||||
|
000000001000000000 |
||||||
|
|
@ -0,0 +1,13 @@ |
|||||||
|
#!/usr/bin/pyton |
||||||
|
|
||||||
|
import blup.frame |
||||||
|
import blup.output |
||||||
|
import blup.animation |
||||||
|
|
||||||
|
out = blup.output.getOutput('e3blp') |
||||||
|
|
||||||
|
points = [] |
||||||
|
|
||||||
|
|
||||||
|
for i in |
||||||
|
|
@ -0,0 +1,183 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import threading |
||||||
|
import os |
||||||
|
import os.path |
||||||
|
import random |
||||||
|
import time |
||||||
|
import sys |
||||||
|
import getopt |
||||||
|
|
||||||
|
import blup.output |
||||||
|
import blup.animation |
||||||
|
import blup.frame |
||||||
|
|
||||||
|
|
||||||
|
class AnimationLoaderThread(threading.Thread): |
||||||
|
""" |
||||||
|
This class is used by the player to pre-load an animation while another one |
||||||
|
is being played. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
def __init__(self, filename): |
||||||
|
threading.Thread.__init__(self) |
||||||
|
self.__filename = filename |
||||||
|
self.__anim = None |
||||||
|
self.__error = False |
||||||
|
|
||||||
|
def run(self): |
||||||
|
try: |
||||||
|
self.__anim = blup.animation.load(self.__filename) |
||||||
|
except Exception as e: |
||||||
|
print '%s: %s while loading %s' % (self.__class__.__name__, |
||||||
|
repr(e), |
||||||
|
self.__filename) |
||||||
|
self.__error = True |
||||||
|
self.__anim = None |
||||||
|
|
||||||
|
def getAnim(self): |
||||||
|
self.join() |
||||||
|
return self.__anim |
||||||
|
|
||||||
|
|
||||||
|
class MiniPlayer(object): |
||||||
|
""" |
||||||
|
Minimal animation player that does nothing but randomly selecting |
||||||
|
animations out of a directory and playing them. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
def __init__(self, animDir, output): |
||||||
|
self.__animDir = animDir |
||||||
|
self.__output = output |
||||||
|
self.loopTime = 10000 |
||||||
|
self.gap = 800 |
||||||
|
self.maxPlayNext = 3 |
||||||
|
self.__playNext = [] |
||||||
|
self.__running = False |
||||||
|
|
||||||
|
def terminate(self): |
||||||
|
self.__running = False |
||||||
|
|
||||||
|
def playNext(self, filename): |
||||||
|
""" Add an animation to the queue. """ |
||||||
|
|
||||||
|
if filename.find('/') >= 0: |
||||||
|
raise ValueError('filename must not contain slashes') |
||||||
|
|
||||||
|
if ( os.path.isfile(os.path.join(self.__animDir, filename)) and |
||||||
|
len(self.__playNext) < self.maxPlayNext ): |
||||||
|
self.__playNext.append(filename) |
||||||
|
else: |
||||||
|
return False |
||||||
|
|
||||||
|
def getNextFilename(self): |
||||||
|
""" |
||||||
|
Return the next animation filename to be played, either from the queue, |
||||||
|
or randomly chosen. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
if len(self.__playNext) > 0 and os.path.isfile(self.__playNext[0]): |
||||||
|
return self.__playNext.pop(0) |
||||||
|
else: |
||||||
|
files = os.listdir(self.__animDir) |
||||||
|
return random.choice(files) |
||||||
|
|
||||||
|
def run(self): |
||||||
|
""" |
||||||
|
Runs the player until terminate() gets called (e.g. by another thread). |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
self.__running = True |
||||||
|
currentAnim = None |
||||||
|
player = blup.animation.AnimationPlayer() |
||||||
|
|
||||||
|
while self.__running: |
||||||
|
|
||||||
|
# begin to load the next animation |
||||||
|
filename = os.path.join(self.__animDir, self.getNextFilename()) |
||||||
|
loader = AnimationLoaderThread(filename) |
||||||
|
loader.start() |
||||||
|
|
||||||
|
# play the animation in case it had been successfully loaded before |
||||||
|
if currentAnim is not None: |
||||||
|
if currentAnim.duration < self.loopTime: |
||||||
|
count = self.loopTime / currentAnim.duration |
||||||
|
else: |
||||||
|
count = 1 |
||||||
|
player.play(currentAnim, self.__output, count=count) |
||||||
|
|
||||||
|
# show a blank frame for some thime |
||||||
|
if self.gap > 0 and self.__running: |
||||||
|
# TODO: use correct frame size |
||||||
|
dim = blup.frame.FrameDimension(18,8,8,3) |
||||||
|
self.__output.sendFrame(blup.frame.Frame(dim)) |
||||||
|
time.sleep(self.gap / 1000.0) |
||||||
|
|
||||||
|
# get the next animation from the loader |
||||||
|
currentAnim = loader.getAnim() |
||||||
|
|
||||||
|
|
||||||
|
def printUsage(errMsg=None): |
||||||
|
if errMsg is not None: |
||||||
|
print 'error: %s\n' % (errMsg) |
||||||
|
print 'usage: %s [OPTIONS] PATH' % (sys.argv[0]) |
||||||
|
print 'where PATH is the directory containing the animations to play' |
||||||
|
print 'supported options:' |
||||||
|
print ' -o OUTPUT where to output the frames (default: shell)' |
||||||
|
print ' --output OUTPUT\n' |
||||||
|
print ' -h print this text' |
||||||
|
print ' --help' |
||||||
|
|
||||||
|
def main(): |
||||||
|
try: |
||||||
|
(opts, args) = getopt.gnu_getopt(sys.argv, 'ho:', ['help', 'output=']) |
||||||
|
opts = dict(opts) |
||||||
|
except getopt.GetoptError as e: |
||||||
|
printUsage(e.msg) |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
if opts.has_key('--help'): |
||||||
|
printUsage() |
||||||
|
sys.exit(0) |
||||||
|
|
||||||
|
if opts.has_key('-o'): |
||||||
|
output = opts['-o'] |
||||||
|
elif opts.has_key('--output'): |
||||||
|
output = opts['--output'] |
||||||
|
else: |
||||||
|
output = 'shell' |
||||||
|
|
||||||
|
try: |
||||||
|
out = blup.output.getOutput(output) |
||||||
|
except blup.output.IllegalOutputSpecificationError: |
||||||
|
print 'illegal output specification' |
||||||
|
print 'available outputs:' |
||||||
|
print blup.output.getOutputDescriptions() |
||||||
|
sys.exit(1) |
||||||
|
except Exception as e: |
||||||
|
print 'could not initialize output: %s' % (str(e)) |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
if len(args) != 2: |
||||||
|
printUsage() |
||||||
|
sys.exit(1) |
||||||
|
else: |
||||||
|
animDir = args[1] |
||||||
|
|
||||||
|
if not os.path.isdir(animDir): |
||||||
|
print '%s is not a directory' % (animDir) |
||||||
|
sys.exit(1) |
||||||
|
|
||||||
|
p = MiniPlayer(animDir, out) |
||||||
|
try: |
||||||
|
p.run() |
||||||
|
except KeyboardInterrupt: |
||||||
|
sys.exit(0) |
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
main() |
||||||
|
|
@ -0,0 +1,873 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<blm width="18" height="8" bits="4" channels="3"> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000000000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000000000000000000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000f00f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000f00000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000000000000000f00000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000f00f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000f00000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000f00000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000f00000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000f00000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000f00000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000000000000f00000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000f00f00000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000f00000f00000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000f00000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000f00000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000f00000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000f00000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000000000f00000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000f00f00000000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000f00000f00000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000f00000000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000f00000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000f00000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000f00000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000000f00000000000000000f00</row> |
||||||
|
<row>000000000000000000000000000000000f00f00000000000f00f00</row> |
||||||
|
<row>000000000000000000000000000000000f00000f00000f00000f00</row> |
||||||
|
<row>000000000000000000000000000000000f00000000f00000000f00</row> |
||||||
|
<row>000000000000000000000000000000000f00000000000000000f00</row> |
||||||
|
<row>000000000000000000000000000000000f00000000000000000f00</row> |
||||||
|
<row>000000000000000000000000000000000f00000000000000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000f00000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000f00f00000000000f00f00000</row> |
||||||
|
<row>000000000000000000000000000000f00000f00000f00000f00000</row> |
||||||
|
<row>000000000000000000000000000000f00000000f00000000f00000</row> |
||||||
|
<row>000000000000000000000000000000f00000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000f00000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000f00000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000f00000000000000000f00000f00</row> |
||||||
|
<row>000000000000000000000000000f00f00000000000f00f00000f00</row> |
||||||
|
<row>000000000000000000000000000f00000f00000f00000f00000f00</row> |
||||||
|
<row>000000000000000000000000000f00000000f00000000f00000f00</row> |
||||||
|
<row>000000000000000000000000000f00000000000000000f00000f00</row> |
||||||
|
<row>000000000000000000000000000f00000000000000000f00000f00</row> |
||||||
|
<row>000000000000000000000000000f00000000000000000f00000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000f00000000000000000f00000f00f00</row> |
||||||
|
<row>000000000000000000000000f00f00000000000f00f00000f00000</row> |
||||||
|
<row>000000000000000000000000f00000f00000f00000f00000f00000</row> |
||||||
|
<row>000000000000000000000000f00000000f00000000f00000f00f00</row> |
||||||
|
<row>000000000000000000000000f00000000000000000f00000f00000</row> |
||||||
|
<row>000000000000000000000000f00000000000000000f00000f00000</row> |
||||||
|
<row>000000000000000000000000f00000000000000000f00000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000f00000000000000000f00000f00f00f00</row> |
||||||
|
<row>000000000000000000000f00f00000000000f00f00000f00000000</row> |
||||||
|
<row>000000000000000000000f00000f00000f00000f00000f00000000</row> |
||||||
|
<row>000000000000000000000f00000000f00000000f00000f00f00f00</row> |
||||||
|
<row>000000000000000000000f00000000000000000f00000f00000000</row> |
||||||
|
<row>000000000000000000000f00000000000000000f00000f00000000</row> |
||||||
|
<row>000000000000000000000f00000000000000000f00000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000f00000000000000000f00000f00f00f00f00</row> |
||||||
|
<row>000000000000000000f00f00000000000f00f00000f00000000000</row> |
||||||
|
<row>000000000000000000f00000f00000f00000f00000f00000000000</row> |
||||||
|
<row>000000000000000000f00000000f00000000f00000f00f00f00f00</row> |
||||||
|
<row>000000000000000000f00000000000000000f00000f00000000f00</row> |
||||||
|
<row>000000000000000000f00000000000000000f00000f00000000000</row> |
||||||
|
<row>000000000000000000f00000000000000000f00000f00000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000f00000000000000000f00000f00f00f00f00f00</row> |
||||||
|
<row>000000000000000f00f00000000000f00f00000f00000000000000</row> |
||||||
|
<row>000000000000000f00000f00000f00000f00000f00000000000000</row> |
||||||
|
<row>000000000000000f00000000f00000000f00000f00f00f00f00f00</row> |
||||||
|
<row>000000000000000f00000000000000000f00000f00000000f00000</row> |
||||||
|
<row>000000000000000f00000000000000000f00000f00000000000f00</row> |
||||||
|
<row>000000000000000f00000000000000000f00000f00000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000f00000000000000000f00000f00f00f00f00f00f00</row> |
||||||
|
<row>000000000000f00f00000000000f00f00000f00000000000000000</row> |
||||||
|
<row>000000000000f00000f00000f00000f00000f00000000000000000</row> |
||||||
|
<row>000000000000f00000000f00000000f00000f00f00f00f00f00f00</row> |
||||||
|
<row>000000000000f00000000000000000f00000f00000000f00000000</row> |
||||||
|
<row>000000000000f00000000000000000f00000f00000000000f00000</row> |
||||||
|
<row>000000000000f00000000000000000f00000f00000000000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000f00000000000000000f00000f00f00f00f00f00f00000</row> |
||||||
|
<row>000000000f00f00000000000f00f00000f00000000000000000f00</row> |
||||||
|
<row>000000000f00000f00000f00000f00000f00000000000000000f00</row> |
||||||
|
<row>000000000f00000000f00000000f00000f00f00f00f00f00f00000</row> |
||||||
|
<row>000000000f00000000000000000f00000f00000000f00000000000</row> |
||||||
|
<row>000000000f00000000000000000f00000f00000000000f00000000</row> |
||||||
|
<row>000000000f00000000000000000f00000f00000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000f00000000000000000f00000f00f00f00f00f00f00000000</row> |
||||||
|
<row>000000f00f00000000000f00f00000f00000000000000000f00000</row> |
||||||
|
<row>000000f00000f00000f00000f00000f00000000000000000f00000</row> |
||||||
|
<row>000000f00000000f00000000f00000f00f00f00f00f00f00000000</row> |
||||||
|
<row>000000f00000000000000000f00000f00000000f00000000000000</row> |
||||||
|
<row>000000f00000000000000000f00000f00000000000f00000000000</row> |
||||||
|
<row>000000f00000000000000000f00000f00000000000000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00000000000000000f00000f00f00f00f00f00f00000000f00</row> |
||||||
|
<row>000f00f00000000000f00f00000f00000000000000000f00000f00</row> |
||||||
|
<row>000f00000f00000f00000f00000f00000000000000000f00000f00</row> |
||||||
|
<row>000f00000000f00000000f00000f00f00f00f00f00f00000000f00</row> |
||||||
|
<row>000f00000000000000000f00000f00000000f00000000000000f00</row> |
||||||
|
<row>000f00000000000000000f00000f00000000000f00000000000f00</row> |
||||||
|
<row>000f00000000000000000f00000f00000000000000f00000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000000000000000f00000f00f00f00f00f00f00000000f00000</row> |
||||||
|
<row>f00f00000000000f00f00000f00000000000000000f00000f00f00</row> |
||||||
|
<row>f00000f00000f00000f00000f00000000000000000f00000f00000</row> |
||||||
|
<row>f00000000f00000000f00000f00f00f00f00f00f00000000f00000</row> |
||||||
|
<row>f00000000000000000f00000f00000000f00000000000000f00000</row> |
||||||
|
<row>f00000000000000000f00000f00000000000f00000000000f00000</row> |
||||||
|
<row>f00000000000000000f00000f00000000000000f00000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000f00000f00f00f00f00f00f00000000f00000000</row> |
||||||
|
<row>f00000000000f00f00000f00000000000000000f00000f00f00000</row> |
||||||
|
<row>000f00000f00000f00000f00000000000000000f00000f00000f00</row> |
||||||
|
<row>000000f00000000f00000f00f00f00f00f00f00000000f00000000</row> |
||||||
|
<row>000000000000000f00000f00000000f00000000000000f00000000</row> |
||||||
|
<row>000000000000000f00000f00000000000f00000000000f00000000</row> |
||||||
|
<row>000000000000000f00000f00000000000000f00000000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000f00000f00f00f00f00f00f00000000f00000000000</row> |
||||||
|
<row>000000000f00f00000f00000000000000000f00000f00f00000000</row> |
||||||
|
<row>f00000f00000f00000f00000000000000000f00000f00000f00000</row> |
||||||
|
<row>000f00000000f00000f00f00f00f00f00f00000000f00000000f00</row> |
||||||
|
<row>000000000000f00000f00000000f00000000000000f00000000000</row> |
||||||
|
<row>000000000000f00000f00000000000f00000000000f00000000000</row> |
||||||
|
<row>000000000000f00000f00000000000000f00000000f00000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000f00000f00f00f00f00f00f00000000f00000000000000</row> |
||||||
|
<row>000000f00f00000f00000000000000000f00000f00f00000000000</row> |
||||||
|
<row>000f00000f00000f00000000000000000f00000f00000f00000f00</row> |
||||||
|
<row>f00000000f00000f00f00f00f00f00f00000000f00000000f00000</row> |
||||||
|
<row>000000000f00000f00000000f00000000000000f00000000000000</row> |
||||||
|
<row>000000000f00000f00000000000f00000000000f00000000000000</row> |
||||||
|
<row>000000000f00000f00000000000000f00000000f00000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000f00000f00f00f00f00f00f00000000f00000000000000000</row> |
||||||
|
<row>000f00f00000f00000000000000000f00000f00f00000000000f00</row> |
||||||
|
<row>f00000f00000f00000000000000000f00000f00000f00000f00000</row> |
||||||
|
<row>000000f00000f00f00f00f00f00f00000000f00000000f00000000</row> |
||||||
|
<row>000000f00000f00000000f00000000000000f00000000000000000</row> |
||||||
|
<row>000000f00000f00000000000f00000000000f00000000000000000</row> |
||||||
|
<row>000000f00000f00000000000000f00000000f00000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00000f00f00f00f00f00f00000000f00000000000000000f00</row> |
||||||
|
<row>f00f00000f00000000000000000f00000f00f00000000000f00f00</row> |
||||||
|
<row>000f00000f00000000000000000f00000f00000f00000f00000f00</row> |
||||||
|
<row>000f00000f00f00f00f00f00f00000000f00000000f00000000f00</row> |
||||||
|
<row>000f00000f00000000f00000000000000f00000000000000000f00</row> |
||||||
|
<row>000f00000f00000000000f00000000000f00000000000000000f00</row> |
||||||
|
<row>000f00000f00000000000000f00000000f00000000000000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000f00f00f00f00f00f00000000f00000000000000000f00000</row> |
||||||
|
<row>f00000f00000000000000000f00000f00f00000000000f00f00000</row> |
||||||
|
<row>f00000f00000000000000000f00000f00000f00000f00000f00000</row> |
||||||
|
<row>f00000f00f00f00f00f00f00000000f00000000f00000000f00000</row> |
||||||
|
<row>f00000f00000000f00000000000000f00000000000000000f00000</row> |
||||||
|
<row>f00000f00000000000f00000000000f00000000000000000f00000</row> |
||||||
|
<row>f00000f00000000000000f00000000f00000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00f00f00f00f00f00000000f00000000000000000f00000000</row> |
||||||
|
<row>000f00000000000000000f00000f00f00000000000f00f00000f00</row> |
||||||
|
<row>000f00000000000000000f00000f00000f00000f00000f00000f00</row> |
||||||
|
<row>000f00f00f00f00f00f00000000f00000000f00000000f00000f00</row> |
||||||
|
<row>000f00000000f00000000000000f00000000000000000f00000f00</row> |
||||||
|
<row>000f00000000000f00000000000f00000000000000000f00000f00</row> |
||||||
|
<row>000f00000000000000f00000000f00000000000000000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00f00f00000000f00000000000000000f00000000f00</row> |
||||||
|
<row>f00000000000000000f00000f00f00000000000f00f00000f00000</row> |
||||||
|
<row>f00000000000000000f00000f00000f00000f00000f00000f00000</row> |
||||||
|
<row>f00f00f00f00f00f00000000f00000000f00000000f00000f00000</row> |
||||||
|
<row>f00000000f00000000000000f00000000000000000f00000f00000</row> |
||||||
|
<row>f00000000000f00000000000f00000000000000000f00000f00000</row> |
||||||
|
<row>f00000000000000f00000000f00000000000000000f00000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00f00000000f00000000000000000f00000000f00f00</row> |
||||||
|
<row>000000000000000f00000f00f00000000000f00f00000f00000000</row> |
||||||
|
<row>000000000000000f00000f00000f00000f00000f00000f00000000</row> |
||||||
|
<row>f00f00f00f00f00000000f00000000f00000000f00000f00000000</row> |
||||||
|
<row>000000f00000000000000f00000000000000000f00000f00000000</row> |
||||||
|
<row>000000000f00000000000f00000000000000000f00000f00000000</row> |
||||||
|
<row>000000000000f00000000f00000000000000000f00000000f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00000000f00000000000000000f00000000f00f00f00</row> |
||||||
|
<row>000000000000f00000f00f00000000000f00f00000f00000000000</row> |
||||||
|
<row>000000000000f00000f00000f00000f00000f00000f00000000000</row> |
||||||
|
<row>f00f00f00f00000000f00000000f00000000f00000f00000000000</row> |
||||||
|
<row>000f00000000000000f00000000000000000f00000f00000000000</row> |
||||||
|
<row>000000f00000000000f00000000000000000f00000f00000000000</row> |
||||||
|
<row>000000000f00000000f00000000000000000f00000000f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00000000f00000000000000000f00000000f00f00f00f00</row> |
||||||
|
<row>000000000f00000f00f00000000000f00f00000f00000000000000</row> |
||||||
|
<row>000000000f00000f00000f00000f00000f00000f00000000000000</row> |
||||||
|
<row>f00f00f00000000f00000000f00000000f00000f00000000000000</row> |
||||||
|
<row>f00000000000000f00000000000000000f00000f00000000000000</row> |
||||||
|
<row>000f00000000000f00000000000000000f00000f00000000000000</row> |
||||||
|
<row>000000f00000000f00000000000000000f00000000f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00000000f00000000000000000f00000000f00f00f00f00f00</row> |
||||||
|
<row>000000f00000f00f00000000000f00f00000f00000000000000000</row> |
||||||
|
<row>000000f00000f00000f00000f00000f00000f00000000000000000</row> |
||||||
|
<row>f00f00000000f00000000f00000000f00000f00000000000000000</row> |
||||||
|
<row>000000000000f00000000000000000f00000f00000000000000000</row> |
||||||
|
<row>f00000000000f00000000000000000f00000f00000000000000000</row> |
||||||
|
<row>000f00000000f00000000000000000f00000000f00f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000000f00000000000000000f00000000f00f00f00f00f00f00</row> |
||||||
|
<row>000f00000f00f00000000000f00f00000f00000000000000000000</row> |
||||||
|
<row>000f00000f00000f00000f00000f00000f00000000000000000000</row> |
||||||
|
<row>f00000000f00000000f00000000f00000f00000000000000000000</row> |
||||||
|
<row>000000000f00000000000000000f00000f00000000000000000000</row> |
||||||
|
<row>000000000f00000000000000000f00000f00000000000000000000</row> |
||||||
|
<row>f00000000f00000000000000000f00000000f00f00f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000f00000000000000000f00000000f00f00f00f00f00f00000</row> |
||||||
|
<row>f00000f00f00000000000f00f00000f00000000000000000000000</row> |
||||||
|
<row>f00000f00000f00000f00000f00000f00000000000000000000000</row> |
||||||
|
<row>000000f00000000f00000000f00000f00000000000000000000000</row> |
||||||
|
<row>000000f00000000000000000f00000f00000000000000000000000</row> |
||||||
|
<row>000000f00000000000000000f00000f00000000000000000000000</row> |
||||||
|
<row>000000f00000000000000000f00000000f00f00f00f00f00f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00000000000000000f00000000f00f00f00f00f00f00000f00</row> |
||||||
|
<row>000f00f00000000000f00f00000f00000000000000000000000f00</row> |
||||||
|
<row>000f00000f00000f00000f00000f00000000000000000000000f00</row> |
||||||
|
<row>000f00000000f00000000f00000f00000000000000000000000f00</row> |
||||||
|
<row>000f00000000000000000f00000f00000000000000000000000f00</row> |
||||||
|
<row>000f00000000000000000f00000f00000000000000000000000f00</row> |
||||||
|
<row>000f00000000000000000f00000000f00f00f00f00f00f00000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000000000000000f00000000f00f00f00f00f00f00000f00f00</row> |
||||||
|
<row>f00f00000000000f00f00000f00000000000000000000000f00000</row> |
||||||
|
<row>f00000f00000f00000f00000f00000000000000000000000f00000</row> |
||||||
|
<row>f00000000f00000000f00000f00000000000000000000000f00000</row> |
||||||
|
<row>f00000000000000000f00000f00000000000000000000000f00000</row> |
||||||
|
<row>f00000000000000000f00000f00000000000000000000000f00000</row> |
||||||
|
<row>f00000000000000000f00000000f00f00f00f00f00f00000f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000f00000000f00f00f00f00f00f00000f00f00f00</row> |
||||||
|
<row>f00000000000f00f00000f00000000000000000000000f00000000</row> |
||||||
|
<row>000f00000f00000f00000f00000000000000000000000f00000000</row> |
||||||
|
<row>000000f00000000f00000f00000000000000000000000f00000000</row> |
||||||
|
<row>000000000000000f00000f00000000000000000000000f00000000</row> |
||||||
|
<row>000000000000000f00000f00000000000000000000000f00000000</row> |
||||||
|
<row>000000000000000f00000000f00f00f00f00f00f00000f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000f00000000f00f00f00f00f00f00000f00f00f00f00</row> |
||||||
|
<row>000000000f00f00000f00000000000000000000000f00000000000</row> |
||||||
|
<row>f00000f00000f00000f00000000000000000000000f00000000000</row> |
||||||
|
<row>000f00000000f00000f00000000000000000000000f00000000000</row> |
||||||
|
<row>000000000000f00000f00000000000000000000000f00000000000</row> |
||||||
|
<row>000000000000f00000f00000000000000000000000f00000000000</row> |
||||||
|
<row>000000000000f00000000f00f00f00f00f00f00000f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000f00000000f00f00f00f00f00f00000f00f00f00f00f00</row> |
||||||
|
<row>000000f00f00000f00000000000000000000000f00000000000000</row> |
||||||
|
<row>000f00000f00000f00000000000000000000000f00000000000000</row> |
||||||
|
<row>f00000000f00000f00000000000000000000000f00000000000000</row> |
||||||
|
<row>000000000f00000f00000000000000000000000f00000000000000</row> |
||||||
|
<row>000000000f00000f00000000000000000000000f00000000000000</row> |
||||||
|
<row>000000000f00000000f00f00f00f00f00f00000f00f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000f00000000f00f00f00f00f00f00000f00f00f00f00f00000</row> |
||||||
|
<row>000f00f00000f00000000000000000000000f00000000000000f00</row> |
||||||
|
<row>f00000f00000f00000000000000000000000f00000000000000000</row> |
||||||
|
<row>000000f00000f00000000000000000000000f00000000000000000</row> |
||||||
|
<row>000000f00000f00000000000000000000000f00000000000000000</row> |
||||||
|
<row>000000f00000f00000000000000000000000f00000000000000f00</row> |
||||||
|
<row>000000f00000000f00f00f00f00f00f00000f00f00f00f00f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00000000f00f00f00f00f00f00000f00f00f00f00f00000000</row> |
||||||
|
<row>f00f00000f00000000000000000000000f00000000000000f00000</row> |
||||||
|
<row>000f00000f00000000000000000000000f00000000000000000f00</row> |
||||||
|
<row>000f00000f00000000000000000000000f00000000000000000f00</row> |
||||||
|
<row>000f00000f00000000000000000000000f00000000000000000f00</row> |
||||||
|
<row>000f00000f00000000000000000000000f00000000000000f00000</row> |
||||||
|
<row>000f00000000f00f00f00f00f00f00000f00f00f00f00f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000000f00f00f00f00f00f00000f00f00f00f00f00000000000</row> |
||||||
|
<row>f00000f00000000000000000000000f00000000000000f00000000</row> |
||||||
|
<row>f00000f00000000000000000000000f00000000000000000f00000</row> |
||||||
|
<row>f00000f00000000000000000000000f00000000000000000f00000</row> |
||||||
|
<row>f00000f00000000000000000000000f00000000000000000f00000</row> |
||||||
|
<row>f00000f00000000000000000000000f00000000000000f00000000</row> |
||||||
|
<row>f00000000f00f00f00f00f00f00000f00f00f00f00f00000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000f00f00f00f00f00f00000f00f00f00f00f00000000000000</row> |
||||||
|
<row>000f00000000000000000000000f00000000000000f00000000f00</row> |
||||||
|
<row>000f00000000000000000000000f00000000000000000f00000000</row> |
||||||
|
<row>000f00000000000000000000000f00000000000000000f00000000</row> |
||||||
|
<row>000f00000000000000000000000f00000000000000000f00000000</row> |
||||||
|
<row>000f00000000000000000000000f00000000000000f00000000f00</row> |
||||||
|
<row>000000f00f00f00f00f00f00000f00f00f00f00f00000000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00f00f00f00f00f00000f00f00f00f00f00000000000000f00</row> |
||||||
|
<row>f00000000000000000000000f00000000000000f00000000f00000</row> |
||||||
|
<row>f00000000000000000000000f00000000000000000f00000000000</row> |
||||||
|
<row>f00000000000000000000000f00000000000000000f00000000000</row> |
||||||
|
<row>f00000000000000000000000f00000000000000000f00000000f00</row> |
||||||
|
<row>f00000000000000000000000f00000000000000f00000000f00000</row> |
||||||
|
<row>000f00f00f00f00f00f00000f00f00f00f00f00000000000f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00f00f00000f00f00f00f00f00000000000000f00f00</row> |
||||||
|
<row>000000000000000000000f00000000000000f00000000f00000000</row> |
||||||
|
<row>000000000000000000000f00000000000000000f00000000000000</row> |
||||||
|
<row>000000000000000000000f00000000000000000f00000000000f00</row> |
||||||
|
<row>000000000000000000000f00000000000000000f00000000f00000</row> |
||||||
|
<row>000000000000000000000f00000000000000f00000000f00000000</row> |
||||||
|
<row>f00f00f00f00f00f00000f00f00f00f00f00000000000f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00f00000f00f00f00f00f00000000000000f00f00f00</row> |
||||||
|
<row>000000000000000000f00000000000000f00000000f00000000000</row> |
||||||
|
<row>000000000000000000f00000000000000000f00000000000000000</row> |
||||||
|
<row>000000000000000000f00000000000000000f00000000000f00f00</row> |
||||||
|
<row>000000000000000000f00000000000000000f00000000f00000000</row> |
||||||
|
<row>000000000000000000f00000000000000f00000000f00000000000</row> |
||||||
|
<row>f00f00f00f00f00000f00f00f00f00f00000000000f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00000f00f00f00f00f00000000000000f00f00f00f00</row> |
||||||
|
<row>000000000000000f00000000000000f00000000f00000000000000</row> |
||||||
|
<row>000000000000000f00000000000000000f00000000000000000000</row> |
||||||
|
<row>000000000000000f00000000000000000f00000000000f00f00f00</row> |
||||||
|
<row>000000000000000f00000000000000000f00000000f00000000000</row> |
||||||
|
<row>000000000000000f00000000000000f00000000f00000000000000</row> |
||||||
|
<row>f00f00f00f00000f00f00f00f00f00000000000f00f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00000f00f00f00f00f00000000000000f00f00f00f00f00</row> |
||||||
|
<row>000000000000f00000000000000f00000000f00000000000000000</row> |
||||||
|
<row>000000000000f00000000000000000f00000000000000000000000</row> |
||||||
|
<row>000000000000f00000000000000000f00000000000f00f00f00f00</row> |
||||||
|
<row>000000000000f00000000000000000f00000000f00000000000000</row> |
||||||
|
<row>000000000000f00000000000000f00000000f00000000000000000</row> |
||||||
|
<row>f00f00f00000f00f00f00f00f00000000000f00f00f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00000f00f00f00f00f00000000000000f00f00f00f00f00000</row> |
||||||
|
<row>000000000f00000000000000f00000000f00000000000000000f00</row> |
||||||
|
<row>000000000f00000000000000000f00000000000000000000000f00</row> |
||||||
|
<row>000000000f00000000000000000f00000000000f00f00f00f00000</row> |
||||||
|
<row>000000000f00000000000000000f00000000f00000000000000000</row> |
||||||
|
<row>000000000f00000000000000f00000000f00000000000000000000</row> |
||||||
|
<row>f00f00000f00f00f00f00f00000000000f00f00f00f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000f00f00f00f00f00000000000000f00f00f00f00f00000000</row> |
||||||
|
<row>000000f00000000000000f00000000f00000000000000000f00000</row> |
||||||
|
<row>000000f00000000000000000f00000000000000000000000f00000</row> |
||||||
|
<row>000000f00000000000000000f00000000000f00f00f00f00000000</row> |
||||||
|
<row>000000f00000000000000000f00000000f00000000000000000000</row> |
||||||
|
<row>000000f00000000000000f00000000f00000000000000000000000</row> |
||||||
|
<row>f00000f00f00f00f00f00000000000f00f00f00f00f00f00f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00f00f00f00f00000000000000f00f00f00f00f00000000000</row> |
||||||
|
<row>000f00000000000000f00000000f00000000000000000f00000f00</row> |
||||||
|
<row>000f00000000000000000f00000000000000000000000f00000f00</row> |
||||||
|
<row>000f00000000000000000f00000000000f00f00f00f00000000f00</row> |
||||||
|
<row>000f00000000000000000f00000000f00000000000000000000f00</row> |
||||||
|
<row>000f00000000000000f00000000f00000000000000000000000f00</row> |
||||||
|
<row>000f00f00f00f00f00000000000f00f00f00f00f00f00f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00f00000000000000f00f00f00f00f00000000000f00</row> |
||||||
|
<row>f00000000000000f00000000f00000000000000000f00000f00000</row> |
||||||
|
<row>f00000000000000000f00000000000000000000000f00000f00000</row> |
||||||
|
<row>f00000000000000000f00000000000f00f00f00f00000000f00000</row> |
||||||
|
<row>f00000000000000000f00000000f00000000000000000000f00000</row> |
||||||
|
<row>f00000000000000f00000000f00000000000000000000000f00000</row> |
||||||
|
<row>f00f00f00f00f00000000000f00f00f00f00f00f00f00000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00000000000000f00f00f00f00f00000000000f00f00</row> |
||||||
|
<row>000000000000f00000000f00000000000000000f00000f00000000</row> |
||||||
|
<row>000000000000000f00000000000000000000000f00000f00000000</row> |
||||||
|
<row>000000000000000f00000000000f00f00f00f00000000f00000000</row> |
||||||
|
<row>000000000000000f00000000f00000000000000000000f00000000</row> |
||||||
|
<row>000000000000f00000000f00000000000000000000000f00000000</row> |
||||||
|
<row>f00f00f00f00000000000f00f00f00f00f00f00f00000000f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00000000000000f00f00f00f00f00000000000f00f00f00</row> |
||||||
|
<row>000000000f00000000f00000000000000000f00000f00000000000</row> |
||||||
|
<row>000000000000f00000000000000000000000f00000f00000000000</row> |
||||||
|
<row>000000000000f00000000000f00f00f00f00000000f00000000000</row> |
||||||
|
<row>000000000000f00000000f00000000000000000000f00000000000</row> |
||||||
|
<row>000000000f00000000f00000000000000000000000f00000000000</row> |
||||||
|
<row>f00f00f00000000000f00f00f00f00f00f00f00000000f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00000000000000f00f00f00f00f00000000000f00f00f00f00</row> |
||||||
|
<row>000000f00000000f00000000000000000f00000f00000000000000</row> |
||||||
|
<row>000000000f00000000000000000000000f00000f00000000000000</row> |
||||||
|
<row>000000000f00000000000f00f00f00f00000000f00000000000000</row> |
||||||
|
<row>000000000f00000000f00000000000000000000f00000000000000</row> |
||||||
|
<row>000000f00000000f00000000000000000000000f00000000000000</row> |
||||||
|
<row>f00f00000000000f00f00f00f00f00f00f00000000f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000000000000f00f00f00f00f00000000000f00f00f00f00f00</row> |
||||||
|
<row>000f00000000f00000000000000000f00000f00000000000000000</row> |
||||||
|
<row>000000f00000000000000000000000f00000f00000000000000000</row> |
||||||
|
<row>000000f00000000000f00f00f00f00000000f00000000000000000</row> |
||||||
|
<row>000000f00000000f00000000000000000000f00000000000000000</row> |
||||||
|
<row>000f00000000f00000000000000000000000f00000000000000000</row> |
||||||
|
<row>f00000000000f00f00f00f00f00f00f00000000f00f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000f00f00f00f00f00000000000f00f00f00f00f00000</row> |
||||||
|
<row>f00000000f00000000000000000f00000f00000000000000000f00</row> |
||||||
|
<row>000f00000000000000000000000f00000f00000000000000000f00</row> |
||||||
|
<row>000f00000000000f00f00f00f00000000f00000000000000000f00</row> |
||||||
|
<row>000f00000000f00000000000000000000f00000000000000000f00</row> |
||||||
|
<row>f00000000f00000000000000000000000f00000000000000000f00</row> |
||||||
|
<row>000000000f00f00f00f00f00f00f00000000f00f00f00f00f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000f00f00f00f00f00000000000f00f00f00f00f00000000</row> |
||||||
|
<row>000000f00000000000000000f00000f00000000000000000f00000</row> |
||||||
|
<row>f00000000000000000000000f00000f00000000000000000f00000</row> |
||||||
|
<row>f00000000000f00f00f00f00000000f00000000000000000f00000</row> |
||||||
|
<row>f00000000f00000000000000000000f00000000000000000f00000</row> |
||||||
|
<row>000000f00000000000000000000000f00000000000000000f00000</row> |
||||||
|
<row>000000f00f00f00f00f00f00f00000000f00f00f00f00f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000f00f00f00f00f00000000000f00f00f00f00f00000000000</row> |
||||||
|
<row>000f00000000000000000f00000f00000000000000000f00000000</row> |
||||||
|
<row>000000000000000000000f00000f00000000000000000f00000f00</row> |
||||||
|
<row>000000000f00f00f00f00000000f00000000000000000f00000000</row> |
||||||
|
<row>000000f00000000000000000000f00000000000000000f00000000</row> |
||||||
|
<row>000f00000000000000000000000f00000000000000000f00000000</row> |
||||||
|
<row>000f00f00f00f00f00f00f00000000f00f00f00f00f00000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00f00f00f00f00000000000f00f00f00f00f00000000000000</row> |
||||||
|
<row>f00000000000000000f00000f00000000000000000f00000000f00</row> |
||||||
|
<row>000000000000000000f00000f00000000000000000f00000f00000</row> |
||||||
|
<row>000000f00f00f00f00000000f00000000000000000f00000000000</row> |
||||||
|
<row>000f00000000000000000000f00000000000000000f00000000000</row> |
||||||
|
<row>f00000000000000000000000f00000000000000000f00000000000</row> |
||||||
|
<row>f00f00f00f00f00f00f00000000f00f00f00f00f00000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00f00000000000f00f00f00f00f00000000000000f00</row> |
||||||
|
<row>000000000000000f00000f00000000000000000f00000000f00000</row> |
||||||
|
<row>000000000000000f00000f00000000000000000f00000f00000000</row> |
||||||
|
<row>000f00f00f00f00000000f00000000000000000f00000000000000</row> |
||||||
|
<row>f00000000000000000000f00000000000000000f00000000000000</row> |
||||||
|
<row>000000000000000000000f00000000000000000f00000000000000</row> |
||||||
|
<row>f00f00f00f00f00f00000000f00f00f00f00f00000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00000000000f00f00f00f00f00000000000000f00f00</row> |
||||||
|
<row>000000000000f00000f00000000000000000f00000000f00000f00</row> |
||||||
|
<row>000000000000f00000f00000000000000000f00000f00000000f00</row> |
||||||
|
<row>f00f00f00f00000000f00000000000000000f00000000000000f00</row> |
||||||
|
<row>000000000000000000f00000000000000000f00000000000000f00</row> |
||||||
|
<row>000000000000000000f00000000000000000f00000000000000f00</row> |
||||||
|
<row>f00f00f00f00f00000000f00f00f00f00f00000000000000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00000000000f00f00f00f00f00000000000000f00f00000</row> |
||||||
|
<row>000000000f00000f00000000000000000f00000000f00000f00000</row> |
||||||
|
<row>000000000f00000f00000000000000000f00000f00000000f00000</row> |
||||||
|
<row>f00f00f00000000f00000000000000000f00000000000000f00000</row> |
||||||
|
<row>000000000000000f00000000000000000f00000000000000f00000</row> |
||||||
|
<row>000000000000000f00000000000000000f00000000000000f00000</row> |
||||||
|
<row>f00f00f00f00000000f00f00f00f00f00000000000000000f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00000000000f00f00f00f00f00000000000000f00f00000000</row> |
||||||
|
<row>000000f00000f00000000000000000f00000000f00000f00000f00</row> |
||||||
|
<row>000000f00000f00000000000000000f00000f00000000f00000000</row> |
||||||
|
<row>f00f00000000f00000000000000000f00000000000000f00000000</row> |
||||||
|
<row>000000000000f00000000000000000f00000000000000f00000000</row> |
||||||
|
<row>000000000000f00000000000000000f00000000000000f00000f00</row> |
||||||
|
<row>f00f00f00000000f00f00f00f00f00000000000000000f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000000000f00f00f00f00f00000000000000f00f00000000f00</row> |
||||||
|
<row>000f00000f00000000000000000f00000000f00000f00000f00000</row> |
||||||
|
<row>000f00000f00000000000000000f00000f00000000f00000000000</row> |
||||||
|
<row>f00000000f00000000000000000f00000000000000f00000000000</row> |
||||||
|
<row>000000000f00000000000000000f00000000000000f00000000000</row> |
||||||
|
<row>000000000f00000000000000000f00000000000000f00000f00000</row> |
||||||
|
<row>f00f00000000f00f00f00f00f00000000000000000f00000000f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000f00f00f00f00f00000000000000f00f00000000f00f00</row> |
||||||
|
<row>f00000f00000000000000000f00000000f00000f00000f00000000</row> |
||||||
|
<row>f00000f00000000000000000f00000f00000000f00000000000000</row> |
||||||
|
<row>000000f00000000000000000f00000000000000f00000000000f00</row> |
||||||
|
<row>000000f00000000000000000f00000000000000f00000000000000</row> |
||||||
|
<row>000000f00000000000000000f00000000000000f00000f00000000</row> |
||||||
|
<row>f00000000f00f00f00f00f00000000000000000f00000000f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000f00f00f00f00f00000000000000f00f00000000f00f00f00</row> |
||||||
|
<row>000f00000000000000000f00000000f00000f00000f00000000000</row> |
||||||
|
<row>000f00000000000000000f00000f00000000f00000000000000000</row> |
||||||
|
<row>000f00000000000000000f00000000000000f00000000000f00f00</row> |
||||||
|
<row>000f00000000000000000f00000000000000f00000000000000000</row> |
||||||
|
<row>000f00000000000000000f00000000000000f00000f00000000000</row> |
||||||
|
<row>000000f00f00f00f00f00000000000000000f00000000f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00f00f00f00f00000000000000f00f00000000f00f00f00f00</row> |
||||||
|
<row>f00000000000000000f00000000f00000f00000f00000000000000</row> |
||||||
|
<row>f00000000000000000f00000f00000000f00000000000000000000</row> |
||||||
|
<row>f00000000000000000f00000000000000f00000000000f00f00f00</row> |
||||||
|
<row>f00000000000000000f00000000000000f00000000000000000000</row> |
||||||
|
<row>f00000000000000000f00000000000000f00000f00000000000000</row> |
||||||
|
<row>000f00f00f00f00f00000000000000000f00000000f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00f00000000000000f00f00000000f00f00f00f00f00</row> |
||||||
|
<row>000000000000000f00000000f00000f00000f00000000000000000</row> |
||||||
|
<row>000000000000000f00000f00000000f00000000000000000000000</row> |
||||||
|
<row>000000000000000f00000000000000f00000000000f00f00f00f00</row> |
||||||
|
<row>000000000000000f00000000000000f00000000000000000000000</row> |
||||||
|
<row>000000000000000f00000000000000f00000f00000000000000000</row> |
||||||
|
<row>f00f00f00f00f00000000000000000f00000000f00f00f00f00f00</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00000000000000f00f00000000f00f00f00f00f00000</row> |
||||||
|
<row>000000000000f00000000f00000f00000f00000000000000000f00</row> |
||||||
|
<row>000000000000f00000f00000000f00000000000000000000000f00</row> |
||||||
|
<row>000000000000f00000000000000f00000000000f00f00f00f00000</row> |
||||||
|
<row>000000000000f00000000000000f00000000000000000000000f00</row> |
||||||
|
<row>000000000000f00000000000000f00000f00000000000000000f00</row> |
||||||
|
<row>f00f00f00f00000000000000000f00000000f00f00f00f00f00000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00000000000000f00f00000000f00f00f00f00f00000000</row> |
||||||
|
<row>000000000f00000000f00000f00000f00000000000000000f00000</row> |
||||||
|
<row>000000000f00000f00000000f00000000000000000000000f00000</row> |
||||||
|
<row>000000000f00000000000000f00000000000f00f00f00f00000000</row> |
||||||
|
<row>000000000f00000000000000f00000000000000000000000f00000</row> |
||||||
|
<row>000000000f00000000000000f00000f00000000000000000f00000</row> |
||||||
|
<row>f00f00f00000000000000000f00000000f00f00f00f00f00000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00000000000000f00f00000000f00f00f00f00f00000000000</row> |
||||||
|
<row>000000f00000000f00000f00000f00000000000000000f00000000</row> |
||||||
|
<row>000000f00000f00000000f00000000000000000000000f00000000</row> |
||||||
|
<row>000000f00000000000000f00000000000f00f00f00f00000000000</row> |
||||||
|
<row>000000f00000000000000f00000000000000000000000f00000000</row> |
||||||
|
<row>000000f00000000000000f00000f00000000000000000f00000000</row> |
||||||
|
<row>f00f00000000000000000f00000000f00f00f00f00f00000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000000000000f00f00000000f00f00f00f00f00000000000000</row> |
||||||
|
<row>000f00000000f00000f00000f00000000000000000f00000000000</row> |
||||||
|
<row>000f00000f00000000f00000000000000000000000f00000000000</row> |
||||||
|
<row>000f00000000000000f00000000000f00f00f00f00000000000000</row> |
||||||
|
<row>000f00000000000000f00000000000000000000000f00000000000</row> |
||||||
|
<row>000f00000000000000f00000f00000000000000000f00000000000</row> |
||||||
|
<row>f00000000000000000f00000000f00f00f00f00f00000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000f00f00000000f00f00f00f00f00000000000000000</row> |
||||||
|
<row>f00000000f00000f00000f00000000000000000f00000000000000</row> |
||||||
|
<row>f00000f00000000f00000000000000000000000f00000000000000</row> |
||||||
|
<row>f00000000000000f00000000000f00f00f00f00000000000000000</row> |
||||||
|
<row>f00000000000000f00000000000000000000000f00000000000000</row> |
||||||
|
<row>f00000000000000f00000f00000000000000000f00000000000000</row> |
||||||
|
<row>000000000000000f00000000f00f00f00f00f00000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000f00f00000000f00f00f00f00f00000000000000000000</row> |
||||||
|
<row>000000f00000f00000f00000000000000000f00000000000000000</row> |
||||||
|
<row>000f00000000f00000000000000000000000f00000000000000000</row> |
||||||
|
<row>000000000000f00000000000f00f00f00f00000000000000000000</row> |
||||||
|
<row>000000000000f00000000000000000000000f00000000000000000</row> |
||||||
|
<row>000000000000f00000f00000000000000000f00000000000000000</row> |
||||||
|
<row>000000000000f00000000f00f00f00f00f00000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000f00f00000000f00f00f00f00f00000000000000000000000</row> |
||||||
|
<row>000f00000f00000f00000000000000000f00000000000000000000</row> |
||||||
|
<row>f00000000f00000000000000000000000f00000000000000000000</row> |
||||||
|
<row>000000000f00000000000f00f00f00f00000000000000000000000</row> |
||||||
|
<row>000000000f00000000000000000000000f00000000000000000000</row> |
||||||
|
<row>000000000f00000f00000000000000000f00000000000000000000</row> |
||||||
|
<row>000000000f00000000f00f00f00f00f00000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00f00000000f00f00f00f00f00000000000000000000000000</row> |
||||||
|
<row>f00000f00000f00000000000000000f00000000000000000000000</row> |
||||||
|
<row>000000f00000000000000000000000f00000000000000000000000</row> |
||||||
|
<row>000000f00000000000f00f00f00f00000000000000000000000000</row> |
||||||
|
<row>000000f00000000000000000000000f00000000000000000000000</row> |
||||||
|
<row>000000f00000f00000000000000000f00000000000000000000000</row> |
||||||
|
<row>000000f00000000f00f00f00f00f00000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00000000f00f00f00f00f00000000000000000000000000000</row> |
||||||
|
<row>000f00000f00000000000000000f00000000000000000000000000</row> |
||||||
|
<row>000f00000000000000000000000f00000000000000000000000000</row> |
||||||
|
<row>000f00000000000f00f00f00f00000000000000000000000000000</row> |
||||||
|
<row>000f00000000000000000000000f00000000000000000000000000</row> |
||||||
|
<row>000f00000f00000000000000000f00000000000000000000000000</row> |
||||||
|
<row>000f00000000f00f00f00f00f00000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000000f00f00f00f00f00000000000000000000000000000000</row> |
||||||
|
<row>f00000f00000000000000000f00000000000000000000000000000</row> |
||||||
|
<row>f00000000000000000000000f00000000000000000000000000000</row> |
||||||
|
<row>f00000000000f00f00f00f00000000000000000000000000000000</row> |
||||||
|
<row>f00000000000000000000000f00000000000000000000000000000</row> |
||||||
|
<row>f00000f00000000000000000f00000000000000000000000000000</row> |
||||||
|
<row>f00000000f00f00f00f00f00000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000f00f00f00f00f00000000000000000000000000000000000</row> |
||||||
|
<row>000f00000000000000000f00000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000f00000000000000000000000000000000</row> |
||||||
|
<row>000000000f00f00f00f00000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000f00000000000000000000000000000000</row> |
||||||
|
<row>000f00000000000000000f00000000000000000000000000000000</row> |
||||||
|
<row>000000f00f00f00f00f00000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000f00f00f00f00f00000000000000000000000000000000000000</row> |
||||||
|
<row>f00000000000000000f00000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000f00000000000000000000000000000000000</row> |
||||||
|
<row>000000f00f00f00f00000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000f00000000000000000000000000000000000</row> |
||||||
|
<row>f00000000000000000f00000000000000000000000000000000000</row> |
||||||
|
<row>000f00f00f00f00f00000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00f00000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000f00000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000f00000000000000000000000000000000000000</row> |
||||||
|
<row>000f00f00f00f00000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000f00000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000f00000000000000000000000000000000000000</row> |
||||||
|
<row>f00f00f00f00f00000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00f00000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000f00000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000f00000000000000000000000000000000000000000</row> |
||||||
|
<row>f00f00f00f00000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000f00000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000f00000000000000000000000000000000000000000</row> |
||||||
|
<row>f00f00f00f00000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00f00000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000f00000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000f00000000000000000000000000000000000000000000</row> |
||||||
|
<row>f00f00f00000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000f00000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000f00000000000000000000000000000000000000000000</row> |
||||||
|
<row>f00f00f00000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00f00000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000f00000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000f00000000000000000000000000000000000000000000000</row> |
||||||
|
<row>f00f00000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000f00000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000f00000000000000000000000000000000000000000000000</row> |
||||||
|
<row>f00f00000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>f00000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000f00000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000f00000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>f00000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000f00000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000f00000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>f00000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>f00000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>f00000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>f00000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>f00000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
<frame duration="100"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
</blm> |
@ -0,0 +1,147 @@ |
|||||||
|
#heart.blm |
||||||
|
#countdown.blm |
||||||
|
test.blm |
||||||
|
klonfish-dancing.blm |
||||||
|
blm/invasion.blm |
||||||
|
blm/torus.blm |
||||||
|
blm/antiwar.blm |
||||||
|
blm/billard.blm |
||||||
|
blm/x-ball.blm |
||||||
|
blm/game.blm |
||||||
|
blm/tropfen.blm |
||||||
|
blm/moewe_frontal.blm |
||||||
|
blm/fireworks_2.blm |
||||||
|
blm/thunderstorm.blm |
||||||
|
blm/biker.blm |
||||||
|
blm/fantasticspace.blm |
||||||
|
blm/allyourbase.blm |
||||||
|
blm/21st_century_man.blm |
||||||
|
blm/dont_try_at_home.blm |
||||||
|
blm/spin.blm |
||||||
|
blm/heart.blm |
||||||
|
blm/encyclops.blm |
||||||
|
blm/fant.blm |
||||||
|
blm/schnecke.blm |
||||||
|
blm/peao.blm |
||||||
|
blm/falling_pix.blm |
||||||
|
blm/tetris.blm |
||||||
|
blm/text.blm |
||||||
|
blm/landing_zone.blm |
||||||
|
blm/dance_micky_chickee.blm |
||||||
|
blm/supermaennchen.blm |
||||||
|
blm/allon.blm |
||||||
|
blm/kame.blm |
||||||
|
blm/kiss.blm |
||||||
|
blm/fallingrows.blm |
||||||
|
blm/jesus.blm |
||||||
|
blm/vlhurg.blm |
||||||
|
blm/wasserhahn.blm |
||||||
|
blm/gewaber.blm |
||||||
|
blm/tla_them.blm |
||||||
|
blm/quix_glitter.blm |
||||||
|
blm/herz.blm |
||||||
|
blm/sanduhr.blm |
||||||
|
blm/defect_car.blm |
||||||
|
blm/peepshow.blm |
||||||
|
blm/countdown.blm |
||||||
|
blm/luftballoons.blm |
||||||
|
blm/impaexpa.blm |
||||||
|
blm/wein_trinken.blm |
||||||
|
blm/coffee.blm |
||||||
|
blm/camel.blm |
||||||
|
blm/matrix.blm |
||||||
|
blm/life.blm |
||||||
|
blm/snake.blm |
||||||
|
blm/windshield.blm |
||||||
|
blm/raumschiff_enterprise.blm |
||||||
|
blm/pumpkin.blm |
||||||
|
blm/yeastman.blm |
||||||
|
blm/genomix.blm |
||||||
|
blm/bad_luck.blm |
||||||
|
blm/om_sweet_om.blm |
||||||
|
blm/invaders_andreas.blm |
||||||
|
blm/manifesto5.blm |
||||||
|
blm/chat_noir.blm |
||||||
|
blm/rakete.blm |
||||||
|
blm/manifesto3.blm |
||||||
|
blm/relativity.blm |
||||||
|
blm/fussballer.blm |
||||||
|
blm/sinus.blm |
||||||
|
blm/love_triangles.blm |
||||||
|
blm/ascii_people.blm |
||||||
|
blm/hanoi.blm |
||||||
|
blm/monster.blm |
||||||
|
blm/come_together.blm |
||||||
|
blm/matrix_maennchen.blm |
||||||
|
blm/silent_night.blm |
||||||
|
blm/halt.blm |
||||||
|
blm/das_leben_ist_schoen.blm |
||||||
|
blm/moving_car.blm |
||||||
|
blm/spirals.blm |
||||||
|
blm/mandel.blm |
||||||
|
blm/alloff.blm |
||||||
|
blm/manifesto1.blm |
||||||
|
blm/quantorenlyrik.blm |
||||||
|
blm/manifesto4.blm |
||||||
|
blm/warterad.blm |
||||||
|
blm/surprise.blm |
||||||
|
blm/oneon.blm |
||||||
|
blm/manifesto7.blm |
||||||
|
blm/fireworks.blm |
||||||
|
blm/labyrinth.blm |
||||||
|
blm/brainfuck.blm |
||||||
|
blm/die_erde.blm |
||||||
|
blm/klo.blm |
||||||
|
blm/psychowarrior.blm |
||||||
|
blm/timeless.blm |
||||||
|
blm/auge.blm |
||||||
|
blm/worm.blm |
||||||
|
blm/colagoboom.blm |
||||||
|
blm/musterbeispiel.blm |
||||||
|
blm/fallingpixels.blm |
||||||
|
blm/franknstoned.blm |
||||||
|
blm/rollo_grow.blm |
||||||
|
blm/illuminati.blm |
||||||
|
blm/3rd_advent.blm |
||||||
|
blm/chaosknoten.blm |
||||||
|
blm/be_happy.blm |
||||||
|
blm/binary_god.blm |
||||||
|
blm/kingzilla.blm |
||||||
|
blm/paradox.blm |
||||||
|
blm/dj.blm |
||||||
|
blm/hut.blm |
||||||
|
blm/sortofselftest.blm |
||||||
|
blm/blubb.blm |
||||||
|
blm/bleeeh.blm |
||||||
|
blm/rain.blm |
||||||
|
blm/flash.blm |
||||||
|
blm/femina_light.blm |
||||||
|
blm/gator_rogat.blm |
||||||
|
blm/speedit.blm |
||||||
|
blm/scooter.blm |
||||||
|
blm/pixie_in_the_box.blm |
||||||
|
blm/zeichen.blm |
||||||
|
blm/humanistic.blm |
||||||
|
blm/pacman_saga.blm |
||||||
|
blm/die_autobahn.blm |
||||||
|
blm/mytest3.blm |
||||||
|
blm/yin_yang.blm |
||||||
|
blm/klettermensch.blm |
||||||
|
blm/baustein.blm |
||||||
|
blm/pwm.blm |
||||||
|
blm/babelfish.blm |
||||||
|
blm/mytest2.blm |
||||||
|
blm/winslows.blm |
||||||
|
blm/dance.blm |
||||||
|
blm/martelo.blm |
||||||
|
blm/raindrops.blm |
||||||
|
blm/g.blm |
||||||
|
blm/clear.blm |
||||||
|
blm/sport_haelt_fit.blm |
||||||
|
blm/kreise.blm |
||||||
|
blm/railroad.blm |
||||||
|
blm/3D_cube.blm |
||||||
|
blm/balloon.blm |
||||||
|
blm/flipp.blm |
||||||
|
blm/mytest.blm |
||||||
|
blm/tux.blm |
@ -0,0 +1,143 @@ |
|||||||
|
blm/invasion.blm |
||||||
|
blm/torus.blm |
||||||
|
blm/antiwar.blm |
||||||
|
blm/billard.blm |
||||||
|
blm/x-ball.blm |
||||||
|
blm/game.blm |
||||||
|
blm/tropfen.blm |
||||||
|
blm/moewe_frontal.blm |
||||||
|
blm/fireworks_2.blm |
||||||
|
blm/thunderstorm.blm |
||||||
|
blm/biker.blm |
||||||
|
blm/fantasticspace.blm |
||||||
|
blm/allyourbase.blm |
||||||
|
blm/21st_century_man.blm |
||||||
|
blm/dont_try_at_home.blm |
||||||
|
blm/spin.blm |
||||||
|
blm/heart.blm |
||||||
|
blm/encyclops.blm |
||||||
|
blm/fant.blm |
||||||
|
blm/schnecke.blm |
||||||
|
blm/peao.blm |
||||||
|
blm/falling_pix.blm |
||||||
|
blm/tetris.blm |
||||||
|
blm/text.blm |
||||||
|
blm/landing_zone.blm |
||||||
|
blm/dance_micky_chickee.blm |
||||||
|
blm/supermaennchen.blm |
||||||
|
blm/allon.blm |
||||||
|
blm/kame.blm |
||||||
|
blm/kiss.blm |
||||||
|
blm/fallingrows.blm |
||||||
|
blm/jesus.blm |
||||||
|
blm/vlhurg.blm |
||||||
|
blm/wasserhahn.blm |
||||||
|
blm/gewaber.blm |
||||||
|
blm/tla_them.blm |
||||||
|
blm/quix_glitter.blm |
||||||
|
blm/herz.blm |
||||||
|
blm/sanduhr.blm |
||||||
|
blm/defect_car.blm |
||||||
|
blm/peepshow.blm |
||||||
|
blm/countdown.blm |
||||||
|
blm/luftballoons.blm |
||||||
|
blm/impaexpa.blm |
||||||
|
blm/wein_trinken.blm |
||||||
|
blm/coffee.blm |
||||||
|
blm/camel.blm |
||||||
|
blm/matrix.blm |
||||||
|
blm/life.blm |
||||||
|
blm/snake.blm |
||||||
|
blm/windshield.blm |
||||||
|
blm/raumschiff_enterprise.blm |
||||||
|
blm/pumpkin.blm |
||||||
|
blm/yeastman.blm |
||||||
|
blm/genomix.blm |
||||||
|
blm/bad_luck.blm |
||||||
|
blm/om_sweet_om.blm |
||||||
|
blm/invaders_andreas.blm |
||||||
|
blm/manifesto5.blm |
||||||
|
blm/chat_noir.blm |
||||||
|
blm/rakete.blm |
||||||
|
blm/manifesto3.blm |
||||||
|
blm/relativity.blm |
||||||
|
blm/fussballer.blm |
||||||
|
blm/sinus.blm |
||||||
|
blm/love_triangles.blm |
||||||
|
blm/ascii_people.blm |
||||||
|
blm/hanoi.blm |
||||||
|
blm/monster.blm |
||||||
|
blm/come_together.blm |
||||||
|
blm/matrix_maennchen.blm |
||||||
|
blm/silent_night.blm |
||||||
|
blm/halt.blm |
||||||
|
blm/das_leben_ist_schoen.blm |
||||||
|
blm/moving_car.blm |
||||||
|
blm/spirals.blm |
||||||
|
blm/mandel.blm |
||||||
|
blm/alloff.blm |
||||||
|
blm/manifesto1.blm |
||||||
|
blm/quantorenlyrik.blm |
||||||
|
blm/manifesto4.blm |
||||||
|
blm/warterad.blm |
||||||
|
blm/surprise.blm |
||||||
|
blm/oneon.blm |
||||||
|
blm/manifesto7.blm |
||||||
|
blm/fireworks.blm |
||||||
|
blm/labyrinth.blm |
||||||
|
blm/brainfuck.blm |
||||||
|
blm/die_erde.blm |
||||||
|
blm/klo.blm |
||||||
|
blm/psychowarrior.blm |
||||||
|
blm/timeless.blm |
||||||
|
blm/auge.blm |
||||||
|
blm/worm.blm |
||||||
|
blm/colagoboom.blm |
||||||
|
blm/musterbeispiel.blm |
||||||
|
blm/fallingpixels.blm |
||||||
|
blm/franknstoned.blm |
||||||
|
blm/rollo_grow.blm |
||||||
|
blm/illuminati.blm |
||||||
|
blm/3rd_advent.blm |
||||||
|
blm/chaosknoten.blm |
||||||
|
blm/be_happy.blm |
||||||
|
blm/binary_god.blm |
||||||
|
blm/kingzilla.blm |
||||||
|
blm/paradox.blm |
||||||
|
blm/dj.blm |
||||||
|
blm/hut.blm |
||||||
|
blm/sortofselftest.blm |
||||||
|
blm/blubb.blm |
||||||
|
blm/bleeeh.blm |
||||||
|
blm/rain.blm |
||||||
|
blm/flash.blm |
||||||
|
blm/femina_light.blm |
||||||
|
blm/gator_rogat.blm |
||||||
|
blm/speedit.blm |
||||||
|
blm/scooter.blm |
||||||
|
blm/pixie_in_the_box.blm |
||||||
|
blm/zeichen.blm |
||||||
|
blm/humanistic.blm |
||||||
|
blm/pacman_saga.blm |
||||||
|
blm/die_autobahn.blm |
||||||
|
blm/mytest3.blm |
||||||
|
blm/yin_yang.blm |
||||||
|
blm/klettermensch.blm |
||||||
|
blm/baustein.blm |
||||||
|
blm/pwm.blm |
||||||
|
blm/babelfish.blm |
||||||
|
blm/mytest2.blm |
||||||
|
blm/winslows.blm |
||||||
|
blm/dance.blm |
||||||
|
blm/martelo.blm |
||||||
|
blm/raindrops.blm |
||||||
|
blm/g.blm |
||||||
|
blm/clear.blm |
||||||
|
blm/sport_haelt_fit.blm |
||||||
|
blm/kreise.blm |
||||||
|
blm/railroad.blm |
||||||
|
blm/3D_cube.blm |
||||||
|
blm/balloon.blm |
||||||
|
blm/flipp.blm |
||||||
|
blm/mytest.blm |
||||||
|
blm/tux.blm |
@ -0,0 +1,456 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import time |
||||||
|
import random |
||||||
|
import sys |
||||||
|
import colorsys |
||||||
|
|
||||||
|
import blup.frame |
||||||
|
import blup.output |
||||||
|
|
||||||
|
|
||||||
|
__numbers = { |
||||||
|
1: [[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0,]], |
||||||
|
2: [[1,1,1,1,1],[0,0,0,0,1],[1,1,1,1,1],[1,0,0,0,0],[1,1,1,1,1,]], |
||||||
|
3: [[1,1,1,1,1],[0,0,0,0,1],[0,0,1,1,1],[0,0,0,0,1],[1,1,1,1,1,]], |
||||||
|
4: [[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1],[0,0,0,0,1],[0,0,0,0,1,]], |
||||||
|
5: [[1,1,1,1,1],[1,0,0,0,0],[1,1,1,1,1],[0,0,0,0,1],[1,1,1,1,1,]], |
||||||
|
6: [[1,1,1,1,1],[1,0,0,0,0],[1,1,1,1,1],[1,0,0,0,1],[1,1,1,1,1,]], |
||||||
|
7: [[1,1,1,1,1],[0,0,0,0,1],[0,0,0,0,1],[0,0,0,0,1],[0,0,0,0,1,]], |
||||||
|
8: [[1,1,1,1,1],[1,0,0,0,1],[1,1,1,1,1],[1,0,0,0,1],[1,1,1,1,1,]], |
||||||
|
9: [[1,1,1,1,1],[1,0,0,0,1],[1,1,1,1,1],[0,0,0,0,1],[1,1,1,1,1,]], |
||||||
|
0: [[1,1,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1,]], |
||||||
|
} |
||||||
|
|
||||||
|
class Paddle(object): |
||||||
|
def __init__(self, playground, xpos, ypos, size): |
||||||
|
self.__playground = playground |
||||||
|
self.__xpos = xpos |
||||||
|
self.__size = size |
||||||
|
self.__ypos = ypos |
||||||
|
self.__nextMove = 0 |
||||||
|
|
||||||
|
@property |
||||||
|
def nextMove(self): |
||||||
|
return self.__nextMove |
||||||
|
@nextMove.setter |
||||||
|
def nextMove(self, value): |
||||||
|
if value in [-1, 0, 1]: |
||||||
|
self.__nextMove = value |
||||||
|
else: |
||||||
|
raise ValueError('invalid move') |
||||||
|
|
||||||
|
@property |
||||||
|
def xpos(self): |
||||||
|
return self.__xpos |
||||||
|
@property |
||||||
|
def ypos(self): |
||||||
|
return self.__ypos |
||||||
|
@property |
||||||
|
def size(self): |
||||||
|
return self.__size |
||||||
|
@property |
||||||
|
def nextMove(self): |
||||||
|
return self.__nextMove |
||||||
|
|
||||||
|
def containsPoint(self, x, y): |
||||||
|
if x == self.__xpos and y in range(self.__ypos, self.__ypos + self.__size): |
||||||
|
return True |
||||||
|
else: |
||||||
|
return False |
||||||
|
|
||||||
|
def nextMoveUp(self): |
||||||
|
self.__nextMove = -1 |
||||||
|
|
||||||
|
def nextMoveDown(self): |
||||||
|
self.__nextMove = 1 |
||||||
|
|
||||||
|
def doNextMove(self): |
||||||
|
if self.__nextMove is not 0: |
||||||
|
if self.__nextMove == -1 and self.__ypos > 0: |
||||||
|
self.__ypos -= 1 |
||||||
|
elif self.__nextMove == 1 and self.__ypos + self.__size < self.__playground.height: |
||||||
|
self.__ypos += 1 |
||||||
|
self.__nextMove = 0 |
||||||
|
|
||||||
|
class Wall(object): |
||||||
|
HORIZONTAL = 1 |
||||||
|
VERTICAL = 2 |
||||||
|
def __init__(self, orientation): |
||||||
|
self.orientation = orientation |
||||||
|
|
||||||
|
class Ball(object): |
||||||
|
def __init__(self, playground, xpos, ypos, xspeed, yspeed): |
||||||
|
self.__playground = playground |
||||||
|
self.__xpos = xpos |
||||||
|
self.__ypos = ypos |
||||||
|
self.__xspeed = xspeed |
||||||
|
self.__yspeed = yspeed |
||||||
|
self.__hitCallbacks = [] |
||||||
|
|
||||||
|
@property |
||||||
|
def xpos(self): |
||||||
|
return self.__xpos |
||||||
|
@property |
||||||
|
def ypos(self): |
||||||
|
return self.__ypos |
||||||
|
@property |
||||||
|
def xspeed(self): |
||||||
|
return self.__xspeed |
||||||
|
@property |
||||||
|
def yspeed(self): |
||||||
|
return self.__yspeed |
||||||
|
@xpos.setter |
||||||
|
def xpos(self, value): |
||||||
|
self.__xpos = value |
||||||
|
@ypos.setter |
||||||
|
def ypos(self, value): |
||||||
|
self.__ypos = value |
||||||
|
@xspeed.setter |
||||||
|
def xspeed(self, value): |
||||||
|
self.__xspeed = value |
||||||
|
@yspeed.setter |
||||||
|
def yspeed(self, value): |
||||||
|
self.__yspeed = value |
||||||
|
|
||||||
|
def addHitCallback(self, callback): |
||||||
|
self.__hitCallbacks.append(callback) |
||||||
|
|
||||||
|
def doHitCallbacks(self, obj): |
||||||
|
for callback in self.__hitCallbacks: |
||||||
|
callback(obj) |
||||||
|
|
||||||
|
def move(self, ignorePaddles=False): |
||||||
|
if self.__xspeed == 0 and self.__yspeed == 0: |
||||||
|
return |
||||||
|
foundpos = False |
||||||
|
while not foundpos: |
||||||
|
if self.__xspeed == 0 and self.__yspeed == 0: |
||||||
|
break |
||||||
|
newx = self.__xpos + self.__xspeed |
||||||
|
newy = self.__ypos + self.__yspeed |
||||||
|
|
||||||
|
newobj = self.__playground.getObjectAtPosition(newx, newy) |
||||||
|
if isinstance(newobj, Wall): |
||||||
|
self.doHitCallbacks(newobj) |
||||||
|
|
||||||
|
# bounce off at horizontal wall |
||||||
|
if newobj.orientation == Wall.HORIZONTAL: |
||||||
|
self.__yspeed *= -1 |
||||||
|
else: |
||||||
|
#self.__xspeed *= -1 |
||||||
|
foundpos = True |
||||||
|
elif isinstance(newobj, Paddle) and not ignorePaddles: |
||||||
|
self.doHitCallbacks(newobj) |
||||||
|
self.__xspeed *= -1 |
||||||
|
|
||||||
|
# bounce off at the paddle |
||||||
|
if self.__yspeed == 0: |
||||||
|
if self.__playground.getObjectAtPosition(newobj.xpos, newobj.ypos - 1) is None: |
||||||
|
self.__yspeed = -1 |
||||||
|
elif self.__plauground.getObjectAtPosition(newobj.xpos, newobj.ypos + 1) is None: |
||||||
|
self.__yspeed = 1 |
||||||
|
else: |
||||||
|
if newobj.xpos < self.__xpos: |
||||||
|
if self.__playground.getObjectAtPosition(self.__xpos - 1, self.__ypos) is None: |
||||||
|
self.__yspeed *= -1 |
||||||
|
if newobj.xpos > self.__xpos: |
||||||
|
if self.__playground.getObjectAtPosition(self.__xpos + 1, self.__ypos) is None: |
||||||
|
self.__yspeed *= -1 |
||||||
|
|
||||||
|
if newobj.nextMove != 0 and random.randint(0, 2) == 0: |
||||||
|
self.__yspeed += newobj.nextMove |
||||||
|
elif abs(self.__yspeed) != 1: |
||||||
|
self.__yspeed = 1 if self.__yspeed > 0 else -1 |
||||||
|
else: |
||||||
|
adjobj = self.__playground.getObjectAtPosition(newx, self.__ypos) |
||||||
|
if not ignorePaddles and isinstance(adjobj, Paddle): |
||||||
|
self.doHitCallbacks(adjobj) |
||||||
|
self.__xspeed *= -1 |
||||||
|
else: |
||||||
|
foundpos = True |
||||||
|
|
||||||
|
|
||||||
|
self.__xpos = newx |
||||||
|
self.__ypos = newy |
||||||
|
|
||||||
|
class Playground(object): |
||||||
|
def __init__(self, width, height, paddlesize=3): |
||||||
|
self.__width = width |
||||||
|
self.__height = height |
||||||
|
|
||||||
|
paddleLeft = Paddle(self, 0, (height - paddlesize)/2, paddlesize) |
||||||
|
paddleRight = Paddle(self, width - 1, (height - paddlesize)/2, paddlesize) |
||||||
|
self.__paddles = [paddleLeft, paddleRight] |
||||||
|
|
||||||
|
self.__ball = Ball(self, 0, 0, 1, 1) |
||||||
|
self.__gameTickCallbacks = [] |
||||||
|
self.__newRoundCallbacks = [] |
||||||
|
|
||||||
|
@property |
||||||
|
def width(self): |
||||||
|
return self.__width |
||||||
|
@property |
||||||
|
def height(self): |
||||||
|
return self.__height |
||||||
|
@property |
||||||
|
def leftPaddle(self): |
||||||
|
return self.__paddles[0] |
||||||
|
@property |
||||||
|
def rightPaddle(self): |
||||||
|
return self.__paddles[1] |
||||||
|
@property |
||||||
|
def ball(self): |
||||||
|
return self.__ball |
||||||
|
|
||||||
|
def containsPoint(self, x, y): |
||||||
|
if x >= 0 and x < self.width and y >= 0 and y < self.height: |
||||||
|
return True |
||||||
|
else: |
||||||
|
return False |
||||||
|
|
||||||
|
def addGameTickCallback(self, callback): |
||||||
|
self.__gameTickCallbacks.append(callback) |
||||||
|
print 'registered callback',callback |
||||||
|
def addNewRoundCallback(self, callback): |
||||||
|
self.__newRoundCallbacks.append(callback) |
||||||
|
|
||||||
|
def getObjectAtPosition(self, x, y): |
||||||
|
if x >= self.__width or x < 0: |
||||||
|
return Wall(Wall.VERTICAL) |
||||||
|
elif y >= self.__height or y < 0: |
||||||
|
return Wall(Wall.HORIZONTAL) |
||||||
|
elif y == self.__ball.ypos and x == self.__ball.xpos: |
||||||
|
return self.__ball |
||||||
|
else: |
||||||
|
for paddle in self.__paddles: |
||||||
|
if paddle.containsPoint(x, y): |
||||||
|
return paddle |
||||||
|
|
||||||
|
def play(self, serve=None): |
||||||
|
leftPaddle = self.__paddles[0] |
||||||
|
rightPaddle = self.__paddles[1] |
||||||
|
ball = self.__ball |
||||||
|
|
||||||
|
if serve not in self.__paddles: |
||||||
|
serve = self.__paddles[random.randint(0, 1)] |
||||||
|
|
||||||
|
ball.ypos = self.__height / 2 |
||||||
|
ball.xpos = self.__width / 2 |
||||||
|
if serve == rightPaddle and self.__width % 2 == 1: |
||||||
|
ball.xpos += 1 |
||||||
|
|
||||||
|
ball.yspeed = 0 |
||||||
|
if serve == rightPaddle: |
||||||
|
ball.xspeed = 1 |
||||||
|
else: |
||||||
|
ball.yspeed = -1 |
||||||
|
|
||||||
|
for callback in self.__newRoundCallbacks: |
||||||
|
callback() |
||||||
|
|
||||||
|
while True: |
||||||
|
time.sleep(0.1) |
||||||
|
ball.move() |
||||||
|
leftPaddle.doNextMove() |
||||||
|
rightPaddle.doNextMove() |
||||||
|
|
||||||
|
if not self.containsPoint(ball.xpos, ball.ypos): |
||||||
|
break |
||||||
|
|
||||||
|
for callback in self.__gameTickCallbacks: |
||||||
|
print callback |
||||||
|
callback() |
||||||
|
|
||||||
|
if ball.xpos >= self.width: |
||||||
|
return leftPaddle |
||||||
|
elif ball.xpos <= 0: |
||||||
|
return rightPaddle |
||||||
|
|
||||||
|
|
||||||
|
def getRandomColor(maxval): |
||||||
|
return map(lambda x: int(round(x*maxval)), colorsys.hsv_to_rgb(random.random(), 1, 1)) |
||||||
|
#return map(lambda x: int(round(x*maxval)), colorsys.hsv_to_rgb(random.random(), random.random(), random.random())) |
||||||
|
|
||||||
|
|
||||||
|
class PlaygroundPainter(object): |
||||||
|
def __init__(self, out, dimension, playground): |
||||||
|
self.__out = out |
||||||
|
self.__playground = playground |
||||||
|
self.__dimension = dimension |
||||||
|
self.__playground.addGameTickCallback(self.update) |
||||||
|
self.__playground.ball.addHitCallback(self.ballhit) |
||||||
|
|
||||||
|
if dimension.channels == 1: |
||||||
|
self.__ballColor = 1 |
||||||
|
self.__paddleColor = 1 |
||||||
|
else: |
||||||
|
self.__ballColor = getRandomColor(dimension.depth - 1) |
||||||
|
self.__leftPaddleColor = getRandomColor(dimension.depth - 1) |
||||||
|
self.__rightPaddleColor = getRandomColor(dimension.depth - 1) |
||||||
|
|
||||||
|
def update(self): |
||||||
|
frame = blup.frame.Frame(self.__dimension) |
||||||
|
#self.__paddleColor = getRandomColor(self.__dimension.depth - 1) |
||||||
|
|
||||||
|
if self.__dimension.channels == 3: |
||||||
|
for x in range(self.__dimension.width): |
||||||
|
for y in range(self.__dimension.height): |
||||||
|
frame.setPixel(x, y, (0,0,0)) |
||||||
|
|
||||||
|
frame.setPixel(self.__playground.ball.xpos, self.__playground.ball.ypos, self.__ballColor) |
||||||
|
|
||||||
|
for i in range(self.__playground.leftPaddle.size): |
||||||
|
frame.setPixel(self.__playground.leftPaddle.xpos, self.__playground.leftPaddle.ypos + i, self.__leftPaddleColor) |
||||||
|
for i in range(self.__playground.rightPaddle.size): |
||||||
|
frame.setPixel(self.__playground.rightPaddle.xpos, self.__playground.rightPaddle.ypos + i, self.__rightPaddleColor) |
||||||
|
|
||||||
|
self.__out.sendFrame(frame) |
||||||
|
|
||||||
|
def ballhit(self, obj): |
||||||
|
if self.__dimension.channels == 3: |
||||||
|
if isinstance(obj, Paddle): |
||||||
|
self.__ballColor = getRandomColor(self.__dimension.depth - 1) |
||||||
|
if obj.xpos == 0: |
||||||
|
self.__leftPaddleColor = self.__ballColor |
||||||
|
else: |
||||||
|
self.__rightPaddleColor = self.__ballColor |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PongBot(object): |
||||||
|
def __init__(self, playground, ownPaddle, dullness=0): |
||||||
|
self.__playground = playground |
||||||
|
self.__ownPaddle = ownPaddle |
||||||
|
self.__dullness = dullness |
||||||
|
self.__playground.addGameTickCallback(self.onGameTick) |
||||||
|
self.__playground.addNewRoundCallback(self.onNewRound) |
||||||
|
self.__playground.ball.addHitCallback(self.onHit) |
||||||
|
self.__hitpoint = None |
||||||
|
self.__oldHitpoint = None |
||||||
|
self.__dull = False |
||||||
|
|
||||||
|
def updateHitpoint(self): |
||||||
|
origball = self.__playground.ball |
||||||
|
ball = Ball(self.__playground, origball.xpos, origball.ypos, origball.xspeed, origball.yspeed) |
||||||
|
ball.move() |
||||||
|
hitpoint = None |
||||||
|
while hitpoint is None: |
||||||
|
if ball.xpos >= self.__playground.width - 1 or ball.xpos <= 0: |
||||||
|
hitpoint = (ball.xpos, ball.ypos) |
||||||
|
break |
||||||
|
|
||||||
|
ball.move(ignorePaddles=True) |
||||||
|
self.__oldHitpoint = self.__hitpoint |
||||||
|
self.__hitpoint = hitpoint |
||||||
|
|
||||||
|
def onHit(self, obj): |
||||||
|
print 'hit!', obj |
||||||
|
if isinstance(obj, Paddle) and obj is not self.__ownPaddle: |
||||||
|
self.updateHitpoint() |
||||||
|
|
||||||
|
if self.__dullness > random.randint(0, 4): |
||||||
|
self.__dull = True |
||||||
|
else: |
||||||
|
self.__dull = False |
||||||
|
|
||||||
|
def onNewRound(self): |
||||||
|
self.updateHitpoint() |
||||||
|
self.__oldHitpoint = None |
||||||
|
self.__dull = False |
||||||
|
|
||||||
|
def onGameTick(self): |
||||||
|
#self.updateHitpoint() |
||||||
|
print 'hitpoint', self.__hitpoint |
||||||
|
(hitx, hity) = self.__hitpoint |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if hitx == self.__ownPaddle.xpos: |
||||||
|
if abs(self.__playground.ball.xpos - self.__ownPaddle.xpos) < 15: |
||||||
|
if not self.__dull: |
||||||
|
if not self.__ownPaddle.containsPoint(hitx, hity): |
||||||
|
print 'moving!!' |
||||||
|
if self.__ownPaddle.ypos < hity: |
||||||
|
self.__ownPaddle.nextMoveDown() |
||||||
|
else: |
||||||
|
self.__ownPaddle.nextMoveUp() |
||||||
|
else: |
||||||
|
if self.__ownPaddle.containsPoint(hitx, hity): |
||||||
|
print 'moving!!' |
||||||
|
if hity < self.__ownPaddle.size: |
||||||
|
self.__ownPaddle.nextMoveDown() |
||||||
|
else: |
||||||
|
self.__ownPaddle.nextMoveUp() |
||||||
|
|
||||||
|
elif self.__dull: |
||||||
|
r = random.randint(-1, 1) |
||||||
|
if r == -1: |
||||||
|
self.__ownPaddle.nextMoveUp() |
||||||
|
elif r == 1: |
||||||
|
self.__ownPaddle.nextMoveDown() |
||||||
|
|
||||||
|
|
||||||
|
def displayScore(out, dimension, leftScore, rightScore, delay=0): |
||||||
|
leftNumber = __numbers[leftScore] |
||||||
|
rightNumber = __numbers[rightScore] |
||||||
|
|
||||||
|
frame = blup.frame.Frame(dimension) |
||||||
|
|
||||||
|
if dimension.channels == 1: |
||||||
|
dotcolor = 1 |
||||||
|
numcolor = 1 |
||||||
|
else: |
||||||
|
dotcolor = getRandomColor(dimension.depth - 1) |
||||||
|
numcolor = getRandomColor(dimension.depth - 1) |
||||||
|
|
||||||
|
frame.setPixel(8, 1, dotcolor) |
||||||
|
frame.setPixel(9, 1, dotcolor) |
||||||
|
frame.setPixel(8, 2, dotcolor) |
||||||
|
frame.setPixel(9, 2, dotcolor) |
||||||
|
frame.setPixel(8, 4, dotcolor) |
||||||
|
frame.setPixel(9, 4, dotcolor) |
||||||
|
frame.setPixel(8, 5, dotcolor) |
||||||
|
frame.setPixel(9, 5, dotcolor) |
||||||
|
|
||||||
|
for x in range(5): |
||||||
|
for y in range(5): |
||||||
|
if leftNumber[y][x] == 1: |
||||||
|
frame.setPixel(x+1, y+1, numcolor) |
||||||
|
if rightNumber[y][x] == 1: |
||||||
|
frame.setPixel(x+12, y+1, numcolor) |
||||||
|
|
||||||
|
out.sendFrame(frame) |
||||||
|
if delay > 0: |
||||||
|
time.sleep(delay / 1000.0) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main(): |
||||||
|
print 'running a \'Bot vs. Bot\' round...' |
||||||
|
#out = blup.output.getOutput('blp:localhost:42421') |
||||||
|
#out = blup.output.getOutput('e3blp:bastel0:4242') |
||||||
|
out = blup.output.getOutput('e3blp:localhost:4242') |
||||||
|
#out = blup.output.getOutput('e3blp:bbunt:42429') |
||||||
|
#dim = blup.frame.FrameDimension(18, 8, 8, 3) |
||||||
|
dim = blup.frame.FrameDimension(22, 16, 255, 3) |
||||||
|
|
||||||
|
playground = Playground(22, 16, paddlesize=4) |
||||||
|
pp = PlaygroundPainter(out, dim, playground) |
||||||
|
|
||||||
|
leftPaddle = playground.leftPaddle |
||||||
|
rightPaddle = playground.rightPaddle |
||||||
|
ball = playground.ball |
||||||
|
|
||||||
|
leftBot = PongBot(playground, leftPaddle, 1) |
||||||
|
rightBot = PongBot(playground, rightPaddle, 1) |
||||||
|
|
||||||
|
print playground.play() |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
main() |
||||||
|
|
||||||
|
|
@ -0,0 +1,178 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import time |
||||||
|
import threading |
||||||
|
import sys |
||||||
|
|
||||||
|
import blup.frame |
||||||
|
import blup.output |
||||||
|
sys.path.append('/var/tmp/r0ket/tools/game') |
||||||
|
#sys.path.append('/var/tmp/r0ket_misc/game_noprint') |
||||||
|
import r0ketrem0te.game |
||||||
|
import pong |
||||||
|
|
||||||
|
logo = [ |
||||||
|
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
||||||
|
[1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0], |
||||||
|
[1,0,1,0,1,0,0,1,0,1,1,0,1,0,1,0,0,1], |
||||||
|
[1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,0,0,0], |
||||||
|
[1,1,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,1], |
||||||
|
[1,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1], |
||||||
|
[1,0,0,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0], |
||||||
|
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] |
||||||
|
] |
||||||
|
onePlayer = [ |
||||||
|
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
||||||
|
[0,0,1,1,0,0,1,1,1,1,0,0,0,1,1,1,0,0], |
||||||
|
[0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0], |
||||||
|
[0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0], |
||||||
|
[0,0,0,1,0,0,1,1,1,1,0,0,0,0,1,0,0,0], |
||||||
|
[0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0], |
||||||
|
[0,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,0,0], |
||||||
|
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] |
||||||
|
] |
||||||
|
|
||||||
|
def convertPixels(dimension, pixels): |
||||||
|
p = [] |
||||||
|
maxval = dimension.depth - 1 |
||||||
|
for i in range(len(pixels)): |
||||||
|
row = [] |
||||||
|
for j in range(len(pixels[i])): |
||||||
|
if pixels[i][j] == 1: |
||||||
|
row.append((maxval, maxval, maxval)) |
||||||
|
else: |
||||||
|
row.append((0,0,0)) |
||||||
|
p.append(row) |
||||||
|
return p |
||||||
|
|
||||||
|
class R0ketPongPlayer(object): |
||||||
|
def __init__(self, playground, ownPaddle, r0ketPlayer): |
||||||
|
self.__playground = playground |
||||||
|
self.__ownPaddle = ownPaddle |
||||||
|
self.__r0ketPlayer = r0ketPlayer |
||||||
|
self.__ready = False |
||||||
|
|
||||||
|
@property |
||||||
|
def ownPaddle(self): |
||||||
|
return self.__ownPaddle |
||||||
|
|
||||||
|
@property |
||||||
|
def ready(self): |
||||||
|
return self.__ready |
||||||
|
|
||||||
|
def receivedPacket(self, packet): |
||||||
|
if self.__r0ketPlayer is not None: |
||||||
|
if packet.id == self.__r0ketPlayer.id: |
||||||
|
if isinstance(packet, r0ketrem0te.packets.Button): |
||||||
|
print 'button=', packet.button |
||||||
|
if packet.button == 1: |
||||||
|
self.__ownPaddle.nextMoveUp() |
||||||
|
print 'up' |
||||||
|
if packet.button == 2: |
||||||
|
self.__ownPaddle.nextMoveDown() |
||||||
|
print 'down' |
||||||
|
if packet.button == 16: |
||||||
|
self.__ready = True |
||||||
|
|
||||||
|
class R0ketPong(object): |
||||||
|
def __init__(self, out, color=False, port='/dev/ttyACM0', gameName='pong'): |
||||||
|
self.__playground = None |
||||||
|
self.__out = out |
||||||
|
self.__rem0te = r0ketrem0te.game.Game(port, gameName, 83, 87, [ord(x) for x in 'REM0T'], 2, False) |
||||||
|
self.__rem0te.registerPlayerCallback(self.playerCallback) |
||||||
|
self.__color = color |
||||||
|
|
||||||
|
self.__players = [] |
||||||
|
self.__playersChangedCondition = threading.Condition() |
||||||
|
|
||||||
|
if color: |
||||||
|
self.__dimension = blup.frame.FrameDimension(18, 8, 8, 3) |
||||||
|
else: |
||||||
|
self.__dimension = blup.frame.FrameDimension(18, 8, 2, 1) |
||||||
|
|
||||||
|
def playerCallback(self, action, player): |
||||||
|
if self.__playground is None: |
||||||
|
return |
||||||
|
print '\n\n\n\nplayer added',player,'\n\n\n\n' |
||||||
|
if action == 'added' and len(self.__players) < 2: |
||||||
|
if len(self.__players) == 0: |
||||||
|
playerPaddle = self.__playground.leftPaddle |
||||||
|
else: |
||||||
|
playerPaddle = self.__playground.rightPaddle |
||||||
|
player = R0ketPongPlayer(self.__playground, playerPaddle, player) |
||||||
|
self.__rem0te.bridge.registerCallback(player.receivedPacket) |
||||||
|
self.__players.append(player) |
||||||
|
with self.__playersChangedCondition: |
||||||
|
self.__playersChangedCondition.notifyAll() |
||||||
|
|
||||||
|
def runGame(self): |
||||||
|
print 'starting a game...' |
||||||
|
scoreLeft = 0 |
||||||
|
scoreRight = 0 |
||||||
|
|
||||||
|
self.__playground = pong.Playground(18, 8) |
||||||
|
pp = pong.PlaygroundPainter(out, self.__dimension, self.__playground) |
||||||
|
|
||||||
|
while len(self.__players) == 0: |
||||||
|
print 'waiting for player...' |
||||||
|
with self.__playersChangedCondition: |
||||||
|
self.__playersChangedCondition.wait() |
||||||
|
|
||||||
|
frame = blup.frame.Frame(self.__dimension) |
||||||
|
global onePlayer |
||||||
|
if self.__color: |
||||||
|
frame.pixels = convertPixels(self.__dimension, onePlayer) |
||||||
|
else: |
||||||
|
frame.pixels = onePlayer |
||||||
|
self.__out.sendFrame(frame) |
||||||
|
|
||||||
|
while len(self.__players) == 1 and not self.__players[0].ready: |
||||||
|
print 'waiting for another player...' |
||||||
|
time.sleep(1) |
||||||
|
self.__out.sendFrame(frame) |
||||||
|
|
||||||
|
frame = blup.frame.Frame(self.__dimension) |
||||||
|
global logo |
||||||
|
if self.__color: |
||||||
|
frame.pixels = convertPixels(self.__dimension, logo) |
||||||
|
else: |
||||||
|
frame.pixels = logo |
||||||
|
self.__out.sendFrame(frame) |
||||||
|
time.sleep(1) |
||||||
|
|
||||||
|
if len(self.__players) == 1: |
||||||
|
bot = pong.PongBot(self.__playground, self.__playground.rightPaddle, 2) |
||||||
|
self.__players.append(bot) |
||||||
|
|
||||||
|
while max(scoreLeft, scoreRight) < 9: |
||||||
|
winner = self.__playground.play() |
||||||
|
if winner is self.__players[0].ownPaddle: |
||||||
|
scoreLeft += 1 |
||||||
|
else: |
||||||
|
scoreRight += 1 |
||||||
|
pong.displayScore(self.__out, self.__dimension, scoreLeft, scoreRight, 3000) |
||||||
|
|
||||||
|
for i in range(3): |
||||||
|
frame = blup.frame.Frame(self.__dimension) |
||||||
|
self.__out.sendFrame(frame) |
||||||
|
time.sleep(0.5) |
||||||
|
pong.displayScore(self.__out, self.__dimension, scoreLeft, scoreRight, 500) |
||||||
|
frame = blup.frame.Frame(self.__dimension) |
||||||
|
self.__out.sendFrame(frame) |
||||||
|
|
||||||
|
self.__playground = None |
||||||
|
self.__players = [] |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
out = blup.output.getOutput('e3blp:localhost:4242') |
||||||
|
|
||||||
|
|
||||||
|
p0ng = R0ketPong(out, color=True) |
||||||
|
while True: |
||||||
|
p0ng.runGame() |
||||||
|
|
||||||
|
sys.exit(0) |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,28 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<blm width="18" height="8" bits="4" channels="3"> |
||||||
|
<header> |
||||||
|
<creator>Blimp (version 0.1.5)</creator> |
||||||
|
</header> |
||||||
|
|
||||||
|
<frame duration="500"> |
||||||
|
<row>000000000FF00F0FF0000000000000000000FF00F0FF0000000000</row> |
||||||
|
<row>0000000000F00F00F00000000000000000000F00F00F0000000000</row> |
||||||
|
<row>000000000000090000000000000000000000000090000000000000</row> |
||||||
|
<row>0000000000F00F00F00000900000000000000F00F00F0000090000</row> |
||||||
|
<row>0000900900F0FF00F00900900000000900900F0FF00F0090090000</row> |
||||||
|
<row>0000900000F00F00F00000000000000900000F00F00F0000000000</row> |
||||||
|
<row>0000000000F00F00F00000000000000000000F00F00F0000000000</row> |
||||||
|
<row>000000000090000090000000000000000000090000090000000000</row> |
||||||
|
</frame> |
||||||
|
|
||||||
|
<frame duration="500"> |
||||||
|
<row>000000000FF00F0FF0000000000000000000FF00F0FF0000000000</row> |
||||||
|
<row>0000000000F00F00F00000000000000000000F00F00F0000000000</row> |
||||||
|
<row>000000000000090000000000000000000000000090000000000000</row> |
||||||
|
<row>0000900000F00F00F00000000000000900000F00F00F0000000000</row> |
||||||
|
<row>0000900900F0FF00F00900900000000900900F0FF00F0090090000</row> |
||||||
|
<row>0000000000F00F00F00000900000000000000F00F00F0000090000</row> |
||||||
|
<row>0000000000F00F00F00000000000000000000F00F00F0000000000</row> |
||||||
|
<row>000000000090000090000000000000000000090000090000000000</row> |
||||||
|
</frame> |
||||||
|
</blm> |
@ -0,0 +1,39 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<blm width="18" height="8" bits="4" channels="3"> |
||||||
|
<header> |
||||||
|
<creator>Blimp (version 0.1.5)</creator> |
||||||
|
</header> |
||||||
|
|
||||||
|
<frame duration="500"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>0000FF0000000FF000000FF0000000FF0000000F0F000000F0F000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>0000FF0000000FF000000FF0000000FF0000000F0F000000F0F000</row> |
||||||
|
<row>0000000FF0FF000000000000FF0FF0000000000000F0FF0F000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
|
||||||
|
<frame duration="500"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>0000F00000000F0000000F00000000F0000000000F00000000F000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>0000F00000000F0000000F00000000F0000000000F00000000F000</row> |
||||||
|
<row>0000000F00F0000000000000F00F0000000000000000F00F000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
|
||||||
|
<frame duration="500"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000FFF000000FFF000000FFF000000FFF000000FFF000000FFF000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000FFF000000FFF000000FFF000000FFF000000FFF000000FFF000</row> |
||||||
|
<row>000000FFFFFF000000000000FFFFFF000000000000FFFFFF000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
</blm> |
@ -0,0 +1,50 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<blm width="18" height="8" bits="4" channels="3"> |
||||||
|
<header> |
||||||
|
<creator>Blimp (version 0.1.5)</creator> |
||||||
|
</header> |
||||||
|
|
||||||
|
<frame duration="500"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000FF0000000FF0000000F0F000000F0F000</row> |
||||||
|
<row>0000FF0000000FF000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000FF0000000FF0000000F0F000000F0F000</row> |
||||||
|
<row>0000FF0000000FF000000000FF0FF0000000000000F0FF0F000000</row> |
||||||
|
<row>0000000FF0FF000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
|
||||||
|
<frame duration="500"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>0000F00000000F000000000000000000000000000F00000000F000</row> |
||||||
|
<row>000000000000000000000F00000000F00000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>0000F00000000F000000000000000000000000000F00000000F000</row> |
||||||
|
<row>0000000F00F0000000000F00000000F0000000000000F00F000000</row> |
||||||
|
<row>000000000000000000000000F00F00000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
|
||||||
|
<frame duration="500"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000FFF000000FFF000000FFF000000FFF000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000FFF000000FFF000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000FFF000000FFF000000FFF000000FFF000000000000000000000</row> |
||||||
|
<row>000000FFFFFF000000000000FFFFFF000000000FFF000000FFF000</row> |
||||||
|
<row>000000000000000000000000000000000000000000FFFFFF000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
|
||||||
|
<frame duration="500"> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000FF0000000FF0000FF0000000FF0000FF0000000FF0000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000FF0000000FF0000FF0000000FF0000FF0000000FF0000000</row> |
||||||
|
<row>000000000FF0FF0000000000FF0FF0000000000FF0FF0000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
<row>000000000000000000000000000000000000000000000000000000</row> |
||||||
|
</frame> |
||||||
|
</blm> |
@ -0,0 +1,135 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
# inspired by: |
||||||
|
# http://lodev.org/cgtutor/plasma.html |
||||||
|
|
||||||
|
import sys |
||||||
|
import time |
||||||
|
import math |
||||||
|
#import pygame |
||||||
|
import colorsys |
||||||
|
import blup.frame |
||||||
|
import blup.output |
||||||
|
|
||||||
|
|
||||||
|
class Plasma(object): |
||||||
|
def __init__(self, width, height): |
||||||
|
self.width = width |
||||||
|
self.height = height |
||||||
|
|
||||||
|
self.pixelvalues = [[0] * height for i in xrange(width)] |
||||||
|
self.pixelsReady = False |
||||||
|
self.offset = 0 |
||||||
|
self.update() |
||||||
|
|
||||||
|
@property |
||||||
|
def minValue(self): |
||||||
|
return min(map(min, self.pixelvalues)) |
||||||
|
|
||||||
|
@property |
||||||
|
def maxValue(self): |
||||||
|
return max(map(max, self.pixelvalues)) |
||||||
|
|
||||||
|
def applyPalette(self, palette): |
||||||
|
min = self.minValue |
||||||
|
max = self.maxValue |
||||||
|
norm = lambda x: ((x - min) / max) |
||||||
|
|
||||||
|
pixeldata = [ [None] * self.height for i in xrange(self.width) ] |
||||||
|
|
||||||
|
for x in xrange(self.width): |
||||||
|
rowvalues = self.pixelvalues[x] |
||||||
|
for y in xrange(self.height): |
||||||
|
pixeldata[x][y] = palette.getColorValue(norm(rowvalues[y])) |
||||||
|
|
||||||
|
return pixeldata |
||||||
|
|
||||||
|
def update(self): |
||||||
|
#if self.pixelsReady: |
||||||
|
# return |
||||||
|
self.offset += 1 |
||||||
|
|
||||||
|
for x in xrange(self.width): |
||||||
|
for y in xrange(self.height): |
||||||
|
xx = x+self.offset |
||||||
|
yy = y+self.offset |
||||||
|
p = 128 + 128 * math.sin(xx / 9.0) |
||||||
|
p += 128 + 128 * math.sin(yy / 16.0) |
||||||
|
p += 128 + 128 * math.sin((yy + xx) / 16.0) |
||||||
|
p += 128 + 128 * math.sin(math.sqrt(yy*yy + xx*xx) / 16.0) |
||||||
|
p += 128 + 8 * math.sin(math.sqrt(yy* xx) / 16.0) |
||||||
|
self.pixelvalues[x][y] = p |
||||||
|
self.pixelsReady = True |
||||||
|
|
||||||
|
class Palette(object): |
||||||
|
def __init__(self): |
||||||
|
self.offset = 0 |
||||||
|
self.cache = {} |
||||||
|
|
||||||
|
def getColorValue(self, x): |
||||||
|
x = round(x, 3) |
||||||
|
if self.cache.has_key(x): |
||||||
|
return self.cache[x] |
||||||
|
c = colorsys.hsv_to_rgb((x + self.offset) % 1, 1, 1) |
||||||
|
c = map(lambda x: int(x * 255), c) |
||||||
|
self.cache[x] = c |
||||||
|
return c |
||||||
|
|
||||||
|
def update(self): |
||||||
|
self.cache = {} |
||||||
|
self.offset += 0.01 |
||||||
|
if self.offset > 1: |
||||||
|
self.offset -= 1 |
||||||
|
|
||||||
|
############################################## |
||||||
|
|
||||||
|
w = 22 |
||||||
|
h = 16 |
||||||
|
|
||||||
|
#w = 80 |
||||||
|
#h = 18 |
||||||
|
|
||||||
|
scalex = 30 |
||||||
|
scaley = 60 |
||||||
|
|
||||||
|
plasma = Plasma(w,h) |
||||||
|
palette= Palette() |
||||||
|
|
||||||
|
#screen = pygame.display.set_mode((w*scalex, h*scaley)) |
||||||
|
#pygame.display.update() |
||||||
|
|
||||||
|
#dim = blup.frame.FrameDimension(w, h, 8, 3) |
||||||
|
dim = blup.frame.FrameDimension(w, h, 256, 3) |
||||||
|
#out = blup.output.getOutput('serialblup:/dev/ttyUSB0:115200') |
||||||
|
#out = blup.output.getOutput('colorfulshell') |
||||||
|
#out = blup.output.getOutput('e3blp:bastel0:4242') |
||||||
|
out = blup.output.getOutput('e3blp') |
||||||
|
|
||||||
|
while True: |
||||||
|
#screen.fill((0,0,0)) |
||||||
|
|
||||||
|
#print 'updating palette...' |
||||||
|
palette.update() |
||||||
|
#print 'updating plasma...' |
||||||
|
plasma.update() |
||||||
|
#print 'applying palette...' |
||||||
|
pixeldata = plasma.applyPalette(palette) |
||||||
|
|
||||||
|
#print 'drawing...' |
||||||
|
f = blup.frame.Frame(dim) |
||||||
|
for x in xrange(w): |
||||||
|
#rowdata = pixeldata[x] |
||||||
|
for y in xrange(h): |
||||||
|
#pygame.draw.rect(screen, pixeldata[x][y], (x*scalex, y*scaley, scalex, scaley), 0) |
||||||
|
#pygame.draw.circle(screen, rowdata[y], (x, y), 1, 1) |
||||||
|
i= f.setPixel(x, y, pixeldata[x][y]) |
||||||
|
#print frame.channels, frame.depth |
||||||
|
#print 'done drawing' |
||||||
|
|
||||||
|
out.sendFrame(f) |
||||||
|
|
||||||
|
#pygame.display.update() |
||||||
|
#print 'done updating' |
||||||
|
#time.sleep(0.05) |
||||||
|
|
||||||
|
|
@ -0,0 +1,152 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
# inspired by: |
||||||
|
# http://lodev.org/cgtutor/plasma.html |
||||||
|
|
||||||
|
import sys |
||||||
|
import time |
||||||
|
import math |
||||||
|
#import pygame |
||||||
|
import colorsys |
||||||
|
from neopixel import * |
||||||
|
|
||||||
|
|
||||||
|
class Plasma(object): |
||||||
|
def __init__(self, width, height): |
||||||
|
self.width = width |
||||||
|
self.height = height |
||||||
|
|
||||||
|
self.pixelvalues = [[0] * height for i in xrange(width)] |
||||||
|
self.pixelsReady = False |
||||||
|
self.offset = 0 |
||||||
|
self.update() |
||||||
|
|
||||||
|
@property |
||||||
|
def minValue(self): |
||||||
|
return min(map(min, self.pixelvalues)) |
||||||
|
|
||||||
|
@property |
||||||
|
def maxValue(self): |
||||||
|
return max(map(max, self.pixelvalues)) |
||||||
|
|
||||||
|
def applyPalette(self, palette): |
||||||
|
min = self.minValue |
||||||
|
max = self.maxValue |
||||||
|
norm = lambda x: ((x - min) / max) |
||||||
|
|
||||||
|
pixeldata = [ [None] * self.height for i in xrange(self.width) ] |
||||||
|
|
||||||
|
for x in xrange(self.width): |
||||||
|
rowvalues = self.pixelvalues[x] |
||||||
|
for y in xrange(self.height): |
||||||
|
pixeldata[x][y] = palette.getColorValue(norm(rowvalues[y])) |
||||||
|
|
||||||
|
return pixeldata |
||||||
|
|
||||||
|
def update(self): |
||||||
|
#if self.pixelsReady: |
||||||
|
# return |
||||||
|
self.offset += 1 |
||||||
|
|
||||||
|
for x in xrange(self.width): |
||||||
|
for y in xrange(self.height): |
||||||
|
xx = x+self.offset |
||||||
|
yy = y+self.offset |
||||||
|
#xx = 10*x+self.offset |
||||||
|
#yy = 10*y+self.offset |
||||||
|
p = 128 + 128 * math.sin(xx / 9.0) |
||||||
|
p += 128 + 128 * math.sin(yy / 16.0) |
||||||
|
p += 128 + 128 * math.sin((yy + xx) / 16.0) |
||||||
|
p += 128 + 128 * math.sin(math.sqrt(yy*yy + xx*xx) / 16.0) |
||||||
|
p += 128 + 8 * math.sin(math.sqrt(yy* xx) / 16.0) |
||||||
|
self.pixelvalues[x][y] = p |
||||||
|
self.pixelsReady = True |
||||||
|
|
||||||
|
class Palette(object): |
||||||
|
def __init__(self): |
||||||
|
self.offset = 0 |
||||||
|
self.cache = {} |
||||||
|
|
||||||
|
def getColorValue(self, x): |
||||||
|
x = round(x, 3) |
||||||
|
if self.cache.has_key(x): |
||||||
|
return self.cache[x] |
||||||
|
c = colorsys.hsv_to_rgb((x + self.offset) % 1, 1, 1) |
||||||
|
#c = map(lambda x: int(x * 7), c) |
||||||
|
depth = 255 |
||||||
|
c = map(lambda x: int(x * depth), c) |
||||||
|
self.cache[x] = c |
||||||
|
return c |
||||||
|
|
||||||
|
def update(self): |
||||||
|
self.cache = {} |
||||||
|
self.offset += 0.01 |
||||||
|
if self.offset > 1: |
||||||
|
self.offset -= 1 |
||||||
|
|
||||||
|
############################################## |
||||||
|
|
||||||
|
w = 22 |
||||||
|
h = 16 |
||||||
|
|
||||||
|
#w = 80 |
||||||
|
#h = 18 |
||||||
|
|
||||||
|
scalex = 30 |
||||||
|
scaley = 60 |
||||||
|
|
||||||
|
plasma = Plasma(w,h) |
||||||
|
palette= Palette() |
||||||
|
|
||||||
|
#screen = pygame.display.set_mode((w*scalex, h*scaley)) |
||||||
|
#pygame.display.update() |
||||||
|
|
||||||
|
##dim = blup.frame.FrameDimension(w, h, 8, 3) |
||||||
|
#dim = blup.frame.FrameDimension(w, h, 8, 3) |
||||||
|
##out = blup.output.getOutput('serialblup:/dev/ttyUSB0:115200') |
||||||
|
##out = blup.output.getOutput('colorfulshell') |
||||||
|
##out = blup.output.getOutput('e3blp:bastel0:4242') |
||||||
|
#out = blup.output.getOutput('e3blp') |
||||||
|
|
||||||
|
|
||||||
|
# LED strip configuration: |
||||||
|
LED_COUNT = 352 # Number of LED pixels. |
||||||
|
LED_PIN = 13 # GPIO pin connected to the pixels (must support PWM!). |
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz) |
||||||
|
LED_DMA = 5 # DMA channel to use for generating signal (try 5) |
||||||
|
LED_BRIGHTNESS = 50 # Set to 0 for darkest and 255 for brightest |
||||||
|
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) |
||||||
|
LED_PWM = 1 |
||||||
|
|
||||||
|
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_PWM) |
||||||
|
strip.begin() |
||||||
|
|
||||||
|
while True: |
||||||
|
#screen.fill((0,0,0)) |
||||||
|
|
||||||
|
#print 'updating palette...' |
||||||
|
palette.update() |
||||||
|
#print 'updating plasma...' |
||||||
|
plasma.update() |
||||||
|
#print 'applying palette...' |
||||||
|
pixeldata = plasma.applyPalette(palette) |
||||||
|
|
||||||
|
#print 'drawing...' |
||||||
|
#f = blup.frame.Frame(dim) |
||||||
|
for y in xrange(h): |
||||||
|
for x in xrange(w): |
||||||
|
if x%2 == 0: |
||||||
|
lednum = x*h + y |
||||||
|
else: |
||||||
|
lednum = x*h - y + 15 |
||||||
|
strip.setPixelColor(lednum, Color(*pixeldata[x][y])) |
||||||
|
strip.show() |
||||||
|
#print 'done drawing' |
||||||
|
|
||||||
|
#out.sendFrame(f) |
||||||
|
|
||||||
|
#pygame.display.update() |
||||||
|
#print 'done updating' |
||||||
|
#time.sleep(0.01) |
||||||
|
|
||||||
|
|
@ -0,0 +1,311 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
|
||||||
|
import time |
||||||
|
import enum |
||||||
|
import math |
||||||
|
import collections |
||||||
|
import blup.frame |
||||||
|
import blup.output |
||||||
|
import random |
||||||
|
|
||||||
|
|
||||||
|
class InvalidMoveError(Exception): |
||||||
|
pass |
||||||
|
|
||||||
|
class Point(collections.namedtuple('Point', ['x', 'y'])): |
||||||
|
__slots__ = () |
||||||
|
|
||||||
|
def __add__(self, other): |
||||||
|
return Point(self.x + other.x, self.y + other.y) |
||||||
|
|
||||||
|
def floored(self): |
||||||
|
return Point(math.floor(self.x), math.floor(self.y)) |
||||||
|
|
||||||
|
Block = collections.namedtuple('Block', ['pos', 'color']) |
||||||
|
|
||||||
|
|
||||||
|
class Tetrimino(): |
||||||
|
def __init__(self, shape, playground, pos): |
||||||
|
self.shape = shape |
||||||
|
self.playground = playground |
||||||
|
self.pos = pos |
||||||
|
|
||||||
|
@property |
||||||
|
def width(self): |
||||||
|
x = list(map(lambda s: s.pos.x, self.shape)) |
||||||
|
return max(x) - min(x) |
||||||
|
|
||||||
|
@property |
||||||
|
def height(self): |
||||||
|
y = list(map(lambda s: s.pos.y, self.shape)) |
||||||
|
return max(y) - min(y) |
||||||
|
|
||||||
|
@property |
||||||
|
def blocks(self): |
||||||
|
ret = { Block((self.pos + b.pos).floored(), b.color) for b in |
||||||
|
self.shape } |
||||||
|
return ret |
||||||
|
|
||||||
|
def __calc_points(self, pos=None, shape=None): |
||||||
|
if pos is None: |
||||||
|
pos = self.pos |
||||||
|
if shape is None: |
||||||
|
shape = self.shape |
||||||
|
return { (pos + b.pos).floored() for b in shape } |
||||||
|
|
||||||
|
@property |
||||||
|
def points(self): |
||||||
|
return self.__calc_points() |
||||||
|
|
||||||
|
def __check_collision(self, newpoints): |
||||||
|
if not self.playground.contains_points(newpoints): |
||||||
|
raise InvalidMoveError('out of playground bounds') |
||||||
|
print(self.playground.block_points) |
||||||
|
print(self.playground.blocks) |
||||||
|
print('new', newpoints) |
||||||
|
if not self.playground.block_points.isdisjoint(newpoints): |
||||||
|
raise InvalidMoveError('new position already occupied') |
||||||
|
other_mino_points = self.playground.mino_points - self.points |
||||||
|
if not other_mino_points.isdisjoint(newpoints): |
||||||
|
raise InvalidMoveError('other Tetrimino at new position') |
||||||
|
|
||||||
|
def rotate(self, ccw=False): |
||||||
|
if ccw: |
||||||
|
transform = lambda s: Block(Point(s.pos.y, -s.pos.x), s.color) |
||||||
|
else: |
||||||
|
transform = lambda s: Block(Point(-s.pos.y, s.pos.x), s.color) |
||||||
|
newshape = set(map(transform, self.shape)) |
||||||
|
newpoints = self.__calc_points(shape=newshape) |
||||||
|
self.__check_collision(newpoints) |
||||||
|
self.shape = newshape |
||||||
|
|
||||||
|
def move(self, m): |
||||||
|
newpos = self.pos + m |
||||||
|
newpoints = self.__calc_points(pos=newpos) |
||||||
|
self.__check_collision(newpoints) |
||||||
|
self.pos = newpos |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TetriL(Tetrimino): |
||||||
|
def __init__(self, playground, pos): |
||||||
|
color = (255,165,0) |
||||||
|
points = [(-1, 1), (-1, 0), (0, 0), (1, 0)] |
||||||
|
shape = { Block(Point(x, y), color) for (x, y) in points } |
||||||
|
Tetrimino.__init__(self, shape, playground, pos) |
||||||
|
|
||||||
|
|
||||||
|
class TetriJ(Tetrimino): |
||||||
|
def __init__(self, playground, pos): |
||||||
|
color = (0,0,255) |
||||||
|
points = [(-1, 0), (0, 0), (1, 0), (1, 1)] |
||||||
|
shape = { Block(Point(x, y), color) for (x, y) in points } |
||||||
|
Tetrimino.__init__(self, shape, playground, pos) |
||||||
|
|
||||||
|
|
||||||
|
class TetriI(Tetrimino): |
||||||
|
def __init__(self, playground, pos): |
||||||
|
color = (0,255,255) |
||||||
|
points = {(1.5, -0.5), (0.5, -0.5), (-0.5, -0.5), (-1.5, -0.5)} |
||||||
|
shape = { Block(Point(x, y), color) for (x, y) in points } |
||||||
|
Tetrimino.__init__(self, shape, playground, pos) |
||||||
|
|
||||||
|
|
||||||
|
class TetriO(Tetrimino): |
||||||
|
def __init__(self, playground, pos): |
||||||
|
color = (255,255,0) |
||||||
|
points = {(-0.5, -0.5), (-0.5, 0.5), (0.5, -0.5), (0.5, 0.5)} |
||||||
|
shape = { Block(Point(x, y), color) for (x, y) in points } |
||||||
|
Tetrimino.__init__(self, shape, playground, pos) |
||||||
|
|
||||||
|
|
||||||
|
class TetriS(Tetrimino): |
||||||
|
def __init__(self, playground, pos): |
||||||
|
color = (128,255,0) |
||||||
|
points = {(-1, 0), (0, 0), (0, -1), (1, -1)} |
||||||
|
shape = { Block(Point(x, y), color) for (x, y) in points } |
||||||
|
Tetrimino.__init__(self, shape, playground, pos) |
||||||
|
|
||||||
|
|
||||||
|
class TetriZ(Tetrimino): |
||||||
|
def __init__(self, playground, pos): |
||||||
|
color = (255,0,0) |
||||||
|
points = {(-1, 0), (0, 0), (0, 1), (1, 1)} |
||||||
|
shape = { Block(Point(x, y), color) for (x, y) in points } |
||||||
|
Tetrimino.__init__(self, shape, playground, pos) |
||||||
|
|
||||||
|
|
||||||
|
class TetriT(Tetrimino): |
||||||
|
def __init__(self, playground, pos): |
||||||
|
color = (128,0,128) |
||||||
|
points = {(-1, 0), (0, 0), (1, 0), (0, 1)} |
||||||
|
shape = { Block(Point(x, y), color) for (x, y) in points } |
||||||
|
Tetrimino.__init__(self, shape, playground, pos) |
||||||
|
|
||||||
|
|
||||||
|
class Playground(): |
||||||
|
def __init__(self, width=10, height=22): |
||||||
|
self.width = width |
||||||
|
self.height = height |
||||||
|
self.blocks = set() |
||||||
|
self.minos = set() |
||||||
|
|
||||||
|
@property |
||||||
|
def block_points(self): |
||||||
|
return set([ b.pos for b in self.blocks ]) |
||||||
|
|
||||||
|
@property |
||||||
|
def mino_points(self): |
||||||
|
return set.union(set(), *[ m.points for m in self.minos ]) |
||||||
|
|
||||||
|
def contains_points(self, points): |
||||||
|
for p in points: |
||||||
|
if p.x >= self.width or p.y >= self.height or p.x < 0 or p.y < 0: |
||||||
|
return False |
||||||
|
return True |
||||||
|
|
||||||
|
def paint(self, frame, xpos, ypos): |
||||||
|
for x in range(frame.dimension.width): |
||||||
|
for y in range(frame.dimension.height): |
||||||
|
frame.setPixel(x, y, (0, 0, 0)) |
||||||
|
for b in set.union(self.blocks, *[ m.blocks for m in self.minos ]): |
||||||
|
frame.setPixel(xpos + int(b.pos.x), ypos + int(b.pos.y), b.color) |
||||||
|
|
||||||
|
|
||||||
|
class TtrsGame(): |
||||||
|
def __init__(self, playground): |
||||||
|
self.playground = playground |
||||||
|
self.running = False |
||||||
|
self.next_move = 0 |
||||||
|
self.rotate = False |
||||||
|
self.drop = False |
||||||
|
self.tick_callbacks = [] |
||||||
|
|
||||||
|
def add_tick_callback(self, cb): |
||||||
|
self.tick_callbacks.append(cb) |
||||||
|
|
||||||
|
def run(self): |
||||||
|
self.running = True |
||||||
|
spawnpos = Point(self.playground.width // 2, 0) |
||||||
|
mino = None |
||||||
|
TICK_TIME = 0.1 |
||||||
|
FALL_INTERVAL = 5 |
||||||
|
MOVE_INTERVAL = 1 |
||||||
|
ticks = 0 |
||||||
|
lastfall = 0 |
||||||
|
lastmove = 0 |
||||||
|
while self.running: |
||||||
|
for cb in self.tick_callbacks: |
||||||
|
cb() |
||||||
|
#time.sleep(TICK_TIME) |
||||||
|
ticks += 1 |
||||||
|
|
||||||
|
x = input() |
||||||
|
if x == 'a': |
||||||
|
self.next_move = -1 |
||||||
|
elif x == 'd': |
||||||
|
self.next_move = 1 |
||||||
|
elif x == 'w': |
||||||
|
self.rotate = True |
||||||
|
elif x == 's': |
||||||
|
self.drop = True |
||||||
|
else: |
||||||
|
self.drop = False |
||||||
|
self.rotate = False |
||||||
|
self.next_move = 0 |
||||||
|
|
||||||
|
|
||||||
|
if mino is None: |
||||||
|
newminocls = random.choice(Tetrimino.__subclasses__()) |
||||||
|
mino = newminocls(self.playground, spawnpos) |
||||||
|
self.playground.minos = {mino} |
||||||
|
|
||||||
|
for y in range(self.playground.height): |
||||||
|
row = { Point(x, y) for x in range(self.playground.width) } |
||||||
|
if row.issubset(self.playground.block_points): |
||||||
|
for b in list(self.playground.blocks): |
||||||
|
if b.pos.y == y: |
||||||
|
self.playground.blocks.remove(b) |
||||||
|
elif b.pos.y < y: |
||||||
|
self.playground.blocks.remove(b) |
||||||
|
newb = Block(b.pos + Point(0, 1), b.color) |
||||||
|
self.playground.blocks.add(newb) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ticks - lastfall >= FALL_INTERVAL or self.drop: |
||||||
|
lastfall = ticks |
||||||
|
try: |
||||||
|
mino.move(Point(0, 1)) |
||||||
|
except InvalidMoveError: |
||||||
|
self.playground.blocks.update(mino.blocks) |
||||||
|
mino = None |
||||||
|
self.playground.minos = set() |
||||||
|
continue |
||||||
|
|
||||||
|
if ticks - lastmove >= MOVE_INTERVAL and self.next_move != 0: |
||||||
|
lastmove = ticks |
||||||
|
try: |
||||||
|
mino.move(Point(self.next_move, 0)) |
||||||
|
except InvalidMoveError: |
||||||
|
pass |
||||||
|
self.next_move = 0 |
||||||
|
|
||||||
|
if self.rotate: |
||||||
|
self.rotate = False |
||||||
|
try: |
||||||
|
mino.rotate() |
||||||
|
except InvalidMoveError: |
||||||
|
pass |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
w = 22 |
||||||
|
h = 16 |
||||||
|
|
||||||
|
dim = blup.frame.FrameDimension(w, h, 256, 3) |
||||||
|
frame = blup.frame.Frame(dim) |
||||||
|
out = blup.output.getOutput('e3blp') |
||||||
|
|
||||||
|
pg = Playground(10, 16) |
||||||
|
pg.paint(frame, 0, 0) |
||||||
|
out.sendFrame(frame) |
||||||
|
time.sleep(0.5) |
||||||
|
|
||||||
|
def repaint(): |
||||||
|
pg.paint(frame, 0, 0) |
||||||
|
out.sendFrame(frame) |
||||||
|
|
||||||
|
game = TtrsGame(pg) |
||||||
|
game.add_tick_callback(repaint) |
||||||
|
game.run() |
||||||
|
|
||||||
|
#t = TetriL(pg, Point(2, 2)) |
||||||
|
#pg.minos.add(t) |
||||||
|
#pg.paint(frame, 0, 0) |
||||||
|
#out.sendFrame(frame) |
||||||
|
#time.sleep(0.5) |
||||||
|
|
||||||
|
#for i in range(10): |
||||||
|
# t.rotate(ccw=(i>=5)) |
||||||
|
# pg.paint(frame, 0, 0) |
||||||
|
# out.sendFrame(frame) |
||||||
|
# time.sleep(0.1) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,49 @@ |
|||||||
|
|
||||||
|
|
||||||
|
import math |
||||||
|
import xml.etree.ElementTree as ET |
||||||
|
|
||||||
|
def writeBml(anim, filename): |
||||||
|
root = ET.Element('blm') |
||||||
|
root.attrib['width'] = str(anim.dimension.width) |
||||||
|
root.attrib['height'] = str(anim.dimension.height) |
||||||
|
bits = int(math.ceil(math.log(anim.dimension.depth, 2))) |
||||||
|
root.attrib['bits'] = str(bits) |
||||||
|
root.attrib['channels'] = str(anim.dimension.channels) |
||||||
|
|
||||||
|
header = ET.Element('header') |
||||||
|
for (name, val) in anim.tags: |
||||||
|
elem = ET.Element(name) |
||||||
|
elem.text = str(val) |
||||||
|
header.append(elem) |
||||||
|
root.append(header) |
||||||
|
|
||||||
|
for animFrame in anim: |
||||||
|
frame = ET.Element('frame') |
||||||
|
frame.attrib['duration'] = str(animFrame.delay) |
||||||
|
for y in range(anim.dimension.height): |
||||||
|
rowData = '' |
||||||
|
for x in range(anim.dimension.width): |
||||||
|
p = animFrame.getPixel(x,y) |
||||||
|
if type(p) == tuple or type(p) == list: |
||||||
|
for v in p: |
||||||
|
if bits >= 5: |
||||||
|
rowData += '%02x' % (v) |
||||||
|
else: |
||||||
|
rowData += '%x' % (v) |
||||||
|
else: |
||||||
|
if bits >= 5: |
||||||
|
rowData += '%02x' % (p) |
||||||
|
else: |
||||||
|
rowData += '%x' % (p) |
||||||
|
|
||||||
|
row = ET.Element('row') |
||||||
|
row.text = rowData |
||||||
|
frame.append(row) |
||||||
|
root.append(frame) |
||||||
|
|
||||||
|
f = open(filename, 'w') |
||||||
|
ET.ElementTree(root).write(f) |
||||||
|
f.close() |
||||||
|
|
||||||
|
|
Loading…
Reference in new issue