Sponsors

FacebookTwitterGoogle Bookmarks

"Petite démo" ? Comment ça, "petite démo"? Le programme que j’ai tapé de mes pattes poilues va révolutionner le monde de l’Amiga... C’est tout simplement du concentré de génie. Non mais ! LE RETOUR ! Tiens, comme je suis bonne patte, je vais essayer de vous en expliquer le fonctionnement... Vous connaissez les déformations sinusoïdales ? En voici une toute simple à réaliser, sur plus de 200 lignes d’écran et au 1 50 ième de secondes, s’il vous plaît ! Elle est de plus totalement paramétrable. J’explique. Il n’est même pas envisageable de calculer une déformation sinusoïdale en temps réel, au 1 50 ième sur 200 lignes : c’est déjà très difficile en langage machine, donc impossible en AMOS. Il faut donc ruser et calculer tout à l’avance : les images étant déjà dessinées, il suffira de les faire défiler à l’écran l’une après l’autre. Bon. La première idée qui vient à l’esprit est d’ouvrir plusieurs écrans et de les faire défiler avec l’instruction SCREEN TO FRONT. C’est pas mal, mais nous somme limités à 8 images au maximum, trop peu pour une bonne animation. Même en passant les écrans en double buffer, on reste encore limités à 16 images, encore trop peu, surtout si l’on veut faire défiler un texte par dessus. Mon idée de génie, je dois le dire, a été de réserver une banque de mémoire CHIP, contenant la place nécessaire à toutes les images pré-calculées. Par exemple, pour 20 pas d’animation d’une image de 320x200 en 2 couleurs, la taille de cette banque est de 160 Kilos. Comment afficher le contenu de cette banque dans un écran ? Mon deuxième coup de génie, je dois l’avouer modestement, est d’utiliser l’instruction SCREEN OFFSET. Car avez-vous remarqué que cette instruction permet d’explorer toute la mémoire graphique de l’Amiga, simplement en utilisant de grandes valeurs en Y ? En calculant la distance entre la grosse banque de mémoire et l’écran numéro 0, on peut connaître les valeurs à utiliser dans l’instruction et afficher tout simplement le contenu de la banque au lieu de l’image normale.

Click image to download PDF

AMIGA NEWS TECH numero 28 (12-1991)

Document sans nom JOYEUX NOËL!
Ce numéro 28 de l’Amiga NewsTech a été tiré à 3500 exemplaires. Amiga NewsTech (ANT) est une publication Commodore Revue SARL 5, rue de la Fidélité, 75010 PARIS, France
45 F.
EDITO
Déjà Noël ! Dans quelques semaines, les cadeaux, les bisous, les vacances aux Deux Alpes, etc. Et après ça, le nouvelle an, re-cadeaux, re-bisous...
Ah ! Quelle période merveilleuse !
Ce numéro de décembre de VANT marquera la fin d’une année riche en événements. D’abord, l’émancipation du magazine, bien sûr, mais aussi le changement de formule puis de Rédacteur en Chef d’Amiga Revue, la naissance du fils d’icelui, le licenciement d’Alain Prost par Ferrari...
Quant au prochain numéro de janvier, il marquera le début d’une nouvelle année pleine de surprises. Avec notamment pas mal de nouvelles rubriques (Pascal, algorythmie...) et l’arrivée dans nos rangs d’une célébré signature : mister Thomas Landspurg himself.
Ce n’est évidemment pas tout, mais je n’en dirai pas plus maintenant pour ne pas gâcher l’effet dramatique...
Stéphane Schreiber
PS : Le (superbe) dessin de couverture est signé Olivia de Berardinis et a été extrait du CD-Rom Exocita Rom édité (pour Mac) par Gazelle Technologies, Inc.
L’enfoiré qui a un jour décidé qu’on n'aurait que 32 pages s’appelle Jean-Yves Primas. C’est le Directeur de Publication et rien qu’à te voir, on comprend qu’il ne programme pas, lui. Fais gaffe à toi, on s’vengera.
Celui qui fait tout ici, c’est Bibi, alias Moi, alias Myself, alias enfin Stéphane Schreiber. Et quand je dis que je fais tout, je déconne pas, je fais vraiment tout : rédaction en chef, secrétariat de rédaction, chef de rubriques (oui, au pluriel !), chef de fab, PAO, piges... Tout ça pour un salaire de misère. Le communisme a mal choisi son moment pour se casser la gueule, c’est moi qui vous le dis.
Heureusement, quelques bonnes âmes m’aident à remplir ces pages. Par ordre d’apparition à l’écran, ce sont Denis Jarril, François Lionet, François Gueugnon, Herr Doktor Von GluttenStimmellmDorf, Jérôme Etienne, Denis Genot, Max, Loïc Far et les inséparables Ok et Cancel. Qu’Us soient ici publiquement tous remerciés, autant qu’ils le méritent (c’est-à-dire un peu plus qu’ils sont payés, eux aussi...).
Pour ce qui est de la fabrication, on fait appel à des gens sympas, qui acceptent nos délais sans broncher, pourvu qu’on les invite à bouffer de temps en temps. Ainsi par exemple, notre flasheur ColorWay (5, rue de la Fidélité, 75010 Paris, Tel: 47.70.87.87) est plutôt cool. Remarquez, y z’ont intérêt, vu qu’y sont juste en dessous de chez nous et que si y nous emmerdent, on yà-ty. 'outre .le fm:,: iipnpmpis.
L’imprimeur par contre, on te connaît un peu moins bien parce que ça fait pas longtemps qu ’on travaille avec lui. Par exemple, moi, je sais seulement qu’il s’appelle INO-Montrouge, qu’il habite au 9, rue Auher. 92120 Montrouge et que son numéro de bigophone est le 46.56.27.69. H sait pas encore sur qui il est tombé, mais il va vite comprendre.
Pour terminer, les abonnements sont gérés sur Thomson MOS avec 2 Ko de mémoire centrale par MCM Europe, 16, quai Jean-Baptiste Clément, 94140 Alfortville. Tel : 43.78.92.10. Si vous avez Claude au bout du fil, faîtes lui une bise de ma part
Rapidement, une petite illustration du fonctionnement des overlays, avec un programme parfaitement inutile, qui ne fera certainement pas date dans l’histoire de la presse informatique...
Il faut quand même reconnaître qu’il n’est pas évident de démontrer par un court programme l’utilisation - mais aussi et surtout l’utilité - des overlays, mais j’ai tout de même décidé de le faire. Les listings qui suivent font donc partie d’un seul programme nommé "Ovls" (raccourcis pratique pour ’Overlays’...). Dans l’ordre, nous avons la
Racine (Racine.c), 3 overlays de niveau 1 (Ovll.c, Ovl2.c et Ovl3.C) et deux overlays de niveau 2 (Ovl3_I.cet Ovl3_2.c). Un fichier WITH pour Blink est également inclus, histoire de montrer comment il est conçu.
Sans transition, je vous laisse méditer là-dessus et vous donne rendez-vous au mois prochain pour de nouvelles aventures.
Listing 1 : Racine, c
**********************************************************
* Arborescence des overlays : *
* +----------+ *
* | Racine.c I *
* + +-----+ *
* I *
* +--------+ +----+---+ +--------+ *
* | Ovll.c +--+ Ovl2.c +--+ Ovl3.c I *
* +--------+ +--------+ +---+----+ *
I *
* +----------+ | +----------+ *
* | Ovl3_l.c +-+-+ Ovl3_2.c | *
* +----------+ +----------+ *
* ********************************************************
include stdio.h>
* Fonctions de main.c * int GetChar(void);
* Fonctions du premier niveau de l'arbre * extern void Ovll(void); * dans Ovll.C *
extern void Ovl2(void); * dans Ovl2.C *
extern void Ovl3(void); * dans Ovl3.C *
* fonction main() *
void main(int argc, char **argv)

int c = 0;
if (large)
return; * N'accepte pas le lancement depuis le WB *
* Petit menu (très) facile... * while (c != 'q' && c != 'Q')
printf(" 014Démonstration du mécanisme des Overlays. n"); printf(" n*** Ici la Racine n n");
printf("1 - Appeler l'overlay l n"); printf("2 - Appeler l'overlay 2 n"); printf("3 - Appeler l'overlay 3 n"); printf("Q - Quitter n"); printf("Appeler quel overlay (1 2 3)
switch(c = GetCharO) case '1':
Ovll(); break;
case '2':
Ovl2(); break;
case '3': Ovl3();
default: break;
int GetChar(void)

int cl, c2;
cl = getcharO;
while ( (c2 = getcharO) != ' n'); return(cl) ;
}
Listing 2 : Ovll.c include stdio.h>
extern int GetChar(void); * dans Racine.c *
void Ovll(void)

printf(" n*** Ici l'overlay l. n");
printf("üne touche pour retourner à la Racine..."); GetChar();
Listing 3 : Ovl2.c include stdio.h>
extern int GetChar(void); * dans Racine.c *
void Ovl2(void)

printf(" n*** Ici l'overlay 2. n");
printf("Une touche pour retourner à la Racine..."); GetChar();
}
Listing 4 ; Ovl3.c include stdio.h>
extern int GetChar(void); * dans Racine.c *
extern void Ovl3_l (void) ; * dans 0vl3_l.c *
extern void Ovl3_2 (void) ; * dans Ovl3_2.c *
void 0vl3(void)

int c = 0;
while (c != 'r' && c != 'R')
printf(" 014*** Ici l'overlay 3. n"); printf("A - Appeler l'overlay 3_l n"); printf("B - Appeler l'overlay 3_2 n"); printf("R - Retourner à la Racine n"); printf("Qu'est-ce qu'on fait (A B R) ? ");
switch(c = GetcharO)
case 'a': case 'A':
0vl3_l(); break;
case 'b': case 'B':
Ovl3_2();
Listing 5 : Ovl3_l.c include stdio.h>
extern int GetChar(void); * dans Racine.c *
void 0vl3_l(void)

printf(" n*** Ici l'overlay 3_l. n");
printf("Une touche pour retourner à l'overlay 3..."); GetChar();
Listing 6 : Ovl3_2.c *
include stdio.h>
extern int GetChar(void); * dans Racine.c *
void Ovl3_2(void)

