Sophie

Sophie

distrib > Mandriva > 10.0-com > i586 > by-pkgid > 9347541fe87a5ea3f3b8dbc50f660e8e > files > 43

libQGLViewer-devel-1.3.6-1mdk.i586.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>libQGLViewer agora example</title>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <link href="../qglviewer.css" rel="stylesheet" type="text/css" />
  <link rel="shortcut icon" href="../images/qglviewer.ico" type="image/x-icon" />
  <link rel="icon" href="../images/qglviewer.icon.png" type="image/png" />
</head>
<body>

<table class="banner">
  <tr>
     <td align="center"><a href="../index.html"><b>Home</b></a></td>
     <td align="center"><a href="../refManual/hierarchy.html"><b>Documentation</b></a></td>
     <td align="center"><a href="../download.html"><b>Download</b></a></td>
     <td align="center" class="qindexHL"><a href="index.html"><b>Screenshots</b></a></td>
     <td align="center"><a href="../developer.html"><b>Developer</b></a></td>
   </tr>
</table>

<h1>The agora example</h1>
<center>
  <img src="../images/agora.jpg" width="300" height="200" alt="agora"/>
</center>

<p>
 Implementation of the game of <i>Agora</i>. 
</p>
<p>
 <i>Agora</i> is a strategy game for two players. The code is rather complex and
 can be divided in two parts : a QGLViewer implementation for the viewer and an artificial
 intelligence that allows you to play against the computer.
</p>
<p>
 You should find the rules of the game on the web. Questions relative to the artificial
 intelligence implementation should be asked to <code>Jean-Guillaume dot Dumas at imag dot fr</code>.
</p>


<h2>agora.h</h2>
<pre>

<span class="com">// =================================================================== //
</span><span class="com">// Time-stamp: &lt;01 Jul 03 16:27:25 Jean-Guillaume.Dumas@imag.fr&gt;
</span><span class="com">// =================================================================== //
</span><span class="dir">#ifndef __Agora_Plateau__
</span><span class="dir">#define __Agora_Plateau__
</span>
<span class="dir">#include &lt;iostream&gt;
</span><span class="dir">#include &lt;vector&gt;
</span><span class="dir">#include </span><span class="dstr">&quot;givtimer.h&quot;</span><span class="dir">
</span>
<span class="dir">#define SHORTCOULEURMASK 32768
</span>
<span class="dir">#define WHITE false
</span><span class="dir">#define BLACK true
</span>
<span class="dir">#define ADVANCEDRULES
</span>
<span class="dir">#include </span><span class="dstr">&quot;agora_class.h&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agora_io.h&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agora_types.h&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agora_coup.h&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agora_container.h&quot;</span><span class="dir">
</span>

<span class="key">template</span>&lt;<span class="key">class </span>Ints&gt;
<span class="key">class </span>Agora : <span class="key">public </span>std::vector&lt;Ints&gt; {
<span class="key">public</span>:
    <span class="key">typedef </span>Agora&lt; Ints &gt; Self_t;
    <span class="key">typedef </span>Ints Pile_t;
    <span class="key">typedef </span>std::vector&lt;Pile_t&gt; Plateau_t;
    <span class="key">typedef </span>std::vector&lt; std::vector&lt; Case_t &gt; &gt;  Voisin_t;

    <span class="key">typedef </span>AgoraCoup Coup;
    <span class="key">typedef </span>AgoraContainer&lt;<span class="num">256</span>, Coup&gt; Possible_t;
    <span class="key">typedef </span>std::vector&lt; Possible_t &gt; Table_Possible_t;
    <span class="key">typedef </span>std::vector&lt;Eval_t&gt; Table_Eval_t;

<span class="key">private</span>:
    Case_t _row, _size;
    Possible_t TopPM;
    Table_Possible_t _PM;
    Hauteur_t _bits;
    Size_t _bsize;
    Table_t _hauteurs, _uns, _pris, _altitude;
    Table_Eval_t _eval;
    Plateau_t _enleve, _ajoute_noir, _ajoute_blanc, _ajoute_prison;
    Voisin_t _voisins;

<span class="key">public</span>:

    Agora(<span class="typ">int </span>n = <span class="num">6</span>) ;
    <span class="typ">void </span>reinit() ;

        <span class="com">// Tabul&eacute;es
</span>    <span class="typ">bool </span>couleur(<span class="typ">const </span>Pile_t p) <span class="typ">const </span>;
    Hauteur_t taille( <span class="typ">const </span>Pile_t i ) <span class="typ">const</span>;
    Hauteur_t uns( <span class="typ">const </span>Pile_t i ) <span class="typ">const</span>;
    Hauteur_t pris( <span class="typ">const </span>Pile_t i ) <span class="typ">const</span>;
    Eval_t eval( <span class="typ">const </span>Pile_t i ) <span class="typ">const</span>;

	<span class="com">// Calcul&eacute;e
</span>    <span class="typ">bool </span>ArriveeRevolution( <span class="typ">const </span>Coup&amp; c) <span class="typ">const</span>;
    <span class="typ">bool </span>DepartRevolution( <span class="typ">const </span>Coup&amp; c) <span class="typ">const</span>;


        <span class="com">// Tabul&eacute;es
</span>    Pile_t enleve( <span class="typ">const </span>Pile_t p ) <span class="typ">const</span>;
    Pile_t ajoute_noir( <span class="typ">const </span>Pile_t p ) <span class="typ">const </span>;
    Pile_t ajoute_blanc( <span class="typ">const </span>Pile_t p ) <span class="typ">const </span>;
    Pile_t ajoute_prison( <span class="typ">const </span>Pile_t p) <span class="typ">const </span>;

        <span class="com">// Initialisation
</span>    Pile_t init( <span class="typ">const </span>Case_t i, <span class="typ">const </span>Pile_t p ) ;

        <span class="com">// Jouer
</span>    <span class="typ">bool </span>jouer( <span class="typ">const </span>Coup&amp; c ) ;
    <span class="typ">bool </span>jouer( <span class="typ">const </span>Case_t depart, <span class="typ">const </span>Case_t arrivee, <span class="typ">const bool </span>dessus );
    <span class="typ">bool </span>jouer( <span class="typ">const </span>Case_t depart, Pile_t&amp; ancien_d, <span class="typ">const </span>Case_t arrivee, Pile_t&amp; ancien_a, <span class="typ">const bool </span>dessus );
    <span class="typ">bool </span>jouer_dessus( <span class="typ">const </span>Case_t depart, Pile_t&amp; ancien_d, <span class="typ">const </span>Case_t arrivee, Pile_t&amp; ancien_a ) ;
    <span class="typ">bool </span>jouer_dessous( <span class="typ">const </span>Case_t depart, Pile_t&amp; ancien_d, <span class="typ">const </span>Case_t arrivee, Pile_t&amp; ancien_a );
    <span class="typ">void </span>jouer( <span class="typ">const </span>Case_t depart, Pile_t&amp; ancien_d, Pile_t&amp; new_d, <span class="typ">const </span>Case_t arrivee, Pile_t&amp; ancien_a, Pile_t&amp; new_a, <span class="typ">const bool </span>dessus );
    <span class="typ">void </span>jouer_dessus( <span class="typ">const </span>Case_t depart, Pile_t&amp; ancien_d, Pile_t&amp; new_d, <span class="typ">const </span>Case_t arrivee, Pile_t&amp; ancien_a, Pile_t&amp; new_a ) ;
    <span class="typ">void </span>jouer_dessous( <span class="typ">const </span>Case_t depart, Pile_t&amp; ancien_d, Pile_t&amp; new_d, <span class="typ">const </span>Case_t arrivee, Pile_t&amp; ancien_a, Pile_t&amp; new_a );
    <span class="typ">void </span>remettre( <span class="typ">const </span>Case_t depart, <span class="typ">const </span>Pile_t ancien_d, <span class="typ">const </span>Case_t arrivee, <span class="typ">const </span>Pile_t ancien_a ) ;


        <span class="com">// Fonction d'&eacute;valuation
</span>    <span class="typ">double</span>&amp; eval(<span class="typ">double</span>&amp; e, <span class="typ">const </span>Pile_t p) <span class="typ">const</span>;
    <span class="typ">double</span>&amp; uneval(<span class="typ">double</span>&amp; e, <span class="typ">const </span>Pile_t p) <span class="typ">const</span>;
    <span class="typ">double</span>&amp; eval(<span class="typ">double</span>&amp; e, <span class="typ">const </span>Pile_t dep, <span class="typ">const </span>Pile_t ndep, <span class="typ">const </span>Pile_t arr, <span class="typ">const </span>Pile_t narr)  <span class="typ">const </span>;
    <span class="typ">double </span>eval() <span class="typ">const </span>;


        <span class="com">// Meilleur coup
</span>        <span class="com">// Default : temps limit&eacute;, mais si depth &gt; 0 --&gt; profondeur fix&eacute;e
</span>    Coup&amp; Suggest(Coup&amp; bp, <span class="typ">bool </span>ordi_color, <span class="typ">double </span>temps_max, <span class="typ">int </span>depth = <span class="num">0</span>);

	<span class="com">// Coups possibles
</span>    <span class="typ">bool </span>gameIsOver() ;
    <span class="typ">bool </span>gameIsOver(<span class="typ">bool </span>color) ;

    Possible_t&amp; CoupsVoisinsBlancs(Possible_t&amp; Liste, <span class="typ">const </span>Case_t i) <span class="typ">const </span>;
    Possible_t&amp; CoupsVoisinsNoirs(Possible_t&amp; Liste, <span class="typ">const </span>Case_t i) <span class="typ">const </span>;
    Possible_t&amp; CoupsVoisins(Possible_t&amp; Liste, <span class="typ">const </span>Case_t i) <span class="typ">const </span>;
    Possible_t&amp; CoupsPossibles(Possible_t&amp; Liste, <span class="typ">const bool </span>c) <span class="typ">const </span>;

<span class="key">private</span>:
<span class="dir">#ifdef __ERRORS__
</span>    <span class="typ">unsigned long long </span>_count;
<span class="dir">#endif
</span>
        <span class="com">// Construction
</span>    <span class="typ">void </span>voisin_g(<span class="typ">const </span>Case_t j, typename Voisin_t::value_type &amp; loc) <span class="typ">const </span>;
    <span class="typ">void </span>voisin_d(<span class="typ">const </span>Case_t j, typename Voisin_t::value_type &amp; loc) <span class="typ">const </span>;
    <span class="typ">void </span>voisin(<span class="typ">const </span>Case_t j, typename Voisin_t::value_type &amp; loc) <span class="typ">const  </span>;

        <span class="com">// Calculs initiaux pour tabulation
</span>    Pile_t&amp; calcule_enleve(Pile_t &amp; r, <span class="typ">const </span>Hauteur_t t, <span class="typ">const </span>Hauteur_t u, <span class="typ">const </span>Pile_t p) <span class="typ">const </span>;
    Pile_t&amp; calcule_prison(Pile_t&amp; a, <span class="typ">const </span>Hauteur_t t, <span class="typ">const </span>Hauteur_t u, <span class="typ">const </span>Pile_t p) <span class="typ">const </span>;
    Pile_t&amp; calcule_ajoute(Pile_t &amp; r_noir, Pile_t&amp; r_blanc, <span class="typ">const </span>Hauteur_t t, <span class="typ">const </span>Hauteur_t u, <span class="typ">const </span>Pile_t p) <span class="typ">const </span>;
    Hauteur_t&amp; calcule_hauteur(Hauteur_t&amp; h, Hauteur_t&amp; u, Hauteur_t&amp; pris, <span class="typ">const </span>Pile_t p) <span class="typ">const </span>;
    Pile_t&amp; calcule_revol(Pile_t&amp; r, <span class="typ">const </span>Hauteur_t t, <span class="typ">const </span>Pile_t p) <span class="typ">const </span>;
    Eval_t&amp; calcule_eval(Eval_t&amp; ev, <span class="typ">const </span>Hauteur_t t, <span class="typ">const </span>Hauteur_t u, <span class="typ">const </span>Pile_t p) <span class="typ">const </span>;

        <span class="com">// Optimisations Branch and Cut
</span>    <span class="typ">double </span>ami_ab(<span class="typ">int </span>depth, <span class="typ">double </span>alpha, <span class="typ">double </span>beta, <span class="typ">bool </span>ordi_color);
    <span class="typ">double </span>ennemi_ab(<span class="typ">int </span>depth, <span class="typ">double </span>alpha, <span class="typ">double </span>beta, <span class="typ">bool </span>ordi_color) ;
    <span class="typ">double </span>ami_ab(<span class="typ">int </span>depth, <span class="typ">double </span>alpha, <span class="typ">double </span>beta, <span class="typ">bool </span>ordi_color, <span class="typ">double </span>currev, <span class="typ">const </span>Pile_t ad, <span class="typ">const </span>Pile_t nd, <span class="typ">const </span>Pile_t aa, <span class="typ">const </span>Pile_t na);
    <span class="typ">double </span>ennemi_ab(<span class="typ">int </span>depth, <span class="typ">double </span>alpha, <span class="typ">double </span>beta, <span class="typ">bool </span>ordi_color, <span class="typ">double </span>currev, <span class="typ">const </span>Pile_t ad, <span class="typ">const </span>Pile_t nd, <span class="typ">const </span>Pile_t aa, <span class="typ">const </span>Pile_t na) ;
        <span class="com">// Meilleur coup en temps limit&eacute;
</span>    Coup&amp; Iteratif(Coup&amp; bp, <span class="typ">bool </span>ordi_color, <span class="typ">double </span>temps_max, <span class="typ">int </span>StartProf) ;
        <span class="com">// Meilleur coup &agrave; profondeur fix&eacute;e
</span>    <span class="typ">double </span>BestPlay(Coup&amp; bp, <span class="typ">bool </span>ordi_color, <span class="typ">int </span>depth);

    <span class="key">inline </span><span class="typ">double </span>MTDFdouble(<span class="typ">int </span>depth, <span class="typ">double </span>f, <span class="typ">bool </span>ordi_color) ;
    <span class="typ">double </span>OnebyOneBP(Coup&amp; bp, <span class="typ">bool </span>ordi_color, <span class="typ">int </span>depth, <span class="typ">double </span>temps_max, Timer&amp; global) ;

        <span class="com">// Possiblit&eacute; de coup
</span>        <span class="com">// Pour l'instant isol&eacute; interdit
</span>    <span class="typ">bool </span>calcule_poss_dessus_noir(<span class="typ">const bool </span>c, <span class="typ">const </span>Hauteur_t t) <span class="typ">const </span>;
    <span class="typ">bool </span>calcule_poss_dessous_noir(<span class="typ">const bool </span>c, <span class="typ">const </span>Hauteur_t t)  <span class="typ">const </span>;
    <span class="typ">bool </span>calcule_poss_dessus_blanc(<span class="typ">const bool </span>c, <span class="typ">const </span>Hauteur_t t)  <span class="typ">const </span>;
    <span class="typ">bool </span>calcule_poss_dessous_blanc(<span class="typ">const bool </span>c, <span class="typ">const </span>Hauteur_t t)  <span class="typ">const </span>;
    Hauteur_t calcule_poss_blancs(Possible_t&amp; Liste, <span class="typ">const </span>Case_t depart, <span class="typ">const </span>Hauteur_t hdepalt, <span class="typ">const </span>Case_t arrivee)  <span class="typ">const </span>;
    Hauteur_t calcule_poss_noirs(Possible_t&amp; Liste, <span class="typ">const </span>Case_t depart, <span class="typ">const </span>Hauteur_t hdepalt, <span class="typ">const </span>Case_t arrivee)  <span class="typ">const </span>;

	<span class="com">// Entr&eacute;es/Sorties
</span>    <span class="key">friend </span>std::ostream&amp; <span class="key">operator</span>&lt;&lt; &lt;&gt;(std::ostream&amp; out, <span class="typ">const </span>Agora&amp; p) ;
    <span class="key">friend </span>std::ostream&amp; affiche &lt;&gt;(std::ostream&amp; out, <span class="typ">const </span>Agora&amp; p) ;
    <span class="key">friend </span>std::ostream&amp; details &lt;&gt;(std::ostream&amp; out, <span class="typ">const </span>Agora&amp; p) ;
    <span class="key">friend </span>std::istream&amp; <span class="key">operator</span>&gt;&gt; &lt;&gt;(std::istream&amp; in, Agora&amp; p) ;

};

