[Tuto] Starfield

[Tuto] Starfield

Messagede tomchi » Sam 21 Nov 2020 10:01

Le peu de connaissances que j'ai en programmation concerne le GFA Basic et vient de la

lecture des articles lus dans le magasine ST Mag. Ce qui suit est facile et basique, toute

contribution (utile) est la bienvenue.

Ok, c'est parti pour un petit Starfield !
Le but : Un programme facilement lisible et modifiable qui doit tourner à 50 fps compilé.
Des étoiles en déplacement vertical ayant des vitesses différentes.
Chaque étoile sortant de l'écran sera remplacée par une nouvelle générée

aléatoirement.


Le principe va être d'effacer les étoiles affichées précédemment puis de calculer leurs

nouvelles ordonnées en ajoutant la vitesse à y pour enfin les afficher.
En pseudo code ça donne:
Code: Tout sélectionner
REPEAT
  VSYNC                        ! rafraichissement ecran
  FOR star&=1 TO maxstar&
    erase(star&)               ! a coder
  NEXT star&
'
  FOR star&=1 TO maxstar&
    ADD y.star&,yspeed&        ! a
    display(star&)             ! coder
  NEXT star&
UNTIL space_pressed


On voit donc qu'il faut stocker les coordonnées de chaque étoile pour l'effacer à son

ancienne position avant de l'afficher à la nouvelle position.
On se rend compte que du coup il faudra définir la position initiale de chaque étoile

avant que la boucle principale ne tourne.
La manière la plus évidente/simple en GFA de gérer ça sera d'utiliser un tableau : nous

definiront la constante maxstar& qui stockera le nombre d'étoiles que nous déplaceront.
D'après le pseudo code il nous faut un tableau à deux dimensions pour stocker les

coordonnées et la vitesse de chaque étoile.
Code: Tout sélectionner
maxstar&=50
DIM star&(maxstar&,2)

On stockera donc :
star&(blah&,0)=x&
star&(blah&,1)=y&
star&(blah&,2)=speed&
Où blah& est le numéro de l'étoile dont nous nous occupons.
Remarquez le "&" : il indique au GFA que nous voulons travailler avec des mots/word (-

32768;...;32767). Premièrement parce que nos valeurs (x& par exemple) pourront être plus

grandes que ce qu'un octet/byte ne peut contenir ("|"), deuxièmement parce que le ST

travaille plus vite ( à fortiori en GFA ) avec des mots qu'avec des longs mots ("%") ou

pire des nombres à virgule.


Nous y reviendront mais utiliser ce tableau à deux dimensions bien qu'étant suffisant pour

afficher quelques points, se révèle peu performant. ( En tout cas il y a une autre façon

facile de faire beaucoup plus efficace.)

Pour l'affichage / effaçage des points nous n'utiliserons *pas* PLOT, simplement parce que

nous voulons un résultat propre, rapide et fluide.

Il nous faut avoir au moins une idée rudimentaire de l'organisation des graphismes sur le

ST.
On va travailler en basse résolution cad 320*200 pixels avec 16 couleurs.
Les graphismes sont sockés par bloc de 16 pixels sur 8 octets : 320 pixels sont donc

stockés dans 160 octets , * 200 lignes = 32000 octets pour la taille d'un écran donc.
Pour obtenir les 16 couleurs, les pixels sont codés en 4 plans, on a donc chaque mot qui

stocke les 16 pixels pour chaque plan.
Code: Tout sélectionner
--------------------------------------------------------
! numb   ! bin     ! plan 1 ! plan 2 ! plan 3 ! plan 4 !
!   00   !  0000   !  non   !  non   |  non   !  non   !
!   01   !  0001   !  oui   !  non   !  non   !  non   !
!   02   !  0010   !  non   !  oui   !  non   !  non   !
!   03   !  0011   !  oui   !  oui   !  non   !  non   !
!   04   !  0100   !  non   !  non   !  oui   !  non   !
!   05   !  0101   !  oui   !  non   !  oui   !  non   !
!   06   !  0110   !  non   !  oui   !  oui   !  non   !
!   07   !  0111   !  oui   !  oui   !  oui   !  non   !
!   08   !  1000   !  non   !  non   !  non   !  oui   !
!   09   !  1001   !  oui   !  non   !  non   !  oui   !
!   10   !  1010   !  non   !  oui   !  non   !  oui   !
!   11   !  1011   !  oui   !  oui   !  non   !  oui   !
!   12   !  1100   !  non   !  non   !  oui   !  oui   !
!   13   !  1101   !  oui   !  non   !  oui   !  oui   !
!   14   !  1110   !  non   !  oui   !  oui   !  oui   !
!   15   !  1111   !  oui   !  oui   !  oui   !  oui   !
--------------------------------------------------------


