; depends in Tbx_code.asm

VERT_RESCAN   equ 3dah
vm320x200x256 EQU 13h
vm640x480x16  EQU 12h
vm80x25x16    EQU 03h
vm_ram        EQU 0a000h
MonoSeg       EQU MONOSCR          ; Mono screen segment
CGASeg        EQU COLORSCR          ; CGA screen segment
BW40          EQU     0               ; 40x25 B/W on Color Adapter
CO40          EQU     1               ; 40x25 Color on Color Adapter
BW80          EQU     2               ; 80x25 B/W on Color Adapter
CO80          EQU     3               ; 80x25 Color on Color Adapter
Mono          EQU     7               ; 80x25 on Monochrome Adapter

; Foreground / Background color constants

LightGray       EQU     GREY

; Foreground color constants

LightBlue       EQU     LTBLUE
LightGreen      EQU     LTGREEN
LightCyan       EQU     LTCYAN
LightRed        EQU     LTRED
LightMagenta    EQU     LTMAGENTA

; Add this for blink

UnderLine       EQU     00000001b       ; Underline Bit (Mono Only)

; Some commonly used attributes

_Normal          EQU     7       ; Gray on Black (Low Intensity)
_Reverse         EQU     112     ; Black on Gray
_HighInt         EQU     15      ; White on Black (High Intensity)

; Window parameter constants

SaveBit         EQU     01H     ; to save or not to save the background
FrameBit        EQU     02H     ; to frame or not to frame
FillBit         EQU     04H     ; to clear or not to clear
MaxSize         EQU     4000    ; size of full screen for save

BaseOfScreen    DW      CGASeg          ; Offset for current vid mode
SnowCheck       DB      0               ; Check for retrace 1/0
video_mode       DB      0               ; Current BIOS INT 10 vid mode

; ===========================================================================
; Graphics DATA AREA
; ===========================================================================

vidtype  db 0
vmode    dw 0
xres     dw 0
yres     dw 0
VidBank  dw 0
GX       dw 00h
GY       dw 00h
GColor   db 00h
novgamsg db 0ffh,'VGA 640x480x16 mode test fail.',0ffh,0

; ===========================================================================
; Graphics Code
; ===========================================================================

fillscr proc far
     push ds
     $textattr
     mov  bh, al
     mov  ax, BaseOfScreen
     mov  ds, ax
     mov  cx, 2000
     xor  ax, ax
     mov  di, ax
     call fillarray
     pop  ds
     ret
fillscr endp

_drawline macro _dlx, _dly, _dlc
      mov  ax, _dlx
      mov  bx, _dly
      mov  cs:gx, ax
      mov  cs:gy, bx
;      mov  cx, 1
      mov  cl, _dlc
      mov  cs:gcolor, cl
      mov  dx, 100
      call cs:drawline
      endm

EGAInstalled proc far
; This procedure checks to see if the current adapter card is an EGA.
; Output : AL = 1 if EGA Adapter is found / 0 if not Modified AX
		push    bx              ; Store used registers
		push    cx
		mov     ax, 1200h       ; BIOS INT 10 function 12h
		mov     bx, 10h         ; sub-func 10h (Get EGA info)
		mov     cx, 0FFFFh      ; lite all bits of CX
		int     10h             ; call INT 10
		xor     ax, ax          ; Clear AX reg
		cmp     cx, 0FFFFh      ; If CX not modified by INT call
		je      EI_Done         ;   then this is not an EGA
		inc     AL              ; Increment AL to show this is EGA
	EI_Done:
		pop     cx              ; Restore regs
		pop     bx
		ret
EGAInstalled endp


; ===========================================================================
is_vga proc far
; Output: CF=CY=TRUE
; ===========================================================================
       push ax
chk_ega:
       mov  ax, 1a00h
       int  10h
       cmp  al, 1ah
       jne  chk_svga
       cmp  bl, 07h
       jae  its_vga
       cmp  bl, 04h
       jae  its_ega
       cmp  bl, 02h
       je   its_cga
       jmp  its_mda  ; unsupported video adapter
chk_svga:
       push cs
       pop  es
       lea  di, cs:SvgaInfo
       mov  ax, 4f00h
       int  10h
       or   ah, ah
       jnz  chk_vga
       cmp  al, 4fh
       je   its_svga
chk_vga:
       push cs
       pop  es
       lea  di, cs:VDS
       xor  bx, bx
       mov  ah, 1bh
       int  10h
       cmp  al, 1bh ; VGA present
       je   its_svga
its_mda:
       mov  bl, 0
       clc
       jmp  short is_vgax
its_cga:
       mov  bl, 1
       clc
       jmp  short is_vgax
its_ega:
       mov  bl, 2
       clc   
       jmp  short is_vgax
its_vga:
       mov  bl, 3
       stc
       jmp  short is_vgax
its_svga:
       mov  bl, 4
       stc
is_vgax:
       pop  ax
       ret
VDS      db 64 dup(0) ; VGA DYNAMIC STATE BUFFER
SVGAINFO db 256 dup(0)
is_vga endp

GetVideoMode proc far
; This procedure checks the video mode and sets the BaseOfScreen accordingly.
; It also sets SnowCheck to 1 if adapter is a CGA.
; Output : BaseOfScreen
;          video_mode
;          SnowCheck
; Uses   : EGAInstalled
		push    ax                      ; Store registers
		push    di
		push    ds
                pop     ax
                push    ds
              ;  mov     ax, @data               ; Move DATASEG segment
		mov     ds, ax                  ;   into DS registers
		mov     di, CGASeg              ; move offset of CGA to DI
		mov     ah, 0Fh                 ; INT 10 get vid mode func
		int     10h                     ; get the video mode
		xor     ah, ah                  ; clear the AH reg
                mov     [video_mode], al         ; place mode into VideoMode
		cmp     al, 7                   ; Is this a mono screen?
		jne     NotMono                 ; if not jump to NotMono
		mov     di, MonoSeg             ; move offset of mono to DI
		mov     [SnowCheck], 0          ; NEVER CHECK RETRACE ON MONO!
		jmp     GVM_Done
	NotMono:                                ; Process CGA/EGA/VGA adap.
		call    EGAInstalled            ; Check for EGA adap.
		rcr     al, 1                   ; Move bit 1 to carry flag
		jc      GVM_Done                ; If EGA then no snow check
		mov     [SnowCheck], 1          ; Not EGA so set snow check
	GVM_Done:
		mov     [BaseOfScreen], di      ; Move DI to base of screen
		pop     ds                      ; Restore regs
		pop     di
		pop     ax
		ret