<span class="dir">#include </span><span class="dstr">&quot;agora_init.inl&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agora_io.inl&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agora_jouer.inl&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agora_evaluation.inl&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agora_alphabeta.inl&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agora_coupspossibles.inl&quot;</span><span class="dir">
</span><span class="dir">#endif</span></pre>


<h2>agoraViewer.h</h2>
<pre>

<span class="dir">#include </span><span class="dstr">&quot;QGLViewer/qglviewer.h&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agora.h&quot;</span><span class="dir">
</span>
<span class="key">typedef </span>Agora&lt;<span class="typ">unsigned short</span>&gt; Agora_t;
<span class="key">typedef </span>Agora_t::Pile_t Pile;
<span class="key">typedef </span>Agora_t::Coup Play;
<span class="key">typedef </span>Case_t Position;
<span class="key">typedef </span>Agora_t::Possible_t Possibles;


<span class="key">class </span>AgoraViewer : <span class="key">public </span>QGLViewer
{
  Q_OBJECT

<span class="key">public</span>:
  AgoraViewer(QWidget* parent=NULL, <span class="typ">const char</span>* name=<span class="num">0</span>);

 <span class="key">public </span>slots:
 <span class="com">// F i l e   m e n u
</span> <span class="typ">void </span>load();
 <span class="typ">void </span>save();
 <span class="typ">void </span>saveAs();
 <span class="typ">void </span>print() { std::cout &lt;&lt; <span class="str">&quot;Print not yet implemented&quot;</span> &lt;&lt; std::endl; }

  <span class="com">// G a m e   m e n u
</span>  <span class="typ">void </span>undo();
  <span class="typ">void </span>redo();
  <span class="typ">void </span>startNewGame() { initGame(); updateGL(); }
  <span class="typ">void </span>suggestPlay() { play_ = agora.Suggest(play_, blackPlay_, gameLevel_.computerMaxReflexionTime_, gameLevel_.computerMaxDepth_); play(); }
  <span class="typ">void </span>togglePlayAgainstComputer(<span class="typ">bool </span>on);
  <span class="typ">void </span>levelIsEasy()      { gameLevel_.computerMaxDepth_ = <span class="num">3</span>; }
  <span class="typ">void </span>levelIsAverage()   { gameLevel_.computerMaxReflexionTime_ = <span class="num">1.5</span>; gameLevel_.computerMaxDepth_ = <span class="num">0</span>; }
  <span class="typ">void </span>levelIsDifficult() { gameLevel_.computerMaxReflexionTime_ = <span class="num">8.0</span>; gameLevel_.computerMaxDepth_ = <span class="num">0</span>; }
  <span class="typ">void </span>toggleComputerIsBlack(<span class="typ">bool </span>black) { computerIsBlack_ = black; }

  <span class="com">// D i s p l a y   m e n u
</span>  <span class="typ">void </span>toggleAnimation(<span class="typ">bool </span>on) { animatePlays_ = on; }
  <span class="typ">void </span>toggleLight(<span class="typ">bool </span>on) { <span class="key">if </span>(on) glEnable(GL_LIGHT1); <span class="key">else </span>glDisable(GL_LIGHT1); updateGL(); }
  <span class="typ">void </span>toggleTexture(<span class="typ">bool </span>on) { textures_ = on; updateGL(); }
  <span class="typ">void </span>toggleShowPossible(<span class="typ">bool </span>on) { displayPossibleDestination_ = on; updateGL(); }

  <span class="com">// H e l p   m e n u
</span>  <span class="typ">void </span>help();
  <span class="typ">void </span>about();

<span class="key">protected </span>:
  <span class="typ">void </span>draw();
  <span class="typ">void </span>mouseDoubleClickEvent(QMouseEvent *) {};
  <span class="typ">void </span>keyPressEvent(QKeyEvent *) {};
  <span class="typ">void </span>select(<span class="typ">const </span>QMouseEvent*);
  <span class="typ">void </span>init();
  <span class="typ">void </span>play();

<span class="key">private </span>slots:
 <span class="typ">void </span>simplePlay();

<span class="key">private </span>:
  <span class="com">// D r a w i n g   f u n c t i o n s
</span>  <span class="typ">void </span>drawAgora() <span class="typ">const</span>;
  <span class="typ">void </span>drawAllPieces(<span class="typ">bool </span>select = <span class="key">false</span>) <span class="typ">const</span>;
  <span class="typ">void </span>drawPiece() <span class="typ">const</span>;
  <span class="typ">void </span>highlightSelectedPiece() <span class="typ">const</span>;
  <span class="typ">void </span>drawPossibleDestinations(<span class="typ">bool </span>select = <span class="key">false</span>) <span class="typ">const</span>;

  <span class="com">// D r a w i n g   u t i l s
</span>  <span class="typ">void </span>drawBorder(<span class="typ">float </span>width, <span class="typ">float </span>height, <span class="typ">bool </span>out=<span class="key">true</span>, <span class="typ">float </span>heightMin=<span class="num">0.0</span>) <span class="typ">const</span>;
  <span class="typ">void </span>drawBorderLines(<span class="typ">float </span>width, <span class="typ">float </span>height, <span class="typ">bool </span>out=<span class="key">true</span>, <span class="typ">float </span>heightMin=<span class="num">0.0</span>) <span class="typ">const</span>;
  <span class="typ">void </span>drawFace(<span class="typ">float </span>width, <span class="typ">float </span>height, <span class="typ">bool </span>up) <span class="typ">const</span>;
  <span class="typ">void </span>drawRing(<span class="typ">float </span>width, <span class="typ">float </span>height, <span class="typ">float </span>thickness=<span class="num">1.0</span>) <span class="typ">const</span>;
  <span class="typ">void </span>drawSeparatingBars(<span class="typ">float </span>width, <span class="typ">float </span>height, <span class="typ">float </span>thickness=<span class="num">1.0</span>) <span class="typ">const</span>;
  <span class="typ">void </span>drawLeveLines(<span class="typ">float </span>width, <span class="typ">float </span>height) <span class="typ">const</span>;

  <span class="com">// I n i t i a l i z a t i o n
</span>  <span class="typ">void </span>initSpotLight();
  <span class="typ">void </span>initCamera();
  <span class="typ">void </span>initViewer();
  <span class="typ">void </span>initGame();

  <span class="com">// G a m e   i n t e r f a c e
</span>  <span class="typ">void </span>reactToSelection(<span class="typ">int </span>selected, <span class="typ">bool </span>onTop);
  <span class="typ">void </span>updatePiecePositions();
  <span class="typ">int </span>higherPieceOnPosition(Position pos) <span class="typ">const</span>;
  <span class="typ">void </span>animatePlay();
  <span class="typ">void </span>deselect();

  <span class="com">// Size of one Agora position is 1.0, entire board is hence 6.0 x 6.0.
</span>  <span class="typ">static const float </span>pieceSize   = <span class="num">29.0 </span>/ <span class="num">38.0</span>;
  <span class="typ">static const float </span>pieceHeight = <span class="num">5.0 </span>/ <span class="num">38.0</span>;
  qglviewer::Vec normal[<span class="num">5</span>];

  Agora_t agora;
  Play play_;

  <span class="typ">bool </span>blackPlay_;
  <span class="typ">bool </span>computerIsBlack_;

  <span class="key">struct </span>AgoraLevel {
    <span class="typ">float </span>computerMaxReflexionTime_;
    <span class="typ">int </span>computerMaxDepth_;
  } gameLevel_;

  <span class="typ">int </span>selectedPiece_;
  <span class="typ">bool </span>playerIsComputer_;
  <span class="typ">bool </span>gameIsOver_;

  <span class="com">// D i s p l a y   F l a g s
</span>  <span class="typ">bool </span>displayPossibleDestination_;
  <span class="typ">bool </span>animatePlays_;
  <span class="typ">bool </span>textures_;

  <span class="key">struct </span>Piece
  {
    Position square;
    <span class="typ">bool </span>isBlack;
    qglviewer::Frame frame;
    <span class="typ">float </span>scale;
    <span class="typ">int </span>level;
  };
  Piece piece_[<span class="num">16</span>];
  qglviewer::Vec casePosition[<span class="num">36</span>];
  Possibles possibleDest_;

  qglviewer::KeyFrameInterpolator kfi_[<span class="num">16</span>];
  QString fileName;

  <span class="key">struct </span>Undo
  {
    Undo() {};
    Undo(<span class="typ">const </span>Play&amp; play, <span class="typ">const </span>Agora_t&amp; agora);
    Position pos1,    pos2;
    Pile     before1, before2;
    Pile     after1,  after2;
  };
  std::vector&lt;Undo&gt; history_;
  <span class="typ">void </span>updateUndoHistory(<span class="typ">bool </span>before);
  <span class="typ">unsigned int </span>undoIndex_, maxUndoIndex_;
};</pre>