printf(" n*** Ici l'overlay 3_2. n");
printf("Une touche pour retourner à l'overlay 3..."); GetChar();
}
Listing 7 : makefile
Ovls; Racine.o Ovll.o Ovl2.o 0vl3.o 0vl3_l.o Ovl3_2.o
Blink WITH Ovls.lnk
Racine.o: Racine.c
Le Racine.c
Ovll.o: Ovll.c
Le Ovll.c
Ovl2.o: Ovl2.c
Le Ovl2.c
Ovl3.o: 0vl3.c
Le 0vl3.c
0vl3_l.o: Ovl3_l.c
Le Ovl3_l.c
Ovl3_2.o: Ovl3_2.c
Le Ovl3_2.c
Listing 8 : Ovls.lnk (fichier WITH pour Blink)
ROOT libic.o Racine.o TO Ovls
LIBRARY lib:lc.lib,lib:small.lib SMALLCODE SMALLDATA NODEBUG NOICONS
OVERLAY Ovll.o Ovl2.o Ovl3.o
* Ovl3_l.o
* Ovl3_2.o
enis Jarril
L
I0l
- LES COURBES |p
?
Salut, c’est encore moi ! Le mois
dernier, je vous avais promis un traceur de courbes en AMOS. Je
' Entrée des expressions Do
tiens mes promesses, voici un traceur de courbes en AMOS. Quel homme de parole !
Cls
Centre At(,2)+">>> Le bo traceur de courbes de Daisy " : Print
Locate 0,10
Print "Entrer une ligne vide pour quitter le programme."
Print
C’est une application directe des procédures du mois dernier ; il suffit donc de les récupérer sous l’éditeur AMOS. Il faut tout de même en modifier quelques unes :
- EVALINIT : un nouvelle procédure qui se
charge de définir les fonctions disponibles, juste
histoire d’être un peu plus structuré. Dans votre
programme, vous définissez les tableaux, et vous appelez EVALINIT.
- EVALUE : j’avais laissé un petit bug. Hum. Il est
maintenant corrigé.
- EVALIT : il faut ajouter une nouvelle routine pour traiter la variable X. Celle-ci s’appelle VARX. Notez que j’ai également ajouté une gestion des erreurs : la variable SYNT est positionnée à -1 en cas d’erreur d’évaluation.
Les autres procédures ne sont pas modifiées, copiez les du programme du mois dernier (si vous avez loupé le dernier numéro, vous trouverez les routines sur la disquette du magazine).
Le reste du programme se passe de commentaires, si j’ose dire car justement, il en est truffé, le programme, de commentaires.
Remarquez cependant que tous les paramètres d’affichage de la courbe sont entrés au moyen des routines d’évaluation. Lorsque vous analysez un sinus par exemple, vous pouvez taper -2*PI au lieu de -
6. 2832. C’est quand même plus pratique.
Remarquez également la procédure _GET_VALUE : je remets l’ancienne valeur du paramètre dans le buffer clavier. Pas besoin de retaper tout à chaque fois.
C’est tout pour aujourd’hui ! Ouf, finies les maths... Je laisse le clavier à mon chien, qui devient de plus en plus mégalo. Mais enfin sa petite démo n’est pas mal du tout.
Traceur de courbes AMOS Par François Lionet
Définition des variables MXE=25
Dim PILE(MXE),PILE (MXE),PILE$ (MXE),PP(MXE),PP (MXE)
Global OPE$ ,FUN$ ,EV$ ,PEV,LEV,SYNT,PILE(),PILE$ (),PILE (),PPILE Global PP(),PP (),PP,NPAR,CHAR$
Nouvelle variable Global XX
Appelle la nouvelle procédure EVALINIT
Ouverture de 1'écran Screen Open 0,640,256,4,Hires Flash Off : Palette 0,$ FFF,$ 62,$ FF0 Paper 0 : Pen 1
' Définition de la fenetre d'affichage de la courbe DX=8 : DY=8 : TX=624 : TY=192
FONC$ ="Sin(X)"
DEBX =-Pi
FINX =Pi
PAS =320 DEBY =-1 FINY =1
' Demande et vérifié la fonction.
Do
Put Key FONC$
Line Input "Fonction à évaluer: ";A$
Exit If A$ ="",2 : _TOKENISE[A$ ] : Exit If Not SYNT
Print "Erreur de syntaxe. Veuillez ré-entrer 1'expression..."
Loop
FONC$ =A$
' Intervalle d'etude Do
_GET_VALUE[DEBX ,"Début de l'intervalle en X"] :
DEBX =Par am
_GET_VALUE[FINX ,"Fin de l'intervalle en X"] : FINX =Param
Exit If FINX >DEBX
Print "En général, le début est inférieur à la fin. Juste pour dire..."
Loop
' Pas du dessin
_GET_VALUE[PAS ,"Nombre de pas de dessin"] : PAS =Param
' Intervalle d'affichage Do
_GET_VALUE[DEBY ,"Début de l'intervalle en Y"] : DEBY =Param
_GET_VALUE[FINY ,"Fin de l'intervalle en Y"] : FINY =Param Exit If FINY >DEBY
Print "Le début, y'en a moins grand que la fin. Ok?"
Loop
' Va tokeniser pour de bon!
_TOKENISE[FONC $ ]
' Dessine une beeelle boite toute verte Cls : Curs Off Clip : Gr Writing 1
Set Pattern 0 : Set Paint 1 : Ink 2,2,1 Bar DX-4,DY-4 To DX+TX+4,DY+TY+4 Gr Writing 0 : Ink 3
' Dessine l'axe en X Draw DX+TX 2,DY To DX+TX 2,DY+TY Draw DX+TX 2-4,DY To DX+TX 2+4,DY Draw DX+TX 2-4,DY+TY To DX+TX 2+4,DY+TY Text DX+TX 2+2,DY+6,Str$ (FINY )
Text DX+TX 2+2,DY+TY,Str$ (DEBY )
' Dessine l'axe des Y
Draw DX,DY+TY 2 To DX+TX,DY+TY 2
Draw DX,DY+TY 2-4 To DX,DY+TY 2+4
Draw DX+TX,DY+TY 2-4 To DX+TX,DY+TY 2+4
Text DX,DY+TY 2+8,Str$ (DEBX )
A$ =Str$ (FINX ) : Text DX+TX-8*Len(A$ ),DY+TY 2+8,A$
' Calcule les coefficients de multiplication STP =(FINX -DEBX ) PAS
MULX =TX (FINX -DEBX )
MULY =TY (FINY -DEBY )
' Boucle de trace de la courbe 0=0 : Ink 1
For XX =DEBX To FINX Step STP
' Appel de l'évaluation EVALUE
' Si pas d'erreur P=0
If Not SYNT
' Calcule la position sur 1'écran X =XX -(DEBX +FINX ) 2.0 Y =Param -(DEBY +FINY ) 2.0 X=TX 2+X *MULX : Y=TY 2-Y *MULY
If Y>=0 and Y =TY If 0
Draw To DX+X,DY+Y : P=1 Else
Plot DX+X,DY+Y : P=1 End If
(suite page 31)
"Petite démo" ? Comment ça, "petite démo"? Le programme que j’ai tapé de mes pattes poilues va révolutionner le monde de l’Amiga... C’est tout simplement du concentré de génie. Non mais !
LE RETOUR !
Tiens, comme je suis bonne patte, je vais essayer de vous en expliquer le fonctionnement... Vous connaissez les déformations sinusoïdales ? En voici une toute simple à réaliser, sur plus de 200 lignes d’écran et au 1 50 ième de secondes, s’il vous plaît ! Elle est de plus totalement
paramétrable. J’explique.
Il n’est même pas envisageable de calculer une déformation sinusoïdale en temps réel, au 1 50 ième sur 200 lignes : c’est déjà très difficile en langage
machine, donc impossible en AMOS. Il faut donc ruser et calculer tout à l’avance : les images étant déjà
dessinées, il suffira de les faire défiler à l’écran l’une après l’autre. Bon.
La première idée qui vient à l’esprit est d’ouvrir
plusieurs écrans et de les faire défiler avec l’instruction SCREEN TO FRONT. C’est pas mal, mais nous somme limités à 8 images au maximum, trop peu pour une bonne animation. Même en passant les écrans en double buffer, on reste encore limités à 16 images, encore trop peu, surtout si l’on veut faire défiler un texte par
dessus.
Mon idée de génie, je dois le dire, a été de réserver une banque de mémoire CHIP, contenant la place nécessaire à toutes les images pré-calculées. Par exemple, pour 20 pas d’animation d’une image de 320x200 en 2 couleurs, la taille de cette banque est de 160 Kilos.
Comment afficher le contenu de cette banque dans un écran ? Mon deuxième coup de génie, je dois l’avouer modestement, est d’utiliser l’instruction SCREEN OFFSET. Car avez-vous remarqué que cette instruction permet d’explorer toute la mémoire graphique de l’Amiga, simplement en utilisant de grandes valeurs en Y ? En calculant la distance entre la grosse banque de mémoire et l’écran numéro 0, on peut connaître les valeurs à utiliser dans l’instruction et afficher tout simplement le contenu de la banque au lieu de l’image normale.
Voila pour la théorie, voyons le programme.
On commence par récupérer le maximum de mémoire possible, en fermant les écrans et l’éditeur. On définit ensuite les valeurs de la déformation :
* NPAS est le nombre d’images calculées. Plus NPAS est grand, plus lente est la déformation. Essayez donc 20 ou 30 pour commencer.
* AMRX1 et AMPY1 définissent la déformation en X.
* AMPX2 et AMPY2 définissent la déformation en Y. Modifiez ces valeurs et voyez le résultat.
Le programme réserve alors la grosse banque de mémoire CHIP puis ouvre l’écran 0. Il faut s’assurer que l’adresse de l’écran 0 est inférieure à celle de la banque, car SCREEN OFFSET n’accepte pas de valeurs négatives. On ouvre maintenant deux écrans de travail, que l’on cache le temps de calculer toutes les déformations. Celle en X est d’abord appliquée entre l’écran 0 et l’écran 1, puis celle en Y, de l’écran 1 dans l’écran 2. On peut alors utiliser l’instruction COPY pour copier le contenu de la bitmap dans la banque de
mémoire, en bonne position. Reste à calculer la "distance" entre l’écran 0 et la première image de la banque, et c’est tout.
C’est AMAL qui se charge de l’animation. Les registres à initialiser sont RA (valeur de base en X), RB (valeur de base en Y), RC (nombre de lignes d’une image) et (RD nombre de pas d’animation). La chaîne AMAL se contente de modifier les valeurs de SCREEN OFFSET en X et en Y. C’est tout.
Une fois la chaîne initialisée, on peut retourner en mode direct : l’animation marche toute seule !
Vous pourrez animer d’autres images en utilisant la même méthode. L’écran 0 peut faire partie d’un dual- playfield et dans ce cas, vous pourrez faire bouger un gros logo devant.
Avouez que c’est tout de même mieux qu’un minable traceur de courbes. Faut vraiment pas avoir d’idées pour publier quelque chose d’aussi éculé (pourquoi tant de haine ?). Holà, le voilà, il faut que je joue le bon chien-chien à son pépère et lui fasse la fête... On se voit le mois prochain, si je peux accéder au clavier.
Waf, waff, wouf ! Slurp, slurp, hop, hop, hop ! Ouah, ouah, slurp, slurp, slurp !
Daisy DemOS numéro 5
"Le retour du come-back II"
Par Daisy Lionet.
(c) OS-Productions 1991
Screen Close 0 Close Editor Close Workbench
' Définition de la deformation
NPAS=16
NSCREEN=NPAS : SX=320 : SY=200 AMPXl =6 : AMPY1 =0.05 AMPY2 =6 : AMPX2 =0.04
' Réservation de la mémoire.
' Assure la presence d'une place EN DESSOUS de la banque Reserve As Chip Work 9,10000
' Reserve la banque
SIZE=SX 8*SY
Reserve As Chip Work 10,SIZE*NSCREEN ' Libéré la place en dessous de la banque Erase 9
' Reserve 1'écran de base
Screen Open 0,SX,SY,2,Lowres Curs Off : Cls 0 Colour 1,$ EEE
' Imprime de zoulis dessins
Scroll Off : For X=0 To 80 : Print "Daisy DemOS !"; : Next BONE[160,100,100, 20, 25]
' Vérifié que tout peut marcher.
If Logbase(0)>Start(10) : Stop : End If
' Ouvre les deux écrans de travail
Screen Open 1,SX,SY,2,Lowres Curs Off : Screen Hide 1 Screen Open 2,SX,SY,2,Lowres Curs Off : Screen Hide 2
REXX
Voici déjà le troisième et dernier volet de notre premier programme Arexx : il concerne plus particulièrement la présentation du répertoire à l’écran.
Nous avons employé la pile pour stocker momentanément trois valeurs : le nom du disque, l’adresse en mémoire du bloc des fichiers créés dans le programme 2 et sa longueur. Nous avons pour cela utilisé trois fois l’instruction PUSH. Bien que cette méthode soit tout-à-fait légale, elle peut présenter un certain danger dans un système multitâches car la pile est publique. Chaque programme peut la charger ou la lire à sa guise. Il serait préférable de l’utiliser ainsi : d’abord créer une chaîne contenant un nom identificateur et les paramètres à transférer et n’effectuer qu’un seul PUSH. A la réception, on effectue un PULL qui retourne la ligne courante de la pile. On vérifie alors que le nom identificateur est correct ; si oui on continue, sinon c’est qu’un autre utilisateur s’en est servi. On stocke alors momentanément la ligne et on recommence jusqu’à la découverte de la bonne ligne. On replace ensuite dans la pile - et dans l’ordre ! - tout ce qu’on en a été extrait. Notons que ce n’est pas spécifique à Arexx mais à tout système partagé.
PARTICULARITES DU PROGRAMME
Nous avions laissé les défauts du programme précédent afin d’utiliser dans celui-ci les possibilités du traitement des chaînes de caractères. Ceci explique les différents traitements, dont l’intérêt est purement didactique.
Le bloc issu du programme précédent est une suite monolithique de caractères : il n’y a qu’un seul retour chariot en fin de bloc et bien que ce soient des caractères ASCII, ils représentent valablement tout ou partie d’un fichier standard dans un langage quelconque. Seule l’acquisition peut être différente (usage de READCH() par exemple).
L’homogénéisation des séparateurs (début en ligne 30) peut sembler faire double emploi avec la fonction remplaçant les séparateurs (III) par des espaces, mise dans les lignes 101 et 102. Il faut se rappeler que dans Arexx, les espaces sont des séparateurs implicites et que certains titres de répertoires ou de fichiers peuvent en contenir, ce qui augmenterait la difficulté à les trier sans les tronquer.
La console a ses définitions et ses limitations. Certaines peuvent être outrepassées, d’autres non. Cela limite la réalisation et attire la critique des esthètes. Nous en sommes conscients et d’accord !
PROCHAINS ARTICLES
Notre prochain article traitera du débogage des programmes, car l’environnement Arexx est bien muni en aides diverses au déverminage et possède des particularités intéressantes. Ensuite, nous verrons comment utiliser les "libraries" ou bibliothèques venant avec la rexxarp.library, qui permet d’accéder aux fonctions d’intuition (menus, gadgets, etc.). Après encore, nous regarderons comment les programmes spécialement prévus pour, fonctionnent de concert avec Arexx, et en particulier, nous vous suggérons de chercher dès à présent à vous procurer cet excellent éditeur de textes du Domaine Public qu’est DME (version 1.35), réalisé par le non moins excellent Matt Dillon, qui est "Rexxable" à satiété. Il sera bien entendu fourni sur la disquette ANT relative à cet article lors de sa parution.
LISTING DU PROGRAMME
Ce programme s’appelle Présentation (n’oubliez pas l’accent aigu sur le "é")... Comme d’habitude, les numéros de ligne sont des repères à ne pas copier.
21 *récupération des paramètres*
22 PULL disque
23 PULL adresse
24 PULL longueur
25 adresse=X2C(adresse)
26 texte=IMPORT(adresse,longueur)
28 SAY CENTER(7Un peu de patience... 7,80)
30 *homogénéisation des séparateurs*
32 début=1
33 position=l
34 DO WHILE position ~=0
35 position=POS('IIIIII7,texte,début)
3 6 texte=DELSTR(texte,position+3,3)
37 debut=position+3
38 END
39 position=l
40 début=1
41 DO WHILE position ~=0
42 position=POS(7)7,texte,début)
43 IF SUBSTR(texte,position+1,1)
~='|' THEN |7,texte,position)
texte=INSERT(7||
44 debut=position+4
45 END
47 *extraction des titres des répertoires*
49 liste.0=0
50 i=0
51 a=l
52 debut=POS(7I 7,texte,1)
54 DO WHILE a ~=0
55 a=POS(7 :7,texte,début)+l
56 IF b=0 THEN BREAK
57 b=POS(7 > 7,texte,début)
58 long=b-a
59 IF long =0 THEN BREAK
60 début=b+l
61 chaine=STRIP(SUBSTR(texte,a,long))
62 x=REVERSE chaine)
63 PARSE VAR x rang chaine
64 rang=REVERSE(rang)
65 chaine=REVERSE(chaine)
66 i=i+l
67 liste.i=rang 7:7 chaine 7:7 b
68 liste.0=liste.0 + 1
69 END
71 *recherche des répertoires extérieurs*
73 DO i=l TO liste.0
74 inter=0
75 PARSE VAR liste.i . 7:7 al 7:7 .
76 DO j=i+l TO liste.0
77 PARSE VAR liste.j . 7:7 bl 7:7 .
78 IF STRIP(al)==STRIP(bl) THEN inter=j
79 END
80 liste.i=inter 7:7 liste.i
81 END
83 *extraction des fichiers relatifs aux répertoires*
85 DO i=l TO liste.0 -1
86 PARSE VAR liste.i kl 7:7 k2 k3 7:7 k4
87 k4=STRIP(k4)
88 posl=POS(7 7,texte,k4)+1
89 long=posl-k4
90 souschaine=SUBSTR(texte,k4,long)
91 pos2=POS(7|II7,souschaine,1)
92 IF pos2 =0 THEN DO
93 liste.i=liste.i 7;7
94 ITERATE i
95 END
96 pos3=POS(7III 7,souschaine,1)
97 souschaine=SUBSTR(souschaine,2,pos3)
98 DO FOREVER
99 posx=POS(7III7,souschaine,1)
100 IF posx=0 THEN BREAK
101 souschaine=DELSTR(souschaine,posx,3)
102 souschaine=INSERT(7 7,souschaine,posx-1)
103 END
104 long=LENGTH(souschaine)-2
105 souschaine=SUBSTR(souschaine,l,long)
106 posx=POS(7 7,souschaine, 5)+l
107 souschaine=SUBSTR(souschaine,posx + 2)
108 liste.i=liste.i 7;7 souschaine 110 END
112 nb=liste.O
113 PARSE VAR liste.nb kl 7:7 k2 7î7 k3 7:7 k4
114 souschaine=SUBSTR(texte,k4+2)
115 posl=POS(7 III7,souschaine,l)+5
116 pos2=POS(7III 7,souschaine,1)
117 souschaine=SUBSTR(souschaine,posl,pos2-posl)
118 DO FOREVER
119 posx=POS(7III7,souschaine,1)
120 IF posx=0 THEN BREAK
121 souschaine=DELSTR(souschaine,posx,3)
122 souschaine=INSERT(7 7,souschaine,posx-1)
123 END
124 liste.nb=liste.nb 7;7 souschaine
126 *calcul de la taille de chaque répertoire*
128 DO i=l TO liste.0
129
PARSE VAR liste.i kl k2 ':' k3 7k4 7;
7 k5
247
CALL WRITECH('écran7,79B 30 6D'X) * typographie normale*
130
début=1
248
RETURN
131
somme=0
250
souligner:
132
DO FOREVER
251
CALL WRITECH('écran7, 79B 34 6D'X) ‘typographie souligné*
133
posl=POS(7(7, k5,début)
252
RETURN
134
IF posl=0 THEN BREAK
254
italique:
135
pos2=POS(7)7,k5,posl)
255
CALL WRITECH('écran7,79B 33 6D'X) ‘typographie italique*
136
long=pos2-l-posl
256
RETURN
137
somme=somme+STRIP(SUBSTR(k5,posl+l, long) )
258
gras:
138
début=pos2+l
259
CALL WRITECH('écran7,79B 31 6D'X) ‘typographie grasse*
139
END
260
RETURN
140
liste.i=kl 7 : 7 k2 7 : 7 k3 7 : 7 somme 7 ; 7 k5
262
lligne:
141
END
263
CALL WRITECH('écran7,79B 31 45'X) ‘curseur 1 lig en bas*
143
‘élimination des lignes doubles*
264
RETURN
145
ligne.0=0
266
couleur: * couleur texte et fond*
146
3=1
267
ARG fond devant
147
DO i=l TO liste.0
268
coul=X2C('9B 34 37i I fond 73B 33 37 IISTRIP(devant) 76D7)
148
PARSE VAR liste.i kl 7:7
269
CALL WRITECH 'écran7,coul)
149
kl=STRIP(kl)
270
RETURN
150
IF kl=7 * 7 THEN ITERATE i
272
filtre:
151
IF kl~=0 THEN DO
273
PARSE ARG dl d2
152
liste.i=liste.kl
274
dl=STRIP(dl)
153
liste.kl=7*7
275
d2=STRIP(d2)
154
END
276
posx=POS(7 7,texte,dl)
155
PARSE VAR liste.i . 7:7 ligne
277
loin=posx-dl
156
ligne.j= STRIP(ligne)
278
essai=SUBSTR(texte,dl,loin)
157
j=j+l
279
y=POS('III7,essai,1)
158
ligne.0=ligne.0 +1
280
IF y=0 THEN DO
159
DROP liste.i
281
chaine=7 7
160
END
282
return chaine
161
DROP liste.0
283
END
163
‘réduction des titres*
284
posl=POS(7||I',texte,dl)
165
DO i=l TO ligne.0 -1
285
IF d2=0 THEN pos2=STRIP(POS(7I 7,texte,dl))
166
PARSE VAR ligne.i rang 7:7 titre 7:7 reste
286
ELSE pos2=d2
167
rang= STRIP(rang)
287
long=pos2-posl+1
168
SELECT
288
IF long =0 THEN DO
169
WHEN rang = 0 THEN NOP
289
chaine=7 7
170
WHEN rang = 1 THEN NOP
290
RETURN chaine
171
OTHERWISE DO
291
END
172
DO j =1 TO rang-1
292
chaine=SUBSTR(texte,posl,long)
173
posx=POS(7 7 titre)+1
293
DO FOREVER
174
titre=SUBSTR(titre,posx)
294
y=POS('III7,chaine,1)
175
END
295
IF y=0 THEN BREAK
176
ligne.i= rang 7:7 titre 7:
7 reste
296
chaine=DELSTR(chaine,y,3)
177
END
297
chaine=INSERT(7 7,chaine,y-1)
178
END
298
END
179
END
299
RETURN chaine
181
‘calcul de la taille utilisée*
301
misenpage:
183
DO i=l TO ligne.0
303
ARG rg back fore
184
PARSE VAR ligne.i . . 7:7 taille .
304
CALL normal; CALL retour
185
somme= somme+STRlP(taille)
305
rg=STRIP(rg)
186
END
306
DO zz=l TO rg
196
‘ouverture de l7écriture sur la console*
307
CALL dec5
198
CALL OPEN('écran7,7*','WRITE7)
308
END
199
CALL WRITECH('écran7,79B 37 3B 33 33 3B 34 30 6D
0B 0D 0C
309
back=STRIP(back)
9B 4D
9b 37 39 757X)
310
fore=STRIP(fore)
200
CALL gras
311
CALL couleur(back fore); CALL italique
201
CALL écrit(CENTER('Nom du disque :'disque,79))
312
dimension=nom taille 'Octets7
202
CALL lligne; CALL retour; CALL normal
313
CALL écrit(dimension)
203
x=ligne.0
314
CALL couleur(0 1); CALL retour; CALL lligne; CALL normal;
204
PARSE VAR ligne.x . Root 7;7 fichiers
CALL lligne
205
texte=CENTER(somme 'Octets utilisés. Taille
315
CALL misenpaquet
206
repertoire ROOT:7 root, 'Octets7,80)
316
CALL normal; CALL lligne; CALL lligne; CALL couleur(0 1)
207
CALL écrit(texte)
317
RETURN
208
CALL lligne; CALL retour
318
209
CALL écrit(fichiers)
319
misenpaquet:
210
CALL lligne; CALL retour; CALL normal; CALL lligne
320
espreel=7 7
212
‘traitement des lignes*
321
espace=7
214
DO i=l TO ligne.0 - 1
322
DO es=l to rg
215
PARSE VAR ligne.i rang nom taille
fichiers
323
espreel=espreel||espace
216
nom= STRIP ( nom)
324
END
217
fichiers=STRIP(fichiers)
325
nblignés=LENGTH fichiers)%(8 0-LENGTH(espreel))
218
SELECT
326
reste=LENGTH(fichiers) (80-LENGTH(espreel))
219
WHEN rang = 1 THEN CALL misenpage(0 3
0)
327
SELECT
220
WHEN rang = 2 THEN CALL misenpage(l 0
3)
328
WHEN nblignés=0 THEN DO
221
WHEN rang = 3 THEN CALL misenpage(2 1
3)
329
fichiers=espreel||fichiers
222
WHEN rang = 4 THEN CALL mi senpage(3 2
3)
330
CALL écrit(fichiers)
223
WHEN rang = 5 THEN CALL misenpage(4 2
1)
331
END
224
OTHERWISE NOP
332
WHEN nblignes~=0 THEN DO WHILE LENGTH(fichiers)>0
225
END
333
ligne=SUBSTR fichiers, 1, 80
227
END
- LENGTH(e spree1)-1)
228
x=FREESPACE(adresse,longueur)
334
fichiers=DELSTR(fichiers,1,80
229
EXIT
- LENGTH(espreel)-1)
231
‘A partir d'ici ce sont les sous programmes*
335
ligne=espreel|lligne
233
écrit: ‘écrit le texte à 1
.'écran *
336
CALL écrit(ligne)
234
arg tex
337
END
235
CALL WRITECH(7 écran7,tex)
338
OTHERWISE NOP
236
RETURN
339
END
238
retour:
340
RETURN
239
CALL WRITECH('écran7, 7OD'X) • ‘retour
chariot*
240
RETURN
242
dec5:
243
244
CALL WRITECH('écran7,79B 30 35 437X) RETURN
Par François G ue a gnon. E3
246
normal :
r
FLEX
Ce mois-ci, nous allons étudier Flex, version AmigaDOS de lex, le célèbre utilitaire que tout utilisateur d’Unix connaît, ne serait-ce que de nom.
..
Flex est un outil permettant de créer rapidement des analyseurs syntaxiques (ou "scanners"). Il s’agit de programmes capables de reconnaître des motifs lexicaux (ou "patterns") dans un texte et de déclencher des actions en fonction des motifs reconnus.
Flex, dans son utilisation, est fort similaire à Gawk, édutidé le mois dernier : il lit un fichier d’entrée (ou l’entrée standard si aucun nom de fichier ne lui est précisé) correspondant à la description du scanner à générer. Il se compose d’une suite d’expressions propres au langage lex et de code source en C définissant, sous forme de fonctions, les actions à effectuer lors de la reconnaissance d’un motif lexical.
A l’aide de ces données d’entrée, Flex génère un autre programme source en langage C, se nommant lex.yy.c et définit la routine yylex() qui est l’analyseur syntaxique créé à partir des règles de l’utilisateur. Cet analyseur syntaxique peut ensuite être utilisé tel quel ou intégré dans une application, comme n’importe quel autre source en C.
Une fois compilé et linké, lex.yy.c produit un exécutable capable d’analyser un fichier et d’exécuter un certain nombre d’actions en fonction des patterns rencontrées.
SYNTAXE
Après ce rapide descriptif des fonctionnalités de Flex, il est temps désormais d’étudier la syntaxe du fichier d’entrée. Attention, le but de cet article n’est pas de vous expliquer toutes les finesses du langage, l’intégralité de la revue n’y suffirait pas. Non, il s’agit simplement de vous familiariser avec Flex afin de vous faire découvrir toute la puissance de ce produit.
Les différentes sections d'un programme lex.
Le fichier d’entrée de Flex peut être décomposé en trois sections distinctes, séparées entre elles par la ligne ’%%’. Ces trois sections sont : Définitions, Règles et Code utilisateur (en C).
La section Définitions contient la déclaration de noms comme équivalence à une définition, ceci afin de simplifier l’écriture de certaines expressions. Cette déclaration s’effectue sous la forme :
nom définition
Le nom doit impérativement commencer à la première colonne de la ligne, sous peine d’être interprété d’une autre manière comme nous le verrons plus tard. De même, la définition commence dès le premier caractère non-blanc de la ligne.
Par exemple, CHIFFRE [0-9] permet de remplacer dans toutes les règles, l’expression [0-9 ] définissant un chiffre par le mot CHIFFRE. Ainsi
CHIFFRE}" CHIFFRE}* remplace ([0-9])+"."([0-9])
¦6©
La section Règles contient une série de règles de la forme :
pattern action
Attention, comme dans la section Définitions, la pattern doit obligatoirement commencer à la première colonne de la ligne sous peine d’une interprétation différente.
Enfin, la section Code utilisateur contient les fonctions appelées par l’analyseur syntaxique. Il s’agit de code en langage C qui sera copié tel quel dans le fichier lex.yy.c
Dans les sections Définitions et Règles, tout texte indenté ou compris entre ’ %’ e ’%}’ est copié tel quel vers le fichier de sortie (les caractères ’ %’ et ’%}’ étant enlevés lors de cette opération).
Dans la section Règles, toute ligne indentée ou comprise entre ’ %’ et ’%}’ apparaissant avant la première règle effective est considérée comme une déclaration de variable locale à la fonction d’analyse syntaxique.
Dans la section Définitions, pour inscrire un commentaire, il suffit que la ligne ne soit pas indentée et comprise entre ’ *’ et ’* ’. Un commentaire est recopié tel quel vers le fichier de sortie. A noter la possibilité de définir une ligne de commentaire à l’aide du ’ ’ situé en première colonne de la ligne. Cette pratique est à éviter car elle risque de disparaître dans de futures versions.
La notion de "Pattern"
Le motif lexical (ou pattern) est défini par une série de règles d’écriture, pour la plupart très proches de celle de Gawk. Notre propos n’est pas de passer en revue toutes ces règles mais d’en étudier quelques unes par l’exemple.
X recherche le caractère 'x'
n'importe quel caractère sauf retour chariot [xyz] une classe de caractères, en 1'occurence 'x', 'y', 'z'
r* zéro ou plusieurs r, où r est une expression régulière
23 le caractère ayant pour valeur 123 (en octal)
x2a le caractère ayant pour valeur 2a (en hexadécimal)
et bien d’autres encore (reportez-vous à la
documentation pour plus de précisions).
Quand l’analyseur de syntaxe est lancé, il analyse le fichier et pour chaque ligne, recherche les occurrences qui correspondent à une ou plusieurs patterns. S’il en
trouve plus d’une, il recherche d’abord celle dont un
maximum de caractères correspond à la pattern. Si l’ambiguïté n’est pas levée, il prend la première par
ordre de déclaration des règles dans le fichier lex.
Une fois le texte trouvé, celui-ci est recopié dans le pointeur yytext et sa longueur dans la variable yyleng. L’action correspondante à la pattern est alors exécutée, et le reste de la ligne analysé.
Si aucune règle n’est déclenchée (c’est-à-dire aucune occurrence de pattern n’est trouvée dans la phrase), la règle par défaut est exécutée : elle consiste à copier les caractères un à un vers la sortie.
Donc, un programme Flex réduit à %% copiera simplement le fichier d’entrée vers le fichier de sortie, sans aucune modification.
La notion d'Action
Chaque pattern dans une règle possède une action qui lui correspond. La pattern se terminant dès le premier caractère blanc rencontré, le reste de la ligne est donc l’action associée.
A titre d’exemple, ce petit programme remplace les suites de caractères blancs (an anglais, "white space") par un espace. Il supprime également tous les caractères blancs en fin de ligne.
%%
[ t]+ putchar(' ');
[ t]+$ * on ignore simplement *
Lorsqu’une action ne tient pas sur une seule ligne il
faut la mettre entre accolades. Il est à noter que Flex sait reconnaître les accolades liées à l’action des éventuelles accolades se trouvant dans le source C
définissant l’action.
Il existe de nombreuses directives lex qui peuvent être intégrées dans les actions et qui représentent en quelque sorte des macro-commandes. Un exemple, ECHO recopie systématiquement le contenu du pointeur de caractères yytext vers la sortie du scanner.
Il existe bien d’autres choses à dire sur Flex, mais la place qui m’est impartie n’étant pas élastique, passons sans plus attendre aux exemples qui vous permettront de mieux cerner son utilisation.
EXEMPLES
int nbr_ligrie = 0, nbrcar =0;
n ++nbr_ligne; ++nbr_car;
++nbr_car;
%%
main()

yylex();
printf( "Nombre de lignes = nombre de caractères =
%d n",nbr_ligne,nbrcar);
Ce premier exemple compte le nombre de caractères et le nombre de lignes d’un fichier d’entrée. Il ne produit aucun autre résultat que ces deux nombres en sortie. La première ligne déclare deux variables globales nbr_ligne et nbr_car, qui sont accessibles à la fois par la routine yylex() (générée par Flex) et par la fonction main() (définie par l’utilisateur).
Deux règles ont été définies : la première recherche les caractères retour chariot ( n) et incrémente les valeurs nbr_ligne et nbr_car à chaque fois qu’elle en découvre un ; la seconde recherche un caractère quelconque autre que n et incrémente nbr_car à chaque fois qu’elle en découvre un.
Passons maintenant à un exemple un peu plus compliqué.
* Analyseur syntaxique pour un langage style C *
%
* Cet include est nécessaire pour récupérer *
* la définition de la fonction atof() *
include math.h>
%}
CHIFFRE [0-9]
VAR [a-z][a-zO-9]*
%%
CHIFFRE}+
printf( "Un entier: %s (%d) n", yytext, atoi( yytext ) );
}
CHIFFRE}+"." CHIFFRE}*
printf( "Un flottant: %s (%g) n", yytext,
atof( yytext ) );
}
if IwhileI do Iswitchlcase I for I break I continue printf( "Un mot clef: %s n", yytext );
}
VAR}+"(" printf( "Une fonction: %s n", yytext );
VAR} printf( "Une variable: %s n", yytext );
i. + «i | n _ ii | « * h | it m printf ("Un opérateur: %s n", yytext );
[ t n]+ * saute les blancs *
printf( "Caractère inconnu: %s n", yytext );
%%
main( argc, argv ) int argc; char **argv;