on comprend que la couleur 0 n'utilise aucun plan, la couleur 1 utilise le plan 1, la

couleur 2 le plan 2, la couleur 3 les plans 1 et 2, etc ...

Disons qu'on veut afficher le 3ème pixel en partant de la gauche avec la couleur 13 il

nous faudra écrire :
&X0010000000000000 à address%
&X0000000000000000 à address%+2 ( 2nd mot )
&X0010000000000000 à address%+4 ( 3ème mot )
&X0010000000000000 à address%+6 ( 4ème mot )
"&X" indique au GFA que nous lui fournissons des valeurs binaires, pour des valeurs

héxadécimales on indiquera "&H" )


Pour afficher les étoiles avec la couleur 1 nous n'aurons qu'à écrire un seul mot dans la

mémoire écran. Comme il est fort probable que plusieurs étoiles se trouvent sur le même

bloc de 16 pixels nous utiliseront l'opérande OR pour "plotter" chaque étoile afin de ne

pas en effacer une qu'on aurait déjà affichée sur le même mot.

Pour gagner du temps machine on va précalculer les 16 positions d'un pixel dans un autre

tableau.
Code: Tout sélectionner
  DIM pxlz&(15)
  pxlz&(0)=-32768                                 !&X1000000000000000=&H8000=-32768
  mystar&=&X0100000000000000
  pxlz&(1)=mystar&
  FOR i&=2 TO 15                                 !
    mystar&=SHR(mystar&,1)                       ! decalage d'un pixel sur la droite
    pxlz&(i&)=mystar&
  NEXT i&


Pour écrire ces mots à l'écran on utilisera la commande CARD:
Code: Tout sélectionner
CARD{screen_address%}=pxlz&(blah&) OR CARD{screen_address%}


Effacer sera encore plus simple, il suffira d'écrire 0 .

On gagnera du temps machine si au lieu de travailler avec des coordonnées on utilise

directement les adresses.
Convertir x en adresse : x.address&=SHL(SHR(x&,4),3)
=> Encore un tableau pour stocker ces adresses:

Code: Tout sélectionner
  DIM xadr.ar&(320)
  for i&=0 to 319
  xadr.ar&(i&)=SHL(SHR(i&,4),3)
  next i&

x offset : xofst&=x& AND 15
Convertir y en addresse : y.address&=y&*160
Vitesse en addresse : y.speed&=speed&*160

On aura donc:
Code: Tout sélectionner
CARD{screen_address%+x.address&+y.address&}=pxlz&(xofst&) OR CARD{screen_address%

+x.address&+y.address&}



Si on écrit à l'écran pendant que le ST rafraichit ce dernier on aura des bugs

d'affichage, pour eviter cela nous allons recourir à l'éternelle technique du double

buffer:
Pendant que le ST affiche l'écran (ecran physique), nous ecrirons dans un second buffer

identique en taille=32000 octets (écran logique), ensuite nouos mettrons à jour l'adresse

vidéo après avoir SWAPpé (=échangé) les adresses écran logique et physique et utiliserons

VSYNC pour attendre la fin du balayage et passage à la prochaine VBL.
Code: Tout sélectionner
  scrbuf%=MALLOC(64000+256)                   ! Alloue la memoire pour 2 ecrans
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)       ! adresse ecran physique
  log%=ADD(phy%,32000)                        ! adresse ecran logique


Sur STf l'adresse écran doit se situer sur une adresse multiple de 256 ce qui explique le

+256 sur la taille mémoire allouée et le fait que l'on mette l'octet de phy% à zéro (

AND&HFFFFFF00).


Notre routine, avant d'afficher les nouvelles étoiles doit les effacer, mais il faut

