Wednesday, January 7, 2009

Getting useful errors from Cg

Since Cg programs are compiled at the program's runtime, you must catch Cg compile and runtime errors from within your program. Here's how:

First, you will need a callback. Cg will call this function whenver there is an error. Example:

void MyErrorCallback(void) {
CGerror error = cgGetError();
const char* errorString = cgGetErrorString(cgGetError());
printf("Cg error: %s\n", errorString);

// check for compiler errors
if (error == CG_COMPILER_ERROR)
printf("%s\n", cgGetLastListing(context));
}


Next, you need to set the callback:
cgSetErrorCallback(MyErrorCallback);

Now you should get more useful output when Cg has problems.

And easy way to make for loops unrollable

Cg will let you use for loops in your shaders, but only if they can be unrolled. Though it loses you the performance benefits of loop unrolling, you can make a for loop unrollable by moving the guard (or "are we done yet?" check) into the loop body.

For example:

int arr[] = {2, 1, 3};
for (int i = 1; i < arr[0]; i ++) {
doStuff(arr[i]);
}

That snippet gives an error like this when you try to compile it:
frag.cg(71) : error C5013: profile does not support "for" statements and "for" could not be unrolled.

Instead, try the following:

int arr[] = {2, 1, 3};
for (int i = 1; i < MAX_LEN; i ++) {
doStuff(arr[i]);
if (i == arr[0])
break;
}


EDIT:
Or better yet, just do this:

int arr[] = {2, 1, 3};
for (int i = 1; i < MAX_LEN && i < arr[0]; i ++) {
doStuff(arr[i]);
if (i == arr[0])
break;
}


Note that I found order to be important (it didn't like arr[0] before MAX_LEN).

Saturday, January 3, 2009

Custom command keybindings in Gnome

Gnome (or, more precisely, Metacity), will let you create 12 custom key bindings. That is, you can set 12 custom commands that are triggered by a given key sequence.

This is done in Configuration Editor (System Tools -> Configuration Editor; enable it in "Edit Menu" if it isn't there). The first custom command is set with /apps/metacity/global_keybindings/run_command_1. The associated keybinding is set with /apps/metacity/keybinding_commands/command_1.

Saturday, December 27, 2008

gluPerspective to glFrustrumf

gluPerspective is a nice, intuitive helper function for setting the projection matrix in OpenGL. However, it's part of the glu library, which doesn't seem to be (readily) available for the iPhone (OpenGL ES).

Here is how to call glFrustrumf with the values you would give to gluPerspective:

float fov = 45;
float near = 0.01, far = 10;
float aspect = (float)windowWidth / (float)windowHeight;

// glPerspective(fov, aspect, near, far);

top = tan(toRad(fov)) * near;
bottom = -top;
left = aspect * bottom;
right = aspect * top;

glFrustumf(left, right, bottom, top, near, far);

Saturday, December 20, 2008

"error: syntax error before '*' token"

I recently began porting Jumper to the iPhone as a winter project. After adding another source file (Level.c in this case), I started getting thousands of build errors, along the lines of:

error: syntax error before '@' token
error: syntax error before '*' token

These were from files in /Developer/Platforms/iPhoneSimulator.platform/..., which was not encouraging. Something weird was going on.

Actually, it was really simple. Turns out that should have been Level.m, not .c. Whoops.

Saturday, December 13, 2008

Drawing triangles for height maps

Two ways of drawing triangles for HeightMap h1:

Simple, like this:

----
|/|/
----



int ndx = 0;
for (int r = 0; r < h1->rows-1; r ++) {
glBegin(GL_TRIANGLE_STRIP); {
for (int c = 0; c < h1->cols; c ++, ndx ++) {
int cols = h1->cols;
glVertex3fv(h1->verts[ndx+cols].xyz);
glVertex3fv(h1->verts[ndx].xyz);
}
glEnd();
}
}



More complex, but lends itself to simplification over distance, like this:

----
|\/|
----
|/\|
----



for (int r = 1; r < h1->rows-1; r += 2) {
for (int c = 1; c < h1->cols-1; c += 2) {
int cols = h1->cols;
int mid = r*cols + c;
glBegin(GL_TRIANGLE_FAN); {
glVertex3fv(h1->verts[mid].xyz);
glVertex3fv(h1->verts[mid-1].xyz);
glVertex3fv(h1->verts[mid-cols-1].xyz);
glVertex3fv(h1->verts[mid-cols].xyz);
glVertex3fv(h1->verts[mid-cols+1].xyz);
glVertex3fv(h1->verts[mid+1].xyz);
glVertex3fv(h1->verts[mid+cols+1].xyz);
glVertex3fv(h1->verts[mid+cols].xyz);
glVertex3fv(h1->verts[mid+cols-1].xyz);
glVertex3fv(h1->verts[mid-1].xyz);
}
glEnd();
}
}

Tuesday, December 9, 2008

Keep ssh connections open

While in college, I've had to do a lot of work by sshing into school machines. Unfortunately, they allow a rather short "idle" time before they kick me out of whatever I was doing (littering my code folders with .swp files in the process :-P)

While one way around this is to run all your sessions in screen, it's still annoying to me to have my sessions freeze every time I go for a snack.

Fortunately, you can keep your sessions open by putting the following into ~/.ssh/config on your (client) machine:

ServerAliveInterval 60

According to the man page:
"Sets a timeout interval in seconds after which if no data has been received from the server, ssh will send a message through the encrypted channel to request a response from the server."