<h2>agoraWindow.ui.h</h2>
<pre>

<span class="com">/****************************************************************************
** ui.h extension file, included from the uic-generated form implementation.
**
** If you wish to add, delete or rename slots use Qt Designer which will
** update this file, preserving your code. Create an init() slot in place of
** a constructor, and a destroy() slot in place of a destructor.
*****************************************************************************/</span>

</pre>


<h2>agora_class.h</h2>
<pre>

<span class="com">// =================================================================== //
</span><span class="com">// Time-stamp: &lt;19 Jun 03 15:53:22 Jean-Guillaume.Dumas@imag.fr&gt;
</span><span class="com">// =================================================================== //
</span><span class="dir">#ifndef __Agora_Class__
</span><span class="dir">#define __Agora_Class__
</span>
<span class="key">template</span>&lt;<span class="key">class </span>Ints = <span class="typ">unsigned short</span>&gt; <span class="key">class </span>Agora ;

<span class="dir">#endif</span></pre>


<h2>agora_container.h</h2>
<pre>

<span class="com">// =================================================================== //
</span><span class="com">// Time-stamp: &lt;23 Jun 03 10:42:45 Jean-Guillaume.Dumas@imag.fr&gt;
</span><span class="com">// =================================================================== //
</span><span class="dir">#ifndef __Agora_Container__
</span><span class="dir">#define __Agora_Container__
</span>
<span class="com">// #include &lt;vector&gt;
</span><span class="com">// typedef std::vector AgoraContainer;
</span>
<span class="dir">#include &lt;iostream&gt;
</span>
<span class="key">template</span>&lt;<span class="typ">int </span>POSS_SIZE, typename Elem&gt; <span class="key">struct </span>AgoraContainer {
<span class="key">private</span>:
    <span class="key">typedef </span>AgoraContainer&lt;POSS_SIZE, Elem&gt; Self_t;
    Elem _container[ POSS_SIZE ];
    Elem * _finish;
<span class="key">public</span>:
    <span class="key">typedef </span>Elem* iterator;
    <span class="key">typedef </span><span class="typ">const </span>Elem* const_iterator;
    AgoraContainer() : _finish(_container) { }
    AgoraContainer(<span class="typ">int </span>s) : _finish(_container+s) { }
    Case_t size() <span class="typ">const </span>{ <span class="key">return </span>Case_t(_finish - _container); }
    <span class="typ">void </span>clear() { _finish = _container; }
    <span class="typ">void </span>resize(<span class="typ">int </span>s) { _finish = _container + s; }
    iterator begin() { <span class="key">return </span>_container; }
    iterator end() { <span class="key">return </span>_finish; }
    const_iterator begin() <span class="typ">const </span>{ <span class="key">return </span>const_iterator(_container); }
    const_iterator end() <span class="typ">const </span>{ <span class="key">return </span>const_iterator(_finish); }
    <span class="typ">void </span>push_back(<span class="typ">const </span>Elem&amp; c) {
        *_finish = c; ++_finish;
    }
};

<span class="dir">#endif</span></pre>


<h2>agora_coup.h</h2>
<pre>

<span class="com">// =================================================================== //
</span><span class="com">// Time-stamp: &lt;20 Jun 03 18:45:45 Jean-Guillaume.Dumas@imag.fr&gt;
</span><span class="com">// =================================================================== //
</span><span class="dir">#ifndef __Agora_Coup__
</span><span class="dir">#define __Agora_Coup__
</span><span class="dir">#include </span><span class="dstr">&quot;agora_types.h&quot;</span><span class="dir">
</span><span class="dir">#include &lt;iostream&gt;
</span>
<span class="key">struct </span>AgoraCoup {
    AgoraCoup() {}
    AgoraCoup(Case_t d, Case_t a, <span class="typ">bool </span>b)
            : _depart(d), _arrivee(a), _dessus(b) {}

    Case_t depart() <span class="typ">const </span>{ <span class="key">return </span>_depart; }
    Case_t arrivee() <span class="typ">const </span>{ <span class="key">return </span>_arrivee; }
    <span class="typ">bool </span>dessus() <span class="typ">const </span>{ <span class="key">return </span>_dessus; }



    <span class="typ">void </span>copy( <span class="typ">const </span>AgoraCoup&amp; c) {
        _depart = c._depart;
        _arrivee = c._arrivee;
        _dessus = c._dessus;
    }

    <span class="typ">bool </span><span class="key">operator</span>==( <span class="typ">const </span>AgoraCoup&amp; c) {
        <span class="key">return </span>(    (_depart  == c._depart)
                    &amp;&amp; (_arrivee == c._arrivee)
                    &amp;&amp; (_dessus  == c._dessus)   );
    }

    <span class="key">friend </span>std::ostream&amp; <span class="key">operator</span>&lt;&lt; (std::ostream&amp; out, <span class="typ">const </span>AgoraCoup&amp; c) {
        <span class="key">return </span>out &lt;&lt; (Size_t)(c._depart) &lt;&lt; (c._dessus?<span class="str">&quot;/&quot;</span>:<span class="str">&quot;</span><span class="esc">\\</span><span class="str">&quot;</span>) &lt;&lt; (Size_t)(c._arrivee);
    }

    <span class="key">friend </span>std::istream&amp; <span class="key">operator</span>&gt;&gt; (std::istream&amp; in, AgoraCoup&amp; c) {
        <span class="typ">char </span>s; Size_t d, a;
        in &gt;&gt; d &gt;&gt; s &gt;&gt; a;
        c._depart = (Case_t)d;
        c._arrivee = (Case_t)a;
        <span class="key">if </span>(s == <span class="str">'/'</span>) c._dessus = <span class="num">1</span>;
        <span class="key">else </span>c._dessus = <span class="num">0</span>;
        <span class="key">return </span>in;
    }

<span class="key">private</span>:
    Case_t _depart, _arrivee;
    <span class="typ">bool </span>_dessus;
};

<span class="dir">#endif</span></pre>


<h2>agora_io.h</h2>
<pre>

<span class="com">// =================================================================== //
</span><span class="com">// Time-stamp: &lt;24 Jun 03 14:51:09 Jean-Guillaume.Dumas@imag.fr&gt;
</span><span class="com">// =================================================================== //
</span><span class="dir">#ifndef __Agora_IO_H__
</span><span class="dir">#define __Agora_IO_H__
</span>
<span class="dir">#include </span><span class="dstr">&quot;agora_class.h&quot;</span><span class="dir">
</span>
<span class="key">template</span>&lt;<span class="key">class </span>Ints&gt;
std::ostream&amp; <span class="key">operator</span>&lt;&lt; (std::ostream&amp; out, <span class="typ">const </span>Agora&lt;Ints&gt;&amp; p) ;

<span class="key">template</span>&lt;<span class="key">class </span>Ints&gt;
std::ostream&amp; details (std::ostream&amp; out, <span class="typ">const </span>Agora&lt;Ints&gt;&amp; p) ;

<span class="key">template</span>&lt;<span class="key">class </span>Ints&gt;
std::ostream&amp; affiche (std::ostream&amp; out, <span class="typ">const </span>Agora&lt;Ints&gt;&amp; p) ;

<span class="key">template</span>&lt;<span class="key">class </span>Ints&gt;
std::istream&amp; <span class="key">operator</span>&gt;&gt; (std::istream&amp; in, Agora&lt;Ints&gt;&amp; p) ;

<span class="dir">#endif</span></pre>


<h2>agora_types.h</h2>
<pre>

<span class="com">// =================================================================== //
</span><span class="com">// Time-stamp: &lt;30 Jun 03 18:50:44 Jean-Guillaume.Dumas@imag.fr&gt;
</span><span class="com">// =================================================================== //
</span><span class="dir">#ifndef __Agora_Types__
</span><span class="dir">#define __Agora_Types__
</span>
<span class="dir">#include &lt;vector&gt;
</span><span class="key">typedef </span><span class="typ">short </span>Eval_t;
<span class="key">typedef </span><span class="typ">unsigned short </span>Hauteur_t;
<span class="key">typedef </span><span class="typ">unsigned long </span>Size_t;
<span class="key">typedef </span><span class="typ">unsigned short </span>Case_t;
<span class="key">typedef </span>std::vector&lt;Hauteur_t&gt; Table_t;


<span class="dir">#endif</span></pre>


<h2>container_stream.h</h2>
<pre>