GetVideoMode endp

; ===========================================================================
setvideo proc far
; ===========================================================================
     ; mov  ax, 13h
     int  10h
     ret
setvideo endp

; ===========================================================================
TextMode proc far 
; ===========================================================================
       mov ax, vm80x25x16
       xor  bx, bx
       call setvideo
       ret
TextMode endp

; ===========================================================================
HiColor proc far    ; 320x200x32
; ===========================================================================
       mov ax, 4f02h
       mov bx, 10fh
       call setvideo
       ret
HiColor endp


; ===========================================================================
wait_retrace proc far
; Waits for the horizontial retrace signal from the monitor before
; continuing. disable interupts first before calling (CLI)
; ===========================================================================
       cli
       mov  dx, VERT_RESCAN
@wait1:
       in   al, dx
       test al, 8h
       jnz  @wait1
@wait2:
       in   al, dx
       test al, 8h
       jz   @wait2
       sti
       ret
wait_retrace endp

WaitRetrace macro
        call wait_retrace
endm

; ============
; Direct Video
; ============

MoveXY_DI proc far
; This procedure moves to the offset indicated by an X & Y cursor location.
; Input : AH = Row
;         AL = Column
; Output: DI = Memory Offset
		push    cx              ; Save CX
		xor     cl, cl          ; Clear CL
		mov     ch, ah          ; CX = Row * 256
		dec     ch              ; CX = (Row - 1) {0-24 Based}
		shr     cx, 1           ; CX = Row * 128
		mov     di, cx          ; Store in DI
		shr     di, 1           ; DI = Row * 64
		shr     di, 1           ; DI = Row * 32
		add     di, cx          ; DI = (Row * 128)+(Row * 32) {Row*160}
		xor     ch, ch          ; Clear CH register
		mov     cl, al          ; CX = Columns
		dec     cx              ; Make 0-79
		shl     cx, 1           ; Account for attribute
		add     di, cx          ; DI = (Row * 160) + (Col * 2)
		pop     cx              ; Restore CX register
		ret
MoveXY_DI endp

MoveXY_SI proc far
; This procedure moves to the offset indicated by an X & Y cursor location.
; Input : AH = Row
;         AL = Column
; Output: SI = Memory Offset - Points 1 byte beyond null of str displayed
		push    cx              ; Save CX
		xor     cl, cl          ; Clear CL
		mov     ch, ah          ; CX = Row * 256
		dec     ch              ; CX = (Row - 1) {0-24 Based}
		shr     cx, 1           ; CX = Row * 128
		mov     si, cx          ; Store in SI
		shr     si, 1           ; SI = Row * 64
		shr     si, 1           ; SI = Row * 32
		add     si, cx          ; SI = (Row * 128)+(Row * 32) {Row*160}
		xor     ch, ch          ; Clear CH register
		mov     cl, al          ; CX = Columns
		dec     cx              ; Make 0-79
		shl     cx, 1           ; Account for attribute
		add     si, cx          ; DI = (Row * 160) + (Col * 2)
		pop     cx              ; Restore CX register
		ret
MoveXY_SI endp