++argv, --argc; if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin; yylex();
Ce petit exemple pourrait représenter le début d’un programme d’analyse de langage il est en effet à même de reconnaître dans un fichier source, les variables, fonctions, mot-clefs du langage, expressions ainsi que les constantes entières et réelles présents dans le source. Il ne traite pas toutes les spécificités du langage, mais montre de manière simple comment on peut envisager la réalisation d’un véritable analyseur syntaxique. Nous y reviendrons d’ailleurs dans un prochain article.
BIBLIOGRAPHIE
Advanced Tools for Programmers : tiré de la
documentation Unix, ce livre traite de Lex et Yacc. FlexDoc.doc : la documentation accompagnant le
logiciel, par Vern Paxson.
OU TROUVER FLEX ?
Comme bon nombre d’utilitaires étudiés dans ces colonnes, Flex est disponible dans le domaine public et plus particulièrement sur la disquette Fred Fish n°412. Cette disquette contient outre l’exécutable, une documentation fort complète de 35 pages (en anglais !) Sur le produit et les sources du logiciel, archivés au format LHArc.
J’espère que cet article vous donnera envie d’en savoir plus sur cet excellent produit qu’est Flex. Le mois prochain, nous continuerons notre exploration du monde Unix avec Yacc, qui permet de réaliser facilement des analyseurs sémantiques, et nous verrons bientôt que couplé à Flex, il nous peut permettre de réaliser notre propre interpréteur ou compilateur ! Mais n’anticipons pas, et à dans un mois pour un premier descriptif de Y acc.
Dura Flex sed Flex !
Je fais cela pour un raison bien simple : moi aussi je manque d’imagination, donc moi aussi je clone bêtement ce que font les autres... La réalisation de cet effet, plus connu sous le nom de Plasma, maintes et maintes fois répété dans les démos, et qui consiste à faire un dessin très coloré, ligne par ligne, tout en faisant cycler les couleurs, est des plus simples : tout se fait grâce à une fonction à deux variables du type z = F(x,y), où x et y sont les coordonnées du point considéré et z, sa couleur.
Nous allons donc balader notre point sur tout l’écran et obtenir ainsi un beau dessin. La courbe du programme qui suit est quelconque et le jeu des démomakers est, d’après ce que j’en ai compris, de faire la plus belle courbe possible. Je vous laisse donc le soin de la modifier à loisir, jusqu’à ce que le résultat vous satisfasse pleinement.
Vous remarquerez aussi que le dessin se fait à une lenteur extrême. Ceci est dû à deux choses : d’une part, il y beaucoup de points (plus précisément, 640*256 =
163. 840) et d’autre part, pour chaque point, on doit calculer sa couleur puis le tracer. Bien que l’opération soit relativement rapide si elle est utilisée ponctuellement, elle l’est bien moins si on la répète
163. 840 fois. De plus, l’écran sur lequel on trace est en haute résolution 16 couleurs, ce qui signifie que l’Amiga prend environ 90% du temps-machine rien que pour envoyer les données des bitplans au moniteur. Donc, je me retrouve avec l’équivalent d’un 68000 à 0,714 Mhz pour calculer mes 163.840 (je le replace une fois de plus car les gros chiffres, c’est toujours impressionnant) points.
Et voici la fin de cette article, d’un haut niveau technique. Si le manque d’inspiration continue, je crains le pire pour le mois prochain... Tous cela ne m’empêche absolument pas de vous donner la phrase du mois : "Lorsque notre fierté est en cause, notre mémoire préfère souvent céder".
NB COLOR
16
* *********************************
VSYNC: macro .LOOP_VSYNC @: move.1 and. 1 cmp. 1 bne. S endm
* la macro habituelle pour le vsync
vposr(a6),d0 $ lff00,dO *$ 100,dO .LOOP_VSYNC @
* ********************************* Début : bsr CLR_SCREEN bsr MAIN_INIT
lea clr .w clr.w clr.l
$ dff000,a6
COOR_Y * init les paramétrés de COOR_X * > la fonction CURRENT_ADR_Y *
bsr
Cycle_Courbe_Couleur
Vbl_Sync:
bsr
Cycle_Courbe_Couleur
cmp.w BPL_Y,COOR_Y bge.s SCREEN_FINISH
bsr CALCUL_FONCTION * 1 Ligne a chaque fois Clr.w TIME_BETWEEN_2_CYCLE
bra SCREEN_NOT_FINISH * Ne fais pas le vsync SCREEN_FINISH * si l'écran n'est pas vsync $ 10 * fini S C RE EN_NOT_FINISH
btst bne. S
6,$ bfe001 * teste le bouton de la souris Vbl_Sync * pour quitter le programme
bsr
moveq
rts
MAIN END 0, dO
* ****************************************************************
CALCUL_FONCTION:
move.l SCREEN,d3 add.1 CURRENT_ADR_Y,d3
Vous vous souvenez du crétin qui pestait contre le manque d’originalité dans le monde des démos ? Hé bien ce même crétin va vous présenter l’exemple type de ce qu’il ne faut absolument pas faire car cela relève des bases de la programmation : un superbe cycle de couleurs.
* d3= adr de la ligne a
* tracer
* al = table sinus
* a2 = table cos
lea Sin_Tab(pc),al
lea $ 100(al),a2
clr.w COOR_X
* d7 = nb d'octet
move.1 BPL_WIDTH~1,d7
LOOP_CALCUL_FONCTION_EACH_BYTE moveq 8-1,d6
* d6 = nb de bit
LOOP_CALCUL_FONCTION_EACH_BIT moveq 0,d0 moveq 0,dl move.w COOR_X(pc),dO move.w COOR_Y(pc),d1
calcul des différents paramétrés de la fonction
move.w d0,d2 * d2= angle du futur cosinus
lsl.w 2,d2 * x2 pour obtenir le mot du cos
* et par 2 pour un beau dessin. $ 3fe,d2* l'angle doit etre entre 0 et 512
and.w
move.w
muls
lsl.l
clr.w
swap
(a2,d2.w),d2 * d2= le cosinus
40,d2 * on le multiplie par 40
l,d2 * savante manipulation avoir
d2 * > pour la véritable valeur
d2 * de d2
* les calculs ci-dessous sont sur le meme principe que ci-dessus move.w d2,d4
opt c-
* ********************************
Execbase
=
4
custom
=
$ dff000
Forbid
=
- 132
Permit
=
- 138
Disable
=
- 120
Enable
=
- 126
openlibrary
¦ =
- 552
StartList
=
38
copllc
=
$ 80
copjmpl
=
$ 88
dmacon
=
$ 96
vposr
=
$ 04
KeyBoard
=
$ bfec01
* ********************************
BPL_X
=
640
BPL_Y
=
256
COOR_Y: ds.w 1
CURRENT ADR_Y: ds . 1 1
move.w
dl, d2
sub.w
d4,d2
lsl .w
3,d2
and.w
$ 3fe,d2
move.w
(a2,d2.w),d2
muls
32,d2
lsl.l
l,d2
clr.w
d2
swap
d2
move.w
d2,d4
* **********************************************************
* Cette routine s'occupe du cycle couleur Cycle_Courbe_Couleur:
subq.w 1, TIME__BETWEEN__2_CYCLE
tSt.w TIME_BETWEEN_2_CYCLE
bgt Fin_Cycle_Courbe_Couleur
* les calculs ci-dessous sont sur le meme principe que ci-dessus
lea ADR_CMAP_IN_CLIST,aO
addq.l 2,a0 * aO > registre couleur.
Move.w
dl, d2
lsl .w
2,d2
lea
TAB_DEGRADE_COULEUR(pc),al
and.w
$ 3fe,d2
move.w
CURRENT_POS_TAB_DEGRADE_COUIjEUR , dO
move.w
(al,d2.w) ,d2
moveq
NB__COLOR-1, d2
muls
40,d2
lsl.l
1, d2
LOOP_Cycle_Courbe Couleur:
clr.w
d2
and.w
NB_COLOR-l,dO
swap
d2
move.w
dO, dl
add.w
dl, dl
aïeuls
ci-dessous sont sur le meme principe que ci-dessus
move.w
(al,dl.w),(aO)
sub.w
d2,d0
addq.1
4, aO
move.w
d0,d2
addq.w
1, dO
lsl .w
3,d2
and.w
$ 3fe,d2
dbf
d2,LOOP_Cycle_Courbe_Couleur
move.w
(al,d2.w),d2
muls
64,d2
addq.w
1,CURRENT_POS_TAB_DEGRADE_COULEUR
lsl.l
1, d2
move.w
5,TIME_BETWEEN_2_CYCLE
clr .w
d2
Fin_Cycle_Courbe_Couleur:
swap
d2
rts
add.w
d4,d2
* arrive ici on a la couleur dans d2.
* On ne racalcule pas a chaque fois l'adresse du point pour gagner du temps d'exécution.
*
move.w COOR_X,d 0 and.w $ 0007,dO
neg.w dO
addq.w 7,d0
and. W NB_COLOR-1,d2
or.w l,d2
move.1 d3, aO
* >d0= du bit ou se trouve le
point
*
*
* -1 pour que la couleur reste
* entre 1 et NB_COLOR
* a0= adr de l'octet ou se trouve
* le point actuel
* trace le point dont la couleur est dans d2
lea SCREEN,aO
LOOP CLR SCREEN:
moveq
BPL_DEPTH-l,d4
clr. 1
(aO ) +
EACH_BPL:
dbf
dO,LOOP_CLR SCREEN
lsr .w
1, d2
rts
bcc. S
CLR_BIT_IN_THIS BPL
bset
dO,(aO)
* **************************************************************
add.l
BPL_SIZE, aO
* Cette routine
initialise les bitplans dans la copperlist
dbf
d4,EACH_BPL
INIT_CLIST:
bra. S
POINT_FINISH
lea
ADR_BPL_IN_CLIST,aO
C LR_BIT_IN_THIS
_BPL
move.1
SCREEN,dO
bclr
dO,(aO)
add.l
BPL_SIZE,aO
moveq
BPL_DEPTH-1,dl
dbf
d4,EACH_BPL
.LOOP_INIT_BPL_
IN_CLIST
POINT_FINISH
swap
dO
move.w dO,(aO) addq.l 4,a0
* continue de tracer des points dans l'octet courant
* et si ils sont tous faits on passe après.
Addq.w 1,COOR_X
dbf d6,LOOP_CALCUL_FONCTION_EACH_BIT
TIME_BETWEEN_2_CYCLE: ds.w 1
CURRENT_POS_TAB_DEGRADE_COULEUR: ds.w 1
TAB_DEGRADE_COULEUR:
de .w $ 0f00,$ 0d02,$ 0b04,$ 0906
de.w $ 0708,$ 050a,$ 030c,$ 010e,$ f
de.w $ 010e,$ 030c,$ 050a,$ 0708
de.w $ 0906,$ 0b04,$ 0d02
* **************************************************************
* Cette routine efface les bitplans CLR_SCREEN:
move.w BPL_WIDTH1BPL_Y*BPL_DEPTH 4-l,d0
dO
swap
move.w dO,(aO) addq.l 4,a0 add.l BPL_SIZE,dO
dbf rts
dl,.LOOP_INIT_BPL_IN_CLIST
* ****************************************************************
MAIN INIT:
* on
incremente les paramétrés pour faire
move.1
(execbase).w,a6
* la
ligne suivante la prochaine fois
lea
custom,a5
add. 1 BPLWIDTH,CURRENT_ADR_Y
jsr
Forbid(a6)
addq.w 1,COOR_Y
jsr
Disable(a6)
rts
move.w
$ 03e0,dmacon(a5)
bsr
INIT__CLIST
o
o
o
_X: ds.w 1
move.1
CLIST,copllc(a5)
clr.w copjmpl(a5)
de .w
$ 8583,$ 85FB,$ 8676,$ 86F7,$ 8770,$ 8806,$ 8894,$ 8927
move.w $ 8380,dmacon(a5)
de .w
$ 89BF,$ 8A5B,$ 8AFC,$ 8BAl,$ 8C4B,$ 8CF9,$ 8DAB,$ 8E62
lea
custom,a6
de .w
$ 8F1E,$ 8FDD,$ 90Al,$ 916A,$ 9236,$ 9307,$ 93DC,$ 94B6
rts
de. W
$ 9593,$ 9674,$ 975A,$ 9843,$ 9931,$ 9A23,$ 9B18,$ 9Cll
de .w
$ 9D0E,$ 9E0F,$ 9F14,$ A01D,$ Al29,$ A239,$ A34C,$ A463
* ************************************************************
de. W
$ A57E,$ A69C,$ A7BE,$ A8E3,$ AA0B,$ AB36,$ AC65,$ AD97
MAIN_END:
de .w
$ AECD,$ B005,$ B141,$ B27F,$ B3Cl,$ B505,$ B64C,$ B797
move.
1 (execbase).w,a6
de .w
$ B8E4,$ BA33,$ BB86,$ BCDB,$ BE32,$ BF8D,$ C0E9,$ 0248
lea
custom,a5
de .w
$ C3AA,$ C50E,$ 0674,$ C7DC,$ 0946,$ CAB3,$ CC22,$ CD92
move.
1 GfxName,al *
de .w
$ CF05,$ D079,$ D1EF,$ D368,$ D4El,$ D65D,$ D7DA,$ D958
moveq 0,d0 * >-remet l'ancienne
de .w
$ DAD8,$ DC5A,$ DDDD,$ DF61,$ E0E7,$ E26D,$ E3F5,$ E57E
jsr
OpenLibrary(a6) * > copper list
de .w
$ E708,$ E893,$ EA1E,$ EBAB,$ ED38,$ EEC7,$ F055,$ F1E5
move.
1 d0,a4 * >
de .w
$ F375,$ F505,$ F696,$ F827,$ F9B9,$ FB4A,$ FCDC,$ FE6E
move.
1 StartList(a4),copllc(a5)
de .w
$ 0000,$ 0192,$ 0324,$ 04B6,$ 0647,$ 07D9,$ 096A,$ 0AFB
move.
W dO,copjmpl(a5)
de .w
$ 0C8B,$ 0E1B,$ 0FAB,$ 1139,$ 1208,$ 1455,$ 15E2,$ 176D
move.w $ 83e0,dmacon(a5)
de .w
$ 18F8,$ 1A82,$ 1C0B,$ 1D93,$ 1F19,$ 209F,$ 2223,$ 23A6
jsr
Enable(a6)
de .w
$ 2528,$ 26A8,$ 2826,$ 29A3,$ 2B1F,$ 2098,$ 2E11,$ 2F87
jsr
Permit(a6)
de .w
$ 3 OFB,$ 326E,$ 33DE,$ 354D,$ 36BA,$ 3824,$ 3980,$ 3AF2
lea
custom,a6
de .w
$ 3056,$ 3DB8,$ 3F17,$ 4073,$ 41CE,$ 4325,$ 447A,$ 45CD
rts
de .w
$ 4710,$ 4869,$ 49B4,$ 4AFB,$ 4C3F,$ 4D81,$ 4EBF,$ 4FFB
GfxName de .b
"graphies.library",0
dc. w
$ 5133,$ 5269,$ 539B,$ 54CA,$ 55F5,$ 57lD,$ 5842, $ 5964
even
de .w
$ 5A82,$ 5B9D,$ 5CB4,$ 5DC7,$ 5ED7,$ 5FE3,$ 60EC,$ 61F1
de .w
$ 62F2,$ 63EF,$ 64E8,$ 65DD,$ 66CF,$ 67BD,$ 68A6,$ 6980
* ************************************************************
de .w
$ 6A6D,$ 6B4A,$ 6024,$ 6CF9,$ 6DCA,$ 6E96,$ 6F5F,$ 7023
* avis aux fainéants :
de .w
$ 70E2,$ 719E,$ 7255,$ 7307,$ 73B5,$ 745F,$ 7504,$ 75A5
* a remplacer par un include avec le programme
de .w
$ 7641,$ 76D9,$ 7760,$ 77FA,$ 7884,$ 7909,$ 798A,$ 7A05
* pour init
les sinus en gfa paru précédemment.
De .w
$ 7A7D,$ 7AEF,$ 7B5D,$ 7BC5,$ 7029,$ 7089,$ 7CE3,$ 7D39
sin_tab de .w
$ 0000,$ 0192,$ 0324,$ 04B6,$ 0647,$ 07D9,$ 096A,$ 0AFB
de .w
$ 7D8A,$ 7DD6,$ 7E1D,$ 7E5F,$ 7E9D,$ 7ED5,$ 7F09,$ 7F38
de .w
$ 0C8B,$ 0ElB,$ 0FAB,$ 1139,$ 12C8,$ 1455,$ 15E2,$ 176D
de .w
$ 7F62,$ 7F87,$ 7FA7,$ 7FC2,$ 7FD8,$ 7FE9,$ 7FF6,$ 7FFD
de .w
$ 18F8,$ 1A82,$ 1C0B,$ 1D93,$ 1F19,$ 2 09F,$ 2223,$ 23A6
de .w
$ 2528,$ 26A8,$ 2826,$ 29A3,$ 2B1F,$ 2C98,$ 2Ell,$ 2F87
* ************
de .w
$ 30FB,$ 326E,$ 33DE,$ 354D,$ 36BA,$ 3824,$ 3980,$ 3AF2
* pour que la
copper list et les bitplans soit en chip ram.
De .w
$ 3056,$ 3DB8,$ 3F17,$ 4073,$ 41CE,$ 4325,$ 447A,$ 45CD
section copper_list,DATA_C
de .w
$ 4710,$ 4869,$ 49B4,$ 4AFB,$ 4C3F,$ 4D81,$ 4EBF,$ 4FFB
de .w
$ 5133,$ 5269,$ 539B,$ 54CA,$ 55F5,$ 571D,$ 5842,$ 5964
CLIST: dc.w
$ 008E,$ 2b81 *
de .w
$ 5A82,$ 5B9D,$ 5CB4,$ 5DC7,$ 5ED7,$ 5FE3,$ 60EC,$ 6lFl
de .w
$ 0090,$ 2bcl * >init un écran de
de .w
$ 62F2,$ 63EF,$ 64E8,$ 65DD,$ 66CF,$ 67BD,$ 68A6,$ 6980
640*256
de .w
$ 6A6D,$ 6B4A,$ 6024,$ 6CF9,$ 6DCA,$ 6E96,$ 6F5F,$ 7023
de .w
$ 0092,$ 0038 * >
de .w
$ 70E2,$ 719E,$ 7255,$ 7307,$ 73B5,$ 745F,$ 7504,$ 75A5
de .w
$ 0094,$ 00d0 *
de. W
$ 7641,$ 76D9,$ 7760,$ 77FA,$ 7884,$ 7909,$ 798A,$ 7A05
de .w
$ 0108,$ 0000,$ 010A,$ 0000
de .w
$ 7A7D,$ 7AEF,$ 7B5D,$ 7BC5,$ 7029,$ 7089,$ 7CE3,$ 7D39
de .w
$ 0100,$ 0200,$ 0102,$ 0000,$ 0104,$ 0000
de .w
$ 7D8A,$ 7DD6,$ 7E1D,$ 7E5F,$ 7E9D,$ 7ED5,$ 7F09,$ 7F38
de .w
$ 7F62,$ 7F87,$ 7FA7,$ 7FC2,$ 7FD8,$ 7FE9,$ 7FF6,$ 7FFD
ADR_CMAP_IN_CLIST:
de .w
$ 7fff,$ 7FFD,$ 7FF6,$ 7FE9,$ 7FD8,$ 7FC2,$ 7FA7,$ 7F87
de .w
$ 0180,$ 0000,$ 0182,$ 0000,$ 0184,$ 0000,$ 0186,$ 0000
de .w
$ 7F62,$ 7F38,$ 7F09,$ 7ED5,$ 7E9D,$ 7E5F,$ 7E1D,$ 7DD6
de .w
$ 0188,$ 0000,$ 018a,$ 0000,$ 018c,$ 0000,$ 018e,$ 0000
de .w
$ 7D8A,$ 7D39,$ 7CE3,$ 7089,$ 7029,$ 7BC5,$ 7B5D,$ 7AEF
de .w
$ 0190,$ 0000,$ 0192,$ 0000,$ 0194,$ 0000,$ 0196,$ 0000
de .w
$ 7A7D,$ 7A05,$ 798A,$ 7909,$ 7884,$ 77FA,$ 7760,$ 76D9
de .w
$ 0198,$ 0000,$ 019a,$ 0000,$ 019c,$ 0000,$ 019e,$ 0000
de .w
$ 7641,$ 75A5,$ 7504,$ 745F,$ 73B5,$ 7307,$ 7255,$ 719E
de .w
$ 70E2,$ 7023,$ 6F5F,$ 6E96,$ 6DCA,$ 6CF9,$ 6024,$ 6B4A
de .w
$ 0180,$ 0005
de .w
$ 6A6D,$ 6980,$ 68A6,$ 67BD,$ 66CF,$ 65DD,$ 64E8,$ 63EF
de .w
$ lb0f,$ fffe,$ 0100, (8 +BPL_DEPTH)*$ 1000+$ 200
de .w
$ 62F2,$ 61F1,$ 60EC,$ 5FE3,$ 5ED7,$ 5DC7,$ 5CB4,$ 5B9D
de .w
$ 00E0
de .w
$ 5A82,$ 5964,$ 5842,$ 571D,$ 55F5,$ 54CA,$ 539B,$ 5269
ADR_BPL_IN__CL IST :
de .w
$ 5133,$ 4FFB,$ 4EBF,$ 4D81,$ 4C3F,$ 4AFB,$ 49B4,$ 4869
de .w
$ 0
de .w
$ 4710,$ 45CD,$ 447A,$ 4325,$ 4lCE,$ 4073,$ 3F17,$ 3DB8
de .w
$ 00E2,$ 0
de .w
$ 3056,$ 3AF2,$ 3980,$ 3824,$ 36BA,$ 354D,$ 33DE,$ 326E
de .w
$ 00E4
de .w
$ 30FB,$ 2F87,$ 2E11,$ 2098,$ 2B1F,$ 29A3,$ 2826,$ 26A8
de .w
$ 0
de .w
$ 2528,$ 23A6,$ 2223,$ 209F,$ 1F19,$ 1D93,$ 1C0B,$ 1A82
de .w
$ 00E6,$ 0
de .w
$ 18F8,$ 176D,$ 15E2,$ 1455,$ 1208,$ 1139,$ 0FAB,$ 0E1B
de .w
$ 00E8
de .w
$ 0C8B,$ 0AFB,$ 096A,$ 07D9,$ 0647,$ 04B6,$ 0324,$ 0192
de .w
$ 0
de .w
$ 0000,$ FE6E,$ FCDC,$ FB4A,$ F9B9,$ F827,$ F696,$ F505
de .w
$ 0 0EA,$ 0
de .w
$ F375,$ F1E5,$ F055,$ EEC7,$ ED38,$ EBAB,$ EAlE,$ E893
de .w
$ 00EC
de .w
$ E7 08,$ E57E,$ E3F5,$ E26D,$ E0E7,$ DF61,$ DDDD,$ DC5A
de .w
$ 0
de .w
$ DAD8,$ D958,$ D7DA,$ D65D,$ D4El,$ D368,$ DlEF,$ D079
de .w
$ 00EE,$ 0
de .w
$ CF05,$ CD92,$ 0022,$ CAB3,$ 0946,$ C7DC,$ 0674,$ C50E
dc. w
$ 00F0
de .w
$ C3AA,$ 0248,$ C0E9,$ BF8D,$ BE32,$ BCDB,$ BB86,$ BA33
dc. w
$ 0
de .w
$ B8E4,$ B797,$ B64C,$ B505,$ B3C1,$ B27F,$ Bl41,$ B005
dc. w
$ 00F2,$ 0
de .w
$ AECD,$ AD97,$ AC65,$ AB36,$ AA0B,$ A8E3,$ A7BE,$ A69C
de .w
$ A57E,$ A463,$ A34C,$ A239,$ Al29,$ A01D,$ 9F14,$ 9E0F
de. 1
$ fffffffe * montre la fin de la list
de .w
$ 9D0E,$ 9011,$ 9B18,$ 9A23,$ 9931,$ 9843,$ 975A,$ 9674
de .w
$ 9593,$ 94B6,$ 93DC,$ 9307,$ 9236,$ 916A,$ 90Al,$ 8FDD
* ************************************************************
de .w
$ 8F1E,$ 8E62,$ 8DAB,$ 8CF9,$ 8C4B,$ 8BAl,$ 8AFC,$ 8A5B
section screen,BSS_C
de .w
$ 89BF,$ 8927,$ 8894,$ 8806,$ 8770,$ 86F7,$ 8676,$ 85FB
de .w
$ 8583,$ 8511,$ 84A3,$ 843B,$ 83D7,$ 8377,$ 831D,$ 8207
SCREEN: ds. 1
BPL_WIDTH*BPL_Y*BPL_DEPTH 4
de .w
$ 8276,$ 822A,$ 8lE3,$ 8lAl,$ 8163,$ 812B,$ 80F7,$ 8008
de .w
$ 809E, $ 8079, $ 8059,$ 803E,$ 8028,$ 8017,$ 800A,$ 8003
END
de .w
$ 8000,$ 8003,$ 800A,$ 8017,$ 8028,$ 803E,$ 8059,$ 8079
de. W
$ 809E,$ 80C8,$ 80F7,$ 812B,$ 8163,$ 81A1,$ 81E3,$ 822A
de .w
$ 8276,$ 8207,$ 831D,$ 8377,$ 83D7,$ 843B,$ 84A3,$ 8511
Par Jérôme Etienne Iji]
Bienvenue dans cette nouvelle rubrique ! Je vais vous proposer ici quelques routines utilitaires en assembleur qui n’auront d’autre but que de vous faciliter la vie.
R0UT1NETTES
Pour commencer, voici un moyen vraiment légal (j’insiste !) Pour empêcher les mouvements de la souris de parvenir au Workbench, lorsque l’on monopolise l’affichage. Allons bon, voila que je me coupe mes effets, alors que j’avais préparé une belle introduction. Bon, c’est pas grave, la voici quand même.
LA BELLE INTRO
Que c’est bien de modifier les listes Copper du système... Comme l’on peut faire de jolies choses dans son propre affichage... On bouge la souris, on clique ici et là, on tape de belles commandes au clavier... Tout semble se passer pour le mieux. Puis on sort de son beau programme, et on constate, ô divine surprise, que toutes les actions de la souris on été enregistrées dans le Workbench ! En sélectionnant telle icône de son programme, on a fait démarrer un utilitaire dans la fenêtre Workbench. Un peu (NDLR : beaucoup) de malchance et on formate son disque dur !
Pourtant, il existe des moyens tout-à-fait légaux pour empêcher les mouvements de la souris et les touches du clavier d’arriver au Workbench. Des moyens vraiment légaux, j’entends, sans toucher aux CIAs, sans poker dans les vecteurs d’interruption, sans même interdire le multitâche.
Le nom magique est "input.device". Sous ce nom est regroupé toute la gestion des entrées de l’Amiga : souris, clavier, mais aussi joystick, disquette insérée ou enlevée, etc.
La routinette d’aujourd’hui se place au beau milieu de l’input.device et joue le rôle de filtre : elles ne laisse pas passer la souris ou le clavier. A part ça, l’Amiga fonctionne tout-à-fait normalement : vous pouvez même faire des accès disques, lancer des tâches secondaires...
LE BEAU PROGRAMME
Comme toutes mes futures routinettes, celle
d’aujourd’hui
est
totalement relogeable, ce qui vous permettra par exemple de l’insérer dans un programme Basic (AMOS bien sûr, mais aussi Amiga et même GFA !). L’assemblage a été réalisé avec le Devpac.
La routinette offre deux points d’entrée :
• Nev_Start : à appeler en début de programme, cette routine ouvre l’input.device et intercepte les événements clavier et souris.
• Nev_Stop : à appeler avant de sortir du programme, pour remettre les choses en place.
Attention, avant de faire un accès disque, il est sage de rebrancher le clavier et la souris : n’oubliez pas qu’un requester de l’AmigaDOS peut apparaître. Dans ce cas, il vaut mieux pouvoir bouger la souris... Voici un tout petit exemple d’utilisation de cette première routinette, dans lequel on se contente de modifier très rapidement la couleur zéro en testant le bouton gauche de la souris directement dans les circuits, en toute quiétude.
LA BELLE CONCLUSION
Bon, voilà pour aujourd’hui. Je ne peux pas vous dire ce que je vais vous trouver pour le mois prochain vu que je ne le sais pas et que je ne le saurai que la veille d’envoyer mon article à Stéphane... C’est ça l’aventure, la vraie.
* ROUTINETTE numéro 1
* A'pu souris,
* Par François
a'pu clavier. In Lionet. Paru dans
Engli
l'A.:
io_command
equ
$ lc
io_data
equ
$ 28
Lof_io
equ
$ 30
AddHandler
equ
9
RemHandler
equ
10
Lof_msg
equ
$ 20
ln_type
equ
$ 08
ln_pri
equ
$ 09
ln_name
equ
$ 0a
is_data
equ
$ 0e
is_code
equ
$ 12
Lof_is
equ
$ 16
Dolo
equ
- 456
FindTask
equ
- 294
OpenDevice
equ
- 444
CloseDevice
equ
- 450
AddPort
equ
- 354
RemPort
equ
- 360
Ie_NextEvent
equ
0
Ie_Class
equ
4
Ie_SubClass
equ
5
Ie_Code
equ
6
Ie_Qualifier
equ
8
le EventAddress
equ
10
le X
equ
10
le Y
equ
12
IECLASS RAWKEY
EQU
$ 01
IECLASS RAWMOUSE
EQU
$ 02
- ---Pitit
exemple
Exemple :
bsr
Nev Start ;
Enlève le clavier et la souris
; Boucle de test
. Loop move. W
dO,$ dff180
Changement de couleur
addq.w
1, dO
btst
6,$ BFE001
Test du bouton souris
bne. S
. Loop
bsr
Nev Stop ;
On remet tout !
Moveq
0, dO
Basta, finito !
Rts
- -------- Point d'entrée 1: démarrage du filtre
Nev_Start:
movem. 1
dO-d7 aO-a6,-(sp)
move.1
$ 4 .w, a6
lea
Nev_msg(pc),a2 ;
Adresse des structures
lea
Nev_io(pc),a3
lea
Nev int(pc),a4
sub. 1
al, al
Fabrication dü port
jsr
FindTask(a6)
move.1
a2, al
move.1
dO,$ 10(al)
jsr
AddPort(a6)
lea
Nev name(pc),aO ;
Ouverture de 1'input.device
move.1
a3, al
moveq
0, dO
moveq
0, dl
Dsr
move.1
OpenDevice(a6) a2,14 (a3)
Branchement de la routine d'interruption lea Nev_Handler(pc),aO
move.l aO,is_code(a4) is_data(a4)
100,ln_pri(a4) a3, al
a4,io_data(al)
AddHandler,io_command(al) DoIo(a6)
Associe le port et le device
Voila, c'est tout.
Clr.l move.b move.1 move.1 move.w jsr
movem. 1 rts
(sp)+,dO-d7 aO-a6
.----------------------Point d'entrée 2: arrêt du filtre.
Nev_Stop:
movem.1 dO-d7 aO-a6,-(sp) move.l $ 4.w,a6 lea Nev_msg(pc),a2 lea Nev_io(pc),a3 lea Nev_int(pc),a4 move.1 a3,al move.l a4,io_data(al) move. W RemHandler, io_coinmand ( al ) move.l $ 4.w,a6 jsr DoIo(a6)
Adresse des structures
Enleve l'interruption
move.1 $ 4.w,a6 ; Ferme 1'input.device
jsr CloseDevice(a6) move.l a2,al jsr RemPort(a6) movem.1 (sp)+,d0-d7 a0-a6 rts
Ferme le port
Routine de filtre en interruption
Nev_Handler:
move.1
a0,d0
move.1
a0,d2
moveq
0,d3
. Loop move. B
le Class(aO),dl
; Boucle d'exploration
cmp .b
IECLASS_RAWMOUSE,dl
; Mouvement souris?
Beq. S
.trash
; Oui! A la poubelle!
Cmp.b
IECLASS_RAWKEY,dl
; Touche clavier?
Beq. S
.trash
; Oui! A la poubelle!
; On garde l'événement.
Move.1
d2,d3
move.1
(aO),d2
. Next move. 1
d2,a0
; Un autre à voir?
Bne. S
. Loop
rts
; Non! C'est fini.
; Balance l'evenement à la poubelle.
.trash tst.l
d3
; Un événement avant?
Beq. S
. Skip
move.1
d3, al
; Oui, il faut changer
move.1
(aO),d2
; les pointeurs.
Move.1
d2,(al)
bra. S
.next
Va voir les suivants..
. Skip move. 1
(aO),d0
Pas d'événement avant.
Move.1
dO, aO
On peut voir le suivant.
Bne. S
. Loop
rts
; Y'en a plus: on sort!
* __
- -------- Toute petite
tchote zone de data.
Nev_io
ds.b Lof_io ; Structure io
Nev_msg
ds.b Lof_msg ; Structure message-port
Nev_int
ds.b Lof_is ; Structure interrupt
Nev_name
dc. b "input.device1 even
",0
END
TRANSFORMEUR
WÊmmmm
Qui n’a pas rêvé de se faire de beaux gadgets ou de superbes images agrémentant la présentation d’un soft que l’on sait en son fort intérieur être le précurseur d’une nouvelle génération de logiciels ?
Correspondant (voir ’case ID_BODY’). Quand ce chunk a été trouvé, il importe de décompacter les données si c’est nécessaire, c’est ce que fait la fonction ’transfertO’.
- CMAP contient les couleurs de l’image, à noter pour pouvoir restituer l’image dans sa pureté primitive... Là encore, voyez la partie ’case ID_CMAP
Ne désespérez plus, voici l’outil ultime, j’ai nommé le Transformeur. La démarche est la suivante : vous prenez votre logiciel de DAO préféré, vous faîtes le dessin de vos rêves, puis, grâce ce programme, vous transformez l’image (ou la brosse) en une suite de nombres au format ASCII, ce qui constitue (comme chacun sait) un fichier source que vous pouvez insérer ou linker... Ah que ouais !
IMAGES IFF
Il est nécessaire de sauvegarder votre dessin au format IFF, ce que font les 9 10èmes des utilitaires de dessin (sinon, prenez-en un autre !). Les images IFF sont codées sous une forme standard qui permet le chargement par d’autres logiciels (mon mari).
Pour mieux saisir le fonctionnement, un bref rappel du format IFF n’est sans doute pas inutile ; suivez sur le listing, à la fonction ’analyse()’.
Chaque image IFF comporte une suite de ’chunks’ dont l’ordre n’est pas imposé. Un chunk peut être représenté par une structure C :
struct Chunk ULONG cklD;
LONG ckSize;
* UBYTE ckData[CkSize]; *
;
où cklD est un mot long servant d’identificateur au chunk et dont la valeur est exprimée sous forme ASCII (FORM, BMHD, CMAP, BODY, etc...), où ckSize représente la taille du chunk en octets et où ckData (qui suit directement le chunk) contient les octets de données (de longueur variable, donc).
Si le fichier IFF est uniquement constitué d’une image, son premier chunk doit avoir pour identificateur ’FORM’. Les autres identificateurs possibles (CAT, PROP, LIST) sont donc rejetés, car ils indiquent un mélange de divers types, par exemple texte et dessin.
Les données de ce premier chunk sont elles-mêmes formées d’autres chunks. Si le fichier étudié est une image, le second identificateur qui se présente doit être de type ILBM. Les autres identificateurs (FTXT, SMUS, 8SVX) sont rejetés car ils indiquent respectivement un fichier texte, musique ou instrument.
On arrive alors aux chunks utilisables : BMHD, BODY, CMAP (il y en a d’autres, mais seuls ces trois là nous intéressent ici) :
- BMHD contient les caractéristiques de l’image : largeur, hauteur, nombre de bitplanes, compression, etc. (voir ’case ID_BMHD’ dans le listing).
- BODY contient les bitplanes eux-mêmes, la valeur de chaque bit déterminant la couleur du pixel
Ces 3 chunks peuvent être trouvés dans n’importe quel ordre, ce qui explique l’étude du fichier sur toute sa longueur et un test final pour savoir si les données nécessaires ont été trouvées. Il ne reste plus alors qu’à sortir les valeurs des bitplanes en fichier source.
COMMENT CA MARCHE ?
Le Transformeur vous demande le type de source que vous désirez créer : ’C’ si vous programmez en C et ’A’ si vous programmez en assembleur (logique !). Il vous demande alors le nom du fichier à charger : image ou brosse. Il travaille quelque temps, affiche les couleurs de l’image en hexadécimal, vous demande le nom du source qu’il va créer et ça baigne.
Ah, j’oubliais : ce programme utilise l’arp.library, qui doit figurer dans le tiroir LIBS: de votre disquette système (NDLR : l’arp.library est fournie sur la
disquette de ce numéro).
Les sources produits en C sont de type "USHORT data[]". Les bitplanes sont séparés par une remarque qui rappelle le nombre de lignes et de colonnes. Un programme d’exemple est fourni sur la manière d’utiliser ces sources.
Les sources produits en assembleur sont aussi en hexadécimal, de type "dc.w" avec une séparation des bitplanes comme ci-dessus. Le programme d’exemple pourra être adapté de celui qui est fourni en C.
z***************************************************
* Convertit une image IFF en SOURCE ASCII C ou ASM *
* *
* par D.GENOT sous LATTICE SAS v5.10 : *
* options de compil : -L *
* **************************************************
include stdio.h>
include string.h>
include exec types.h>
include exec mémory.h>
include libraries dos.h>
include libraries dosextens.h> include intuition intuition.h> include graphics gfx.h>
include graphics view.h>
pragma libcall ArpBase FileRequest 126 801
********** déclarations ******************
LONG FileRequest();
LONG input(UBYTE *); void output_C(); void output_A();
Struct FileLock *Lock(), *clef=NULL; struct FilelnfoBlock bloc; short Examine(), ExNext();
void UnLock(), cleanexitO, load_fichier(), analyseO, void lib_mem(), transfert(UBYTE *);
********* variables **************** short res;
ULONG filesize, planes_long, planel;
UBYTE fdir, prof;
UWORD haut;
char categ=' ';
LONG resul;
int dummy=0, hdle, ncoul;
ULONG nom,mode, taille; int vu, long_forme;
SHORT bpr; * Bytes Per Row = par rangée *
APTR *filemem=NULL;
UBYTE *pteurb=NULL, *planeptr=NULL;
ULONG *pteurl=NULL;
char fname[80], dirname[12 0], nom_complet[200];
APTR ArpBase=NULL;
**********************************************************
* définitions diverses utilisées pour le maniement des *
* images IFF (simples...) *
* *********************************************************
define makeid(a,b,c,d) ((a 24)|(b 16)I(c 8)|d)
define
ID
CAT
MAKEID(

)
define
ID
FTXT
MAKEID(
)
define
ID
PROP
MAKEID(
t
)
define
ID
8SVX
MAKEID(
)
define
ID
SMUS
MAKEID(
)
define
ID
LIST
MAKEID(
)
define
ID
FORM
MAKEID(
t
)
define
ID
ILBM
MAKEID(
'I'
,
'L'
,
'B'
,
'M'
)
define
ID
BMHD
MAKEID(
)
define
ID
CMAP
MAKEID(
)
define
ID
GRAB
MAKEID(
)
define
ID
DEST
MAKEID(
Ê
)
define
ID
CAMG
MAKEID(
1
)
define
ID
n
o
PQ
MAKEID(
1
)
j********** structures *****************
struct Chunk
LONG cklD;
LONG ckSize;
} ;
struct Chunk *chk=NULL;
define isodd(a) ((a)&l) * 1 si impair *
define wa(size) ((size)+isodd(size)) * complète au mot près * define chsize(datasize) (wa(datasize) +8) * taille du chunk *
struct FileRequester
UBYTE *fr_titre; *
texte fenetre
*
UBYTE *fr_file;
*
filename
*
UBYTE *fr_dir;
*
dirname
*
struct Window *fr_window;
*
Win voulue ou
NULL *
UBYTE fr_flags;
*
f lags
*
UBYTE fr_reservedl;
*
mettre à 0
*
APTR fr_fonction;
*
UserFunction
*
LONG fr_reserved2;
*
occupe !
*
} Freq =
" Mon Requester ",fname,dirname,NULL,NULL,NULL,NULL,NULL>;
struct BMHD
UWORD bmhd_w;
UWORD bmhd_h; * largeur et hauteur *
UWORD bmhd_x;
UWORD bmhd_y; * position de l'image *
UBYTE bmhd nplanes;
UBYTE bmhd_ masking;
UBYTE bmhd_compress;
UBYTE bmhd_padl;
UWORD bmhd_transpcolor;
UBYTE bmhd_xaspect;
UBYTE bmhd_yaspect;
UWORD bmhd_pagew;
UWORD bmhd_pageh;
) *bmhd=NULL;
***** ROUTINES ********
LONG input(UBYTE *txt)

