[gnome-games/glchess-vala] Port of glchess from Python to Vala. 3D is disabled for now as it doesn't work in GTK3



commit 84bccb3c4562f4ae11c7c8b6ee6992d2201ed0d1
Author: Robert Ancell <robert ancell canonical com>
Date:   Wed Dec 8 18:18:30 2010 +1100

    Port of glchess from Python to Vala. 3D is disabled for now as it doesn't work in GTK3

 configure.in                               |   44 +-
 glchess/ChangeLog.old                      | 1366 ------------------------
 glchess/data/Makefile.am                   |   20 +-
 glchess/data/ai.xml                        |  276 -----
 glchess/data/engines.conf                  |  141 +++
 glchess/data/glchess.schemas.in            |  293 ------
 glchess/data/glchess.ui                    |  202 +---
 glchess/data/load_game.ui                  |   95 --
 glchess/data/log.ui                        |  103 --
 glchess/data/network_game.ui               |  464 ---------
 glchess/data/network_new_server.ui         |  214 ----
 glchess/data/new_game.ui                   |  409 --------
 glchess/data/org.gnome.glchess.gschema.xml |  135 +++
 glchess/data/pieces/3d/Makefile.am         |   12 +
 glchess/data/pieces/3d/bishop.3ds          |  Bin 0 -> 29376 bytes
 glchess/data/pieces/3d/king.3ds            |  Bin 0 -> 29734 bytes
 glchess/data/pieces/3d/knight.3ds          |  Bin 0 -> 59316 bytes
 glchess/data/pieces/3d/pawn.3ds            |  Bin 0 -> 14894 bytes
 glchess/data/pieces/3d/queen.3ds           |  Bin 0 -> 33055 bytes
 glchess/data/pieces/3d/rook.3ds            |  Bin 0 -> 22214 bytes
 glchess/data/pieces/Makefile.am            |    2 +-
 glchess/data/preferences.ui                |  707 ++++++++++---
 glchess/data/save_game.ui                  |   76 --
 glchess/src/3ds.vala                       |  238 +++++
 glchess/src/Makefile.am                    |   47 +-
 glchess/src/ai-profile.vala                |   54 +
 glchess/src/chess-engine-cecp.vala         |   85 ++
 glchess/src/chess-engine-uci.vala          |  108 ++
 glchess/src/chess-engine.vala              |  147 +++
 glchess/src/chess-game.vala                |  696 +++++++++++++
 glchess/src/chess-pgn.vala                 |  351 +++++++
 glchess/src/chess-view-2d.vala             |  212 ++++
 glchess/src/chess-view-3d.vala             |  392 +++++++
 glchess/src/chess-view-options.vala        |  107 ++
 glchess/src/chess-view.vala                |   19 +
 glchess/src/gl.vapi                        | 1402 +++++++++++++++++++++++++
 glchess/src/glchess.in.in                  |   83 --
 glchess/src/glchess.vala                   | 1108 ++++++++++++++++++++
 glchess/src/glu.vapi                       |  301 ++++++
 glchess/src/gtkglext-1.0.vapi              |  373 +++++++
 glchess/src/lib/Makefile.am                |   27 -
 glchess/src/lib/__init__.py                |    2 -
 glchess/src/lib/ai.py                      |  490 ---------
 glchess/src/lib/cecp.py                    |  246 -----
 glchess/src/lib/chess/Makefile.am          |   12 -
 glchess/src/lib/chess/__init__.py          |  132 ---
 glchess/src/lib/chess/bitboard.py          |  194 ----
 glchess/src/lib/chess/board.py             | 1194 ---------------------
 glchess/src/lib/chess/fics/Makefile.am     |    9 -
 glchess/src/lib/chess/fics/__init__.py     |    3 -
 glchess/src/lib/chess/fics/client.py       |  492 ---------
 glchess/src/lib/chess/fics/server.py       |  561 ----------
 glchess/src/lib/chess/fics/style12.py      |  205 ----
 glchess/src/lib/chess/fics/telnet.py       |  207 ----
 glchess/src/lib/chess/lan.py               |  193 ----
 glchess/src/lib/chess/pgn.py               |  592 -----------
 glchess/src/lib/chess/san.py               |  450 --------
 glchess/src/lib/config.py                  |  229 ----
 glchess/src/lib/defaults.py.in             |   89 --
 glchess/src/lib/display.py                 |  647 ------------
 glchess/src/lib/game.py                    |  812 ---------------
 glchess/src/lib/ggz/Makefile.am            |    8 -
 glchess/src/lib/ggz/__init__.py            |    6 -
 glchess/src/lib/ggz/chess.py               |  175 ----
 glchess/src/lib/ggz/client.py              |  669 ------------
 glchess/src/lib/ggz/protocol.py            |  716 -------------
 glchess/src/lib/glchess.py                 |    5 -
 glchess/src/lib/gtkui/Makefile.am          |   10 -
 glchess/src/lib/gtkui/__init__.py          |    3 -
 glchess/src/lib/gtkui/chessview.py         |  654 ------------
 glchess/src/lib/gtkui/dialogs.py           |  830 ---------------
 glchess/src/lib/gtkui/gtkui.py             |  884 ----------------
 glchess/src/lib/gtkui/log.py               |  120 ---
 glchess/src/lib/gtkui/network.py           |  659 ------------
 glchess/src/lib/history.py                 |  160 ---
 glchess/src/lib/i18n.py                    |   10 -
 glchess/src/lib/main.py                    |  747 --------------
 glchess/src/lib/network.py                 |  552 ----------
 glchess/src/lib/player.py                  |   82 --
 glchess/src/lib/scene/Makefile.am          |    8 -
 glchess/src/lib/scene/__init__.py          |  162 ---
 glchess/src/lib/scene/cairo/Makefile.am    |    5 -
 glchess/src/lib/scene/cairo/__init__.py    |  553 ----------
 glchess/src/lib/scene/human.py             |  154 ---
 glchess/src/lib/scene/opengl/Makefile.am   |    8 -
 glchess/src/lib/scene/opengl/__init__.py   |   25 -
 glchess/src/lib/scene/opengl/models.py     | 1543 ----------------------------
 glchess/src/lib/scene/opengl/opengl.py     |  932 -----------------
 glchess/src/lib/scene/opengl/texture.py    |  101 --
 glchess/src/lib/uci.py                     |  184 ----
 glchess/src/lib/ui/Makefile.am             |    6 -
 glchess/src/lib/ui/__init__.py             |    2 -
 glchess/src/lib/ui/ui.py                   |  499 ---------
 93 files changed, 6556 insertions(+), 20984 deletions(-)
---
diff --git a/configure.in b/configure.in
index c1fdaf2..9221da0 100644
--- a/configure.in
+++ b/configure.in
@@ -141,7 +141,11 @@ for game in $gamelist; do
     *) ;;
   esac
   case $game in
-    glchess|gnome-sudoku) need_python=yes ;;
+    glchess) need_gtkglext=yes ;;
+    *) ;;
+  esac
+  case $game in
+    gnome-sudoku) need_python=yes ;;
     *) ;;
   esac
   case $game in
@@ -153,7 +157,7 @@ for game in $gamelist; do
     *) disallow_hildon=yes ;;
   esac
   case $game in
-    aisleriot) ;;
+    aisleriot|glchess) ;;
     *) need_rsvg=yes ;;
   esac
   case $game in
@@ -208,6 +212,7 @@ PKG_PROG_PKG_CONFIG([0.15])
 
 AC_PROG_CC
 AC_PROG_CPP
+AM_PROG_VALAC
 AC_PROG_LN_S
 AC_PROG_SED
 
@@ -608,6 +613,10 @@ PKG_CHECK_MODULES([GTHREAD],[gthread-2.0])
 AC_SUBST([GTHREAD_CFLAGS])
 AC_SUBST([GTHREAD_LIBS])
 
+PKG_CHECK_MODULES([GMODULE],[gmodule-2.0])
+AC_SUBST([GMODULE_CFLAGS])
+AC_SUBST([GMODULE_LIBS])
+
 PKG_CHECK_MODULES([GTK],[gtk+-$GTK_API_VERSION >= $GTK_REQUIRED])
 AC_SUBST([GTK_CFLAGS])
 AC_SUBST([GTK_LIBS])
@@ -688,6 +697,24 @@ fi
 
 AM_CONDITIONAL([HAVE_RSVG],[test "$have_rsvg" = "yes"])
 
+# Check for GTKGLExt
+
+have_gtkglext=no
+if test "$need_gtkglext" = "yes"; then
+  have_gtkglext=yes
+
+  # Errors out if gtkglext is not found
+  PKG_CHECK_MODULES([GTKGLEXT],[
+    gtklext-1.0])
+
+  AC_SUBST([GTKGLEXT_CFLAGS])
+  AC_SUBST([GTKGLEXT_LIBS])
+
+  AC_DEFINE([HAVE_GTKGLEXT],[1],[Define if GtkGLExt is available])
+fi
+
+AM_CONDITIONAL([HAVE_GTKGLEXT],[test "$have_gtkglext" = "yes"])
+
 # Check for Clutter
 
 if test "$need_clutter" = "yes"; then
@@ -1169,23 +1196,13 @@ aisleriot/help/Makefile
 glchess/Makefile
 glchess/data/Makefile
 glchess/data/pieces/Makefile
+glchess/data/pieces/3d/Makefile
 glchess/data/pieces/fancy/Makefile
 glchess/data/pieces/simple/Makefile
 glchess/data/textures/Makefile
 glchess/gnuchess/Makefile
 glchess/help/Makefile
-glchess/src/glchess.in
 glchess/src/Makefile
-glchess/src/lib/Makefile
-glchess/src/lib/defaults.py
-glchess/src/lib/chess/Makefile
-glchess/src/lib/chess/fics/Makefile
-glchess/src/lib/ggz/Makefile
-glchess/src/lib/gtkui/Makefile
-glchess/src/lib/scene/Makefile
-glchess/src/lib/scene/cairo/Makefile
-glchess/src/lib/scene/opengl/Makefile
-glchess/src/lib/ui/Makefile
 gnome-sudoku/Makefile
 gnome-sudoku/src/gnome-sudoku.in
 gnome-sudoku/src/Makefile
@@ -1241,6 +1258,7 @@ echo "
     Help method:           ${with_help_method} ${with_help_file_format}
     Using SM Client:       ${with_smclient}
     Using RSVG:            ${have_rsvg}
+    Using GtkGLExt:        ${have_gtkglext}
     Card theme formats:    ${with_card_theme_formats}
     Default theme format:  ${with_default_card_theme_format}
     Default theme:         ${with_default_card_theme}
diff --git a/glchess/data/Makefile.am b/glchess/data/Makefile.am
index 37a4557..51a9169 100644
--- a/glchess/data/Makefile.am
+++ b/glchess/data/Makefile.am
@@ -3,29 +3,15 @@ SUBDIRS = pieces textures
 uidir = $(datadir)/glchess
 ui_DATA = \
 	glchess.ui \
-	load_game.ui \
-	log.ui \
-	new_game.ui \
-	network_game.ui \
-	network_new_server.ui \
-	preferences.ui \
-	save_game.ui
-
-schemadir   = @GCONF_SCHEMA_FILE_DIR@
-schema_in_files = glchess.schemas.in
-schema_DATA = $(schema_in_files:.schemas.in=.schemas)
- INTLTOOL_SCHEMAS_RULE@
+	preferences.ui
 
 man_MANS = glchess.6
 
-EXTRA_DIST = ai.xml \
-             $(schema_in_files) \
+EXTRA_DIST = engines.conf \
 	     $(man_MANS) \
 	     $(ui_DATA)
 
 aidir = $(datadir)/glchess/
-ai_DATA = ai.xml
-
-DISTCLEANFILES = $(schema_DATA)
+ai_DATA = engines.conf
 
 -include $(top_srcdir)/git.mk
