gyorgyf@5
|
1 #!/usr/bin/env python
|
gyorgyf@5
|
2 # encoding: utf-8
|
gyorgyf@5
|
3 """
|
gyorgyf@5
|
4 visclient.py
|
gyorgyf@5
|
5
|
gyorgyf@5
|
6 Created by George Fazekas on 2012-06-17.
|
gyorgyf@5
|
7 Copyright (c) 2012 . All rights reserved.
|
gyorgyf@5
|
8 """
|
gyorgyf@5
|
9
|
gyorgyf@12
|
10 import sys,os,math,time,copy
|
gyorgyf@5
|
11 import pygame as pg
|
gyorgyf@5
|
12 from pygame.locals import *
|
gyorgyf@31
|
13 from pygame import gfxdraw as gd
|
gyorgyf@5
|
14 import httplib as ht
|
gyorgyf@5
|
15
|
gyorgyf@5
|
16 import gradients
|
gyorgyf@5
|
17 from gradients import genericFxyGradient
|
gyorgyf@5
|
18
|
gyorgyf@27
|
19 from threading import Thread
|
gyorgyf@27
|
20 from random import random
|
gyorgyf@27
|
21
|
gyorgyf@28
|
22 import colorsys as cs
|
gyorgyf@28
|
23
|
gyorgyf@12
|
24 scol = (0,255,0,255)
|
gyorgyf@12
|
25 ecol = (0,0,0,255)
|
gyorgyf@12
|
26
|
gyorgyf@12
|
27 # X,Y=1140,900
|
gyorgyf@27
|
28 # X,Y = 600,400
|
gyorgyf@27
|
29 X,Y = 800,600
|
gyorgyf@27
|
30
|
gyorgyf@28
|
31 # Fullscreen resolution:
|
gyorgyf@28
|
32 # XF,YF = 1280,900
|
gyorgyf@28
|
33 # XF,YF = 1440,900
|
gyorgyf@28
|
34 XF,YF = 1344,900
|
gyorgyf@28
|
35 # display calibrated
|
gyorgyf@28
|
36
|
gyorgyf@28
|
37 # detect display resolution
|
gyorgyf@28
|
38 import subprocess
|
gyorgyf@28
|
39 screenres = subprocess.Popen('xrandr | grep "\*" | cut -d" " -f4',shell=True, stdout=subprocess.PIPE).communicate()[0]
|
gyorgyf@28
|
40 screenres = map(lambda x: int(x.strip()), screenres.split('x'))
|
gyorgyf@28
|
41 XF,YF = screenres
|
gyorgyf@28
|
42 print "Screen resolution: ",XF,YF
|
gyorgyf@28
|
43
|
gyorgyf@27
|
44 NBLOBS = 18
|
gyorgyf@22
|
45 BLOBSIZE = 25
|
gyorgyf@14
|
46 G=110
|
gyorgyf@22
|
47 FADE = 15
|
gyorgyf@30
|
48 DIST = 0.15 # blob equivalence tolerance
|
gyorgyf@27
|
49 FRAMERATE = 60
|
gyorgyf@27
|
50
|
gyorgyf@27
|
51 # Connection:
|
gyorgyf@35
|
52 # IP = "127.0.0.1:8030"
|
gyorgyf@29
|
53 # IP = "192.168.2.158:8030"
|
gyorgyf@35
|
54 IP = "138.37.95.215"
|
gyorgyf@27
|
55 HTTP_TIMEOUT = 3
|
gyorgyf@27
|
56 SERVER_UPDATE_INTERVAL = 0.8
|
gyorgyf@27
|
57
|
gyorgyf@29
|
58
|
gyorgyf@27
|
59 class Indicator(object):
|
gyorgyf@27
|
60
|
gyorgyf@27
|
61 off_color = pg.Color(110,0,0)
|
gyorgyf@27
|
62 on_color = pg.Color(0,120,0)
|
gyorgyf@27
|
63
|
gyorgyf@27
|
64 def __init__(self,bg,pos):
|
gyorgyf@27
|
65 self.visible = True
|
gyorgyf@27
|
66 self.ison = True
|
gyorgyf@27
|
67 self.x,self.y = pos
|
gyorgyf@27
|
68 self.xs = int(self.x * X)
|
gyorgyf@27
|
69 self.ys = int(Y - (self.y * Y))
|
gyorgyf@27
|
70 self.c = self.off_color
|
gyorgyf@27
|
71 self.size = 6
|
gyorgyf@27
|
72 self.bg = bg
|
gyorgyf@27
|
73
|
gyorgyf@27
|
74 def reinit(self,bg):
|
gyorgyf@27
|
75 self.bg = bg
|
gyorgyf@27
|
76 self.xs = int(self.x * X)
|
gyorgyf@27
|
77 self.ys = int(Y - (self.y * Y))
|
gyorgyf@27
|
78
|
gyorgyf@27
|
79 def draw(self):
|
gyorgyf@27
|
80 if self.visible :
|
gyorgyf@31
|
81 # pg.draw.circle(self.bg, self.c, (self.xs,self.ys),self.size,0)
|
gyorgyf@31
|
82 # gd.aacircle(self.bg, self.xs, self.ys, self.size+1, self.c)
|
gyorgyf@31
|
83 gd.filled_circle(self.bg, self.xs, self.ys, self.size, self.c)
|
gyorgyf@31
|
84 gd.aacircle(self.bg, self.xs, self.ys, self.size, self.c)
|
gyorgyf@31
|
85
|
gyorgyf@27
|
86
|
gyorgyf@27
|
87 def toggle(self):
|
gyorgyf@27
|
88 if self.ison == True :
|
gyorgyf@27
|
89 self.off()
|
gyorgyf@27
|
90 else :
|
gyorgyf@27
|
91 self.on()
|
gyorgyf@27
|
92 return self
|
gyorgyf@27
|
93
|
gyorgyf@27
|
94 def on(self):
|
gyorgyf@27
|
95 self.c = self.on_color
|
gyorgyf@27
|
96 self.ison = True
|
gyorgyf@27
|
97 return self
|
gyorgyf@27
|
98
|
gyorgyf@27
|
99 def off(self):
|
gyorgyf@27
|
100 self.c = self.off_color
|
gyorgyf@27
|
101 self.ison = False
|
gyorgyf@27
|
102 return self
|
gyorgyf@27
|
103
|
gyorgyf@12
|
104
|
gyorgyf@12
|
105 class Blob(object):
|
gyorgyf@12
|
106
|
gyorgyf@22
|
107 def __init__(self,bg,x,y,color=(255,255,255),mood=None,fade=FADE):
|
gyorgyf@12
|
108 self.x = x
|
gyorgyf@12
|
109 self.y = y
|
gyorgyf@12
|
110 self.xs = x * X
|
gyorgyf@12
|
111 self.ys = Y - (y * Y)
|
gyorgyf@12
|
112 self.bg = bg
|
gyorgyf@14
|
113 self.size = BLOBSIZE
|
gyorgyf@12
|
114 self.time = time.time()
|
gyorgyf@12
|
115 self.alpha = 255
|
gyorgyf@12
|
116 self.c = color
|
gyorgyf@14
|
117 self.count = 1
|
gyorgyf@12
|
118 self.visible = True
|
gyorgyf@22
|
119 self.FADE = fade
|
gyorgyf@12
|
120 if mood and mood.color :
|
gyorgyf@12
|
121 self.c = mood.color
|
gyorgyf@12
|
122
|
gyorgyf@12
|
123 def __cmp__(self,other):
|
gyorgyf@12
|
124 d = math.sqrt( math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2) )
|
gyorgyf@27
|
125 if d < DIST :
|
gyorgyf@12
|
126 return 0
|
gyorgyf@12
|
127 else :
|
gyorgyf@12
|
128 return -1
|
gyorgyf@12
|
129
|
gyorgyf@12
|
130 def draw(self):
|
gyorgyf@27
|
131 if not self.visible : return
|
gyorgyf@14
|
132 d=int(self.size)
|
gyorgyf@14
|
133 self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,self.alpha)), (self.xs-d,self.ys-d))
|
gyorgyf@22
|
134 self.alpha = 255 - int(self.age()*self.FADE)
|
gyorgyf@12
|
135 if self.alpha < 5 :
|
gyorgyf@12
|
136 self.alpha = 1
|
gyorgyf@12
|
137 self.visible = False
|
gyorgyf@12
|
138
|
gyorgyf@12
|
139 def age(self):
|
gyorgyf@12
|
140 return time.time() - self.time
|
gyorgyf@12
|
141
|
gyorgyf@12
|
142 def increment(self,count):
|
gyorgyf@21
|
143 self.time = time.time()
|
gyorgyf@14
|
144 self.count = count
|
gyorgyf@28
|
145 # self.size = int(BLOBSIZE * int(self.count/1.5))
|
gyorgyf@28
|
146 self.to = int(BLOBSIZE * int(self.count/1.5))
|
gyorgyf@28
|
147 self.start_animate()
|
gyorgyf@12
|
148
|
gyorgyf@12
|
149 def get_distance(self,x,y):
|
gyorgyf@12
|
150 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) )
|
gyorgyf@22
|
151
|
gyorgyf@22
|
152 def fade(self,fade):
|
gyorgyf@22
|
153 if not fade : self.alpha = 255
|
gyorgyf@22
|
154 self.FADE = fade
|
gyorgyf@22
|
155
|
gyorgyf@22
|
156 def reset_time(self):
|
gyorgyf@22
|
157 self.time = time.time()
|
gyorgyf@28
|
158
|
gyorgyf@28
|
159 def start_animate(self):
|
gyorgyf@28
|
160 self.thread = Thread(target = self.animate)
|
gyorgyf@28
|
161 self.thread.daemon = True
|
gyorgyf@28
|
162 self.thread.start()
|
gyorgyf@28
|
163
|
gyorgyf@28
|
164 def animate(self):
|
gyorgyf@28
|
165 '''Animate the way bubbles are grown.'''
|
gyorgyf@28
|
166 while self.size < self.to :
|
gyorgyf@28
|
167 self.size += 1
|
gyorgyf@28
|
168 time_inc = 20.0 / (pow(1.2, self.to-self.size) * 200.0)
|
gyorgyf@28
|
169 time.sleep(0.02+time_inc)
|
gyorgyf@12
|
170
|
gyorgyf@12
|
171
|
gyorgyf@12
|
172
|
gyorgyf@12
|
173
|
gyorgyf@12
|
174 class Mood():
|
gyorgyf@12
|
175 def __init__(self,word,x,y):
|
gyorgyf@12
|
176 self.word = word
|
gyorgyf@12
|
177 self.x = float(x)
|
gyorgyf@12
|
178 self.y = float(y)
|
gyorgyf@12
|
179 self.color = []
|
gyorgyf@12
|
180
|
gyorgyf@12
|
181 def get_distance(self,x,y):
|
gyorgyf@12
|
182 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) )
|
gyorgyf@12
|
183
|
gyorgyf@12
|
184
|
gyorgyf@12
|
185
|
gyorgyf@12
|
186 class VisualClient(object):
|
gyorgyf@27
|
187 '''Main visualisation client.'''
|
gyorgyf@12
|
188
|
gyorgyf@12
|
189 def __init__(self):
|
gyorgyf@12
|
190 # self.conn = ht.HTTPConnection("192.168.2.184:8030")
|
gyorgyf@27
|
191 # self.conn = ht.HTTPConnection("138.37.95.215")
|
gyorgyf@29
|
192 self.s_age = 10
|
gyorgyf@29
|
193 self.s_dist = DIST
|
gyorgyf@29
|
194 self.s_ninp = 18
|
gyorgyf@12
|
195
|
gyorgyf@12
|
196 pg.init()
|
gyorgyf@12
|
197
|
gyorgyf@12
|
198 # fontObj = pg.font.Font("freesansbold.ttf",18)
|
gyorgyf@12
|
199 white = ( 255, 255, 255)
|
gyorgyf@12
|
200 black = ( 0,0,0)
|
gyorgyf@12
|
201
|
gyorgyf@12
|
202 self.fpsClock = pg.time.Clock()
|
gyorgyf@12
|
203 self.screen = pg.display.set_mode((X, Y))
|
gyorgyf@12
|
204 pg.display.set_caption('Mood Conductor')
|
gyorgyf@12
|
205 self.bg = pg.Surface(self.screen.get_size())
|
gyorgyf@12
|
206 self.bg = self.bg.convert()
|
gyorgyf@12
|
207 self.bg.fill((0,0,0))
|
gyorgyf@27
|
208 pg.display.set_gamma(100.0)
|
gyorgyf@12
|
209
|
gyorgyf@12
|
210
|
gyorgyf@12
|
211 self.scol = (0,255,0,255)
|
gyorgyf@12
|
212 self.ecol = (0,0,0,255)
|
gyorgyf@12
|
213 coordstxt = "test"
|
gyorgyf@12
|
214
|
gyorgyf@12
|
215 self.blobs = []
|
gyorgyf@12
|
216 self.moods = []
|
gyorgyf@12
|
217 self.read_mood_data()
|
gyorgyf@12
|
218
|
gyorgyf@22
|
219 self.FADE = FADE
|
gyorgyf@22
|
220
|
gyorgyf@27
|
221 self.indicators = {
|
gyorgyf@27
|
222 "conn":Indicator(self.bg,(0.98,0.02)),
|
gyorgyf@27
|
223 "update":Indicator(self.bg,(0.96,0.02)),
|
gyorgyf@27
|
224 "data":Indicator(self.bg,(0.94,0.02)),
|
gyorgyf@27
|
225 "receive":Indicator(self.bg,(0.92,0.02))}
|
gyorgyf@27
|
226
|
gyorgyf@27
|
227 self.thread = None
|
gyorgyf@27
|
228 self.running = False
|
gyorgyf@27
|
229 self.fullscreen = False
|
gyorgyf@27
|
230 self.init_reconnect = False
|
gyorgyf@30
|
231
|
gyorgyf@12
|
232 pass
|
gyorgyf@12
|
233
|
gyorgyf@27
|
234
|
gyorgyf@12
|
235 def read_mood_data(self):
|
gyorgyf@27
|
236 '''Read the mood position and color information form csv file.'''
|
gyorgyf@12
|
237 with open('moods.csv') as mf:
|
gyorgyf@12
|
238 data = mf.readlines()[1:]
|
gyorgyf@12
|
239 for line in data :
|
gyorgyf@12
|
240 l = line.split(',')
|
gyorgyf@14
|
241 mood = Mood(l[0],l[1],l[2])
|
gyorgyf@12
|
242 self.moods.append(mood)
|
gyorgyf@22
|
243 with open('colors.txt') as ff:
|
gyorgyf@22
|
244 data = ff.readlines()[1:]
|
gyorgyf@22
|
245 data = map(lambda x: x.split(','),data)
|
gyorgyf@12
|
246 for mood in self.moods :
|
gyorgyf@22
|
247 d = cd = sys.float_info.max
|
gyorgyf@12
|
248 for colors in data :
|
gyorgyf@22
|
249 d = mood.get_distance(float(colors[0]),float(colors[1]))
|
gyorgyf@22
|
250 if d < cd :
|
gyorgyf@22
|
251 cd = d
|
gyorgyf@28
|
252 # mood.color = tuple(map(lambda x: int(pow(math.atan((float(x)/7.0)),12.5)),(colors[2],colors[3],colors[4])))
|
gyorgyf@28
|
253 mood.color = self.set_color(tuple(map(lambda x: int(x),(colors[2],colors[3],colors[4]))))
|
gyorgyf@27
|
254 return True
|
gyorgyf@27
|
255
|
gyorgyf@28
|
256 def set_color(self,color):
|
gyorgyf@28
|
257 '''Move to HLS colour space and manipulate saturation there.'''
|
gyorgyf@28
|
258 # TODO: ideally, we need a non-linear compressor of the lightness and saturation values
|
gyorgyf@28
|
259 r,g,b = map(lambda x: (1.0*x/255.0), color)
|
gyorgyf@28
|
260 h,l,s = cs.rgb_to_hls(r,g,b)
|
gyorgyf@28
|
261 s = 1.0 #1.0 - (1.0 / pow(50.0,s))
|
gyorgyf@28
|
262 l = 1.0 - (1.0 / pow(20.0,l)) #0.6
|
gyorgyf@28
|
263 r,g,b = map(lambda x: int(x*255), cs.hls_to_rgb(h,l,s))
|
gyorgyf@28
|
264 return r,g,b
|
gyorgyf@22
|
265
|
gyorgyf@27
|
266 def start_update_thread(self):
|
gyorgyf@27
|
267 '''Start the thread that reads data from the server.'''
|
gyorgyf@27
|
268 self.thread = Thread(target = self.update_thread)
|
gyorgyf@27
|
269 self.thread.daemon = True
|
gyorgyf@35
|
270 self.running = True
|
gyorgyf@27
|
271 self.thread.start()
|
gyorgyf@32
|
272 print "OK. Update thread started."
|
gyorgyf@12
|
273
|
gyorgyf@27
|
274 def stop_update_thread(self):
|
gyorgyf@27
|
275 '''Stop the thread and allow some time fot the connections to close.'''
|
gyorgyf@27
|
276 self.running = False
|
gyorgyf@27
|
277 try :
|
gyorgyf@27
|
278 self.thread.join(2)
|
gyorgyf@27
|
279 except :
|
gyorgyf@27
|
280 print "No update thread to join."
|
gyorgyf@27
|
281
|
gyorgyf@27
|
282 def update_thread(self):
|
gyorgyf@27
|
283 '''The server update thread'''
|
gyorgyf@35
|
284 print "Thread reporting..."
|
gyorgyf@27
|
285 while self.running :
|
gyorgyf@32
|
286 # self.update()
|
gyorgyf@27
|
287 try :
|
gyorgyf@27
|
288 self.update()
|
gyorgyf@27
|
289 # self.indicators["update"].visible = True
|
gyorgyf@27
|
290 except Exception, e:
|
gyorgyf@27
|
291 if str(e).strip() : print "Exception: ", str(e), type(e), len(str(e).strip())
|
gyorgyf@27
|
292 self.indicators["conn"].off()
|
gyorgyf@27
|
293 # self.indicators["update"].visible = False
|
gyorgyf@27
|
294 time.sleep(SERVER_UPDATE_INTERVAL)
|
gyorgyf@27
|
295
|
gyorgyf@12
|
296
|
gyorgyf@12
|
297 def update(self):
|
gyorgyf@27
|
298 '''Update the blob list from the server. This should be in a thread.'''
|
gyorgyf@27
|
299
|
gyorgyf@27
|
300 # indicate connection health by toggling an indictor
|
gyorgyf@27
|
301 self.indicators["update"].toggle()
|
gyorgyf@12
|
302
|
gyorgyf@12
|
303 # delete invisibles
|
gyorgyf@12
|
304 for blob in self.blobs :
|
gyorgyf@12
|
305 if not blob.visible :
|
gyorgyf@12
|
306 self.blobs.remove(blob)
|
gyorgyf@12
|
307
|
gyorgyf@12
|
308 # get new coordinates from the server
|
gyorgyf@12
|
309 self.conn.putrequest("GET","/moodconductor/result", skip_host=True)
|
gyorgyf@12
|
310 self.conn.putheader("Host", "www.isophonics.net")
|
gyorgyf@12
|
311 self.conn.endheaders()
|
gyorgyf@12
|
312 res = self.conn.getresponse()
|
gyorgyf@12
|
313 data = res.read()
|
gyorgyf@27
|
314 data = eval(data)
|
gyorgyf@12
|
315 if not data :
|
gyorgyf@12
|
316 self.conn.close()
|
gyorgyf@27
|
317 self.indicators["data"].toggle()
|
gyorgyf@12
|
318 return False
|
gyorgyf@12
|
319 for d in data :
|
gyorgyf@14
|
320 # coordstxt = "x:%s y:%s c:%s" %d
|
gyorgyf@27
|
321 x,y,count = d
|
gyorgyf@27
|
322 self.add_blob(x,y,count)
|
gyorgyf@27
|
323 self.indicators["receive"].toggle()
|
gyorgyf@12
|
324 self.conn.close()
|
gyorgyf@21
|
325 self.blobs = self.blobs[:NBLOBS]
|
gyorgyf@12
|
326 return True
|
gyorgyf@27
|
327
|
gyorgyf@27
|
328
|
gyorgyf@27
|
329 def add_blob(self,x,y,count=1):
|
gyorgyf@27
|
330 '''Insert a blob to the list of blobs'''
|
gyorgyf@27
|
331 # find mood correxponding to x,y
|
gyorgyf@27
|
332 cmood = None
|
gyorgyf@27
|
333 d = cd = sys.float_info.max
|
gyorgyf@27
|
334 for mood in self.moods :
|
gyorgyf@27
|
335 d = mood.get_distance(x,y)
|
gyorgyf@27
|
336 if d < cd :
|
gyorgyf@27
|
337 cd = d
|
gyorgyf@27
|
338 cmood = mood
|
gyorgyf@27
|
339 # create new blob or increase click count on existing one
|
gyorgyf@27
|
340 new = Blob(self.bg,x,y,mood=cmood,fade=self.FADE)
|
gyorgyf@27
|
341 if not new in self.blobs :
|
gyorgyf@27
|
342 self.blobs.insert(0,new)
|
gyorgyf@27
|
343 elif count > self.blobs[self.blobs.index(new)].count:
|
gyorgyf@27
|
344 self.blobs[self.blobs.index(new)].increment(count)
|
gyorgyf@27
|
345 pass
|
gyorgyf@12
|
346
|
gyorgyf@12
|
347
|
gyorgyf@12
|
348 def draw(self):
|
gyorgyf@27
|
349 self.bg.fill((0,0,0))
|
gyorgyf@12
|
350 # self.bg.blit(gradients.radial(19, self.scol, self.ecol), (rect_x,rect_y))
|
gyorgyf@12
|
351 l = copy.copy(self.blobs)
|
gyorgyf@12
|
352 l.reverse()
|
gyorgyf@12
|
353 for blob in l :
|
gyorgyf@12
|
354 blob.draw()
|
gyorgyf@12
|
355
|
gyorgyf@14
|
356 # axis
|
gyorgyf@14
|
357 pg.draw.line(self.bg, (G,G,G), (int(X/2.0),0),(int(X/2.0),Y), 1)
|
gyorgyf@14
|
358 pg.draw.line(self.bg, (G,G,G), (0,int(Y/2.0)),(X,int(Y/2.0)), 1)
|
gyorgyf@14
|
359
|
gyorgyf@27
|
360 # indicators
|
gyorgyf@27
|
361 for i in self.indicators.itervalues() :
|
gyorgyf@27
|
362 i.draw()
|
gyorgyf@27
|
363
|
gyorgyf@27
|
364 def read_keys(self):
|
gyorgyf@27
|
365 '''Read keys'''
|
gyorgyf@27
|
366 for event in pg.event.get() :
|
gyorgyf@27
|
367 # Quit (event)
|
gyorgyf@27
|
368 if event.type == QUIT:
|
gyorgyf@27
|
369 self.quit()
|
gyorgyf@27
|
370 elif event.type == KEYDOWN :
|
gyorgyf@27
|
371 # Post Quit: Esc, q
|
gyorgyf@27
|
372 if event.key == K_ESCAPE or event.key == K_q :
|
gyorgyf@27
|
373 pg.event.post(pg.event.Event(QUIT))
|
gyorgyf@27
|
374 # Reset: Space
|
gyorgyf@27
|
375 elif event.key == K_SPACE :
|
gyorgyf@27
|
376 self.blobs = []
|
gyorgyf@27
|
377 # Random : r
|
gyorgyf@27
|
378 elif event.key == K_r :
|
gyorgyf@27
|
379 self.add_blob(random(),random(),count=5)
|
gyorgyf@27
|
380 # Connection : c
|
gyorgyf@27
|
381 elif event.key == K_c :
|
gyorgyf@27
|
382 self.init_reconnect = True
|
gyorgyf@27
|
383 self.indicators["conn"].off()
|
gyorgyf@27
|
384 # Fullscreen: f
|
gyorgyf@27
|
385 elif event.key == K_f :
|
gyorgyf@27
|
386 # pg.display.toggle_fullscreen()
|
gyorgyf@27
|
387 self.toggle_screen_mode()
|
gyorgyf@27
|
388 # Toggle fade: s
|
gyorgyf@27
|
389 elif event.key == K_s :
|
gyorgyf@27
|
390 if self.FADE :
|
gyorgyf@27
|
391 print "fade off"
|
gyorgyf@27
|
392 self.indicators["conn"].off()
|
gyorgyf@27
|
393 self.FADE = 0
|
gyorgyf@27
|
394 for blob in self.blobs :
|
gyorgyf@27
|
395 blob.fade(0)
|
gyorgyf@27
|
396 else:
|
gyorgyf@27
|
397 print "fade on"
|
gyorgyf@27
|
398 self.indicators["conn"].on()
|
gyorgyf@27
|
399 self.FADE = 15
|
gyorgyf@27
|
400 for blob in self.blobs :
|
gyorgyf@27
|
401 blob.fade(15)
|
gyorgyf@27
|
402 blob.reset_time()
|
gyorgyf@29
|
403 # inc age
|
gyorgyf@29
|
404 elif event.key == K_1 :
|
gyorgyf@29
|
405 self.s_age += 1
|
gyorgyf@29
|
406 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@29
|
407 # dec age
|
gyorgyf@29
|
408 elif event.key == K_2 :
|
gyorgyf@29
|
409 self.s_age -= 1
|
gyorgyf@29
|
410 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@29
|
411 # inc dist
|
gyorgyf@29
|
412 elif event.key == K_3 :
|
gyorgyf@29
|
413 self.s_dist += 0.025
|
gyorgyf@29
|
414 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@29
|
415 # dec dist
|
gyorgyf@29
|
416 elif event.key == K_4 :
|
gyorgyf@29
|
417 self.s_dist -= 0.025
|
gyorgyf@29
|
418 if self.s_dist < 0.025 : self.s_dist = 0.025
|
gyorgyf@29
|
419 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@29
|
420 # inc ninp
|
gyorgyf@29
|
421 elif event.key == K_5 :
|
gyorgyf@29
|
422 self.s_ninp += 1
|
gyorgyf@29
|
423 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@29
|
424 # dec ninp
|
gyorgyf@29
|
425 elif event.key == K_6 :
|
gyorgyf@29
|
426 self.s_ninp -= 1
|
gyorgyf@29
|
427 if self.s_ninp < 2 : self.s_ninp = 2
|
gyorgyf@29
|
428 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@29
|
429
|
gyorgyf@29
|
430 pass
|
gyorgyf@27
|
431 pass
|
gyorgyf@27
|
432
|
gyorgyf@27
|
433 def toggle_screen_mode(self):
|
gyorgyf@27
|
434 '''Go back and forth between full screen mode.'''
|
gyorgyf@27
|
435 if self.fullscreen == False:
|
gyorgyf@27
|
436 globals()['_X'] = globals()['X']
|
gyorgyf@27
|
437 globals()['_Y'] = globals()['Y']
|
gyorgyf@28
|
438 globals()['X'] = XF
|
gyorgyf@28
|
439 globals()['Y'] = YF
|
gyorgyf@28
|
440 self.screen = pg.display.set_mode((X, Y))
|
gyorgyf@28
|
441 # self.screen = pg.display.set_mode((0,0),pg.FULLSCREEN)
|
gyorgyf@27
|
442 self.fullscreen = True
|
gyorgyf@27
|
443 self.bg = pg.Surface(self.screen.get_size())
|
gyorgyf@27
|
444 self.bg = self.bg.convert()
|
gyorgyf@27
|
445 self.bg.fill((0,0,0))
|
gyorgyf@27
|
446 for i in self.indicators.itervalues() :
|
gyorgyf@27
|
447 i.reinit(self.bg)
|
gyorgyf@27
|
448 i.draw()
|
gyorgyf@27
|
449 else :
|
gyorgyf@27
|
450 globals()['X'] = globals()['_X']
|
gyorgyf@27
|
451 globals()['Y'] = globals()['_Y']
|
gyorgyf@27
|
452 self.screen = pg.display.set_mode((X, Y))
|
gyorgyf@27
|
453 self.fullscreen = False
|
gyorgyf@27
|
454 self.bg = pg.Surface(self.screen.get_size())
|
gyorgyf@27
|
455 self.bg = self.bg.convert()
|
gyorgyf@27
|
456 self.bg.fill((0,0,0))
|
gyorgyf@27
|
457 for i in self.indicators.itervalues() :
|
gyorgyf@27
|
458 i.reinit(self.bg)
|
gyorgyf@27
|
459 i.draw()
|
gyorgyf@27
|
460 pg.display.toggle_fullscreen()
|
gyorgyf@27
|
461
|
gyorgyf@14
|
462
|
gyorgyf@12
|
463
|
gyorgyf@12
|
464 def run(self):
|
gyorgyf@12
|
465
|
gyorgyf@27
|
466 # setup connection
|
gyorgyf@27
|
467 self.connect()
|
gyorgyf@27
|
468
|
gyorgyf@12
|
469 # main loop
|
gyorgyf@12
|
470 while True :
|
gyorgyf@12
|
471 # pg.draw.circle(screen, pg.Color(255,0,0), (300,50),20,0)
|
gyorgyf@12
|
472 # screen.blit(gradients.radial(99, scol, ecol), (401, 1))
|
gyorgyf@12
|
473
|
gyorgyf@27
|
474 self.read_keys()
|
gyorgyf@12
|
475
|
gyorgyf@12
|
476 # Draw
|
gyorgyf@12
|
477 self.draw()
|
gyorgyf@12
|
478
|
gyorgyf@12
|
479 # update display
|
gyorgyf@12
|
480 self.screen.blit(self.bg, (0, 0))
|
gyorgyf@12
|
481 pg.display.flip()
|
gyorgyf@27
|
482 self.fpsClock.tick(FRAMERATE)
|
gyorgyf@27
|
483
|
gyorgyf@27
|
484 if self.init_reconnect:
|
gyorgyf@27
|
485 self.reconnect()
|
gyorgyf@27
|
486
|
gyorgyf@27
|
487 return True
|
gyorgyf@28
|
488
|
gyorgyf@28
|
489 def configure_server(self):
|
gyorgyf@28
|
490 '''Send the server some configuration data.'''
|
gyorgyf@29
|
491 # age = 10.0
|
gyorgyf@29
|
492 # dist = DIST
|
gyorgyf@29
|
493 # ninp = 18
|
gyorgyf@29
|
494 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@29
|
495
|
gyorgyf@27
|
496
|
gyorgyf@29
|
497 def update_server_config(self,age,dist,ninp,retry = 3):
|
gyorgyf@29
|
498 '''Send the server some configuration data.'''
|
gyorgyf@29
|
499 try :
|
gyorgyf@32
|
500 print "Sending configuration data."
|
gyorgyf@29
|
501 self.conn.putrequest("GET","/moodconductor/config?age=%(age)s&dist=%(dist)s&ninp=%(ninp)s" %locals(), skip_host=True)
|
gyorgyf@29
|
502 self.conn.putheader("Host", "www.isophonics.net")
|
gyorgyf@29
|
503 self.conn.endheaders()
|
gyorgyf@29
|
504 res = self.conn.getresponse()
|
gyorgyf@32
|
505 res.read()
|
gyorgyf@29
|
506 if not res.status == 200 :
|
gyorgyf@29
|
507 print "Server response:", res.status, res.reason
|
gyorgyf@29
|
508 self.indicators["conn"].off()
|
gyorgyf@29
|
509 time.sleep(0.5)
|
gyorgyf@29
|
510 self.conn.putrequest("GET","/moodconductor/getconf", skip_host=True)
|
gyorgyf@29
|
511 self.conn.putheader("Host", "www.isophonics.net")
|
gyorgyf@29
|
512 self.conn.endheaders()
|
gyorgyf@29
|
513 res = self.conn.getresponse()
|
gyorgyf@29
|
514 if not res.status == 200 :
|
gyorgyf@29
|
515 print "Server response:", res.status, res.reason
|
gyorgyf@32
|
516 self.indicators["conn"].off()
|
gyorgyf@29
|
517 print "Server configuration:", res.read()
|
gyorgyf@29
|
518 except:
|
gyorgyf@32
|
519 print "Failed to send configuration data."
|
gyorgyf@29
|
520 time.sleep(2)
|
gyorgyf@29
|
521 retry -= 1
|
gyorgyf@29
|
522 self.update_server_config(age,dist,ninp,retry)
|
gyorgyf@29
|
523
|
gyorgyf@27
|
524
|
gyorgyf@27
|
525 def connect(self,retry = 5):
|
gyorgyf@27
|
526 '''Connect to the server and test connection.'''
|
gyorgyf@27
|
527 if not retry :
|
gyorgyf@27
|
528 print "Server unreachable"
|
gyorgyf@27
|
529 pg.quit()
|
gyorgyf@27
|
530 raise SystemExit
|
gyorgyf@27
|
531 if retry < 5 :
|
gyorgyf@27
|
532 time.sleep(3)
|
gyorgyf@27
|
533 try :
|
gyorgyf@32
|
534 print "connecting to server..."
|
gyorgyf@27
|
535 self.conn = ht.HTTPConnection(IP,timeout=HTTP_TIMEOUT)
|
gyorgyf@27
|
536 self.indicators["conn"].on()
|
gyorgyf@27
|
537 except :
|
gyorgyf@27
|
538 self.indicators["conn"].off()
|
gyorgyf@27
|
539 self.connect(retry = retry-1)
|
gyorgyf@32
|
540 print "connection failed."
|
gyorgyf@27
|
541
|
gyorgyf@27
|
542 try:
|
gyorgyf@32
|
543 print "Testing connection."
|
gyorgyf@33
|
544 # self.conn.putrequest("GET","/moodconductor/index.html", skip_host=True)
|
gyorgyf@33
|
545 self.conn.putrequest("GET","/moodconductor/test", skip_host=True)
|
gyorgyf@27
|
546 self.conn.putheader("Host", "www.isophonics.net")
|
gyorgyf@27
|
547 self.conn.endheaders()
|
gyorgyf@27
|
548 res = self.conn.getresponse()
|
gyorgyf@33
|
549 print res.read()
|
gyorgyf@27
|
550 if res.status == 200 :
|
gyorgyf@27
|
551 self.indicators["conn"].on()
|
gyorgyf@27
|
552 else :
|
gyorgyf@27
|
553 print "Server response:", res.status, res.reason
|
gyorgyf@27
|
554 self.indicators["conn"].off()
|
gyorgyf@27
|
555 if not hasattr(self,"noretry") and raw_input("Go offline? ") in ['y',''] :
|
gyorgyf@27
|
556 return False
|
gyorgyf@27
|
557 else :
|
gyorgyf@32
|
558 print "Failed. retrying."
|
gyorgyf@27
|
559 self.noretry = None
|
gyorgyf@27
|
560 self.connect(retry = retry-1)
|
gyorgyf@27
|
561 except :
|
gyorgyf@27
|
562 print "Exception while testing connection."
|
gyorgyf@27
|
563 self.indicators["conn"].off()
|
gyorgyf@27
|
564 # comment out in offline mode
|
gyorgyf@27
|
565 if not hasattr(self,"noretry") and raw_input("Go offline? ") in ['y',''] :
|
gyorgyf@27
|
566 return False
|
gyorgyf@27
|
567 else :
|
gyorgyf@27
|
568 self.noretry = None
|
gyorgyf@27
|
569 self.connect(retry = retry-1)
|
gyorgyf@28
|
570 self.configure_server()
|
gyorgyf@32
|
571 print "OK. Starting update thread..."
|
gyorgyf@27
|
572 self.start_update_thread()
|
gyorgyf@27
|
573 return True
|
gyorgyf@27
|
574
|
gyorgyf@27
|
575
|
gyorgyf@27
|
576
|
gyorgyf@27
|
577 def reconnect(self):
|
gyorgyf@27
|
578 '''Called when c is pressed.'''
|
gyorgyf@27
|
579 self.init_reconnect = False
|
gyorgyf@27
|
580
|
gyorgyf@27
|
581 self.stop_update_thread()
|
gyorgyf@27
|
582 time.sleep(1)
|
gyorgyf@27
|
583 try :
|
gyorgyf@27
|
584 self.conn.close()
|
gyorgyf@27
|
585 except :
|
gyorgyf@27
|
586 self.indicators["conn"].off()
|
gyorgyf@27
|
587 try :
|
gyorgyf@27
|
588 self.conn = ht.HTTPConnection(IP,timeout=HTTP_TIMEOUT)
|
gyorgyf@27
|
589 self.conn.connect()
|
gyorgyf@27
|
590 self.indicators["conn"].on()
|
gyorgyf@27
|
591 print "Reconnected."
|
gyorgyf@27
|
592 except :
|
gyorgyf@27
|
593 self.indicators["conn"].off()
|
gyorgyf@27
|
594 print "Error while reconnecting."
|
gyorgyf@27
|
595 self.start_update_thread()
|
gyorgyf@27
|
596
|
gyorgyf@27
|
597
|
gyorgyf@27
|
598 def quit(self):
|
gyorgyf@27
|
599 print "Quitting.."
|
gyorgyf@27
|
600 self.indicators["conn"].off()
|
gyorgyf@27
|
601 self.stop_update_thread()
|
gyorgyf@27
|
602 self.conn.close()
|
gyorgyf@27
|
603 pg.quit()
|
gyorgyf@27
|
604 sys.exit()
|
gyorgyf@5
|
605
|
gyorgyf@5
|
606
|
gyorgyf@5
|
607 def main():
|
gyorgyf@5
|
608
|
gyorgyf@12
|
609 v = VisualClient()
|
gyorgyf@12
|
610 v.run()
|
gyorgyf@5
|
611
|
gyorgyf@5
|
612 if __name__ == '__main__':
|
gyorgyf@5
|
613 pass
|
gyorgyf@5
|
614 main()
|
gyorgyf@5
|
615
|