régister LONG réponse;
Freq.fr_titre=txt;
ArpBase=(APTR)OpenLibrary("arp.library",0);
if (ArpBase==NULL)

printf("Il me faut la 'ARP.LIBRARY' ..."); exit(FALSE);
}
reponse=FileRequest(&Freq);
CloseLibrary(ArpBase);
if(réponse)
strmfp(nom_complet,dirname,fname);
retum(réponse) ;
}
void cleanexit(
)
UnLock(clef);
Close(hdle);
FreeMem(planeptr,planes_long); FreeMem(filemem,filesize);

if(clef) if(hdle) if(planeptr) if ( filemem) exit(RETURN_OK)
void load_fichier()

filemem=(APTR *)Al1ocMem(filesize,MEMF CLEAR|MEMF__PUBLIC); if(filemem==NULL)

printf(" n Impossible de réserver la mémoire ... n"); cleanexit();
}
hdle=Open(nom_complet,MODE_OLDFILE); * lecture *
if(hdle==NULL)

printf(" n Impossible d'ouvrir ce &!!§ ù? Fichier ... n" cleanexit();
}
else

Read(hdle,filemem,filesize);
Close(hdle); hdle=0;
printf(" n Fichier lu ... n");
}
void analyse()

BOOL filbm=FALSE, fbmhd=FALSE, fbody=FALSE;
SHORT var;
UWORD couleur; int ncoul;
UBYTE re,gr,bl; * red ,green ,blue *
chk=(struct Chunk *)filemem; switch (chk->ckID)

case ID_CAT: case ID_PR0P: case ID_LIST:
printf(" n C'est un fichier IFF composé n"); break; case ID_FORM: filbm=TRUE; break; default:
printf(" n Ce n'est pas un fichier IFF ... n"); break;
}
if( Jfilbm )
cleanexit();
taille=chk->ckSize;
long_forme=taille;
pteurl=(ULONG *)chk;
pteurl++;
pteurl++;
chk=(struct Chunk *)pteurl; vu=8 ;
switch (chk->ckID)

case ID_FTXT:
printf(" n C'est un TEXTE ... n"); break; case ID_SMUS:
printf(" n C'est de la MUSIQUE ... n");
break; case ID_8SVX:
printf(" n C'est un INSTRUMENT musical ... n"); break; case ID_ILBM:
filbm=TRUE; break; default:
printf(" n Ce n'est pas un format ILBM n")? Break;
}
if( Ifilbm )
cleanexit();
vu+=4;
pteurl=(ULONG *)chk; pteurl++;
chk=(struct Chunk *)pteurl; do

taille=chsize(chk->ckSize); * taille du CHUNK *
vu+=taille;
switch(chk->ckID)

case ID_BMHD:
fbmhd=TRUE;
pteurl=(ULONG *)chk;
pteurl++;
pteurl++;
bmhd=(struct BMHD *)pteurl;
prof = bmhd->bmhd_nplanes; haut = bmhd->bmhd_h;
bpr=bmhd->bmhd_w;
var=bpr%16;
var=16-var;
bpr+=var; * multiple de 16 *
bpr =8; * octets rangée *
break; case ID_B0DY:
if ( fbmhd )

* taille datas : chk->ckSize *
pteurl=(ULONG *)chk;
pteurl++;
pteurl++;
fbody=TRUE; transfert (UBYTE *)pteurl );
}
else
fbody=FALSE; break; case IDCMAP:
pteurl=(ULONG *)chk;
pteurl++;
pteurl++;
pteurb=(UBYTE *)pteurl; ncoul=(int)( (chk->ckSize) 3);
printf(" n %d COULEUR(S) = '$ RGB' n ",ncoul);
while(ncoul--)

re=*pteurb++;
gr=*pteurb++;
bl=*pteurb++;
couleur=((UWORD)(re)*0x100+(UWORD)(gr)*0x10+(UWORD)bl) 0xl0; print f("$ %3X ",couleur);
}
break; default: break;
pteurb=(UBYTE *)chk+taille; chk=(struct Chunk *)pteurb;
}while( vu long_forme );
if( !fbody )
cleanexit();
printf(" n Analyse terminée ... n");
void transfert(dptr)
UBYTE *dptr;

régister UBYTE pixel, *pixelptr;
register SHORT plane,row,nbytes,count;
planes_long=bpr * bmhd->bmhd_h; * 1 bitplane * planel=planes_long; * long d'un bitplane *
planes_long*=prof; * 4 bitplanes ou plus ...*
planeptr=(UBYTE *)AllocMem(planes_long,MEMF_CLEAR|MEMF_PUBLIC); if(planeptr==NULL)

printf(" nImpossible de réserver la mémoire des datas... n"); cleanexit();
if(bmhd->bmhd_compress==l) * compression habituelle *

for(row=0;rowcbmhd->bmhd_h;row++)

for(plane=0;planecbmhd->bmhd_nplanes;plane++)

pixelptr=planeptr+(plane*planel)+(row*bpr); nbytes=bpr; while(nbytes > 0)

count=(char)*dptr++;
if(count >= 0) * copier n+1 littéral *

count++; nbytes-=count; while(count )
* pixelptr++=*dptr++;
else if(count >= -127) * répéter -n+1 fois *

count=1-count; nbytes-=count; pixel=*dptr++; while(count--)
* pixelptr++=pixel;
}
}
else * pas de compression ( ou inconnue ! ! ) *

for(row=0;row bmhd->bmhd_h;row++)

for(plane=0;plane bmhd->bmhd_nplanes;plane++)

pixelptr=planeptr+(plane*planel)+(row*bpr);
nbytes=bpr;
while(nbytes )
* pixelptr++=*dptr++;
}
vo id 1ib_mem()

if(hdle)
Close(hdle); hdle=0;
if ( filemem)
FreeMem(f ilemem, filesize) ; f ilemem=0;
void output_C()

register SHORT plane,row,nword,wpr;
UWORD *wordptr;
FILE *fp,*fopen(); char tpn[80];
SHORT cpt; int i;
fp=fopen(nom_complet,"w"); * écriture *
if(fp==NULL)

printf(" n Impossible d'ouvrir ce &!!§ ù? Fichier ... n"); cleanexit();
wpr=bpr 2;
for(plane=0;plane prof;plane++)

fputc(' 2',fp); * ligne suivante *
sprintf(tpn," * bitplane No %d : %d lignes de %d mots * ", plane*1,haut,wpr); fwrite(tpn,1,(UBYTE)strlen(tpn),fp); fpute( ' 2',fp); * ligne suivante *
cpt=0;
sprintf (tpn, " ");
fwrite(tpn,1,5,fp); * tabulation *
for(row= 0;rowchaut;row++)

wordptr=(UWORD *)( planeptr+(plane*planel)+(row*bpr) ); nword=wpr;
while(nword--)

sprintf(tpn,"0x%4X,",*wordptr); for(i=0;i =3;i++)

if( tpn[2+i] == • • ) tpn[2+i] =7 0 ';
}
fwrite(tpn,1,(UBYTE)strlen(tpn),fp);
wordptr++;
cpt++;
if( cpt==8 )

fputc(' 2',fp); * ligne suivante * sprintf(tpn," ");
fwrite(tpn,1,5,fp); * tabulation *
cpt=0;
}
} *fin de la rangée *
} * fin du bitplane *
}
fclose(fp);
void output_A()

register SHORT plane,row,nword,wpr;
UWORD *wordptr;
FILE *fp,*fopen(); char tpn[80];
SHORT cpt ; int i;
fp=fopen(nom_complet,"w"); * écriture *
if(fp==NULL)

