The
previous article describes
features of my world rendering engine. This article describes graphics engine techniques used to render the world. I highlight two competing approaches with which I've experimented.
The goal is to paint a picture of the world. This includes layers of terrain, characters, creatures, and other surface features, as well as special effects graphics. See the
previous article for a small sample of the rendered world.
Under the hood, I've employed two approaches: (a) Off-screen, background-thread, pre-rendering vs. (b) On-demand, in-line rendering. This represents a classic memory-versus-speed tradeoff. Allocating the world image in memory, to be rendered by a background thread, should improve the speed of screen painting and overall client responsiveness. This is a theoretically reasonable approach, which is actually rather common (often used for
double-buffering). However, the devil is in the details.
Due to Java's painting architecture, my background rendering thread must be synchronized with Java's painting thread. Ultimately, my background rendering thread becomes a tripwire to Java's painting. (
Tripple-buffering might overcome this, but would be memory prohibitive and even more complicated.)
The second approach embraces Java's painting architecture, rendering the world on demand. Since all the painting calculations are now performed in Java's painting thread, more careful optimization is needed to avoid stalling the application. Optimization adds complexity, but in this case I consider in-line rendering to be more straight-forward than off-screen rendering.
In my usual manner of over-analyzing and over-engineering, I've experimented with a hybrid approach. Terrain is pre-rendered off-screen, while characters, surface features, and effects are drawn on-demand. In this case, the Java painting thread still synchronizes with my background rendering thread, but is only grabbing part of the terrain layer, which rarely changes once drawn, thus avoiding the tripwire effect described above. This approach may provide the best of both worlds.
During alpha testing, I've tried all three techniques. The first technique is too cumbersome. The second technique is performance sensitive, but seems promising. The hybrid approach provides the best and worst of both worlds, at the same time solving and creating more subtle issues. From a software standpoint, I'd love to perfect the hybrid engine. Someday I will, but the on-demand drawing system is the simplest to pursue for my immediate needs.
From a performance standpoint, I do not have any hard statistics yet, but on-demand rendering seems to perform well on 5-year-old hardware, in Linux, in windowed mode (not full screen exclusive mode), with no accelerated hardware drivers. With
further rendering optimizations and
improvements promised for Java, my graphics engine should support
Potential RPG and future projects.
Having never built a graphics engine before, I've found this to be one of the most challenging and interesting components of this project.