j'ouvre un sujet spécifique pour les dev en Turbo Pascal v3 sur CPC6128 et 6128+ en CP/M3 (appelé aussi CP/M+). Cela me servira d'aide-mémoire et pourra faire gagner du temps à ceux qui voudraient s'y essayer. Curieusement l'utilisation spécifique du TP3 sur CPC6128 ne semble pas très documentée (le CP/M et TP3 le sont très bien par contre). Pourtant il y a des choses très sympa à faire. Mon objectif à terme est le dév d'un jeu d'aventure texte/image dans cet environnement.
Déjà pourquoi développer en Turbo-Pascal sur CPC? On pourrait aussi se dire pourquoi utiliser encore ces bons vieux CPC ;D Chacun à sa réponse. Mais pourquoi utiliser un compilateur Pascal qui a plus de 35 ans et compile sur CPC à l'heure des cross-compilateurs modernes? Parce que je trouve intéressant d'utiliser un outil de l'époque qui tourne entièrement sur CPC. Parce que le TP3 est un compilateur très sympa, très compact et très fiable. Oui il y manque pas mal de chose vs les compilateurs Pascal plus récents mais l'essentiel y est. Et puis ça m'amuse de me pencher aussi sur le CP/M, cet ancêtre du MS/DOS que j'avais totalement ignoré à l'époque, cette époque où on pouvait 'tout' connaitre d'un ordinateur et de ses logiciels. Epoque intéressante et révolue à l'heure des machines, des OS et logiciels monstrueusement obèses. Ici 128ko et un processeur Z80A à 4MHz.
Mon environnement est composé d'un CPC6128+ avec un lecteur GOTEK externe + W10 avec WinAPE
Ce que permet le TP3 sur CPC6128 et 6128+ : - Des programmes d'un seul bloc jusque 61Ko - Des projet de plus de 61ko avec la gestion des "overlays" de programmes - Accès total au firmware - Fichiers séquentiels indexés, fichiers binaires... - Intégration facile de code assembleur - Appel facile à des programmes assembleurs externes avec passages de paramêtre entrants/sortants - Pointeurs - Structures de données complexes - Adresses absolues de mémoire pour les variables - Une éditeur pleine page très pratique (une fois qu'on maitrise les raccourcis clavier!) etc.
L'émulateur WinAPE apporte - La possibilité d'utiliser NotePad++ pour éditer les sources avec coloration syntaxique - Le mode Turbo et accélération de la vitesse pour des compilations quasi instantanées - Surtout la possibilité des tester très facilement et debugger des routines ASM appelées par le Pascal etc...
Pour une première approche de l'environnement TP3/CPM+/CPC6128 :
Dernière édition par Nemo59 le 11 Nov 2020, 12:15, édité 2 fois.
Le TP3 et CPM+ permettent d'accéder aux fonctions du firmware. Mais comme le CPM+ gère un système particulier de banque mémoire (ce qui permet d'avoir 61ko de ram linéaire pour programmer, on verra plus tard çà en détail) il y a une subtilité. Les appels doivent passer un vecteur particulier à l'adresse #fc5a
Par exemple masquer le curseur texte qui se fait par un CALL #BB84 doit être appelé en TP3 par un CALL #FC5A DW #BB84 En TP3 ça peut se coder comme çà (HidTxtCur pour Hide Text Cursor) :
Code :
Procedure HidTxtCur; Begin InLine($cd/$fc5a/$bb7e); End;
Le programme Grafik3.inc fourni avec le TP3 utilise çà. Je l'ai réécris comme suit en ajoutant de nouvelles commandes (work in progress). L'idée est de créer des unités thématique UGraph/USound/UKeyboard etc... (même si les UNITS Pascal n'apparaissent qu'avec les versions ultérieures de TP).
J'avais au départ repris les noms des commandes du Firmware mais c'est très verbeux. Je suis parti sur des instructions par blocs de 3 lettres (qui vont sans doute changer un peu l'usage).
Un exemple de programme (résolution du parcours du cavalier) :
Procedure SetTxtCur(X,Y:Byte); Begin InLine($3a/X/$67/$3a/Y/$6f/$cd/$fc5a/$bb75); End;
Procedure GetTxtCur(Var X,Y:Byte); Begin InLine($cd/$fc5a/$bb78/$7c/$32/X/$7d/$32/Y); End;
Procedure DspTxtCur; Begin InLine($cd/$fc5a/$bb7b); End;
Procedure HidTxtCur; Begin InLine($cd/$fc5a/$bb7e); End;
Procedure SetTxtPap(Paper:byte); Begin InLine($3a/Paper/$cd/$fc5a/$bb96); End;
Procedure SetTxtPen(Pen:byte); Begin InLine($3a/Pen/$cd/$fc5a/$bb90); End;
Procedure IniGra; Begin InLine($cd/$fc5a/$bbba);End;
Procedure SetMod(Mode:Byte); Begin InLine($3a/Mode/$cd/$fc5a/$bc0e); End;
Function EncInk(InkNumber:Byte):Byte; Begin InLine($3a/InkNumber/$cd/$fc5a/$bc2c/$32/BGraph); EncInk:=BGraph; End;
Procedure SetInk(Ink,C1,C2:Byte); Begin InLine($3a/C1/$47/$3a/C2/$4f/$3a/Ink/$cd/$fc5a/$bc32); End;
Procedure SetBdr(C1,C2:Byte); Begin InLine($3a/C1/$47/$3a/C2/$4f/$cd/$fc5a/$bc38); End;
Procedure DrwScrFldBox(EncodedInk:Byte; Adr:Integer; WidthBytes,Height:Byte); Begin InLine($3a/EncodedInk/$4f/$2A/Adr/$3a/WidthBytes/$57/$3a/Height/$5f/$cd/$fc5a/$bc47); End;
Procedure DrwScrHorLin(EncodedInk:Byte; XStart,XEnd,Y:Integer); Begin Inline($3a/EncodedInk/$ed/$5b/XStart/$ed/$4b/XEnd/$2a/Y/$cd/$fc5a/$bc5f); End;
Procedure DrwScrVerLin(EncodedInk:Byte; YStart,YEnd,X:Integer); Begin Inline($3a/EncodedInk/$ed/$5b/X/$ed/$4b/YEnd/$2a/YStart/$cd/$fc5a/$bc62); End;
Procedure GetScrDotAdr(X,Y:Integer; Var Addr:Integer; Var Mask:Byte); Begin InLine($ed/$5b/X/$2a/Y/$cd/$fc5a/$bc1d/$22/IGraph1/$79/$32/BGraph); Addr:=IGraph1; Mask:=BGraph; End;
Procedure MovAbs(x,y:Integer); Begin InLine($2a/x/$eb/$2a/y/$cd/$fc5a/$bbc0) End;
Procedure MovRel(x,y:Integer); Begin InLine($2a/x/$eb/$2a/y/$cd/$fc5a/$bbc3) End;
Procedure SetOrg(x,y:Integer); Begin InLine($2a/x/$eb/$2a/y/$cd/$fc5a/$bbc9) End;
Procedure SetWinWdt(x1,x2:Integer); Begin inline($2a/x2/$eb/$2a/x1/$cd/$fc5a/$bbcf) End;
Procedure SetWinHht(y1,y2:Integer); Begin InLine($2a/y2/$eb/$2a/y1/$cd/$fc5a/$bbd2) End;
Procedure DrwLinAbs(x,y:Integer); Begin InLine($2a/x/$eb/$2a/y/$cd/$fc5a/$bbf6) End;
Procedure DrwLinRel(x,y:Integer); Begin InLine($2a/x/$eb/$2a/y/$cd/$fc5a/$bbf9) End;
Procedure DrwPntAbs(x,y:Integer); Begin InLine($00/$ed/$ff/$2A/x/$eb/$2A/y/$cd/$fc5a/$bbea/$ed/$ff) End;
Procedure DrwPntRel(x,y:Integer); Begin InLine($2A/x/$eb/$2a/y/$cd/$fc5a/$bbed) End;
Function GetPntAbs(x,y:Integer):Byte; Begin InLine($2a/x/$eb/$2a/y/$cd/$fc5a/$bbf0/$32/BGraph); GetPntAbs:=BGraph; End;
Function GetPntRel(x,y:Integer):Byte; Begin InLine($2a/x/$eb/$2a/y/$cd/$fc5a/$bbf3/$32/BGraph); GetPntRel:=BGraph; End;
Procedure SetGraPen(Pen:Byte); Begin InLine($3a/Pen/$cd/$fc5a/$bbde) End;
Procedure SetGraPap(Paper:Byte); Begin InLine($3A/Paper/$cd/$fc5a/$bbe4) End;
Procedure GetGraCur(Var X,Y:Integer); Begin InLine($cd/$fc5a/$bbc6/$22/IGraph2/$eb/$22/IGraph1); X:=IGraph1; Y:=IGraph2; End;
Procedure ClrGraWin; Begin InLine($cd/$fc5a/$bbdb) End;
Procedure DrwGraChr(Ch:char); Begin InLine($3a/Ch/$cd/$fc5a/$bbfc) End;
Procedure SetLinMsk(Mask:Byte); Begin InLine($3A/Mask/$cd/$fc5a/$bd4c) End;
Procedure SetPalMod1(c0,c1,c2,c3:Byte); Begin SetInk(0,c0,c0);SetInk(1,c1,c1);SetInk(2,c2,c2);SetInk(3,c3,c3); End;
Procedure DrwScrRec(E:Byte; x1,y1,x2,y2:Integer); Begin DrwScrHorLin(E,x1,x2,y1); DrwScrHorLin(E,x1,x2,y2); DrwScrVerLin(E,y1,y2,x1); DrwScrVerLin(E,y1,y2,x2); End;
Procedure SetTxtWin(c1,c2,l1,l2:Byte); Begin InLine($3a/c1/$67/$3a/c2/$57/$3a/l1/$6f/$3a/l2/$5f/$cd/$fc5a/$bb66); End;
Procedure GrafOut(ch:Char); Begin InLine($3a/ch/$cd/$fc5a/$bbfc); End;
Procedure SetTag; Begin If Not TagFlag Then Begin TagAddr:=ConOutPtr; TagFlag:=True; ConOutPtr:=Addr(GrafOut); End; End;
Procedure RmvTag; Begin If TagFlag Then Begin ConOutPtr:=TagAddr; TagFlag:=False; End; End;
Var x,y,i,j,Adr,Err: Integer; b,E0,E1,E2,E3,Mini,iMini,Total: Byte; PCav, nPCav: TCoord; Echiquier:Array[-1..10,-1..10] Of Boolean; Rep : String[2];
Begin PCav.x:=0; Repeat For i:=-1 To 10 Do For j:=-1 To 10 Do If (i In [1..8]) And (j In [1..8]) Then Echiquier[i,j]:=True Else Echiquier[i,j]:=False;
{Dessin de l'echiquier et fenetre resultat} SetPalMod1(1,1,1,1); SetBdr(1,1); SetMod(1); E0:=EncInk(0);E1:=EncInk(1); E2:=EncInk(2); E3:=EncInk(3); DrwScrRec(E3,19,20,180,181); DrwScrRec(E3,18,19,181,182); GetScrDotAdr(20,180,Adr,b); DrwScrFldBox(E1,Adr,40,160); For y:=1 To 8 Do For x:=1 To 8 Do Begin GetScrDotAdr(20*x,200-20*y,Adr,b); If (x Mod 2<>y Mod 2) Then DrwScrFldBox(E2,Adr,5,20) End; SetPalMod1(1,13,26,0); SetTag; SetGraPen(2); For x:=1 To 8 Do Begin MovAbs(16+x*40,30); Write(Char(x+64)); MovAbs(14,30+x*40); Write(x); End; RmvTag; HidTxtCur;
SetTxtWin(24,39,2,20); GotoXY(1,1); IF PCav.x<>0 Then Begin
{Resolution}
Echiquier[PCav.x,PCav.y]:=False; DrwScrRec(E3,7+20*PCav.x, 7+20*PCav.y,13+20*PCav.x,13+20*PCav.y); SetGraPen(3); SetGraPap(0); Repeat Mini:=9; iMini:=0; For i:=1 To 8 Do Begin nPCav.x:=PCav.x+Dep[i].x; nPCav.y:=PCav.y+Dep[i].y; Total:=0; If Echiquier[nPCav.x,nPCav.y] Then Begin For j:=1 To 8 Do If Echiquier[nPCav.x+Dep[j].x,nPCav.y+Dep[j].y] Then Total:=Total+1; If (Total<Mini) Or ((Total=Mini) And (Random(10)>5)) Then Begin Mini:=Total; iMini:=i End; End; End; If iMini<>0 Then Begin DrwScrRec(E3,9+20*PCav.x, 9+20*PCav.y,11+20*PCav.x,11+20*PCav.y); MovAbs(20+40*PCav.x,20+40*PCav.y); PCav.x:=PCav.x+Dep[iMini].x;PCav.y:=PCav.y+Dep[iMini].y; Echiquier[PCav.x,PCav.y]:=False; DrwLinAbs(20+40*PCav.x,20+40*PCav.y); End; Until iMini=0; DrwScrRec(E3,8+20*PCav.x, 8+20*PCav.y,12+20*PCav.x,12+20*PCav.y);
WriteLn('Entree : Repete'); WriteLn('Q : Quitte'); End Else Begin PCav.x:=1; PCav.y:=1; End; WriteLn('Position? Ex:C3'); DspTxtCur; ReadLn(Rep); Case UpCase(Rep[1]) Of 'A'..'H' : Begin PCav.x:=Ord(UpCase(Rep[1]))-64; If Not(Pcav.x In [1..8]) Then PCav.x:=1; Val(Rep[2],PCav.y,Err); If Not(PCav.y In [1..8]) Then PCav.y:=1; End; End; Until UpCase(Rep[1])='Q'; SetMod(2); SetInk(1,26,26); End.
TEnv = Record NbrSec: Byte; Sec: Array[1..5] Of TSection; End;
Procedure RazSnd; Begin InLine($cd/$fc5a/$bca7); End;
Procedure AddSndQue(Sound:TSound); Begin InLine($21/Sound/$cd/$fc5a/$bcaa); End;
Function TstSndQue(Chn:Byte):Byte; Var bSnd:Byte; Begin InLine($3a/Chn/$cd/$fc5a/$bcad/$32/bSnd); TstSndQue:=bSnd; End;
Procedure SetEnvVol(EnvNbr:Byte; Env:TEnv); Begin InLine($3a/EnvNbr/$21/Env/$cd/$fc5a/$bcbc);End;
Procedure SetEnvTon(EnvNbr: Byte; Env: TEnv); Begin InLine($3a/EnvNbr/$21/Env/$cd/$fc5a/$bcbf) End;
Procedure RlsChn(Channel:Byte); Begin InLIne($3a/Channel/$cd/$fc5a/$bcb3) End;
Exemple de programme :
Code :
Program Son; {$i USound.inc}
Var Sound,Sound2 : Tsound; Env,Env2: TEnv;
Begin
WriteLn('-> Debut du prgramme'); RazSnd;
With Env Do Begin NbrSec:=3 Or $80; { 'Or $80' permet la repetition de l'enveloppe} Sec[1].Cnt:=50; Sec[1].Siz:=-3; Sec[1].Tim:=1; Sec[2].Cnt:=1; Sec[2].Siz:=0; Sec[2].Tim:=40; Sec[3].Cnt:=150; Sec[3].Siz:=1; Sec[3].Tim:=1; End; SetEnvTon(1,Env);
With Env Do Begin NbrSec:=2 Or $80; Sec[1].Cnt:=10; Sec[1].Siz:= 4; Sec[1].Tim:=2; Sec[2].Cnt:=5; Sec[2].Siz:=-8; Sec[2].Tim:=2; End; SetEnvTon(2,Env);
With Env Do Begin NbrSec:=2 Or $80; Sec[1].Cnt:=20; Sec[1].Siz:= 4; Sec[1].Tim:=6; Sec[2].Cnt:=10; Sec[2].Siz:=-8; Sec[2].Tim:=2; End; SetEnvTon(3,Env);
With Env Do Begin NbrSec:=1; Sec[1].Cnt:=1; Sec[1].Siz:=0; Sec[1].Tim:=240; End; SetEnvVol(1,Env);
WriteLn('-> Fin du programme. Le Turbo Pascal ne fait deja plus rien!'); WriteLn(' Les bruitages s''effectuent en tache de fond'); WriteLn(' - 3 canaux stereos, enveloppes de volumes, de tons, bruits, repetitions.'); WriteLn(' - Gestion des ''rendez-vous'' entre canaux'); Repeat Until KeyPressed;
Bonjour, Je ne fais pas parti des personnes intéressées par l'utilisation du Pascal sur Amstrad, et encore moins sous CP/M. Cependant, l'information sur ce sujet est rarissime, donc je ne peux que te féliciter pour documenter tout cela ! Cela me rappelle, il y a quelques années sur ce meme forum, un certain "SPOKE" qui était très actif et faisait partager plein d'info intéressantes sur CP/M. Pour l'Histoire, avec un grand H !
Bonjour, Je ne fais pas parti des personnes intéressées par l'utilisation du Pascal sur Amstrad, et encore moins sous CP/M. Cependant, l'information sur ce sujet est rarissime, donc je ne peux que te féliciter pour documenter tout cela ! Cela me rappelle, il y a quelques années sur ce meme forum, un certain "SPOKE" qui était très actif et faisait partager plein d'info intéressantes sur CP/M. Pour l'Histoire, avec un grand H !
Merci... Le fait que ce soit peu documenté est assez stimulant en fait... Pour le son je vais essayer de lancer des procédures Pascal quand les "queues" sont vides, ça doit être possible d'après la doc de Borland qui précise que le Pascal sait gérer les interruptions et j'ai compris comment appeler des procédures Pascal en ASM. Ca permettrait aussi de faire l'équivalent des commandes EVERY ou AFTER du Basic. Pour la suite on va voir la gestion des banks mémoires et l'accès à la RAM vidéo qui se trouve dans le mode d'organisation mémoire 1 à l'adresse #4000 (block 1). Le premiers tests sont concluants, par contre dès qu'on commence à jongler avec les banks mémoires ça devient chaud.
De ce que je comprends le CPM+ utilise les modes mémoires 1, 2 et 3 et la ROM basse. Le Turbo Pascal utilise le mode 2 (ce que le CPM+ appelle zone TPA : 61ko + quelques ko réservés dans ces 64ko en partie basse et haute de cette RAM pour gérer le Bank switching et les interuptions). Le block 7 (en mémoire haute) est toujours accessible. En debuggant j'ai l'impression que la config mémoire 3 est essentiellement utilisée comme cache et pour les accès disques.
Function GetChr:Char; { Touche 'au vol'} Begin InLine($cd/$fc5a/$da/$00/$79/$32/KbdChr); GetChr:=KbdChr; End;
Function StpChr:Char; { Attend une touche } Begin Inline($cd/$fc5a/$bb06/$32/KbdChr); StpChr:=KbdChr; End;
Function TstKey(Key:Byte):Boolean; Begin InLine($3a/Key/$cd/$fc5a/$bb1e/$3e/$00/$28/$02/$3e/$ff/$32/KbdByt); If KbdByt=0 Then TstKey:=False Else TstKey:=True; End;
Function GetJoyA:Byte; Begin InLine($cd/$fc5a/$bb24/$32/KbdByt); GetJoyA:=KbdByt; End;
Function GetJoyB:Byte; Begin InLine($cd/$fc5a/$bb24/$7d/$32/KbdByt); GetJoyB:=KbdByt; End;
Pour les Joysticks si on veut tester à la fois "Haut et Fire1" par exemple appuyés en même temps sur le premier Joystick, faire :
If GetJoyA = Up Or Fire1 Then ... etc avec des 'Or' pour toutes les combinaisons. C'est un peu contre-intuitif mais logique vu qu'on teste les bits.
Si même action pour Fire1 et Fire2 par exemple faire:
Salut tout le monde... Un Amstrad CPC+ et ma période Turbo Pascal, c'est l'occasion de tester les Sprites Hard dans cet environnement Et bien voilà ce que ça donne :
Coté source, l'unité USprite est très compacte et simple :
Code :
{ --------------------------------------------------------------- Unite USprite. Gestion des Sprite hardware CPC+ v0.1 GC-2020 ----------------------------------------------------------------} Type TSpr = Array[0..$ff] Of Byte; TSprPos = Record x,y: Integer; z: Byte; Bazar : Integer; End;
Const Zy1=1; Zy2=2; Zy4=3; Zx1=4; Zx2=8; Zx4=12;
Var TbSpr: Array[0..15] Of TSpr Absolute $4000; TbSprPos: Array[0..15] Of TPoSpr Absolute $6000; TbPal: Array[1..15] Of Integer Absolute $6422;
Procedure DlkAsic; { Delock ASIC } Type TCode = Array[1..17] Of Byte; Const Code:TCode=(255,0,255,119,179,81,168,212,98,57,156,70,43,21,138,205,238); Var b:Byte; Begin For b:=1 To 17 Do Port[$bc00]:=Code[b]; End;
Procedure OpnAsic; Begin Port[$7f00]:=$b8 End;
Procedure CloAsic; Begin Port[$7f00]:=$a0 End;
Procedure SetSprPal(n,r,v,b:Byte); Begin TbPal[n]:=v*256+16*r+b; End;
et un exemple d'utilisation :
Code :
Program Sprite; {$i UGraph.inc} {$i UKbd.inc} {$i USprite.inc} {$i pacman.spr} Var r,v,b:Byte; Begin HidTxtCur; SetMod(1); SetBdr(0,0); DlkAsic; OpnAsic; SetSprPal(1,0,0,15); SetSprPal(2,1,1,1); SetSprPal(3,15,15,15);SetSprPal(4,0,0,0); TbSpr[0]:=Fantome; With TbSprPos[0] Do Begin x:=160; y:=100; z:=Zx2+Zy1 End; Repeat With TbSprPos[0] Do Case GetJoyA of Up : y:=y-1; Down : y:=y+1; Right: x:=x+2; Left : x:=x-2; End; Until GetJoyA=Fire1;
TbSprPos[0].z:=Zx4+Zy2; For r:=3 to 15 Do For v:=3 To 15 Do For b:=3 To 15 Do SetSprPal(3,r,v,b); TbSprPos[0].z:=0; CloAsic; RazKbdBuf; SetInk(0,0,0); SetMod(2); End.
J'ai commencé une version qui déplace les yeux des fantômes en fonction de leur direction. Ca marche mais coder sans éditeur de sprite ça devient galère, vais voir çà. Il suffit de modifier dans l'ASIC les octets contenant les pixels des sprites à changer.
Sur les Sprites Hard, peu de chose à ajouter qu'on ne trouve pas déjà en ligne. Quand on a compris le truc c'est simple à utiliser. Parmi les trucs bizarres, je ne comprends pas pourquoi les zooms sont codés sur 4 octets comme décris ici : https://sites.google.com/site/asmtradcpc/asic-cpc-gx4000/x-tableau-de-la-page-io-asic J'ai bêtement perdu 1 heure à cause de çà par etourderie:O Je me demande bien à quoi servent ces 2 octets en plus...
Sinon c'est étonnamment simple ;D Il faut juste être vigilant sur la gestion des blocs mémoire pour ne pas utiliser le bloc de &4000 à &8000 en même temps que les accès ASIC. Tout ça m'a d'ailleurs fait réaliser qu'on peut très probablement utiliser 2 pages videos en Turbo Pascal sur CPC (à condition de sacrifier une partie des 61ko de Ram du Pascal)...
Sur les spécificités du Turbo Pascal : -> "Port" est équivalent des "Out" en basic ou ASM -> 'Absolute' permet de positionner des variables en mémoire. En l'occurrence ici la mémoire de l'ASIC. -> Bien sur le TP ne "sait pas" où pointe la mémoire de &4000 à &8000 (rn RAM, sur l'ASIC, sur la vidéo?). C'est au programmeur d'être vigilant. C'est la joie des 8 bits ;D -> Ca se goupille plutôt bien ici puisque qu'un programme TP compilé en RAM est placé au dessus de &8000. Et sur disque (en .com) à partir de &20e2. Il faudra juste être vigilant sur les "gros programmes". Soit placer tout le code qui utilise l'Asic dans des sous-programmes en début de mémoire (et faire gaffe aux pointeurs...). Soit changer les paramètres de compilation pour compiler au dessus de &8000, là se sera très "safe" mais on perd de la RAM. Bref rien de bloquant. - Les calculs trigos sont très lents :O (je pensais qu'il y avait un bug...). Bon on s'en fout un peu ;D
A noter qu'il est très facile de copier un sprite (ou ses positions et zoom) dans un autre par une simple affectation. Par exemple :
Code :
TbSpr[15]:=TbSpr[0] copie le dessin du sprite 0 en sprite 15. Idem pour les coordonnées et zoom TbSprPos[15]:=TbSprPos[0]
Pour 'swapper' deux sprites (juste les images) :
Procedure SwpSpr(Var Spr1, Spr2 : TSpr); Var Tmp : TSpr Begin Tmp:=Spr1; Spr1:=Spr2; Spr2:=Tmp End;
On pourrait aussi facilement créer des "mega sprites" composés de axb sprites 16x16. Par exemple un gros sprite de 64x64 pixels en 16 couleurs parmi 4096, zoomable en plus.
Finalement mon exploration de TP est bien plus fructueuse que je ne le pensais. Si j'ajoute que le TP gère très bien les "overlays' (morceaux de programmes sur disque qui peut en remplacer un autre), il y a quoi bien s'amuser...
PS : Je découvre que WinAPE est développé en... Pascal. J'aime bien ce genre de coïncidence ;D en tout cas cet émulateur est formidable !
J'ai moins de temps là et pas mon CPC+ sous la main. Mais en faisant quelques tests avec l'émulateur à vitesse réelle je suis agréablement étonné de la rapidité d'animation des Sprites alors qu'il y quand même 256 octets à copier pour chaque image (dans le pire des cas où on change tous les octets du sprite, pour les fantomes pacman c'est juste quelques octets, et on peut aussi animer en utilisant plusieurs sprite hard pour une animation, ou jouer sur la palette des couleurs... bref il y a x façons de faire ou de combiner tout ça... (Dommage qu'il n'ait pas plus de sprites hard dispo). Mise à jour position d'après un tableau+mise à jour totale de l'image du sprite 16x16 + affichage + boucle = moins de 0.003 sec en Pascal sans aucun code assembleur. Doit y avoir une erreur lol... ? J'ai testé aussi une fonction PLOT (NrSprite, x,y,couleur) à l'intérieur d'un sprite (ou bloc de sprites...).
Savez-vous ou je peux trouver des sprites animés en 16*16 en 16 couleurs pour mes essais? et même des 32x32 ou autre formats ? Et si il y a la palette CPC+ avec c'est encore mieux ;D
EDIT : J'ai fais un test sur le vrai CPC+ et pas d'erreur sur la vitesse de 0.00265 sec. y compris le déplacement, et chargement des 255 octets pour l'animation(26,5s pour 10.000 boucles...) :O Copier 256 octets en ASM sur CPC prend combien? de plus comme ça n'a aucun intérêt d'aller aussi vite pour l'animation ca prendra en fait beaucoup moins de temps que çà.
En plus c'est d'une simplicité totale, l'animation du sprite se faisant par une simple affectation : TbSpr[nr du Sprite]:=Animation[Nr image] Pour une animation cyclique : Animation[ Cycle mod Nombre d'image]
Le code pour l'animation (parcours sur une ellipse avec un cycle d'animation:
Code :
For i:=1 To 100 Do {100 tours de l'ellipse} For j:=1 To 100 Do Begin {Ellipse précalculée de 100 positions xy} TbSprPos[0].xy:=Ellipse[j]; {Force position du sprite hard n°0} TbSpr[0]:=Tableau[j Mod 16];{Change l'image du sprite, animation de 16 images dans Tableau[0..15] Of TSpr} End;
C'est pas évident avec cette série de sprites (seule la couleur change et mon cpc+ est en N&B) mais le sprite est bien rechargé après chaque affichage (je ne joue pas sur la palette). Il y a un seul sprite au début que je recopie dans un tableau en changeant chaque fois l'encre principale du Sprite par une encre aléatoire. Comme j'ai trouvé toute une collection publique d'animation de sprites 16x16, ce sera plus parlant ;D (... à suivre...) Plus simple on peut pas, lol... Si j'arrive à gérer les "événements" du firmware, là ça va devenir génial et encore pplus facile à utiliser ;D....
le zoom des sprites prends 4 bits sur un octet.Il y a 3 valeurs de zoom en x et 3 aussi en Y ,exemple pour le zoom max : %00001111 et le minimum %00000101 mettre l'un des 2 zooms à 0 équivaut à ne pas afficher le sprite.
les couleurs sont codées sur 2 octets,1 pour rouge et bleu et le 2e pour le vert,mais seul 4 bits sont utilisés(4 bits par couleur) les data des sprites peuvent aller de 0 à 15 (4 bits) mais prennent 1 octet tout de même.
Des éditeurs de sprites il y en a au moins quatre : dans la rom impdraw d'AST, l'éditeur de sprite d'IRON(rom) ,CPC+ Sprite Editor v1.0,Hard Sprite Designer Version Beta 3(je ne sais pas s'il propose la sauvegarde celui-la).
Quant à trouver des sprites tous prêt,tu peu aller sur le site https://www.spriters-resource.com/ il y a pas mal de sprites venant d'ordi/console en tout genre
Ca marche très bien et j'obtiens une anim sympa avec des Sprites animés je vais finaliser et optimiser tout ça... J'ai essayé AMSprite qui est bien (mais avec quelques bug sans conséquence en w10) mais ça prends beaucoup de temps à faire :/ . Comme tu le dis, sans compression ça consomme _énormément_ de mémoire :O 256 octets par image 16x16! Si on fait pas gaffe on est vite à 64ko lol. Réduire à 128 est facile sans perte de qualité (mais prends du temps CPU pour décompresser, mais on peut décompresser juste ce dont on a besoin au debut dans tel ou tel tableau, idem pour les symétrie droite-gauche) et même à 66 octets si on limite le nombre de couleurs d'un sprite à 4 (même plutôt 3 avec la transparence) avec une mini-palette parmi les 15 de tous les Sprites.
comme un octet de sprite hard ne se sert que de 4bits,on peu dans un fichier,se servir des 4 autres bits pour d'autre sprites,il y aura juste une moulinette( ) a faire quand on voudra envoyer les datas dans les sprites,mais ça donnera un fichier de 2048ko avec 32 sprites au lieu de 16.
Si on veu des sprites monochromes,un octet pourrai contenir 8 sprites differents vu que l'on a besoin que d'une seule couleur.
Et des sprites en 4 couleurs,un octet pourrai en stocker 4,pas mal de bidouilles à tester au final
comme un octet de sprite hard ne se sert que de 4bits,on peu dans un fichier,se servir des 4 autres bits pour d'autre sprites,il y aura juste une moulinette( ) a faire quand on voudra envoyer les datas dans les sprites,mais ça donnera un fichier de 2048ko avec 32 sprites au lieu de 16.
Si on veut des sprites monochromes,un octet pourrai contenir 8 sprites differents vu que l'on a besoin que d'une seule couleur.
Et des sprites en 4 couleurs,un octet pourrai en stocker 4,pas mal de bidouilles à tester au final
Oui, il y a vraiment de quoi faire. Le meilleur compromis serait peut-être de stocker les sprites "compressés" quand ils ne sont pas utilisés et les décompresser "à l'usage" mais pas en en temps réel à chaque fois (une fois par tableau pour faire simple). Il faudra alors juste une zone tampon pour tous les sprites utilisés en même temps... J'ai retesté Antiriad qui est un jeu qui m'avait beaucoup marqué et en fait il y très peu de sprites actifs en même temps... Pourtant le résultat est top, mais il y a dû avoir un travail énorme sur chaque pixel et coté palette de couleurs! Hors le personnages principal les autres animations doivent avoir 2 ou 3 images.
Question de béotien dont je ne suis même sur qu'elle ait un sens : pour un jeu de plateforme genre CPC quel est le "frame rate" raisonnable? Ou dit autrement : quelle fréquence / sec pour tester la manette et bouger le perso principal en gardant un bon confort d'usage?
Utilisateur(s) parcourant ce forum : Aucun utilisateur inscrit et 1 invité
Vous ne pouvez pas publier de nouveaux sujets dans ce forum Vous ne pouvez pas répondre aux sujets dans ce forum Vous ne pouvez pas éditer vos messages dans ce forum Vous ne pouvez pas supprimer vos messages dans ce forum Vous ne pouvez pas insérer de pièces jointes dans ce forum