printf(" n Impossible d'ouvrir ce &!!§ ù? Fichier ...An"); cleanexit();
wpr=bpr 2;
for(plane=0 ;plane prof;plane++)

fputc( 2fp); * ligne suivante *
sprintf(tpn," ; bitplane No %d : %d. Lignes de %d mots ", plane*1,haut,wpr); fwrite(tpn,1,(UBYTE)strlen(tpn),fp); fputc(' 2',fp); * ligne suivante *
cpt=0;
sprintf(tpn," DC.W ");
fwrite(tpn,1,9,fp); * tabulation *
for(row=0;rowchaut;row++)

wordptr=(UWORD *)( planeptr*(plane*planel)+(row*bpr) ); nword=wpr;
while(nword )

sprintf(tpn,"$ %4X",*wordptr); for(i=0;i =3;i++)

if( tpn[l+i] == ' ' ) tpn[1+i]='0';
}
fwrite(tpn,1,(UBYTE)strlen(tpn),fp);
wordptr++;
cpt++;
if( cpt==8 )

fputc(' 2', fp); * ligne suivante *
if( (row != haut-1)|I(nword != 0) )

sprintf(tpn," DC.W ");
fwrite(tpn,1,9,fp); * tabulation *
cpt=0;
}
else

if( (row != haut-1)II(nword != 0) )
fputc(',',fp); * + la virgule *
}
} *fin de la rangée *
} * fin du bitplane *
}
fclose(fp);
*************** ROUTINE PRINCIPALE **********
void main()

do

printf(" n Type de SOURCE voulu :"); printf(" n 'C' pour LATTICE "); printf(" n 'A' pour DEVPAC "); categ=fgetchar(); if(categ == 'a') categ='A'; if(categ == 'c') categ='C';
)while( (categ != 'C')&&(categ != 'A') );
resul=input("NOM de 1'IMAGE IFF à LIRE"); if( resul == 0) cleanexit();
printf(" n CHEMIN : '%&' ; FICHIER : '%s' n",
dirname,fname) ;
clef=Lock(nom complet,ACCESS_READ); if(clef==NULL)

printf(" n Accès lecture impossible ; le chemin existe ? n"); cleanexit();
res=Examine(clef,&bloc);
i f(bloc.f ib_DirEntryType > 0)

printf(" n C'est un répertoire ... n n"); cleanexit();
}
filesize=bloc.fib_Size;
if(filesize != 0)

load_fichier() ; analyse();
lib__mem(); * libère une partie de la mémoire et le handle *
UnLock(clef); clef=0;
if(categ == 'C')
resul=input("NOM du SOURCE-C à CREER"); else
resul=input("NOM du SOURCE-ASSEMBLEUR à CREER");
if( resul == 0) cleanexit();
printf(" n CHEMIN : '%s' ; FICHIER : '%s' n",
dirname, fname) ;
printf(" n Sortie en cours ... n");
if(categ == 'C') output_C(); else
output_A();
cleanexit() ;
}
Il y a de cela deux mois, nous avons étudié l’animation à base de Vsprites à l’aide d’un programme faisant bouger des petits logos ANT sur un écran Intuition. Le programme étant assez long, peu d’explications avaient été fournies.
SPRITES VIRTUELS
Le système d’animation de l’Amiga, dénommé GELS (pour Graphics Elements System), est constitué d’un certain nombre de couches logicielles superposées, chacune utilisable indépendamment des autres. Ainsi, lorsque nous avions
étudié les sprites Hardware (,simple sprites), nous avons utilisé la couche la plus basse du GELS qui consiste littéralement en une interface pour piloter les circuits spécialisés de l’Amiga.
En programmant des Vsprites, nous avons utilisé la couche supérieure du GELS : en effet, un Vsprite n’existe pas physiquement, il ne s’agit que d’une représentation virtuelle (d’où son nom !) Qui est utilisée par le GELS pour créer, animer et détruire des "simple sprites" à l’écran. Cette phase de création, animation et destruction n’étant plus
contrôlable par l’utilisateur, mais gérée automatiquement par le système.
Le "simple sprite" alloué pour un Vsprite ne l’est que le temps nécessaire à sa visualisation, ce qui permet d’avoir plus de huit Vsprites à l’écran, pour peu qu’ils ne soient pas positionnés à plus de 8 sur les mêmes lignes au même instant (cf. Figure 1).
Un Vsprite possède une structure de données associée contenant la position du sprite, sa taille, son image et ses couleurs propres (cf.
Descriptif paru dans le numéro 26), ce qui permet au système
d’animation de travailler convenablement.
AVANTAGES ET INCONVENIENTS
Le gros avantage d’utiliser les Vsprites est que l’on n’a plus à se préoccuper exactement de la manière d’allouer les sprites Hardware : on indique seulement où les sprites doivent apparaître et le GELS fait le reste. Autre avantage, la possibilité d’utiliser plus de huit Vsprites en même temps, sachant que le système peut réutiliser le même sprite Hardware pour afficher deux objets différents à des endroits différents de l’écran.
Malheureusement, il n’y a pas que des avantages dans l’utilisation des Vsprites et un certain nombre de contraintes sont à prendre en compte si l’on ne veut pas avoir la désagréable surprise de voir son programme fonctionner de manière stochastique...
Comme mentionné plus haut, le hardware de l’Amiga n’autorise que huit "vrais" sprites maximum. Cela signifie que si l’on demande au système d’afficher plus de huit Vsprites à une même coordonnée, certains ne seront pas affiché. C’est comme cela et on y peut rien. Mais là où le problème se corse (comme disait Napoléon), c’est que, pratiquement, on ne peut pas allouer les huit sprites : le sprite 0 est réservé à Intuition pour afficher le pointeur de souris, il est donc inutilisable. Et comme le sprite 1 lui est associé (les sprites Hardware allant par paire), il est également déconseillé de s’en servir. En effet cette paire de sprites utilise les mêmes registres de couleur (17 à 19, le 16 étant considéré comme transparent). Toute modification de la couleur du sprite 1 entraînera donc une modification de celle du sprite 0 et vous aurez la désagréable surprise de voir flasher votre pointeur de souris.
Un deuxième problème peut survenir dans le cas de superposition des sprites : il faut savoir que les sprites Hardware, lorsqu’ils se superposent, se cachent mutuellement suivant un ordre de priorité bien établi. Celui ayant le plus faible numéro étant toujours "au dessus" de l’autre (c’est pour cela que le pointeur de souris ne peut jamais être
caché). Quand l’on utilise des Vsprites, le système graphique associe arbitrairement un numéro de sprite à chaque Vsprite, et ce dynamiquement. Cette allocation dont l’utilisateur n’est pas maître pose donc deux problèmes :
• on ne sait pas quel sprite passera "au dessus" de l’autre ;
• il peut arriver que, lors d’un changement d’assignation, il y ait basculement des deux sprites, ce qui a pour effet de les permuter à l’écran.
Troisième contrainte, si tous vos Vsprites utilisent des couleurs différentes, vous ne pouvez pas avoir au maximum huit sprites mais seulement quatre. Pourquoi ? Hé bien c’est fort simple : comme chaque sprite d’une paire utilise les mêmes registres de couleurs que son petit copain, le système ne peut afficher les huit sur une même ligne... Pour se simplifier la tâche, il n’en affiche que quatre !
Enfin, quatrième contrainte, mais qui est propre à l’utilisation des sprites en général, plus l’on utilise de sprites, moins l’on a de couleurs disponibles pour le playfield. N’oublions pas que les circuits de gestion des sprites Hardware utilisent les registres de couleurs 17 à 19, 21 à 23, 25 à 27, 29 à 31, qu’il ne faudra donc pas utiliser pour le playfield, ou alors très judicieusement.
GELS
Que vous désiriez utiliser des Vsprites, des Bobs ou tout autre objet géré par le GELS, il faudra commencer par l’initialiser. Le système d’animation graphique tient à jour une liste chaînée des éléments graphiques à visualiser, liste qui doit toujours au minimum contenir deux éléments "bidons", c’est-à-dire deux Vsprites qui ne seront jamais représentés à l’écran, mais qui servent au GELS à repérer facilement le début et la fin de la liste. Ces Vsprites sont appelés "sprite de tête" et "sprite de queue" puisque tous les objets crées ensuite seront insérés entre eux. La première chose qu’il faut faire est donc créer cette liste de deux éléments bidons.
Par défaut, le système de gestion des sprites s’alloue tous les sprites disponibles, y compris le sprite 1, ce qui, nous l’avons vu précédemment, peut entraîner des problèmes avec le pointeur de souris. Pour palier à cela, il suffit d’indiquer quels sprites doivent être réservés par le système : il existe un champ dans la structure Gelslnfo qui permet cela, le champ sprRsrvd. Ainsi, pour réserver les sprites 2 à 7, on tapera la ligne suivante :
struct Gelslnfo *gel;
* en binaire : SôllllllOO *
gel->sprRsrvd = OxFC;
Si l’on veut réserver le maximum de sprites disponibles (hors les sprites 0 et 1), il faudra se renseigner au préalable quels sont les sprites utilisés par d’autres tâches (pour éviter les conflits). On est capable de savoir quels sont les sprites effectivement réservés par d’autres tâches en regardant le champ SpriteReserved de la structure GfxBase. Chaque sprite est visualisé par un bit de ce champ : si le bit est à 1, le sprite correspondant est réservé.
Pour s’allouer les sprites encore disponible on tapera donc :
gel->sprRsrvd = OxFC & (!(GfxBase->SpriteReserved));
Le système d’animation a besoin de certaines données d’entrée pour décider quel sprite Hardware il va utiliser pour visualiser le prochain Vsprite. Ces variables d’état sont placées dans la structure Gelslnfo et comprennent deux tableaux, nextLine et lastColor.
Dans nextLine, le système stocke le numéro de la prochaine ligne écran ou sera disponible chaque sprite hardware. Ceci lui permet de savoir quels sont les sprites Hardware qui peuvent être candidats pour afficher un Vsprite à une position donnée, et ceux qui ne peuvent le faire car déjà occupés.
Dans lastColor, le système stocke pour chaque sprite Hardware un pointeur vers le jeu de couleurs utilisés en dernier. Ainsi, lorsqu’un Vsprite a besoin d’être utilisé, le système recherche dans le tableau lastColor et en fonction des sprites susceptibles d’être utilisés, quel sprite Hardware possède le même jeu de couleur que le Vsprite à afficher. S’il en existe un, il l’utilise en premier car celà évite des modification des registres de couleurs associés au sprite, très coûteuses en temps-machine.
Ces deux champs de la structure Gelslnfo doivent bien entendu être alloués dans votre programme, ce qui se fera sans problème de la manière suivante :
gel->nextLine = (WORD *)AllocMem(sizeof(WORD) * 8,
MEMF_PUBLIC|MEMF CLEAR));
et
gel->lastColor = (WORD *)AllocMem(sizeof(WORD) * 8, MEMF_PUBLIC|MEMF_CLEAR));
CREATION DU VSPRITE
La création d’un Vsprite s’effectue de manière simple. La première étape consiste à remplir une structure Vsprite, soit déclarée statiquement, soit allouée dynamiquement avec AllocMem(). Cette structure possède un certain nombre de champs dont certains ont les mêmes fonctions que ceux de la structure SimpleSprite décrite dans un précédent numéro.
Pour placer à l’écran un Vsprite, il faut d’abord indiquer sa position dans les champs v->X et v->7. Ensuite, sa largeur et sa heuteur seront placées dans v->Width (la largeur s’exprime en mots de 16 bit et un Vsprite a toujours une largeur de 16 pixels, donc de 1 mot) et v- Height. La profondeur v->Depth doit également être indiquée : pour un Vsprite, la profondeur est toujours égale à 2, mais on peut avoir plus de couleur avec un Bob (qui utilise la même structure). On associe ensuite l’image du sprite au champ v->ImageData et sa couleur au champ v->SprColors.
On continue en mettant dans le champ v->Flag la valeur VSPRITE pour indiquer qu’il s’agit d’un Vsprite et non d’un Bob, et on termine allègrement par la gestion des collisions :
• en mettant la valeur 1 dans v->MeMask et v->HitMask afin d’avoir une détection de collision sur les bordures de l’écran ;
• en réservant de la mémoire pour le champ v->jBorder Line, qui contiendra une image rectangulaire, sur un seul plan de bits, du Vsprite afin de permettre une détection plus rapide, bien qu’approximative, des collisions ; 7
• en réservant également de la mémoire pour le champ v->CollMask qui contiendra une image de la projection du Vsprite sur un bitplane afin de faire des détections exactes de collision.
Que reste-t’il à faire ? Presque rien, sinon mettre à 0 les champs v- PlanePick et v->PlaneOnOff qui ne servent que pour les Bobs et appeller la fonction InitMasks() de la graphics.library, qui finira automatiquement le travail en créant effectivement les deux masques CollMask et Border Line.
Pour ajouter le Vsprite ainsi créé, il suffit de faire appel à la fonction AddVSprite() qui fait le travail tout seul. On lui passe en paramètres l’adresse (de la structure) du Vsprite à ajouter et celle du RastPort de l’écran visé.
AFFICHAGE ET DEPLACEMENT
Nos Vsprites sont maintenant dans la liste, tout est donc pour le mieux. Pour déplacer un Vsprite, on modifiera les champs v->X et v->Y et on lancera un processus qui consiste à réactualiser l’ensemble de la visualisation pour prendre en compte cette modification de position.
Les Vsprites devant être affichés du haut de l’écran vers le bas, il faut commencer par trier la liste des éléments graphiques à afficher, en appelant la fonction SortGLisî(). On crée ensuite les instructions Copper de visualisation des sprites pour le ViewPort, en appelant la routine DrawGList(), avec comme argument le RastPort et le ViewPort.
Enfin, on demande à Intuition d’effectuer elle-même les modifications sur l’écran et de le réafficher grâce à la séquence MakeScreen() RethinkDisplay(). Si on n’utilise pas Intuition, MakeVPort() et LoadView() seront mises à contribution.
FIN DU TRAVAIL
Une fois nos Vsprites devenus inutiles, il faut les effacer et libérer proprement les ressources utilisées, à savoir la structure v elle-même, v->CollMask et v->BorderLine, sans oublier v->VSBob->SaveBuffer, v- VSBob->DBuffer et v->VSBob si notre Vsprite était un Bob.
Un petit bout de code valant des fois mieux qu’un long discours, voici la routine permettant de libérer toutes ces ressources.
Void FreeVSprite(v) struct Vsprite *v;

