From b8f5b59be0d901ffd6a3a390645c6ec69903ec8c Mon Sep 17 00:00:00 2001 From: Marcel Hellkamp Date: Thu, 10 May 2012 23:44:29 +0200 Subject: [PATCH] Added text/font support (ascii only for now). Added canvas.clear() (press 'c') command. Some other improvements. --- font.png | Bin 0 -> 3667 bytes pixelflut.py | 54 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 font.png diff --git a/font.png b/font.png new file mode 100644 index 0000000000000000000000000000000000000000..fb7686ea62f82c10514eec305e751821b305bf29 GIT binary patch literal 3667 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 literal 0 HcmV?d00001 diff --git a/pixelflut.py b/pixelflut.py index eafde29..6b267b4 100755 --- a/pixelflut.py +++ b/pixelflut.py @@ -1,5 +1,7 @@ #coding: utf8 +__version__ = '0.4' + import time from gevent import spawn, sleep as gsleep from gevent.server import StreamServer @@ -9,6 +11,8 @@ from collections import deque class Client(object): + px_per_tick = 10 + def __init__(self, canvas, socket, address): self.canvas = canvas self.socket = socket @@ -16,8 +20,9 @@ class Client(object): self.connect_ts = time.time() # This buffer discards all but the newest 1024 messages self.sendbuffer = deque([], 1024) + # And this is used to limit clients to X messages per tick + # We start at 0 (instead of x) to add a reconnect-penalty. self.limit = Semaphore(0) - self.counter = 0 print 'CONNECT', address def send(self, line): @@ -25,7 +30,6 @@ class Client(object): def disconnect(self): print 'DISCONNECT', self.address - print self.counter / (time.time() - self.connect_ts) self.socket.close() del self.canvas.clients[self.address] @@ -54,7 +58,6 @@ class Client(object): self.send('SIZE %d %d' % self.canvas.get_size()) def on_PX(self, args): - self.counter += 1 self.limit.acquire() x,y,color = args x,y = int(x), int(y) @@ -72,7 +75,7 @@ class Client(object): self.canvas.set_pixel(x, y, r, g, b, a) def tick(self): - while self.limit.counter <= 10: + while self.limit.counter <= self.px_per_tick: self.limit.release() @@ -86,19 +89,36 @@ import random import array class Canvas(object): - size = 200,300 + size = 640,480 flags = pygame.RESIZABLE#|pygame.FULLSCREEN def __init__(self): pygame.init() pygame.mixer.quit() - pygame.display.set_caption('PIXELSTORM') + pygame.display.set_caption('P1XELFLUT') self.screen = pygame.display.set_mode(self.size, self.flags) self.ticks = 0 self.width = self.screen.get_width() self.height = self.screen.get_height() self.clients = {} + def load_font(self, fname): + self.font_img = pygame.image.load(fname) + self.font_res = int(self.font_img.get_width())/16 + + def putc(self, x, y, c): + if not self.font_img: return + fpos = ord(c) + fx = (fpos%16) * self.font_res + fy = (fpos/16) * self.font_res + self.screen.blit(self.font_img, (x,y), + (fx,fy,self.font_res,self.font_res)) + + def text(self, x, y, text): + for i, line in enumerate(text.splitlines()): + for j, c in enumerate(line): + self.putc(x+j*self.font_res, y+i*self.font_res, c) + def serve(self, host, port): self.server = StreamServer((host, port), self.make_client) self.server.start() @@ -118,6 +138,8 @@ class Canvas(object): self.on_resize(e.size) if e.type == pygame.KEYDOWN and e.unicode == 'q': return + if e.type == pygame.KEYDOWN and e.unicode == 'c': + self.clear() if e.type == pygame.QUIT: return self.ticks += 1 @@ -135,6 +157,9 @@ class Canvas(object): self.width = self.screen.get_width() self.height = self.screen.get_height() + def clear(self): + self.screen.fill((0,0,0)) + def get_size(self): return self.width, self.height @@ -152,10 +177,23 @@ class Canvas(object): b = (b2*(0xff-a)+(b*a)) / 0xff self.screen.set_at((x, y), (r,g,b)) - +def guess_IP(): + import socket + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.connect(("google.com", 80)) + return s.getsockname()[0] + finally: + s.close() + if __name__ == '__main__': + port = 2342 canvas = Canvas() - canvas.serve('', 2342).join() + task = canvas.serve('0.0.0.0', port) + canvas.load_font('./font.png') + canvas.text(5, 5, 'P1XELFLUT! v%s\nConnect to %s:%d' % + (__version__, guess_IP(), port)) + task.join()