mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
moving the libraries
This commit is contained in:
+7
-4
@@ -8,6 +8,7 @@ X this way can avoid duplicating / breaking things
|
||||
o what is the stroked version of a sphere? a circle?
|
||||
X write list of params that can be passed to PApplet
|
||||
o document in the code a note about how size() et al place themselves
|
||||
X saveFrame was double-adding the save path because of save() changes
|
||||
|
||||
size(200, 200, P3D) - createGraphics and placement issues
|
||||
X make pappletgl work back inside papplet
|
||||
@@ -28,6 +29,8 @@ X can this be done with g2 and if exception just falls back to g1?
|
||||
X this way people can remove g1 by hand
|
||||
o size() that changes renderer will throw nasty exception in draw()
|
||||
X or maybe that's ok? document that no changing renderers?
|
||||
X take a look to see what needs to happen to get PAppletGL merged in
|
||||
X i.e. can i just extend GLCanvas?
|
||||
|
||||
present mode
|
||||
o call present() from inside the code?
|
||||
@@ -50,6 +53,9 @@ X make sure the program compiles before starting present mode
|
||||
_ fix the flicker in java2d mode
|
||||
X is it because the lock was taken off (g) in PApplet?
|
||||
|
||||
_ apply tint() to textures as well
|
||||
_ otherwise no good way to color textures
|
||||
|
||||
_ cellular automata examples broken
|
||||
|
||||
_ gl smoothing.. how to disable polygon but keep line enabled
|
||||
@@ -71,15 +77,12 @@ _ make illustrator lib
|
||||
|
||||
BETA
|
||||
|
||||
_ take a look to see what needs to happen to get PAppletGL merged in
|
||||
_ i.e. can i just extend GLCanvas?
|
||||
_ get PGraphics.java engine working again
|
||||
|
||||
_ don't grab pixels of java2d images unless asked
|
||||
_ this is the difference between a lot of loadPixels() and not
|
||||
_ so important to have it in before beta if that's the change
|
||||
|
||||
_ get PGraphics.java engine working again
|
||||
|
||||
_ if (modified) don't loadPixels again, just ignore it
|
||||
_ make a note that updatePixels() only sets a flag in PImage
|
||||
_ (but not PGraphics, which does it immediately)
|
||||
|
||||
+442
@@ -0,0 +1,442 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
PClient - basic network client implementation
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004 Ben Fry
|
||||
The previous version of this code was developed by Hernando Barragan
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.net;
|
||||
import processing.core.*;
|
||||
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
|
||||
|
||||
public class Client implements Runnable {
|
||||
|
||||
PApplet parent;
|
||||
Method clientEventMethod;
|
||||
|
||||
Thread thread;
|
||||
Socket socket;
|
||||
String ip;
|
||||
int port;
|
||||
String host;
|
||||
|
||||
|
||||
// read buffer and streams
|
||||
|
||||
InputStream input;
|
||||
OutputStream output;
|
||||
|
||||
byte buffer[] = new byte[32768];
|
||||
int bufferIndex;
|
||||
int bufferLast;
|
||||
|
||||
|
||||
public Client(PApplet parent, String host, int port) {
|
||||
this.parent = parent;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
|
||||
//parent.attach(this);
|
||||
|
||||
try {
|
||||
socket = new Socket(this.host, this.port);
|
||||
input = socket.getInputStream();
|
||||
output = socket.getOutputStream();
|
||||
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
|
||||
parent.registerDispose(this);
|
||||
|
||||
// reflection to check whether host applet has a call for
|
||||
// public void serialEvent(processing.serial.Serial)
|
||||
// which would be called each time an event comes in
|
||||
try {
|
||||
clientEventMethod =
|
||||
parent.getClass().getMethod("clientEvent",
|
||||
new Class[] { Client.class });
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
errorMessage("<init>", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Client(PApplet parent, Socket socket) throws IOException {
|
||||
this.socket = socket;
|
||||
|
||||
input = socket.getInputStream();
|
||||
output = socket.getOutputStream();
|
||||
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disconnect from the server.
|
||||
* <P>
|
||||
* Use this to shut the connection if you're finished with it
|
||||
* while your applet is still running. Otherwise, it will be
|
||||
* automatically be shut down by the host PApplet
|
||||
* (using dispose, which is identical)
|
||||
*/
|
||||
public void stop() {
|
||||
dispose();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disconnect from the server: internal use only.
|
||||
* <P>
|
||||
* This should only be called by the internal functions in PApplet,
|
||||
* use stop() instead from within your own applets.
|
||||
*/
|
||||
public void dispose() {
|
||||
try {
|
||||
// do io streams need to be closed first?
|
||||
if (input != null) input.close();
|
||||
if (output != null) output.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
input = null;
|
||||
output = null;
|
||||
|
||||
try {
|
||||
if (socket != null) socket.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
socket = null;
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
while (Thread.currentThread() == thread) {
|
||||
try {
|
||||
while (input.available() > 0) { // this will block
|
||||
synchronized (buffer) {
|
||||
if (bufferLast == buffer.length) {
|
||||
byte temp[] = new byte[bufferLast << 1];
|
||||
System.arraycopy(buffer, 0, temp, 0, bufferLast);
|
||||
buffer = temp;
|
||||
}
|
||||
buffer[bufferLast++] = (byte) input.read();
|
||||
}
|
||||
}
|
||||
// now post an event
|
||||
if (clientEventMethod != null) {
|
||||
try {
|
||||
clientEventMethod.invoke(parent, new Object[] { this });
|
||||
} catch (Exception e) {
|
||||
System.err.println("error, disabling clientEvent() for " + host);
|
||||
e.printStackTrace();
|
||||
clientEventMethod = null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// uhh.. not sure what's best here.. since blocking,
|
||||
// do we need to worry about sleeping much? or is this
|
||||
// gonna try to slurp cpu away from the main applet?
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException ex) { }
|
||||
|
||||
} catch (IOException e) {
|
||||
errorMessage("run", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the ip address of this feller as a String.
|
||||
*/
|
||||
public String ip() {
|
||||
return socket.getInetAddress().getHostAddress();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that have been read from serial
|
||||
* and are waiting to be dealt with by the user.
|
||||
*/
|
||||
public int available() {
|
||||
return (bufferLast - bufferIndex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ignore all the bytes read so far and empty the buffer.
|
||||
*/
|
||||
public void clear() {
|
||||
bufferLast = 0;
|
||||
bufferIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a number between 0 and 255 for the next byte that's
|
||||
* waiting in the buffer.
|
||||
* Returns -1 if there was no byte (although the user should
|
||||
* first check available() to see if things are ready to avoid this)
|
||||
*/
|
||||
public int read() {
|
||||
if (bufferIndex == bufferLast) return -1;
|
||||
|
||||
synchronized (buffer) {
|
||||
int outgoing = buffer[bufferIndex++] & 0xff;
|
||||
if (bufferIndex == bufferLast) { // rewind
|
||||
bufferIndex = 0;
|
||||
bufferLast = 0;
|
||||
}
|
||||
return outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the next byte in the buffer as a char.
|
||||
* Returns -1, or 0xffff, if nothing is there.
|
||||
*/
|
||||
public char readChar() {
|
||||
if (bufferIndex == bufferLast) return (char)(-1);
|
||||
return (char) read();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a byte array of anything that's in the serial buffer.
|
||||
* Not particularly memory/speed efficient, because it creates
|
||||
* a byte array on each read, but it's easier to use than
|
||||
* readBytes(byte b[]) (see below).
|
||||
*/
|
||||
public byte[] readBytes() {
|
||||
if (bufferIndex == bufferLast) return null;
|
||||
|
||||
synchronized (buffer) {
|
||||
int length = bufferLast - bufferIndex;
|
||||
byte outgoing[] = new byte[length];
|
||||
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
||||
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
return outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Grab whatever is in the serial buffer, and stuff it into a
|
||||
* byte buffer passed in by the user. This is more memory/time
|
||||
* efficient than readBytes() returning a byte[] array.
|
||||
*
|
||||
* Returns an int for how many bytes were read. If more bytes
|
||||
* are available than can fit into the byte array, only those
|
||||
* that will fit are read.
|
||||
*/
|
||||
public int readBytes(byte outgoing[]) {
|
||||
if (bufferIndex == bufferLast) return 0;
|
||||
|
||||
synchronized (buffer) {
|
||||
int length = bufferLast - bufferIndex;
|
||||
if (length > outgoing.length) length = outgoing.length;
|
||||
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
||||
|
||||
bufferIndex += length;
|
||||
if (bufferIndex == bufferLast) {
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads from the serial port into a buffer of bytes up to and
|
||||
* including a particular character. If the character isn't in
|
||||
* the serial buffer, then 'null' is returned.
|
||||
*/
|
||||
public byte[] readBytesUntil(int interesting) {
|
||||
if (bufferIndex == bufferLast) return null;
|
||||
byte what = (byte)interesting;
|
||||
|
||||
synchronized (buffer) {
|
||||
int found = -1;
|
||||
for (int k = bufferIndex; k < bufferLast; k++) {
|
||||
if (buffer[k] == what) {
|
||||
found = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == -1) return null;
|
||||
|
||||
int length = found - bufferIndex + 1;
|
||||
byte outgoing[] = new byte[length];
|
||||
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
||||
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
return outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads from the serial port into a buffer of bytes until a
|
||||
* particular character. If the character isn't in the serial
|
||||
* buffer, then 'null' is returned.
|
||||
*
|
||||
* If outgoing[] is not big enough, then -1 is returned,
|
||||
* and an error message is printed on the console.
|
||||
* If nothing is in the buffer, zero is returned.
|
||||
* If 'interesting' byte is not in the buffer, then 0 is returned.
|
||||
*/
|
||||
public int readBytesUntil(int interesting, byte outgoing[]) {
|
||||
if (bufferIndex == bufferLast) return 0;
|
||||
byte what = (byte)interesting;
|
||||
|
||||
synchronized (buffer) {
|
||||
int found = -1;
|
||||
for (int k = bufferIndex; k < bufferLast; k++) {
|
||||
if (buffer[k] == what) {
|
||||
found = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == -1) return 0;
|
||||
|
||||
int length = found - bufferIndex + 1;
|
||||
if (length > outgoing.length) {
|
||||
System.err.println("readBytesUntil() byte buffer is" +
|
||||
" too small for the " + length +
|
||||
" bytes up to and including char " + interesting);
|
||||
return -1;
|
||||
}
|
||||
//byte outgoing[] = new byte[length];
|
||||
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
||||
|
||||
bufferIndex += length;
|
||||
if (bufferIndex == bufferLast) {
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return whatever has been read from the serial port so far
|
||||
* as a String. It assumes that the incoming characters are ASCII.
|
||||
*
|
||||
* If you want to move Unicode data, you can first convert the
|
||||
* String to a byte stream in the representation of your choice
|
||||
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
|
||||
*/
|
||||
public String readString() {
|
||||
if (bufferIndex == bufferLast) return null;
|
||||
return new String(readBytes());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Combination of readBytesUntil and readString. See caveats in
|
||||
* each function. Returns null if it still hasn't found what
|
||||
* you're looking for.
|
||||
*
|
||||
* If you want to move Unicode data, you can first convert the
|
||||
* String to a byte stream in the representation of your choice
|
||||
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
|
||||
*/
|
||||
public String readStringUntil(int interesting) {
|
||||
byte b[] = readBytesUntil(interesting);
|
||||
if (b == null) return null;
|
||||
return new String(b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This will handle both ints, bytes and chars transparently.
|
||||
*/
|
||||
public void write(int what) { // will also cover char
|
||||
try {
|
||||
output.write(what & 0xff); // for good measure do the &
|
||||
output.flush(); // hmm, not sure if a good idea
|
||||
|
||||
} catch (Exception e) { // null pointer or serial port dead
|
||||
errorMessage("write", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void write(byte bytes[]) {
|
||||
try {
|
||||
output.write(bytes);
|
||||
output.flush(); // hmm, not sure if a good idea
|
||||
|
||||
} catch (Exception e) { // null pointer or serial port dead
|
||||
//errorMessage("write", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a String to the output. Note that this doesn't account
|
||||
* for Unicode (two bytes per char), nor will it send UTF8
|
||||
* characters.. It assumes that you mean to send a byte buffer
|
||||
* (most often the case for networking and serial i/o) and
|
||||
* will only use the bottom 8 bits of each char in the string.
|
||||
* (Meaning that internally it uses String.getBytes)
|
||||
*
|
||||
* If you want to move Unicode data, you can first convert the
|
||||
* String to a byte stream in the representation of your choice
|
||||
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
|
||||
*/
|
||||
public void write(String what) {
|
||||
write(what.getBytes());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* General error reporting, all corraled here just in case
|
||||
* I think of something slightly more intelligent to do.
|
||||
*/
|
||||
public void errorMessage(String where, Exception e) {
|
||||
parent.die("Error inside Client." + where + "()", e);
|
||||
//e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
PServer - basic network server implementation
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004 Ben Fry
|
||||
The previous version of this code was developed by Hernando Barragan
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.net;
|
||||
import processing.core.*;
|
||||
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
|
||||
|
||||
public class Server implements Runnable {
|
||||
|
||||
PApplet parent;
|
||||
Method serverEventMethod;
|
||||
|
||||
Thread thread;
|
||||
ServerSocket server;
|
||||
int port;
|
||||
Vector clients; // people payin the bills
|
||||
|
||||
|
||||
public Server(PApplet parent, int port) {
|
||||
this.parent = parent;
|
||||
this.port = port;
|
||||
|
||||
//parent.attach(this);
|
||||
|
||||
try {
|
||||
server = new ServerSocket(this.port);
|
||||
clients = new Vector();
|
||||
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
|
||||
parent.registerDispose(this);
|
||||
|
||||
// reflection to check whether host applet has a call for
|
||||
// public void serverEvent(Server s, Client c);
|
||||
// which is called when a new guy connects
|
||||
try {
|
||||
serverEventMethod =
|
||||
parent.getClass().getMethod("serverEvent",
|
||||
new Class[] { Server.class,
|
||||
Client.class });
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
errorMessage("<init>", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disconnect a particular client.
|
||||
*/
|
||||
public void disconnect(Client client) {
|
||||
//client.stop();
|
||||
client.dispose();
|
||||
clients.removeElement(client);
|
||||
}
|
||||
|
||||
|
||||
// the last index used for available. can't just cycle through
|
||||
// the clients in order from 0 each time, because if client 0 won't
|
||||
// shut up, then the rest of the clients will never be heard from.
|
||||
int lastAvailable = -1;
|
||||
|
||||
/**
|
||||
* Returns the next client in line that has something to say.
|
||||
*/
|
||||
public Client available() {
|
||||
synchronized (clients) {
|
||||
int clientCount = clients.size();
|
||||
int index = lastAvailable + 1;
|
||||
if (index >= clientCount) index = 0;
|
||||
|
||||
for (int i = 0; i < clientCount; i++) {
|
||||
int which = (index + i) % clientCount;
|
||||
Client client = (Client) clients.elementAt(which);
|
||||
if (client.available() > 0) {
|
||||
lastAvailable = which;
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disconnect all clients and stop the server.
|
||||
* <P>
|
||||
* Use this to shut down the server if you finish using it
|
||||
* while your applet is still running. Otherwise, it will be
|
||||
* automatically be shut down by the host PApplet
|
||||
* (using dispose, which is identical)
|
||||
*/
|
||||
public void stop() {
|
||||
dispose();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disconnect all clients and stop the server: internal use only.
|
||||
*/
|
||||
public void dispose() {
|
||||
try {
|
||||
thread = null;
|
||||
|
||||
if (clients != null) {
|
||||
Enumeration en = clients.elements();
|
||||
while (en.hasMoreElements()) {
|
||||
disconnect((Client) en.nextElement());
|
||||
}
|
||||
clients = null;
|
||||
}
|
||||
|
||||
if (server != null) {
|
||||
server.close();
|
||||
server = null;
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
errorMessage("stop", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
while (Thread.currentThread() == thread) {
|
||||
try {
|
||||
Socket socket = server.accept();
|
||||
Client client = new Client(parent, socket);
|
||||
synchronized (clients) {
|
||||
clients.addElement(client);
|
||||
if (serverEventMethod != null) {
|
||||
try {
|
||||
serverEventMethod.invoke(parent, new Object[] { this, client });
|
||||
} catch (Exception e) {
|
||||
System.err.println("error, disabling serverEvent() " +
|
||||
" for port " + port);
|
||||
e.printStackTrace();
|
||||
serverEventMethod = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
errorMessage("run", e);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(8);
|
||||
} catch (InterruptedException ex) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a value to all the connected clients.
|
||||
* See Client.write() for operational details.
|
||||
*/
|
||||
public void write(int what) { // will also cover char
|
||||
Enumeration en = clients.elements();
|
||||
while (en.hasMoreElements()) {
|
||||
Client client = (Client) en.nextElement();
|
||||
client.write(what);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a byte array to all the connected clients.
|
||||
* See Client.write() for operational details.
|
||||
*/
|
||||
public void write(byte bytes[]) {
|
||||
Enumeration en = clients.elements();
|
||||
while (en.hasMoreElements()) {
|
||||
Client client = (Client) en.nextElement();
|
||||
client.write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a String to all the connected clients.
|
||||
* See Client.write() for operational details.
|
||||
*/
|
||||
public void write(String what) {
|
||||
Enumeration en = clients.elements();
|
||||
while (en.hasMoreElements()) {
|
||||
Client client = (Client) en.nextElement();
|
||||
client.write(what);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* General error reporting, all corraled here just in case
|
||||
* I think of something slightly more intelligent to do.
|
||||
*/
|
||||
public void errorMessage(String where, Exception e) {
|
||||
parent.die("Error inside Server." + where + "()", e);
|
||||
//System.err.println("Error inside Server." + where + "()");
|
||||
//e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
net.jar
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
opengl.jar
|
||||
@@ -0,0 +1,644 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
PSerial - class for serial port goodness
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004 Ben Fry & Casey Reas
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.serial;
|
||||
import processing.core.*;
|
||||
|
||||
import gnu.io.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
|
||||
public class Serial implements SerialPortEventListener {
|
||||
|
||||
PApplet parent;
|
||||
Method serialEventMethod;
|
||||
|
||||
// properties can be passed in for default values
|
||||
// otherwise defaults to 9600 N81
|
||||
|
||||
// these could be made static, which might be a solution
|
||||
// for the classloading problem.. because if code ran again,
|
||||
// the static class would have an object that could be closed
|
||||
|
||||
public SerialPort port;
|
||||
|
||||
public int rate;
|
||||
public int parity;
|
||||
public int databits;
|
||||
public int stopbits;
|
||||
|
||||
|
||||
// read buffer and streams
|
||||
|
||||
public InputStream input;
|
||||
public OutputStream output;
|
||||
|
||||
byte buffer[] = new byte[32768];
|
||||
int bufferIndex;
|
||||
int bufferLast;
|
||||
|
||||
//boolean bufferUntil = false;
|
||||
int bufferSize = 1; // how big before reset or event firing
|
||||
boolean bufferUntil;
|
||||
int bufferUntilByte;
|
||||
|
||||
|
||||
// defaults
|
||||
|
||||
static String dname = "COM1";
|
||||
static int drate = 9600;
|
||||
static char dparity = 'N';
|
||||
static int ddatabits = 8;
|
||||
static float dstopbits = 1;
|
||||
|
||||
|
||||
public void setProperties(Properties props) {
|
||||
dname =
|
||||
props.getProperty("serial.port", dname);
|
||||
drate =
|
||||
Integer.parseInt(props.getProperty("serial.rate", "9600"));
|
||||
dparity =
|
||||
props.getProperty("serial.parity", "N").charAt(0);
|
||||
ddatabits =
|
||||
Integer.parseInt(props.getProperty("serial.databits", "8"));
|
||||
dstopbits =
|
||||
new Float(props.getProperty("serial.stopbits", "1")).floatValue();
|
||||
}
|
||||
|
||||
|
||||
public Serial(PApplet parent) {
|
||||
this(parent, dname, drate, dparity, ddatabits, dstopbits);
|
||||
}
|
||||
|
||||
public Serial(PApplet parent, int irate) {
|
||||
this(parent, dname, irate, dparity, ddatabits, dstopbits);
|
||||
}
|
||||
|
||||
public Serial(PApplet parent, String iname, int irate) {
|
||||
this(parent, iname, irate, dparity, ddatabits, dstopbits);
|
||||
}
|
||||
|
||||
public Serial(PApplet parent, String iname) {
|
||||
this(parent, iname, drate, dparity, ddatabits, dstopbits);
|
||||
}
|
||||
|
||||
public Serial(PApplet parent, String iname, int irate,
|
||||
char iparity, int idatabits, float istopbits) {
|
||||
//if (port != null) port.close();
|
||||
this.parent = parent;
|
||||
//parent.attach(this);
|
||||
|
||||
this.rate = irate;
|
||||
|
||||
parity = SerialPort.PARITY_NONE;
|
||||
if (iparity == 'E') parity = SerialPort.PARITY_EVEN;
|
||||
if (iparity == 'O') parity = SerialPort.PARITY_ODD;
|
||||
|
||||
this.databits = idatabits;
|
||||
|
||||
stopbits = SerialPort.STOPBITS_1;
|
||||
if (istopbits == 1.5f) stopbits = SerialPort.STOPBITS_1_5;
|
||||
if (istopbits == 2) stopbits = SerialPort.STOPBITS_2;
|
||||
|
||||
try {
|
||||
Enumeration portList = CommPortIdentifier.getPortIdentifiers();
|
||||
while (portList.hasMoreElements()) {
|
||||
CommPortIdentifier portId =
|
||||
(CommPortIdentifier) portList.nextElement();
|
||||
|
||||
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
|
||||
//System.out.println("found " + portId.getName());
|
||||
if (portId.getName().equals(iname)) {
|
||||
port = (SerialPort)portId.open("serial madness", 2000);
|
||||
input = port.getInputStream();
|
||||
output = port.getOutputStream();
|
||||
port.setSerialPortParams(rate, databits, stopbits, parity);
|
||||
port.addEventListener(this);
|
||||
port.notifyOnDataAvailable(true);
|
||||
//System.out.println("opening, ready to roll");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
errorMessage("<init>", e);
|
||||
//exception = e;
|
||||
//e.printStackTrace();
|
||||
port = null;
|
||||
input = null;
|
||||
output = null;
|
||||
}
|
||||
|
||||
parent.registerDispose(this);
|
||||
|
||||
// reflection to check whether host applet has a call for
|
||||
// public void serialEvent(processing.serial.Serial)
|
||||
// which would be called each time an event comes in
|
||||
try {
|
||||
serialEventMethod =
|
||||
parent.getClass().getMethod("serialEvent",
|
||||
new Class[] { Serial.class });
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void dispose() {
|
||||
try {
|
||||
// do io streams need to be closed first?
|
||||
if (input != null) input.close();
|
||||
if (output != null) output.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
input = null;
|
||||
output = null;
|
||||
|
||||
try {
|
||||
if (port != null) port.close(); // close the port
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
port = null;
|
||||
}
|
||||
|
||||
|
||||
synchronized public void serialEvent(SerialPortEvent serialEvent) {
|
||||
if (serialEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
|
||||
try {
|
||||
while (input.available() > 0) {
|
||||
synchronized (buffer) {
|
||||
if (bufferLast == buffer.length) {
|
||||
byte temp[] = new byte[bufferLast << 1];
|
||||
System.arraycopy(buffer, 0, temp, 0, bufferLast);
|
||||
buffer = temp;
|
||||
}
|
||||
buffer[bufferLast++] = (byte) input.read();
|
||||
if (serialEventMethod != null) {
|
||||
if ((bufferUntil && (buffer[bufferLast-1] == bufferUntilByte)) ||
|
||||
((bufferLast - bufferIndex) >= bufferSize)) {
|
||||
try {
|
||||
serialEventMethod.invoke(parent, new Object[] { this });
|
||||
} catch (Exception e) {
|
||||
String msg = "error, disabling serialEvent() for " + port;
|
||||
System.err.println(msg);
|
||||
e.printStackTrace();
|
||||
serialEventMethod = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
errorMessage("serialEvent", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set number of bytes to buffer before calling serialEvent()
|
||||
* in the host applet.
|
||||
*/
|
||||
public void buffer(int count) {
|
||||
bufferUntil = false;
|
||||
bufferSize = count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a specific byte to buffer until before calling
|
||||
* serialEvent() in the host applet.
|
||||
*/
|
||||
public void bufferUntil(int what) {
|
||||
bufferUntil = true;
|
||||
bufferUntilByte = what;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that have been read from serial
|
||||
* and are waiting to be dealt with by the user.
|
||||
*/
|
||||
public int available() {
|
||||
return (bufferLast - bufferIndex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ignore all the bytes read so far and empty the buffer.
|
||||
*/
|
||||
public void clear() {
|
||||
bufferLast = 0;
|
||||
bufferIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a number between 0 and 255 for the next byte that's
|
||||
* waiting in the buffer.
|
||||
* Returns -1 if there was no byte (although the user should
|
||||
* first check available() to see if things are ready to avoid this)
|
||||
*/
|
||||
public int read() {
|
||||
if (bufferIndex == bufferLast) return -1;
|
||||
|
||||
synchronized (buffer) {
|
||||
int outgoing = buffer[bufferIndex++] & 0xff;
|
||||
if (bufferIndex == bufferLast) { // rewind
|
||||
bufferIndex = 0;
|
||||
bufferLast = 0;
|
||||
}
|
||||
return outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Same as read() but returns the very last value received
|
||||
* and clears the buffer. Useful when you just want the most
|
||||
* recent value sent over the port.
|
||||
*/
|
||||
public int last() {
|
||||
if (bufferIndex == bufferLast) return -1;
|
||||
synchronized (buffer) {
|
||||
int outgoing = buffer[bufferLast-1];
|
||||
bufferIndex = 0;
|
||||
bufferLast = 0;
|
||||
return outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the next byte in the buffer as a char.
|
||||
* Returns -1, or 0xffff, if nothing is there.
|
||||
*/
|
||||
public char readChar() {
|
||||
if (bufferIndex == bufferLast) return (char)(-1);
|
||||
return (char) read();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Just like last() and readChar().
|
||||
*/
|
||||
public char lastChar() {
|
||||
if (bufferIndex == bufferLast) return (char)(-1);
|
||||
return (char) last();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a byte array of anything that's in the serial buffer.
|
||||
* Not particularly memory/speed efficient, because it creates
|
||||
* a byte array on each read, but it's easier to use than
|
||||
* readBytes(byte b[]) (see below).
|
||||
*/
|
||||
public byte[] readBytes() {
|
||||
if (bufferIndex == bufferLast) return null;
|
||||
|
||||
synchronized (buffer) {
|
||||
int length = bufferLast - bufferIndex;
|
||||
byte outgoing[] = new byte[length];
|
||||
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
||||
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
return outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Grab whatever is in the serial buffer, and stuff it into a
|
||||
* byte buffer passed in by the user. This is more memory/time
|
||||
* efficient than readBytes() returning a byte[] array.
|
||||
*
|
||||
* Returns an int for how many bytes were read. If more bytes
|
||||
* are available than can fit into the byte array, only those
|
||||
* that will fit are read.
|
||||
*/
|
||||
public int readBytes(byte outgoing[]) {
|
||||
if (bufferIndex == bufferLast) return 0;
|
||||
|
||||
synchronized (buffer) {
|
||||
int length = bufferLast - bufferIndex;
|
||||
if (length > outgoing.length) length = outgoing.length;
|
||||
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
||||
|
||||
bufferIndex += length;
|
||||
if (bufferIndex == bufferLast) {
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads from the serial port into a buffer of bytes up to and
|
||||
* including a particular character. If the character isn't in
|
||||
* the serial buffer, then 'null' is returned.
|
||||
*/
|
||||
public byte[] readBytesUntil(int interesting) {
|
||||
if (bufferIndex == bufferLast) return null;
|
||||
byte what = (byte)interesting;
|
||||
|
||||
synchronized (buffer) {
|
||||
int found = -1;
|
||||
for (int k = bufferIndex; k < bufferLast; k++) {
|
||||
if (buffer[k] == what) {
|
||||
found = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == -1) return null;
|
||||
|
||||
int length = found - bufferIndex + 1;
|
||||
byte outgoing[] = new byte[length];
|
||||
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
||||
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
return outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads from the serial port into a buffer of bytes until a
|
||||
* particular character. If the character isn't in the serial
|
||||
* buffer, then 'null' is returned.
|
||||
*
|
||||
* If outgoing[] is not big enough, then -1 is returned,
|
||||
* and an error message is printed on the console.
|
||||
* If nothing is in the buffer, zero is returned.
|
||||
* If 'interesting' byte is not in the buffer, then 0 is returned.
|
||||
*/
|
||||
public int readBytesUntil(int interesting, byte outgoing[]) {
|
||||
if (bufferIndex == bufferLast) return 0;
|
||||
byte what = (byte)interesting;
|
||||
|
||||
synchronized (buffer) {
|
||||
int found = -1;
|
||||
for (int k = bufferIndex; k < bufferLast; k++) {
|
||||
if (buffer[k] == what) {
|
||||
found = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == -1) return 0;
|
||||
|
||||
int length = found - bufferIndex + 1;
|
||||
if (length > outgoing.length) {
|
||||
System.err.println("readBytesUntil() byte buffer is" +
|
||||
" too small for the " + length +
|
||||
" bytes up to and including char " + interesting);
|
||||
return -1;
|
||||
}
|
||||
//byte outgoing[] = new byte[length];
|
||||
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
||||
|
||||
bufferIndex += length;
|
||||
if (bufferIndex == bufferLast) {
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return whatever has been read from the serial port so far
|
||||
* as a String. It assumes that the incoming characters are ASCII.
|
||||
*
|
||||
* If you want to move Unicode data, you can first convert the
|
||||
* String to a byte stream in the representation of your choice
|
||||
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
|
||||
*/
|
||||
public String readString() {
|
||||
if (bufferIndex == bufferLast) return null;
|
||||
return new String(readBytes());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Combination of readBytesUntil and readString. See caveats in
|
||||
* each function. Returns null if it still hasn't found what
|
||||
* you're looking for.
|
||||
*
|
||||
* If you want to move Unicode data, you can first convert the
|
||||
* String to a byte stream in the representation of your choice
|
||||
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
|
||||
*/
|
||||
public String readStringUntil(int interesting) {
|
||||
byte b[] = readBytesUntil(interesting);
|
||||
if (b == null) return null;
|
||||
return new String(b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This will handle both ints, bytes and chars transparently.
|
||||
*/
|
||||
public void write(int what) { // will also cover char
|
||||
try {
|
||||
output.write(what & 0xff); // for good measure do the &
|
||||
output.flush(); // hmm, not sure if a good idea
|
||||
|
||||
} catch (Exception e) { // null pointer or serial port dead
|
||||
errorMessage("write", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void write(byte bytes[]) {
|
||||
try {
|
||||
output.write(bytes);
|
||||
output.flush(); // hmm, not sure if a good idea
|
||||
|
||||
} catch (Exception e) { // null pointer or serial port dead
|
||||
//errorMessage("write", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a String to the output. Note that this doesn't account
|
||||
* for Unicode (two bytes per char), nor will it send UTF8
|
||||
* characters.. It assumes that you mean to send a byte buffer
|
||||
* (most often the case for networking and serial i/o) and
|
||||
* will only use the bottom 8 bits of each char in the string.
|
||||
* (Meaning that internally it uses String.getBytes)
|
||||
*
|
||||
* If you want to move Unicode data, you can first convert the
|
||||
* String to a byte stream in the representation of your choice
|
||||
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
|
||||
*/
|
||||
public void write(String what) {
|
||||
write(what.getBytes());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If this just hangs and never completes on Windows,
|
||||
* it may be because the DLL doesn't have its exec bit set.
|
||||
* Why the hell that'd be the case, who knows.
|
||||
*/
|
||||
static public String[] list() {
|
||||
Vector list = new Vector();
|
||||
try {
|
||||
//System.err.println("trying");
|
||||
Enumeration portList = CommPortIdentifier.getPortIdentifiers();
|
||||
//System.err.println("got port list");
|
||||
while (portList.hasMoreElements()) {
|
||||
CommPortIdentifier portId =
|
||||
(CommPortIdentifier) portList.nextElement();
|
||||
//System.out.println(portId);
|
||||
|
||||
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
|
||||
String name = portId.getName();
|
||||
list.addElement(name);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
//System.err.println("1");
|
||||
errorMessage("ports", e);
|
||||
|
||||
} catch (Exception e) {
|
||||
//System.err.println("2");
|
||||
errorMessage("ports", e);
|
||||
}
|
||||
//System.err.println("move out");
|
||||
String outgoing[] = new String[list.size()];
|
||||
list.copyInto(outgoing);
|
||||
return outgoing;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* General error reporting, all corraled here just in case
|
||||
* I think of something slightly more intelligent to do.
|
||||
*/
|
||||
static public void errorMessage(String where, Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("Error inside Serial." + where + "()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
class SerialMenuListener implements ItemListener {
|
||||
//public SerialMenuListener() { }
|
||||
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
int count = serialMenu.getItemCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
((CheckboxMenuItem)serialMenu.getItem(i)).setState(false);
|
||||
}
|
||||
CheckboxMenuItem item = (CheckboxMenuItem)e.getSource();
|
||||
item.setState(true);
|
||||
String name = item.getLabel();
|
||||
//System.out.println(item.getLabel());
|
||||
PdeBase.properties.put("serial.port", name);
|
||||
//System.out.println("set to " + get("serial.port"));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
protected Vector buildPortList() {
|
||||
// get list of names for serial ports
|
||||
// have the default port checked (if present)
|
||||
Vector list = new Vector();
|
||||
|
||||
//SerialMenuListener listener = new SerialMenuListener();
|
||||
boolean problem = false;
|
||||
|
||||
// if this is failing, it may be because
|
||||
// lib/javax.comm.properties is missing.
|
||||
// java is weird about how it searches for java.comm.properties
|
||||
// so it tends to be very fragile. i.e. quotes in the CLASSPATH
|
||||
// environment variable will hose things.
|
||||
try {
|
||||
//System.out.println("building port list");
|
||||
Enumeration portList = CommPortIdentifier.getPortIdentifiers();
|
||||
while (portList.hasMoreElements()) {
|
||||
CommPortIdentifier portId =
|
||||
(CommPortIdentifier) portList.nextElement();
|
||||
//System.out.println(portId);
|
||||
|
||||
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
|
||||
//if (portId.getName().equals(port)) {
|
||||
String name = portId.getName();
|
||||
//CheckboxMenuItem mi =
|
||||
//new CheckboxMenuItem(name, name.equals(defaultName));
|
||||
|
||||
//mi.addItemListener(listener);
|
||||
//serialMenu.add(mi);
|
||||
list.addElement(name);
|
||||
}
|
||||
}
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
e.printStackTrace();
|
||||
problem = true;
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("exception building serial menu");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//if (serialMenu.getItemCount() == 0) {
|
||||
//System.out.println("dimming serial menu");
|
||||
//serialMenu.setEnabled(false);
|
||||
//}
|
||||
|
||||
// only warn them if this is the first time
|
||||
if (problem && PdeBase.firstTime) {
|
||||
JOptionPane.showMessageDialog(this, //frame,
|
||||
"Serial port support not installed.\n" +
|
||||
"Check the readme for instructions\n" +
|
||||
"if you need to use the serial port. ",
|
||||
"Serial Port Warning",
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/bin/sh
|
||||
|
||||
# originally fixperm.sh from rxtx-2.1_6/contrib
|
||||
# with a couple additions from pathsetup.command from fink [fry]
|
||||
|
||||
# A script to fix permissions for lock files on Mac OS X
|
||||
# Contributed by Dmitry Markman <dimitry.markman@verizon.net>
|
||||
# Fri Aug 23 15:46:46 MDT 2002
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "This command will take care of a couple system things"
|
||||
echo "so that you can properly use the serial port to communicate"
|
||||
echo "between hardware devices and processing."
|
||||
echo ""
|
||||
echo "If there are actually changes that need to be made, then"
|
||||
echo "enter your password when prompted. The command uses sudo,"
|
||||
echo "and you'll need to have administrator access."
|
||||
echo ""
|
||||
|
||||
echo -n "Do you want to continue? [Y/n] "
|
||||
read answer
|
||||
answer=`echo $answer | sed 's/^[yY].*$/y/'`
|
||||
if [ -z "$answer" -o "x$answer" = "xy" ]; then
|
||||
curruser=`sudo id -p | grep 'login' | sed 's/login.//'`
|
||||
|
||||
if [ ! -d /var/spool/uucp ]
|
||||
then
|
||||
sudo mkdir /var/spool/uucp
|
||||
fi
|
||||
|
||||
sudo chgrp uucp /var/spool/uucp
|
||||
sudo chmod 775 /var/spool/uucp
|
||||
|
||||
if [ ! `sudo niutil -readprop / /groups/uucp users | grep $curruser > /dev/null` ]
|
||||
then
|
||||
sudo niutil -mergeprop / /groups/uucp users $curruser
|
||||
fi
|
||||
|
||||
echo "Finished making changes, you should be all set"
|
||||
else
|
||||
echo "Ok, nevermind then."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo " (All done... you can close this window now)"
|
||||
echo ""
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
@@ -26,13 +26,21 @@ X significantly limit range of cases.. if presenting ext is ok
|
||||
X uses internal pretty much only when single class, etc
|
||||
X remove initialWidth/Height stuff from PdeRuntime for when running internally
|
||||
|
||||
|
||||
monday evening
|
||||
|
||||
_ when centering applet on-screen, needs to check for multiple screens
|
||||
_ this is both for PApplet and PdeRuntime
|
||||
_ PApplet screen size constant is no good
|
||||
|
||||
_ ability to select monitor via preferences panel
|
||||
_ check current present code with multiple monitors
|
||||
_ if it's working, make it all reflection-based in PApplet
|
||||
|
||||
_ first pass on full screen
|
||||
_ exceptions in full screen mode will quit the app completely
|
||||
_ (can't keep window open because things are hosed)
|
||||
|
||||
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
@@ -54,10 +62,6 @@ _ and queue events by registering for draw or whatever they'd like
|
||||
_ lib could call queueEvent with the args
|
||||
_ then call them inside post()
|
||||
|
||||
_ first pass on full screen
|
||||
_ exceptions in full screen mode will quit the app completely
|
||||
_ (can't keep window open because things are hosed)
|
||||
|
||||
_ update checker (can be turned off in prefs)
|
||||
_ send unique id, and information about person's java vm/platform
|
||||
_ using timezone would be an interesting method for tracking location
|
||||
@@ -110,6 +114,8 @@ can tell, is to Save As once, make at least one change, then Save.
|
||||
|
||||
what happens if folder already exists on save as?
|
||||
|
||||
saving a project over an already existing project does not get rid of the .pde files that arent overwritten. not sure if this is feature or bug, but it took me by surprise. it seemed to only overwrite .pde files with the same name, but everything else in that project folder stays as is.
|
||||
|
||||
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
@@ -0,0 +1,473 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Camera - whatchin shit on tv
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
The previous version of this code was developed by Hernando Barragan
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.video;
|
||||
import processing.core.*;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
|
||||
import quicktime.*;
|
||||
import quicktime.qd.*;
|
||||
import quicktime.std.*;
|
||||
import quicktime.std.sg.*;
|
||||
import quicktime.util.RawEncodedImage;
|
||||
|
||||
|
||||
public class Camera extends PImage
|
||||
implements StdQTConstants, StdQTConstants4, Runnable {
|
||||
PApplet parent;
|
||||
Method cameraEventMethod;
|
||||
String name; // keep track for error messages
|
||||
Thread runner;
|
||||
|
||||
//PImage borderImage;
|
||||
//boolean removeBorders = true;
|
||||
boolean available = false;
|
||||
|
||||
/** Temporary storage for the raw image data read directly from the camera */
|
||||
public int data[];
|
||||
|
||||
public int dataWidth;
|
||||
public int dataHeight;
|
||||
public int dataRowBytes;
|
||||
|
||||
public boolean crop;
|
||||
public int cropX;
|
||||
public int cropY;
|
||||
public int cropW;
|
||||
public int cropH;
|
||||
|
||||
int fps;
|
||||
RawEncodedImage raw;
|
||||
SequenceGrabber capture;
|
||||
|
||||
static {
|
||||
//System.out.println("Camera init");
|
||||
try {
|
||||
QTSession.open();
|
||||
} catch (QTException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
QTRuntimeException.registerHandler(new QTRuntimeHandler() {
|
||||
public void exceptionOccurred(QTRuntimeException e,
|
||||
Object obj, String s, boolean flag) {
|
||||
System.err.println("Problem inside Camera");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public Camera(PApplet parent, int requestWidth, int requestHeight) {
|
||||
this(parent, "", requestWidth, requestHeight, 30);
|
||||
}
|
||||
|
||||
public Camera(PApplet parent, int reqWidth, int reqHeight, int fps) {
|
||||
this(parent, "", reqWidth, reqHeight, fps);
|
||||
}
|
||||
|
||||
public Camera(PApplet parent, String name, int reqWidth, int reqHeight) {
|
||||
this(parent, name, reqWidth, reqHeight, 30);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
quicktime.QTSession.open();
|
||||
quicktime.std.sg.SequenceGrabber sg = new quicktime.std.sg.SequenceGrabber();
|
||||
quicktime.std.sg.SGVideoChannel sc = new quicktime.std.sg.SGVideoChannel(sg);
|
||||
quicktime.std.sg.VideoDigitizer vd = sc.getDigitizerComponent();
|
||||
println( "dv.getNumberOfInputs :" ); println( vd.getNumberOfInputs() ); println();
|
||||
//change line below to set input source
|
||||
vd.setInput(1);
|
||||
//
|
||||
println( "dv.getInput :" ); println( vd.getInput() ); println();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* If 'name' is the empty string, don't set a specific device,
|
||||
* which means that QuickTime will use that last device used by
|
||||
* a QuickTime application. If name is set to null, a prompt
|
||||
* will show up, allowing the user to choose the good stuff.
|
||||
* <P>
|
||||
* If the following function:
|
||||
* public void cameraEvent(Camera c)
|
||||
* is defined int the host PApplet, then it will be called every
|
||||
* time a new frame is available from the camera.
|
||||
*/
|
||||
public Camera(PApplet parent, String name,
|
||||
int requestWidth, int requestHeight, int fps) {
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
this.fps = fps;
|
||||
|
||||
try {
|
||||
/*
|
||||
QTSession.open();
|
||||
QTRuntimeException.registerHandler(new QTRuntimeHandler() {
|
||||
public void exceptionOccurred(QTRuntimeException e,
|
||||
Object obj, String s, boolean flag) {
|
||||
System.err.println("Problem inside Camera");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
*/
|
||||
//System.out.println("0");
|
||||
|
||||
QDRect qdrect = new QDRect(requestWidth, requestHeight);
|
||||
QDGraphics qdgraphics = new QDGraphics(qdrect);
|
||||
|
||||
//System.out.println("0a");
|
||||
|
||||
capture = new SequenceGrabber();
|
||||
//System.out.println("0b");
|
||||
capture.setGWorld(qdgraphics, null);
|
||||
|
||||
//System.out.println("0c");
|
||||
|
||||
// CRASHING HERE ON OSX
|
||||
SGVideoChannel channel = new SGVideoChannel(capture);
|
||||
//System.out.println("0c1");
|
||||
channel.setBounds(qdrect);
|
||||
//System.out.println("0c2");
|
||||
channel.setUsage(2); // what is this usage number?
|
||||
//System.out.println("0c3");
|
||||
capture.startPreview(); // maybe this comes later?
|
||||
|
||||
//System.out.println("0d");
|
||||
|
||||
PixMap pixmap = qdgraphics.getPixMap();
|
||||
raw = pixmap.getPixelData();
|
||||
|
||||
//System.out.println("0e");
|
||||
|
||||
if (name == null) {
|
||||
channel.settingsDialog();
|
||||
|
||||
} else if (name.length() > 0) {
|
||||
channel.setDevice(name);
|
||||
}
|
||||
//System.out.println("0f");
|
||||
//channel.setDevice("Logitech QuickCam Express-WDM");
|
||||
/*
|
||||
if (showDialog) channel.settingsDialog();
|
||||
SGDeviceList list = channel.getDeviceList(0);
|
||||
System.out.println("count is " + list.getCount());
|
||||
for (int i = 0; i < list.getCount(); i++) {
|
||||
System.out.println(list.getDeviceName(i).getName());
|
||||
}
|
||||
//System.out.println(channel.getSettings());
|
||||
*/
|
||||
|
||||
//int grabWidthBytes = raw.getRowBytes();
|
||||
dataRowBytes = raw.getRowBytes();
|
||||
dataWidth = dataRowBytes / 4;
|
||||
|
||||
//System.out.println("row bytes " + raw.getRowBytes() + " " +
|
||||
// (raw.getRowBytes() / 4));
|
||||
//int extraBytes = dataRowBytes - requestWidth*4;
|
||||
//int extraPixels = extraBytes / 4;
|
||||
//int videoWidth = requestWidth + extraPixels;
|
||||
dataHeight = raw.getSize() / dataRowBytes;
|
||||
|
||||
//System.out.println("height req, actual: " + requestHeight +
|
||||
// " " + dataHeight);
|
||||
|
||||
if (dataWidth != requestWidth) {
|
||||
crop = true;
|
||||
cropX = 0;
|
||||
cropY = 0;
|
||||
cropW = requestWidth;
|
||||
cropH = requestHeight;
|
||||
|
||||
/*
|
||||
System.out.println("dataWidth is " + dataWidth +
|
||||
" not " + requestWidth);
|
||||
if (removeBorders) {
|
||||
int bpixels[] = new int[dataWidth * requestHeight];
|
||||
borderImage = new PImage(bpixels, dataWidth, requestHeight, RGB);
|
||||
} else {
|
||||
requestWidth = dataWidth;
|
||||
}
|
||||
*/
|
||||
}
|
||||
// initialize my PImage self
|
||||
super.init(requestWidth, requestHeight, RGB);
|
||||
|
||||
runner = new Thread(this);
|
||||
runner.start();
|
||||
|
||||
parent.registerDispose(this);
|
||||
|
||||
try {
|
||||
cameraEventMethod =
|
||||
parent.getClass().getMethod("cameraEvent",
|
||||
new Class[] { Camera.class });
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
//e.printStackTrace();
|
||||
}
|
||||
|
||||
} catch (StdQTException qte) {
|
||||
//qte.printStackTrace();
|
||||
|
||||
int errorCode = qte.errorCode();
|
||||
// where's the friggin constant for this?
|
||||
if (errorCode == -9405) {
|
||||
// this can happen when the camera isn't available or
|
||||
// wasn't shut down properly
|
||||
parent.die("The camera (or VDIG) is not " +
|
||||
"installed correctly (see readme.txt).", qte);
|
||||
} else {
|
||||
parent.die("Error while setting up Camera", qte);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
parent.die("Error while setting up Camera", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* True if a frame is ready to be read. Example:
|
||||
* if (camera.available()) camera.read();
|
||||
* <P>
|
||||
* Alternatively, you can use cameraEvent(Camera c) to notify you
|
||||
* whenever available() is set to true.
|
||||
*/
|
||||
public boolean available() {
|
||||
return available;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the video to crop from its original.
|
||||
* <P>
|
||||
* It seems common that cameras add lines to the top or bottom
|
||||
* of an image, so this can be useful for removing them.
|
||||
* Internally, the pixel buffer size returned from QuickTime is
|
||||
* often a different size than requested, so crop will be set
|
||||
* more often than not.
|
||||
*/
|
||||
public void crop(int x, int y, int w, int h) {
|
||||
if (imageMode == CORNERS) {
|
||||
w -= x; // w was actually x2
|
||||
h -= y; // h was actually y2
|
||||
}
|
||||
|
||||
crop = true;
|
||||
cropX = Math.max(0, x);
|
||||
cropY = Math.max(0, y);
|
||||
cropW = Math.min(w, dataWidth);
|
||||
cropH = Math.min(dataHeight, y + h) - cropY;
|
||||
|
||||
// if size has changed, re-init this image
|
||||
if ((cropW != width) || (cropH != height)) {
|
||||
init(w, h, RGB);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void noCrop() {
|
||||
crop = false;
|
||||
}
|
||||
|
||||
|
||||
public void read() {
|
||||
//try {
|
||||
//synchronized (capture) {
|
||||
synchronized (pixels) {
|
||||
//long t1 = System.currentTimeMillis();
|
||||
|
||||
if (crop) {
|
||||
/*
|
||||
// f#$)(#$ing quicktime / jni is so g-d slow that this
|
||||
// code takes literally 100x longer to run
|
||||
int sourceOffset = cropX*4 + cropY*dataRowBytes;
|
||||
int destOffset = 0;
|
||||
for (int y = 0; y < cropH; y++) {
|
||||
raw.copyToArray(sourceOffset, pixels, destOffset, cropW);
|
||||
sourceOffset += dataRowBytes;
|
||||
destOffset += width;
|
||||
}
|
||||
*/
|
||||
if (data == null) {
|
||||
data = new int[dataWidth * dataHeight];
|
||||
}
|
||||
raw.copyToArray(0, data, 0, dataWidth * dataHeight);
|
||||
int sourceOffset = cropX + cropY*dataWidth;
|
||||
int destOffset = 0;
|
||||
for (int y = 0; y < cropH; y++) {
|
||||
System.arraycopy(data, sourceOffset, pixels, destOffset, cropW);
|
||||
sourceOffset += dataWidth;
|
||||
destOffset += width;
|
||||
}
|
||||
|
||||
/*
|
||||
if (borderImage != null) { // need to remove borders
|
||||
raw.copyToArray(0, borderImage.pixels,
|
||||
0, borderImage.width * borderImage.height);
|
||||
int borderIndex = 0;
|
||||
int targetIndex = 0;
|
||||
for (int i = 0; i < height; i++) {
|
||||
System.arraycopy(borderImage.pixels, borderIndex,
|
||||
pixels, targetIndex, width);
|
||||
borderIndex += borderImage.width;
|
||||
targetIndex += width;
|
||||
}
|
||||
*/
|
||||
} else { // just copy directly
|
||||
raw.copyToArray(0, pixels, 0, width * height);
|
||||
}
|
||||
//long t2 = System.currentTimeMillis();
|
||||
//System.out.println(t2 - t1);
|
||||
|
||||
available = false;
|
||||
// mark this image as modified so that PGraphics2 and PGraphicsGL
|
||||
// willproperly re-blit and draw this guy
|
||||
updatePixels();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
while ((Thread.currentThread() == runner) && (capture != null)) {
|
||||
try {
|
||||
synchronized (capture) {
|
||||
capture.idle();
|
||||
//read();
|
||||
available = true;
|
||||
|
||||
if (cameraEventMethod != null) {
|
||||
try {
|
||||
cameraEventMethod.invoke(parent, new Object[] { this });
|
||||
} catch (Exception e) {
|
||||
System.err.println("Disabling cameraEvent() for " + name +
|
||||
" because of an error.");
|
||||
e.printStackTrace();
|
||||
cameraEventMethod = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (QTException e) {
|
||||
errorMessage("run", e);
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(1000 / fps);
|
||||
} catch (InterruptedException e) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the framerate for how quickly new frames are read
|
||||
* from the camera.
|
||||
*/
|
||||
public void framerate(int ifps) {
|
||||
if (ifps <= 0) {
|
||||
System.err.println("Camera: ignoring bad framerate of " +
|
||||
ifps + " fps.");
|
||||
return;
|
||||
}
|
||||
fps = ifps;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by applets to stop capturing video.
|
||||
*/
|
||||
public void stop() {
|
||||
if (capture != null) {
|
||||
try {
|
||||
capture.stop(); // stop the "preview"
|
||||
} catch (StdQTException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
capture = null;
|
||||
}
|
||||
runner = null; // unwind the thread
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by PApplet to shut down video so that QuickTime
|
||||
* can be used later by another applet.
|
||||
*/
|
||||
public void dispose() {
|
||||
stop();
|
||||
//System.out.println("calling dispose");
|
||||
// this is important so that the next app can do video
|
||||
QTSession.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* General error reporting, all corraled here just in case
|
||||
* I think of something slightly more intelligent to do.
|
||||
*/
|
||||
protected void errorMessage(String where, Exception e) {
|
||||
parent.die("Error inside Camera." + where + "()", e);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows the settings dialog for this channel.
|
||||
*/
|
||||
//public void prompt() {
|
||||
//channel.settingsDialog();
|
||||
//}
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of all available cameras as a String array.
|
||||
* i.e. printarr(Camera.list()) will show you the goodies.
|
||||
*/
|
||||
static public String[] list() {
|
||||
try {
|
||||
SequenceGrabber grabber = new SequenceGrabber();
|
||||
SGVideoChannel channel = new SGVideoChannel(grabber);
|
||||
|
||||
//VideoDigitizer digitizer = channel.getDigitizerComponent();
|
||||
//digitizer.setInput(2); // or something
|
||||
//DigitizerInfo di = digitizer.getDigitizerInfo()
|
||||
|
||||
SGDeviceList deviceList = channel.getDeviceList(0); // flags is 0
|
||||
String listing[] = new String[deviceList.getCount()];
|
||||
for (int i = 0; i < deviceList.getCount(); i++) {
|
||||
listing[i] = deviceList.getDeviceName(i).getName();
|
||||
}
|
||||
// properly shut down the channel so the app can use it again
|
||||
grabber.disposeChannel(channel);
|
||||
return listing;
|
||||
|
||||
} catch (QTException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,571 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
PMovie - reading from video files
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004 Ben Fry
|
||||
The previous version of this code was developed by Hernando Barragan
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.video;
|
||||
import processing.core.*;
|
||||
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
|
||||
import quicktime.*;
|
||||
import quicktime.io.QTFile;
|
||||
import quicktime.qd.*;
|
||||
import quicktime.std.*;
|
||||
import quicktime.std.movies.*;
|
||||
import quicktime.std.movies.media.DataRef;
|
||||
import quicktime.util.RawEncodedImage;
|
||||
|
||||
|
||||
public class Movie extends PImage
|
||||
implements StdQTConstants, StdQTConstants4, PConstants, Runnable {
|
||||
PApplet parent;
|
||||
Method movieEventMethod;
|
||||
String filename;
|
||||
Thread runner;
|
||||
|
||||
PImage borderImage;
|
||||
boolean removeBorders = true;
|
||||
|
||||
boolean play;
|
||||
boolean repeat;
|
||||
boolean available;
|
||||
//float rate;
|
||||
int fps;
|
||||
|
||||
/** The movie object, made public in case anyone wants to play with it. */
|
||||
public quicktime.std.movies.Movie movie;
|
||||
|
||||
QDRect movieRect;
|
||||
QDGraphics movieGraphics;
|
||||
boolean firstFrame = true;
|
||||
RawEncodedImage raw;
|
||||
|
||||
|
||||
static {
|
||||
try {
|
||||
//System.out.println("jlp = " + System.getProperty("java.library.path"));
|
||||
QTSession.open();
|
||||
} catch (QTException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
QTRuntimeException.registerHandler(new QTRuntimeHandler() {
|
||||
public void exceptionOccurred(QTRuntimeException e,
|
||||
Object obj, String s, boolean flag) {
|
||||
System.err.println("Problem inside Movie");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public Movie(PApplet parent, String filename) {
|
||||
this(parent, filename, 30);
|
||||
}
|
||||
|
||||
|
||||
public Movie(PApplet parent, String filename, int ifps) {
|
||||
//this(parent, parent.getClass().getResource("data/" + filename), ifps);
|
||||
|
||||
// this creates a fake image so that the first time this
|
||||
// attempts to draw, something happens that's not an exception
|
||||
super.init(1, 1, RGB);
|
||||
|
||||
URL url = null;
|
||||
this.filename = filename; // for error messages
|
||||
|
||||
if (filename.startsWith("http://")) {
|
||||
try {
|
||||
url = new URL(filename);
|
||||
DataRef urlRef = new DataRef(url.toExternalForm());
|
||||
movie = fromDataRef(urlRef);
|
||||
//movie = quicktime.std.movies.Movie.fromDataRef(urlRef,
|
||||
//StdQTConstants4.newMovieAsyncOK |
|
||||
//StdQTConstants.newMovieActive);
|
||||
init(parent, movie, ifps);
|
||||
return;
|
||||
|
||||
} catch (QTException qte) {
|
||||
qte.printStackTrace();
|
||||
return;
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
url = getClass().getResource(filename);
|
||||
if (url != null) {
|
||||
init(parent, url, ifps);
|
||||
return;
|
||||
}
|
||||
|
||||
url = getClass().getResource("data/" + filename);
|
||||
if (url != null) {
|
||||
init(parent, url, ifps);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
// look inside the sketch folder (if set)
|
||||
String location = parent.folder + File.separator + "data";
|
||||
File file = new File(location, filename);
|
||||
if (file.exists()) {
|
||||
movie = fromDataRef(new DataRef(new QTFile(file)));
|
||||
//movie = quicktime.std.movies.Movie.fromDataRef(new DataRef(new QTFile(file)),
|
||||
//StdQTConstants4.newMovieAsyncOK |
|
||||
//StdQTConstants.newMovieActive);
|
||||
init(parent, movie, ifps);
|
||||
return;
|
||||
}
|
||||
} catch (QTException e) { } // ignored
|
||||
|
||||
try {
|
||||
File file = new File("data", filename);
|
||||
if (file.exists()) {
|
||||
movie = fromDataRef(new DataRef(new QTFile(file)));
|
||||
//movie = quicktime.std.movies.Movie.fromDataRef(new DataRef(new QTFile(file)),
|
||||
//StdQTConstants4.newMovieAsyncOK |
|
||||
//StdQTConstants.newMovieActive);
|
||||
init(parent, movie, ifps);
|
||||
return;
|
||||
}
|
||||
} catch (QTException e2) { }
|
||||
|
||||
try {
|
||||
File file = new File(filename);
|
||||
if (file.exists()) {
|
||||
movie = fromDataRef(new DataRef(new QTFile(file)));
|
||||
//movie = quicktime.std.movies.Movie.fromDataRef(new DataRef(new QTFile(file)),
|
||||
//StdQTConstants4.newMovieAsyncOK |
|
||||
//StdQTConstants.newMovieActive);
|
||||
init(parent, movie, ifps);
|
||||
return;
|
||||
}
|
||||
} catch (QTException e1) { }
|
||||
|
||||
} catch (SecurityException se) { } // online, whups
|
||||
|
||||
parent.die("Could not find movie file " + filename, null);
|
||||
}
|
||||
|
||||
|
||||
public Movie(PApplet parent, URL url) {
|
||||
init(parent, url, 30);
|
||||
}
|
||||
|
||||
|
||||
public Movie(PApplet parent, URL url, int ifps) {
|
||||
init(parent, url, ifps);
|
||||
}
|
||||
|
||||
|
||||
public void init(PApplet parent, URL url, int ifps) {
|
||||
|
||||
// qtjava likes file: urls to read file:/// not file:/
|
||||
// so this changes them when appropriate
|
||||
String externalized = url.toExternalForm();
|
||||
if (externalized.startsWith("file:/") &&
|
||||
!externalized.startsWith("file:///")) {
|
||||
externalized = "file:///" + url.getPath();
|
||||
}
|
||||
|
||||
// the url version is the only available that can take
|
||||
// an InputStream (indirectly) since it uses url syntax
|
||||
//DataRef urlRef = new DataRef(requestFile);
|
||||
try {
|
||||
DataRef urlRef = new DataRef(externalized);
|
||||
movie = fromDataRef(urlRef);
|
||||
//movie = quicktime.std.movies.Movie.fromDataRef(urlRef,
|
||||
//StdQTConstants4.newMovieAsyncOK |
|
||||
//StdQTConstants.newMovieActive);
|
||||
init(parent, movie, ifps);
|
||||
|
||||
} catch (QTException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//System.out.println("done with init");
|
||||
}
|
||||
|
||||
|
||||
private quicktime.std.movies.Movie fromDataRef(DataRef ref)
|
||||
throws QTException {
|
||||
|
||||
return
|
||||
quicktime.std.movies.Movie.fromDataRef(ref,
|
||||
StdQTConstants4.newMovieAsyncOK |
|
||||
StdQTConstants.newMovieActive);
|
||||
}
|
||||
|
||||
|
||||
public void init(PApplet parent,
|
||||
quicktime.std.movies.Movie movie, int ifps) {
|
||||
this.parent = parent;
|
||||
|
||||
try {
|
||||
movie.prePreroll(0, 1.0f);
|
||||
movie.preroll(0, 1.0f);
|
||||
while (movie.maxLoadedTimeInMovie() == 0) {
|
||||
movie.task(100);
|
||||
}
|
||||
movie.setRate(1);
|
||||
fps = ifps;
|
||||
|
||||
runner = new Thread(this);
|
||||
runner.start();
|
||||
|
||||
|
||||
// register methods
|
||||
|
||||
parent.registerDispose(this);
|
||||
|
||||
try {
|
||||
movieEventMethod =
|
||||
parent.getClass().getMethod("movieEvent",
|
||||
new Class[] { Movie.class });
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
}
|
||||
|
||||
} catch (QTException qte) {
|
||||
qte.printStackTrace();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean available() {
|
||||
return available;
|
||||
}
|
||||
|
||||
|
||||
public void read() {
|
||||
try {
|
||||
if (firstFrame) {
|
||||
movieRect = movie.getBox();
|
||||
movieGraphics = new QDGraphics(movieRect);
|
||||
}
|
||||
|
||||
Pict pict = movie.getPict(movie.getTime()); // returns an int
|
||||
pict.draw(movieGraphics, movieRect);
|
||||
PixMap pixmap = movieGraphics.getPixMap();
|
||||
raw = pixmap.getPixelData();
|
||||
|
||||
// It needs to get at least a small part
|
||||
// of the video to get the parameters
|
||||
if (firstFrame) {
|
||||
//int intsPerRow = pixmap.getRowBytes() / 4;
|
||||
int movieWidth = movieRect.getWidth();
|
||||
int movieHeight = movieRect.getHeight();
|
||||
int j = raw.getRowBytes() - movieWidth*4;
|
||||
// this doesn't round up.. does it need to?
|
||||
int k = j / 4;
|
||||
int dataWidth = movieWidth + k;
|
||||
|
||||
if (dataWidth != movieWidth) {
|
||||
if (removeBorders) {
|
||||
int bpixels[] = new int[dataWidth * movieHeight];
|
||||
borderImage = new PImage(bpixels, dataWidth, movieHeight, RGB);
|
||||
} else {
|
||||
movieWidth = dataWidth;
|
||||
}
|
||||
}
|
||||
int vpixels[] = new int[movieWidth * movieHeight];
|
||||
//image = new PImage(vpixels, movieWidth, movieHeight, RGB);
|
||||
super.init(movieWidth, movieHeight, RGB);
|
||||
//parent.video = image;
|
||||
firstFrame = false;
|
||||
}
|
||||
// this happens later (found by hernando)
|
||||
//raw.copyToArray(0, image.pixels, 0, image.width * image.height);
|
||||
|
||||
// this is identical to a chunk of code inside PCamera
|
||||
// this might be a candidate to move up to PVideo or something
|
||||
if (borderImage != null) { // need to remove borders
|
||||
raw.copyToArray(0, borderImage.pixels,
|
||||
0, borderImage.width * borderImage.height);
|
||||
int borderIndex = 0;
|
||||
int targetIndex = 0;
|
||||
for (int i = 0; i < height; i++) {
|
||||
System.arraycopy(borderImage.pixels, borderIndex,
|
||||
pixels, targetIndex, width);
|
||||
borderIndex += borderImage.width;
|
||||
targetIndex += width;
|
||||
}
|
||||
} else { // just copy directly
|
||||
raw.copyToArray(0, pixels, 0, width * height);
|
||||
}
|
||||
|
||||
// ready to rock
|
||||
//System.out.println("updating pixels");
|
||||
updatePixels(); // mark as modified
|
||||
|
||||
} catch (QTException qte) {
|
||||
qte.printStackTrace();
|
||||
QTSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Begin playing the movie, with no repeat.
|
||||
*/
|
||||
public void play() {
|
||||
play = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Begin playing the movie, with repeat.
|
||||
*/
|
||||
public void loop() {
|
||||
play = true;
|
||||
repeat = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shut off the repeating loop.
|
||||
*/
|
||||
public void noLoop() {
|
||||
repeat = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pause the movie at its current time.
|
||||
*/
|
||||
public void pause() {
|
||||
play = false;
|
||||
System.out.println("pause");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop the movie, and rewind.
|
||||
*/
|
||||
public void stop() {
|
||||
play = false;
|
||||
System.out.println("stop");
|
||||
try {
|
||||
movie.setTimeValue(0);
|
||||
|
||||
} catch (StdQTException e) {
|
||||
errorMessage("stop", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set how often new frames are to be read from the movie.
|
||||
*/
|
||||
public void framerate(int ifps) {
|
||||
if (ifps <= 0) {
|
||||
System.err.println("Movie: ignoring bad framerate of " +
|
||||
ifps + " fps.");
|
||||
return;
|
||||
}
|
||||
fps = ifps;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a multiplier for how fast/slow the movie should be run.
|
||||
* speed(2) will play the movie at double speed (2x).
|
||||
* speed(0.5) will play at half speed.
|
||||
* speed(-1) will play backwards at regular speed.
|
||||
*/
|
||||
public void speed(float rate) {
|
||||
//rate = irate;
|
||||
try {
|
||||
movie.setRate(rate);
|
||||
|
||||
} catch (StdQTException e) {
|
||||
errorMessage("speed", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the current time in seconds.
|
||||
* The number is a float so fractions of seconds can be used.
|
||||
*/
|
||||
public float time() {
|
||||
try {
|
||||
return (float)movie.getTime() / (float)movie.getTimeScale();
|
||||
|
||||
} catch (StdQTException e) {
|
||||
errorMessage("time", e);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Jump to a specific location (in seconds).
|
||||
* The number is a float so fractions of seconds can be used.
|
||||
*/
|
||||
//public void jump(int where) {
|
||||
public void jump(float where) {
|
||||
try {
|
||||
//movie.setTime(new TimeRecord(rate, where)); // scale, value
|
||||
//movie.setTime(new TimeRecord(1, where)); // scale, value
|
||||
int scaledTime = (int) (where * movie.getTimeScale());
|
||||
movie.setTimeValue(scaledTime);
|
||||
|
||||
} catch (StdQTException e) {
|
||||
errorMessage("jump", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the full length of this movie (in seconds).
|
||||
*/
|
||||
public float duration() {
|
||||
try {
|
||||
return (float)movie.getDuration() / (float)movie.getTimeScale();
|
||||
|
||||
} catch (StdQTException e) {
|
||||
errorMessage("length", e);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public void play() {
|
||||
if(!play) {
|
||||
play = true;
|
||||
}
|
||||
start();
|
||||
while( image == null) {
|
||||
try {
|
||||
Thread.sleep(5);
|
||||
} catch (InterruptedException e) { }
|
||||
}
|
||||
pixels = image.pixels;
|
||||
width = image.width;
|
||||
height = image.height;
|
||||
}
|
||||
|
||||
|
||||
public void repeat() {
|
||||
loop = true;
|
||||
if(!play) {
|
||||
play = true;
|
||||
}
|
||||
start();
|
||||
while( image == null) {
|
||||
try {
|
||||
Thread.sleep(5);
|
||||
} catch (InterruptedException e) { }
|
||||
}
|
||||
pixels = image.pixels;
|
||||
width = image.width;
|
||||
height = image.height;
|
||||
}
|
||||
|
||||
|
||||
public void pause() {
|
||||
play = false;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
public void run() {
|
||||
//System.out.println("entering thread");
|
||||
while (Thread.currentThread() == runner) {
|
||||
//System.out.print("<");
|
||||
try {
|
||||
//Thread.sleep(5);
|
||||
Thread.sleep(1000 / fps);
|
||||
} catch (InterruptedException e) { }
|
||||
//System.out.print(">");
|
||||
|
||||
// this could be a lie, but..
|
||||
if (play) {
|
||||
//read();
|
||||
//System.out.println("play");
|
||||
available = true;
|
||||
|
||||
if (movieEventMethod != null) {
|
||||
try {
|
||||
movieEventMethod.invoke(parent, new Object[] { this });
|
||||
} catch (Exception e) {
|
||||
System.err.println("error, disabling movieEvent() for " +
|
||||
filename);
|
||||
e.printStackTrace();
|
||||
movieEventMethod = null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (movie.isDone() && repeat) {
|
||||
movie.goToBeginning();
|
||||
}
|
||||
} catch (StdQTException e) {
|
||||
play = false;
|
||||
errorMessage("rewinding", e);
|
||||
}
|
||||
//} else {
|
||||
//System.out.println("no play");
|
||||
}
|
||||
|
||||
//try {
|
||||
//read();
|
||||
//if (movie.isDone() && loop) movie.goToBeginning();
|
||||
|
||||
//} catch (QTException e) {
|
||||
//System.err.println("Movie exception");
|
||||
//e.printStackTrace();
|
||||
//QTSession.close(); ??
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void dispose() {
|
||||
System.out.println("disposing");
|
||||
stop();
|
||||
runner = null;
|
||||
QTSession.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* General error reporting, all corraled here just in case
|
||||
* I think of something slightly more intelligent to do.
|
||||
*/
|
||||
protected void errorMessage(String where, Exception e) {
|
||||
parent.die("Error inside Movie." + where + "()", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
video.jar
|
||||
Reference in New Issue
Block a user