<span class="com">// =================================================================== //
</span><span class="com">// Time-stamp: &lt;20 Jun 03 18:42:27 Jean-Guillaume.Dumas@imag.fr&gt;
</span><span class="com">// =================================================================== //
</span><span class="dir">#ifndef __CONTAINER_STREAM__
</span><span class="dir">#define __CONTAINER_STREAM__
</span>
<span class="dir">#include &lt;iostream&gt;
</span><span class="key">template</span>&lt;<span class="key">class </span>T, <span class="key">template </span>&lt;<span class="key">class </span>T&gt; <span class="key">class </span>Container &gt;
std::ostream&amp; <span class="key">operator</span>&lt;&lt; (std::ostream&amp; o, <span class="typ">const </span>Container&lt;T&gt;&amp; v) {
    o &lt;&lt; <span class="str">&quot;[&quot;</span>;
    typename Container&lt;T&gt;::const_iterator vi = v.begin();
    <span class="key">for</span>( ; vi != v.end(); ++vi)
        o &lt;&lt; *vi &lt;&lt; <span class="str">&quot; &quot;</span>;
    <span class="key">return </span>o &lt;&lt; <span class="str">&quot;]&quot;</span>;
}

<span class="key">template</span>&lt;<span class="typ">int </span>I, <span class="key">class </span>T, <span class="key">template </span>&lt;<span class="typ">int </span>I, <span class="key">class </span>T&gt; <span class="key">class </span>Container &gt;
std::ostream&amp; <span class="key">operator</span>&lt;&lt; (std::ostream&amp; o, <span class="typ">const </span>Container&lt;I,T&gt;&amp; v) {
    o &lt;&lt; <span class="str">&quot;[&quot;</span>;
    typename Container&lt;I,T&gt;::const_iterator vi = v.begin();
    <span class="key">for</span>( ; vi != v.end(); ++vi)
        o &lt;&lt; *vi &lt;&lt; <span class="str">&quot; &quot;</span>;
    <span class="key">return </span>o &lt;&lt; <span class="str">&quot;]&quot;</span>;
}

<span class="dir">#endif</span></pre>


<h2>givtimer.h</h2>
<pre>

<span class="dir">#ifndef _TIMER_H_
</span><span class="dir">#define _TIMER_H_
</span><span class="com">// ==========================================================================
</span><span class="com">// $Source: /local/cvs/Agora/givtimer.h,v $
</span><span class="com">// Copyright(c)'94-97 by Givaro Team
</span><span class="com">// see the copyright file.
</span><span class="com">// Authors: T. Gautier
</span><span class="com">// $Id: givtimer.h,v 1.1.1.1 2003/06/20 13:03:43 jgdumas Exp $
</span><span class="com">// ==========================================================================
</span><span class="com">// Description:
</span>
<span class="dir">#include &lt;iostream&gt;
</span>
<span class="com">// class RealTimer; class SysTimer; class UserTimer;
</span>
<span class="key">class </span>BaseTimer {
<span class="key">public</span>:
<span class="key">enum </span>{
  MSPSEC = <span class="num">1000000  </span><span class="com">// microsecond per second
</span>};

   <span class="com">// -- Clear timer :
</span>  <span class="key">inline </span><span class="typ">void </span>clear() { _t = <span class="num">0</span>; }

  <span class="com">// -- total amount of second spent
</span>  <span class="key">inline </span><span class="typ">double </span>time() <span class="typ">const </span>{ <span class="key">return </span>_t; }

  <span class="com">// -- Return a value to initialize random generator
</span><span class="typ">static long </span>seed();

  <span class="com">// -- basic methods:
</span>  std::ostream&amp; print( std::ostream&amp; ) <span class="typ">const</span>;

  <span class="com">// -- Some arithmetic operators to compute cumulative time :
</span>  BaseTimer&amp; <span class="key">operator </span>= (<span class="typ">const </span>BaseTimer &amp; T) ;
  <span class="typ">const </span>BaseTimer <span class="key">operator </span>- (<span class="typ">const </span>BaseTimer &amp; T)  <span class="typ">const</span>;
  <span class="typ">const </span>BaseTimer <span class="key">operator </span>- () ;
  <span class="typ">const </span>BaseTimer <span class="key">operator </span>+  (<span class="typ">const </span>BaseTimer &amp; T)  <span class="typ">const</span>;
  <span class="typ">const </span>BaseTimer <span class="key">operator </span>+= (<span class="typ">const </span>BaseTimer &amp; T) { <span class="key">return </span>*<span class="key">this </span>= *<span class="key">this </span>+ T; };
  <span class="typ">const </span>BaseTimer <span class="key">operator </span>-= (<span class="typ">const </span>BaseTimer &amp; T) { <span class="key">return </span>*<span class="key">this </span>= *<span class="key">this </span>- T; };

<span class="key">public</span>:
   <span class="typ">double </span>_t;  <span class="com">// time
</span>};
<span class="key">inline </span>std::ostream&amp; <span class="key">operator</span>&lt;&lt; (std::ostream&amp; o, <span class="typ">const </span>BaseTimer&amp; BT)
{ <span class="key">return </span>BT.print(o);}


<span class="key">class </span>RealTimer : <span class="key">public </span>BaseTimer {
<span class="key">public</span>:
  <span class="key">inline </span>RealTimer( <span class="typ">const </span>BaseTimer&amp; BT ): BaseTimer(BT) {};
  <span class="key">inline </span>RealTimer( ){};
  <span class="typ">void </span>start();
  <span class="typ">void </span>stop();
};


<span class="key">class </span>UserTimer : <span class="key">public </span>BaseTimer {
<span class="key">public</span>:
  <span class="key">inline </span>UserTimer( <span class="typ">const </span>BaseTimer&amp; BT ): BaseTimer(BT) {};
  <span class="key">inline </span>UserTimer( ) {};
  <span class="typ">void </span>start();
  <span class="typ">void </span>stop();
};


<span class="key">class </span>SysTimer : <span class="key">public </span>BaseTimer {
<span class="key">public</span>:
  <span class="key">inline </span>SysTimer( <span class="typ">const </span>BaseTimer&amp; BT ): BaseTimer(BT) {};
  <span class="key">inline </span>SysTimer( ) {};
  <span class="typ">void </span>start();
  <span class="typ">void </span>stop();
};


<span class="key">class </span>Timer {
<span class="key">public </span>:

   <span class="com">// Clear timer :
</span>  <span class="typ">void </span>clear();

   <span class="com">// Start timer
</span>  <span class="typ">void </span>start();

  <span class="com">// Stop timer
</span>  <span class="typ">void </span>stop();

  <span class="com">// total amount of second spent in user mode
</span>  <span class="typ">double </span>usertime() <span class="typ">const </span>{ <span class="key">return </span>ut.time(); }

  <span class="com">// total amount of second spent in system mode
</span>  <span class="typ">double </span>systime () <span class="typ">const </span>{ <span class="key">return </span>st.time(); }

  <span class="com">// real total amount of second spent.
</span>  <span class="typ">double </span>realtime () <span class="typ">const </span>{ <span class="key">return </span>rt.time(); }

  <span class="com">// retourne une petite graine
</span>  <span class="com">// long seed() const { return RealTimer::seed(); }
</span>
  <span class="com">// Some arithmetic operators to compute cumulative time :
</span>  Timer&amp; <span class="key">operator </span>= (<span class="typ">const </span>Timer &amp; T) ;
  <span class="typ">const </span>Timer <span class="key">operator </span>- (<span class="typ">const </span>Timer &amp; T)  <span class="typ">const</span>;
  <span class="typ">const </span>Timer <span class="key">operator </span>- () ;
  <span class="typ">const </span>Timer <span class="key">operator </span>+ (<span class="typ">const </span>Timer &amp; T)  <span class="typ">const</span>;
  <span class="typ">const </span>Timer <span class="key">operator </span>+= (<span class="typ">const </span>Timer &amp; T) { <span class="key">return </span>*<span class="key">this </span>= *<span class="key">this </span>+ T; };
  <span class="typ">const </span>Timer <span class="key">operator </span>-= (<span class="typ">const </span>Timer &amp; T) { <span class="key">return </span>*<span class="key">this </span>= *<span class="key">this </span>- T; };


  <span class="com">// -- methods :
</span>  std::ostream&amp; print( std::ostream&amp; ) <span class="typ">const</span>;

<span class="key">public</span>:
 RealTimer rt;
 UserTimer ut;
 SysTimer  st;
};
<span class="com">// inline std::ostream&amp; operator&lt;&lt;( std::ostream&amp; o, const Timer&amp; T)
</span><span class="com">// { return T.print(o);}
</span>
<span class="key">inline </span>std::ostream&amp; <span class="key">operator</span>&lt;&lt;( std::ostream&amp; o, <span class="typ">const </span>Timer&amp; T)
{ <span class="key">return </span>o &lt;&lt; T.realtime() &lt;&lt; <span class="str">&quot;s (&quot;</span> &lt;&lt; T.usertime() &lt;&lt; <span class="str">&quot; cpu)&quot;</span>; }


<span class="dir">#endif</span></pre>


<h2>agoraViewer.cpp</h2>
<pre>

<span class="dir">#include </span><span class="dstr">&quot;agoraViewer.h&quot;</span><span class="dir">
</span><span class="dir">#include </span><span class="dstr">&quot;agoraWindow.h&quot;</span><span class="dir">
</span><span class="dir">#include &lt;fstream&gt;
</span><span class="dir">#include &lt;math.h&gt;
</span><span class="dir">#include &lt;qmessagebox.h&gt;
</span><span class="dir">#include &lt;qimage.h&gt;
</span><span class="dir">#include &lt;qfile.h&gt;
</span><span class="dir">#include &lt;qfileinfo.h&gt;
</span><span class="dir">#include &lt;qfiledialog.h&gt;
</span><span class="dir">#include &lt;qaction.h&gt;
</span>
<span class="key">using namespace </span>std;
<span class="key">using namespace </span>qglviewer;

AgoraViewer::AgoraViewer(QWidget* parent, <span class="typ">const char</span>* name)
  : QGLViewer(parent, name), computerIsBlack_(<span class="key">true</span>), selectedPiece_(<span class="num">-1</span>),
    playerIsComputer_(<span class="key">true</span>), displayPossibleDestination_(<span class="key">true</span>), animatePlays_(<span class="key">true</span>), textures_(<span class="key">true</span>),
    fileName(<span class="str">&quot;savedGame.ago&quot;</span>), undoIndex_(<span class="num">0</span>), maxUndoIndex_(<span class="num">0</span>)
{
  <span class="com">// Stored once and for all
</span>  normal[<span class="num">0</span>] = Vec(<span class="num">-1.0</span>,  <span class="num">0.0</span>, <span class="num">0.0</span>);
  normal[<span class="num">1</span>] = Vec( <span class="num">0.0</span>,  <span class="num">1.0</span>, <span class="num">0.0</span>);
  normal[<span class="num">2</span>] = Vec( <span class="num">1.0</span>,  <span class="num">0.0</span>, <span class="num">0.0</span>);
  normal[<span class="num">3</span>] = Vec( <span class="num">0.0</span>, <span class="num">-1.0</span>, <span class="num">0.0</span>);
  normal[<span class="num">4</span>] = normal[<span class="num">0</span>];

  levelIsEasy();

  <span class="com">// Prevent too many updateGL when several KFI are runned together. Only kfi_[0] updatesGL.
</span>  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">1</span>; i&lt;<span class="num">16</span>; ++i)
    QObject::disconnect(&amp;kfi_[i], SIGNAL(interpolated()), <span class="key">this</span>, SLOT(updateGL()));
  QObject::connect(&amp;kfi_[<span class="num">0</span>], SIGNAL(finished()), <span class="key">this</span>, SLOT(simplePlay()));
}