ULONG vSizel, vSize2;
vSizel = sizeof(SHORT) * v->Width * v->Height; vSize2 = vSizel * v->Depth;
if (v != NULL)
if (v->VSBob != NULL)
if (v->VSBob->SaveBuffer != NULL)
FreeMem(v->VSBob~>SaveBuffer, vSizel);
}
if (v->VSBob->DBuffer != NULL)
if (v->VSBob->DBuffer->BufBuffer != 0) FreeMem(v->VSBob->DBuffer->BufBuffer, vSizel);
}
FreeMem(v->VSBob->DBuffer,
sizeof(struct DbufPacket));
}
FreeMem(v->VSBob, sizeof(struct Bob));
}
if (v->CollMask != NULL)
FreeMem(v->CollMask, vSize2);
if (v->BorderLine != NULL)
FreeMem(v->BorderLine, vSize2);
}
FreeMem(v, sizeof(struct Vsprite));
}
Ensuite on détruira le GELS, ce dernier n’ayant désormais plus de raison d’être. On libérera donc les zones collHandler, lastColor, nextLine, gelHead et gelTail.
Soit par programme :
if (gelinfo.collHandler != NULL)
FreeMem(gelinfo.collHandler, sizeof(struct collTable)); if (gelinfo.lastColor != NULL)
FreeMem(gelinfo.lastColor, sizeof(LONG) * 8); if (gelinfo.nextLine != NULL)
FreeMem(gelinfo.nextLine, sizeof(WORD) * 8); if (gelinfo.gelHead != NULL)
FreeMem(gelinfo.gelHead, sizeof(struct Vsprite)); if (gelinfo.gelTail != NULL)
FreeMem(gelinfo.gelTail, sizeof(struct Vsprite));
Bon, hé bien voilà pour la description du programme sur les Vsprites proposé il y a deux mois. J’espère que c’est beaucoup plus clair pour vous désormais. Le reste du programme concerne des parties que nous avons vues en détail précédemment, je ne reviendrai donc pas dessus.
Le mois prochain, nous terminerons cette partie animation sur Amiga par les Bobs, ou Blitter Objects. Vous pourrez faire ainsi la comparaison avec les Vsprites et utiliser l’un ou l’autre selon la nature de votre application. En attendant, je vous souhaite une bonne lecture et vous dis : "à dans un mois".
‘b
Par Herr Doktor Von GlutenSïimmellmDorf.
Comme promis, voici la suite du méga-listing de notre utilitaire du mois dernier, ExecMaster. Après ça, vous pourrez enfin disposer de cet excellent programme de Vami Max.
Histoire de vous simplifier les choses, voici tout de même un petit mode d’emploi. Rassurez-vous, rien de bien compliqué, mais il paraît que ça ne se fait pas de commencer un article directement par du listing, alors il faut que j’écrive quelques lignes... O, pas grand chose, juste un ou deux paragraphes, histoire de préserver l’harmonie visuelle du magazine. En jargon de journaliste, on appelle ça du remplissage. Ah ma pauv’ dame, on est bien peu de choses, c’est moi qui vous l’dis.
De. W
de. 1 de .w de .w de. 1 de .b de. 1 de .w de. 1 de .b de. W de. 1
de. 1 de .w de .w de. 1 de .b de. 1 de .w de. 1 de .b de .w de. 1
de. 1 de .w de .w de. 1 de .b de. 1 de .w de. 1 de .b de .w de. 1
de. 1 de .w de .w de. 1
dc. b de. 1 de .w de. 1 de .b de .w de. 1
de .1 de .w de .w de. 1 de .b de. 1 de .w de. 1 de .b de .w de. 1
dc. l de .w de .w de. 1 de - b
dc. l de .w de. 1
dc. b de .w
dc. l
de. 1
dc. w de .w
dc. l de .b
dc. l de .w de. 1 de .b de .w
dc. l
dc. l de .w de .w
dc. l de .b de. 1 de .w
dc. l de .b
mlITl
mlIT2
Or donc, voici un mode d’emploi des deux listings suivants : vous les tapez, vous les mettez dans le même répertoire que ExecMaster.s publié dans notre précédent numéro et vous assemblez le tout pour obtenir un programme exécutable du nom de ExecMaster, et c’est tout ! Avouez que c’était simple. Si, juste une petite précision : le premier listing s’appelle em_windows.j et contient la définition de l’écran et des fenêtres d’ExecMaster, et le second s’appelle em_menus.s et contient la définition de tous les menus du programme.
MlIT3
Bon, ben cette fois-ci, c’est tout, je retourne me coucher. Atchao bonsoir.
MlIT4
mlIT5
mllT6
mlIT7
mlltem8
mlIT8
Listing
1 : em
_windows.s
ns
de .w
0,0,640,256,2
dc. b
1 2
de .w
V_HIRES,CUSTOMSCREEN
dc. l
0,setitre,0,0
nw
de .w
0,0,640,256
dc. b
1 2
de. 1
MENUPICK
dc. l
BACKDROP!BORDERLESS1ACTIVATE|NOCAREREFRESH
dc. l
0,0,0,0,0
de .w
0,0,0,0
de .w
CUSTOMSCREEN
nw3
de .w
134,0,300,10
dc. b
1,2
dc. l
GADGETUP|ACTIVEWINDOW
de. 1
ACTIVATE|RMBTRAP
de. 1
w3gad,0,0,0,0
de .w
0,0,0,0
de .w
CUSTOMSCREEN
w3gad
de. 1
0
de .w
120,1,150,8
de .w
GADGHCOMP|SELECTED
de .w
TOPBORDER|RELVERIFY|LONGINT
dc. w
STRGADGET
de. 1
0,0,0,0,strinfo
de .w
0
de. 1
0
strinfo
dc. l
strbuf,strbuf+40
de .w
1,40,0,0,0,0,0,0
dc. l
o
o
o
s
o
strbuf
dc. b
'0'
dcb.b
79,0
Palette
de .w
$ 0356,$ 0FFF,$ 0000,$ 00AF
setitre
de .b even
"ExecMaster 0.7 - 1991, Max pour ANT",0
Listing
2 : em_menus.s
. *****
Menu '
Affichage'
MainMenuList:
ml
dc. l
0
de .w
2,0,79,0,MENUENABLED
de. 1
mlName,mllteml
0,0,0,0
Af f iche Tache s
mlltem2 0,0,195,10
CHECKIT|ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP %11111111111111111111111111111110,mlITl,0 'T', 0 0
MENUNULL
Affiche_taches ; xi_Func
1. 2,RP_JAM2,0 20,1
0,mlTxtl,0
mlltem3 ; Affiche Libraries
0,10,195,10
CHECKIT|ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP %11111111111111111111111111111101,mHT2, 0 ' L ' , 0 0
MENUNULL
Af f iche_libraries ; xi_Func
1. 2,RP_JAM2,0 20,1
0,mlTxt2,0
mlltem4 ; Affiche Devices
0,20,195,10
CHECKIT|ITEMTEXT|COMMSEQIITEMENABLED|HIGHCOMP %11111111111111111111111111111011, mHT3, 0
'D', 0 0
MENUNULL
Affiche_devices ; xi_Func
1. 2,RP_JAM2,0 20,1
0,mlTxt3,0
mlltem5 ; Affiche Ports
0,30,195,10
CHECKIT|ITEMTEXT|COMMSEQIITEMENABLED|HIGHCOMP %11111111111111111111111111110111,mlIT4,0 'P' ,0 0
MENUNULL
Affiche_ports ; xi_Func
1. 2,RP_JAM2,0 20,1
0,mlTxt4,0
mlltem6 ; Affiche Mémoire
0,40,195,10
CHECKIT|ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP %11111111111111111111111111101111,mlIT5,0 'M',0 0
MENUNULL
Af fiche mémoire ; xi_Func
1. 2,RP_JAM2,0 20,1
0,mlTxt5,0
mlltem7 ; Affiche Resources
0,50,195,10
CHECKIT|ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP %111111111111111111111111H011111,mlIT6, 0 'R', 0 0
MENUNULL
Affiche_resources ; xi_Func
1. 2,RP_JAM2,0 20,1
0,mlTxt6,0
mlltem8 ; Affiche Modules résidents
0,60,195,10
CHECKIT|ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP 9611111111111111111111111110111111,mlIT7,0 'O',0 0
MENUNULL
Affiche_modules ; xi_Func
1. 2,RP_JAM2,0 20,1
0,mlTxt7,0
mlltem9 ; Affiche Interruptions
0,70,195,10
CHECKIT|ITEMTEXT|COMMSEQIITEMENABLED|HIGHCOMP 9611111111111111111111111101111111,mlIT8,0 'I',0 0
MENUNULL
Af f iche_interr ; xi_Func
1. 2,RP_JAM2,0
dc. w
20 1
de. 1
0,mlTxt8,0
mlltem9
dc. l
0 ; Affiche Quitter
de .w
0,85 195,10
de. W
ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP
de. 1
0,mlIT9,0
dc. b
'Q',0
dc. l
0
de. W
MENUNULL
de. 1
Affiche_Quitter ; xi Func
mlIT9
de .b
1,2,RP JAM2,0
de. W
20,1
dc. l
0,mlTxt9,0
. *****
Menu
'Tâches'
m2
dc. l
0
de .w
87,0,79,0,MENUENABLED
de. 1
m2Name, m2 Iteml
dc. w
o
o
o
o
m2lteml
dc. l
m2ltem2 ; Tâches SetTaskPri
de .w
0,0,120,10
de .w
ITEMTEXT|ITEMENABLED|HIGHCOMP
dc. l
0,m2lTl,0
de .b
0,0
de. 1
0
de .w
MENUNULL
de. 1
Pri_tache ,* xi_Func
m2lTl
de .b
1,2,RP JAM2,0
de .w
20,1
dc. l
0,m2Txtl, 0
m2ltem2
dc. l
m2ltem3 ; Tâches Geler
de .w
0,10,120,10
de .w
ITEMTEXT|ITEMENABLED|HIGHCOMP
dc. l
0,m2lT2,0
de .b
0,0
dc. l
0
de .w
MENUNULL
de. 1
Gele_tache ; xi Func
m2IT2
de .b
1,2,RP JAM2,0
de .w
20,1
dc. l
0,m2Txt2,0
m2Item3
dc. l
0 ; Tâches Réchauffer
de .w
0,20,120,10
de .w
ITEMTEXT|ITEMENABLED|HIGHCOMP
de. 1
0,m2lT3, 0
dc. b
0,0
dc. l
0
de .w
MENUNULL
de. 1
Chauffe_tache ; xi_Func
m2IT3
dc. b
1,2,RP JAM2,0
dc. w
20,1
dc. l
0,m2Txt3,0
. ***** r
Menu
'Libraries'
m3
dc. l
0
de. W
87,0,79,0,MENUENABLED
dc. l
m3Name, m3 Iteml
dc. w
0,0,0,0
m3lteml
dc. l
m3Item2 ; Libraries Ouvrir
de .w
0,0,90,10
dc. w
ITEMTEXT|ITEMENABLED|HIGHCOMP
dc. l
0,m3ITl,0
dc. b
0,0
dc. l
0
de .w
MENUNULL
dc. l
Ouvre_lib ; xiFunc
m3lTl
de .b
1,2,RP JAM2,0
de .w
20,1
dc. l
0,m3Txtl,0
m3ltem2
dc. l
m3ltem3 ; Libraries Fermer
de .w
0,10,90,10
de .w
ITEMTEXT|ITEMENABLED|HIGHCOMP
dc. l
0,m3lT2,0
dc. b
0,0
dc. l
0
de .w
MENUNULL
dc. l
Ferme_lib ; xiFunc
m3IT2
de .b
1,2,RP JAM2,0
de .w
20,1
de. 1
0,m3Txt2,0
m3ltem3
dc. l
0 ; Libraries Purger
de .w
0,20,90,10
dc. w
ITEMTEXT|ITEMENABLED|HIGHCOMP
dc. l
0,m3lT3,0
dc. b
0,0
dc. l
0
de .w
MENUNULL
dc. l
Purge_lib ; xi_Func
m3IT3
dc. b
1,2,RP JAM2,0
de .w
20,1
dc. l
0,m3Txt3,0
. *****
Menu
Ports
m4
dc. l
0
dc. w
87,0,79,0,MENUENABLED
dc. l
m4Name, m4 Iteml
dc. w
0, 0,0,0
m4Iteml
dc. l
m4ltem2 ; Ports Cacher
dc. w
0,0,100,10
dc. w
ITEMTEXT|ITEMENABLED|HIGHCOMP
dc. l
0,m4lTl,0
dc. b
0,0
dc. l
0
dc. w
MENUNULL
de. 1
Cache_port ; xi_Func
m4ITl
de .b
1,2,RP JAM2,0
de .w
20,1
dc. l
0,m4Txtl,0
m4Item2
de. 1
0
de .w
0,10,100,10
dc. w
ITEMTEXT|ITEMENABLED|HIGHCOMP
dc. l
0,m4IT2,0
de .b
0,0
dc. l
0
de .w
MENUNULL
dc. l
Revele_port ; xi_Func
m4IT2
dc. b
1,2,RP JAM2,0
de .w
20,1
dc. l
0,m4Txt2,0
Menu
'Mémoire'
m5
de. 1
0
de .w
87,0,79,0,MENUENABLED
dc. l
m5Name, m5 Iteml
de .w
o
o
o
o
m5 Iteml
dc. l
0
de .w
0,0,100,10
dc. w
ITEMTEXT|ITEMENABLED|HIGHCOMP
dc. l
0,m5lTl,0
de .b
0,0
de. 1
0
de .w
MENUNULL
dc. l
Pri_memoire ; xi_Func
m5ITl
dc. b
1,2,RP JAM2,0
de .w
20,1
dc. l
0,m5Txtl,0
. *****
Chaînes ASCII
TOPAZ80
dc. l
TOPAZname
dc. w
TOPAZ EIGHTY
de .b
0,0
TOPAZname:
dc. b
"topaz.font”,0
mlName
de .b
"Affichage", 0
mlTxtl
dc. b
"Tâches",0
mlTxt2
dc. b
"Libraries",0
mlTxt3
dc. b
"Devices", 0
mlTxt4
dc. b
"Ports",0
mlTxt5
dc. b
"Mémoire",0
mlTxt6
dc. b
"Resources",0
mlTxt7
dc. b
"Modules résidents",0
mlTxt8
dc. b
"Interruptions",0
mlTxt9
dc. b
"Quitter", 0
m2Name
dc. b
"Contrôles",0
m2Txtl
dc. b
"SetTaskPri",0
m2Txt2
dc. b
"Geler",0
m2Txt3
de .b
"Réchauffer", 0
m3Name
dc. b
"Contrôles", 0
m3Txtl
dc. b
"Ouvrir",0
m3Txt2
dc. b
"Fermer",0
m3Txt3
dc. b
"Purger",0
m4Name
dc. b
"Contrôles",0
m4Txtl
dc. b
"Cacher",0
m4Txt2
dc. b
"Révéler",0
m5Name
dc. b
"Contrôles",0
m5Txtl
dc. b
even
"Priorité", 0
L« parole est ici donnée à Pierre Chalamet dont le Sinus-Scroll est du plus bel effet. Pierre gagne les 1500 F promis ainsi que toute notre considération. Et la vôtre. Ce qui n’est pas peu dire.
_SINUS-SCROLL
Le principe du scroll est assez simple : il est d’abord créé dans une zone qui ne sera jamais affichée (hidden_screen) puis recopié tranche par tranche grâce au blitter. Mais pour faire ce genre de travail, il faut beaucoup de temps et utiliser deux écrans en alternance (double buffering).
Durant la VBL on effectue les opération suivantes :
• permutation des écrans
• effacement de l’écran non affiché
• on rentre les lettres s’il le faut dans la zone
hidden_screen et on donne un coup de blitter pour faire bouger de droite à gauche
• on recopie par tranche de deux colonnes la zone
hidden_screen dans l’écran caché. Le blitter ne permettant des transferts que d’un mot minimum, on est obligés de ruser et de faire un OR avec la source et la destination, car sinon on effacerait les autres tranches. Il ne faut donc pas s’étonner de voir que bltBpt et bltDpt pointent sur la même adresse (A or B -> D).
Remarques :
• l’image à insérer au label lettres doit être de 320 pixels (40 octets) sur 256 lignes au format RAW (surtout pas IFF !) Et un seul bitplan. Chaque lettre fait 32 pixels de large sur 32 de haut.
• l’impression d’une onde qui passe est donnée par le
déplacement d’un pointeur sur la table des
déplacements.
Il est possible d’optimiser le programme (code relatif au PC, initialisation du blitter avant d’entrer dans les boucles...) mais pas des masses, car le blitter prend un sacré temps pour recopier tous les blocs d’image, même s’il tourne à plein régime (le bit 10 de dmacon est mis).
Listing 1 : MakeSinus.bas
c=0
OPEN "o", 1,"sinus.s"
FOR a=0 TO 2*3.14159 STEP .01 b=INT(SIN(a)*100+105)
PSET(c,b) c=c+l b=b*40 IF C=1 THEN
a$ =CHR$ (9)+"dc.w"+STR$ (b)
END IF IF C>1 THEN
IF LEN(a$ ) 60 THEN a$ =a$ +","+STR$ (b)
ELSE PRINT 1,a$
a$ =CHR$ (9)+"dc.w"+STR$ (b)
END IF END IF NEXT a PRINT 1, a$
CLOSE 1
Listing 2: Registers.i
dmacon=$ 96
dmaconr=$ 02
intreq=$ 9c
intreqr=$ le
intena=$ 9a
intenar=$ lc
ciaapra=$ bfe001
color00=$ 180
copllc=$ 80
copjmpl=$ 88
startlist=38
diwstrt=$ 8e
ddfstrt=$ 92
bplcon0=$ 100
bplconl=$ 102
bplcon2=$ 104
bp1lmod=$ 108
bpl2mod=$ 10a
bpllptH=$ e0
bpllptL=$ e2
forbid=-132
permit=-138
openlibrary=-5 5 2
close1ibrary=-414
execbase=4
bltapt=$ 50
bltbpt=$ 4c
bltdpt=$ 54
bltamod=$ 64
blIBMod=$ 62
bltdmod=$ 66
bltafwm=$ 44
bltalwm=$ 46
bltcon0=$ 40
bltconl=$ 42
bltsize=$ 58
bltadat=$ 74
Listing 3 : Save_All.s
save_all lea $ dff000,a5
arrête drives base d'exec enleve multitâche vecteur irq intena met bit 15 dmacon met bit 15 fin
adresse base custom chip remet vecteur irq vire intena remet save_intena vire dmacon remet dameon_save base d'exec pointeur sur gfx lib vide dO ouvre gfx lib récupéré addresse
move.b %10000111,$ bfdl00 move.1 execbase,a6 jsr forbid(a6) move.1 $ 6c,save_vecteur_irq move.w intenar(a5),save_intena or.w $ 8100,save_intena move.w dmaconr(a5),save_dmacon or.w $ c000,save_dmacon rts restore_all
lea $ dff000,a5 move.1 save_vecteur_irq,$ 6c move.w $ 7fff,intena(a5) move.w save_intena,intena(a5) move.w $ 7fff,dmacon(a5) move.w save_dmacon, dmacon(a5) move.1 execbase,a6 lea name_glib,al moveq 0,d0 jsr openlibrary(a6) move.l d0,a0
move.l startlist(aO),copllc(a5) met ancienne adresse
coplist
valide coplist adresse gfx lib dans al ferme gfx
clr.w copjmpl(a5) move.l d0,al jsr closelibrary(a6) jsr permit(a6) rts
dc. w 0 de .w 0
dc. b "graphies.library",0
save_intena s ave_dma c on
save_vecteur_irq de. 1 0 name glib
even
Listing 4 : SinusScroll.s
include Registers.i
bsr save_all
inits écran et vbl
lea $ dff000,a6 move.w $ 7fff,d0 move.w dO,dmacon(a6) move.w dO,intena(a6) move.l $ 003800d0,ddfstrt(a6) move.l $ 2c8129cl,diwstrt(a6) move.w 0,bpllmod(a6) move.w 0,bpl2mod(a6) move.w $ 1200,bplcon0(a6) move.w 0,bplconl(a6) move.w 0,bplcon2(a6) move.l $ 00000fff,colorOO(a6) move.1 vbl,$ 6c move.l coplist,copllc(a6) clr.w copjmpl(a6) move.w $ 87c0,dmacon(a6) move.w $ c020,intena(a6)
btst 6,ciaapra bne mickey bsr restore_all moveq.1 0,d0 rts
mickey
include Save_All.s movem.l d0-d7 a0-a6,-(sp) lea $ dff000,a6
vbl
btst 5,intreqr+1(a6) ;test la provenance
beq pas_vbl ;de l'interrupt niveau 3
bsr flip_screen permute les écrans
bsr clear_hidden_screen efface 1'écran caché
bsr do_scroll déplacé le scroll caché
bsr put_scroll copie scrolldans écran caché
move.w $ 20,intreq(a6) fin vbl
movem.l (sp)+,d0-d7 a0-a6
pas_vbl
rte
next_screen
dc. l ecranl ; adresse de l'écran caché
wait_blit
btst 14,dmaconr(a6) loop_blit
btst 14,dmaconr(a6) bne loop_blit rts
flip_screen
move.1 next_screen,dO move.1 ecranl,dl cmp.l dO,dl beq put_ecranl
; échangé les écrans
pour faire du double-buffering
move.1 ecran2,bpllptH(a6) move.l ecranl,next_screen rts
put_ecranl
move.l ecranl,bpllptH a6) move.l ecran2,next_screen rts
clear_hidden_screen
bsr wait_blit ;afface 1'écran caché
clr.w bltadat a6)
clr.w bltamod(a6)
move.w $ ffff,bltafwm(a6)
move.w $ ffff,bltalwm(a6)
move.w $ 01f0,bltcon0(a6)
move.w $ 0,bltconl(a6)
move.w $ 0,bltdmod(a6)
move.l next_screen,bltdpt(a6)
move.w 256*64+20,bltsize(a6)
rts
do_scroll
move.l pointeur_text,aO ;fait entrer les letttres move.w letter_count,dO ;dans l'écran caché beq new_letter sub.w 1,letter_count bra scroll new_letter
move.w 7,letter_count clr.l dO move.b (a0)+ d0 bne continue lea text,a0 move.b (a0)+,d0 continue
cmp.b 32,dO bne continue2 move.b "Z"+l,dO continue2
;test pour le character espace chr=32=$ 20
sub.b "A",dO lsl.l 1,dO lea table_pos,al bsr wait_blit move.l 0,a2 move.w 0(al,dO.1),a2 add.l lettres,a2 move.l a2,bltapt(a6) move.w 36,bltamod(a6) move.1 hidden_screen+42,bltdpt(a6) move.w 44,bltdmod(a6) move.w $ 09f0,bltcon0(a6) move.w $ 0,bltconl(a6) move.w 32*64+2,bltsize(a6)
;A est la base de la table ; table composée de mot => *2
; calcul adresse lettre ; dans image ;
scroll bsr wait_blit ; scroll tout le texte
move.l hidden_screen+2,bltapt(a6) ;caché
move.w 2,bltamod(a6) move.1 hidden_screen,bltdpt(a6) move.w 2,bltdmod(a6) move.w $ c9fO bltconO(a6) move.w $ 0,bltconl(a6) move.w 32*64+23,bltsize a6) move.l aO,pointeur_text rts
put_scroll
move.l 159,dO ;met scroll dans
move.l pointeur_onde,al ; écran caché
move.1 hidden_screen+2,a2 move.l next_screen,aO lea table_mask,a4 loop_cut
move.l a0,a3 clr.l dl move.w al)+,dl
;et on le met 2 colones par ;2 colones
bne continue_loop lea table_sinus,al move.w al)+,dl continue_loop
add.l dl,a3 bsr wait_blit move.l a2,bltapt(a6)
;a3=arrivée, a2=source
move.w 46,bltamod(a6) move.l a3,bltbpt(a6) move.w 38,blIBMod(a6) move.l a3,bltdpt(a6) move.w 38,bltdmod(a6) move.w (a4),bltafwm(a6) move.w (a4)+,bltalwm(a6)
move.w $ 0dfc,bltconO(a6) fait un or pour ne pas
move.w $ 0,bltconl(a6) effacer les autres tranches move.w 32*64+1,bltsize(a6) transfer !
Cmp.w 0,(a4) test les masques
beq change_bloc si =0 alors on reprend au début
bra next_bloc sinon on continue
change_bloc
lea table_mask,a4 add.l 2,a0 add.l 2,a2 next_bloc
dbf dO,loop_cut
move.l pointeur_onde,aO fait avancer le pointeur add.l 10,aO ;de l'onde => donne impression
move.w a0),d0 qu'une onde passe
bne fin_sinus
move.1 table_sinus,pointeur_onde rts fin_sinus
move.1 aO,pointeur_onde rts
pointeur_text
de.1 text letter_count
dc. w 0
text de.b "SINUS SCROLL POUR ANT ",0
even table_pos
dc. w 0,4,8,12,16,20,24,28,32,36
dc. w 1280,1284,1288,1292,1296,1300,1304,1308,1312,1316
dc. w 2560,2564,2568,2572,2576,2580,2584 pointeur_onde
dc. l table_sinus table_sinus
include Sinus.s dcb.l 3,0 table_mask
dc. w $ c000,$ 3000,$ c00,$ 300,$ c0,$ 30,$ c,$ 3 de .w 0
section écran,da ecranl dcb.b 10240,$ 0 ecran2 dcb.b 10240,$ 0 hidden screen
écran de 40*256 écran de 40*256
hidden screen de 48*32
dcb.b 1536,0
lettres inebin Font
coplistdc.w color00,0
dc. w $ 640f,$ fffe
dc. w color00,$ 2
dc. w $ 8c0f,$ fffe de.w colorOO,$ 5
dc. w $ b40f,$ fffe
dc. w colorOO,$ 9
dc. w $ dc0f,$ fffe
dc. w colorOO,$ d
dc. w $ ffOf,$ fffe de .w colorOO,$ f
dc. l $ fffffffe
Figure 1 : la fonte
BL&E.FËHIJ LMNOPORST
vwxyz
Chaque lettre mesure 32x32 pixels. La taille totale de Limage est 320x256x2.
Par Pierre Chaînai ci
Ce qui suit est le programme que vous auriez normalement du trouver dans le précédent numéro de l’ANT et qui s’est perdu quelque part dans les méandres d’une PAO encore hésitante...
!?!
* Largeur de l'écran *
* Hauteur de l'écran *
* Profondeur *
* Position et taille du premier layer *
C
’est donc avec toutes nos excuses que nous vous le présentons aujourd’hui, accompagné de quelques lignes d’explications que Max a écrites spécialement pour l’occasion. Mais il est grand temps de lui laisser la parole.
Ce programme met en oeuvre trois layers : deux de type SIMPLELAYER et un de type SUPERLAYER, c’est-à-dire utilsant une BitMap qui lui est personnelle, plus grande que le layer lui-même. Une seule partie en est donc effectivement affichée et l’on peut en faire défiler le contenu, histoire de visualiser la BitMap entière. Ce layer est au départ rempli - par le biais de SetAfPt() et de RectFill() - par un motif multicolore, pour être sûr que le scrolling sera bien visible...
Ce SuperLayer se superpose à un SimpleLayer dans lequel un Quix joue tout seul. Les lignes sont clippées par le système, de sorte qu’elles ne coupent pas le layer supérieur.
Enfin, le troisième layer sert uniquement à afficher un petit texte de bienvenue.
Certes, cette "Little LayersDemo" comme je l’ai appelée ne montre pas toutes les capacités de la layers.library... Il faut en effet savoir que mis à part le clipping en lui-même, la gestion des layers est très lente (déplacement, changement de taille, rafraîchissement...), ce dont on peut de temps en temps se rendre compte au clignotement du SuperLayer et au ralentissement du Quix, d’autant plus que le multitâche est toujours actif. Mais enfin, son but était de démontrer l’utilisation des layers en dehors de la bibliothèque Intuition et de ses fenêtres, et je pense qu’il a été atteint...
***************************************************************
* Démonstration des Layers sans passer par Intuition. *
* Septembre 1991, par Max pour Amiga NewsTech *
* Domaine Public. *
* ****************************************************************
* Serait sans doute plus joli en utilisant le double-buffering. * ***************************************************************
include stdio.h>
include stdlib.h>
include string.h>
include exec types.h>
include exec memory.h>
include graphics gfxbase.h>
include graphics gfxmacros.h>
include graphics view.h>
include graphies layers.h>
include graphics clip.h>
* Constantes *
define SALUTl "Little Layers Demo, par Max pour ANT"
define SALUT2 "Bouton gauche de la souris pour quitter"
define GFXNAME "graphies.library"
define LAYERSNAME "layers.library"
define SCR_W 320
define SCR_H 256
define SCR_D 2
define LAYl_Xl0 define LAY1_Y10 define LAY1_W 320 define LAYl_H 30 define LAYl_X2 (LAYl_Xl+LAYl_W-l) define LAY1Y2 (LAYl_Yl+LAYl_H-l)
* Position et taille du second layer *
define LAY2_X10 define LAY2_Yl 40 define LAY2_W 320 define LAY2_H 216 define LAY2_X2 (LAY2_X1+LAY2_W-1) define LAY2_Y2 (LAY2_Yl+LAY2_H-l)
* Position & taille du troisième layer*
define LAY3_Xl 40 define LAY3_Y1 100 define LAY3_W 240 ftdefine LAY3_H 100 define LAY3_X2 (LAY3_X1+LAY3_W-1) define LAY3_Y2 (LAY3_Yl+LAY3_H-l)
* Largeur de la BitMap du SuperLayer * * Hauteur de la BitMap du SuperLayer *
define SUPER_W320 define SUPER_H 256
* Prototypes *
include proto exec.h>
include proto graphics.h>
include proto layers.h>
void main(void); void LayersDemo(void);
BOOL initScreen(void); void freeScreen(void);
BOOL initLayers(void); void freeLayers(void);
void doLayerl(void); void doLayer2(void); void doLayer3(void);
* variables globales pour l'affichage graphique *
* pas besoin de RastPort ici, on utilisera celui des layers *
struct View view, *oldview = NULL;
struct ViewPort vport;
struct Raslnfo rinfo;
struct BitMap bmap;
struct ColorMap *cmap = NULL;
USHORT Palette[] = 0x0000, OxOOOf, OxOfOO, OxOfff };
* variables globales pour la gestion des layers *
struct Layer_Info *linfo = NULL;
struct Layer *layl = NULL;
struct Layer *lay2 = NULL;
struct Layer *lay3 = NULL;
*
*
struct BitMap superbmap; * Ca, c'est pour le SuperLayer
USHORT motif[] = * Un zouli 'A' en 4 couleurs
0x0002,0x0002,0x0002,0x0002,0x0002,0x0012,0x0022,0x0042, 0x0082,0x0102,0x0002,0x07F2,0x0802,0x1002,0x2002,0x0000, 0x0002,0x0006,OxOOOE,OxOOlE,0x003E,0x007E,OxOOEE,OxOlCE, 0x038E,0x070E,OxOFFE,OxlFFE,0x380E,0x700E,OxEOOE,0x0000
};
* Autres variables globales * struct GfxBase *GfxBase = NULL; struct Library *LayersBase = NULL;
***************************************************************
* main() *
***************************************************************11 void main(void)

if (GfxBase = (struct GfxBase *)OpenLibrary(GFXNAME, 33L))
if (LayersBase = OpenLibrary(LAYERSNAME, 33L))
if (initScreen())
LayersDemo ( ) ; freeScreen();
CloseLibrary(LayersBase);
}
CloseLibrary((struct Library *)GfxBase);
}
exit(0);
}
***************************************************************
* initScreen() *
***************************************************************y
BOOL initScreen(void)

