Another glance at LambdaHack — a year later

A while back, when I first started to get serious about writing a game in Haskell, I decided to take a look at some existing code and try to figure out how they did things. At the time I had an interest in roguelikes so LambdaHack was a natural choice for investigaion. (part 1 and part 2)

I learned a lot from that project, though the way I wrote up my posts was a little bizarre. After making some decent progress on my turn-based strategy game, I stalled out after getting frustrated with Haskell and my difficulty in managing game state. Oddly enough, after a year, I’m getting the urge to give Haskell another shot so I figured I’d catch up on what’s changed with LambdaHack and take another run through the code now that I have some more experience.

Installation

Firstly, the project now has documentation on how to play and the design of the project. Writing them up in markdown is a great idea and github displays it nicely.

I’m also sad to report that there were still some installation issues for me. I’m running a new install of Fedora 15 with Haskell Platform 2011.2.0.0 and I could not cabal install LambdaHack my way through a default install. I don’t believe this to be LambdaHack’s problem as it appears to be some issue with cairo-0.12.0 and it’s dependencies. Cabal is a pretty awesome tool, but one problem with having a wide and deep dependency tree is that one hitch in the install process ruins it all. In my previous posts I installed LambdaHack using the -fcurses flag in cabal. This installed successfully, but ended up corrupting the terminal when I ran the game. The README now mentions using the following to install for terminals (which did work for me, though I also used –global):

cabal install -fvty LambdaHack

Interesting Bits

With the installation done, I want to cover some things that a new Haskell programmer [like me] might find interesting that I didn’t cover in earlier posts. My hope is that this post helps other people new to Haskell navigate the code to LambdaHack and make it easier to learn from the project.

Startup and Display Specific Code

As noted in part 2, the definition of main in LambdaHack.ls immediately calls into whatever module got included into the build (controlled via LambdaHack.cabal). For the steps above, this is Display\Vty.hs. Each of the sub-systems in the Display folder end up implementing a startup function that takes a parameter of type Session. For vty, this is simply a Graphics.Vty.Vty type synonym.

type Session = V.Vty

Gtk.hs and Curses.hs each implement a record.

-- Gtk.hs
data Session =
  Session {
    schan :: Chan String,
    stags :: Map AttrKey TextTag,
    sview :: TextView }
-- Curses.hs
data Session =
  Session
    { win :: Window,
      styles :: Map (Maybe AttrColor, Maybe AttrColor) C.CursesStyle }

All of these are called Session, so that way cabal can choose which implementation to include. Naturally, each of the display implementations have a startup function defined (to be called straight away from main) with the same type:

startup :: (Session -> IO ()) -> IO ()

The Game Loop

Once some boilerplate stuff is done in the startup code of LambdaHack.hs, ultimately a call is made to handlerToIO.

handlerToIO :: Session -> State -> Message -> Action () -> IO ()

This can be found in Action.hs and exists to run the Action monad defined in that file. As a new Haskeller, also having been away for a while, the code in here is a bit scary. Fortunately, the details of this are not important to getting a high level view of the game loop.

Lets approach this from a practical standpoint by looking at Turn.hs. The start and generate functions from LambdaHack.ls eventually call handlerToIO feeding it a function called handle defined in Turn.hs.

handle :: Action ()

This function simply returns an Action monad. It does some updating to the state, updates monsters and the player and then ultimately calls nextMove which then calls handle. That’s effectively it. The functions in Turn.hs do some book keeping by updating time, perceptions, monsters and running the player’s commands, but that it.

In this loop, handlePlayer may get called if the player can make a turn. This function will eventually evoke playerCommand which is where all of the input handling takes place. The playerCommand function handles some special run processing, but then calls handleKey (defined in KeyBindings.hs) looks the action up in the standard key bindings (defined back in Turn.hs) that were passed in and then returns the Action associated with that key (defined in Command.hs). As for the Actions themselves, they’re defined in Actions.hs which is where you should go to see the game logic.

What’s Next

This barely scratches the surface of interesting stuff about LambdaHack like the level generation stuff in Dungeon.hs.

Getting Started with F# 2.0, Mono 2.10, and Fedora