<span class="com">// I n i t i a l i z a t i o n   f u n c t i o n s //
</span>
<span class="typ">void </span>AgoraViewer::init()
{
  initViewer();
  initSpotLight();
  initCamera();
  initGame();

  setMouseBinding(Qt::RightButton, CAMERA, ManipulatedFrame::ROTATE);
  setMouseBinding(Qt::LeftButton, SELECT);
}

<span class="typ">void </span>AgoraViewer::initSpotLight()
{
  glMatrixMode(GL_MODELVIEW);
  glEnable(GL_LIGHT1);
  glLoadIdentity();

  <span class="com">// Light default parameters
</span>  <span class="typ">const </span>GLfloat light_ambient[<span class="num">4</span>]  = {<span class="num">2.0</span>, <span class="num">2.0</span>, <span class="num">2.0</span>, <span class="num">1.0</span>};
  <span class="typ">const </span>GLfloat light_specular[<span class="num">4</span>] = {<span class="num">2.0</span>, <span class="num">2.0</span>, <span class="num">2.0</span>, <span class="num">1.0</span>};
  <span class="typ">const </span>GLfloat light_diffuse[<span class="num">4</span>]  = {<span class="num">2.0</span>, <span class="num">2.0</span>, <span class="num">2.0</span>, <span class="num">1.0</span>};

  glLightf( GL_LIGHT1, GL_SPOT_EXPONENT,  <span class="num">2.0</span>);
  glLightf( GL_LIGHT1, GL_SPOT_CUTOFF,    <span class="num">60.0</span>);
  glLightf( GL_LIGHT1, GL_CONSTANT_ATTENUATION, <span class="num">0.1</span>);
  glLightf( GL_LIGHT1, GL_LINEAR_ATTENUATION, <span class="num">0.3</span>);
  glLightf( GL_LIGHT1, GL_QUADRATIC_ATTENUATION, <span class="num">0.3</span>);
  glLightfv(GL_LIGHT1, GL_AMBIENT,  light_ambient);
  glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular);
  glLightfv(GL_LIGHT1, GL_DIFFUSE,  light_diffuse);
}

