Moved the french html docs from trunk to the new french section of the wiki.

git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@976 416bcca6-2ee7-4201-b75f-2eb2f807beb1
This commit is contained in:
Adrien Destugues 2009-08-05 19:33:51 +00:00
parent 4bf44d6d9e
commit c199ad22eb
2 changed files with 0 additions and 560 deletions

View File

@ -1,384 +0,0 @@
<html>
<head>
<BASE HREF="http://www-msi.ensil.unilim.fr/~maritaud/sunset/GrafX2-fra-OpEngine.html">
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<title>GrafX2 - Le moteur des opérations</title>
</head>
<body bgcolor="#FFFFFF">
<h1 align="center">GrafX2 - Le moteur des opérations</h1>
<hr>
<h2>Explication du principe&nbsp;:</h2>
<p>Qu'appelle-t'on une opération? C'est l'emploi d'un outil de
dessin. Par exemple, le tracé libre à la main d'un pinceau (ou
d'une brosse) est une opération. Plus exactement, c'est tout
comportement de la souris lorsqu'elle se trouve sur les pixels de
l'image éditée. De ce fait, la gestion de la pipette se fait
également au travers des opérations.</p>
<p>Le moteur chargé de gérer ces opérations est simplifié
autant que possible. Son principe est le suivant&nbsp;: lorsque
la souris est au-dessus de l'image, la boucle principale de
gestion de GrafX2 (située dans MOTEUR.C) détermine la partie
atomique d'instructions à exécuter, puis l'exécute, pour
chaque combinaison d'un type d'opération (un entier, que l'on
nommera pour les besoins de cette page ID_OP), d'un état de la
souris (état de ses boutons plus exactement, codé sur un entier
également), et d'un nombre de valeurs présentes dans une pile
(pas la pile système, mais une pile de mots 16-bits
spécialement mise en place pour les opérations, afin qu'elles y
stockent des paramètres pour les opérations suivantes). On
appelle &quot;partie atomique&quot; une séquence d'instructions
qui doivent être exécutées intégralement à chaque itération
de la boucle principale. Elle se contente de ne faire que ce
qu'elle doit faire face à la situation qu'implique la
combinaison (ID_OP,Code souris, Etat pile) pour laquelle elle est
appelée.</p>
<p>En fait, le moteur doit être aidé pour déterminer les
insctructions à exécuter. Chacune de ces parties atomiques est
écrite sous la forme d'une fonction contenant tout le code qui
lui est nécessaire. Ces fonctions sont ce que l'on a appelé des
&quot;Func_action&quot; (définition dans STRUCT.H), c'est à
dire une simple fonction qui ne reçoit pas de paramètres et qui
n'en renvoie pas. Un simple void Ma_fonction(void)...</p>
<p>Il n'est pas dans mon intention de vous apprendre à écrire
ces fonctions atomiques. Dans le cas des opérations les plus
simples à implémenter selon ce principe, la conception des
parties atomiques est assez intuitive, mais il arrive dans
certains cas que la méthode trouve certaines limites, il faut
alors tricher un peu (mais gentiment! - en plaçant des valeurs
arbitraires dans la pile uniquement pour permettre la transition
vers une autre combinaison choisie, donc une autre partie
atomique, par exemple). Vous pourrez trouver tous les exemples
que vous voudrez dans le fichier OPERATIO.C.</p>
<p>Après avoir écrit les parties atomiques qui vont être
nécessaires pour la gestion complète d'une opération (dans le
fichier OPERATIO.C), et avoir renseigné les prototypes de ces
fonctions (dans OPERATIO.H), il faut indiquer au moteur dans
quelles conditions utiliser ces fonctions. Cela se fait dans la
phase d'initialisation du programme (située dans le fichier
INIT.C), où l'on renseigne chacune des fonctions atomiques, en
décrivant les valeurs de combinaison qui doivent déclencher
leur appel. La fonction appelée se contente d'en prendre note en
remplissant un tableau nommé &quot;Operation&quot; (variable
globale déclarée dans GLOBAL.H, et indexée par les 3 valeurs
de la combinaison : ID_OP, code souris, état pile) à l'aide de
l'adresse de la fonction à appeler. Ce tableau va servir au
moteur à faire un appel direct de la fonction atomique d'après
la combinaison, sans avoir à faire toute une série de tests
(swich/case) fastidieux.</p>
<p>Comme nous avons pressenti qu'il arriverait fréquemment que
des fonctions atomiques auraient besoin systématiquement
d'effacer la souris pour faire des affichages à l'écran ou dans
l'image, et de la rafficher ensuite, et dans le souci d'éviter
de faire abusivement du copier/coller de code, nous avons
rajouté un booléen dans le tableau Operation qui permet
d'indiquer que la fonction atomique demande au moteur de se
charger lui-même de l'effacement et de la restauration du
curseur de la souris à l'écran. Finalement, je ne suis pas
certain que cela s'est révelé d'une grande utilité, mais je
vous le signale tout de même pour que vous compreniez
l'existance du paramètre &quot;Effacer souris&quot; qu'il faut
indiquer lorsqu'on renseigne une fonction atomique lors de
l'initialisation.</p>
<p>Il est important de noter qu'une fonction atomique est
appelée en permanence par la boucle principale, indépendamment
du fait que la souris change d'état ou non. Ces appels
répétés permettent par exemple d'avoir un spray qui continue
à agir lorsqu'on presse le bouton de la souris sans la
déplacer.</p>
<p>De plus, les fonctions atomiques n'ont pas à se soucier du
positionnement de la souris car dès que la pile contient des
données (généralement dès le premier clic), la souris est
limitée par le moteur afin de ne pas sortir de l'image. Le
moteur s'assure également que la souris ne franchis pas la barre
de split en mode &quot;loupe&quot;. Enfin, n'oubliez pas de vider
complètement la pile en temps voulu, lorsque l'opération peut
s'achever! ;-)</p>
<hr>
<h2>Informations pour l'implémentation&nbsp;:</h2>
<ul>
<li>Le renseignement d'une fonction atomique se fait dans
INIT.C à l'aide de&nbsp;:</li>
</ul>
<blockquote>
<p>Initialisation_operation(ID_OP, Etat souris, Taille pile,
Callback, Effacer souris);</p>
</blockquote>
<ul>
<li>La pile à disposition des opérations pour le stockage
des paramètres&nbsp;:<ul>
<li>Elle contient des mots 16-bits (type word,
définit dans STRUCT.H)</li>
<li>Pour y poser une valeur&nbsp;:
Operation_push(val)</li>
<li>Pour en retirer une valeur&nbsp;:
Operation_pop(&amp;var)</li>
<li>Exemples de valeurs à y mettre&nbsp;:
coordonnées de souris, de pinceau... des
couleurs... des valeurs bidons pour changer
l'état de la pile...<br>
</li>
</ul>
</li>
<li>A l'intérieur d'une fonction atomique&nbsp;:<ul>
<li>Si la fonction correspond à la première étape
d'une opération, appeler
Init_start_operation()</li>
<li>Si la fonction correspond à la première étape
d'une opération qui peut modifier l'image,
appeler Backup() avant modification de l'image ;
ce qui permettra à l'utilisateur d'annuler la
modification avec &quot;undo&quot; s'il le
souhaite.</li>
<li>Pour afficher les coordonnées de la souris,
appeler Print_coordinates() sans vous soucier de
savoir si la barre d'outils est visible. Si vous
avez besoin d'afficher une coordonnée qui doit
s'adapter au mode relatif ou absolu (selon le
paramétrage effectué par l'utilisateur),
utilisez Display_coords_rel_or_abs(RefX,RefY). Si les
coordonnées sont configurées pour être
relatives, cette fonction affichera la
différence entre les coordonnées actuelles du
pinceau et les coordonnées de référence
passées en paramètres. Dans le cas d'infos
spéciales à afficher dans la barre de menu, on
pourra se servir de la fonction
Print_in_menu(texte,position en caractères).</li>
<li>Si vous avez besoin de vous assurer que les
boutons de la souris sont relâchés à un moment
de la fonction, utilisez Wait_end_of_click()</li>
<li>Etudiez OPERATIO.C pour avoir des exemples.<br>
</li>
</ul>
</li>
<li>Pour démarrer une opération (après avoir cliqué sur
un bouton de la barre d'outils par exemple), appeler
Start_operation_stack(ID_OP). Note: il faut que le
curseur soit caché avant l'appel (et son état n'est pas
changé après). (voir exemples dans BOUTONS.C)<br>
</li>
<li>On peut connaître l'ID_OP de l'opération en cours
grâce à la variable globale Current_operation<br>
</li>
<li>La variable globale Operation_stack_size correspond à
la taille de la pile d'opérations. Elle peut être
consultée et éventuellement modifiée (même s'il est
préférable d'utiliser Operation_push et Operation_pop
dans ce dernier cas).</li>
</ul>
<hr>
<p>Comment rajouter une opération?</p>
<div align="center"><center>
<table border="1" width="100%">
<tr>
<td width="100%">Dans CONST.H&nbsp;:<ul>
<li>rajouter un identifiant (ID_OP) dans l'enum
OPERATIONS (exemple&nbsp;: OPERATION_DUMMY)</li>
</ul>
</td>
</tr>
<tr>
<td width="100%">Dans GLOBAL.H&nbsp;:<ul>
<li>rajouter l'identifiant de la forme de curseur à
utiliser pour cette opération dans la table
CURSOR_FOR_OPERATION[]. Faites bien attention à
l'insérer au bon endroit (place correspondant à
ID_OP).</li>
</ul>
</td>
</tr>
<tr>
<td width="100%">Dans OPERATIO.C&nbsp;:<ul>
<li>Ecrire chaque fonction atomique de l'opération.</li>
</ul>
<blockquote>
<p>Exemple&nbsp;:</p>
</blockquote>
<blockquote>
<blockquote>
<p>void Dummy_1_0(void)<br>
// Opération : OPERATION_DUMMY<br>
// Click Souris: 1<br>
// Taille_Pile : 0<br>
// Souris effacée: Oui (précisé grâce à
Init_operation() dans INIT.C)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Init_start_operation();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Backup();<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ACTIONS...<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Operation_push(une_valeur_nécessaire_pour_les_prochaines_étapes);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Operation_push(une_autre_valeur_nécessaire_plus_tard);<br>
}</p>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<p>(Pour cet exemple, l'étape suivante à
définir sera donc une étape avec la taille de
pile à 2)</p>
</blockquote>
</blockquote>
<ul>
<li>Il y a une action par défaut qui se contente
d'afficher les coordonnées de la souris
lorsqu'on ne définit pas explicitement de
fonction atomique gérant une certaine
combinaison (ID_OP, Etat souris, Taille pile).</li>
<li>Si l'opération représente une interruption
temporaire, et qu'il vous paraît juste de
restaurer l'opération précédente une fois
qu'elle est terminée (cas de la loupe, de la
pipette, des prises de brosse, ...), rajouter
l'ID_OP dans la section correspondante de la
fonction Start_operation_stack(), en début de
fichier.</li>
<li>Si l'opération voit un intérêt à accepter que
l'utilisateur change de couleur de pinceau en
cours d'opération (cas du dessin continu,
discontinu, le spray, et les lignes centrées),
rajouter l'ID_OP dans la section correspondante
de la fonction Start_operation_stack(), en
début de fichier.</li>
</ul>
</td>
</tr>
<tr>
<td width="100%">Dans OPERATIO.H&nbsp;:<ul>
<li>Ecrire le prototype des ces fonctions atomiques.</li>
</ul>
</td>
</tr>
<tr>
<td width="100%">Dans INIT.C&nbsp;:<ul>
<li>Dans Init_operations(), pour chaque
fonction atomique de l'opération, écrire un
appel à Init_operation(ID_OP, Etat
souris, Taille pile, Callback, Effacer souris);<ul>
<li>ID_OP&nbsp;: identifiant de l'opération
dont dépend la fonction atomique
(défini dans CONST.H)</li>
<li>Etat souris&nbsp;:<ul>
<li>0 = boutons relachés</li>
<li>1 = bouton gauche enfoncé</li>
<li>2 = bouton droit enfoncé</li>
<li>(note : l'état &quot;boutons
gauche et droit enfoncés&quot;
n'existe pas, seuls les 3 états
ci-dessus sont autorisés)</li>
</ul>
</li>
<li>Taille pile&nbsp;: nombre de paramètres
dans la pile</li>
<li>Callback&nbsp;: nom de la fonction
atomique à appeler pour la combinaison
des 3 paramètres précédents</li>
<li>Effacer souris&nbsp;: booléen indiquant
que le moteur se chargera d'effacer le
curseur souris avant l'appel à la
fonction atomique, et de le rafficher
après sa sortie.</li>
</ul>
</li>
</ul>
<blockquote>
<p>Exemple&nbsp;:</p>
</blockquote>
<blockquote>
<blockquote>
<p>Init_operation(OPERATION_DUMMY, 1, 0,
Dummy_1_0, 1);</p>
</blockquote>
</blockquote>
</td>
</tr>
</table>
</center></div>
</body>
<SCRIPT language="Javascript">
<!--
// FILE ARCHIVED ON 20021206090126 AND RETRIEVED FROM THE
// INTERNET ARCHIVE ON 20070414155905.
// JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
// ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
// SECTION 108(a)(3)).
var sWayBackCGI = "http://web.archive.org/web/20021206090126/";
function xResolveUrl(url) {
var image = new Image();
image.src = url;
return image.src;
}
function xLateUrl(aCollection, sProp) {
var i = 0;
for(i = 0; i < aCollection.length; i++) {
if (typeof(aCollection[i][sProp]) == "string") {
if (aCollection[i][sProp].indexOf("mailto:") == -1 &&
aCollection[i][sProp].indexOf("javascript:") == -1) {
if(aCollection[i][sProp].indexOf("http") == 0) {
aCollection[i][sProp] = sWayBackCGI + aCollection[i][sProp];
} else {
aCollection[i][sProp] = sWayBackCGI + xResolveUrl(aCollection[i][sProp]);
}
}
}
}
}
xLateUrl(document.getElementsByTagName("IMG"),"src");
xLateUrl(document.getElementsByTagName("A"),"href");
xLateUrl(document.getElementsByTagName("AREA"),"href");
xLateUrl(document.getElementsByTagName("OBJECT"),"codebase");
xLateUrl(document.getElementsByTagName("OBJECT"),"data");
xLateUrl(document.getElementsByTagName("APPLET"),"codebase");
xLateUrl(document.getElementsByTagName("APPLET"),"archive");
xLateUrl(document.getElementsByTagName("EMBED"),"src");
xLateUrl(document.getElementsByTagName("BODY"),"background");
var forms = document.getElementsByTagName("FORM");
if (forms) {
var j = 0;
for (j = 0; j < forms.length; j++) {
f = forms[j];
if (typeof(f.action) == "string") {
if(typeof(f.method) == "string") {
if(typeof(f.method) != "post") {
f.action = sWayBackCGI + f.action;
}
}
}
}
}
//-->
</SCRIPT>
</html>

