67 |
68 |
69 |
--------------------------------------------------------------------------------
/examples/Template/Template.pde:
--------------------------------------------------------------------------------
1 | import be.cmbsoft.ilda.*;
2 | import be.cmbsoft.laseroutput.*;
3 |
4 |
5 | // Use graphic calls on the IldaRenderer object to create laser art
6 | IldaRenderer r;
7 |
8 | // The output can receive laser art from the renderer and send it to a laser
9 | LaserOutput output;
10 |
11 | boolean showPointCount = true;
12 |
13 | void setup() {
14 | // Since the projection surface of the laser effect is a square, use a square canvas in Processing
15 | size(800, 800, P3D);
16 |
17 | // The renderer requires just a reference to the sketch
18 | r = new IldaRenderer(this);
19 |
20 | // Because we are continuously sending to a laser in real time, we don't want to keep everything that's been rendered
21 | // in memory. That's what this method does: it tells the renderer to keep writing to the same frame instead of making
22 | // a new frame every time we call r.beginDraw(). If we would want to export the animation to a file, this should be
23 | // false.
24 | r.setOverwrite(true);
25 |
26 | // The LSX OSC output sends frames over OSC to LSX.
27 | output = new LsxOscOutput(1, // Timeline (projector number)
28 | 10, // Frame catalog index
29 | "127.0.0.1", // IP address of computer running LSX
30 | 10000 // Port of the LSX OSC server. This can be changed using Setup >> Remote Control >> OSC Setup >> Listening port.
31 | );
32 | }
33 |
34 | void draw() {
35 | // Clear the Processing window
36 | background(0);
37 |
38 | // It is required to call beginDraw() and endDraw() on the laser renderer
39 | r.beginDraw();
40 |
41 | // Reset the frame
42 | r.background();
43 |
44 |
45 | /*
46 | Here, you can program the actual graphical elements for the laser output.
47 | You can only use stroke-based vector elements such as:
48 | - stroke() (determines line colour)
49 | - ellipse()
50 | - rect()
51 | - triangle()
52 | - text()
53 | - shape()
54 | - vertex()
55 |
56 | You cannot use methods that are pixel based, like:
57 | - fill()
58 | - strokeWeight()
59 | - image()
60 | - texture()
61 | */
62 |
63 | // Calling beginDraw() requires calling endDraw()
64 | r.endDraw();
65 |
66 | // Retrieve the freshly created frame from the renderer
67 | IldaFrame currentFrame = r.getCurrentFrame();
68 |
69 | // This will display the laser frame in the Processing window
70 | currentFrame.renderFrame(this);
71 |
72 | // Display the point count on the screen, toggle with "P" on the keyboard.
73 | // It's a good idea to limit point count to 1500 points to reduce flickering.
74 | if (showPointCount) {
75 | int pointCount = currentFrame.getPointCount();
76 | fill(255);
77 | if (pointCount > 1500) {
78 | fill(255, 0, 0);
79 | }
80 | text(pointCount, 20, 20);
81 | }
82 |
83 | // This will send the laser frame to the laser
84 | output.project(currentFrame);
85 | }
86 |
87 | void keyPressed() {
88 | // Toggle the point count display
89 | if (key == 'P' || key == 'p') {
90 | showPointCount = !showPointCount;
91 | }
92 | }
93 |
94 | void exit() {
95 | // It is a good idea to clear output to the projector when exiting
96 | output.sendEmptyFrame();
97 | super.exit();
98 | }
99 |
--------------------------------------------------------------------------------
/examples-wip/LoadDisplaySVG/LoadDisplaySVG.pde:
--------------------------------------------------------------------------------
1 | /**
2 | * Load and Display a Shape.
3 | * Illustration by George Brower.
4 | *
5 | * The loadShape() command is used to read simple SVG (Scalable Vector Graphics)
6 | * files and OBJ (Object) files into a Processing sketch. This example loads an
7 | * SVG file of a monster robot face and displays it to the screen.
8 | */
9 |
10 | import be.cmbsoft.ilda.*;
11 | import be.cmbsoft.laseroutput.*;
12 |
13 |
14 | // Use graphic calls on the IldaRenderer object to create laser art
15 | IldaRenderer r;
16 |
17 | // The output can receive laser art from the renderer and send it to a laser
18 | LaserOutput output;
19 |
20 | boolean showPointCount = true;
21 |
22 | PShape bot;
23 |
24 | void setup() {
25 | size(640, 640, P3D);
26 | // The file "bot1.svg" must be in the data folder
27 | // of the current sketch to load successfully
28 | bot = loadShape("bot1.svg");
29 |
30 | // The renderer requires just a reference to the sketch
31 | r = new IldaRenderer(this);
32 |
33 | // Because we are continuously sending to a laser in real time, we don't want to keep everything that's been rendered
34 | // in memory. That's what this method does: it tells the renderer to keep writing to the same frame instead of making
35 | // a new frame every time we call r.beginDraw(). If we would want to export the animation to a file, this should be
36 | // false.
37 | r.setOverwrite(true);
38 |
39 | // The LSX OSC output sends frames over OSC to LSX.
40 | output = new LsxOscOutput(1, // Timeline (projector number)
41 | 10, // Frame catalog index
42 | "127.0.0.1", // IP address of computer running LSX
43 | 10000 // Port of the LSX OSC server. This can be changed using Setup >> Remote Control >> OSC Setup >> Listening port.
44 | );
45 | }
46 |
47 | void draw(){
48 | // It is required to call beginDraw() and endDraw() on the laser renderer
49 | r.beginDraw();
50 |
51 | // Reset the frame
52 | r.background();
53 | background(102);
54 | r.shape(bot, 110, 90, 100, 100); // Draw at coordinate (110, 90) at size 100 x 100
55 | r.shape(bot, 280, 40); // Draw at coordinate (280, 40) at the default size
56 |
57 | // Calling beginDraw() requires calling endDraw()
58 | r.endDraw();
59 |
60 | // Retrieve the freshly created frame from the renderer
61 | IldaFrame currentFrame = r.getCurrentFrame();
62 |
63 | // This will display the laser frame in the Processing window
64 | currentFrame.renderFrame(this);
65 |
66 | // Display the point count on the screen, toggle with "P" on the keyboard.
67 | // It's a good idea to limit point count to 1500 points to reduce flickering.
68 | if (showPointCount) {
69 | int pointCount = currentFrame.getPointCount();
70 | fill(255);
71 | if (pointCount > 1500) {
72 | fill(255, 0, 0);
73 | }
74 | text(pointCount, 20, 20);
75 | }
76 |
77 | // This will send the laser frame to the laser
78 | output.project(currentFrame);
79 | }
80 |
81 | void keyPressed() {
82 | // Toggle the point count display
83 | if (key == 'P' || key == 'p') {
84 | showPointCount = !showPointCount;
85 | }
86 | }
87 |
88 | void exit() {
89 | // It is a good idea to clear output to the projector when exiting
90 | output.sendEmptyFrame();
91 | super.exit();
92 | }
--------------------------------------------------------------------------------
/examples-wip/LsxLiveOscOutput/RectanglesToLSX/RectanglesToLSX.pde:
--------------------------------------------------------------------------------
1 | /*
2 | Example sketch to send laser frames generated by the ilda library to LSX using the OSC protocol.
3 | For this example to work, LSX has to run on the same computer with an Animation event on timeline 1 set to frame 10.
4 | The frames generated in this sketch will appear in the Animation event.
5 | */
6 |
7 |
8 | import netP5.*;
9 | import oscP5.*;
10 |
11 | import ilda.*;
12 |
13 |
14 |
15 | //The canvas for laser art, treat this as a PGraphics
16 | IldaRenderer r;
17 |
18 | OscP5 osc;
19 | //Change this to the IP and port of LSX
20 | NetAddress lsxLocation = new NetAddress("127.0.0.1", 10000);
21 |
22 | //Some bouncy bois
23 | ArrayList rects = new ArrayList();
24 |
25 | void setup()
26 | {
27 |
28 | size(600, 600, P3D);
29 |
30 |
31 | //Create an OSC client, listening to port 12000 (but received messages will be ignored)
32 | osc = new OscP5(this, 12000);
33 |
34 |
35 | r = new IldaRenderer(this);
36 |
37 | //This line causes the renderer to keep on reusing its current frame, otherwise it would create a new frame in each draw() loop
38 | r.setOverwrite(true);
39 |
40 | //Add the bouncy bois!
41 | for (int i =0; i < 5; i++)
42 | {
43 | rects.add(new Rectangle());
44 | }
45 | }
46 |
47 | void draw()
48 | {
49 | background(0);
50 |
51 | //To begin creating laser frames, use beginDraw() on the IldaRenderer
52 | r.beginDraw();
53 | r.background(); //this line removes the points from the previous frame
54 |
55 | for (Rectangle rect : rects)
56 | {
57 | rect.update(); //update the rectangle's position
58 | r.stroke(rect.colour);
59 | r.rect(rect.x, rect.y, 40, 40); //draw the rectangle on the IldaRenderer, previous line specifies colour
60 | }
61 |
62 |
63 |
64 | //Don't forget to call endDraw()!
65 | r.endDraw();
66 |
67 | //The next line displays the laser frame on the Processing canvas
68 | r.getCurrentFrame().renderFrame(this, false);
69 |
70 |
71 | //This line sends the frame to LSX over OSC
72 | ildaframeToLsx(r.getCurrentFrame(), 1, 10, lsxLocation);
73 | }
74 |
75 | void mouseClicked()
76 | {
77 | rects.add(new Rectangle(mouseX, mouseY));
78 | }
79 |
80 | void keyPressed()
81 | {
82 | if (key == 'c') rects.clear();
83 | }
84 |
85 |
86 |
87 | class Rectangle
88 | {
89 | float x, y;
90 | float velx, vely;
91 | int colour;
92 | Rectangle()
93 | {
94 | this( random(width), random(height));
95 | }
96 |
97 | Rectangle(float x, float y)
98 | {
99 | this.x = x;
100 | this.y = y;
101 | velx = random(-5, 5);
102 | vely = random(-5, 5);
103 | colour = color(random(255), random(255), random(255));
104 | }
105 |
106 | void update()
107 | {
108 | x += velx;
109 | y += vely;
110 |
111 | if (x < 0)
112 | {
113 | velx = -velx;
114 | x = 0;
115 | }
116 | if (x > width-40)
117 | {
118 | velx = - velx;
119 | x = width-40;
120 | }
121 | if (y < 0)
122 | {
123 | vely = - vely;
124 | y = 0;
125 | }
126 | if (y > height-40)
127 | {
128 | vely = - vely;
129 | y = height-40;
130 | }
131 | }
132 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/colouredmirrorball/Ilda/actions/workflows/maven.yml)
2 |
3 | ilda
4 | ====
5 |
6 | A Processing library that allows the import, creation, editing and export of ilda-compliant files for laser show use.
7 |
8 | Download latest (v0.1.2): https://github.com/colouredmirrorball/Ilda/releases/download/v0.1.2/ilda.zip
9 |
10 | Manual install: unzip the above file in the Processing libraries folder
11 |
12 | Javadoc: http://colouredmirrorball.github.io/Ilda/
13 |
14 |
15 | First time usage:
16 |
17 | * Download Processing from processing.org if you haven't already (latest version should work, if not file an issue)
18 | * Unzip and run it at least once
19 | * Find the sketch path: File >> Settings >> Sketchpath
20 | * Use a file browser and open this path
21 | * Create or open the folder "libraries"
22 | * Unzip ilda.zip in this directory
23 | * Should now look like this: *Sketchpath*\libraries\ilda\library\ilda.jar
24 | * Restart Processing
25 | * Open an example or get coding! Good luck!
26 |
27 |
28 | Functionality:
29 |
30 | * Load ilda file
31 | * Write ilda file
32 | * Load LSX PIC file
33 | * Get ilda file properties as Processing datatypes (PVector, color)
34 | * Display ilda file on screen
35 | * Render ilda frame as if it were a PGraphics, supported operations (tested):
36 | * line()
37 | * point()
38 | * ellipse()
39 | * rect()
40 | * stroke()
41 | * text() (wonky)
42 | * shape() (includes SVG files - not all SVG tags supported or tested)
43 | * vertex()
44 |
45 | Todo:
46 |
47 | * Finish optimisation:
48 | * blank transition dwell points
49 | * angle dwell
50 | * Clip points outside of canvas
51 | * Make library official
52 |
53 | Compatibility:
54 |
55 | * Tested with Processing 2.2.1 and 3.3.4
56 | * Tested on Windows 10 64 bit but should be 100 % cross-platform
57 |
58 | No real time laser output is supported and is out of scope for this library. However, some examples include a way to send
59 | IldaFrames to LSX using the OSC protocol in real time.
60 |
61 |
62 | **DISCLAIMER**
63 |
64 | This library is capable of producing laser art files that when scanned by an actual laser projector, might cause permanent
65 | eye damage when exposed. Always observe proper safety guidelines and local regulations. The authors of this software can
66 | in no regards be held responsible for damage caused by improper use of this software. Always avoid scanning into an audience
67 | and if you can't help yourself, then make sure the beam is always fast moving. Multiple points at the same location will
68 | cause hot beams that pop eyes or cause fires.
69 |
70 | It is possible using this software to create laser art files with a relatively long distance between consecutive points.
71 | These jumps might be hazardous to the projector scan system (galvo's, scanners, etc.). This can be avoided by optimising
72 | files before exporting. The authors of this software can in no way be held responsible for damage to laser projector systems
73 | caused by the use of this library.
74 |
75 | By using this library it is assumed you are aware of the possible consequences of improper use and accept the sole responsibility.
76 |
--------------------------------------------------------------------------------
/Ilda.txt:
--------------------------------------------------------------------------------
1 | # UTF-8 supported.
2 |
3 | # The name of your library as you want it formatted.
4 | name = ILDA for Processing
5 |
6 | # List of authors. Links can be provided using the syntax [author name](url).
7 | authors = Florian Bonte
8 |
9 | # A web page for your library, NOT a direct link to where to download it.
10 | url = https://github.com/colouredmirrorball/Ilda
11 |
12 | # The category (or categories) of your library, must be from the following list:
13 | # "3D" "Animation" "Compilations" "Data"
14 | # "Fabrication" "Geometry" "GUI" "Hardware"
15 | # "I/O" "Language" "Math" "Simulation"
16 | # "Sound" "Utilities" "Typography" "Video & Vision"
17 | #
18 | # If a value other than those listed is used, your library will listed as
19 | # "Other". Many categories must be comma-separated.
20 | categories = I/O
21 |
22 | # A short sentence (or fragment) to summarize the library's function. This will
23 | # be shown from inside the PDE when the library is being installed. Avoid
24 | # repeating the name of your library here. Also, avoid saying anything redundant
25 | # like mentioning that it's a library. This should start with a capitalized
26 | # letter, and end with a period.
27 | sentence = Library that allows the import, creation, editing and export of ILDA-compliant files for laser show use.
28 |
29 | # Additional information suitable for the Processing website. The value of
30 | # 'sentence' always will be prepended, so you should start by writing the
31 | # second sentence here. If your library only works on certain operating systems,
32 | # mention it here.
33 | paragraph = Using this library, the contents of an ilda file can be converted to familiar Processing variables (color datatype, PVector datatype) for manipulation. Also featured is a PGraphics extension (IldaRenderer) that allows the programmer to call Processing functions to it (stroke(), line(), rectangle() and so on). text() and shape() for svg files also work but are in testing phase. Since this is laser art, pixel-based methods such as fill() are not supported.
34 |
35 | # Links in the 'sentence' and 'paragraph' attributes can be inserted using the
36 | # same syntax as for authors.
37 | # That is, [here is a link to Processing](http://processing.org/)
38 |
39 | # A version number that increments once with each release. This is used to
40 | # compare different versions of the same library, and check if an update is
41 | # available. You should think of it as a counter, counting the total number of
42 | # releases you've had.
43 | version = 1 # This must be parsable as an int
44 |
45 | # The version as the user will see it. If blank, the version attribute will be
46 | # used here. This should be a single word, with no spaces.
47 | prettyVersion = 0.1a # This is treated as a String
48 |
49 | # The min and max revision of Processing compatible with your library.
50 | # Note that these fields use the revision and not the version of Processing,
51 | # parsable as an int. For example, the revision number for 2.2.1 is 227.
52 | # You can find the revision numbers in the change log:
53 | # https://raw.githubusercontent.com/processing/processing/master/build/shared/revisions.txt
54 | # Only use maxRevision (or minRevision), when your library is known to
55 | # break in a later (or earlier) release. Otherwise, use the default value 0.
56 | minRevision = 227
57 | maxRevision = 0
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | # UTF-8 supported.
2 |
3 | # The name of your library as you want it formatted.
4 | name = ILDA for Processing
5 |
6 | # List of authors. Links can be provided using the syntax [author name](url).
7 | authors = Florian Bonte
8 |
9 | # A web page for your library, NOT a direct link to where to download it.
10 | url = https://github.com/colouredmirrorball/Ilda
11 |
12 | # The category (or categories) of your library, must be from the following list:
13 | # "3D" "Animation" "Compilations" "Data"
14 | # "Fabrication" "Geometry" "GUI" "Hardware"
15 | # "I/O" "Language" "Math" "Simulation"
16 | # "Sound" "Utilities" "Typography" "Video & Vision"
17 | #
18 | # If a value other than those listed is used, your library will listed as
19 | # "Other". Many categories must be comma-separated.
20 | categories = I/O, Hardware
21 |
22 | # A short sentence (or fragment) to summarize the library's function. This will
23 | # be shown from inside the PDE when the library is being installed. Avoid
24 | # repeating the name of your library here. Also, avoid saying anything redundant
25 | # like mentioning that it's a library. This should start with a capitalized
26 | # letter, and end with a period.
27 | sentence = Library that allows the import, creation, editing and export of ILDA-compliant files for laser show use.
28 |
29 | # Additional information suitable for the Processing website. The value of
30 | # 'sentence' always will be prepended, so you should start by writing the
31 | # second sentence here. If your library only works on certain operating systems,
32 | # mention it here.
33 | paragraph = Using this library, the contents of an ilda file can be converted to familiar Processing variables (color datatype, PVector datatype) for manipulation. Also featured is a PGraphics extension (IldaRenderer) that allows the programmer to call Processing functions to it (stroke(), line(), rectangle() and so on). Since this is laser art, pixel-based methods such as fill() are not supported. There is preliminary, experimental support for live laser output.
34 |
35 | # Links in the 'sentence' and 'paragraph' attributes can be inserted using the
36 | # same syntax as for authors.
37 | # That is, [here is a link to Processing](http://processing.org/)
38 |
39 | # A version number that increments once with each release. This is used to
40 | # compare different versions of the same library, and check if an update is
41 | # available. You should think of it as a counter, counting the total number of
42 | # releases you've had.
43 | version = 1 # This must be parsable as an int
44 |
45 | # The version as the user will see it. If blank, the version attribute will be
46 | # used here. This should be a single word, with no spaces.
47 | prettyVersion = 0.1.1 # This is treated as a String
48 |
49 | # The min and max revision of Processing compatible with your library.
50 | # Note that these fields use the revision and not the version of Processing,
51 | # parsable as an int. For example, the revision number for 2.2.1 is 227.
52 | # You can find the revision numbers in the change log:
53 | # https://raw.githubusercontent.com/processing/processing/master/build/shared/revisions.txt
54 | # Only use maxRevision (or minRevision), when your library is known to
55 | # break in a later (or earlier) release. Otherwise, use the default value 0.
56 | minRevision = 1278
57 | maxRevision = 0
--------------------------------------------------------------------------------
/src/main/java/be/cmbsoft/ilda/PicReader.java:
--------------------------------------------------------------------------------
1 | package be.cmbsoft.ilda;
2 |
3 | import java.io.File;
4 | import java.io.FileNotFoundException;
5 |
6 |
7 | public class PicReader extends FileParser
8 | {
9 | PicReader(String location) throws FileNotFoundException
10 | {
11 | super(new File(location));
12 | }
13 |
14 | public PicReader(File location) throws FileNotFoundException
15 | {
16 | super(location);
17 | }
18 |
19 | /**
20 | * Returns the frame in a .PIC file
21 | *
22 | * @param location String that contains the path to the file on disk
23 | * @return
24 | */
25 |
26 | public static IldaFrame getFrame(String location)
27 | {
28 | PicReader parser;
29 | try
30 | {
31 | parser = new PicReader(location);
32 | }
33 | catch (FileNotFoundException exception)
34 | {
35 | Utilities.logException(exception);
36 | return null;
37 | }
38 | return parser.getFrame();
39 | }
40 |
41 | public static IldaFrame getFrame(File location)
42 | {
43 | PicReader parser;
44 | try
45 | {
46 | parser = new PicReader(location);
47 | }
48 | catch (FileNotFoundException exception)
49 | {
50 | Utilities.logException(exception);
51 | return null;
52 | }
53 | return parser.getFrame();
54 | }
55 |
56 | public IldaFrame getFrame()
57 | {
58 | int version = b[0];
59 | int bbp = (version == 1 || version == 0) ? 8 : 11; //bits per point
60 | int begin = version == 0 ? 15 : 14;
61 | IldaFrame frame = new IldaFrame();
62 | for (int i = begin; i < b.length; i++)
63 | {
64 | if (i <= b.length - bbp)
65 | {
66 | float x = ((b[i] << 8) & 0xff00) | (b[i + 1] & 0x00ff);
67 | float y = ((b[i + 2] << 8) & 0xff00) | (b[i + 3] & 0x00ff);
68 | float z = ((b[i + 4] << 8) & 0xff00) | (b[i + 5] & 0x00ff);
69 |
70 | boolean bl = false; //blanking
71 | boolean normalVector = false; //ignore normal vectors
72 |
73 |
74 | if ((b[i + 6] & 0x40) == 64) {bl = true;}
75 | if ((b[i + 6] & 0x80) != 128) {normalVector = true;}
76 | int palIndex = b[i + 6] & 0x3F; //only the last 6 bits are used for the palette colour
77 | // (64 maximum)
78 |
79 | if (!normalVector)
80 | {
81 | IldaPoint point;
82 | if (version == 0 || version == 1)
83 | {
84 | point = new IldaPoint(x * 0.00003051757f, y * 0.00003051757f, z * 0.00003051757f, palIndex, bl);
85 | }
86 | else
87 | {
88 | point = new IldaPoint(x * 0.00003051757f, y * 0.00003051757f, z * 0.00003051757f, b[i + 8],
89 | b[i + 9], b[i + 10], bl);
90 | }
91 | frame.addPoint(point);
92 |
93 | }
94 |
95 | }
96 | }
97 | frame.palette = version == 0 || version == 1;
98 | frame.frameName = "PicFrame";
99 | frame.companyName = "Ilda4P5";
100 |
101 | return frame;
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/examples/Rectangles/Rectangles.pde:
--------------------------------------------------------------------------------
1 | /*
2 | Example sketch to send laser frames generated by the ilda library to LSX using the OSC protocol.
3 | For this example to work, LSX has to run on the same computer with an Animation event on timeline 1 set to frame 10.
4 | The frames generated in this sketch will appear in the Animation event.
5 | */
6 |
7 |
8 | import be.cmbsoft.ilda.*;
9 | import be.cmbsoft.laseroutput.*;
10 |
11 | //The canvas for laser art, treat this as a PGraphics
12 | IldaRenderer r;
13 |
14 | // The output can receive laser art from the renderer and send it to a laser
15 | LaserOutput output;
16 |
17 | //Some bouncy bois
18 | ArrayList rects = new ArrayList();
19 |
20 | void setup()
21 | {
22 |
23 | size(600, 600, P3D);
24 |
25 | r = new IldaRenderer(this);
26 |
27 | //This line causes the renderer to keep on reusing its current frame, otherwise it would create a new frame in each draw() loop
28 | r.setOverwrite(true);
29 |
30 | //Add the bouncy bois!
31 | for (int i =0; i < 5; i++)
32 | {
33 | rects.add(new Rectangle());
34 | }
35 |
36 | // The LSX OSC output sends frames over OSC to LSX.
37 | output = new LsxOscOutput(1, // Timeline (projector number)
38 | 10, // Frame catalog index
39 | "127.0.0.1", // IP address of computer running LSX
40 | 10000 // Port of the LSX OSC server. This can be changed using Setup >> Remote Control >> OSC Setup >> Listening port.
41 | );
42 | }
43 |
44 | void draw()
45 | {
46 | background(0);
47 |
48 | //To begin creating laser frames, use beginDraw() on the IldaRenderer
49 | r.beginDraw();
50 | r.background(); //this line removes the points from the previous frame
51 |
52 | for (Rectangle rect : rects)
53 | {
54 | rect.update(); //update the rectangle's position
55 | r.stroke(rect.colour);
56 | r.rect(rect.x, rect.y, 40, 40); //draw the rectangle on the IldaRenderer, previous line specifies colour
57 | }
58 |
59 | //Don't forget to call endDraw()!
60 | r.endDraw();
61 |
62 | IldaFrame frame = r.getCurrentFrame();
63 |
64 | //The next line displays the laser frame on the Processing canvas
65 | frame.renderFrame(this, false);
66 |
67 | output.project(frame);
68 | }
69 |
70 | void mouseClicked()
71 | {
72 | rects.add(new Rectangle(mouseX, mouseY));
73 | }
74 |
75 | void keyPressed()
76 | {
77 | if (key == 'c') rects.clear();
78 | }
79 |
80 | void exit() {
81 | // It is a good idea to clear output to the projector when exiting
82 | output.sendEmptyFrame();
83 | super.exit();
84 | }
85 |
86 |
87 |
88 | class Rectangle
89 | {
90 | float x, y;
91 | float velx, vely;
92 | int colour;
93 | Rectangle()
94 | {
95 | this( random(width), random(height));
96 | }
97 |
98 | Rectangle(float x, float y)
99 | {
100 | this.x = x;
101 | this.y = y;
102 | velx = random(-5, 5);
103 | vely = random(-5, 5);
104 | colour = color(random(255), random(255), random(255));
105 | }
106 |
107 | void update()
108 | {
109 | x += velx;
110 | y += vely;
111 |
112 | if (x < 0)
113 | {
114 | velx = -velx;
115 | x = 0;
116 | }
117 | if (x > width-40)
118 | {
119 | velx = - velx;
120 | x = width-40;
121 | }
122 | if (y < 0)
123 | {
124 | vely = - vely;
125 | y = 0;
126 | }
127 | if (y > height-40)
128 | {
129 | vely = - vely;
130 | y = height-40;
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/examples/CircuitPulse/CircuitPulse.pde:
--------------------------------------------------------------------------------
1 | /*
2 | Modified sketch from https://github.com/BarneyWhiteman/CodingChallenges/tree/master/cc5_pulse/pulse
3 | */
4 |
5 |
6 | import be.cmbsoft.ilda.*;
7 | import be.cmbsoft.laseroutput.*;
8 |
9 | // Use graphic calls on the IldaRenderer object to create laser art
10 | IldaRenderer r;
11 |
12 | // The output can receive laser art from the renderer and send it to a laser
13 | LaserOutput output;
14 |
15 | boolean showPointCount = true;
16 |
17 | ArrayList p = new ArrayList();
18 |
19 | void setup() {
20 | size(720, 720, P3D);
21 |
22 | r = new IldaRenderer(this);
23 |
24 | //In the overwrite mode, the renderer will keep on drawing to the same frame instead of storing a frame array.
25 | //Since we're sending the generated frames straight to LSX there's no need to store them in the renderer
26 | //so it can keep on reusing the same frame for better memory management.
27 | //If we were saving the animation to an ILDA file this line should be removed.
28 | r.setOverwrite(true);
29 |
30 | r.setOptimise(false);
31 |
32 | // The LSX OSC output sends frames over OSC to LSX.
33 | output = new LsxOscOutput(1, // Timeline (projector number)
34 | 10, // Frame catalog index
35 | "127.0.0.1", // IP address of computer running LSX
36 | 10000 // Port of the LSX OSC server. This can be changed using Setup >> Remote Control >> OSC Setup >> Listening port.
37 | );
38 |
39 | //By default, optimisation is turned on
40 | //r.setOptimise(false);
41 | r.colorMode(HSB);
42 |
43 | surface.setLocation(20, 20);
44 | }
45 |
46 | void draw() {
47 | background(0);
48 |
49 | //Always call beginDraw() on the renderer
50 | r.beginDraw();
51 |
52 | //Remove the contents of the frame to start with a blank canvas
53 | r.background();
54 |
55 | //Loops over all particles
56 | for (int i = p.size() - 1; i >= 0; i --)
57 | {
58 | p.get(i).update();
59 | if (p.get(i).dead)
60 | {
61 | p.remove(i);
62 | continue;
63 | }
64 | //Displays the particle on the IldaRenderer object
65 | p.get(i).show(r);
66 | }
67 | r.endDraw();
68 | // Retrieve the freshly created frame from the renderer
69 | IldaFrame currentFrame = r.getCurrentFrame();
70 |
71 | // This will display the laser frame in the Processing window
72 | currentFrame.renderFrame(this);
73 |
74 | // Display the point count on the screen, toggle with "P" on the keyboard.
75 | // It's a good idea to limit point count to 1500 points to reduce flickering.
76 | if (showPointCount) {
77 | int pointCount = currentFrame.getPointCount();
78 | fill(255);
79 | if (pointCount > 1500) {
80 | fill(255, 0, 0);
81 | }
82 | text(pointCount, 20, 20);
83 | }
84 | // This will send the laser frame to the laser
85 | output.project(currentFrame);
86 | }
87 |
88 | void mousePressed()
89 | {
90 | burst(10);
91 | }
92 |
93 | void burst(int num) {
94 | int c = int(random(255));
95 | for (int i = 0; i < num; i ++) {
96 | float a = int(random(8)) * PI/4;
97 | p.add(new Particle(mouseX, mouseY, a, c));
98 | }
99 | }
100 |
101 |
102 | void keyPressed() {
103 | // Toggle the point count display
104 | if (key == 'P' || key == 'p') {
105 | showPointCount = !showPointCount;
106 | }
107 | }
108 |
109 | void exit() {
110 | // It is a good idea to clear output to the projector when exiting
111 | output.sendEmptyFrame();
112 | super.exit();
113 | }
114 |
--------------------------------------------------------------------------------
/examples/Beams/Beams.pde:
--------------------------------------------------------------------------------
1 | import be.cmbsoft.ilda.*;
2 | import be.cmbsoft.laseroutput.*;
3 |
4 | /*
5 | * A selection of beam effects. These look great with a bit of fog.
6 | * Controls:
7 | * Left/right arrow keys: select effect
8 | * Mouse buttons: modify effect (dependent on effect)
9 | * Left mouse button: pick new random colours
10 | * P: toggle displaying of point count on canvas
11 | */
12 |
13 | IldaRenderer r;
14 | LsxOscOutput output;
15 | Effect currentEffect;
16 |
17 | color firstColor;
18 | color secondColor;
19 |
20 | color newFirstColor;
21 | color newSecondColor;
22 | float colorSpeed = 0.075f;
23 |
24 | int effectIndex = 0;
25 | int amountOfEffects = 4;
26 |
27 | boolean showPointCount = false;
28 |
29 | void setup() {
30 |
31 | // Since the projection surface of the laser effect is a square, use a square canvas in Processing
32 | size(800, 800, P3D);
33 |
34 | // The IldaRenderer object can be used to draw on, similar to a PGraphics object
35 | r = new IldaRenderer(this);
36 |
37 | r.setOverwrite(true);
38 |
39 | // The LSX OSC output sends frames over OSC to LSX.
40 | output = new LsxOscOutput(1, // Timeline (projector number)
41 | 10, // Frame catalog index
42 | "127.0.0.1", // IP address of computer running LSX
43 | 10000 // Port of the LSX OSC server. This can be changed using Setup >> Remote Control >> OSC Setup >> Listening port.
44 | );
45 |
46 | // Use the arrow keys to switch between effects.
47 | currentEffect = new BeamEffect();
48 | colorMode(HSB);
49 | assignRandomColors();
50 | }
51 |
52 | void draw() {
53 | background(0);
54 |
55 | lerpColors();
56 |
57 | r.beginDraw();
58 | r.background();
59 |
60 | currentEffect.display(r);
61 | r.endDraw();
62 | IldaFrame currentFrame = r.getCurrentFrame();
63 | currentFrame.renderFrame(this);
64 |
65 | if (showPointCount) {
66 | int pointCount = currentFrame.getPointCount();
67 | fill(255);
68 | text(pointCount, 20, 20);
69 | }
70 |
71 | output.project(currentFrame);
72 | }
73 |
74 | void mousePressed() {
75 | if (mouseButton == LEFT) {
76 | assignRandomColors();
77 | }
78 | currentEffect.mouse();
79 | }
80 |
81 | void keyPressed() {
82 | if (key == CODED) {
83 | if (keyCode == LEFT) {
84 | previousEffect();
85 | } else if (keyCode == RIGHT) {
86 | nextEffect();
87 | }
88 | }
89 | if (key == 'P' || key == 'p') {
90 | showPointCount = !showPointCount;
91 | }
92 | }
93 |
94 | void exit() {
95 | // For safety, disable laser output when exiting
96 | output.sendEmptyFrame();
97 | super.exit();
98 | }
99 |
100 | void nextEffect() {
101 | setEffect(++effectIndex >= amountOfEffects ? effectIndex = 0 : effectIndex);
102 | }
103 |
104 | void previousEffect() {
105 | setEffect(--effectIndex < 0 ? effectIndex = amountOfEffects-1 : effectIndex);
106 | }
107 |
108 | void setEffect(int index) {
109 | switch(index) {
110 | case 0:
111 | default:
112 | currentEffect = new BeamEffect();
113 | break;
114 | case 1 :
115 | currentEffect = new ConeEffect();
116 | break;
117 | case 2:
118 | currentEffect = new SineEffect();
119 | break;
120 | case 3:
121 | currentEffect = new LineEffect();
122 | break;
123 | }
124 | }
125 |
126 | void assignRandomColors() {
127 | newFirstColor = randomColor();
128 | newSecondColor = randomColor();
129 | }
130 |
131 | void lerpColors() {
132 | // Fade nicely between the new color and the old one
133 | firstColor = lerpColor(firstColor, newFirstColor, colorSpeed);
134 | secondColor = lerpColor(secondColor, newSecondColor, colorSpeed);
135 | }
136 |
137 | color randomColor() {
138 | // Use Gaussian distribution to favor saturated colours
139 | return color((int) random(255), (int) 255-255*randomGaussian(), 255);
140 | }
141 |
--------------------------------------------------------------------------------
/docs/deprecated-list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Deprecated List
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/src/main/java/be/cmbsoft/ilda/IldaReader.java:
--------------------------------------------------------------------------------
1 | package be.cmbsoft.ilda;
2 |
3 |
4 | import java.io.File;
5 | import java.io.FileNotFoundException;
6 | import java.util.ArrayList;
7 | import java.util.Collections;
8 | import java.util.List;
9 |
10 | /**
11 | * This class reads a file and passes the data to frames and points.
12 | *
13 | * Ilda files are explained here
14 | * This document only
15 | * mentions Ilda V0, 1, 2 and 3, no V4 and V5 so here's a breakdown: ILDA V0 is 3D and uses
16 | * palettes ILDA V1 is 2D and
17 | * uses palettes ILDA V2 is a palette ILDA V3 is a 24-bit palette, but was discontinued and is
18 | * not a part of the
19 | * official standard anymore ILDA V4 is 3D with true-colour information in BGR format ILDA V5 is
20 | * 2D with true-colour
21 | * information in BGR format.
22 | *
23 | * An Ilda file is composed of headers that always start with "ILDA", followed by three zeros and
24 | * the version number. A
25 | * complete header is 32 bytes. After the header, the data follows. In case of a palette (V2),
26 | * each data point has three
27 | * bytes: R, G and B. In case of a frame (V0/1/4/5), the X, Y and Z (for 3D frames) values are
28 | * spread out over two bytes
29 | * Then either two status bytes follow with a blanking bit and palette colour number, or BGR
30 | * values.
31 | */
32 | public class IldaReader extends FileParser
33 | {
34 |
35 | private IldaPalette palette;
36 |
37 | private IldaReader(String location) throws FileNotFoundException
38 | {
39 | this(new File(location));
40 | }
41 |
42 | private IldaReader(File file) throws FileNotFoundException
43 | {
44 | super(file);
45 | }
46 |
47 | /**
48 | * Parse an ilda file from disk and retrieve its contents. Note that since there is no
49 | * information here about canvas
50 | * size, all positions are normalised between -1 and 1.
51 | *
52 | * @param location absolute path to the ilda file
53 | * @return list of all loaded frames
54 | */
55 |
56 | public static List readFile(String location)
57 | {
58 | IldaReader reader;
59 | try
60 | {
61 | reader = new IldaReader(location);
62 | }
63 | catch (FileNotFoundException exception)
64 | {
65 | Utilities.logException(exception);
66 | return Collections.emptyList();
67 | }
68 | return reader.getFramesFromBytes();
69 | }
70 |
71 | public static List readFile(File location)
72 | {
73 | IldaReader reader;
74 | try
75 | {
76 | reader = new IldaReader(location);
77 | }
78 | catch (FileNotFoundException exception)
79 | {
80 | Utilities.logException(exception);
81 | return Collections.emptyList();
82 | }
83 | return reader.getFramesFromBytes();
84 | }
85 |
86 | public void setPalette(IldaPalette palette)
87 | {
88 | this.palette = palette;
89 | }
90 |
91 | private List getFramesFromBytes()
92 | {
93 | reset();
94 | ArrayList theFrames = new ArrayList<>();
95 | if (b == null)
96 | {
97 | return Collections.emptyList();
98 | }
99 |
100 | if (b.length < 32) {
101 | //There isn't even a complete header here!
102 | throw new RuntimeException("Error: file is not long enough to be a valid ILDA file!");
103 | }
104 |
105 | //Check if the first four bytes read ILDA:
106 | String header = parseString(4);
107 | if (!header.equals("ILDA")) {
108 | throw new RuntimeException(
109 | "Error: invalid ILDA file, found " + header + ", expected ILDA instead");
110 | }
111 |
112 | reset();
113 |
114 | loadIldaFrame(theFrames);
115 | return theFrames;
116 | }
117 |
118 | /**
119 | * Iterative method to load ilda frames, the new frames are appended to an ArrayList.
120 | *
121 | * @param frames IldaFrame List where the new frame will be appended
122 | */
123 |
124 | private void loadIldaFrame(List frames) {
125 | if (position >= b.length - 32) {
126 | return; //no complete header
127 | }
128 |
129 | //Bytes 0-3: ILDA
130 | String hdr = parseString(4);
131 | if (!hdr.equals("ILDA")) {
132 | return;
133 | }
134 |
135 | //Bytes 4-6: Reserved
136 | skip(3);
137 |
138 | //Byte 7: format code
139 | int ildaVersion = parseByte();
140 |
141 | //Bytes 8-15: frame name
142 | String name = parseString(8);
143 |
144 | //Bytes 16-23: company name
145 | String company = parseString(8);
146 |
147 | //Bytes 24-25: point count
148 | int pointCount = parseShort();
149 |
150 | //Bytes 26-27: frame number in frames or palette number in palettes
151 | int frameNumber = parseShort();
152 |
153 | //Bytes 28-29: total frames
154 | skip(2);
155 |
156 | //Byte 30: projector number
157 | int scannerhead = parseByte() & 0xff;
158 |
159 | //Byte 31: Reserved
160 | skip(1);
161 |
162 |
163 | if (ildaVersion == 2) {
164 |
165 | palette = new IldaPalette();
166 |
167 | palette.setName(name);
168 | palette.setCompanyName(company);
169 |
170 | //Byte 30: scanner head.
171 | palette.setScannerHead(scannerhead);
172 | palette.setPaletteNumber(frameNumber);
173 |
174 |
175 | // ILDA V2: Palette information
176 |
177 | for (int i = 0; i < pointCount; i++)
178 | {
179 | palette.addColour(parseByte(), parseByte(), parseByte());
180 | }
181 | } else {
182 | IldaFrame frame = new IldaFrame();
183 |
184 | frame.setIldaFormat(ildaVersion);
185 | frame.setFrameName(name);
186 | frame.setCompanyName(company);
187 | frame.setFrameNumber(frameNumber);
188 | frame.setPalette(ildaVersion == 0 || ildaVersion == 1);
189 |
190 | boolean is3D = ildaVersion == 0 || ildaVersion == 4;
191 |
192 |
193 | for (int i = 0; i < pointCount; i++) {
194 | float x = parseShort();
195 | float y = parseShort();
196 | float z = 0;
197 | if (is3D) {z = parseShort();}
198 | boolean bl = (parseByte() & 0x40) == 64;
199 | if (ildaVersion == 0 || ildaVersion == 1) {
200 | IldaPoint point = new IldaPoint(x * 0.00003051757f, y * -0.00003051757f,
201 | z * 0.00003051757f, parseByte() & 0xff, bl);
202 | frame.addPoint(point);
203 | } else if (ildaVersion == 4 || ildaVersion == 5) {
204 | int blue = parseByte();
205 | int g = parseByte();
206 | int r = parseByte();
207 | IldaPoint point = new IldaPoint(x * 0.00003051757f, y * -0.00003051757f,
208 | z * 0.00003051757f, blue & 0xff, g & 0xff, r & 0xff, bl);
209 | frame.addPoint(point);
210 | }
211 | }
212 |
213 | if (frame.isPalette()) {
214 | if (palette == null) {
215 | palette = new IldaPalette();
216 | palette.setDefaultPalette();
217 | }
218 |
219 | frame.palettePaint(palette);
220 | }
221 | frames.add(frame);
222 |
223 | loadIldaFrame(frames);
224 | }
225 | }
226 |
227 | }
228 |
--------------------------------------------------------------------------------
/docs/index-files/index-6.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | F-Index
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
24 |
Fixes the frame headers eg.updates point count, frame number, total frames It
108 | sets the
109 | frame name and company name to the arguments you gave it.
110 |