register i;
* Alloue et initialise une ColorMap * if (!(cmap = GetColorMap(IL 2))) return(FALSE); memcpy(cmap->ColorTable, Palette, sizeof(Palette));
* Prépare le View *
InitView(&view); view.ViewPort = fcvport;
* Prépare le ViewPort *
InitVPort(&vport); vport.DWidth = 320; vport.DHeight = 256; vport.Raslnfo = fcrinfo; vport.ColorMap = cmap;
* Prépare la BitMap principale *
InitBitMap(&bmap, 2, 320, 256);
* Alloue les bitplanes * for (i = 0; i 2; i++)
if (î(bmap.Planes[i] = AllocRaster(320, 256))) return(FALSE);
BltClear(bmap.Planes[i], RASSIZE(320, 256), 1);
}
* Prépare le Raslnfo * rinfo.BitMap = &bmap; rinfo.RxOffset = 0; rinfo.RyOffset = 0;
* Sauve le View actif (celui d'intuition) * oldview = GfxBase->ActiView;
* Construit l'affichage *
MakeVPort(&view, &vport);
MrgCop(&view);
LoadView(&view);
WaitTOF() ;
return(TRUE);
}
***************************************************************
* freeScreen() *
***************************************************************yI
void freeScreen(void)

register i;
if (oldview) * si non null, notre view a été chargé *
LoadView(oldview);
WaitTOF();
FreeVPortCopLists(&vport);
FreeCprList(view.LOFCprList);
}
if (cmap)
FreeColorMap(cmap);
for (i = 0; i 2; i++)
if (bmap.Planes[i])
FreeRaster(bmap.Planes[i], 320, 256);
}
}
***************************************************************
* LayersDemo() - routine principale de démonstration des layers *
*************************************************************** j
void LayersDemo(void)

register UBYTE *ciaapra = (UBYTE *)0xbfe001;
if (initLayers())
while (*ciaapra & 0x40)
doLayerl(); * Gère le 1er layer *
doLayer2(); * Gère le layer quix *
doLayer3(); * Gère le SuperLayer *
WaitTOF();
}
}
freeLayers();
************************ **************************************
* initLayers() - Crée et initialise les 3 layers *
*************************************************************** BOOL initLayers(void)

register SHORT i;
* Alloue la structure Layer_Info * if (!(linfo = NewLayerlnfoO ) ) return(FALSE);
* Crée le premier layer (bleu) * if (!(layl = CreateBehindLayer(linfo, &bmap,
LAY1_X1, LAYl_Yl, LAYl_X2, LAYl_Y2,
LAYERSIMPLE, NULL))) return(FALSE);
SetRast(layl->rp, 1);
SetDrMd(layl->rp, JAMl);
SetAPen(layl->rp, 3);
Move(layl->rp, (LAY1_W-(sizeof(SALUT1)-1)*8) 2, 14);
Text(layl->rp, SALUT1, sizeof(SALUTl)-1);
Move(layl->rp, (LAY1_W-(sizeof(SALUT2)-1)*8) 2, 24);
Text(layl->rp, SALUT2, sizeof(SALUT2)-1);
* Crée le second layer (blanc) * if (!(lay2 = CréâteBehindLayer(linfo, fcbmap,
LAY2_X1, LAY2_Yl, LAY2_X2, LAY2_Y2,
LAYERSIMPLE, NULL))) retum(FALSE) ;
SetRast(lay2->rp, 3);
SetDrMd(lay2->rp, JAM1);
* Crée le troisième layer (rouge) de type LAYERSUPER * InitBitMap(&superbmap, 2, SUPER_W, SUPER_H); for (i = 0; i 2; i++)
if (!(superbmap.Planes[i]=AllocRaster(SUPER_W SUPER_H))) return(FALSE);
BltClear(superbmap.Planes[i],RASSIZE(SUPER_W,SUPER_H),1);
if (!(lay3 = CreateUpfrontLayer(linfo, fcbmap,
LAY3_X1, LAY3_Yl, LAY3_X2, LAY3_Y2,
LAYERSUPER, fcsuperbmap))) return(FALSE);
SetAfPt(lay3->rp, motif, -4); * motif 16 lignes de haut *
SetAPen(lay3->rp, 255);
SetBPen(lay3->rp, 0);
SetDrMd(lay3->rp, JAM2);
RectFill(lay3->rp, 0, 0, SUPER_W-1, SUPER_H-1); return(TRUE);
}
***************************************************************
* freeLayersO - Libère la mémoire des 3 layers et du Layer_Info*
*************************************************************** void freeLayers(void)

régister SHORT i;
if (lay3) DeleteLayer(NULL, lay3);
if (lay2) DeleteLayer(NULL, lay2);
if (layl) DeleteLayer(NULL, layl);
for (i = 0; i 2; i++)
if (superbmap.Planes[i])
FreeRaster(superbmap.Planes[i],SUPER_W,SUPER_H);
}
if (linfo) DisposeLayerlnfo(linfo);
***************************************************************
* doLayerl() - Gère le premier Layer * *************************************************************** void doLayerl(void)

* Rien à faire !!! *
}
***************************************************************
* doLayer2() - Gère le Quix dans le second Layer * *************************************************************** void doLayer2(void)

* Données statiques pour le Quix * static new - 0, old = 0, full = FALSE; static SHORT xl[32], yl[32], x2[32], y2[32];
static SHORT veloc[4] = -4, 5, 3, -7 };
static SHORT start[4] = 110, 25, 160, 74 };
static SHORT max[4] = LAY2_W+20, LAY2_H+20,
LAY2_W+20, LAY2_H+20 };
régister SHORT i, temp;
for (i = 0; i 4; i++)
temp = start[i] + velocti]; if (temp >= max[i])
temp = (max[i] * 2) - start[i] - veloc[i]; veloc[i] = -veloc[i];
}
else if (temp -20)
temp = -20;
velocti] = -velocti];
}
start[i] = temp;
}
if (full)
SetAPen(lay2->rp, 3);
Move(lay2->rp, xl[old], yl[old]); Draw(lay2->rp, x2[old], y2[old]); old++; old %= 32;
}
xl[new] = start[0]; yl[new] = start[1]; x2[new] = start[2]; y2[new] = start[3];
if (new == 31) full = TRUE;
SetAPen(lay2->rp, 0);
Move(lay2->rp, xl[new], yl[new]);
Draw(lay2->rp, x2[new], y2[new]); new++; new %= 32;
***************************************************************
* doLayer3 ) - Gère le scrolling du SuperLayer * ***************************************************************
void doLayer3(void)

static SHORT posx = 0, posy = 0, dirx = -2, diry = -1;
if ((posx = 0) Il (posx >= SUPER_W-LAY3_W-2)) dirx - -dirx;
if ((posy = 0) Il (posy >= SUPER_H-LAY3_H-1)) diry =- diry;
ScrollLayer(NULL, lay3, dirx, diry); posx += dirx; posy += diry;
}
***************************************************************
* C'est fini !î! * ***************************************************************
Pur Ma.
Comme disait mon grand-père, après la théorie vient la pratique. Et puisque l’on sait maintenant tout sur le fonctionnement du clavier, ne pensez-vous pas qu’il est grand temps de mettre ces nouvelles connaissances en application ? No problemo.
Le programme qui suit peut paraître démesurément grand ou en tout cas, hors de proportion avec une gestion simple du clavier. Il n’en est rien : la gestion elle-même s’effectue en quelques de lignes de code à peine. Ce qui prend de la place, c’est toute la partie d’initialisation. Car pour obtenir un résultat tangible, il fallait que l’on puisse voir à l’écran ce qui se passe lorsque l’on appuie sur une touche. Aussi ai-je dû initialiser un RastPort et une BitMap, ceci afin de pouvoir utiliser la fonction Text() de la graphics.library et donner quelques indications visuelles. De même, la sauvegarde du contexte hardware actuel et sa restauration en fin de programme prennent quelques lignes supplémentaires... Les fainéants, qui sont toujours débrouillards lorsqu’il s’agit de ne pas travailler, pourront éviter de recopier ces lignes, pour ne plus se consacrer qu’à l’essentiel (NDLR : ou bien s’abonner avec disquette !).
L’ESSENTIEL
Pour la partie qui nous intéresse aujourd’hui, l’essentiel se limite à 1 initialisation des deux CIAs (le premier pour l’interruption clavier, le second pour le Timer), aux deux routines d’interruptions elles- mêmes (Newlrq2 et Newlrqb), ainsi qu’aux routines GetKey et TestKey.
S’il n’est même pas besoin de rappeler pourquoi l’on utilise le premier CIA (cf. ANT numéro 26), on peut à juste titre se demander pourquoi l’on utilise également le second... Pour, une fois de plus, une raison qui est vraiment toute bête.
En effet, si l’on utilise le premier CIA à la fois pour l’interruption clavier et l’interruption timer, deux cas peuvent se présenter : soit la gestion du clavier est suffisamment rapide et elle se termine avant que l’interruption timer ne se déclenche, auquel cas tout ira bien, soit elle est trop lente et l’interruption timer surviendra pendant l’interruption clavier. Les deux étant de même niveau pour le 68000 (niveau 2), l’interruption timer devra attendre que l’interruption clavier soit terminée avant d’être traitée, d’où une possible perte d’information (le processeur clavier rentrant alors dans une phase de correction d’erreur, re-cf. ANT numéro 26). Le CIA-B quant à lui provoque une interruption de niveau 6 ; en l’utilisant, on est donc sûr qu’elle sera de toute façon immédiatement prise en compte par le 68000, même si elle devait survenir pendant celle de niveau 2. Notez au passage et tout-à-fait dans un autre domaine que pour ces mêmes raisons, il est préférable d’utiliser le CIA-B pour réguler le "stepping delay" du contrôleur de disquette, les interruptions DSKBLK (Disk Block) et DSKSYNC (Disk Synchro) étant respectivement de niveaux 1 et 5...
Le timer est programmé avec la valeur 120, ce qui correspond à (exactement) 85,125 microsecondes sur un Amiga PAL et 85,90 microsecondes sur un Amiga NTSC (cf. Cette fois-ci l’ANT numéro
23) . Plus précis, tu meurs. On atteint ainsi et quoiqu’il arrive le délai minimum de 85 microsecondes recommandé par les concepteurs de 1 Amiga, quelle que soit la version du KickStart et le microprocesseur utilisé (ce programme tourne sans aucun problème sur un A3000 25, ce qui prouve bien qu’il est parfaitement compatible !).
Tiens, en parlant de clavier et de timer, je ne peux m’empêcher d ouvrir ici une petite parenthèse pour vous narrer une anecdote intéressante... Il est écrit partout dans les RKM que le keyboard.device utilise le Timer A du CIA-A pour gérer le
CLAVIER (II)
handshaking du clavier, et tout le monde, y compris votre serviteur, l’a cru et rapporté dans plusieurs articles. Or, il n’en est rien ! Comme on peut s’en rendre compte en traçant la routine d’interruption de niveau 2, ce timer n’est absolument pas utilisé du tout par le système (tout au moins dans sa version 1.3 ; qu’en est-il de la 2.0 ? Mystère et boules de gomme), lequel système se contente de compter sur la vitesse d’exécution de sa routine pour être sûr de retomber sur ses pattes ! Peut-être d’ailleurs est-ce là la raison d’une fourchette aussi importante (il y a loin de 85 us à 145 ms...) : on s’assure ainsi de la compatibilité avec tout type de microprocesseur... Je sais bien que tout le monde s’en fout, mais il me semblait important de révéler la supercherie à la face du monde. Fin de la parenthèse et retour à des considérations nettement plus matérielles.
LA MATRICE CLAVIER
Or donc, ce programme permet d’obtenir indifféremment soit le code de la dernière touche appuyée, soit l’état d’une touche particulière (enfoncée ou non), ce qui permet, ô joie exquise, de gérer le multi- touche.
Le premier s’obtient en appelant la routine GetKey : l’interruption clavier engrange au fur et à mesure qu’elle les récolte, tous les codes des touches appuyées dans un buffer dont la taille a été arbitrairement fixée à 128 octets, et GetKey se contente de les en ressortir en ordre inverse, à raison d’un par appel. Si le buffer est vide, GetKey renvoie -1.
Le remplissage du buffer est donc séquentiel et s’arrête dès que celui-ci est plein. Il existe évidemment de bien meilleurs algorythmes (le "buffer tournant" pour ne citer que lui) mais celui-ci présente l’avantage indéniable d’être à la fois rapide et simple à programmer. Jeu : amusez-vous à programmer une routine Clearlnput qui se charge de "vider" le buffer, sans altérer son contenu (une seule ligne de code suffit amplement !).
L’état d’une touche donnée s’obtient en appelant la routine TestKey, le code de la touche à tester étant placé dans dO.W. Au retour, le bit Z de CCR est positionné à 1 si la touche est actuellement appuyée et effacé sinon. La méthode est tout aussi simple, bien que moins courante : on utilise un second buffer, baptisé "matrice clavier", dont chaque bit représente l’état d’une touche (si le bit est mis, la touche est effectivement enfoncée). Ce buffer est évidemment remis à jour à chaque interruption en provenance du clavier.
Comment ça marche ? Les codes touches pouvant être compris entre $ 00 et $ 7F (les codes $ 80 à $ FF étant réservés pour des cas particuliers, comme par exemple le signalement d’une erreur de synchronisation), 128 bits sont nécessaires, soit seulement (128 8) = 16 octets pour représenter le clavier entier. Le code de la touche concernée sert d’index lors de l’accès à la matrice. Le calcul est très simple : (code 8) donne le numéro de l’octet dans la matrice et (code MOD 8) donne le numéro du bit dans cet octet. Un exemple concrêt sera peut-être plus efficace.
Soit à accéder au bit représentant la touche ESC dans la matrice. Le code-clavier de ESC est $ 45. On calcule ($ 45 8) = 8 et ($ 45 MOD
8) = 5. La touche ESC est donc représentée par le bit numéro 5 de l’octet numéro 8 de la matrice.
Un autre exemple ? Bon, d’accord, mais c’est bien parce que c’est- vous. Juste le temps de modifier une variable, et je suis à vous... CODE = &H5F : GOTO Exemple. Voilà, ça y est, merci.
Soit à accéder au bit représentant la touche HELP dans la matrice. Le code-clavier de HELP est $ 5F. On calcule ($ 5F 8) = 11 et ($ 5F MOD 8) = 7. La touche HELP est donc représentée par le bit numéro 7 de l’octet numéro 11 de la matrice.
Cette technique est très rapide en assembleur, puisqu’une division par 8 du code s’obtient par un décalage logique de 3 bits vers la droite (instruction LSR) et que le modulo par 8 s’obtient par une simple
instruction AND 7 (de même que le modulo par 4 s’obtient par AND 3, que le modulo par 16 s’obtient par ANE) 15, etc. Essayez, vous verrez bien ! Ca marche avec toutes les puissances de 2).
La routine d’interruption clavier n’a donc plus qu’à positionner (respectivement effacer) le bit de la matrice correspondant à la touche appuyée (respectivement relâchée). TestKey pour sa part se contente de tester le bit correspondant au code touche passé en paramètre. Notez que l’instruction BTST positionne Z à 1 si le bit testé était à 0 et inversement. Il faut donc inverser Z avant de revenir au programme appelant, ce qui se fait très simplement avec l’instruction EORLB -l,CCR (qui n’est pas une instruction privilégiée, c’est EOR to SR qui l’est). On aurait tout aussi bien pu convenir depuis le début que TestKey positionnerait Z à 0 si la touche testée était appuyée, mais ça me semblait beaucoup moins naturel...
ori.w $ c000,oldint(a5)
move.1 $ 68.w,oldirq2(a5)
move.1 $ 78.w,oldirq6(a5)
move.w $ 7fff,d0 ;
move.w dO,dmacon(a6) move.w dO,intena(a6) move.w dO,intreq(a6)
lea CIAA,aO ;
move.b $ 1F,ciaicr(aO) ; move.b $ 88,ciaicr(a0) ;
lea CIAB,aO ;
move.b ciacra(aO),dO andi.b %11000000, dO ori.b 900 0 0 0 10 0 0, dO move.b dO,ciacra(aO)
Maintenant, on s'installe l
Prépare le CIA-A : Interruptions off Interruption SP on
Prépare le CIA-B :
Timer A mode one-shot
Interruptions off ; Pré-programme le délai : Le timer démarre aussitôt, donc on attend la fin de ce premier décompte.
Interruption TA on
; Nouvelle CopperList on
Irq 2 (CIA-A)
Irq 6 (CIA-B)
; Copper, Bitplane, Blitter ; IRQs 2 et 6
Code clavier de Ctrl La touche est appuyée ? Non
Code clavier de Esc La touche est appuyée ? Oui, fin avec Ctrl-Esc
Touche appuyée ?
Move.b
$ lF,ciaicr(aO) ;
Voilà, juste un
mot pour finir : ne faîtes pas attention à la manière
move.b
DELAI,c iatalo(aO)
dont i’affiche
le contenu de la matrice entière dans la boucle
move.b
0,ciatahi(a0) ;
principale, les premières inspirations ne sont pas forcément toujours
.wait
btst beq. S
0,ciaicr(aO) ; .wait j
les meilleures...
Asta la vista, baby !
Move.b
$ 81,ciaicr(aO) ;

; Exemple de programmation du Clavier.
Move. 1
NewCop,copllc(a6)

move.w
d0,copjmpl(a6)
; 1991, Loïc
Far pour Amiga NewsTech. Aule Raillete Riserveude.
Move.1
NewIrq2,$ 68.w ;

move.1
NewIrq6,$ 7 8.w ;
opt
o+, ow-
move.w
$ 83c0,dmacon(a6)
incdir
"include:"
move.w
$ e008,intena(a6)
include
"graphie s rastport.i"
include
"hardware custom.i"
f
include
"hardware cia.i"
movea.1
_GfxBase(pc),a6 ;
include
"exec exec_lib.i"
Wait
btst
6,CIAA+ciapra
include
"graphics graphics_lib.i"
beq
Fini
. ************************************
moveq
$ 63,dO
CALLSYS MACRO
bsr
TestKey ;
IFNC
",' 2'
bne. S
.noCtrl ;
movea.1
2,a6
moveq
$ 45,dO
ENDC
bsr
TestKey ;
jsr
LVO l(a6)
beq
Fini ;
ENDM
.noCtrlbsr
GetKey ;

bmi. S
.1
Custom EQU
$ dff000
CIAA EQU
$ bfe001
lea
buf1+19(pc),a0 ;
CIAB EQU
$ bfd000
bsr
Hex8
DELAI EQU
120 ; Délai pour 85 s (en PAL; NTSC=86 s)
KBSIZE EQU
128 ; Taille du buffer clavier
.1
lea
rport(pc),al
moveq
10,dO
moveq
20,dl
rsreset
CALLSYS
Move
oldcopl rs. 1
1 ; Liste Copper Système 1
lea
rport(pc),al
oldcop2 rs. 1
1 ; Liste Copper Système 2
lea
buf1(pc),aO
olddma rs.w
1 ; DMACON Système
moveq
21,dO
oldint rs.w
1 ; INTENA Système
CALLSYS
Text
oldirq2 rs. 1
1 ; IRQ Level 2 Système
oldirq6 rs.l
1 ; IRQ Level 6 Système
lea
rport(pc),al ;
keymat rs.b
16 ; Matrice clavier
moveq
10,dO
keybuf rs.b
KBSIZE ; Buffer clavier
moveq
40,dl
keypos rs.w
1 ; Position dans le buffer
CALLSYS
Move
VARSIZE rs .w
0
lea
rport(pc),al
lea
titre(pc),a0
moveq
9,d0
Start lea
VARS(pc),a5
CALLSYS
Text
lea
gfxname(pc),al ; Ouvre la graphies.library
lea
keymat(a5),a2
moveq
0, dO
moveq
0,d2
CALLSYS
OpenLibrary,$ 4.w
MatLoop lea
rport(pc),al
move.1
d0,_GfxBase
moveq
10,dO
beq
NoGfx
move.w
rp_cp_y(al),dl
movea.1
dO, a6
addq.w
8,dl
move.1
$ 26(a6),oldcopl(a5)
CALLSYS
Move
move.1
$ 32(a6),oldcop2(a5)
lea
buf2(pc),aO
lea
rport(pc),al ; Initialise le RastPort
move.w
d2,dl
CALLSYS
InitRastPort
bsr. S
Hex4
move.1
bitmap,rport+rp_BitMap
moveq
0,d3
move.1
ecran,dO ; Initialise la CopperList
moveq
0, d4
move.w
dO,CopBpl+6
bset
d2,d4
swap
dO
MatLop2 move. B
I(a2,d3.w),d5
move.w
dO,CopBpl+2
lsl .w
8,d5
or .b
0(a2,d3.w),d5
lea
Custom,a6 ; Sauve la configuration système
move.w
dmaconr(a6),olddma(a5)
moveq
'-',dO
ori .w
$ 8200,olddma(a5)
and.w
d4,d5
move.w
intenar(a6),oldint(a5)
beq. S
.non
Prépare a6
Oui, affiche son code
Affiche la matrice
n
?
Moveq
'*',d0
.non
move.b
dO,(aO)+
addq.w
2,d3
empi.w
16,d3
bit .s
MatLop2
lea
buf2(pc),aO
lea
rport(pc) ,al
moveq
9, dO
CALLSYS
Text
addq.w
1, d2
empi.w
16,d2
bit. S
MatLoop
bra
Wait
Hex8
move.w
dO, dl
lsr .b
4, dl
bsr. S
Hex4
move.w
dO, dl
Hex4
andi.b
$ f,dl
empi.b
9, dl
ble. S
.1
addq.b
7, dl
.1
addi.b
'0',dl
move. B rts
dl,(aO)+
bufl
dc. b
"Dernière tou
buf2
de .b
"x--------"
titre
de .b
" 01234567"
Fini
lea
Custom,a6
move.w
$ 7fff,dO
move.w
dO,dmacon(a6)
move.w
dO,intena(a6)
move.w
dO,intreq(a6)
* *********
; Restaure le système
lea
CIAA,aO
move.b
ciaicr(aO) ,d0
btst
3, dO
;
Interruption clavier ?
Beq. S
.ret
moveq
0, dO
move.b
ciasdr(aO),d0

Lit la touche reçue
ori .b
$ 40,ciacra(a0)
;
Met SP en sortie (hanshaking)
bset
0,CIAB+ciacra
'
Démarre le Timer A du CIA-B
lea
VARS(pc), al
not .b
dO
ror.b
1, dO
move.w
dO, dl
andi.w
$ 7f,dl
lsr .w
3, dl
;
dl = Code 8
move.w
d0,d2
andi.w
7,d2

