Alex Saint Croix

I know that Scala has no static methods and it uses singleton objects instead.  I also know that Scala is supposed to be able to call Java methods, including Java static members.

Further, I know that org.lwjgl.opengl.ARBVertexBufferObject extends org.lwjgl.opengl.ARBBufferObject in the LWJGL library, and that the latter is generated code.

What I did not appreciate, but do now, is that Scala cannot make calls to static members in a superclass of a given class.  In order to call ARBVertexBufferObject.glGenBuffersARB(…) I need to either call ARBBufferObject.glGenBuffersARB(…) directly, or use some sort of calling class antipattern.

Needless to say, this is a headache.  Java / Scala interop is not quite where I’d like it to be, but I’m grateful for what does exist.

Software Engineering for breakfast at Espresso Royale on Ann Arbor Saline Road.

Eye candy for Isographer, Isometric, Java, OpenGL, Rendering, Terrain, LWJGL,

After a great deal of refactoring, and building a unit testing harness with JUnit for the project, I finally implemented “diagonal hilltop smoothing”. This feature makes a second pass over the terrain and identifies locations that could benefit from a slope inversion. So, instead of “down and then over”, the hilltop pieces move “over and then down” in a diagonal direction. As you can see, this gets rid of a lot of the unnatural “scaling”, where there are diagonal rows of rounded corner bottoms on interior curves of the terrain.

Not all cliff edges are meant to go away. If that were the goal, I’d just make a surface mesh. I want impassable cliff-like edges between certain tiles. Next I’m going to work on improving the appearance of certain impassable ridges. Should be faster, with the new testing tools and refactored terrain processing code.

I just ran into a rather annoying roadblock.

// Will not compile, because you can't make generic arrays in Java!
x = new Tuple<Float,Tuple<Slope,Direction>>[24][24];

Rather serious bummer, but probably for the best all the same. I spent some time digging for a generic 2D matrix implementation, to no avail. In general, I try to find these things online before I sit down to roll my own.  I think in this case I’ll just make some sort of data bean for this, but what a serious bummer.

Once I’m done with the proof of concept rendering pipeline for this I’m going to very seriously investigate moving it all to Scala.  It’s already evolving into a stream-processing computational model.  Basically, nothing but lots and lots and LOTS of functions mapped over filtered lists, list transforms, and so on.

Eye candy for 3D, Heightmap, LWJGL, Tile, Rendering, Java, OpenGL, Isographer, Isometric,

First iteration of my terrain smoother for Isographer.  Renders a heightmap using a set of 37 discrete tile types.  Hills along cardinal directions, and rounded corners between them.  In the next few days I’ll work on improving the smoother algorithm to account for “scaling” surface texture on the inside of hill curves, and also detecting undergirding cases to prevent gaps in the map under steep terrain.

/**
 * Copyright 2011 Alexander R. Saint Croix (saintx@umn.edu)
 * 
 * Available for personal or commercial use under the terms
 * of the Apache Software License, version 2.0
 */
public class Tuple implements Comparable {

    private S s;
    private T t;

    public Tuple(S s, T t) {
        this.setCar(s);
        this.setCdr(t);
    }

    public int compareTo(Object o) {
        if(o instanceof Tuple) {
            Tuple that = (Tuple)o;
            int r = that.getCar().hashCode() - 
                this.getCar().hashCode();
            if(r != 0) {
                return r;
            } else {
                return that.getCdr().hashCode() - 
                    this.getCdr().hashCode();
            }
        }
        return o.hashCode() - this.hashCode();
    }

    public int hashCode() {
        int hash = 0;
        hash = hash * 31 + s.hashCode();
        hash = hash * 31 + t.hashCode();
        return hash;
    }

    public boolean equals(Object o) {
        if(o instanceof Tuple) {
            Tuple that = (Tuple)o;
            return that.getCar().equals(getCar())
                    && that.getCdr().equals(getCdr());
        }
        return false;
    }

    public S getCar() {
        return s;
    }

    public void setCar(S s) {
        this.s = s;
    }

    public T getCdr() {
        return t;
    }

    public void setCdr(T t) {
        this.t = t;
    }
}

2nd demonstration of Isographer terrain heightmap processing.  This demo uses the same terrain as the first demo, only with 65x65 datapoints gotten by expansion and diamond square recursion.  Next steps will include discretizing the terrain height values, using the terrain slope data to swap out different angled tile types for smooth surface translation.

First demo of terrain heightmap processing and bare-bones Isometric 3D rendering in Isographer.

For the last five or six days I’ve been working very diligently to build a simple 3D isometric terrain rendering engine using JavaMonkeyEngine 3 (JME3).  I was delighted when, by the end of the first night I had assembled the necessary geometries for my surface tiles and textured them.  By the end of the second night I’d forced the camera into a parallel projection mode and positioned the scene with respect to the camera so that everything was rendered at the requisite angle.

From this point on, all I really need is to light the scene.  However, this disarmingly simple thing has turned into a frustrating and heart-wrenching struggle.  I have to conclude, after several days of hammering, chiseling, scraping, poring through source code, online tutorials, and relevant books on the subject, that JME3 is not going to work for my project.

After several confusing false starts, I decided to simplify the lighting problem.  I ditched my complex models and implemented a Mesh that is, functionally, half of a cube.  Just the 3 quads that face the camera.  I computed the surface normals for these quads (this is very simple, because the object is a cube, and it is aligned to the X,Y, and Z axes), and then set up three directional spotlights.  One red, one green, and one blue.  The goal of my experiment was to shine each of these lights on a different face of the mesh.  For comparison, I included a com.jme3.scene.shape.Box in the same node as my mesh.

One of the first things that I noticed was that the Box model had to be rotated slightly in order for its normal vectors to align properly—in other words, shining a light straight down from above (0,1,0) lit one of the back-facing quads on the cube.  That was straightforward to resolve by rotating the cube. Still, as the days marched on, no combination of effort and experimentation would result in the effect that I was attempting to produce, which was a light shining down on the tile nearly vertically, while lighting the two vertical faces of the tile at noticeably different degrees. Eventually, I realized that even if I did manage to tweak and torque the normals around and the lights to get the effect I was after, it would almost certainly break or behave counterintuitively once I began to vary the angle of the top of my tiles, which is the whole point of this work.

I’ve decided to give up JME and work more directly with the Lightweight Java Games Library (LWJGL). I don’t need physics, collision detection, particle systems from a massive game engine. I just need rendering. Triangles, textures, and light. Still, it’s a big surprise, to come so frustratingly close to completion only to turn away from an otherwise excellent library.