<span class="key">class </span>BoardConstraint : <span class="key">public </span>Constraint
{
<span class="key">public</span>:
  <span class="key">virtual </span><span class="typ">void </span>constrainRotation(Quaternion&amp; q, Frame * <span class="typ">const </span>fr)
  {
    <span class="typ">const </span>Vec up = fr-&gt;transformOf(Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">1.0</span>));
    Vec axis = q.axis();
    <span class="typ">float </span>angle = <span class="num">2.0</span>*acos(q[<span class="num">3</span>]);
    <span class="key">if </span>(fabs(axis*up) &gt; fabs(axis.x))
      axis.projectOnAxis(up);
    <span class="key">else
      </span>{
	angle = (axis.x &gt; <span class="num">0.0</span>) ? angle : -angle;
	axis.setValue(fabs(axis.x), <span class="num">0.0</span>, <span class="num">0.0</span>);
	<span class="typ">const float </span>currentAngle = asin(fr-&gt;inverseTransformOf(Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">-1.0</span>)).z);
	<span class="key">if </span>(currentAngle + angle &gt; <span class="num">-0.2</span>)
	  angle = <span class="num">-0.2 </span>- currentAngle; <span class="com">// Not too low
</span>	<span class="key">if </span>(currentAngle + angle &lt; -M_PI/<span class="num">2.0</span>)
	  angle = -M_PI/<span class="num">2.0 </span>- currentAngle; <span class="com">// Do not pass on the other side
</span>      }
    q = Quaternion(axis, angle);
  }
};

<span class="typ">void </span>AgoraViewer::initCamera()
{
  camera()-&gt;setUpVector(Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">1.0</span>));
  camera()-&gt;setPosition(Vec(<span class="num">-6.0</span>, <span class="num">-6.0</span>, <span class="num">4.0</span>));
  camera()-&gt;lookAt(sceneCenter());
  setSceneRadius(<span class="num">3.5</span>);
  showEntireScene();

  <span class="com">// Limit camera rotation motion
</span>  camera()-&gt;frame()-&gt;setConstraint(<span class="key">new </span>BoardConstraint());
}

<span class="typ">void </span>AgoraViewer::initGame()
{
  agora.reinit();
  updatePiecePositions();
  blackPlay_ = <span class="key">false</span>;
  gameIsOver_ = <span class="key">false</span>;
}

<span class="typ">void </span>AgoraViewer::initViewer()
{
  <span class="typ">int </span>count = <span class="num">0</span>;
  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">6</span>; ++i)
    <span class="key">for </span>(<span class="typ">int </span>j=<span class="num">0</span>; j&lt;<span class="num">6</span>; ++j)
      {
	<span class="typ">float </span>height;
	<span class="key">if </span>((i==<span class="num">0</span>) || (j==<span class="num">0</span>) || (i==<span class="num">5</span>) || (j==<span class="num">5</span>))
	  height = <span class="num">6.0 </span>* pieceHeight;
	<span class="key">else
	  if </span>((i==<span class="num">1</span>) || (j==<span class="num">1</span>) || (i==<span class="num">4</span>) || (j==<span class="num">4</span>))
	    height = <span class="num">3.0 </span>* pieceHeight;
	  <span class="key">else
	    </span>height = pieceHeight;

	casePosition[count++] = Vec(i-2.<span class="num">5</span>, j-2.<span class="num">5</span>, height);
      }

  glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA);
  <span class="com">// Enable GL textures
</span>  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  glEnable( GL_TEXTURE_2D );

  <span class="com">// Nice texture coordinate interpolation
</span>  glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

  <span class="typ">const </span>QString texFileName(<span class="str">&quot;wood.png&quot;</span>);
  QImage img(texFileName);

  <span class="key">if </span>(img.isNull())
    {
      cerr &lt;&lt; <span class="str">&quot;Unable to load wood texture from &quot;</span> &lt;&lt; texFileName &lt;&lt; endl;
      exit(<span class="num">1</span>);
    }

  <span class="com">// 1E-3 needed. Just try with width=128 and see !
</span>  <span class="key">if </span>( ( img.width()  != <span class="num">1</span>&lt;&lt;(<span class="typ">int</span>)(<span class="num">1</span>+log(img.width() <span class="num">-1</span>+<span class="num">1</span>E-3) / log(<span class="num">2.0</span>)) ) ||
       ( img.height() != <span class="num">1</span>&lt;&lt;(<span class="typ">int</span>)(<span class="num">1</span>+log(img.height()<span class="num">-1</span>+<span class="num">1</span>E-3) / log(<span class="num">2.0</span>))) )
    {
      cerr &lt;&lt; <span class="str">&quot;Texture dimensions are not powers of 2 in &quot;</span> &lt;&lt; texFileName &lt;&lt; endl;
      exit(<span class="num">1</span>);
    }

  QImage glImg = QGLWidget::convertToGLFormat(img);  <span class="com">// flipped 32bit RGBA
</span>
  <span class="com">// Bind the img texture...
</span>  glTexImage2D(GL_TEXTURE_2D, <span class="num">0</span>, <span class="num">4</span>, glImg.width(), glImg.height(), <span class="num">0</span>,
	       GL_RGBA, GL_UNSIGNED_BYTE, glImg.bits());
}




<span class="com">// D r a w i n g  f u n c t i o n s //
</span>
<span class="typ">void </span>AgoraViewer::draw()
{
  glColor3f(<span class="num">0.7</span>, <span class="num">0.7</span>, <span class="num">0.7</span>);
  glDisable(GL_LIGHTING);
  <span class="key">if </span>(blackPlay_)
    drawText(<span class="num">20</span>, <span class="num">20</span>, <span class="str">&quot;Blacks play&quot;</span>);
  <span class="key">else
    </span>drawText(<span class="num">20</span>, <span class="num">20</span>, <span class="str">&quot;Whites play&quot;</span>);
  glEnable(GL_LIGHTING);

  drawAgora();
  drawAllPieces();
  <span class="key">if </span>(selectedPiece_ &gt;= <span class="num">0</span>)
    {
      highlightSelectedPiece();
      <span class="key">if </span>(displayPossibleDestination_)
	drawPossibleDestinations();
    }
}

<span class="typ">void </span>AgoraViewer::drawAgora() <span class="typ">const
</span>{
  <span class="typ">static const </span>GLfloat pos[<span class="num">4</span>] = {<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">3.0</span>, <span class="num">1.0</span>};
  <span class="typ">const </span>GLfloat spot_dir[<span class="num">3</span>]   = {<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">-1.0</span>};
  glLightfv(GL_LIGHT1, GL_POSITION, pos);
  glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_dir);

  glColor3f(<span class="num">0.5</span>, <span class="num">0.5</span>, <span class="num">0.5</span>);
  <span class="key">if </span>(textures_)
    glEnable(GL_TEXTURE_2D);
  <span class="key">else
    </span>glDisable(GL_TEXTURE_2D);

  drawBorder(<span class="num">6.0</span>, <span class="num">6.0 </span>* pieceHeight);
  drawBorder(<span class="num">4.0</span>, <span class="num">6.0 </span>* pieceHeight, <span class="key">false</span>, <span class="num">3.0 </span>* pieceHeight);
  drawBorder(<span class="num">2.0</span>, <span class="num">3.0 </span>* pieceHeight, <span class="key">false</span>, pieceHeight);

  drawRing(<span class="num">6.0</span>, <span class="num">6.0 </span>* pieceHeight);
  drawRing(<span class="num">4.0</span>, <span class="num">3.0 </span>* pieceHeight);
  drawRing(<span class="num">2.0</span>, pieceHeight);
  drawFace(<span class="num">6.0</span>, <span class="num">0.0</span>, <span class="key">false</span>);
  glDisable(GL_TEXTURE_2D);

  glDisable(GL_LIGHTING);

  glLineWidth(<span class="num">3.0</span>);
  glColor3f(<span class="num">0.4</span>, <span class="num">0.4</span>, <span class="num">0.4</span>);
  drawBorderLines(<span class="num">6.0</span>, <span class="num">6.0 </span>* pieceHeight);
  drawBorderLines(<span class="num">4.0</span>, <span class="num">6.0 </span>* pieceHeight, <span class="key">false</span>, <span class="num">3.0 </span>* pieceHeight);
  drawBorderLines(<span class="num">2.0</span>, <span class="num">3.0 </span>* pieceHeight, <span class="key">false</span>, pieceHeight);

  drawLeveLines(<span class="num">4.0</span>, <span class="num">5.0 </span>* pieceHeight);
  drawLeveLines(<span class="num">4.0</span>, <span class="num">4.0 </span>* pieceHeight);
  drawLeveLines(<span class="num">2.0</span>, <span class="num">2.0 </span>* pieceHeight);

  glLineWidth(<span class="num">4.0</span>);
  glColor3f(<span class="num">0.1</span>, <span class="num">0.1</span>, <span class="num">0.1</span>);
  drawSeparatingBars(<span class="num">6.0</span>, <span class="num">6.0 </span>* pieceHeight);
  drawSeparatingBars(<span class="num">4.0</span>, <span class="num">3.0 </span>* pieceHeight);
  drawSeparatingBars(<span class="num">2.0</span>, pieceHeight);

  glEnable(GL_LIGHTING);
}

<span class="typ">void </span>AgoraViewer::drawPiece() <span class="typ">const
</span>{
  drawBorder(pieceSize, pieceHeight);
  drawFace(pieceSize, pieceHeight, <span class="key">true</span>);
  drawFace(pieceSize, <span class="num">0.0</span>, <span class="key">false</span>);

  glLineWidth(<span class="num">2.0</span>);
  glDisable(GL_LIGHTING);
  glColor3f(<span class="num">0.4</span>, <span class="num">0.4</span>, <span class="num">0.4</span>);
  drawBorderLines(pieceSize, pieceHeight);
  glEnable(GL_LIGHTING);
}

<span class="typ">void </span>AgoraViewer::highlightSelectedPiece() <span class="typ">const
</span>{
  glEnable(GL_BLEND);
  <span class="typ">const float </span>s = <span class="num">1.1 </span>* piece_[selectedPiece_].scale;
  glColor4f(<span class="num">0.3</span>, <span class="num">0.9</span>, <span class="num">0.3</span>, <span class="num">0.3</span>);
  glPushMatrix();
  glMultMatrixd(piece_[selectedPiece_].frame.matrix());
  glScalef(s, s, s);
  drawPiece();
  glPopMatrix();
  glDisable(GL_BLEND);
}

<span class="typ">void </span>AgoraViewer::drawAllPieces(<span class="typ">bool </span>select) <span class="typ">const
</span>{
  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">16</span>; ++i)
    {
      glPushMatrix();
      glMultMatrixd(piece_[i].frame.matrix());
      glScalef(piece_[i].scale, piece_[i].scale, <span class="num">1.0</span>);

      <span class="key">if </span>(piece_[i].isBlack)
	glColor3f(<span class="num">0.2</span>, <span class="num">0.2</span>, <span class="num">0.2</span>);
      <span class="key">else
	</span>glColor3f(<span class="num">0.9</span>, <span class="num">0.9</span>, <span class="num">0.9</span>);

      <span class="key">if </span>(select)
	glPushName(i);

      drawPiece();

      <span class="key">if </span>(select)
	glPopName();

      glPopMatrix();
    }
}

<span class="typ">void </span>AgoraViewer::drawPossibleDestinations(<span class="typ">bool </span>select) <span class="typ">const
</span>{
  glEnable(GL_BLEND);
  glColor4f(<span class="num">0.3</span>, <span class="num">0.3</span>, <span class="num">0.9</span>, <span class="num">0.5</span>);
  <span class="key">for </span>(Possibles::const_iterator it=possibleDest_.begin(), end=possibleDest_.end(); it != end; ++it)
    {
      <span class="typ">const int </span>dest = (*it).arrivee();

      glPushMatrix();
      glTranslatef(casePosition[dest].x, casePosition[dest].y, casePosition[dest].z + <span class="num">0.01</span>);

      <span class="key">if </span>(select)
	glPushName(dest);

      drawFace(<span class="num">0.9</span>, <span class="num">0.0</span>, <span class="key">true</span>);

      <span class="key">if </span>(select)
	<span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">16</span>; ++i)
	  <span class="key">if </span>(piece_[i].square == dest)
	    {
	      glPushMatrix();
	      glTranslatef(<span class="num">0.0</span>, <span class="num">0.0</span>, piece_[i].level * pieceHeight);
	      drawPiece();
	      glPopMatrix();
	    }

      <span class="key">if </span>(select)
	glPopName();

      glPopMatrix();
    }
  glDisable(GL_BLEND);
}

<span class="typ">void </span>AgoraViewer::drawBorder(<span class="typ">float </span>width, <span class="typ">float </span>height, <span class="typ">bool </span>out, <span class="typ">float </span>heightMin) <span class="typ">const
</span>{
  <span class="typ">const </span>Vec up(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">1.0</span>);
  <span class="typ">const float </span>coef = sqrt(<span class="num">2.0</span>) / <span class="num">2.0</span>;

  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">4</span>; ++i)
    {
      <span class="key">if </span>(out)
	glNormal3fv(normal[i].address());
      <span class="key">else
	</span>glNormal3fv((-normal[i]).address());

      glBegin(GL_QUADS);
      glTexCoord2f(-width*coef, heightMin);
      glVertex3fv((width/<span class="num">2.0</span>*(normal[i] - normal[i+<span class="num">1</span>]) + heightMin*up).address());
      glTexCoord2f(width*coef, heightMin);
      glVertex3fv((width/<span class="num">2.0</span>*(normal[i] + normal[i+<span class="num">1</span>]) + heightMin*up).address());
      glTexCoord2f(width*coef, height);
      glVertex3fv((width/<span class="num">2.0</span>*(normal[i] + normal[i+<span class="num">1</span>]) + height*up).address());
      glTexCoord2f(-width*coef,height);
      glVertex3fv((width/<span class="num">2.0</span>*(normal[i] - normal[i+<span class="num">1</span>]) + height*up).address());
      glEnd();
    }
}

<span class="typ">void </span>AgoraViewer::drawBorderLines(<span class="typ">float </span>width, <span class="typ">float </span>height, <span class="typ">bool </span>out, <span class="typ">float </span>heightMin) <span class="typ">const
</span>{
  <span class="typ">const </span>Vec up(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">1.0</span>);

  <span class="com">// Avoid aliassing on inside agora
</span>  <span class="key">if </span>(!out)
    {
      heightMin += <span class="num">0.01</span>;
      width     -= <span class="num">0.01</span>;
    }

  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">4</span>; ++i)
    {
      glBegin(GL_LINE_LOOP);
      glVertex3fv((width/<span class="num">2.0</span>*(normal[i] - normal[i+<span class="num">1</span>]) + heightMin*up).address());
      glVertex3fv((width/<span class="num">2.0</span>*(normal[i] + normal[i+<span class="num">1</span>]) + heightMin*up).address());
      glVertex3fv((width/<span class="num">2.0</span>*(normal[i] + normal[i+<span class="num">1</span>]) + height*up).address());
      glVertex3fv((width/<span class="num">2.0</span>*(normal[i] - normal[i+<span class="num">1</span>]) + height*up).address());
      glEnd();
    }
}

<span class="typ">void </span>AgoraViewer::drawRing(<span class="typ">float </span>width, <span class="typ">float </span>height, <span class="typ">float </span>thickness) <span class="typ">const
</span>{
  <span class="typ">const </span>Vec up(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">1.0</span>);
  <span class="typ">const float </span>dist1 = width/<span class="num">2.0</span>;
  <span class="typ">const float </span>dist2 = width/<span class="num">2.0</span>-thickness;

  glNormal3fv(up.address());

  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">4</span>; ++i)
    {
      <span class="typ">const </span>Vec dir1 = normal[i] - normal[i+<span class="num">1</span>];
      <span class="typ">const </span>Vec dir2 = normal[i] + normal[i+<span class="num">1</span>];

      glBegin(GL_QUADS);
      glTexCoord2f(dist1*dir1.x, dist1*dir1.y);
      glVertex3fv((dist1*dir1 + height*up).address());
      glTexCoord2f(dist1*dir2.x, dist1*dir2.y);
      glVertex3fv((dist1*dir2 + height*up).address());
      glTexCoord2f(dist2*dir2.x, dist2*dir2.y);
      glVertex3fv((dist2*dir2 + height*up).address());
      glTexCoord2f(dist2*dir1.x, dist2*dir1.y);
      glVertex3fv((dist2*dir1 + height*up).address());
      glEnd();
    }
}

<span class="typ">void </span>AgoraViewer::drawSeparatingBars(<span class="typ">float </span>width, <span class="typ">float </span>height, <span class="typ">float </span>thickness) <span class="typ">const
</span>{
  <span class="typ">const </span>Vec up(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">1.0</span>);

  height += <span class="num">0.01</span>;

  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">4</span>; ++i)
    {
      <span class="key">for </span>(<span class="typ">int </span>j=<span class="num">1</span>; j&lt;width-0.<span class="num">9</span>; ++j)
	{
	  glBegin(GL_LINES);
	  glVertex3fv((width/<span class="num">2.0</span>*normal[i] + (j*thickness-width/<span class="num">2.0</span>)*normal[i+<span class="num">1</span>] + height*up).address());
	  glVertex3fv(((width/<span class="num">2.0</span>-thickness)*normal[i] + (j-width/<span class="num">2.0</span>)*normal[i+<span class="num">1</span>] + height*up).address());
	  glEnd();
	}
    }
}

<span class="typ">void </span>AgoraViewer::drawLeveLines(<span class="typ">float </span>width, <span class="typ">float </span>height) <span class="typ">const
</span>{
  <span class="typ">const </span>Vec up(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">1.0</span>);
  width -= <span class="num">0.01</span>;

  glBegin(GL_LINE_LOOP);

  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">4</span>; ++i)
    glVertex3fv((width/<span class="num">2.0</span>*(normal[i] + normal[i+<span class="num">1</span>]) + height*up).address());

  glEnd();
}

<span class="typ">void </span>AgoraViewer::drawFace(<span class="typ">float </span>width, <span class="typ">float </span>height, <span class="typ">bool </span>up) <span class="typ">const
</span>{
  <span class="key">if </span>(up)
    glNormal3f(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">1.0</span>);
  <span class="key">else
    </span>glNormal3f(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">-1.0</span>);

  glBegin(GL_QUADS);
  glVertex3f(-width/<span class="num">2.0</span>, -width/<span class="num">2.0</span>, height);
  glVertex3f(-width/<span class="num">2.0</span>,  width/<span class="num">2.0</span>, height);
  glVertex3f( width/<span class="num">2.0</span>,  width/<span class="num">2.0</span>, height);
  glVertex3f( width/<span class="num">2.0</span>, -width/<span class="num">2.0</span>, height);
  glEnd();
}

<span class="typ">void </span>AgoraViewer::animatePlay()
{
  <span class="typ">float </span>start = <span class="num">0.0</span>;
  <span class="typ">float </span>end = <span class="num">0.8</span>;
  <span class="typ">int </span>hpops = higherPieceOnPosition(play_.depart());
  <span class="typ">int </span>hpope = higherPieceOnPosition(play_.arrivee());

  <span class="key">if </span>(hpops &lt; <span class="num">0</span>)
    cerr &lt;&lt; <span class="str">&quot;Internal error&quot;</span> &lt;&lt; endl;

  <span class="typ">int </span>nbKfi = <span class="num">0</span>;
  <span class="key">if </span>(play_.dessus())
    {
      <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">16</span>; ++i)
	<span class="key">if </span>((piece_[i].square == play_.arrivee()) &amp;&amp; (piece_[i].isBlack != piece_[hpops].isBlack) &amp;&amp; (piece_[hpops].isBlack != piece_[hpope].isBlack))
	  {
	    <span class="com">// piece_[i].isBlack = piece_[hpops].isBlack;
</span>	    nbKfi++;
	    kfi_[nbKfi].deletePath();
	    kfi_[nbKfi].setFrame(&amp;piece_[i].frame);
	    kfi_[nbKfi].addKeyFrame(piece_[i].frame, <span class="num">0.0</span>);
	    Frame midFrame(piece_[i].frame.position()+Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">4</span>*pieceHeight*(piece_[i].level+<span class="num">2</span>)),
			   Quaternion(Vec(<span class="num">1.0</span>, <span class="num">0.0</span>, <span class="num">0.0</span>), <span class="num">2.0</span>));
	    kfi_[nbKfi].addKeyFrame(midFrame, <span class="num">0.3</span>);
	    Frame endFrame(piece_[i].frame.position()+Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, pieceHeight),
			   Quaternion(Vec(<span class="num">1.0</span>, <span class="num">0.0</span>, <span class="num">0.0</span>), M_PI));
	    kfi_[nbKfi].addKeyFrame(endFrame, <span class="num">0.6</span>);
	    start = <span class="num">0.6</span>;
	  }
    }
  <span class="key">else
    </span>{
      <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">16</span>; ++i)
	<span class="key">if </span>(piece_[i].square == play_.arrivee())
	  {
	    nbKfi++;
	    kfi_[nbKfi].deletePath();
	    kfi_[nbKfi].setFrame(&amp;piece_[i].frame);
	    kfi_[nbKfi].addKeyFrame(piece_[i].frame, <span class="num">0.0</span>);
	    Frame midFrame, endFrame;
	    <span class="key">if </span>((agora.ArriveeRevolution(play_)) &amp;&amp; (piece_[i].isBlack != piece_[hpops].isBlack))
	      {
		midFrame = Frame(piece_[i].frame.position()+Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">3.0</span>*pieceHeight*(piece_[i].level+<span class="num">2</span>)),
				 Quaternion(Vec(<span class="num">1.0</span>, <span class="num">0.0</span>, <span class="num">0.0</span>), <span class="num">2.0</span>));
		endFrame = Frame(piece_[i].frame.position()+Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">2.0</span>*pieceHeight),
				 Quaternion(Vec(<span class="num">1.0</span>, <span class="num">0.0</span>, <span class="num">0.0</span>), M_PI));

		<span class="com">// piece_[i].isBlack = piece_[hpops].isBlack;
</span>	      }
	    <span class="key">else
	      </span>{
		midFrame.setPosition(piece_[i].frame.position()+Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">3.0</span>*pieceHeight*(piece_[i].level+<span class="num">2</span>)));
		endFrame.setPosition(piece_[i].frame.position()+Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, pieceHeight));
	      }
	    kfi_[nbKfi].addKeyFrame(midFrame, <span class="num">0.4</span>);
	    kfi_[nbKfi].addKeyFrame(endFrame, <span class="num">1.0</span>);
	    end = <span class="num">1.0</span>;
	  }
    }

  <span class="com">// Revolution on starting case
</span>  <span class="key">if </span>(agora.DepartRevolution(play_))
    <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">16</span>; ++i)
      <span class="key">if </span>((piece_[i].square == play_.depart()) &amp;&amp; (i!=hpops) &amp;&amp; (piece_[i].isBlack == piece_[hpops].isBlack))
	{
	  nbKfi++;
	  kfi_[nbKfi].deletePath();
	  kfi_[nbKfi].setFrame(&amp;piece_[i].frame);
	  kfi_[nbKfi].addKeyFrame(piece_[i].frame, <span class="num">0.0</span>);
	  kfi_[nbKfi].addKeyFrame(piece_[i].frame, <span class="num">0.6</span>);
	  Frame midFrame(piece_[i].frame.position()+Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, <span class="num">3.0</span>*pieceHeight*(piece_[i].level+<span class="num">2</span>)),
			 Quaternion(Vec(<span class="num">1.0</span>, <span class="num">0.0</span>, <span class="num">0.0</span>), <span class="num">2.0</span>));
	  Frame endFrame(piece_[i].frame.position()+Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, pieceHeight),
			 Quaternion(Vec(<span class="num">1.0</span>, <span class="num">0.0</span>, <span class="num">0.0</span>), M_PI));

	  <span class="com">// piece_[i].isBlack = !piece_[hpops].isBlack;
</span>	  kfi_[nbKfi].addKeyFrame(midFrame, <span class="num">0.9</span>);
	  kfi_[nbKfi].addKeyFrame(endFrame, <span class="num">1.5</span>);
	  end = <span class="num">1.5</span>;
	}

  <span class="com">// Selected piece
</span>  kfi_[<span class="num">0</span>].deletePath();
  kfi_[<span class="num">0</span>].setFrame(&amp;piece_[hpops].frame);
  Frame arrival;
  <span class="key">if </span>((hpope &gt;= <span class="num">0</span>) &amp;&amp; (play_.dessus()))
    arrival.setPosition(piece_[hpope].frame.position() + Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, pieceHeight));
  <span class="key">else
    </span>arrival.setPosition(casePosition[play_.arrivee()]);

  Vec mid(<span class="num">0.5 </span>* (piece_[hpops].frame.position() + arrival.position()));
  mid.z = max(piece_[hpops].frame.position().z, arrival.position().z) + <span class="num">2.0 </span>* pieceHeight;
  <span class="typ">const </span>Frame intermediate(mid, Quaternion());

  kfi_[<span class="num">0</span>].addKeyFrame(piece_[higherPieceOnPosition(play_.depart())].frame, <span class="num">0.0</span>);
  kfi_[<span class="num">0</span>].addKeyFrame(piece_[higherPieceOnPosition(play_.depart())].frame, start);
  kfi_[<span class="num">0</span>].addKeyFrame(intermediate, start+<span class="num">0.3</span>);
  kfi_[<span class="num">0</span>].addKeyFrame(arrival, start+<span class="num">0.8</span>);
  kfi_[<span class="num">0</span>].addKeyFrame(arrival, start+end);

  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">1</span>; i&lt;=nbKfi; ++i)
    kfi_[i].startInterpolation();
  kfi_[<span class="num">0</span>].startInterpolation();
}

<span class="typ">int </span>AgoraViewer::higherPieceOnPosition(Position pos) <span class="typ">const
</span>{
  <span class="typ">float </span>levelMax = <span class="num">-1.0</span>;
  <span class="typ">int </span>res = <span class="num">-1</span>;

  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">16</span>; ++i)
    <span class="key">if </span>((piece_[i].square == pos) &amp;&amp; (piece_[i].level &gt; levelMax))
      {
	res = i;
	levelMax = piece_[i].level;
      }
  <span class="key">return </span>res;
}



<span class="com">// G a m e   I n t e r f a c e  //
</span>
<span class="typ">void </span>AgoraViewer::play()
{
  <span class="key">if </span>(animatePlays_)
    animatePlay();
  <span class="key">else
    </span>simplePlay();
}

<span class="typ">void </span>AgoraViewer::deselect()
{
  selectedPiece_ = <span class="num">-1</span>;
  possibleDest_.clear();
}

<span class="typ">void </span>AgoraViewer::simplePlay()
{
  deselect();
  updateUndoHistory(<span class="key">true</span>);
  agora.jouer(play_);
  updateUndoHistory(<span class="key">false</span>);
  updatePiecePositions();
  blackPlay_ = !blackPlay_;
  updateGL();

  gameIsOver_ = agora.gameIsOver();
  <span class="key">if </span>(gameIsOver_)
  {
      <span class="key">if </span>(agora.gameIsOver(BLACK))
          QMessageBox::information(<span class="key">this</span>, <span class="str">&quot;Whites won !&quot;</span>, <span class="str">&quot;The whites won !&quot;</span>);
      <span class="key">else
          </span>QMessageBox::information(<span class="key">this</span>, <span class="str">&quot;Blacks won !&quot;</span>, <span class="str">&quot;The blacks won !&quot;</span>);
  } <span class="key">else if </span>((playerIsComputer_) &amp;&amp; (computerIsBlack_==blackPlay_))
  {
      play_ = agora.Suggest(play_, blackPlay_, gameLevel_.computerMaxReflexionTime_, gameLevel_.computerMaxDepth_);
      play();
  }
}

<span class="typ">void </span>AgoraViewer::reactToSelection(<span class="typ">int </span>selected, <span class="typ">bool </span>onTop)
{
  <span class="key">if </span>(selectedPiece_ &gt;= <span class="num">0</span>)
    {
      <span class="key">if </span>(selected &gt;= <span class="num">0</span>)
	{
	  <span class="typ">bool </span>playOnTopIsValid = <span class="key">false</span>;
	  <span class="typ">bool </span>playPrisonnerIsValid = <span class="key">false</span>;
	  Play playOnTop, playPrisonner;
	  <span class="key">for </span>(Possibles::const_iterator it=possibleDest_.begin(), end=possibleDest_.end(); it != end; ++it)
	    <span class="key">if </span>(((*it).depart() == piece_[selectedPiece_].square) &amp;&amp; ((<span class="typ">int</span>)((*it).arrivee()) == selected))
	      <span class="key">if </span>((*it).dessus())
		{
		  playOnTopIsValid = <span class="key">true</span>;
		  playOnTop = (*it);
		}
	      <span class="key">else
		</span>{
		  playPrisonnerIsValid = <span class="key">true</span>;
		  playPrisonner = (*it);
		}

	  <span class="key">if </span>(playOnTopIsValid)
	    <span class="key">if </span>(playPrisonnerIsValid)
	      play_ = (onTop) ? playOnTop : playPrisonner;
	    <span class="key">else
	      </span>play_ = playOnTop;
	  <span class="key">else
	    if </span>(playPrisonnerIsValid)
	      play_ = playPrisonner;
	    <span class="key">else
	      </span>cerr &lt;&lt; <span class="str">&quot;Internal error : invalid play in reactToSelection.&quot;</span> &lt;&lt; endl;

	  play();
	}
      <span class="key">else
	</span>deselect();
    }
  <span class="key">else
    </span><span class="com">// New piece selection. Color must correspond to current player
</span>    <span class="key">if </span>((selected &gt;= <span class="num">0</span>) &amp;&amp; (piece_[selected].isBlack == blackPlay_))
      {
	<span class="com">// Search for the piece at highest level on this heap
</span>	selectedPiece_ = higherPieceOnPosition(piece_[selected].square);
        agora.CoupsVoisins( possibleDest_, piece_[selectedPiece_].square );
      }
}

<span class="typ">void </span>AgoraViewer::select(<span class="typ">const </span>QMouseEvent* e)
{
  <span class="key">if </span>(gameIsOver_)
    <span class="key">return</span>;

  <span class="com">// Make openGL context current
</span>  makeCurrent();

  <span class="typ">const int </span>SENSITIVITY = <span class="num">4</span>;
  <span class="typ">const int </span>NB_HITS_MAX = <span class="num">50</span>;

  <span class="com">// Prepare the selection mode
</span>  <span class="typ">static </span>GLuint hits[NB_HITS_MAX];

  glSelectBuffer(NB_HITS_MAX, hits);
  glRenderMode(GL_SELECT);
  glInitNames();

  <span class="com">// Loads the matrices
</span>  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  GLint viewport[<span class="num">4</span>];
  glGetIntegerv(GL_VIEWPORT,viewport);
  gluPickMatrix(<span class="key">static_cast</span>&lt;GLdouble&gt;(e-&gt;x()), <span class="key">static_cast</span>&lt;GLdouble&gt;(viewport[<span class="num">3</span>] - e-&gt;y()), SENSITIVITY, SENSITIVITY, viewport);

  <span class="com">// loadProjectionMatrix() first resets the GL_PROJECTION matrix with a glLoadIdentity.
</span>  <span class="com">// Give false as a parameter in order to prevent this and to combine the matrices.
</span>  camera()-&gt;loadProjectionMatrix(<span class="key">false</span>);

  camera()-&gt;loadModelViewMatrix();

  <span class="com">// Render scene with objects ids
</span>  <span class="key">if </span>(selectedPiece_ &gt;= <span class="num">0</span>)
    drawPossibleDestinations(<span class="key">true</span>);
  <span class="key">else
    </span>drawAllPieces(<span class="key">true</span>);
  glFlush();

  <span class="com">// Get the results
</span>  GLint nb_hits = glRenderMode(GL_RENDER);

  <span class="com">// Interpret results
</span>  <span class="typ">unsigned int </span>zMin = UINT_MAX;
  <span class="typ">int </span>id = <span class="num">-1</span>;
  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;nb_hits; ++i)
    <span class="key">if </span>(hits[i*<span class="num">4</span>+<span class="num">1</span>] &lt; zMin)
      {
	zMin = hits[i*<span class="num">4</span>+<span class="num">1</span>];
	id = hits[i*<span class="num">4</span>+<span class="num">3</span>];
      }

  reactToSelection(id, e-&gt;state() == Qt::NoButton);
}

<span class="typ">void </span>AgoraViewer::updatePiecePositions()
{
  <span class="typ">int </span>nb = <span class="num">0</span>;
  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;<span class="num">36</span>; ++i)
    {
      Pile p = agora[i];
      <span class="typ">bool </span>topIsBlack = agora.couleur(p);
      <span class="key">for </span>(<span class="typ">int </span>j=<span class="num">0</span>; j&lt;agora.taille(p); ++j)
	{
	  <span class="key">if </span>(j == agora.uns(p))
	    topIsBlack = !topIsBlack;

	  piece_[nb].square = i;
	  piece_[nb].isBlack = topIsBlack;
	  piece_[nb].level = agora.taille(p)<span class="num">-1</span>-j;
	  piece_[nb].frame.setPosition(casePosition[i] + Vec(<span class="num">0.0</span>, <span class="num">0.0</span>, pieceHeight * piece_[nb].level));
	  piece_[nb].frame.setOrientation(Quaternion());
	  piece_[nb].scale = <span class="num">1.0 </span>- <span class="num">0.1</span>*(agora.taille(p)-j-1)/(<span class="typ">float</span>)agora.taille(p);
	  nb++;
	}
    }
  <span class="key">if </span>(nb &gt; <span class="num">16</span>)
    cerr &lt;&lt; <span class="str">&quot;More than 16 pieces in the Agora !!!&quot;</span> &lt;&lt; endl;
}




<span class="com">// F i l e  m e n u   f u n c t i o n s
</span><span class="typ">void </span>AgoraViewer::load()
{
  fileName = QFileDialog::getOpenFileName(<span class="str">&quot;&quot;</span>, <span class="str">&quot;Agora files (*.ago);;All files (*)&quot;</span>, <span class="key">this</span>);

  <span class="com">// In case of Cancel
</span>  <span class="key">if </span>(fileName.isEmpty())
    <span class="key">return</span>;

  std::ifstream f(fileName.latin1());
  f &gt;&gt; agora;
  f &gt;&gt; undoIndex_ &gt;&gt; maxUndoIndex_;
  history_.clear();
  <span class="key">for </span>(<span class="typ">unsigned int </span>i=<span class="num">0</span>; i&lt;maxUndoIndex_; ++i)
    {
      Undo u;
      f &gt;&gt; u.pos1 &gt;&gt; u.pos2 &gt;&gt; u.before1 &gt;&gt; u.before2 &gt;&gt; u.after1 &gt;&gt; u.after2;
      history_.push_back(u);
    }
  f.close();

  blackPlay_ = undoIndex_%<span class="num">2 </span>== <span class="num">1</span>;

  updatePiecePositions();
  deselect();
}

<span class="typ">void </span>AgoraViewer::save()
{
  std::ofstream f(fileName.latin1());
  f &lt;&lt; agora;
  <span class="com">// save undo history
</span>  f &lt;&lt; undoIndex_ &lt;&lt; <span class="str">&quot; &quot;</span> &lt;&lt; maxUndoIndex_ &lt;&lt; endl;
  <span class="key">for </span>(std::vector&lt;Undo&gt;::iterator it=history_.begin(), end=history_.end(); it != end; ++it)
    f &lt;&lt; (*it).pos1 &lt;&lt; <span class="str">&quot; &quot;</span> &lt;&lt; (*it).pos2 &lt;&lt; <span class="str">&quot; &quot;</span>
      &lt;&lt; (*it).before1 &lt;&lt; <span class="str">&quot; &quot;</span> &lt;&lt; (*it).before2 &lt;&lt; <span class="str">&quot; &quot;</span>
      &lt;&lt; (*it).after1 &lt;&lt; <span class="str">&quot; &quot;</span> &lt;&lt; (*it).after2 &lt;&lt; endl;
  f.close();
}

<span class="typ">void </span>AgoraViewer::saveAs()
{
  fileName = QFileDialog::getSaveFileName(<span class="str">&quot;&quot;</span>, <span class="str">&quot;Agora files (*.ago);;All files (*)&quot;</span>, <span class="key">this</span>, fileName.latin1());

  QFileInfo fi(fileName);

  <span class="key">if </span>(fi.extension().isEmpty())
    {
      fileName += <span class="str">&quot;.ago&quot;</span>;
      fi.setFile(fileName);
    }

  <span class="key">if </span>(fi.exists())
    <span class="key">if </span>(QMessageBox::warning(<span class="key">this </span>,<span class="str">&quot;Existing file&quot;</span>,
			     <span class="str">&quot;File &quot;</span>+fi.fileName()+<span class="str">&quot; already exists.</span><span class="esc">\n</span><span class="str">Save anyway ?&quot;</span>,
			     QMessageBox::Yes,
			     QMessageBox::Cancel) == QMessageBox::Cancel)
      <span class="key">return</span>;

  <span class="key">if </span>(!fi.isWritable())  <span class="com">// CHECK THIS
</span>    {
      QMessageBox::warning(<span class="key">this </span>,<span class="str">&quot;Cannot save&quot;</span>, <span class="str">&quot;File &quot;</span>+fi.fileName()+<span class="str">&quot; is not writeable.&quot;</span>);
      <span class="key">return</span>;
    }

  save();
}


<span class="com">// U n d o   a n d   R e do
</span>AgoraViewer::Undo::Undo(<span class="typ">const </span>Play&amp; play, <span class="typ">const </span>Agora_t&amp; agora)
{
  pos1    = play.depart();
  pos2    = play.arrivee();
  before1 = agora[pos1];
  before2 = agora[pos2];
}

<span class="typ">void </span>AgoraViewer::updateUndoHistory(<span class="typ">bool </span>before)
{
  <span class="key">if </span>(before)
    {
      <span class="key">if </span>(undoIndex_ &lt; history_.size())
	history_[undoIndex_] = Undo(play_, agora);
      <span class="key">else
	</span>history_.push_back(Undo(play_, agora));
    }
  <span class="key">else
    </span>{
      history_[undoIndex_].after1 = agora[play_.depart()];
      history_[undoIndex_].after2 = agora[play_.arrivee()];
      undoIndex_++;
      maxUndoIndex_ = undoIndex_;
    }
}

<span class="typ">void </span>AgoraViewer::undo()
{
  <span class="key">if </span>(undoIndex_ &gt; <span class="num">0</span>)
    undoIndex_--;
  <span class="key">else
    return</span>;

  agora.remettre(history_[undoIndex_].pos1, history_[undoIndex_].before1,
		 history_[undoIndex_].pos2, history_[undoIndex_].before2);
  updatePiecePositions();
  blackPlay_ = !blackPlay_;
  updateGL();
}

<span class="typ">void </span>AgoraViewer::redo()
{
  <span class="key">if </span>(undoIndex_ &gt;= maxUndoIndex_)
    {
      QMessageBox::warning(<span class="key">this</span>, <span class="str">&quot;No more redo&quot;</span>, <span class="str">&quot;No more redo is possible&quot;</span>);
      <span class="key">return</span>;
    }

  agora.remettre(history_[undoIndex_].pos1, history_[undoIndex_].after1,
		 history_[undoIndex_].pos2, history_[undoIndex_].after2);
  undoIndex_++;
  updatePiecePositions();
  blackPlay_ = !blackPlay_;
  updateGL();
}

<span class="typ">void </span>AgoraViewer::help()
{
  QMessageBox::information(<span class="key">this</span>, <span class="str">&quot; A g o r a&quot;</span>, <span class="str">&quot;Rules of Agora</span><span class="esc">\n</span><span class="str">Not yet available, please browse the web.&quot;</span>);
}

<span class="typ">void </span>AgoraViewer::about()
{
  QMessageBox::about(<span class="key">this</span>, <span class="str">&quot; A g o r a&quot;</span>, <span class="str">&quot;A g o r a</span><span class="esc">\n</span><span class="str">Created by Gilles Debunne and Jean-Guillaume Dumas</span><span class="esc">\n</span><span class="str">Version 1.0 - June 2003&quot;</span>);
}

<span class="typ">void </span>AgoraViewer::togglePlayAgainstComputer(<span class="typ">bool </span>on)
{
  playerIsComputer_ = on;

  <span class="com">// Disable menu items
</span>  AgoraWindow* window = <span class="key">dynamic_cast</span>&lt;AgoraWindow*&gt;(parent()-&gt;parent());
  <span class="key">if </span>(!window)
    {
      qWarning(<span class="str">&quot;Unable to disable menu items&quot;</span>);
      <span class="key">return</span>;
    }
  window-&gt;levelActionGroup-&gt;setEnabled(on);
  window-&gt;computerBlackAction-&gt;setEnabled(on);
}</pre>


<h2>main.cpp</h2>
<pre>

<span class="dir">#include &lt;qapplication.h&gt;
</span><span class="dir">#include </span><span class="dstr">&quot;agoraWindow.h&quot;</span><span class="dir">
</span>
<span class="typ">int </span>main(<span class="typ">int </span>argc, <span class="typ">char </span>* argv[])
{
  <span class="com">// Read command lines arguments.
</span>  QApplication application(argc,argv);

  AgoraWindow aw;
  aw.show();
  application.setMainWidget(&amp;aw);

  <span class="com">// Run main loop.
</span>  <span class="key">return </span>application.exec();
}
</pre>



<p>
  <a href="index.html">Go back</a> to the examples main page
</p>

<p>
  <a href="http://validator.w3.org/check/referer"><img src="../images/xhtml.png" alt="Valid XHTML 1.0!" height="31" width="88" border="0"/></a>
  <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="../images/css.png" width="88" height="31" alt="Valid CSS!" border="0"/></a>
<i>Last modified on Thursday, February 5, 2004.</i>
</p>

</body>
</html>