I’ve recently found F#, which is a programming language that sells itself as primarily a functional language that can also do imperative style programming and integrates with the .NET platform. This sounds like nothing but win for me, combining a lot of my favorite features in programming languages. Having recently installed Fedora 14 on a few desktops, I’ve decided to take it out for a spin.

Installing Mono 2.10

At the time of this writing, I could not find official RPM files for Fedora. Like Ubuntu, the repository only has old releases of the mono project (v2.6). To build it from scratch, I started off with this post by Nathan.

After using the provided script in Ubuntu, I’ve decided to run through the steps by hand in Fedora to take a look at configure options and such. The steps that I executed from a fairly new install of Fedora 14 were as follows (mostly cribbed from Nathan’s script linked to above):

1) Modify a few exports in ~/.bash_profile

export PATH=/opt/mono-2.10/bin:$PATH
export PKG_CONFIG_PATH=/opt/mono-2.10/lib/pkgconfig:$PKG_CONFIG_PATH
export LD_LIBRARY_PATH=/opt/mono-2.10/lib:$LD_LIBRARY_PATH

and then run

source ~/.bash_profile

to get all of the new settings.

2) Make a folder to house the source tars and cd to it.

mkdir builds
mkdir builds/mono-2.10
cd builds/mono-2.10

3) Install some dependencies.

yum install -y make automake glibc-devel gcc-c++ gcc glib2-devel pkgconfig subversion bison gettext-libs autoconf httpd httpd-devel libtool wget libtiff-devel gtk2-devel atk-devel pango-devel giflib-devel libglade2-devel libexif-devel libexif libjpeg-devel git

4) Download the source packages that we’ll be building

wget http://ftp.novell.com/pub/mono/sources/libgdiplus/libgdiplus-2.10.tar.bz2
wget http://ftp.novell.com/pub/mono/sources/mono/mono-2.10.1.tar.bz2
wget http://ftp.novell.com/pub/mono/sources/gtk-sharp212/gtk-sharp-2.12.10.tar.bz2

5) Build and install libgdiplus

tar jxvf libgdiplus-2.10.tar.bz2
cd libgdiplus-2.10
./configure --prefix=/opt/mono-2.10
make
sudo make install

6) Install mono 2.10 itself.

tar jxvf mono-2.10.1.tar.bz2
cd mono-2.10
./configure --prefix=/opt/mono-2.10
make
sudo make install

7) Then install gtk-sharp.

tar jxvf gtk-sharp-2.12.10.tar.bz2
cd gtk-sharp-2.12.10
./configure --prefix=/opt/mono-2.10
make
sudo make install

Installing F#

At this point you can get the F# 2.0 code that was released under the Apache license by using git and then compiling. “su -m” is used so that the environment variables for PATH, and LD_LIBRARY_PATH stay accessible to the root command when installing. These steps are based on Chris’s article found here.

git clone git://github.com/fsharp/fsharp
cd fsharp
autoreconf
./configure –-prefix=/opt/mono-2.10
make
su -m
make install

Troubleshooting

  • The list of dependencies may not be 100% complete, but it should be close. Be aware of potentially missing *-devel packages.
  • If a “sudo make install” for F# fails because it can’t find the gacutil program, it’s probably because the root user doesn’t have modified PATH and LD_LIBRARY_PATH environment variables to find the program in /opt/mono-2.10/bin despite the user executing this command having updated variables. This is why I just did “su -m”.
  • If gtk-sharp complains about not finding csc.exe while executing ./configure, it’s because you need to set PKG_CONFIG_PATH=/opt/mono-2.10/lib/pkgconfig:$PKG_CONFIG_PATH. Once that environment variable is set, things will continue fine.

Testing out F#

Now that we got the core mono and F# software installed, lets write the obligatory hello world dialog box. Put the following code into a file called test.fs.

#light

open System
open System.Windows.Forms
open System.Drawing

type MainForm() as form =
    inherit Form()
    let label1 = new Label()
    do form.InitializeForm

    member this.InitializeForm =
        this.FormBorderStyle <- FormBorderStyle.Sizable
        this.Text <- "Hello World Application"
        this.Width <- 300
        this.Height <- 300
        label1.Text <- "Hello Internet!"
        this.Controls.AddRange([|(label1:> Control)|])