d2 = Code MOD 8
lea
keymat (al) ,a0
bclr
7, dû
bne. S
.KeyUp
bset
d2,0(a0,dl.w)
;
Touche enfoncée : met le bit.
Move.w
keypos(al),dl
i
et insère le code-touche
cmpi.w
KBSIZE,dl
;
dans le buffer clavier.
Bge.s
.ret
addq.w
l,keypos(al)
lea
keybuf(al) ,a0
move.b
dO,(a0,dl.w)
bra. S
.ret
bclr
d2, 0 (a0,dl.w)
;
Touche relâchée : efface le
bit.
• ret move.w $ 8,Custom+intreq Irq2Retmovem. 1 (sp)+,d0-d2 a0-al rte
move.b $ 1F,CIAA+ciaicr move.b $ 9F,CIAA+ciaicr move.b $ 1F,CIAB+ciaicr move.b $ 9F CIAB+ciaicr
move.l oldirq2(a5),$ 68.w move.l oldirq6(a5),$ 78.w
move.l oldcopl(a5),copllc(a6) move.l oldcop2(a5),cop21c(a6) move.w dO,copjmpl(a6)
move.w olddma(a5), dmacon(a6) move.w oldint(a5),intena(a6)
movea.1 _6fxBase(pc),al CALLSYS CloseLibrary,$ 4.w
Newlrq6movem. 1 dO aO-al, - (sp)
lea
move.w btst beq. S and.w btst beq. S
lea
move.b btst beq. S
Custom,aO intenar(aO), dO 14,dO Irq6Ret
intreqr(aO),d0 13,dO Irq6Ret
CIAB,al ciaicr(al),d0 0,d0 .ret
Bit INTEN mis ? Interruption CIAB ?
Interruption Timer A ?
; Met SP du CIA-A en sortie
andi.b $ bf,CIAA+ciacra ,
.ret move.w $ 2000,intreq(aO) Irq6Ret movem. 1 ( sp)+, dO aO-al rte
NoGfx
0, dO
moveq
rts
* ***********************************
GetKey
move.w
keypos(a5),d0
subq.w
1, dO
bmi. S
.nokey
move.w
dO,keypos(a5)
lea
keybuf(a5),a0
move.b
(a0,d0.w),d0
ext .w
dO
.nokey
rts
Renvoie dans dO.w le code de la dernière touche appuyée ou -1 si le buffer clavier est vide.
VARS ds. B
_GfxBase dc.l gfxname de. B even
rport ds. B bitmap dc.w
dc. l
VARSIZE
0
"graphies.library",0
rp_SIZEOF ; RastPort pour TextO
40,256,1,0
écran,0,0,0,0,0,0,0
Teste si la touche dont le code est dans dO.w est appuyée et positionne Z en conséquence (Z=l -> touche appuyée)
Tes tKey move.w d0,dl 3,d0 7, dl
keymat (a5) ,a0 dl,(a0,d0.w)
-l,ccr ; inverse (entre autres) Z 1
section CopperList,DATA_C
NewCop dc.w
dc. w de .w
dc. w de .w CopBpl dc.w de .w CopEnd de. 1
diwstrt, ddfstrt, bplconO, bplconl, bpllmod, bplpt+0, color+0, -2
$ 2981,
$ 0038,
$ 1200
$ 0000,
$ 0000,
$ 0000,
$ 0000,
diwstop,
ddfstop,
bplcon2, bpl2mod, bplpt+2, color+2.
$ 29cl
$ 00d0
$ 0000
$ 0000
$ 0000
$ 0fff
lsr .w andi.w lea btst eori. B rts
; IRQ 2 (CIA-A, clavier)
Newlrq2 movem. 1 d0-d2 a0-al, - (sp)
lea Custom, aO
move.w intenar(aO),d0
btst 14,dO
beq.s Irq2Ret
and.w intreqr(aO),d0
btst 3,dO ;
beq.s Irq2Ret
section Screen,BSS_C écran ds.b $ 2800 ; écran 320x200, 1 bitplan
• *******************
END
Bit INTEN mis ?
Interruption n°3 ?
L
EQUESTE
Salut à tous ! Avant que de commencer à éplucher votre courrier toujours plus abondant, voici quelques recommandations qui nous passent par la tête, comme ça, sans prévenir.
D abord et le plus important, il est complètement inutile de joindre une enveloppe timbrée libellée à votre adresse dans l’espoir d’une réponse personnelle : nous n’avons
absolument pas le temps de répondre à chacun d’entre vous, même avec toute la meilleure volonté du monde. Faîtes donc des économies, et cessez de faire grossir notre collection de timbres...
Deuxièmement, évitez les questions du style "mon imprimante XYZ ne fonctionne pas sur mon Amiga 500 avec 2 mégas de Ram et un disque dur alors que chez mon copain qui a un 2000, si" (rigolez pas, j’en reçois plein). D’une part, je m’en fous royalement et d’autre part, je n’y puis rien.
Enfin, si vous joignez un programme qui ne marche pas et que vous espérez que l’on déboguera pour vous, n’attendez pas une réponse dans les trois jours... Donnez-nous d’abord le temps de... trouver le temps de nous pencher sur la question et de repérer le bug (en supposant qu’on y arrive !).
Voilà. On terminera en vous rappelant l’adresse à laquelle votre courrier doit nous parvenir (certains trouvent encore le moyen de confondre rédaction et service abonnements) :
Amiga NewsTech - Requester 5, rue de la Fidélité 75010 Paris
Merci de votre attention.
Bonjour. Connaissant le Basic et ayant quelques notions d’assembleur sur une autre machine, je souhaiterais maintenant apprendre l’assembleur sur Amiga. Je dois donc acquérir un certain nombre de logiciels et de livres. Quel est à votre avis la meilleure configuration (assembleur, débogueur, environnement permettant à fois de travailler avec l’assembleur et le débogueur) ? Et quels sont les livres nécessaires (initiation à l’assembleur, dictionnaire des mnémoniques, ouvrages détaillant le jeu d’instructions du 68000 ou le système...) ? Et où puis-je trouver ces livres ?
Benoît Kerdraon, Brest
D’accord, mais c’est la première et la dernière fois que nous répondons à ce genre de lettre : beaucoup de "débutants" sur Amiga sont dans votre cas, et 80% du courrier que nous recevons pose ces mêmes questions. Veuillez donc tous bien noter ce qui va suivre, on ne le répétera pas.
Le meilleur environnement de développement en assembleur est à notre humble avis, on n’a pas cessé de le dire, le Devpac version II de la société anglaise HiSoft : éditeur, assembleur et débogueur travaillent de concert et main dans la main et garantissent un développement rapide et sûr. Toutefois, de petits nouveaux font leur apparition depuis quelques temps, notamment AsmOne de l’allemand DMV-Verlag, pas mal non plus dans son genre. Pour les petites bourses, nous vous conseillons de vous tourner vers le domaine public : A68K, pour ne citer que lui, est un excellent assembleur (qui ne présente qu’un seul défaut, celui d’être incapable de produire un fichier exécutable sans passer par une phase supplémentaire de linkage).
Côté livres, en plus de l’ANT, il faudra (qui a dit hélas ?) Vous tourner du côte de Micro-Application : 'Bien débuter en Assembleur", 'Ee livre du langage-machine", 'La Bible de l Amiga"... vous permettront, une fois toutes les erreurs détectées et corrigées, de vous en sortir. Par la suite, si vous désirez vous attaquer plus avant au système multitâche, les 'Rom Kernal Manuals" (en 3 volumes) seront indispensables.
Divers ouvrages sur le 68000 lui-même existent çà et là, le meilleur étant - je pense - "Mise en oeuvre du 68000" par Christine Viellefond

?
Aux éditions Sybex. Sachez également que le mode d’emploi du Devpac contient un guide du MC 68000, véritable petit bijou que tout programmeur en assembleur se devrait de posséder.
Chère ANT, je me permets de vous écrire afin que vous puissiez apporter un peu de lumière au pauvre programmeur que je suis. Je voudrais connaître le moyen d’appler un programme systématiquement après que toutes les tentatives de recherche ont échouées et ce à partir de n ’importe quel Cll. Par exemple, on tape 'bonjour" et si le programme bonjour n’existe pas (ou bien s’il n’est pas trouvé dans le path courant), ce programme par défaut s’exécute pour afficher, par exemple, "tu t’as gouru. " Je cheche aussi à encapsuler un programme, comme pour IF, ELSE, ECHO... du Shell d’ARP (ASH), mais pas à la mainère du CSH, c ’est-à-dire un programme lancé, qui prend la main et utilise ses propres fonctions pour les exécuter et donc avec aucune modification possible. Ceci dans le but de créer une sorte de Shell qui serait adaptable au plaisir de chacun, mais qui prendrait moins de place sur disquette et éviterait de jouer au grille-pain pour ceux qui n ’ont qu ’un seul lecteur. Quelles sont les limites de Forbid() et Disable(), dans quelle mesure peut-on les utiliser sans risquer un effondrement du système ?
Quelques remarques avant de vous quitter. D’abord, quelques erreurs se sont glissées dans l’article de Loïc Far sur le MC 68000 : l’instruction MOVE générale se code comme suit :
15
14
13 12
11 10 9 8 7 6
5 4 3 2 1 0
o
0
SIZE
ADRESSEJEFFECTIVE
EFPECTXVE__.M3RESSE
où SIZE égale 01 pour un octet, 11 pour un mot et 10 pour un mot long, ADRESSEJEFFECTIVE est codée comme expliqué dans le premier article, ainsi que EFFECTIVE_ADRESSE, avec toutefois inversion des tribits, c’est-à-dire Registre (3 bits) + Code-Op (3 bits).
De plus, certaines instructions n’ont pas tous les modes d’adressage. Mais sinon, l’article était bienfait, et je le remercie de l’avoir écrit.
Olivier Garrigues, Lunel
Si l’on excepte le fait qu’ANT est masculin (on dit un Amiga NewsTech, hé oui, qui l’eût cru ?), votre lettre est exemplaire. Laissez- nous donc vous remercier comme vous le méritez.
Merci donc, et tout d’abord pour cette longue lettre elle-même, dont nous n’avons évidemment pu publier que quelques passages. Merci également pour les rectifications apportées à l’article de Loïc Far. Comme quoi personne n’est jamais parfait...
Désolé, mais nous ne sommes pour l’instant pas en mesure de répondre à vos questions sur le PATH et l’encapsulation de programmes... Avec quelques recherches, la première pourra sans doute être rapidement résolue (nous vous tiendrons au courant)... Quant à la seconde, je crains qu’il ne vous faille renoncer à cette idée. Une solution acceptable, aux résultats identiques, serait de profiter de la possibilité de résidence de quasiment toutes les commandes CLI : une fois en mémoire, elles y restent, et ce sont les mêmes segments de code qui sont réutilisés à chaque appel...
Forbid() interdit le multitâche, c’est-à-dire qu’Exec ne gère plus le partage du temps CPU entre les différentes tâches actives, gestion qui intervient à chaque interruption, lesquelles sont d’ailleurs toujours autorisées. Car c’est justement Disable() qui se charge de les interdire - et donc le multitâche avec. Le problème, c’est que certaines tâches particulières du système, comme le keyboard.de vice et le trackdisk.device, comptent énormément sur la disponibilité d’autres sous-tâches qui leur sont rattachées... Ainsi par exemple, si vous travaillez en mode multitâche et appelez Fobrid() ou Disable() pendant un accès disque, des erreurs de lecture peuvent survenir. Par contre, il n’y a aucune problème à interdire les interruptions, même pendant une très longue période, si votre programme s’approprie la machine entière (démo, jeu...). Le retour au système (si retour au système il y a...) ne posera aucun problème.
End If End If 0=P
Next
Centre At(,27)+"Y="+FONC$
Centre At(,29)+">>> Pressez une touche "
Clear Key : Wait Key
Loop
Procédure _GET_VALUE[N ,A$ ]
Do
' On met l'ancienne valeur dans le buffer clavier Put Key Str$ (N )
' On imprime le texte
Print A$ ; : Line Input " : ";B$
' Si pas de réponse -> la fin!
If B$ ="" : _THE_END : End If ' On essaie de tokeniser _TOKENISE[B$ ] : Exit If Not SYNT ' Un erreur, on boucle!
Print "On enlève les mouffles, et on retape l'expression. Merci."
Loop
' On calcule la belle valeur de retour EVALUE
End Proc[Param ]
Procédure _THE_END Edit End Proc
' PROCEDURES DE TOKENISATION Procédure EVALINIT
' Définition des operateurs, en ordre inverse OPE$ ="+PLUS-MINS*TIME DIVDAPOWR"
' Définition des fonctions
FUN$ =" X>VARX PI)PIPI VAR(}VARS2 SIN(JSINU1 COS(JCOSIl" FUN $ =FUN $ + " TAN(> TANG1 SQR(}SQRR1 L0G(}L0GG1 EXP(}EXPP1" FUN$ =FUN$ +" LN( LNNN1 ABS(>ABSS1 INT(>INTT1 SGN(}INTT1" FUN$ =FUN$ +" RND(}RNDD1"
End Proc
Procédure _TOKENISE[A$ ]
Procédure _TEVALUE[N]
Procédure _TOPERAND Procédure CHAR
' PROCEDURES DE CALCUL
Procédure EVALUE
PP=-1 : PPILE=-1 : SYNT=0 : EVALIT End Proc[PP (PP)]
Procédure EVALIT
On Error Goto _ERROR Repeat
Inc
PPILE :
Gosub PILE$ (PPILE)
Until
E
Pop Proc
_END:
E=1 : Return
_CONST
: Inc PP
: PP (PP)=PILE (PPILE) : Return
_PLUS:
Dec PP :
PP (PP)=PP (PP)+PP (PP+1) : Return
_MINS:
Dec PP :
PP (PP)=PP (PP)-PP (PP+1) ; Return
_DIVD:
Dec PP :
PP (PP)=PP (PP) PP (PP+1) ; Return
_TIME:
Dec PP :
PP (PP)=PP (PP)*PP (PP+1) : Return
_POWR:
Dec PP :
PP (PP)=PP (PP)APP (PP+1) : Return
_SINU:
EVALIT :
PP (PP)=Sin(PP (PP))
: Return
_COSI:
EVALIT :
PP (PP)=Cos(PP (PP))
: Return
TANG:
EVALIT :
PP (PP)=Tan(PP (PP))
: Return
_PIPI:
Inc PP :
PP (PP)=Pi : Return
_SQRR:
EVALIT :
PP (PP)=Sqr(PP (PP))
: Return
_LOGG:
EVALIT :
PP (PP)=Log(PP (PP))
: Return
_LNNN :
EVALIT :
PP (PP)=Ln(PP (PP))
: Return
_ABSS:
EVALIT :
PP (PP)=Abs(PP (PP))
: Return
_EXPP:
EVALIT :
PP (PP)=Exp(PP (PP) )
: Return
_INTT:
EVALIT :
PP (PP)=Int(PP (PP))
: Return
_RNDD:
EVALIT :
PP (PP)=Rnd(PP (PP))
: Return
_VARX:
Inc PP :
PP (PP)=XX : Return
_ERROR
: Résumé
_ERROR2
_ERROR2: PP (PP)=0.0 : SYNT=-1 : Return
End Proc
' Calcul du pas de progression des sinus STP =2*Pi NPAS
' Boucle de fabrication de la deformation For N=0 To NPAS-1 P =P +STP
Screen 1 : Cls 0 : Screen 2 : Cls 0
' Deformation en X, écran 0 -> écran 1 For Y=0 To SY-1
X=AMPXl *Sin(Y*AMPYl -P )
Screen Copy 0,0,Y,SX,Y+1 To 1,X,Y Next
' Deformation en Y, écran 1 -> écran 2 For X=0 To SX-1
Y=AMPY2 *Sin(X*AMPX2 -P )
Screen Copy 1,X,0,X+1,SY To 2,X,Y Next
' On peut copier dans la banque
Copy Logbase(0),Logbase(0)+SIZE To Start(10)+N*SIZE Next
' Efface les écrans de travail Screen Close 1 : Screen Close 2 Screen 0 : Cls 0
' Calcule la distance entre 1'écran 0 et la banque TL=SX 8
D=Start(10)-Logbase(0)
OY=D TL : OX=(D mod TL)*8
' Met les valeurs dans les registres AMAL
Amreg(0)=OX : Amreg(l)=OY : Amreg(2)=SY : Amreg(3)=NPAS
' Initialise l'animation Channel 0 To Screen Offset 0
A$ =A$ +"L: For R0=0 To RD;"
A$ =A$ +" Let X=RA;"
A$ =A$ +" Let Y=R0*RC+RB;"
A$ =A$ +" Next R0;"
A$ =A$ +" Jump L;"
' On peut démarrer et revenir en mode direct !
Amal 0,A$ : Amal On Direct
Procédure BONE[X,Y,SX,SY,C]
Bar X-SX,Y-SY To X+SX,Y+SY For R=1 To C
Circle X-SX,Y-SY,R Circle X-SX,Y+SY,R Circle X+SX,Y-SY,R Circle X+SX,Y+SY,R Next End Proc
P a r F r a n ç i ) i s L i o n e i
Tiens, un blanc...
(ou plutôt un noir...)
Et si on en profitait de ces petits carrés pour caser de la pub, ça vous dérangerait beaucoup ?
Pensez aux conséquences et donnez-nous votre avis!
Par François Lia net bi A m i g a NewsTech
Règlement e t P rop o sition d ’ Article
r
1. ) La rubrique Transactor de Vamiga NewsTech est la rubrique écrite par les lecteurs, pour les lecteurs. Son but est de leur permettre de s’exprimer librement sur tout sujet qui les passionne, dans quelques langage de programmation que ce soit. Seule restriction : la Rédaction doit avoir la possibilité de tester le bon fonctionnement de tous les programmes fournis, complets ou simples routines d’illustration. Non mais.
2. ) Tout lecteur désirant participer à la rubrique Transactor devra envoyer son article sur disquette au format Amiga, en respectant les quotas définis aux
paragraphes 4 et 5. Les disquettes ne seront pas retournées, sauf demande expresse et écrite de l’auteur, et encore.
3. ) Tout article publié sera rémunéré au tarif forfaitaire de 1, 500 F HT les deux pages ; un article de plus de deux pages sera publié en plusieurs fois, à concurrence de trois épisodes maximum. Le paiement a lieu le mois suivant celui de la parution. Les auteurs des articles retenus pour parution seront directement prévenus par téléphone.
4. ) Les articles doivent parvenir au format ASCII standard (utilisez un éditeur de textes ou l’option de sauvegarde "text only" ou "ASCII" de votre traitement de texte). Les programmes illustrant les articles, qu’ils soient complets ou de simples routines d’exemple, doivent également être fournis sous forme ASCII, et éventuellement en format "brut" le cas échéant Basic, AMOS...). Le(s) fichier(s) exécutable(s) doivent se trouver sur la disquette. L’auteur doit fournir à TANT la possibilité de recompiler ou d’interpréter ses programmes sans difficulté (joindre au besoin une version "run-only" du langage utilisé).
5. ) La taille totale du fichier ASCII donne le nombre de signes de votre article ; une page de l’ANT contient en moyenne 7, 000 signes de texte. Une colonne de listing contient 80 lignes de 65 caractères de large. Un programme de 160 lignes occupe donc une page entière. Les programmes en assembleur particulièrement longs peuvent être publiés en trois colonnes de 40 caractères chaque (240 lignes par page).
6. ) Toute proposition d’article pour Transactor devra être accompagnée du bon ci-dessous, découpé ou photocopié, mais en aucun cas reproduit à la main.
7. ) Toute proposition d’article pour Transactor entraîne l’acceptation par l’auteur que les programmes joints soient placés sur la disquette d accompagnement de l’ANT. L’auteur doit préciser dans des commentaires en tête de listing s’il place son programme dans le Domaine Public ou s’il désire conserver son copyright. Aucun commentaire implique la mise en Domaine Public.
8. ) Ni TANT, ni Commodore Revue SARL, ni les auteurs collaborant à la rubrique Transactor ne sauraient être tenus pour responsables en cas de dommages quelconques survenus à l’ordinateur, suite à une mauvaise utilisation des documents (textes et programmes) publiés dans cette rubrique.
9. ) Toute proposition d’article pour Transactor entraîne l’entière acceptation par l’auteur de ce règlement, et sans discuter.
Abonnement à JL’ANX et Anciens Numéros
C’est nouveau, ça vient de sortir : si vous êtes déjà abonné, vous pourrez parrainer des copains à vous. Le deal est simple : vous nous trouvez cinq nouveaux z’amis et vous empochez un digitaliseur sonore PerfectSound offert par CIS (merci, CIS). De plus, tout le monde recevra un logiciel de téléchargement ChanelSoft gratuit. Alors qu’est-ce que vous attendez ?
Vous pouvez également commander les anciens numéros de l’ANT, histoire de compléter votre collection. Il vous en coûtera 45 F pièce ou 60 F avec sa disquette. Y’a un bon de commande là- dessous, servez-vous en.
Bon de commande à découper ou photocopier (pas de recopie manuelle SVP) et à retourner correctement rempli et accompagné de votre règlement à MCM Europe, 16, Quai Jean-Baptiste Clément, 94140 Alfortville, France.
OUI, je m'abonne à Amiga NewsTech. Je choisis la formule :
? 1 an (11 numéros) sans disquette 350 FF
? 1 an (11 numéros) avec disquette 600 FF
? (cochez cette case pour un ré-abonnement)
Je commande les anciens numéros suivants :
?
N°20
(?
Avec
disquette)
?
Nc
’ 2 5
(? Avec
disquette)
?
N°21
(?
Avec
disquette)
?
Nc
26
(? Avec
disquette)
?
N°22
(?
Avec
disquette)
?
Nc
'27
(? Avec
disquette)
?
N°23
(?
Avec
disquette)
?
N°24
(?
Avec
disquette)
au tarif
unitaire
de 45 F (60 F
avec
disquette), pour un total
Nom : .
Prénom : .
Adresse : .
Code Postal : ... Ville : .. Pays :
Signature (des parents pour les mineurs) :
1
continue de tracer dans les octets
* et si ils sont tous fait on s'en va.
Addq.l l,d3
dbf d7,LOOP_CALCUL_FONCTIONEACH BYTE
lign:bottom;"> (?
Avec
disquette)
?
Nc
26
(? Avec
disquette)
?
N°22
(?
Avec
disquette)
?
Nc
'27
(? Avec
disquette)
?
N°23
(?
Avec
disquette)
?
N°24
(?
Avec
disquette)
au tarif
unitaire
de 45 F (60 F
avec
disquette), pour un total
Nom : .
Prénom : .
Adresse : .
Code Postal : ... Ville : .. Pays :
Signature (des parents pour les mineurs) :
1
continue de tracer dans les octets
* et si ils sont tous fait on s'en va.
Addq.l l,d3
dbf d7,LOOP_CALCUL_FONCTIONEACH BYTE

Click image to download PDF

AMIGA NEWS TECH numero 28 (12-1991)

Merci pour votre aide à l'agrandissement d'Amigaland.com !


Thanks for you help to extend Amigaland.com !
frdanlenfideelhuitjanoplptroruessvtr

Connexion

Pub+

31.4% 
18.4% 
6.2% 
5% 
4.9% 
4.5% 
2.8% 
2% 
1.4% 
1.1% 

Today: 35
Yesterday: 104
This Week: 338
Last Week: 762
This Month: 2894
Last Month: 2931
Total: 63962

Information cookies

Cookies are short reports that are sent and stored on the hard drive of the user's computer through your browser when it connects to a web. Cookies can be used to collect and store user data while connected to provide you the requested services and sometimes tend not to keep. Cookies can be themselves or others.

There are several types of cookies:

  • Technical cookies that facilitate user navigation and use of the various options or services offered by the web as identify the session, allow access to certain areas, facilitate orders, purchases, filling out forms, registration, security, facilitating functionalities (videos, social networks, etc..).
  • Customization cookies that allow users to access services according to their preferences (language, browser, configuration, etc..).
  • Analytical cookies which allow anonymous analysis of the behavior of web users and allow to measure user activity and develop navigation profiles in order to improve the websites.

So when you access our website, in compliance with Article 22 of Law 34/2002 of the Information Society Services, in the analytical cookies treatment, we have requested your consent to their use. All of this is to improve our services. We use Google Analytics to collect anonymous statistical information such as the number of visitors to our site. Cookies added by Google Analytics are governed by the privacy policies of Google Analytics. If you want you can disable cookies from Google Analytics.

However, please note that you can enable or disable cookies by following the instructions of your browser.

Visitors

Visite depuis
03-10-2004
Visite depuis
23-02-2014