maintenant prendre en compte le double buffering .
En effet, il nous faudra connaitre la position de chaque étoile que nous voudrons effacer

non pas une mais deux VBL plus tôt :
1ère VBL: affiche buffer 1, on écrit dans le buffer 2 l'étoile est à y.
2ème VBL: affiche buffer 2, on écrit dans le buffer 1 l'étoile est à y+yspeed
3ème VBL: affiche buffer 1, on écrit dans le buffer 2, l'étoile est à y+yspeed+yspeed

Comme la routine peut avoir créé une nouvelle étoile dans le cas où la précédente serait

sortie de l'écran nous ne pouvons pas nous contenter de soustraire 2*yspeed, au lieu de

cela nous utiliserons (encore) 3 tableaux et utiliseront SWAP pour les intervertir, comme

pour les adresses écran.
Code: Tout sélectionner
DIM current.star&(maxstar&,3)
DIM middle.star&(maxstar&,3)
DIM old.star&(maxstar&,3)


Assez de blabla basico théorique, passons au code complet.
Quelques mots à propose de PROCEDURE inits:
Le programme avant de tourner vous demandera combien d'étoiles vous souhaitez qu'il

affiche, le maximum en 1 VBL (programme compilé) est d'environ 75.
On utilisera le mode superviseur afin d'écrire directement dans certains registres mémoire

du ST.
Le buffer alloué avec MALLOC sera effacé (rempli de 0), evitant que quelque donnée

résidant en mémoire ne se situe dans ledit bloc et vienne parasiter nos données.
Le pus facile/rapide en GFA est d'utiliser RC_COPY.

Certains pourront remarquer qu'il n'y a pas d'appel à la fonction XBIOS(5) (qui sert à

mettre en place les adresses écran logique et physique) dans la boucle principale mais

écriture dans les registres mémoire correspondants.
Il n'est pas du tout indispensable de procéder de cette façon mais comme mes programmes

sont principalement destinés au STE, j'ai pris l'habitude de coder de cette manière.

Appuyer sur Alternate pendant que le programme tourne changera la couleur de fond en bleu,

la partie de l'écran en bleu représentant le temps machine encore disponible avant la fin

de la VBL.

Code: Tout sélectionner
RESERVE 10000
'
@inits

REPEAT
  VSYNC
  CARD{&HFFFF8240}=0                              ! fond noir
  ' clear oldstars
  FOR i&=0 TO maxstar&
    xadr&=old.star&(i&,0)
    yadr&=old.star&(i&,2)
    CARD{ADD(log%,ADD(xadr&,yadr&))}=0            ! efface les anciennes etoiles
  NEXT i&
  '
  ' calc new coords and display star
  FOR i&=0 TO maxstar&
    yadr&=middle.star&(i&,2)
    yspeed&=middle.star&(i&,3)
    newy%=ADD(yadr&,yspeed&)
    IF newy%>31999                                ! hors de l'ecran
      x&=RAND(319)                                ! nouvelle etoile randomisee
      xadr&=xadr.ar&(x&)
      xofst&=x& AND 15                            ! offset
      current.star&(i&,0)=xadr&
      current.star&(i&,1)=xofst&
      current.star&(i&,2)=0                       ! y nouvelle etoile = 0
      current.star&(i&,3)=(RAND(8)+1)*160         ! y speed
      '
      dest%=ADD(log%,xadr&)                       ! y=0 donc address=x address
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
    ELSE
      xadr&=middle.star&(i&,0)
      xofst&=middle.star&(i&,1)
      '
      current.star&(i&,0)=xadr&
      current.star&(i&,1)=xofst&
      current.star&(i&,2)=newy%
      current.star&(i&,3)=yspeed&
      '
      dest%=ADD(log%,ADD(xadr&,newy%))
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
    ENDIF
  NEXT i&
  tuch&=BYTE{&HFFFFFC02}
  IF tuch&=&H38                                   ! appui sur Alt
    CARD{&HFFFF8240}=&HF                          ! CPU restant
  ENDIF
  SWAP middle.star&(),old.star&()                 ! swap stars data arrays old=middle
  SWAP current.star&(),middle.star&()             !                        middle=current
  SWAP phy%,log%
  BYTE{&HFFFF8201}=SHR(phy%,16)
  BYTE{&HFFFF8203}=SHR(phy%,8)
  '