do Application.Run(new MainForm())

Without getting into details, this block of code: 1) Opens up the System.Windows.Forms library, 2) Creates a new Form called MainForm, 3) Constructs a basic Form and adds a Label control, 4) Runs the Application by passing it a Form. Keep in mind that spaces are significant in F# and your code should be aligned in the same manor my sample is. The F# compiler will also complain if you insert tab characters in the source code, so just stick to spaces.

If you’ve had experience with C# and .NET before, most of this will look familiar … and probably not particularly ground breaking. More on this another time!

To compile this, execute the following commands:

fsc test.fs
mono test.exe

Hello World Application

Joy!

[P.S. More of this is typed in by hand and untested than a normal post of mine because I'm short on time. Apologies in advance!]

XNA 4.0 on Windows Phone 7 using BasicEffect

Introduction

This post will provide a quick overview of basic topics regarding XNA 4.0 games and Windows Phone 7 (wp7). At the end of this tutorial, you’ll be using 3d graphics to draw a colored cube on the windows phone emulator.

For the duration of the post, I will assume that you have the Windows Phone Developer Tools RTW installed and have a copy of Visual Studio 2010 around; I’m using VS 2010 Professional. I also assume that you have some programming experience with C# and .NET. It will also help to have some knowledge of XNA 4.0 or a book handy because I only give the most cursory explanations possible.

Lets get started!

Working with the emulator

The first step will be to open Visual Studio 2010 and create a new project. There are many project wizards available, each tailored to one of the three XNA platforms: Windows, XBox 360 and Windows Phone 7. For this tutorial, create a Windows Phone Game.

Once you create the project based on the wizard, you get a solution with two C# projects: one for content to link into the game and another project for the game itself. The meat of the generated code can be found in the Game1.cs file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;

namespace BasicPhoneGame
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            // Frame rate is 30 fps by default for Windows Phone.
            TargetElapsedTime = TimeSpan.FromTicks(333333);
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here

            base.Draw(gameTime);
        }
    }
}

Have the Debug configuration selected (which it is by default) and build the solution. After it finishes building, run the game in the wp7 emulator. When you choose to Start Debugging, you’ll see the emulator load up.

After a few seconds, your game will load.

That’s right, the project wizard creates a game that consists of a background drawn in cornflower blue. Not very exciting.

If you click the back button (in the lower left corner of the emulator) or the start button (the windows icon button), the emulator will take you back to the start page of the phone. If you don’t know how a real Windows Phone 7 phone works, this part is a little confusing.  The only things shown here are items that are “pinned” … which, when you first start, is only Internet Explorer. You must click the arrow near the top right corner to get the full list of programs.

The full list of applications on the emulator is pretty short! You can see the wizard-created program at the top of the list.

Clicking BasicPhoneGame will restart the game and show the cornflower blue background.

Creating content in Blender

It is possible to create content procedurally with XNA. In fact, a lot of tutorials start out with that method to draw a 3d cube since the number of vertices is relatively small and it illustrates the principles of the work going on “behind the scenes” in XNA.

This method of typing in coordinates for vertices doesn’t scale very well however, and eventually you will likely want to use a tool to create your content to add to your programs. One such tool that XNA supports is Blender, since Blender is able to export Autodesk .fbx files. [A full list of supported content importers is here.] For this tutorial, I will use Blender 2.56 beta, but any reasonably recent version should do just fine.

Start up the Blender.

Without going into too much detail, this shows the default scene that Blender starts out with: a cube, a light and a camera. Lets delete it! Press ‘a’ once to deselect everything and then press ‘a’ again to select everything. When objects in blender are selected you should see a color highlight around them – in this version, that color is orange. Press the ‘delete’ key to delete all the objects. Click on Delete in the window that pops up to confirm the deletion. Your scene should now be empty.

The little icon that looks like a life preserver is the ‘cursor’ in Blender. When you add objects, Blender uses this cursor to determine the new objects initial position.