View File

@ -1,176 +0,0 @@
<html>
<head>
<BASE HREF="http://www-msi.ensil.unilim.fr/~maritaud/sunset/GrafX2-fra-Input.html">
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<title>GrafX2 - Les entrées</title>
</head>
<body bgcolor="#FFFFFF">
<h1 align="center">GrafX2 - Les entrées</h1>
<hr>
<p>Get_input() (dans DIVERS.ASM):</p>
<ul>
<li>Touches :<ul>
<li>Met à jour la variable &quot;Touche&quot;, un
mot 16-bits qui contient dans sa partie basse la
valeur du scan-code (valeur plutôt liée à la
géographie de la touche) de la touche enfoncée
à traiter, et dans sa partie haute un codage des
touches de contrôles enfoncées au moment de
l'appel.<ul>
<li>(Touche &amp; 0x0100) =&gt; Shift</li>
<li>(Touche &amp; 0x0200) =&gt; Control</li>
<li>(Touche &amp; 0x0400) =&gt; Alt</li>
</ul>
</li>
<li>Met dans la variable &quot;Touche_ASCII&quot; la
valeur ASCII (valeur liée au caractère que
représente la touche) de la touche enfoncée à
traiter.</li>
<li>Dans le cas où la variable globale
&quot;Autoriser_changement_de_couleur_pendant_operation&quot;
serait à 0, et qu'il existerait au moins une
valeur dans la pile des opérations, la fonction
filtre les touches. Cela signifie que l'on ne
peut pas interrompre une opération en cours,
sauf pour changer la couleur du pinceau si
l'opération l'autorise (utile pour faire varier
la couleur du pinceau à l'aide des touches
pendant qu'on dessine).</li>
</ul>
</li>
<li>Souris :<ul>
<li>Met à jour la position (Mouse_X,Mouse_Y) de la
souris en fonction de sa position dans un écran
virtuel. Cet écran est volontairement plus grand
que la résolution réelle du mode vidéo car de
nombreux drivers ne fournissent pas la position
de la souris au pixel près...</li>
<li>Met à jour l'état des boutons de la souris
(Mouse_K). La variable vaut 0 si aucun bouton
n'est enfoncé, 1 si seul le bouton gauche est
enfoncé, et 2 si seul le bouton droit est
enfoncé. Dans le cas où les 2 boutons seraient
enfoncé, Get_input() considère qu'aucun bouton
n'est enfoncé (Mouse_K = 0).</li>
<li>La fonction corrige la position de la souris afin
de l'empêcher de sortir de la surface d'image
sur laquelle elle se trouve si au moins une
valeur est dans la pile des opérations (la
souris ne sort pas de la zone de dessin tant que
l'opération de dessin n'est pas terminée), et
elle simule également le déplacement et les
clics de la souris si la combinaison de touches
courante correspond à de telles commandes. Dans
ce dernier cas, la touche est ensuite filtrée
afin d'éviter de faire travailler la fonction
appelante pour rien.</li>
<li>Dans le cas où la souris change d'état ou que
la variable globale
&quot;Forcer_affichage_curseur&quot; est placée
à 1, le curseur de la souris est réaffiché. La
fonction laisse toujours la variable
Forcer_affichage_curseur à 0 en fin d'appel.</li>
<li>La fonction fait appel à
Calculer_coordonnees_pinceau() qui se charge de
calculer convenablement les coordonnées du
pinceau (Pinceau_X,Pinceau_Y) en fonction de la
position de la souris à l'écran, de la position
de la zone de dessin dans l'image, du facteur de
zoom et de l'effet de la grille.</li>
</ul>
<p><strong>Important :</strong> Dans la plupart des cas,
vous n'avez pas à appeler cette fonction car le moteur
(boucle principale, gestionnaire de fenêtre, sélecteurs
de fichier, ...) s'en est déjà chargé. Vous pouvez
donc considérer que les variables concernées sont
déjà à jour. Si vous appeliez vous-même la fonction
Get_input() à un moment inoportun, certaines commandes
de l'utilisateur, prises en compte par le moteur, ne
seraient pas traitées.</p>
</li>
</ul>
<p>Attendre_fin_de_click() (dans DIVERS.ASM):</p>
<blockquote>
<p>S'il vous arrive d'avoir besoin de vous assurer que
l'utilisateur n'appuie plus sur les boutons de la souris à
un instant donné, cette fonction attend jusqu'à ce que
l'utilisateur relache le bouton. La valeur de Mouse_K vaut
alors 0, mais s'il a déplacé la souris avant de suspendre
sa pression, la position (Mouse_X,Mouse_Y) n'est pas encore
à jour. Cependant, cela ne devrait pas être génant (au
pire, un appel à Get_input() mettra ces valeurs à jour).</p>
</blockquote>
</body>
<SCRIPT language="Javascript">
<!--
// FILE ARCHIVED ON 20021011041425 AND RETRIEVED FROM THE
// INTERNET ARCHIVE ON 20070414155906.
// JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
// ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
// SECTION 108(a)(3)).
var sWayBackCGI = "http://web.archive.org/web/20021011041425/";
function xResolveUrl(url) {
var image = new Image();
image.src = url;
return image.src;
}
function xLateUrl(aCollection, sProp) {
var i = 0;
for(i = 0; i < aCollection.length; i++) {
if (typeof(aCollection[i][sProp]) == "string") {
if (aCollection[i][sProp].indexOf("mailto:") == -1 &&
aCollection[i][sProp].indexOf("javascript:") == -1) {
if(aCollection[i][sProp].indexOf("http") == 0) {
aCollection[i][sProp] = sWayBackCGI + aCollection[i][sProp];
} else {
aCollection[i][sProp] = sWayBackCGI + xResolveUrl(aCollection[i][sProp]);
}
}
}
}
}
xLateUrl(document.getElementsByTagName("IMG"),"src");
xLateUrl(document.getElementsByTagName("A"),"href");
xLateUrl(document.getElementsByTagName("AREA"),"href");
xLateUrl(document.getElementsByTagName("OBJECT"),"codebase");
xLateUrl(document.getElementsByTagName("OBJECT"),"data");
xLateUrl(document.getElementsByTagName("APPLET"),"codebase");
xLateUrl(document.getElementsByTagName("APPLET"),"archive");
xLateUrl(document.getElementsByTagName("EMBED"),"src");
xLateUrl(document.getElementsByTagName("BODY"),"background");
var forms = document.getElementsByTagName("FORM");
if (forms) {
var j = 0;
for (j = 0; j < forms.length; j++) {
f = forms[j];
if (typeof(f.action) == "string") {
if(typeof(f.method) == "string") {
if(typeof(f.method) != "post") {
f.action = sWayBackCGI + f.action;
}
}
}
}
}
//-->
</SCRIPT>
</html>