UNTIL tuch&=&H39                                  ! Spacebar pressed
'
@fin
'
PROCEDURE inits
  CLS
  INPUT "Max Stars",maxstar&                      ! combien d'etoiles ? screen
  DIM pxlz&(15)                                   ! tableau des 16 positions d'un pixel
  DIM xadr.ar&(320)                               ! tableau conversion X en adresse
  DIM current.star&(maxstar&,3)                   ! tableau stockant X adresse/ X ofset/ Y

adresse / Y speed pour chaque etoile
  DIM middle.star&(maxstar&,3)                    ! meme chose
  DIM old.star&(maxstar&,3)                       ! idem <= on swappera ces 3 tableaux

pour avoir les anciennes positions des etoiles
  scrbuf%=MALLOC(64000+256+32)                    ! 1 buffer pour les 2 ecrans +

sauvegarde de la palette
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)           ! phy% sur un octet nul
  log%=ADD(phy%,32000)                            ! log% 32000 octets plus loin
  palette%=ADD(starzbuf%,64000)                   ! palette% apres log%
  super%=GEMDOS(32,L:0)                           ! supervisor mode
  '
 HIDEM
  BYTE{&HFFFFFC02}=&H12                           ! no mouse
  rez|=XBIOS(4)                                   ! resolution sauvee
  xb2%=XBIOS(2)                                   ! adresse ecran sauvee
  '
  for i&=0 to 319
  xadr.ar&(i&)=SHL(SHR(i&,4),3)                   ! conversion X en adresse
  next i&
  BMOVE &HFFFF8240,palette%,32                    ! ancienne palette sauvee
  BYTE{&HFFFF8260}=0                              ! basse resolution
  VSYNC
  ~XBIOS(5,L:log%,L:phy%,-1)                      ! met en place les ecrans
  VSYNC
  RC_COPY phy%,0,0,320,400 TO phy%,0,0,0          ! effaceles buffers phy% et log%
  VSYNC
  SETCOLOR 1,&H777                                ! etoiles blanches, oh my god !
  FOR i&=0 TO maxstar&
    x&=RAND(319)
    xadr&=SHL(SHR(x&,4),3)                        ! adresse
    xofst&=x& AND 15                              ! offset
    middle.star&(i&,0)=xadr&
    middle.star&(i&,1)=xofst&
    middle.star&(i&,2)=RAND(199)*160              ! y adr
    middle.star&(i&,3)=(RAND(8)+1)*160            ! y speed
    '
    old.star&(i&,0)=0
    old.star&(i&,1)=0
    old.star&(i&,2)=0
    old.star&(i&,3)=0
  NEXT i&
  pxlz&(0)=-32768                                 ! -32768=&H8000=&X1000000000000000
  mystar&=&X0100000000000000
  pxlz&(1)=mystar&
  FOR i&=2 TO 15                               
    mystar&=SHR(mystar&,1)                        ! 1 pixel decale a droite
    pxlz&(i&)=mystar&
  NEXT i&
RETURN
'
PROCEDURE fin
  SHOWM
  BYTE{&HFFFFFC02}=&H8                            ! rend la souris ! mouse alive
  ~MFREE(scrbuf%)
  BMOVE palette%,&HFFFF8240,32                    ! remet ancienne palette
  ~XBIOS(5,L:xb2%,L:xb2%,rez|)
  ~GEMDOS(32,L:super%)                            ! user mode
  EDIT
RETURN


J'ai écrit cet article après des échanges constructifs avec Thomas, l'auteur de plusieurs

jeux en GFA (anarcho ride / frogs / randomazer ...).
Ma première routine utilisait CARD pour lire/écrire dans les buffers au lieu d'utiliser

les tableaux.
On a pas mal discuté sur la rapidité en temps machine de ces tableaux et Thomas a proposé

une routine plus rapide que celle que j'avais écrite en utilisant des tableaux à une

dimension. Après tests il s'avère que les tableaux à deux dimensions prenaient énormément

plus de temps que d'utiliser plusieurs tableaux simples. Bien que cela lui convienne

parfaitement, j'avaonçais que ça faisait trop de tableaux/variables à gérer pour moi. Il