If you left-click in the Blender window, you move this 3d cursor around which will cause new objects to not be added at the 3d origin. Of the many ways to center the 3d cursor, one is to press ‘shift+c’.

To add a new mesh, you can use the ‘Add’ menu at the top and choose ‘Mesh’ and then ‘Cube’.

This creates a basic cube with a scale of [1, 1, 1] and dimensions of [2, 2, 2]. If you want to see all of the properties you can click ‘n’. This is also a good way to make sure it’s position is at (0, 0, 0). If you lost the selection on the cube, you can press ‘a’ until it’s selected again, or you can right-click on the cube to select it.

This is the extent of our modeling for this tutorial. If you want to substitue another shape, go ahead and do so now because the next step is exporting the data into a file format that XNA can understand.

Click the File menu at the top, choose Export and Autodesk FBX. Blender will then give you its version of a file-save dialog box. Choose to save it as ‘Cube.fbx’ in the content project directory (e.g. BasicPhoneGameContent).

This is all we need of Blender for this tutorial. If this has sparked your interest at all, there are many great websites, resources and training videos out there. I encourage you to check them out.

Code overview

Now that we’ve seen the results of the wizard and made a 3d model, lets go back and quickly review the code. There are five overrides on the base Game class that the wizard generates:

If you’re familiar with game or graphics programming, your intuition will be able to give you good insight into what those methods do. For this basic tutorial, we will modify LoadContent and Draw to eventually draw our cube on the screen.

Lets start by adding in our 3d model. As mentioned above, you should have exported the model to the content project folder. While this is probably not strictly necessary, it does make it more logically consistent with what the wizard generated for you. Add the content by right-clicking the content project and select ‘Add’ and then ‘Existing Item…’

With the file added to the project in the solution, add a private member of type Model called cubeModel to the Game1 class.

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        private Model cubeModel;            //** NEW

Looking inside the LoadContent method, you can see the only thing it does right now is create a new SpriteBatch. Add the line of code shown below to actually load the model.

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // Load the model
            cubeModel = Content.Load<Model>("Cube");

The Load method is passed a string that will locate the resource to load, in this case our Cube.fbx file. Note that you do not have to supply an extension to this file. Also, you can create sub-directories in the game content project and then find content in these sub-directories by using a double-slash (“\\”) as a divider. For example, if I created a “models” folder in the content project and moved the Cube.fbx into it, the “models\\Cube” string can be passed to Load.

In order to see the loaded model in the game, we need to setup a view and projection Matrix objects. You can read an article about views and projections here and there are many more available on the Internet. Matrix.CreatePerspectiveFieldOfView and Matrix.CreateLookAt make setting up these matrices easy.

            // Make the projection matrix
            float aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
                                (float)graphics.GraphicsDevice.Viewport.Height;
            float fov = MathHelper.PiOver4 * aspectRatio * 3 / 4;
            Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(fov, aspectRatio, 5f, 1000f);

            // Setup the camera vectors objects and view matrix
            Vector3 camPos = new Vector3(0.0f, 0.9f, 15.0f);
            Vector3 camView = new Vector3(0.0f, 0.9f, -5.0f);
            Vector3 camUp = new Vector3(0.0f, 1.0f, 0.0f);
            Matrix viewMatrix = Matrix.CreateLookAt(camPos, camView, camUp);

For this tutorial, you don’t need a deep understanding of the matrix math, because BasicEffect will take care of the work for you. Speaking of BasicEffect, we need to set one up here.

Define the basicShader member at the top of the class.

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        private Model cubeModel;            //** NEW
        private BasicEffect basicShader;    //** NEW

Then create the object and initialize it in the LoadContent method right after the camera work we just did.

            // Initialize the basic shader
            basicShader = new BasicEffect(graphics.GraphicsDevice);
            basicShader.Alpha = 1.0f;
            basicShader.LightingEnabled = true;
            basicShader.DiffuseColor = new Vector3(0.95f, 0.0f, 0.0f);
            basicShader.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f);
            basicShader.SpecularPower = 5.0f;
            basicShader.AmbientLightColor = new Vector3(0.70f, 0.70f, 0.70f);
            basicShader.World = Matrix.Identity;
            basicShader.View = viewMatrix;
            basicShader.Projection = projectionMatrix;

