Author Archives: Tim Gustafson

Five Days To Go

On Friday – just 5 days from now – I will set foot in the Pacific Crest Trail at the Mexican border near Campo, CA.  I will then begin a 200 mile walk North towards Idyllwild, CA that will take me about twelve or fourteen days.  I will walk through a desert and up a mountain.

I first decided to hike the Appalachian Trail in 2000.  The dot-com bubble had burst, and I was out of work and had no direction in my life.  I thought that a pilgrimage on foot might be just the thing for me, and I started getting ready to go with the plan being to leave in Spring 2001.  But then life happened and I never made it to the trail head in Georgia.

Eleven years later, I am in a very different place.  I live in California rather than New York. I have a good job.  I love my life.  But I still want to walk.

The aforementioned good job prevents me hiking the entire trail in one setting, so I will chunk the PCT up into tidy little 2-week and 3-week sections, and hopefully complete the trail in eight or ten years.  That is a span of time that is hard for me to comprehend – I have never done anything for so many years – but on the other hand I have waited longer than that to start and those years seem to have flown by at a break-neck pace, so why shouldn’t these next few years?  It will certainly feel like an accomplishment when some number of years from now I stand on the Canadian border looking back towards Mexico.

I have never spent two whole weeks out-of-doors.  It’s a long time.  I will probably stay at a hotel at least one night along the way, if only to shower, but being out-of-doors more hours of the day than not will be a novelty.  Sleeping on the ground every day and waking up with the sun – or even before the sun, as I expect the case will be – will be new.  Sleeping under the night sky will be new.

I do not  know what will change during the journey or what will be different at the end, but I expect I will feel differently about some things.  Certainly the fast pace of real life will be jarring.  Will I walk more in my normal life?  Will I spend more weekends camping?  Maybe.  Or maybe I’ll savor the annual trip.  I can’t say.

All I know for sure is that I am excited in a way that reminds me of how excited I was to hike the trail the first time.  I really am happy that this is finally going to happen.

Carl Sagan on the Pale Blue Dot

This narrow-angle color image of the Earth, dubbed ‘Pale Blue Dot’, is a part of the first ever ‘portrait’ of the solar system taken by Voyager 1. The spacecraft acquired a total of 60 frames for a mosaic of the solar system from a distance of more than 4 billion miles from Earth and about 32 degrees above the ecliptic. From Voyager’s great distance Earth is a mere point of light, less than the size of a picture element even in the narrow-angle camera. Earth was a crescent only 0.12 pixel in size. Coincidentally, Earth lies right in the center of one of the scattered light rays resulting from taking the image so close to the sun. This blown-up image of the Earth was taken through three color filters – violet, blue and green – and recombined to produce the color image. The background features in the image are artifacts resulting from the magnification.

We succeeded in taking that picture [from deep space], and, if you look at it, you see a dot. That’s here. That’s home. That’s us. On it, everyone you ever heard of, every human being who ever lived, lived out their lives. The aggregate of all our joys and sufferings, thousands of confident religions, ideologies and economic doctrines, every hunter and forager, every hero and coward, every creator and destroyer of civilizations, every king and peasant, every young couple in love, every hopeful child, every mother and father, every inventor and explorer, every teacher of morals, every corrupt politician, every superstar, every supreme leader, every saint and sinner in the history of our species, lived there on a mote of dust, suspended in a sunbeam.

The Earth is a very small stage in a vast cosmic arena. Think of the rivers of blood spilled by all those generals and emperors so that in glory and in triumph they could become the momentary masters of a fraction of a dot. Think of the endless cruelties visited by the inhabitants of one corner of the dot on scarcely distinguishable inhabitants of some other corner of the dot. How frequent their misunderstandings, how eager they are to kill one another, how fervent their hatreds. Our posturings, our imagined self-importance, the delusion that we have some privileged position in the universe, are challenged by this point of pale light. Our planet is a lonely speck in the great enveloping cosmic dark. In our obscurity – in all this vastness – there is no hint that help will come from elsewhere to save us from ourselves. It is up to us. It’s been said that astronomy is a humbling, and I might add, a character-building experience. To my mind, there is perhaps no better demonstration of the folly of human conceits than this distant image of our tiny world. To me, it underscores our responsibility to deal more kindly and compassionately with one another and to preserve and cherish that pale blue dot, the only home we’ve ever known.

- Carl Sagan, Pale Blue Dot: A Vision of the Human Future in Space, p. 6

A Simple LWJGL Interleaved VBO Example

After hunting around on Google for what seemed like ages for a good, fully working example of how to use interleaved Vertex Buffer Objects with LWJGL, I decided to make my own and share it with everyone.  This example draws a simple cube using vertex buffer objects.  The cube rotates on all three axes, and has a different color on each side so that you can better visualize the relationship between the code and the visual display.  On my laptop, I was able to get about 1,700 FPS.  If you want to see what sort of frame rates you are getting, turn on your Java Console.

/*
 * Copyright (C) 2011
 * Tim Gustafson
 * tjg@tgustafson.com
 * http://tgustafson.com/
 * All Rights Reserved
 *
 * Licensed for non-commercial use by an individual for educational purposes only.
 */

package simpleinterleavedvboexample;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Date;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.util.glu.GLU;