faut un tableau pour x adr, x ofst, y, yspeed et tout cela multiplié par 3 (

current/mid/old).

L'intégriste du CARD que je suis se mit en tête d'optimiser la routine originale tirant

parti de chaque technique. Le code qui suit affichera 150 étoiles chaque VBL.
Le but étant d'éviter les calculs (additions) au maximum.

Au lieu d'utiliser plusieurs tableaux, les données seront stockées dans un unique buffer:
Code: Tout sélectionner
  INPUT "Max Stars",maxstar&
  DIM pxlz&(15)
  DIM xadr.ar&(320)
  scrbuf%=MALLOC(64000+256+maxstar&*8*3+32)
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)
  log%=ADD(phy%,32000)
  starzbuf%=ADD(log%,32000)             !MALLOC(maxstar&*8*3) (1 mot X / 1 mot offset / 1

mot Y / 1 mot speed)*3 buffers
  palette%=ADD(starzbuf%,maxstar&*8*3)  !MALLOC(32)


Un seul buffer donc, et des pointeurs pour chaque "buffer dans le buffer".
La quantité de mémoire nécessaire est alors maxstar&*8*3: on a besoin de stocker current /

mid / old positions des étoiles (=>*3) et un bloc de data pour une étoile fait 8 octets

(4*2).
Les pointeurs:
Code: Tout sélectionner
  starz%=starzbuf%
  mid.starz%=ADD(starzbuf%,maxstar&*8)
  old.starz%=ADD(starzbuf%,maxstar&*8*2)


dernier point, au lieu d'utiliser une boucle FOR/NEXT j'ai opté pour REPEAT/UNTIL,

définissant une variable qui pointe dans le buffer dans lequel je veux taper et lui

ajoutant 8 à chaque étoile jusqu'à ce qu'elle pointe à la fin du buffer.

Code: Tout sélectionner
RESERVE 10000
'
@inits

REPEAT
  VSYNC
  CARD{&HFFFF8240}=0                           ! black backgroud
  ' clear oldstars
  old.starz.pointer%=old.starz%
  old.starz.pointer.max%=ADD(old.starz%,maxstar.lg&)
  REPEAT
    xadr&=CARD{old.starz.pointer%}
    yadr&=CARD{ADD(old.starz.pointer%,4)}
    CARD{ADD(log%,ADD(xadr&,yadr&))}=0            ! clear previous starz
    ADD old.starz.pointer%,8
  UNTIL old.starz.pointer%=old.starz.pointer.max%
  '
  ' calc new coords and display star
  starz.pointer%=starz%
  starz.pointer.max%=ADD(starz%,maxstar.lg&)
  mid.starz.pointer%=mid.starz%
  REPEAT
    yadr&=CARD{ADD(mid.starz.pointer%,4)}
    yspeed&=CARD{ADD(mid.starz.pointer%,6)}
    newy%=ADD(yadr&,yspeed&)
    IF newy%>31999                              ! outside screen
      x&=RAND(319)                              ! new random star
      xadr&=xadr.ar&(x&)
      xofst&=x& AND 15                          ! offset
      CARD{starz.pointer%}=xadr&
      CARD{ADD(starz.pointer%,2)}=xofst&
      CARD{ADD(starz.pointer%,4)}=0
      CARD{ADD(starz.pointer%,6)}=MUL(ADD(RAND(8),1),160) !MUL(ADD(x& AND 7,1),160)  !

(RAND(8)+1)*160
      '
      dest%=ADD(log%,xadr&)
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
      ADD starz.pointer%,8
      ADD mid.starz.pointer%,8
    ELSE
      xadr&=CARD{mid.starz.pointer%}
      xofst&=CARD{ADD(mid.starz.pointer%,2)}
      '
      CARD{starz.pointer%}=xadr&
      CARD{ADD(starz.pointer%,2)}=xofst&
      CARD{ADD(starz.pointer%,4)}=newy%
      CARD{ADD(starz.pointer%,6)}=yspeed&
      '
      dest%=ADD(log%,ADD(xadr&,newy%))
      CARD{dest%}=CARD{dest%} OR pxlz&(xofst&)
      ADD starz.pointer%,8
      ADD mid.starz.pointer%,8
    ENDIF
  UNTIL starz.pointer%=starz.pointer.max%
  tuch&=BYTE{&HFFFFFC02}
  IF tuch&=&H38                                  ! Alt pressed
    CARD{&HFFFF8240}=&HF                         ! show CPU left
  ENDIF
  SWAP mid.starz%,old.starz%
  SWAP starz%,mid.starz%
  SWAP phy%,log%
  BYTE{&HFFFF8201}=SHR(phy%,16)
  BYTE{&HFFFF8203}=SHR(phy%,8)
  '
UNTIL tuch&=&H39                              ! Spacebar pressed
'
@fin
'
PROCEDURE inits
  CLS
  INPUT "Max Stars",maxstar&
  DIM pxlz&(15)
  DIM xadr.ar&(320)
  scrbuf%=MALLOC(64000+256+maxstar&*8*3+32)
  phy%=AND(ADD(scrbuf%,255),&HFFFFFF00)
  log%=ADD(phy%,32000)
  starzbuf%=ADD(log%,32000)             !MALLOC(maxstar&*8*3)               ! (1 word X /

1 word offset / 1 word Y / 1 word speed)*3 buffers
  palette%=ADD(starzbuf%,maxstar&*8*3)       !MALLOC(32)
  super%=GEMDOS(32,L:0)                       ! supervisor mode
  '
 HIDEM
  BYTE{&HFFFFFC02}=&H12                        ! plus de souris ! no mouse
  rez|=XBIOS(4)
  xb2%=XBIOS(2)
  '
  for i&=0 to 319
  xadr.ar&(i&)=SHL(SHR(i&,4),3)
  next i&
  BMOVE &HFFFF8240,palette%,32                 ! saves oldpal
  BYTE{&HFFFF8260}=0                           ! low REZ
  VSYNC
  ~XBIOS(5,L:log%,L:phy%,-1)                   ! set screens
  VSYNC
  RC_COPY phy%,0,0,320,400 TO phy%,0,0,0       ! clears both phy% and log% buffers
  VSYNC
  SETCOLOR 1,&H777
  mid.pointer&=maxstar&*8
  old.pointer&=maxstar&*8*2
  FOR i|=0 TO maxstar&-1
    x&=RAND(319)
    xadr&=SHL(SHR(x&,4),3)                   ! address
    xofst&=x& AND 15                           ! offset
    CARD{starzbuf%+mid.pointer&}=xadr&
    CARD{starzbuf%+mid.pointer&+2}=xofst&
    CARD{starzbuf%+mid.pointer&+4}=RAND(199)*160      ! y adr
    CARD{starzbuf%+mid.pointer&+6}=(RAND(8)+1)*160    ! y speed
    '
    CARD{starzbuf%+old.pointer&}=0
    CARD{starzbuf%+old.pointer&+2}=0
    CARD{starzbuf%+old.pointer&+4}=0
    CARD{starzbuf%+old.pointer&+6}=0
    ADD mid.pointer&,8
    ADD old.pointer&,8
  NEXT i|
  maxstar.lg&=SHL(maxstar&-1,3)                  ! X8
  starz%=starzbuf%
  mid.starz%=ADD(starzbuf%,maxstar&*8)
  old.starz%=ADD(starzbuf%,maxstar&*8*2)
  pxlz&(0)=-32768                                 !&X1000000000000000
  mystar&=&X0100000000000000
  pxlz&(1)=mystar&
  FOR i&=2 TO 15                                !2 TO 30 STEP 2
    mystar&=SHR(mystar&,1)                      ! 1 pixel shift to the right
    pxlz&(i&)=mystar&
  NEXT i&
RETURN
'
PROCEDURE fin
  SHOWM
  BYTE{&HFFFFFC02}=&H8                         ! rend la souris ! mouse alive
  ~MFREE(scrbuf%)
  ~MFREE(starzbuf%)
  BMOVE palette%,&HFFFF8240,32                  ! restore old palette
  ~XBIOS(5,L:xb2%,L:xb2%,rez|)
  ~GEMDOS(32,L:super%)                          ! user mode
  EDIT
RETURN

Avatar de l’utilisateur
tomchi
Administrateur du site
 
Messages: 342
Inscription: Mer 15 Oct 2008 20:51

Retourner vers Gfx/Démo

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 1 invité

cron