diff --git a/glchess/data/engines.conf b/glchess/data/engines.conf
new file mode 100644
index 0000000..d2168c5
--- /dev/null
+++ b/glchess/data/engines.conf
@@ -0,0 +1,141 @@
+# gnome-gnuchess is bundled with gnome-games
+[GNU Chess]
+protocol=cecp
+binary=gnome-gnuchess
+args=--xboard
+option-easy-0=easy
+option-easy-1=depth 1
+option-normal-0=depth 4
+option-hard-0=hard
+
+[GNUchess]
+protocol=cecp
+args=--xboard
+option-easy-0=easy
+option-easy-1=depth 1
+option-normal-0=depth 4
+option-hard-0=hard
+
+[Sjeng]
+protocol=cecp
+binary=sjeng
+option-easy-0=easy
+option-easy-1=depth 1
+option-normal-0=depth 4
+option-hard-0=hard
+
+[Amy]
+protocol=cecp
+binary=Amy
+option-easy-0=easy
+option-easy-1=depth 1
+option-normal-0=depth 4
+option-hard-0=hard
+
+[Crafty]
+protocol=cecp
+binary=crafty
+option-easy-0=easy
+option-easy-1=depth 1
+option-normal-0=depth 4
+option-hard-0=hard
+
+[Faile]
+protocol=cecp
+binary=faile
+option-easy-0=easy
+option-easy-1=depth 1
+option-normal-0=depth 4
+option-hard-0=hard
+
+[Phalanx]
+protocol=cecp
+binary=phalanx
+option-easy-0=easy
+option-easy-1=depth 1
+option-easy-2=level 5
+option-normal-0=depth 4
+option-hard-0=hard
+
+[Glaurung]
+protocol=uci
+binary=glaurung
+option-easy-0=Aggressiveness=50
+option-easy-1=Cowardice=200
+option-easy-2=Ponder=false
+option-normal-0=Aggressiveness=130
+option-normal-1=Cowardice=100
+option-normal-2=Ponder=false
+option-hard-0=Aggressiveness=200
+option-hard-1=Cowardice=50
+option-hard-2=Ponder=true
+
+[Stockfish]
+protocol=uci
+binary=stockfish
+option-easy-0=Aggressiveness=50
+option-easy-1=Cowardice=200
+option-easy-2=Ponder=false
+option-normal-0=Aggressiveness=130
+option-normal-1=Cowardice=100
+option-normal-2=Ponder=false
+option-hard-0=Aggressiveness=200
+option-hard-1=Cowardice=50
+option-hard-2=Ponder=true
+
+[HoiChess]
+protocol=cecp
+binary=hoichess
+option-easy-0=easy
+option-easy-1=depth 1
+option-normal-0=depth 4
+option-hard-0=hard
+
+[Diablo]
+protocol=uci
+binary=diablo
+option-easy-0=Ponder=false
+option-normal-0=Ponder=true
+option-hard-0=Ponder=true
+
+[BBChess]
+protocol=uci
+binary=bbchess
+# FIXME: Add some difficulty levels
+
+[Fruit]
+protocol=uci
+binary=fruit
+# FIXME: Add some difficulty levels
+
+[Gambit Fruit]
+protocol=uci
+binary=gfruit
+# FIXME: Add some difficulty levels
+
+[Toga II]
+protocol=uci
+binary=toga2
+# FIXME: Add some difficulty levels
+
+[Amundsen]
+protocol=cecp
+binary=amundsen
+option-easy-0=easy
+option-easy-1=depth 1
+option-normal-0=depth 4
+option-hard-0=hard
+
+[Boo's Chess Engine]
+protocol=cecp
+binary=bce boochess BACE
+
+[Fairy-Max]
+protocol=cecp
+binary=fairymax
+# FIXME: Add some difficulty levels
+
+[Shredder]
+protocol=uci
+binary=ShredderClassicLinux
+# FIXME: Add some difficulty levels
diff --git a/glchess/data/glchess.ui b/glchess/data/glchess.ui
index 9d9fe49..76d1a20 100644
--- a/glchess/data/glchess.ui
+++ b/glchess/data/glchess.ui
@@ -1,17 +1,15 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy toplevel-contextual -->
   <object class="GtkWindow" id="glchess_app">
-    <property name="title">glChess</property>
+    <property name="title">Chess</property>
     <property name="default_width">400</property>
     <accel-groups>
       <group name="accelgroup1"/>
     </accel-groups>
-    <signal name="focus_in_event" handler="_on_focus_changed" after="yes"/>
-    <signal name="configure_event" handler="_on_resize"/>
-    <signal name="delete_event" handler="_on_close_window"/>
-    <signal name="window_state_event" handler="_on_window_state_changed"/>
+    <signal name="delete_event" handler="glchess_app_delete_event_cb"/>
+    <signal name="window_state_event" handler="glchess_app_window_state_event_cb"/>
     <child>
       <object class="GtkVBox" id="vbox1">
         <property name="visible">True</property>
@@ -26,13 +24,13 @@
                 <child type="submenu">
                   <object class="GtkMenu" id="menuitem1_menu">
                     <child>
-                      <object class="GtkImageMenuItem" id="new1">
+                      <object class="GtkImageMenuItem" id="new_menu_item">
                         <property name="label">gtk-new</property>
                         <property name="visible">True</property>
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
                         <property name="accel_group">accelgroup1</property>
-                        <signal name="activate" handler="_on_new_game_button_clicked"/>
+                        <signal name="activate" handler="new_game_cb"/>
                       </object>
                     </child>
                     <child>
@@ -42,7 +40,7 @@
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
                         <property name="accel_group">accelgroup1</property>
-                        <signal name="activate" handler="_on_open_game_button_clicked"/>
+                        <signal name="activate" handler="open_game_cb"/>
                       </object>
                     </child>
                     <child>
@@ -53,7 +51,7 @@
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
                         <property name="accel_group">accelgroup1</property>
-                        <signal name="activate" handler="_on_save_game_button_clicked"/>
+                        <signal name="activate" handler="save_game_cb"/>
                       </object>
                     </child>
                     <child>
@@ -63,7 +61,7 @@
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
                         <property name="accel_group">accelgroup1</property>
-                        <signal name="activate" handler="_on_save_as_game_button_clicked"/>
+                        <signal name="activate" handler="save_game_as_cb"/>
                       </object>
                     </child>
                     <child>
@@ -72,23 +70,6 @@
                       </object>
                     </child>
                     <child>
-                      <object class="GtkImageMenuItem" id="menu_play_online_item">
-                        <property name="label" translatable="yes">Network _Game</property>
-                        <property name="visible">True</property>
-                        <property name="use_underline">True</property>
-                        <property name="image">image2</property>
-                        <property name="use_stock">False</property>
-                        <property name="accel_group">accelgroup1</property>
-                        <accelerator key="L" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                        <signal name="activate" handler="_on_join_game_button_clicked"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkSeparatorMenuItem" id="separator2">
-                        <property name="visible">True</property>
-                      </object>
-                    </child>
-                    <child>
                       <object class="GtkImageMenuItem" id="menu_undo_move">
                         <property name="label" translatable="yes">_Undo Move</property>
                         <property name="visible">True</property>
@@ -97,7 +78,7 @@
                         <property name="use_stock">False</property>
                         <property name="accel_group">accelgroup1</property>
                         <accelerator key="Z" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                        <signal name="activate" handler="_on_undo_move_clicked"/>
+                        <signal name="activate" handler="undo_move_cb"/>
                       </object>
                     </child>
                     <child>
@@ -108,7 +89,7 @@
                         <property name="image">image3</property>
                         <property name="use_stock">False</property>
                         <property name="accel_group">accelgroup1</property>
-                        <signal name="activate" handler="_on_resign_clicked"/>
+                        <signal name="activate" handler="resign_cb"/>
                       </object>
                     </child>
                     <child>
@@ -116,7 +97,7 @@
                         <property name="visible">True</property>
                         <property name="label" translatable="yes">Claim _Draw</property>
                         <property name="use_underline">True</property>
-                        <signal name="activate" handler="_on_claim_draw_clicked"/>
+                        <signal name="activate" handler="claim_draw_cb"/>
                       </object>
                     </child>
                     <child>
@@ -131,7 +112,7 @@
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
                         <property name="accel_group">accelgroup1</property>
-                        <signal name="activate" handler="_on_menu_quit"/>
+                        <signal name="activate" handler="quit_cb"/>
                       </object>
                     </child>
                   </object>
@@ -153,33 +134,7 @@
                         <property name="use_stock">True</property>
                         <property name="accel_group">accelgroup1</property>
                         <accelerator key="F11" signal="activate"/>
-                        <signal name="activate" handler="_on_view_fullscreen_clicked"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menu_leave_fullscreen">
-                        <property name="label">gtk-leave-fullscreen</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">accelgroup1</property>
-                        <accelerator key="F11" signal="activate"/>
-                        <signal name="activate" handler="_on_view_unfullscreen_clicked"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkCheckMenuItem" id="menu_view_3d">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">3_D Chess View</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="_on_toggle_3d_clicked"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkCheckMenuItem" id="menu_view_logs">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Show _Logs</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="_on_show_logs_clicked"/>
+                        <signal name="activate" handler="toggle_fullscreen_cb"/>
                       </object>
                     </child>
                     <child>
@@ -189,7 +144,7 @@
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
                         <property name="accel_group">accelgroup1</property>
-                        <signal name="activate" handler="_on_preferences_clicked"/>
+                        <signal name="activate" handler="preferences_cb"/>
                       </object>
                     </child>
                   </object>
@@ -212,7 +167,7 @@
                         <property name="use_stock">False</property>
                         <property name="accel_group">accelgroup1</property>
                         <accelerator key="F1" signal="activate"/>
-                        <signal name="activate" handler="_on_help_clicked"/>
+                        <signal name="activate" handler="help_cb"/>
                       </object>
                     </child>
                     <child>
@@ -222,7 +177,7 @@
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
                         <property name="accel_group">accelgroup1</property>
-                        <signal name="activate" handler="_on_about_clicked"/>
+                        <signal name="activate" handler="about_cb"/>
                       </object>
                     </child>
                   </object>
@@ -247,23 +202,7 @@
                 <property name="label" translatable="yes" comments="The New Game toolbar button">New Game</property>
                 <property name="use_underline">True</property>
                 <property name="stock_id">gtk-new</property>
-                <signal name="clicked" handler="_on_new_game_button_clicked"/>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="homogeneous">True</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkToolButton" id="play_online_button">
-                <property name="visible">True</property>
-                <property name="tooltip_text" translatable="yes">Start a new multiplayer network game</property>
-                <property name="visible_vertical">False</property>
-                <property name="is_important">True</property>
-                <property name="label" translatable="yes" comments="The Network Game toolbar button">Network _Game</property>
-                <property name="use_underline">True</property>
-                <property name="stock_id">gtk-network</property>
-                <signal name="clicked" handler="_on_join_game_button_clicked"/>
+                <signal name="clicked" handler="new_game_cb"/>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -277,7 +216,7 @@
                 <property name="label" translatable="yes">Undo Move</property>
                 <property name="use_underline">True</property>
                 <property name="stock_id">gtk-undo</property>
-                <signal name="clicked" handler="_on_undo_move_clicked"/>
+                <signal name="clicked" handler="undo_move_cb"/>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -291,7 +230,7 @@
                 <property name="label" translatable="yes" comments="The tooltip for the Resign toolbar button">Resign</property>
                 <property name="use_underline">True</property>
                 <property name="stock_id">gtk-dialog-warning</property>
-                <signal name="clicked" handler="_on_resign_clicked"/>
+                <signal name="clicked" handler="resign_cb"/>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -306,26 +245,24 @@
           </packing>
         </child>
         <child>
-          <object class="GtkVBox" id="vbox11">
+          <object class="GtkVBox" id="view_box">
             <property name="visible">True</property>
             <property name="spacing">3</property>
             <child>
-              <object class="GtkViewport" id="game_viewport">
-                <property name="width_request">300</property>
-                <property name="height_request">300</property>
+              <object class="GtkAlignment" id="view_container">
                 <property name="visible">True</property>
-                <property name="shadow_type">none</property>
                 <child>
                   <placeholder/>
                 </child>
               </object>
               <packing>
-                <property name="position">0</property>
+                <property name="pack_type">end</property>
+                <property name="position">1</property>
               </packing>
             </child>
             <child>
               <object class="GtkHBox" id="navigation_box">
-                <property name="sensitive">False</property>
+                <property name="visible">True</property>
                 <property name="spacing">6</property>
                 <child>
                   <object class="GtkHBox" id="left_nav_box">
@@ -338,7 +275,7 @@
                         <property name="can_focus">True</property>
                         <property name="receives_default">False</property>
                         <property name="tooltip_text" translatable="yes">Rewind to the game start</property>
-                        <signal name="clicked" handler="_on_history_start_clicked"/>
+                        <signal name="clicked" handler="history_start_clicked_cb"/>
                         <child>
                           <object class="GtkImage" id="image6">
                             <property name="visible">True</property>
@@ -358,7 +295,7 @@
                         <property name="can_focus">True</property>
                         <property name="receives_default">False</property>
                         <property name="tooltip_text" translatable="yes">Show the previous move</property>
-                        <signal name="clicked" handler="_on_history_previous_clicked"/>
+                        <signal name="clicked" handler="history_previous_clicked_cb"/>
                         <child>
                           <object class="GtkImage" id="image7">
                             <property name="visible">True</property>
@@ -377,7 +314,7 @@
                         <property name="can_focus">True</property>
                         <property name="receives_default">False</property>
                         <property name="tooltip_text" translatable="yes">Show the next move</property>
-                        <signal name="clicked" handler="_on_history_next_clicked"/>
+                        <signal name="clicked" handler="history_next_clicked_cb"/>
                         <child>
                           <object class="GtkImage" id="image8">
                             <property name="visible">True</property>
@@ -396,7 +333,7 @@
                         <property name="can_focus">True</property>
                         <property name="receives_default">False</property>
                         <property name="tooltip_text" translatable="yes">Show the current move</property>
-                        <signal name="clicked" handler="_on_history_latest_clicked"/>
+                        <signal name="clicked" handler="history_latest_clicked_cb"/>
                         <child>
                           <object class="GtkImage" id="image5">
                             <property name="visible">True</property>
@@ -417,7 +354,14 @@
                 <child>
                   <object class="GtkComboBox" id="history_combo">
                     <property name="visible">True</property>
-                    <signal name="changed" handler="_on_history_combo_changed"/>
+                    <property name="model">history_model</property>
+                    <signal name="changed" handler="history_combo_changed_cb"/>
+                    <child>
+                      <object class="GtkCellRendererText" id="history_combo_cellrenderer"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
                   </object>
                   <packing>
                     <property name="position">1</property>
@@ -432,7 +376,7 @@
                       <object class="GtkDrawingArea" id="white_time_label">
                         <property name="width_request">20</property>
                         <property name="visible">True</property>
-                        <signal name="expose_event" handler="_on_white_time_paint"/>
+                        <signal name="draw" handler="white_time_draw_cb"/>
                       </object>
                       <packing>
                         <property name="position">0</property>
@@ -442,7 +386,7 @@
                       <object class="GtkDrawingArea" id="black_time_label">
                         <property name="width_request">20</property>
                         <property name="visible">True</property>
-                        <signal name="expose_event" handler="_on_black_time_paint"/>
+                        <signal name="draw" handler="black_time_draw_cb"/>
                       </object>
                       <packing>
                         <property name="position">1</property>
@@ -457,64 +401,13 @@
               </object>
               <packing>
                 <property name="expand">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="position">2</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-  </object>
-  <object class="GtkWindow" id="log_window">
-    <property name="border_width">6</property>
-    <property name="title" translatable="yes" comments="The title of the log dialaog">Logs</property>
-    <property name="default_width">600</property>
-    <property name="default_height">400</property>
-    <signal name="delete_event" handler="_on_log_window_delete_event"/>
-    <child>
-      <object class="GtkNotebook" id="log_notebook">
-        <property name="visible">True</property>
-        <property name="show_tabs">False</property>
-        <property name="show_border">False</property>
-        <property name="scrollable">True</property>
-        <child>
-          <object class="GtkHBox" id="hbox6">
-            <property name="visible">True</property>
-            <property name="border_width">6</property>
-            <property name="spacing">6</property>
-            <child>
-              <object class="GtkImage" id="image13">
-                <property name="visible">True</property>
-                <property name="stock">gtk-dialog-info</property>
-                <property name="icon-size">6</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
+                <property name="pack_type">end</property>
                 <property name="position">0</property>
               </packing>
             </child>
-            <child>
-              <object class="GtkLabel" id="label57">
-                <property name="visible">True</property>
-                <property name="xalign">0</property>
-                <property name="label" translatable="yes" comments="Message displayed in log window when no logs are present">There are no active logs.</property>
-                <property name="wrap">True</property>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-        </child>
-        <child type="tab">
-          <object class="GtkLabel" id="label51">
-            <property name="visible">True</property>
           </object>
           <packing>
-            <property name="tab_fill">False</property>
+            <property name="position">2</property>
           </packing>
         </child>
       </object>
@@ -526,11 +419,6 @@
     <property name="stock">gtk-undo</property>
     <property name="icon-size">1</property>
   </object>
-  <object class="GtkImage" id="image2">
-    <property name="visible">True</property>
-    <property name="stock">gtk-network</property>
-    <property name="icon-size">1</property>
-  </object>
   <object class="GtkImage" id="image3">
     <property name="visible">True</property>
     <property name="stock">gtk-dialog-warning</property>
@@ -541,4 +429,12 @@
     <property name="stock">gtk-help</property>
     <property name="icon-size">1</property>
   </object>
+  <object class="GtkListStore" id="history_model">
+    <columns>
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name move-number -->
+      <column type="gint"/>
+    </columns>
+  </object>
 </interface>
diff --git a/glchess/data/org.gnome.glchess.gschema.xml b/glchess/data/org.gnome.glchess.gschema.xml
new file mode 100644
index 0000000..50e7dbb
--- /dev/null
+++ b/glchess/data/org.gnome.glchess.gschema.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schemalist>
+  <enum id="org.gnome.glchess.PieceType">
+    <value value="0" nick="pawn"/>
+    <value value="1" nick="rook"/>
+    <value value="2" nick="knight"/>
+    <value value="3" nick="bishop"/>
+    <value value="4" nick="queen"/>
+    <value value="5" nick="king"/>
+  </enum>
+
+  <enum id="org.gnome.glchess.MoveFormat">
+    <value value="0" nick="human"/>
+    <value value="1" nick="san"/>
+    <value value="2" nick="fan"/>
+    <value value="3" nick="lan"/>
+  </enum>
+
+  <enum id="org.gnome.glchess.BoardSide">
+    <value value="0" nick="white"/>
+    <value value="1" nick="black"/>
+    <value value="2" nick="human"/>
+    <value value="3" nick="current"/>
+    <value value="4" nick="facetoface"/>
+  </enum>
+
+  <enum id="org.gnome.glchess.Difficulty">
+    <value value="0" nick="easy"/>
+    <value value="1" nick="normal"/>
+    <value value="2" nick="hard"/>
+  </enum>
+
+  <schema id="org.gnome.glchess.Settings" path="/apps/glchess/">
+    <key name="width" type="i">
+      <default>500</default>
+      <summary>The width of the window</summary>
+      <description>The width of the main window in pixels.</description>
+    </key>
+    <key name="height" type="i">
+      <default>550</default>
+      <summary>The height of the window</summary>
+      <description>The height of the main window in pixels.</description>
+    </key>
+    <key name="maximised" type="b">
+      <default>false</default>
+      <summary>A flag to enable maximised mode</summary>
+      <description>A flag to enable maximised mode</description>
+    </key>
+    <key name="fullscreen" type="b">
+      <default>false</default>
+      <summary>A flag to enable fullscreen mode</summary>
+      <description>A flag to enable fullscreen mode</description>
+    </key>
+    <key name="promotion-type" enum="org.gnome.glchess.PieceType">
+      <default>'queen'</default>
+      <summary>The piece to promote pawns to</summary>
+      <description>The piece to promote to when a human player moves a pawn to the far rank</description>
+    </key>
+    <key name="show-3d" type="b">
+      <default>false</default>
+      <summary>A flag to enable 3D mode</summary>
+      <description>A flag to enable 3D mode</description>
+    </key>
+    <key name="show-3d-smooth" type="b">
+      <default>false</default>
+      <summary>A flag to smooth (anti-alias) the 3D display</summary>
+      <description>A flag to smooth (anti-alias) the 3D display</description>
+    </key>
+    <key name="piece-theme" type="s">
+      <default>'simple'</default>
+      <summary>The piece theme to use</summary>
+      <description>The piece theme to use</description>
+    </key>
+    <key name="show-move-hints" type="b">
+      <default>true</default>
+      <summary>A flag to enable move hints</summary>
+      <description>A flag to enable move hints</description>
+    </key>
+    <key name="show-numbering" type="b">
+      <default>false</default>
+      <summary>A flag to enable board numbering</summary>
+      <description>A flag to enable board numbering</description>
+    </key>
+    <key name="show-history" type="b">
+      <default>true</default>
+      <summary>A flag to enable the move history browser</summary>
+      <description>A flag to enable the move history browser</description>
+    </key>
+    <key name="show-toolbar" type="b">
+      <default>false</default>
+      <summary>A flag to enable the toolbar</summary>
+      <description>A flag to enable the toolbar</description>
+    </key>
+    <key name="save-directory" type="s">
+      <default>''</default>
+      <summary>The directory to open the save game dialog in</summary>
+      <description>The directory to open the save game dialog in</description>
+    </key>
+    <key name="load-directory" type="s">
+      <default>''</default>
+      <summary>The directory to open the load game dialog in</summary>
+      <description>The directory to open the load game dialog in</description>
+    </key>
+    <key name="move-format" enum="org.gnome.glchess.MoveFormat">
+      <default>'human'</default>
+      <summary>The format to display moves in</summary>
+      <description>The format to display moves in</description>
+    </key>
+    <key name="board-side" enum="org.gnome.glchess.BoardSide">
+      <default>'human'</default>
+      <summary>The side of the board that is in the foreground</summary>
+      <description>The side of the board that is in the foreground</description>
+    </key>
+    <key name="duration" type="i">
+      <default>0</default>
+      <summary>The duration of a game in seconds (0 for no limit)</summary>
+      <description>The duration of a game in seconds (0 for no limit)</description>
+    </key>
+    <key name="play-as-white" type="b">
+      <default>true</default>
+      <summary>true if the human player is playing white</summary>
+      <description>true if the human player is playing white</description>
+    </key>
+    <key name="opponent" type="s">
+      <default>''</default>
+      <summary>The opponent player</summary>
+      <description>Can be 'human' (play against another human player), '' (use the first available chess engine) or the name of a specific engine to play against</description>
+    </key>
+    <key name="difficulty" enum="org.gnome.glchess.Difficulty">
+      <default>'easy'</default>
+      <summary>Difficulty of the opponent chess engine</summary>
+      <description>Difficulty of the opponent chess engine</description>
+    </key>
+  </schema>
+</schemalist>
diff --git a/glchess/data/pieces/3d/Makefile.am b/glchess/data/pieces/3d/Makefile.am
new file mode 100644
index 0000000..ef67fe5
--- /dev/null
+++ b/glchess/data/pieces/3d/Makefile.am
@@ -0,0 +1,12 @@
+modeldir = $(datadir)/glchess/pieces/3d
+model_DATA = \
+	bishop.3ds \
+	king.3ds \
+	knight.3ds \
+	pawn.3ds \
+	queen.3ds \
+	rook.3ds
+
+EXTRA_DIST = $(model_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/glchess/data/pieces/3d/bishop.3ds b/glchess/data/pieces/3d/bishop.3ds
new file mode 100644
index 0000000..bc24839
Binary files /dev/null and b/glchess/data/pieces/3d/bishop.3ds differ
diff --git a/glchess/data/pieces/3d/king.3ds b/glchess/data/pieces/3d/king.3ds
new file mode 100644
index 0000000..143e76f
Binary files /dev/null and b/glchess/data/pieces/3d/king.3ds differ
diff --git a/glchess/data/pieces/3d/knight.3ds b/glchess/data/pieces/3d/knight.3ds
new file mode 100644
index 0000000..ff06552
Binary files /dev/null and b/glchess/data/pieces/3d/knight.3ds differ
diff --git a/glchess/data/pieces/3d/pawn.3ds b/glchess/data/pieces/3d/pawn.3ds
new file mode 100644
index 0000000..d77b3bb
Binary files /dev/null and b/glchess/data/pieces/3d/pawn.3ds differ
diff --git a/glchess/data/pieces/3d/queen.3ds b/glchess/data/pieces/3d/queen.3ds
new file mode 100644
index 0000000..fceaa4b
Binary files /dev/null and b/glchess/data/pieces/3d/queen.3ds differ
diff --git a/glchess/data/pieces/3d/rook.3ds b/glchess/data/pieces/3d/rook.3ds
new file mode 100644
index 0000000..6a12a34
Binary files /dev/null and b/glchess/data/pieces/3d/rook.3ds differ
diff --git a/glchess/data/pieces/Makefile.am b/glchess/data/pieces/Makefile.am
index ade34c9..f74d95a 100644
--- a/glchess/data/pieces/Makefile.am
+++ b/glchess/data/pieces/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS = fancy simple
+SUBDIRS = 3d fancy simple
 
 -include $(top_srcdir)/git.mk
diff --git a/glchess/data/preferences.ui b/glchess/data/preferences.ui
index 543c40e..f0451f3 100644
--- a/glchess/data/preferences.ui
+++ b/glchess/data/preferences.ui
@@ -1,4 +1,4 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy toplevel-contextual -->
@@ -7,9 +7,8 @@
     <property name="resizable">False</property>
     <property name="destroy_with_parent">True</property>
     <property name="type_hint">dialog</property>
-    <property name="has_separator">False</property>
-    <signal name="response" handler="_on_response"/>
-    <signal name="delete_event" handler="_on_delete"/>
+    <signal name="response" handler="preferences_response_cb"/>
+    <signal name="delete_event" handler="preferences_delete_event_cb"/>
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox1">
         <property name="visible">True</property>
@@ -19,19 +18,18 @@
             <property name="can_focus">True</property>
             <property name="border_width">5</property>
             <child>
-              <object class="GtkTable" id="game_table">
+              <object class="GtkTable" id="game_table1">
                 <property name="visible">True</property>
                 <property name="border_width">10</property>
-                <property name="n_rows">3</property>
+                <property name="n_rows">7</property>
                 <property name="n_columns">2</property>
                 <property name="column_spacing">5</property>
                 <property name="row_spacing">5</property>
-                <property name="homogeneous">True</property>
                 <child>
-                  <object class="GtkLabel" id="board_label">
+                  <object class="GtkLabel" id="side_label">
                     <property name="visible">True</property>
                     <property name="xalign">0</property>
-                    <property name="label" translatable="yes" comments="Preferences Dialog: Label before board orientation combo box">Board Orientation:</property>
+                    <property name="label" translatable="yes" comments="Preferences Dialog: Label before player side (white/black) combo box">Play as:</property>
                   </object>
                   <packing>
                     <property name="x_options">GTK_FILL</property>
@@ -39,38 +37,77 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="format_label">
+                  <object class="GtkLabel" id="opposing_player_label">
                     <property name="visible">True</property>
                     <property name="xalign">0</property>
-                    <property name="label" translatable="yes" comments="Preferences Dialog: Label before move format combo box">Move Format:</property>
+                    <property name="label" translatable="yes" comments="Preferences Dialog: Label before opposing player combo box">Opposing Player:</property>
                   </object>
                   <packing>
-                    <property name="top_attach">1</property>
-                    <property name="bottom_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
                     <property name="x_options">GTK_FILL</property>
                     <property name="y_options"></property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="label5">
+                  <object class="GtkLabel" id="label2">
                     <property name="visible">True</property>
                     <property name="xalign">0</property>
-                    <property name="label" translatable="yes" comments="Preferences Dialog: Label before promotion type combo box">Promotion Type:</property>
+                    <property name="label" translatable="yes" comments="Preferences Dialog: Label before promotion type combo box">Difficulty:</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="side_combo">
+                    <property name="visible">True</property>
+                    <property name="model">side_model</property>
+                    <signal name="changed" handler="side_combo_changed_cb"/>
+                    <child>
+                      <object class="GtkCellRendererText" id="side_cellrenderer"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="opponent_combo">
+                    <property name="visible">True</property>
+                    <property name="model">opponent_model</property>
+                    <signal name="changed" handler="opponent_combo_changed_cb"/>
+                    <child>
+                      <object class="GtkCellRendererText" id="opponent_cellrenderer"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
                   </object>
                   <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
                     <property name="top_attach">2</property>
                     <property name="bottom_attach">3</property>
                     <property name="x_options">GTK_FILL</property>
-                    <property name="y_options"></property>
+                    <property name="y_options">GTK_FILL</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkComboBox" id="board_combo">
+                  <object class="GtkComboBox" id="difficulty_combo">
                     <property name="visible">True</property>
-                    <property name="model">liststore3</property>
-                    <signal name="changed" handler="_on_board_combo_changed"/>
+                    <property name="model">difficulty_model</property>
+                    <signal name="changed" handler="difficulty_combo_changed_cb"/>
                     <child>
-                      <object class="GtkCellRendererText" id="cellrenderertext3"/>
+                      <object class="GtkCellRendererText" id="difficulty_cellrenderer"/>
                       <attributes>
                         <attribute name="text">0</attribute>
                       </attributes>
@@ -79,16 +116,82 @@
                   <packing>
                     <property name="left_attach">1</property>
                     <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="x_options">GTK_FILL</property>
                     <property name="y_options">GTK_FILL</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkComboBox" id="move_format_combo">
+                  <object class="GtkAlignment" id="custom_duration_box">
+                    <property name="left_padding">18</property>
+                    <child>
+                      <object class="GtkHBox" id="hbox22">
+                        <property name="visible">True</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkSpinButton" id="custom_duration_spin">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="invisible_char">â?¢</property>
+                            <property name="adjustment">duration_adjustment</property>
+                            <property name="climb_rate">1</property>
+                            <property name="numeric">True</property>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkComboBox" id="custom_duration_units_combo">
+                            <property name="visible">True</property>
+                            <property name="model">custom_duration_units_model</property>
+                            <signal name="changed" handler="duration_changed_cb"/>
+                            <child>
+                              <object class="GtkCellRendererText" id="custom_duration_units_cellrenderer"/>
+                              <attributes>
+                                <attribute name="text">0</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">5</property>
+                    <property name="bottom_attach">6</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label3">
                     <property name="visible">True</property>
-                    <property name="model">liststore2</property>
-                    <signal name="changed" handler="_on_move_format_combo_changed"/>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes" comments="New Game Dialog: Label before game timer settings">Game Duration:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">duration_combo</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="duration_combo">
+                    <property name="visible">True</property>
+                    <property name="model">duration_model</property>
+                    <signal name="changed" handler="duration_combo_changed_cb"/>
                     <child>
-                      <object class="GtkCellRendererText" id="cellrenderertext2"/>
+                      <object class="GtkCellRendererText" id="duration_cellrenderer"/>
                       <attributes>
                         <attribute name="text">0</attribute>
                       </attributes>
@@ -97,19 +200,31 @@
                   <packing>
                     <property name="left_attach">1</property>
                     <property name="right_attach">2</property>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label5">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes" comments="Preferences Dialog: Label before promotion type combo box">Promotion Type:</property>
+                  </object>
+                  <packing>
                     <property name="top_attach">1</property>
                     <property name="bottom_attach">2</property>
                     <property name="x_options">GTK_FILL</property>
-                    <property name="y_options">GTK_FILL</property>
+                    <property name="y_options"></property>
                   </packing>
                 </child>
                 <child>
                   <object class="GtkComboBox" id="promotion_type_combo">
                     <property name="visible">True</property>
-                    <property name="model">liststore1</property>
-                    <signal name="changed" handler="_on_promotion_type_combo_changed"/>
+                    <property name="model">promotion_type_model</property>
+                    <signal name="changed" handler="promotion_type_combo_changed_cb"/>
                     <child>
-                      <object class="GtkCellRendererText" id="cellrenderertext1"/>
+                      <object class="GtkCellRendererText" id="promotion_type_cellrenderer"/>
                       <attributes>
                         <attribute name="text">0</attribute>
                       </attributes>
@@ -118,53 +233,79 @@
                   <packing>
                     <property name="left_attach">1</property>
                     <property name="right_attach">2</property>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
                     <property name="x_options">GTK_FILL</property>
                     <property name="y_options">GTK_FILL</property>
                   </packing>
                 </child>
+                <child>
+                  <object class="GtkHBox" id="hbox2">
+                    <property name="visible">True</property>
+                    <property name="spacing">5</property>
+                    <child>
+                      <object class="GtkImage" id="image1">
+                        <property name="visible">True</property>
+                        <property name="stock">gtk-dialog-info</property>
+                        <property name="icon-size">6</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label4">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Changes will take effect for the next game.</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">6</property>
+                    <property name="bottom_attach">7</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
               </object>
             </child>
             <child type="tab">
-              <object class="GtkLabel" id="game_label">
+              <object class="GtkLabel" id="label1">
                 <property name="visible">True</property>
-                <property name="xalign">0.4699999988079071</property>
-                <property name="label" translatable="yes" comments="Preferences Dialog: Title of game options tab">_Game</property>
-                <property name="use_underline">True</property>
+                <property name="label" translatable="yes">Game</property>
               </object>
               <packing>
                 <property name="tab_fill">False</property>
               </packing>
             </child>
             <child>
-              <object class="GtkVBox" id="view_box">
+              <object class="GtkTable" id="table1">
                 <property name="visible">True</property>
                 <property name="border_width">10</property>
+                <property name="n_rows">3</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">5</property>
+                <property name="row_spacing">5</property>
                 <child>
-                  <object class="GtkCheckButton" id="show_3d">
-                    <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if 3D view is available">3_D Chess View</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="tooltip_text" translatable="yes">View the chess board by default in 2D mode, or optionally in 3D mode using OpenGL.</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="_on_3d_view_activate"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkHBox" id="hbox1">
+                  <object class="GtkVBox" id="view_box">
                     <property name="visible">True</property>
                     <child>
-                      <object class="GtkLabel" id="label6">
+                      <object class="GtkCheckButton" id="show_3d_check">
+                        <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if 3D view is available">3_D Chess View</property>
                         <property name="visible">True</property>
-                        <property name="label">    </property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="show_3d_toggle_cb"/>
                       </object>
                       <packing>
                         <property name="expand">False</property>
@@ -173,149 +314,207 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkCheckButton" id="show_3d_smooth">
-                        <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if the 3D view is smoothed (anti-aliased)">_Smooth Display</property>
+                      <object class="GtkHBox" id="hbox1">
+                        <property name="visible">True</property>
+                        <child>
+                          <object class="GtkLabel" id="label6">
+                            <property name="visible">True</property>
+                            <property name="label">    </property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="show_3d_smooth_check">
+                            <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if the 3D view is smoothed (anti-aliased)">_Smooth Display</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_underline">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkTable" id="theme_table">
+                        <property name="visible">True</property>
+                        <property name="n_columns">2</property>
+                        <property name="column_spacing">5</property>
+                        <property name="row_spacing">5</property>
+                        <child>
+                          <object class="GtkLabel" id="piece_style_label">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes" comments="Preferences Dialog: Label before piece style combo box">Piece Style:</property>
+                          </object>
+                          <packing>
+                            <property name="x_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkComboBox" id="piece_style_combo">
+                            <property name="visible">True</property>
+                            <property name="model">piece_style_model</property>
+                            <signal name="changed" handler="piece_style_combo_changed_cb"/>
+                            <child>
+                              <object class="GtkCellRendererText" id="piece_style_cellrenderer"/>
+                              <attributes>
+                                <attribute name="text">0</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                            <property name="x_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="show_toolbar_check">
+                        <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if toolbar is visible">Show _Toolbar</property>
                         <property name="visible">True</property>
-                        <property name="sensitive">False</property>
                         <property name="can_focus">True</property>
                         <property name="receives_default">False</property>
-                        <property name="tooltip_text" translatable="yes">Smooth edges of the 3D elements (anti-alias)</property>
                         <property name="use_underline">True</property>
                         <property name="draw_indicator">True</property>
-                        <signal name="toggled" handler="_on_3d_smooth_toggled"/>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
-                        <property name="position">1</property>
+                        <property name="position">3</property>
                       </packing>
                     </child>
-                  </object>
-                  <packing>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkTable" id="theme_table">
-                    <property name="visible">True</property>
-                    <property name="n_columns">2</property>
-                    <property name="column_spacing">5</property>
-                    <property name="row_spacing">5</property>
                     <child>
-                      <object class="GtkLabel" id="piece_style_label">
+                      <object class="GtkCheckButton" id="show_history_check">
+                        <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if history browser is visible">Show _History</property>
                         <property name="visible">True</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes" comments="Preferences Dialog: Label before piece style combo box">Piece Style:</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
                       </object>
                       <packing>
-                        <property name="x_options">GTK_FILL</property>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">4</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkComboBox" id="piece_style_combo">
+                      <object class="GtkCheckButton" id="show_move_hints_check">
+                        <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if move hints are visible">_Move Hints</property>
                         <property name="visible">True</property>
-                        <signal name="changed" handler="_on_piece_style_combo_changed"/>
-                        <child>
-                          <object class="GtkCellRendererText" id="cellrenderertext4"/>
-                          <attributes>
-                            <attribute name="text">0</attribute>
-                          </attributes>
-                        </child>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
                       </object>
                       <packing>
-                        <property name="left_attach">1</property>
-                        <property name="right_attach">2</property>
-                        <property name="x_options">GTK_FILL</property>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">5</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="show_numbering_check">
+                        <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if board numbering is visible">_Board Numbering</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">6</property>
                       </packing>
                     </child>
                   </object>
                   <packing>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkCheckButton" id="show_captured_pieces">
-                    <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if captured pieces are visible">Show _Captured Pieces</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="tooltip_text" translatable="yes">Show or hide captured pieces</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="_on_show_captured_pieces_activate"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">3</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkCheckButton" id="show_toolbar">
-                    <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if toolbar is visible">Show _Toolbar</property>
+                  <object class="GtkLabel" id="board_label">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="tooltip_text" translatable="yes">Show or hide the toolbar</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="_on_show_toolbar_activate"/>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes" comments="Preferences Dialog: Label before board orientation combo box">Board Orientation:</property>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">4</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkCheckButton" id="show_history">
-                    <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if history browser is visible">Show _History</property>
+                  <object class="GtkLabel" id="format_label">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="tooltip_text" translatable="yes">Show or hide the game history panel</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="_on_show_history_activate"/>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes" comments="Preferences Dialog: Label before move format combo box">Move Format:</property>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">5</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkCheckButton" id="show_move_hints">
-                    <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if move hints are visible">_Move Hints</property>
+                  <object class="GtkComboBox" id="orientation_combo">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="tooltip_text" translatable="yes">Shows hints during chess games</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="_on_move_hints_activate"/>
+                    <property name="model">orientation_model</property>
+                    <signal name="changed" handler="orientation_combo_changed_cb"/>
+                    <child>
+                      <object class="GtkCellRendererText" id="orientation_cellrenderer"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">6</property>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="y_options">GTK_FILL</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkCheckButton" id="show_numbering">
-                    <property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if board numbering is visible">_Board Numbering</property>
+                  <object class="GtkComboBox" id="move_format_combo">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="tooltip_text" translatable="yes">Show or hide numbering on the chess board</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="_on_board_numbering_activate"/>
+                    <property name="model">move_format_model</property>
+                    <signal name="changed" handler="move_format_combo_changed_cb"/>
+                    <child>
+                      <object class="GtkCellRendererText" id="move_format_cellrenderer"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">7</property>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
                   </packing>
                 </child>
               </object>
@@ -371,22 +570,220 @@
       <action-widget response="-7">closebutton1</action-widget>
     </action-widgets>
   </object>
-  <object class="GtkListStore" id="liststore1">
+  <object class="GtkListStore" id="difficulty_model">
+    <columns>
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name difficulty -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Easy</col>
+        <col id="1">easy</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Normal</col>
+        <col id="1">normal</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Hard</col>
+        <col id="1">hard</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="opponent_model">
+    <columns>
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name opposing-player -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Human</col>
+        <col id="1">human</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="side_model">
+    <columns>
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name play-as-white -->
+      <column type="gboolean"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">White</col>
+        <col id="1">False</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Black</col>
+        <col id="1">False</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="duration_model">
+    <columns>
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name duration -->
+      <column type="gint"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">No limit</col>
+        <col id="1">0</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">One minute</col>
+        <col id="1">60</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Five minutes</col>
+        <col id="1">300</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">30 minutes</col>
+        <col id="1">1800</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">One hour</col>
+        <col id="1">3600</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Custom</col>
+        <col id="1">-1</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="piece_style_model">
+    <columns>
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name piece-style -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Simple</col>
+        <col id="1">simple</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Fancy</col>
+        <col id="1">fancy</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="orientation_model">
     <columns>
-      <!-- column-name item -->
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name board-orientation -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">White Side</col>
+        <col id="1">white</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Black Side</col>
+        <col id="1">black</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Human Side</col>
+        <col id="1">human</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Current Player</col>
+        <col id="1">current</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Face to Face</col>
+        <col id="1">facetoface</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="move_format_model">
+    <columns>
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name move-format -->
       <column type="gchararray"/>
     </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Human</col>
+        <col id="1">human</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Standard Algebraic</col>
+        <col id="1">san</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Figurine</col>
+        <col id="1">fan</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Long Algebraic</col>
+        <col id="1">lan</col>
+      </row>
+    </data>
   </object>
-  <object class="GtkListStore" id="liststore2">
+  <object class="GtkListStore" id="promotion_type_model">
     <columns>
-      <!-- column-name item -->
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name piece-type -->
       <column type="gchararray"/>
     </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Queen</col>
+        <col id="1">queen</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Knight</col>
+        <col id="1">knight</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Rook</col>
+        <col id="1">rook</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Bishop</col>
+        <col id="1">bishop</col>
+      </row>
+    </data>
   </object>
-  <object class="GtkListStore" id="liststore3">
+  <object class="GtkListStore" id="custom_duration_units_model">
     <columns>
-      <!-- column-name item -->
+      <!-- column-name label -->
       <column type="gchararray"/>
+      <!-- column-name multiplier -->
+      <column type="gint"/>
     </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">seconds</col>
+        <col id="1">1</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">minutes</col>
+        <col id="1">60</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">hours</col>
+        <col id="1">3600</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkAdjustment" id="duration_adjustment">
+    <property name="upper">86400</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+    <signal name="value_changed" handler="duration_changed_cb"/>
   </object>
 </interface>
diff --git a/glchess/src/3ds.vala b/glchess/src/3ds.vala
new file mode 100644
index 0000000..c62dee6
--- /dev/null
+++ b/glchess/src/3ds.vala
@@ -0,0 +1,238 @@
+using GL;
+
+public class TDSModel
+{
+    private GLfloat[] vertices;
+    private GLushort[] triangles;
+    private GLfloat[] normals;
+
+    public TDSModel (GLib.File file) throws GLib.Error
+    {
+        var stream = file.read ();
+        parse_block (stream, stream.query_info (GLib.FILE_ATTRIBUTE_STANDARD_SIZE).get_size ());
+
+        /* Calculate normals */
+        normals = new GLfloat[vertices.length];
+        for (int i = 0; i < normals.length; i++)
+            normals[i] = 0f;
+        for (int i = 0; i < triangles.length; i += 3)
+        {
+            var v0 = triangles[i] * 3;
+            var v1 = triangles[i+1] * 3;
+            var v2 = triangles[i+2] * 3;
+
+            /* Do cross-product of face to get normal */
+            GLfloat a[3], b[3], normal[3];
+            a[0] = vertices[v1] - vertices[v0];
+            a[1] = vertices[v1+1] - vertices[v0+1];
+            a[2] = vertices[v1+2] - vertices[v0+2];
+            b[0] = vertices[v2] - vertices[v0];
+            b[1] = vertices[v2+1] - vertices[v0+1];
+            b[2] = vertices[v2+2] - vertices[v0+2];
+            normal[0] = a[1]*b[2] - a[2]*b[1];
+            normal[1] = a[2]*b[0] - a[0]*b[2];
+            normal[2] = a[0]*b[1] - a[1]*b[0];
+
+            /* Add this normal to the three vertices of this face */
+            normals[v0] += normal[0];
+            normals[v0+1] += normal[1];
+            normals[v0+2] += normal[2];
+            normals[v1] += normal[0];
+            normals[v1+1] += normal[1];
+            normals[v1+2] += normal[2];
+            normals[v2] += normal[0];
+            normals[v2+1] += normal[1];
+            normals[v2+2] += normal[2];
+        }
+
+        /* Normalize normals */
+        for (int i = 0; i < normals.length; i += 3)
+        {
+            GLfloat length = (GLfloat) Math.sqrt (normals[i]*normals[i] + normals[i+1]*normals[i+1] + normals[i+2]*normals[i+2]);
+            normals[i] /= length;
+            normals[i+1] /= length;
+            normals[i+2] /= length;
+        }
+    }
+    
+    private void parse_block (GLib.FileInputStream stream, int64 length) throws GLib.Error
+    {
+        while (length > 6)
+        {
+            var id = read_uint16 (stream);
+            int64 block_length = read_uint32 (stream);
+            if (block_length < 6)
+            {
+                return;
+            }
+            if (block_length > length)
+            {
+                // throw error
+                stderr.printf("Overflow, need %lli octets for %04X, but only have %lli\n", block_length, id, length);
+                return;
+            }
+
+            switch (id)
+            {
+            /* Main chunk */
+            case 0x4D4D:
+                //stdout.printf("<root>\n");
+                parse_block (stream, block_length - 6);
+                //stdout.printf("</root>\n");
+                break;
+
+            /* Version */
+            /*case 0x0002:
+                var version = read_uint32 (stream);
+                //stdout.printf("<version>%u</version>\n", version);
+                break;*/
+
+            /* 3D editor */
+            case 0x3D3D:
+                //stdout.printf("<editor>\n");
+                parse_block (stream, block_length - 6);
+                //stdout.printf("</editor>\n");
+                break;
+
+            /* Object block */
+            case 0x4000:
+                var name = read_string (stream);
+                //stdout.printf("<object name=\"%s\">\n", name);
+                parse_block (stream, block_length - 6 - (name.length + 1));
+                //stdout.printf("</object>\n");
+                break;
+                
+            /* Triangular mesh */
+            case 0x4100:
+                //stdout.printf("<triangles>\n");
+                parse_block (stream, block_length - 6);
+                //stdout.printf("</triangles>\n");
+                break;
+
+            /* Vertices */
+            case 0x4110:
+                //stdout.printf("<vertices>\n");
+                var n = read_uint16 (stream);
+                vertices = new GLfloat[n*3];
+                for (var i = 0; i < n; i++)
+                {
+                    var x = read_float (stream);
+                    var y = read_float (stream);
+                    var z = read_float (stream);
+                    var scale = 3.5f;
+                    vertices[i*3] = scale*x;
+                    vertices[i*3+1] = scale*z;
+                    vertices[i*3+2] = scale*y;
+                    //stdout.printf ("<vertex x=\"%f\" y=\"%f\" z=\"%f\"/>\n", x, y, z);
+                }
+                //stdout.printf("</vertices>\n");
+                break;
+
+            /* Faces */
+            case 0x4120:
+                //stdout.printf("<faces>\n");
+                if (block_length < 2)
+                    return;
+                var n = read_uint16 (stream);
+                triangles = new GLushort[n*3];
+                if (block_length < 2 + n * 8)                  
+                {
+                    stderr.printf("Invalid face data, need %u, have %lli\n", 2+n*8, block_length);
+                    return;
+                }
+                for (var i = 0; i < n; i++)
+                {
+                    var a = read_uint16 (stream);
+                    var b = read_uint16 (stream);
+                    var c = read_uint16 (stream);
+                    /*var flags = */read_uint16 (stream);
+                    triangles[i*3] = (GLushort) a;
+                    triangles[i*3+1] = (GLushort) c;
+                    triangles[i*3+2] = (GLushort) b;
+                    //stdout.printf ("<face a=\"%u\" b=\"%u\" c=\"%u\"/ flags=\"%u\">\n", a, b, c, flags);
+                }
+                parse_block (stream, block_length - (2 + n*8));
+                //stdout.printf("</faces>\n");
+                break;
+
+            /* Keyframer */
+/*            case 0xB000:
+                //stdout.printf("<keyframe>\n");
+                parse_block (stream, block_length - 6);
+                //stdout.printf("</keyframe>\n");
+                break;*/
+
+            default:
+                //stdout.printf ("<%04X>", id);
+                for (var i = 0; i < block_length - 6; i++)
+                {
+                    /*var c = */read_uint8 (stream);
+                    //stdout.printf("%02X ", c);
+                }
+                //stdout.printf ("<\\%04X>\n", id);
+                break;
+            }
+
+            length -= block_length;
+                //stream.seek (block_length - 6, GLib.SeekType.CUR);
+        }
+        
+        if (length != 0)
+        {
+            return; // throw error
+        }
+    }
+
+    public void render ()
+    {
+        glEnable (GL_CULL_FACE);
+
+        glEnableClientState (GL_VERTEX_ARRAY);
+        glVertexPointer (3, GL_FLOAT, 0, vertices);
+        glEnableClientState (GL_NORMAL_ARRAY);
+        glNormalPointer (GL_FLOAT, 0, normals);
+        glDrawElements (GL_TRIANGLES, (GLsizei) triangles.length, GL_UNSIGNED_SHORT, triangles);
+        glDisableClientState (GL_VERTEX_ARRAY);
+    }
+
+    private uint8 read_uint8 (GLib.InputStream stream) throws GLib.Error
+    {
+        uchar buffer[1];
+        stream.read_all (buffer, null, null);
+        return buffer[0];
+    }
+
+    private uint16 read_uint16 (GLib.InputStream stream) throws GLib.Error
+    {
+        uchar buffer[2];
+        stream.read_all (buffer, null, null);
+        return buffer[1] << 8 | buffer[0];
+    }
+
+    private uint32 read_uint32 (GLib.InputStream stream) throws GLib.Error
+    {
+        uchar buffer[4];
+        stream.read_all (buffer, null, null);
+        return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
+    }
+
+    private float read_float (GLib.InputStream stream) throws GLib.Error
+    {
+        uint8 buffer[4];
+        stream.read_all (buffer, null, null);
+        float[] fbuffer = (float[]) buffer;
+        return fbuffer[0];
+    }
+
+    private string read_string (GLib.InputStream stream) throws GLib.Error
+    {
+        var value = new StringBuilder();
+        while (true)
+        {
+            var c = read_uint8 (stream);
+            if (c == 0)
+                return value.str;
+            value.append_c ((char)c);
+        }
+    }
+}
\ No newline at end of file
diff --git a/glchess/src/Makefile.am b/glchess/src/Makefile.am
index 53051e6..4682774 100644
--- a/glchess/src/Makefile.am
+++ b/glchess/src/Makefile.am
@@ -1,12 +1,43 @@
-SUBDIRS = lib
+bin_PROGRAMS = glchess
 
-#################################################################
+glchess_SOURCES = \
+	glchess.vala \
+	ai-profile.vala \
+	chess-engine.vala \
+	chess-engine-cecp.vala \
+	chess-engine-uci.vala \
+	chess-game.vala \
+	chess-pgn.vala \
+	chess-view.vala \
+	chess-view-2d.vala \
+	chess-view-options.vala
 
-## Executable
-bin_SCRIPTS = glchess
-CLEANFILES  = glchess glchess.in
+#	3ds.vala
+#	chess-view-3d.vala
 
-glchess: glchess.in
-	$(AM_V_GEN) $(SED) -e "s|\#pyexecdir\#|$(pyexecdir)|" $< > $@ && chmod u+x $@
+glchess_CFLAGS = \
+	$(GMODULE_CFLAGS) \
+	$(GTK_CFLAGS) \
+	$(RSVG_CFLAGS) \
+	$(GTKGLEXT_CFLAGS) \
+	$(WARN_CFLAGS)
 
--include $(top_srcdir)/git.mk
+glchess_LDADD = \
+	$(GMODULE_LIBS) \
+	$(GTK_LIBS) \
+	$(RSVG_LIBS) \
+	$(GTKGLEXT_LIBS)
+
+glchess_VALAFLAGS = \
+    --pkg gtk+-3.0 \
+    --pkg gmodule-2.0 \
+    --pkg librsvg-2.0 \
+    --pkg posix \
+    --vapidir . \
+    --pkg gl \
+    --pkg glu
+
+#    --pkg gtkglext-1.0
+
+DISTCLEANFILES = \
+	Makefile.in
diff --git a/glchess/src/ai-profile.vala b/glchess/src/ai-profile.vala
new file mode 100644
index 0000000..ab29ab9
--- /dev/null
+++ b/glchess/src/ai-profile.vala
@@ -0,0 +1,54 @@
+public GLib.List<AIProfile> load_ai_profiles (string filename)
+{
+   var profiles = new GLib.List<AIProfile> ();
+
+   var file = new GLib.KeyFile ();
+   try
+   {
+       file.load_from_file (filename, GLib.KeyFileFlags.NONE);
+   }
+   catch (GLib.KeyFileError e)
+   {
+       GLib.warning ("Failed to load AI profiles: %s", e.message);
+       return profiles;   
+   }
+   catch (GLib.FileError e)
+   {
+       GLib.warning ("Failed to load AI profiles: %s", e.message);
+       return profiles;
+   }
+
+   foreach (string name in file.get_groups ())
+   {
+       GLib.debug ("Loading AI profile %s", name);
+       var profile = new AIProfile ();
+       try
+       {
+           profile.name = name;
+           profile.protocol = file.get_value (name, "protocol");
+           profile.binary = file.get_value (name, "binary");
+           if (file.has_key (name, "args"))
+               profile.args = file.get_value (name, "args");
+       }
+       catch (GLib.KeyFileError e)
+       {
+           continue;
+       }
+
+       if (Environment.find_program_in_path (profile.binary) != null)
+           profiles.append (profile);
+   }
+
+   return profiles;
+}
+
+public class AIProfile
+{
+    public string name;
+    public string protocol;
+    public string binary;
+    public string args = "";
+    public string[] easy_options;
+    public string[] normal_options;
+    public string[] hard_options;
+}
diff --git a/glchess/src/chess-engine-cecp.vala b/glchess/src/chess-engine-cecp.vala
new file mode 100644
index 0000000..fdeb9bc
--- /dev/null
+++ b/glchess/src/chess-engine-cecp.vala
@@ -0,0 +1,85 @@
+public class ChessEngineCECP : ChessEngine
+{
+    private char[] buffer;
+    private bool moving = false;
+
+    public ChessEngineCECP ()
+    {
+        starting.connect (start_cb);
+    }
+    
+    private void start_cb ()
+    {
+        write_line ("xboard");
+        ready = true;
+    }
+
+    public override void process_input (char[] data)
+    {
+        /* Copy new data */
+        int current = buffer.length;
+        buffer.resize ((int) (buffer.length + data.length));
+        for (int i = 0; i < data.length; i++)
+            buffer[current + i] = data[i];
+
+        /* Parse lines */
+        while (true)
+        {
+            int offset;
+
+            for (offset = 0; offset < buffer.length && buffer[offset] != '\n'; offset++);
+            if (offset >= buffer.length)
+                return;
+
+            buffer[offset] = '\0';
+            string line = (string) buffer;
+
+            GLib.debug ("Read from engine: '%s'", line);
+
+            string[] move_prefixes = { "My move is: ", "my move is ", "move " };
+            foreach (string prefix in move_prefixes)
+            {
+                if (line.has_prefix (prefix))
+                {
+                    string move = line[prefix.length:line.length];
+                    GLib.debug ("Engine moves %s", move);
+                    moving = true;
+                    moved (move);
+                }
+            }
+
+            if (line.has_prefix ("Illegal move: "))
+            {
+            }
+            else if (line == "resign" || line == "tellics resign")
+            {
+            }
+            else if (line == "offer draw")
+            {
+            }
+
+            buffer = buffer[offset+1:buffer.length];
+        }
+    }
+
+    public override void start_game ()
+    {
+    }
+
+    public override void request_move ()
+    {
+        write_line ("go");
+    }
+
+    public override void report_move (ChessMove move)
+    {
+        /* Don't repeat the engines move back to it */
+        if (!moving)
+        {
+            /* Stop the AI from automatically moving in response to this one */
+            write_line ("force");
+            write_line (move.lan);
+        }
+        moving = false;
+    }
+}
diff --git a/glchess/src/chess-engine-uci.vala b/glchess/src/chess-engine-uci.vala
new file mode 100644
index 0000000..78fd3d3
--- /dev/null
+++ b/glchess/src/chess-engine-uci.vala
@@ -0,0 +1,108 @@
+public class ChessEngineUCI : ChessEngine
+{
+    private char[] buffer;
+    private string position_command;
+    
+    public ChessEngineUCI ()
+    {
+        buffer = new char[0];
+        position_command = "position startpos";
+        starting.connect (start_cb);
+    }
+
+    private void start_cb ()
+    {
+        write_line ("uci");
+    }
+
+    public override void start_game ()
+    {
+        write_line ("ucinewgame");
+    }
+
+    public override void request_move ()
+    {
+        write_line ("go wtime 30000 btime 30000");
+    }
+
+    public override void report_move (ChessMove move)
+    {
+        if (position_command == "position startpos")
+            position_command += " moves";
+        position_command += " " + move.lan;
+        write_line (position_command);
+    }
+
+    public override void process_input (char[] data)
+    {
+        /* Copy new data */
+        int current = buffer.length;
+        buffer.resize ((int) (buffer.length + data.length));
+        for (int i = 0; i < data.length; i++)
+            buffer[current + i] = data[i];
+
+        /* Parse lines */
+        while (true)
+        {
+            int offset;
+
+            for (offset = 0; offset < buffer.length && buffer[offset] != '\n'; offset++);
+            if (offset >= buffer.length)
+                return;
+
+            buffer[offset] = '\0';
+            string line = (string) buffer;
+
+            GLib.debug ("Read from engine: '%s'", line);
+            
+            string[] tokens = line.split (" ");
+            if (tokens.length > 0)
+            {
+                switch (tokens[0])
+                {
+                case "id":
+                    break;
+
+                case "uciok":
+                    if (tokens.length != 1)
+                        GLib.warning ("Unexpected arguments on uciok: %s", line);
+                        
+                    configure ();
+                    break;
+
+                case "readyok":
+                    if (tokens.length != 1)
+                        GLib.warning ("Unexpected arguments on readyok: %s", line);
+
+                    ready = true;
+                    break;
+
+                case "bestmove":
+                    if (tokens.length < 2)
+                        GLib.warning ("No move with bestmove: %s", line);
+                    GLib.debug ("Engine moves %s", tokens[1]);
+                    moved (tokens[1]);
+                    break;
+
+                case "info":
+                    break;
+
+                case "option":
+                    break;
+
+                default:
+                    GLib.warning ("Unknown command: '%s'", line);
+                    break;
+                }
+            }
+
+            buffer = buffer[offset+1:buffer.length];
+        }
+    }
+
+    private void configure ()
+    {
+        //write_line ("setoption ...");
+        write_line ("isready");
+    }
+}
diff --git a/glchess/src/chess-engine.vala b/glchess/src/chess-engine.vala
new file mode 100644
index 0000000..df1a4cb
--- /dev/null
+++ b/glchess/src/chess-engine.vala
@@ -0,0 +1,147 @@
+public class ChessEngine : GLib.Object
+{
+    public string binary;
+    private GLib.Pid pid;
+    private int stdin_fd;
+    private int stderr_fd;
+    private GLib.IOChannel stdout_channel;
+
+    protected virtual void process_input (char[] data) {}
+
+    public signal void starting ();
+    public signal void ready_changed ();
+    public signal void moved (string move);
+    public signal void resigned ();
+    public signal void stopped ();
+    
+    private bool _ready = false;
+    public bool ready
+    {
+        protected set
+        {
+           _ready = value;
+           ready_changed ();
+        }
+        public get
+        {
+            return _ready;
+        }
+    }
+    
+    public bool start ()
+    {
+        string[] argv = { binary, null };
+        int stdout_fd;
+        try
+        {
+            GLib.Process.spawn_async_with_pipes (null, argv, null,
+                                                 GLib.SpawnFlags.SEARCH_PATH,
+                                                 null,
+                                                 out pid, out stdin_fd, out stdout_fd, out stderr_fd);
+        }
+        catch (GLib.SpawnError e)
+        {
+            stderr.printf ("Failed to execute chess engine: %s\n", e.message);
+            return false;
+        }
+
+        stdout_channel = new GLib.IOChannel.unix_new (stdout_fd);
+        try
+        {
+            stdout_channel.set_flags (GLib.IOFlags.NONBLOCK);
+        }
+        catch (GLib.IOChannelError e)
+        {
+            stderr.printf ("Failed to set input from chess engine to non-blocking: %s", e.message);
+        }
+        stdout_channel.add_watch (GLib.IOCondition.IN, read_cb);
+
+        starting ();
+
+        return true;
+    }
+    
+    public virtual void start_game ()
+    {
+    }
+
+    public virtual void request_move ()
+    {
+    }
+
+    public virtual void report_move (ChessMove move)
+    {
+    }
+
+    public void stop ()
+    {
+        // FIXME
+        stopped ();
+    }
+
+    private bool read_cb (GLib.IOChannel source, GLib.IOCondition condition)
+    {
+        char[] buf;
+        size_t n_read;
+        GLib.IOStatus status;
+
+        buf = new char[1024];
+        try
+        {
+            status = source.read_chars (buf, out n_read);
+        }
+        catch (GLib.ConvertError e)
+        {
+            return false;
+        }
+        catch (GLib.IOChannelError e)
+        {
+            return false;
+        }
+
+        if (status == GLib.IOStatus.EOF)
+        {
+            stdout.printf ("EOF\n");
+            return false;
+        }
+        if (status == GLib.IOStatus.NORMAL)
+        {
+            //GLib.debug ("Read %zu octets from engine", n_read);
+            buf.resize ((int) n_read);
+            process_input (buf);
+        }
+
+        return true;
+    }
+
+    protected void write (char[] data)
+    {
+        size_t offset = 0;
+        size_t n_written;
+        
+        while (offset < data.length)
+        {
+            /* Unnecessary copying but there seems to be a vala bug here */
+            char[] d = new char[data.length - offset];
+            for (int i = 0; i < data.length - offset; i++)
+                d[i] = data[offset + i];
+
+            n_written = Posix.write(stdin_fd, d, d.length);
+            if (n_written < 0)
+                return;
+
+            //GLib.debug ("Wrote %zu octets to engine", n_written);
+
+            offset += n_written;
+        }
+    }
+
+    protected void write_line (string line)
+    {
+        string l = line + "\n";
+        GLib.debug ("Writing line to engine: '%s'", line);
+        char[] d = l.to_utf8 ();
+        if (d != null)
+            write (d);
+    }
+}
diff --git a/glchess/src/chess-game.vala b/glchess/src/chess-game.vala
new file mode 100644
index 0000000..28a0a2f
--- /dev/null
+++ b/glchess/src/chess-game.vala
@@ -0,0 +1,696 @@
+public enum Color
+{
+    WHITE,
+    BLACK
+}
+
+public class ChessPlayer : GLib.Object
+{
+    public Color color;
+    public signal void start_turn ();
+    public signal bool do_move (string move, bool apply);
+    public signal bool do_move_with_coords (int r0, int f0, int r1, int f1, bool apply);
+    public signal bool do_resign ();
+    public signal bool do_claim_draw ();
+
+    public ChessPlayer (Color color)
+    {
+        this.color = color;
+    }
+
+    public bool move (string move, bool apply = true)
+    {
+        return do_move (move, apply);
+    }
+
+    public bool move_with_coords (int r0, int f0, int r1, int f1, bool apply = true)
+    {
+        return do_move_with_coords (r0, f0, r1, f1, apply);
+    }
+
+    public bool resign ()
+    {
+        return do_resign ();
+    }
+    
+    public bool claim_draw ()
+    {
+        return do_claim_draw ();
+    }
+}
+
+public enum PieceType
+{
+    PAWN,
+    ROOK,
+    KNIGHT,
+    BISHOP,
+    QUEEN,
+    KING
+}
+
+public class ChessPiece
+{
+    public ChessPlayer player;
+    public PieceType type;
+
+    public signal void moved ();
+    public signal void promoted ();
+    public signal void died ();
+
+    public ChessPiece (ChessPlayer player, PieceType type)
+    {
+        this.player = player;
+        this.type = type;
+    }
+}
+
+public class ChessMove
+{
+    public int number;
+    public ChessPiece piece;
+    public ChessPiece? moved_rook;
+    public ChessPiece? victim;
+    public int r0;
+    public int f0;
+    public int r1;
+    public int f1;
+    public string lan = "";
+    public string san = "";
+    public string human = "";
+    
+    public string fan
+    {
+        get
+        {
+            // FIXME: Translate the san move
+            //â??â??â??â??â??â??
+            //â??â??â??â??â??â??
+            return san;
+        }
+    }
+
+    public ChessMove copy ()
+    {
+        var move = new ChessMove ();
+        move.number = number;
+        move.piece = piece;
+        move.moved_rook = moved_rook;
+        move.victim = victim;
+        move.r0 = r0;
+        move.f0 = f0;
+        move.r1 = r1;
+        move.f1 = f1;
+        move.lan = lan;        
+        move.san = san;
+        move.human = human;
+        return move;
+    }
+}
+
+public class ChessState
+{
+    public int number = 0;
+    public ChessPlayer white;
+    public ChessPlayer black;    
+    public ChessPlayer current_player;
+
+    public ChessPiece[,] board;
+    public ChessMove? last_move = null;
+
+    public ChessState ()
+    {
+        current_player = white = new ChessPlayer (Color.WHITE);
+        black = new ChessPlayer (Color.BLACK);
+
+        board = new ChessPiece[8,8];
+        for (int file = 0; file < 8; file++)
+            for (int rank = 0; rank < 8; rank++)
+                board[rank, file] = null;
+
+        add_piece (0, 0, white, PieceType.ROOK);
+        add_piece (0, 1, white, PieceType.KNIGHT);
+        add_piece (0, 2, white, PieceType.BISHOP);
+        add_piece (0, 3, white, PieceType.QUEEN);
+        add_piece (0, 4, white, PieceType.KING);
+        add_piece (0, 5, white, PieceType.BISHOP);
+        add_piece (0, 6, white, PieceType.KNIGHT);
+        add_piece (0, 7, white, PieceType.ROOK);
+        add_piece (7, 0, black, PieceType.ROOK);
+        add_piece (7, 1, black, PieceType.KNIGHT);
+        add_piece (7, 2, black, PieceType.BISHOP);
+        add_piece (7, 3, black, PieceType.QUEEN);
+        add_piece (7, 4, black, PieceType.KING);
+        add_piece (7, 5, black, PieceType.BISHOP);
+        add_piece (7, 6, black, PieceType.KNIGHT);
+        add_piece (7, 7, black, PieceType.ROOK);
+        for (int file = 0; file < 8; file++)
+        {
+            add_piece (1, file, white, PieceType.PAWN);
+            add_piece (6, file, black, PieceType.PAWN);
+        }
+    }
+
+    private void add_piece (int rank, int file, ChessPlayer player, PieceType type)
+    {
+        ChessPiece piece = new ChessPiece (player, type);
+        board[rank, file] = piece;
+    }
+    
+    public ChessState copy ()
+    {
+        ChessState state = new ChessState ();
+
+        state.number = number;
+        state.white = white;
+        state.black = black;
+        state.current_player = current_player;
+        if (last_move != null)
+            state.last_move = last_move.copy();
+        for (int file = 0; file < 8; file++)
+            for (int rank = 0; rank < 8; rank++)
+                state.board[rank, file] = board[rank, file];
+
+        return state;
+    }
+
+    public bool move (string move, bool apply = true)
+    {
+        int r0, f0, r1, f1;
+        if (!decode_move (move, out r0, out f0, out r1, out f1))
+            return false;
+        return move_with_coords (r0, f0, r1, f1, apply);
+    }
+
+    public bool move_with_coords (int r0, int f0, int r1, int f1, bool apply = true, bool test_check = true)
+    {
+        /* Must be moving own piece */
+        ChessPiece? piece = board[r0, f0];
+
+        if (piece == null || piece.player != current_player)
+            return false;
+
+        /* Can't take own pieces */
+        ChessPiece? victim = board[r1, f1];
+        if (victim != null && victim.player == current_player)
+            return false;
+
+        /* Get rank relative to base rank */
+        int rel_rank = r0;
+        int rel_march = r1 - r0;
+        if (piece.player.color == Color.BLACK)
+        {
+            rel_rank = 7 - rel_rank;
+            rel_march = -rel_march;
+        }
+
+        /* Distance moved in each dimension */
+        int file_distance = (f1 - f0).abs();
+        int rank_distance = (r1 - r0).abs();
+
+        /* Direction moved in each dimension */
+        int rank_step = r1 - r0;
+        if (rank_distance != 0)
+            rank_step /= rank_distance;
+        int file_step = f1 - f0;
+        if (file_distance != 0)
+            file_step /= file_distance;
+
+        bool valid = false, check_inbetween = false;
+        int rook_file = -1;
+        switch (piece.type)
+        {
+        case PieceType.PAWN:
+            /* Can move forward one, forward two from the base rank or
+             * diagonally and take an opponent piece */
+            valid = (victim == null && rel_march == 1 && file_distance == 0) ||
+                    (victim == null && rel_march == 2 && file_distance == 0 && rel_rank == 1) ||
+                    (victim != null && rel_march == 1 && file_distance == 1);
+
+            // FIXME: Check en passant
+
+            check_inbetween = true;
+            break;
+        case PieceType.ROOK:
+            /* Can move horizontal or vertical */
+            valid = file_distance == 0 ||
+                    rank_distance == 0;
+            check_inbetween = true;
+            break;
+        case PieceType.KNIGHT:
+            /* Can move one square in one direction and two in the other */
+            valid = file_distance * rank_distance == 2;
+            break;
+        case PieceType.BISHOP:
+            /* Can move diagonal */
+            valid = file_distance == rank_distance;
+            check_inbetween = true;
+            break;
+        case PieceType.QUEEN:
+            /* Can move horizontal, vertical or diagonal */
+            valid = file_distance == 0 ||
+                    rank_distance == 0 ||
+                    file_distance == rank_distance;
+            check_inbetween = true;
+            break;
+        case PieceType.KING:
+            /* Can only move one square */
+            valid = file_distance < 2 && rank_distance < 2;
+
+            /* Castle move */
+            if (file_distance == 2 && rank_distance == 0 && rel_rank == 0)
+            {
+                // FIXME: Check rook and king hasn't moved
+
+                /* File the rook is on */
+                rook_file = file_step > 0 ? 7 : 0; 
+
+                /* Need space between king and rook */
+                for (int f = f0 + file_step; f < 7 && f > 0; f += file_step)
+                    if (board[r0, f] != null)
+                        return false;
+
+                // FIXME: Need to check if can get taken on square moved over
+
+                valid = true;
+            }
+            break;
+        }
+        if (!valid)
+            return false;
+
+        /* Check if squares being moved over are free */
+        if (check_inbetween)
+        {
+            int r = r0 + rank_step, f = f0 + file_step;
+            for (; !(r == r1 & f == f1); r += rank_step, f += file_step)
+                if (board[r, f] != null)
+                    return false;
+        }
+
+        if (test_check)
+        {
+            /* Check if would put us into check */
+            // FIXME: Check 2-3 squares if king was moved
+            var state = copy ();
+            state.move_with_coords (r0, f0, r1, f1, true, false);
+
+            int king_rank = -1, king_file = -1;
+            for (int file = 0; file < 8; file++)
+                for (int rank = 0; rank < 8; rank++)
+                {
+                    var p = state.board[rank, file];
+                    if (p != null && p.player == current_player && p.type == PieceType.KING)
+                    {
+                        king_rank = rank;
+                        king_file = file;
+                    }
+                }
+                
+            /* See if any enemy pieces can take the king */
+            for (int file = 0; file < 8; file++)
+                for (int rank = 0; rank < 8; rank++)
+                    if (state.move_with_coords (rank, file, king_rank, king_file, false, false))
+                        return false;
+        }
+
+        if (!apply)
+            return true;
+
+        /* Move piece */
+        board[r0, f0] = null;
+        board[r1, f1] = piece;
+
+        last_move = new ChessMove ();
+        last_move.number = number;
+        last_move.piece = piece;
+        last_move.victim = victim;
+
+        /* Move rook in castle */
+        if (rook_file >= 0)
+        {
+            ChessPiece rook = board[r0, rook_file];
+            board[r0, rook_file] = null;
+            board[r0, f0 + file_step] = rook;
+            last_move.moved_rook = rook;
+        }
+
+        if (current_player == white)
+            current_player = black;
+        else
+            current_player = white;
+
+        last_move.r0 = r0;
+        last_move.f0 = f0;
+        last_move.r1 = r1;
+        last_move.f1 = f1;
+        // FIXME: Promotion
+        last_move.lan = "%c%d%c%d".printf ('a' + f0, r0 + 1, 'a' + f1, r1 + 1);
+        // FIXME: Generate SAN move
+        last_move.san = last_move.lan;
+
+        return true;
+    }
+
+    private bool decode_piece_type (unichar c, out PieceType type)
+    {
+        switch (c)
+        {
+        case 'P':
+            type = PieceType.PAWN;
+            return true;
+        case 'R':
+            type = PieceType.ROOK;
+            return true;
+        case 'N':
+            type = PieceType.KNIGHT;
+            return true;
+        case 'B':
+            type = PieceType.BISHOP;
+            return true;
+        case 'Q':
+            type = PieceType.QUEEN;
+            return true;
+        case 'K':
+            type = PieceType.KING;
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    private bool decode_move (string move, out int r0, out int f0, out int r1, out int f1)
+    {
+        int i = 0;
+        
+        if (move.has_prefix ("O-O-O"))
+        {
+            if (current_player == white)
+                r0 = r1 = 0;
+            else
+                r0 = r1 = 7;
+            f0 = 4;
+            f1 = 2;
+            i += (int) "O-O-O".length;
+        }
+        else if (move.has_prefix ("O-O"))
+        {
+            if (current_player == white)
+                r0 = r1 = 0;
+            else
+                r0 = r1 = 7;
+            f0 = 4;
+            f1 = 6;
+            i += (int) "O-O".length;
+        }
+        else
+        {
+            PieceType type = PieceType.PAWN;
+            if (decode_piece_type (move[i], out type))
+                i++;
+
+            r0 = f0 = r1 = f1 = -1;
+            if (move[i] >= 'a' && move[i] <= 'h')
+            {
+                f1 = (int) (move[i] - 'a');
+                i++;
+            }
+            if (move[i] >= '1' && move[i] <= '8')
+            {
+                r1 = (int) (move[i] - '1');
+                i++;
+            }
+            if (move[i] == 'x')
+                i++;
+            if (move[i] >= 'a' && move[i] <= 'h')
+            {
+                f0 = f1;
+                f1 = (int) (move[i] - 'a');
+                i++;
+            }
+            if (move[i] >= '1' && move[i] <= '8')
+            {
+                r0 = r1;
+                r1 = (int) (move[i] - '1');
+                i++;
+            }
+            if (move[i] == '=')
+                i++;
+            PieceType promotion_type;
+            if (decode_piece_type (move[i], out promotion_type))
+                i++;
+
+            /* Don't have a destination to move to */
+            if (r1 < 0 || f1 < 0)
+            {
+                GLib.debug ("Move %s missing destination", move);
+                return false;
+            }
+
+            /* Find source piece */
+            if (r0 < 0 || f0 < 0)
+            {
+                int match_rank = -1, match_file = -1;
+
+                for (int file = 0; file < 8; file++)
+                {
+                    if (f0 >= 0 && file != f0)
+                        continue;
+
+                    for (int rank = 0; rank < 8; rank++)
+                    {
+                        if (r0 >= 0 && rank != r0)
+                            continue;
+
+                        /* Only check this players pieces of the correct type */
+                        var piece = board[rank,file];
+                        if (piece == null || piece.type != type || piece.player != current_player)
+                            continue;
+
+                        /* See if can move here */
+                        if (!this.move_with_coords (rank, file, r1, f1, false))
+                            continue;
+
+                        /* Duplicate match */
+                        if (match_rank >= 0)
+                        {
+                            GLib.debug ("Move %s is ambiguous", move);
+                            return false;
+                        }
+
+                        match_rank = rank;
+                        match_file = file;
+                    }
+                }
+
+                if (match_rank < 0)
+                {
+                    GLib.debug ("Move %s has no matches", move);
+                    return false;
+                }
+
+                r0 = match_rank;
+                f0 = match_file;
+            }
+        }
+
+        if (move[i] == '+')
+            i++;
+        else if (move[i] == '#')
+            i++;
+
+        if (move[i] != '\0')
+        {
+            GLib.debug ("Move %s has unexpected characters", move);
+            return false;
+        }
+
+        return true;
+    }
+}
+
+public enum ChessResult
+{
+    IN_PROGRESS,
+    WHITE_WON,
+    BLACK_WON,
+    DRAW
+}
+
+public enum ChessRule
+{
+    CHECKMATE,
+    STALEMATE,
+    FIFTY_MOVES,
+    TIMEOUT,
+    THREE_FOLD_REPETITION,
+    INSUFFICIENT_MATERIAL,
+    RESIGN,
+    ABANDONMENT,
+    DEATH
+}
+
+public class ChessGame
+{
+    public bool is_started;
+    public ChessResult result;
+    public ChessRule rule;
+    public GLib.List<ChessState> move_stack;
+
+    public signal void started ();
+    public signal void turn_started (ChessPlayer player);
+    public signal void moved (ChessMove move);
+    public signal void ended ();
+
+    public ChessPlayer white
+    {
+        get { return move_stack.data.white; }
+    }
+    public ChessPlayer black
+    {
+        get { return move_stack.data.black; }
+    }
+    public ChessPlayer current_player
+    {
+        get { return move_stack.data.current_player; }
+    }
+
+    public ChessGame ()
+    {
+        is_started = false;
+        move_stack.prepend (new ChessState ());
+        result = ChessResult.IN_PROGRESS;
+
+        white.do_move.connect (move_cb);
+        white.do_move_with_coords.connect (move_with_coords_cb);
+        white.do_resign.connect (resign_cb);
+        white.do_claim_draw.connect (claim_draw_cb);
+        black.do_move.connect (move_cb);
+        black.do_move_with_coords.connect (move_with_coords_cb);
+        black.do_resign.connect (resign_cb);
+        black.do_claim_draw.connect (claim_draw_cb);
+    }
+
+    private bool move_cb (ChessPlayer player, string move, bool apply)
+    {
+        return do_move (player, move, -1, -1, -1, -1, apply);
+    }
+
+    private bool move_with_coords_cb (ChessPlayer player, int r0, int f0, int r1, int f1, bool apply)
+    {
+        return do_move (player, null, r0, f0, r1, f1, apply);
+    }
+
+    private bool do_move (ChessPlayer player, string? move, int r0, int f0, int r1, int f1, bool apply)
+    {
+        if (!is_started)
+            return false;
+        if (player != current_player)
+            return false;
+
+        var state = move_stack.data.copy ();
+        state.number++;
+        if (move != null)
+        {
+            if (!state.move (move, apply))
+                return false;
+        }
+        else
+        {
+            if (!state.move_with_coords (r0, f0, r1, f1, apply))
+                return false;
+        }
+
+        if (!apply)
+            return true;
+
+        move_stack.prepend (state);
+        if (state.last_move.victim != null)
+            state.last_move.victim.died ();
+        state.last_move.piece.moved ();
+        if (state.last_move.moved_rook != null)
+            state.last_move.moved_rook.moved ();
+        moved (state.last_move);
+
+        current_player.start_turn ();
+        turn_started (current_player);
+
+        return true;
+    }
+
+    private bool resign_cb (ChessPlayer player)
+    {
+        if (!is_started)
+            return false;
+
+        if (player == white)
+            stop (ChessResult.BLACK_WON, ChessRule.RESIGN);
+        else
+            stop (ChessResult.WHITE_WON, ChessRule.RESIGN);
+
+        return true;
+    }
+
+    private bool claim_draw_cb (ChessPlayer player)
+    {
+        if (!is_started)
+            return false;
+
+        // FIXME: Check if can
+
+        stop (ChessResult.DRAW, ChessRule.FIFTY_MOVES);
+
+        return true;
+    }
+
+    public void start ()
+    {
+        if (is_started)
+            return;
+        is_started = true;
+
+        reset ();
+
+        started ();
+        current_player.start_turn ();
+        turn_started (current_player);
+    }
+    
+    public void abandon ()
+    {
+        if (!is_started)
+            return;
+        stop (ChessResult.DRAW, ChessRule.ABANDONMENT);
+    }
+    
+    public ChessPiece? get_piece (int rank, int file, int move_number = -1)
+    {
+        if (move_number < 0)
+            move_number += (int) move_stack.length ();
+
+        var state = move_stack.nth_data (move_stack.length () - move_number - 1);
+    
+        return state.board[rank, file];
+    }
+
+    public uint n_moves
+    {
+        get { return move_stack.length() - 1; }
+    }
+
+    private void reset ()
+    {
+        result = ChessResult.IN_PROGRESS;
+        var state = move_stack.data;
+        move_stack = null;
+        move_stack.prepend (state);
+    }
+
+    private void stop (ChessResult result, ChessRule rule)
+    {
+        this.result = result;
+        this.rule = rule;
+        is_started = false;
+        ended ();
+    }
+}
diff --git a/glchess/src/chess-pgn.vala b/glchess/src/chess-pgn.vala
new file mode 100644
index 0000000..d805dc5
--- /dev/null
+++ b/glchess/src/chess-pgn.vala
@@ -0,0 +1,351 @@
+private int str_index (string name)
+{
+    if (name == "Event")
+        return 0;
+    else if (name == "Site")
+        return 1;
+    else if (name == "Date")
+        return 2;
+    else if (name == "Round")
+        return 3;
+    else if (name == "White")
+        return 4;
+    else if (name == "Black")
+        return 5;
+    else if (name == "Result")
+        return 6;
+    else
+        return 7;
+}
+
+private int compare_tag (string name0, string name1)
+{
+    int str_index0 = str_index (name0);
+    int str_index1 = str_index (name1);
+
+    /* If both not in STR then just order alphabetically */
+    if (str_index0 == 7 && str_index1 == 7)
+        return strcmp (name0, name1);
+    else
+        return str_index0 - str_index1;
+}
+
+public class PGNGame
+{
+    public GLib.HashTable<string, string> tags;
+    public GLib.List<string> moves;
+
+    public string event
+    {
+        get { return tags.lookup ("Event"); }
+        set { tags.insert ("Event", value); }
+    }
+    public string site
+    {
+        get { return tags.lookup ("Site"); }
+        set { tags.insert ("Site", value); }
+    }
+    public string date
+    {
+        get { return tags.lookup ("Date"); }
+        set { tags.insert ("Date", value); }
+    }
+    public string round
+    {
+        get { return tags.lookup ("Round"); }
+        set { tags.insert ("Round", value); }
+    }
+    public string white
+    {
+        get { return tags.lookup ("White"); }
+        set { tags.insert ("White", value); }
+    }
+    public string black
+    {
+        get { return tags.lookup ("Black"); }
+        set { tags.insert ("Black", value); }
+    }
+    public string result
+    {
+        get { return tags.lookup ("Result"); }
+        set { tags.insert ("Result", value); }
+    }
+
+    public PGNGame ()
+    {
+        tags = new GLib.HashTable<string, string> (str_hash, str_equal);
+        tags.insert ("Event", "?");
+        tags.insert ("Site", "?");
+        tags.insert ("Date", "????.??.??");
+        tags.insert ("Round", "?");
+        tags.insert ("White", "?");
+        tags.insert ("Black", "?");
+        tags.insert ("Result", "*");
+    }
+
+    public void write (OutputStream stream) throws GLib.Error
+    {
+        // FIXME: Escape \ and " in tag values
+        var keys = tags.get_keys ();
+        keys.sort ((GLib.CompareFunc) compare_tag);
+        foreach (var key in keys)
+            write_string (stream, "[%s \"%s\"]\n".printf (key, tags.lookup (key)));
+        write_string (stream, "\n");
+
+        int i = 0;
+        foreach (string move in moves)
+        {
+            if (i % 2 == 0)
+                write_string (stream, "%d. ".printf (i / 2 + 1));
+            write_string (stream, move);
+            write_string (stream, " ");
+            i++;
+        }
+        write_string (stream, result);
+        write_string (stream, "\n");
+    }
+
+    private void write_string (OutputStream stream, string value) throws GLib.Error
+    {
+        stream.write_all ((uint8[]) value, null);
+    }
+}
+
+enum State
+{
+    IDLE,
+    LINE_COMMENT,
+    BRACE_COMMENT,
+    TAG_START,
+    TAG_NAME,
+    PRE_TAG_VALUE,
+    TAG_VALUE,
+    POST_TAG_VALUE,
+    SYMBOL,
+    NAG,
+    ERROR
+}
+
+public class PGN
+{
+    public GLib.List<PGNGame> games;
+
+    public PGN ()
+    {
+    }
+
+    public PGN.from_file (GLib.File file) throws GLib.Error
+    {
+        string contents;
+        size_t n_read;
+        file.load_contents (null, out contents, out n_read);
+        
+        // FIXME: Feed through newline at end to make sure parsing complete
+       
+        State state = State.IDLE;
+        PGNGame game = new PGNGame ();
+        bool in_escape = false;
+        size_t token_start = 0, line_offset = 0;
+        string tag_name = "";
+        StringBuilder tag_value = new StringBuilder ();
+        int line = 1;
+        bool have_tags = false;
+        int rav_level = 0;
+        for (size_t offset = 0; offset < contents.length; offset++)
+        {
+            unichar c = contents[(long) offset];
+            
+            if (c == '\n')
+            {
+               line++;
+               line_offset = offset + 1;
+            }
+            
+            switch (state)
+            {
+            case State.IDLE:
+                if (c.isspace ())
+                    ;//
+                else if (c == ';')
+                    state = State.LINE_COMMENT;
+                else if (c == '{')
+                    state = State.BRACE_COMMENT;
+                else if (c == '[')
+                {
+                    have_tags = true;
+                    state = State.TAG_START;
+                }
+                else if (have_tags && c == '*')
+                {
+                    if (rav_level == 0)
+                    {
+                        game.result = "*";
+                        games.append (game);
+                        game = new PGNGame ();
+                        have_tags = false;
+                    }
+                    state = State.IDLE;
+                }
+                else if (have_tags && c == '.')
+                    continue;
+                else if (have_tags && c.isalnum ())
+                {
+                    token_start = offset;
+                    state = State.SYMBOL;
+                }
+                else if (have_tags && c == '$')
+                {
+                    token_start = offset + 1;
+                    state = State.NAG;
+                }
+                else if (have_tags && c == '(')
+                {
+                    rav_level++;
+                    continue;
+                }
+                else if (have_tags && c == ')')
+                {
+                    if (rav_level == 0)
+                        state = State.ERROR;
+                    else
+                        rav_level--;
+                }
+                else
+                    state = State.ERROR;
+                break;
+
+            case State.LINE_COMMENT:
+                if (c == '\n')
+                    state = State.IDLE;
+                break;
+
+            case State.BRACE_COMMENT:
+                if (c == '}')
+                    state = State.IDLE;
+                break;
+
+            case State.TAG_START:
+                if (c.isspace ())
+                    continue;
+                else if (c.isalnum())
+                {
+                    token_start = offset;
+                    state = State.TAG_NAME;
+                }
+                else
+                    state = State.ERROR;
+                break;
+
+            case State.TAG_NAME:
+                if (c.isspace ())
+                {
+                    tag_name = contents[(long)token_start:(long)offset];
+                    state = State.PRE_TAG_VALUE;
+                }
+                else if (c.isalnum() || c == '_' || c == '+' || c == '#' || c == '=' || c == ':' || c == '-')
+                    continue;
+                else
+                    state = State.ERROR;
+                break;
+
+            case State.PRE_TAG_VALUE:
+                if (c.isspace ())
+                    continue;
+                else if (c == '"')
+                {
+                    state = State.TAG_VALUE;
+                    tag_value.erase ();
+                    in_escape = false;
+                }
+                else
+                    state = State.ERROR;
+                break;
+
+            case State.TAG_VALUE:
+                if (c == '\\' && !in_escape)
+                    in_escape = true;
+                else if (c == '"' && !in_escape)
+                    state = State.POST_TAG_VALUE;
+                else if (c.isprint ())
+                {
+                    tag_value.append_unichar (c);
+                    in_escape = false;
+                }
+                else
+                    state = State.ERROR;
+                break;
+
+            case State.POST_TAG_VALUE:
+                if (c.isspace ())
+                    continue;
+                else if (c == ']')
+                {
+                    game.tags.insert (tag_name, tag_value.str);
+                    state = State.IDLE;
+                }
+                else
+                    state = State.ERROR;
+                break;
+
+            case State.SYMBOL:
+                /* NOTE: '/' not in spec but required for 1/2-1/2 symbol */
+                if (c.isalnum () || c == '_' || c == '+' || c == '#' || c == '=' || c == ':' || c == '-' || c == '/')
+                    continue;
+                else
+                {
+                    string symbol = contents[(long)token_start:(long)offset];
+
+                    bool is_number = true;
+                    for (int i = 0; i < symbol.length; i++)
+                       if (!symbol[i].isdigit ())
+                           is_number = false;
+
+                    /* Game termination markers */
+                    if (symbol == "1/2-1/2" || symbol == "1-0" || symbol == "0-1")
+                    {
+                        if (rav_level == 0)
+                        {
+                            game.result = symbol;
+                            games.append (game);
+                            game = new PGNGame ();
+                            have_tags = false;
+                        }
+                    }
+                    else if (!is_number)
+                    {
+                        if (rav_level == 0)
+                            game.moves.append (symbol);
+                    }
+
+                    state = State.IDLE;
+                    offset--;
+                }
+                break;
+
+            case State.NAG:
+                if (c.isdigit ())
+                    continue;
+                else
+                {
+                    //string nag = contents[(long)token_start:(long)offset];
+                    //stdout.printf ("nag = '%s'\n", nag);
+                    state = State.IDLE;
+                    offset--;
+                }
+                break;
+
+            case State.ERROR:
+                size_t char_offset = offset - line_offset - 1;
+                var filename = file.get_path ();
+                if (filename == null)
+                    filename = file.get_uri ();
+                stderr.printf ("%s:%d.%d: error: Unexpected character\n", filename, line, (int) (char_offset + 1));
+                stderr.printf ("%s\n", contents[(long)line_offset:(long)offset]);
+                for (int i = 0; i < char_offset; i++)
+                    stderr.printf (" ");
+                stderr.printf ("^\n");
+                return;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/glchess/src/chess-view-2d.vala b/glchess/src/chess-view-2d.vala
new file mode 100644
index 0000000..5a9e375
--- /dev/null
+++ b/glchess/src/chess-view-2d.vala
@@ -0,0 +1,212 @@
+private class ChessView2D : ChessView
+{
+    private int border = 6;
+    private double square_size;
+    
+    private double border_size
+    {
+        get { return square_size / 2; }
+    }
+    
+    public ChessView2D ()
+    {
+        add_events (Gdk.EventMask.BUTTON_PRESS_MASK);
+    }
+
+    public override bool configure_event (Gdk.EventConfigure event)
+    {
+        int short_edge = int.min (get_allocated_width (), get_allocated_height ());
+            
+        square_size = (int) Math.floor ((short_edge - 2 * border) / 9.0);
+
+        return true;
+    }
+
+    public override bool draw (Cairo.Context c)
+    {
+        c.translate (get_allocated_width () / 2, get_allocated_height () / 2);
+        //c.scale (s, s);
+        //c.rotate (angle);
+
+        int bord_size = (int) Math.ceil (square_size * 4 + border_size);
+        c.set_source_rgb (0x2e/255.0, 0x34/255.0, 0x36/255.0);
+        c.rectangle (-bord_size, -bord_size, bord_size * 2, bord_size * 2);
+        c.fill ();
+
+        var selected_piece = options.get_selected_piece ();
+
+        for (int file = 0; file < 8; file++)
+        {
+            for (int rank = 0; rank < 8; rank++)
+            {
+                int x = (int) ((file - 4) * square_size);
+                int y = (int) ((3 - rank) * square_size);
+                
+                bool selected = false;
+                bool hinted = false;
+                if (options.move_number == -1 && options.selected_rank == rank && options.selected_file == file)
+                    selected = true;
+                else if (options.move_number == -1 && options.show_move_hints && selected_piece != null && selected_piece.player.move_with_coords (options.selected_rank, options.selected_file, rank, file, false))
+                    hinted = true;
+
+                c.rectangle (x, y, square_size, square_size);
+                if ((file + rank) % 2 == 0)
+                {
+                    if (selected)
+                        c.set_source_rgb (0x73/255.0, 0xd2/255.0, 0x16/255.0);
+                    else if (hinted)
+                        c.set_source_rgb (0x34/255.0, 0x65/255.0, 0xa4/255.0);
+                    else
+                        c.set_source_rgb (0xba/255.0, 0xbd/255.0, 0xb6/255.0);
+                }
+                else
+                {
+                    if (selected)
+                        c.set_source_rgb (0x8a/255.0, 0xe2/255.0, 0x34/255.0);
+                    else if (hinted)
+                        c.set_source_rgb (0x20/255.0, 0x4a/255.0, 0x87/255.0);
+                    else
+                        c.set_source_rgb (0xee/255.0, 0xee/255.0, 0xec/255.0);
+                }
+                c.fill ();
+            }
+        }
+
+        if (options.show_numbering)
+        {
+            string[] files = { "a", "b", "c", "d", "e", "f", "g", "h" };
+            string[] ranks = { "1", "2", "3", "4", "5", "6", "7", "8" };
+
+            /* Files are centered individiual glyph width and combined glyph height,
+             * ranks are centered on individual glyph widths and heights */
+
+            c.set_source_rgb (0x88/255.0, 0x8a/255.0, 0x85/255.0);
+            c.set_font_size (border_size * 0.6);
+            c.select_font_face ("sans-serif", Cairo.FontSlant.NORMAL, Cairo.FontWeight.BOLD);
+
+            Cairo.TextExtents extents;
+            c.text_extents ("abcdefgh", out extents);
+            double y_offset = (square_size / 2 - extents.height) / 2 + extents.height + extents.y_bearing;
+            double top = -(square_size * 4 + y_offset);
+            double bottom = square_size * 4 + border_size - y_offset;
+
+            double file_offset = -(square_size * 3.5);
+            double rank_offset = -(square_size * 3.5);
+
+            for (int i = 0; i < 8; i++)
+            {
+                c.text_extents (ranks[i], out extents);
+
+                /* Black file */
+                c.save ();
+                c.move_to (file_offset - extents.width / 2, top);
+                c.show_text (files[i]);
+                c.restore ();
+
+                /* White file */
+                c.save ();
+                c.move_to (file_offset - extents.width / 2, bottom);
+                c.show_text (files[i]);
+                c.restore ();
+
+                c.text_extents (ranks[i], out extents);
+                y_offset = -(extents.y_bearing + extents.height / 2);
+
+                /* Left rank */
+                c.save ();
+                c.move_to (-((double) square_size * 4 + border_size - (border_size - extents.width) / 2), rank_offset + y_offset);
+                c.show_text (ranks[i]);
+                c.restore ();
+
+                /* Right rank */
+                c.save ();
+                c.move_to ((double) square_size * 4 + (border_size - extents.width) / 2, rank_offset + y_offset);
+                c.show_text (ranks[i]);
+                c.restore ();
+
+                file_offset += square_size;
+                rank_offset += square_size;
+            }
+        }
+
+        if (options.game == null)
+            return true;
+
+        for (int rank = 0; rank < 8; rank++)
+        {
+            for (int file = 0; file < 8; file++)
+            {
+                ChessPiece? piece = options.game.get_piece (rank, file, options.move_number);
+                if (piece == null)
+                    continue;
+
+                string file_name = "";
+                switch (piece.player.color)
+                {
+                case Color.WHITE:
+                    file_name += "white";
+                    break;
+                case Color.BLACK:
+                    file_name += "black";
+                    break;
+                }
+                switch (piece.type)
+                {
+                case PieceType.PAWN:
+                    file_name += "Pawn";
+                    break;
+                case PieceType.ROOK:
+                    file_name += "Rook";
+                    break;
+                case PieceType.KNIGHT:
+                    file_name += "Knight";
+                    break;
+                case PieceType.BISHOP:
+                    file_name += "Bishop";
+                    break;
+                case PieceType.QUEEN:
+                    file_name += "Queen";
+                    break;
+                case PieceType.KING:
+                    file_name += "King";
+                    break;
+                }
+
+                Rsvg.Handle handle;
+                try
+                {
+                    handle = new Rsvg.Handle.from_file ("data/pieces/" + options.theme_name + "/" + file_name + ".svg");
+                }
+                catch (GLib.Error e)
+                {
+                    stderr.printf ("Failed to load piece svg: %s", e.message);
+                    handle = null;
+                }
+                c.save ();
+                c.translate ((file - 4) * square_size, (3 - rank) * square_size);
+                c.scale ((double) square_size / handle.width, (double) square_size / handle.height);
+                c.set_source_rgb (0, 0, 0);
+                handle.render_cairo (c);
+                c.restore ();
+            }
+        }
+
+        return true;
+    }
+
+    public override bool button_press_event (Gdk.EventButton event)
+    {
+        if (options.game == null || event.button != 1)
+            return false;
+
+        int file = (int) Math.floor((event.x - 0.5 * get_allocated_width () + square_size * 4) / square_size);
+        int rank = 7 - (int) Math.floor((event.y - 0.5 * get_allocated_height () + square_size * 4) / square_size);
+        
+        if (file < 0 || file >= 8 || rank < 0 || rank >= 8)
+            return false;
+
+        options.select_square (file, rank);
+
+        return true;
+    }
+}
diff --git a/glchess/src/chess-view-3d.vala b/glchess/src/chess-view-3d.vala
new file mode 100644
index 0000000..9235640
--- /dev/null
+++ b/glchess/src/chess-view-3d.vala
@@ -0,0 +1,392 @@
+using GL;
+using GLU;
+
+private class ChessView3D : ChessView
+{
+    private int border = 6;
+    private int square_size;
+    private TDSModel pawn_model;
+    private TDSModel knight_model;
+    private TDSModel bishop_model;
+    private TDSModel rook_model;
+    private TDSModel queen_model;
+    private TDSModel king_model;
+    private GLfloat[] board_vertices;
+    private GLushort[] board_quads;
+
+    private GLfloat SQUARE_WIDTH;
+    private GLfloat BOARD_DEPTH;
+    private GLfloat BOARD_BORDER;
+    private GLfloat BOARD_CHAMFER;
+    private GLfloat BOARD_INNER_WIDTH;
+    private GLfloat BOARD_OUTER_WIDTH;
+    private GLfloat OFFSET;
+
+    public ChessView3D ()
+    {
+        SQUARE_WIDTH = 10.0f;
+        BOARD_DEPTH = 3.0f;
+        BOARD_BORDER = 5.0f;
+        BOARD_CHAMFER = 2.0f;
+        BOARD_INNER_WIDTH = (SQUARE_WIDTH * 8.0f);
+        BOARD_OUTER_WIDTH = (BOARD_INNER_WIDTH + BOARD_BORDER * 2.0f);
+        OFFSET            = (BOARD_OUTER_WIDTH * 0.5f);
+
+        add_events (Gdk.EventMask.BUTTON_PRESS_MASK);
+        var gl_config = new Gdk.GLConfig.by_mode (Gdk.GLConfigMode.RGB | Gdk.GLConfigMode.DEPTH | Gdk.GLConfigMode.DOUBLE | Gdk.GLConfigMode.ACCUM);
+        Gtk.WidgetGL.set_gl_capability (this, gl_config, null, true, Gdk.GLRenderType.RGBA_TYPE);
+        try
+        {
+            pawn_model = new TDSModel (File.new_for_path ("data/pawn.3ds"));
+            knight_model = new TDSModel (File.new_for_path ("data/knight.3ds"));
+            bishop_model = new TDSModel (File.new_for_path ("data/bishop.3ds"));
+            rook_model = new TDSModel (File.new_for_path ("data/rook.3ds"));
+            queen_model = new TDSModel (File.new_for_path ("data/queen.3ds"));
+            king_model = new TDSModel (File.new_for_path ("data/king.3ds"));
+        }
+        catch (GLib.Error e)
+        {
+        }
+        create_board ();
+    }
+    
+    private void create_board ()
+    {
+        /* Board vertices
+         * (lower 12-15 are under 8-11)
+         *
+         * a b c         d e f
+         *
+         * 8-----------------9  g
+         * |\               /|
+         * | 4-------------5 |  h
+         * | |             | |
+         * | | 0---------1 | |  i
+         * | | |         | | |
+         * | | |         | | |
+         * | | 3---------2 | |  j
+         * | |             | |
+         * | 7-------------6 |  k
+         * |/               \|
+         * 11---------------10  l
+         *
+         *     |- board -|
+         *        width
+         */
+        var a = 0.0f;
+        var b = BOARD_CHAMFER;
+        var c = BOARD_BORDER;
+        var d = c + (SQUARE_WIDTH * 8.0f);
+        var e = d + BOARD_BORDER - BOARD_CHAMFER;
+        var f = d + BOARD_BORDER;
+        var l = 0.0f;
+        var k = -BOARD_CHAMFER;
+        var j = -BOARD_BORDER;
+        var i = j - (SQUARE_WIDTH * 8.0f);
+        var h = i - BOARD_BORDER + BOARD_CHAMFER;
+        var g = i - BOARD_BORDER;
+        board_vertices = {c, 0.0f, i,  d, 0.0f, i,
+                          d, 0.0f, j,  c, 0.0f, j,
+                          b, 0.0f, h,  e, 0.0f, h,
+                          e, 0.0f, k,  b, 0.0f, k,
+                          a, -BOARD_CHAMFER, g,  f, -BOARD_CHAMFER, g,
+                          f, -BOARD_CHAMFER, l,  a, -BOARD_CHAMFER, l,
+                          a, -BOARD_DEPTH, g,  f, -BOARD_DEPTH, g,  f, -BOARD_DEPTH, l,  a, -BOARD_DEPTH, l};
+        board_quads = {0, 1, 5, 4,  0, 4, 7, 3,  3, 7, 6, 2,  2, 6, 5, 1,
+                      4, 5, 9, 8,  4, 8, 11, 7,  7, 11, 10, 6,  6, 10, 9, 5};
+    }
+
+    public override bool configure_event (Gdk.EventConfigure event)
+    {
+        int short_edge = int.min (allocation.width, allocation.height);
+
+        square_size = (int) Math.floor ((short_edge - 2 * border) / 9.0);
+
+        var drawable = Gtk.WidgetGL.get_gl_drawable (this);
+        if (drawable.gl_begin (Gtk.WidgetGL.get_gl_context (this)))
+        {
+            glViewport (0, 0, (GLsizei) allocation.width, (GLsizei) allocation.height);
+            drawable.gl_end ();
+        }
+
+        return true;
+    }
+
+    private void accFrustum (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far,
+                             GLfloat pixdx, GLfloat pixdy, GLfloat eyedx, GLfloat eyedy, GLfloat focus)
+    {
+        var xwsize = right - left;
+        var ywsize = top - bottom;
+        var dx = -(pixdx * xwsize / allocation.width + eyedx * near/focus);
+        var dy = -(pixdy * ywsize / allocation.height + eyedy * near/focus);
+
+        glFrustum (left + dx, right + dx, bottom + dy, top + dy, near, far);
+        glTranslatef (-eyedx, -eyedy, 0.0f);
+    }
+
+    private void accPerspective (GLfloat fovy, GLfloat aspect,
+                                 GLfloat near, GLfloat far,
+                                 GLfloat pixdx, GLfloat pixdy,
+                                 GLfloat eyedx, GLfloat eyedy, GLfloat focus)
+    {
+        var fov2 = ((fovy * (GLfloat) Math.PI) / 180.0f) / 2.0f;
+        var top = near / ((GLfloat) Math.cos (fov2) / (GLfloat) Math.sin (fov2));
+        var bottom = -top;
+        var right = top * aspect;
+        var left = -right;
+        accFrustum (left, right, bottom, top, near, far, pixdx, pixdy, eyedx, eyedy, focus);
+    }
+
+    public override bool draw (Cairo.Context c)
+    {
+        var drawable = Gtk.WidgetGL.get_gl_drawable (this);
+        GLfloat[] jitters = {0.0033922635f, 0.3317967229f, 0.2806016275f, -0.2495619123f, -0.273817106f, -0.086844639f};
+
+        if (!drawable.gl_begin (Gtk.WidgetGL.get_gl_context (this)))
+            return true;
+
+        var n_passes = 1;
+        if (options.show_3d_smooth)
+        {
+            glClear (GL_ACCUM_BUFFER_BIT);
+            n_passes = 3;
+        }
+
+        for (var i = 0; i < n_passes; i++)
+        {
+            var bg = style.bg[state];
+            glClearColor (bg.red / 65535.0f, bg.green / 65535.0f, bg.blue / 65535.0f, 1.0f);
+            glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+            glEnable (GL_DEPTH_TEST);
+
+            glMatrixMode (GL_PROJECTION);
+            glLoadIdentity ();
+            if (options.show_3d_smooth)
+                accPerspective (60.0f, (float) allocation.width / allocation.height, 0.1f, 1000, jitters[i*2], jitters[i*2+1], 0, 0, 1);
+            else
+                gluPerspective (60.0f, (float) allocation.width / allocation.height, 0.1f, 1000);
+
+            glMatrixMode(GL_MODELVIEW);
+            transform_camera ();
+
+            GLfloat[] pos = { 100.0f, 100.0f, 100.0f, 1.0f };
+            glLightfv (GL_LIGHT0, GL_POSITION, pos);
+            glEnable (GL_LIGHTING);
+            glEnable (GL_LIGHT0);
+
+            draw_board ();
+            draw_pieces ();
+
+            if (options.show_3d_smooth)
+                glAccum (GL_ACCUM, 1.0f / n_passes);
+        }
+
+        if (options.show_3d_smooth)
+            glAccum (GL_RETURN, 1);
+
+        if (drawable.is_double_buffered ())
+            drawable.swap_buffers ();
+        else
+            glFlush ();
+
+        drawable.gl_end ();
+
+        return true;
+    }
+
+    private void draw_board ()
+    {
+        glPushMatrix ();
+        glTranslatef(-OFFSET, 0.0f, OFFSET);
+
+        glEnable (GL_COLOR_MATERIAL);
+        glColor3f (0x2e / 255f, 0x34 / 255f, 0x36 / 255f);
+        glNormal3f (0.0f, 1.0f, 0.0f);
+        glEnableClientState (GL_VERTEX_ARRAY);
+        glVertexPointer (3, GL_FLOAT, 0, board_vertices);
+        glDrawElements (GL_QUADS, (GLsizei) board_quads.length, GL_UNSIGNED_SHORT, board_quads);
+        glDisableClientState (GL_VERTEX_ARRAY);
+
+        var selected_piece = options.get_selected_piece ();
+
+        glNormal3f (0.0f, 1.0f, 0.0f);
+        for (var rank = 0; rank < 8; rank++)
+            for (var file = 0; file < 8; file++)
+            {
+                bool selected = false;
+                bool hinted = false;
+                if (options.move_number == -1 && options.selected_rank == rank && options.selected_file == file)
+                    selected = true;
+                else if (options.move_number == -1 && options.show_move_hints && selected_piece != null && selected_piece.player.move_with_coords (options.selected_rank, options.selected_file, rank, file, false))
+                    hinted = true;
+
+                if ((file + rank) % 2 == 0)
+                {
+                    if (selected)
+                        glColor3f (0x73 / 255f, 0xd2 / 255f, 0x16 / 255f);
+                    else if (hinted)
+                        glColor3f (0x34 / 255f, 0x65 / 255f, 0xa4 / 255f);
+                    else
+                        glColor3f (0xee / 255f, 0xee / 255f, 0xec / 255f);
+                }
+                else
+                {
+                    if (selected)
+                        glColor3f (0x8a / 255f, 0xe2 / 255f, 0x34 / 255f);
+                    else if (hinted)
+                        glColor3f (0x20 / 255f, 0x4a / 255f, 0x87 / 255f);
+                    else
+                        glColor3f (0xba / 255f, 0xbd / 255f, 0xb6 / 255f);
+                }
+
+                glBegin (GL_QUADS);
+                GLfloat x0 = BOARD_BORDER + (file * SQUARE_WIDTH);
+                GLfloat x1 = x0 + SQUARE_WIDTH;
+                GLfloat z0 = BOARD_BORDER + (rank * SQUARE_WIDTH);
+                GLfloat z1 = z0 + SQUARE_WIDTH;
+
+                glVertex3f(x0, 0.0f, -z0);
+                glVertex3f(x1, 0.0f, -z0);
+                glVertex3f(x1, 0.0f, -z1);
+                glVertex3f(x0, 0.0f, -z1);
+                glEnd ();
+            }
+        glDisable (GL_COLOR_MATERIAL);
+        glPopMatrix ();
+    }
+    
+    private void draw_pieces ()
+    {
+        if (options.game == null)
+            return;
+
+        glEnable (GL_COLOR_MATERIAL);
+        for (int rank = 0; rank < 8; rank++)
+        {
+            for (int file = 0; file < 8; file++)
+            {
+                ChessPiece? piece = options.game.get_piece (rank, file, options.move_number);
+                if (piece == null)
+                    continue;
+
+                switch (piece.player.color)
+                {
+                case Color.WHITE:
+                    glColor3f (0.8f, 0.8f, 0.8f);
+                    break;
+                case Color.BLACK:
+                    glColor3f (0.2f, 0.2f, 0.2f);
+                    break;
+                }
+
+                glPushMatrix ();
+                glTranslatef ((file - 4) * SQUARE_WIDTH + SQUARE_WIDTH / 2, 0.0f, (4 - rank) * SQUARE_WIDTH - SQUARE_WIDTH / 2);
+
+                switch (piece.type)
+                {
+                case PieceType.PAWN:
+                    pawn_model.render ();
+                    break;
+                case PieceType.ROOK:
+                    rook_model.render ();
+                    break;
+                case PieceType.KNIGHT:
+                    knight_model.render ();
+                    break;
+                case PieceType.BISHOP:
+                    bishop_model.render ();
+                    break;
+                case PieceType.QUEEN:
+                    queen_model.render ();
+                    break;
+                case PieceType.KING:
+                    king_model.render ();
+                    break;
+                }
+
+                glPopMatrix ();
+            }
+        }
+
+        glDisable (GL_COLOR_MATERIAL);
+    }
+
+    public override bool button_press_event (Gdk.EventButton event)
+    {
+        if (options.game == null || event.button != 1)
+            return false;
+
+        var drawable = Gtk.WidgetGL.get_gl_drawable (this);
+
+        if (!drawable.gl_begin (Gtk.WidgetGL.get_gl_context (this)))
+            return true;
+
+        /* Don't render to screen, just select */
+        GLuint buffer[20];
+        glSelectBuffer((GLsizei) buffer.length, buffer);
+        glRenderMode(GL_SELECT);
+
+        glInitNames();
+
+        /* Create pixel picking region near cursor location */
+        glMatrixMode(GL_PROJECTION);
+        glLoadIdentity();
+        GLint[] viewport = {0, 0, (GLint) allocation.width, (GLint) allocation.height};
+        gluPickMatrix(event.x, ((float) allocation.height - event.y), 1.0, 1.0, viewport);
+        gluPerspective(60.0, (float) allocation.width / (float) allocation.height, 0, 1);
+
+        /* Draw the squares that can be selected */
+        glMatrixMode(GL_MODELVIEW);
+        glLoadIdentity();
+        transform_camera();
+        glTranslatef(-OFFSET, 0.0f, OFFSET);
+        for (var rank = 0; rank < 8; rank++)
+        {
+            glPushName(rank);
+
+            for (var file = 0; file < 8; file++)
+            {
+                glPushName(file);
+
+                glBegin(GL_QUADS);
+                var x0 = BOARD_BORDER + (file * SQUARE_WIDTH);
+                var x1 = x0 + SQUARE_WIDTH;
+                var z0 = BOARD_BORDER + (rank * SQUARE_WIDTH);
+                var z1 = z0 + SQUARE_WIDTH;
+
+                glVertex3f(x0, 0.0f, -z0);
+                glVertex3f(x1, 0.0f, -z0);
+                glVertex3f(x1, 0.0f, -z1);
+                glVertex3f(x0, 0.0f, -z1);
+                glEnd();
+
+                glPopName();
+            }
+            glPopName();
+        }
+
+        /* Render and check for hits */
+        glFlush();
+        var n_hits = glRenderMode(GL_RENDER);
+
+        if (n_hits > 0)
+        {
+            var rank = buffer[3];
+            var file = buffer[4];
+            options.select_square (file, rank);
+        }
+
+        drawable.gl_end ();
+
+        return true;
+    }
+
+    private void transform_camera ()
+    {
+        glLoadIdentity();
+        gluLookAt(0.0, 80.0, 40.0,
+                  0.0,  0.0, 5.0,
+                  0.0,  1.0,  0.0);
+    }
+}
diff --git a/glchess/src/chess-view-options.vala b/glchess/src/chess-view-options.vala
new file mode 100644
index 0000000..7128b9b
--- /dev/null
+++ b/glchess/src/chess-view-options.vala
@@ -0,0 +1,107 @@
+public class ChessViewOptions : GLib.Object
+{
+    public signal void changed ();
+
+    public int selected_rank = -1;
+    public int selected_file = -1;
+
+    private ChessGame? _game = null;
+    public ChessGame? game
+    {
+        get { return _game; }
+        set
+        {
+            _game = value;
+            selected_rank = -1;
+            selected_file = -1;
+            changed ();
+        }
+    }
+
+    public ChessPiece? get_selected_piece ()
+    {
+        if (game != null && selected_rank >= 0)
+            return game.get_piece (selected_rank, selected_file, move_number);
+        return null;
+    }
+
+    private int _move_number = -1;
+    public int move_number
+    {
+        get { return _move_number; }
+        set
+        {
+            if (_move_number == value)
+                return;
+            _move_number = value;
+            changed ();
+        }
+    }
+
+    private bool _show_numbering = true;
+    public bool show_numbering
+    {
+        get { return _show_numbering; }
+        set { _show_numbering = value; changed (); }
+    }
+
+    private bool _show_move_hints = true;
+    public bool show_move_hints
+    {
+        get { return _show_move_hints; }
+        set { _show_move_hints = value; changed (); }
+    }
+
+    private string _theme_name = "simple";
+    public string theme_name
+    {
+       get { return _theme_name; }
+       set { _theme_name = value; changed (); }
+    }
+
+    private bool _show_3d_smooth = false;
+    public bool show_3d_smooth
+    {
+       get { return _show_3d_smooth; }
+       set { _show_3d_smooth = value; changed (); }
+    }
+
+    private string _move_format = "human";
+    public string move_format
+    {
+       get { return _move_format; }
+       set { _move_format = value; changed (); }
+    }
+
+    public void select_square (int file, int rank)
+    {
+        if (game == null)
+            return;
+
+        /* Can only control when showing the current move */
+        if (move_number != -1)
+            return;
+
+        ChessPiece? piece = game.get_piece (rank, file, move_number);
+
+        /* Deselect by clicking on the same square */
+        if (file == selected_file && rank == selected_rank)
+        {
+            selected_rank = selected_file = -1;
+        }
+        /* Select new piece */
+        else if (piece != null && piece.player == game.current_player)
+        {
+            selected_rank = rank;
+            selected_file = file;
+        }
+        /* Move to this square */
+        else if (selected_file != -1)
+        {
+            if (game.current_player.move_with_coords(selected_rank, selected_file, rank, file))
+                selected_rank = selected_file = -1;            
+        }
+
+        changed ();
+    }
+}
diff --git a/glchess/src/chess-view.vala b/glchess/src/chess-view.vala
new file mode 100644
index 0000000..2c617f5
--- /dev/null
+++ b/glchess/src/chess-view.vala
@@ -0,0 +1,19 @@
+public class ChessView : Gtk.DrawingArea
+{
+    private ChessViewOptions _options;
+    public ChessViewOptions options
+    {
+        get { return _options; }
+        set
+        {
+            _options = value;
+            _options.changed.connect (options_changed_cb);
+            queue_draw ();
+        }
+    }
+
+    private void options_changed_cb (ChessViewOptions options)
+    {
+        queue_draw ();
+    }
+}
diff --git a/glchess/src/gl.vapi b/glchess/src/gl.vapi
new file mode 100644
index 0000000..e8a8327
--- /dev/null
+++ b/glchess/src/gl.vapi
@@ -0,0 +1,1402 @@
+/* gl.vapi
+ *
+ * Copyright (C) 2008  Matias De la Puente
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Matias De la Puente <mfpuente ar gmail com>
+ */
+ 
+[CCode (lower_case_cprefix ="", cheader_filename="GL/gl.h")]
+namespace GL
+{
+	[CCode (cname="GLenum")]
+	public struct GLenum : uint { }
+	[CCode (cname="GLboolean")]
+	public struct GLboolean : bool { }
+	[CCode (cname="GLbitfield")]
+	public struct GLbitfield : uint { }
+	[CCode (cname="GLvoid")]
+	public struct GLvoid { }
+	[CCode (cname="GLbyte")]
+	public struct GLbyte : char { }
+	[CCode (cname="GLshort")]
+	public struct GLshort : short { }
+	[CCode (cname="GLint")]
+	public struct GLint : int { }
+	[CCode (cname="GLubyte")]
+	public struct GLubyte : uchar { }
+	[CCode (cname="GLushort")]
+	public struct GLushort : ushort { }
+	[CCode (cname="GLuint")]
+	public struct GLuint : uint { }
+	[CCode (cname="GLsizei")]
+	public struct GLsizei : int { }
+	[CCode (cname="GLfloat")]
+	[FloatingType (rank = 1)]
+	public struct GLfloat : float { }
+	[CCode (cname="GLclampf")]
+	[FloatingType (rank = 1)]
+	public struct GLclampf : float { }
+	[CCode (cname="GLdouble")]
+	[FloatingType (rank = 2)]
+	public struct GLdouble : double { }
+	[CCode (cname="GLclampd")]
+	[FloatingType (rank = 2)]
+	public struct GLclampd : double { }
+	
+	
+	// Data Types
+	public const GLenum GL_BYTE;
+	public const GLenum GL_UNSIGNED_BYTE;
+	public const GLenum GL_SHORT;
+	public const GLenum GL_UNSIGNED_SHORT;
+	public const GLenum GL_INT;
+	public const GLenum GL_UNSIGNED_INT;
+	public const GLenum GL_FLOAT;
+	public const GLenum GL_2_BYTES;
+	public const GLenum GL_3_BYTES;
+	public const GLenum GL_4_BYTES;
+	public const GLenum GL_DOUBLE;
+	
+	// Primitives
+	public const GLenum GL_POINTS;
+	public const GLenum GL_LINES;
+	public const GLenum GL_LINE_LOOP;
+	public const GLenum GL_LINE_STRIP;
+	public const GLenum GL_TRIANGLES;
+	public const GLenum GL_TRIANGLE_STRIP;
+	public const GLenum GL_TRIANGLE_FAN;
+	public const GLenum GL_QUADS;
+	public const GLenum GL_QUAD_STRIP;
+	public const GLenum GL_POLYGON;
+	
+	// Vertex Arrays
+	public const GLenum GL_VERTEX_ARRAY;
+	public const GLenum GL_NORMAL_ARRAY;
+	public const GLenum GL_COLOR_ARRAY;
+	public const GLenum GL_INDEX_ARRAY;
+	public const GLenum GL_TEXTURE_COORD_ARRAY;
+	public const GLenum GL_EDGE_FLAG_ARRAY;
+	public const GLenum GL_VERTEX_ARRAY_SIZE;
+	public const GLenum GL_VERTEX_ARRAY_TYPE;
+	public const GLenum GL_VERTEX_ARRAY_STRIDE;
+	public const GLenum GL_NORMAL_ARRAY_TYPE;
+	public const GLenum GL_NORMAL_ARRAY_STRIDE;
+	public const GLenum GL_COLOR_ARRAY_SIZE;
+	public const GLenum GL_COLOR_ARRAY_TYPE;
+	public const GLenum GL_COLOR_ARRAY_STRIDE;
+	public const GLenum GL_INDEX_ARRAY_TYPE;
+	public const GLenum GL_INDEX_ARRAY_STRIDE;
+	public const GLenum GL_TEXTURE_COORD_ARRAY_SIZE;
+	public const GLenum GL_TEXTURE_COORD_ARRAY_TYPE;
+	public const GLenum GL_TEXTURE_COORD_ARRAY_STRIDE;
+	public const GLenum GL_EDGE_FLAG_ARRAY_STRIDE;
+	public const GLenum GL_VERTEX_ARRAY_POINTER;
+	public const GLenum GL_NORMAL_ARRAY_POINTER;
+	public const GLenum GL_COLOR_ARRAY_POINTER;
+	public const GLenum GL_INDEX_ARRAY_POINTER;
+	public const GLenum GL_TEXTURE_COORD_ARRAY_POINTER;
+	public const GLenum GL_EDGE_FLAG_ARRAY_POINTER;
+	public const GLenum GL_V2F;
+	public const GLenum GL_V3F;
+	public const GLenum GL_C4UB_V2F;
+	public const GLenum GL_C4UB_V3F;
+	public const GLenum GL_C3F_V3F;
+	public const GLenum GL_N3F_V3F;
+	public const GLenum GL_C4F_N3F_V3F;
+	public const GLenum GL_T2F_V3F;
+	public const GLenum GL_T4F_V4F;
+	public const GLenum GL_T2F_C4UB_V3F;
+	public const GLenum GL_T2F_C3F_V3F;
+	public const GLenum GL_T2F_N3F_V3F;
+	public const GLenum GL_T2F_C4F_N3F_V3F;
+	public const GLenum GL_T4F_C4F_N3F_V4F;
+	
+	// Matrix Mode
+	public const GLenum GL_MATRIX_MODE;
+	public const GLenum GL_MODELVIEW;
+	public const GLenum GL_PROJECTION;
+	public const GLenum GL_TEXTURE;
+	
+	// Points
+	public const GLenum GL_POINT_SMOOTH;
+	public const GLenum GL_POINT_SIZE;
+	public const GLenum GL_POINT_SIZE_GRANULARITY;
+	public const GLenum GL_POINT_SIZE_RANGE;
+	
+	// Lines
+	public const GLenum GL_LINE_SMOOTH;
+	public const GLenum GL_LINE_STIPPLE;
+	public const GLenum GL_LINE_STIPPLE_PATTERN;
+	public const GLenum GL_LINE_STIPPLE_REPEAT;
+	public const GLenum GL_LINE_WIDTH;
+	public const GLenum GL_LINE_WIDTH_GRANULARITY;
+	public const GLenum GL_LINE_WIDTH_RANGE;
+	
+	// Polygons
+	public const GLenum GL_POINT;
+	public const GLenum GL_LINE;
+	public const GLenum GL_FILL;
+	public const GLenum GL_CW;
+	public const GLenum GL_CCW;
+	public const GLenum GL_FRONT;
+	public const GLenum GL_BACK;
+	public const GLenum GL_POLYGON_MODE;
+	public const GLenum GL_POLYGON_SMOOTH;
+	public const GLenum GL_POLYGON_STIPPLE;
+	public const GLenum GL_EDGE_FLAG;
+	public const GLenum GL_CULL_FACE;
+	public const GLenum GL_CULL_FACE_MODE;
+	public const GLenum GL_FRONT_FACE;
+	public const GLenum GL_POLYGON_OFFSET_FACTOR;
+	public const GLenum GL_POLYGON_OFFSET_UNITS;
+	public const GLenum GL_POLYGON_OFFSET_POINT;
+	public const GLenum GL_POLYGON_OFFSET_LINE;
+	public const GLenum GL_POLYGON_OFFSET_FILL;
+	
+	// Display Lists
+	public const GLenum GL_COMPILE;
+	public const GLenum GL_COMPILE_AND_EXECUTE;
+	public const GLenum GL_LIST_BASE;
+	public const GLenum GL_LIST_INDEX;
+	public const GLenum GL_LIST_MODE;
+	
+	// Depth Buffer
+	public const GLenum GL_NEVER;
+	public const GLenum GL_LESS;
+	public const GLenum GL_EQUAL;
+	public const GLenum GL_LEQUAL;
+	public const GLenum GL_GREATER;
+	public const GLenum GL_NOTEQUAL;
+	public const GLenum GL_GEQUAL;
+	public const GLenum GL_ALWAYS;
+	public const GLenum GL_DEPTH_TEST;
+	public const GLenum GL_DEPTH_BITS;
+	public const GLenum GL_DEPTH_CLEAR_VALUE;
+	public const GLenum GL_DEPTH_FUNC;
+	public const GLenum GL_DEPTH_RANGE;
+	public const GLenum GL_DEPTH_WRITEMASK;
+	public const GLenum GL_DEPTH_COMPONENT;
+	
+	// Lighting
+	public const GLenum GL_LIGHTING;
+	public const GLenum GL_LIGHT0;
+	public const GLenum GL_LIGHT1;
+	public const GLenum GL_LIGHT2;
+	public const GLenum GL_LIGHT3;
+	public const GLenum GL_LIGHT4;
+	public const GLenum GL_LIGHT5;
+	public const GLenum GL_LIGHT6;
+	public const GLenum GL_LIGHT7;
+	public const GLenum GL_SPOT_EXPONENT;
+	public const GLenum GL_SPOT_CUTOFF;
+	public const GLenum GL_CONSTANT_ATTENUATION;
+	public const GLenum GL_LINEAR_ATTENUATION;
+	public const GLenum GL_QUADRATIC_ATTENUATION;
+	public const GLenum GL_AMBIENT;
+	public const GLenum GL_DIFFUSE;
+	public const GLenum GL_SPECULAR;
+	public const GLenum GL_SHININESS;
+	public const GLenum GL_EMISSION;
+	public const GLenum GL_POSITION;
+	public const GLenum GL_SPOT_DIRECTION;
+	public const GLenum GL_AMBIENT_AND_DIFFUSE;
+	public const GLenum GL_COLOR_INDEXES;
+	public const GLenum GL_LIGHT_MODEL_TWO_SIDE;
+	public const GLenum GL_LIGHT_MODEL_LOCAL_VIEWER;
+	public const GLenum GL_LIGHT_MODEL_AMBIENT;
+	public const GLenum GL_FRONT_AND_BACK;
+	public const GLenum GL_SHADE_MODEL;
+	public const GLenum GL_FLAT;
+	public const GLenum GL_SMOOTH;
+	public const GLenum GL_COLOR_MATERIAL;
+	public const GLenum GL_COLOR_MATERIAL_FACE;
+	public const GLenum GL_COLOR_MATERIAL_PARAMETER;
+	public const GLenum GL_NORMALIZE;
+	
+	// User Clipping Planes
+	public const GLenum GL_CLIP_PLANE0;
+	public const GLenum GL_CLIP_PLANE1;
+	public const GLenum GL_CLIP_PLANE2;
+	public const GLenum GL_CLIP_PLANE3;
+	public const GLenum GL_CLIP_PLANE4;
+	public const GLenum GL_CLIP_PLANE5;
+	
+	// Accumulation Buffer
+	public const GLenum GL_ACCUM_RED_BITS;
+	public const GLenum GL_ACCUM_GREEN_BITS;
+	public const GLenum GL_ACCUM_BLUE_BITS;
+	public const GLenum GL_ACCUM_ALPHA_BITS;
+	public const GLenum GL_ACCUM_CLEAR_VALUE;
+	public const GLenum GL_ACCUM;
+	public const GLenum GL_ADD;
+	public const GLenum GL_LOAD;
+	public const GLenum GL_MULT;
+	public const GLenum GL_RETURN;
+	
+	// Alpha Testing
+	public const GLenum GL_ALPHA_TEST;
+	public const GLenum GL_ALPHA_TEST_REF;
+	public const GLenum GL_ALPHA_TEST_FUNC;
+	
+	// Blending
+	public const GLenum GL_BLEND;
+	public const GLenum GL_BLEND_SRC;
+	public const GLenum GL_BLEND_DST;
+	public const GLenum GL_ZERO;
+	public const GLenum GL_ONE;
+	public const GLenum GL_SRC_COLOR;
+	public const GLenum GL_ONE_MINUS_SRC_COLOR;
+	public const GLenum GL_SRC_ALPHA;
+	public const GLenum GL_ONE_MINUS_SRC_ALPHA;
+	public const GLenum GL_DST_ALPHA;
+	public const GLenum GL_ONE_MINUS_DST_ALPHA;
+	public const GLenum GL_DST_COLOR;
+	public const GLenum GL_ONE_MINUS_DST_COLOR;
+	public const GLenum GL_SRC_ALPHA_SATURATE;
+	
+	// Render Mode
+	public const GLenum GL_FEEDBACK;
+	public const GLenum GL_RENDER;
+	public const GLenum GL_SELECT;
+	
+	// Feedback
+	public const GLenum GL_2D;
+	public const GLenum GL_3D;
+	public const GLenum GL_3D_COLOR;
+	public const GLenum GL_3D_COLOR_TEXTURE;
+	public const GLenum GL_4D_COLOR_TEXTURE;
+	public const GLenum GL_POINT_TOKEN;
+	public const GLenum GL_LINE_TOKEN;
+	public const GLenum GL_LINE_RESET_TOKEN;
+	public const GLenum GL_POLYGON_TOKEN;
+	public const GLenum GL_BITMAP_TOKEN;
+	public const GLenum GL_DRAW_PIXEL_TOKEN;
+	public const GLenum GL_COPY_PIXEL_TOKEN;
+	public const GLenum GL_PASS_THROUGH_TOKEN;
+	public const GLenum GL_FEEDBACK_BUFFER_POINTER;
+	public const GLenum GL_FEEDBACK_BUFFER_SIZE;
+	public const GLenum GL_FEEDBACK_BUFFER_TYPE;
+	
+	// Selection Buffer
+	public const GLenum GL_SELECTION_BUFFER_POINTER;
+	public const GLenum GL_SELECTION_BUFFER_SIZE;
+	
+	// Fog
+	public const GLenum GL_FOG;
+	public const GLenum GL_FOG_MODE;
+	public const GLenum GL_FOG_DENSITY;
+	public const GLenum GL_FOG_COLOR;
+	public const GLenum GL_FOG_INDEX;
+	public const GLenum GL_FOG_START;
+	public const GLenum GL_FOG_END;
+	public const GLenum GL_LINEAR;
+	public const GLenum GL_EXP;
+	public const GLenum GL_EXP2;
+	
+	// Logic Ops
+	public const GLenum GL_LOGIC_OP;
+	public const GLenum GL_INDEX_LOGIC_OP;
+	public const GLenum GL_COLOR_LOGIC_OP;
+	public const GLenum GL_LOGIC_OP_MODE;
+	public const GLenum GL_CLEAR;
+	public const GLenum GL_SET;
+	public const GLenum GL_COPY;
+	public const GLenum GL_COPY_INVERTED;
+	public const GLenum GL_NOOP;
+	public const GLenum GL_INVERT;
+	public const GLenum GL_AND;
+	public const GLenum GL_NAND;
+	public const GLenum GL_OR;
+	public const GLenum GL_NOR;
+	public const GLenum GL_XOR;
+	public const GLenum GL_EQUIV;
+	public const GLenum GL_AND_REVERSE;
+	public const GLenum GL_AND_INVERTED;
+	public const GLenum GL_OR_REVERSE;
+	public const GLenum GL_OR_INVERTED;
+	
+	// Stencil
+	public const GLenum GL_STENCIL_BITS;
+	public const GLenum GL_STENCIL_TEST;
+	public const GLenum GL_STENCIL_CLEAR_VALUE;
+	public const GLenum GL_STENCIL_FUNC;
+	public const GLenum GL_STENCIL_VALUE_MASK;
+	public const GLenum GL_STENCIL_FAIL;
+	public const GLenum GL_STENCIL_PASS_DEPTH_FAIL;
+	public const GLenum GL_STENCIL_PASS_DEPTH_PASS;
+	public const GLenum GL_STENCIL_REF;
+	public const GLenum GL_STENCIL_WRITEMASK;
+	public const GLenum GL_STENCIL_INDEX;
+	public const GLenum GL_KEEP;
+	public const GLenum GL_REPLACE;
+	public const GLenum GL_INCR;
+	public const GLenum GL_DECR;
+	
+	// Buffers, Pixel Drawing/Reading
+	public const GLenum GL_NONE;
+	public const GLenum GL_LEFT;
+	public const GLenum GL_RIGHT;
+	public const GLenum GL_FRONT_LEFT;
+	public const GLenum GL_FRONT_RIGHT;
+	public const GLenum GL_BACK_LEFT;
+	public const GLenum GL_BACK_RIGHT;
+	public const GLenum GL_AUX0;
+	public const GLenum GL_AUX1;
+	public const GLenum GL_AUX2;
+	public const GLenum GL_AUX3;
+	public const GLenum GL_COLOR_INDEX;
+	public const GLenum GL_RED;
+	public const GLenum GL_GREEN;
+	public const GLenum GL_BLUE;
+	public const GLenum GL_ALPHA;
+	public const GLenum GL_LUMINANCE;
+	public const GLenum GL_LUMINANCE_ALPHA;
+	public const GLenum GL_ALPHA_BITS;
+	public const GLenum GL_RED_BITS;
+	public const GLenum GL_GREEN_BITS;
+	public const GLenum GL_BLUE_BITS;
+	public const GLenum GL_INDEX_BITS;
+	public const GLenum GL_SUBPIXEL_BITS;
+	public const GLenum GL_AUX_BUFFERS;
+	public const GLenum GL_READ_BUFFER;
+	public const GLenum GL_DRAW_BUFFER;
+	public const GLenum GL_DOUBLEBUFFER;
+	public const GLenum GL_STEREO;
+	public const GLenum GL_BITMAP;
+	public const GLenum GL_COLOR;
+	public const GLenum GL_DEPTH;
+	public const GLenum GL_STENCIL;
+	public const GLenum GL_DITHER;
+	public const GLenum GL_RGB;
+	public const GLenum GL_RGBA;
+	
+	// Implementation Limits
+	public const GLenum GL_MAX_LIST_NESTING;
+	public const GLenum GL_MAX_EVAL_ORDER;
+	public const GLenum GL_MAX_LIGHTS;
+	public const GLenum GL_MAX_CLIP_PLANES;
+	public const GLenum GL_MAX_TEXTURE_SIZE;
+	public const GLenum GL_MAX_PIXEL_MAP_TABLE;
+	public const GLenum GL_MAX_ATTRIB_STACK_DEPTH;
+	public const GLenum GL_MAX_MODELVIEW_STACK_DEPTH;
+	public const GLenum GL_MAX_NAME_STACK_DEPTH;
+	public const GLenum GL_MAX_PROJECTION_STACK_DEPTH;
+	public const GLenum GL_MAX_TEXTURE_STACK_DEPTH;
+	public const GLenum GL_MAX_VIEWPORT_DIMS;
+	public const GLenum GL_MAX_CLIENT_ATTRIB_STACK_DEPTH;
+	
+	// Gets
+	public const GLenum GL_ATTRIB_STACK_DEPTH;
+	public const GLenum GL_CLIENT_ATTRIB_STACK_DEPTH;
+	public const GLenum GL_COLOR_CLEAR_VALUE;
+	public const GLenum GL_COLOR_WRITEMASK;
+	public const GLenum GL_CURRENT_INDEX;
+	public const GLenum GL_CURRENT_COLOR;
+	public const GLenum GL_CURRENT_NORMAL;
+	public const GLenum GL_CURRENT_RASTER_COLOR;
+	public const GLenum GL_CURRENT_RASTER_DISTANCE;
+	public const GLenum GL_CURRENT_RASTER_INDEX;
+	public const GLenum GL_CURRENT_RASTER_POSITION;
+	public const GLenum GL_CURRENT_RASTER_TEXTURE_COORDS;
+	public const GLenum GL_CURRENT_RASTER_POSITION_VALID;
+	public const GLenum GL_CURRENT_TEXTURE_COORDS;
+	public const GLenum GL_INDEX_CLEAR_VALUE;
+	public const GLenum GL_INDEX_MODE;
+	public const GLenum GL_INDEX_WRITEMASK;
+	public const GLenum GL_MODELVIEW_MATRIX;
+	public const GLenum GL_MODELVIEW_STACK_DEPTH;
+	public const GLenum GL_NAME_STACK_DEPTH;
+	public const GLenum GL_PROJECTION_MATRIX;
+	public const GLenum GL_PROJECTION_STACK_DEPTH;
+	public const GLenum GL_RENDER_MODE;
+	public const GLenum GL_RGBA_MODE;
+	public const GLenum GL_TEXTURE_MATRIX;
+	public const GLenum GL_TEXTURE_STACK_DEPTH;
+	public const GLenum GL_VIEWPORT;
+	
+	// Evaluators
+	public const GLenum GL_AUTO_NORMAL;
+	public const GLenum GL_MAP1_COLOR_4;
+	public const GLenum GL_MAP1_INDEX;
+	public const GLenum GL_MAP1_NORMAL;
+	public const GLenum GL_MAP1_TEXTURE_COORD_1;
+	public const GLenum GL_MAP1_TEXTURE_COORD_2;
+	public const GLenum GL_MAP1_TEXTURE_COORD_3;
+	public const GLenum GL_MAP1_TEXTURE_COORD_4;
+	public const GLenum GL_MAP1_VERTEX_3;
+	public const GLenum GL_MAP1_VERTEX_4;
+	public const GLenum GL_MAP2_COLOR_4;
+	public const GLenum GL_MAP2_INDEX;
+	public const GLenum GL_MAP2_NORMAL;
+	public const GLenum GL_MAP2_TEXTURE_COORD_1;
+	public const GLenum GL_MAP2_TEXTURE_COORD_2;
+	public const GLenum GL_MAP2_TEXTURE_COORD_3;
+	public const GLenum GL_MAP2_TEXTURE_COORD_4;
+	public const GLenum GL_MAP2_VERTEX_3;
+	public const GLenum GL_MAP2_VERTEX_4;
+	public const GLenum GL_MAP1_GRID_DOMAIN;
+	public const GLenum GL_MAP1_GRID_SEGMENTS;
+	public const GLenum GL_MAP2_GRID_DOMAIN;
+	public const GLenum GL_MAP2_GRID_SEGMENTS;
+	public const GLenum GL_COEFF;
+	public const GLenum GL_ORDER;
+	public const GLenum GL_DOMAIN;
+	
+	// Hints
+	public const GLenum GL_PERSPECTIVE_CORRECTION_HINT;
+	public const GLenum GL_POINT_SMOOTH_HINT;
+	public const GLenum GL_LINE_SMOOTH_HINT;
+	public const GLenum GL_POLYGON_SMOOTH_HINT;
+	public const GLenum GL_FOG_HINT;
+	public const GLenum GL_DONT_CARE;
+	public const GLenum GL_FASTEST;
+	public const GLenum GL_NICEST;
+	
+	// Scissor box
+	public const GLenum GL_SCISSOR_BOX;
+	public const GLenum GL_SCISSOR_TEST;
+	
+	// Pixel Mode / Transfer
+	public const GLenum GL_MAP_COLOR;
+	public const GLenum GL_MAP_STENCIL;
+	public const GLenum GL_INDEX_SHIFT;
+	public const GLenum GL_INDEX_OFFSET;
+	public const GLenum GL_RED_SCALE;
+	public const GLenum GL_RED_BIAS;
+	public const GLenum GL_GREEN_SCALE;
+	public const GLenum GL_GREEN_BIAS;
+	public const GLenum GL_BLUE_SCALE;
+	public const GLenum GL_BLUE_BIAS;
+	public const GLenum GL_ALPHA_SCALE;
+	public const GLenum GL_ALPHA_BIAS;
+	public const GLenum GL_DEPTH_SCALE;
+	public const GLenum GL_DEPTH_BIAS;
+	public const GLenum GL_PIXEL_MAP_S_TO_S_SIZE;
+	public const GLenum GL_PIXEL_MAP_I_TO_I_SIZE;
+	public const GLenum GL_PIXEL_MAP_I_TO_R_SIZE;
+	public const GLenum GL_PIXEL_MAP_I_TO_G_SIZE;
+	public const GLenum GL_PIXEL_MAP_I_TO_B_SIZE;
+	public const GLenum GL_PIXEL_MAP_I_TO_A_SIZE;
+	public const GLenum GL_PIXEL_MAP_R_TO_R_SIZE;
+	public const GLenum GL_PIXEL_MAP_G_TO_G_SIZE;
+	public const GLenum GL_PIXEL_MAP_B_TO_B_SIZE;
+	public const GLenum GL_PIXEL_MAP_A_TO_A_SIZE;
+	public const GLenum GL_PIXEL_MAP_S_TO_S;
+	public const GLenum GL_PIXEL_MAP_I_TO_I;
+	public const GLenum GL_PIXEL_MAP_I_TO_R;
+	public const GLenum GL_PIXEL_MAP_I_TO_G;
+	public const GLenum GL_PIXEL_MAP_I_TO_B;
+	public const GLenum GL_PIXEL_MAP_I_TO_A;
+	public const GLenum GL_PIXEL_MAP_R_TO_R;
+	public const GLenum GL_PIXEL_MAP_G_TO_G;
+	public const GLenum GL_PIXEL_MAP_B_TO_B;
+	public const GLenum GL_PIXEL_MAP_A_TO_A;
+	public const GLenum GL_PACK_ALIGNMENT;
+	public const GLenum GL_PACK_LSB_FIRST;
+	public const GLenum GL_PACK_ROW_LENGTH;
+	public const GLenum GL_PACK_SKIP_PIXELS;
+	public const GLenum GL_PACK_SKIP_ROWS;
+	public const GLenum GL_PACK_SWAP_BYTES;
+	public const GLenum GL_UNPACK_ALIGNMENT;
+	public const GLenum GL_UNPACK_LSB_FIRST;
+	public const GLenum GL_UNPACK_ROW_LENGTH;
+	public const GLenum GL_UNPACK_SKIP_PIXELS;
+	public const GLenum GL_UNPACK_SKIP_ROWS;
+	public const GLenum GL_UNPACK_SWAP_BYTES;
+	public const GLenum GL_ZOOM_X;
+	public const GLenum GL_ZOOM_Y;
+	
+	// Texture Mapping
+	public const GLenum GL_TEXTURE_ENV;
+	public const GLenum GL_TEXTURE_ENV_MODE;
+	public const GLenum GL_TEXTURE_1D;
+	public const GLenum GL_TEXTURE_2D;
+	public const GLenum GL_TEXTURE_WRAP_S;
+	public const GLenum GL_TEXTURE_WRAP_T;
+	public const GLenum GL_TEXTURE_MAG_FILTER;
+	public const GLenum GL_TEXTURE_MIN_FILTER;
+	public const GLenum GL_TEXTURE_ENV_COLOR;
+	public const GLenum GL_TEXTURE_GEN_S;
+	public const GLenum GL_TEXTURE_GEN_T;
+	public const GLenum GL_TEXTURE_GEN_MODE;
+	public const GLenum GL_TEXTURE_BORDER_COLOR;
+	public const GLenum GL_TEXTURE_WIDTH;
+	public const GLenum GL_TEXTURE_HEIGHT;
+	public const GLenum GL_TEXTURE_BORDER;
+	public const GLenum GL_TEXTURE_COMPONENTS;
+	public const GLenum GL_TEXTURE_RED_SIZE;
+	public const GLenum GL_TEXTURE_GREEN_SIZE;
+	public const GLenum GL_TEXTURE_BLUE_SIZE;
+	public const GLenum GL_TEXTURE_ALPHA_SIZE;
+	public const GLenum GL_TEXTURE_LUMINANCE_SIZE;
+	public const GLenum GL_TEXTURE_INTENSITY_SIZE;
+	public const GLenum GL_NEAREST_MIPMAP_NEAREST;
+	public const GLenum GL_NEAREST_MIPMAP_LINEAR;
+	public const GLenum GL_LINEAR_MIPMAP_NEAREST;
+	public const GLenum GL_LINEAR_MIPMAP_LINEAR;
+	public const GLenum GL_OBJECT_LINEAR;
+	public const GLenum GL_OBJECT_PLANE;
+	public const GLenum GL_EYE_LINEAR;
+	public const GLenum GL_EYE_PLANE;
+	public const GLenum GL_SPHERE_MAP;
+	public const GLenum GL_DECAL;
+	public const GLenum GL_MODULATE;
+	public const GLenum GL_NEAREST;
+	public const GLenum GL_REPEAT;
+	public const GLenum GL_CLAMP;
+	public const GLenum GL_S;
+	public const GLenum GL_T;
+	public const GLenum GL_R;
+	public const GLenum GL_Q;
+	public const GLenum GL_TEXTURE_GEN_R;
+	public const GLenum GL_TEXTURE_GEN_Q;
+	
+	// Utility
+	public const GLenum GL_VENDOR;
+	public const GLenum GL_RENDERER;
+	public const GLenum GL_VERSION;
+	public const GLenum GL_EXTENSIONS;
+	
+	// Errors
+	public const GLenum GL_NO_ERROR;
+	public const GLenum GL_INVALID_ENUM;
+	public const GLenum GL_INVALID_VALUE;
+	public const GLenum GL_INVALID_OPERATION;
+	public const GLenum GL_STACK_OVERFLOW;
+	public const GLenum GL_STACK_UNDERFLOW;
+	public const GLenum GL_OUT_OF_MEMORY;
+	
+	// glPush/Pop Attrib Bits
+	public const GLenum GL_CURRENT_BIT;
+	public const GLenum GL_POINT_BIT;
+	public const GLenum GL_LINE_BIT;
+	public const GLenum GL_POLYGON_BIT;
+	public const GLenum GL_POLYGON_STIPPLE_BIT;
+	public const GLenum GL_PIXEL_MODE_BIT;
+	public const GLenum GL_LIGHTING_BIT;
+	public const GLenum GL_FOG_BIT;
+	public const GLenum GL_DEPTH_BUFFER_BIT;
+	public const GLenum GL_ACCUM_BUFFER_BIT;
+	public const GLenum GL_STENCIL_BUFFER_BIT;
+	public const GLenum GL_VIEWPORT_BIT;
+	public const GLenum GL_TRANSFORM_BIT;
+	public const GLenum GL_ENABLE_BIT;
+	public const GLenum GL_COLOR_BUFFER_BIT;
+	public const GLenum GL_HINT_BIT;
+	public const GLenum GL_EVAL_BIT;
+	public const GLenum GL_LIST_BIT;
+	public const GLenum GL_TEXTURE_BIT;
+	public const GLenum GL_SCISSOR_BIT;
+	public const GLenum GL_ALL_ATTRIB_BITS;
+	
+	// OpenGL 1.1
+	public const GLenum GL_PROXY_TEXTURE_1D;
+	public const GLenum GL_PROXY_TEXTURE_2D;
+	public const GLenum GL_TEXTURE_PRIORITY;
+	public const GLenum GL_TEXTURE_RESIDENT;
+	public const GLenum GL_TEXTURE_BINDING_1D;
+	public const GLenum GL_TEXTURE_BINDING_2D;
+	public const GLenum GL_TEXTURE_INTERNAL_FORMAT;
+	public const GLenum GL_ALPHA4;
+	public const GLenum GL_ALPHA8;
+	public const GLenum GL_ALPHA12;
+	public const GLenum GL_ALPHA16;
+	public const GLenum GL_LUMINANCE4;
+	public const GLenum GL_LUMINANCE8;
+	public const GLenum GL_LUMINANCE12;
+	public const GLenum GL_LUMINANCE16;
+	public const GLenum GL_LUMINANCE4_ALPHA4;
+	public const GLenum GL_LUMINANCE6_ALPHA2;
+	public const GLenum GL_LUMINANCE8_ALPHA8;
+	public const GLenum GL_LUMINANCE12_ALPHA4;
+	public const GLenum GL_LUMINANCE12_ALPHA12;
+	public const GLenum GL_LUMINANCE16_ALPHA16;
+	public const GLenum GL_INTENSITY;
+	public const GLenum GL_INTENSITY4;
+	public const GLenum GL_INTENSITY8;
+	public const GLenum GL_INTENSITY12;
+	public const GLenum GL_INTENSITY16;
+	public const GLenum GL_R3_G3_B2;
+	public const GLenum GL_RGB4;
+	public const GLenum GL_RGB5;
+	public const GLenum GL_RGB8;
+	public const GLenum GL_RGB10;
+	public const GLenum GL_RGB12;
+	public const GLenum GL_RGB16;
+	public const GLenum GL_RGBA2;
+	public const GLenum GL_RGBA4;
+	public const GLenum GL_RGB5_A1;
+	public const GLenum GL_RGBA8;
+	public const GLenum GL_RGB10_A2;
+	public const GLenum GL_RGBA12;
+	public const GLenum GL_RGBA16;
+	public const GLenum GL_CLIENT_PIXEL_STORE_BIT;
+	public const GLenum GL_CLIENT_VERTEX_ARRAY_BIT;
+	public const GLenum GL_ALL_CLIENT_ATTRIB_BITS;
+	public const GLenum GL_CLIENT_ALL_ATTRIB_BITS;
+	
+	// OpenGL 1.2
+	public const GLenum GL_RESCALE_NORMAL;
+	public const GLenum GL_CLAMP_TO_EDGE;
+	public const GLenum GL_MAX_ELEMENTS_VERTICES;
+	public const GLenum GL_MAX_ELEMENTS_INDICES;
+	public const GLenum GL_BGR;
+	public const GLenum GL_BGRA;
+	public const GLenum GL_UNSIGNED_BYTE_3_3_2;
+	public const GLenum GL_UNSIGNED_BYTE_2_3_3_REV;
+	public const GLenum GL_UNSIGNED_SHORT_5_6_5;
+	public const GLenum GL_UNSIGNED_SHORT_5_6_5_REV;
+	public const GLenum GL_UNSIGNED_SHORT_4_4_4_4;
+	public const GLenum GL_UNSIGNED_SHORT_4_4_4_4_REV;
+	public const GLenum GL_UNSIGNED_SHORT_5_5_5_1;
+	public const GLenum GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	public const GLenum GL_UNSIGNED_INT_8_8_8_8;
+	public const GLenum GL_UNSIGNED_INT_8_8_8_8_REV;
+	public const GLenum GL_UNSIGNED_INT_10_10_10_2;
+	public const GLenum GL_UNSIGNED_INT_2_10_10_10_REV;
+	public const GLenum GL_LIGHT_MODEL_COLOR_CONTROL;
+	public const GLenum GL_SINGLE_COLOR;
+	public const GLenum GL_SEPARATE_SPECULAR_COLOR;
+	public const GLenum GL_TEXTURE_MIN_LOD;
+	public const GLenum GL_TEXTURE_MAX_LOD;
+	public const GLenum GL_TEXTURE_BASE_LEVEL;
+	public const GLenum GL_TEXTURE_MAX_LEVEL;
+	public const GLenum GL_SMOOTH_POINT_SIZE_RANGE;
+	public const GLenum GL_SMOOTH_POINT_SIZE_GRANULARITY;
+	public const GLenum GL_SMOOTH_LINE_WIDTH_RANGE;
+	public const GLenum GL_SMOOTH_LINE_WIDTH_GRANULARITY;
+	public const GLenum GL_ALIASED_POINT_SIZE_RANGE;
+	public const GLenum GL_ALIASED_LINE_WIDTH_RANGE;
+	public const GLenum GL_PACK_SKIP_IMAGES;
+	public const GLenum GL_PACK_IMAGE_HEIGHT;
+	public const GLenum GL_UNPACK_SKIP_IMAGES;
+	public const GLenum GL_UNPACK_IMAGE_HEIGHT;
+	public const GLenum GL_TEXTURE_3D;
+	public const GLenum GL_PROXY_TEXTURE_3D;
+	public const GLenum GL_TEXTURE_DEPTH;
+	public const GLenum GL_TEXTURE_WRAP_R;
+	public const GLenum GL_MAX_3D_TEXTURE_SIZE;
+	public const GLenum GL_TEXTURE_BINDING_3D;
+	
+	// GL_ARB_imaging
+	public const GLenum GL_ARB_imaging;
+	public const GLenum GL_CONSTANT_COLOR;
+	public const GLenum GL_ONE_MINUS_CONSTANT_COLOR;
+	public const GLenum GL_CONSTANT_ALPHA;
+	public const GLenum GL_ONE_MINUS_CONSTANT_ALPHA;
+	public const GLenum GL_COLOR_TABLE;
+	public const GLenum GL_POST_CONVOLUTION_COLOR_TABLE;
+	public const GLenum GL_POST_COLOR_MATRIX_COLOR_TABLE;
+	public const GLenum GL_PROXY_COLOR_TABLE;
+	public const GLenum GL_PROXY_POST_CONVOLUTION_COLOR_TABLE;
+	public const GLenum GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE;
+	public const GLenum GL_COLOR_TABLE_SCALE;
+	public const GLenum GL_COLOR_TABLE_BIAS;
+	public const GLenum GL_COLOR_TABLE_FORMAT;
+	public const GLenum GL_COLOR_TABLE_WIDTH;
+	public const GLenum GL_COLOR_TABLE_RED_SIZE;
+	public const GLenum GL_COLOR_TABLE_GREEN_SIZE;
+	public const GLenum GL_COLOR_TABLE_BLUE_SIZE;
+	public const GLenum GL_COLOR_TABLE_ALPHA_SIZE;
+	public const GLenum GL_COLOR_TABLE_LUMINANCE_SIZE;
+	public const GLenum GL_COLOR_TABLE_INTENSITY_SIZE;
+	public const GLenum GL_CONVOLUTION_1D;
+	public const GLenum GL_CONVOLUTION_2D;
+	public const GLenum GL_SEPARABLE_2D;
+	public const GLenum GL_CONVOLUTION_BORDER_MODE;
+	public const GLenum GL_CONVOLUTION_FILTER_SCALE;
+	public const GLenum GL_CONVOLUTION_FILTER_BIAS;
+	public const GLenum GL_REDUCE;
+	public const GLenum GL_CONVOLUTION_FORMAT;
+	public const GLenum GL_CONVOLUTION_WIDTH;
+	public const GLenum GL_CONVOLUTION_HEIGHT;
+	public const GLenum GL_MAX_CONVOLUTION_WIDTH;
+	public const GLenum GL_MAX_CONVOLUTION_HEIGHT;
+	public const GLenum GL_POST_CONVOLUTION_RED_SCALE;
+	public const GLenum GL_POST_CONVOLUTION_GREEN_SCALE;
+	public const GLenum GL_POST_CONVOLUTION_BLUE_SCALE;
+	public const GLenum GL_POST_CONVOLUTION_ALPHA_SCALE;
+	public const GLenum GL_POST_CONVOLUTION_RED_BIAS;
+	public const GLenum GL_POST_CONVOLUTION_GREEN_BIAS;
+	public const GLenum GL_POST_CONVOLUTION_BLUE_BIAS;
+	public const GLenum GL_POST_CONVOLUTION_ALPHA_BIAS;
+	public const GLenum GL_CONSTANT_BORDER;
+	public const GLenum GL_REPLICATE_BORDER;
+	public const GLenum GL_CONVOLUTION_BORDER_COLOR;
+	public const GLenum GL_COLOR_MATRIX;
+	public const GLenum GL_COLOR_MATRIX_STACK_DEPTH;
+	public const GLenum GL_MAX_COLOR_MATRIX_STACK_DEPTH;
+	public const GLenum GL_POST_COLOR_MATRIX_RED_SCALE;
+	public const GLenum GL_POST_COLOR_MATRIX_GREEN_SCALE;
+	public const GLenum GL_POST_COLOR_MATRIX_BLUE_SCALE;
+	public const GLenum GL_POST_COLOR_MATRIX_ALPHA_SCALE;
+	public const GLenum GL_POST_COLOR_MATRIX_RED_BIAS;
+	public const GLenum GL_POST_COLOR_MATRIX_GREEN_BIAS;
+	public const GLenum GL_POST_COLOR_MATRIX_BLUE_BIAS;
+	public const GLenum GL_POST_COLOR_MATRIX_ALPHA_BIAS;
+	public const GLenum GL_HISTOGRAM;
+	public const GLenum GL_PROXY_HISTOGRAM;
+	public const GLenum GL_HISTOGRAM_WIDTH;
+	public const GLenum GL_HISTOGRAM_FORMAT;
+	public const GLenum GL_HISTOGRAM_RED_SIZE;
+	public const GLenum GL_HISTOGRAM_GREEN_SIZE;
+	public const GLenum GL_HISTOGRAM_BLUE_SIZE;
+	public const GLenum GL_HISTOGRAM_ALPHA_SIZE;
+	public const GLenum GL_HISTOGRAM_LUMINANCE_SIZE;
+	public const GLenum GL_HISTOGRAM_SINK;
+	public const GLenum GL_MINMAX;
+	public const GLenum GL_MINMAX_FORMAT;
+	public const GLenum GL_MINMAX_SINK;
+	public const GLenum GL_TABLE_TOO_LARGE;
+	public const GLenum GL_BLEND_EQUATION;
+	public const GLenum GL_MIN;
+	public const GLenum GL_MAX;
+	public const GLenum GL_FUNC_ADD;
+	public const GLenum GL_FUNC_SUBTRACT;
+	public const GLenum GL_FUNC_REVERSE_SUBTRACT;
+	public const GLenum GL_BLEND_COLOR;
+	
+	// OpenGL 1.3
+	public const GLenum GL_TEXTURE0;
+	public const GLenum GL_TEXTURE1;
+	public const GLenum GL_TEXTURE2;
+	public const GLenum GL_TEXTURE3;
+	public const GLenum GL_TEXTURE4;
+	public const GLenum GL_TEXTURE5;
+	public const GLenum GL_TEXTURE6;
+	public const GLenum GL_TEXTURE7;
+	public const GLenum GL_TEXTURE8;
+	public const GLenum GL_TEXTURE9;
+	public const GLenum GL_TEXTURE10;
+	public const GLenum GL_TEXTURE11;
+	public const GLenum GL_TEXTURE12;
+	public const GLenum GL_TEXTURE13;
+	public const GLenum GL_TEXTURE14;
+	public const GLenum GL_TEXTURE15;
+	public const GLenum GL_TEXTURE16;
+	public const GLenum GL_TEXTURE17;
+	public const GLenum GL_TEXTURE18;
+	public const GLenum GL_TEXTURE19;
+	public const GLenum GL_TEXTURE20;
+	public const GLenum GL_TEXTURE21;
+	public const GLenum GL_TEXTURE22;
+	public const GLenum GL_TEXTURE23;
+	public const GLenum GL_TEXTURE24;
+	public const GLenum GL_TEXTURE25;
+	public const GLenum GL_TEXTURE26;
+	public const GLenum GL_TEXTURE27;
+	public const GLenum GL_TEXTURE28;
+	public const GLenum GL_TEXTURE29;
+	public const GLenum GL_TEXTURE30;
+	public const GLenum GL_TEXTURE31;
+	public const GLenum GL_ACTIVE_TEXTURE;
+	public const GLenum GL_CLIENT_ACTIVE_TEXTURE;
+	public const GLenum GL_MAX_TEXTURE_UNITS;
+	public const GLenum GL_NORMAL_MAP;
+	public const GLenum GL_REFLECTION_MAP;
+	public const GLenum GL_TEXTURE_CUBE_MAP;
+	public const GLenum GL_TEXTURE_BINDING_CUBE_MAP;
+	public const GLenum GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+	public const GLenum GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
+	public const GLenum GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
+	public const GLenum GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
+	public const GLenum GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
+	public const GLenum GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
+	public const GLenum GL_PROXY_TEXTURE_CUBE_MAP;
+	public const GLenum GL_MAX_CUBE_MAP_TEXTURE_SIZE;
+	public const GLenum GL_COMPRESSED_ALPHA;
+	public const GLenum GL_COMPRESSED_LUMINANCE;
+	public const GLenum GL_COMPRESSED_LUMINANCE_ALPHA;
+	public const GLenum GL_COMPRESSED_INTENSITY;
+	public const GLenum GL_COMPRESSED_RGB;
+	public const GLenum GL_COMPRESSED_RGBA;
+	public const GLenum GL_TEXTURE_COMPRESSION_HINT;
+	public const GLenum GL_TEXTURE_COMPRESSED_IMAGE_SIZE;
+	public const GLenum GL_TEXTURE_COMPRESSED;
+	public const GLenum GL_NUM_COMPRESSED_TEXTURE_FORMATS;
+	public const GLenum GL_COMPRESSED_TEXTURE_FORMATS;
+	public const GLenum GL_MULTISAMPLE;
+	public const GLenum GL_SAMPLE_ALPHA_TO_COVERAGE;
+	public const GLenum GL_SAMPLE_ALPHA_TO_ONE;
+	public const GLenum GL_SAMPLE_COVERAGE;
+	public const GLenum GL_SAMPLE_BUFFERS;
+	public const GLenum GL_SAMPLES;
+	public const GLenum GL_SAMPLE_COVERAGE_VALUE;
+	public const GLenum GL_SAMPLE_COVERAGE_INVERT;
+	public const GLenum GL_MULTISAMPLE_BIT;
+	public const GLenum GL_TRANSPOSE_MODELVIEW_MATRIX;
+	public const GLenum GL_TRANSPOSE_PROJECTION_MATRIX;
+	public const GLenum GL_TRANSPOSE_TEXTURE_MATRIX;
+	public const GLenum GL_TRANSPOSE_COLOR_MATRIX;
+	public const GLenum GL_COMBINE;
+	public const GLenum GL_COMBINE_RGB;
+	public const GLenum GL_COMBINE_ALPHA;
+	public const GLenum GL_SOURCE0_RGB;
+	public const GLenum GL_SOURCE1_RGB;
+	public const GLenum GL_SOURCE2_RGB;
+	public const GLenum GL_SOURCE0_ALPHA;
+	public const GLenum GL_SOURCE1_ALPHA;
+	public const GLenum GL_SOURCE2_ALPHA;
+	public const GLenum GL_OPERAND0_RGB;
+	public const GLenum GL_OPERAND1_RGB;
+	public const GLenum GL_OPERAND2_RGB;
+	public const GLenum GL_OPERAND0_ALPHA;
+	public const GLenum GL_OPERAND1_ALPHA;
+	public const GLenum GL_OPERAND2_ALPHA;
+	public const GLenum GL_RGB_SCALE;
+	public const GLenum GL_ADD_SIGNED;
+	public const GLenum GL_INTERPOLATE;
+	public const GLenum GL_SUBTRACT;
+	public const GLenum GL_CONSTANT;
+	public const GLenum GL_PRIMARY_COLOR;
+	public const GLenum GL_PREVIOUS;
+	public const GLenum GL_DOT3_RGB;
+	public const GLenum GL_DOT3_RGBA;
+	public const GLenum GL_CLAMP_TO_BORDER;
+	
+	// GL_ARB_multitexture (ARB extension 1 and OpenGL 1.2.1)
+	public const GLenum GL_TEXTURE0_ARB;
+	public const GLenum GL_TEXTURE1_ARB;
+	public const GLenum GL_TEXTURE2_ARB;
+	public const GLenum GL_TEXTURE3_ARB;
+	public const GLenum GL_TEXTURE4_ARB;
+	public const GLenum GL_TEXTURE5_ARB;
+	public const GLenum GL_TEXTURE6_ARB;
+	public const GLenum GL_TEXTURE7_ARB;
+	public const GLenum GL_TEXTURE8_ARB;
+	public const GLenum GL_TEXTURE9_ARB;
+	public const GLenum GL_TEXTURE10_ARB;
+	public const GLenum GL_TEXTURE11_ARB;
+	public const GLenum GL_TEXTURE12_ARB;
+	public const GLenum GL_TEXTURE13_ARB;
+	public const GLenum GL_TEXTURE14_ARB;
+	public const GLenum GL_TEXTURE15_ARB;
+	public const GLenum GL_TEXTURE16_ARB;
+	public const GLenum GL_TEXTURE17_ARB;
+	public const GLenum GL_TEXTURE18_ARB;
+	public const GLenum GL_TEXTURE19_ARB;
+	public const GLenum GL_TEXTURE20_ARB;
+	public const GLenum GL_TEXTURE21_ARB;
+	public const GLenum GL_TEXTURE22_ARB;
+	public const GLenum GL_TEXTURE23_ARB;
+	public const GLenum GL_TEXTURE24_ARB;
+	public const GLenum GL_TEXTURE25_ARB;
+	public const GLenum GL_TEXTURE26_ARB;
+	public const GLenum GL_TEXTURE27_ARB;
+	public const GLenum GL_TEXTURE28_ARB;
+	public const GLenum GL_TEXTURE29_ARB;
+	public const GLenum GL_TEXTURE30_ARB;
+	public const GLenum GL_TEXTURE31_ARB;
+	public const GLenum GL_ACTIVE_TEXTURE_ARB;
+	public const GLenum GL_CLIENT_ACTIVE_TEXTURE_ARB;
+	public const GLenum GL_MAX_TEXTURE_UNITS_ARB;
+
+	
+	// Miscellaneous
+	public static void glClearIndex (GLfloat c);
+	public static void glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+	public static void glClear (GLbitfield mask);
+	public static void glIndexMask (GLuint mask);
+	public static void glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+	public static void glAlphaFunc (GLenum func, GLclampf @ref);
+	public static void glBlendFunc (GLenum sfactor, GLenum dfactor);
+	public static void glLogicOp (GLenum opcode);
+	public static void glCullFace (GLenum mode);
+	public static void glFrontFace (GLenum mode);
+	public static void glPointSize (GLfloat size);
+	public static void glLineWidth (GLfloat width);
+	public static void glLineStipple (GLint factor, GLushort pattern);
+	public static void glPolygonMode (GLenum face, GLenum mode);
+	public static void glPolygonOffset (GLfloat factor, GLfloat units);
+	public static void glPolygonStipple ([CCode (array_length = false)] GLubyte[] mask);
+	public static void glGetPolygonStipple (out GLubyte mask);
+	public static void glEdgeFlag (GLboolean flag);
+	public static void glEdgeFlagv ([CCode (array_length = false)] GLboolean[] flag);
+	public static void glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+	public static void glClipPlane (GLenum plane, [CCode (array_length = false)] GLdouble[] equation);
+	public static void glGetClipPlane (GLenum plane, [CCode (array_length = false)] GLdouble[] equation);
+	public static void glDrawBuffer (GLenum mode);
+	public static void glReadBuffer (GLenum mode);
+	public static void glEnable (GLenum cap);
+	public static void glDisable (GLenum cap);
+	public static GLboolean glIsEnabled (GLenum cap);
+	public static void glEnableClientState (GLenum cap);
+	public static void glDisableClientState (GLenum cap);
+	public static void glGetBooleanv (GLenum pname, [CCode (array_length = false)] GLboolean[] params);
+	public static void glGetDoublev (GLenum pname, [CCode (array_length = false)] GLdouble[] params);
+	public static void glGetFloatv (GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glGetIntegerv (GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glPushAttrib (GLbitfield mask);
+	public static void glPopAttrib ();
+	public static void glPushClientAttrib (GLbitfield mask);
+	public static void glPopClientAttrib ();
+	public static GLint glRenderMode (GLenum mode);
+	public static GLenum glGetError ();
+	public static unowned string glGetString (GLenum name);
+	public static void glFinish ();
+	public static void glFlush ();
+	public static void glHint (GLenum target, GLenum mode);
+
+	// Depth Buffer
+	public static void glClearDepth (GLclampd depth);
+	public static void glDepthFunc (GLenum func);
+	public static void glDepthMask (GLboolean flag);
+	public static void glDepthRange (GLclampd near_val, GLclampd far_val);
+
+	// Accumulation Buffer
+	public static void glClearAccum (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+	public static void glAccum (GLenum op, GLfloat @value);
+
+	// Transformation
+	public static void glMatrixMode (GLenum mode);
+	public static void glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val);
+	public static void glFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val);
+	public static void glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+	public static void glPushMatrix ();
+	public static void glPopMatrix ();
+	public static void glLoadIdentity ();
+	public static void glLoadMatrixd ([CCode (array_length = false)] GLdouble[] m);
+	public static void glLoadMatrixf ([CCode (array_length = false)] GLfloat[] m);
+	public static void glMultMatrixd ([CCode (array_length = false)] GLdouble[] m);
+	public static void glMultMatrixf ([CCode (array_length = false)] GLfloat[] m);
+	public static void glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+	public static void glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+	public static void glScaled (GLdouble x, GLdouble y, GLdouble z);
+	public static void glScalef (GLfloat x, GLfloat y, GLfloat z);
+	public static void glTranslated (GLdouble x, GLdouble y, GLdouble z);
+	public static void glTranslatef (GLfloat x, GLfloat y, GLfloat z);
+
+	// Display Lists
+	public static GLboolean glIsList (GLuint list);
+	public static void glDeleteLists (GLuint list, GLsizei range);
+	public static GLuint glGenLists (GLsizei range);
+	public static void glNewList (GLuint list, GLenum mode);
+	public static void glEndList ();
+	public static void glCallList (GLuint list);
+	public static void glCallLists (GLsizei n, GLenum type, [CCode (array_length = false)] GLvoid[] lists);
+	public static void glListBase (GLuint @base);
+
+	// Drawing Functions
+	public static void glBegin (GLenum mode);
+	public static void glEnd ();
+	public static void glVertex2d (GLdouble x, GLdouble y);
+	public static void glVertex2f (GLfloat x, GLfloat y);
+	public static void glVertex2i (GLint x, GLint y);
+	public static void glVertex2s (GLshort x, GLshort y);
+	public static void glVertex3d (GLdouble x, GLdouble y, GLdouble z);
+	public static void glVertex3f (GLfloat x, GLfloat y, GLfloat z);
+	public static void glVertex3i (GLint x, GLint y, GLint z);
+	public static void glVertex3s (GLshort x, GLshort y, GLshort z);
+	public static void glVertex4d (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+	public static void glVertex4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+	public static void glVertex4i (GLint x, GLint y, GLint z, GLint w);
+	public static void glVertex4s (GLshort x, GLshort y, GLshort z, GLshort w);
+	public static void glVertex2dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glVertex2fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glVertex2iv ([CCode (array_length = false)] GLint[] v);
+	public static void glVertex2sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glVertex3dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glVertex3fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glVertex3iv ([CCode (array_length = false)] GLint[] v);
+	public static void glVertex3sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glVertex4dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glVertex4fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glVertex4iv ([CCode (array_length = false)] GLint[] v);
+	public static void glVertex4sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glNormal3b (GLbyte nx, GLbyte ny, GLbyte nz);
+	public static void glNormal3d (GLdouble nx, GLdouble ny, GLdouble nz);
+	public static void glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);
+	public static void glNormal3i (GLint nx, GLint ny, GLint nz);
+	public static void glNormal3s (GLshort nx, GLshort ny, GLshort nz);
+	public static void glNormal3bv ([CCode (array_length = false)] GLbyte[] v);
+	public static void glNormal3dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glNormal3fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glNormal3iv ([CCode (array_length = false)] GLint[] v);
+	public static void glNormal3sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glIndexd (GLdouble c);
+	public static void glIndexf (GLfloat c);
+	public static void glIndexi (GLint c);
+	public static void glIndexs (GLshort c);
+	public static void glIndexub (GLubyte c);
+	public static void glIndexdv ([CCode (array_length = false)] GLdouble[] c);
+	public static void glIndexfv ([CCode (array_length = false)] GLfloat[] c);
+	public static void glIndexiv ([CCode (array_length = false)] GLint[] c);
+	public static void glIndexsv ([CCode (array_length = false)] GLshort[] c);
+	public static void glIndexubv ([CCode (array_length = false)] GLubyte[] c);
+	public static void glColor3b (GLbyte red, GLbyte green, GLbyte blue);
+	public static void glColor3d (GLdouble red, GLdouble green, GLdouble blue);
+	public static void glColor3f (GLfloat red, GLfloat green, GLfloat blue);
+	public static void glColor3i (GLint red, GLint green, GLint blue);
+	public static void glColor3s (GLshort red, GLshort green, GLshort blue);
+	public static void glColor3ub (GLubyte red, GLubyte green, GLubyte blue);
+	public static void glColor3ui (GLuint red, GLuint green, GLuint blue);
+	public static void glColor3us (GLushort red, GLushort green, GLushort blue);
+	public static void glColor4b (GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
+	public static void glColor4d (GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
+	public static void glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+	public static void glColor4i (GLint red, GLint green, GLint blue, GLint alpha);
+	public static void glColor4s (GLshort red, GLshort green, GLshort blue, GLshort alpha);
+	public static void glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+	public static void glColor4ui (GLuint red, GLuint green, GLuint blue, GLuint alpha);
+	public static void glColor4us (GLushort red, GLushort green, GLushort blue, GLushort alpha);
+	public static void glColor3bv ([CCode (array_length = false)] GLbyte[] v);
+	public static void glColor3dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glColor3fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glColor3iv ([CCode (array_length = false)] GLint[] v);
+	public static void glColor3sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glColor3ubv ([CCode (array_length = false)] GLubyte[] v);
+	public static void glColor3uiv ([CCode (array_length = false)] GLuint[] v);
+	public static void glColor3usv ([CCode (array_length = false)] GLushort[] v);
+	public static void glColor4bv ([CCode (array_length = false)] GLbyte[] v);
+	public static void glColor4dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glColor4fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glColor4iv ([CCode (array_length = false)] GLint[] v);
+	public static void glColor4sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glColor4ubv ([CCode (array_length = false)] GLubyte[] v);
+	public static void glColor4uiv ([CCode (array_length = false)] GLuint[] v);
+	public static void glColor4usv ([CCode (array_length = false)] GLushort[] v);
+	public static void glTexCoord1d (GLdouble s);
+	public static void glTexCoord1f (GLfloat s);
+	public static void glTexCoord1i (GLint s);
+	public static void glTexCoord1s (GLshort s);
+	public static void glTexCoord2d (GLdouble s, GLdouble t);
+	public static void glTexCoord2f (GLfloat s, GLfloat t);
+	public static void glTexCoord2i (GLint s, GLint t);
+	public static void glTexCoord2s (GLshort s, GLshort t);
+	public static void glTexCoord3d (GLdouble s, GLdouble t, GLdouble r);
+	public static void glTexCoord3f (GLfloat s, GLfloat t, GLfloat r);
+	public static void glTexCoord3i (GLint s, GLint t, GLint r);
+	public static void glTexCoord3s (GLshort s, GLshort t, GLshort r);
+	public static void glTexCoord4d (GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+	public static void glTexCoord4f (GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+	public static void glTexCoord4i (GLint s, GLint t, GLint r, GLint q);
+	public static void glTexCoord4s (GLshort s, GLshort t, GLshort r, GLshort q);
+	public static void glTexCoord1dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glTexCoord1fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glTexCoord1iv ([CCode (array_length = false)] GLint[] v);
+	public static void glTexCoord1sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glTexCoord2dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glTexCoord2fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glTexCoord2iv ([CCode (array_length = false)] GLint[] v);
+	public static void glTexCoord2sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glTexCoord3dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glTexCoord3fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glTexCoord3iv ([CCode (array_length = false)] GLint[] v);
+	public static void glTexCoord3sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glTexCoord4dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glTexCoord4fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glTexCoord4iv ([CCode (array_length = false)] GLint[] v);
+	public static void glTexCoord4sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glRasterPos2d (GLdouble x, GLdouble y);
+	public static void glRasterPos2f (GLfloat x, GLfloat y);
+	public static void glRasterPos2i (GLint x, GLint y);
+	public static void glRasterPos2s (GLshort x, GLshort y);
+	public static void glRasterPos3d (GLdouble x, GLdouble y, GLdouble z);
+	public static void glRasterPos3f (GLfloat x, GLfloat y, GLfloat z);
+	public static void glRasterPos3i (GLint x, GLint y, GLint z);
+	public static void glRasterPos3s (GLshort x, GLshort y, GLshort z);
+	public static void glRasterPos4d (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+	public static void glRasterPos4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+	public static void glRasterPos4i (GLint x, GLint y, GLint z, GLint w);
+	public static void glRasterPos4s (GLshort x, GLshort y, GLshort z, GLshort w);
+	public static void glRasterPos2dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glRasterPos2fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glRasterPos2iv ([CCode (array_length = false)] GLint[] v);
+	public static void glRasterPos2sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glRasterPos3dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glRasterPos3fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glRasterPos3iv ([CCode (array_length = false)] GLint[] v);
+	public static void glRasterPos3sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glRasterPos4dv ([CCode (array_length = false)] GLdouble[] v);
+	public static void glRasterPos4fv ([CCode (array_length = false)] GLfloat[] v);
+	public static void glRasterPos4iv ([CCode (array_length = false)] GLint[] v);
+	public static void glRasterPos4sv ([CCode (array_length = false)] GLshort[] v);
+	public static void glRectd (GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
+	public static void glRectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
+	public static void glRecti (GLint x1, GLint y1, GLint x2, GLint y2);
+	public static void glRects (GLshort x1, GLshort y1, GLshort x2, GLshort y2);
+	public static void glRectdv ([CCode (array_length = false)] GLdouble[] v1, [CCode (array_length = false)] GLdouble[] v2);
+	public static void glRectfv ([CCode (array_length = false)] GLfloat[] v1, [CCode (array_length = false)] GLfloat[] v2);
+	public static void glRectiv ([CCode (array_length = false)] GLint[] v1, [CCode (array_length = false)] GLint[] v2);
+	public static void glRectsv ([CCode (array_length = false)] GLshort[] v1, [CCode (array_length = false)] GLshort[] v2);
+    
+	// Vertex Arrays  (1.1)
+	public static void glVertexPointer (GLint size, GLenum type, GLsizei stride, GLvoid* ptr);
+	public static void glNormalPointer (GLenum type, GLsizei stride, GLvoid* ptr);
+	public static void glColorPointer (GLint size, GLenum type, GLsizei stride, GLvoid* ptr);
+	public static void glIndexPointer (GLenum type, GLsizei stride, GLvoid* ptr);
+	public static void glTexCoordPointer (GLint size, GLenum type, GLsizei stride, GLvoid* ptr);
+	public static void glEdgeFlagPointer (GLsizei stride, GLvoid* ptr);
+	public static void glGetPointerv (GLenum pname, GLvoid** params); 
+	public static void glArrayElement (GLint i);
+	public static void glDrawArrays (GLenum mode, GLint first, GLsizei count);
+	public static void glDrawElements (GLenum mode, GLsizei count, GLenum type, GLvoid* indices);
+	public static void glInterleavedArrays (GLenum format, GLsizei stride, GLvoid* pointer);
+
+	// Lighting
+	public static void glShadeModel (GLenum mode);
+	public static void glLightf (GLenum light, GLenum pname, GLfloat param);
+	public static void glLighti (GLenum light, GLenum pname, GLint param);
+	public static void glLightfv (GLenum light, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glLightiv (GLenum light, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glGetLightfv (GLenum light, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glGetLightiv (GLenum light, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glLightModelf (GLenum pname, GLfloat param);
+	public static void glLightModeli (GLenum pname, GLint param);
+	public static void glLightModelfv (GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glLightModeliv (GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glMaterialf (GLenum face, GLenum pname, GLfloat param);
+	public static void glMateriali (GLenum face, GLenum pname, GLint param);
+	public static void glMaterialfv (GLenum face, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glMaterialiv (GLenum face, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glGetMaterialfv (GLenum face, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glGetMaterialiv (GLenum face, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glColorMaterial (GLenum face, GLenum mode);
+
+	// Raster functions
+	public static void glPixelZoom (GLfloat xfactor, GLfloat yfactor);
+	public static void glPixelStoref (GLenum pname, GLfloat param);
+	public static void glPixelStorei (GLenum pname, GLint param);
+	public static void glPixelTransferf (GLenum pname, GLfloat param);
+	public static void glPixelTransferi (GLenum pname, GLint param);
+	public static void glPixelMapfv (GLenum map, GLsizei mapsize, [CCode (array_length = false)] GLfloat[] values);
+	public static void glPixelMapuiv (GLenum map, GLsizei mapsize, [CCode (array_length = false)] GLuint[] values);
+	public static void glPixelMapusv (GLenum map, GLsizei mapsize, [CCode (array_length = false)] GLushort[] values);
+	public static void glGetPixelMapfv (GLenum map, [CCode (array_length = false)] GLfloat[] values);
+	public static void glGetPixelMapuiv (GLenum map, [CCode (array_length = false)] GLuint[] values);
+	public static void glGetPixelMapusv (GLenum map, [CCode (array_length = false)] GLushort[] values);
+	public static void glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, GLubyte* bitmap);
+	public static void glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+	public static void glDrawPixels (GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+	public static void glCopyPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
+
+	// Stenciling
+	public static void glStencilFunc (GLenum func, GLint @ref, GLuint mask);
+	public static void glStencilMask (GLuint mask);
+	public static void glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+	public static void glClearStencil (GLint s);
+
+	// Texture mapping
+	public static void glTexGend (GLenum coord, GLenum pname, GLdouble param);
+	public static void glTexGenf (GLenum coord, GLenum pname, GLfloat param);
+	public static void glTexGeni (GLenum coord, GLenum pname, GLint param);
+	public static void glTexGendv (GLenum coord, GLenum pname, [CCode (array_length = false)] GLdouble[] params);
+	public static void glTexGenfv (GLenum coord, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glTexGeniv (GLenum coord, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glGetTexGendv (GLenum coord, GLenum pname, [CCode (array_length = false)] GLdouble[] params);
+	public static void glGetTexGenfv (GLenum coord, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glGetTexGeniv (GLenum coord, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glTexEnvf (GLenum target, GLenum pname, GLfloat param);
+	public static void glTexEnvi (GLenum target, GLenum pname, GLint param);
+	public static void glTexEnvfv (GLenum target, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glTexEnviv (GLenum target, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glGetTexEnvfv (GLenum target, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glGetTexEnviv (GLenum target, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+	public static void glTexParameteri (GLenum target, GLenum pname, GLint param);
+	public static void glTexParameterfv (GLenum target, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glTexParameteriv (GLenum target, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glGetTexParameterfv (GLenum target, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glGetTexParameteriv (GLenum target, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glGetTexLevelParameterfv (GLenum target, GLint level, [CCode (array_length = false)] GLenum pname, GLfloat[] params);
+	public static void glGetTexLevelParameteriv (GLenum target, GLint level, GLenum pname,[CCode (array_length = false)]  GLint[] params);
+	public static void glTexImage1D (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, GLvoid* pixels);
+	public static void glTexImage2D (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLvoid* pixels);
+	public static void glGetTexImage (GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
+
+	// 1.1 functions
+	public static void glGenTextures (GLsizei n, [CCode (array_length = false)] GLuint[] textures);
+	public static void glDeleteTextures (GLsizei n, [CCode (array_length = false)] GLuint[] textures);
+	public static void glBindTexture (GLenum target, GLuint texture);
+	public static void glPrioritizeTextures (GLsizei n, [CCode (array_length = false)] GLuint[] textures, [CCode (array_length = false)] GLclampf[] priorities);
+	public static GLboolean glAreTexturesResident (GLsizei n, [CCode (array_length = false)] GLuint[] textures, [CCode (array_length = false)] GLboolean[] residences);
+	public static GLboolean glIsTexture (GLuint texture);
+	public static void glTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, GLvoid* pixels);
+	public static void glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+	public static void glCopyTexImage1D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+	public static void glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+	public static void glCopyTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+	public static void glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+
+	// Evaluators
+	public static void glMap1d (GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, [CCode (array_length = false)] GLdouble[] points);
+	public static void glMap1f (GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, [CCode (array_length = false)] GLfloat[] points);
+	public static void glMap2d (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder,[CCode (array_length = false)]  GLdouble[] points);
+	public static void glMap2f (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, [CCode (array_length = false)] GLfloat[] points);
+	public static void glGetMapdv (GLenum target, GLenum query, [CCode (array_length = false)] GLdouble[] v);
+	public static void glGetMapfv (GLenum target, GLenum query, [CCode (array_length = false)] GLfloat[] v);
+	public static void glGetMapiv (GLenum target, GLenum query, [CCode (array_length = false)] GLint[] v);
+	public static void glEvalCoord1d (GLdouble u);
+	public static void glEvalCoord1f (GLfloat u);
+	public static void glEvalCoord1dv ([CCode (array_length = false)] GLdouble[] u);
+	public static void glEvalCoord1fv ([CCode (array_length = false)] GLfloat[] u);
+	public static void glEvalCoord2d (GLdouble u, GLdouble v);
+	public static void glEvalCoord2f (GLfloat u, GLfloat v);
+	public static void glEvalCoord2dv ([CCode (array_length = false)] GLdouble[] u);
+	public static void glEvalCoord2fv ([CCode (array_length = false)] GLfloat[] u);
+	public static void glMapGrid1d (GLint un, GLdouble u1, GLdouble u2);
+	public static void glMapGrid1f (GLint un, GLfloat u1, GLfloat u2);
+	public static void glMapGrid2d (GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);
+	public static void glMapGrid2f (GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);
+	public static void glEvalPoint1 (GLint i);
+	public static void glEvalPoint2 (GLint i, GLint j);
+	public static void glEvalMesh1 (GLenum mode, GLint i1, GLint i2);
+	public static void glEvalMesh2 (GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
+
+	// Fog
+	public static void glFogf (GLenum pname, GLfloat param);
+	public static void glFogi (GLenum pname, GLint param);
+	public static void glFogfv (GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glFogiv (GLenum pname, [CCode (array_length = false)] GLint[] params);
+
+	// Selection and Feedback
+	public static void glFeedbackBuffer (GLsizei size, GLenum type, [CCode (array_length = false)] GLfloat[] buffer);
+	public static void glPassThrough (GLfloat token);
+	public static void glSelectBuffer (GLsizei size, [CCode (array_length = false)] GLuint[] buffer);
+	public static void glInitNames ();
+	public static void glLoadName (GLuint name);
+	public static void glPushName (GLuint name);
+	public static void glPopName ();
+	
+	// OpenGL 1.2
+	public static void glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid* indices);
+	public static void glTexImage3D (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLvoid* pixels);
+	public static void glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid* pixels);
+	public static void glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+	
+	// GL_ARB_imaging
+	public static void glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, GLvoid* table);
+	public static void glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, GLvoid* data);
+	public static void glColorTableParameteriv (GLenum target, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glColorTableParameterfv (GLenum target, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+	public static void glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+	public static void glGetColorTable (GLenum target, GLenum format, GLenum type, out GLvoid table);
+	public static void glGetColorTableParameterfv (GLenum target, GLenum pname, out GLfloat params);
+	public static void glGetColorTableParameteriv (GLenum target, GLenum pname, out GLint params);
+	public static void glBlendEquation (GLenum mode);
+	public static void glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+	public static void glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+	public static void glResetHistogram (GLenum target);
+	public static void glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, out GLvoid values);
+	public static void glGetHistogramParameterfv (GLenum target, GLenum pname, out GLfloat params);
+	public static void glGetHistogramParameteriv (GLenum target, GLenum pname, out GLint params);
+	public static void glMinmax (GLenum target, GLenum internalformat, GLboolean sink);
+	public static void glResetMinmax (GLenum target);
+	public static void glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum types, out GLvoid values);
+	public static void glGetMinmaxParameterfv (GLenum target, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glGetMinmaxParameteriv (GLenum target, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, GLvoid* image);
+	public static void glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* image);
+	public static void glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params);
+	public static void glConvolutionParameterfv (GLenum target, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glConvolutionParameteri (GLenum target, GLenum pname, GLint params);
+	public static void glConvolutionParameteriv (GLenum target, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+	public static void glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+	public static void glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image);
+	public static void glGetConvolutionParameterfv (GLenum target, GLenum pname, [CCode (array_length = false)] GLfloat[] params);
+	public static void glGetConvolutionParameteriv (GLenum target, GLenum pname, [CCode (array_length = false)] GLint[] params);
+	public static void glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* row, GLvoid* column);
+	public static void glGetSeparableFilter (GLenum target, GLenum format, GLenum type, out GLvoid row, out GLvoid column, out GLvoid span);
+
+	//OpenGL 1.3
+	public static void glActiveTexture (GLenum texture);
+	public static void glClientActiveTexture (GLenum texture);
+	public static void glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, GLvoid* data);
+	public static void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLvoid* data);
+	public static void glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLvoid* data);
+	public static void glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, GLvoid* data);
+	public static void glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLvoid* data);
+	public static void glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLvoid* data);
+	public static void glGetCompressedTexImage (GLenum target, GLint lod, out GLvoid img);
+	public static void glMultiTexCoord1d (GLenum target, GLdouble s);
+	public static void glMultiTexCoord1dv (GLenum target, [CCode (array_length = false)] GLdouble[] v);
+	public static void glMultiTexCoord1f (GLenum target, GLfloat s);
+	public static void glMultiTexCoord1fv (GLenum target, [CCode (array_length = false)] GLfloat[] v);
+	public static void glMultiTexCoord1i (GLenum target, GLint s);
+	public static void glMultiTexCoord1iv (GLenum target, [CCode (array_length = false)] GLint[] v);
+	public static void glMultiTexCoord1s (GLenum target, GLshort s);
+	public static void glMultiTexCoord1sv (GLenum target, [CCode (array_length = false)] GLshort[] v);
+	public static void glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t);
+	public static void glMultiTexCoord2dv (GLenum target, [CCode (array_length = false)] GLdouble[] v);
+	public static void glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t);
+	public static void glMultiTexCoord2fv (GLenum target, [CCode (array_length = false)] GLfloat[] v);
+	public static void glMultiTexCoord2i (GLenum target, GLint s, GLint t);
+	public static void glMultiTexCoord2iv (GLenum target, [CCode (array_length = false)] GLint[] v);
+	public static void glMultiTexCoord2s (GLenum target, GLshort s, GLshort t);
+	public static void glMultiTexCoord2sv (GLenum target, [CCode (array_length = false)] GLshort[] v);
+	public static void glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+	public static void glMultiTexCoord3dv (GLenum target, [CCode (array_length = false)] GLdouble[] v);
+	public static void glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+	public static void glMultiTexCoord3fv (GLenum target, [CCode (array_length = false)] GLfloat[] v);
+	public static void glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r);
+	public static void glMultiTexCoord3iv (GLenum target, [CCode (array_length = false)] GLint[] v);
+	public static void glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r);
+	public static void glMultiTexCoord3sv (GLenum target, [CCode (array_length = false)] GLshort[] v);
+	public static void glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+	public static void glMultiTexCoord4dv (GLenum target, [CCode (array_length = false)] GLdouble[] v);
+	public static void glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+	public static void glMultiTexCoord4fv (GLenum target, [CCode (array_length = false)] GLfloat[] v);
+	public static void glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q);
+	public static void glMultiTexCoord4iv (GLenum target, [CCode (array_length = false)] GLint[] v);
+	public static void glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+	public static void glMultiTexCoord4sv (GLenum target, [CCode (array_length = false)] GLshort[] v);
+	public static void glLoadTransposeMatrixd ([CCode (array_length = false)] GLdouble[] m);
+	public static void glLoadTransposeMatrixf ([CCode (array_length = false)] GLfloat[] m);
+	public static void glMultTransposeMatrixd ([CCode (array_length = false)] GLdouble[] m);
+	public static void glMultTransposeMatrixf ([CCode (array_length = false)] GLfloat[] m);
+	public static void glSampleCoverage (GLclampf @value, GLboolean invert);
+	
+	// GL_ARB_multitexture (ARB extension 1 and OpenGL 1.2.1)
+	public static void glActiveTextureARB (GLenum texture);
+	public static void glClientActiveTextureARB (GLenum texture);
+	public static void glMultiTexCoord1dARB (GLenum target, GLdouble s);
+	public static void glMultiTexCoord1dvARB (GLenum target, [CCode (array_length = false)] GLdouble[] v);
+	public static void glMultiTexCoord1fARB (GLenum target, GLfloat s);
+	public static void glMultiTexCoord1fvARB (GLenum target, [CCode (array_length = false)] GLfloat[] v);
+	public static void glMultiTexCoord1iARB (GLenum target, GLint s);
+	public static void glMultiTexCoord1ivARB (GLenum target, [CCode (array_length = false)] GLint[] v);
+	public static void glMultiTexCoord1sARB (GLenum target, GLshort s);
+	public static void glMultiTexCoord1svARB (GLenum target, [CCode (array_length = false)] GLshort[] v);
+	public static void glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t);
+	public static void glMultiTexCoord2dvARB (GLenum target, [CCode (array_length = false)] GLdouble[] v);
+	public static void glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t);
+	public static void glMultiTexCoord2fvARB (GLenum target, [CCode (array_length = false)] GLfloat[] v);
+	public static void glMultiTexCoord2iARB (GLenum target, GLint s, GLint t);
+	public static void glMultiTexCoord2ivARB (GLenum target, [CCode (array_length = false)] GLint[] v);
+	public static void glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t);
+	public static void glMultiTexCoord2svARB (GLenum target, [CCode (array_length = false)] GLshort[] v);
+	public static void glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+	public static void glMultiTexCoord3dvARB (GLenum target, [CCode (array_length = false)] GLdouble[] v);
+	public static void glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+	public static void glMultiTexCoord3fvARB (GLenum target, [CCode (array_length = false)] GLfloat[] v);
+	public static void glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r);
+	public static void glMultiTexCoord3ivARB (GLenum target, [CCode (array_length = false)] GLint[] v);
+	public static void glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r);
+	public static void glMultiTexCoord3svARB (GLenum target, [CCode (array_length = false)] GLshort[] v);
+	public static void glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+	public static void glMultiTexCoord4dvARB (GLenum target, [CCode (array_length = false)] GLdouble[] v);
+	public static void glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+	public static void glMultiTexCoord4fvARB (GLenum target, [CCode (array_length = false)] GLfloat[] v);
+	public static void glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q);
+	public static void glMultiTexCoord4ivARB (GLenum target, [CCode (array_length = false)] GLint[] v);
+	public static void glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+	public static void glMultiTexCoord4svARB (GLenum target, [CCode (array_length = false)] GLshort[] v);
+}
+
diff --git a/glchess/src/glchess.vala b/glchess/src/glchess.vala
new file mode 100644
index 0000000..163f528
--- /dev/null
+++ b/glchess/src/glchess.vala
@@ -0,0 +1,1108 @@
+public class Application
+{
+    private GLib.Settings settings;
+    private Gtk.Builder builder;
+    private Gtk.Builder preferences_builder;
+    private Gtk.Window window;
+    private Gtk.Widget save_menu;
+    private Gtk.Widget save_as_menu;
+    private Gtk.MenuItem fullscreen_menu;
+    private Gtk.InfoBar info_bar;
+    private Gtk.Label info_title_label;
+    private Gtk.Label info_label;
+    private Gtk.Container view_container;
+    private ChessViewOptions view_options;
+    private ChessView view;
+    private Gtk.Widget first_move_button;
+    private Gtk.Widget prev_move_button;
+    private Gtk.Widget next_move_button;
+    private Gtk.Widget last_move_button;
+    private Gtk.ComboBox history_combo;
+    private Gtk.Dialog? preferences_dialog = null;
+    private Gtk.ComboBox duration_combo;
+    private Gtk.Adjustment duration_adjustment;
+    private Gtk.Container custom_duration_box;
+    private Gtk.ComboBox custom_duration_units_combo;
+    private uint save_duration_timeout = 0;
+    private Gtk.FileChooserDialog? open_dialog = null;
+    private Gtk.InfoBar? open_dialog_info_bar = null;
+    private Gtk.Label? open_dialog_error_label = null;
+    private Gtk.FileChooserDialog? save_dialog = null;
+    private Gtk.InfoBar? save_dialog_info_bar = null;
+    private Gtk.Label? save_dialog_error_label = null;
+    private Gtk.AboutDialog? about_dialog = null;
+
+    private ChessGame game;
+    private GLib.List<AIProfile> ai_profiles;
+    private ChessPlayer? opponent = null;
+    private ChessEngine? opponent_engine = null;
+
+    public Application ()
+    {
+        settings = new GLib.Settings ("org.gnome.glchess.Settings");
+
+        builder = new Gtk.Builder ();
+        try
+        {
+            builder.add_from_file ("data/glchess.ui");
+        }
+        catch (GLib.Error e)
+        {
+            GLib.warning ("Could not load UI: %s", e.message);
+        }
+        window = (Gtk.Window) builder.get_object ("glchess_app");
+        save_menu = (Gtk.Widget) builder.get_object ("menu_save_item");
+        save_as_menu = (Gtk.Widget) builder.get_object ("menu_save_as_item");
+        fullscreen_menu = (Gtk.MenuItem) builder.get_object ("menu_fullscreen");
+        first_move_button = (Gtk.Widget) builder.get_object ("first_move_button");
+        prev_move_button = (Gtk.Widget) builder.get_object ("prev_move_button");
+        next_move_button = (Gtk.Widget) builder.get_object ("next_move_button");
+        last_move_button = (Gtk.Widget) builder.get_object ("last_move_button");
+        history_combo = (Gtk.ComboBox) builder.get_object ("history_combo");
+        settings.bind ("show-toolbar", builder.get_object ("toolbar"), "visible", SettingsBindFlags.DEFAULT);
+        settings.bind ("show-history", builder.get_object ("navigation_box"), "visible", SettingsBindFlags.DEFAULT);
+        var view_box = (Gtk.VBox) builder.get_object ("view_box");
+        view_container = (Gtk.Container) builder.get_object ("view_container");
+        builder.connect_signals (this);
+
+        info_bar = new Gtk.InfoBar ();
+        var content_area = (Gtk.Container) info_bar.get_content_area ();
+        view_box.pack_start (info_bar, true, true, 0);
+        var vbox = new Gtk.VBox (false, 6);
+        vbox.show ();
+        content_area.add (vbox);
+        info_title_label = new Gtk.Label ("");
+        info_title_label.show ();
+        vbox.pack_start (info_title_label, false, true, 0);
+        info_label = new Gtk.Label ("");
+        info_label.show ();
+        vbox.pack_start (info_label, true, true, 0);
+
+        view_options = new ChessViewOptions ();
+        view_options.changed.connect (options_changed_cb);
+        settings.bind ("show-move-hints", view_options, "show-move-hints", SettingsBindFlags.GET);
+        settings.bind ("show-numbering", view_options, "show-numbering", SettingsBindFlags.GET);
+        settings.bind ("piece-theme", view_options, "theme-name", SettingsBindFlags.GET);
+        settings.bind ("show-3d-smooth", view_options, "show-3d-smooth", SettingsBindFlags.GET);
+        settings.bind ("move-format", view_options, "move-format", SettingsBindFlags.GET);
+
+        settings.changed.connect (settings_changed_cb);
+        settings_changed_cb (settings, "show-3d");
+    }
+
+    public void quit ()
+    {
+        if (save_duration_timeout != 0)
+            save_duration ();
+        settings.sync ();
+        Gtk.main_quit ();
+    }
+
+    private void settings_changed_cb (Settings settings, string key)
+    {
+        if (key == "show-3d")
+        {
+            if (view != null)
+                view.destroy ();
+            /*if (settings.get_boolean ("show-3d"))
+                view = new ChessView3D ();
+            else*/
+                view = new ChessView2D ();
+            view.set_size_request (300, 300);
+            view.options = view_options;
+            view_container.add (view);
+            view.show ();
+        }
+    }
+
+    private void update_history_panel ()
+    {
+        if (game == null)
+            return;
+
+        var move_number = view_options.move_number;
+        var n_moves = (int) game.n_moves;
+        if (move_number < 0)
+            move_number += 1 + n_moves;
+
+        first_move_button.sensitive = n_moves > 0 && move_number != 0;
+        prev_move_button.sensitive = move_number > 0;
+        next_move_button.sensitive = move_number < n_moves;
+        last_move_button.sensitive = n_moves > 0 && move_number != n_moves;
+
+        int i = n_moves;
+        foreach (var state in game.move_stack)
+        {
+            if (state.last_move != null)
+            {
+                Gtk.TreeIter iter;
+                if (history_combo.model.iter_nth_child (out iter, null, i))
+                    set_move_text (iter, state.last_move);
+            }
+            i--;
+        }
+    }
+
+    private void options_changed_cb (ChessViewOptions options)
+    {
+        update_history_panel ();
+    }
+
+    private void start_game (bool use_ai = false)
+    {
+        game = new ChessGame ();
+        game.started.connect (game_start_cb);
+        game.turn_started.connect (game_turn_cb);
+        game.moved.connect (game_move_cb);
+        game.ended.connect (game_end_cb);
+
+        var model = (Gtk.ListStore) history_combo.model;
+        model.clear ();
+        Gtk.TreeIter iter;
+        model.append (out iter);
+        model.set (iter, 0, "Game Start", 1, 0, -1);
+        history_combo.set_active_iter (iter);
+
+        view_options.game = game;
+        info_bar.hide ();
+        save_menu.sensitive = false;
+        save_as_menu.sensitive = false;
+        update_history_panel ();
+
+        opponent_engine = get_engine (settings.get_string ("opponent"));
+        opponent = null;
+        if (opponent_engine != null)
+        {
+            if (settings.get_boolean ("play-as-white"))
+                opponent = game.black;
+            else
+                opponent = game.white;
+            opponent_engine.ready_changed.connect (engine_ready_cb);
+            opponent_engine.moved.connect (engine_move_cb);
+            opponent_engine.start ();
+        }
+
+        game.start ();
+    }
+
+    private ChessEngine? get_engine (string name)
+    {
+        ChessEngine engine;
+        AIProfile? profile = null;
+
+        if (name == "human")
+            return null;
+
+        foreach (var p in ai_profiles)
+        {
+            if (name == "" || p.name == name)
+            {
+                profile = p;
+                break;
+            }
+        }
+        if (profile == null)
+        {
+            GLib.warning ("Unknown AI profile %s", name);
+            if (ai_profiles == null)
+                return null;
+            profile = ai_profiles.data;
+        }
+
+        if (profile.protocol == "cecp")
+            engine = new ChessEngineCECP ();
+        else if (profile.protocol == "uci")
+            engine = new ChessEngineUCI ();
+        else
+        {
+            GLib.warning ("Unknown AI protocol %s", profile.protocol);
+            return null;
+        }
+        engine.binary = profile.binary;
+
+        return engine;
+    }
+
+    public void start ()
+    {
+        ai_profiles = load_ai_profiles ("data/engines.conf");
+        foreach (var profile in ai_profiles)
+            GLib.message ("Detected AI profile %s", profile.name);
+
+        start_game ();
+        if (settings.get_boolean ("fullscreen"))
+            window.fullscreen ();
+        show ();
+    }
+
+    private void engine_ready_cb (ChessEngine engine)
+    {
+        if (opponent_engine.ready)
+        {
+            game.start ();
+            view.queue_draw ();
+        }
+    }
+    
+    private void engine_move_cb (ChessEngine engine, string move)
+    {
+        opponent.move (move);
+    }
+
+    private void game_start_cb (ChessGame game)
+    {
+        if (opponent_engine != null)
+            opponent_engine.start_game ();
+    }
+
+    private void game_turn_cb (ChessGame game, ChessPlayer player)
+    {
+        if (opponent_engine != null && player == opponent)
+            opponent_engine.request_move ();
+    }
+
+    private void set_move_text (Gtk.TreeIter iter, ChessMove move)
+    {
+        /* Note there are no move formats for pieces taking kings and this is not allowed in Chess rules */
+        /* Translators: Human Move String: Description of a white pawn moving from %1s to %2s, e.g. 'c2 to c4' */
+        const string human_descriptions[] = {"White pawn moves from %1s to %2s",
+                                             "White pawn at %1s takes the black pawn at %2s",
+                                             "White pawn at %1s takes the black rook at %2s",
+                                             "White pawn at %1s takes the black knight at %2s",
+                                             "White pawn at %1s takes the black bishop at %2s",
+                                             "White pawn at %1s takes the black queen at %2s",
+        /* Translators: Human Move String: Description of a white rook moving from %1s to %2s, e.g. 'a1 to a5' */
+                                             "White rook moves from %1s to %2s",
+                                             "White rook at %1s takes the black pawn at %2s",
+                                             "White rook at %1s takes the black rook at %2s",
+                                             "White rook at %1s takes the black knight at %2s",
+                                             "White rook at %1s takes the black bishop at %2s",
+                                             "White rook at %1s takes the black queen at %2s",
+        /* Translators: Human Move String: Description of a white knight moving from %1s to %2s, e.g. 'b1 to c3' */
+                                             "White knight moves from %1s to %2s",
+                                             "White knight at %1s takes the black pawn at %2s",
+                                             "White knight at %1s takes the black rook at %2s",
+                                             "White knight at %1s takes the black knight at %2s",
+                                             "White knight at %1s takes the black bishop at %2s",
+                                             "White knight at %1s takes the black queen at %2s",
+        /* Translators: Human Move String: Description of a white bishop moving from %1s to %2s, e.g. 'f1 to b5' */
+                                             "White bishop moves from %1s to %2s",
+                                             "White bishop at %1s takes the black pawn at %2s",
+                                             "White bishop at %1s takes the black rook at %2s",
+                                             "White bishop at %1s takes the black knight at %2s",
+                                             "White bishop at %1s takes the black bishop at %2s",
+                                             "White bishop at %1s takes the black queen at %2s",
+        /* Translators: Human Move String: Description of a white queen moving from %1s to %2s, e.g. 'd1 to d4' */
+                                             "White queen moves from %1s to %2s",
+                                             "White queen at %1s takes the black pawn at %2s",
+                                             "White queen at %1s takes the black rook at %2s",
+                                             "White queen at %1s takes the black knight at %2s",
+                                             "White queen at %1s takes the black bishop at %2s",
+                                             "White queen at %1s takes the black queen at %2s",
+        /* Translators: Human Move String: Description of a white king moving from %1s to %2s, e.g. 'e1 to f1' */
+                                             "White king moves from %1s to %2s",
+                                             "White king at %1s takes the black pawn at %2s",
+                                             "White king at %1s takes the black rook at %2s",
+                                             "White king at %1s takes the black knight at %2s",
+                                             "White king at %1s takes the black bishop at %2s",
+                                             "White king at %1s takes the black queen at %2s",
+        /* Translators: Human Move String: Description of a black pawn moving from %1s to %2s, e.g. 'c8 to c6' */
+                                             "Black pawn moves from %1$s to %2$s",
+                                             "Black pawn at %1$s takes the white pawn at %2$s",
+                                             "Black pawn at %1$s takes the white rook at %2$s",
+                                             "Black pawn at %1$s takes the white knight at %2$s",
+                                             "Black pawn at %1$s takes the white bishop at %2$s",
+                                             "Black pawn at %1$s takes the white queen at %2$s",
+        /* Translators: Human Move String: Description of a black rook moving from %1$s to %2$s, e.g. 'a8 to a4' */
+                                             "Black rook moves from %1s to %2s",
+                                             "Black rook at %1s takes the white pawn at %2s",
+                                             "Black rook at %1s takes the white rook at %2s",
+                                             "Black rook at %1s takes the white knight at %2s",
+                                             "Black rook at %1s takes the white bishop at %2s",
+                                             "Black rook at %1s takes the white queen at %2s",
+        /* Translators: Human Move String: Description of a black knight moving from %1s to %2s, e.g. 'b8 to c6' */
+                                             "Black knight moves from %1s to %2s",
+                                             "Black knight at %1s takes the white pawn at %2s",
+                                             "Black knight at %1s takes the white rook at %2s",
+                                             "Black knight at %1s takes the white knight at %2s",
+                                             "Black knight at %1s takes the white bishop at %2s",
+                                             "Black knight at %1s takes the white queen at %2s",
+        /* Translators: Human Move String: Description of a black bishop moving from %1s to %2s, e.g. 'f8 to b3' */
+                                             "Black bishop moves from %1s to %2s",
+                                             "Black bishop at %1s takes the white pawn at %2s",
+                                             "Black bishop at %1s takes the white rook at %2s",
+                                             "Black bishop at %1s takes the white knight at %2s",
+                                             "Black bishop at %1s takes the white bishop at %2s",
+                                             "Black bishop at %1s takes the white queen at %2s",
+        /* Translators: Human Move String: Description of a black queen moving from %1s to %2s, e.g. 'd8 to d5' */
+                                             "Black queen moves from %1s to %2s",
+                                             "Black queen at %1s takes the white pawn at %2s",
+                                             "Black queen at %1s takes the white rook at %2s",
+                                             "Black queen at %1s takes the white knight at %2s",
+                                             "Black queen at %1s takes the white bishop at %2s",
+                                             "Black queen at %1s takes the white queen at %2s",
+        /* Translators: Human Move String: Description of a black king moving from %1s to %2s, e.g. 'e8 to f8' */
+                                             "Black king moves from %1s to %2s",
+                                             "Black king at %1s takes the white pawn at %2s",
+                                             "Black king at %1s takes the white rook at %2s",
+                                             "Black king at %1s takes the white knight at %2s",
+                                             "Black king at %1s takes the white bishop at %2s",
+                                             "Black king at %1s takes the white queen at %2s"};
+
+        var move_text = "";
+        switch (view_options.move_format)
+        {
+        case "human":
+            int index;
+            if (move.victim == null)
+                index = 0;
+            else
+                index = move.victim.type + 1;
+            index *= move.piece.type;
+            if (move.piece.player.color == Color.BLACK)
+                index += 36;
+
+            var start = "%c%d".printf ('a' + move.f0, move.r0 + 1);
+            var end = "%c%d".printf ('a' + move.f1, move.r1 + 1);
+            move_text = human_descriptions[index].printf (start, end);
+            break;
+
+        case "san":
+            move_text = move.san;
+            break;
+
+        case "fan":
+            move_text = move.fan;
+            break;
+
+        default:
+        case "lan":
+            move_text = move.lan;
+            break;
+        }
+
+        var model = (Gtk.ListStore) history_combo.model;
+        var label = "%u%c. %s".printf ((move.number + 1) / 2, move.number % 2 == 0 ? 'b' : 'a', move_text);
+        model.set (iter, 0, label, -1);
+    }
+
+    private void game_move_cb (ChessGame game, ChessMove move)
+    {
+        Gtk.TreeIter iter;
+        var model = (Gtk.ListStore) history_combo.model;
+        model.append (out iter);
+        model.set (iter, 1, game.n_moves, -1);        
+        set_move_text (iter, move);
+        if (view_options.move_number == -1)
+            history_combo.set_active_iter (iter);
+
+        save_menu.sensitive = true;
+        save_as_menu.sensitive = true;
+        update_history_panel ();
+
+        if (opponent_engine != null)
+            opponent_engine.report_move (move);
+        view.queue_draw ();
+    }
+
+    private void game_end_cb (ChessGame game)
+    {
+        string title = "";
+        switch (game.result)
+        {
+        case ChessResult.WHITE_WON:
+            title = "White wins";
+            break;
+        case ChessResult.BLACK_WON:
+            title = "Black wins";
+            break;
+        case ChessResult.DRAW:
+            title = "Game is drawn";
+            break;
+        default:
+            break;
+        }
+
+        string reason = "";
+        switch (game.rule)
+        {
+        case ChessRule.CHECKMATE:
+            /* Message displayed when the game ends due to a player being checkmated */
+            reason = "Opponent is in check and cannot move (checkmate)";
+            break;
+        case ChessRule.STALEMATE:
+            /* Message displayed when the game terminates due to a stalemate */
+            reason = "Opponent cannot move (stalemate)";
+            break;
+        case ChessRule.FIFTY_MOVES:
+            /* Message displayed when the game is drawn due to the fifty move rule */
+            reason = "No piece has been taken or pawn moved in the last fifty moves";
+            break;
+        case ChessRule.TIMEOUT:
+            /* Message displayed when the game ends due to one player's clock stopping */
+            reason = "Opponent has run out of time";
+            break;
+        case ChessRule.THREE_FOLD_REPETITION:
+            /* Message displayed when the game is drawn due to the three-fold-repitition rule */
+            reason = "The same board state has occurred three times (three fold repetition)";
+            break;
+        case ChessRule.INSUFFICIENT_MATERIAL:
+            /* Message displayed when the game is drawn due to the insufficient material rule */
+            reason = "Neither player can cause checkmate (insufficient material)";
+            break;
+        case ChessRule.RESIGN:
+            if (game.result == ChessResult.WHITE_WON)
+            {
+                /* Message displayed when the game ends due to the black player resigning */
+                reason = "The black player has resigned";
+            }
+            else
+            {
+                /* Message displayed when the game ends due to the white player resigning */
+                reason = "The white player has resigned";
+            }
+            break;
+        case ChessRule.ABANDONMENT:
+            /* Message displayed when a game is abandoned */
+            reason = "The game has been abandoned";
+            break;
+        case ChessRule.DEATH:
+            /* Message displayed when the game ends due to a player dying */
+            reason = "One of the players has died";
+            break;
+        }
+
+        info_title_label.set_markup ("<big><b>%s</b></big>".printf (title));
+        info_label.set_text (reason);
+        info_bar.show ();
+    }
+
+    public void show ()
+    {
+        window.show ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT glchess_app_delete_event_cb", instance_pos = -1)]
+    public bool glchess_app_delete_event_cb (Gtk.Widget widget, Gdk.Event event)
+    {
+        quit ();
+        return false;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT glchess_app_window_state_event_cb", instance_pos = -1)]
+    public bool glchess_app_window_state_event_cb (Gtk.Widget widget, Gdk.EventWindowState event)
+    {
+        if ((event.changed_mask & Gdk.WindowState.FULLSCREEN) != 0)
+        {
+            bool is_fullscreen = (event.new_window_state & Gdk.WindowState.FULLSCREEN) != 0;
+            settings.set_boolean ("fullscreen", is_fullscreen);
+            fullscreen_menu.label = is_fullscreen ? Gtk.Stock.LEAVE_FULLSCREEN : Gtk.Stock.FULLSCREEN;
+        }
+
+        return false;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT new_game_cb", instance_pos = -1)]
+    public void new_game_cb (Gtk.Widget widget)
+    {
+        start_game ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT resign_cb", instance_pos = -1)]
+    public void resign_cb (Gtk.Widget widget)
+    {
+        game.current_player.resign ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT claim_draw_cb", instance_pos = -1)]
+    public void claim_draw_cb (Gtk.Widget widget)
+    {
+        game.current_player.claim_draw ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT undo_move_cb", instance_pos = -1)]
+    public void undo_move_cb (Gtk.Widget widget)
+    {
+        GLib.warning ("FIXME: Undo last move");
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT quit_cb", instance_pos = -1)]
+    public void quit_cb (Gtk.Widget widget)
+    {
+        quit ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT black_time_draw_cb", instance_pos = -1)]
+    public bool black_time_draw_cb (Gtk.Widget widget, Cairo.Context c)
+    {
+        return false;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT white_time_draw_cb", instance_pos = -1)]
+    public bool white_time_draw_cb (Gtk.Widget widget, Cairo.Context c)
+    {
+        return false;    
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT history_combo_changed_cb", instance_pos = -1)]
+    public void history_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        Gtk.TreeIter iter;
+        if (!combo.get_active_iter (out iter))
+            return;
+        int move_number;
+        combo.model.get (iter, 1, out move_number, -1);
+        if (move_number == game.n_moves)
+            move_number = -1;
+        view_options.move_number = move_number;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT history_latest_clicked_cb", instance_pos = -1)]
+    public void history_latest_clicked_cb (Gtk.Widget widget)
+    {
+        view_options.move_number = -1;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT history_next_clicked_cb", instance_pos = -1)]
+    public void history_next_clicked_cb (Gtk.Widget widget)
+    {
+        int move_number = view_options.move_number + 1;
+        if (move_number == game.n_moves)
+            view_options.move_number = -1;
+        else
+            view_options.move_number = move_number;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT history_previous_clicked_cb", instance_pos = -1)]
+    public void history_previous_clicked_cb (Gtk.Widget widget)
+    {
+        if (view_options.move_number == -1)
+            view_options.move_number = (int) game.n_moves - 1;
+        else
+            view_options.move_number = view_options.move_number - 1;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT history_start_clicked_cb", instance_pos = -1)]
+    public void history_start_clicked_cb (Gtk.Widget widget)
+    {
+        view_options.move_number = 0;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT toggle_fullscreen_cb", instance_pos = -1)]
+    public void toggle_fullscreen_cb (Gtk.Widget widget)
+    {
+        if (fullscreen_menu.label == Gtk.Stock.FULLSCREEN)
+            window.fullscreen ();
+        else
+            window.unfullscreen ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT preferences_cb", instance_pos = -1)]
+    public void preferences_cb (Gtk.Widget widget)
+    {
+        if (preferences_dialog != null)
+        {
+            preferences_dialog.present ();
+            return;
+        }
+
+        preferences_builder = new Gtk.Builder ();
+        try
+        {
+            preferences_builder.add_from_file ("data/preferences.ui");
+        }
+        catch (GLib.Error e)
+        {
+            GLib.warning ("Could not load preferences UI: %s", e.message);
+        }
+        preferences_dialog = (Gtk.Dialog) preferences_builder.get_object ("preferences");
+        
+        settings.bind ("show-numbering", preferences_builder.get_object ("show_numbering_check"),
+                       "active", SettingsBindFlags.DEFAULT);
+        settings.bind ("show-move-hints", preferences_builder.get_object ("show_move_hints_check"),
+                       "active", SettingsBindFlags.DEFAULT);
+        settings.bind ("show-toolbar", preferences_builder.get_object ("show_toolbar_check"),
+                       "active", SettingsBindFlags.DEFAULT);
+        settings.bind ("show-history", preferences_builder.get_object ("show_history_check"),
+                       "active", SettingsBindFlags.DEFAULT);
+        settings.bind ("show-3d", preferences_builder.get_object ("show_3d_check"),
+                       "active", SettingsBindFlags.DEFAULT);
+        settings.bind ("show-3d-smooth", preferences_builder.get_object ("show_3d_smooth_check"),
+                       "active", SettingsBindFlags.DEFAULT);
+
+        var side_combo = (Gtk.ComboBox) preferences_builder.get_object ("side_combo");
+        side_combo.set_active (settings.get_boolean ("play-as-white") ? 0 : 1);
+
+        var ai_combo = (Gtk.ComboBox) preferences_builder.get_object ("opponent_combo");
+        var ai_model = (Gtk.ListStore) ai_combo.model;
+        var opponent_name = settings.get_string ("opponent");
+        if (opponent_name == "human")
+            ai_combo.set_active (0);
+        foreach (var p in ai_profiles)
+        {
+            Gtk.TreeIter iter;
+            ai_model.append (out iter);
+            ai_model.set (iter, 0, p.name, 1, p.name, -1);
+            if (p.name == opponent_name || (opponent_name == "" && ai_combo.get_active () == -1))
+                ai_combo.set_active_iter (iter);
+        }
+        settings.bind ("show-history", ai_combo, "visible", SettingsBindFlags.SET);
+
+        var difficulty_combo = (Gtk.ComboBox) preferences_builder.get_object ("difficulty_combo");
+        set_combo (difficulty_combo, 1, settings.get_string ("difficulty"));
+
+        duration_combo = (Gtk.ComboBox) preferences_builder.get_object ("duration_combo");
+        duration_adjustment = (Gtk.Adjustment) preferences_builder.get_object ("duration_adjustment");
+        custom_duration_box = (Gtk.Container) preferences_builder.get_object ("custom_duration_box");
+        custom_duration_units_combo = (Gtk.ComboBox) preferences_builder.get_object ("custom_duration_units_combo");
+        set_duration (settings.get_int ("duration"));
+
+        var orientation_combo = (Gtk.ComboBox) preferences_builder.get_object ("orientation_combo");
+        set_combo (orientation_combo, 1, settings.get_string ("board-side"));
+
+        var move_combo = (Gtk.ComboBox) preferences_builder.get_object ("move_format_combo");
+        set_combo (move_combo, 1, settings.get_string ("move-format"));
+
+        var promotion_combo = (Gtk.ComboBox) preferences_builder.get_object ("promotion_type_combo");
+        set_combo (promotion_combo, 1, settings.get_string ("promotion-type"));
+
+        var theme_combo = (Gtk.ComboBox) preferences_builder.get_object ("piece_style_combo");
+        set_combo (theme_combo, 1, settings.get_string ("piece-theme"));
+
+        preferences_builder.connect_signals (this);
+
+        preferences_dialog.present ();
+    }
+
+    private void set_combo (Gtk.ComboBox combo, int value_index, string value)
+    {
+        Gtk.TreeIter iter;
+        var model = combo.model;
+        if (!model.get_iter_first (out iter))
+            return;
+        do
+        {
+            string v;
+            model.get (iter, value_index, out v, -1);
+            if (v == value)
+            {
+                combo.set_active_iter (iter);
+                return;
+            }
+        } while (model.iter_next (ref iter));
+    }
+
+    private string? get_combo (Gtk.ComboBox combo, int value_index)
+    {
+        string value;
+        Gtk.TreeIter iter;
+        if (!combo.get_active_iter (out iter))
+            return null;
+        combo.model.get (iter, value_index, out value, -1);
+        return value;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT side_combo_changed_cb", instance_pos = -1)]
+    public void side_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        Gtk.TreeIter iter;
+        if (!combo.get_active_iter (out iter))
+            return;
+        bool play_as_white;
+        combo.model.get (iter, 1, out play_as_white, -1);
+        settings.set_boolean ("play-as-white", play_as_white);
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT opponent_combo_changed_cb", instance_pos = -1)]
+    public void opponent_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        Gtk.TreeIter iter;
+        if (!combo.get_active_iter (out iter))
+            return;
+        string opponent;
+        combo.model.get (iter, 1, out opponent, -1);
+        settings.set_string ("opponent", opponent);
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT difficulty_combo_changed_cb", instance_pos = -1)]
+    public void difficulty_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        Gtk.TreeIter iter;
+        if (!combo.get_active_iter (out iter))
+            return;
+        string difficulty;
+        combo.model.get (iter, 1, out difficulty, -1);
+        settings.set_string ("difficulty", difficulty);
+    }
+
+    private void set_duration (int duration, bool simplify = true)
+    {
+        var model = custom_duration_units_combo.model;
+        Gtk.TreeIter iter, max_iter = {};
+        int max_multiplier = 0;
+        if (model.get_iter_first (out iter))
+        {
+            do
+            {
+                int multiplier;
+                model.get (iter, 1, out multiplier, -1);
+                if (multiplier > max_multiplier && duration % multiplier == 0)
+                {
+                    max_multiplier = multiplier;
+                    max_iter = iter;
+                }
+            } while (model.iter_next (ref iter));
+        }
+        if (max_multiplier > 0)
+        {
+            duration_adjustment.value = duration / max_multiplier;
+            custom_duration_units_combo.set_active_iter (max_iter);
+        }
+
+        if (!simplify)
+            return;
+
+        model = duration_combo.model;
+        if (!model.get_iter_first (out iter))
+            return;
+        do
+        {
+            int v;
+            model.get (iter, 1, out v, -1);
+            if (v == duration || v == -1)
+            {
+                duration_combo.set_active_iter (iter);
+                custom_duration_box.visible = v == -1;
+                return;
+            }
+        } while (model.iter_next (ref iter));
+    }
+
+    private int get_duration ()
+    {
+        var magnitude = (int) duration_adjustment.value;
+        int multiplier = 1;
+        Gtk.TreeIter iter;
+        if (custom_duration_units_combo.get_active_iter (out iter))
+            custom_duration_units_combo.model.get (iter, 1, out multiplier, -1);
+        return magnitude * multiplier;
+    }
+
+    private bool save_duration ()
+    {
+        settings.set_int ("duration", get_duration ());
+        Source.remove (save_duration_timeout);
+        save_duration_timeout = 0;
+        return false;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT duration_changed_cb", instance_pos = -1)]
+    public void duration_changed_cb (Gtk.Widget widget)
+    {
+        if (save_duration_timeout != 0)
+            Source.remove (save_duration_timeout);
+        /* Do this delayed as it might change a lot being connected to a spin button */
+        save_duration_timeout = Timeout.add (100, save_duration);
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT duration_combo_changed_cb", instance_pos = -1)]
+    public void duration_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        Gtk.TreeIter iter;
+        if (!combo.get_active_iter (out iter))
+            return;
+        int duration;
+        combo.model.get (iter, 1, out duration, -1);
+        custom_duration_box.visible = duration < 0;
+
+        if (duration >= 0)
+            set_duration (duration, false);
+        /* Default to 5 minutes when setting custom duration */
+        else if (get_duration () <= 0)
+            set_duration (5 * 60, false);
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT preferences_response_cb", instance_pos = -1)]
+    public void preferences_response_cb (Gtk.Widget widget, int response_id)
+    {
+        preferences_dialog.hide ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT preferences_delete_event_cb", instance_pos = -1)]
+    public bool preferences_delete_event_cb (Gtk.Widget widget, Gdk.Event event)
+    {
+        preferences_response_cb (widget, Gtk.ResponseType.CANCEL);
+        return true;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT piece_style_combo_changed_cb", instance_pos = -1)]
+    public void piece_style_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        settings.set_string ("piece-theme", get_combo (combo, 1));
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT show_3d_toggle_cb", instance_pos = -1)]
+    public void show_3d_toggle_cb (Gtk.ToggleButton widget)
+    {
+        var w = (Gtk.Widget) preferences_builder.get_object ("show_3d_smooth_check");
+        w.sensitive = widget.active;
+
+        w = (Gtk.Widget) preferences_builder.get_object ("piece_style_combo");
+        w.sensitive = !widget.active;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT promotion_type_combo_changed_cb", instance_pos = -1)]
+    public void promotion_type_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        settings.set_string ("promotion-type", get_combo (combo, 1));
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT move_format_combo_changed_cb", instance_pos = -1)]
+    public void move_format_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        settings.set_string ("move-format", get_combo (combo, 1));
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT orientation_combo_changed_cb", instance_pos = -1)]
+    public void orientation_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        settings.set_string ("board-side", get_combo (combo, 1));    
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT help_cb", instance_pos = -1)]
+    public void help_cb (Gtk.Widget widget)
+    {
+        try
+        {
+            Gtk.show_uri (window.get_screen (), "ghelp:glchess", Gtk.get_current_event_time ());
+        }
+        catch (GLib.Error e)
+        {
+            GLib.warning ("Unable to open help: %s", e.message);
+        }
+    }
+
+    private const string[] authors = { "Robert Ancell <robert ancell gmail com>" };
+    private const string[] artists = { "" };
+
+    [CCode (cname = "G_MODULE_EXPORT about_cb", instance_pos = -1)]
+    public void about_cb (Gtk.Widget widget)
+    {
+        if (about_dialog != null)
+        {
+            about_dialog.present ();
+            return;
+        }
+
+        about_dialog = new Gtk.AboutDialog ();
+        about_dialog.transient_for = window;
+        about_dialog.name = "glchess";
+        about_dialog.version = "TEST";
+        about_dialog.copyright = "Copyright 2010";
+        about_dialog.license = "LICENSE";
+        about_dialog.wrap_license = true;
+        about_dialog.comments = "Description";
+        about_dialog.authors = authors;
+        about_dialog.artists = artists;
+        about_dialog.translator_credits = "";
+        about_dialog.website = "http://example.com";;
+        about_dialog.logo_icon_name = "glchess";
+        about_dialog.response.connect (about_response_cb);
+        about_dialog.show ();
+    }
+    
+    private void about_response_cb (int response_id)
+    {
+        about_dialog.destroy ();
+        about_dialog = null;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT save_game_as_cb", instance_pos = -1)]
+    public void save_game_as_cb (Gtk.Widget widget)
+    {
+        save_game ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT save_game_cb", instance_pos = -1)]
+    public void save_game_cb (Gtk.Widget widget)
+    {
+        save_game ();
+    }
+
+    private void add_info_bar_to_dialog (Gtk.Dialog dialog, out Gtk.InfoBar info_bar, out Gtk.Label label)
+    {
+        var vbox = new Gtk.VBox (false, 0);
+        vbox.show ();
+
+        info_bar = new Gtk.InfoBar ();
+        var content_area = (Gtk.Container) info_bar.get_content_area ();
+        vbox.pack_start (info_bar, false, true, 0);
+
+        label = new Gtk.Label ("");
+        content_area.add (label);
+        label.show ();
+
+        var child = (Gtk.Container) dialog.get_child ();
+        child.reparent (vbox);
+        child.border_width = dialog.border_width;
+        dialog.border_width = 0;
+        dialog.add (vbox);
+    }
+
+    private void save_game ()
+    {
+        /* Show active dialog */
+        if (save_dialog != null)
+        {
+            save_dialog.present ();
+            return;
+        }
+
+        save_dialog = new Gtk.FileChooserDialog ("Save Chess Game", window, Gtk.FileChooserAction.SAVE,
+                                                 Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL,
+                                                 Gtk.Stock.SAVE, Gtk.ResponseType.OK, null);
+        add_info_bar_to_dialog (save_dialog, out save_dialog_info_bar, out save_dialog_error_label);
+
+        save_dialog.file_activated.connect (save_file_cb);        
+        save_dialog.response.connect (save_cb);
+
+        /* Filter out non PGN files by default */
+        var pgn_filter = new Gtk.FileFilter ();
+        pgn_filter.set_name ("PGN files");
+        pgn_filter.add_pattern ("*.pgn");
+        save_dialog.add_filter (pgn_filter);
+
+        var all_filter = new Gtk.FileFilter ();
+        all_filter.set_name ("All files");
+        all_filter.add_pattern ("*");
+        save_dialog.add_filter (all_filter);
+
+        save_dialog.present ();
+    }    
+
+    private void save_file_cb ()
+    {
+        save_cb (Gtk.ResponseType.OK);
+    }
+
+    private void save_cb (int response_id)
+    {
+        if (response_id == Gtk.ResponseType.OK)
+        {
+            save_menu.sensitive = false;
+
+            var pgn = new PGNGame ();
+            foreach (var i in game.move_stack)
+            {
+                if (i.last_move != null)
+                    pgn.moves.append (i.last_move.lan);
+            }
+
+            try
+            {
+                var stream = save_dialog.get_file ().replace (null, false, GLib.FileCreateFlags.NONE);
+                pgn.write (stream);
+            }
+            catch (GLib.Error e)
+            {
+                save_dialog_error_label.set_text ("Failed to save game: %s".printf (e.message));
+                save_dialog_info_bar.set_message_type (Gtk.MessageType.ERROR);
+                save_dialog_info_bar.show ();
+                return;
+            }
+        }
+
+        save_dialog.destroy ();
+        save_dialog = null;
+        save_dialog_info_bar = null;
+        save_dialog_error_label = null;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT open_game_cb", instance_pos = -1)]
+    public void open_game_cb (Gtk.Widget widget)
+    {
+        /* Show active dialog */
+        if (open_dialog != null)
+        {
+            open_dialog.present ();
+            return;
+        }
+
+        open_dialog = new Gtk.FileChooserDialog ("Load Chess Game", window, Gtk.FileChooserAction.OPEN,
+                                                 Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL,
+                                                 Gtk.Stock.OPEN, Gtk.ResponseType.OK, null);
+        add_info_bar_to_dialog (open_dialog, out open_dialog_info_bar, out open_dialog_error_label);
+
+        open_dialog.file_activated.connect (open_file_cb);        
+        open_dialog.response.connect (open_cb);
+
+        /* Filter out non PGN files by default */
+        var pgn_filter = new Gtk.FileFilter ();
+        pgn_filter.set_name ("PGN files");
+        pgn_filter.add_pattern ("*.pgn");
+        open_dialog.add_filter (pgn_filter);
+
+        var all_filter = new Gtk.FileFilter ();
+        all_filter.set_name ("All files");
+        all_filter.add_pattern ("*");
+        open_dialog.add_filter (all_filter);
+
+        open_dialog.present ();
+    }
+    
+    private void open_file_cb ()
+    {
+        open_cb (Gtk.ResponseType.OK);
+    }
+
+    private void open_cb (int response_id)
+    {
+        if (response_id == Gtk.ResponseType.OK)
+        {
+            PGN pgn;        
+            try
+            {
+                pgn = new PGN.from_file (open_dialog.get_file ());
+            }
+            catch (GLib.Error e)
+            {
+                open_dialog_error_label.set_text ("Failed to open game: %s".printf (e.message));
+                open_dialog_info_bar.set_message_type (Gtk.MessageType.ERROR);
+                open_dialog_info_bar.show ();
+                return;
+            }
+
+            var pgn_game = pgn.games.nth_data (0);
+            start_game ();
+            foreach (var move in pgn_game.moves)
+            {
+                GLib.debug ("Move: %s", move);
+                if (!game.current_player.move (move))
+                {
+                    GLib.warning ("Invalid move: %s", move);
+                    break;
+                }
+            }
+        }
+
+        open_dialog.destroy ();
+        open_dialog = null;
+        open_dialog_info_bar = null;
+        open_dialog_error_label = null;
+    }
+}
+
+class GlChess
+{
+    public static int main (string[] args)
+    {
+        Gtk.init (ref args);
+
+        Application app = new Application ();
+        app.start ();
+
+        Gtk.main ();
+
+        return 0;
+    }
+}
diff --git a/glchess/src/glu.vapi b/glchess/src/glu.vapi
new file mode 100644
index 0000000..ee77a18
--- /dev/null
+++ b/glchess/src/glu.vapi
@@ -0,0 +1,301 @@
+/* glu.vapi
+ *
+ * Copyright (C) 2008  Matias De la Puente
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Matias De la Puente <mfpuente ar gmail com>
+ */
+ 
+[CCode (lower_case_cprefix ="", cheader_filename="GL/glu.h")]
+namespace GLU
+{
+	// Extensions
+	public const GL.GLenum GLU_EXT_object_space_tess;
+	public const GL.GLenum GLU_EXT_nurbs_tessellator;
+	
+	// Version
+	public const GL.GLenum GLU_VERSION_1_1;
+	public const GL.GLenum GLU_VERSION_1_2;
+	public const GL.GLenum GLU_VERSION_1_3;
+	
+	// StringName
+	public const GL.GLenum GLU_VERSION;
+	public const GL.GLenum GLU_EXTENSIONS;
+	
+	// ErrorCode
+	public const GL.GLenum GLU_INVALID_ENUM;
+	public const GL.GLenum GLU_INVALID_VALUE;
+	public const GL.GLenum GLU_OUT_OF_MEMORY;
+	public const GL.GLenum GLU_INCOMPATIBLE_GL_VERSION;
+	public const GL.GLenum GLU_INVALID_OPERATION;
+	
+	// NurbsDisplay
+	public const GL.GLenum GLU_OUTLINE_POLYGON;
+	public const GL.GLenum GLU_OUTLINE_PATCH;
+	
+	// NurbsCallback
+	public const GL.GLenum GLU_NURBS_ERROR;
+	public const GL.GLenum GLU_ERROR;
+	public const GL.GLenum GLU_NURBS_BEGIN;
+	public const GL.GLenum GLU_NURBS_BEGIN_EXT;
+	public const GL.GLenum GLU_NURBS_VERTEX;
+	public const GL.GLenum GLU_NURBS_VERTEX_EXT;
+	public const GL.GLenum GLU_NURBS_NORMAL;
+	public const GL.GLenum GLU_NURBS_NORMAL_EXT;
+	public const GL.GLenum GLU_NURBS_COLOR;
+	public const GL.GLenum GLU_NURBS_COLOR_EXT;
+	public const GL.GLenum GLU_NURBS_TEXTURE_COORD;
+	public const GL.GLenum GLU_NURBS_TEX_COORD_EXT;
+	public const GL.GLenum GLU_NURBS_END;
+	public const GL.GLenum GLU_NURBS_END_EXT;
+	public const GL.GLenum GLU_NURBS_BEGIN_DATA;
+	public const GL.GLenum GLU_NURBS_BEGIN_DATA_EXT;
+	public const GL.GLenum GLU_NURBS_VERTEX_DATA;
+	public const GL.GLenum GLU_NURBS_VERTEX_DATA_EXT;
+	public const GL.GLenum GLU_NURBS_NORMAL_DATA;
+	public const GL.GLenum GLU_NURBS_NORMAL_DATA_EXT;
+	public const GL.GLenum GLU_NURBS_COLOR_DATA;
+	public const GL.GLenum GLU_NURBS_COLOR_DATA_EXT;
+	public const GL.GLenum GLU_NURBS_TEXTURE_COORD_DATA;
+	public const GL.GLenum GLU_NURBS_TEX_COORD_DATA_EXT;
+	public const GL.GLenum GLU_NURBS_END_DATA;
+	public const GL.GLenum GLU_NURBS_END_DATA_EXT;
+	
+	// NurbsError
+	public const GL.GLenum GLU_NURBS_ERROR1;
+	public const GL.GLenum GLU_NURBS_ERROR2;
+	public const GL.GLenum GLU_NURBS_ERROR3;
+	public const GL.GLenum GLU_NURBS_ERROR4;
+	public const GL.GLenum GLU_NURBS_ERROR5;
+	public const GL.GLenum GLU_NURBS_ERROR6;
+	public const GL.GLenum GLU_NURBS_ERROR7;
+	public const GL.GLenum GLU_NURBS_ERROR8;
+	public const GL.GLenum GLU_NURBS_ERROR9;
+	public const GL.GLenum GLU_NURBS_ERROR10;
+	public const GL.GLenum GLU_NURBS_ERROR11;
+	public const GL.GLenum GLU_NURBS_ERROR12;
+	public const GL.GLenum GLU_NURBS_ERROR13;
+	public const GL.GLenum GLU_NURBS_ERROR14;
+	public const GL.GLenum GLU_NURBS_ERROR15;
+	public const GL.GLenum GLU_NURBS_ERROR16;
+	public const GL.GLenum GLU_NURBS_ERROR17;
+	public const GL.GLenum GLU_NURBS_ERROR18;
+	public const GL.GLenum GLU_NURBS_ERROR19;
+	public const GL.GLenum GLU_NURBS_ERROR20;
+	public const GL.GLenum GLU_NURBS_ERROR21;
+	public const GL.GLenum GLU_NURBS_ERROR22;
+	public const GL.GLenum GLU_NURBS_ERROR23;
+	public const GL.GLenum GLU_NURBS_ERROR24;
+	public const GL.GLenum GLU_NURBS_ERROR25;
+	public const GL.GLenum GLU_NURBS_ERROR26;
+	public const GL.GLenum GLU_NURBS_ERROR27;
+	public const GL.GLenum GLU_NURBS_ERROR28;
+	public const GL.GLenum GLU_NURBS_ERROR29;
+	public const GL.GLenum GLU_NURBS_ERROR30;
+	public const GL.GLenum GLU_NURBS_ERROR31;
+	public const GL.GLenum GLU_NURBS_ERROR32;
+	public const GL.GLenum GLU_NURBS_ERROR33;
+	public const GL.GLenum GLU_NURBS_ERROR34;
+	public const GL.GLenum GLU_NURBS_ERROR35;
+	public const GL.GLenum GLU_NURBS_ERROR36;
+	public const GL.GLenum GLU_NURBS_ERROR37;
+	
+	// NurbsProperty
+	public const GL.GLenum GLU_AUTO_LOAD_MATRIX;
+	public const GL.GLenum GLU_CULLING;
+	public const GL.GLenum GLU_SAMPLING_TOLERANCE;
+	public const GL.GLenum GLU_DISPLAY_MODE;
+	public const GL.GLenum GLU_PARAMETRIC_TOLERANCE;
+	public const GL.GLenum GLU_SAMPLING_METHOD;
+	public const GL.GLenum GLU_U_STEP;
+	public const GL.GLenum GLU_V_STEP;
+	public const GL.GLenum GLU_NURBS_MODE;
+	public const GL.GLenum GLU_NURBS_MODE_EXT;
+	public const GL.GLenum GLU_NURBS_TESSELLATOR;
+	public const GL.GLenum GLU_NURBS_TESSELLATOR_EXT;
+	public const GL.GLenum GLU_NURBS_RENDERER;
+	public const GL.GLenum GLU_NURBS_RENDERER_EXT;
+	
+	// NurbsSampling
+	public const GL.GLenum GLU_OBJECT_PARAMETRIC_ERROR;
+	public const GL.GLenum GLU_OBJECT_PARAMETRIC_ERROR_EXT;
+	public const GL.GLenum GLU_OBJECT_PATH_LENGTH;
+	public const GL.GLenum GLU_OBJECT_PATH_LENGTH_EXT;
+	public const GL.GLenum GLU_PATH_LENGTH;
+	public const GL.GLenum GLU_PARAMETRIC_ERROR;
+	public const GL.GLenum GLU_DOMAIN_DISTANCE;
+	
+	// NurbsTrim
+	public const GL.GLenum GLU_MAP1_TRIM_2;
+	public const GL.GLenum GLU_MAP1_TRIM_3;
+	
+	// QuadricDrawStyle
+	public const GL.GLenum GLU_POINT;
+	public const GL.GLenum GLU_LINE;
+	public const GL.GLenum GLU_FILL;
+	public const GL.GLenum GLU_SILHOUETTE;
+	
+	// QuadricNormal
+	public const GL.GLenum GLU_SMOOTH;
+	public const GL.GLenum GLU_FLAT;
+	public const GL.GLenum GLU_NONE;
+	
+	// QuadricOrientation
+	public const GL.GLenum GLU_OUTSIDE;
+	public const GL.GLenum GLU_INSIDE;
+	
+	// TessCallback
+	public const GL.GLenum GLU_TESS_BEGIN;
+	public const GL.GLenum GLU_BEGIN;
+	public const GL.GLenum GLU_TESS_VERTEX;
+	public const GL.GLenum GLU_VERTEX;
+	public const GL.GLenum GLU_TESS_END;
+	public const GL.GLenum GLU_END;
+	public const GL.GLenum GLU_TESS_ERROR;
+	public const GL.GLenum GLU_TESS_EDGE_FLAG;
+	public const GL.GLenum GLU_EDGE_FLAG;
+	public const GL.GLenum GLU_TESS_COMBINE;
+	public const GL.GLenum GLU_TESS_BEGIN_DATA;
+	public const GL.GLenum GLU_TESS_VERTEX_DATA;
+	public const GL.GLenum GLU_TESS_END_DATA;
+	public const GL.GLenum GLU_TESS_ERROR_DATA;
+	public const GL.GLenum GLU_TESS_EDGE_FLAG_DATA;
+	public const GL.GLenum GLU_TESS_COMBINE_DATA;
+	
+	// TessContour
+	public const GL.GLenum GLU_CW;
+	public const GL.GLenum GLU_CCW;
+	public const GL.GLenum GLU_INTERIOR;
+	public const GL.GLenum GLU_EXTERIOR;
+	public const GL.GLenum GLU_UNKNOWN;
+	
+	// TessProperty
+	public const GL.GLenum GLU_TESS_WINDING_RULE;
+	public const GL.GLenum GLU_TESS_BOUNDARY_ONLY;
+	public const GL.GLenum GLU_TESS_TOLERANCE;
+	
+	// TessError
+	public const GL.GLenum GLU_TESS_ERROR1;
+	public const GL.GLenum GLU_TESS_ERROR2;
+	public const GL.GLenum GLU_TESS_ERROR3;
+	public const GL.GLenum GLU_TESS_ERROR4;
+	public const GL.GLenum GLU_TESS_ERROR5;
+	public const GL.GLenum GLU_TESS_ERROR6;
+	public const GL.GLenum GLU_TESS_ERROR7;
+	public const GL.GLenum GLU_TESS_ERROR8;
+	public const GL.GLenum GLU_TESS_MISSING_BEGIN_POLYGON;
+	public const GL.GLenum GLU_TESS_MISSING_BEGIN_CONTOUR;
+	public const GL.GLenum GLU_TESS_MISSING_END_POLYGON;
+	public const GL.GLenum GLU_TESS_MISSING_END_CONTOUR;
+	public const GL.GLenum GLU_TESS_COORD_TOO_LARGE;
+	public const GL.GLenum GLU_TESS_NEED_COMBINE_CALLBACK;
+	
+	// TessWinding
+	public const GL.GLenum GLU_TESS_WINDING_ODD;
+	public const GL.GLenum GLU_TESS_WINDING_NONZERO;
+	public const GL.GLenum GLU_TESS_WINDING_POSITIVE;
+	public const GL.GLenum GLU_TESS_WINDING_NEGATIVE;
+	public const GL.GLenum GLU_TESS_WINDING_ABS_GEQ_TWO;
+	public const GL.GLenum GLU_TESS_MAX_COORD;
+
+	[CCode (cname="_GLUfuncptr", has_target = false)]
+	public delegate void GLUfuncptr ();
+
+	[Compact]
+	[CCode (cname="GLUnurbsObj", cprefix="glu", free_function="gluDeleteNurbsRenderer")]
+	public class Nurbs
+	{
+		[CCode (cname="gluNewNurbsRenderer")]
+		public Nurbs ();
+
+		public void BeginCurve ();
+		public void BeginSurface ();
+		public void BeginTrim ();
+		public void EndCurve ();
+		public void EndSurface ();
+		public void EndTrim ();
+		public void GetNurbsProperty (GL.GLenum property, out GL.GLfloat data);
+		public void LoadSamplingMatrices ([CCode (array_length = false)] GL.GLfloat[] model, [CCode (array_length = false)] GL.GLfloat[] perspective, [CCode (array_length = false)] GL.GLint[] view);
+		public void NurbsCallback (GL.GLenum which, GLUfuncptr CallBackFunc);
+		public void NurbsCallbackData (GL.GLvoid* userData);
+		public void NurbsCallbackDataEXT (GL.GLvoid* userData);
+		public void NurbsCurve (GL.GLint knotCount, [CCode (array_length = false)] GL.GLfloat[] knots, [CCode (array_length = false)] GL.GLint stride, [CCode (array_length = false)] GL.GLfloat[] control, GL.GLint order, GL.GLenum type);
+		public void NurbsProperty (GL.GLenum property, GL.GLfloat @value);
+		public void NurbsSurface (GL.GLint sKnotCount, [CCode (array_length = false)] GL.GLfloat[] sKnots, GL.GLint tKnotCount, [CCode (array_length = false)] GL.GLfloat[] tKnots, GL.GLint sStride, GL.GLint tStride, [CCode (array_length = false)] GL.GLfloat[] control, GL.GLint sOrder, GL.GLint tOrder, GL.GLenum type);
+		public void PwlCurve (GL.GLint count, [CCode (array_length = false)] GL.GLfloat[] data, GL.GLint stride, GL.GLenum type);
+	}
+	
+	[Compact]
+	[CCode (cname="GLUquadricObj", cprefix="glu", free_function="gluDeleteQuadric")]
+	public class Quadric
+	{
+		[CCode (cname="gluNewQuadric")]
+		public Quadric ();
+		
+		public void Cylinder (GL.GLdouble @base, GL.GLdouble top, GL.GLdouble height, GL.GLint slices, GL.GLint stacks);
+		public void Disk (GL.GLdouble inner, GL.GLdouble outer, GL.GLint slices, GL.GLint loops);
+		public void PartialDisk (GL.GLdouble inner, GL.GLdouble outer, GL.GLint slices, GL.GLint loops, GL.GLdouble start, GL.GLdouble sweep);
+		public void Sphere (GL.GLdouble radius, GL.GLint slices, GL.GLint stacks);
+		public void QuadricCallback (GL.GLenum which, GLUfuncptr CallBackFunc);
+		public void QuadricDrawStyle (GL.GLenum draw);
+		public void QuadricNormals (GL.GLenum normal);
+		public void QuadricOrientation (GL.GLenum orientation);
+		public void QuadricTexture (GL.GLboolean texture);
+	}
+	
+	[Compact]
+	[CCode (cname="GLUtesselatorObj", cprefix="glu", free_function="gluDeleteTess")]
+	public class Tesselator
+	{
+		[CCode (cname="gluNewTess")]
+		public Tesselator ();
+
+		public void BeginPolygon ();
+		public void EndPolygon ();
+		public void GetTessProperty (GL.GLenum which, out GL.GLdouble data);
+		public void NextContour (GL.GLenum type);
+		public void TessBeginContour ();
+		public void TessBeginPolygon (GL.GLvoid* data);
+		public void TessCallback (GL.GLenum which, GLUfuncptr CallBackFunc);
+		public void TessEndContour ();
+		public void TessEndPolygon ();
+		public void TessNormal (GL.GLdouble valueX, GL.GLdouble valueY, GL.GLdouble valueZ);
+		public void TessProperty (GL.GLenum which, GL.GLdouble data);
+		public void TessVertex ([CCode (array_length = false)] GL.GLdouble[] location, GL.GLvoid* data);
+	}
+
+
+	public static GL.GLint gluBuild1DMipmapLevels (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLenum format, GL.GLenum type, GL.GLint level, GL.GLint @base, GL.GLint max, void* data);
+	public static GL.GLint gluBuild1DMipmaps (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLenum format, GL.GLenum type, void* data);
+	public static GL.GLint gluBuild2DMipmapLevels (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLsizei height, GL.GLenum format, GL.GLenum type, GL.GLint level, GL.GLint @base, GL.GLint max, void* data);
+	public static GL.GLint gluBuild2DMipmaps (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLsizei height, GL.GLenum format, GL.GLenum type, void* data);
+	public static GL.GLint gluBuild3DMipmapLevels (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLsizei height, GL.GLsizei depth, GL.GLenum format, GL.GLenum type, GL.GLint level, GL.GLint @base, GL.GLint max, void* data);
+	public static GL.GLint gluBuild3DMipmaps (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLsizei height, GL.GLsizei depth, GL.GLenum format, GL.GLenum type, void* data);
+	public static GL.GLboolean gluCheckExtension (string extName, string extString);
+	public static unowned string gluErrorString (GL.GLenum error);
+	public static unowned string gluGetString (GL.GLenum name);
+	public static void gluLookAt (GL.GLdouble eyeX, GL.GLdouble eyeY, GL.GLdouble eyeZ, GL.GLdouble centerX, GL.GLdouble centerY, GL.GLdouble centerZ, GL.GLdouble upX, GL.GLdouble upY, GL.GLdouble upZ);
+	public static void gluOrtho2D (GL.GLdouble left, GL.GLdouble right, GL.GLdouble bottom, GL.GLdouble top);
+	public static void gluPerspective (GL.GLdouble fovy, GL.GLdouble aspect, GL.GLdouble zNear, GL.GLdouble zFar);
+	public static void gluPickMatrix (GL.GLdouble x, GL.GLdouble y, GL.GLdouble delX, GL.GLdouble delY, [CCode (array_length = false)] GL.GLint[] viewport);
+	public static GL.GLint gluProject (GL.GLdouble objX, GL.GLdouble objY, GL.GLdouble objZ, [CCode (array_length = false)] GL.GLdouble[] model, [CCode (array_length = false)] GL.GLdouble[] proj, [CCode (array_length = false)] GL.GLint[] view, out GL.GLdouble winX, out GL.GLdouble winY, out GL.GLdouble winZ);
+	public static GL.GLint gluScaleImage (GL.GLenum format, GL.GLsizei wIn, GL.GLsizei hIn, GL.GLenum typeIn, void* dataIn, GL.GLsizei wOut, GL.GLsizei hOut, GL.GLenum typeOut, GL.GLvoid* dataOut);
+	public static GL.GLint gluUnProject (GL.GLdouble winX, GL.GLdouble winY, GL.GLdouble winZ, [CCode (array_length = false)] GL.GLdouble[] model, [CCode (array_length = false)] GL.GLdouble[] proj, [CCode (array_length = false)] GL.GLint[] view, out GL.GLdouble objX, out GL.GLdouble objY, out GL.GLdouble objZ);
+	public static GL.GLint gluUnProject4 (GL.GLdouble winX, GL.GLdouble winY, GL.GLdouble winZ, GL.GLdouble clipW, [CCode (array_length = false)] GL.GLdouble[] model, [CCode (array_length = false)] GL.GLdouble[] proj, [CCode (array_length = false)] GL.GLint[] view, GL.GLdouble nearVal, GL.GLdouble farVal, out GL.GLdouble objX, out GL.GLdouble objY, out GL.GLdouble objZ, out GL.GLdouble objW);
+
+}
+
diff --git a/glchess/src/gtkglext-1.0.vapi b/glchess/src/gtkglext-1.0.vapi
new file mode 100644
index 0000000..48e0500
--- /dev/null
+++ b/glchess/src/gtkglext-1.0.vapi
@@ -0,0 +1,373 @@
+/* gtkglext-1.0.vapi
+ *
+ * Copyright (C) 2008  Matias De la Puente
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Matias De la Puente <mfpuente ar gmail com>
+ * 	Yu Feng <rainwoodman gmail com>
+ */
+
+[CCode (lower_case_cprefix="gdk_", cprefix="Gdk")]
+namespace Gdk {
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLConfigAttrib
+	{
+		USE_GL,
+		BUFFER_SIZE,
+		LEVEL,
+		RGBA,
+		DOUBLEBUFFER,
+		STEREO,
+		AUX_BUFFERS,
+		RED_SIZE,
+		GREEN_SIZE,
+		BLUE_SIZE,
+		ALPHA_SIZE,
+		DEPTH_SIZE,
+		STENCIL_SIZE,
+		ACCUM_RED_SIZE,
+		ACCUM_GREEN_SIZE,
+		ACCUM_BLUE_SIZE,
+		ACCUM_ALPHA_SIZE,
+		CONFIG_CAVEAT,
+		X_VISUAL_TYPE,
+		TRANSPARENT_TYPE,
+		TRANSPARENT_INDEX_VALUE,
+		TRANSPARENT_RED_VALUE,
+		TRANSPARENT_GREEN_VALUE,
+		TRANSPARENT_BLUE_VALUE,
+		TRANSPARENT_ALPHA_VALUE,
+		DRAWABLE_TYPE,
+		RENDER_TYPE,
+		X_RENDERABLE,
+		FBCONFIG_ID,
+		MAX_PBUFFER_WIDTH,
+		MAX_PBUFFER_HEIGHT,
+		MAX_PBUFFER_PIXELS,
+		VISUAL_ID,
+		SCREEN,
+		SAMPLE_BUFFERS,
+		SAMPLES
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLConfigCaveat
+	{
+		CONFIG_CAVEAT_DONT_CARE,
+		CONFIG_CAVEAT_NONE,
+		SLOW_CONFIG,
+		NON_CONFORMANT_CONFIG
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLVisualType
+	{
+		VISUAL_TYPE_DONT_CARE,
+		TRUE_COLOR,
+		DIRECT_COLOR,
+		PSEUDO_COLOR,
+		STATIC_COLOR,
+		GRAY_SCALE,
+		STATIC_GRAY
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLTransparentType
+	{
+		TRANSPARENT_NONE,
+		TRANSPARENT_RGB,
+		TRANSPARENT_INDEX
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLDrawableTypeMask
+	{
+		WINDOW_BIT,
+		PIXMAP_BIT,
+		PBUFFER_BIT
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLRenderTypeMask
+	{
+		RGBA_BIT,
+		COLOR_INDEX_BIT
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLBufferMask
+	{
+		FRONT_LEFT_BUFFER_BIT,
+		FRONT_RIGHT_BUFFER_BIT,
+		BACK_LEFT_BUFFER_BIT,
+		BACK_RIGHT_BUFFER_BIT,
+		AUX_BUFFERS_BIT,
+		DEPTH_BUFFER_BIT,
+		STENCIL_BUFFER_BIT,
+		ACCUM_BUFFER_BIT
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLConfigError
+	{
+		BAD_SCREEN,
+		BAD_ATTRIBUTE,
+		NO_EXTENSION,
+		BAD_VISUAL,
+		BAD_CONTEXT,
+		BAD_VALUE,
+		BAD_ENUM
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLRenderType
+	{
+		RGBA_TYPE,
+		COLOR_INDEX_TYPE
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLDrawableAttrib
+	{
+		PRESERVED_CONTENTS,
+		LARGEST_PBUFFER,
+		WIDTH,
+		HEIGHT,
+		EVENT_MASK
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLPbufferAttrib
+	{
+		PBUFFER_PRESERVED_CONTENTS,
+		PBUFFER_LARGEST_PBUFFER,
+		PBUFFER_HEIGHT,
+		PBUFFER_WIDTH
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLEventMask
+	{
+		PBUFFER_CLOBBER_MASK
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLEventType
+	{
+		DAMAGED,
+		SAVED
+	}
+	
+	[CCode (cprefix="GDK_GL_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLDrawableType
+	{
+		WINDOW,
+		PBUFFER
+	}
+	
+	[CCode (cprefix="GDK_GL_MODE_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public enum GLConfigMode
+	{
+		RGB,
+		RGBA,
+		INDEX,
+		SINGLE,
+		DOUBLE,
+		STEREO,
+		ALPHA,
+		DEPTH,
+		STENCIL,
+		ACCUM,
+		MULTISAMPLE
+	}
+	
+	[CCode (cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public static const uint GL_SUCCESS;
+	[CCode (cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public static const uint GL_ATTRIB_LIST_NONE;
+	[CCode (cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public static const uint GL_DONT_CARE;
+	[CCode (cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public static const uint GL_NONE;
+	
+	[CCode (has_target = false)]
+	public delegate void GLProc ();
+
+	[CCode (cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public static void gl_init ([CCode (array_length_pos = 0.9)] ref unowned string[] argv);
+	[CCode (cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public static bool gl_init_check ([CCode (array_length_pos = 0.9)] ref unowned string[] argv);
+	[CCode (cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public static bool gl_parse_args ([CCode (array_length_pos = 0.9)] ref unowned string[] argv);
+	public static bool gl_query_extension ();
+	public static bool gl_query_extension_for_display (Gdk.Display display);
+	public static bool gl_query_version (out int major, out int minor);
+	public static bool gl_query_version_for_display (Gdk.Display display, out int major, out int minor);
+	public static bool gl_query_gl_extension (string extension);
+	public static GLProc gl_get_proc_address (string proc_name);
+	public static unowned Pango.Font gl_font_use_pango_font (Pango.FontDescription font_desc, int first, int count, int list_base);
+	public static unowned Pango.Font gl_font_use_pango_font_for_display (Gdk.Display display, Pango.FontDescription font_desc, int first, int count, int list_base);
+		
+	[CCode (lower_case_cprefix="gdk_gl_draw_")]
+	namespace GLDraw
+	{
+		public static void cube (bool solid, double size);
+		public static void sphere (bool solid, double radius, int slices, int stacks);
+		public static void cone (bool solid, double @base, double height, int slices, int stacks);
+		public static void torus (bool solid, double inner_radius, double outer_radius, int nsides, int rings);
+		public static void tetrahedron  (bool solid);
+		public static void octahedron (bool solid);
+		public static void dodecahedron (bool solid);
+		public static void icosahedron (bool solid);
+		public static void teapot (bool solid, double scale);
+	}
+
+	public class GLConfig : GLib.Object
+	{
+		public GLConfig ([CCode (array_length = false)] int[] attrib_list);
+		public GLConfig.for_screen (Gdk.Screen screen, [CCode (array_length = false)] int[] attib_list);
+		public GLConfig.by_mode (GLConfigMode mode);
+		public GLConfig.by_mode_for_screen (Gdk.Screen screen, GLConfigMode mode);
+		public unowned Gdk.Screen get_screen ();
+		public bool get_attrib (int attribute, out int @value);
+		public unowned Gdk.Colormap get_colormap ();
+		public unowned Gdk.Visual get_visual ();
+		public int get_depth ();
+		public int get_layer_plane ();
+		public int get_n_aux_buffers ();
+		public int get_n_sample_buffers ();
+		public bool is_rgba ();
+		public bool is_double_buffered ();
+		public bool is_stereo ();
+		public bool has_alpha ();
+		public bool has_depth_buffer ();
+		public bool has_stencil_buffer ();
+		public bool has_accum_buffer ();
+	}
+		
+	public class GLContext : GLib.Object
+	{
+		public GLContext (Gdk.GLDrawable gldrawable, Gdk.GLContext share_list, bool direct, int render_type);
+		public void destroy ();
+		public bool copy (Gdk.GLContext src, ulong mask);
+		public unowned Gdk.GLDrawable get_gl_drawable ();
+		public unowned Gdk.GLConfig get_gl_config ();
+		public unowned Gdk.GLContext get_share_list ();
+		public bool is_direct ();
+		public int get_render_type ();
+		public static unowned Gdk.GLContext get_current ();
+	}
+		
+	public class GLDrawable : GLib.Object
+	{
+		public bool make_current (Gdk.GLContext  glcontext);
+		public bool is_double_buffered ();
+		public void swap_buffers ();
+		public void wait_gl ();
+		public void wait_gdk ();
+		public bool gl_begin (Gdk.GLContext glcontext);
+		public void gl_end ();
+		public unowned Gdk.GLConfig get_gl_config ();
+		public void get_size (out int width, out int height);
+		public static Gdk.GLDrawable get_current ();
+	
+		/*public virtual signal Gdk.GLContext create_new_context (Gdk.GLContext share_list, bool direct, int render_type);
+		public virtual signal bool make_context_current (Gdk.GLDrawable read, Gdk.GLContext glcontext);
+		public virtual signal bool is_double_buffered ();
+		public virtual signal void swap_buffers ();
+		public virtual signal void wait_gl ();
+		public virtual signal void wait_gdk ();
+		public virtual signal bool gl_begin (Gdk.GLDrawable read, Gdk.GLContext glcontext);
+		public virtual signal void gl_end ();
+		public virtual signal Gdk.GLConfig  get_gl_config ();
+		public virtual signal void get_size (out int width, out int height);
+		*/
+	}
+	
+	public class GLPixmap : Gdk.Drawable
+	{
+		public GLPixmap (Gdk.GLConfig glconfig, Gdk.Pixmap pixmap, [CCode (array_length = false)] int[] attrib_list);
+		public void destroy ();
+		public unowned Gdk.Pixmap get_pixmap ();
+	}
+
+	[CCode (cprefix="gdk_pixmap_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public class PixmapGL {
+		public static unowned Gdk.GLPixmap set_gl_capability (Gdk.Pixmap pixmap, Gdk.GLConfig glconfig, [CCode (array_length = false)] int[] attrib_list);
+		public static void unset_gl_capability (Gdk.Pixmap pixmap);
+		public static bool is_gl_capable (Gdk.Pixmap pixmap);
+		public static unowned Gdk.GLPixmap get_gl_pixmap (Gdk.Pixmap pixmap);
+		public static unowned Gdk.GLDrawable get_gl_drawable (Gdk.Pixmap pixmap);
+	}
+	
+	public class GLWindow : Gdk.Drawable
+	{
+		public GLWindow (Gdk.GLConfig glconfig, Gdk.Window window, [CCode (array_length = false)] int[] attrib_list);
+		public void destroy ();
+		public unowned Gdk.Window get_window ();
+	}
+
+	[CCode (cprefix="gdk_window_", cheader_filename="gtkglext-1.0/gdk/gdkgl.h")]
+	public class WindowGL {
+		public static unowned Gdk.GLWindow set_gl_capability (Gdk.Window window, Gdk.GLConfig glconfig, [CCode (array_length = false)] int[] attrib_list);
+		public static void unset_gl_capability (Gdk.Window window);
+		public static bool is_gl_capable (Gdk.Window window);
+		public static unowned Gdk.GLWindow get_gl_window (Gdk.Window window);
+		public static unowned Gdk.GLDrawable get_gl_drawable (Gdk.Window window);
+	}
+}
+
+[CCode (lower_case_cprefix="gtk_", cprefix="Gtk")]
+namespace Gtk
+{
+	[CCode (cheader_filename="gtkglext-1.0/gtk/gtkgl.h")]
+	public static void gl_init ([CCode (array_length_pos = 0.9)] ref unowned string[] argv);
+	[CCode (cheader_filename="gtkglext-1.0/gtk/gtkgl.h")]
+	public static bool gl_init_check ([CCode (array_length_pos = 0.9)] ref unowned string[] argv);
+	[CCode (cheader_filename="gtkglext-1.0/gtk/gtkgl.h")]
+	public static bool gl_parse_args ([CCode (array_length_pos = 0.9)] ref unowned string[] argv);
+	
+	[CCode (cprefix="gtk_widget_", cheader_filename="gtkglext-1.0/gtk/gtkgl.h")]
+	public class WidgetGL
+	{
+		public static bool set_gl_capability (Gtk.Widget widget, Gdk.GLConfig glconfig, Gdk.GLContext? share_list, bool direct, int render_type);
+		public static bool is_gl_capable (Gtk.Widget widget);
+		public static unowned Gdk.GLConfig get_gl_config (Gtk.Widget widget);
+		public static unowned Gdk.GLContext create_gl_context (Gtk.Widget widget, Gdk.GLContext share_list, bool direct, int render_type);
+		public static unowned Gdk.GLContext get_gl_context (Gtk.Widget widget);
+		public static unowned Gdk.GLWindow  get_gl_window (Gtk.Widget widget);
+		public static unowned Gdk.GLDrawable get_gl_drawable (Gtk.Widget widget);
+		public static bool gl_begin(Gtk.Widget widget) {
+			Gdk.GLContext context = get_gl_context(widget);
+			Gdk.GLDrawable drawable = get_gl_drawable(widget);
+			return drawable.gl_begin(context);
+		}
+		public static bool gl_swap(Gtk.Widget widget) {
+			Gdk.GLDrawable drawable = get_gl_drawable(widget);
+			if(drawable.is_double_buffered()) {
+				drawable.swap_buffers();
+				return true;
+			}
+			return false;
+		}
+		public static void gl_end(Gtk.Widget widget) {
+			Gdk.GLDrawable drawable = get_gl_drawable(widget);
+			drawable.gl_end();
+		}
+	}
+}
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]