public class SimpleInterleavedVboExample {
  public void start() {
    // create our display window
    try {
      Display.setTitle("Simple Interleaved Vbo Example");
      Display.setDisplayMode(new DisplayMode(600, 600));
      Display.create();
    } catch (Exception e) {
      System.err.println(e.toString());

      System.exit(1);
    }

    // set up OpenGL
    GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    GL11.glShadeModel(GL11.GL_SMOOTH);

    GL11.glEnable(GL11.GL_COLOR_MATERIAL);
    GL11.glEnable(GL11.GL_DEPTH_TEST);

    GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
    GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
    GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);

    // set up lighting
    GL11.glEnable(GL11.GL_LIGHTING);
    GL11.glEnable(GL11.GL_LIGHT0);

    GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, floatBuffer(1.0f, 1.0f, 1.0f, 1.0f));
    GL11.glMaterialf(GL11.GL_FRONT, GL11.GL_SHININESS, 25.0f);

    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, floatBuffer(-5.0f, 5.0f, 15.0f, 0.0f));

    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_SPECULAR, floatBuffer(1.0f, 1.0f, 1.0f, 1.0f));
    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_DIFFUSE, floatBuffer(1.0f, 1.0f, 1.0f, 1.0f));

    GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, floatBuffer(0.1f, 0.1f, 0.1f, 1.0f));

    // set up the camera
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GLU.gluPerspective(45.0f, 1.0f, 0.1f, 100.0f);

    GL11.glMatrixMode(GL11.GL_MODELVIEW);
    GL11.glLoadIdentity();

    GLU.gluLookAt(
      0.0f,
      0.0f,
      5.0f,
      0.0f,
      0.0f,
      0.0f,
      0.0f,
      1.0f,
      0.0f
    );

    // create our vertex buffer objects
    IntBuffer buffer = BufferUtils.createIntBuffer(1);
    GL15.glGenBuffers(buffer);

    int vertex_buffer_id = buffer.get(0);

    float[] vertex_data_array = {
    //   x      y      z      nx     ny     nz     r      g      b      a
    // back quad
         1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,
        -1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,
        -1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,
         1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,

    // front quad
         1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f,  1.0f,
        -1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f,  1.0f,
        -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f,  1.0f,
         1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f,  1.0f,

    // left quad
        -1.0f,  1.0f, -1.0f, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f,  1.0f,  1.0f,
        -1.0f,  1.0f,  1.0f, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f,  1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f,  1.0f,  1.0f,
        -1.0f, -1.0f, -1.0f, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f,  1.0f,  1.0f,

    // right quad
         1.0f,  1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,
         1.0f,  1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,
         1.0f, -1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,
         1.0f, -1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,

    // top quad
        -1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,  0.0f,  1.0f,
        -1.0f,  1.0f,  1.0f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,  0.0f,  1.0f,
         1.0f,  1.0f,  1.0f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,  0.0f,  1.0f,
         1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,  0.0f,  1.0f,

    // bottom quad
        -1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f,
         1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f,
         1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f
    };

    FloatBuffer vertex_buffer_data = BufferUtils.createFloatBuffer(vertex_data_array.length);
    vertex_buffer_data.put(vertex_data_array);
    vertex_buffer_data.rewind();

    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertex_buffer_id);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertex_buffer_data, GL15.GL_STATIC_DRAW);

    // set up frame rate counter stuff
    int framerate_count = 0;
    long framerate_timestamp = new Date().getTime();
    double rotate_x, rotate_y, rotate_z;

    while (!Display.isCloseRequested()) {
      // increment frame rate counter, and display current frame rate
      // if it is time to do so
      framerate_count++;

      Date d = new Date();
      long this_framerate_timestamp = d.getTime();

      if ((this_framerate_timestamp - framerate_timestamp) >= 1000) {
        System.err.println("Frame Rate: " + framerate_count);

        framerate_count = 0;
        framerate_timestamp = this_framerate_timestamp;
      }

      // clear the display
      GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

      // perform rotation transformations
      GL11.glPushMatrix();

      rotate_x = ((double)this_framerate_timestamp / 300.0) % 360.0;
      rotate_y = ((double)this_framerate_timestamp / 200.0) % 360.0;
      rotate_z = ((double)this_framerate_timestamp / 100.0) % 360.0;

      GL11.glRotated(
        rotate_x,
        1.0,
        0.0,
        0.0
      );

      GL11.glRotated(
        rotate_y,
        0.0,
        1.0,
        0.0
      );

      GL11.glRotated(
        rotate_z,
        0.0,
        0.0,
        1.0
      );

      // render the cube
      GL11.glVertexPointer(3, GL11.GL_FLOAT, 40, 0);
      GL11.glNormalPointer(GL11.GL_FLOAT, 40, 12);
      GL11.glColorPointer(4, GL11.GL_FLOAT, 40, 24);

      GL11.glDrawArrays(GL11.GL_QUADS, 0, vertex_data_array.length / 10);

      // restore the matrix to pre-transformation values
      GL11.glPopMatrix();

      // update the display
      Display.update();
    }

    // clean things up
    Display.destroy();
  }

  public FloatBuffer floatBuffer(float a, float b, float c, float d) {
    float[] data = new float[]{a,b,c,d};
    FloatBuffer fb = BufferUtils.createFloatBuffer(data.length);
    fb.put(data);
    fb.flip();
    return fb;
  }

  public static void main(String[] args) {
    SimpleInterleavedVboExample example = new SimpleInterleavedVboExample();
    example.start();
  }
}

Henry David Thoreau

“I went to the woods because I wished to live deliberately, to front the essential facts of life, and see if I could not learn what it had to teach, and not, when I came to die, discover that I had not lived.” – Henry David Thoreau