diff --git a/README.md b/README.md index 99cb68d..ceef8b9 100644 --- a/README.md +++ b/README.md @@ -11,16 +11,12 @@ A software laser server with GUI for up to 4 lasers live actions. Think creative LJ has 3 main components : -- A tracer per etherdream/laser that take current client point list, correct geometry, recompute in etherdreams coordinates, send it to its controller,... and report etherdream status to the manager. -- A manager that talk to all tracers (which client number point lists to draw, new geometry correction,...), handle the webui functions, OSC commands,... +- A "tracer" per etherdream/laser that take its point list, correct geometry, recompute in etherdreams coordinates, send it to its controller,... and report etherdream status to the manager. +- A "manager" that talk to all tracers (which client number point lists to draw, new geometry correction,...), handle the webui functions, OSC commands,... - Up to ten clients, that simultaneously send one point list per laser. -You write abd run your laser client software in any redis capable programming langage (50+ : https://redis.io/clients). - Needs at least : an etherdream DAC connected to an ILDA laser, RJ 45 IP network (gigabits only !! no wifi, 100 mpbs doesn't work well with several lasers) -The server approach is based on redis. - LJ supports Linux and OS X. Windows is unkown but welcome, if someone want to jump in and care about it. @@ -32,50 +28,13 @@ LJ supports Linux and OS X. Windows is unkown but welcome, if someone want to ju (Doc in progress) - OSC and websocket commands. Very cool : LJ can script or be scripted. -- Web ui : In your browser open webui/index.html. Javascript is needed. +- Web ui : In your browser open webui/index.html. Javascript is needed. By default it connect to localhost. If you want to control a remote server, you need to change the uri line in LJ.js. - Status update every 0.5 seconds : every etherdream DAC state, number of buffer points sent,... - "Optimisation" points automatically added, can be changed live for glitch art. Search "resampler" commands. - A compiled version for os x and linux of nannou.org etherdream+laser emulator is included. For more informations, like license see https://github.com/nannou-org/ether-dream -- A 3D anaglyph client example +- Some fancy examples are available : 3D anaglyph, Laser Pong, Laser Wars -# -# Networking -# - - -LJ is network based and this is *critical and flickering reason #1* if not managed properly, especially you have several lasers. - -Our "always working solution", as we regularly move our gear for different venues : - -We use static network configuration. Our Etherdreams controllers have static IPs defined in their SDcard from 192.168.1.1 to 192.168.1.9. Because wifi will always finally sucks for many reasons, our computers (laser server and clients) are *gigabits wired connected* with 192.168.1.10 and after. Don't trust end user gear marketing on wifi, we have a big gigabits switch for laser only stuff. We provide Internet through wifi on different network like 192.168.2.x - -Even if etherdreams are 100 Mbits, we use gigabits gear. - - -By default LJ uses on 127.0.0.1 (localhost) : - -- A websocket on port 9001 for WebUI interaction. -- The redis server on port 6379 ('ljayserverip') -- An OSC server on port 8002. -- An OSC client for 'bhoroscIP' port 8001. -- An OSC client for Nozoids support on 'nozoscIP', port 8003. - -You need to update LJ.conf to your network/etherdreams IPs and be sure to check command arguments : python main.py --help - -The need for a dedicated computer to act as "laser server" usually depends on how many lasers you want to control and your main computer load. If you seen flickering with small point lists, try the dedicated computer option and/or stop process interfering like redis monitoring,... - - - -Program your own "Client" : -------------------------- - -- Read the Introduction part in this readme. -- Carefully read all comments in clients examples. -- Generate at least one point list array (say a square). -- Feed your point list array in string format to redis server. -- laserglyph.py is - # # Install @@ -112,7 +71,7 @@ Order is : - Redis server once. - This server. see below. - Load/reload webUI page from disk in a browser (webui/index.html). Javascript must be enabled. -- A Client, see in clients folder for examples. +- Run a client, see in clients folder for examples. A typical start is python main.py -L numberoflasers. Use -h to display all possible arguments. @@ -150,6 +109,20 @@ redis-cli -h redisserverIP monitor +# +# Program your own "Client" +# + + +The server approach is based on redis, so you write and run your laser client software in any redis capable programming langage (50+ : https://redis.io/clients). + +- Read the Introduction part in this readme. +- There is a clients folders with examples in different languages. +- Generate at least one point list array (say a square). +- Feed your point list array in string format to redis server. +- + + # # Todo # @@ -160,6 +133,34 @@ redis-cli -h redisserverIP monitor - A grid style warp correction process in webUI +# +# Networking +# + + +LJ is network based and this is *critical and flickering reason #1* if not managed properly, especially if you have several lasers. + +Our "always working solution", as we regularly move our gear for different venues : + +We use static network configuration. Our Etherdreams controllers have static IPs defined in their SDcard from 192.168.1.1 to 192.168.1.9. Because wifi will always finally sucks for many reasons, our computers (laser server and clients) are *gigabits wired connected* with 192.168.1.10 and after. Don't trust end user gear marketing on wifi, we have a big gigabits switch for laser only stuff. We provide Internet through wifi on different network like 192.168.2.x + +Even if etherdreams are 100 Mbits, we use gigabits gear. + + +By default LJ uses on 127.0.0.1 (localhost) : + +- A websocket on port 9001 for WebUI interaction. +- The redis server on port 6379 ('ljayserverip') +- An OSC server on port 8002. +- An OSC client as output on port 8001. +- An OSC client for Nozoids support on 'nozoscIP', port 8003. + +You need to update LJ.conf to your network/etherdreams IPs and be sure to check command arguments : python main.py --help + +The need for a dedicated computer to act as "laser server" usually depends on how many lasers you want to control and your main computer load. If you seen flickering with small point lists, try the dedicated computer option and/or stop process interfering like redis monitoring,... + + + # # Ether dream configuration # @@ -172,10 +173,10 @@ This program suppose that the ether dream is configured in a certain way especia /net/netmask 255.255.255.0 -/net/gateway 192.168.1.1 +/net/gateway 192.168.1.10 /ilda/pps 25000 /ilda/fps 25 -About hardware setup, especially if you have several lasers : ILDA cables are insanely expensive. You may consider the Power Over Ethernet 'POE' option. Buy a very small ILDA cable, a POE splitter and connect everything to the ether dream fixed near your laser. You can have then a simple and very long network cable and use a Power Over Ethernet injector or switch closed to the driving computer. Beware some vendors use 24V POE Injector : POE injectors and splitters must match. +About hardware setup, especially if you have several lasers : ILDA cables are insanely expensive. You may consider the Power Over Ethernet 'POE' option. Buy a very small ILDA cable, a POE splitter and connect everything to the ether dream fixed near your laser. You can have then a simple and very long network cable and use a Power Over Ethernet injector or switch close to the driving computer. Beware some vendors use 24V POE Injector : POE injectors and splitters must match. diff --git a/cli.py b/cli.py index 0ad40fe..ca134a4 100644 --- a/cli.py +++ b/cli.py @@ -22,20 +22,18 @@ def handle(): #have to be done before importing bhorosc.py to get correct port assignment - argsparser = argparse.ArgumentParser(description="LJay") - argsparser.add_argument("-r","--redisIP",help="Redis computer IP address (gstt.LjayServerIP by default)",type=str) - argsparser.add_argument("-i","--iport",help="OSC port number to listen to (8001 by default)",type=int) - argsparser.add_argument("-o","--oport",help="OSC port number to send to (8002 by default)",type=int) + argsparser = argparse.ArgumentParser(description="LJ v0.8") + argsparser.add_argument("-r","--redisIP",help="IP address to bind builtin servers (OSC and websocket) also must be the Redis server IP ",type=str) + argsparser.add_argument("-L","--Lasers",help="Number of lasers connected.",type=int) + argsparser.add_argument("-v","--verbose",help="Debug mode 0,1 or 2.",type=int) argsparser.add_argument("-x","--invx",help="Invert laser 0 X axis again",action="store_true") argsparser.add_argument("-y","--invy",help="Invert laser 0 Y axis again",action="store_true") - argsparser.add_argument("-s","--set",help="Only for VJ version. Specify wich generator set to use (default is in gstt.py)",type=int) - argsparser.add_argument("-c","--curve",help="Only for VJ version. Specify with generator curve to use (default is in gstt.py)",type=int) + argsparser.add_argument("-d","--display",help="Point List number displayed in simulator",type=int) argsparser.add_argument("-a","--align",help="Reset laser 0 alignement values",action="store_true") - argsparser.add_argument("-d","--display",help="Point List number displayed in pygame simulator",type=int) - argsparser.add_argument("-v","--verbose",help="Debug mode 0,1 or 2.",type=int) - argsparser.add_argument("-L","--Lasers",help="Number of lasers connected.",type=int) - argsparser.add_argument("-b","--bhoroscIP",help="Computer IP running bhorosc ('127.0.0.1' by default)",type=str) - argsparser.add_argument("-n","--nozoscIP",help="Computer IP running Nozosc ('127.0.0.1' by default)",type=str) + argsparser.add_argument("-i","--iport",help="port number for builtin LJ OSC server (8002 by default)",type=int) + argsparser.add_argument("-n","--nozoidIP",help="IP for llstr' Nozoid OSC server port 8003 ('127.0.0.1' by default)",type=str) + argsparser.add_argument("-b","--bhoroscIP",help="IP for OSC output ('127.0.0.1' by default)",type=str) + argsparser.add_argument("-o","--oport",help="OSC output port number (8001 by default)",type=int) @@ -98,24 +96,12 @@ def handle(): gstt.LjayServerIP = args.redisIP - # Set / Curves arguments - if args.set != None: - gstt.Set = args.set - print "Set : " + str(gstt.Set) - - if args.curve != None: - gstt.Curve = args.curve - print "Curve : " + str(gstt.Curve) - # Point list number used by simulator if args.display != None: gstt.simuPL = args.display print "Display : " + str(gstt.simuPL) - - - # Lasers = number of laser connected @@ -128,8 +114,8 @@ def handle(): else: gstt.oscIPin = '127.0.0.1' - if args.nozoscIP != None: - gstt.nozoscIP = args.nozoscIP + if args.nozoidIP != None: + gstt.nozoscIP = args.nozoidIP else: gstt.nozoscIP = '127.0.0.1' diff --git a/clients/3dsines.py b/clients/3dsines.py index 22b10ec..581b091 100644 --- a/clients/3dsines.py +++ b/clients/3dsines.py @@ -7,7 +7,7 @@ LICENCE : CC ''' import redis -import framy +import lj import math import time import numpy as np @@ -34,21 +34,7 @@ observer_altitude = 30000 map_plane_altitude = 0.0 samparray = [0] * 100 -vertices = [ - (- 1.0, 1.0,- 1.0), - ( 1.0, 1.0,- 1.0), - ( 1.0,- 1.0,- 1.0), - (- 1.0,- 1.0,- 1.0), - (- 1.0, 1.0, 1.0), - ( 1.0, 1.0, 1.0), - ( 1.0,- 1.0, 1.0), - (- 1.0,- 1.0, 1.0) - ] -# Define the vertices that compose each of the 6 faces. These numbers are -# indices to the vertices list defined above. -#faces = [(0,1,2,3),(1,5,6,2),(5,4,7,6),(4,0,3,7),(0,4,5,1),(3,2,6,7)] -faces = [(0,1,2,3),(1,5,6,2),(5,4,7,6),(4,0,3,7),(0,4,5,1),(3,2,6,7)] def LeftShift(elevation): @@ -131,54 +117,7 @@ def Proj(x,y,z,angleX,angleY,angleZ): -def Draw2PL(): - - Shape = [] - Left = [] - Right = [] - counter =0 - - while 1: - Shape = [] - Left = [] - Right = [] - for fa in faces: - #print "" - #print "face",fa - - for point in fa: - #print "" - #print "point ", point - x = vertices[point][0] - y = vertices[point][1] - z = vertices[point][2] - #print x,y,z - #print "left",x+LeftShift(z*25),y,z, Proj(x+LeftShift(z*25),y,z) - #print "right",x+RightShift(z*25),y,z, Proj(x+RightShift(z*25),y,z) - - - #Shape.append(Proj(x,y,z,0,0,counter)) - Left.append( Proj(x+LeftShift(z*5),y,z,0,0,counter)) - Right.append(Proj(x+RightShift(z*5),y,z,0,0,counter)) - - #framy.PolyLineOneColor(Shape, c = white, PL = 0, closed = False) - framy.PolyLineOneColor(Left, c = red, PL = 1, closed = False) - framy.PolyLineOneColor(Right, c = green, PL = 2, closed = False) - ''' - framy.rPolyLineOneColor(Shape, c = white, PL = 0, closed = False, xpos = 200, ypos = 250, resize = 1.5, rotx =0, roty =0 , rotz=0) - framy.rPolyLineOneColor(Left, c = red, PL = 1, closed = False, xpos = 200, ypos = 250, resize = 1.5, rotx =0, roty =0 , rotz=0) - framy.rPolyLineOneColor(Right, c = blue, PL = 2, closed = False, xpos = 200, ypos = 250, resize = 1.5, rotx =0, roty =0 , rotz=0) - ''' - #print framy.LinesPL(0) - #print framy.LinesPL(1) - #print framy.LinesPL(2) - - #counter -= 1 - #if counter >360: - # counter =0 - - -def Draw1PL(): +def DrawPL(): Shape = [] Left = [] @@ -198,8 +137,8 @@ def Draw1PL(): Right.append(Proj(x+RightShift(z*25),step/yfactor,z,0,0,0)) x += 0.02 - framy.rPolyLineOneColor(Left, c = red, PL = 0, closed = False, xpos = 0, ypos = 10, resize = 1.5, rotx =0, roty =0 , rotz=0) - framy.rPolyLineOneColor(Right, c = green, PL = 0, closed = False, xpos = 0, ypos = 10, resize = 1.5, rotx =0, roty =0 , rotz=0) + lj.rPolyLineOneColor(Left, c = red, PL = 0, closed = False, xpos = 0, ypos = 10, resize = 1.5, rotx =0, roty =0 , rotz=0) + lj.rPolyLineOneColor(Right, c = green, PL = 0, closed = False, xpos = 0, ypos = 10, resize = 1.5, rotx =0, roty =0 , rotz=0) Left = [] Right = [] @@ -211,8 +150,8 @@ def Draw1PL(): Right.append(Proj(x+RightShift(z*25),step/yfactor,z,0,0,0)) x += 0.02 - framy.rPolyLineOneColor(Left, c = red, PL = 0, closed = False, xpos = 0, ypos = 25, resize = 1.5, rotx =0, roty =0 , rotz=0) - framy.rPolyLineOneColor(Right, c = green, PL = 0, closed = False, xpos = 0, ypos = 25, resize = 1.5, rotx =0, roty =0 , rotz=0) + lj.rPolyLineOneColor(Left, c = red, PL = 0, closed = False, xpos = 0, ypos = 25, resize = 1.5, rotx =0, roty =0 , rotz=0) + lj.rPolyLineOneColor(Right, c = green, PL = 0, closed = False, xpos = 0, ypos = 25, resize = 1.5, rotx =0, roty =0 , rotz=0) Left = [] Right = [] @@ -224,11 +163,11 @@ def Draw1PL(): Right.append(Proj(x+RightShift(z*25),step/yfactor,z,0,0,0)) x += 0.02 - framy.rPolyLineOneColor(Left, c = red, PL = 0, closed = False, xpos = 0, ypos = 50, resize = 1.5, rotx =0, roty =0 , rotz=0) - framy.rPolyLineOneColor(Right, c = green, PL = 0, closed = False, xpos = 0, ypos = 50, resize = 1.5, rotx =0, roty =0 , rotz=0) + lj.rPolyLineOneColor(Left, c = red, PL = 0, closed = False, xpos = 0, ypos = 50, resize = 1.5, rotx =0, roty =0 , rotz=0) + lj.rPolyLineOneColor(Right, c = green, PL = 0, closed = False, xpos = 0, ypos = 50, resize = 1.5, rotx =0, roty =0 , rotz=0) - framy.LinesPL(0) + lj.DrawPL(0) time.sleep(0.005) white = rgb2int(255,255,255) @@ -240,4 +179,4 @@ y0 = ssine(100,5,-0.5) y1 = ssine(100,5,0) y2 = ssine(100,5,0.5) -Draw1PL() \ No newline at end of file +DrawPL() \ No newline at end of file diff --git a/clients/framy.py b/clients/framy.py deleted file mode 100644 index 89d6a1c..0000000 --- a/clients/framy.py +++ /dev/null @@ -1,115 +0,0 @@ -# coding=UTF-8 - -''' -LJay v0.8.0 - - -LICENCE : CC -pclf, Sam Neurohack - -''' - -import math -import redis - -redisIP = '127.0.0.1' -r = redis.StrictRedis(host=redisIP, port=6379, db=0) - -point_list = [] -pl = [[],[],[],[]] - -def LineTo(xy, c, PL): - - pl[PL].append((xy + (c,))) - -def Line(xy1, xy2, c, PL): - LineTo(xy1, 0, PL) - LineTo(xy2, c , PL) - - -def PolyLineOneColor(xy_list, c, PL , closed ): - #print "--" - #print "c",c - #print "xy_list",xy_list - #print "--" - xy0 = None - for xy in xy_list: - if xy0 is None: - xy0 = xy - #print "xy0:",xy0 - LineTo(xy0,0, PL) - else: - #print "xy:",xy - LineTo(xy,c, PL) - if closed: - LineTo(xy0,c, PL) - - -# Computing points coordinates for rPolyline function from 3D and around 0,0 to pygame coordinates -def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): - - x = xy[0] * resize - y = xy[1] * resize - z = 0 - - rad = rotx * math.pi / 180 - cosaX = math.cos(rad) - sinaX = math.sin(rad) - - y2 = y - y = y2 * cosaX - z * sinaX - z = y2 * sinaX + z * cosaX - - rad = roty * math.pi / 180 - cosaY = math.cos(rad) - sinaY = math.sin(rad) - - z2 = z - z = z2 * cosaY - x * sinaY - x = z2 * sinaY + x * cosaY - - rad = rotz * math.pi / 180 - cosZ = math.cos(rad) - sinZ = math.sin(rad) - - x2 = x - x = x2 * cosZ - y * sinZ - y = x2 * sinZ + y * cosZ - - #print xy, (x + xpos,y+ ypos) - return (x + xpos,y+ ypos) - ''' - to understand why it get negative Y - - # 3D to 2D projection - factor = 4 * gstt.cc[22] / ((gstt.cc[21] * 8) + z) - print xy, (x * factor + xpos, - y * factor + ypos ) - return (x * factor + xpos, - y * factor + ypos ) - ''' - -# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos -#def rPolyLineOneColor(self, xy_list, c, PL , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): -def rPolyLineOneColor(xy_list, c, PL , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0): - xy0 = None - for xy in xy_list: - if xy0 is None: - xy0 = xy - LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),0, PL) - else: - LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz),c, PL) - if closed: - LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL) - - -# set all points for given laser. special behavior depends on GridDisplay flag -# 0: point list / 1: Grid -def LinesPL(PL): - #print '/pl/0/'+str(PL), str(pl[PL]) - if r.set('/pl/0/'+str(PL), str(pl[PL])) == True: - pl[PL] = [] - return True - else: - return False - -def ResetPL(self, PL): - pl[PL] = [] diff --git a/clients/games/ljpong/controller.py b/clients/games/ljpong/controller.py new file mode 100755 index 0000000..912afd2 --- /dev/null +++ b/clients/games/ljpong/controller.py @@ -0,0 +1,255 @@ +""" +Directions Buttons defined correctly only for PS3 and USBJoystick + + +Represent various videogame controllers + +TODO: Various play schemes/configs +XXX: UNTESTED +""" + +import re + +def setup_controls(joystick): + """ + Joystick wrapper. + """ + if re.search('playstation', joystick.get_name(), re.I): + return Ps3Controller(joystick) + + elif re.search('X-box', joystick.get_name(), re.I): + return XboxController(joystick) + + elif re.search('Saitek', joystick.get_name(), re.I): + return MySaitekController(joystick) + + elif re.search('Thrustmaster dual analog 3.2', joystick.get_name(), re.I): + return MyThrustController(joystick) + + elif re.search('2n1 USB', joystick.get_name(), re.I): + return CSLController(joystick) + + elif re.search('Joystick', joystick.get_name(), re.I): + return USBController(joystick) + + return Controller(joystick) + +class Controller(object): + + def __init__(self, joystick): + """Pass a PyGame joystick instance.""" + self.js = joystick + + def getLeftHori(self): + return self.js.get_axis(2) + + def getLeftVert(self): + return self.js.get_axis(3) + + def getRightHori(self): + return self.js.get_axis(0) + + def getRightVert(self): + return self.js.get_axis(1) + + def getLeftTrigger(self): + return self.js.get_button(9) + + def getRightTrigger(self): + return self.js.get_button(2) + +class XboxController(Controller): + + def __init__(self, joystick): + super(XboxController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(3) + + def getRightVert(self): + return self.js.get_axis(4) + + def getLeftTrigger(self): + return self.js.get_axis(2) + + def getRightTrigger(self): + return self.js.get_button(11) + +class Ps3Controller(Controller): + +#up 4 _DOWN 6 left 7 right 5 croix 14 rond 13 triangle 12 + + def __init__(self, joystick): + super(Ps3Controller, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(2) + + def getRightVert(self): + return self.js.get_axis(3) + + def getLeftTrigger(self): + # TODO: Verify + return self.js.get_button(8) + + def getRightTrigger(self): + # TODO: Verify + return self.js.get_button(9) + + def getUp(self): + return self.js.get_button(4) + + def getDown(self): + return self.js.get_button(6) + + def getLeft(self): + return self.js.get_button(7) + + def getRight(self): + return self.js.get_button(5) + + def getFire1(self): + return self.js.get_button(14) + + def getFire2(self): + return self.js.get_button(13) + + +class MySaitekController(Controller): + + def __init__(self, joystick): + super(MySaitekController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(3) + + def getRightVert(self): + return self.js.get_axis(2) + + def getLeftTrigger(self): + return self.js.get_button(6) + + def getRightTrigger(self): + return self.js.get_button(7) + +class MyThrustController(Controller): + + def __init__(self, joystick): + super(MyThrustController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(2) + + def getRightVert(self): + return self.js.get_axis(3) + + def getLeftTrigger(self): + return self.js.get_button(5) + + def getRightTrigger(self): + return self.js.get_button(7) + + +class CSLController(Controller): + + def __init__(self, joystick): + super(CSLController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(2) + + def getLeftVert(self): + return self.js.get_axis(3) + + def getRightHori(self): + return self.js.get_axis(0) + + def getRightVert(self): + return self.js.get_axis(1) + + def getLeftTrigger(self): + return self.js.get_button(6) + + def getRightTrigger(self): + return self.js.get_button(7) + + def getFire1(self): + return self.js.get_button(2) + + def getFire2(self): + return self.js.get_button(1) + +class USBController(Controller): + + +# my USB Joystick +#up axis 0 -1 DOWN axis 0 1 left axis 1 1 right axis 1 -1 bouton gauche 10 bouton droite 9 + + def __init__(self, joystick): + super(USBController, self).__init__(joystick) + + + def getUp(self): + if self.js.get_axis(0) == -1: + return 1 + else: + return 0 + + def getDown(self): + if self.js.get_axis(0) > 0.9: + return 1 + else: + return 0 + + def getLeft(self): + if self.js.get_axis(1) == 1: + return 1 + else: + return 0 + + def getRight(self): + if self.js.get_axis(1) == -1: + return 1 + else: + return 0 + + def getLeftTrigger(self): + return self.js.get_button(10) + + def getRightTrigger(self): + return self.js.get_button(9) + + def getFire1(self): + if self.js.get_button(10) == 1: + print "fire 1" + return self.js.get_button(10) + + def getFire2(self): + if self.js.get_button(9) == 1: + print "fire 2" + return self.js.get_button(9) + diff --git a/clients/games/ljpong/entities.py b/clients/games/ljpong/entities.py new file mode 100644 index 0000000..4d787a3 --- /dev/null +++ b/clients/games/ljpong/entities.py @@ -0,0 +1,259 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- +''' + +LJ Laser Pong entities +v0.1 + +Sam Neurohack + +''' + + +# STDLIB +import math +import itertools +import sys +import os +import lj + +import time +import random + + + +screen_size = [800,600] + +top_left = [200,100] +bottom_left = [200,300] +top_right = [600,100] +bottom_right = [600,300] + +score_pos = [550,40] +score2_pos = [259,40] + +# X Y position on bottom left of each paddle (="flips") +ball_origin = [400,300,200] +text_pos = [300,500,200] +BALL_acc = 0.06 +PADDLE_height = 100 +PADDLE_width = 10 +PADDLE3D_height = 100 +PADDLE3D_width = 100 +FACT3D = 2 +FLIPS_lorigin = [10,300,0] +FLIPS_rorigin = [780,300,400] +flips_attraction = 0.007 + +xy_center = [screen_size[0]/2,screen_size[1]/2] + +DEFAULT_SPOKES = range(0,359,60) +DEFAULT_PLAYER_EXPLODE_COLOR = 0xFFFF00 +DEFAULT_SIDE_COUNT = 6 +DREARRANGE_SIDES = .02 + + +CRASH_SHAKE_MAX = 6 +TDN_CRASH = 200 + +GAME_FS_QUIT = -1 +GAME_FS_MENU = 0 +GAME_FS_PLAY = 1 +GAME_FS_LAUNCH = 2 +GAME_FS_GAMEOVER = 3 + +BUMPERS_COLOR_YELLOW = 0xFFFF00 +BUMPERS_COLOR_RED = 0xFF0000 +BUMPERS_COLOR_BLACK = 0x000000 +BUMPERS_SIZE_X = 60 +BUMPERS_SIZE_Y = 110 +BUMPERS_FORCE = 1.1 + + +BALL_SPEED = 5 +BALL_MAX = 4 +BALL_SIZE_X = 3 +BALL_SIZE_Y = 3 +LASER_ANGLE = 0 + + + +GRAVITY = 0.0001 + +NO_BGM = False +#NO_BGM = True + +def rgb2int(r,g,b): + return int('0x%02x%02x%02x' % (r,g,b),0) + +white = rgb2int(255,255,255) +red = rgb2int(255,0,0) +blue = rgb2int(0,0,255) +green = rgb2int(0,255,0) + + +LOGO = [ + # L/o + [[(-140,-100),(-200,20),(40,20)],0xFF00], + # aser + [[(-140,-40),(-100,-40,),(-120,0),(-160,0),(-110,-20)],0xFFFF], + [[(-40,-40),(-60,-40),(-90,-20),(-50,-20),(-80,0),(-100,0)],0xFFFF], + [[(-30,-20),(10,-20),(0,-40),(-20,-40),(-30,-20),(-30,0),(-10,0)],0xFFFF], + [[(20,0),(40,-40),(35,-30),(50,-40),(70,-40)],0xFFFF], + # Pinball + [[(-185,50),(-145,50),(-130,20),(-170,20),(-200,80)],0xFFFF00], #P + [[(-80,40),(-120,40),(-140,80),(-100,80),(-80,40)],0xFFFF], #O + [[(-80,80),(-60,40),(-65,50),(-40,40),(-25,50),(-40,80)],0xFFFF], #N + [[(40,40),(0,40),(-20,80),(20,80),(30,60),(10,60)],0xFFFF], #G + ] + + +LOGO_OFFSET_X = 460 +LOGO_OFFSET_Y = 250 + +def LogoDraw(): + ''' + Dessine le logo + ''' + for pl_color in LOGO: + c = pl_color[1] + xy_list = [] + for xy in pl_color[0]: + xy_list.append((LOGO_OFFSET_X + xy[0], LOGO_OFFSET_Y + xy[1])) + #print xy_list + lj.PolyLineOneColor(xy_list, c,0, False) + + + + +FlipsLx, FlipsLy = FLIPS_lorigin[0], FLIPS_lorigin[1] +FlipsRx, FlipsRy = FLIPS_rorigin[0], FLIPS_rorigin[1] +FlipsSpeed = 7 + + +def FlipsMove(left_key,right_key,up_key,down_key): + global FlipsLx, FlipsLy, FlipsRx, FlipsRy + + if left_key: + FlipsLy -= FlipsSpeed + if FlipsLy < 1: + FlipsLy = 1 + + if right_key: + FlipsLy += FlipsSpeed + if FlipsLy > screen_size[1] - PADDLE_height: + FlipsLy = screen_size[1] - PADDLE_height + + if up_key: + FlipsRy -= FlipsSpeed + if FlipsRy < 1: + FlipsRy = 1 + + if down_key: + FlipsRy += FlipsSpeed + if FlipsRy > screen_size[1] - PADDLE_height: + FlipsRy = screen_size[1] - PADDLE_height + + return FlipsLy, FlipsRy + +def FlipsMoveJoy(left_key,right_key,up_key,down_key,lvertax): + + if left_key: + FlipsLy -= FlipsSpeed + if FlipsLy < 1: + FlipsLy = 1 + + if right_key: + FlipsLy += FlipsSpeed + if FlipsLy > screen_size[1] - PADDLE_height: + FlipsLy = screen_size[1] - PADDLE_height + + if up_key: + FlipsRy -= FlipsSpeed + if FlipsRy < 1: + FlipsRy = 1 + if down_key > 0.01: + FlipsRy += FlipsSpeed + if FlipsRy > screen_size[1] - PADDLE_height: + FlipsRy = screen_size[1] - PADDLE_height + + if lvertax: + print lvertax + if lvertax < 0: + FlipsLy -= FlipsSpeed + if FlipsLy < 1: + FlipsLy = 1 + elif lvertax > 0.01: + FlipsLy += FlipsSpeed + if FlipsLy > screen_size[1] - PADDLE_height: + FlipsLy = screen_size[1] - PADDLE_height + return FlipsLy, FlipsRy + +def FlipsDraw(): + + lj.PolyLineOneColor([(FlipsLx,FlipsLy),(FlipsLx,FlipsLy + PADDLE_height),(FlipsLx + PADDLE_width , FlipsLy + PADDLE_height),(FlipsLx + PADDLE_width,FlipsLy)], white,0,True) + lj.PolyLineOneColor([(FlipsRx,FlipsRy),(FlipsRx,FlipsRy + PADDLE_height),(FlipsRx + PADDLE_width , FlipsRy + PADDLE_height),(FlipsRx + PADDLE_width,FlipsRy)], white,0,True) + + +def FiletDraw(): + lj.PolyLineOneColor([(screen_size[0]/2,screen_size[1]),(screen_size[0]/2,0)], white, 0,True) + + +def Score1Draw(score): + #print "score1",score + lj.Text(str(score),white, 0, 350, 50, 1, 0, 0, 0) + +def Score2Draw(score): + #print "score2",score + lj.Text(str(score),white, 0, 500, 50, 1, 0, 0, 0) + + + +BallX, BallY = ball_origin[0], ball_origin[1] +BallZoom = 1 + + +def BallMove(xcoord,ycoord): + global BallX,BallY + + BallX = xcoord + BallY = ycoord + #print "ball move",xcoord,ycoord + + #BallZoom = ? + + if BallX < 0: + BallX = 0 + + elif BallX >= screen_size[0]: + BallX = screen_size[0] + + if BallY < 0: + BallY = 0 + + elif BallY >= screen_size[1]: + BallY = screen_size[1] + +def BallDraw(): + global BallX,BallY + + xmin = 0 + xmax = BALL_SIZE_X * 2 + ymin = 0 + ymax = BALL_SIZE_Y * 2 + + xmin = (xmin*BallZoom) + ymin = (ymin*BallZoom) + xmax = (xmax*BallZoom) + ymax = (ymax*BallZoom) + + xmin += BallX + xmax += BallX + ymin += BallY + ymax += BallY + + #print "ball position",xmin,xmax,ymin,ymax + + lj.PolyLineOneColor([(xmin,ymin),(xmin,ymax),(xmax,ymax),(xmax,ymin)], white,0,True) + diff --git a/clients/games/ljpong/gstt.py b/clients/games/ljpong/gstt.py new file mode 100755 index 0000000..f89893f --- /dev/null +++ b/clients/games/ljpong/gstt.py @@ -0,0 +1,17 @@ +# coding=UTF-8 +''' +Etat global (anciennement singleton de la classe GameState + autres VARIABLES nécessaires partout)" +''' + +from globalVars import * + +# Etat global général +app_path = "" + +# anciennement GameState +fs = GAME_FS_GAMEOVER +plyr = None +score = None +bmprs = None + + diff --git a/clients/games/ljpong/lj.py b/clients/games/ljpong/lj.py new file mode 100644 index 0000000..da6fe60 --- /dev/null +++ b/clients/games/ljpong/lj.py @@ -0,0 +1,310 @@ +# coding=UTF-8 + +''' +LJ v0.8.0 +Some LJ functions useful for python clients (was framy.py) + +Config +PolyLineOneColor +rPolyLineOneColor +Text +sendlj : remote control +DrawPL + +LICENCE : CC +Sam Neurohack + +''' + +import math +import redis +from OSC import OSCServer, OSCClient, OSCMessage + +redisIP = '127.0.0.1' +r = redis.StrictRedis(host=redisIP, port=6379, db=0) + +ClientNumber = 0 + +point_list = [] +pl = [[],[],[],[]] + + +''' +LJIP = "127.0.0.1" + +osclientlj = OSCClient() +oscmsg = OSCMessage() +osclientlj.connect((redisIP, 8002)) +''' + +def sendlj(oscaddress,oscargs=''): + + oscmsg = OSCMessage() + oscmsg.setAddress(oscaddress) + oscmsg.append(oscargs) + + #print ("sending to bhorosc : ",oscmsg) + try: + osclientlj.sendto(oscmsg, (redisIP, 8002)) + oscmsg.clearData() + except: + print ('Connection to LJ refused : died ?') + pass + #time.sleep(0.001 + + + + +ASCII_GRAPHICS = [ + +#implementé + + [(-50,30), (-30,-30), (30,-30), (10,30), (-50,30)], #0 + [(-20,30), (0,-30), (-20,30)], #1 + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #2 + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #3 + [(30,10), (-30,10), (0,-30), (0,30)], #4 + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #5 + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #6 + [(-30,-30), (30,-30), (-30,30)], #7 + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], #8 + [(30,0), (-30,0), (-30,-10), (0,-30), (30,-30), (30,10), (0,30), (-30,30)], #9 + +# A implementer + [(-30,10), (30,-10), (30,10), (0,30), (-30,10), (-30,-10), (0,-30), (30,-10)], #: + [(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], #; + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #< + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #= + [(30,10), (-30,10), (0,-30), (0,30)], #> + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #? + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #@ + +# Implementé + + + [(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A + [(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], #B + [(30,30), (-30,30), (-30,-30), (30,-30)], #C + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], #D + [(30,30), (-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], #E + [(-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], #F + [(0,0), (30,0), (30,30), (-30,30), (-30,-30),(30,-30)], #G + [(-30,-30), (-30,30), (-30,0), (30,0), (30,30), (30,-30)], #H + [(0,30), (0,-30)], #I + [(-30,30), (0,-30), (0,-30), (-30,-30), (30,-30)], #J + [(-30,-30), (-30,30), (-30,0), (30,-30), (-30,0), (30,30)], #K + [(30,30), (-30,30), (-30,-30)], #L + [(-30,30), (-30,-30), (0,0), (30,-30), (30,30)], #M + [(-30,30), (-30,-30), (30,30), (30,-30)], #N + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], #O + [(-30,0), (30,0), (30,-30), (-30,-30), (-30,30)], #P + [(30,30), (30,-30), (-30,-30), (-30,30), (30,30),(35,35)], #Q + [(-30,30), (-30,-30), (30,-30), (30,0), (-30,0), (30,30)], #R + [(30,-30), (-30,-30), (-30,0), (30,0), (30,30), (-30,30)], #S + [(0,30), (0,-30), (-30,-30), (30,-30)], #T + [(-30,-30), (-30,30), (30,30), (30,-30)], #U + [(-30,-30), (0,30), (30,-30)], #V + [(-30,-30), (-30,30), (0,0), (30,30), (30,-30)], #W + [(-30,30), (30,-30)], [(-30,-30), (30,30)], #X + [(0,30), (0,0), (30,-30), (0,0), (-30,-30)], #Y + [(30,30), (-30,30), (30,-30), (-30,-30)], #Z + + # A implementer + + [(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], #[ + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #\ + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #] + [(30,10), (-30,10), (0,-30), (0,30)], #^ + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #_ + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #` + + # Implementé + + [(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], #a + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20), (-20,0), (20,0)], #b + [(20,20), (-20,20), (-20,-20), (20,-20)], #c + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], #d + [(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], #e + [(-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], #f + [(0,0), (20,0), (20,20), (-20,20), (-20,-20),(20,-20)], #g + [(-20,-20), (-20,20), (-20,0), (20,0), (20,20), (20,-20)], #H + [(0,20), (0,-20)], #I + [(-20,20), (0,-20), (0,-20), (-20,-20), (20,-20)], #J + [(-20,-20), (-20,20), (-20,0), (20,-20), (-20,0), (20,20)], #K + [(20,20), (-20,20), (-20,-20)], #L + [(-20,20), (-20,-20), (0,0), (20,-20), (20,20)], #M + [(-20,20), (-20,-20), (20,20), (20,-20)], #N + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], #O + [(-20,0), (20,0), (20,-20), (-20,-20), (-20,20)], #P + [(20,20), (20,-20), (-20,-20), (-20,20), (20,20),(25,25)], #Q + [(-20,20), (-20,-20), (20,-20), (20,0), (-20,0), (20,20)], #R + [(20,-20), (-20,-20), (-20,0), (20,0), (20,20), (-20,20)], #S + [(0,20), (0,-20), (-20,-20), (20,-20)], #T + [(-20,-20), (-20,20), (20,20), (20,-20)], #U + [(-20,-20), (0,20), (20,-20)], #V + [(-20,-20), (-20,20), (0,0), (20,20), (20,-20)], #W + [(-20,20), (20,-20)], [(-20,-20), (20,20)], #X + [(0,20), (0,0), (20,-20), (0,0), (-20,-20)], #Y + [(20,20), (-20,20), (20,-20), (-20,-20)], #Z + + [(-2,15), (2,15)] # Point a la place de { +] + +def Config(redisIP,client): + global ClientNumber + + r = redis.StrictRedis(host=redisIP, port=6379, db=0) + ClientNumber = client + #print "client configured",ClientNumber + + +def LineTo(xy, c, PL): + + pl[PL].append((xy + (c,))) + +def Line(xy1, xy2, c, PL): + LineTo(xy1, 0, PL) + LineTo(xy2, c , PL) + + +def PolyLineOneColor(xy_list, c, PL , closed ): + #print "--" + #print "c",c + #print "xy_list",xy_list + #print "--" + xy0 = None + for xy in xy_list: + if xy0 is None: + xy0 = xy + #print "xy0:",xy0 + LineTo(xy0,0, PL) + LineTo(xy0,c, PL) + else: + #print "xy:",xy + LineTo(xy,c, PL) + if closed: + LineTo(xy0,c, PL) + + +# Computing points coordinates for rPolyline function from 3D and around 0,0 to pygame coordinates +def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): + + x = xy[0] * resize + y = xy[1] * resize + z = 0 + + rad = math.radians(rotx) + cosaX = math.cos(rad) + sinaX = math.sin(rad) + + y2 = y + y = y2 * cosaX - z * sinaX + z = y2 * sinaX + z * cosaX + + rad = math.radians(roty) + cosaY = math.cos(rad) + sinaY = math.sin(rad) + + z2 = z + z = z2 * cosaY - x * sinaY + x = z2 * sinaY + x * cosaY + + rad = math.radians(rotz) + cosZ = math.cos(rad) + sinZ = math.sin(rad) + + x2 = x + x = x2 * cosZ - y * sinZ + y = x2 * sinZ + y * cosZ + + #print xy, (x + xpos,y+ ypos) + return (x + xpos,y+ ypos) + ''' + to understand why it get negative Y + + # 3D to 2D projection + factor = 4 * gstt.cc[22] / ((gstt.cc[21] * 8) + z) + print xy, (x * factor + xpos, - y * factor + ypos ) + return (x * factor + xpos, - y * factor + ypos ) + ''' + +# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos +#def rPolyLineOneColor(self, xy_list, c, PL , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): +def rPolyLineOneColor(xy_list, c, PL , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0): + xy0 = None + for xy in xy_list: + if xy0 is None: + xy0 = xy + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),0, PL) + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL) + else: + LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz),c, PL) + if closed: + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL) + + +def LinesPL(PL): + print "Stupido !! your code is to old : use DrawPL() instead of LinesPL()" + DrawPL(PL) + +def DrawPL(PL): + #print '/pl/0/'+str(PL), str(pl[PL]) + if r.set('/pl/'+str(ClientNumber)+'/'+str(PL), str(pl[PL])) == True: + #print '/pl/'+str(ClientNumber)+'/'+str(PL), str(pl[PL]) + pl[PL] = [] + return True + else: + return False + +def ResetPL(self, PL): + pl[PL] = [] + + + +def DigitsDots(number,color): + dots =[] + for dot in ASCII_GRAPHICS[number]: + #print dot + dots.append((gstt.xy_center[0]+dot[0],gstt.xy_center[1]+dot[1],color)) + #self.point_list.append((xy + (c,))) + return dots + +def CharDots(char,color): + + dots =[] + for dot in ASCII_GRAPHICS[ord(char)-46]: + dots.append((dot[0],dot[1],color)) + return dots + +def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz): + + dots =[] + + l = len(message) + i= 0 + #print message + + for ch in message: + + #print "" + # texte centre en x automatiquement selon le nombre de lettres l + x_offset = 26 * (- (0.9*l) + 3*i) + # Digits + if ord(ch)<58: + char_pl_list = ASCII_GRAPHICS[ord(ch) - 48] + else: + char_pl_list = ASCII_GRAPHICS[ord(ch) - 46] + char_draw = [] + #dots.append((char_pl_list[0][0] + x_offset,char_pl_list[0][1],0)) + + for xy in char_pl_list: + char_draw.append((xy[0] + x_offset,xy[1],c)) + i +=1 + #print ch,char_pl_list,char_draw + rPolyLineOneColor(char_draw, c, PL , False, xpos, ypos, resize, rotx, roty, rotz) + #dots.append(char_draw) + + + + \ No newline at end of file diff --git a/clients/games/ljpong/main.py b/clients/games/ljpong/main.py new file mode 100755 index 0000000..5e7c7f3 --- /dev/null +++ b/clients/games/ljpong/main.py @@ -0,0 +1,367 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- +''' +LJ Laser Pong v0.8 + +Sam Neurohack + +''' + +import pygame +import math +import itertools +import sys +import os + +''' +is_py2 = sys.version[0] == '2' +if is_py2: + from Queue import Queue +else: + from queue import Queue +''' + +import thread +import time +import random +import lj +import entities +from controller import setup_controls +import argparse + + +score = None + +screen_size = [800,600] + +top_left = [200,100] +bottom_left = [200,300] +top_right = [600,100] +bottom_right = [600,300] + +score_pos = [550,40] +score2_pos = [259,40] +text_pos = [300,500,200] + +ball_origin = [400,300,200] +BALL_SPEED = 5 +BALL_SIZE_X = 3 +BALL_SIZE_Y = 3 +BALL_acc = 0.06 + +PADDLE_height = 100 +PADDLE_width = 10 + +FlipsSpeed = 7 +FLIPS_lorigin = [10,300,0] +FLIPS_rorigin = [780,300,400] +FlipsLx, FlipsLy = FLIPS_lorigin[0], FLIPS_lorigin[1] +FlipsRx, FlipsRy = FLIPS_rorigin[0], FLIPS_rorigin[1] + + +xy_center = [screen_size[0]/2,screen_size[1]/2] + +GAME_FS_QUIT = -1 +GAME_FS_MENU = 0 +GAME_FS_PLAY = 1 +GAME_FS_GAMEOVER = 2 +GAME_FS_LAUNCH = 2 + +SCORE_ZOOM_PLAYING = 1.6 +SCORE_ZOOM_GAMEOVER = 5.0 +SCORE_DZOOM_PLAYING = -0.4 +SCORE_DZOOM_GAMEOVER = 0.1 + +Score1Zoom = SCORE_ZOOM_PLAYING + +GRAVITY = 0.0001 + +fs = GAME_FS_MENU + +def rgb2int(r,g,b): + return int('0x%02x%02x%02x' % (r,g,b),0) + +white = rgb2int(255,255,255) +red = rgb2int(255,0,0) +blue = rgb2int(0,0,255) +green = rgb2int(0,255,0) + + +print ("") +print ("Arguments parsing if needed...") +argsparser = argparse.ArgumentParser(description="Laserpong") + +argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str) +argsparser.add_argument("-c","--client",help="LJ client number (0 by default)",type=int) +argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int) + +args = argsparser.parse_args() + + +if args.client: + ljclient = args.client +else: + ljclient = 0 + +if args.laser: + plnumber = args.laser +else: + plnumber = 0 + +# Redis Computer IP +if args.redisIP != None: + redisIP = args.redisIP +else: + redisIP = '127.0.0.1' + +lj.Config(redisIP,ljclient) + + +def StartPlaying(first_time = False): + global fs + + lscore = 0 + rscore = 0 + fs = GAME_FS_LAUNCH + x = ball_origin[0] + y = ball_origin[1] + +app_path = os.path.dirname(os.path.realpath(__file__)) + +pygame.init() +#sounds.InitSounds() + +clock = pygame.time.Clock() + +Nbpads = pygame.joystick.get_count() +print ("Joypads : ", str(Nbpads)) + +if Nbpads != 2: + + print ('') + print ('') + print ("THIS VERSION NEEDS 2 PADS. PLEASE CONNECT THEM.") + print ('') + sys.exit() + + + +if Nbpads > 1: + + pad2 = pygame.joystick.Joystick(1) + pad2.init() + print "Pad2 :", pad2.get_name() + numButtons = pad2.get_numbuttons() + #print ("Axis Pad 2 :", str(pad2.get_numaxes())) + #print ("Buttons Pad 2 :" , str(numButtons)) + + # joy is pad abstraction to handle many different devices. + joy2 = setup_controls(pad2) + +if Nbpads > 0: + + pad1 = pygame.joystick.Joystick(0) + pad1.init() + print "Pad1 :",pad1.get_name() + numButtons = pad1.get_numbuttons() + joy1 = setup_controls(pad1) + #print ("Axis Pad 1 :", str(pad1.get_numaxes())) + #print ("Buttons Pad 1 :" , str(numButtons)) + +update_screen = False + +xvel = - 1 +yvel = 0 +lscore = 0 +rscore = 0 +ly = FLIPS_lorigin[1] +ry = FLIPS_rorigin[1] +flipsy = [ly, ry] +stick = 0 +x = ball_origin[0] +y = ball_origin[1] + +keystates = pygame.key.get_pressed() + + +while fs != GAME_FS_QUIT: + + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + fs = GAME_FS_QUIT + + keystates_prev = keystates[:] + keystates = pygame.key.get_pressed()[:] + + + # Etats du jeu + + if fs == GAME_FS_MENU: + + if keystates[pygame.K_ESCAPE] and not keystates_prev[pygame.K_ESCAPE]: + fs = GAME_FS_QUIT + elif keystates[pygame.K_SPACE] and not keystates_prev[pygame.K_SPACE]: + StartPlaying(True) + lscore = 0 + rscore = 0 + + if joy1.getFire1() or joy2.getFire1(): + StartPlaying(False) + lscore =0 + rscore = 0 + + + + elif fs == GAME_FS_PLAY: + + if keystates[pygame.K_ESCAPE] and not keystates_prev[pygame.K_ESCAPE]: + fs = GAME_FS_MENU + + ''' + if Nbpads > 0: + print "pad 1 :", joy1.getUp(), joy1.getDown(), joy1.getLeftTrigger(),joy1.getRightTrigger() + print "pad 2 :", joy2.getUp(), joy2.getDown(), joy2.getLeftTrigger(),joy2.getRightTrigger() + ''' + + # Lost ball / first to ten points ? + #print " ball : " , x, y, " left : ", ly, " right : ", ry + + if x < FLIPS_lorigin[0] + PADDLE_width: + + print ("ball.y : ", y, " ly : ", ly) + if y > (ly + PADDLE_height + 1) or y < (ly - BALL_SIZE_Y - 1): + rscore += 1 + xvel = random.uniform(-1,-0.6) + if rscore == 11: + fs = GAME_FS_MENU + else: + fs = GAME_FS_LAUNCH + else: + x = FLIPS_lorigin[0] + PADDLE_width + xvel *= -1 + + + if x > FLIPS_rorigin[0] - PADDLE_width: + + print ("ball.y : ", y, " ry : ", ry) + + if y < (ry - BALL_SIZE_Y - 1) or y > (ry + PADDLE_height + 1): + lscore += 1 + xvel = random.uniform(1,0.6) + if lscore == 11: + fs = GAME_FS_MENU + else: + fs = GAME_FS_LAUNCH + else: + xvel *= -1 + x = FLIPS_rorigin[0] - PADDLE_width + + # wall detect + + if y < 0: + y = 1 + yvel *= -1 + + if y > screen_size[1]: + y = screen_size[1] - 1 + yvel *= -1 + + # Anim + + x += BALL_SPEED * xvel + y += BALL_SPEED * yvel + yvel += GRAVITY + entities.BallMove(x,y) + + if Nbpads > 0: + flipsy = entities.FlipsMove(joy1.getUp(),joy1.getDown(),joy2.getUp(),joy2.getDown()) + + else: + flipsy = entities.FlipsMove(keystates[pygame.K_a],keystates[pygame.K_q],keystates[pygame.K_UP],keystates[pygame.K_DOWN]) + + ly = flipsy[0] + ry = flipsy[1] + + + + elif fs == GAME_FS_LAUNCH: + + ''' + if Nbpads > 0: + print "pad 1 :", joy1.getUp(), joy1.getDown(), joy1.getLeftTrigger(),joy1.getRightTrigger() + print "pad 2 :", joy2.getUp(), joy2.getDown(), joy2.getLeftTrigger(),joy2.getRightTrigger() + print pad1.get_axis(0),pad2.get_axis(0) + ''' + + if keystates[pygame.K_ESCAPE] and not keystates_prev[pygame.K_ESCAPE]: + fs = GAME_FS_MENU + + if keystates[pygame.K_SPACE] and not keystates_prev[pygame.K_SPACE]: + fs = GAME_FS_PLAY + yvel = 0 + while math.fabs(xvel + yvel) < 1: + #xvel = random.uniform(-1,1) + yvel = random.uniform(-1,1) + + if joy1.getFire1() or joy2.getFire1(): + fs = GAME_FS_PLAY + yvel = 0 + while math.fabs(xvel + yvel) < 1: + #xvel = random.uniform(-1,1) + yvel = random.uniform(-1,1) + + x = ball_origin[0] + y = ball_origin[1] + entities.BallMove(x,y) + + if Nbpads > 0: + flipsy = entities.FlipsMove(joy1.getUp(),joy1.getDown(),joy2.getUp(),joy2.getDown()) + + else: + flipsy = entities.FlipsMove(keystates[pygame.K_a],keystates[pygame.K_q],keystates[pygame.K_UP],keystates[pygame.K_DOWN]) + ly = flipsy[0] + ry = flipsy[1] + + + + elif fs == GAME_FS_GAMEOVER: + + #TODO : MODE GAME OVER, autres opérations d'animation + # Remarque : on peut supprimer le mode GAME OVER et le gérer dans le mode jeu + # si les traitements sont les mêmes + ''' + if keystates[pygame.K_SPACE] and not keystates_prev[pygame.K_SPACE]: + StartPlaying(False) + ''' + + if joy1.getFire1() or joy2.getFire1(): + StartPlaying(False) + + elif keystates[pygame.K_ESCAPE] and not keystates_prev[pygame.K_ESCAPE]: + fs = GAME_FS_MENU + # Peut-être aussi réinitialiser l'état dans le mode menu + + + if fs == GAME_FS_PLAY or fs == GAME_FS_GAMEOVER or fs == GAME_FS_LAUNCH: + + entities.Score1Draw(lscore) + entities.Score2Draw(rscore) + entities.FlipsDraw() + entities.BallDraw() + entities.FiletDraw() + lj.DrawPL(0) + + if fs == GAME_FS_MENU: + + entities.LogoDraw() + lj.DrawPL(0) + + + # TODO : rendre indépendante la fréquence de rafraîchissement de l'écran par + # rapport à celle de l'animation du jeu + clock.tick(100) + +pygame.quit() + diff --git a/clients/games/ljpong/vectors.py b/clients/games/ljpong/vectors.py new file mode 100755 index 0000000..64efd3f --- /dev/null +++ b/clients/games/ljpong/vectors.py @@ -0,0 +1,76 @@ +# coding=UTF-8 +''' +Created on 13 nov. 2014 + +@author: pclf +''' +import math + +class Polar2D(object): + ''' + classdocs + ''' + + + def __init__(self, r, theta): + ''' + Constructor + ''' + self.r = r + self.theta = theta + + def Rotate(self, theta): + return Polar2D(self.r, self.theta + theta) + + def RotateSelf(self, theta): + self.theta += theta + + def Zoom(self, r): + return Polar2D(self.r * r, self.theta) + + def ZoomSelf(self, r): + self.r *= r + + def RotateZoom(self, r, theta): + return Polar2D(self.r * r, self.theta + theta) + + def RotateZoomSelf(self, r, theta): + self.r *= r + self.theta += theta + + def ToXY(self): + theta_rd = math.radians(self.theta) + return Vector2D(self.r * math.sin(theta_rd), - self.r * math.cos(theta_rd)) + +class Vector2D(object): + + def __init__(self, x, y): + self.x = x + self.y = y + + def __add__(self, other): + return Vector2D(self.x + other.x, self.y + other.y) + + def __sub__(self, other): + return Vector2D(self.x - other.x, self.y - other.y) + + # __iadd__ et __isub__ si nécessaire + + def __mul__(self, k): + return Vector2D(self.x * k, self.y * k) + + def __div__(self, k): + return Vector2D(self.x / k, self.y / k) + + def ScalarProduct(self, v): + return self.x*v.x + self.y*v.y + + def Det(self, v): + return self.x*v.y - self.y*v.x + + def MatrixProduct(self, vx, vy): + return Vector2D(self.ScalarProduct(vx),self.ScalarProduct(vy)) + + def ToTuple(self): + return (self.x,self.y) + \ No newline at end of file diff --git a/clients/laserglyph.py b/clients/laserglyph.py index e51b102..da9e9e1 100644 --- a/clients/laserglyph.py +++ b/clients/laserglyph.py @@ -1,19 +1,47 @@ # coding=UTF-8 ''' -Anaglyphed cube +Anaglyphed rotating cube (for red and green glasses) + +This client uses the drawing functions (polyline) provided by LJ in lj.py +You must check in lj.py if the redis server IP is correct. LICENCE : CC ''' import redis -import framy +import lj import math import time +import argparse -# IP defined in /etd/redis/redis.conf -redisIP = '127.0.0.1' -r = redis.StrictRedis(host=redisIP, port=6379, db=0) +print ("") +print ("Arguments parsing if needed...") +argsparser = argparse.ArgumentParser(description="Text Cycling for LJ") +argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str) +argsparser.add_argument("-c","--client",help="LJ client number (0 by default)",type=int) +argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int) + +args = argsparser.parse_args() + + +if args.client: + ljclient = args.client +else: + ljclient = 0 + +if args.laser: + plnumber = args.laser +else: + plnumber = 0 + +# Redis Computer IP +if args.redisIP != None: + redisIP = args.redisIP +else: + redisIP = '127.0.0.1' + +lj.Config(redisIP,ljclient) width = 800 @@ -21,18 +49,22 @@ height = 600 centerX = width / 2 centerY = height / 2 +# 3D to 2D projection parameters fov = 256 viewer_distance = 2.2 + +# Anaglyph computation parameters for right and left eyes. eye_spacing = 100 nadir = 0.5 observer_altitude = 30000 #observer_altitude = 10000 # elevation = z coordinate - -# 0.0 or -2000 pop out) +# 0.0, -2000 pop out map_plane_altitude = 0.0 +# Cube coordinates +# Define the vertices that compose each of the 6 faces. vertices = [ (- 1.0, 1.0,- 1.0), ( 1.0, 1.0,- 1.0), @@ -43,11 +75,10 @@ vertices = [ ( 1.0,- 1.0, 1.0), (- 1.0,- 1.0, 1.0) ] - -# Define the vertices that compose each of the 6 faces. These numbers are -# indices to the vertices list defined above. faces = [(0,1,2,3),(0,4,5,1),(1,5,6,2),(2,3,7,6),(6,5,4,7),(7,3,0,4)] + + def LeftShift(elevation): diff = elevation - map_plane_altitude @@ -93,17 +124,15 @@ def Proj(x,y,z,angleX,angleY,angleZ): y = - y * factor + centerY return (x,y) +def Run(): -def Draw2PL(): - - Shape = [] Left = [] Right = [] counter =0 while 1: - Shape = [] + Left = [] Right = [] @@ -111,101 +140,44 @@ def Draw2PL(): y = vertices[0][1] z = vertices[0][2] - Left.append( Proj(x+LeftShift(z*5),y,z,0,0,counter)) - Right.append(Proj(x+RightShift(z*5),y,z,0,0,counter)) - - #framy.PolyLineOneColor(Shape, c = white, PL = 0, closed = False) - framy.PolyLineOneColor(Left, c = red, PL = 1, closed = False) - framy.PolyLineOneColor(Right, c = green, PL = 2, closed = False) - - for fa in faces: - #print "" - #print "face",fa - - for point in fa: - #print "" - #print "point ", point - x = vertices[point][0] - y = vertices[point][1] - z = vertices[point][2] - #print x,y,z - #print "left",x+LeftShift(z*25),y,z, Proj(x+LeftShift(z*25),y,z) - #print "right",x+RightShift(z*25),y,z, Proj(x+RightShift(z*25),y,z) - - - #Shape.append(Proj(x,y,z,0,0,counter)) - Left.append( Proj(x+LeftShift(z*5),y,z,0,0,counter)) - Right.append(Proj(x+RightShift(z*5),y,z,0,0,counter)) - - #framy.PolyLineOneColor(Shape, c = white, PL = 0, closed = False) - framy.PolyLineOneColor(Left, c = red, PL = 1, closed = False) - framy.PolyLineOneColor(Right, c = green, PL = 2, closed = False) - ''' - framy.rPolyLineOneColor(Shape, c = white, PL = 0, closed = False, xpos = 200, ypos = 250, resize = 1, rotx =0, roty =0 , rotz=0) - framy.rPolyLineOneColor(Left, c = red, PL = 1, closed = False, xpos = 200, ypos = 250, resize = 1, rotx =0, roty =0 , rotz=0) - framy.rPolyLineOneColor(Right, c = blue, PL = 2, closed = False, xpos = 200, ypos = 250, resize = 1, rotx =0, roty =0 , rotz=0) - ''' - #counter += 1 - #if counter >360: - # counter =0 - - -def Draw1PL(): - - Shape = [] - Left = [] - Right = [] - counter =0 - - while 1: - #Shape = [] - Left = [] - Right = [] - - # Polyline will "move" the laser to this first point in black, then move to the next with second point color. + # The cube start always with vertice 0 + # LJ tracers will "move" the laser to this first point in black, then move to the next with second point color. # For more accuracy in dac emulator, repeat this first point. - # Here the cube start always with vertice 0 - x = vertices[0][0] - y = vertices[0][1] - z = vertices[0][2] + # Cube Y axis rotation of 'counter' angle and 3d-2d Proj function. + #Left.append( Proj(x+LeftShift(z*5),y,z,0,counter,0)) + #Right.append(Proj(x+RightShift(z*5),y,z,0,counter,0)) - Left.append( Proj(x+LeftShift(z*5),y,z,0,counter,0)) - Right.append(Proj(x+RightShift(z*5),y,z,0,counter,0)) - + + # Add all the cube points face by face. for fa in faces: - #print "" - #print "face",fa - for point in fa: - #print "" - #print "point ", point x = vertices[point][0] y = vertices[point][1] z = vertices[point][2] - #print x,y,z,counter - #if point == 0: - # print Proj(x+LeftShift(z*5),y,z,0,0,counter) - #print "left", Proj(x+LeftShift(z*25),y,z,0,counter,0) - #print "right",x+RightShift(z*25),y,z, Proj(x+RightShift(z*25),y,z) - - #Shape.append(Proj(x,y,z,0,0,counter)) Left.append( Proj(x+LeftShift(z*25),y,z,0,counter,0)) Right.append(Proj(x+RightShift(z*25),y,z,0,counter,0)) - #framy.PolyLineOneColor(Shape, c = white, PL = 0, closed = False) - #print Left - framy.PolyLineOneColor(Left, c = red, PL = 0, closed = True) - framy.PolyLineOneColor(Right, c = green, PL = 0, closed = True) + + # Drawing step, 2 possibilities + + # Red and Green drawn by laser 0 + lj.PolyLineOneColor(Left, c = red, PL = 0, closed = True) + lj.PolyLineOneColor(Right, c = green, PL = 0, closed = True) + lj.DrawPL(0) ''' - framy.rPolyLineOneColor(Shape, c = white, PL = 0, closed = False, xpos = 200, ypos = 250, resize = 1, rotx =0, roty =0 , rotz=0) - framy.rPolyLineOneColor(Left, c = red, PL = 1, closed = False, xpos = 200, ypos = 250, resize = 1, rotx =0, roty =0 , rotz=0) - framy.rPolyLineOneColor(Right, c = blue, PL = 2, closed = False, xpos = 200, ypos = 250, resize = 1, rotx =0, roty =0 , rotz=0) + # Red on laser 1 and green on laser 2 + lj.PolyLineOneColor(Left, c = red, PL = 1, closed = True) + lj.PolyLineOneColor(Right, c = green, PL = 2, closed = True) + lj.DrawPL(1) + lj.DrawPL(2) + ''' - framy.LinesPL(0) + time.sleep(0.1) + counter += 1 if counter >360: counter =0 @@ -216,20 +188,4 @@ blue = rgb2int(0,0,255) green = rgb2int(0,255,0) -Draw1PL() - #r.set('/pl/0/0', str(pl0)) -# S = (e / 2) (d - p) / (a - d) - - -''' -# /pl/clientnumber/lasernumber pointlist - -# Consider you're client 0 -# Send to laser 0 (see mainy.conf) -r.set('/pl/0/0', str(pl0)) - -# Send to laser 1 (see mainy.conf) -r.set('/pl/0/1', str(pl1)) -# Send to laser 2 (see mainy.conf) -r.set('/pl/0/2', str(pl1)) -''' +Run() diff --git a/clients/lj.py b/clients/lj.py new file mode 100644 index 0000000..37c8900 --- /dev/null +++ b/clients/lj.py @@ -0,0 +1,314 @@ +# coding=UTF-8 + +''' +LJ v0.8.1 +Some LJ functions useful for python clients (was framy.py) + +Config(redisIP, client number) +PolyLineOneColor +rPolyLineOneColor + +Text(word, color, PL, xpos, ypos, resize, rotx, roty, rotz) : Display a word +Send(adress,message) : remote control. See commands.py +WebStatus(message) : display message on webui +DrawPL(point list number) : once you stacked all wanted elements, like 2 polylines, send them to lasers. + +LICENCE : CC +Sam Neurohack + +''' + +import math +import redis +from OSC import OSCServer, OSCClient, OSCMessage + +redisIP = '127.0.0.1' +r = redis.StrictRedis(host=redisIP, port=6379, db=0) + +ClientNumber = 0 + +point_list = [] +pl = [[],[],[],[]] + + +''' +LJIP = "127.0.0.1" + +osclientlj = OSCClient() +oscmsg = OSCMessage() +osclientlj.connect((redisIP, 8002)) +''' + +def Send(oscaddress,oscargs=''): + + oscmsg = OSCMessage() + oscmsg.setAddress(oscaddress) + oscmsg.append(oscargs) + + #print ("sending to bhorosc : ",oscmsg) + try: + osclientlj.sendto(oscmsg, (redisIP, 8002)) + oscmsg.clearData() + except: + print ('Connection to LJ refused : died ?') + pass + #time.sleep(0.001 + + +def WebStatus(message): + Send("/status",message) + + + +ASCII_GRAPHICS = [ + +#implementé + + [(-50,30), (-30,-30), (30,-30), (10,30), (-50,30)], #0 + [(-20,30), (0,-30), (-20,30)], #1 + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #2 + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #3 + [(30,10), (-30,10), (0,-30), (0,30)], #4 + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #5 + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #6 + [(-30,-30), (30,-30), (-30,30)], #7 + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], #8 + [(30,0), (-30,0), (-30,-10), (0,-30), (30,-30), (30,10), (0,30), (-30,30)], #9 + +# A implementer + [(-30,10), (30,-10), (30,10), (0,30), (-30,10), (-30,-10), (0,-30), (30,-10)], #: + [(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], #; + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #< + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #= + [(30,10), (-30,10), (0,-30), (0,30)], #> + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #? + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #@ + +# Implementé + + + [(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A + [(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], #B + [(30,30), (-30,30), (-30,-30), (30,-30)], #C + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], #D + [(30,30), (-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], #E + [(-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], #F + [(0,0), (30,0), (30,30), (-30,30), (-30,-30),(30,-30)], #G + [(-30,-30), (-30,30), (-30,0), (30,0), (30,30), (30,-30)], #H + [(0,30), (0,-30)], #I + [(-30,30), (0,-30), (0,-30), (-30,-30), (30,-30)], #J + [(-30,-30), (-30,30), (-30,0), (30,-30), (-30,0), (30,30)], #K + [(30,30), (-30,30), (-30,-30)], #L + [(-30,30), (-30,-30), (0,0), (30,-30), (30,30)], #M + [(-30,30), (-30,-30), (30,30), (30,-30)], #N + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], #O + [(-30,0), (30,0), (30,-30), (-30,-30), (-30,30)], #P + [(30,30), (30,-30), (-30,-30), (-30,30), (30,30),(35,35)], #Q + [(-30,30), (-30,-30), (30,-30), (30,0), (-30,0), (30,30)], #R + [(30,-30), (-30,-30), (-30,0), (30,0), (30,30), (-30,30)], #S + [(0,30), (0,-30), (-30,-30), (30,-30)], #T + [(-30,-30), (-30,30), (30,30), (30,-30)], #U + [(-30,-30), (0,30), (30,-30)], #V + [(-30,-30), (-30,30), (0,0), (30,30), (30,-30)], #W + [(-30,30), (30,-30)], [(-30,-30), (30,30)], #X + [(0,30), (0,0), (30,-30), (0,0), (-30,-30)], #Y + [(30,30), (-30,30), (30,-30), (-30,-30)], #Z + + # A implementer + + [(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], #[ + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #\ + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #] + [(30,10), (-30,10), (0,-30), (0,30)], #^ + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #_ + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #` + + # Implementé + + [(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], #a + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20), (-20,0), (20,0)], #b + [(20,20), (-20,20), (-20,-20), (20,-20)], #c + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], #d + [(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], #e + [(-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], #f + [(0,0), (20,0), (20,20), (-20,20), (-20,-20),(20,-20)], #g + [(-20,-20), (-20,20), (-20,0), (20,0), (20,20), (20,-20)], #H + [(0,20), (0,-20)], #I + [(-20,20), (0,-20), (0,-20), (-20,-20), (20,-20)], #J + [(-20,-20), (-20,20), (-20,0), (20,-20), (-20,0), (20,20)], #K + [(20,20), (-20,20), (-20,-20)], #L + [(-20,20), (-20,-20), (0,0), (20,-20), (20,20)], #M + [(-20,20), (-20,-20), (20,20), (20,-20)], #N + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], #O + [(-20,0), (20,0), (20,-20), (-20,-20), (-20,20)], #P + [(20,20), (20,-20), (-20,-20), (-20,20), (20,20),(25,25)], #Q + [(-20,20), (-20,-20), (20,-20), (20,0), (-20,0), (20,20)], #R + [(20,-20), (-20,-20), (-20,0), (20,0), (20,20), (-20,20)], #S + [(0,20), (0,-20), (-20,-20), (20,-20)], #T + [(-20,-20), (-20,20), (20,20), (20,-20)], #U + [(-20,-20), (0,20), (20,-20)], #V + [(-20,-20), (-20,20), (0,0), (20,20), (20,-20)], #W + [(-20,20), (20,-20)], [(-20,-20), (20,20)], #X + [(0,20), (0,0), (20,-20), (0,0), (-20,-20)], #Y + [(20,20), (-20,20), (20,-20), (-20,-20)], #Z + + [(-2,15), (2,15)] # Point a la place de { +] + +def Config(redisIP,client): + global ClientNumber + + r = redis.StrictRedis(host=redisIP, port=6379, db=0) + ClientNumber = client + + +def LineTo(xy, c, PL): + + pl[PL].append((xy + (c,))) + +def Line(xy1, xy2, c, PL): + LineTo(xy1, 0, PL) + LineTo(xy2, c , PL) + + +def PolyLineOneColor(xy_list, c, PL , closed ): + #print "--" + #print "c",c + #print "xy_list",xy_list + #print "--" + xy0 = None + for xy in xy_list: + if xy0 is None: + xy0 = xy + #print "xy0:",xy0 + LineTo(xy0,0, PL) + LineTo(xy0,c, PL) + else: + #print "xy:",xy + LineTo(xy,c, PL) + if closed: + LineTo(xy0,c, PL) + + +# Computing points coordinates for rPolyline function from 3D and around 0,0 to pygame coordinates +def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): + + x = xy[0] * resize + y = xy[1] * resize + z = 0 + + rad = rotx * math.pi / 180 + cosaX = math.cos(rad) + sinaX = math.sin(rad) + + y2 = y + y = y2 * cosaX - z * sinaX + z = y2 * sinaX + z * cosaX + + rad = roty * math.pi / 180 + cosaY = math.cos(rad) + sinaY = math.sin(rad) + + z2 = z + z = z2 * cosaY - x * sinaY + x = z2 * sinaY + x * cosaY + + rad = rotz * math.pi / 180 + cosZ = math.cos(rad) + sinZ = math.sin(rad) + + x2 = x + x = x2 * cosZ - y * sinZ + y = x2 * sinZ + y * cosZ + + #print xy, (x + xpos,y+ ypos) + return (x + xpos,y+ ypos) + ''' + to understand why it get negative Y + + # 3D to 2D projection + factor = 4 * gstt.cc[22] / ((gstt.cc[21] * 8) + z) + print xy, (x * factor + xpos, - y * factor + ypos ) + return (x * factor + xpos, - y * factor + ypos ) + ''' + +# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos +#def rPolyLineOneColor(self, xy_list, c, PL , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): +def rPolyLineOneColor(xy_list, c, PL , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0): + xy0 = None + for xy in xy_list: + if xy0 is None: + xy0 = xy + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),0, PL) + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL) + else: + LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz),c, PL) + if closed: + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL) + + +def LinesPL(PL): + print "Stupido !! your code is to old : use DrawPL() instead of LinesPL()" + DrawPL(PL) + +def DrawPL(PL): + #print '/pl/0/'+str(PL), str(pl[PL]) + if r.set('/pl/'+str(ClientNumber)+'/'+str(PL), str(pl[PL])) == True: + pl[PL] = [] + return True + else: + return False + +def ResetPL(self, PL): + pl[PL] = [] + + + +def DigitsDots(number,color): + dots =[] + for dot in ASCII_GRAPHICS[number]: + #print dot + dots.append((gstt.xy_center[0]+dot[0],gstt.xy_center[1]+dot[1],color)) + #self.point_list.append((xy + (c,))) + return dots + +def CharDots(char,color): + + dots =[] + for dot in ASCII_GRAPHICS[ord(char)-46]: + dots.append((dot[0],dot[1],color)) + return dots + +def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz): + + dots =[] + + l = len(message) + i= 0 + #print message + + for ch in message: + + #print "" + # texte centre en x automatiquement selon le nombre de lettres l + x_offset = 26 * (- (0.9*l) + 3*i) + #print i,x_offset + if ord(ch)<58: + char_pl_list = ASCII_GRAPHICS[ord(ch) - 48] + else: + char_pl_list = ASCII_GRAPHICS[ord(ch) - 46] + + char_draw = [] + #dots.append((char_pl_list[0][0] + x_offset,char_pl_list[0][1],0)) + + for xy in char_pl_list: + char_draw.append((xy[0] + x_offset,xy[1],c)) + i +=1 + #print ch,char_pl_list,char_draw + rPolyLineOneColor(char_draw, c, PL , False, xpos, ypos, resize, rotx, roty, rotz) + #dots.append(char_draw) + + + + \ No newline at end of file diff --git a/clients/ljremote.py b/clients/ljremote.py new file mode 100644 index 0000000..6cf0905 --- /dev/null +++ b/clients/ljremote.py @@ -0,0 +1,44 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- +''' + +LJ Remote control via OSC in python + +This is different than sending pointlist to draw. See pyclient or laserglyph for that. +Say your client want to display some information on the weUI status field or remote control any other LJ functions. + +See commands.py for LJ functions list. +See Doctodo for all webUI elements. + +LJ OSC server is listening on port 8002, talk to it. + +''' +from OSC import OSCServer, OSCClient, OSCMessage + +LJIP = "127.0.0.1" + +osclientlj = OSCClient() +oscmsg = OSCMessage() +osclientlj.connect((LJIP, 8002)) + +def sendlj(oscaddress,oscargs=''): + + oscmsg = OSCMessage() + oscmsg.setAddress(oscaddress) + oscmsg.append(oscargs) + + #print ("sending to bhorosc : ",oscmsg) + try: + osclientlj.sendto(oscmsg, (LJIP, 8002)) + oscmsg.clearData() + except: + print ('Connection to LJ refused : died ?') + pass + #time.sleep(0.001) + +# display pouet in status display +sendlj("/status","pouet") + +# switch laser 0 ack led to green +sendlj("/lack/0", 1) \ No newline at end of file diff --git a/clients/pyclient.py b/clients/pyclient.py index b9481f8..c85c5f4 100644 --- a/clients/pyclient.py +++ b/clients/pyclient.py @@ -1,7 +1,9 @@ # coding=UTF-8 ''' -Multi Laser client example +Multi Laser client example with direct send of point lists to redis server. + +Remember : LJ will automatically warp geometry according to alignement data. See webUI. LICENCE : CC ''' @@ -29,32 +31,11 @@ pl1 = [(100,300,rgb2int(255,255,255)),(200,300,rgb2int(255,255,255)),(200,200,r # /pl/clientnumber/lasernumber pointlist # Consider you're client 0 -# Send to laser 0 (see mainy.conf) +# Send to laser 0 (see LJ.conf) r.set('/pl/0/0', str(pl0)) -# Send to laser 1 (see mainy.conf) +# Send to laser 1 (see LJ.conf) r.set('/pl/0/1', str(pl1)) -# Send to laser 2 (see mainy.conf) +# Send to laser 2 (see LJ.conf) r.set('/pl/0/2', str(pl1)) -''' -You can also use PolyLineOneColor or rPolylineOneColor to stack n point lists to build a "frame" - -import framy - -# for laser0 : - -pl0 = [(100,300),(200,300),(200,200),(100,200)] -framy.PolyLineOneColor(pl0, rgb2int(255,255,255), 0 , closed = False) -# You can add as much polylineOneColor as you want = construct a "frame" -# Then send it to the laser server : -print "All one color lines sent to laser 0 :",framy.LinesPL(0) # Will be True is sent correctly - -# instead of PolyLineOneColor you can use rPolylineOneColor to send 2D point list around 0,0 with 3D rotation,resizing and repositioning at xpos ypos -# rPolylineOneColor is very useful to add different polylines to different position. Imagine different game elements. -# rPolyLineOneColor(xy_list, c, PL , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): -# Send the pl0 to laser 1 - -framy.rPolyLineOneColor((pl0, c = rgb2int(255,255,255), PL = 1, closed = False, xpos = 200, ypos = 250, resize = 1, rotx =0, roty =0 , rotz=0) -print "All one color lines sent to laser 1 :",framy.LinesPL(1) # Will be True is sent correctly -''' \ No newline at end of file diff --git a/clients/rebclient.r b/clients/rebclient.r deleted file mode 100644 index 881e137..0000000 --- a/clients/rebclient.r +++ /dev/null @@ -1,39 +0,0 @@ -REBOL [] - -outport: open/lines tcp://localhost:13857 -on: 1 -off: 0 - -pl0: "[(100,200, 0), (100,300, 65280), (200,300, 65280), (200,200, 65280), (100,200, 65280)]" - - -oscommand: to-string reduce ["pl/0 " pl0] -insert outport oscommand - -for counter 1 2 1 [ - ;; print counter - oscommand: to-string reduce ["/40h/clear " on] - insert outport oscommand - wait 0.3 - -] - -for counter 1 2 1 [ - for raw 0 7 1 [ - oscommand: to-string reduce ["/40h/led_row " raw " " on] - insert outport oscommand - wait 0.001 - ] - -] - -for counter 1 2 1 [ - ;; print counter - oscommand: to-string reduce ["/40h/frame 0 126 126 126 126 126 126 0"] - insert outport oscommand - - wait 0.3 - -] - -close outport \ No newline at end of file diff --git a/clients/rebserver.py b/clients/rebserver.py deleted file mode 100644 index bf92910..0000000 --- a/clients/rebserver.py +++ /dev/null @@ -1,47 +0,0 @@ - -#!/usr/bin/env python -# coding=UTF-8 -""" - -TCP server for rebol links like from Amiga -Forward /pl/lasernumber pointslist to redis server - - -by Sam Neurohack -from /team/laser - -""" - -import socket, time,random, redis - - -r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0) - - - -# TCP listener - -TCP_IP = '127.0.0.1' -TCP_PORT = 13857 -BUFFER_SIZE = 1024 # Normally 1024, but we want fast response - -s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -s.bind((TCP_IP, TCP_PORT)) -s.listen(1) -conn, addr = s.accept() -print 'Connection address:', addr - - -while 1: - data = conn.recv(BUFFER_SIZE) - if not data: break - #print "received data:", data - commands = data.split() - nb_oscargs = len(commands) - print commands - - #r.set('/pl/'+str(PL), str(something to code with commands, nb_oscargs)) - #conn.send(data) # echo - - -conn.close() \ No newline at end of file diff --git a/clients/redclient.red b/clients/redclient.red deleted file mode 100644 index 40056cf..0000000 --- a/clients/redclient.red +++ /dev/null @@ -1,8 +0,0 @@ -Red [] - - -#https://github.com/red/red/wiki/[DOC]-Guru-Meditations#how-to-make-http-requests - -pl0: "[(100,200, 0), (100,300, 65280), (200,300, 65280), (200,200, 65280), (100,200, 65280)]" - -read http://127.0.0.1:13857/path?name="jones" \ No newline at end of file diff --git a/clients/redserver.py b/clients/redserver.py deleted file mode 100644 index 8bc226e..0000000 --- a/clients/redserver.py +++ /dev/null @@ -1,57 +0,0 @@ - -#!/usr/bin/env python -# coding=UTF-8 -""" - -Http server for red 0.6.4 -Forward /pl/lasernumber pointslist to redis server - -by Sam Neurohack -from /team/laser - -""" - - -import redis - -r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0) - -from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer - -PORT_NUMBER = 8080 - -#This class will handles any incoming request from -#the browser -class myHandler(BaseHTTPRequestHandler): - - #Handler for the GET requests - def do_GET(self): - self.send_response(200) - self.send_header('Content-type','text/html') - self.end_headers() - - # Send the html message - self.wfile.write("Hello World !") - - # r.set('/pl/'+str(PL), str(self.grid_points)) - - return - -try: - #Create a web server and define the handler to manage the - #incoming request - server = HTTPServer(('', PORT_NUMBER), myHandler) - print 'Started httpserver on port ' , PORT_NUMBER - - #Wait forever for incoming htto requests - server.serve_forever() - -except KeyboardInterrupt: - print '^C received, shutting down the web server' -server.socket.close() - - - - - - diff --git a/gstt.py b/gstt.py index b2d7629..52868dc 100644 --- a/gstt.py +++ b/gstt.py @@ -17,7 +17,7 @@ from /team/laser #ConfigName = "setexample.conf" ConfigName = "LJ.conf" -debug = 2 +debug = 0 anims= [[],[],[],[]] @@ -28,7 +28,7 @@ LaserNumber = 2 LasClientNumber = 0 MaxLasClient = 3 -screen_size = [800,600] +screen_size = [400,400] xy_center = [screen_size[0]/2,screen_size[1]/2] LjayServerIP = '192.168.1.13' diff --git a/homographyp.py b/homographyp.py index d2a8f61..5552c5f 100755 --- a/homographyp.py +++ b/homographyp.py @@ -170,7 +170,7 @@ def EDpoint(mylaser,(pygamex,pygamey)): YY = pygamey - gstt.xy_center[1] CosANGLE = math.cos(gstt.finANGLE[mylaser]) SinANGLE = math.sin(gstt.finANGLE[mylaser]) - # Multilaser style + x = (gstt.xy_center[0] + ((XX * CosANGLE) - (YY * SinANGLE)) - gstt.xy_center[0]) * gstt.zoomX[mylaser] + gstt.centerX[mylaser] y = (gstt.xy_center[1] + ((XX * SinANGLE) + (YY * CosANGLE)) - gstt.xy_center[1]) * gstt.zoomY[mylaser] + gstt.centerY[mylaser] diff --git a/main.py b/main.py index b5b0c49..dcb1987 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,6 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- ''' LJ Laser Server v0.8 @@ -91,23 +94,23 @@ print "Lasers requested :", gstt.LaserNumber wsPORT = 9001 # With Bhorosc -# OSC Server : relay OSC message from Bhorosc outport 8002 to UI +# OSC Server : accept OSC message on port 8002 #oscIPin = "192.168.1.10"s bhoroscIPin = serverIP bhoroscPORTin = 8002 -# OSC Client : relay message from UI to Bhorosc inport 8001 +# OSC Client : to send OSC message to an IP port 8001 bhoroscIPout = bhoroscIP bhoroscPORTout = 8001 -# With Nozosc -# OSC Client : relay message from UI to Nozosc inport 8003 +# With Nozoid +# OSC Client : to send OSC message to Nozoid inport 8003 NozoscIPout = nozoscIP NozoscPORTout = 8003 +#print bhoroscIPin -print bhoroscIPin oscserver = OSCServer( (bhoroscIPin, bhoroscPORTin) ) oscserver.timeout = 0 OSCRunning = True @@ -164,7 +167,7 @@ def sendnozosc(oscaddress,oscargs=''): #time.sleep(0.001) -# OSC default path handler : send OSC message from Bhorosc 8002 to UI via websocket 9001 +# OSC default path handler : send incoming OSC message to UI via websocket 9001 def handler(path, tags, args, source): oscpath = path.split("/") @@ -190,7 +193,7 @@ def osc_frame(): -# OSC Thread. OSC handler and Automated status sender to UI. +# OSC server Thread : handler, dacs reports and simulator points sender to UI. def osc_thread(): while True: @@ -233,6 +236,7 @@ def osc_thread(): sendWSall("/points/" + str(laserid) + " " + str(r.get('/cap/'+str(laserid)))) #print "Sending simu frame from",'/pl/'+str(gstt.LasClientNumber)+'/'+str(gstt.Laser) + #print r.get('/pl/'+str(gstt.LasClientNumber)+'/'+str(gstt.Laser)) sendWSall("/simul" +" "+ r.get('/pl/'+str(gstt.LasClientNumber)+'/'+str(gstt.Laser))) diff --git a/tracer.py b/tracer.py index 0f16057..5088adf 100644 --- a/tracer.py +++ b/tracer.py @@ -31,6 +31,8 @@ Etherdream status reports in redis keys: Geometric corrections : +Doctodo + ''' import socket diff --git a/visualiser-linux b/visualiser-linux new file mode 100755 index 0000000..6530ef0 Binary files /dev/null and b/visualiser-linux differ diff --git a/webui/ljaygrid.css b/webui/LJgrid.css similarity index 100% rename from webui/ljaygrid.css rename to webui/LJgrid.css diff --git a/webui/index.html b/webui/index.html index 669fae2..ef12264 100644 --- a/webui/index.html +++ b/webui/index.html @@ -18,7 +18,7 @@ } - + @@ -549,10 +549,39 @@ // Store Reference To The Canvas & Set Context var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); - var lastpoint = { x: 0, y: 0, color: 0}; - ctx.clearRect(0,0,400,400); - //ctx.save + var lastpoint = { x: 0, y: 0, color: 0}; + ctx.clearRect(0,0,400,400); + var zoom = 0.5; + var mousePosDown = { x: 0, y: 0}; + var mousePosUp = { x: 0, y: 0 }; + var mouseMsgDown = ''; + var mouseMsgUp = ''; + //ctx.save + canvas.addEventListener("mouseup", MouseUp, false); + canvas.addEventListener("mousedown", MouseDown, false); + + function getMousePos(canvas,evt) + { + var rect = canvas.getBoundingClientRect(); + return { x: evt.clientX - rect.left, y: evt.clientY - rect.top }; + } + + function MouseDown(evt) + { + mousePosDown = getMousePos(canvas, evt); + mouseMsgDown = mousePosDown.x + ' ' + mousePosDown.y; + _WS.showin(mouseMsgDown); + } + + function MouseUp(evt) + { + mousePosUp = getMousePos(canvas, evt); + mouseMsgUp = mousePosUp.x + ' ' + mousePosUp.y; + _WS.showin(mouseMsgUp); + _WS.s.send('/mouse '+mouseMsgDown+' '+mouseMsgUp); + _WS.showin('/mouse '+mouseMsgDown+' '+mouseMsgUp); + } // Todo : laser point will have black points to go from a polyline to another. Need to discard those black points. function draw() { @@ -568,7 +597,7 @@ ctx.clearRect(0,0,400,400); ctx.beginPath(); - ctx.moveTo(pl2[0]*0.5, pl2[1]*0.5); + ctx.moveTo(pl2[0]*zoom, pl2[1]*zoom); lastpoint.color = pl2[2]; // Draw n Lines @@ -578,7 +607,7 @@ // New point has the same color -> add a new line to the new point if (pl2[2+(i*3)] === lastpoint.color) { - ctx.lineTo(pl2[i*3]*0.5, pl2[1+(i*3)]*0.5); + ctx.lineTo(pl2[i*3]*zoom, pl2[1+(i*3)]*zoom); } // New point has different color -> stroke with previous color @@ -591,13 +620,13 @@ ctx.beginPath(); //ctx.clearRect(0,0,400,400); - ctx.moveTo(pl2[i*3]*0.5, pl2[1+(i*3)]*0.5); + ctx.moveTo(pl2[i*3]*zoom, pl2[1+(i*3)]*zoom); } // Last point -> stroke with current color if (i === (pl2.length/3)-1 ) { - ctx.moveTo(pl2[i*3]*0.5, pl2[1+(i*3)]*0.5); + ctx.moveTo(pl2[i*3]*zoom, pl2[1+(i*3)]*zoom); ctx.strokeStyle = "#"+((pl2[2+(i*3)]) + Math.pow(16, 6)).toString(16).slice(-6); ctx.stroke();