Advanced example

This is a more advanced example. I assume that you are familiar with jPCT's basic, i.e. that you understand the Hello World example. I won't explain the basics that Hello World already covers again.
In this example, you'll find...

The first two lines (glAvoid... and maxPolys...) are mainly to save some memory. We don't need copies of your textures in main memory once uploaded to the graphics card and we are using Compiled objects, which is why our VisList won't get very huge, so 1000 polygons are more than enough here.
The next few lines are basic stuff. You can read about them in the docs at [2], if you need more information. But i'll cover the last two lines: collideOffset is needed to make the Collision detection work with the plane. It's a common problem when using collision detection, that your collision sources are passing through the obstacles, if this value is too low. 500 is a reasonable value for this example. The last line (glTrilinear) makes jPCT use trilinear filtering. It simply looks better that way.

The first part loads the textures. Nothing new here. In the second section, the call to setPaintListener() is interesting, because it shows you how to use an IPaintListener implementation. Pretty simple, but what's the point? Well, the point is, that you have two methods that will be called before and after a frame is being drawn. In this example, we are using this to count frames per second. This example doesn't really need to do it this way, it would have been fine in the game loop itself too, but it's more flexible to do it this way right from the start. Once you decide to switch to AWTGLRenderer or to JOGL for example, this makes the transition easier.

Why two? Because one is for the scene itself and one is for the sky dome. This makes it much easier to handle the dome, but you don't have to do it this way. Adding the dome to the scene itself would work too.

Key- and mouse mapping

The example uses helper classes to access the keyboard and the mouse. The keyboard helper comes with jPCT in form of the KeyMapper. The mouse mapper is similar, just for the mouse. It's part of the source code:

While we are at it, i'll post the code for the keyboard access here too. It's nothing special, but it shows the basic concept that you should always remember when using the keyboard in games: Don't work with the events but just set/clear a flag for a key pressed/released.

There are three interesting things in here. At first, the loading of the 3DS files (more/additional information on loading models, can be found on Loading models page). A 3DS file may contains different parts/meshes. Each part will be loaded as a separate Object3D in jPCT, which is why you get an array as return value from the loader. However, an array of objects isn't needed in this case. The rock consists of a single mesh and the dome...to be honest, i don't know...but regardless of its numbers of meshes, we only need one object for it. Therefore, we only use the first instance from the rock-array and use the mergeAll-method from Object3D to merge all dome parts (if any...) into one.
The dome already has texture coordinates, but they are not really suitable for displaying a star field. We are using a method that can be found in the jPCT forum (tileTexture) to improve this.
And finally, the plane is a primitive. So it's flat right now. Later, we'll take care of this.

Compiling the objects

We want maximum performance, so we are compiling the objects. This happens in this code snippet:

Deforming the plane

As said above, the plane is flat...which is boring. We want some flat hills. We could model something like that in a modeler, we could create a vertex shader that does it at runtime (which is pretty bad, because it makes collision detection with the deformed plane very difficult), or we can use an IVertexController. This is what we do here:

It's a pretty simple controller. All it does, is to modify the plane's mesh data based on a simple sin/cos function. We only apply this controller once, which is why we remove it right afterwards. This isn't needed. As long as you don't apply it again, it doesn't change anything no matter if it's still attached or not.

Setting up the shadow mapping

This example uses shadow mapping on hardware that supports it. To ease things, we are using the ShadowHelper that comes with jPCT. Some code:

We need a projector (which is basically the sun) and set up the shadow helper with that. In this example, the plane is a receiver (i.e. shadows will be cast to it) and the animated model (the snork) and the rock are casters. Rock and snork are not receivers, because self shadowing tends to create artifacts and the rock uses shaders, but more about that in the next section.

Shaders for the rock

The rock uses a simple shader. The shader is exactly the same as the one on the Shaders page. Here's the code:

When using a shader, the fixed function pipeline is disabled completely for this object. This is why an object that uses shaders can't be a receiver of shadows in the way the ShadowHelper does shadow mapping. If you want shadows in a shader object, you would have to do this in the shader. In this example, we won't to this, because it's the advanced example, not the expert one...
There's one line commented out in the code. This method is available in jPCT 1.19+ only, which hasn't been released as i'm writing this. If it has been released, you may uncomment this line again.

The game loop

The game loop is where the action happens. To prevent modern cpus from throttling, which makes timing calculations too difficult for this example, this example renders more frames than it actually has to. However, for the game logic (animations, controls,...), we are using a ticks based approach. The ticks are provided by a simple Ticker class:

This implementation uses System.currentTimeMillis(), because it's simple. But it's not very accurate. For a better timing, consider to use System.nanoTime() (which it prone to problems with cpu throttling) or the LWJGL timer (which has some problems with running at double the speed on some VMs). Anyway, correct timing isn't an easy task and for sure not something that we'll cover here in detail.

It simply animates the snork based on its key frames and make it walk around in circles in the scene. The interesting part here is, where the snork gets translated 50 units up (more info: Coordinate system) and then dropped back onto the plane using the collision detection methods that jPCT provides. This way, it follows the terrain quite nicely.

The shadows

Because the projector and the casters move each tick, the shadow map has to be recalculated at least each tick. For reasons mentioned above, we are doing this every frame instead to keep the cpu busy:

This is pretty basic code except that it renders two worlds into one buffer. The world with the sky dome and the one with the scene. To make the IPaintListener not be called twice (and count double the fps that we actually have), it has to be disabled for one of these calls. We are doing this for sky dome, we could have done it for the scene as well.
Please note that rendering the scene doesn't require the usual render...draw...update-sequence in this case, because it uses the shadow helper and its implementation already takes care of this. A simple call to ShadowHelper.drawScene() is sufficient here.

Screen shot

If all goes well, this is how it looks like:

Final words

That's it. This tutorial doesn't cover each and every detail of the code and the code may not be optimal. However, it should help to get a better understanding for some aspects. Have fun!