X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=_PandaDriver.pde;h=26ac3d74c49aedfdb306290417044f9119ec7baf;hb=344908672b7cfe1efba03f739ef945601dae1b8e;hp=d6cd995b69080193e90e0f401f04f0ca1b6cefb5;hpb=1d75c8a91217d2e9ff9d8b877a5e04f2f63afb00;p=SugarCubes.git diff --git a/_PandaDriver.pde b/_PandaDriver.pde index d6cd995..26ac3d7 100644 --- a/_PandaDriver.pde +++ b/_PandaDriver.pde @@ -1,6 +1,7 @@ import netP5.*; import oscP5.*; + /** * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND * @@ -15,15 +16,30 @@ import oscP5.*; * will be moved into GLucose once stabilized. */ public static class PandaDriver { - + + interface Listener { + public void onToggle(boolean enabled); + } + + private Listener listener = null; + // IP address public final String ip; + + public PandaMapping pm; + + private final static int PORT = 779; + + private final DatagramSocket socket; // Address to send to private final NetAddress address; // Whether board output is enabled private boolean enabled = false; + + // Frame count for Grizzlies + private int frameNum = 1; // OSC message private final OscMessage message; @@ -32,24 +48,45 @@ public static class PandaDriver { private final int[] points; // Packet data - private final byte[] packet = new byte[4*352]; // magic number, our UDP packet size + private final byte[] packet = new byte[4*280]; // magic number, our UDP packet size private static final int NO_POINT = -1; - public PandaDriver(String ip) { - this.ip = ip; - - // Initialize our OSC output stuff - address = new NetAddress(ip, 9001); - message = new OscMessage("/shady/pointbuffer"); - - // Build the array of points, initialize all to nothing - points = new int[PandaMapping.PIXELS_PER_BOARD]; - for (int i = 0; i < points.length; ++i) { - points[i] = NO_POINT; - } - } + private Model _model; + //////////////////////////////////////////////////////////////// + // + // READ THIS RIGHT NOW BEFORE YOU MODIFY THE BELOW!!!!!!!!!!!!! + // READ THIS RIGHT NOW BEFORE YOU MODIFY THE BELOW!!!!!!!!!!!!! + // READ THIS RIGHT NOW BEFORE YOU MODIFY THE BELOW!!!!!!!!!!!!! + // + // The mappings below indicate the physical order of strips + // connected to a pandaboard channel. The strip numbers are a + // reflection of how the model is built. + // + // For ANYTHING in the model which is a rectangular prism, + // which means Cubes, the BassBox, and each Speaker, the + // strips are numbered incrementally by face. The first + // face is always the FRONT, which you are looking at. + // The next face is the RIGHT, then the BACK, then the LEFT. + // + // For every face, the strips are ordered numerically moving + // clockwise from the the TOP LEFT. + // + // So, for a cube: + // + // Strip 0: front face, top strip, left to right + // Strip 1: front face, right strip, top to bottom + // Strip 2: front face, bottom strip, right to left + // Strip 3: front face, left strip, bottom to top + // + // Strip 4: right face, top strip, left to right + // ... and so on + // Strip 14: left face, bottom strip, right to left + // Strip 15: left face, left strip, bottom to top + // + //////////////////////////////////////////////////////////////// + private final static int FORWARD = -1; private final static int BACKWARD = -2; @@ -59,16 +96,23 @@ public static class PandaDriver { * corner of the cube the data wire comes in. */ private final static int[][] CUBE_STRIP_ORDERINGS = new int[][] { +// { 2, 1, 0, 3, 13, 12, 15, 14, 4, 7, 6, 5, 11, 10, 9, 8 }, // FRONT_LEFT +// { 6, 5, 4, 7, 1, 0, 3, 2, 8, 11, 10, 9, 15, 14, 13, 12 }, // FRONT_RIGHT +// { 14, 13, 12, 15, 9, 8, 11, 10, 0, 3, 2, 1, 7, 6, 5, 4 }, // REAR_LEFT +// { 10, 9, 8, 11, 5, 4, 7, 6, 12, 15, 14, 13, 3, 2, 1, 0 }, // REAR_RIGHT + + { 2, 1, 0, 3, 13, 12, 15, 14, 4, 7, 6, 5, 11, 10, 9, 8 }, // FRONT_LEFT { 6, 5, 4, 7, 1, 0, 3, 2, 8, 11, 10, 9, 15, 14, 13, 12 }, // FRONT_RIGHT { 14, 13, 12, 15, 9, 8, 11, 10, 0, 3, 2, 1, 7, 6, 5, 4 }, // REAR_LEFT - { 10, 9, 8, 11, 5, 4, 7, 6, 12, 15, 14, 13, 3, 2, 1, 0 }, // REAR_RIGHT + { 9, 8, 11, 5, 4, 7, 6, 10, 14, 2, 1, 0, 3, 13, 12, 15 }, // REAR_RIGHT + }; private final static int[][] BASS_STRIP_ORDERING = { // front face, counterclockwise from bottom front left - {2, BACKWARD }, - {1, BACKWARD }, + {2, BACKWARD /* if this strip has extra pixels, you can add them here */ /*, 4 */ }, + {1, BACKWARD /* if this strip is short some pixels, substract them here */ /*, -3 */ }, {0, BACKWARD }, {3, BACKWARD }, @@ -98,7 +142,7 @@ public static class PandaDriver { {3, FORWARD}, {2, BACKWARD}, {1, FORWARD}, - {0, BACKWARD, /* dummy pixels at the end of string, remove when strip is fixed */ 4}, + {0, BACKWARD}, {7, FORWARD}, }; @@ -113,7 +157,7 @@ public static class PandaDriver { // as cubes with Wiring.FRONT_LEFT. If this needs to be changed, // remove this null assignment and change the below to have mappings // for the LEFT and RIGHT speaker - private final static int[][][] SPEAKER_STRIP_ORDERING = null; /* { + private final static int[][][] SPEAKER_STRIP_ORDERING = { // Left speaker { // Front face, counter-clockwise from bottom left @@ -130,20 +174,38 @@ public static class PandaDriver { {0, BACKWARD }, {3, BACKWARD }, } - };*/ - - private final static int[][] LEFT_SPEAKER_STRIP_ORDERING = { }; - - public PandaDriver(String ip, Model model, PandaMapping pm) { - this(ip); + public PandaDriver(String ip) { + this.ip = ip; + + // Initialize our OSC output stuff + address = new NetAddress(ip, 779); + message = new OscMessage("/shady/pointbuffer"); + + try { + socket = new DatagramSocket(); + } catch (Exception x) { + throw new RuntimeException(x); + } + + // Build the array of points, initialize all to nothing + points = new int[PandaMapping.PIXELS_PER_BOARD]; + for (int i = 0; i < points.length; ++i) { + points[i] = NO_POINT; + } + } + + public PandaDriver(String ip, Model model, PandaMapping _pm) { + this(ip); + pm = _pm; + _model = model; // Ok, we are initialized, time to build the array if points in order to // send out. We start at the head of our point buffer, and work our way // down. This is the order in which points will be sent down the wire. int ci = -1; - // Iterate through all our channels + // Iterate through all our channelq s for (ChannelMapping channel : pm.channelList) { ++ci; int pi = ci * ChannelMapping.PIXELS_PER_CHANNEL; @@ -168,6 +230,9 @@ public static class PandaDriver { case REAR_RIGHT: stripOrderIndex = 3; break; } + // TODO(mcslee): clean up, ordering always consistent now + stripOrderIndex = 2; + // Iterate through all the strips on the cube and add the points for (int stripIndex : CUBE_STRIP_ORDERINGS[stripOrderIndex]) { // We go backwards here... in the model strips go clockwise, but @@ -227,12 +292,20 @@ public static class PandaDriver { } private int mapStrip(Strip s, int direction, int[] points, int pi) { + return mapStrip(s, direction, points, pi, s.points.size()); + } + + private int mapStrip(Strip s, int direction, int[] points, int pi, int len) { if (direction == FORWARD) { - for (Point p : s.points) { + int i = 0; + for (LXPoint p : s.points) { points[pi++] = p.index; + if (++i >= len) { + break; + } } } else if (direction == BACKWARD) { - for (int i = s.points.size()-1; i >= 0; --i) { + for (int i = len-1; i >= 0; --i) { points[pi++] = s.points.get(i).index; } } else { @@ -241,64 +314,125 @@ public static class PandaDriver { return pi; } - public void disable() { - if (enabled) { - enabled = false; - println("PandaBoard/" + ip + ": OFF"); + public PandaDriver setListener(Listener listener) { + this.listener = listener; + return this; + } + + public void setEnabled(boolean enabled) { + if (this.enabled != enabled) { + this.enabled = enabled; + println("PandaBoard/" + ip + ": " + (enabled ? "ON" : "OFF")); + if (listener != null) { + listener.onToggle(enabled); + } } } + public boolean isEnabled() { + return this.enabled; + } + + public void disable() { + setEnabled(false); + } + public void enable() { - if (!enabled) { - enabled = true; - println("PandaBoard/" + ip + ": ON"); - } + setEnabled(true); } public void toggle() { - enabled = !enabled; - println("PandaBoard/" + ip + ": " + (enabled ? "ON" : "OFF")); + setEnabled(!enabled); } + private final int[] GRIZZLY_STRIP_ORDERING = new int[] { 9, 8, 11, 5, 4, 7, 6, 10, 14, 2, 1, 0, 3, 13, 12, 15 }; + public final void send(int[] colors) { if (!enabled) { return; } + frameNum++; int len = 0; int packetNum = 0; - for (int index : points) { - int c = (index < 0) ? 0 : colors[index]; - byte r = (byte) ((c >> 16) & 0xFF); - byte g = (byte) ((c >> 8) & 0xFF); - byte b = (byte) ((c) & 0xFF); - packet[len++] = 0; // alpha channel, unused but makes for 4-byte alignment - packet[len++] = r; - packet[len++] = g; - packet[len++] = b; - - // Flush once packet is full buffer size - if (len >= packet.length) { - sendPacket(packetNum++); - len = 0; + for (ChannelMapping channel : pm.channelList) { + for (int rawCubeIndex : channel.objectIndices) { + if (rawCubeIndex > 0) { + Cube cube = _model.getCubeByRawIndex(rawCubeIndex); + + // TODO(mcslee): clean this up, precompute paths + for (int stripIndex : GRIZZLY_STRIP_ORDERING) { + Strip strip = cube.strips.get(stripIndex); + int stripLen = ((stripIndex == 9) || (stripIndex == 16)) ? 15 : 16; + for (int i = stripLen-1; i >= 0; --i) { + int c = colors[strip.points.get(i).index]; + byte r = (byte) ((c >> 16) & 0xFF); + byte g = (byte) ((c >> 8) & 0xFF); + byte b = (byte) ((c) & 0xFF); + packet[len++] = (byte) 0; // alpha channel, unused but makes for 4-byte alignment + packet[len++] = (byte) r; + packet[len++] = (byte) g; + packet[len++] = (byte) b; + } + } + +// for (LXPoint p : cube.points) { +// int c = (p.index < 0) ? 0 : colors[p.index]; +// byte r = (byte) ((c >> 16) & 0xFF); +// byte g = (byte) ((c >> 8) & 0xFF); +// byte b = (byte) ((c) & 0xFF); +// packet[len++] = (byte) 0; // alpha channel, unused but makes for 4-byte alignment +// packet[len++] = (byte) r; +// packet[len++] = (byte) g; +// packet[len++] = (byte) b; +// } + } } + // println("Packet number: " + packetNum); + sendPacket(frameNum, packetNum++); + len = 0; } + // for (int index : points) { + // int c = (index < 0) ? 0 : colors[index]; + // byte r = (byte) ((c >> 16) & 0xFF); + // byte g = (byte) ((c >> 8) & 0xFF); + // byte b = (byte) ((c) & 0xFF); + // packet[len++] = 0; // alpha channel, unused but makes for 4-byte alignment + // packet[len++] = r; + // packet[len++] = g; + // packet[len++] = b; - // Flush any remaining data - if (len > 0) { - sendPacket(packetNum++); - } + // // Flush once packet is full buffer size + // if (len >= packet.length) { + // sendPacket(packetNum++); + // len = 0; + // } + // } + + // // Flush any remaining data + // if (len > 0) { + // sendPacket(packetNum++); + // } } - private void sendPacket(int packetNum) { + + private void sendPacket(int frameNum, int packetNum) { + // println("Sending frame #" + frameNum + ", channel # " + packetNum); message.clearArguments(); + message.add(frameNum); + message.add(0xDEADBEEF); message.add(packetNum); + message.add(0xFEEDBEEF); message.add(packet.length); message.add(packet); + message.add(0xBEFFFFEB); + try { - OscP5.flush(message, address); + // OscP5.flush(message, address); // new DatagramSocket every time, no thanks + byte[] bytes = message.getBytes(); + DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address.inetaddress(), PORT); + socket.send(packet); } catch (Exception x) { x.printStackTrace(); } } } -