If you’re familiar with graphics programming, these settings have obvious meanings. We set the View and Projection properties once here, making a static camera. The world matrix is simply the identity matrix. The color the shader will use is bright red with some specular highlights and a decent amount ambient light.

You may wonder: Why use a built-in effect when I could have used a custom shader specific to my needs? The answer is because the Windows Phone target does not support custom shaders; only built-in shaders are supported. That sounds like a bad thing at first, but these effects are really configurable and do a lot of things.

With the model loaded, the camera set and the BasicEffect shader initialized, we are done loading our content for the sample. All that remains is to draw the cube!

Define a new function called DrawSampleModel

        private void DrawSampleModel(Model m)
        {
            if (m == null)
                return;

            // only one part in the model
            ModelMesh mesh = m.Meshes[0];
            ModelMeshPart meshPart = mesh.MeshParts[0];

            // set the vertex source to the mesh part's vertex buffer @ offset
            graphics.GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer, meshPart.VertexOffset);

            // set the index buffer to the mesh part's
            graphics.GraphicsDevice.Indices = meshPart.IndexBuffer;

            // Set a new world position
            Matrix scale = Matrix.CreateScale(4f, 4f, 4f);
            Matrix rot = Matrix.CreateRotationY((float)Math.PI / 8);
            basicShader.World = Matrix.Identity * scale * rot;

            foreach (EffectPass effectPass in basicShader.CurrentTechnique.Passes)
            {
                effectPass.Apply();
                graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                                                              0,
                                                              0,
                                                              meshPart.NumVertices,
                                                              meshPart.StartIndex,
                                                              meshPart.PrimitiveCount);
            }
        }

What does this function do?

It takes the first, and only, ModelMeshPart in the Model and hooks it into the graphics device by setting its VertexBuffer and IndexBuffer. [An older article explaining these buffers can be found here.] The world matrix is set using the ISROT (Identity, Scale, Rotate, Orbit, Translate) sequence. Finally, for each EffectPass it draws the primitive.

All that’s left now is to call this new method from within Draw.

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            DrawSampleModel(cubeModel); //** New

            base.Draw(gameTime);
        }

Now, we’re ready! Build and run the program in the emulator. You should see something like this:

The entire source code for the modified Game1.cs file is here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;

namespace BasicPhoneGame
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        private Model cubeModel;            //** NEW
        private BasicEffect basicShader;    //** NEW

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            // Frame rate is 30 fps by default for Windows Phone.
            TargetElapsedTime = TimeSpan.FromTicks(333333);
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // Load the model
            cubeModel = Content.Load<Model>("Cube");

            // Make the projection matrix
            float aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
                                (float)graphics.GraphicsDevice.Viewport.Height;
            float fov = MathHelper.PiOver4 * aspectRatio * 3 / 4;
            Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(fov, aspectRatio, 5f, 1000f);

            // Setup the camera vectors objects and view matrix
            Vector3 camPos = new Vector3(0.0f, 0.9f, 15.0f);
            Vector3 camView = new Vector3(0.0f, 0.9f, -5.0f);
            Vector3 camUp = new Vector3(0.0f, 1.0f, 0.0f);
            Matrix viewMatrix = Matrix.CreateLookAt(camPos, camView, camUp);

            // Initialize the basic shader
            basicShader = new BasicEffect(graphics.GraphicsDevice);
            basicShader.Alpha = 1.0f;
            basicShader.LightingEnabled = true;
            basicShader.DiffuseColor = new Vector3(0.95f, 0.0f, 0.0f);
            basicShader.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f);
            basicShader.SpecularPower = 5.0f;
            basicShader.AmbientLightColor = new Vector3(0.70f, 0.70f, 0.70f);
            basicShader.World = Matrix.Identity;
            basicShader.View = viewMatrix;
            basicShader.Projection = projectionMatrix;
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            DrawSampleModel(cubeModel);

            base.Draw(gameTime);
        }

        private void DrawSampleModel(Model m)
        {
            if (m == null)
                return;

            // only one part in the model
            ModelMesh mesh = m.Meshes[0];
            ModelMeshPart meshPart = mesh.MeshParts[0];

            // set the vertex source to the mesh part's vertex buffer @ offset
            graphics.GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer, meshPart.VertexOffset);

            // set the index buffer to the mesh part's
            graphics.GraphicsDevice.Indices = meshPart.IndexBuffer;

            // Set a new world position
            Matrix scale = Matrix.CreateScale(4f, 4f, 4f);
            Matrix rot = Matrix.CreateRotationY((float)Math.PI / 8);
            basicShader.World = Matrix.Identity * scale * rot;

            foreach (EffectPass effectPass in basicShader.CurrentTechnique.Passes)
            {
                effectPass.Apply();
                graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                                                              0,
                                                              0,
                                                              meshPart.NumVertices,
                                                              meshPart.StartIndex,
                                                              meshPart.PrimitiveCount);
            }
        }
    }
}

