Ŀ
   Doc. technique pour GrafX 2.00 - Version 1.08 (5 octobre 1997)   ۲


Ce fichier traite:

  - du format d'image PKM
  - des valeurs  envoyer au CRTC pour avoir accs  tous les modes vidos
    incroyables disponibles dans GrafX 2.00



Ŀ
             Le format d'image PKM - par Karl Maritaud ۲             



    Tout d'abord, je tiens a dire que j'ai cr ce format il y a dj quelques
  annes,  l'poque o je ne savais pas comment charger les meilleurs formats
  (GIF par exemple) et que je voulais galement avoir mon propre format.
    Le format PKM a t conu pour tre trs simple, facile  encoder et 
  dcoder. De plus, son header est trs simple (court) et evolutif.
    Le seul vrai dfaut que je puisse y trouver est que l'on ne peut sauver
  des images qu'en 256 couleurs.
    Je sais que vous allez vous dire:
      "Oh non! Encore un nouveau format  la con! J'm'en servirai jamais! En
      plus le taux de compression est naze! Je prefre le GIF!".
    Et je rpondrai:
      "Ouais! T'as raison. Mais si tu ne sais pas comment charger du GIF et
      que tu veux un format simple avec une compression correcte (du moins sur
      les images simples), il peut tre utile."

  Donc, voici la documentation de ce format...



Le HEADER:


  Le header est la structure de 780 octets suivante. (Ne vous inquitez pas 
  propos de la taille. C'est tout simplement parce que la palette fait partie
  du header).


  Ŀ
   Pos  Champ      Type Taille Description                              
  ͵
     0  Signature  char    3   Chane constante "PKM" (SANS dlimitation
                               de taille '\0' ou autres...)             
  Ĵ
     3  Version    byte    1   Pour le moment, ce champ ne peut prendre 
                               que la valeur 0.                         
                               D'autres mthodes de compression pourront
                               la modifier mais pour l'instant il n'y en
                               a qu'une seule.                          
  Ĵ
     4  Pack_byte  byte    1   Valeur de l'octet de reconnaissance pour 
                               les rptitions de couleurs codes sur 1 
                               Octet. (Voir la section sur la mthode de
                               compression pour plus d'informations)    
  Ĵ
     5  Pack_word  byte    1   Valeur de l'octet de reconnaissance pour 
                               les rptitions de couleurs codes sur 2 
                               Octets. (Voir la section sur la mthode  
                               de compression pour plus d'informations) 
  Ĵ
     6  Largeur    word    2   Largeur de l'image (en pixels)           
  Ĵ
     8  Hauteur    word    2   Hauteur de l'image (en pixels)           
  Ĵ
    10  Palette    byte  768   Palette RGB (RGB RGB ... 256 fois) avec  
                               des valeurs de 0  63. Je sais que le    
                               standard dans les fichiers d'images est  
                               de 0  255 mais je trouve a crtin!     
                               C'est tellement plus simple d'envoyer la 
                               palette toute entire dans le port 3C9h  
                               avec un REP OUTSB sans avoir  convertir 
                               la palette.                              
  Ĵ
   778  Taille_PH  word    2   Taille du Post-header. C'est le nombre   
                               d'octets entre le header et les donnes  
                               de l'image. Cette valeur peut valoir 0.  
  

  Les donnes du type "word" sont stockes selon les conventions d'Intel:
  c'est--dire l'octet de poids le plus faible en premier.



Le POST-HEADER:


  Le post-header a une taille variable. Il a t conu pour supporter les
nouvelles fonctions de ce format sans avoir a changer compltement le format.

  Il est constitu d'identificateurs de champ suivis par leur taille et leur
contenu.
  Un identificateur de champ est cod sur 1 octet ainsi que sa taille.


  Ces identificateurs de champ sont:  (cette liste peut tre rallonge...)
  

    0 : Commentaire sur l'image
    1 : Dimensions de l'cran d'origine
    2 : Couleur de fond (couleur de transparence)

  Si vous rencontrez un champ inconnu par votre routine de chargment, sautez
  simplement au del. Mais, par contre, si un champ vous dit de sauter  une
  position qui tombe aprs le dbut thorique des donnes de l'image, alors
  c'est qu'il y a une erreur dans le fichier.


  Les champs:
  

    * Commentaire:

      Grce  ce champ, les artistes vont pouvoir commenter leurs dessins.
      Notez que GrafX 2 a une taille limite de commentaire de 32 caractres.
      Mais vous pourrez avoir des commentaires allant jusqu' 255 caractres
      si vous crez votre propre viewer puisque GrafX 2 ignorera simplement
      les caractres en trop.

      Exemple: [0],[15],[Dessin de X-Man]
      Cette squence signifie:
        - le champ est un commentaire
        - le commentaire a une taille de 15 caractres (il n'y a pas de
          caractre de fin de chane puisque vous connaissez sa taille)
        - le commentaire est "Dessin de X-Man"

    * Dimensions de l'cran d'origine:

      Puisque GrafX 2 propose un norme choix de rsolutions, il a sembl
      pratique d'ajouter un champ indicant quelles taient les dimensions de
      l'cran d'origine.

      Exemple: [1],[4],[320],[256]
      Cette squence signifie:
        - Le champ dcrit les dimensions de l'cran d'origine
        - Les dimensions sont 2 words (donc cette valeur doit tre gale  4)
        - La largeur de l'cran d'origine tait de 320 pixels
        - La hauteur de l'cran d'origine tait de 256 pixels

      Notez que les words stocks dans les champs sont crits  la manire
      Intel. La BETA-version 90% ne respectait pas cette norme (dsol).
      Ce n'est pas bien grve mais les images sauves avec la version 90% et
      recharges avec une version postrieure (91% et plus) ne passeront pas
      dans la bonne rsolution.

    * Couleur de fond:

      Enregistrer la couleur de fond (couleur de transparence) se rvle
      particulirement utile lorsque vous voulez sauvegarder une brosse.
      La taille de ce champ est 1 octet (indice de la couleur entre 0 et 255).

      Exemple: [2],[1],[255]
      Cette squence signifie:
        - le champ dcrit la couleur de fond
        - la valeur prend 1 octet
        - La couleur de transparence est 255


La METHODE DE COMPACTAGE DE L'IMAGE:


  La mthode de compression PKM est une sorte de "Run-Length-Compression" qui
est trs efficace sur les images comportant de longues rptitions d'une mme
couleur horizontalement.
  En fait la compression commence  tre efficace s'il y a souvent plus de 3
fois la mme couleur conscutivement.

  Je pense qu'il est prfrable de vous donner directement l'algorithme plutt
que de nager dans des explications incomprehensibles.


  DEBUT
    /*
      fonctions:
        Lire_octet(Fichier)            Lit et retourne 1 octet  partir de
                                     Fichier
        Dessiner_pixel(X,Y,Couleur)    Dessine un pixel d'une certaine Couleur
                                      la position (X,Y)
        Taille_fichier(Fichier)        Retourne la taille totale d'un Fichier
                                     en octets

      variables:
        le type de Taille_image        est dword
        le type de Taille_donnees      est dword
        le type de Compteur_donnees    est dword
        le type de Compteur_pixels     est dword
        le type de Couleur             est byte
        le type de Octet_lu            est byte
        le type de Word_lu             est word
        le type de Compteur            est word
        le type de Fichier             est <fichier binaire>
    */

    /* A cet endroit, le header et le post-header ont dj t lus. */

    Taille_image        <- Header.Largeur * Header.Hauteur
    Taille_donnees      <- Taille_fichier(Fichier) - (780+Header.Taille_PH)

    Compteur_donnees    <- 0
    Compteur_pixels     <- 0

    /* Boucle de dcompression: */
    TANT QUE ((Compteur_pixels<Taille_image)
           ET (Compteur_donnees<Taille_donnees)) FAIRE
    {
      Octet_lu <- Lire_octet(Fichier)

      /* Si pas un octet de reconnaissance de paquet, c'est un pixel brut */
      SI ((Octet_lu<>Header.Pack_byte) ET (Octet_lu<>Header.Pack_word))
      ALORS
      {
        Dessiner_pixel(Compteur_pixels MOD Header.Largeur,
                       Compteur_pixels DIV Header.Largeur,
                       Octet_lu)

        Compteur_pixels  <- Compteur_pixels + 1
        Compteur_donnees <- Compteur_donnees + 1
      }
      SINON   /* Est-ce que le nombre de pixels  rpter est cod... */
      {       /* ... sur 1 octet ? */
        SI (Octet_lu = Header.Pack_byte) ALORS
        {
          Couleur  <- Lire_octet(Fichier)
          Octet_lu <- Lire_octet(Fichier)

          POUR Compteur ALLANT DE 0 A (Octet_lu-1) PAR PAS DE +1
            Dessiner_pixel((Compteur_pixels+Compteur) MOD Header.Largeur,
                           (Compteur_pixels+Compteur) DIV Header.Largeur,
                           Couleur)

          Compteur_pixels  <- Compteur_pixels + Octet_lu
          Compteur_donnees <- Compteur_donnees + 3
        }
        SINON /* ... sur 2 octets ? */
        {
          Couleur <- Lire_octet(Fichier)
          Word_lu <- (word) (Lire_octet(Fichier) SHL 8)+Lire_octet(Fichier)

          POUR Compteur ALLANT DE 0 A (Word_lu-1) PAR PAS DE +1
            Dessiner_pixel((Compteur_pixels+Compteur) MOD Header.Largeur,
                           (Compteur_pixels+Compteur) DIV Header.Largeur,
                           Couleur)

          Compteur_pixels  <- Compteur_pixels + Word_lu
          Compteur_donnees <- Compteur_donnees + 4
        }
      }
    }
  FIN


  Par exemple, la squence suivante:
    (on suppose que Pack_byte=01 et Pack_word=02)
    04 03 01 05 06 03 02 00 01 2C
  sera dcode comme:
    04 03 05 05 05 05 05 05 03 00 00 00 ... (repter 0 300 fois (012Ch=300))

  Les rptitions qui tiennent sur un word doivent tre crites avec leur
  octet de poids le plus fort en premier. Je sais que a va  l'encontre du
  standard Intel mais puisque je lis les octets du fichier au travers d'un
  buffer (franchement plus rapide), Je me fous compltement de l'ordre
  (Dsol :)). Mais les words du header et du post-header doivent tre crits
  et lus  la manire Intel!


  Conseils de compactage:
  

  * Comme vous pouvez le constater, il pourrait y avoir un problme lorsque
  vous devriez compacter un pixel brut de couleur gale  Pack_byte ou 
  Pack_word. Ces pixels doivent toujours tre cods comme des paquets mme
  s'il n'y a qu'un seul pixel.

    Exemple: (supposons que Pack_byte=9)
      9   sera encod 9,9,1     (Le 1er 9 dans la squence...
      9,9 sera encod 9,9,2     ... encode est Pack_byte)
      etc...

  * Il semble vident de trouver des valeurs pour Pack_byte et Pack_word qui
  ne sont jamais (ou presque) utilises. Donc, une petite routine qui trouve
  les 2 couleurs les moins utilises dans l'image devrait tre appele avant
  de commencer la compression. Ceci peut tre ralis presque instantanment
  en Assembleur.

  * Quand vous voulez crire une squence de 2 couleurs identiques, crivez
  simplement ces 2 couleurs l'une aprs l'autre (Couleur,Couleur) puisque a
  ne prend que 2 octets au lieu de 3 si vous aviez crit un paquet (Pack_byte,
  Couleur,2).

  * Si vous compressez une image extrmement simple qui comporte une squence
  de plus de 65535 fois la mme couleur conscutivement, vous devez "casser"
  la squence et continuer avec un nouveau paquet.

    Exemple: vous devez compacter les 65635 mmes octets conscutifs (de
             couleur 0 par exemple)
      (On suppose que Pack_byte=01 et Pack_word=02)
      Vous devrez alors crire: 02 00 FF FF 01 00 64    (FFFFh=65535, 64h=100)



Ŀ
             Passer dans les modes vidos de GrafX 2.00 ۲            



    Toutes les procdures d'initialisation de mode sont crites en ASM 386. De
  toutes faons, si vous ne comprenez pas une ligne d'ASM, je ne vois vraiment
  pas  quoi pourront vous servir ces procdures.

    Elles ont t conues pour tre utilises dans le modle de mmoire FLAT.
  Mais cela ne devrait pas vous prendre trop de temps de les adapter au modle
  que vous souhaitez utiliser puisqu'il n'y a que les manipulations de mmoire
  que cela affectera (utilisez donc DS:SI au lieu de ESI, ES:DI  la place de
  EDI et fates attention  l'adresse 0A0000h qui se transforme en l'adresse
  0A000h:0000h).


MCGA: (Mode VGA standard)


    Y-a-t'il quelqu'un sur cette plante qui ne sache toujours pas comment
  on passe en mode MCGA 320x200 en 256 couleurs ??!?
    Bon... Je suppose que vous tes un novice si vous lisez les 2 lignes
  suivantes :)


    mov  ax,0013h
    int  10h



Modes X: (Modes VGA tendus)


    Bon... Il me semble que le Mode X original tait en 320x240, mais
  maintenant tout le monde appelle "Modes X" (ou X-Modes, ou Tweaked modes)
  tous les modes VGA qui utilise plus de 64Ko de mmoire vido et la structure
  "Unchained".
    Afficher un pixel dans n'importe quel Mode X peut tre effectu par la
  mme et unique fonction (mais je ne vous expliquerai pas comment faire, il
  vous suffit d'indiquer  la fonction la taille des plans (Largeur/4)).
    Si vous ne comprenez rien  ce que je dis, (Unchained, plans...) il vous
  suffit de lire n'importe quelle bonne documentation sur le Mode X.


    Nous tenons  remercier les auteurs de XLIB2 pour nous avoir conomis du
  temps en ayant crit cette fonction. Nous l'avons lgrement optimise en
  fonction de nos besoins, mais l'essentiel en a t conserv.


    mov  ax,13h      ; Oui! Encore le mode MCGA! Tous les Modes X doivent
    int  10h         ; commencer  partir du mode VGA standard, mais bien des
                     ; choses changent par la suite.

    mov  dx,3C6h     ; Pour la dure de l'initialisation, on va teindre la
    xor  al,al       ; palette de faon  ce que l'utilisateur ne subisse pas
    out  dx,al       ; nos triturations.

    mov  dx,3C4h     ; Nous allons demander au registre TIMING SEQUENCER de
    mov  ax,0604h    ; passer dans le mode "Unchained" (mode X), sans grer de
    out  dx,ax       ; parit, et un accs aux 256Ko de la carte vido.
    mov  ax,0100h    ; On va ensuite enclencher le reset synchrone du registre
    out  dx,ax       ; TS car on s'apprte  jouer avec les registres.

    mov  al,01h      ; De la mme faon que pour la palette, on demande  la
    out  dx,al       ; carte vido de ne plus scruter la mmoire pour
    inc  dx          ; afficher son contenu. Ainsi, c'est une faon de plus
    in   al,dx       ; d'viter l'affichage parasite qui arrive le temps que
    mov  ah,al       ; le mode soit totalement initialis et stabilis.
    mov  al,01h      ; De plus, on peut esprer qu'en demandant un arrt de
    push ax          ; la lecture de la mmoire, le systme s'en voit un peu
    mov  al,ah       ; acclr, et ainsi acclrer l'initialisation du mode
    or   al,20h      ; graphique (l'espoir fait vivre :))
    out  dx,al       ;

    mov  esi,X_ptr   ; Pointeur sur la liste des constantes  envoyer au CRTC.
    cld

    lodsb            ; Ceci charge dans AL une valeur qui nous dira quoi faire
                     ; avec le registre MISCELLANEOUS, et incrmente ESI.
                     ; La valeur est gale  ZERO => Rien  faire
                     ;                      sinon => Envoyer AL au reg. MISC.

    or   al,al       ; Devons nous modifier le mode vido de base ?
    jz   NonMerci    ; Non?Ŀ En fait, la rponse est toujours "Oui".
    mov  dx,3C2h     ;       Sauf pour quelques modes tels que le
    out  dx,al       ;       320x200 en Mode X
    NonMerci:        ; < (mais notre mode 320x200 est en MCGA...)

    mov  dx,3C4h     ; On en a termin avec les manipulations du registre
    mov  ax,0300h    ; MISCELLANEOUS, on peut maintenant dsenclencher le
    out  dx,ax       ; reset synchrone du registre TIMING SEQUENCER.

    ; Et maintenant, si on jouait avec le CRTC?

    mov  dx,3D4h     ; Dans le 18me registre du CRTC, on va dsenclencher le
    mov  al,11h      ; bit de protection. Sans cela, les valeurs que nous
    out  dx,al       ; aurions envoyes aux registres du CRTC auraient t
    inc  dx          ; ignores.
    in   al,dx
    and  al,7Fh
    out  dx,al

    dec  dx          ; DX pointe  nouveau sur "l'entre" du registre CRTC.
    lodsb            ; Ceci met dans AL le nombre de registres CRTC  changer
    xor  ecx,ecx     ; On doit nettoyer ECX avant de commencer  rpter...
    mov  cl,al       ; ...CL (AL) fois OUTSW
    rep  outsw       ; On peut envoyer la sauce aux registres du CRTC!

    ; Juste au cas o le 20me registre CRTC aurait t oubli dans la table
    ; d'initialisation, on peut le calculer nous-mmes (Ouaip, on est des
    ; braves gars).

    mov  ax,Screen_width ; Vous devez indiquer  la routine quelle est la
    shr  ax,3            ; largeur de l'cran
    mov  ah,al
    mov  al,13h
    out  dx,ax

    mov  dx,3C4h     ; Maintenant vous avez la bonne rsolution mais il peut
    mov  ax,0F02h    ; y avoir des pixels pourris  l'cran  cause de zones
    out  dx,ax       ; non nettoyes de la mmoire vido.
    mov  edi,0A0000h ; Donc on va nettoyer la mmoire  partir de 0A0000h
    xor  eax,eax     ; avec la valeur 0 (qui est le noir standard) et sur une
    mov  ecx,4000h   ; longueur de 4000h dwords (256Ko).
    rep  stosd       ; Allez, liquidez-moi tout a!

    mov  dx,3C4h     ; On peut redemander  la carte VGA de relire la mmoire
    pop  ax          ; pour afficher l'cran...
    out  dx,ax       ;
    mov  dx,3C6h     ; ... et rtablir la palette pour que l'image soit
    mov  al,0FFh     ; visible  l'utilisateur.
    out  dx,al       ;



  La table de constantes que vous devez employer est l'une des suivantes:
  (Ces tables sont au format C, mais elles peuvent facilement tres employes
   dans d'autres langages)

  word X320Y224[] =
    { 0x0BA3, 0x6F06, 0xBA07, 0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0x0014,
      0xC715, 0x0416, 0xE317 };
  word X320Y240[] =
    { 0x0AE3, 0x0D06, 0x3E07, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x0014, 0xE715,
      0x0616, 0xE317 };
  word X320Y256[] =
    { 0x0CE3, 0x2306, 0xB207, 0x0008, 0x6109, 0x0A10, 0xAC11, 0xFF12, 0x2013,
      0x0014, 0x0715, 0x1A16, 0xE317 };
  word X320Y270[] =
    { 0x0BE7, 0x3006, 0xF007, 0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x0014,
      0x1F15, 0x2F16, 0xE317 };
  word X320Y282[] =
    { 0x0CE3, 0x6206, 0xF007, 0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x2F13,
      0x0014, 0x3C15, 0x5C16, 0xE317 };
  word X320Y300[] =
    { 0x0DE3, 0x4606, 0x1F07, 0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x2013,
      0x0014, 0x2F15, 0x4416, 0xE317 };
  word X320Y360[] =
    { 0x09E3, 0x4009, 0x8810, 0x8511, 0x6712, 0x2013, 0x0014, 0x6D15, 0xBA16,
      0xE317 };
  word X320Y400[] =
    { 0x03E3, 0x4009, 0x0014, 0xE317 };
  word X320Y448[] =
    { 0x0BA3, 0x6F06, 0xBA07, 0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0x0014,
      0xC715, 0x0416, 0xE317 };
  word X320Y480[] =
    { 0x0AE3, 0x0D06, 0x3E07, 0x4009, 0xEA10, 0xAC11, 0xDF12, 0x0014, 0xE715,
      0x0616 , 0xE317};
  word X320Y512[] =
    { 0x0CE3, 0x2306, 0xB207, 0x0008, 0x6009, 0x0A10, 0xAC11, 0xFF12, 0x2013,
      0x0014, 0x0715, 0x1A16, 0xE317 };
  word X320Y540[] =
    { 0x0BE7, 0x3006, 0xF007, 0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x0014,
      0x1F15, 0x2F16, 0xE317 };
  word X320Y564[] =
    { 0x0CE7, 0x6206, 0xF007, 0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x2013,
      0x0014, 0x3C15, 0x5C16, 0xE317 };
  word X320Y600[] =
    { 0x0BE7, 0xBE06, 0xF007, 0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x0014,
      0x5815, 0x7016, 0xE317 };
  word X360Y200[] =
    { 0x09E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x2D13, 0x0014,
      0xE317 };
  word X360Y224[] =
    { 0x12A7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6F06, 0xBA07,
      0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0x2D13, 0x0014, 0xC715, 0x0416,
      0xE317 };
  word X360Y240[] =
    { 0x11E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x0D06, 0x3E07,
      0x4109, 0xEA10, 0xAC11, 0xDF12, 0x2D13, 0x0014, 0xE715, 0x0616, 0xE317 };
  word X360Y256[] =
    { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x2B06, 0xB207,
      0x0008, 0x6109, 0x0E10, 0xAC11, 0xFF12, 0x2D13, 0x0014, 0x0715, 0x1A16,
      0xE317 };
  word X360Y270[] =
    { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x3006, 0xF007,
      0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x2D13, 0x0014, 0x1F15, 0x2F16,
      0xE317 };
  word X360Y282[] =
    { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6206, 0xF007,
      0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x2D13, 0x0014, 0x3C15, 0x5C16,
      0xE317 };
  word X360Y300[] =
    { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x4606, 0x1F07,
      0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x2D13, 0x0014, 0x2F15, 0x4416,
      0xE317 };
  word X360Y360[] =
    { 0x0FE7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x4009, 0x8810,
      0x8511, 0x6712, 0x2D13, 0x0014, 0x6D15, 0xBA16, 0xE317 };
  word X360Y400[] =
    { 0x0AE7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x4009, 0x2D13,
      0x0014, 0xE317 };
  word X360Y448[] =
    { 0x12A7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6F06, 0xBA07,
      0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0x2D13, 0x0014, 0xC715, 0x0416,
      0xE317 };
  word X360Y480[] =
    { 0x11E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x0D06, 0x3E07,
      0x4009, 0xEA10, 0xAC11, 0xDF12, 0x2D13, 0x0014, 0xE715, 0x0616, 0xE317 };
  word X360Y512[] =
    { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x2B06, 0xB207,
      0x0008, 0x6009, 0x0E10, 0xAC11, 0xff12, 0x2D13, 0x0014, 0x0715, 0x1A16,
      0xE317 };
  word X360Y540[] =
    { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x3006, 0xF007,
      0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x2D13, 0x0014, 0x1F15, 0x2F16,
      0xE317 };
  word X360Y564[] =
    { 0x12EB, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6206, 0xF007,
      0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x2D13, 0x0014, 0x3C15, 0x5C16,
      0xE317 };
  word X360Y600[] =
    { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0xBE06, 0xF007,
      0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x2D13, 0x0014, 0x5815, 0x7016,
      0xE317 };
  word X400Y200[] =
    { 0x09E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x3213, 0x0014,
      0xE317 };
  word X400Y224[] =
    { 0x12A7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6F06, 0xBA07,
      0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0x3213, 0x0014, 0xC715, 0x0416,
      0xE317 };
  word X400Y240[] =
    { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x0D06, 0x3E07,
      0x0008, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x3213, 0x0014, 0xE715, 0x0616,
      0xE317 };
  word X400Y256[] =
    { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x2B06, 0xB207,
      0x0008, 0x6109, 0x1310, 0xAC11, 0xFF12, 0x3213, 0x0014, 0x0715, 0x1A16,
      0xE317 };
  word X400Y270[] =
    { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x3006, 0xF007,
      0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x3213, 0x0014, 0x1F15, 0x2F16,
      0xE317 };
  word X400Y282[] =
    { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6206, 0xF007,
      0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x3213, 0x0014, 0x3C15, 0x5C16,
      0xE317 };
  word X400Y300[] =
    { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x4606, 0x1F07,
      0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x3213, 0x0014, 0x2F15, 0x4416,
      0xE317 };
  word X400Y360[] =
    { 0x0FE7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x4009, 0x8810,
      0x8511, 0x6712, 0x3213, 0x0014, 0x6D15, 0xBA16, 0xE317 };
  word X400Y400[] =
    { 0x0AE7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x4009, 0x3213,
      0x0014, 0xE317 };
  word X400Y448[] =
    { 0x12A7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6F06, 0xBA07,
      0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0x3213, 0x0014, 0xC715, 0x0416,
      0xE317 };
  word X400Y480[] =
    { 0x11E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x0D06, 0x3E07,
      0x4009, 0xEA10, 0xAC11, 0xDF12, 0x3213, 0x0014, 0xE715, 0x0616, 0xE317 };
  word X400Y512[] =
    { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x2B06, 0xB207,
      0x0008, 0x6009, 0x1310, 0xAC11, 0xFF12, 0x3213, 0x0014, 0x0715, 0x1A16,
      0xE317 };
  word X400Y540[] =
    { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x3006, 0xF007,
      0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x3213, 0x0014, 0x1F15, 0x2F16,
      0xE317 };
  word X400Y564[] =
    { 0x12EB, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6206, 0xF007,
      0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x3213, 0x0014, 0x3C15, 0x5C16,
      0xE317 };
  word X400Y600[] =
    { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0xBE06, 0xF007,
      0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x3213, 0x0014, 0x5815, 0x7016,
      0xE317 };


  La structure: (exemple)

       Ceci est le nombre de valeurs  envoyer aux registres CRTC. C'est
           en fait le nombre de words dans la table moins 1 ( cause du 1er
           word de la table qui n'est pas envoy au CRTC mais qui contient
           une valeur  envoyer au registre MISCELLANEOUS et le nombre de
           valeurs  envoyer aux registres CRTC ;) ).
       
        Ceci est la valeur  envoyer au registre MISCELLANEOUS (ou 0 si
          aucune valeur ne doit y tre envoye).
        
             Ceci est une valeur  envoyer dans un registre du CRTC.
             
              Ceci est le numro du registre du CRTC qui recevra la
               valeur cite prcdemment.
       ÿÿ    ÿÿ
   { 0x0AE3, 0x0D06, 0x3E07, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x0014, 0xE715,
     0x0616, 0xE317 };

    Vous pouvez remarquer que les registres 0  5 (et le 13h) du CRTC
  dfinissent la largeur de l'cran, alors que les registres 6  17h (
  l'exception du 13h) definissent la hauteur de l'cran.


    Nous avons plus de modes en poche que les quelques-uns :) que nous avons
  inclus dans GrafX 2.00, mais ils ne sont ni vraiment utiles ni vraiment
  stables. Nous pourrons toutefois dcider de les inclure dans une prochaine
  version.
    S'il manque certains de vos modes prfres, envoyez nous simplement la
  liste des constantes que l'on doit balancer au CRTC  la manire de la
  structure utilise ci-dessus.

  IMPORTANT! Les valeurs des constantes cites plus haut ne sont pas
             supportes par tous les moniteurs ou les cartes vidos.
             Nous avons test GrafX2 avec diffrentes configurations et avons
             constats que certains modes ne marchent pas du tout avec
             certaines cartes vidos, alors que d'autres dbordent de l'cran,
             sont dcentrs, assombris, trop clairs, ou tasss.
             Toutefois, ils marchent tous correctement avec notre pauvre
             petite Tseng Labs ET4000...

  Si vous avez dj une bonne connaissance  propos du CRTC, et avez des
  valeurs diffrentes des notres pour certains modes, merci de nous en
  informer. Nous nous en servirons s'ils marchent mieux sur une majorit
  d'ordinateurs.



VESA: (Un "pseudo-standard" pour les modes Super-VGA)


    Nous nous servons du VESA pour des modes qui ncessitent une largeur de
  640, 800 ou 1024 pixels. Mais il existe un moyen de combiner la hauteur des
  Modes X avec les modes VESA, il est ainsi possible d'avoir des modes aussi
  timbrs qu'en Mode X.


  mov  ax,4F02h
  mov  bx,Video_mode
  int  10h


  Les modes VESA 256 couleur VESA sont:
    100h :  640x400
    101h :  640x480
    103h :  800x600
    105h : 1024x768
    107h : 1280x1024 (non disponible dans GrafX2 parce qu'uniquement support
                     par des cartes vido avec 2 Megaoctets ou plus de mmoire
                     vido)


  Comme avec les Modes X, vous pouvez modifier les registres CRTC pour accder
  aux modes "VESA-X"! (Notez que certaines cartes vido ne supportent pas les
  modifications des registres du CRTC VGA dans les modes VESA.)


  Pour passer dans ces modes tendus, passez dans un mode VESA standard ayant
  la bonne largeur, puis appelez Modif_registres_CRTC avec la bonne table de
  hauteur.

  Exemple (640x512) :
    VESA_Set_mode(101h)         // On passe dans un mode qui a la mme largeur
    Modif_registres_CRTC(Y512)  // On modifie la hauteur


  * Tables des hauteurs:

  word Y224[] =
    { 0x09A3, 0x6F06, 0xBA07, 0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0xC715,
      0x0416 };
  word Y240[] =
    { 0x09E3, 0x0D06, 0x3E07, 0x0008, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0xE715,
      0x0616 };
  word Y256[] =
    { 0x0900, 0x2B06, 0xB207, 0x0008, 0x6109, 0x0A10, 0xAC11, 0xFF12, 0x0715,
      0x1A16 };
  word Y270[] =
    { 0x09E7, 0x3006, 0xF007, 0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x1F15,
      0x2F16 };
  word Y282[] =
    { 0x0AE3, 0x6206, 0xF007, 0x0008, 0x6109, 0x310F, 0x3710, 0x8911, 0x3312,
      0x3C15, 0x5C16 };
  word Y300[] =
    { 0x09E3, 0x4606, 0x1F07, 0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x2F15,
      0x4416 };
  word Y350[] =
    { 0x09A3, 0xBF06, 0x1F07, 0x0008, 0x4009, 0x8310, 0x8511, 0x5D12, 0x6315,
      0xBA16 };
  word Y360[] =
    { 0x07E3, 0x0008, 0x4009, 0x8810, 0x8511, 0x6712, 0x6D15, 0xBA16 };
  word Y400[] =
    { 0x01E3, 0x4009 };
  word Y448[] =
    { 0x09A3, 0x6F06, 0xBA07, 0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0xC715,
      0x0416 };
  word Y480[] =
    { 0x09E3, 0x0D06, 0x3E07, 0x0008, 0x4009, 0xEA10, 0xAC11, 0xDF12, 0xE715,
      0x0616 };
  word Y512[] =
    { 0x0900, 0x2B06, 0xB207, 0x0008, 0x6009, 0x0A10, 0xAC11, 0xFF12, 0x0715,
      0x1A16 };
  word Y540[] =
    { 0x09E7, 0x3006, 0xF007, 0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x1F15,
      0x2F16 };
  word Y564[] =
    { 0x09E7, 0x6206, 0xF007, 0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x3C15,
      0x5C16 };
  word Y600[] =
    { 0x09E7, 0xBE06, 0xF007, 0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x5815,
      0x7016 };



  Modifier les registres CRTC: (inspir de l'init. des Modes X... voir plus
    haut pour de plus amples dtails)

  mov  esi,XVESA_Ptr
  cld

  lodsb
  or   al,al       ; Devons nous modifier le mode vido de base ?
  jz   NonMerci    ; Non?Ŀ La rponse peut tre "Non" car les initialisations
  mov  dx,3C2h     ;       de certains modes VESA mettent directement la
  out  dx,al       ;       bonne valeur pour le registre MISCELLANEOUS.
  NonMerci:        ; <

  mov  dx,3D4h
  mov  al,11h
  out  dx,al
  inc  dx
  in   al,dx
  and  al,7Fh
  out  dx,al

  dec  dx
  lodsb
  xor  ecx,ecx
  mov  cl,al
  rep  outsw



    Si vous tes suffisament astucieux, vous pourrez combiner les constantes
  utilises dans les Modes X pour obtenir plus de modes "VESA-X" tels que le
  640x200, 800x480, etc... (mais je ne pense pas que a marche convenablement
  avec les largeurs de 1024 pixels puisque ce mode est gnralement
  entrelac... Mais qui sait?...)
    Je pense que le plus difficile est de trouver la bonne valeur du registre
  MISCELLANEOUS.
