Monday, October 26, 2009

My Speech on Stardust for PTT Flash Workshop 2009

Actually this workshop was held a couple of months ago (Aug 31st to be specific).

PTT is the most popular bulletin-board system in Taiwan. This workshop was for the PTT Flash forum members and people from the Taiwan RIA industry. I gave an one-hour speech on Stardust for this workshop. And here's the vid: WATCH VIDEO.

This was a workshop in Taiwan, so I spoke in Chinese :p
I'll start recording video tutorials on Stardust in English as soon as I have time.

Thursday, October 22, 2009

Stardust Tutorial And Examples by Matt Eley

Matt Eley has recently written a tutorial and some examples for Stardust!
Thanks a lot, Matt :)




View tutorial


Check it out! Matt has written this very detailed tutorial on the nitty-gritty of Stardust. He covered all the things you need to know to build a Stardust particle effect from the ground up, including initializers, actions, emitters, clocks, and renderers. I think reading this tutorial might help learning Stardust even more easily than reading the Stardust Manual. It's probably because I'm not a native English speaker...oh well, this gives me a rather nice motivation to practice English harder :p




View example


In this example, Matt showed the magic of combining bitmap filters with Stardust, creating this fantastic glowy spaceship thruster effect.




View example


I have to admire Matt for creating this example. He's done a brilliant job on integrating Stardust with Papervision3D, using particle effects to bring 3D Flash into an even higher level!

Thinner Builder, Smaller Stardust



Stardust project homepage
Stardust Manual (PDF)

I should have done this long time ago.

As listed in the feature list, Stardust supports XML serialization. The XMLBuilder class is in charge of converting a particle system to XML representation and reconstructing a particle system from a give XML representation.

How does the XMLBuilder class know the mapping from an XML tag's name to an actual Stardust class? The answer is the registerClass(), registerClasses(), and registerClassesFromClassPackage() methods. The XMLBuilder relies on these methods to acquire the knowledge of which XML tag name maps to which actual class.

These methods have to be called by the programmer: the more classes you wish the builder to build from XML data, the more classes you must register. The more classes you register, the larger the compiled file size, since more classes are linked together.

The registerClassesFromClassPackage() method is worth mentioning in particular. Subclasses of the ClassPackage class, which is essentially a collection of classes for convenience, all override the populateClasses() method to populate the classes (an array) property with class references. The registerClassesFromClassPackage() would register all the classes in a ClassPackage object in just one line of code. There are already several build-in class packages at your disposal: CommonClassPackage, TwoDClassPacakge, ThreeDClassPackage, ZBClassPackage, PV3DClassPackage, and ND3DClassPackage. All these class packages provide a getInstance() method to return a singleton object, since it's not necessary to instantiate a collection with a fixed set of elements yourself.

Class packages are convenient. But please beware: it's very likely that you would not use all the classes in a class package during XML deserialization, thus wasting some file size. It doesn't matter when the file size is of no concern; however, when you are working with a file-size-sensitive project, such as banner, file size becomes critically. In such circumstances, I would highly recommend you register classes one by one through the registerClass() method, just registering the class you would like to use when deserializing from XML data.

Originally, the XMLBuilder class registers the CommonClassPackage, TwoDClassPacakge, and ThreeDClassPackage by default. I've removed this default action in the latest revision (1.0.110 Beta), which I should have done long time ago.

You can see this class registering process in action in the 6th step of the XML reconstruction example in the Stardust Manual on page 41, which I just updated today.

Monday, October 12, 2009

CJLibrary Java - Client/Server and Signals

I chose Java as primary language for my Internet & Multimedia Lab class, and I decided to start the CJLibrary Java project. Eventually, I'll port some useful code from my CJLibrary (for AS3) to CJLibrary Java.

Here's the documentation for CJLibrary Java.

Currently the project mainly consists of the idv.cjcat.net and the idv.cjcat.signals packages; the former is for client-server connection and the latter is an Observer Pattern framework inspired by Robert Penner's AS3 Signals project.

The idv.cjcat.net package encapsulates complex client-server connection handling and exposes a set of user-friendly interface, including the use of the idv.cjcat.signals package.

Here's a quick look at how the idv.cjcat.net package works.

//creates an EchoServer object and starts the server on port 2266
Sever server = new EchoServer(2266);
server.start();

//creates two clients that connects to the server
Client client1 = new EchoClient();
Client client2 = new EchoClient();
client1.connect("localhost", 2266);
client2.connect("localhost", 2266);

Note that the Server and Client classes are both abstract. You have to extend them to create concrete subclasses. The createListener() method is the only method that has to be implemented. In this method you should return your desired SocketListener object, which is also abstract and whose mainLoop() method should be implemented.

Here's the EchoServer class:
(Sorry for the ugly intending. I'm still unable to get the code highlighter to work properly.)
public class EchoServer extends Server {
public EchoServer(int port) {
super(port);
}
@Override
protected SocketListener createListener() {
return new EchoSocketListener();
}
}

As you can see, this concrete class is only overriding the createListener() method to tell this server which socket listener it should use, which listens to socket input.

The same logic is the same for the EchoClient class:
public class EchoClient extends Client {
@Override
protected SocketListener createListener() {
return new PrinterSocketListener();
}
}


Now let's take a look at the EchoSocketListener, which sends back, i.e. echoes, whatever it receives.
public class EchoSocketListener extends LazySocketListener {
public EchoSocketListener() {
onReceive().add(new SignalListener() {
@Override
public void update(Signal signal) {
getWriter().println(signal.getMessage());
}
});
}
}

This class extends the LasySocketListener class instead of SocketListener, because the LasySocketListener class further encapsulates the socket IO, providing a getReader() and getWriter() accessors to give user an even easier way of socket IO handling.

This class also demonstrates the usage of the idv.cjcat.signals package. The onReceive() accessor returns a Signaller object that dispatches signal objects of the Signal class. The add() method adds a listener that listens to signals of the Signal class, therefore the listener must implement the SignalListener interface and implement the update(Signal signal) method. This listener object simply tells the writter to print whatever message the signal is containing, which is the direct message sent over by the other end of the socket.


Finally, here's the PrinterSocketListener class for the client, which simply prints out whatever message received.
public class PrinterSocketListener extends LazySocketListener {
public PrinterSocketListener() {
onReceive().add(new SignalListener() {
@Override
public void update(Signal signal) {
System.out.println("client received: "+ signal.getMessage());
}
});
}
}


Now in the main program, the following additional lines of code would cause the two clients to send messages to the server and receive messages that are echoed back.
//sends messages to the server
client1.send("Hello. I'm client #1.");
client2.send("Hello. I'm client #2.");


And this is what you'll get from the console output:
Hello. I'm client #1.
Hello. I'm client #2.

These are messages that are echoed back by the server, and the order might be reversed, since the two clients have independent socket listener threads.