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 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/docs/jquery-ui.overrides.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * This code is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU General Public License version 2 only, as
7 | * published by the Free Software Foundation. Oracle designates this
8 | * particular file as subject to the "Classpath" exception as provided
9 | * by Oracle in the LICENSE file that accompanied this code.
10 | *
11 | * This code is distributed in the hope that it will be useful, but WITHOUT
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 | * version 2 for more details (a copy is included in the LICENSE file that
15 | * accompanied this code).
16 | *
17 | * You should have received a copy of the GNU General Public License version
18 | * 2 along with this work; if not, write to the Free Software Foundation,
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 | *
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 | * or visit www.oracle.com if you need additional information or have any
23 | * questions.
24 | */
25 |
26 | .ui-state-active,
27 | .ui-widget-content .ui-state-active,
28 | .ui-widget-header .ui-state-active,
29 | a.ui-button:active,
30 | .ui-button:active,
31 | .ui-button.ui-state-active:hover {
32 | /* Overrides the color of selection used in jQuery UI */
33 | background: #F8981D;
34 | }
35 |
--------------------------------------------------------------------------------
/docs/module-search-index.js:
--------------------------------------------------------------------------------
1 | moduleSearchIndex = [];
2 | updateSearchResults();
--------------------------------------------------------------------------------
/docs/overview-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
24 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/docs/package-list:
--------------------------------------------------------------------------------
1 | ilda
2 |
--------------------------------------------------------------------------------
/docs/package-search-index.js:
--------------------------------------------------------------------------------
1 | packageSearchIndex = [{"l": "All Packages", "u": "allpackages-index.html"}, {"l": "be.cmbsoft.ilda"}];
2 | updateSearchResults();
--------------------------------------------------------------------------------
/docs/resources/glass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/resources/glass.png
--------------------------------------------------------------------------------
/docs/resources/x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/resources/x.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-bg_glass_55_fbf9ee_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-bg_glass_55_fbf9ee_1x400.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-bg_glass_65_dadada_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-bg_glass_65_dadada_1x400.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-bg_glass_75_dadada_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-bg_glass_75_dadada_1x400.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-bg_glass_75_e6e6e6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-bg_glass_75_e6e6e6_1x400.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-bg_glass_95_fef1ec_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-bg_glass_95_fef1ec_1x400.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-bg_highlight-soft_75_cccccc_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-bg_highlight-soft_75_cccccc_1x100.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-icons_2e83ff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-icons_2e83ff_256x240.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-icons_454545_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-icons_454545_256x240.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-icons_888888_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-icons_888888_256x240.png
--------------------------------------------------------------------------------
/docs/script-dir/images/ui-icons_cd0a0a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/docs/script-dir/images/ui-icons_cd0a0a_256x240.png
--------------------------------------------------------------------------------
/docs/script-dir/jquery-ui.structure.min.css:
--------------------------------------------------------------------------------
1 | /*! jQuery UI - v1.12.1 - 2018-12-06
2 | * http://jqueryui.com
3 | * Copyright jQuery Foundation and other contributors; Licensed MIT */
4 |
5 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}
--------------------------------------------------------------------------------
/docs/script.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * This code is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU General Public License version 2 only, as
7 | * published by the Free Software Foundation. Oracle designates this
8 | * particular file as subject to the "Classpath" exception as provided
9 | * by Oracle in the LICENSE file that accompanied this code.
10 | *
11 | * This code is distributed in the hope that it will be useful, but WITHOUT
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 | * version 2 for more details (a copy is included in the LICENSE file that
15 | * accompanied this code).
16 | *
17 | * You should have received a copy of the GNU General Public License version
18 | * 2 along with this work; if not, write to the Free Software Foundation,
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 | *
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 | * or visit www.oracle.com if you need additional information or have any
23 | * questions.
24 | */
25 |
26 | var moduleSearchIndex;
27 | var packageSearchIndex;
28 | var typeSearchIndex;
29 | var memberSearchIndex;
30 | var tagSearchIndex;
31 | function loadScripts(doc, tag) {
32 | createElem(doc, tag, 'search.js');
33 |
34 | createElem(doc, tag, 'module-search-index.js');
35 | createElem(doc, tag, 'package-search-index.js');
36 | createElem(doc, tag, 'type-search-index.js');
37 | createElem(doc, tag, 'member-search-index.js');
38 | createElem(doc, tag, 'tag-search-index.js');
39 | }
40 |
41 | function createElem(doc, tag, path) {
42 | var script = doc.createElement(tag);
43 | var scriptElement = doc.getElementsByTagName(tag)[0];
44 | script.src = pathtoroot + path;
45 | scriptElement.parentNode.insertBefore(script, scriptElement);
46 | }
47 |
48 | function show(tableId, selected, columns) {
49 | if (tableId !== selected) {
50 | document.querySelectorAll('div.' + tableId + ':not(.' + selected + ')')
51 | .forEach(function (elem) {
52 | elem.style.display = 'none';
53 | });
54 | }
55 | document.querySelectorAll('div.' + selected)
56 | .forEach(function (elem, index) {
57 | elem.style.display = '';
58 | var isEvenRow = index % (columns * 2) < columns;
59 | elem.classList.remove(isEvenRow ? oddRowColor : evenRowColor);
60 | elem.classList.add(isEvenRow ? evenRowColor : oddRowColor);
61 | });
62 | updateTabs(tableId, selected);
63 | }
64 |
65 | function updateTabs(tableId, selected) {
66 | document.querySelector('div#' + tableId + ' .summary-table')
67 | .setAttribute('aria-labelledby', selected);
68 | document.querySelectorAll('button[id^="' + tableId + '"]')
69 | .forEach(function (tab, index) {
70 | if (selected === tab.id || (tableId === selected && index === 0)) {
71 | tab.className = activeTableTab;
72 | tab.setAttribute('aria-selected', true);
73 | tab.setAttribute('tabindex', 0);
74 | } else {
75 | tab.className = tableTab;
76 | tab.setAttribute('aria-selected', false);
77 | tab.setAttribute('tabindex', -1);
78 | }
79 | });
80 | }
81 |
82 | function switchTab(e) {
83 | var selected = document.querySelector('[aria-selected=true]');
84 | if (selected) {
85 | if ((e.keyCode === 37 || e.keyCode === 38) && selected.previousSibling) {
86 | // left or up arrow key pressed: move focus to previous tab
87 | selected.previousSibling.click();
88 | selected.previousSibling.focus();
89 | e.preventDefault();
90 | } else if ((e.keyCode === 39 || e.keyCode === 40) && selected.nextSibling) {
91 | // right or down arrow key pressed: move focus to next tab
92 | selected.nextSibling.click();
93 | selected.nextSibling.focus();
94 | e.preventDefault();
95 | }
96 | }
97 | }
98 |
99 | var updateSearchResults = function () {
100 | };
101 |
102 | function indexFilesLoaded() {
103 | return moduleSearchIndex
104 | && packageSearchIndex
105 | && typeSearchIndex
106 | && memberSearchIndex
107 | && tagSearchIndex;
108 | }
109 |
110 | function copySnippet(button) {
111 | var textarea = document.createElement("textarea");
112 | textarea.style.height = 0;
113 | document.body.appendChild(textarea);
114 | textarea.value = button.nextElementSibling.innerText;
115 | textarea.select();
116 | document.execCommand("copy");
117 | document.body.removeChild(textarea);
118 | var span = button.firstElementChild;
119 | var copied = span.getAttribute("data-copied");
120 | if (span.innerHTML !== copied) {
121 | var initialLabel = span.innerHTML;
122 | span.innerHTML = copied;
123 | var parent = button.parentElement;
124 | parent.onmouseleave = parent.ontouchend = function () {
125 | span.innerHTML = initialLabel;
126 | };
127 | }
128 | }
129 |
130 | // Workaround for scroll position not being included in browser history (8249133)
131 | document.addEventListener("DOMContentLoaded", function (e) {
132 | var contentDiv = document.querySelector("div.flex-content");
133 | window.addEventListener("popstate", function (e) {
134 | if (e.state !== null) {
135 | contentDiv.scrollTop = e.state;
136 | }
137 | });
138 | window.addEventListener("hashchange", function (e) {
139 | history.replaceState(contentDiv.scrollTop, document.title);
140 | });
141 | contentDiv.addEventListener("scroll", function (e) {
142 | var timeoutID;
143 | if (!timeoutID) {
144 | timeoutID = setTimeout(function () {
145 | history.replaceState(contentDiv.scrollTop, document.title);
146 | timeoutID = null;
147 | }, 100);
148 | }
149 | });
150 | if (!location.hash) {
151 | history.replaceState(contentDiv.scrollTop, document.title);
152 | }
153 | });
154 |
--------------------------------------------------------------------------------
/docs/tag-search-index.js:
--------------------------------------------------------------------------------
1 | tagSearchIndex = [];
2 | updateSearchResults();
--------------------------------------------------------------------------------
/docs/type-search-index.js:
--------------------------------------------------------------------------------
1 | typeSearchIndex = [{"l": "All Classes and Interfaces", "u": "allclasses-index.html"}, {
2 | "p": "be.cmbsoft.ilda",
3 | "l": "IldaFrame"
4 | }, {"p": "be.cmbsoft.ilda", "l": "IldaPalette"}, {"p": "be.cmbsoft.ilda", "l": "IldaPoint"}, {
5 | "p": "be.cmbsoft.ilda",
6 | "l": "IldaReader"
7 | }, {"p": "be.cmbsoft.ilda", "l": "IldaRenderer"}, {"p": "be.cmbsoft.ilda", "l": "IldaWriter"}, {
8 | "p": "be.cmbsoft.ilda",
9 | "l": "OptimisationSettings"
10 | }, {"p": "be.cmbsoft.ilda", "l": "Optimiser"}, {"p": "be.cmbsoft.ilda", "l": "PicReader"}, {
11 | "p": "be.cmbsoft.ilda",
12 | "l": "Utilities"
13 | }];
14 | updateSearchResults();
--------------------------------------------------------------------------------
/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/CircuitPulse/Particle.pde:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/examples-wip/LsxLiveOscOutput/CircuitPulse/Particle.pde
--------------------------------------------------------------------------------
/examples-wip/LsxLiveOscOutput/LoadAndDisplayIldaFile/LoadAndDisplayIldaFile.pde:
--------------------------------------------------------------------------------
1 | import be.cmbsoft.ilda.*;
2 | import be.cmbsoft.laseroutput.*;
3 | import java.util.*;
4 |
5 | List theFrames = new ArrayList();
6 | LsxOscOutput output;
7 |
8 | void setup()
9 | {
10 | size(600, 600, P3D);
11 | output = new LsxOscOutput(1, 10, "127.0.0.1", 10000);
12 |
13 | theFrames = IldaReader.readFile(this, "lines.ild");
14 | smooth();
15 | }
16 |
17 | void draw()
18 | {
19 | background(00);
20 | IldaFrame currentFrame = theFrames.get(0);
21 | currentFrame.renderFrame(this);
22 | output.project(currentFrame);
23 | }
--------------------------------------------------------------------------------
/examples-wip/LsxLiveOscOutput/LoadAndDisplayIldaFile/data/lines.ild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/examples-wip/LsxLiveOscOutput/LoadAndDisplayIldaFile/data/lines.ild
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/examples-wip/LsxLiveOscOutput/RectanglesToLSX/ildaframeToLsx.pde:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/examples-wip/LsxLiveOscOutput/RectanglesToLSX/ildaframeToLsx.pde
--------------------------------------------------------------------------------
/examples-wip/LsxLiveOscOutput/RectanglesToLSX/sketch.properties:
--------------------------------------------------------------------------------
1 | mode.id=processing.mode.java.JavaMode
2 | mode=Java
3 |
--------------------------------------------------------------------------------
/examples-wip/Optimisation/Optimisation.pde:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/examples-wip/Optimisation/Optimisation.pde
--------------------------------------------------------------------------------
/examples-wip/Optimisation/sketch.properties:
--------------------------------------------------------------------------------
1 | mode.id = processing.mode.java.JavaMode
2 | mode = Java
3 |
--------------------------------------------------------------------------------
/examples-wip/Rectangles/Rectangles.pde:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/examples-wip/Rectangles/Rectangles.pde
--------------------------------------------------------------------------------
/examples/AudioEffects/AudioEffects.pde:
--------------------------------------------------------------------------------
1 | import processing.sound.*;
2 |
3 | import be.cmbsoft.ilda.*;
4 | import be.cmbsoft.laseroutput.*;
5 |
6 |
7 | // Use graphic calls on the IldaRenderer object to create laser art
8 | IldaRenderer r;
9 |
10 | // The output can receive laser art from the renderer and send it to a laser
11 | LaserOutput output;
12 |
13 | boolean showPointCount = true;
14 |
15 | AudioIn input;
16 | Amplitude amplitude;
17 | Waveform waveform;
18 | FFT fft;
19 |
20 | AudioIn inputRight;
21 | Amplitude amplitudeRight;
22 |
23 | int samples = 200;
24 | int bands = 256;
25 | int maxBand = 16;
26 |
27 | int effectIndex = 0;
28 | int amountOfEffects = 4;
29 |
30 | Effect currentEffect;
31 |
32 | void setup() {
33 | // Since the projection surface of the laser effect is a square, use a square canvas in Processing
34 | size(800, 800, P3D);
35 |
36 | input = new AudioIn(this, 0);
37 | input.start();
38 |
39 | inputRight = new AudioIn(this, 1);
40 | inputRight.start();
41 |
42 | amplitude = new Amplitude(this);
43 | amplitude.input(input);
44 |
45 | amplitudeRight = new Amplitude(this);
46 | amplitudeRight.input(inputRight);
47 |
48 | waveform = new Waveform(this, samples);
49 | waveform.input(input);
50 |
51 | fft = new FFT(this, bands);
52 | fft.input(input);
53 |
54 | // The renderer requires just a reference to the sketch
55 | r = new IldaRenderer(this);
56 |
57 | // Because we are continuously sending to a laser in real time, we don't want to keep everything that's been rendered
58 | // in memory. That's what this method does: it tells the renderer to keep writing to the same frame instead of making
59 | // a new frame every time we call r.beginDraw(). If we would want to export the animation to a file, this should be
60 | // false.
61 | r.setOverwrite(true);
62 |
63 | // The LSX OSC output sends frames over OSC to LSX.
64 | output = new LsxOscOutput(1, // Timeline (projector number)
65 | 10, // Frame catalog index
66 | "127.0.0.1", // IP address of computer running LSX
67 | 10000 // Port of the LSX OSC server. This can be changed using Setup >> Remote Control >> OSC Setup >> Listening port.
68 | );
69 |
70 | nextEffect();
71 | }
72 |
73 | void draw() {
74 |
75 |
76 | // Clear the Processing window
77 | background(0);
78 |
79 | // It is required to call beginDraw() and endDraw() on the laser renderer
80 | r.beginDraw();
81 |
82 | // Reset the frame
83 | r.background();
84 |
85 | currentEffect.display(r);
86 |
87 | // Calling beginDraw() requires calling endDraw()
88 | r.endDraw();
89 |
90 | // Retrieve the freshly created frame from the renderer
91 | IldaFrame currentFrame = r.getCurrentFrame();
92 |
93 | // This will display the laser frame in the Processing window
94 | currentFrame.renderFrame(this);
95 |
96 | // Display the point count on the screen, toggle with "P" on the keyboard.
97 | // It's a good idea to limit point count to 1500 points to reduce flickering.
98 | if (showPointCount) {
99 | int pointCount = currentFrame.getPointCount();
100 | fill(255);
101 | if (pointCount > 1500) {
102 | fill(255, 0, 0);
103 | }
104 | text(pointCount, 20, 20);
105 | }
106 |
107 | // This will send the laser frame to the laser
108 | output.project(currentFrame);
109 | }
110 |
111 | void keyPressed() {
112 | // Toggle the point count display
113 | if (key == 'P' || key == 'p') {
114 | showPointCount = !showPointCount;
115 | }
116 | if (key == CODED) {
117 | if (keyCode == LEFT) {
118 | previousEffect();
119 | } else if (keyCode == RIGHT) {
120 | nextEffect();
121 | }
122 | }
123 | }
124 |
125 | void exit() {
126 | // It is a good idea to clear output to the projector when exiting
127 | output.sendEmptyFrame();
128 | super.exit();
129 | }
130 |
131 | void nextEffect() {
132 | setEffect(++effectIndex >= amountOfEffects ? effectIndex = 0 : effectIndex);
133 | }
134 |
135 | void previousEffect() {
136 | setEffect(--effectIndex < 0 ? effectIndex = amountOfEffects-1 : effectIndex);
137 | }
138 |
139 | void setEffect(int index) {
140 | switch(index) {
141 | case 0:
142 | default:
143 | currentEffect = new WaveformEffect();
144 | break;
145 | case 1:
146 | currentEffect = new SpectrumBarsEffect();
147 | break;
148 | case 2:
149 | currentEffect = new VUEffect();
150 | break;
151 | case 3:
152 | currentEffect = new CircleWaveEffect();
153 | break;
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/examples/AudioEffects/CircleWaveEffect.pde:
--------------------------------------------------------------------------------
1 | class CircleWaveEffect extends Effect {
2 |
3 | int hue;
4 | float radius;
5 |
6 | public CircleWaveEffect() {
7 | hue = (int) random(255);
8 | radius = random(width/2)+10;
9 | }
10 |
11 | @Override
12 | void display(IldaRenderer r) {
13 | waveform.analyze();
14 | float intensity = amplitude.analyze();
15 | float angle = mousePressed ? HALF_PI : TAU/samples;
16 | r.colorMode(HSB);
17 |
18 |
19 | r.resetMatrix();
20 | r.translate(width/2, height/2);
21 | r.beginShape(LINE);
22 | for (int i = 0; i < samples; i++) {
23 | float data = abs(waveform.data[i]);
24 | float offset = data*radius+radius/4;
25 | r.stroke(hue+intensity*50, 255, map(data, 0, 0.5, 25, 255));
26 | r.vertex(offset, offset);
27 | r.rotate(angle);
28 | }
29 | r.endShape();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/examples/AudioEffects/Effect.pde:
--------------------------------------------------------------------------------
1 | abstract class Effect {
2 | abstract void display(IldaRenderer renderer);
3 | }
4 |
--------------------------------------------------------------------------------
/examples/AudioEffects/SpectrumBarsEffect.pde:
--------------------------------------------------------------------------------
1 | class SpectrumBarsEffect extends Effect {
2 |
3 | int barWidth;
4 |
5 | public SpectrumBarsEffect() {
6 | barWidth = width/maxBand;
7 | }
8 |
9 | @Override
10 | void display(IldaRenderer r) {
11 | r.colorMode(HSB);
12 | fft.analyze();
13 | for (int i = 0; i < maxBand; i++) {
14 | float signal = fft.spectrum[i];
15 | r.stroke(map(signal, 0, 0.5, 90, 0), 255, 255);
16 | // Draw the rectangles, adjust their height using the scale factor
17 | r.rect(i*barWidth, height, barWidth, -signal*height*2);
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/examples/AudioEffects/VUEffect.pde:
--------------------------------------------------------------------------------
1 | class VUEffect extends Effect {
2 |
3 | int bars = 10;
4 | int barWidth = height/bars-10;
5 |
6 | public VUEffect() {
7 | }
8 |
9 | @Override
10 | void display(IldaRenderer r) {
11 | r.colorMode(HSB);
12 | float signalLeft=map(amplitude.analyze(), 0, 0.5, 0, bars);
13 | float signalRight=map(amplitudeRight.analyze(), 0, 0.5, 0, bars);
14 |
15 | for (int i = 0; i < bars; i++) {
16 | if (signalLeft >= i) {
17 | r.stroke(map(i, 0, bars, 90, 0), 255, 255);
18 | r.rect(width/2-barWidth-10, height-(i+1)*(barWidth+10), barWidth, barWidth);
19 | }
20 | if (signalRight >= i) {
21 | r.stroke(map(i, 0, bars, 90, 0), 255, 255);
22 | r.rect(width/2+barWidth+10, height-(i+1)*(barWidth+10), barWidth, barWidth);
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/examples/AudioEffects/WaveformEffect.pde:
--------------------------------------------------------------------------------
1 | class WaveformEffect extends Effect {
2 |
3 | int hue;
4 |
5 | public WaveformEffect() {
6 | hue = (int) random(255);
7 | }
8 |
9 | @Override
10 | void display(IldaRenderer r) {
11 | waveform.analyze();
12 | float intensity = amplitude.analyze();
13 | r.stroke(hue, 255, map(intensity, 0, 0.3, 25, 255));
14 |
15 | r.beginShape(LINE);
16 | for (int i = 0; i < samples; i++) {
17 | r.vertex(map(i, 0, samples, 0, width), map(waveform.data[i], -1, 1, 0, height));
18 | }
19 | r.endShape();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/examples/Beams/BeamEffect.pde:
--------------------------------------------------------------------------------
1 | class BeamEffect extends Effect {
2 |
3 | int amount = 10;
4 | float speed = 0.1f;
5 | PVector[] positions = new PVector[amount];
6 | PVector[] oldPositions = new PVector[amount];
7 |
8 | public BeamEffect() {
9 | assignRandomPositions();
10 | for (int i = 0; i < positions.length; i++) {
11 | oldPositions[i] = positions[i];
12 | }
13 | }
14 |
15 | @Override
16 | void display(IldaRenderer renderer) {
17 | for (int i = 0; i < positions.length; i++) {
18 | renderer.stroke( i % 2 == 0 ? firstColor : secondColor);
19 | float x = oldPositions[i].x;
20 | float y = oldPositions[i].y;
21 | renderer.point(x, y);
22 | oldPositions[i].x = x + (positions[i].x-x)*speed;
23 | oldPositions[i].y = y + (positions[i].y-y)*speed;
24 | }
25 | }
26 |
27 | @Override
28 | void mouse() {
29 | if (mouseButton == RIGHT) {
30 | assignRandomPositions();
31 | }
32 | }
33 |
34 | void assignRandomPositions() {
35 | for (int i = 0; i < positions.length; i++) {
36 | positions[i] = new PVector((int) random(width), (int) random(height));
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/examples/Beams/ConeEffect.pde:
--------------------------------------------------------------------------------
1 | class ConeEffect extends Effect {
2 |
3 | int amount = 6;
4 |
5 | float radius = 50;
6 | float effectRadius = 0.8f;
7 | float speed = 1f;
8 |
9 | float oldRadius = radius;
10 | float oldEffectRadius = effectRadius;
11 | float oldSpeed = 0;
12 |
13 | float effectSpeed = 0.1f;
14 | double previousTime = millis();
15 | double time =0;
16 |
17 | public ConeEffect() {
18 | randomize();
19 | randomizeAmount();
20 | }
21 |
22 | void display(IldaRenderer renderer) {
23 | renderer.setEllipseDetail(0.3);
24 | renderer.setEllipseCorrection(1);
25 | oldRadius = oldRadius + (radius-oldRadius)*effectSpeed;
26 | oldEffectRadius = oldEffectRadius + (effectRadius - oldEffectRadius)*effectSpeed;
27 | oldSpeed = oldSpeed + (speed - oldSpeed)*effectSpeed;
28 | time = time + (millis() - previousTime)*oldSpeed;
29 | previousTime = millis();
30 |
31 | for (int i = 0; i < amount; i++) {
32 |
33 | double phase = TWO_PI* (map(i, 0, amount, 0, 1) + time);
34 | renderer.stroke( i % 2 == 0 ? firstColor : secondColor);
35 | renderer.ellipse((float)(width*(0.5+0.5*oldEffectRadius*Math.sin(phase))), (float)( height*(0.5+0.5*oldEffectRadius*Math.cos(phase))), oldRadius, oldRadius);
36 | }
37 | }
38 |
39 | void mouse() {
40 | if (mouseButton == RIGHT) {
41 | randomize();
42 | } else if (mouseButton == CENTER) {
43 | randomizeAmount();
44 | }
45 | }
46 |
47 | void randomize() {
48 | radius = random(20, 100);
49 | effectRadius = random(0.2, 0.9);
50 | speed = (random(1) < 0.5 ? -1 : 1) * random(0.00005, 0.0003);
51 | }
52 |
53 | void randomizeAmount() {
54 | amount = (int) random(1, 6)*2;
55 | };
56 | }
57 |
--------------------------------------------------------------------------------
/examples/Beams/Effect.pde:
--------------------------------------------------------------------------------
1 | abstract class Effect {
2 | abstract void display(IldaRenderer renderer);
3 |
4 | abstract void mouse();
5 | }
6 |
--------------------------------------------------------------------------------
/examples/Beams/LineEffect.pde:
--------------------------------------------------------------------------------
1 | class LineEffect extends Effect {
2 |
3 | float effectSpeed = 0.05f;
4 |
5 | float offset = height/2;
6 | float angle = 0;
7 |
8 | float oldOffset = offset;
9 | float oldAngle = angle;
10 |
11 | boolean dots = false;
12 |
13 | public LineEffect() {
14 | randomize();
15 | }
16 |
17 | void display(IldaRenderer renderer) {
18 |
19 | oldAngle = oldAngle + (angle - oldAngle)*effectSpeed;
20 | oldOffset = oldOffset + (offset - oldOffset)*effectSpeed;
21 |
22 | renderer.pushMatrix();
23 | renderer.translate(width/2, height/2);
24 | renderer.rotateZ(oldAngle);
25 | renderer.translate(-width/2, -height/2+oldOffset);
26 | if (dots) {
27 | renderer.stroke(secondColor);
28 | renderer.point(10, 0);
29 | renderer.point(20, 0);
30 | renderer.point(30, 0);
31 | }
32 | renderer.stroke(firstColor);
33 | renderer.line(dots?40:0, 0, dots?width-40:width, 0);
34 | if (dots) {
35 | renderer.stroke(secondColor);
36 | renderer.point(width-30, 0);
37 | renderer.point(width-20, 0);
38 | renderer.point(width-10, 0);
39 | }
40 | renderer.popMatrix();
41 | }
42 |
43 | void mouse() {
44 | if (mouseButton == RIGHT) {
45 | randomize();
46 | } else if (mouseButton == CENTER) {
47 | toggleDots();
48 | }
49 | }
50 |
51 | void randomize() {
52 | offset = random(height/2-height/4, height/2+height/4);
53 | angle = random(0, TWO_PI);
54 | }
55 |
56 | void toggleDots() {
57 | dots = !dots;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/examples/Beams/SineEffect.pde:
--------------------------------------------------------------------------------
1 | class SineEffect extends Effect {
2 |
3 | int amount = 200;
4 |
5 | float frequency = 0;
6 | float amplitude = 0f;
7 | float speed = 1f;
8 |
9 | float oldFrequency = frequency;
10 | float oldAmplitude = amplitude;
11 | float oldSpeed = 0;
12 |
13 | float effectSpeed = 0.1f;
14 | double previousTime = millis();
15 | double time = 0;
16 |
17 | boolean dots = false;
18 | int shapeKind = LINES;
19 |
20 | public SineEffect() {
21 | randomize();
22 | }
23 |
24 | void display(IldaRenderer renderer) {
25 | oldFrequency = oldFrequency + (frequency-oldFrequency)*effectSpeed*0.2f;
26 | oldAmplitude = oldAmplitude + (amplitude - oldAmplitude)*effectSpeed;
27 | oldSpeed = oldSpeed + (speed - oldSpeed)*effectSpeed;
28 | time = time + (millis() - previousTime)*oldSpeed;
29 | previousTime = millis();
30 | renderer.beginShape(shapeKind);
31 |
32 | for (int i = 0; i < amount; i++) {
33 |
34 | double phase = TWO_PI* (map(i-amount/2, 0, amount, 0, oldFrequency) + time);
35 | renderer.stroke( lerpColor(firstColor, secondColor, abs(map(i, 0, amount, 0, 2)-1)));
36 | renderer.vertex((width*i)/amount, (float)(height*(0.5+0.5*oldAmplitude*Math.sin(phase))));
37 | }
38 | renderer.endShape();
39 | }
40 |
41 | void mouse() {
42 | if (mouseButton == RIGHT) {
43 | randomize();
44 | } else if (mouseButton == CENTER) {
45 | toggleDots();
46 | }
47 | }
48 |
49 | void randomize() {
50 | frequency = (int)(7*randomGaussian()+1);
51 | amplitude = random(0.02, 0.5);
52 | speed = (random(1) < 0.5 ? -1 : 1) * random(0.00005, 0.0003);
53 | }
54 |
55 | void toggleDots() {
56 | if (dots = !dots) {
57 | shapeKind = POINTS;
58 | amount = 30;
59 | } else {
60 | shapeKind = LINES;
61 | amount = 200;
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/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/CircuitPulse/Particle.pde:
--------------------------------------------------------------------------------
1 | class Particle {
2 |
3 | ArrayList old = new ArrayList();
4 |
5 | float x, y, ang;
6 | float spd = 5;
7 | int sz = 5;
8 | int c;
9 |
10 | int tailLength = 50;
11 |
12 | boolean dead = false;
13 |
14 | Particle(float x, float y, float ang, int c) {
15 | this.x = x;
16 | this.y = y;
17 | this.ang = ang;
18 | this.c = c;
19 | }
20 |
21 | void update() {
22 | if (random(1) > 0.95) {
23 | if (random(1) > 0.5) {
24 | ang += PI/4;
25 | } else {
26 | ang -= PI/4;
27 | }
28 | }
29 |
30 | old.add(new PVector(x, y));
31 |
32 | while (old.size() > tailLength) {
33 | old.remove(0);
34 | }
35 |
36 | x += cos(ang) * spd;
37 | y += sin(ang) * spd;
38 |
39 | if (old.get(0).x < 0 || old.get(0).x > width || old.get(0).y < 0 || old.get(0).y > height) {
40 | dead = true;
41 | }
42 | }
43 |
44 | void show(PGraphics r) {
45 | r.beginShape(LINE);
46 | r.stroke(c, 255, 255);
47 | if (old.size() > 1) {
48 | for (int i = 0; i < old.size(); i ++) {
49 | r.stroke(c, 255, 255, map(i, 0, old.size() - 1, 0, 255));
50 | r.vertex(old.get(i).x, old.get(i).y, 0);
51 | }
52 | }
53 | r.endShape();
54 | }
55 | }
--------------------------------------------------------------------------------
/examples/LoadAndDisplayIldaFile/LoadAndDisplayIldaFile.pde:
--------------------------------------------------------------------------------
1 | import be.cmbsoft.ilda.*;
2 | import java.util.*;
3 |
4 | List theFrames = new ArrayList();
5 |
6 |
7 | void setup()
8 | {
9 | size(600, 600, P3D);
10 |
11 |
12 | theFrames = IldaReader.readFile(this, "lines.ild");
13 | smooth();
14 | }
15 |
16 | void draw()
17 | {
18 | background(00);
19 | theFrames.get(0).renderFrame(this);
20 |
21 | /*
22 | //This code will manually display the points
23 | List points = theFrames.get(0).getPoints();
24 | boolean firstPoint = true;
25 | float oldpositionx = 0;
26 | float oldpositiony = 0;
27 | float oldpositionz = 0;
28 | //println(points.size());
29 | for (IldaPoint point : points)
30 | {
31 | PVector position = point.getPosition(width, height, 0);//(width+height)*0.5);
32 | if ( !point.isBlanked())
33 | {
34 | strokeWeight(3);
35 | stroke(red(point.getColour()), green(point.getColour()), blue(point.getColour()));
36 | //stroke(random(255));
37 |
38 |
39 | point(position.x, position.y);
40 | //point(random(width), random(height));
41 | //println(red(point.getColour()), point.isBlanked(), position.x, position.y, position.z, oldpositionx, oldpositiony, oldpositionz);
42 | }
43 |
44 | if (!firstPoint)
45 | {
46 | strokeWeight(1);
47 | if (point.isBlanked()) stroke(0);
48 | else
49 | {
50 | line(position.x, position.y, oldpositionx, oldpositiony);
51 | }
52 | oldpositionx = position.x;
53 | oldpositiony = position.y;
54 | oldpositionz = position.z;
55 | } else
56 | {
57 | firstPoint = false;
58 | oldpositionx = position.x;
59 | oldpositiony = position.y;
60 | oldpositionz = position.z;
61 | }
62 | }
63 | */
64 | }
--------------------------------------------------------------------------------
/examples/LoadAndDisplayIldaFile/data/lines.ild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/examples/LoadAndDisplayIldaFile/data/lines.ild
--------------------------------------------------------------------------------
/examples/ParseFile/ParseFile.pde:
--------------------------------------------------------------------------------
1 | import be.cmbsoft.ilda.*;
2 | import be.cmbsoft.laseroutput.*;
3 | import java.util.*;
4 |
5 | List frames;
6 | LsxOscOutput output;
7 |
8 |
9 | void setup()
10 | {
11 | size(800, 800, P3D);
12 | output = new LsxOscOutput(1, 10, "127.0.0.1", 10000);
13 | try
14 | {
15 | //Read the Ilda file and retrieve the frames it contains
16 | frames = IldaReader.readFile(this, "Circles.ild");
17 | }
18 | catch(Exception e)
19 | {
20 | //Invalid ILDA file!
21 | e.printStackTrace();
22 | }
23 | println("There are", frames.size(), "frames in the ILDA file");
24 |
25 | frameRate(20);
26 | }
27 |
28 | void draw()
29 | {
30 | background(0);
31 |
32 | //Display the current frame on the Processing canvas
33 | IldaFrame currentFrame = frames.get(frameCount%frames.size());
34 | currentFrame.renderFrame(this);
35 | output.project(currentFrame);
36 | }
--------------------------------------------------------------------------------
/examples/ParseFile/data/Circles.ild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/colouredmirrorball/Ilda/a75a3f62ba0fc0858743e03f671fad048316f5cc/examples/ParseFile/data/Circles.ild
--------------------------------------------------------------------------------
/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/Rectangles/sketch.properties:
--------------------------------------------------------------------------------
1 | mode.id = processing.mode.java.JavaMode
2 | mode = Java
3 |
--------------------------------------------------------------------------------
/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/Text/Text.pde:
--------------------------------------------------------------------------------
1 | import be.cmbsoft.ilda.*;
2 | import be.cmbsoft.laseroutput.*;
3 |
4 | IldaRenderer r;
5 | LsxOscOutput output;
6 |
7 | String content;
8 |
9 | float offset;
10 | color colour;
11 |
12 | boolean showPointCount = true;
13 |
14 | void setup() {
15 |
16 | // Since the projection surface of the laser effect is a square, use a square canvas in Processing
17 | size(800, 800, P3D);
18 |
19 | // The IldaRenderer object can be used to draw on, similar to a PGraphics object
20 | r = new IldaRenderer(this);
21 |
22 | // Because we are continuously sending to a laser in real time, we don't want to keep everything that's been rendered
23 | // in memory. That's what this method does: it tells the renderer to keep writing to the same frame instead of making
24 | // a new frame every time we call r.beginDraw(). If we would want to export the animation to a file, this should be
25 | // false.
26 | r.setOverwrite(true);
27 |
28 | // The LSX OSC output sends frames over OSC to LSX.
29 | output = new LsxOscOutput(1, // Timeline (projector number)
30 | 10, // Frame catalog index
31 | "127.0.0.1", // IP address of computer running LSX
32 | 10000 // Port of the LSX OSC server. This can be changed using Setup >> Remote Control >> OSC Setup >> Listening port.
33 | );
34 |
35 | // Fetch some data from Wikipedia
36 | JSONObject json = loadJSONObject("https://en.wikipedia.org/api/rest_v1/page/random/summary");
37 | content = json.getString("extract").replace('\n', ' ');
38 | println(json.getString("title"));
39 | println(content);
40 |
41 | colorMode(HSB);
42 | colour = color(random(255), 255, 255);
43 |
44 | // Initialise some parameters in the renderer
45 | r.beginDraw();
46 | r.stroke(colour);
47 | r.textSize(height/4);
48 | r.endDraw();
49 |
50 | colorMode(RGB);
51 |
52 | offset = width;
53 | }
54 |
55 | void draw() {
56 | // Clear the Processing window
57 | background(0);
58 |
59 | // It is required to call beginDraw() and endDraw() on the laser renderer
60 | r.beginDraw();
61 |
62 | // Reset the frame
63 | r.background();
64 |
65 | // Draw some text
66 | r.text(content, offset, height/2);
67 |
68 | // Calling beginDraw() requires calling endDraw()
69 | r.endDraw();
70 | offset-=10;
71 | IldaFrame currentFrame = r.getCurrentFrame();
72 |
73 | // This will display the laser frame in the Processing window
74 | currentFrame.renderFrame(this);
75 |
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 |
85 | // This will send the laser frame to the laser
86 | output.project(currentFrame);
87 | }
88 |
89 | void keyPressed() {
90 | if (key == 'P' || key == 'p') {
91 | showPointCount = !showPointCount;
92 | }
93 | }
94 |
95 | void exit() {
96 | // It is a good idea to clear output to the projector when exiting
97 | output.sendEmptyFrame();
98 | super.exit();
99 | }
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.cmbsoft
8 | Ilda
9 | 0.1.3-SNAPSHOT
10 |
11 |
12 | 17
13 | 17
14 |
15 |
16 |
17 |
18 | org.processing
19 | core
20 | 4.3.2
21 | provided
22 |
23 |
24 | org.jogamp.gluegen
25 | gluegen-rt
26 |
27 |
28 | org.jogamp.jogl
29 | jogl-all
30 |
31 |
32 |
33 |
34 | org.jetbrains
35 | annotations
36 | 23.0.0
37 | compile
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/main/java/be/cmbsoft/ilda/FileParser.java:
--------------------------------------------------------------------------------
1 | package be.cmbsoft.ilda;
2 |
3 | import java.io.File;
4 | import java.io.FileNotFoundException;
5 |
6 | import processing.core.PApplet;
7 |
8 | class FileParser
9 | {
10 |
11 | protected byte[] b;
12 | protected int position = 0;
13 |
14 | public FileParser(File file) throws FileNotFoundException
15 | {
16 | b = PApplet.loadBytes(file);
17 | if (b == null)
18 | {
19 | throw new FileNotFoundException("Error: could not read file at " + file);
20 | }
21 | }
22 |
23 | byte parseByte()
24 | {
25 | return (byte) (b[position++] & 0xff);
26 | }
27 |
28 | short parseShort()
29 | {
30 | return (short) (b[position++] << 8 | (b[position++] & 0xff));
31 | }
32 |
33 | String parseString(int length) {
34 | StringBuilder out = new StringBuilder();
35 | for (int i = 0; i < length; i++) {
36 | out.append((char) b[position++]);
37 | }
38 | return out.toString();
39 | }
40 |
41 | void skip(int times) {
42 | for (int i = 0; i < times; i++) {
43 | position++;
44 | }
45 | }
46 |
47 | void reset() {
48 | position = 0;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/be/cmbsoft/ilda/IldaPalette.java:
--------------------------------------------------------------------------------
1 | package be.cmbsoft.ilda;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * A Palette is a collection of colours. Points in a format 0 or 1 file have an index referring
8 | * to a colour in a palette.
9 | * Changing a palette results in changing the colours of a frame.
10 | */
11 | public class IldaPalette
12 | {
13 | private final List colours = new ArrayList<>();
14 | private String name;
15 | private String companyName;
16 | private int paletteNumber;
17 | private int scannerHead;
18 |
19 | public void addColour(int r, int g, int b)
20 | {
21 | colours.add(((r & 0xFF) << 16) + ((g & 0xFF) << 8) + (b & 0xFF));
22 | }
23 |
24 | /**
25 | * Colors are stored as 32-bit integers, first eight bits are not used, next eight bits are red,
26 | * following eight bits are green and last eight bits are blue
27 | *
28 | * @param index number referring to the palette
29 | * @return the color in the aforementioned format
30 | */
31 |
32 | public int getColour(int index) {
33 | if (index >= colours.size() || index < 0) {return 0;} else {return colours.get(index);}
34 | }
35 |
36 | /**
37 | * Converts the palette to bytes which can be added in front of an ilda file or stored
38 | * separately
39 | *
40 | * @return array of bytes with ilda-compliant palette
41 | */
42 |
43 | public byte[] paletteToBytes() {
44 | byte[] result;
45 | ArrayList theBytes;
46 | theBytes = new ArrayList<>();
47 |
48 | IldaWriter.writeCommonIldaHeader(theBytes);
49 | theBytes.add((byte) 2); //version byte
50 |
51 | writeField(theBytes, name);
52 |
53 | if (companyName == null) //Bytes 17-24: Company Name
54 | {
55 | IldaWriter.writeCustomCompanyName(theBytes);
56 | } else {
57 | writeField(theBytes, companyName);
58 | }
59 |
60 | int totalSize = colours.size();
61 | if (totalSize < 1) {
62 | result = new byte[0];
63 | } else {
64 | if (totalSize > 255) {totalSize = 256;}
65 | theBytes
66 | .add((byte) ((totalSize >> 8) & 0xff)); //Bytes 25-26: total colours
67 | theBytes.add((byte) (totalSize & 0xff)); //Limited to 256 so byte 25 is redundant
68 | //Bytes 27-28: Palette number
69 | theBytes.add((byte) 0); //This better be correct
70 | theBytes.add((byte) 0);
71 | theBytes.add((byte) 0); //Bytes 29-30: Future
72 | theBytes.add((byte) 0);
73 | theBytes.add((byte) scannerHead); //Byte 31: Scanner head
74 | theBytes.add((byte) 0); //Also Future
75 | for (int i = 0; i < Math.min(256, colours.size()); i++) //Rest: colour data
76 | {
77 | int colour = colours.get(i);
78 | theBytes.add((byte) ((colour >> 16) & 0xFF));
79 | theBytes.add((byte) ((colour >> 8) & 0xFF));
80 | theBytes.add((byte) (colour & 0xFF));
81 | }
82 | byte[] bt = new byte[theBytes.size()];
83 | for (int i = 0; i < theBytes.size(); i++)
84 | {
85 | bt[i] = theBytes.get(i);
86 | }
87 | result = bt;
88 | }
89 |
90 | return result;
91 | }
92 |
93 | private void writeField(ArrayList theBytes, String companyName)
94 | {
95 | for (int i = 0; i < 8; i++)
96 | {
97 | char letter;
98 | if (companyName.length() < i + 1) {letter = ' ';}
99 | else
100 | {
101 | letter = companyName.charAt(i);
102 | }
103 | theBytes.add((byte) letter);
104 | }
105 | }
106 |
107 | /**
108 | * Converts this palette to the standard 64 color palette used in most programs
109 | */
110 |
111 | public void setDefaultPalette()
112 | {
113 | name = "Ilda64";
114 | companyName = "Ilda4P5";
115 | paletteNumber = 0;
116 | scannerHead = 0;
117 |
118 | colours.clear();
119 | addColour(255, 0, 0);
120 | addColour(255, 16, 0);
121 | addColour(255, 32, 0);
122 | addColour(255, 48, 0);
123 | addColour(255, 64, 0);
124 | addColour(255, 80, 0);
125 | addColour(255, 96, 0);
126 | addColour(255, 112, 0);
127 | addColour(255, 128, 0);
128 | addColour(255, 144, 0);
129 | addColour(255, 160, 0);
130 | addColour(255, 176, 0);
131 | addColour(255, 192, 0);
132 | addColour(255, 208, 0);
133 | addColour(255, 224, 0);
134 | addColour(255, 240, 0);
135 | addColour(255, 255, 0);
136 | addColour(224, 255, 0);
137 | addColour(192, 255, 0);
138 | addColour(160, 255, 0);
139 | addColour(128, 255, 0);
140 | addColour(96, 255, 0);
141 | addColour(64, 255, 0);
142 | addColour(32, 255, 0);
143 | addColour(0, 255, 0);
144 | addColour(0, 255, 32);
145 | addColour(0, 255, 64);
146 | addColour(0, 255, 96);
147 | addColour(0, 255, 128);
148 | addColour(0, 255, 160);
149 | addColour(0, 255, 192);
150 | addColour(0, 255, 224);
151 | addColour(0, 130, 255);
152 | addColour(0, 114, 255);
153 | addColour(0, 104, 255);
154 | addColour(10, 96, 255);
155 | addColour(0, 82, 255);
156 | addColour(0, 74, 255);
157 | addColour(0, 64, 255);
158 | addColour(0, 32, 255);
159 | addColour(0, 0, 255);
160 | addColour(32, 0, 255);
161 | addColour(64, 0, 255);
162 | addColour(96, 0, 255);
163 | addColour(128, 0, 255);
164 | addColour(160, 0, 255);
165 | addColour(192, 0, 255);
166 | addColour(224, 0, 255);
167 | addColour(255, 0, 255);
168 | addColour(255, 32, 255);
169 | addColour(255, 64, 255);
170 | addColour(255, 96, 255);
171 | addColour(255, 128, 255);
172 | addColour(255, 160, 255);
173 | addColour(255, 192, 255);
174 | addColour(255, 224, 255);
175 | addColour(255, 255, 255);
176 | addColour(255, 224, 224);
177 | addColour(255, 192, 192);
178 | addColour(255, 160, 160);
179 | addColour(255, 128, 128);
180 | addColour(255, 96, 96);
181 | addColour(255, 64, 64);
182 | addColour(15, 32, 32);
183 |
184 | }
185 |
186 | public List getColours()
187 | {
188 | return colours;
189 | }
190 |
191 | public int getColoursAmount()
192 | {
193 | return colours.size();
194 | }
195 |
196 | public String getName()
197 | {
198 | return name;
199 | }
200 |
201 | public void setName(String name)
202 | {
203 | this.name = name;
204 | }
205 |
206 | public String getCompanyName()
207 | {
208 | return companyName;
209 | }
210 |
211 | public void setCompanyName(String companyName)
212 | {
213 | this.companyName = companyName;
214 | }
215 |
216 | public int getPaletteNumber()
217 | {
218 | return paletteNumber;
219 | }
220 |
221 | public void setPaletteNumber(int paletteNumber)
222 | {
223 | this.paletteNumber = paletteNumber;
224 | }
225 |
226 | public int getScannerHead()
227 | {
228 | return scannerHead;
229 | }
230 |
231 | public void setScannerHead(int scannerHead)
232 | {
233 | this.scannerHead = scannerHead;
234 | }
235 |
236 | public void resizePalette(int newSize)
237 | {
238 | //Delete all colours that are above the new size:
239 | if (newSize < colours.size() && newSize >= 0)
240 | {
241 | colours.subList(newSize, colours.size()).clear();
242 | }
243 |
244 | //Add new black colour if the new size is bigger than the previous one:
245 | else
246 | {
247 | for (int i = colours.size(); i < newSize; i++)
248 | {
249 | colours.add(0);
250 | }
251 | }
252 | }
253 |
254 | public void addColour(int colour)
255 | {
256 | colours.add(colour);
257 | }
258 |
259 | }
260 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/main/java/be/cmbsoft/ilda/OptimisationSettings.java:
--------------------------------------------------------------------------------
1 | package be.cmbsoft.ilda;
2 |
3 | import processing.data.FloatList;
4 | import processing.data.JSONArray;
5 | import processing.data.JSONObject;
6 |
7 | /**
8 | * Bundles all optimisation settings, so they are easily shared across the package and easily
9 | * transported to other
10 | * projects. You can create a settings file for each projector and load it in all your sketches
11 | * and projects without
12 | * having to recreate the settings again.
13 | */
14 | public class OptimisationSettings
15 | {
16 |
17 | boolean interpolateLit;
18 | boolean interpolateBlanked;
19 | float maxDistLit = 0.01f;
20 | float maxDistBlank = 0.01f;
21 | boolean angleDwell = true;
22 | float angleDwellFactor = 1;
23 | boolean blankDwell = true;
24 | int blankDwellAmount = 11;
25 | boolean clippingEnabled;
26 | boolean reduceData = true;
27 | float[] clipBounds = new float[]{-1f, 1f, 1f, -1f};
28 |
29 | public OptimisationSettings()
30 | {
31 | interpolateLit = true;
32 | interpolateBlanked = true;
33 | clippingEnabled = true;
34 | }
35 |
36 | public float getAngleDwellFactor()
37 | {
38 | return angleDwellFactor;
39 | }
40 |
41 | public OptimisationSettings setAngleDwellFactor(float angleDwellFactor)
42 | {
43 | this.angleDwellFactor = angleDwellFactor;
44 | return this;
45 | }
46 |
47 | public boolean isBlankDwell()
48 | {
49 | return blankDwell;
50 | }
51 |
52 | public OptimisationSettings setBlankDwell(boolean blankDwell)
53 | {
54 | this.blankDwell = blankDwell;
55 | return this;
56 | }
57 |
58 | public int getBlankDwellAmount()
59 | {
60 | return blankDwellAmount;
61 | }
62 |
63 | public OptimisationSettings setBlankDwellAmount(int blankDwellAmount)
64 | {
65 | this.blankDwellAmount = blankDwellAmount;
66 | return this;
67 | }
68 |
69 | public float[] getClipBounds()
70 | {
71 | return clipBounds;
72 | }
73 |
74 | /**
75 | * Set the boundaries of the rectangle outside of which points should be clipped away
76 | *
77 | * @param clipBounds float array containing coordinates in the range -1..1, in this order: left, up, right, down
78 | * (clockwise)
79 | * @return this
80 | */
81 | public OptimisationSettings setClipBounds(float[] clipBounds)
82 | {
83 | this.clipBounds = clipBounds;
84 | return this;
85 | }
86 |
87 | public boolean isInterpolateLit()
88 | {
89 | return interpolateLit;
90 | }
91 |
92 | public OptimisationSettings setInterpolateLit(boolean interpolateLit)
93 | {
94 | this.interpolateLit = interpolateLit;
95 | return this;
96 | }
97 |
98 | public boolean isInterpolateBlanked()
99 | {
100 | return interpolateBlanked;
101 | }
102 |
103 | public OptimisationSettings setInterpolateBlanked(boolean interpolateBlanked)
104 | {
105 | this.interpolateBlanked = interpolateBlanked;
106 | return this;
107 | }
108 |
109 | public float getMaxDistLit()
110 | {
111 | return maxDistLit;
112 | }
113 |
114 | public OptimisationSettings setMaxDistLit(float maxDistLit)
115 | {
116 | this.maxDistLit = maxDistLit;
117 | return this;
118 | }
119 |
120 | public float getMaxDistBlank()
121 | {
122 | return maxDistBlank;
123 | }
124 |
125 | public OptimisationSettings setMaxDistBlank(float maxDistBlank)
126 | {
127 | this.maxDistBlank = maxDistBlank;
128 | return this;
129 | }
130 |
131 | public boolean isAngleDwell()
132 | {
133 | return angleDwell;
134 | }
135 |
136 | public OptimisationSettings setAngleDwell(boolean angleDwell)
137 | {
138 | this.angleDwell = angleDwell;
139 | return this;
140 | }
141 |
142 | public boolean isClippingEnabled()
143 | {
144 | return clippingEnabled;
145 | }
146 |
147 | public OptimisationSettings setClippingEnabled(boolean clippingEnabled)
148 | {
149 | this.clippingEnabled = clippingEnabled;
150 | return this;
151 | }
152 |
153 | public boolean isReduceData()
154 | {
155 | return reduceData;
156 | }
157 |
158 | public OptimisationSettings setReduceData(boolean reduceData)
159 | {
160 | this.reduceData = reduceData;
161 | return this;
162 | }
163 |
164 |
165 | public String toJSON()
166 | {
167 | JSONObject output = new JSONObject();
168 | output.setFloat("maxDistBlank", maxDistBlank);
169 | output.setFloat("maxDistLit", maxDistLit);
170 | output.setBoolean("isAngleDwell", angleDwell);
171 | output.setBoolean("isInterpolateBlanked", interpolateBlanked);
172 | output.setBoolean("isInterpolateLit", interpolateLit);
173 | output.setInt("blankDwellAmount", blankDwellAmount);
174 | output.setFloat("angleDwellFactor", angleDwellFactor);
175 | output.setBoolean("reduceData", reduceData);
176 | output.setBoolean("clippingEnabled", clippingEnabled);
177 | output.setJSONArray("clipBounds", new JSONArray(new FloatList(clipBounds)));
178 |
179 | return output.toString();
180 | }
181 |
182 | public void fromJSON(String json)
183 | {
184 | JSONObject input = JSONObject.parse(json);
185 | maxDistBlank = input.getFloat("maxDistBlank", maxDistBlank);
186 | maxDistLit = input.getFloat("maxDistLit", maxDistLit);
187 | angleDwell = input.getBoolean("isAngleDwell", angleDwell);
188 | interpolateBlanked = input.getBoolean("isInterpolateBlanked", interpolateBlanked);
189 | interpolateLit = input.getBoolean("isInterpolateLit", interpolateLit);
190 | blankDwellAmount = input.getInt("blankDwellAmount", blankDwellAmount);
191 | angleDwellFactor = input.getFloat("angleDwellFactor", angleDwellFactor);
192 | reduceData = input.getBoolean("reduceData", reduceData);
193 | clippingEnabled = input.getBoolean("clippingEnabled", clippingEnabled);
194 | clipBounds = input.getJSONArray("clipBounds").getFloatArray();
195 | }
196 |
197 |
198 | }
199 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/main/java/be/cmbsoft/ilda/Utilities.java:
--------------------------------------------------------------------------------
1 | package be.cmbsoft.ilda;
2 |
3 | public class Utilities
4 | {
5 |
6 | private Utilities()
7 | {
8 | throw new UnsupportedOperationException("Utility class");
9 | }
10 |
11 | public static void logException(Exception exception)
12 | {
13 | // TODO figure out best way to log
14 | exception.printStackTrace();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------