DWriteCH proc far
	;
	; Writes a character to the screen using direct memory access.
	;
	; *** IMPORTANT -- CALL GetVideoMode Before using this routine!
	;
	; Input
	;       AH      Row on screen 1-25
	;       AL      Column on screen 1-80
	;       BH      Video Attribute
	;       BL      Character
	;       CX      Number of times
	; Output
	;       Screen memory (B000:0000 or 8000 CGA/MONO
	;
		push    ax              ; Store the registers
		push    cx
		push    dx
		push    es
		push    di
		call    MoveXY_DI       ; Set DI to row / column offset
		mov     es, [BaseOfScreen]      ; Move screen seg to ES
		mov     al, [SnowCheck]         ; Move snow check to al
		rcr     al, 1           ; SnowCheck
		jnc     DWC_NoWait      ; if no snowcheck goto FW_NoWait
	DWC_Next:
		cli                     ; Disable interrupts
		WaitRetrace             ; Macro to wait for horiz retrace
		mov     ax, bx          ; Move char/attr into AX
		stosw                   ; Move char/attr to screen
		sti                     ; Enable interrupts
		loop    DWC_Next        ; Repeat CX times
		jmp     DWC_Exit        ; Exit this routine
	DWC_NoWait:
		mov     ax, bx          ; Move char/attr into AX
		rep     stosw           ; Move char/attr to screen CX times

	DWC_Exit:
		pop     di              ; Restore the registers
		pop     es
		pop     dx
		pop     cx
		pop     ax
		ret

DWriteCH endp

DWriteCHNA proc far
	;
	; Writes a character to the screen using direct memory access.
	; This procedure does not disturb current attr setting.
	;
	; *** IMPORTANT -- CALL GetVideoMode Before using this routine!
	;
	; Input
	;       AH      Row on screen 1-25
	;       AL      Column on screen 1-80
	;       BL      Character
	;       CX      Number of times
	; Output
	;       Screen memory (B000:0000 or 8000 CGA/MONO
	;

		push    ax              ; Store the registers
		push    cx
		push    dx
		push    es
		push    di
		call    MoveXY_DI       ; Set DI to row / column offset
		mov     es, [BaseOfScreen]      ; Move screen seg to ES
		mov     al, [SnowCheck]         ; Move snow check to al
		rcr     al, 1           ; SnowCheck
		jnc     DWCN_NoWait     ; if no snowcheck goto FW_NoWait
	DWCN_Next:
		cli                     ; Disable interrupts
		WaitRetrace             ; Macro to wait for horiz retrace
		mov     al, bl          ; Move char into al
		stosb                   ; Move char to screen
		sti                     ; Enable interrupts
		inc     di              ; Skip over attr
		loop    DWCN_Next       ; Repeat CX times
		jmp     DWCN_Exit       ; Exit this routine
	DWCN_NoWait:
		mov     al, bl          ; Move char into AX
	DWCN_NoWaitLoop:
		stosb                   ; Move char to screen
		inc     di              ; Skip over attr
		loop    DWCN_NoWaitLoop ; Repeat CX times

	DWCN_Exit:
		pop     di              ; Restore the registers
		pop     es
		pop     dx
		pop     cx
		pop     ax
		ret

DWriteCHNA endp

DWriteStr proc far
	;
	; This procedure writes a null delimited string to the screen using
	; direct memory access.
	;
	; *** IMPORTANT -- CALL GetVideoMode Before using this routine!
	;
	; Input
	;       DS:SI   Null terminated string to print
	;       AH      Row on screen 1-25
	;       AL      Column on screen 1-80
	;       BH      Video Attribute
	; Output
	;       Screen memory (B000:0000 or 8000 CGA/MONO
	; Modifies
	;       SI - Points 1 byte beyond null of str displayed
	;
		push    ax              ; Store the registers
		push    bx
		push    cx
		push    dx
		push    es
		push    di

		call    MoveXY_DI       ; Set DI to row / column offset
		mov     es, [BaseOfScreen]      ; Move screen seg to ES
		mov     cl, [SnowCheck]         ; Move snow check to al
		cld                     ; Clear the direction flag
		rcr     cl, 1           ; SnowCheck
		mov     ah, bh          ; Place video attr in AH
		jnc     DWS_NoWait      ; if no snowcheck goto DWS_NoWait
	DWS_Next:
		lodsb                   ; Get a character from source
		or      al, al          ; Check for NULL
		jz      DWS_Exit        ; If NULL then exit
		mov     bx, ax          ; Store video word into BX
		cli                     ; Disable interrupts
		WaitRetrace             ; Macro to wait for horiz retrace
		mov     ax, bx          ; Move word back to AX...
		stosw                   ; Move word to screen
		sti                     ; Enable interrupts
		jmp     DWS_Next        ; Continue
	DWS_NoWait:
		lodsb                   ; Get a character from string
		or      al, al          ; Check for NULL
		jz      DWS_Exit        ; If NULL then exit
		stosw                   ; Move word to screen
		loop    DWS_NoWait      ; Continue
	DWS_Exit:
		pop     di              ; Restore the registers
		pop     es
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		ret

DWriteStr endp

DWriteStrNA proc far
	;
	; This procedure writes a null delimited string to the screen using
	; direct memory access, attribute is not changed.
	;
	; *** IMPORTANT -- CALL GetVideoMode Before using this routine!
	;
	; Input
	;       DS:SI   Null terminated string to print
	;       AH      Row on screen 1-25
	;       AL      Column on screen 1-80
	; Output
	;       Screen memory (B000:0000 or 8000 CGA/MONO)
	; Modifies
	;       SI - Points 1 byte beyond null of str displayed
	;
		push    ax              ; Store the registers
		push    bx
		push    cx
		push    dx
		push    es
		push    di

		call    MoveXY_DI       ; Set DI to screen offset pos
		mov     es, [BaseOfScreen]      ; Move screen seg to ES
		mov     cl, [SnowCheck]         ; Move snow check to cl
		cld                     ; Clear the direction flag
		rcr     cl, 1           ; SnowCheck
		jnc     DWSN_NoWait     ; if no snowcheck goto DWSN_NoWait
	DWSN_Next:
		lodsb                   ; Get a character from source
		or      al, al          ; Check for NULL
		jz      DWSN_Exit       ; If NULL then exit
		mov     bx, ax          ; Store video word into BX
		cli                     ; Turn off interrupts
		WaitRetrace             ; Macro - Waits for horiz retrace
		mov     ax, bx          ; Move word back to AX...
		stosb                   ; Move word to screen
		sti                     ; Enable interrupts
		inc     di              ; Skip the attribute.
		jmp     DWSN_Next       ; Continue
	DWSN_NoWait:
		lodsb                   ; Get a character from string
		or      al, al          ; Check for NULL
		jz      DWSN_Exit       ; If NULL then exit
		stosb                   ; Store the byte on screen
		inc     di              ; Skip attribute byte
		loop    DWSN_NoWait     ; Continue
	DWSN_Exit:
		pop     di              ; Restore the registers
		pop     es
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		ret

DWriteStrNA endp

DFillCH proc far
	;
	; This procedure fills an area of the screen with the specified
	; character and attribute.
	;
	; *** IMPORTANT -- CALL GetVideoMode Before using this routine!
	;
	; Input
	;       AH      = Top Row
	;       AL      = Left Column
	;       BH      = Number of rows
	;       BL      = Number of columns
	;       DH      = Attribute
	;       DL      = Character
	;
		push    ax                      ; Store Registers
		push    bx
		push    cx
		push    dx
		push    es
		push    di

                jz      DFC_Exit                ; string won't fit
		mov     es, [BaseOfScreen]      ; Move screen seg to ES
		mov     cl, [SnowCheck]         ; Move snow check to CL

		cld                     ; Clear the direction flag
		rcr     cl, 1           ; SnowCheck
		mov     ch, 0           ; Clear CH
		jnc     DFC_NoWait      ; if no snowcheck goto DFC_NoWait

	DFC_Top:
		mov     cl, bl          ; Load the number of columns
		call    MoveXY_DI       ; Set DI to screen offset pos
		push    ax              ; Store Registers AX, BX
		push    bx

	DFC_Next:
		cli                     ; Turn off interrupts
		push    dx              ; Store video word
		WaitRetrace             ; Macro - Waits for horiz retrace
		pop     dx              ; Restore video word
		mov     ax, dx          ; Move word into AX
		stosw                   ; Move word to screen
		sti                     ; Enable interrupts
		loop    DFC_Next        ; Continue

		pop     bx              ; Restore registers BX, AX
		pop     ax
		inc     ah              ; Next row
		dec     bh              ; Decrement the number of rows done
		or      bh, bh          ; Check Number of columns
		jnz     DFC_Top         ; Do next column if not done
		jmp     DFC_Exit        ; Exit routine

	DFC_NoWait:
		mov     cl, bl          ; Load the number of columns
		call    MoveXY_DI       ; Set DI to screen offset pos
		push    ax              ; Store the char/attr
		mov     ax, dx          ; Move char/attr into ax
		rep     stosw           ; Thats it!
		pop     ax              ; Restore the char/attr
		inc     ah              ; Next row
		dec     bh              ; Decrement number of rows done
		or      bh, bh          ; Check number of columns
		jnz     DFC_NoWait      ; Do next column

	DFC_Exit:
		pop     di              ; Restore registers
		pop     es
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		ret

DFillCH endp

DFillCHNA proc far
	;
	; This procedure fills an area of the screen with the specified
	; character. Attribute remains the same.
	;
	; *** IMPORTANT -- CALL GetVideoMode Before using this routine!
	;
	; Input
	;       AH      = Top Row
	;       AL      = Left Column
	;       BH      = Number of rows
	;       BL      = Number of columns
	;       DL      = Character
	;
		push    ax                      ; Store Registers
		push    bx
		push    cx
		push    dx
		push    es
		push    di

		mov     es, [BaseOfScreen]      ; Move screen seg to ES
		mov     cl, [SnowCheck]         ; Move snow check to CL

		cld                     ; Clear the direction flag
		rcr     cl, 1           ; SnowCheck
		mov     ch, 0           ; Clear CH
		jnc     DFCN_NoWait     ; if no snowcheck goto DFCN_NoWait

	DFCN_Top:
		mov     cl, bl          ; Load the number of columns
		call    MoveXY_DI       ; Set DI to screen offset pos
		push    ax              ; Store Registers AX, BX
		push    bx

	DFCN_Next:
		cli                     ; Turn off interrupts
		push    dx              ; Save video word
		WaitRetrace             ; Macro - Waits for horiz retrace
		pop     dx              ; Restore video word
		mov     al, dl          ; Move character into al
		stosb                   ; Move word to screen
		sti                     ; Enable interrupts
		inc     di              ; Skip attr
		loop    DFCN_Next       ; Continue

		pop     bx              ; Restore registers BX, AX
		pop     ax
		inc     ah              ; Next row
		dec     bh              ; Decrement the number of rows done
		or      bh, bh          ; Check Number of columns
		jnz     DFCN_Top        ; Do next column if not done
		jmp     DFCN_Exit       ; Exit routine

	DFCN_NoWait:
		mov     cl, bl          ; Load the number of columns
		call    MoveXY_DI       ; Set DI to screen offset pos
		push    ax              ; Store the row/col info
		mov     al, dl          ; Move char into ax
	DFCN_NoWaitLoop:
		stosb                   ; Thats it!
		inc     di              ; Skip over attr
		loop    DFCN_NoWaitLoop ; Loop for all columns
		pop     ax              ; Restore the row/col info
		inc     ah              ; Next row
		dec     bh              ; Decrement number of rows done
		or      bh, bh          ; Check number of columns
		jnz     DFCN_NoWait     ; Do next column

	DFCN_Exit:
		pop     di              ; Restore registers
		pop     es
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		ret

DFillCHNA endp

DFillAttr proc far
	;
	; This procedure fills an area of the screen with the specified
	; attribute. Character remains the same.
	;
	; *** IMPORTANT -- CALL GetVideoMode Before using this routine!
	;
	; Input
	;       AH      = Top Row
	;       AL      = Left Column
	;       BH      = Number of rows
	;       BL      = Number of columns
	;       DH      = Attribute
	;
		push    ax                      ; Store Registers
		push    bx
		push    cx
		push    dx
		push    es
		push    di

		mov     es, [BaseOfScreen]      ; Move screen seg to ES
		mov     cl, [SnowCheck]         ; Move snow check to CL

		cld                     ; Clear the direction flag
		rcr     cl, 1           ; SnowCheck
		mov     ch, 0           ; Clear CH
		jnc     DFA_NoWait      ; if no snowcheck goto DFA_NoWait

	DFA_Top:
		mov     cl, bl          ; Load the number of columns
		call    MoveXY_DI       ; Set DI to screen offset pos
		push    ax              ; Store Registers AX, BX
		push    bx

	DFA_Next:
		cli                     ; Turn off interrupts
		push    dx              ; Save attribute in DH
		WaitRetrace             ; Macro - Waits for horiz retrace
		pop     dx              ; Restore attr
		inc     di              ; Skip character
		mov     al, dh          ; Move attr into al
		stosb                   ; Move attr to screen
		sti                     ; Enable interrupts
		loop    DFA_Next        ; Continue

		pop     bx              ; Restore registers BX, AX
		pop     ax
		inc     ah              ; Next row
		dec     bh              ; Decrement the number of rows done
		or      bh, bh          ; Check Number of columns
		jnz     DFA_Top         ; Do next column if not done
		jmp     DFA_Exit        ; Exit routine

	DFA_NoWait:
		mov     cl, bl          ; Load the number of columns
		call    MoveXY_DI       ; Set DI to screen offset pos
		push    ax              ; Store the row/col info
		mov     al, dh          ; Move attr into ax
	DFA_NoWaitLoop:
		inc     di              ; Skip over character
		stosb                   ; Thats it!
		loop    DFA_NoWaitLoop  ; Loop for all columns
		pop     ax              ; Restore the row/col info
		inc     ah              ; Next row
		dec     bh              ; Decrement number of rows done
		or      bh, bh          ; Check number of columns
		jnz     DFA_NoWait      ; Do next column

	DFA_Exit:
		pop     di              ; Restore registers
		pop     es
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		ret

DFillAttr endp

StoreToMem proc far
	;
	; This procedure moves an image from the screen to the designated
	; memory area.
	;
	; *** IMPORTANT -- CALL GetVideoMode Before using this routine!
	;
	; Input
	;       AH      = Top Row
	;       AL      = Left Column
	;       BH      = Number of rows
	;       BL      = Number of columns
	;       ES:DI   = Memory Destination
	; Modifies
	;       DI
	;
		push    ax
		push    bx
		push    cx
		push    dx
		push    ds              ; Store registers
		push    si

		mov cl, [SnowCheck]     ; Move snow check to CL
		mov ds, [BaseOfScreen]  ; Move screen seg to DS mov cl,

		cld                     ; Clear the direction flag
		rcr     cl, 1           ; SnowCheck
		mov     ch, 0           ; Clear CH
		jnc     STM_NoWait      ; if no snowcheck goto STM_NoWait

	STM_Top:
		mov     cl, bl          ; Load the number of columns
		call    MoveXY_SI       ; Set SI to screen offset pos
		push    ax              ; Store row/column info
		push    bx              ; Store number of row/columns info
	STM_Next:
		lodsw                   ; Get a char/word from screen
		mov     bx, ax          ; Store video word into BX
		cli                     ; Turn off interrupts
		WaitRetrace             ; Macro - Waits for horiz retrace
		mov     ax, bx          ; Move word back to AX...
		stosw                   ; Move word to memory
		sti                     ; Enable interrupts
		loop    STM_Next        ; Continue
		pop     bx              ; Restore number of row/columns info
		pop     ax              ; Restore row/column info
		inc     ah              ; Next row
		dec     bh              ; Decrement the number of rows done
		or      bh, bh          ; Check Number of columns
		jnz     STM_Top         ; Do next column if not done
		jmp     STM_Exit        ; Exit routine

	STM_NoWait:
		mov     cl, bl          ; Load the number of columns
		call    MoveXY_SI       ; Set SI to screen offset pos
		rep     movsw           ; Thats it!
		inc     ah              ; Next row
		dec     bh              ; Decrement number of rows done
		or      bh, bh          ; Check number of columns
		jnz     STM_NoWait      ; Do next column

	STM_Exit:
		pop     si
		pop     ds
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		ret
StoreToMem endp

StoreToScr proc far
	;
	; This procedure moves an image from memory to the designated
	; screen location.
	;
	; *** IMPORTANT -- CALL GetVideoMode Before using this routine!
	;
	; Input
	;       AH      = Top Row
	;       AL      = Left Column
	;       BH      = Number of rows
	;       BL      = Number of columns
        ;       DX      = Base of segment where image is stored
	;       SI      = Offset from DX to Memory Area of image
	; Modifies
	;       SI
	;
		push    ax                      ; Store Registers
		push    bx
                push    cx
		push    dx
		push    es
		push    di

		mov     es, [BaseOfScreen]      ; Move screen seg to ES
		mov     cl, [SnowCheck]         ; Move snow check to CL

                mov     ds,dx           ; set up new data segment
		cld                     ; Clear the direction flag
		rcr     cl, 1           ; SnowCheck
		mov     ch, 0           ; Clear CH
		jnc     STS_NoWait      ; if no snowcheck goto STS_NoWait

	STS_Top:
		mov     cl, bl          ; Load the number of columns
		call    MoveXY_DI       ; Set DI to screen offset pos
		push    ax              ; Store Registers AX, BX
		push    bx

	STS_Next:
		lodsw                   ; Get a char/word from memory
		mov     bx, ax          ; Store video word into BX
		cli                     ; Turn off interrupts
		WaitRetrace             ; Macro - Waits for horiz retrace
		mov     ax, bx          ; Move word back to AX...
		stosw                   ; Move word to screen
		sti                     ; Enable interrupts
		loop    STS_Next        ; Continue

		pop     bx              ; Restore registers BX, AX
		pop     ax
		inc     ah              ; Next row
		dec     bh              ; Decrement the number of rows done
		or      bh, bh          ; Check Number of columns
		jnz     STS_Top         ; Do next column if not done
		jmp     STS_Exit        ; Exit routine

	STS_NoWait:
		mov     cl, bl          ; Load the number of columns
		call    MoveXY_DI       ; Set DI to screen offset pos
		rep     movsw           ; Thats it!
		inc     ah              ; Next row
		dec     bh              ; Decrement number of rows done
		or      bh, bh          ; Check number of columns
		jnz     STS_NoWait      ; Do next column

	STS_Exit:
		pop     di              ; Restore registers
		pop     es
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		ret
StoreToScr endp

CursorOff Proc far
	;
	; This procedure simply turns the Cursor off
	;

		push    ax
		push    bx
		push    cx
		push    dx
		mov     ah, 03h         ; BIOS INT 10 func 3 (Get Cursor pos)
		int     10h             ; Call INT 10
		or      ch, 0100000b    ; Turn on cursor bit
		mov     ah, 01h         ; BIOS INT 10 func 1 (Set cursor type)
		int     10h             ; Call INT 10
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		ret
CursorOff endp

CursorOn proc far
	;
	; This procedure simply turns the Cursor on
	;
		push    ax
		push    bx
		push    cx
		push    dx
		mov     ah, 03h         ; BIOS INT 10 func 3 (Get Cursor pos)
		int     10h             ; Call INT 10
		and     ch, 1011111b    ; Turn off cursor bit
		mov     ah, 01h         ; BIOS INT 10 func 1 (Set cursor type)
		int     10h             ; Call INT 10
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		ret

CursorOn endp



; ===========================================================================
putpixel proc far                                               ; y*320+x=ofs
; compute di = Y * 320 using shifting
; Remember that y*320 == y *(256 + 64) == y*256 + y*64
; byte offset = Y * (horz_res / 8) + int(X / 8)
; ===========================================================================
       push es
       mov  ax, 0a000h
       mov  es, ax
       mov  ax, 320
       xor  dx, dx
       mul  GY
       add  ax, GX
       mov  di, ax
       ; mov  al, bl
       ; mov  al, byte ptr [GC]
       mov  es:[di], bl
       pop  es
       ret
putpixel endp

; ===========================================================================
vidclr proc far
; ===========================================================================
       xor  bx, bx
       mov  bl, al
       mov  cx, 320
vidc1:
       mov  dx, 200
vidc2:
       push dx
       push cx
       mov  GX, cx
       mov  GY, dx
       push bx
       call putpixel
       pop  bx
       pop  cx
       pop  dx
       dec  dx
       jnz  vidc2
       loop vidc1
;       for 320 down to 0 do
;           for  200 down to 0 do putpixel x, y, 0
       ret
vidclr endp

; ===========================================================================
vclrscr proc far
; ===========================================================================
     mov  Gcolor, bl
     mov  cx, xres
     ;for (i=0; i<640;i++) {
vclr1:
      mov dx, yres
     ;   for (j=0; j<480;j++) {
vclr2:
             push dx
             push cx
             mov GX, cx
             mov GY, dx
             call putpixel                       ; g_putpixel(i,j,Gcolor);
             pop  cx
             pop  dx
             dec  dx
             jnz  vclr2
             ; {
      loop vclr1 ; }
      ret
vclrscr endp

; ===========================================================================
fillscrn proc far
; BL = COLOR
; ===========================================================================
       push es
       mov  ax, vm_ram
       mov  es, ax
       mov  di, 0
       mov  cx, -1
       mov  bh, bl
fills:
       mov  es:[di], word ptr bx    ; 0f0fh
       add  di, 2
       loop fills
       pop  es
       ret
fillscrn endp

; ===========================================================================
VGACLS proc far
; ===========================================================================
       mov  ax, 0a000h
       mov  di, ax
       xor  ax, ax
       mov  al, cs:Gcolor
       mov  cx, 16000
       cld
       rep  stosw
       ret
VGACLS endp

; ======================================================
vga30 proc far
; VGA25->VGA30 changer, derived from Linux-Kernel-Source
; ======================================================
	push ds
	push cs
	pop  ds
  	mov  dx, 3d4h
        mov  si, cs:vga30t
	mov  cx, 7
	cld
crtloop:
	lodsw
	out  dx, ax
	jmp  short dly1
dly1:	loop crtloop
	pop  ds
	xor  ax, ax
	mov  dx, 3cch     ; set some special flags
	in   al, dx
	and  al, 0dh
	or   al, 0e2h
	mov  dx, 3c2h
	out  dx, al
        push ds		; finally, adjust BIOS data
	mov  ax, 40h	; BIOS data seg
	mov  ds, ax
        mov  ax, 12c0h
        mov  word ptr ds:[4ch], ax
        mov  al, 1dh
        mov  byte ptr ds:[84h], al    ; max row = 29
 	pop  ds
        ret
vga30t	dw 0c11h, 0b06h, 3e07h, 0ea10h, 0df12h, 0e715h, 0416h
vga30 endp

pixread PROC    far
        PUSH    BP
        MOV     BP, SP
        MOV     CX, GX                    ;Load pixel (column)
        MOV     DX, GY                    ;Load raster (row)
        MOV     AH, 0DH                  ;Function = READ PIXEL
        INT     10H                     ;Ask BIOS to read the pixel
        XOR     AH,AH                   ;Clear upper bits of AX (since value in
        POP     BP
        RET
pixread ENDP

vx dw ?
vy dw ?
vr db ?
vg db ?
vb db ?
pix32rgb proc far
; AX = X
; BX = Y
; CH = R
; CL = G
; DH = B
         mov vx, ax
         mov vy, bx
         mov vr, ch
         mov vg, cl
         mov vb, dh
         ;
         mov ax, vy
         mov di, ax
         shl ax, 6
         shl di, 8
         add di, ax
         add di, vx
         mov dx, di
         shr dx, 14
         cmp dx, vidbank
         je  putpix
         mov ax, 4f05h
         xor bx,bx
         mov vidbank, dx
         int 10h
putpix:
         mov ax, 0a000h
         mov es, ax
         shl di, 2
.386p
         mov eax, dword ptr vr
         shl eax,16
         mov ah, vg
         mov al, vb
         mov es:[di], eax
.286p
         ret
pix32rgb endp 

; ===========================================================================
drawline proc far
; CX = direction = 1 = Vertical else Horizonal
; DX = length to draw 
; ===========================================================================
         mov  ax, vm_ram
         push ax
         pop  es
         ;
         mov  ax, cs:GY
         mov  bx, cs:GY

         ; compute di = Y * 320 using shifting
         ; Remember that y*320 == y *(256 + 64) == y*256 + y*64
         shl  ax, 8            ;    multiply y by 256
         shl  bx, 6            ;    multiply y by 64
         add  ax, bx           ;    add y * 256 + y * 64
         mov  bx, cs:GX           ; get X coordinate
         add  ax, bx           ; add x to y*320
         mov  di, ax           ; di = y*320 +x 

         ;;; draw horizontal line starting at first computed pixel

         mov  al, cs:GColor     ; get pixel color
         or   cx, cx
         jnz  dl_horiz 
dl_vertz:
         mov  cx, dx          ; get number of pixels to print
b10loop:
         mov  es:[di],al      ;   VGA[di] = color,  write colored pixel to VGA memory 
         add  di, cs:xres     ;   advance pointer to next pixel in vertical line
         loop b10loop
         jmp  drwl_exit
dl_horiz:
         mov  cx, dx          ; get number of pixels to print
a10loop:	                ; loop to print each pixel
         mov   es:[di],al      ;   VGA[di] = color,  write colored pixel to VGA memory 
         inc   di              ;   advance pointer to next pixel in the line
         loop  a10loop         
drwl_exit:
         ret
; mov  word ptr GX,0001h       
; mov  word ptr GY,0001h            ;
; mov  byte ptr GColor,00h  
; mov  cx, 480           
;         call putpixel
;         inc  word ptr GX          
;         inc  word ptr GY                  ;
;         inc  byte ptr GColor  
;         and  byte ptr GColor,0Fh       ; 00h - 0Fh only
;         loop DrawLine                ; do it
drawline endp

draw_rect proc far
         mov  cs:hlen, ax
         mov  cs:vlen, bx
         mov  ax, cs:GY
         mov  bx, cs:GY
         ; compute di = Y * 320 using shifting
         ; Remember that y*320 == y *(256 + 64) == y*256 + y*64
         shl  ax, 8            ;    multiply y by 256
         shl  bx, 6            ;    multiply y by 64
         add  ax, bx           ;    add y * 256 + y * 64
         mov  bx, cs:GX           ; get X coordinate
         add  ax, bx           ; add x to y*320
         mov  di, ax           ; di = y*320 +x 

         mov  cx, 0
         mov  dx, cs:hlen
         call drawline
         mov  ax, cs:GY
         mov  bx, cs:GY
         ; compute di = Y * 320 using shifting
         ; Remember that y*320 == y *(256 + 64) == y*256 + y*64
         shl  ax, 8            ;    multiply y by 256
         shl  bx, 6            ;    multiply y by 64
         add  ax, bx           ;    add y * 256 + y * 64
         mov  bx, cs:GX           ; get X coordinate
         add  ax, bx           ; add x to y*320
         mov  di, ax           ; di = y*320 +x 

         mov  cx, 1
         mov  dx, cs:vlen
         call drawline
         push cs:GY  
         mov  ax, cs:GY
         add  ax, cs:vlen         ; compute new Y coordinate for bottom line
         mov  cs:GY, ax
         mov  cx, 0
         mov  dx, cs:hlen
         call Drawline          ; draw bottom line
         mov  ax, cs:GX
         add  ax, cs:hlen         ; compute new X coordinate for right side Vline
         mov  cs:GX, ax
         pop  cs:GY           ; retrieve original Y value
         mov  cx, 0
         mov  dx, cs:vlen
         call Drawline
         ret
hlen dw 0
vlen dw 0
draw_rect endp

; ===========================================================================
; Misc 
; ===========================================================================

ulpal	db	20 dup(00h)
	db	20 dup(09h)
	db	20 dup(0bh)
	db	20 dup(0fh)
	db	20 dup(0fh)
	db	20 dup(0fh)
	db	20 dup(0fh)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(07h)
	db	20 dup(07h)
	db	20 dup(07h)
	db	20 dup(07h)
urpal	db	20 dup(00h)
	db	20 dup(00h)
	db	20 dup(0ch)
	db	20 dup(0eh)
	db	20 dup(0fh)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(07h)
llpal	db	20 dup(00h)
	db	20 dup(0ch)
	db	20 dup(0ch)
	db	20 dup(0dh)
	db	20 dup(0fh)
	db	20 dup(0fh)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(07h)
	db	20 dup(07h)
lrpal	db	20 dup(00h)
	db	20 dup(0ah)
	db	20 dup(0bh)
	db	20 dup(0bh)
	db	20 dup(0fh)
	db	20 dup(0fh)
	db	20 dup(0fh)
	db	20 dup(0fh)
	db	20 dup(08h)
	db	20 dup(08h)
	db	20 dup(07h)
	db	20 dup(07h)
	db	20 dup(07h)

save_dacs	db	256 * 3 dup(?)
gray_dacs	db	256 * 3 dup(?)


set_ega_pallete proc far
	mov	ax,1000h		;change the palette entry for 7
	mov	bx,77Q*256 + 7		;  to 77 octal.
	int	10h

	mov	ax,1000h
	mov	bx,007Q*256 + 08h
	int	10h

	mov	ax,1000h
	mov	bx,010Q*256 + 09h
	int	10h

	mov	ax,1000h
	mov	bx,020Q*256 + 0ah
	int	10h

	mov	ax,1000h
	mov	bx,030Q*256 + 0bh
	int	10h

	mov	ax,1000h
	mov	bx,040Q*256 + 0ch
	int	10h

	mov	ax,1000h
	mov	bx,050Q*256 + 0dh
	int	10h

	mov	ax,1000h
	mov	bx,060Q*256 + 0eh
	int	10h

	mov	ax,1000h
	mov	bx,070Q*256 + 0fh
	int	10h
        ret
set_ega_pallete endp

move_right_vga:
	inc	di
	ret

move_left_vga:
	dec	di
	ret

move_up_vga:
	sub	di,320			;width of screen.
	ret

move_down_vga:
	add	di,320			;width of screen.
	ret

set_bit_vga:
	mov	es:[di],al
	ret



move_right_ega:
	shr	ah,1			;move right by a bit.
	ror	ah,1			;move right by another bit,

	adc	di,0			;  and handle byte increment.
	ret


move_left_ega:
	rol	ah,1			;move left by a bit,
	adc	di,0			;  and handle byte increment.
	shl	ah,1			;move left by another bit.
	ret


move_up_ega:
	sub	di,80*2			;width of screen.
	ret


move_down_ega:
	add	di,80*2			;width of screen.
	ret


set_bit_ega:
	mov	bl,al
	xor	bh,bh

	mov	al,ah
	out	dx,al
	mov	al,ulpal[bx]
	xchg	es:[di],al		;store the palette value.
	mov	al,llpal[bx]
	xchg	es:[di+80],al		;store the palette value.

	shr	ah,1			;move right by a bit.

	mov	al,ah
	out	dx,al
	mov	al,urpal[bx]
	xchg	es:[di],al		;store the palette value.
	mov	al,lrpal[bx]
	xchg	es:[di+80],al		;store the palette value.

	shl	ah,1			;restore the bit.

	ret

Save_Name        DB      'IMAGE__.000',0
Save_Handle      DW      0
Save_Counter     DB      0
Load_Name       db 31 dup(0),0
Load_Handle     DW      0
Load_Counter    DB      0
; ===========================================================================
Screen_Dump    PROC    FAR
; ===========================================================================
        PUSH    DS                      ;Preserve DS

        ;--- Open next file (*.001 first time, *.002 next,  ...)

        MOV     AX,CS                   ;Setup pointer to file name
        MOV     DS,AX                   ;into DS:DX

        INC     Save_Name[10]           ;Change name so that we can call
                                        ;this routine several times
        LEA     DX,Save_Name
        MOV     CX,0                    ;Normal attribute for the file
        MOV     AH,3CH                  ;DOS function to open file
        INT     21H                     ;Ask DOS to open the file
        JC      Dump_Error              ;Quit on open error
        MOV     Save_Handle,AX          ;Save the handle to the opened file

        ;--- Enable next plane and write the 28,000 bytes into a file

        MOV     Save_Counter,3          ;Initialize counter of planes done
        MOV     DX,3CEH                 ;Select READ MAP SELECT register
        MOV     AL,4                    ;in graphics controller
        OUT     DX,AL
        MOV     AX,0A000H               ;Point DS:DX to display buffer
        MOV     DS,AX
Dump_Plane_Loop:
        MOV     AL,CS:Save_Counter      ;Select next plane for read
        MOV     DX,3CFH
        OUT     DX,AL
        XOR     DX,DX
        MOV     CX,28000                ;Number of bytes to write
        MOV     BX,CS:Save_Handle       ;File handle
        MOV     AH,40H                  ;DOS function to write into a file
        INT     21H                     ;Ask DOS to write data into a file
        JC      Close_Dump_File         ;Quit on error
        CMP     AX,28000
        JNE     Close_Dump_File
        DEC     CS:Save_Counter         ;Check if all planes are done
        JGE     Dump_Plane_Loop ;and if not go do next plane

        ;--- Close the file

Close_Dump_File:
        MOV     BX,CS:Save_Handle       ;Fetch handle
        MOV     AH,3EH                  ;DOS function to close a file
        INT     21H                     ;Ask DOS to close the file
Dump_Done:
        MOV     DX,3CEH                 ;Restore plane 0 for read by
        MOV     AL,3                    ;setting READ MAP register
        OUT     DX,AL                   ;in GRAPHICS controller
        INC     DX
        MOV     AL,0
        OUT     DX,AL

        POP     DS                      ;Restore DS
        RET
Dump_Error:                             ;This is where we can add error
        JMP     Dump_Done               ;reporting
Screen_Dump    ENDP

Screen_Load    PROC    FAR
        PUSH    BP                      ;Standard high level entry
        MOV     BP,SP
        PUSH    DS                      ;Preserve DS

        ;--- Open the file

        lea     DX, Load_Name            ;Fetch pointer to the file name
        MOV     CX,0                    ;Normal attribute for the file
        MOV     AH,3DH                  ;DOS function to open file
        MOV     AL,0                    ;Open file for READ
        INT     21H                     ;Ask DOS to open the file
        JC      Load_Error              ;Quit on open error
        MOV     Load_Handle,AX          ;Save the handle to the opened file

        ;--- Enable next plane and read 28,000 bytes into it

        MOV     Load_Counter,8          ;Initialize counter of planes done
        MOV     AX,0A000H               ;Point DS:DX to display buffer
        MOV     DS,AX
        MOV     DX,3C4H                 ;Select PLANE ENABLE register
        MOV     AL,2                    ;in SEQUENCER
        OUT     DX,AL
Load_Loop:
        MOV     AL,CS:Load_Counter      ;Select next plane for write
        MOV     DX,3C5H
        OUT     DX,AL
        XOR     DX,DX
        MOV     CX,28000                ;Number of bytes to read
        MOV     BX,CS:Load_Handle       ;File handle
        MOV     AH,3FH                  ;DOS function to read from a file
        INT     21H                     ;Ask DOS to read data from a file
        JC      Close_Load_File         ;Quit on error
        CMP     AX,28000
        JNE     Close_Load_File
        SHR     CS:Load_Counter,1       ;Check if all planes are done
        JNZ     Load_Loop               ;and if not go do next plane

        ;--- Close the file

Close_Load_File:
        MOV     BX,CS:Load_Handle       ;Fetch handle
        MOV     AH,3EH                  ;DOS function to close a file
        INT     21H                     ;Ask DOS to close the file
Load_Done:
        MOV     DX,3C4H                 ;Restore all four planes for write
        MOV     AL,2                    ;By loading PLANE ENABLE register
        OUT     DX,AL                   ;in the SEQUENCER
        INC     DX
        MOV     AL,0FH
        OUT     DX,AL

        POP     DS                      ;Restore DS
        POP     BP
        RET
Load_Error:                             ;This is where we can add error
        JMP     Load_Done               ;reporting
Screen_Load    ENDP

; ===========================================================================
openvideo proc far
; ===========================================================================
        cmp  ax, 13h
        je   set_lohic
        cmp  ax, 12h
        je   set_hiloc
        cmp  ax, 10h
        je   set_egamode
        ;
        ; autodetect and open appropiate mode
        ;
        call cs:is_vga
        mov  cs:vidtype, bl
        cmp  bl, 3
        je   set_lohic
        cmp  bl, 4
        je   set_hiloc
        stc
        jmp  ov_x
set_hiloc:
        mov  ax, vm640x480x16
        call cs:setvideo
        clc
        jmp  ov_x
set_lohic:
        mov  ax, vm320x200x256                  ;put the screen into vga mode.
        call cs:setvideo
        clc
        jmp  ov_x
set_egamode:
        mov  ax, 10h                  ;put the screen into ega mode.
        call setvideo
        ; enter with cx,dx = point on screen.
        ; exit with es:di,ah -> byte/bit on screen.
	mov	ax,640/8*2		;bytes per scan line * scan lines per pixel
	mul	dx
	mov	di,ax
	mov	ax,cx			;/8*2
	shr	ax,1
	shr	ax,1
	add	di,ax

	mov	dx,03ceh		;graphics controller
	mov	ax,0205h		;write mode 2.
	out	dx,al
	inc	dx
	mov	al,ah
	out	dx,al
	dec	dx
	mov	al,08h			;select bitmap register.
	out	dx,al
	inc	dx

	shl	cx,1			;compute the bit.
	and	cl,7
	mov	ah,80h
	shr	ah,cl

        call cs:set_ega_pallete
        clc

        jmp  ov_x

ov_x:   mov  bl, cs:vidtype
        mov  al, cs:_oldmode
        mov  dx, cs:vmode
        ret
openvideo endp 

; ===========================================================================
closevideo proc far
; ===========================================================================
        mov  ax, cs:vmode
        cmp  ax, 13h
        je   close_mode13
        cmp  ax, 12h
        je   close_mode12
        cmp  ax, 10h
        je   close_mode10
        jmp  close2text
close_mode10:
	mov	al,0ffh			;mask = all ones.
	out	dx,al
	dec	dx
	mov	ax,0005h		;write mode 0
	out	dx,al
	inc	dx
	mov	al,ah
	out	dx,al
        jmp  close2text
close_mode12:

        jmp  close2text
close_mode13:
        jmp  close2text

close2text:
        mov  ax, vm80x25x16
        call setvideo
        ret
closevideo endp

; ===========================================================================
; OpenGL Sample Implementation    URL: http://oss.sgi.com/projects/ogl-sample
; ===========================================================================

; ===========================================================================
ogl_initialize proc far
; Input : DS:SI = bdigrapgicsinit, passing null will use defaults
; Initializes the NXDOS Runtime API for OpenGL environment
; Should only be called once per program execution. Call ogl_getdefualts to
; fill the init structure before changing entries.
; ===========================================================================

         ret
ogl_initialize endp

; ===========================================================================
ogl_getdefaults proc far
; Input : DS:SI = bdigrapgicsinit
; ===========================================================================

         ret
ogl_getdefaults endp

; ===========================================================================
ogl_generate_character_texture_list proc far
; Scenario* scenario, int character_index
; ===========================================================================

         ret
ogl_generate_character_texture_list endp

;if texture count > 0 {
;   int texture_index
;   for texture index = 0 texture index < texture count texture index++
;       texture_object = ogl_get_character_texture_list_texture_object_at_index(scenario

