diff --git a/clitools/README.md b/clitools/README.md new file mode 100644 index 0000000..34a6c3b --- /dev/null +++ b/clitools/README.md @@ -0,0 +1,70 @@ +# Chaining Lasers In Submission Tools for LJ + +Alright everybody, ready for some fun? Here comes The Piping And Plumbing Your Way To The Top Show! + +You're going to push so many points to this laser it will hog and cry... + +BOOM | WIIIIIZ :: PHHHHHRACKRACKRACK ~~ WOOP ~~###~~ WIIT + + +## The basic loop +``` +python3 generators/dummy.py -f 2 | filters/kaleidoscope.py | exports/toRedis.py -v + ------------------------------ --------------------- ------------------- + \/ \/ \/ + Generator Filter Export +``` + +1. The Generator + +Use it to produce some points in any manner, orderly or total chaos. + +Don't be that boring Sinusoids bugger! Flash Maps of Dooms, Disbitnic sprites, Dismorphic HexaFonts all over the walls! + +2. The Filter(s) + +These babies will modify data on the wire by passing around the points and modifying them in sequence. + +Want your Double Heavy Laser Cannons to bounce together like they been drinking Jagerbombs for two hours? That's the place. + +3. The Exporter + +Now, this IS the most boring part. Send your points to whatever output system. Yawn. Are we there yet? + +## Hacking around + +Say what!? Why, this is exactly the place for that! + +Take a seat and copy paste the "dummy.py" files, they present the basic structure you need to play around. + +Just be cautious to use the `debug` method if you're the kind of miss that debugs by outputing data structures (who does not, yah know, sometimes?). Or you'll break the chain. + +### Generators + +They must send list of points to standard out. Don't forget the "flush" argument, or the piping will be breaking, ain't no Mario lazering. + +* dummy.py : sends always the same list of points. The Monomaniac. +* @todo : read texts from redis and others + +### Filters + +These do listen and read on STDIN and do the same print'n'flush on STDOUT. + +* kaleidoscope.py : mirrors the points based on a pivot +* @todo : fourier analysis and other realtime reaction + +### Export + +Read from STDIN and send to redis mostly + +* toRedis.py : provide a key, server IP, etc. + +### Common parameters + +Every command can be called with a `-h/--help` flag to get some help + +Every command has a `-v/--verbose` flag to send debug info to STDERR. + +Generators have a `-f/--fps` param for FPS, to be fast but not so furious on your machine + +Filters and Exports are their own beasts diff --git a/clitools/exports/toRedis.py b/clitools/exports/toRedis.py new file mode 100755 index 0000000..a42ac55 --- /dev/null +++ b/clitools/exports/toRedis.py @@ -0,0 +1,55 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- + + +''' + +redis exporter +v0.1.0 + +A basic exporter + +LICENCE : CC + +by cocoa + + +''' +from __future__ import print_function +import sys +import os +import argparse +import redis +import time + +argsparser = argparse.ArgumentParser(description="Redis exporter LJ") +argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str) +argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str) +argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=int) +argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose") +args = argsparser.parse_args() + +ip = args.ip +port = args.port +key = args.key +verbose=args.verbose + +def debug(*args, **kwargs): + if( verbose == False ): + return + print(*args, file=sys.stderr, **kwargs) + +r=redis.StrictRedis(host=ip, port=port, db=0) + +try: + while True: + line = sys.stdin.readline() + if line == "": + time.sleep(0.01) + line = line.rstrip('\n') + if r.set(key,line)==True: + debug("exports::redis set("+str(key)+") to "+line) +except EOFError: + debug("break")# no more information + diff --git a/clitools/filters/kaleidoscope.py b/clitools/filters/kaleidoscope.py new file mode 100755 index 0000000..52e6a2b --- /dev/null +++ b/clitools/filters/kaleidoscope.py @@ -0,0 +1,161 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- + + +''' + +kaleidoscop +v0.1.0 + +A simple effect : mirror a quadrant of the input + +LICENCE : CC + +by Sam Neurohack + + +''' +from __future__ import print_function +import sys +import ast +import os +import argparse +ljpath = r'%s' % os.getcwd().replace('\\','/') +sys.path.append(ljpath +'/../libs/') +sys.path.append(ljpath +'/libs/') + +import time +name = "filters::kaleidoscope" + +argsparser = argparse.ArgumentParser(description="Redis exporter LJ") +argsparser.add_argument("-x","--centerX",help="geometrical center X position",default=300,type=int) +argsparser.add_argument("-y","--centerY",help="geometrical center Y position",default=300,type=int) +argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int) +argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose") + +args = argsparser.parse_args() +fps = args.fps +centerX = args.centerX +centerY = args.centerY +verbose = args.verbose + +optimal_looptime = 1 / fps + +def debug(*args, **kwargs): + if( verbose == False ): + return + print(*args, file=sys.stderr, **kwargs) + +def kaleidoscope( pl ): + + # Stage 1: Crop points in single quadrant + quad1 = [] + # Iterate trough the segments + for i in range( 0, len(pl) - 1 ): + #debug(name+" point #", i) + currentpoint = cp = pl[i] + nextpoint = pl[i+1] + cx,cy,cc = [cp[0],cp[1],cp[2]] + nx,ny,nc = [nextpoint[0],nextpoint[1],nextpoint[2]] + rect=[[cx,cy],[cx,ny],[nx,ny],[nx,cy]] + + right = wrong = 0 + #debug(name+" rect: ", rect,"curr",currentpoint,"next",nextpoint ) + + # Enumerate the points in rectangle to see + # how many right / wrong there are to add or skip early + # + for iterator, p in enumerate(rect): + if p[0] >= centerX and p[1] >= centerY: + right += 1 + else: + #if p[0] <= centerX and p[1] <= centerY: + wrong += 1 + # If all rectangle points are in the right quadrant, Add and Skip + if right == 4: + quad1.append(pl[i]) + #debug(name+" found valid point", pl[i]) + continue + # If all rectangle points in wrong quadrant, Skip + if wrong == 4: + #debug(name+" found bad point", pl[i]) + continue + + # Find the (x,y) intersections + # + #debug(name+" Looking for crossing point between ("+str(cx)+","+str(cy)+") and ("+str(nx)+","+str(ny)+")") + delta=[ nx - cx, ny - cy ] + #debug(name+" delta:",delta) + crossX = None + crossY = None + absnewX = 0 + absnewY = 0 + # If one point has negative x, search y axis crossing + if cx < centerX or nx < centerX: + if delta[0] == 0 : + delta[0] = 0.0000001 + v=[ delta[0]/abs(delta[0]), delta[1]/abs(delta[0]) ] + absnewX = abs( centerX - cx ) + #print("on y axis, v=",str(v)," and absnewX=",str(absnewX)) + crossX = [( absnewX*v[0] + cx ),( absnewX*v[1]+cy ), nc] + # If one point has negative y, search x axis crossing + if cy < centerY or ny < centerY: + if delta[1] == 0 : + delta[1] = 0.0000001 + v=[ delta[0]/abs(delta[1]), delta[1]/abs(delta[1])] + absnewY = abs( centerY - cy ) + #print("on x axis, v=",str(v)," and absnewY=",str(absnewY)) + crossY = [( absnewY*v[0] + cy ),( absnewY*v[1]+cy ), nc] + # Inject in order + # If current is valid, Add + if cx >= centerX and cy >= centerY : + quad1.append( currentpoint ) + # If absnewX smaller, it is closest to currentPoint + if absnewX < absnewY: + if None != crossX : quad1.append( crossX ) + if None != crossY : quad1.append( crossY ) + else : + if None != crossY : quad1.append( crossY ) + if None != crossX : quad1.append( crossX ) + + ## Stage 2 : Mirror points + # + quad2 = [] + # quad2 = vertical symetric of quad1 + for iterator in range( len(quad1) -1 , -1, -1): + point = quad1[iterator] + quad2.append([ point[0], 2*centerY - point[1], point[2] ]) + # quad3 is the merge of 1 and 2 + quad3 = quad1 + quad2 + # quad4 is the horizontal symetric of quad3 + quad4 = [] + for iterator in range( len(quad3) -1, -1, -1): + point = quad3[iterator] + quad4.append([ 2*centerX - point[0], point[1], point[2] ]) + + #debug(name+" quad1:",quad1) + #debug(name+" quad2:", quad2 ) + debug(name+" quad3:", quad3 ) + debug(name+" quad4:", quad4 ) + return quad3+quad4 + +try: + while True: + start = time.time() + line = sys.stdin.readline() + if line == "": + time.sleep(0.01) + line = line.rstrip('\n') + pointsList = ast.literal_eval(line) + # Do the filter + result = kaleidoscope( pointsList ) + print( result, flush=True ) + looptime = time.time() - start + # debug(name+" looptime:"+str(looptime)) + if( looptime < optimal_looptime ): + time.sleep( optimal_looptime - looptime) + # debug(name+" micro sleep:"+str( optimal_looptime - looptime)) +except EOFError: + debug(name+" break")# no more information + diff --git a/clitools/generators/dummy.py b/clitools/generators/dummy.py new file mode 100644 index 0000000..ef621c6 --- /dev/null +++ b/clitools/generators/dummy.py @@ -0,0 +1,51 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- + + +''' + +This is the most basic generator you can imagine: straight up static! +v0.1.0 + +Use it to test your filters and outputs + +LICENCE : CC + +by cocoa + +''' + +from __future__ import print_function +import time +import argparse +import sys +name="generator::dummy" + + +def debug(*args, **kwargs): + if( verbose == False ): + return + print(*args, file=sys.stderr, **kwargs) + + +argsparser = argparse.ArgumentParser(description="Dummy generator") +argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int) +argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output") +args = argsparser.parse_args() + +fps=args.fps +verbose=args.verbose +optimal_looptime = 1 / fps +debug(name+" optimal looptime "+str(optimal_looptime)) + +while True: + start = time.time() + #print("[(100.0, 100.0, 65280), (100.0, 500.0, 65280), (500.0, 500.0, 65280), (500.0, 100.0, 65280), (100.0, 100.0, 65280)]", flush=True); + print("[(100.0, 100.0, 65280), (110.0, 500.0, 65280), (510.0, 500.0, 65280), (510.0, 100.0, 65280), (100.0, 110.0, 65280)]", flush=True); + looptime = time.time() - start + if( looptime < optimal_looptime ): + time.sleep( optimal_looptime - looptime) + debug(name+" micro sleep:"+str( optimal_looptime - looptime)) + + diff --git a/clitools/generators/example.py b/clitools/generators/example.py new file mode 100644 index 0000000..b1ad01c --- /dev/null +++ b/clitools/generators/example.py @@ -0,0 +1,182 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- + + +''' + +example, based on custom +v0.1.0 + +A copy of square.py you can modify to code your plugin. +custom1 has necessary hooks in LJ.conf, webui and so on. + + +LICENCE : CC + +by Sam Neurohack + + +''' +import sys +import os +ljpath = r'%s' % os.getcwd().replace('\\','/') + +# import from shell +sys.path.append(ljpath +'/../../libs/') + +#import from LJ +sys.path.append(ljpath +'/libs/') +print(ljpath+'/../libs/') + +import lj23layers as lj + +sys.path.append('../libs') +import math +import time +import argparse + + +print ("") +print ("Arguments parsing if needed...") +argsparser = argparse.ArgumentParser(description="Custom1 example for LJ") +argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",default=0,type=int) +args = argsparser.parse_args() + +# Useful variables init. +white = lj.rgb2int(255,255,255) +red = lj.rgb2int(255,0,0) +blue = lj.rgb2int(0,0,255) +green = lj.rgb2int(0,255,0) + +width = 800 +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. +# algorythm come from anaglyph geo maps +eye_spacing = 100 +nadir = 0.5 +observer_altitude = 30000 +map_layerane_altitude = 0.0 + +# square coordinates : vertices that compose each of the square. +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) + ] + +face = [0,1,2,3] + +# +# LJ inits +# + +layer = 0 + +# Define properties for each drawn "element" : name, intensity, active, xy, color, red, green, blue, layer , closed +Leftsquare = lj.FixedObject('Leftsquare', True, 255, [], red, 255, 0, 0, layer , True) +Rightsquare = lj.FixedObject('Rightsquare', True, 255, [], green, 0, 255, 0, layer , True) + +# 'Destination' for given layer : name, number, active, layer , scene, laser +Dest0 = lj.DestObject('0', 0, True, 0 , 0, 0) # Dest0 will send layer 0 points to scene 0, laser 0 + + +# +# Anaglyph computation : different X coordinate for each eye +# + +def LeftShift(elevation): + + diff = elevation - map_layerane_altitude + return nadir * eye_spacing * diff / (observer_altitude - elevation) + +def RightShift(elevation): + + diff = map_layerane_altitude - elevation + return (1 - nadir) * eye_spacing * diff / (observer_altitude - elevation) + + +def Proj(x,y,z,angleX,angleY,angleZ): + + rad = angleX * math.pi / 180 + cosa = math.cos(rad) + sina = math.sin(rad) + y2 = y + y = y2 * cosa - z * sina + z = y2 * sina + z * cosa + + rad = angleY * math.pi / 180 + cosa = math.cos(rad) + sina = math.sin(rad) + z2 = z + z = z2 * cosa - x * sina + x = z2 * sina + x * cosa + + rad = angleZ * math.pi / 180 + cosa = math.cos(rad) + sina = math.sin(rad) + x2 = x + x = x2 * cosa - y * sina + y = x2 * sina + y * cosa + + + """ Transforms this 3D point to 2D using a perspective projection. """ + factor = fov / (viewer_distance + z) + x = x * factor + centerX + y = - y * factor + centerY + return (x,y) + + +# +# Main +# + +def Run(): + Left = [] + Right = [] + counter =0 + try: + while True: + Left = [] + Right = [] + x = vertices[0][0] + y = vertices[0][1] + z = vertices[0][2] + + # 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. + + # generate all points in square. + for point in face: + x = vertices[point][0] + y = vertices[point][1] + z = vertices[point][2] + left.append(proj(x+leftshift(z*25),y,z,0,counter,0)) + right.append(proj(x+rightshift(z*25),y,z,0,counter,0)) + + + lj.polylineonecolor(left, c = leftsquare.color , layer = leftsquare.layer, closed = leftsquare.closed) + lj.polylineonecolor(right, c = rightsquare.color , layer = rightsquare.layer, closed = rightsquare.closed) + lj.drawdests() + time.sleep(0.1) + counter += 1 + if counter > 360: + counter = 0 + + except KeyboardInterrupt: + pass + + # Gently stop on CTRL C + finally: + lj.ClosePlugin() + + +Run()