If you liked how easy it is to work with 3d graphics in XNA, there are a lot of resources for you to learn more. However, a lot of material out there was written for versions previous to XNA 4.0, which introduced a lot of breaking changes. Just be mindful of that.

Here are a few links I found useful when learning XNA:

I also want to mention that I found the “Microsoft XNA Game Studio Creator’s Guide” second edition book very helpful. Of the XNA books I’ve seen, this was by far the one that made the most sense to me as a 3d graphics neophyte. Unfortunately it’s not for XNA 4.0 which causes some problems when trying to type in examples exactly as found in the book. The core concepts are mostly the same.

It should also be mentioned that App Hub has a huge amount of sample code available (here and here). One particular example I looked at a lot when writing this tutorial was bounce.

And finally, you can also download Petzold’s wp7 book for free [legally] from Microsoft here. It covers many topics of wp7 programming, though it is light on details of working with XNA.

Using Gambit Scheme on Windows with SDL and OpenGL

As you can see from past posts, I usually develop software within a GNU/Linux environment. However, I do recognize the importance of being able to target Windows for binaries. Here’s a quick rundown of what you need to do to compile a quick test using Gambit Scheme, OpenGL SDL and SDL_image on Windows 7.

Step 1: MinGW

Download mingw-get-inst-20100909.exe from here (look in the Automated MinGW Installer\mingw-get-inst\mingw-get-insta-20100909 sub-folder). When running the installer, I used the “Use pre-packaged repository catalogues” option, put the files in C:\MinGW and insalled these components: C Compiler, C++ Compiler, MSYS Basic System and MinGW Developer ToolKit. Maybe other ways to setup MinGW work — I’m not a MinGW expert.

This gets you a basic gcc setup from which you can compile software in Windows. It also comes with a shell to make you feel a little more at home — if you’re used to Unix, that is. Gambit needs gcc to create binaries too.

Step 2: Gambit Scheme

Get the installer from Gambit’s main page. Install the software with default settings. Quick and painless.

The next few steps install dependencies for SDL and SDL_image.

Step 3: ZLib

Download zlib125.zip source code from the website. Unzip the source code, open up a MinGW shell (accessible from the Windows start menu), “cd” into the source directory and execute:

$ make -f win32/Makefile.gcc

After the compile is done, copy the static libraries to user local from within the MinGW shell

$ cp -iv zconf.h zlib.h /usr/local/include/

`zconf.h' -> `/usr/local/include/zconf.h'
`zlib.h' -> `/usr/local/include/zlib.h'

$ cp -iv libz.a /usr/local/lib
`libz.a' -> `/usr/local/lib/libz.a'

Step 4: Libpng

Download libpng source code from the website. Make sure to get the .tar.gz version so that the configure scripts are included (libpng-1.4.3.tar.gz). In a MinGW shell, extract the source code, “cd” into the directory and execute:

$ configure --disable-shared --enable-static CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"

This builds only static libraries, which is what we’ll use for now. This way you do not have to mess with making sure DLLs can be found. The CFLAGS and LDFLAGS setting help the configure script find zlib and other libraries we will be building.

Complete the build by executing:

$ make

and then

$ make install

Step 5: JPEG library

Download the jpegsrc.v8b.tar.gz source code package from the website. In a MinGW shell, extract the source code, “cd” into the directory and execute:

$ configure --disable-shared --enable-static CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"

Again, we’re only building the static libraries. Follow this up with:

$ make

and

$ make install

Step 6: SDL

Download the SDL-1.2.14.zip source code from the website. In a MinGW shell, extract the source code, “cd” into the directory and execute:

$ configure --disable-shared --enable-static CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"

Again, follow this up with:

$ make

and

$ make install

With SDL installed, you should be able to execute the “sdl-config” program in the shell to access what flags to use while compiling software. With what I’ve built so far, here’s the output of sdl-config for me:

$ sdl-config --cflags
-I/usr/local/include/SDL -D_GNU_SOURCE=1 -Dmain=SDL_main

$ sdl-config --libs
-L/usr/local/lib -lmingw32 -lSDLmain -lSDL -mwindows -liconv -lm -luser32 -lgdi32 -lwinmm

$ sdl-config --static-libs
-L/usr/local/lib -lmingw32 -lSDLmain -lSDL -mwindows -liconv -lm -luser32 -lgdi32 -lwinmm

Step 7: SDL_image

1 Download SDL_image-1.2.10.zip source code from the website. For my quick test, I’m only going to enable the png and jpeg support libraries (built in steps 4 and 5 above). This means the  tiff format will not be supported, but if this is important to you there is a library for that as well. In a MinGW shell, extract the source code, “cd” into the directory and execute:

$ configure --disable-shared --enable-static --enable-jpg --enable-png CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"

followed by

$ make

and

$ make install

Step 8: Test Time!

Use the code from this post of mine (download from here). Save the test-03.scm and water-128×128.png files to a directory, run a MinGW shell, “cd” to this directory and compile the scheme source code with the Gambit compiler like this:

$ gsc -cc-options "-I/usr/local/include/SDL/" -ld-options "-L/usr/local/lib/ -lmingw32 -lSDLmain -lSDL -mwindows -liconv -lm -luser32 -lgdi32 -lwinmm -lopengl32 -lSDL_image -lpng -ljpeg -lz" -exe test-03.scm

This should produce a “test-03.exe” file that has all of the files statically linked.

Now, there are legal ramifications of static linking SDL, SDL_image and other LGPL projects. Essentially, you have to provide a way for the user to relink your project which essentially means you cannot use it in closed source applications. The fix for that is to dynamically link the software.

Extra: How to dynamically link?

Zlib, libpng and libjpeg can all be linked statically without any repercussions per their respective licenses. This means we just have SDL and SDL_image to worry about.

Within the MinGW shell, change directories to the SDL library source code and run:

$ make uninstall

$ make clean

$ configure --enable-shared --disable-static CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"

Copy SDL.dll from C:\MinGW\msys\1.0\local\bin\SDL.dll to the test directory where test-03.scm is compiled.

For the SDL_image library, within the shell, change directories to the SDL_image library source code and run:

make uninstall

make clean

$ configure --enable-shared --disable-static --enable-png --enable-jpg CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"

Copy SDL_image.dll from C:\MinGW\msys\1.0\local\bin\SDL.dll to test directory. This DLL depends on SDL.dll which was already copied.

Now recompile the code with gambit using a simplified command:

$ gsc -cc-options "-I/usr/local/include/SDL/" -ld-options  "-L/usr/local/lib/ -lmingw32 -lSDLmain -lSDL -lopengl32 -lSDL_image" -exe  test-03.scm

This should produce a slightly lighter executable (2.65 MB stripped, 3.29 MB unstripped) that only needs the SDL and SDL_image DLL files next to it.

New web hosting

Animal-machine.com is finally hosted on a webserver again, instead of my home PC.

However, I have not fixed all of the links yet and have to find out if my new host can link port 8080 back to 80. This is the first time in years I’ve used shared hosting, so I’m not sure how big of a hassle this will be.

So for a day or two there might be some broken links around. Sorry about that.

In other news, I’m working on a basic roguelike example using Gambit scheme, SDL and opengl. The basic fixed pipeline is mostly in place. I just need to create some better art, implement some random dungeon creation and add some basic game logic in.