Adding Rotation to the "GLQuad_gt"

While reviewing the plugin project for the quad I posted about in my last entry, I noticed that it would be really easy to add in rotation for the object. All in all, it took my around five minutes.

Having xyz translation and xyz rotation built into the object is handy to have because I tend to "shape" my Quad, then move it around via a 3D transform to place it where it needs to go.

Now, one could move all 4 corners, or figure out x/y/z translations for the four corners to deduce rotation, but having the parameters built into the object is handy. It's all too often that I get the basic shape of the Quad I want, and then simply wish to move it back or forward, rotate it 10 degrees one way, etc., without manipulating every single corner. Out comes the 3D transform macro. It's a pretty solid bet that if I'm using Quads like that, sooner or later multiple 3D transforms will start working there way into the picture.

So, why not try to add those functions into a patch and have them available off top? That's really one of the great things about QC; there's a robust system for visual programming a graph (with a really nice looking GUI as well), but also some extendability. If I wanted to, I could likely work something up really similar (and probably slightly quicker, given the instant compile) with OpenCL using code *inside* of QCPlugin, by using a few different stock patches, but we also have the flexibility of making a plugin that makes some GL calls, wraps everything up in a patch, and is 10.5 compatible. The GLSquare Project from the 10.5 Developer examples proves to be a decent starting point for fleshing out something more complex than a simple square with Image Input, and is what I initially used as my starting point, first adding x/y parameters for the corners, then texture offset. Later I experimented with adding the texture offsets, Z for the corners, and transforms.

I'm running through this to explain how it's pretty reasonable to have a plugin, work with it, and then decide that you wish to add in new parameters in Xcode, compile, and reload into the system, while not having compositions break as long as you haven't eliminated (or renamed - same thing) any ports. Adding ports is fine. I find Kinemecore.plugin ( to be especially handy for automating plugin installs, as it automatically appends ".old" onto your old version of the plugin, keeping Quartz Composer from loading it. It also automates the restart of QC, so that your new plugin loads without having shut down and reopen QC yourself.

Adding in rotation to the plugin requires one to declare more property inputs. So, in GLQuadPlugin.h it looks something like:

@interface GLQuad_gtPlugIn : QCPlugIn



@property double inputX;

@property double inputY;

@property double inputZ;

@property double inputRotationX;

@property double inputRotationY;

@property double inputRotationZ;

@property double inputX1;

@property double inputY1;

etc., etc....

Implementing the rotation in the .m file is a little more involved, but not too hard.

First, one declares the ins and outs as dynamic; the line is already setup in the plugin project, because there are already dynamic inputs. It winds up looking like:

/* We need to declare the input / output properties as dynamic as Quartz Composer will handle their implementation */

@dynamic inputX, inputY, inputZ, inputRotationX, inputRotationY, inputRotationZ, inputX1, inputY1, inputZ1, inputX2, inputY2, inputZ2, inputX3, inputY3, inputZ3, inputX4, inputY4, inputZ4, inputA1, inputA2, inputB1, inputB2, inputC1, inputC2, inputD1, inputD2, inputColor, inputImage;

The plugin project necessitates that the rotation also be added in at + (NSArray*) sortedPropertyPortKeys (this is where port ordering on the plugin happens)
, and
+ (NSDictionary*) attributesForPropertyPortWithKey:(NSString*)key
(this is where default values for the plugin happen).

Finally, we get to where the rotation itself "happens".

Currently, the plugin contains:

/* Save and set modelview matrix */

glGetIntegerv(GL_MATRIX_MODE, &saveMode);



glTranslatef(self.inputX, self.inputY, self.inputZ);

This makes the GL Matrix "Model View", and adds translation to the plugin. Notice one directly uses glTranslatef.

Adding the rotation using that using this "freebie" route, looks pretty similar to the Translate method, but slightly different:

glRotatef(self.inputRotationX, 1.0, 0.0, 0.0);

glRotatef(self.inputRotationY, 0.0, 1.0, 0.0);

glRotatef(self.inputRotationZ, 0.0, 0.0, 1.0);

This is pretty straightforward. Note that there are 3 lanes in each line. These correspond to x, y and z. By making the x lane in the first line 1.0, it allows the input to manipulate X rotation. For Y, this is moved to the 2nd lane, and for Z, the 1.0 value is moved to the 3rd lane.

The thing that's really handy about this plugin (and project) for me, is that it can be used in ways similarly to the stock line plugin, as opposed to something like a sprite.

Some situations lend themselves to manipulating corner positions, instead of translate happening from a center point. With a Sprite, it becomes really hard to have it act in a line like way (interfacing with something like Hough Lines or the OpenNI User Tracker comes to mind). Similarly, a GL Quad gives that kind of control, but many times I wish to address the Quad like a Sprite, and just move it around or rotate without having to do maths for every single corner. Having the texturing offsets built in is a nice freebie; one can skew the quad to a non rectangular shape, and then use the A1~D2 controls to go and correct aspect ratio.

No extra maths have to be done for the texturing since rotation the entire object wouldn't be expected to "do anything" to the texture.

The modelview matrix MUST be restored after color, texture, and vert point calcs happen; this is shown in the Xcode project. All of this should really be looked at in context of the actual XCode project, so that one understands the good (and important) stuff I'm glossing over for the purpose of semi-succinctly explaining the rotation addition.

Compiled plugin and sample comp: