;********************
;Fonctions graphiques
;********************
    DOSSEG
    .MODEL LARGE
    .286

;**********
;Constantes
;**********



;********************************
;D‚claration des fonctions public
;********************************


    PUBLIC SR_PRINT_CHAR
    PUBLIC SR_PRINT_CHAIN
    PUBLIC SR_PRINT_NOMBRE_SIGNE
    PUBLIC SR_ACTIVE_PAGE
    PUBLIC SR_LIGNE
    PUBLIC SR_LOAD_IMG
    PUBLIC SR_COPY_PAGE

    PUBLIC CHAR_PTR
    EXTRN VIDEO_SEG:WORD
    
;***************************************
;Variables pour les fonctions graphiques
;***************************************
    .DATA

    CHAR_PTR DD 0
    PAGE0_SEG DW 0A000H
    PAGE1_SEG DW 0A800H
    BUFFER DW 0
    BUFFER2 DW 0
    HANDLE DW 0

;*******************
;D‚but des fonctions
;*******************
    .CODE
;***************************
; Selectionne la page active
;***************************
    SR_ACTIVE_PAGE PROC FAR
     PUSH BP
     MOV BP,SP

     CMP BYTE PTR [BP+6],0
     JE @PAGE0
      MOV AX,PAGE1_SEG
     JMP @PAGE1
     @PAGE0:
      MOV AX,PAGE0_SEG
     @PAGE1:

     MOV VIDEO_SEG,AX

     POP BP
     RETF 2
    ENDP


;***********************************
;Copy un segment m‚moire dans la ram
;***********************************
    SR_COPY_PAGE PROC FAR
     PUSH BP
     MOV BP,SP
     PUSHA
     PUSH ES
     PUSH DS

      MOV AX,[BP+8]
      MOV DS,AX
      MOV AX,[BP+6]
      MOV ES,AX

      XOR DI,DI
      XOR SI,SI

      MOV DX,3C4H
      MOV AL,2
      OUT DX,AL
      INC DX
      MOV AL,1
      OUT DX,AL
      MOV CX,16000

      @B0:
       MOV AL,DS:[SI]
       MOV ES:[DI],AL
       INC DI
       ADD SI,4
      LOOP @B0

      XOR DI,DI
      MOV SI,1

      MOV AL,10b
      OUT DX,AL
      MOV CX,16000

      @B1:
       MOV AL,DS:[SI]
       MOV ES:[DI],AL
       INC DI
       ADD SI,4
      LOOP @B1
      
      XOR DI,DI
      MOV SI,2

      MOV AL,100b
      OUT DX,AL
      MOV CX,16000

      @B2:
       MOV AL,DS:[SI]
       MOV ES:[DI],AL
       INC DI
       ADD SI,4
      LOOP @B2

      XOR DI,DI
      MOV SI,3

      MOV AL,1000b
      OUT DX,AL
      MOV CX,16000

      @B3:
       MOV AL,DS:[SI]
       MOV ES:[DI],AL
       INC DI
       ADD SI,4
      LOOP @B3



     POP DS
     POP ES
     POPA
     POP BP
    RETF 4
    ENDP

;******************
;Ecrit un caract‚re
;******************

    SR_PRINT_CHAR PROC FAR
     PUSH BP
     MOV BP,SP
     PUSH DS
     PUSHA

      MOV AX,@DATA
      MOV DS,AX

      MOV DX,3C4H
      MOV AL,2
      OUT DX,AL


      
      MOV AX,[BP+6]
      XOR AH,AH
      SHL AX,3
      MOV SI,AX



      MOV AX,[BP+10]
      MOV BX,5
      MUL BX
      ADD AX,VIDEO_SEG    ;fixe le segment
      MOV ES,AX



      ADD SI,WORD PTR [CHAR_PTR]
      MOV AX,WORD PTR [CHAR_PTR+2]
      MOV DS,AX

      MOV CX,[BP+12]   ;fixe le plan de bit adr‚ss‚
      AND CL,3
      MOV AL,1
      SHL AL,CL
      MOV DX,3C5H
      OUT DX,AL

      MOV DI,[BP+12]   ;fixe l'offset
      SHR DI,2

      CLD
      MOV AH,[BP+8]          ;AH=couleur
      MOV CX,8
      @PCB0:
       PUSH CX
       MOV BH,10000000b
       MOV BL,00001000b
       LODSB

       MOV CX,4
       @PCB4:
        PUSH CX

        TEST AL,BH
        JZ @PCB1
         MOV ES:[DI],AH
        @PCB1:

        TEST AL,BL
        JZ @PCB2
         MOV ES:[DI+1],AH
        @PCB2:

        PUSH AX
         SHR BX,1
         IN AL,DX
         SHL AL,1
         TEST AL,10000b
         JZ @PCB3
          INC DI
          MOV AL,1
         @PCB3:
         OUT DX,AL
        POP AX

        POP CX
       LOOP @PCB4

       ADD DI,79
       POP CX
      LOOP @PCB0



     POPA
     POP DS
     POP BP
    RETF 8
    ENDP


;******************************
;Ecrit une chaine de caract‚res
;******************************

    SR_PRINT_CHAIN PROC FAR
     PUSH BP
     MOV BP,SP
     PUSH SI
     PUSH DS
     

      MOV AX,@DATA
      MOV DS,AX
      MOV SI,[BP+6]

       CLD
       LODSB
       CMP AL,0
      JE @CHAIN_FINI
      @DEPART_CHAIN:
       PUSH [BP+12]
       PUSH [BP+10]
       PUSH [BP+8]
       PUSH AX
       CALL SR_PRINT_CHAR

       CLD
       LODSB
       CMP AL,0
      JE @CHAIN_FINI

       CMP AL,32
       JNE @PCHAIN0
        ADD WORD PTR [BP+12],3  ;Si c'est un espace l'ecart et moin grand
       JMP @DEPART_CHAIN
       @PCHAIN0:

       TEST AL,32
       JNZ @PCHAIN1
        CMP AL,91
        JA @PCHAIN1       ;si symbole sp‚cial  ne pas agrandir l'ecart
         ADD WORD PTR [BP+12],1 ;SI majuscule agrandir l'‚cart
       @PCHAIN1:
        ADD WORD PTR [BP+12],7 ; FIXER l'ecart
       @PCHAIN2:

       CMP AL,57
       JA @PCHAIN3
       CMP AL,48
       JB @PCHAIN3
        ADD WORD PTR [BP+12],1 ;nombre? agrandir l'ecart
       @PCHAIN3:

       JMP @DEPART_CHAIN
      @CHAIN_FINI:

     
     POP DS
     POP SI
     POP BP
    RETF 8
    ENDP

;*********************
;Ecrit un nombre sign‚
;*********************

    SR_PRINT_NOMBRE_SIGNE PROC FAR
     PUSH BP
     MOV BP,SP
     PUSH DX
     PUSH BX

     MOV AX,[BP+6]          ;Affiche le signe et calcul la valeur absolue
     CMP AX,0
     JNS @NB_NOT_NEG
      PUSH [BP+12]
      PUSH [BP+10]
      PUSH [BP+8]
      PUSH 45
      CALL SR_PRINT_CHAR
      NEG WORD PTR [BP+6]          
     @NB_NOT_NEG:
      
      MOV AX,WORD PTR [BP+14]
      DEC AX
      MOV BX,8
      MUL BX
      ADD AX,7
      ADD WORD PTR [BP+12],AX

     MOV BX,10
     MOV CX,[BP+14]          ;5 chiffres a afficher
     @PRINT_NB0:
      MOV AX,[BP+6]
      XOR DX,DX
      DIV BX
      MOV [BP+6],AX          ;non
      ADD DX,48

      PUSH [BP+12]           ;empile X
      PUSH [BP+10]           ;empile Y
      PUSH [BP+8]            ;empile couleur
      PUSH DX                ;empile caractere 
      CALL SR_PRINT_CHAR     ;Affiche un chiffre
      SUB WORD PTR [BP+12],8          ;d‚cr‚mente X

     LOOP @PRINT_NB0


     POP BX
     POP DX
     POP BP
    RETF 10
    ENDP

;****************
; Trace une ligne
;****************
    ALIGN WORD
    INCY DW 0
    DELTAX DW 0
    DELTAY DW 0
    PBD    DB 0
    PBF    DB 0
    OFSfin DW 0

    SR_LIGNE PROC FAR
     PUSH BP
     MOV BP,SP
     PUSH ES
     PUSHA

      ;CALCUL DELTAX 

      MOV AX,[BP+10]          ;AX=X2
      SUB AX,[BP+14]          ;AX=X2-X1
      JNS @X2SUPX1            ;SI X2<X1
       NEG AX                  ;DELTAX=-DELTAX
       MOV BX,[BP+10]
       XCHG BX,[BP+14]
       MOV [BP+10],BX

       MOV BX,[BP+12]
       XCHG BX,[BP+8]
       MOV [BP+12],BX
      @X2SUPX1:
      INC AX
      MOV DELTAX,AX


      ;CALCUL DELTAY ET INCY

      MOV INCY,80             ;INCY=largeur de l'ecran/4(mode lineaire)
      MOV AX,[BP+8]           ;AX=Y2
      SUB AX,[BP+12]          ;AX=Y2-Y1
      JNS @Y2SUPY1            ;SI Y2<Y1
       NEG INCY                ;INCY=-INCY
       NEG AX                  ;DELTAY=-DELTAY
      @Y2SUPY1:
      INC AX
      MOV DELTAY,AX


      ;CALCUL L'OFFSET ET LE PLAN DE BITS DE DEPART

      XOR AH,AH
      MOV CX,[BP+14]    ;calcul le plan de bits de depart
      AND CL,11B
      MOV AL,1
      SHL AL,CL
      MOV AH,AL
      SHL AH,4
      OR AL,AH
      MOV PBD,AL
      
      MOV AX,[BP+12]    ;et l'offset de depart
      MOV BX,80
      MUL BX
      MOV CX,[BP+14]    
      SHR CX,2
      ADD CX,AX
      MOV DI,CX

      ;CALCUL L'OFFSET ET LE PLAN DE BITS DE FIN

      XOR AH,AH
      MOV CX,[BP+10]    ;calcul le plan de bits de fin
      AND CL,11B
      MOV AL,1
      SHL AL,CL
      MOV AH,AL
      SHL AH,4
      OR AL,AH
      MOV PBF,AL
      
      MOV AX,[BP+8]    ;et l'offset de fin
      MOV BX,80
      MUL BX
      MOV CX,[BP+10]    
      SHR CX,2
      ADD CX,AX
      MOV OFSfin,CX

      ;FIXE ES SUR LE SEGMENT VIDEO

      MOV AX,VIDEO_SEG
             Number := Number mod 256;
              S := S + Hex_Char (Number div 16);
              Number := Number mod 16;
              S := S + Hex_Char (Number);
              Hex_String := S + 'h';
            end; { Function Hex_String }


          Writing Programs That Use Expanded Memory                      20





            {------------------------------------------------------------}
            { The function Emm_Installed checks to see if the            }
            { EMM is loaded in memory.  It does this by looking          }
            { for the string 'EMMXXXX0', which should be located         }
            { at 10 bytes from the beginning of the code segment the     }
            { EMM interrupt, 67h, points to.                             }
            {------------------------------------------------------------}
            Function Emm_Installed: Boolean;
              Var
                Emm_Device_Name   : string[8];
                Int_67_Device_Name: string[8];
                Position          : integer;
                Regs              : registers;

              Begin
                Int_67_Device_Name := '';
                Emm_Device_Name    := 'EMMXXXX0';
                with Regs do
                  Begin
                    {----------------------------------------------------}
                    { Get the code segment interrupt 67h points to       }
                    { the EMM interrupt by using DOS function 35h.       }
                    { (get interrupt vector)                             }
                    {----------------------------------------------------}
                    AH := $35;
                    AL := EMM_INT;
                    Intr (DOS_Int, Regs);
                    {----------------------------------------------------}
                    { The ES pseudo-register contains the segment        }
                    { address pointed to by interrupt 67h.  Create an    }
                    { eight character string from the eight successive   }
                    { bytes at address ES:$000A (10 bytes from ES)       }
                    {----------------------------------------------------}
                    For Position := 0 to 7 do
                      Int_67_Device_Name :=
                        Int_67_Device_Name + Chr (mem[ES:Position + $0A]);
                    Emm_Installed := True;
                    {----------------------------------------------------}
                    { If the string is the EMM manager signature,        }
                    { 'EMMXXXX0', then EMM is installed and ready for    }
                    { use.  If not, then EMM is not present.             }
                    {----------------------------------------------------}
                    If Int_67_Device_Name <> Emm_Device_Name
                      then Emm_Installed := False;
                  end; { with Regs do }
              end; { Function Emm_Installed }







          Writing Programs That Use Expanded Memory                      21





            {------------------------------------------------------------}
            { This function returns the total number of EMM pages        }
            { present in the system, and the number of EMM pages that    }
            { are available.                                             }
            {------------------------------------------------------------}
            Function EMM_Pages_Available
              (Var Total_EMM_Pages, Pages_Available: Integer): Integer;
              Var
                Regs: Registers;

              Begin
                with Regs do
                  Begin
                    {------------------------