From 378a14ea6548341da2eb90f31a1f5b87672867cf Mon Sep 17 00:00:00 2001
From: sparky4 <sparky4@cock.li>
Date: Thu, 19 Nov 2015 12:12:28 -0600
Subject: [PATCH] readded modex library

---
 16/x/DEFAULT.FNT | 260 +++++++++++++++++++
 16/x/MAKEFILE    |  81 ++++++
 16/x/MODEX.BAK   | Bin 0 -> 25600 bytes
 16/x/MODEX.DEF   | 163 ++++++++++++
 16/x/MODEX.H     | 153 +++++++++++
 16/x/MODEX.LBR   |  39 +++
 16/x/MODEX.PAS   | 194 ++++++++++++++
 16/x/MXBB.ASM    | 278 ++++++++++++++++++++
 16/x/MXCC.ASM    | 644 +++++++++++++++++++++++++++++++++++++++++++++++
 16/x/MXCG.ASM    |  69 +++++
 16/x/MXCL.ASM    | 151 +++++++++++
 16/x/MXCR.ASM    | 380 ++++++++++++++++++++++++++++
 16/x/MXEL.ASM    | 167 ++++++++++++
 16/x/MXFB.ASM    | 194 ++++++++++++++
 16/x/MXFP.ASM    | 326 ++++++++++++++++++++++++
 16/x/MXGC.ASM    |  54 ++++
 16/x/MXGI.ASM    | 132 ++++++++++
 16/x/MXGM.ASM    |  63 +++++
 16/x/MXGP.ASM    |  56 +++++
 16/x/MXGV.ASM    |  25 ++
 16/x/MXHL.ASM    |  76 ++++++
 16/x/MXIT.ASM    |  98 ++++++++
 16/x/MXLL.ASM    |  82 ++++++
 16/x/MXLN.ASM    | 414 ++++++++++++++++++++++++++++++
 16/x/MXOT.ASM    | 330 ++++++++++++++++++++++++
 16/x/MXPB.ASM    |  22 ++
 16/x/MXPF.ASM    | 420 +++++++++++++++++++++++++++++++
 16/x/MXPG.ASM    | 589 +++++++++++++++++++++++++++++++++++++++++++
 16/x/MXPI.ASM    | 267 ++++++++++++++++++++
 16/x/MXPN.ASM    |  60 +++++
 16/x/MXPP.ASM    | 121 +++++++++
 16/x/MXRA.ASM    |  37 +++
 16/x/MXRP.ASM    | 101 ++++++++
 16/x/MXSA.ASM    |  44 ++++
 16/x/MXSC.ASM    |  50 ++++
 16/x/MXSI.ASM    | 317 +++++++++++++++++++++++
 16/x/MXSL.ASM    |  62 +++++
 16/x/MXSM.ASM    | 508 +++++++++++++++++++++++++++++++++++++
 16/x/MXSP.ASM    |  57 +++++
 16/x/MXSS.ASM    |  72 ++++++
 16/x/MXTL.ASM    | 169 +++++++++++++
 16/x/MXVS.ASM    | 110 ++++++++
 16/x/MXWD.ASM    |  28 +++
 16/x/MXWM.ASM    |  39 +++
 16/x/MXWP.ASM    |  62 +++++
 16/x/MXWR.ASM    |  28 +++
 16/x/readme.txt  |   8 +
 47 files changed, 7600 insertions(+)
 create mode 100755 16/x/DEFAULT.FNT
 create mode 100755 16/x/MAKEFILE
 create mode 100755 16/x/MODEX.BAK
 create mode 100755 16/x/MODEX.DEF
 create mode 100755 16/x/MODEX.H
 create mode 100755 16/x/MODEX.LBR
 create mode 100755 16/x/MODEX.PAS
 create mode 100755 16/x/MXBB.ASM
 create mode 100755 16/x/MXCC.ASM
 create mode 100755 16/x/MXCG.ASM
 create mode 100755 16/x/MXCL.ASM
 create mode 100755 16/x/MXCR.ASM
 create mode 100755 16/x/MXEL.ASM
 create mode 100755 16/x/MXFB.ASM
 create mode 100755 16/x/MXFP.ASM
 create mode 100755 16/x/MXGC.ASM
 create mode 100755 16/x/MXGI.ASM
 create mode 100755 16/x/MXGM.ASM
 create mode 100755 16/x/MXGP.ASM
 create mode 100755 16/x/MXGV.ASM
 create mode 100755 16/x/MXHL.ASM
 create mode 100755 16/x/MXIT.ASM
 create mode 100755 16/x/MXLL.ASM
 create mode 100755 16/x/MXLN.ASM
 create mode 100755 16/x/MXOT.ASM
 create mode 100755 16/x/MXPB.ASM
 create mode 100755 16/x/MXPF.ASM
 create mode 100755 16/x/MXPG.ASM
 create mode 100755 16/x/MXPI.ASM
 create mode 100755 16/x/MXPN.ASM
 create mode 100755 16/x/MXPP.ASM
 create mode 100755 16/x/MXRA.ASM
 create mode 100755 16/x/MXRP.ASM
 create mode 100755 16/x/MXSA.ASM
 create mode 100755 16/x/MXSC.ASM
 create mode 100755 16/x/MXSI.ASM
 create mode 100755 16/x/MXSL.ASM
 create mode 100755 16/x/MXSM.ASM
 create mode 100755 16/x/MXSP.ASM
 create mode 100755 16/x/MXSS.ASM
 create mode 100755 16/x/MXTL.ASM
 create mode 100755 16/x/MXVS.ASM
 create mode 100755 16/x/MXWD.ASM
 create mode 100755 16/x/MXWM.ASM
 create mode 100755 16/x/MXWP.ASM
 create mode 100755 16/x/MXWR.ASM
 create mode 100755 16/x/readme.txt

diff --git a/16/x/DEFAULT.FNT b/16/x/DEFAULT.FNT
new file mode 100755
index 00000000..12eb22cb
--- /dev/null
+++ b/16/x/DEFAULT.FNT
@@ -0,0 +1,260 @@
+;
+; MODEX library default font
+; Copyright (c) 1993-1994 by Alessandro Scotti
+;
+  DB    000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h  ; #0
+  DB	07Eh, 081h, 0A5h, 081h, 0A5h, 099h, 081h, 07Eh	; #1
+  DB	07Eh, 0FFh, 0DBh, 0FFh, 0DBh, 0E7h, 0FFh, 07Eh	; #2
+  DB	06Ch, 0FEh, 0FEh, 0FEh, 07Ch, 038h, 010h, 000h	; #3
+  DB	010h, 038h, 07Ch, 0FEh, 07Ch, 038h, 010h, 000h	; #4
+  DB	010h, 038h, 010h, 054h, 0FEh, 054h, 010h, 0FEh	; #5
+  DB	010h, 038h, 07Ch, 0FEh, 0FEh, 07Ch, 010h, 0FEh	; #6
+  DB	000h, 018h, 03Ch, 07Eh, 07Eh, 03Ch, 018h, 000h	; #7
+  DB	0FFh, 0E7h, 0C3h, 081h, 081h, 0C3h, 0E7h, 0FFh	; #8
+  DB	000h, 03Ch, 066h, 042h, 042h, 066h, 03Ch, 000h	; #9
+  DB	0FFh, 0C3h, 099h, 0BDh, 0BDh, 099h, 0C3h, 0FFh	; #10
+  DB	007h, 003h, 005h, 078h, 084h, 084h, 084h, 078h	; #11
+  DB	07Ch, 082h, 082h, 082h, 07Ch, 010h, 038h, 010h	; #12
+  DB	01Ch, 010h, 01Ch, 010h, 010h, 010h, 030h, 030h	; #13
+  DB	03Eh, 022h, 03Eh, 022h, 022h, 026h, 066h, 060h	; #14
+  DB	099h, 05Ah, 03Ch, 0E7h, 0E7h, 03Ch, 05Ah, 099h	; #15
+  DB	000h, 010h, 030h, 070h, 0F0h, 070h, 030h, 010h	; #16
+  DB	000h, 080h, 0C0h, 0E0h, 0F0h, 0E0h, 0C0h, 080h	; #17
+  DB	010h, 038h, 054h, 010h, 010h, 054h, 038h, 010h	; #18
+  DB	048h, 048h, 048h, 048h, 048h, 000h, 048h, 000h	; #19
+  DB	07Eh, 092h, 092h, 072h, 012h, 012h, 012h, 000h	; #20
+  DB	03Ch, 022h, 018h, 024h, 024h, 018h, 044h, 03Ch	; #21
+  DB	000h, 000h, 000h, 000h, 000h, 03Eh, 03Eh, 000h	; #22
+  DB	038h, 054h, 010h, 010h, 010h, 054h, 038h, 0FEh	; #23
+  DB	000h, 010h, 038h, 054h, 010h, 010h, 010h, 000h	; #24
+  DB	000h, 010h, 010h, 010h, 054h, 038h, 010h, 000h	; #25
+  DB	000h, 008h, 004h, 0FEh, 004h, 008h, 000h, 000h	; #26
+  DB	000h, 020h, 040h, 0FEh, 040h, 020h, 000h, 000h	; #27
+  DB	000h, 000h, 080h, 080h, 080h, 0FCh, 000h, 000h	; #28
+  DB	000h, 024h, 042h, 0FFh, 042h, 024h, 000h, 000h	; #29
+  DB	000h, 000h, 010h, 038h, 07Ch, 0FEh, 000h, 000h	; #30
+  DB	000h, 000h, 0FEh, 07Ch, 038h, 010h, 000h, 000h	; #31
+  DB	000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	;  
+  DB	010h, 010h, 010h, 010h, 010h, 000h, 010h, 000h	; !
+  DB	000h, 024h, 024h, 000h, 000h, 000h, 000h, 000h	; "
+  DB	024h, 024h, 07Eh, 024h, 07Eh, 024h, 024h, 000h	; #
+  DB	038h, 054h, 050h, 038h, 014h, 054h, 038h, 010h	; $
+  DB	000h, 002h, 044h, 008h, 010h, 020h, 042h, 000h	; %
+  DB	038h, 044h, 038h, 060h, 094h, 088h, 074h, 000h	; &
+  DB	020h, 020h, 040h, 000h, 000h, 000h, 000h, 000h	; '
+  DB	010h, 020h, 040h, 040h, 040h, 020h, 010h, 000h	; (
+  DB	040h, 020h, 010h, 010h, 010h, 020h, 040h, 000h	; )
+  DB	000h, 024h, 018h, 07Eh, 018h, 024h, 000h, 000h	; *
+  DB	000h, 010h, 010h, 07Ch, 010h, 010h, 000h, 000h	; +
+  DB	000h, 000h, 000h, 000h, 000h, 010h, 010h, 020h	; ,
+  DB	000h, 000h, 000h, 0FCh, 000h, 000h, 000h, 000h	; -
+  DB	000h, 000h, 000h, 000h, 000h, 000h, 010h, 000h	; .
+  DB	000h, 004h, 008h, 010h, 020h, 040h, 080h, 000h	; /
+  DB	07Ch, 0C6h, 08Ah, 092h, 0A2h, 0C6h, 07Ch, 000h	; 0
+  DB	010h, 030h, 010h, 010h, 010h, 010h, 038h, 000h	; 1
+  DB	078h, 084h, 004h, 018h, 060h, 080h, 0FCh, 000h	; 2
+  DB	078h, 084h, 004h, 038h, 004h, 084h, 078h, 000h	; 3
+  DB	01Ch, 024h, 044h, 084h, 0FEh, 004h, 00Eh, 000h	; 4
+  DB	0FCh, 080h, 0F8h, 004h, 004h, 084h, 078h, 000h	; 5
+  DB	078h, 084h, 080h, 0F8h, 084h, 084h, 078h, 000h	; 6
+  DB	0FCh, 004h, 004h, 008h, 010h, 020h, 020h, 000h	; 7
+  DB	078h, 084h, 084h, 078h, 084h, 084h, 078h, 000h	; 8
+  DB	078h, 084h, 084h, 07Ch, 004h, 084h, 078h, 000h	; 9
+  DB	000h, 000h, 010h, 000h, 000h, 000h, 010h, 000h	; :
+  DB	000h, 000h, 010h, 000h, 000h, 010h, 010h, 020h	; ;
+  DB	008h, 010h, 020h, 040h, 020h, 010h, 008h, 000h	; <
+  DB	000h, 000h, 0FCh, 000h, 000h, 0FCh, 000h, 000h	; =
+  DB	040h, 020h, 010h, 008h, 010h, 020h, 040h, 000h	; >
+  DB	078h, 084h, 004h, 008h, 010h, 000h, 010h, 000h	; ?
+  DB	07Ch, 082h, 0BAh, 0A6h, 0BEh, 080h, 07Ch, 000h	; @
+  DB	078h, 084h, 084h, 0FCh, 084h, 084h, 084h, 000h	; A
+  DB	0F8h, 084h, 084h, 0F8h, 084h, 084h, 0F8h, 000h	; B
+  DB	078h, 084h, 080h, 080h, 080h, 084h, 078h, 000h	; C
+  DB	0F0h, 088h, 084h, 084h, 084h, 088h, 0F0h, 000h	; D
+  DB	0FCh, 080h, 080h, 0F0h, 080h, 080h, 0FCh, 000h	; E
+  DB	0FCh, 080h, 080h, 0F0h, 080h, 080h, 080h, 000h	; F
+  DB	078h, 084h, 080h, 09Ch, 084h, 084h, 078h, 000h	; G
+  DB	084h, 084h, 084h, 0FCh, 084h, 084h, 084h, 000h	; H
+  DB	038h, 010h, 010h, 010h, 010h, 010h, 038h, 000h	; I
+  DB	01Ch, 008h, 008h, 008h, 088h, 088h, 070h, 000h	; J
+  DB	084h, 088h, 090h, 0E0h, 090h, 088h, 084h, 000h	; K
+  DB	080h, 080h, 080h, 080h, 080h, 080h, 0FCh, 000h	; L
+  DB	0C6h, 0AAh, 092h, 082h, 082h, 082h, 082h, 000h	; M
+  DB	082h, 0C2h, 0A2h, 092h, 08Ah, 086h, 082h, 000h	; N
+  DB	078h, 084h, 084h, 084h, 084h, 084h, 078h, 000h	; O
+  DB	0F8h, 084h, 084h, 0F8h, 080h, 080h, 080h, 000h	; P
+  DB	078h, 084h, 084h, 084h, 094h, 088h, 076h, 000h	; Q
+  DB	0F8h, 084h, 084h, 0F8h, 090h, 088h, 084h, 000h	; R
+  DB	078h, 084h, 080h, 078h, 004h, 084h, 078h, 000h	; S
+  DB	0FEh, 010h, 010h, 010h, 010h, 010h, 010h, 000h	; T
+  DB	084h, 084h, 084h, 084h, 084h, 084h, 078h, 000h	; U
+  DB	084h, 084h, 084h, 084h, 084h, 048h, 030h, 000h	; V
+  DB	082h, 082h, 082h, 082h, 092h, 0AAh, 0C6h, 000h	; W
+  DB	082h, 044h, 028h, 010h, 028h, 044h, 082h, 000h	; X
+  DB	044h, 044h, 044h, 038h, 010h, 010h, 010h, 000h	; Y
+  DB	0FEh, 004h, 008h, 010h, 020h, 040h, 0FEh, 000h	; Z
+  DB	078h, 040h, 040h, 040h, 040h, 040h, 078h, 000h	; [
+  DB	000h, 080h, 040h, 020h, 010h, 008h, 004h, 000h	; \
+  DB	078h, 008h, 008h, 008h, 008h, 008h, 078h, 000h	; ]
+  DB	010h, 028h, 044h, 082h, 000h, 000h, 000h, 000h	; ^
+  DB	000h, 000h, 000h, 000h, 000h, 000h, 000h, 0FFh	; _
+  DB	020h, 020h, 010h, 000h, 000h, 000h, 000h, 000h	; `
+  DB	000h, 000h, 038h, 004h, 03Ch, 044h, 07Ch, 000h	; a
+  DB	000h, 040h, 040h, 078h, 044h, 044h, 078h, 000h	; b
+  DB	000h, 000h, 03Ch, 040h, 040h, 040h, 03Ch, 000h	; c
+  DB	000h, 004h, 004h, 03Ch, 044h, 044h, 03Ch, 000h	; d
+  DB	000h, 000h, 038h, 044h, 07Ch, 040h, 03Ch, 000h	; e
+  DB	000h, 00Ch, 010h, 03Ch, 010h, 010h, 010h, 000h	; f
+  DB	000h, 000h, 03Ch, 044h, 044h, 03Ch, 004h, 038h	; g
+  DB	000h, 040h, 040h, 078h, 044h, 044h, 044h, 000h	; h
+  DB	000h, 010h, 000h, 010h, 010h, 010h, 010h, 000h	; i
+  DB	000h, 004h, 000h, 004h, 004h, 004h, 044h, 038h	; j
+  DB	000h, 040h, 040h, 050h, 060h, 050h, 048h, 000h	; k
+  DB	000h, 030h, 010h, 010h, 010h, 010h, 010h, 000h	; l
+  DB	000h, 000h, 068h, 054h, 054h, 044h, 044h, 000h	; m
+  DB	000h, 000h, 078h, 044h, 044h, 044h, 044h, 000h	; n
+  DB	000h, 000h, 038h, 044h, 044h, 044h, 038h, 000h	; o
+  DB	000h, 000h, 078h, 044h, 044h, 078h, 040h, 040h	; p
+  DB	000h, 000h, 03Ch, 044h, 044h, 03Ch, 004h, 004h	; q
+  DB	000h, 000h, 05Ch, 060h, 040h, 040h, 040h, 000h	; r
+  DB	000h, 000h, 038h, 040h, 07Ch, 004h, 07Ch, 000h	; s
+  DB	000h, 010h, 038h, 010h, 010h, 010h, 018h, 000h	; t
+  DB	000h, 000h, 044h, 044h, 044h, 044h, 038h, 000h	; u
+  DB	000h, 000h, 044h, 044h, 044h, 028h, 010h, 000h	; v
+  DB	000h, 000h, 044h, 044h, 054h, 054h, 06Ch, 000h	; w
+  DB	000h, 000h, 044h, 028h, 010h, 028h, 044h, 000h	; x
+  DB	000h, 000h, 044h, 044h, 044h, 03Ch, 004h, 07Ch	; y
+  DB	000h, 000h, 07Ch, 004h, 038h, 040h, 07Ch, 000h	; z
+  DB	000h, 008h, 010h, 010h, 030h, 010h, 010h, 008h	; {
+  DB	000h, 010h, 010h, 010h, 000h, 010h, 010h, 010h	; |
+  DB	000h, 020h, 010h, 010h, 018h, 010h, 010h, 020h	; }
+  DB	064h, 098h, 000h, 000h, 000h, 000h, 000h, 000h	; ~
+  DB	000h, 010h, 028h, 044h, 082h, 082h, 0FEh, 000h	; 
+  DB	07Ch, 080h, 080h, 080h, 080h, 07Ch, 004h, 07Ch	; #128
+  DB	000h, 028h, 000h, 044h, 044h, 044h, 038h, 000h	; #129
+  DB	03Ch, 000h, 07Ch, 044h, 07Ch, 040h, 07Ch, 000h	; #130
+  DB	07Eh, 081h, 038h, 004h, 03Ch, 044h, 07Ch, 000h	; #131
+  DB	024h, 000h, 038h, 004h, 03Ch, 044h, 07Ch, 000h	; #132
+  DB	078h, 000h, 038h, 004h, 03Ch, 044h, 07Ch, 000h	; #133
+  DB	018h, 018h, 038h, 004h, 03Ch, 044h, 07Ch, 000h	; #134
+  DB	000h, 000h, 078h, 080h, 080h, 078h, 008h, 038h	; #135
+  DB	07Ch, 082h, 038h, 044h, 07Ch, 040h, 03Ch, 000h	; #136
+  DB	048h, 000h, 038h, 044h, 07Ch, 040h, 03Ch, 000h	; #137
+  DB	078h, 000h, 038h, 044h, 07Ch, 040h, 03Ch, 000h	; #138
+  DB	000h, 028h, 000h, 010h, 010h, 010h, 010h, 000h	; #139
+  DB	010h, 028h, 000h, 010h, 010h, 010h, 010h, 000h	; #140
+  DB	000h, 030h, 000h, 010h, 010h, 010h, 010h, 000h	; #141
+  DB	048h, 000h, 078h, 084h, 0FCh, 084h, 084h, 000h	; #142
+  DB	030h, 030h, 078h, 084h, 0FCh, 084h, 084h, 000h	; #143
+  DB	038h, 000h, 0FCh, 080h, 0F0h, 080h, 0FCh, 000h	; #144
+  DB	000h, 000h, 07Eh, 008h, 07Eh, 048h, 07Eh, 000h	; #145
+  DB	07Eh, 090h, 090h, 0FCh, 090h, 090h, 09Eh, 000h	; #146
+  DB	07Ch, 082h, 038h, 044h, 044h, 044h, 038h, 000h	; #147
+  DB	028h, 000h, 038h, 044h, 044h, 044h, 038h, 000h	; #148
+  DB	070h, 000h, 038h, 044h, 044h, 044h, 038h, 000h	; #149
+  DB	038h, 044h, 000h, 044h, 044h, 044h, 038h, 000h	; #150
+  DB	070h, 000h, 044h, 044h, 044h, 044h, 038h, 000h	; #151
+  DB	028h, 000h, 044h, 044h, 044h, 03Ch, 004h, 07Ch	; #152
+  DB	048h, 000h, 078h, 084h, 084h, 084h, 078h, 000h	; #153
+  DB	048h, 000h, 084h, 084h, 084h, 084h, 078h, 000h	; #154
+  DB	000h, 010h, 038h, 040h, 040h, 040h, 038h, 010h	; #155
+  DB	038h, 044h, 040h, 0E0h, 040h, 040h, 082h, 0FCh	; #156
+  DB	044h, 07Ch, 010h, 07Ch, 010h, 07Ch, 010h, 000h	; #157
+  DB	0F0h, 088h, 08Ah, 0F7h, 082h, 082h, 082h, 000h	; #158
+  DB	00Ch, 012h, 010h, 018h, 030h, 010h, 090h, 060h	; #159
+  DB	03Ch, 000h, 038h, 004h, 03Ch, 044h, 07Ch, 000h	; #160
+  DB	000h, 018h, 000h, 010h, 010h, 010h, 010h, 000h	; #161
+  DB	01Ch, 000h, 038h, 044h, 044h, 044h, 038h, 000h	; #162
+  DB	01Ch, 000h, 044h, 044h, 044h, 044h, 038h, 000h	; #163
+  DB	07Ch, 000h, 078h, 044h, 044h, 044h, 044h, 000h	; #164
+  DB	07Ch, 000h, 044h, 064h, 054h, 04Ch, 044h, 000h	; #165
+  DB	018h, 024h, 024h, 01Eh, 000h, 03Eh, 000h, 000h	; #166
+  DB	01Ch, 022h, 022h, 01Ch, 000h, 03Eh, 000h, 000h	; #167
+  DB	010h, 000h, 010h, 020h, 040h, 042h, 03Ch, 000h	; #168
+  DB	000h, 000h, 000h, 0FCh, 080h, 080h, 000h, 000h	; #169
+  DB	000h, 000h, 000h, 0FCh, 004h, 004h, 000h, 000h	; #170
+  DB	040h, 044h, 048h, 057h, 021h, 047h, 004h, 007h	; #171
+  DB	040h, 044h, 048h, 052h, 026h, 04Ah, 01Fh, 002h	; #172
+  DB	010h, 000h, 010h, 010h, 010h, 010h, 010h, 000h	; #173
+  DB	000h, 024h, 048h, 090h, 048h, 024h, 000h, 000h	; #174
+  DB	000h, 048h, 024h, 012h, 024h, 048h, 000h, 000h	; #175
+  DB	022h, 088h, 022h, 088h, 022h, 088h, 022h, 088h	; #176
+  DB	055h, 0AAh, 055h, 0AAh, 055h, 0AAh, 055h, 0AAh	; #177
+  DB	0DBh, 077h, 0DBh, 0EEh, 0DBh, 077h, 0DBh, 0EEh	; #178
+  DB	018h, 018h, 018h, 018h, 018h, 018h, 018h, 018h	; #179
+  DB	018h, 018h, 018h, 018h, 0F8h, 018h, 018h, 018h	; #180
+  DB	018h, 018h, 0F8h, 018h, 0F8h, 018h, 018h, 018h	; #181
+  DB	036h, 036h, 036h, 036h, 0F6h, 036h, 036h, 036h	; #182
+  DB	000h, 000h, 000h, 000h, 0FEh, 036h, 036h, 036h	; #183
+  DB	000h, 000h, 0F8h, 018h, 0F8h, 018h, 018h, 018h	; #184
+  DB	036h, 036h, 0F6h, 006h, 0F6h, 036h, 036h, 036h	; #185
+  DB	036h, 036h, 036h, 036h, 036h, 036h, 036h, 036h	; #186
+  DB	000h, 000h, 0FEh, 006h, 0F6h, 036h, 036h, 036h	; #187
+  DB	036h, 036h, 0F6h, 006h, 0FEh, 000h, 000h, 000h	; #188
+  DB	036h, 036h, 036h, 036h, 0FEh, 000h, 000h, 000h	; #189
+  DB	018h, 018h, 0F8h, 018h, 0F8h, 000h, 000h, 000h	; #190
+  DB	000h, 000h, 000h, 000h, 0F8h, 018h, 018h, 018h	; #191
+  DB	018h, 018h, 018h, 018h, 01Fh, 000h, 000h, 000h	; #192
+  DB	018h, 018h, 018h, 018h, 0FFh, 000h, 000h, 000h	; #193
+  DB	000h, 000h, 000h, 000h, 0FFh, 018h, 018h, 018h	; #194
+  DB	018h, 018h, 018h, 018h, 01Fh, 018h, 018h, 018h	; #195
+  DB	000h, 000h, 000h, 000h, 0FFh, 000h, 000h, 000h	; #196
+  DB	018h, 018h, 018h, 018h, 0FFh, 018h, 018h, 018h	; #197
+  DB	018h, 018h, 01Fh, 018h, 01Fh, 018h, 018h, 018h	; #198
+  DB	036h, 036h, 036h, 036h, 037h, 036h, 036h, 036h	; #199
+  DB	036h, 036h, 037h, 030h, 03Fh, 000h, 000h, 000h	; #200
+  DB	000h, 000h, 03Fh, 030h, 037h, 036h, 036h, 036h	; #201
+  DB	036h, 036h, 0F7h, 000h, 0FFh, 000h, 000h, 000h	; #202
+  DB	000h, 000h, 0FFh, 000h, 0F7h, 036h, 036h, 036h	; #203
+  DB	036h, 036h, 037h, 030h, 037h, 036h, 036h, 036h	; #204
+  DB	000h, 000h, 0FFh, 000h, 0FFh, 000h, 000h, 000h	; #205
+  DB	036h, 036h, 0F7h, 000h, 0F7h, 036h, 036h, 036h	; #206
+  DB	018h, 018h, 0FFh, 000h, 0FFh, 000h, 000h, 000h	; #207
+  DB	036h, 036h, 036h, 036h, 0FFh, 000h, 000h, 000h	; #208
+  DB	000h, 000h, 0FFh, 000h, 0FFh, 018h, 018h, 018h	; #209
+  DB	000h, 000h, 000h, 000h, 0FFh, 036h, 036h, 036h	; #210
+  DB	036h, 036h, 036h, 036h, 03Fh, 000h, 000h, 000h	; #211
+  DB	018h, 018h, 01Fh, 018h, 01Fh, 000h, 000h, 000h	; #212
+  DB	000h, 000h, 01Fh, 018h, 01Fh, 018h, 018h, 018h	; #213
+  DB	000h, 000h, 000h, 000h, 03Fh, 036h, 036h, 036h	; #214
+  DB	036h, 036h, 036h, 036h, 0FFh, 036h, 036h, 036h	; #215
+  DB	018h, 018h, 0FFh, 018h, 0FFh, 018h, 018h, 018h	; #216
+  DB	018h, 018h, 018h, 018h, 0F8h, 000h, 000h, 000h	; #217
+  DB	000h, 000h, 000h, 000h, 01Fh, 018h, 018h, 018h	; #218
+  DB	0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh	; #219
+  DB	000h, 000h, 000h, 000h, 0FFh, 0FFh, 0FFh, 0FFh	; #220
+  DB	0F0h, 0F0h, 0F0h, 0F0h, 0F0h, 0F0h, 0F0h, 0F0h	; #221
+  DB	00Fh, 00Fh, 00Fh, 00Fh, 00Fh, 00Fh, 00Fh, 00Fh	; #222
+  DB	0FFh, 0FFh, 0FFh, 0FFh, 000h, 000h, 000h, 000h	; #223
+  DB	000h, 000h, 062h, 094h, 088h, 094h, 062h, 000h	; #224
+  DB	000h, 0F0h, 088h, 0F0h, 088h, 088h, 0F0h, 080h	; #225
+  DB	000h, 0F8h, 088h, 080h, 080h, 080h, 080h, 000h	; #226
+  DB	000h, 0FCh, 048h, 048h, 048h, 048h, 048h, 000h	; #227
+  DB	0FCh, 084h, 040h, 020h, 040h, 084h, 0FCh, 000h	; #228
+  DB	03Ch, 040h, 038h, 044h, 044h, 044h, 038h, 000h	; #229
+  DB	000h, 000h, 044h, 044h, 044h, 078h, 040h, 040h	; #230
+  DB	000h, 036h, 048h, 008h, 008h, 008h, 008h, 000h	; #231
+  DB	038h, 010h, 038h, 044h, 044h, 038h, 010h, 038h	; #232
+  DB	078h, 084h, 084h, 0FCh, 084h, 084h, 078h, 000h	; #233
+  DB	078h, 084h, 084h, 084h, 048h, 048h, 0CCh, 000h	; #234
+  DB	078h, 004h, 038h, 044h, 044h, 044h, 038h, 000h	; #235
+  DB	000h, 000h, 06Ch, 092h, 092h, 06Ch, 000h, 000h	; #236
+  DB	000h, 000h, 03Ah, 044h, 05Ah, 022h, 05Ch, 000h	; #237
+  DB	018h, 020h, 040h, 078h, 040h, 020h, 018h, 000h	; #238
+  DB	078h, 084h, 084h, 084h, 084h, 084h, 084h, 000h	; #239
+  DB	000h, 0FCh, 000h, 0FCh, 000h, 0FCh, 000h, 000h	; #240
+  DB	020h, 020h, 0F8h, 020h, 020h, 000h, 0F8h, 000h	; #241
+  DB	020h, 010h, 008h, 010h, 020h, 000h, 07Ch, 000h	; #242
+  DB	008h, 010h, 020h, 010h, 008h, 000h, 07Ch, 000h	; #243
+  DB	00Ch, 012h, 010h, 010h, 010h, 010h, 010h, 010h	; #244
+  DB	010h, 010h, 010h, 010h, 010h, 010h, 090h, 060h	; #245
+  DB	000h, 010h, 000h, 07Ch, 000h, 010h, 000h, 000h	; #246
+  DB	000h, 032h, 04Ch, 000h, 032h, 04Ch, 000h, 000h	; #247
+  DB	038h, 044h, 044h, 038h, 000h, 000h, 000h, 000h	; #248
+  DB	000h, 000h, 000h, 018h, 018h, 000h, 000h, 000h	; #249
+  DB	000h, 000h, 000h, 000h, 018h, 000h, 000h, 000h	; #250
+  DB	00Eh, 008h, 008h, 008h, 048h, 028h, 018h, 008h	; #251
+  DB	038h, 024h, 024h, 024h, 024h, 000h, 000h, 000h	; #252
+  DB	03Ch, 004h, 03Ch, 020h, 03Ch, 000h, 000h, 000h	; #253
+  DB	000h, 000h, 03Ch, 03Ch, 03Ch, 03Ch, 000h, 000h	; #254
+  DB	000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h	; #255
diff --git a/16/x/MAKEFILE b/16/x/MAKEFILE
new file mode 100755
index 00000000..d3ad8b71
--- /dev/null
+++ b/16/x/MAKEFILE
@@ -0,0 +1,81 @@
+#
+# MODEX library makefile (for Borland MAKE)
+# Copyright (c) 1993,1994 by Alessandro Scotti
+#
+LIBINCS = MODEX.DEF
+
+LIBOBJS = MXBB.OBJ \
+          MXCC.OBJ \
+          MXCG.OBJ \
+          MXCL.OBJ \
+          MXCR.OBJ \
+          MXFB.OBJ \
+          MXFP.OBJ \
+          MXGC.OBJ \
+          MXGI.OBJ \
+          MXGM.OBJ \
+          MXGP.OBJ \
+          MXGV.OBJ \
+          MXHL.OBJ \
+          MXIT.OBJ \
+          MXLL.OBJ \
+          MXLN.OBJ \
+          MXOT.OBJ \
+          MXPB.OBJ \
+          MXPF.OBJ \
+          MXPG.OBJ \
+          MXPI.OBJ \
+          MXPN.OBJ \
+          MXPP.OBJ \
+          MXRA.OBJ \
+          MXRP.OBJ \
+          MXSA.OBJ \
+          MXSC.OBJ \
+          MXSI.OBJ \
+          MXSL.OBJ \
+          MXSM.OBJ \
+          MXSP.OBJ \
+          MXSS.OBJ \
+          MXTL.OBJ \
+          MXVS.OBJ \
+          MXWD.OBJ \
+          MXWM.OBJ \
+          MXWP.OBJ \
+          MXWR.OBJ
+
+#
+# ASM compiler
+#
+ASMC = tasm
+ASMO = /m5 /p
+
+#
+# PAS compiler
+#
+PASC = tpc
+PASO = /m -$D- -$L- -$S-
+
+#
+# LIB maker, uses response file
+#
+LIBC = tlib
+
+.asm.obj:
+        $(ASMC) $(ASMO) $<
+
+target: modex.lib
+# modex.tpu modex.tpp
+
+#modex.tpu: $(LIBOBJS) modex.pas
+#        $(PASC) $(PASO) modex
+#        copy modex.tpu ..
+#        copy modex.pas ..
+
+#modex.tpp: $(LIBOBJS) modex.pas
+#        $(PASC) /cp $(PASO) modex
+#        copy modex.tpp ..
+
+modex.lib: modex.lbr $(LIBOBJS)
+        $(LIBC) modex.lib @modex.lbr
+
+$(LIBOBJS):   modex.def
diff --git a/16/x/MODEX.BAK b/16/x/MODEX.BAK
new file mode 100755
index 0000000000000000000000000000000000000000..560a1c68304c56844f41325820f296a21192ac4e
GIT binary patch
literal 25600
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
aYMYlCQRoM`ir$`=9Z}>r1>yg*e*Xh>)L^y%

literal 0
HcmV?d00001

diff --git a/16/x/MODEX.DEF b/16/x/MODEX.DEF
new file mode 100755
index 00000000..45bd900f
--- /dev/null
+++ b/16/x/MODEX.DEF
@@ -0,0 +1,163 @@
+;------------------------------------------------------------
+;
+; MODEX.DEF - Include file
+; Copyright (c) 1993-1994 by Alessandro Scotti
+;
+JUMPS
+LOCALS
+
+TRUE            EQU     1       ; Boolean constants
+FALSE           EQU     0
+
+USE286  = FALSE                  ; TRUE enables 80286 instructions
+USE386  = FALSE                  ; TRUE enables 80386 (and 80286) instructions
+
+IF USE286 EQ TRUE
+        P286
+ENDIF
+
+IF USE386 EQ TRUE
+        P386
+        USE286  = TRUE
+ENDIF
+
+MXVERSION       EQU     0128h   ; Library version (1.40)
+
+;------------------------------------------------------------
+;
+; VGA definitions
+;
+MISC    EQU     3C2h            ; Miscellaneous output
+TS      EQU     3C4h            ; Timing Sequencer index register
+GDC     EQU     3CEh            ; Graphics Data Controller index register
+CRTC    EQU     3D4h            ; CRTC index register
+STATUS  EQU     3DAh            ; Input Status register one
+
+;------------------------------------------------------------
+;
+; Raster operators
+;
+OP_SET          EQU     0
+OP_MOVE         EQU     0       ; Same as OP_SET
+OP_AND          EQU     1
+OP_OR           EQU     2
+OP_XOR          EQU     3
+OP_TRANS        EQU     4
+OP_ADD          EQU     5       ; Must be last op
+
+;------------------------------------------------------------
+;
+; Polygon fill functions
+;
+POLYSCANBUFSIZE EQU     4*1024
+
+;------------------------------------------------------------
+; Macro to push registers, variables or flags onto the stack
+; Usage: .push "loc16"[,"loc16"...]
+; where "loc16" is a 16-bit register, a word-sized variable or the
+; keyword "FLAGS".
+; Exmpl: .push ax, flags, var1
+;        .pop  ax, flags, var1
+;
+.push   MACRO   r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10
+    IFNB <r10>
+        .ERROR <.PUSH has more than 10 arguments>
+    ENDIF
+    IRP $reg, <r0, r1, r2, r3, r4, r5, r6, r7, r8, r9>
+        IFB <$reg>                      ;; Is argument blank?
+            EXITM                       ;; Yes, exit
+        ELSEIFIDNI <$reg>, <FLAGS>      ;; Is argument the keyword "FLAGS"?
+            pushf                       ;; Yes, push flags
+        ELSE
+            push    $reg                ;; Push argument
+        ENDIF
+    ENDM
+ENDM
+
+;------------------------------------------------------------
+; Macro to pop registers, variables or flags from the stack
+; Usage: .pop "loc16"[,"loc16"...]
+; where "loc16" is a 16-bit register, a word-sized variable or the
+; keyword "FLAGS".
+; Exmpl: .push ax, flags, var1
+;        .pop  ax, flags, var1
+;
+.pop    MACRO   r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10
+    IFNB <r10>
+        .ERROR <.POP has more than 10 arguments>
+    ENDIF
+    IRP $reg, <r9, r8, r7, r6, r5, r4, r3, r2, r1, r0>
+        IFNB <$reg>                     ;; Is argument non-blank?
+            IFIDNI <$reg>, <FLAGS>      ;; Yes, is it the keyword "FLAGS"?
+                popf                    ;; Yes, pop flags
+            ELSE
+                pop     $reg            ;; Pop argument
+            ENDIF
+        ENDIF
+    ENDM
+ENDM
+
+;------------------------------------------------------------
+;
+.enter  MACRO   localsize
+    IF USE286 EQ TRUE
+        enter   localsize, 0
+    ELSE
+        push    bp
+        mov     bp, sp
+        sub     sp, localsize
+    ENDIF
+ENDM
+
+;------------------------------------------------------------
+;
+.leave  MACRO   argsize
+    IF USE286 EQ TRUE
+        leave
+    ELSE
+        mov     sp, bp
+        pop     bp
+    ENDIF
+    IFNB <argspace>
+        ret     argsize
+    ELSE
+        ret
+    ENDIF
+ENDM
+
+;------------------------------------------------------------
+;
+.shr    MACRO   arg, count
+    IF USE286 EQ TRUE
+        shr     arg, count
+    ELSE
+        $temp = count
+        WHILE $temp GT 0
+            shr arg, 1
+            $temp = $temp-1
+        ENDM
+    ENDIF
+ENDM
+
+;------------------------------------------------------------
+;
+.shl    MACRO   arg, count
+    IF USE286 EQ TRUE
+        shl     arg, count
+    ELSE
+        $temp = count
+        WHILE $temp GT 0
+            shl arg, 1
+            $temp = $temp-1
+        ENDM
+    ENDIF
+ENDM
+
+;------------------------------------------------------------
+;
+.chk386 MACRO   name, jump
+    IF USE386 EQ FALSE
+        .OUT    "Warning: ", <name>, " needs a 386 or better to run!"
+        jmp     @@jump
+    ENDIF
+ENDM
diff --git a/16/x/MODEX.H b/16/x/MODEX.H
new file mode 100755
index 00000000..2c1f1ebe
--- /dev/null
+++ b/16/x/MODEX.H
@@ -0,0 +1,153 @@
+/*
+    MODEX.H - C/C++ include file for the MODEX library
+    Copyright (c) 1994 Alessandro Scotti
+*/
+
+#ifndef _MODEX_H_               // Avoid nested inclusions
+#define _MODEX_H_
+
+//
+// Video modes
+//
+#define MX_TEXT     0           // 80x25 text
+#define MX_320x175  1           // 320x175x256
+#define MX_320x200  2           // 320x200x256, 4 pages, aspect 6:5
+#define MX_320x240  3           // 320x240x256, 3 pages, aspect 1:1
+#define MX_320x350  4           // 320x350x256
+#define MX_320x400  5           // 320x400x256, 2 pages
+#define MX_320x480  6           // 320x480x256, 1 page
+#define MX_360x175  7           // 360x175x256
+#define MX_360x200  8           // 360x200x256, 3 pages
+#define MX_360x240  9           // 360x240x256, 2 pages
+#define MX_360x350  10          // 360x350x256
+#define MX_360x400  11          // 360x400x256, 1 page
+#define MX_360x480  12          // 360x480x256, 1 page
+#define MX_400x600  13          // 400x600x256, 1 page
+
+//
+// Fade effects
+//
+#define MX_FADEIN   0
+#define MX_FADEOUT  1
+
+//
+// Raster ops
+//
+#define OP_SET      0           // No operator
+#define OP_AND      1           // And
+#define OP_OR       2           // Or
+#define OP_XOR      3           // Xor
+#define OP_TRANS    4           // Transparent
+#define OP_ADD      5           // Additive
+#define OP_MOVE     0           // Alias for OP_SET
+
+//
+// Temporary definitions
+//
+#define MXBYTE      unsigned char
+#define MXBOOL      short int
+#define MXSINT      short int
+#define MXUINT      unsigned short int
+#define MXAPI       far pascal
+#define MXPTR       void far *
+
+// Functions
+
+#ifdef __cplusplus                      // Avoid C++ name mangling
+extern "C" {
+#endif
+
+//
+// Initialization
+//
+MXSINT  MXAPI mxInit( void );             // Returns 0 if successful
+void    MXAPI mxTerm( void );
+MXUINT  MXAPI mxGetVersion( void );
+//
+// Mode setting
+//
+void    MXAPI mxChangeMode( MXUINT mode );
+void    MXAPI mxSetMode( MXUINT mode );
+void    MXAPI mxGetAspect( MXUINT far *aspectx, MXUINT far *aspecty );
+void    MXAPI mxGetScreenSize( MXUINT far *width, MXUINT far *height );
+//
+// Hardware support
+//
+void    MXAPI mxWriteMode( MXBYTE wm );
+void    MXAPI mxSplitScreen( MXUINT line );
+void    MXAPI mxStartAddress( MXUINT sa );
+void    MXAPI mxStartLine( MXUINT sl );
+void    MXAPI mxWaitDisplay( void );
+void    MXAPI mxWaitRetrace( void );
+void    MXAPI mxWritePlane( MXBYTE wp );
+void    MXAPI mxReadPlane( MXBYTE rp );
+void    MXAPI mxRowAddress( MXBYTE ra );
+//
+// Virtual screen
+//
+void    MXAPI mxGetVirtualScreen( MXUINT far *width, MXUINT far *height );
+void    MXAPI mxSetVirtualScreen( MXUINT width, MXUINT height );
+void    MXAPI mxPan( MXUINT x, MXUINT y );
+//
+// Clipping
+//
+MXBOOL  MXAPI mxGetClip( void );
+MXBOOL  MXAPI mxGetClipRegion( MXSINT far *x, MXSINT far *y, MXSINT far *w, MXSINT far *h );
+MXBOOL  MXAPI mxSetClip( MXBOOL );
+void    MXAPI mxSetClipRegion( MXUINT x, MXUINT y, MXUINT width, MXUINT height );
+//
+// Graphics
+//
+void    MXAPI mxBitBlt( MXSINT sx, MXSINT sy, MXUINT width, MXUINT height, MXSINT dx, MXSINT dy );
+void    MXAPI mxFillBox( MXSINT x, MXSINT y, MXUINT width, MXUINT height, MXUINT color, MXUINT op );
+MXBYTE  MXAPI mxGetPixel( MXSINT x, MXSINT y );
+void    MXAPI mxPutPixel( MXSINT x, MXSINT y, MXBYTE color );
+void    MXAPI mxLine( MXSINT x1, MXSINT y1, MXSINT x2, MXSINT y2, MXUINT color, MXUINT op );
+void    MXAPI mxGetImage( MXPTR img, MXSINT x, MXSINT y, MXUINT width, MXUINT height );
+void    MXAPI mxPutImage( MXPTR img, MXSINT x, MXSINT y, MXUINT w, MXUINT h, MXUINT op );
+void    MXAPI mxPutTile( MXPTR tile, MXSINT x, MXSINT y, MXUINT width, MXUINT height );
+void    MXAPI mxTransPutTile( MXPTR tile, MXSINT x, MXSINT y, MXUINT w, MXUINT h );
+void    MXAPI mxCircle( MXSINT x, MXSINT y, MXUINT radius, MXBYTE color );
+void    MXAPI mxStretchImage( MXPTR img, MXSINT x, MXSINT y, MXUINT w, MXUINT h, MXUINT neww, MXUINT newh, MXUINT op );
+//
+// Palette
+//
+void    MXAPI mxColorToGray( MXPTR source, MXPTR dest, MXUINT count );
+void    MXAPI mxGammaCorrect( MXPTR source, MXPTR dest, MXUINT count );
+void    MXAPI mxGetColor( MXUINT index, MXSINT far *r, MXSINT far *g, MXSINT far *b );
+void    MXAPI mxSetColor( MXUINT index, MXSINT red, MXSINT green, MXSINT blue );
+void    MXAPI mxGetPalette( MXPTR palette, MXUINT index, MXUINT count );
+void    MXAPI mxSetPalette( MXPTR palette, MXUINT index, MXUINT count );
+void    MXAPI mxFadePalette( MXPTR, MXUINT, MXUINT, MXUINT, MXUINT, MXUINT, MXUINT );
+void    MXAPI mxRotatePalette( MXPTR palette, MXUINT count, MXSINT step );
+//
+// Text
+//
+MXSINT  MXAPI mxSetFont( MXPTR font, MXUINT charwidth, MXUINT charheight );
+void    MXAPI mxSetTextColor( MXUINT color, MXUINT op );
+void    MXAPI mxGetTextStep( MXSINT far *deltax, MXSINT far *deltay );
+void    MXAPI mxSetTextStep( MXSINT deltax, MXSINT deltay );
+void    MXAPI mxOutChar( MXSINT x, MXSINT y, char c );
+void    MXAPI mxOutText( MXSINT x, MXSINT y, char far *sz );
+//
+// Convex polygons
+//
+void    MXAPI mxFillPoly( MXUINT, MXPTR, MXPTR, MXUINT, MXUINT );
+void    MXAPI mxGouraudPoly( MXUINT, MXPTR, MXPTR, MXPTR, MXUINT, MXUINT );
+void    MXAPI mxTexturePoly( MXUINT, MXPTR, MXPTR, MXPTR, MXPTR, MXUINT, MXUINT );
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+// Remove temporary defines
+//
+#undef  MXBYTE
+#undef  MXBOOL
+#undef  MXSINT
+#undef  MXUINT
+#undef  MXPTR
+#undef  MXAPI
+
+#endif  // _MODEX_H_
diff --git a/16/x/MODEX.LBR b/16/x/MODEX.LBR
new file mode 100755
index 00000000..93fc7801
--- /dev/null
+++ b/16/x/MODEX.LBR
@@ -0,0 +1,39 @@
++-MXBB.OBJ &
++-MXCC.OBJ &
++-MXCG.OBJ &
++-MXCL.OBJ &
++-MXCR.OBJ &
++-MXFB.OBJ &
++-MXFP.OBJ &
++-MXGC.OBJ &
++-MXGI.OBJ &
++-MXGM.OBJ &
++-MXGP.OBJ &
++-MXGV.OBJ &
++-MXHL.OBJ &
++-MXIT.OBJ &
++-MXLL.OBJ &
++-MXLN.OBJ &
++-MXOT.OBJ &
++-MXPB.OBJ &
++-MXPF.OBJ &
++-MXPG.OBJ &
++-MXPI.OBJ &
++-MXPN.OBJ &
++-MXPP.OBJ &
++-MXPT.OBJ &
++-MXRA.OBJ &
++-MXRP.OBJ &
++-MXSA.OBJ &
++-MXSC.OBJ &
++-MXSI.OBJ &
++-MXSL.OBJ &
++-MXSM.OBJ &
++-MXSP.OBJ &
++-MXSS.OBJ &
++-MXTL.OBJ &
++-MXVS.OBJ &
++-MXWD.OBJ &
++-MXWM.OBJ &
++-MXWP.OBJ &
++-MXWR.OBJ
diff --git a/16/x/MODEX.PAS b/16/x/MODEX.PAS
new file mode 100755
index 00000000..7d9d26ed
--- /dev/null
+++ b/16/x/MODEX.PAS
@@ -0,0 +1,194 @@
+(*
+   Turbo Pascal interface to the MODEX library
+   Copyright (c) 1993,1994 by Alessandro Scotti
+*)
+unit ModeX;
+interface
+
+const
+  (* Video modes *)
+  MX_TEXT       = 0;
+  MX_320x175    = 1;
+  MX_320x200    = 2;
+  MX_320x240    = 3;
+  MX_320x350    = 4;
+  MX_320x400    = 5;
+  MX_320x480    = 6;
+  MX_360x175    = 7;
+  MX_360x200    = 8;
+  MX_360x240    = 9;
+  MX_360x350    = 10;
+  MX_360x400    = 11;
+  MX_360x480    = 12;
+  MX_400x600    = 13;
+
+  (* Fade effects *)
+  MX_FADEIN     = 0;
+  MX_FADEOUT    = 1;
+
+  (* Raster ops *)
+  OP_SET        = 0;
+  OP_AND        = 1;
+  OP_OR         = 2;
+  OP_XOR        = 3;
+  OP_TRANS      = 4;
+  OP_ADD        = 5;
+  OP_MOVE       = 0;                    (* Alias for OP_SET *)
+
+procedure mxBitBlt( SX, SY: integer; Width, Height: word; DX, DY: integer );
+procedure mxCircle( CX, CY: integer; Radius: word; Color: byte );
+procedure mxChangeMode( Mode: word );
+procedure mxColorToGray( ColorPalette, GrayPalette: pointer; Count: word );
+procedure mxFadePalette( Palette: pointer; Cmd, Start, Count, R, G, B: word );
+procedure mxFillBox( X, Y: integer; Width, Height: word; Color: byte; Op: word );
+procedure mxGammaCorrect( ColorPalette, GammaPalette: pointer; Count: word );
+procedure mxGetAspect( var AspectX, AspectY: word );
+function  mxGetClipRegion( var X1, Y1, Width, Height: word ): boolean;
+function  mxGetClip: boolean;
+procedure mxGetImage( Image: pointer; X, Y: integer; Width, Height: word );
+procedure mxGetPalette( Palette: pointer; Start, Count: word );
+function  mxGetPixel( X, Y: word ): byte;
+procedure mxGetScreenSize( var Width, Height: word );
+procedure mxGetTextStep( var DeltaX, DeltaY: integer );
+function  mxGetVersion: word;
+procedure mxGetVirtualScreen( var Width, Height: word );
+procedure mxInit;
+procedure mxLine( X1, Y1, X2, Y2: integer; Color, Op: word );
+procedure mxOutChar( X, Y: integer; C: char );
+procedure mxOutText( X, Y: integer; S: pointer );
+procedure mxPan( X, Y: word );
+procedure mxPutImage( Image: pointer; X, Y: integer; Width, Height, Op: word );
+procedure mxPutPixel( X, Y: word; C: byte );
+procedure mxPutTile( Tile: pointer; X, Y: integer; Width, Height: word );
+procedure mxReadPlane( Plane: byte );
+procedure mxRotatePalette( Palette: pointer; Count: word; Step: integer );
+procedure mxRowAddress( RowAddress: byte );
+function  mxSetClip( Clip: boolean ): boolean;
+procedure mxSetClipRegion( X1, Y1, Width, Height: word );
+procedure mxSetColor( Index, R, G, B: word );
+procedure mxSetFont( Font: pointer; Width, Height: word );
+procedure mxSetMode( Mode: word );
+procedure mxSetPalette( Palette: pointer; Start, Count: word );
+procedure mxSetTextColor( Color, Op: word );
+procedure mxSetTextStep( DeltaX, DeltaY: integer );
+procedure mxSetVirtualScreen( Width, Height: word );
+procedure mxStretchImage( Image: pointer; X, Y: integer; Width, Height, NewWidth, NewHeight, Op: word );
+procedure mxSplitScreen( Line: word );
+procedure mxStartAddress( StartAddress: word );
+procedure mxStartLine( Line: word );
+procedure mxTerm;
+procedure mxTransPutTile( Tile: pointer; X, Y: integer; Width, Height: word );
+procedure mxWaitDisplay;
+procedure mxWaitRetrace;
+procedure mxWriteMode( Mode: byte );
+procedure mxWritePlane( Plane: byte );
+
+procedure mxFillPoly( Count: word; var Map, Points; Color: word );
+procedure mxGouraudPoly( Count: word; var Map, Points, Colors; BaseColor: word );
+procedure mxTexturePoly( Count: word; var Map, Points, ImgPoints, Texture; Width: word );
+
+procedure mxOutStr( X, Y: integer; S: string );
+
+implementation
+
+procedure mxBitBlt;                                             external;
+procedure mxChangeMode( Mode: word );                           external;
+procedure mxCircle;                                             external;
+procedure mxColorToGray;                                        external;
+procedure mxFadePalette;                                        external;
+procedure mxFillBox;                                            external;
+procedure mxGammaCorrect;                                       external;
+procedure mxGetAspect( var AspectX, AspectY: word );            external;
+function  mxGetClipRegion;                                      external;
+function  mxGetClip: boolean;                                   external;
+procedure mxGetImage;                                           external;
+procedure mxGetPalette( Palette: pointer; Start, Count: word ); external;
+function  mxGetPixel( X, Y: word ): byte;                       external;
+procedure mxGetScreenSize( var Width, Height: word );           external;
+procedure mxGetTextStep( var DeltaX, DeltaY: integer );         external;
+function  mxGetVersion: word;                                   external;
+procedure mxGetVirtualScreen( var Width, Height: word );        external;
+procedure mxInit;                                               external;
+procedure mxLine( X1, Y1, X2, Y2: integer; Color, Op: word );   external;
+procedure mxOutChar( X, Y: integer; C: char );                  external;
+procedure mxOutText( X, Y: integer; S: pointer );               external;
+procedure mxPan( X, Y: word );                                  external;
+procedure mxPutImage;                                           external;
+procedure mxPutPixel( X, Y: word; C: byte );                    external;
+procedure mxPutTile;                                            external;
+procedure mxReadPlane( Plane: byte );                           external;
+procedure mxRotatePalette;                                      external;
+procedure mxRowAddress( RowAddress: byte );                     external;
+function  mxSetClip( Clip: boolean ): boolean;                  external;
+procedure mxSetClipRegion( X1, Y1, Width, Height: word );       external;
+procedure mxSetColor( Index, R, G, B: word );                   external;
+procedure mxSetFont( Font: pointer; Width, Height: word );      external;
+procedure mxSetMode( Mode: word );                              external;
+procedure mxSetPalette( Palette: pointer; Start, Count: word ); external;
+procedure mxSetTextColor( Color, Op: word );                    external;
+procedure mxSetTextStep( DeltaX, DeltaY: integer );             external;
+procedure mxSetVirtualScreen( Width, Height: word );            external;
+procedure mxSplitScreen( Line: word );                          external;
+procedure mxStartAddress( StartAddress: word );                 external;
+procedure mxStartLine;                                          external;
+procedure mxStretchImage;                                       external;
+procedure mxTerm;                                               external;
+procedure mxTransPutTile;                                       external;
+procedure mxWaitDisplay;                                        external;
+procedure mxWaitRetrace;                                        external;
+procedure mxWriteMode( Mode: byte );                            external;
+procedure mxWritePlane( Plane: byte );                          external;
+
+procedure mxFillPoly;                                           external;
+procedure mxGouraudPoly;                                        external;
+procedure mxTexturePoly;                                        external;
+{$L MXPB}
+{$L MXPF}
+{$L MXPG}
+{$L MXPT}
+
+{$L MXBB}
+{$L MXCC}
+{$L MXCG}
+{$L MXCL}
+{$L MXCR}
+{$L MXFB}
+{$L MXFP}
+{$L MXGI}
+{$L MXGM}
+{$L MXGP}
+{$L MXGV}
+{$L MXHL}
+{$L MXIT}
+{$L MXLN}
+{$L MXOT}
+{$L MXPI}
+{$L MXPN}
+{$L MXPP}
+{$L MXRA}
+{$L MXRP}
+{$L MXSA}
+{$L MXSC}
+{$L MXSI}
+{$L MXSL}
+{$L MXSM}
+{$L MXSP}
+{$L MXSS}
+{$L MXTL}
+{$L MXVS}
+{$L MXWD}
+{$L MXWM}
+{$L MXWP}
+{$L MXWR}
+
+(*
+   Prints a Turbo Pascal string.
+   Note: BP 7.0 supports ASCIIZ strings (PChar type).
+*)
+procedure mxOutStr;
+begin
+  S := S + #0;
+  mxOutText( X, Y, @S[1] );
+end;
+
+end.
diff --git a/16/x/MXBB.ASM b/16/x/MXBB.ASM
new file mode 100755
index 00000000..ac6668ce
--- /dev/null
+++ b/16/x/MXBB.ASM
@@ -0,0 +1,278 @@
+;-----------------------------------------------------------
+;
+; MXBB.ASM - Bit block transfer
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxBitBlt
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   subHorizontalLineInfo   : NEAR
+
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_BytesPerLine : WORD
+
+;-----------------------------------------------------------
+;
+; Moves a block of video memory.
+;
+; Input:
+;       SX, SY  = source coordinates
+;       Width   = source width
+;       Height  = source height
+;       DX, DY  = destination coordinates
+; Output:
+;       none
+;
+; Note: overlapping regions are not allowed.
+;
+mxBitBlt        PROC    FAR
+        ARG     DestY:WORD,             \
+                DestX:WORD,             \
+                Height:WORD,            \
+                Width:WORD,             \
+                SY:WORD,                \
+                SX:WORD                 = ARG_SIZE
+        LOCAL   PlaneWidth:WORD:4,      \
+                SourceOffset:WORD,      \
+                DestOffset:WORD,        \
+                Count:BYTE,             \
+                ReadPlane:BYTE,         \
+                WritePlane:BYTE,        \
+                LeftMask:BYTE,          \
+                RightMask:BYTE          = AUTO_SIZE
+        .enter  AUTO_SIZE
+        .push   ds, si, es, di
+
+; Exit now if null width
+        cmp     [Width], 0
+        je      @@Exit
+
+; Calls the proper procedure to handle transfer
+        mov     ax, [SX]
+        and     al, 03h                 ; AL = source plane
+        mov     dx, [DestX]
+        and     dl, 03h                 ; DL = destination plane
+        mov     bx, OFFSET subPlaneBlt
+        cmp     al, dl                  ; Same source and destination plane?
+        jne     @@BitBlt                ; No, use slow procedure
+        mov     bx, OFFSET subMoveBlt
+@@BitBlt:
+        call    bx
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+
+;-----------------------------------------------------------
+; Uses write mode 1 for maximum speed. Only works if source
+; and destination are plane-aligned.
+;
+subMoveBlt      PROC    NEAR
+; Get horizontal line info and address of destination
+        mov     bx, [DestX]
+        mov     ax, [DestY]
+        mov     cx, [Width]
+        call    subHorizontalLineInfo
+        mov     [LeftMask], al
+        mov     [RightMask], ah
+        mov     [Width], cx
+
+; Setup segments
+        mov     ax, [mx_VideoSegment]
+        mov     ds, ax
+        mov     es, ax
+
+; Get address of source pixel
+        mov     ax, [SY]
+        mul     [mx_BytesPerLine]
+        mov     si, [SX]
+        .shr    si, 2
+        add     si, ax
+
+; Set write mode 1
+        mov     dx, GDC
+        mov     ax, 4105h
+        out     dx, ax
+        cld
+
+; Move left block
+@@L0:
+        mov     ah, [LeftMask]
+        or      ah, ah
+        jz      @@C0
+        mov     dx, TS
+        mov     al, 02h
+        out     dx, ax                  ; Set write plane mask
+        mov     ax, [mx_BytesPerLine]
+        dec     ax
+        mov     cx, [Height]
+        .push   si, di
+@@L1:
+        movsb
+        add     si, ax
+        add     di, ax
+        dec     cx
+        jnz     @@L1
+        .pop    si, di
+        inc     si
+        inc     di
+
+; Move center block
+@@C0:
+        mov     bx, [Width]
+        test    bx, bx
+        jz      @@R0
+        mov     dx, TS
+        mov     ax, 0F02h
+        out     dx, ax                  ; Enable all planes
+        mov     ax, [mx_BytesPerLine]
+        sub     ax, bx
+        mov     dx, [Height]
+        .push   si, di
+@@C1:
+        mov     cx, bx                  ; CX = image width
+        rep     movsb                   ; Cannot use "movsw" here!
+        add     si, ax                  ; Next scan line
+        add     di, ax                  ; Next scan line
+        dec     dx                      ; All lines processed?
+        jnz     @@C1                    ; No, continue
+        .pop    si, di
+        add     si, bx
+        add     di, bx
+
+; Move right block
+@@R0:
+        mov     ah, [RightMask]
+        or      ah, ah
+        jz      @@Done
+        mov     dx, TS
+        mov     al, 02h
+        out     dx, ax                  ; Set write plane mask
+        mov     ax, [mx_BytesPerLine]
+        dec     ax
+        mov     cx, [Height]
+@@R1:
+        movsb
+        add     si, ax
+        add     di, ax
+        dec     cx
+        jnz     @@R1
+
+@@Done:
+        mov     dx, GDC
+        mov     ax, 4005h
+        out     dx, ax                  ; Restore write mode 0
+
+@@Exit:
+        ret
+subMoveBlt      ENDP
+
+;-----------------------------------------------------------
+; Moves one plane at a time.
+;
+subPlaneBlt     PROC    NEAR
+; Compute extra bytes and width count for each plane
+        mov     cx, [Width]
+        mov     bx, cx
+        shr     bx, 1
+        shr     bx, 1                   ; Width for each plane
+        and     cl, 03h
+        mov     al, 00001000b
+        shr     al, cl
+        mov     si, 3 SHL 1
+@@PatchLoop:
+        mov     PlaneWidth[si], bx
+        shr     al, 1
+        adc     bx, 0
+        dec     si
+        dec     si
+        jge     @@PatchLoop
+
+; Get pixel addresses
+        mov     ax, [mx_VideoSegment]
+        mov     ds, ax
+        mov     es, ax
+        mov     ax, [SY]
+        mul     [mx_BytesPerLine]
+        mov     si, [SX]
+        shr     si, 1
+        shr     si, 1
+        add     si, ax                  ; DS:SI points to source
+        mov     [SourceOffset], si
+        mov     ax, [DestY]
+        mul     [mx_BytesPerLine]
+        mov     di, [DestX]
+        shr     di, 1
+        shr     di, 1
+        add     di, ax                  ; ES:DI points to destination
+        mov     [DestOffset], di
+
+; Adjust plane for output to VGA registers
+        mov     ax, [SX]
+        and     al, 03h
+        mov     [ReadPlane], al
+        mov     cx, [DestX]
+        and     cl, 03h
+        mov     al, 00010001b
+        shl     al, cl
+        mov     [WritePlane], al
+
+; Ready to move now
+        cld
+        mov     [Count], 4              ; Four planes
+        lea     bx, PlaneWidth          ; SS:[BX] = width in bytes for plane
+@@PlaneLoop:
+        cmp     WORD PTR ss:[bx], 0
+        je      @@Done
+        mov     ah, [WritePlane]
+        and     ah, 0Fh
+        mov     al, 02h
+        mov     dx, TS
+        out     dx, ax                  ; Select write plane
+        mov     ah, [ReadPlane]
+        mov     al, 04h
+        mov     dx, GDC
+        out     dx, ax                  ; Select read plane
+        mov     dx, [Height]
+        mov     ax, [mx_BytesPerLine]
+        sub     ax, ss:[bx]             ; AX = extra bytes per line
+@@Loop:
+        mov     cx, ss:[bx]
+        shr     cx, 1
+        rep     movsw
+        rcl     cx, 1
+        rep     movsb
+        add     si, ax
+        add     di, ax
+        dec     dx
+        jnz     @@Loop                  ; Repeat for all lines
+        inc     bx
+        inc     bx                      ; Select width for next plane
+        inc     [ReadPlane]
+        and     [ReadPlane], 03h        ; Should be faster on 386 using
+        jnz     @@ReadPlaneOk           ; BTR and ADC...
+        inc     [SourceOffset]
+@@ReadPlaneOk:
+        rol     [WritePlane], 1
+        adc     [DestOffset], 0
+        mov     si, [SourceOffset]
+        mov     di, [DestOffset]
+        dec     [Count]
+        jnz     @@PlaneLoop             ; Repeat for all planes
+
+@@Done:
+        ret
+subPlaneBlt     ENDP
+
+mxBitBlt        ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXCC.ASM b/16/x/MXCC.ASM
new file mode 100755
index 00000000..4f78adb9
--- /dev/null
+++ b/16/x/MXCC.ASM
@@ -0,0 +1,644 @@
+;-----------------------------------------------------------
+;
+; MXCC.ASM - Fast clip line function
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  xsubClipLine
+
+MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'
+        ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_BytesPerLine : WORD
+EXTRN   mx_VideoSegment : WORD
+
+EXTRN   mx_ClipX1       : WORD
+EXTRN   mx_ClipY1       : WORD
+EXTRN   mx_ClipX2       : WORD
+EXTRN   mx_ClipY2       : WORD
+
+tblGroups       LABEL WORD
+        DW      10,     tbl00
+        DW      10,     tbl10
+        DW      9,      tbl20
+        DW      -1,     0
+        DW      10,     tbl40
+        DW      10,     tbl50
+        DW      9,      tbl60
+        DW      -1,     0
+        DW      6,      tbl80
+        DW      6,      tbl90
+        DW      5,      tblA0
+        DW      -1,     0
+        DW      -1,     0
+        DW      -1,     0
+        DW      -1,     0
+        DW      -1,     0
+tbl00   DW cc00, cc01, cc02, ccFF, cc04, cc05, cc06, ccFF, cc08, cc09, cc0A
+tbl10   DW cc10, ccFF, cc12, ccFF, cc14, ccFF, cc16, ccFF, cc18, ccFF, cc1A
+tbl20   DW cc20, cc21, ccFF, ccFF, cc24, cc25, ccFF, ccFF, cc28, cc29
+tbl40   DW cc40, cc41, cc42, ccFF, ccFF, ccFF, ccFF, ccFF, cc48, cc49, cc4A
+tbl50   DW cc50, ccFF, cc52, ccFF, ccFF, ccFF, ccFF, ccFF, cc58, ccFF, cc5A
+tbl60   DW cc60, cc61, ccFF, ccFF, ccFF, ccFF, ccFF, ccFF, cc68, cc69
+tbl80   DW cc80, cc81, cc82, ccFF, cc84, cc85, cc86
+tbl90   DW cc90, ccFF, cc92, ccFF, cc94, ccFF, cc96
+tblA0   DW ccA0, ccA1, ccFF, ccFF, ccA4, ccA5
+
+ccTT:   clc
+        ret
+ccFF:   stc
+        ret
+
+; Group 00 -------------------------------------------------
+;
+cc00:
+        clc
+        ret
+cc01:
+        jmp     ClipQLeft
+cc02:
+        jmp     ClipQRight
+cc04:
+        jmp     ClipQTop
+cc05:
+        call    ClipQLeft
+        cmp     si, [mx_ClipY1]
+        jge     ccTT
+        jmp     ClipQTop
+cc06:
+        call    ClipQRight
+        cmp     si, [mx_ClipY1]
+        jge     ccTT
+        jmp     ClipQTop
+cc08:
+        jmp     ClipQBottom
+cc09:
+        call    ClipQLeft
+        cmp     si, [mx_ClipY2]
+        jle     ccTT
+        jmp     ClipQBottom
+cc0A:
+        call    ClipQRight
+        cmp     si, [mx_ClipY2]
+        jle     ccTT
+        jmp     ClipQBottom
+
+; Group 10 -------------------------------------------------
+;
+cc10FF:
+        stc
+        ret
+cc10TT:
+        clc
+        ret
+cc10:
+        jmp     ClipPLeft
+cc12:
+        call    ClipPLeft
+        jmp     ClipQRight
+cc14:
+        call    ClipPLeft
+        cmp     bx, [mx_ClipY1]
+        jl      cc10FF
+        jmp     ClipQTop
+cc16:
+        call    ClipPLeft
+        cmp     bx, [mx_ClipY1]
+        jl      cc10FF
+        call    ClipQTop
+        cmp     cx, [mx_ClipX2]
+        jle     cc10TT
+        jmp     ClipQRight
+cc18:
+        call    ClipPLeft
+        cmp     bx, [mx_ClipY2]
+        jg      cc10FF
+        jmp     ClipQBottom
+cc1A:
+        call    ClipPLeft
+        cmp     bx, [mx_ClipY2]
+        jg      cc10FF
+        call    ClipQBottom
+        cmp     cx, [mx_ClipX2]
+        jle     cc10TT
+        jmp     ClipQRight
+
+; Group 20 -------------------------------------------------
+;
+cc20TT:
+        clc
+        ret
+cc20FF:
+        stc
+        ret
+cc20:
+        jmp     ClipPRight
+cc21:
+        call    ClipPRight
+        jmp     ClipQLeft
+cc24:
+        call    ClipPRight
+        cmp     bx, [mx_ClipY1]
+        jl      cc20FF
+        jmp     ClipQTop
+cc25:
+        call    ClipPRight
+        cmp     bx, [mx_ClipY1]
+        jl      cc20FF
+        call    ClipQTop
+        cmp     cx, [mx_ClipX1]
+        jge     cc20TT
+        jmp     ClipQLeft
+cc28:
+        call    ClipPRight
+        cmp     bx, [mx_ClipY2]
+        jg      cc20FF
+        jmp     ClipQBottom
+cc29:
+        call    ClipPRight
+        cmp     bx, [mx_ClipY2]
+        jg      cc20FF
+        call    ClipQBottom
+        cmp     cx, [mx_ClipX1]
+        jge     cc20TT
+        jmp     ClipQLeft
+
+; Group 40 -------------------------------------------------
+;
+cc40TT:
+        clc
+        ret
+cc40FF:
+        stc
+        ret
+cc40:
+        jmp     ClipPTop
+cc41:
+        call    ClipPTop
+        cmp     di, [mx_ClipX1]
+        jl      cc40FF
+        call    ClipQLeft
+        cmp     si, [mx_ClipY1]
+        jge     cc40TT
+        jmp     ClipQTop
+cc42:
+        call    ClipPTop
+        cmp     di, [mx_ClipX2]
+        jg      cc40FF
+        jmp     ClipQRight
+cc48:
+        call    ClipPTop
+        jmp     ClipQBottom
+cc49:
+        call    ClipPTop
+        cmp     di, [mx_ClipX1]
+        jl      cc40FF
+        call    ClipQLeft
+        cmp     si, [mx_ClipY2]
+        jle     cc40TT
+        jmp     ClipQBottom
+cc4A:
+        call    ClipPTop
+        cmp     di, [mx_ClipX2]
+        jg      cc40FF
+        call    ClipQRight
+        cmp     si, [mx_ClipY2]
+        jle     cc40TT
+        jmp     ClipQBottom
+
+
+; Group 50 -------------------------------------------------
+;
+cc50TT:
+        clc
+        ret
+cc50FF:
+        stc
+        ret
+cc50:
+        call    ClipPLeft
+        cmp     bx, [mx_ClipY1]
+        jge     cc50TT
+        jmp     ClipPTop
+cc52:
+        call    ClipQRight
+        cmp     si, [mx_ClipY1]
+        jl      cc50FF
+        call    ClipPTop
+        cmp     di, [mx_ClipX1]
+        jge     cc50TT
+        jmp     ClipPLeft
+cc58:
+        call    ClipQBottom
+        cmp     cx, [mx_ClipX1]
+        jl      cc50FF
+        call    ClipPTop
+        cmp     di, [mx_ClipX1]
+        jge     cc50TT
+        jmp     ClipPLeft
+cc5A:
+        call    ClipPLeft
+        cmp     bx, [mx_ClipY2]
+        jg      cc50FF
+        call    ClipQRight
+        cmp     bx, [mx_ClipY1]
+        jl      cc50FF
+        cmp     si, [mx_ClipY2]
+        jle     cc50TT
+        jmp     ClipQBottom
+
+; Group 60 -------------------------------------------------
+;
+cc60TT:
+        clc
+        ret
+cc60FF:
+        stc
+        ret
+cc60:
+        call    ClipPRight
+        cmp     bx, [mx_ClipY1]
+        jge     cc60TT
+        jmp     ClipPTop
+cc61:
+        call    ClipQLeft
+        cmp     si, [mx_ClipY2]
+        jl      cc60FF
+        call    ClipPTop
+        cmp     di, [mx_ClipX2]
+        jle     cc60TT
+        jmp     ClipPRight
+cc68:
+        call    ClipQBottom
+        cmp     cx, [mx_ClipX2]
+        jg      cc60FF
+        call    ClipPRight
+        cmp     bx, [mx_ClipY1]
+        jge     cc60TT
+        jmp     ClipPTop
+cc69:
+        call    ClipQLeft
+        cmp     si, [mx_ClipY1]
+        jl      cc60FF
+        call    ClipPRight
+        cmp     bx, [mx_ClipY2]
+        jg      cc60FF
+        cmp     si, [mx_ClipY2]
+        jle     cc69_1
+        call    ClipQBottom
+cc69_1:
+        cmp     bx, [mx_ClipY1]
+        jge     cc60TT
+        jmp     ClipPTop
+
+; Group 80 -------------------------------------------------
+;
+cc80TT:
+        clc
+        ret
+cc80FF:
+        stc
+        ret
+cc80:
+        jmp     ClipPBottom
+cc81:
+        call    ClipPBottom
+        cmp     di, [mx_ClipX1]
+        jl      cc80FF
+        jmp     ClipQLeft
+cc82:
+        call    ClipPBottom
+        cmp     di, [mx_ClipX2]
+        jg      cc80FF
+        jmp     ClipQRight
+cc84:
+        call    ClipPBottom
+        jmp     ClipQTop
+cc85:
+        call    ClipPBottom
+        cmp     di, [mx_ClipX1]
+        jl      cc80FF
+        call    ClipQLeft
+        cmp     si, [mx_ClipY1]
+        jge     cc80FF
+        jmp     ClipQTop
+cc86:
+        call    ClipPBottom
+        cmp     di, [mx_ClipX2]
+        jg      cc80FF
+        call    ClipQRight
+        cmp     si, [mx_ClipY1]
+        jge     cc80TT
+        jmp     ClipQTop
+
+; Group 90 -------------------------------------------------
+;
+cc90TT:
+        clc
+        ret
+cc90FF:
+        stc
+        ret
+cc90:
+        call    ClipPLeft
+        cmp     bx, [mx_ClipY2]
+        jle     cc90TT
+        jmp     ClipPBottom
+cc92:
+        call    ClipQRight
+        cmp     si, [mx_ClipY2]
+        jg      cc90FF
+        call    ClipPBottom
+        cmp     di, [mx_ClipX1]
+        jge     cc90TT
+        jmp     ClipPLeft
+cc94:
+        call    ClipQTop
+        cmp     cx, [mx_ClipX1]
+        jl      cc90FF
+        call    ClipPLeft
+        cmp     bx, [mx_ClipY2]
+        jle     cc90TT
+        jmp     ClipPBottom
+cc96:
+        call    ClipPLeft
+        cmp     bx, [mx_ClipY1]
+        jl      cc90FF
+        call    ClipQRight
+        cmp     si, [mx_ClipY2]
+        jg      cc90FF
+        cmp     bx, [mx_ClipY2]
+        jle     cc96_1
+        call    ClipPBottom
+cc96_1:
+        cmp     si, [mx_ClipY1]
+        jge     cc90TT
+        jmp     ClipQTop
+
+; Group A0 -------------------------------------------------
+;
+ccA0TT:
+        clc
+        ret
+ccA0FF:
+        stc
+        ret
+ccA0:
+        call    ClipPRight
+        cmp     bx, [mx_ClipY2]
+        jle     ccA0TT
+        jmp     ClipPBottom
+ccA1:
+        call    ClipQLeft
+        cmp     si, [mx_ClipY2]
+        jg      ccA0FF
+        call    ClipPBottom
+        cmp     di, [mx_ClipX2]
+        jle     ccA0TT
+        jmp     ClipPRight
+ccA4:
+        call    ClipQTop
+        cmp     cx, [mx_ClipX2]
+        jg      ccA0FF
+        call    ClipPRight
+        cmp     bx, [mx_ClipY2]
+        jle     ccA0TT
+        jmp     ClipPBottom
+ccA5:
+        call    ClipQLeft
+        cmp     si, [mx_ClipY2]
+        jg      ccA0FF
+        call    ClipPRight
+        cmp     bx, [mx_ClipY1]
+        jl      ccA0FF
+        cmp     si, [mx_ClipY1]
+        jge     ccA5_1
+        call    ClipQTop
+ccA5_1:
+        cmp     bx, [mx_ClipY2]
+        jle     ccA0TT
+        jmp     ClipPBottom
+
+; Y1 = (Y2-Y1)*(mx_ClipX1-X1)/(X2-X1)+Y1 = (SI-BX)*(mx_ClipX1-DI)/(CX-DI)+BX
+; X1 = mx_ClipX1
+ClipPLeft:
+        mov     ax, si
+        sub     ax, bx
+        mov     dx, [mx_ClipX1]
+        sub     dx, di
+        imul    dx
+        mov     bp, cx
+        sub     bp, di
+        idiv    bp
+        add     bx, ax
+        mov     di, [mx_ClipX1]
+        clc
+        ret
+
+; Y1 = (Y2-Y1)*(mx_ClipX2-X1)/(X2-X1)+Y1 = (SI-BX)*(mx_ClipX2-DI)/(CX-DI)+BX
+; X1 = mx_ClipX2
+ClipPRight:
+        mov     ax, si
+        sub     ax, bx
+        mov     dx, [mx_ClipX2]
+        sub     dx, di
+        imul    dx
+        mov     bp, cx
+        sub     bp, di
+        idiv    bp
+        add     bx, ax
+        mov     di, [mx_ClipX2]
+        clc
+        ret
+
+; X1 = (X2-X1)*(mx_ClipY2-Y1)/(Y2-Y1)+X1 = (CX-DI)*(mx_ClipY2-BX)/(SI-BX)+DI
+; Y1 = mx_ClipY2
+ClipPBottom:
+        mov     ax, cx
+        sub     ax, di
+        mov     dx, [mx_ClipY2]
+        sub     dx, bx
+        imul    dx
+        mov     bp, si
+        sub     bp, bx
+        idiv    bp
+        add     di, ax
+        mov     bx, [mx_ClipY2]
+        clc
+        ret
+
+; X1 = (X2-X1)*(mx_ClipY1-Y1)/(Y2-Y1)+X1 = (CX-DI)*(mx_ClipY1-BX)/(SI-BX)+DI
+; Y1 = mx_ClipY1
+ClipPTop:
+        mov     ax, cx
+        sub     ax, di
+        mov     dx, [mx_ClipY1]
+        sub     dx, bx
+        imul    dx
+        mov     bp, si
+        sub     bp, bx
+        idiv    bp
+        add     di, ax
+        mov     bx, [mx_ClipY1]
+        clc
+        ret
+
+; Y2 = (Y1-Y2)*(mx_ClipX1-X2)/(X1-X2)+Y2 = (BX-SI)*(mx_ClipX1-CX)/(DI-CX)+SI
+; X2 = mx_ClipX1
+ClipQLeft:
+        mov     ax, bx
+        sub     ax, si
+        mov     dx, [mx_ClipX1]
+        sub     dx, cx
+        imul    dx
+        mov     bp, di
+        sub     bp, cx
+        idiv    bp
+        add     si, ax
+        mov     cx, [mx_ClipX1]
+        clc
+        ret
+
+; Y2 = (Y1-Y2)*(mx_ClipX2-X2)/(X1-X2)+Y2 = (BX-SI)*(mx_ClipX2-CX)/(DI-CX)+SI
+; X2 = mx_ClipX1
+ClipQRight:
+        mov     ax, bx
+        sub     ax, si
+        mov     dx, [mx_ClipX2]
+        sub     dx, cx
+        imul    dx
+        mov     bp, di
+        sub     bp, cx
+        idiv    bp
+        add     si, ax
+        mov     cx, [mx_ClipX2]
+        clc
+        ret
+
+; X2 = (X1-X2)*(mx_ClipY2-Y2)/(Y1-Y2)+X2 = (DI-CX)*(mx_ClipY2-SI)/(BX-SI)+CX
+; Y2 = mx_ClipY1
+ClipQBottom:
+        mov     ax, di
+        sub     ax, cx
+        mov     dx, [mx_ClipY2]
+        sub     dx, si
+        imul    dx
+        mov     bp, bx
+        sub     bp, si
+        idiv    bp
+        add     cx, ax
+        mov     si, [mx_ClipY2]
+        clc
+        ret
+
+; X2 = (X1-X2)*(mx_ClipY1-Y2)/(Y1-Y2)+X2 = (DI-CX)*(mx_ClipY1-SI)/(BX-SI)+CX
+; Y2 = mx_ClipY1
+ClipQTop:
+        mov     ax, di
+        sub     ax, cx
+        mov     dx, [mx_ClipY1]
+        sub     dx, si
+        imul    dx
+        mov     bp, bx
+        sub     bp, si
+        idiv    bp
+        add     cx, ax
+        mov     si, [mx_ClipY1]
+        clc
+        ret
+
+;-----------------------------------------------------------
+;
+; Checks the coordinates of a line against the active
+; clip region.
+; Uses the Sobkow-Pospisil-Yang (SPY) algorithm: this was
+; supposed to be twice as fast as Cohen-Sutherland, but my
+; tests show only a very small increase in speed and a noticeable
+; increase of the program size! Maybe this is caused by the
+; slow speed of VGA cards, so probably a better test should
+; be performed with lines drawn in RAM.
+;
+; Input:
+;       AX, BX  = X1, Y1
+;       CX, DX  = X2, Y2
+; Output:
+;       CF      = set if line is full clipped
+;       AX, BX  = clipped X1, Y1
+;       CX, DX  = clipped X2, Y2
+; Note:
+;       destroys SI, DI
+;
+xsubClipLine     PROC    NEAR
+        push    bp
+        xor     si, si                  ; SPY code
+
+        cmp     dx, [mx_ClipY2]
+        jle     @@1
+        or      si, 08h
+        jmp     @@2
+@@1:
+        cmp     dx, [mx_ClipY1]
+        jge     @@2
+        or      si, 04h
+@@2:
+
+        cmp     cx, [mx_ClipX2]
+        jle     @@3
+        or      si, 02h
+        jmp     @@4
+@@3:
+        cmp     cx, [mx_ClipX1]
+        jge     @@4
+        or      si, 01h
+@@4:
+
+        cmp     bx, [mx_ClipY2]
+        jle     @@5
+        or      si, 80h
+        jmp     @@6
+@@5:
+        cmp     bx, [mx_ClipY1]
+        jge     @@6
+        or      si, 40h
+@@6:
+
+        cmp     ax, [mx_ClipX2]
+        jle     @@7
+        or      si, 20h
+        jmp     @@8
+@@7:
+        cmp     ax, [mx_ClipX1]
+        jge     @@8
+        or      si, 10h
+@@8:
+
+        mov     di, si
+        and     di, 000Fh               ; Index of procedure
+        and     si, 00F0h
+        .shr    si, 2                   ; Index of group (times 4)
+        cmp     di, cs:tblGroups[si]    ; Is index within range?
+        jg      @@Exit                  ; No, line is full clipped
+        mov     si, cs:tblGroups[si+2]  ; Get offset of group table
+        shl     di, 1                   ; We must index word elements
+        add     si, di                  ; Make full offset
+        mov     di, ax                  ; Move X1 to DI and free AX
+        mov     si, cs:[si]             ; Get subroutine address
+        xchg    dx, si                  ; Move Y2 to SI and free DX
+        call    dx                      ; Call the proper subroutine
+        mov     ax, di                  ; Restore AX to X1
+        mov     dx, si                  ; Restore DX to Y2
+        pop     bp
+        ret
+
+@@Exit:
+        pop     bp
+        stc
+        ret
+xsubClipLine     ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXCG.ASM b/16/x/MXCG.ASM
new file mode 100755
index 00000000..42163d7a
--- /dev/null
+++ b/16/x/MXCG.ASM
@@ -0,0 +1,69 @@
+;-----------------------------------------------------------
+;
+; MXCG.ASM - Color to gray conversion
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxColorToGray
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Converts RGB colors to gray shades.
+;
+; Input:
+;       CPal    = pointer to color palette
+;       GPal    = pointer to destination (gray) palette
+;       Count   = number of colors to convert
+; Output:
+;       none
+;
+; Note: CPal and GPal may point to the same buffer.
+;
+mxColorToGray   PROC    FAR
+        ARG     Count:WORD,     \
+                DPal:DWORD,     \
+                SPal:DWORD      = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds, si, es, di
+
+        mov     cx, [Count]
+        jcxz    @@Exit
+        lds     si, [SPal]
+        les     di, [DPal]
+        cld
+; We use the standard formula
+;       gray=(red*30 + green*59 + blue*11)/100
+; in the equivalent form
+;       gray=(red*77 + green*151 + blue*28)/256
+; which doesn't need the last divide.
+        mov     bx, 77 SHL 8 + 151
+@@Loop:
+        lodsb                           ; Red
+        mul     bh
+        mov     dx, ax
+        lodsb                           ; Green
+        mul     bl
+        add     dx, ax
+        lodsb                           ; Blue
+        mov     ah, 28
+        mul     ah
+        add     ax, dx
+        mov     al, ah
+        stosw                           ; Save new RGB
+        stosb
+        loop    @@Loop
+
+@@Exit:
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxColorToGray   ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXCL.ASM b/16/x/MXCL.ASM
new file mode 100755
index 00000000..aaa0bac3
--- /dev/null
+++ b/16/x/MXCL.ASM
@@ -0,0 +1,151 @@
+;-----------------------------------------------------------
+;
+; MXCL.ASM - Bresenham circle
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxCircle
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_BytesPerLine : WORD
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_ClipX1       : WORD
+EXTRN   mx_ClipY1       : WORD
+EXTRN   mx_ClipX2       : WORD
+EXTRN   mx_ClipY2       : WORD
+
+;-----------------------------------------------------------
+;
+; Draws a circle using the Bresenham algorithm.
+;
+; Input:
+;       XC, YC  = center coordinates
+;       Radius  = circle radius
+;       Color   = circle color
+; Output:
+;       none
+; Note:
+;       computes only points in the first octant, all other
+;       points are obtained by symmetry.
+;
+mxCircle        PROC FAR
+        ARG     Color:BYTE:2,           \
+                Radius:WORD,            \
+                YC:WORD,                \
+                XC:WORD                 = ARG_SIZE
+        LOCAL   Delta:WORD              = AUTO_SIZE
+        .enter  AUTO_SIZE
+        .push   ds, si, di
+
+        xor     si, si                  ; X
+        mov     di, [Radius]            ; Y
+        mov     ax, 3
+        sub     ax, di
+        sub     ax, di
+        mov     [Delta], ax             ; Delta = 3-R*2
+
+        mov     ds, [mx_VideoSegment]
+
+@@Loop:
+        cmp     si, di                  ;
+        jg      @@Done                  ; Exit when X > Y
+; Draw points
+        mov     ax, si
+        mov     bx, di
+        call    @@subPutPixel
+        mov     ax, si
+        neg     ax
+        mov     bx, di
+        call    @@subPutPixel
+        mov     ax, si
+        mov     bx, di
+        neg     bx
+        call    @@subPutPixel
+        mov     ax, si
+        neg     ax
+        mov     bx, di
+        neg     bx
+        call    @@subPutPixel
+        mov     ax, di
+        mov     bx, si
+        call    @@subPutPixel
+        mov     ax, di
+        neg     ax
+        mov     bx, si
+        call    @@subPutPixel
+        mov     ax, di
+        mov     bx, si
+        neg     bx
+        call    @@subPutPixel
+        mov     ax, di
+        neg     ax
+        mov     bx, si
+        neg     bx
+        call    @@subPutPixel
+; Moves coordinates to next point
+        mov     ax, [Delta]
+        test    ax, ax
+        jl      @@Next
+        mov     ax, di
+        .shl    ax, 2
+        sub     ax, 4
+        sub     [Delta], ax
+        dec     di
+@@Next:
+        mov     ax, si
+        .shl    ax, 2
+        add     ax, 6
+        add     [Delta], ax
+        inc     si
+        jmp     @@Loop
+
+@@Done:
+        xor     ax, ax
+        .pop    ds, si, di
+        .leave  ARG_SIZE
+
+;---------------------------------------
+; Put pixel function.
+; Input:
+;       BX      = X coordinate (relative to center)
+;       AX      = Y coordinate (relative to center)
+;       DS      = video segment
+@@subPutPixel:
+        add     bx, [XC]                ; Get absolute coordinates
+        add     ax, [YC]
+
+        cmp     bx, [mx_ClipX1]         ; Clip pixel
+        jl      @@subExit
+        cmp     bx, [mx_ClipX2]
+        jg      @@subExit
+        cmp     ax, [mx_ClipY1]
+        jl      @@subExit
+        cmp     ax, [mx_ClipY2]
+        jg      @@subExit
+
+        mul     [mx_BytesPerLine]       ; Get pixel offset
+        mov     cx, bx                  ; Save X coordinate
+        .shr    bx, 2
+        add     bx, ax                  ; DS:BX = pixel offset
+
+        and     cl, 3                   ; Set write plane
+        mov     ax, 0102h
+        shl     ah, cl
+        mov     dx, TS
+        out     dx, ax
+
+        mov     al, [Color]             ; Write pixel
+        mov     ds:[bx], al
+
+@@subExit:
+        retn
+mxCircle        ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXCR.ASM b/16/x/MXCR.ASM
new file mode 100755
index 00000000..ca1fa7bb
--- /dev/null
+++ b/16/x/MXCR.ASM
@@ -0,0 +1,380 @@
+;-----------------------------------------------------------
+;
+; MXCR.ASM - Clip functions
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxSetSysClipRegion
+PUBLIC  mxGetClipRegion
+PUBLIC  mxSetClipRegion
+PUBLIC  mxSetClip
+PUBLIC  mxGetClip
+
+PUBLIC  subClipBox
+PUBLIC  subClipImage
+
+PUBLIC  mx_ClipX1
+PUBLIC  mx_ClipY1
+PUBLIC  mx_ClipX2
+PUBLIC  mx_ClipY2
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_CodeSegment  : WORD
+
+mx_ClipX1       DW      ?               ; Clip coordinates
+mx_ClipY1       DW      ?
+mx_ClipX2       DW      ?
+mx_ClipY2       DW      ?
+
+mx_SysClipX1    DW      ?               ; System clip coordinates
+mx_SysClipY1    DW      ?               ; (active when mx_ClipStatus is FALSE)
+mx_SysClipX2    DW      ?
+mx_SysClipY2    DW      ?
+
+mx_UserClipX1   DW      ?               ; User clip coordinates
+mx_UserClipY1   DW      ?               ; (active when mx_ClipStatus is TRUE)
+mx_UserClipX2   DW      ?
+mx_UserClipY2   DW      ?
+
+mx_ClipStatus   DB      ?
+
+;-----------------------------------------------------------
+;
+; Toggles clipping between user and system regions.
+;
+; Input:
+;       ClipStatus      = TRUE (FALSE) to enable (disable) clipping
+; Output:
+;       AX      = old clip status
+;
+mxSetClip       PROC    FAR
+        ARG     ClipStatus:BYTE:2       = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds
+        mov     ds, [mx_CodeSegment]
+        ASSUME  ds:MX_TEXT
+
+        mov     ax, [mx_UserClipX1]
+        mov     bx, [mx_UserClipY1]
+        mov     cx, [mx_UserClipX2]
+        mov     dx, [mx_UserClipY2]
+        cmp     [ClipStatus], TRUE
+        je      @@Done
+        mov     ax, [mx_SysClipX1]
+        mov     bx, [mx_SysClipY1]
+        mov     cx, [mx_SysClipX2]
+        mov     dx, [mx_SysClipY2]
+@@Done:
+        mov     [mx_ClipX1], ax
+        mov     [mx_ClipY1], bx
+        mov     [mx_ClipX2], cx
+        mov     [mx_ClipY2], dx
+
+        mov     al, [ClipStatus]
+        xchg    al, [mx_ClipStatus]
+        xor     ah, ah
+
+        .pop    ds
+        .leave  ARG_SIZE
+mxSetClip       ENDP
+
+;-----------------------------------------------------------
+;
+; Returns the current clipping status.
+;
+; Input:
+;       none
+; Output:
+;       TRUE (FALSE) if clipping enabled (disabled)
+;
+mxGetClip       PROC    FAR
+        ASSUME  ds:NOTHING
+        mov     al, [mx_ClipStatus]
+        xor     ah, ah
+        ret
+mxGetClip       ENDP
+
+;-----------------------------------------------------------
+;
+; Sets the system clip region and disables user clipping.
+;
+; Input:
+;       Width   = width in pixels of clip region
+;       Height  = height in pixels of clip region
+; Output:
+;       old clip status.
+;
+mxSetSysClipRegion      PROC    FAR
+        ARG     Height:WORD,            \
+                Width:WORD              = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds
+        mov     ds, [mx_CodeSegment]
+        ASSUME  ds:MX_TEXT
+
+        xor     ax, ax                  ; Sys clip region always starts at (0,0)
+        mov     [mx_SysClipX1], ax
+        mov     [mx_SysClipY1], ax
+        mov     ax, [Width]
+        dec     ax
+        mov     [mx_SysClipX2], ax
+        mov     ax, [Height]
+        dec     ax
+        mov     [mx_SysClipY2], ax
+
+    IF USE286 EQ TRUE
+        push    FALSE
+    ELSE
+        mov     ax, FALSE
+        push    ax
+    ENDIF
+        call    mxSetClip
+
+        .pop    ds
+        .leave  ARG_SIZE
+mxSetSysClipRegion      ENDP
+
+;-----------------------------------------------------------
+;
+; Sets the clip region.
+;
+; Input:
+;       X, Y    = coordinates of top left corner of clip region
+;       Width   = width in pixels of clip region
+;       Height  = height in pixels of clip region
+; Output:
+;       none (no checking on parameters)
+;
+mxSetClipRegion PROC    FAR
+        ARG     Height:WORD,            \
+                Width:WORD,             \
+                Y:WORD,                 \
+                X:WORD                  = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds
+        mov     ds, [mx_CodeSegment]
+        ASSUME  ds:MX_TEXT
+
+        mov     ax, [X]
+        mov     [mx_UserClipX1], ax
+        mov     ax, [Y]
+        mov     [mx_UserClipY1], ax
+        mov     ax, [Width]
+        add     ax, [X]
+        dec     ax
+        mov     [mx_UserClipX2], ax
+        mov     ax, [Height]
+        add     ax, [Y]
+        dec     ax
+        mov     [mx_UserClipY2], ax
+
+        mov     al, [mx_ClipStatus]
+        cmp     al, TRUE
+        jne     @@Exit
+        push    ax
+        call    mxSetClip
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds
+        .leave  ARG_SIZE
+mxSetClipRegion ENDP
+
+;-----------------------------------------------------------
+;
+; Returns the current user clip region.
+;
+; Input:
+;       X, Y    = pointers to integer coordinates of top left corner
+;       Width   = pointer to word width of clip region
+;       Height  = pointer to word height of clip region
+; Output:
+;       AX      = current clip status
+;
+mxGetClipRegion PROC    FAR
+        ARG     Height:DWORD,           \
+                Width:DWORD,            \
+                Y:DWORD,                \
+                X:DWORD                 = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   es, di
+
+        mov     ax, [mx_UserClipX1]
+        les     di, [X]
+        mov     es:[di], ax
+        mov     ax, [mx_UserClipY1]
+        les     di, [Y]
+        mov     es:[di], ax
+
+        mov     ax, [mx_UserClipX2]
+        sub     ax, [mx_UserClipX1]
+        inc     ax
+        les     di, [Width]
+        mov     es:[di], ax
+        mov     ax, [mx_UserClipY2]
+        sub     ax, [mx_UserClipY1]
+        inc     ax
+        les     di, [Height]
+        mov     es:[di], ax
+
+        mov     al, [mx_ClipStatus]
+        xor     ah, ah
+        .pop    es, di
+        .leave  ARG_SIZE
+mxGetClipRegion ENDP
+
+;-----------------------------------------------------------
+;
+; Internal use: checks the coordinates of a rectangle against
+; the active clip region.
+; This function assumes that a "raw" image has to be clipped,
+; so it returns in SI the number of "raw" bytes to skip if
+; X, Y were clipped.
+;
+; Input:
+;       BX, AX  = X, Y coordinates of rectangle (signed)
+;       CX      = box width
+;       DX      = box height
+; Output:
+;       CF      = set if rectangle is full clipped
+;       BX, AX  = new X, Y coordinates of rectangle
+;       CX, DX  = clipped width and height
+;       SI      = number of bytes to skip before copying a buffer
+;       DI destroyed
+;
+subClipImage    PROC    NEAR
+        ASSUME  ds:NOTHING
+        xor     si, si
+
+; Check clip height
+        mov     di, [mx_ClipY1]
+        cmp     ax, di
+        jge     @@CheckBottom
+        sub     di, ax                  ; Number of lines to clip
+        sub     dx, di                  ; New box height
+        jle     @@Exit
+        mov     ax, di
+        mov     di, dx                  ; Save box height into DI
+        mul     cx                      ; DX:AX = number of bytes to skip
+        mov     si, ax
+        mov     dx, di                  ; Restore box height
+        mov     ax, [mx_ClipY1]
+@@CheckBottom:
+        mov     di, [mx_ClipY2]
+        cmp     ax, di
+        jg      @@Exit
+        inc     di
+        sub     di, dx
+        sub     di, ax
+        jge     @@DoneHeight            ; None, continue
+        add     dx, di                  ; Clip lines
+@@DoneHeight:
+
+; Check clip width
+@@CheckLeft:
+        mov     di, [mx_ClipX1]
+        cmp     bx, di
+        jge     @@CheckRight
+        sub     di, bx                  ; Number of columns to clip left
+        sub     cx, di
+        jle     @@Exit
+        add     si, di                  ; Update skip count
+        mov     bx, [mx_ClipX1]
+@@CheckRight:
+        mov     di, [mx_ClipX2]
+        cmp     bx, di
+        jg      @@Exit
+        inc     di
+        sub     di, bx
+        sub     di, cx
+        jge     @@DoneWidth             ; None, exit
+        add     cx, di                  ; New box width
+@@DoneWidth:
+
+; Set return flag and exit
+@@Done:
+        clc
+        ret
+@@Exit:
+        stc
+        ret
+subClipImage    ENDP
+
+;-----------------------------------------------------------
+;
+; Internal use: checks the coordinates of a rectangle against
+; the active clip region.
+;
+; Input:
+;       BX, AX  = X, Y coordinates of rectangle (signed)
+;       CX      = box width
+;       DX      = box height
+; Output:
+;       CF      = set if rectangle is full clipped
+;       BX, AX  = new X, Y coordinates of rectangle
+;       CX, DX  = clipped width and height
+;       DI destroyed
+;
+subClipBox      PROC    NEAR
+        ASSUME  ds:NOTHING
+
+; Check clip height
+        mov     di, [mx_ClipY1]
+        cmp     ax, di
+        jge     @@CheckBottom
+        sub     di, ax                  ; Number of lines to clip
+        sub     dx, di                  ; New box height
+        jle     @@Exit
+        mov     ax, [mx_ClipY1]
+@@CheckBottom:
+        mov     di, [mx_ClipY2]
+        cmp     ax, di
+        jg      @@Exit
+        inc     di
+        sub     di, dx
+        sub     di, ax                  ; Clipped some point?
+        jge     @@DoneHeight            ; No, continue
+        add     dx, di                  ; Clip lines (DI is negative)
+@@DoneHeight:
+
+; Check clip width
+@@CheckLeft:
+        mov     di, [mx_ClipX1]
+        cmp     bx, di
+        jge     @@CheckRight
+        sub     di, bx                  ; Number of columns to clip left
+        sub     cx, di
+        jle     @@Exit
+        mov     bx, [mx_ClipX1]
+@@CheckRight:
+        mov     di, [mx_ClipX2]
+        cmp     bx, di
+        jg      @@Exit
+        inc     di
+        sub     di, bx
+        sub     di, cx                  ; Clipped some point?
+        jge     @@DoneWidth             ; No, exit
+        add     cx, di                  ; New box width (DI is negative)
+@@DoneWidth:
+
+; Set return flag and exit
+@@Done:
+        clc
+        ret
+@@Exit:
+        stc
+        ret
+subClipBox      ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXEL.ASM b/16/x/MXEL.ASM
new file mode 100755
index 00000000..2c9dda2a
--- /dev/null
+++ b/16/x/MXEL.ASM
@@ -0,0 +1,167 @@
+;-----------------------------------------------------------
+;
+; MXEL.ASM - Mid-point ellipse
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxEllipse
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_BytesPerLine : WORD
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_ClipX1       : WORD
+EXTRN   mx_ClipY1       : WORD
+EXTRN   mx_ClipX2       : WORD
+EXTRN   mx_ClipY2       : WORD
+
+;-----------------------------------------------------------
+;
+; Draws an ellipse using the mid-point algorithm.
+;
+; Input:
+;       XC, YC  = center coordinates
+;       A       = horizontal radius
+;       B       = vertical radius
+;       Color   = ellipse color
+; Output:
+;       none
+; Note:
+;       computes only points in the first quadrant, all other
+;       points are obtained by symmetry.
+;
+mxEllipse       PROC FAR
+        ARG     Color:BYTE:2,   \
+                B:WORD,         \
+                A:WORD,         \
+                YC:WORD,        \
+                XC:WORD         = ARG_SIZE
+        LOCAL   A2:DWORD,       \
+                B2:DWORD,       \
+                CC:DWORD,       \
+                DD:DWORD,       \
+                X:DWORD,        \
+                Y:DWORD         = AUTO_SIZE
+        .enter  AUTO_SIZE
+        .push   ds, si, di
+
+        .chk386 mxEllipse, @@Exit
+
+; Initialize variables
+        xor     eax, eax
+        mov     [X], ax         ; X = 0
+        mov     ax, [A]
+        mul     eax             ; EAX = A*A
+        mov     [DD], eax       ; DD = A*A
+        shl     eax, 1
+        mov     [CC], eax       ; CC = 2*A*A
+        shl     eax, 1
+        mov     [A2], eax       ; A2 = 4*A*A
+        movzx   edx, [B]
+        mov     [Y], edx
+        mul     edx             ; EAX = 4*A*A*B
+        sub     [DD], eax       ; DD = A*A - 4*A*A*B
+        movzx   eax, [B]
+        mul     eax             ; EAX = B*B
+        shl     eax, 2          ; EAX = 4*B*B
+        mov     [B2], eax       ; B2 = 4*B*B
+        add     [CC], eax       ; CC = 2*A*A + 4*B*B
+        add     [D1], eax       ; DD = A*A - 4*A*A*B + 4*B*B
+
+; Draw initial points
+        call    subPlot4
+
+; First loop
+@@Loop1:
+        mov     eax, [X]        ; Check slope
+        mul     [B2]
+        mov     ecx, eax
+        mov     eax, [Y]
+        mul     [A2]
+        sub     eax, ecx
+        sub     eax, [CC]       ; EAX = Y*A2 - X*B2 - CC
+        jle     @@Done1         ; Crossed critical point, jump to next loop
+
+        mov     ecx, [DD]       ; Get error
+        test    ecx, ecx        ; Positive?
+        jl      @@Draw1         ; No, use default step
+
+        mov     eax, 1
+        sub     eax, [Y]
+        mul     [A2]
+        shl     eax, 1
+        add     ecx, eax        ; Bump error
+        dec     WORD PTR [Y]    ; Decrement Y coordinate
+
+@@Draw1:
+        mov     eax, [X]
+        shl     eax, 1
+        add     eax, 3
+        mul     [B2]
+        add     ecx, eax        ; Bump error
+        mov     [DD], ecx       ; Save error
+        inc     WORD PTR [X]    ; Increment X coordinate
+
+        call    subPlot4        ; Draw points
+        jmp     @@Loop1
+@@Done1:
+
+; Initialize variables
+        shr     [B2], 2
+        mov     eax, [X]
+        mul     eax
+        add     [X]
+        shl     eax, 2
+        inc     eax
+        mul     [B2]
+        mov     [DD], eax
+        mov     eax, [Y]
+        mul     eax
+        add     [Y]
+        dec     eax
+        add     [Y]
+        sub     eax, [B2]
+        add     [DD], eax
+        shl     [B2], 3
+        inc     WORD PTR [X]
+
+; Second loop
+@@Loop2:
+        cmp     WORD PTR [Y], 0
+        ja      @@Done2
+
+        mov     ecx, [DD]
+        test    ecx, ecx
+        jge     @@Draw2
+
+        mov     eax, [X]
+        inc     eax
+        mul     [B2]
+        add     ecx, eax
+        inc     WORD PTR [X]
+
+@@Draw2:
+        mov     eax, [Y]
+        shl     eax, 1
+        sub     eax, 3
+        neg     eax
+        imul    [A2]
+        add     ecx, eax
+        dec     WORD PTR [Y]
+
+        call    subPlot4
+        jmp     @@Loop2
+@@Done2:
+
+@@Exit:
+        xor     ax, ax
+        .leave  ARG_SIZE
+mxEllipse       ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXFB.ASM b/16/x/MXFB.ASM
new file mode 100755
index 00000000..41ea5deb
--- /dev/null
+++ b/16/x/MXFB.ASM
@@ -0,0 +1,194 @@
+;-----------------------------------------------------------
+;
+; MXFB.ASM - Fill box function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxFillBox
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_BytesPerLine         : WORD
+EXTRN   mx_VideoSegment         : WORD
+EXTRN   subClipBox              : NEAR
+EXTRN   subHorizontalLineInfo   : NEAR
+
+;-----------------------------------------------------------
+;
+; Raster op functions. Raster op is limited to OP_MOVE,
+; OP_AND, OP_OR and OP_XOR. The VGA hardware is used to
+; perform the selected logical functions on up to four
+; pixel at a time.
+;
+subRepFill      PROC    NEAR
+        mov     ah, al
+        shr     cx, 1
+        rep     stosw
+        rcl     cx, 1
+        rep     stosb
+        ret
+subRepFill      ENDP
+;
+subFill         PROC    NEAR
+@@Loop:
+        mov     ds:[bx], al
+        add     bx, dx
+        loop    @@Loop
+        ret
+subFill         ENDP
+;
+subRepMove      PROC    NEAR
+        mov     si, di
+@@Loop:
+        mov     ah, ds:[si]             ; Dummy read to latch the data
+        mov     ds:[si], al
+        inc     si
+        loop    @@Loop
+        ret
+subRepMove      ENDP
+;
+subMove         PROC    NEAR
+@@Loop:
+        mov     ah, ds:[bx]             ; Dummy read to latch the data
+        mov     ds:[bx], al
+        add     bx, dx
+        loop    @@Loop
+        ret
+subMove         ENDP
+
+;-----------------------------------------------------------
+;
+; Fills a rectangle with a specified color.
+;
+; Input:
+;       X, Y            = X, Y coordinates of rectangle
+;       Width           = width of rectangle
+;       Height          = height of rectangle
+;       Color           = fill color
+;       Op              = raster operator
+; Output:
+;       none
+;
+; Note: raster op is limited to OP_MOVE, OP_AND, OP_OR and OP_XOR.
+;
+mxFillBox       PROC    FAR
+        ARG     Op:WORD,                \
+                Color:BYTE:2,           \
+                Height:WORD,            \
+                Width:WORD,             \
+                Y:WORD,                 \
+                X:WORD                  = ARG_SIZE
+        LOCAL   LeftMask:BYTE,          \
+                RightMask:BYTE,         \
+                FillFunction:WORD,      \
+                RepFillFunction:WORD    = AUTO_SIZE
+        .enter  AUTO_SIZE
+        .push   ds, si, es, di
+        ASSUME  ds:NOTHING
+
+; Clip rectangle
+        mov     bx, [X]
+        mov     ax, [Y]
+        mov     cx, [Width]
+        mov     dx, [Height]
+        call    subClipBox
+        jc      @@Exit                  ; Full clipped
+
+        mov     [Height], dx            ; Save clipped height
+        call    subHorizontalLineInfo   ; Get additional info, init DI
+        mov     [Width], cx
+        mov     [LeftMask], al
+        mov     [RightMask], ah
+
+; Initialize segments
+        mov     ax, [mx_VideoSegment]
+        mov     es, ax                  ; ES:DI points to pixel
+        mov     ds, ax
+        cld                             ; Clear direction flag
+
+; Select fill functions
+        mov     [FillFunction], OFFSET subFill
+        mov     [RepFillFunction], OFFSET subRepFill
+        mov     ax, [Op]                ; Get raster op
+        cmp     al, OP_XOR
+        ja      @@1                     ; Assume it's a fill
+        cmp     al, OP_MOVE
+        je      @@1
+        .shl    al, 3
+        mov     ah, al
+        mov     al, 03h
+        mov     dx, GDC
+        out     dx, ax                  ; Set GDC logical function
+        mov     [FillFunction], OFFSET subMove
+        mov     [RepFillFunction], OFFSET subRepMove
+@@1:
+
+; Fill left block
+@@L0:
+        mov     ah, [LeftMask]
+        or      ah, ah
+        jz      @@C0                    ; Nothing to do, go to center block
+        mov     dx, TS
+        mov     al, 02h
+        out     dx, ax                  ; Set write plane mask
+        mov     dx, [mx_BytesPerLine]
+        mov     cx, [Height]
+        mov     bx, di
+        mov     al, [Color]
+        call    [FillFunction]          ; Fill this column
+        inc     di                      ; Update starting video offset
+
+; Fill center block
+@@C0:
+        mov     cx, [Width]
+        jcxz    @@R0                    ; Nothing to do, go to right block
+        mov     dx, TS
+        mov     ax, 0F02h
+        out     dx, ax                  ; Write to all planes
+        mov     al, [Color]
+        mov     bx, di
+        mov     dx, [Height]
+        push    di                      ; Save pixel address
+@@C1:
+        mov     di, bx                  ; Update video offset
+        call    [RepFillFunction]       ; Fill current scan line
+        mov     cx, [Width]             ; Restore byte count
+        add     bx, [mx_BytesPerLine]   ; Bump to next scan line
+        dec     dx                      ; Done all lines?
+        jnz     @@C1                    ; No, continue
+        pop     di                      ; Restore pixel address
+        add     di, [Width]             ; Go to right block
+
+; Fill right block
+@@R0:
+        mov     ah, [RightMask]
+        or      ah, ah
+        jz      @@Done                  ; Nothing to do, exit
+        mov     dx, TS
+        mov     al, 02h
+        out     dx, ax                  ; Set write plane mask
+        mov     dx, [mx_BytesPerLine]
+        mov     cx, [Height]
+        mov     bx, di
+        mov     al, [Color]
+        call    [FillFunction]          ; Fill this column
+
+; Restore VGA registers
+@@Done:
+        mov     dx, GDC
+        mov     ax, 0003h
+        out     dx, ax                  ; Set logical function to "move"
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxFillBox       ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXFP.ASM b/16/x/MXFP.ASM
new file mode 100755
index 00000000..8eea25be
--- /dev/null
+++ b/16/x/MXFP.ASM
@@ -0,0 +1,326 @@
+;-----------------------------------------------------------
+;
+; MXFP.ASM - Fade palette function
+; Copyright (c) 1992-1994 ARTIS s.r.l.
+; Author: Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxFadePalette
+
+MAXCOLOR        EQU     256
+FADE_IN         EQU     0
+FADE_OUT        EQU     1
+
+; The actual speed of fading depends on the number of passes (FADE_SPEED) and
+; the delay between two consecutive passes (FADE_DELAY). Below are the
+; default values, used when no parameters are specified.
+;
+FADE_DELAY      EQU     1               ; Vert. retraces between video updates
+FADE_SPEED      EQU     48              ; Speed of effect (max 127)
+
+; Bit field record for fade commands
+;
+FADE_COMMAND    RECORD  fpDELAY:8,fpSPEED:7,fpDIRECTION:1
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+DB      'Copyright (c) 1992-1994 ARTIS s.r.l. All rights reserved.'
+
+;-----------------------------------------------------------
+;
+; Fades a VGA palette.
+;
+; Input:
+;       Buffer          = pointer to source/destination palette
+;       Command         = fading direction and optional parameters
+;       Start           = index of first color to fade
+;       Count           = number of color to fade
+;       Red             = destination red
+;       Green           = destination green
+;       Blue            = destination blue
+; Output:
+;       none
+; Notes:
+;    -  about 1.5 Kbytes of stack space are needed for internal buffers;
+;    -  the Command argument usually is 0 to fade in and 1 to fade out,
+;       however additional parameters may be specified. To set the effect
+;       speed, i.e. the number of iterations needed to completely fade a
+;       palette, shift the value one bit left and "or" it with the
+;       direction bit (range is 0..127). To set the delay between two
+;       consecutive passes, shift it eight bits left (range is 0..255).
+;
+mxFadePalette   PROC FAR
+        ARG     bBlue:WORD,                     \
+                bGreen:WORD,                    \
+                bRed:WORD,                      \
+                wCount:WORD,                    \
+                wStartIdx:WORD,                 \
+                wCommand:WORD,                  \
+                vfpPalette:DWORD = ARG_SIZE
+        LOCAL   bSPalette:BYTE:MAXCOLOR*3,      \
+                bDPalette:BYTE:MAXCOLOR*3,      \
+                bLoopIndex:BYTE,                \
+                bLoopStep:BYTE,                 \
+                bLoopCount:BYTE,                \
+                wDelay:WORD,                    \
+                wSpeed:WORD     = AUTO_SIZE
+        ASSUME  ds:NOTHING
+        .enter  AUTO_SIZE
+        .push   si, di, ds, es                  ; Save registers
+;
+; Check parameters and setup variables
+;
+@@GetDelay:
+        mov     [wDelay], FADE_DELAY            ; Set default delay
+        mov     ax, [wCommand]                  ; Get command word
+        and     ax, MASK fpDELAY                ; Mask delay command
+        jz      @@GetSpeed                      ; No command, get speed
+    IF USE286 EQ TRUE
+        shr     ax, fpDELAY
+    ELSE
+        mov     cl, fpDELAY                     ; Get size of delay field
+        shr     ax, cl                          ; Right justify the field
+    ENDIF
+        mov     [wDelay], ax                    ; Set new delay
+
+@@GetSpeed:
+        mov     ax, [wCommand]                  ; Get command
+        and     ax, MASK fpSPEED                ; Mask speed
+    IF USE286 EQ TRUE
+        shr     ax, fpSPEED
+    ELSE
+        mov     cl, fpSPEED                     ; Get size of speed field
+        shr     ax, cl                          ; Right justify the field
+    ENDIF
+        or      ax, ax                          ; Any speed specified?
+        jnz     @@SetVariables                  ; Yes, set variables
+        mov     ax, FADE_SPEED                  ; Set default speed
+
+@@SetVariables:
+        mov     [wSpeed], ax                    ; Set speed
+        inc     ax                              ; Number of iterations
+        mov     [bLoopCount], al                ; Set loop count
+        mov     [bLoopStep], 1                  ; Assume we're fading in
+        mov     [bLoopIndex], 0
+;
+; Check bounds for bad values
+;
+        mov     ax, [wStartIdx]                 ; Get first index
+        cmp     ax, MAXCOLOR                    ; Is in the valid range?
+        jae     @@Exit                          ; No, exit
+        add     ax, [wCount]                    ; Get last index
+        cmp     ax, MAXCOLOR                    ; Is in the valid range?
+        jbe     @@BoundsOk                      ; Yes, continue
+        mov     ax, MAXCOLOR
+        sub     ax, [wStartIdx]
+        mov     [wCount], ax                    ; Set count to maximum value
+        or      ax, ax
+        jz      @@Exit                          ; Nothing to do, exit
+@@BoundsOk:
+;
+; Copy the source palette in a local array: if we fade in it's ready to
+; use, otherwise we'll overwrite it later
+;
+        mov     cx, [wCount]
+        mov     ax, cx
+        shl     ax, 1
+        add     cx, ax                          ; CX = wCount * 3
+        mov     ax, ss
+        mov     es, ax
+        lea     di, [bSPalette]                 ; ES:DI points to local palette
+        mov     ax, [wStartIdx]
+        mov     si, ax
+        shl     ax, 1
+        add     ax, si
+        lds     si, [vfpPalette]                ; DS:SI points to user palette
+        add     si, ax                          ; Skip unused entries
+        cld
+        shr     cx, 1
+        rep     movsw
+        rcl     cx, 1
+        rep     movsb
+;
+; Check direction
+;
+        test    [wCommand], MASK fpDIRECTION    ; Are we fading in?
+        jz      @@Main                          ; Yes, ok to continue
+        mov     ax, [wSpeed]                    ; Get speed
+        mov     [bLoopIndex], al                ; Exchange first and last index
+        mov     [bLoopStep], -1                 ; Move backward
+        mov     ax, ss                          ; Overwrite our copy of
+        mov     ds, ax                          ; user palette with the
+        mov     es, ax                          ; current active palette
+        lea     di, [bSPalette]
+        mov     ax, [wStartIdx]
+        mov     cx, [wCount]
+        call    ReadPalette                     ; Read current palette
+;
+; Prepare variables and registers for fading
+;
+@@Main:
+        mov     bh, BYTE PTR [bRed]             ; Destination red
+        and     bh, 00111111b                   ; Be sure it's a valid VGA value
+        mov     bl, BYTE PTR [bGreen]           ; Destination green
+        and     bl, 00111111b                   ; Be sure it's a valid VGA value
+        mov     dh, BYTE PTR [bBlue]            ; Destination blue
+        and     dh, 00111111b                   ; Be sure it's a valid VGA value
+        mov     dl, [bLoopIndex]                ; Loop index
+        mov     ax, ss                          ; All tables are stored
+        mov     ds, ax                          ; in the stack segment,
+        mov     es, ax                          ; set DS and ES
+;
+; Main loop
+;
+@@Loop:
+        mov     ax, [wCount]                    ; Store count in AX
+        mov     cx, [wSpeed]                    ; Set maximum speed in CX
+        lea     si, [bSPalette]                 ; DS:SI points to source palette
+        lea     di, [bDPalette]                 ; ES:DI points to dest. palette
+        call    RecalcPalette                   ; Build a faded palette
+
+        .push   bx, dx                          ; Save registers we need
+        lea     si, [bDPalette]                 ; DS:SI points to palette
+        mov     ax, [wStartIdx]                 ; First index to write
+        mov     bx, [wCount]                    ; Total entries to write
+        mov     cx, [wDelay]                    ; Fade delay between updates
+        call    WritePalette                    ; Write palette
+        .pop    bx, dx                          ; Restore BX and DX
+
+        add     dl, [bLoopStep]                 ; Change fade intensity
+        dec     [bLoopCount]                    ; Done?
+        jnz     @@Loop                          ; No, loop again
+
+@@Exit:
+        .pop    si, di, ds, es                  ; Restore registers
+        .leave  ARG_SIZE
+mxFadePalette   ENDP
+
+;------- INTERNAL USE ONLY ------------------------------------------------
+;
+; Calculates a partially faded palette.
+;
+; Input:
+;       AX      = number of entries in palette
+;       CX      = maximum fade intensity (same as fade speed)
+;       DS:SI   = pointer to source palette
+;       ES:DI   = pointer to destination palette
+;       BH      = destination red
+;       BL      = destination green
+;       DH      = destination blue
+;       DL      = relative intensity of destination palette
+; Note:
+;       it's important that a new palette can be calculated in less
+;       than 1/70th of second. Fading to any RGB value requires use
+;       of "imul" instructions: "idiv" may be replaced with faster
+;       "sar", but only when the number of passes is a power of two,
+;       thus reducing the range of selectable speeds.
+;       In both cases an extimate of CPU cycles required by this
+;       procedure shows that it's too slow to run on a 4.77 Mhz 8086
+;       CPU and a 256 color palette, so we keep "idiv" and hope
+;       the target machine to be at least a 6 Mhz 80286 (that's not
+;       asking too much...).
+;
+RecalcPalette   PROC NEAR
+        cld
+        push    bp                              ; Save BP
+        mov     bp, ax                          ; Copy counter in BP
+@@Loop:
+        lodsb                                   ; Red: read value
+        sub     al, bh                          ; Subtract destination value
+        imul    dl                              ; Scale to desired weight
+        idiv    cl                              ; Put value in AL
+        add     al, bh                          ; Add destination value...
+        stosb                                   ; ...and store it
+        lodsb                                   ; Green: read value
+        sub     al, bl                          ; Subtract destination value
+        imul    dl                              ; Scale to desired weight
+        idiv    cl                              ; Put value in AL
+        add     al, bl                          ; Add destination value...
+        stosb                                   ; ...and store it
+        lodsb                                   ; Blue: read value
+        sub     al, dh                          ; Subtract destination value
+        imul    dl                              ; Scale to desired weight
+        idiv    cl                              ; Put value in AL
+        add     al, dh                          ; Add destination value...
+        stosb                                   ; ...and store it
+        dec     bp
+        jnz     @@Loop
+        pop     bp                              ; Restore BP
+        ret
+RecalcPalette   ENDP
+
+;------- INTERNAL USE ONLY ------------------------------------------------
+;
+; Writes a 256 color palette.
+;
+; Input:
+;       AX      = index of first color to write
+;       BX      = number of colors to write (each color is an RGB triplet)
+;       CX      = number of vertical retraces to wait before writing to DACs
+;       DS:SI   = pointer to first entry of palette
+;
+WritePalette    PROC NEAR
+        ASSUME  ds:NOTHING
+        mov     ah, al                          ; Save index
+        mov     dx, 03DAh                       ; Input status register
+@@Delay1:
+        in      al, dx
+        test    al, 08h
+        jnz     @@Delay1                        ; Wait for display mode
+@@Delay2:
+        in      al, dx
+        test    al, 08h
+        jz      @@Delay2                        ; Wait for vertical retrace mode
+        loop    @@Delay1                        ; Repeat CX times
+@@Write:
+        mov     cx, bx                          ; Get number of colors
+        mov     dx, 03C8h                       ; PEL write address register
+        mov     al, ah                          ; Restore index
+        out     dx, al                          ; Select index of first color
+        inc     dx                              ; PEL data register
+        cld                                     ; Move forward
+        cli                                     ; Disable interrupts
+@@Loop:
+        lodsb
+        out     dx, al                          ; Red
+        lodsb
+        out     dx, al                          ; Green
+        lodsb
+        out     dx, al                          ; Blue
+        loop    @@Loop                          ; Loop until done
+        sti                                     ; Enable interrupts
+        ret
+WritePalette    ENDP
+
+;------- INTERNAL USE ONLY ------------------------------------------------
+;
+; Reads the current palette.
+;
+; Input:
+;       AX      = index of first color to read
+;       CX      = number of colors
+;       ES:DI   = pointer to destination buffer
+;
+ReadPalette     PROC    NEAR
+        mov     dx, 03C7h
+        out     dx, al
+        inc     dx
+        inc     dx
+        cld
+@@Loop:
+        in      al, dx
+        stosb
+        in      al, dx
+        stosb
+        in      al, dx
+        stosb
+        loop    @@Loop
+        ret
+ReadPalette     ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXGC.ASM b/16/x/MXGC.ASM
new file mode 100755
index 00000000..85edf7a6
--- /dev/null
+++ b/16/x/MXGC.ASM
@@ -0,0 +1,54 @@
+;-----------------------------------------------------------
+;
+; MXGC.ASM - Get color function
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxGetColor
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Returns the current setting of the selected DAC register.
+;
+; Input:
+;       Index   = color index (0-255)
+;       R, G, B = byte pointers to red, green and blue
+; Output:
+;       none
+;
+mxGetColor      PROC FAR
+        ARG     B:DWORD,        \
+                G:DWORD,        \
+                R:DWORD,        \
+                Index:WORD      = ARG_SIZE
+        .enter  0
+        .push   ds, si
+
+        mov     ax, [Index]
+        mov     dx, 3C7h                ; PEL read address register
+        out     dx, al
+        inc     dx
+        inc     dx
+
+        lds     si, [R]
+        in      al, dx
+        mov     ds:[si], al
+        lds     si, [G]
+        in      al, dx
+        mov     ds:[si], al
+        lds     si, [B]
+        in      al, dx
+        mov     ds:[si], al
+
+        .pop    ds, si
+        .leave  ARG_SIZE
+mxGetColor      ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXGI.ASM b/16/x/MXGI.ASM
new file mode 100755
index 00000000..7037d411
--- /dev/null
+++ b/16/x/MXGI.ASM
@@ -0,0 +1,132 @@
+;-----------------------------------------------------------
+;
+; MXGI.ASM - Get image
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxGetImage
+
+EXTRN   subClipImage            : NEAR
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_BytesPerLine : WORD
+
+;-----------------------------------------------------------
+;
+; Copies an image from screen to memory.
+;
+; Input:
+;       Image   = pointer to buffer for image
+;       X, Y    = coordinates of image on screen
+;       Width   = width of image in pixels
+;       Height  = height of image in pixels
+; Output:
+;       none
+;
+mxGetImage      PROC    FAR
+        ARG     Height:WORD,            \
+                Width:WORD,             \
+                Y:WORD,                 \
+                X:WORD,                 \
+                Image:DWORD             = ARG_SIZE
+        LOCAL   PlaneWidth:WORD:4,      \
+                PixelOffset:WORD,       \
+                MoveFunction:WORD,      \
+                ReadPlane:BYTE,         \
+                Count:BYTE              = AUTO_SIZE
+        ASSUME  ds:NOTHING
+        .enter  AUTO_SIZE
+        .push   ds, si, es, di
+
+; Clip image
+        mov     bx, [X]
+        mov     ax, [Y]
+        mov     cx, [Width]
+        mov     dx, [Height]
+        call    subClipImage
+        jc      @@Exit                  ; Full clipped
+        mov     [Height], dx
+        add     WORD PTR Image[0], si   ; Skip clipped pixels
+
+; Get pixel address
+        mul     [mx_BytesPerLine]
+        mov     si, bx
+        shr     si, 1
+        shr     si, 1
+        add     si, ax
+        mov     [PixelOffset], si
+        mov     ds, [mx_VideoSegment]   ; DS:SI points to pixel
+        and     bl, 03h
+        mov     [ReadPlane], bl
+
+; Compute extra bytes and width count for each plane
+        mov     bx, cx
+        shr     bx, 1
+        shr     bx, 1                   ; Width for each plane
+        and     cl, 03h
+        mov     al, 00001000b
+        shr     al, cl
+        mov     di, 3 SHL 1
+@@PatchLoop:
+        mov     PlaneWidth[di], bx
+        shr     al, 1
+        adc     bx, 0
+        dec     di
+        dec     di
+        jge     @@PatchLoop
+
+; Get image
+        cld
+        mov     [Count], 4              ; Four planes
+        lea     bx, PlaneWidth          ; SS:[BX] = width in bytes for plane
+        mov     es, WORD PTR Image[2]   ; ES:DI will point to image
+        mov     ah, [ReadPlane]
+@@PlaneLoop:
+        cmp     WORD PTR ss:[bx], 0     ; Exit if nothing more to do
+        je      @@Exit                  ; (also, never try to move zero bytes!)
+        mov     di, WORD PTR Image[0]
+        mov     al, 04h
+        mov     dx, GDC
+        out     dx, ax                  ; Select read plane
+        mov     dx, [Height]
+        mov     si, [PixelOffset]       ; DS:SI points to video memory
+@@Loop:
+        .push   si, di
+        mov     cx, WORD PTR ss:[bx]    ; Number of bytes to move
+@@MoveLoop:
+        movsb
+        add     di, 3
+        dec     cx
+        jnz     @@MoveLoop
+        .pop    si, di
+        add     di, [Width]             ; Go to next image line
+        add     si, [mx_BytesPerLine]   ; Go to next screen row
+        dec     dx
+        jnz     @@Loop                  ; Repeat for all lines
+        inc     bx
+        inc     bx                      ; Select width for next plane
+        inc     ah
+        test    ah, 04h                 ; Plane wraparound?
+        jz      @@PlaneOk               ; No
+        inc     [PixelOffset]           ; Yes, bump video pointer
+        and     ah, 03h
+@@PlaneOk:
+        inc     WORD PTR Image[0]
+        dec     [Count]
+        jnz     @@PlaneLoop             ; Repeat for all planes
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxGetImage      ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXGM.ASM b/16/x/MXGM.ASM
new file mode 100755
index 00000000..a67476a0
--- /dev/null
+++ b/16/x/MXGM.ASM
@@ -0,0 +1,63 @@
+;-----------------------------------------------------------
+;
+; MXGM.ASM - Gamma correction
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxGammaCorrect
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+mx_tblGamma     LABEL BYTE
+    DB  00, 10, 14, 17, 19, 21, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34
+    DB  35, 36, 37, 37, 38, 39, 40, 41, 41, 42, 43, 44, 44, 45, 46, 46
+    DB  47, 48, 48, 49, 49, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55
+    DB  56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63
+
+;-----------------------------------------------------------
+;
+; Correct palette colors (gamma is 2.3).
+;
+; Input:
+;       CPal    = pointer to color palette
+;       GPal    = pointer to destination (gamma corrected) palette
+;       Count   = number of colors to convert
+; Output:
+;       none
+;
+; Note: CPal and GPal may point to the same buffer.
+;
+mxGammaCorrect  PROC    FAR
+        ARG     Count:WORD,     \
+                DPal:DWORD,     \
+                SPal:DWORD      = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds, si, es, di
+
+        mov     cx, [Count]
+        jcxz    @@Exit                  ; Exit now if nothing to do
+        lds     si, [SPal]
+        les     di, [DPal]
+        mov     bx, OFFSET mx_tblGamma  ; Setup BX for XLAT instruction
+        cld
+        mov     ax, cx                  ; AX = Count
+        add     cx, cx                  ; CX = Count*2
+        add     cx, ax                  ; CX = Count*3
+@@Loop:
+        lodsb
+        xlat    mx_tblGamma
+        stosb
+        loop    @@Loop
+
+@@Exit:
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxGammaCorrect  ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXGP.ASM b/16/x/MXGP.ASM
new file mode 100755
index 00000000..6c143173
--- /dev/null
+++ b/16/x/MXGP.ASM
@@ -0,0 +1,56 @@
+;-----------------------------------------------------------
+;
+; MXGP.ASM - Get palette function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxGetPalette
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Returns the current setting of the VGA palette.
+;
+; Input:
+;       Buffer          = pointer to palette data (R,G,B)
+;       Start           = index of first color to get
+;       Count           = number of color to get
+; Output:
+;       none
+;
+mxGetPalette    PROC    FAR
+        ARG     Count:WORD,             \
+                Start:WORD,             \
+                Buffer:DWORD            = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   es, di
+
+        les     di, [Buffer]
+        mov     cx, [Count]
+        mov     ax, [Start]
+        mov     dx, 3C7h                ; PEL read address register
+        out     dx, al
+        inc     dx
+        inc     dx
+        cld
+@@Loop:
+        in      al, dx
+        stosb
+        in      al, dx
+        stosb
+        in      al, dx
+        stosb
+        loop    @@Loop                  ; Loop until done
+
+        .pop    es, di
+        .leave  ARG_SIZE
+mxGetPalette    ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXGV.ASM b/16/x/MXGV.ASM
new file mode 100755
index 00000000..2a54b1d0
--- /dev/null
+++ b/16/x/MXGV.ASM
@@ -0,0 +1,25 @@
+;-----------------------------------------------------------
+;
+; MXGV.ASM - Get version function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxGetVersion
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Returns the library version.
+;
+mxGetVersion    PROC    FAR
+        mov     ax, MXVERSION
+        ret
+mxGetVersion    ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXHL.ASM b/16/x/MXHL.ASM
new file mode 100755
index 00000000..049a0566
--- /dev/null
+++ b/16/x/MXHL.ASM
@@ -0,0 +1,76 @@
+;-----------------------------------------------------------
+;
+; MXHL.ASM - Horizontal line mask utility
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  subHorizontalLineInfo
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_BytesPerLine : WORD
+
+tblLeftSize     DW      00h, 03h, 02h, 01h
+tblLeftMask     DB      00h, 0Eh, 0Ch, 08h
+tblRightMask    DB      00h, 01h, 03h, 07h
+tblPatchMask    DB      02h, 06h
+
+;-----------------------------------------------------------
+;
+; Prepares register for fast horizontal line drawing.
+;
+; Input:
+;       BX, AX  = X, Y address of left pixel
+;       CX      = line width
+; Output:
+;       DI      = left pixel offset in video memory
+;       AL      = left block write plane mask (0 = none)
+;       AH      = right block write plane mask (0 = none)
+;       CX      = center block width in 4-pixel blocks
+;
+subHorizontalLineInfo   PROC NEAR
+        ASSUME  ds:NOTHING
+
+        mul     [mx_BytesPerLine]
+        mov     di, bx
+        shr     di, 1
+        shr     di, 1
+        add     di, ax                  ; Offset of left pixel
+
+        and     bx, 03h
+        mov     al, tblLeftMask[bx]
+        shl     bx, 1
+        sub     cx, tblLeftSize[bx]
+        jge     @@1                     ; Ok to continue
+
+; Special case: start and end in the middle of a 4-pixel block.
+; There are only three cases:
+;    Pixels     Left mask       CX      CX+2    Patch mask      Result
+; 1)  ..o.        ..xx          -1      1       .xx.            ..x.
+; 2)  .oo.        .xxx          -1      1       .xx.            .xx.
+; 3)  .o..        .xxx          -2      0       .x..            .x..
+; All other cases are automatically handled with the standard masks.
+        mov     bx, cx
+        inc     bx
+        inc     bx
+        and     al, tblPatchMask[bx]    ; Combine masks
+        xor     ah, ah                  ; No right block
+        xor     cx, cx                  ; No center block
+        jmp     @@Exit
+
+@@1:
+        mov     bx, cx
+        and     bx, 03h
+        mov     ah, tblRightMask[bx]
+        shr     cx, 2
+
+@@Exit:
+        ret
+subHorizontalLineInfo   ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXIT.ASM b/16/x/MXIT.ASM
new file mode 100755
index 00000000..c0d9cedd
--- /dev/null
+++ b/16/x/MXIT.ASM
@@ -0,0 +1,98 @@
+;-----------------------------------------------------------
+;
+; MXIT.ASM - Initialization/termination functions
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxInit
+PUBLIC  mxTerm
+
+PUBLIC  mx_VideoSegment
+PUBLIC  mx_CodeSegment
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+DB      'MODEX library - Copyright (c) 1992-1994 Alessandro Scotti'
+
+mx_VideoSegment DW      0A000h
+mx_CodeSegment  DW      SEG MX_TEXT
+
+;-----------------------------------------------------------
+;
+; Initialization.
+;
+; Input:
+;       none
+; Output:
+;       AX      = 0 on success
+;
+mxInit  PROC FAR
+        LOCAL   Result:WORD,            \
+                VideoSeg:WORD,          \
+                CStoDSalias:WORD        = AUTO_SIZE
+        ASSUME  ds:NOTHING
+        .enter  AUTO_SIZE
+        .push   ds, si, es, di
+
+        mov     [Result], -1            ; Assume an error
+        mov     [VideoSeg], 0A000h      ; Real mode video segment
+        mov     [CStoDSalias], cs       ; Real mode data alias for CS
+
+; Check if running in protected mode under DPMI
+        mov     ax, 1686h
+        int     2Fh
+        or      ax, ax
+         jnz    @@1                     ; DPMI not found, continue in real mode
+
+; Get a data alias for CS
+        mov     ax, 000Ah               ; DMPI: create data alias
+        mov     bx, cs
+        int     31h
+         jc     @@Exit                  ; Exit if service failed
+        mov     [CStoDSalias], ax       ; Save data alias for CS
+; Get a protected-mode selector for the video segment
+        mov     ax, 0002h
+        mov     bx, 0A000h              ; Real mode segment of video
+        int     31h                     ; DPMI: get segment selector
+         jc     @@Exit                  ; Exit if service failed
+        mov     [VideoSeg], ax          ; Save protected mode video selector
+
+; Initialize variables
+@@1:
+        mov     ds, [CStoDSalias]
+        ASSUME  ds:MX_TEXT
+        mov     [mx_CodeSegment], ds
+        mov     ax, [VideoSeg]
+        mov     [mx_VideoSegment], ax
+
+; Don't bother with VGA check for now...
+
+        mov     [Result], 0
+
+@@Exit:
+        mov     ax, [Result]
+        .pop    ds, si, es, di
+        .leave
+mxInit  ENDP
+
+;-----------------------------------------------------------
+;
+; Termination.
+;
+; Input:
+;       none
+; Output:
+;       always 0.
+;
+mxTerm  PROC FAR
+        ASSUME  ds:NOTHING
+        xor     ax, ax
+        ret
+mxTerm  ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXLL.ASM b/16/x/MXLL.ASM
new file mode 100755
index 00000000..34fec043
--- /dev/null
+++ b/16/x/MXLL.ASM
@@ -0,0 +1,82 @@
+;-----------------------------------------------------------
+;
+; MXLL.ASM - Load latches
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxLoadLatches
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_VideoSegment : WORD
+
+;-----------------------------------------------------------
+;
+; Loads the specified value into the VGA latches.
+;
+; Input:
+;       BL      = value to load into latches
+; Output:
+;       none
+; Changes:
+;       bit mask register to FFh;
+;       function select register to "move";
+;       write mode to 00h.
+; Note:
+;       this is for internal use only.
+;
+mxLoadLatches   PROC    NEAR
+        ASSUME  ds:NOTHING
+
+        .push   ds, si
+        mov     dx, GDC
+        mov     ax, 0FF08h
+        out     dx, ax                  ; Set bit mask to FFh
+        mov     ax, 0003h
+        out     dx, ax                  ; Set function to "move"
+        mov     ax, 0005h
+        out     dx, ax                  ; Set write mode
+        mov     ax, [mx_VideoSegment]
+        mov     ds, ax
+        mov     si, 0FFFFh
+        mov     bh, 8                   ; BH = write plane mask
+        mov     cx, 3                   ; CX = count = read plane
+; Saves old values and force BL into latches
+@@SetLoop:
+        mov     dx, GDC
+        mov     al, 04h
+        mov     ah, cl
+        out     dx, ax                  ; Select read plane
+        mov     dx, TS
+        mov     al, 02h
+        mov     ah, bh
+        out     dx, ax                  ; Select write plane
+        mov     al, ds:[si]
+        push    ax
+        mov     ds:[si], bl
+        mov     al, ds:[di]             ; Force value into latch
+        shr     bh, 1                   ; Next write plane
+        loop    @@SetLoop
+; Restore previous values
+        mov     cx, 3
+        mov     bh, 8
+        mov     dx, TS
+@@ResetLoop:
+        mov     al, 02h
+        mov     ah, bh
+        out     dx, ax                  ; Select write plane
+        pop     ax
+        mov     ds:[si], al
+        shr     bh, 1                   ; Next write plane
+        loop    @@ResetLoop
+; Exit
+        .pop    ds, si
+        ret
+mxLoadLatches   ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXLN.ASM b/16/x/MXLN.ASM
new file mode 100755
index 00000000..fbc4ab94
--- /dev/null
+++ b/16/x/MXLN.ASM
@@ -0,0 +1,414 @@
+;-----------------------------------------------------------
+;
+; MXLN.ASM - Line function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxLine
+
+MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'
+        ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_BytesPerLine : WORD
+EXTRN   mx_VideoSegment : WORD
+
+EXTRN   mx_ClipX1       : WORD
+EXTRN   mx_ClipY1       : WORD
+EXTRN   mx_ClipX2       : WORD
+EXTRN   mx_ClipY2       : WORD
+
+tblDrawFunc     LABEL   WORD
+        DW      subWidthMove
+        DW      subHeightMove
+        DW      subWidthOp
+        DW      subHeightOp
+
+;-----------------------------------------------------------
+;
+; Draws a line from (X1,Y1) to (X2,Y2) using the Bresenham
+; algorithm.
+;
+; Input:
+;       X1, Y1  = start point
+;       X2, Y2  = end point
+;       Color   = line color
+;       Op      = raster operator
+; Output:
+;       none
+;
+; Note: the end point (X2,Y2) *IS* drawed. I don't like this very much
+; but clipping is much simpler.
+;
+mxLine  PROC FAR
+        ARG     Op:WORD,        \
+                Color:WORD,     \
+                Y2:WORD,        \
+                X2:WORD,        \
+                Y1:WORD,        \
+                X1:WORD         = ARG_SIZE
+        LOCAL   Width:WORD,     \
+                Height:WORD,    \
+                ErrorAdd:WORD,  \
+                ErrorSub:WORD,  \
+                DeltaX:WORD,    \
+                DeltaY:WORD,    \
+                P1:BYTE,        \
+                P2:BYTE,        \
+                WritePlane:BYTE = AUTO_SIZE
+        .enter  AUTO_SIZE
+        .push   ds, si, di
+        ASSUME  ds:NOTHING
+
+        mov     ax, [X1]
+        mov     bx, [Y1]
+        mov     cx, [X2]
+        mov     dx, [Y2]
+        call    subClipLine
+        jc      @@Exit                  ; Line is full clipped
+
+; Get width
+        mov     si, cx
+        xchg    ax, si                  ; SI = X1, AX = X2
+        sub     ax, si
+        jge     @@1
+; Swap points, we want X1 < X2
+        xchg    si, cx                  ; Swap X1 and X2
+        xchg    bx, dx                  ; Swap Y1 and Y2
+        neg     ax
+@@1:
+        mov     [Width], ax
+
+; Get height
+        mov     cx, [mx_BytesPerLine]   ; We don't need X2 anymore
+        mov     ax, dx
+        sub     ax, bx
+        jge     @@2
+        neg     cx                      ; Move from bottom to top
+        neg     ax                      ; Get absolute value of AX
+@@2:
+        mov     [Height], ax
+        mov     [DeltaY], cx
+
+; Get pixel address and write plane
+        mov     ax, bx
+        mul     [mx_BytesPerLine]
+        mov     cx, si                  ; CX = X1
+        shr     si, 1
+        shr     si, 1
+        add     si, ax                  ; SI = pixel offset
+        and     cl, 03h
+        mov     ax, 1102h
+        shl     ah, cl
+        mov     [WritePlane], ah
+        mov     dx, TS
+        out     dx, ax                  ; Set write plane
+        mov     ax, [mx_VideoSegment]
+        mov     ds, ax                  ; DS:SI points to (X1,Y1)
+
+; Select the function to handle the drawing loop
+        xor     bx, bx
+        mov     al, BYTE PTR [Op]
+        cmp     al, OP_MOVE
+        je      @@3
+        and     al, 03h
+        shl     al, 1
+        shl     al, 1
+        shl     al, 1
+        mov     ah, al
+        mov     al, 03h
+        mov     dx, GDC
+        out     dx, ax                  ; Set logical function
+        inc     bx
+        inc     bx
+@@3:
+        mov     ax, [Width]
+        mov     cx, [Height]
+; Horizontal, vertical and diagonal lines are not optimized yet
+        cmp     ax, cx
+        jae     @@4
+        inc     bx
+@@4:
+        shl     bx, 1
+        call    tblDrawFunc[bx]
+
+; Reset logical function if needed
+        cmp     BYTE PTR [Op], OP_MOVE
+        je      @@Exit
+        mov     ax, 0003h
+        mov     dx, GDC
+        out     dx, ax
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds, si, di
+        .leave  ARG_SIZE
+
+;-----------------------------------------------------------
+;
+; Checks the coordinates of a line against the active
+; clip region.
+; Uses a variation of the Cohen-Sutherland algorithm developed
+; by Victor Duvanenko.
+;
+; Input:
+;       AX, BX  = X1, Y1
+;       CX, DX  = X2, Y2
+; Output:
+;       CF      = set if line is full clipped
+;       AX, BX  = clipped X1, Y1
+;       CX, DX  = clipped X2, Y2
+; Note:
+;       destroys SI, DI
+;
+subClipLine     PROC    NEAR
+        mov     di, ax                  ; Copy X1 to DI and free AX
+        mov     si, dx                  ; Copy Y2 to SI and free DX
+; Compute clip codes for point (X2,Y2)=(CX,SI)
+        xor     al, al
+@@P2X1: cmp     cx, [mx_ClipX1]
+        jge     @@P2X2
+        or      al, 1
+@@P2X2: cmp     cx, [mx_ClipX2]
+        jle     @@P2Y1
+        or      al, 2
+@@P2Y1: cmp     si, [mx_ClipY1]
+        jge     @@P2Y2
+        or      al, 4
+@@P2Y2: cmp     si, [mx_ClipY2]
+        jle     @@P2XY
+        or      al, 8
+@@P2XY: mov     [P2], al
+; Compute clip codes for point (X1,Y1)=(DI,BX)
+        xor     al, al
+@@P1X1: cmp     di, [mx_ClipX1]
+        jge     @@P1X2
+        or      al, 1
+@@P1X2: cmp     di, [mx_ClipX2]
+        jle     @@P1Y1
+        or      al, 2
+@@P1Y1: cmp     bx, [mx_ClipY1]
+        jge     @@P1Y2
+        or      al, 4
+@@P1Y2: cmp     bx, [mx_ClipY2]
+        jle     @@P1XY
+        or      al, 8
+@@P1XY: mov     [P1], al
+; Check codes for trivial cases
+        mov     ah, [P2]
+        test    al, ah                  ; Is line invisible?
+        jnz     @@FullClip              ; Yes, exit
+        or      ah, al                  ; Both points clipped?
+        jz      @@Done                  ; Yes, exit
+; Calculate deltas
+        mov     ax, cx
+        sub     ax, di
+        mov     [DeltaX], ax
+        mov     ax, si
+        sub     ax, bx
+        mov     [DeltaY], ax
+        mov     al, [P1]                ; Init clipping code
+; Clipping loop
+@@ClipLoop:
+        test    al, al                  ; Is first point clipped?
+        jnz     @@ClipX1                ; No, continue
+        xchg    cx, di                  ; Swap points...
+        xchg    bx, si
+        xchg    al, [P2]                ; ...and codes
+; Clip left: Y1 = Y1 + DeltaY*(mx_ClipX1-X1)/DeltaX
+@@ClipX1:
+        test    al, 1
+        jz      @@ClipX2
+        mov     ax, [mx_ClipX1]
+        sub     ax, di
+        mov     di, [mx_ClipX1]
+        jmp     @@ClipX1X2
+; Clip right: Y1 = Y1 + DeltaY*(mx_ClipX2-X1)/DeltaX
+@@ClipX2:
+        test    al, 2
+        jz      @@ClipY1
+        mov     ax, [mx_ClipX2]
+        sub     ax, di
+        mov     di, [mx_ClipX2]
+@@ClipX1X2:
+        imul    [DeltaY]
+        idiv    [DeltaX]
+        add     bx, ax
+        mov     al, 8
+        cmp     bx, [mx_ClipY2]
+        jg      @@CheckLoop
+        mov     al, 4
+        cmp     bx, [mx_ClipY1]
+        jl      @@CheckLoop
+        xor     al, al
+        jmp     @@CheckLoop
+; Clip top: X1 = X1 + DeltaX*(mx_ClipY1-Y1)/DeltaY
+@@ClipY1:
+        test    al, 4
+        jz      @@ClipY2
+        mov     ax, [mx_ClipY1]
+        sub     ax, bx
+        mov     bx, [mx_ClipY1]
+        jmp     @@ClipY1Y2
+; Clip bottom: X1 = X1 + DeltaX*(mx_ClipY2-Y1)/DeltaY
+@@ClipY2:
+        mov     ax, [mx_ClipY2]
+        sub     ax, bx
+        mov     bx, [mx_ClipY2]
+@@ClipY1Y2:
+        imul    [DeltaX]
+        idiv    [DeltaY]
+        add     di, ax
+        mov     al, 1
+        cmp     di, [mx_ClipX1]
+        jl      @@CheckLoop
+        mov     al, 2
+        cmp     di, [mx_ClipX2]
+        jg      @@CheckLoop
+        xor     al, al
+@@CheckLoop:
+        mov     ah, [P2]
+        test    al, ah
+        jnz     @@FullClip
+        or      ah, al
+        jnz     @@ClipLoop
+
+@@Done:
+        mov     ax, di
+        mov     dx, si
+        clc
+        ret
+@@FullClip:
+        stc
+        ret
+subClipLine     ENDP
+
+; Called when Width >= Height and Op = OP_MOVE
+subWidthMove    PROC NEAR
+        mov     di, ax
+        neg     di                      ; Initialize error term
+        shl     cx, 1
+        mov     [ErrorAdd], cx
+        mov     cx, ax
+        shl     ax, 1
+        mov     [ErrorSub], ax
+        mov     al, 02h
+        mov     ah, [WritePlane]
+        mov     bl, BYTE PTR [Color]
+        mov     dx, TS
+        inc     cx
+@@Loop:
+        mov     ds:[si], bl
+        dec     cx
+        jz      @@Exit
+        rol     ah, 1
+        adc     si, 0
+        out     dx, ax
+        add     di, [ErrorAdd]
+        jl      @@Loop
+        add     si, [DeltaY]
+        sub     di, [ErrorSub]
+        jmp     @@Loop
+@@Exit:
+        ret
+subWidthMove    ENDP
+
+; Called when Width < Height and Op = OP_MOVE
+subHeightMove   PROC NEAR
+        mov     di, cx
+        neg     di                      ; Initialize error term
+        shl     ax, 1
+        mov     [ErrorAdd], ax
+        mov     ax, cx
+        shl     ax, 1
+        mov     [ErrorSub], ax
+        mov     bl, BYTE PTR [Color]
+        mov     ah, [WritePlane]
+        mov     al, 02h
+        mov     dx, TS
+        inc     cx
+@@Loop:
+        mov     ds:[si], bl
+        dec     cx
+        jz      @@Exit
+        add     si, [DeltaY]
+        add     di, [ErrorAdd]
+        jl      @@Loop
+        rol     ah, 1                   ; Next write plane
+        adc     si, 0                   ; Bump video offset if plane overflows
+        out     dx, ax
+        sub     di, [ErrorSub]          ; Adjust error down
+        jmp     @@Loop
+@@Exit:
+        ret
+subHeightMove   ENDP
+
+; Called when Width >= Height and Op <> OP_MOVE
+subWidthOp      PROC NEAR
+        mov     di, ax
+        neg     di                      ; Initialize error term
+        shl     cx, 1
+        mov     [ErrorAdd], cx
+        mov     cx, ax
+        shl     ax, 1
+        mov     [ErrorSub], ax
+        mov     al, 02h
+        mov     ah, [WritePlane]
+        mov     bl, BYTE PTR [Color]
+        mov     dx, TS
+        inc     cx
+@@Loop:
+        mov     bh, ds:[si]             ; Latch data
+        mov     ds:[si], bl
+        dec     cx
+        jz      @@Exit
+        rol     ah, 1
+        adc     si, 0
+        out     dx, ax
+        add     di, [ErrorAdd]
+        jl      @@Loop
+        add     si, [DeltaY]
+        sub     di, [ErrorSub]
+        jmp     @@Loop
+@@Exit:
+        ret
+subWidthOp      ENDP
+
+; Called when Width < Height and Op <> OP_MOVE
+subHeightOp     PROC NEAR
+        mov     di, cx
+        neg     di                      ; Initialize error term
+        shl     ax, 1
+        mov     [ErrorAdd], ax
+        mov     ax, cx
+        shl     ax, 1
+        mov     [ErrorSub], ax
+        mov     bl, BYTE PTR [Color]
+        mov     ah, [WritePlane]
+        mov     al, 02h
+        mov     dx, TS
+        inc     cx
+@@Loop:
+        mov     bh, ds:[si]
+        mov     ds:[si], bl
+        dec     cx
+        jz      @@Exit
+        add     si, [DeltaY]
+        add     di, [ErrorAdd]
+        jl      @@Loop
+        rol     ah, 1                   ; Next write plane
+        adc     si, 0                   ; Bump video offset if plane overflows
+        out     dx, ax
+        sub     di, [ErrorSub]          ; Adjust error down
+        jmp     @@Loop
+@@Exit:
+        ret
+subHeightOp     ENDP
+
+mxLine  ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXOT.ASM b/16/x/MXOT.ASM
new file mode 100755
index 00000000..62547665
--- /dev/null
+++ b/16/x/MXOT.ASM
@@ -0,0 +1,330 @@
+;-----------------------------------------------------------
+;
+; MXOT.ASM - Text functions
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES                             ; We use the reserved name 'WIDTH'
+INCLUDE MODEX.DEF
+
+PUBLIC  mxOutChar
+PUBLIC  mxOutText
+PUBLIC  mxSetFont
+PUBLIC  mxSetTextColor
+PUBLIC  mxGetTextStep
+PUBLIC  mxSetTextStep
+
+MAX_WIDTH       EQU     16              ; Must be <= 16
+MAX_HEIGHT      EQU     32
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_CodeSegment  : WORD
+EXTRN   mxPutImage      : FAR
+
+; Default 8x8 font
+fnt_Default     LABEL
+        INCLUDE DEFAULT.FNT
+
+; Table of system fonts
+tbl_SystemFont   LABEL   WORD
+        DW      fnt_Default, 8, 8
+
+MX_MAXSYSFONT   EQU     ($-OFFSET tbl_SystemFont) SHR 2
+
+mx_FontPtr      DW      OFFSET fnt_Default, SEG MX_TEXT
+mx_FontWidth    DW      8               ; Font width in pixels
+mx_FontHeight   DW      8               ; Font height in pixels
+mx_FontCharSize DW      8               ; Size in bytes of a font character
+mx_FontColor    DW      00FFh           ; Color: foreground + background*256
+mx_FontOp       DW      OP_MOVE         ; Raster op
+mx_DeltaX       DW      8               ; Horizontal step
+mx_DeltaY       DW      0               ; Vertical step
+
+;-----------------------------------------------------------
+;
+; Sets the current font.
+;
+; Input:
+;       Font    = pointer to font data
+;       Width   = width of font character in pixels
+;       Height  = height of font character in pixels
+; Output:
+;       AX = 0 on success, else invalid parameters
+;
+; Note: when the high word of Font (i.e. the segment) is zero, the low
+;       word is used to select one of the system fonts.
+;
+mxSetFont       PROC FAR
+        ARG     Height:WORD,    \
+                Width:WORD,     \
+                Font:DWORD      = ARG_SIZE
+        .enter  0
+        .push   ds
+
+        mov     ds, [mx_CodeSegment]
+        ASSUME  ds:MX_TEXT
+
+        mov     ax, WORD PTR Font[2]    ; Get font segment
+        test    ax, ax                  ; Null segment?
+        jnz     @@UserFont              ; No, install user font
+
+; Install system font
+        mov     ax, WORD PTR Font[0]    ; Get font number
+        cmp     ax, MX_MAXSYSFONT       ; Check range
+        jb      @@SystemFont
+        xor     ax, ax                  ; Out of range, use default font
+@@SystemFont:
+        shl     ax, 1
+        shl     ax, 1
+        mov     bx, ax
+        mov     ax, tbl_SystemFont[bx]  ; Get font offset
+        mov     WORD PTR mx_FontPtr[0], ax
+        mov     WORD PTR mx_FontPtr[2], cs
+        mov     al, BYTE PTR tbl_SystemFont[bx+2]
+        xor     ah, ah
+        mov     [mx_FontWidth], ax
+        mov     [mx_DeltaX], ax
+        mov     dl, BYTE PTR tbl_SystemFont[bx+3]
+        xor     dh, dh
+        mov     [mx_FontHeight], dx
+        mul     dx
+        mov     [mx_FontCharSize], ax
+        mov     [mx_DeltaX], ax
+        xor     ax, ax
+        mov     [mx_DeltaY], ax
+        jmp     @@Exit
+
+; Install user font
+@@UserFont:
+        mov     ax, -1                  ; Assume an error
+        mov     bx, [Width]
+        cmp     bx, MAX_WIDTH
+        ja      @@Exit                  ; Invalid character width
+        mov     dx, [Height]
+        cmp     dx, MAX_HEIGHT
+        ja      @@Exit                  ; Invalid character height
+        mov     [mx_FontWidth], bx
+        mov     [mx_FontHeight], dx
+        mov     ax, bx
+        add     ax, 7
+        .shr    ax, 3
+        mul     dx
+        mov     [mx_FontCharSize], ax
+        mov     ax, WORD PTR Font[0]
+        mov     WORD PTR mx_FontPtr[0], ax
+        mov     ax, WORD PTR Font[2]
+        mov     WORD PTR mx_FontPtr[2], ax
+        xor     ax, ax
+
+@@Exit:
+        .pop    ds
+        ASSUME  ds:NOTHING
+        .leave  ARG_SIZE
+mxSetFont       ENDP
+
+;-----------------------------------------------------------
+;
+; Sets the text color and raster op.
+;
+; Input:
+;       Color   = text color (foreground + background*256)
+;       Op      = raster op
+; Output:
+;       none
+;
+mxSetTextColor  PROC FAR
+        ARG     Op:WORD,        \
+                Color:WORD      = ARG_SIZE
+        .enter  0
+        .push   ds
+
+        mov     ds, [mx_CodeSegment]
+        ASSUME  ds:MX_TEXT
+
+        mov     ax, [Color]
+        mov     [mx_FontColor], ax
+        mov     ax, [Op]
+        mov     [mx_FontOp], ax
+
+        xor     ax, ax
+        .pop    ds
+        ASSUME  ds:NOTHING
+        .leave  ARG_SIZE
+mxSetTextColor  ENDP
+
+;-----------------------------------------------------------
+;
+; Writes a character using the current font and attributes.
+;
+; Input:
+;       X, Y    = video coordinates
+;       C       = character to print
+; Output:
+;       none
+;
+mxOutChar       PROC FAR
+        ARG     C:BYTE:2,       \
+                Y:WORD,         \
+                X:WORD          = ARG_SIZE
+        LOCAL   Image:BYTE:MAX_WIDTH*MAX_HEIGHT,        \
+                Count:WORD                              = AUTO_SIZE
+        .enter  AUTO_SIZE
+        .push   ds, si, es, di
+        ASSUME  ds:NOTHING
+
+; Gets the pointer to font data for the selected character
+        lds     si, DWORD PTR [mx_FontPtr]
+        mov     al, [C]
+        xor     ah, ah
+        mul     [mx_FontCharSize]       ; Offset into font
+        add     si, ax                  ; DS:SI -> font data for character
+
+; Converts font data into a 256-color linear image
+        mov     ax, ss
+        mov     es, ax
+        lea     di, [Image]
+        mov     dx, [mx_FontColor]
+        mov     ax, [mx_FontHeight]
+        mov     [Count], ax
+@@HeightLoop:
+        mov     cx, [mx_FontWidth]
+        mov     bh, ds:[si]
+        inc     si                      ; Get a byte from font data
+        cmp     cx, 8
+        jbe     @@WidthLoop             ; Ok for width <= 8
+        mov     bl, ds:[si]             ; Get another byte
+        inc     si
+@@WidthLoop:
+        mov     al, dl                  ; Assume foreground color
+        shl     bx, 1                   ; Is font bit set?
+        jc      @@1                     ; Yes, foreground is just great
+        mov     al, dh                  ; Get background color
+@@1:
+        mov     es:[di], al             ; Put pixel into image
+        inc     di
+        dec     cx
+        jnz     @@WidthLoop
+        dec     [Count]
+        jnz     @@HeightLoop
+
+; Now pass image to mx_PutImage
+        lea     ax, [Image]
+        push    es
+        push    ax                      ; Pointer to image
+        push    [X]
+        push    [Y]                     ; Image coordinates
+        push    [mx_FontWidth]
+        push    [mx_FontHeight]         ; Image size
+        push    [mx_FontOp]             ; Raster op
+        call    mxPutImage              ; Write character
+
+        xor     ax, ax
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxOutChar       ENDP
+
+;-----------------------------------------------------------
+;
+; Writes a string at the coordinates specified.
+;
+; Input:
+;       X, Y    = text coordinates
+;       S       = pointer to ASCIIZ string
+; Output:
+;       none
+;
+mxOutText       PROC FAR
+        ARG     S:DWORD,        \
+                Y:WORD,         \
+                X:WORD          = ARG_SIZE
+        .enter  0
+        .push   ds, si
+        ASSUME  ds:NOTHING
+
+        lds     si, [S]
+@@Loop:
+        mov     al, ds:[si]
+        test    al, al                  ; End of string?
+        jz      @@Exit                  ; Yes, exit
+        inc     si
+        push    [X]                     ; Display character
+        push    [Y]
+        push    ax
+        call    mxOutChar
+        mov     ax, [mx_DeltaX]
+        add     [X], ax                 ; Bump X coordinate
+        mov     ax, [mx_DeltaY]
+        add     [Y], ax                 ; Bump Y coordinate
+        dec     [Count]
+        jnz     @@Loop
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds, si
+        .leave  ARG_SIZE
+        ret
+mxOutText       ENDP
+
+;-----------------------------------------------------------
+;
+; Sets the distance between characters.
+;
+; Input:
+;       DeltaX  = horizontal distance in pixels
+;       DeltaY  = vertical distance in pixels
+; Output:
+;       none
+;
+; Note: this function may be used to set the text direction.
+;
+mxSetTextStep   PROC FAR
+        ARG     DeltaY:WORD,    \
+                DeltaX:WORD     = ARG_SIZE
+        .enter  0
+        .push   ds
+
+        mov     ds, [mx_CodeSegment]
+        ASSUME  ds:MX_TEXT
+
+        mov     ax, [DeltaX]
+        mov     [mx_DeltaX], ax
+        mov     ax, [DeltaY]
+        mov     [mx_DeltaY], ax
+
+        .pop    ds
+        .leave  ARG_SIZE
+mxSetTextStep   ENDP
+
+;-----------------------------------------------------------
+;
+; Gets the current distance between characters.
+;
+; Input:
+;       DeltaX  = pointer to horizontal distance in pixels (integer)
+;       DeltaY  = pointer to vertical distance in pixels (integer)
+; Output:
+;       none
+;
+mxGetTextStep   PROC FAR
+        ARG     DeltaY:DWORD,   \
+                DeltaX:DWORD    = ARG_SIZE
+        .enter  0
+        .push   ds, si
+        ASSUME  ds:NOTHING
+
+        mov     ax, [mx_DeltaX]
+        lds     si, [DeltaX]
+        mov     ds:[si], ax
+        mov     ax, [mx_DeltaY]
+        lds     si, [DeltaY]
+        mov     ds:[si], ax
+
+        .pop    ds, si
+        .leave  ARG_SIZE
+mxGetTextStep   ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXPB.ASM b/16/x/MXPB.ASM
new file mode 100755
index 00000000..8c6aa449
--- /dev/null
+++ b/16/x/MXPB.ASM
@@ -0,0 +1,22 @@
+;-----------------------------------------------------------
+;
+; MXPB.ASM - Scan buffer for convex polygon fills
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mx_ScanBuffer
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+ALIGN   4
+
+mx_ScanBuffer   LABEL
+        DW      POLYSCANBUFSIZE DUP(?)
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXPF.ASM b/16/x/MXPF.ASM
new file mode 100755
index 00000000..db0da898
--- /dev/null
+++ b/16/x/MXPF.ASM
@@ -0,0 +1,420 @@
+;-----------------------------------------------------------
+;
+; MXPG.ASM - Convex polygon fill
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxFillPoly
+
+;-----------------------------------------------------------
+;
+; "Local" definitions
+;
+TPOINT  STRUC
+        X       DW      ?
+        Y       DW      ?
+TPOINT  ENDS
+
+; Do NOT change order!
+TSCAN   STRUC
+        Y1      DW      ?
+        Y2      DW      ?
+TSCAN   ENDS
+
+MAXSCANCOLUMNS  EQU     POLYSCANBUFSIZE / SIZE TSCAN
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_CodeSegment  : WORD
+EXTRN   mx_BytesPerLine : WORD
+EXTRN   mx_ClipX1       : WORD
+EXTRN   mx_ClipY1       : WORD
+EXTRN   mx_ClipX2       : WORD
+EXTRN   mx_ClipY2       : WORD
+EXTRN   mx_ScanBuffer   : NEAR
+
+;-----------------------------------------------------------
+;
+; Scans an edge using the DDA (digital differential analyzer) algorithm.
+;
+; Input:
+;       DS:BX   = pointer to start point (X1, Y1)
+;       DS:SI   = pointer to end point (X2, Y2)
+;       ES:DI   = pointer to edge buffer
+; Output:
+;       ES:DI   = updated pointer to edge buffer
+; Notes:
+;       must preserve DS:SI.
+;
+subScan         PROC NEAR
+        mov     cx, ds:[si].X
+        sub     cx, ds:[bx].X           ; Get width
+        jg      @@1
+        ret
+@@1:
+        push    bp                      ; Save BP
+
+        mov     ax, ds:[si].Y
+        mov     bx, ds:[bx].Y
+        sub     ax, bx                  ; Get height
+        jg      @@T2B                   ; Scan top to bottom
+        jl      @@B2T                   ; Scan bottom to top
+
+; Special case: vertical line
+        mov     ax, bx
+@@V:
+        mov     es:[di].Y1, ax
+        add     di, SIZE TSCAN
+        dec     cx
+	jnz	@@V
+        jmp     @@Exit
+
+; Scan top to bottom
+@@T2B:
+        cwd
+        div     cx
+        mov     bp, ax
+        xor     ax, ax
+        div     cx
+        xchg    ax, bx                  ; BP:BX = fixed 16:16 step
+        mov     dx, 8000h
+@@T2BLoop:
+        mov     es:[di].Y1, ax
+        add     di, SIZE TSCAN
+        add     dx, bx
+        adc     ax, bp
+        dec     cx
+        jnz     @@T2BLoop
+        jmp     @@Exit
+
+; Scan bottom to top
+@@B2T:
+        neg     ax
+        cwd
+        div     cx
+        mov     bp, ax
+        xor     ax, ax
+        div     cx
+        xchg    ax, bx
+        mov     dx, 8000h
+@@B2TLoop:
+        mov     es:[di].Y1, ax
+        add     di, SIZE TSCAN
+        sub     dx, bx
+        sbb     ax, bp
+        dec     cx
+        jnz     @@B2TLoop
+
+@@Exit:
+        pop     bp                      ; Restore BP
+        ret
+subScan         ENDP
+
+;-----------------------------------------------------------
+;
+; Fills a convex polygon with the specified color.
+;
+; Input:
+;       Count   = number of vertexes
+;       Map     = indexes of points and colors (integer)
+;       Points  = array of points (integer X, Y coordinates)
+;       Color   = base color
+; Output:
+;       none
+; Notes:
+;       vertexes must be in counterclockwise order, arrays are 0-based.
+;
+mxFillPoly      PROC FAR
+        ARG     Color:WORD,     \
+                Points:DWORD,   \
+                Map:DWORD,      \
+                Count:WORD      = ARG_SIZE
+        LOCAL   WritePlane:BYTE:2,      \
+                ScanOffsetT:WORD,       \
+                ScanOffsetB:WORD,       \
+                ScanCount:WORD,         \
+                Holder:WORD,            \
+                Height:WORD,            \
+                MinIdxT:WORD,           \
+                MinIdxB:WORD,           \
+                MaxIdx:WORD,            \
+                Width:WORD,             \
+                BoxX1:WORD,             \
+                BoxY1:WORD,             \
+                BoxX2:WORD,             \
+                BoxY2::WORD             = AUTO_SIZE
+        .enter  AUTO_SIZE
+        .push   ds, si, es, di
+        ASSUME  ds:NOTHING
+
+; Check that at least three vertexes are specified
+        mov     cx, [Count]
+        cmp     cx, 3
+        jb      @@Exit
+
+;------------------------------
+; Find bounding box for polygon
+        les     di, [Map]
+        lds     si, [Points]            ; Pointer to vertex array
+        mov     [BoxX1], 32767
+        mov     [BoxX2], -32768
+        mov     [BoxY1], 32767
+        mov     [BoxY2], -32768
+
+        xor     dx, dx
+@@MinMaxLoop:
+        mov     bx, es:[di]             ; Get index of vertex
+        .shl    bx, 2                   ; Get offset in point array
+        add     bx, si
+
+; Check X range
+@@CheckMinX:
+        mov     ax, ds:[bx].X           ; Get X coordinate
+        cmp     ax, [BoxX1]
+        jge     @@CheckMaxX
+        mov     [BoxX1], ax
+        mov     [MinIdxT], dx
+        mov     [MinIdxB], dx
+@@CheckMaxX:
+        cmp     ax, [BoxX2]
+        jle     @@CheckMinY
+        mov     [BoxX2], ax
+        mov     [MaxIdx], dx
+
+; Check Y range
+@@CheckMinY:
+        mov     ax, ds:[bx].Y
+        cmp     ax, [BoxY1]
+        jge     @@CheckMaxY
+        mov     [BoxY1], ax
+@@CheckMaxY:
+        cmp     ax, [BoxY2]
+        jle     @@CheckDone
+        mov     [BoxY2], ax
+
+; Repeat thru all points
+@@CheckDone:
+        inc     di                      ; Next map entry
+        inc     dx
+        inc     di
+        inc     dx
+        dec     cx
+        jnz     @@MinMaxLoop
+
+;---------------------------------
+; Check if polygon is full clipped
+        mov     ax, [BoxX2]
+        cmp     ax, [mx_ClipX1]         ; Is poly full clipped?
+        jl      @@Exit
+        mov     bx, [BoxX1]
+        cmp     bx, [mx_ClipX2]         ; Is poly full clipped?
+        jg      @@Exit
+        sub     ax, bx                  ; Get width
+        jle     @@Exit                  ; Exit if not positive
+        mov     ax, [BoxY2]
+        cmp     ax, [mx_ClipY1]         ; Is poly full clipped?
+        jl      @@Exit
+        mov     bx, [BoxY1]
+        cmp     bx, [mx_ClipY2]         ; Is poly full clipped?
+        jg      @@Exit
+        sub     ax, bx                  ; Get height
+        jle     @@Exit                  ; Exit if not positive
+
+        dec     [Count]
+        shl     [Count], 1              ; We'll work with word offsets
+        mov     es, [mx_CodeSegment]
+
+;--------------
+; Scan top edge
+        mov     ax, OFFSET mx_ScanBuffer
+        mov     [ScanOffsetT], ax
+        mov     si, [MinIdxT]           ; Offset of bottom point index
+@@STLoop:
+        lds     bx, [Map]               ; DS:BX -> map table
+        mov     di, ds:[bx+si]          ; Index of top point #1
+        dec     si                      ; Next point
+        dec     si
+        test    si, si
+        jnl     @@ST1
+        mov     si, [Count]
+@@ST1:
+        mov     [MinIdxT], si           ; Save new index of top point
+        mov     si, ds:[bx+si]          ; Get index of top point #2
+        .shl    di, 2                   ; Convert indexes to offsets
+        .shl    si, 2
+        lds     bx, [Points]            ; DS:BX -> point array
+        add     si, bx                  ; DS:SI -> top point #2
+        add     bx, di                  ; DS:BX -> top point #1
+        mov     di, [ScanOffsetT]
+        call    subScan                 ; Scan edge
+        mov     [ScanOffsetT], di
+        mov     si, [MinIdxT]
+        cmp     si, [MaxIdx]            ; End of edge?
+        jne     @@STLoop                ; No, continue
+
+;-----------------
+; Scan bottom edge
+        mov     ax, OFFSET mx_ScanBuffer + OFFSET Y2
+        mov     [ScanOffsetB], ax
+        mov     si, [MinIdxB]           ; Offset of bottom point index
+@@SBLoop:
+        lds     bx, [Map]               ; DS:BX -> map table
+        mov     di, ds:[bx+si]          ; Index of bottom point #1
+        inc     si                      ; Next bottom point
+        inc     si
+        cmp     si, [Count]
+        jbe     @@SB1
+        xor     si, si
+@@SB1:
+        mov     [MinIdxB], si           ; Save new index of bottom point
+        mov     si, ds:[bx+si]          ; Get index of bottom point #2
+        .shl    di, 2                   ; Convert indexes to offsets
+        .shl    si, 2
+        lds     bx, [Points]            ; DS:BX -> point array
+        add     si, bx                  ; DS:SI -> top point #2
+        add     bx, di                  ; DS:BX -> top point #1
+        mov     di, [ScanOffsetB]
+        call    subScan                 ; Scan edge
+        mov     [ScanOffsetB], di
+        mov     si, [MinIdxB]
+        cmp     si, [MaxIdx]            ; End of edge?
+        jne     @@SBLoop                ; No, continue
+
+;--------------------
+; Clip left and right
+        mov     si, OFFSET mx_ScanBuffer
+        mov     ax, [BoxX1]
+        mov     cx, [BoxX2]
+        sub     cx, ax                  ; CX = bounding box width
+        mov     bx, [mx_ClipX1]
+        sub     bx, ax
+        jle     @@ClipL1                ; No need to clip left
+        sub     cx, bx                  ; Update width
+        add     ax, bx                  ; BoxX1 = mx_ClipX1
+        mov     [BoxX1], ax
+        .shl    bx, 2                   ; Warning!!! This is an hand-coded
+        add     si, bx                  ; multiply by the size of TSCAN
+@@ClipL1:
+        mov     bx, ax
+        add     bx, cx                  ; Last scan column
+        sub     bx, [mx_ClipX2]
+        jle     @@ClipL2                ; No need to clip right
+        sub     cx, bx                  ; Clip right
+@@ClipL2:
+        test    cx, cx                  ; Is clipped width positive?
+        jle     @@Exit                  ; No, exit
+        mov     [ScanCount], cx         ; Save number of columns to draw
+        mov     [ScanOffsetT], si       ; Remember offset of (clipped) buffer
+        mov     ds, [mx_CodeSegment]    ; DS:SI -> scan buffer
+
+;------------------------------
+; Check if Y clipping is needed
+        mov     ax, [BoxY1]
+        cmp     ax, [mx_ClipY1]
+        jl      @@ClipTB                ; Need to clip top
+        mov     ax, [BoxY2]
+        cmp     ax, [mx_ClipY2]
+        jg      @@ClipTB                ; Need to clip bottom
+        jmp     @@ClipYExit             ; Skip Y clipping
+
+;--------------------
+; Clip top and bottom
+@@ClipTB:
+        mov     di, cx                  ; DI = scan count
+        inc     di                      ; Increment count for pre-loop test
+        sub     si, SIZE TSCAN
+@@ClipYLoop:
+        dec     di                      ; Any column left?
+        jz      @@ClipYExit             ; No, exit
+        add     si, SIZE TSCAN
+        mov     ax, ds:[si].Y1          ; Y1
+        mov     cx, ds:[si].Y2          ; Y2
+        mov     dx, [mx_ClipY2]
+        cmp     ax, dx                  ; Full clipped?
+        jg      @@ClipYClip             ; Yes, skip this column
+        cmp     cx, dx                  ; Need to clip bottom?
+        jle     @@ClipY1                ; No, continue
+; Clip bottom
+        mov     ds:[si].Y2, dx
+        mov     bx, cx
+        sub     bx, dx                  ; Clip distance
+        sub     cx, ax                  ; Height
+        jle     @@ClipYClip
+        mov     cx, ds:[si].Y2
+@@ClipY1:
+        mov     dx, [mx_ClipY1]
+        cmp     cx, dx                  ; Full top clipped?
+        jl      @@ClipYClip             ; Yes, skip
+        sub     cx, ax                  ; Get height
+        jle     @@ClipYClip             ; Skip if not positive
+        cmp     ax, dx                  ; Need to clip top?
+        jge     @@ClipYLoop             ; No, continue
+; Clip top
+        mov     ds:[si].Y1, dx          ; Y1 = mx_ClipY1
+        sub     dx, ax                  ; DX = number of pixels clipped
+        cmp     cx, dx
+        ja      @@ClipYLoop             ; Not clipped, continue
+@@ClipYClip:
+        mov     ds:[si].Y1, -1          ; Mark column as clipped
+        jmp     @@ClipYLoop
+@@ClipYExit:
+
+;-------------
+; Draw columns
+        mov     es, [mx_VideoSegment]
+        mov     si, [ScanOffsetT]
+        mov     cl, BYTE PTR [BoxX1]    ; Init write plane
+        and     cl, 03h
+        mov     al, 11h
+        shl     al, cl
+        mov     [WritePlane], al
+        .shr    [BoxX1], 2
+@@DrawLoop:
+        mov     ax, ds:[si].Y1
+        test    ax, ax                  ; Was column clipped?
+        js      @@DrawNext              ; Yes, skip
+        mov     cx, ds:[si].Y2
+        sub     cx, ax                  ; CX = height
+        jle     @@DrawNext
+        mul     [mx_BytesPerLine]       ; Get pixel address
+        add     ax, [BoxX1]
+        mov     di, ax
+        mov     ah, [WritePlane]
+        mov     dx, TS
+        mov     al, 02h
+        out     dx, ax
+        mov     ax, [Color]
+        mov     dx, [mx_BytesPerLine]
+        shr     cx, 1
+        jnc     @@FillScan
+        mov     es:[di], al
+        add     di, dx
+        jcxz    @@DrawNext
+@@FillScan:
+        mov     es:[di], al
+        add     di, dx
+        mov     es:[di], al
+        add     di, dx
+        dec     cx
+        jnz     @@FillScan
+@@DrawNext:
+        rol     [WritePlane], 1
+        adc     [BoxX1], 0              ; Bump pointer to video memory if needed
+        add     si, SIZE TSCAN
+        dec     [ScanCount]
+        jnz     @@DrawLoop
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxFillPoly      ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXPG.ASM b/16/x/MXPG.ASM
new file mode 100755
index 00000000..caa7cf1b
--- /dev/null
+++ b/16/x/MXPG.ASM
@@ -0,0 +1,589 @@
+;-----------------------------------------------------------
+;
+; MXPG.ASM - Convex polygon fill with Gouraud shading
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxGouraudPoly
+
+;-----------------------------------------------------------
+;
+; "Local" definitions
+;
+TPOINT  STRUC
+        X       DW      ?
+        Y       DW      ?
+TPOINT  ENDS
+
+; Do NOT change order!
+TSCAN   STRUC
+        Y1      DW      ?
+        E1      DB      ?
+        C1      DB      ?
+        Y2      DW      ?
+        E2      DB      ?
+        C2      DB      ?
+TSCAN   ENDS
+
+MAXSCANCOLUMNS  EQU     POLYSCANBUFSIZE / SIZE TSCAN
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_CodeSegment  : WORD
+EXTRN   mx_BytesPerLine : WORD
+EXTRN   mx_ClipX1       : WORD
+EXTRN   mx_ClipY1       : WORD
+EXTRN   mx_ClipX2       : WORD
+EXTRN   mx_ClipY2       : WORD
+EXTRN   mx_ScanBuffer   : NEAR
+
+;-----------------------------------------------------------
+;
+; Scans an edge using the DDA (digital differential analyzer) algorithm.
+; Also interpolates color for shading.
+;
+; Input:
+;       DS:BX   = pointer to start point (X1, Y1)
+;       DS:SI   = pointer to end point (X2, Y2)
+;       ES:DI   = pointer to edge buffer
+;       DX      = start color
+;       AX      = end color
+; Output:
+;       ES:DI   = updated pointer to edge buffer
+; Notes:
+;       must preserve DS:SI.
+;
+subScan         PROC NEAR
+        mov     cx, ds:[si].X
+        sub     cx, ds:[bx].X           ; Get width
+        jg      @@1
+        ret
+@@1:
+        push    bp                      ; Save BP
+        push    di                      ; Save scan info offset
+        push    cx                      ; Save height
+        push    ax                      ; Save colors
+        push    dx
+
+        mov     ax, ds:[si].Y
+        mov     bx, ds:[bx].Y
+        sub     ax, bx                  ; Get height
+        jg      @@T2B                   ; Scan top to bottom
+        jl      @@B2T                   ; Scan bottom to top
+
+; Special case: vertical line
+        mov     ax, bx
+@@V:
+        mov     es:[di].Y1, ax
+        add     di, SIZE TSCAN
+        dec     cx
+	jnz	@@V
+        jmp     @@GetColorInfo
+
+; Scan top to bottom
+@@T2B:
+        cwd
+        div     cx
+        mov     bp, ax
+        xor     ax, ax
+        div     cx
+        xchg    ax, bx                  ; BP:BX = fixed 16:16 step
+        mov     dx, 8000h
+@@T2BLoop:
+        mov     es:[di].Y1, ax
+        add     di, SIZE TSCAN
+        add     dx, bx
+        adc     ax, bp
+        dec     cx
+        jnz     @@T2BLoop
+        jmp     @@GetColorInfo
+
+; Scan bottom to top
+@@B2T:
+        neg     ax
+        cwd
+        div     cx
+        mov     bp, ax
+        xor     ax, ax
+        div     cx
+        xchg    ax, bx
+        mov     dx, 8000h
+@@B2TLoop:
+        mov     es:[di].Y1, ax
+        add     di, SIZE TSCAN
+        sub     dx, bx
+        sbb     ax, bp
+        dec     cx
+        jnz     @@B2TLoop
+
+; Now get the color info
+@@GetColorInfo:
+        pop     bx                      ; Restore colors
+        pop     ax
+        pop     cx                      ; Height
+        pop     di                      ; ES:DI -> scan info
+
+        sub     ax, bx                  ; Get color range
+        jg      @@CL2R
+        jl      @@CR2L
+
+; Special case: same color
+        mov     ah, bl
+        mov     al, 80h
+@@CV:
+        mov     WORD PTR es:[di].E1, ax
+        add     di, SIZE TSCAN
+        dec     cx
+        jnz     @@CV
+        jmp     @@Exit
+
+; Scan left to right
+@@CL2R:
+        cwd
+        div     cx
+        mov     bp, ax
+        xor     ax, ax
+        div     cx
+        xchg    ax, bx                  ; BP:BX = fixed 16:16 step
+        mov     dx, 8000h
+@@CL2RLoop:
+        mov     es:[di].C1, al
+        mov     es:[di].E1, dh
+        add     di, SIZE TSCAN
+        add     dx, bx
+        adc     ax, bp
+        dec     cx
+        jnz     @@CL2RLoop
+        jmp     @@Exit
+
+; Scan right to left
+@@CR2L:
+        neg     ax
+        cwd
+        div     cx
+        mov     bp, ax
+        xor     ax, ax
+        div     cx
+        xchg    ax, bx
+        mov     dx, 8000h
+
+@@CR2LLoop:
+        mov     es:[di].C1, al
+        mov     es:[di].E1, dh
+        add     di, SIZE TSCAN
+        sub     dx, bx
+        sbb     ax, bp
+        dec     cx
+        jnz     @@CR2LLoop
+
+@@Exit:
+        pop     bp
+        ret
+subScan         ENDP
+
+;-----------------------------------------------------------
+;
+; Fills a scan column.
+;
+; Input:
+;       DS:SI   = current TSCAN
+;       ES:DI   = address of top pixel
+;       CX      = number of pixels to write
+;       DX      = base color
+; Output:
+;       none
+;
+subFillScan     PROC NEAR
+        mov     ax, WORD PTR ds:[si].E2
+        mov     bx, WORD PTR ds:[si].E1
+        cmp     ah, bh
+        jg      @@L2R                   ; Color increases
+        jl      @@R2L                   ; Color decreases
+
+; Special case: color doesn't change
+        add     ax, dx
+        mov     dx, [mx_BytesPerLine]
+@@V:
+        mov     es:[di], ah
+        add     di, dx
+        dec     cx
+        jnz     @@V
+        ret
+
+; Color increases
+@@L2R:
+        .push   bp, si
+        mov     si, bx
+        add     si, dx                  ; Relocate color
+        sub     ax, bx
+        xor     dx, dx
+        div     cx
+        mov     bp, ax                  ; BP = color step, integer part
+        xor     ax, ax
+        div     cx
+        mov     bx, ax                  ; BX = color step, fractional part
+        mov     dx, 8000h
+        mov     ax, [mx_BytesPerLine]
+        xchg    si, ax
+@@L2RLoop:
+        mov     es:[di], ah
+        add     dx, bx
+        adc     ax, bp
+        add     di, si
+        dec     cx
+        jnz     @@L2RLoop
+        .pop    bp, si
+        ret
+
+; Color decreases
+@@R2L:
+        .push   bp, si
+        mov     si, bx
+        add     si, dx                  ; Relocate color
+        sub     ax, bx
+        neg     ax
+        xor     dx, dx
+        div     cx
+        mov     bp, ax                  ; BP = color step, integer part
+        xor     ax, ax
+        div     cx
+        mov     bx, ax                  ; BX = color step, fractional part
+        mov     dx, 8000h
+        mov     ax, [mx_BytesPerLine]
+        xchg    si, ax
+@@R2LLoop:
+        mov     es:[di], ah
+        sub     dx, bx
+        sbb     ax, bp
+        add     di, si
+        dec     cx
+        jnz     @@R2LLoop
+        .pop    bp, si
+        ret
+subFillScan     ENDP
+
+;-----------------------------------------------------------
+;
+; Fills a convex polygon with the specified color.
+; Interpolates pixel colors using the Gouraud algorithm.
+;
+; Input:
+;       Count   = number of vertexes
+;       Map     = indexes of points and colors (integer)
+;       Points  = array of points (integer X, Y coordinates)
+;       Colors  = array of colors (integer)
+;       Color   = base color
+; Output:
+;       none
+; Notes:
+;       vertexes must be in counterclockwise order, arrays are 0-based.
+;
+mxGouraudPoly	PROC FAR
+        ARG     Color:WORD,     \
+                Colors:DWORD,   \
+                Points:DWORD,   \
+                Map:DWORD,      \
+                Count:WORD      = ARG_SIZE
+        LOCAL   WritePlane:BYTE:2,      \
+                ScanOffsetT:WORD,       \
+                ScanOffsetB:WORD,       \
+                ScanCount:WORD,         \
+                Holder:WORD,            \
+                Height:WORD,            \
+                MinIdxT:WORD,           \
+                MinIdxB:WORD,           \
+                MaxIdx:WORD,            \
+                Width:WORD,             \
+                BoxX1:WORD,             \
+                BoxY1:WORD,             \
+                BoxX2:WORD,             \
+                BoxY2::WORD             = AUTO_SIZE
+        .enter  AUTO_SIZE
+        .push   ds, si, es, di
+        ASSUME  ds:NOTHING
+
+; Check that at least three vertexes are specified
+        mov     cx, [Count]
+        cmp     cx, 3
+        jb      @@Exit
+
+;------------------------------
+; Find bounding box for polygon
+        les     di, [Map]
+        lds     si, [Points]            ; Pointer to vertex array
+        mov     [BoxX1], 32767
+        mov     [BoxX2], -32768
+        mov     [BoxY1], 32767
+        mov     [BoxY2], -32768
+
+        xor     dx, dx
+@@MinMaxLoop:
+        mov     bx, es:[di]             ; Get index of vertex
+        .shl    bx, 2                   ; Get offset in point array
+        add     bx, si
+
+; Check X range
+@@CheckMinX:
+        mov     ax, ds:[bx].X           ; Get X coordinate
+        cmp     ax, [BoxX1]
+        jge     @@CheckMaxX
+        mov     [BoxX1], ax
+        mov     [MinIdxT], dx
+        mov     [MinIdxB], dx
+@@CheckMaxX:
+        cmp     ax, [BoxX2]
+        jle     @@CheckMinY
+        mov     [BoxX2], ax
+        mov     [MaxIdx], dx
+
+; Check Y range
+@@CheckMinY:
+        mov     ax, ds:[bx].Y
+        cmp     ax, [BoxY1]
+        jge     @@CheckMaxY
+        mov     [BoxY1], ax
+@@CheckMaxY:
+        cmp     ax, [BoxY2]
+        jle     @@CheckDone
+        mov     [BoxY2], ax
+
+; Repeat thru all points
+@@CheckDone:
+        inc     di                      ; Next map entry
+        inc     di
+        inc     dx
+        inc     dx
+        dec     cx
+        jnz     @@MinMaxLoop
+
+;---------------------------------
+; Check if polygon is full clipped
+        mov     ax, [BoxX2]
+        cmp     ax, [mx_ClipX1]         ; Is poly full clipped?
+        jl      @@Exit
+        mov     bx, [BoxX1]
+        cmp     bx, [mx_ClipX2]         ; Is poly full clipped?
+        jg      @@Exit
+        sub     ax, bx                  ; Get width
+        jle     @@Exit                  ; Exit if not positive
+        mov     ax, [BoxY2]
+        cmp     ax, [mx_ClipY1]         ; Is poly full clipped?
+        jl      @@Exit
+        mov     bx, [BoxY1]
+        cmp     bx, [mx_ClipY2]         ; Is poly full clipped?
+        jg      @@Exit
+        sub     ax, bx                  ; Get height
+        jle     @@Exit                  ; Exit if not positive
+
+        dec     [Count]
+        shl     [Count], 1              ; We'll work with word offsets
+        mov     es, [mx_CodeSegment]
+
+;--------------
+; Scan top edge
+        mov     ax, OFFSET mx_ScanBuffer
+        mov     [ScanOffsetT], ax
+        mov     si, [MinIdxT]           ; Offset of bottom point index
+@@STLoop:
+        lds     bx, [Map]               ; DS:BX -> map table
+        mov     di, ds:[bx+si]          ; Index of top point #1
+        dec     si                      ; Next point
+        dec     si
+        test    si, si
+        jnl     @@ST1
+        mov     si, [Count]
+@@ST1:
+        mov     [MinIdxT], si           ; Save new index of top point
+        mov     si, ds:[bx+si]          ; Get index of top point #2
+        lds     bx, [Colors]            ; Get pointer to color array
+        shl     di, 1                   ; Convert indexes to offsets
+        shl     si, 1
+        mov     ax, ds:[bx+si]          ; Get colors
+        mov     dx, ds:[bx+di]
+        lds     bx, [Points]            ; DS:BX -> point array
+        shl     si, 1
+        shl     di, 1
+        add     si, bx                  ; DS:SI -> top point #2
+        add     bx, di                  ; DS:BX -> top point #1
+        mov     di, [ScanOffsetT]
+        call    subScan                 ; Scan edge
+        mov     [ScanOffsetT], di
+        mov     si, [MinIdxT]
+        cmp     si, [MaxIdx]            ; End of edge?
+        jne     @@STLoop                ; No, continue
+
+;-----------------
+; Scan bottom edge
+        mov     ax, OFFSET mx_ScanBuffer + OFFSET Y2
+        mov     [ScanOffsetB], ax
+        mov     si, [MinIdxB]           ; Offset of bottom point index
+@@SBLoop:
+        lds     bx, [Map]               ; DS:BX -> map table
+        mov     di, ds:[bx+si]          ; Index of bottom point #1
+        inc     si                      ; Next bottom point
+        inc     si
+        cmp     si, [Count]
+        jbe     @@SB1
+        xor     si, si
+@@SB1:
+        mov     [MinIdxB], si           ; Save new index of bottom point
+        mov     si, ds:[bx+si]          ; Get index of bottom point #2
+        lds     bx, [Colors]            ; Get pointer to color array
+        shl     di, 1                   ; Convert indexes to offsets
+        shl     si, 1
+        mov     ax, ds:[bx+si]          ; Get colors
+        mov     dx, ds:[bx+di]
+        lds     bx, [Points]            ; DS:BX -> point array
+        shl     si, 1
+        shl     di, 1
+        add     si, bx                  ; DS:SI -> top point #2
+        add     bx, di                  ; DS:BX -> top point #1
+        mov     di, [ScanOffsetB]
+        call    subScan                 ; Scan edge
+        mov     [ScanOffsetB], di
+        mov     si, [MinIdxB]
+        cmp     si, [MaxIdx]            ; End of edge?
+        jne     @@SBLoop                ; No, continue
+
+;--------------------
+; Clip left and right
+        mov     si, OFFSET mx_ScanBuffer
+        mov     ax, [BoxX1]
+        mov     cx, [BoxX2]
+        sub     cx, ax                  ; CX = bounding box width
+        mov     bx, [mx_ClipX1]
+        sub     bx, ax
+        jle     @@ClipL1                ; No need to clip left
+        sub     cx, bx                  ; Update width
+        add     ax, bx                  ; BoxX1 = mx_ClipX1
+        mov     [BoxX1], ax
+        .shl    bx, 3                   ; Warning!!! This is an hand-coded
+        add     si, bx                  ; multiply by the size of TSCAN
+@@ClipL1:
+        mov     bx, ax
+        add     bx, cx                  ; Last scan column
+        sub     bx, [mx_ClipX2]
+        jle     @@ClipL2                ; No need to clip right
+        sub     cx, bx                  ; Clip right
+@@ClipL2:
+        test    cx, cx                  ; Is clipped width positive?
+        jle     @@Exit                  ; No, exit
+        mov     [ScanCount], cx         ; Save number of columns to draw
+        mov     [ScanOffsetT], si       ; Remember offset of (clipped) buffer
+        mov     ds, [mx_CodeSegment]    ; DS:SI -> scan buffer
+
+;------------------------------
+; Check if Y clipping is needed
+        mov     ax, [BoxY1]
+        cmp     ax, [mx_ClipY1]
+        jl      @@ClipTB                ; Need to clip top
+        mov     ax, [BoxY2]
+        cmp     ax, [mx_ClipY2]
+        jg      @@ClipTB                ; Need to clip bottom
+        jmp     @@ClipYExit             ; Skip Y clipping
+
+;--------------------
+; Clip top and bottom
+@@ClipTB:
+        mov     di, cx                  ; DI = scan count
+        inc     di                      ; Increment count for pre-loop test
+        sub     si, SIZE TSCAN
+@@ClipYLoop:
+        dec     di                      ; Any column left?
+        jz      @@ClipYExit             ; No, exit
+        add     si, SIZE TSCAN
+        mov     ax, ds:[si].Y1          ; Y1
+        mov     cx, ds:[si].Y2          ; Y2
+        mov     dx, [mx_ClipY2]
+        cmp     ax, dx                  ; Full clipped?
+        jg      @@ClipYClip             ; Yes, skip this column
+        cmp     cx, dx                  ; Need to clip bottom?
+        jle     @@ClipY1                ; No, continue
+; Clip bottom, need to scale colors too
+        mov     ds:[si].Y2, dx
+        mov     bx, cx
+        sub     bx, dx                  ; Clip distance
+        sub     cx, ax                  ; Height
+        jle     @@ClipYClip
+        mov     ax, WORD PTR ds:[si].E1
+        sub     ax, WORD PTR ds:[si].E2
+        imul    bx
+        idiv    cx
+        add     WORD PTR ds:[si].E2, ax
+        mov     ax, ds:[si].Y1          ; Restore AX and CX
+        mov     cx, ds:[si].Y2
+@@ClipY1:
+        mov     dx, [mx_ClipY1]
+        cmp     cx, dx                  ; Full top clipped?
+        jl      @@ClipYClip             ; Yes, skip
+        sub     cx, ax                  ; Get height
+        jle     @@ClipYClip             ; Skip if not positive
+        cmp     ax, dx                  ; Need to clip top?
+        jge     @@ClipYLoop             ; No, continue
+; Clip top, need to scale colors too
+        mov     ds:[si].Y1, dx          ; Y1 = mx_ClipY1
+        sub     dx, ax                  ; DX = number of pixels clipped
+        cmp     cx, dx
+        jbe     @@ClipYClip             ; Full clipped, skip
+        mov     ax, WORD PTR ds:[si].E2
+        sub     ax, WORD PTR ds:[si].E1 ; AX = color distance
+        imul    dx
+        idiv    cx
+        add     WORD PTR ds:[si].E1, ax ; Update starting color
+        jmp     @@ClipYLoop
+@@ClipYClip:
+        mov     ds:[si].Y1, -1          ; Mark column as clipped
+        jmp     @@ClipYLoop
+@@ClipYExit:
+
+;-------------
+; Draw columns
+        mov     es, [mx_VideoSegment]
+        mov     si, [ScanOffsetT]
+        mov     cl, BYTE PTR [BoxX1]    ; Init write plane
+        and     cl, 03h
+        mov     al, 11h
+        shl     al, cl
+        mov     [WritePlane], al
+        .shr    [BoxX1], 2
+        mov     ax, [Color]             ; Make 8:8 fixed color
+        mov     ah, al
+        xor     al, al
+        mov     [Color], ax
+@@DrawLoop:
+        mov     ax, ds:[si].Y1
+        test    ax, ax                  ; Was column clipped?
+        js      @@DrawNext              ; Yes, skip
+        mov     cx, ds:[si].Y2
+        sub     cx, ax                  ; CX = height
+        jle     @@DrawNext
+        mul     [mx_BytesPerLine]       ; Get pixel address
+        add     ax, [BoxX1]
+        mov     di, ax
+        mov     ah, [WritePlane]
+        mov     al, 02h
+        mov     dx, TS
+        out     dx, ax
+        mov     dx, [Color]
+        call    subFillScan
+@@DrawNext:
+        rol     [WritePlane], 1
+        adc     [BoxX1], 0              ; Bump pointer to video memory if needed
+        add     si, SIZE TSCAN
+        dec     [ScanCount]
+        jnz     @@DrawLoop
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxGouraudPoly	ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXPI.ASM b/16/x/MXPI.ASM
new file mode 100755
index 00000000..9e8525f5
--- /dev/null
+++ b/16/x/MXPI.ASM
@@ -0,0 +1,267 @@
+;-----------------------------------------------------------
+;
+; MXPI.ASM - Put image
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxPutImage
+
+EXTRN   subClipImage            : NEAR
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_BytesPerLine : WORD
+
+mxTable LABEL   WORD                    ; Raster ops
+        DW      subMove
+        DW      subAnd
+        DW      subOr
+        DW      subXor
+        DW      subTrans
+        DW      subAdd
+
+;-----------------------------------------------------------
+;
+; Move functions.
+; Note: loops unrolled and optimized for CX even, no check for CX = 0.
+;
+subMove         PROC    NEAR
+        shr     cx, 1                   ; Make CX even
+        jc      @@Odd                   ; Special case if odd byte
+@@Loop: movsb
+        add     si, 3
+        movsb
+        add     si, 3
+        dec     cx
+        jnz     @@Loop
+@@Exit: ret
+@@Odd:  movsb
+        add     si, 3
+        jcxz    @@Exit
+        jmp     @@Loop
+subMove         ENDP
+;
+subAnd          PROC     NEAR
+        shr     cx, 1
+        jc      @@Odd
+@@Loop: mov     al, ds:[si]
+        mov     ah, ds:[si+4]
+        and     es:[di], ax
+        inc     di
+        inc     di
+        add     si, 8
+        dec     cx
+        jnz     @@Loop
+@@Exit: ret
+@@Odd:  lodsb
+        and     es:[di], al
+        inc     di
+        add     si, 3
+        jcxz    @@Exit
+        jmp     @@Loop
+subAnd          ENDP
+;
+subOr           PROC     NEAR
+        shr     cx, 1
+        jc      @@Odd
+@@Loop: mov     al, ds:[si]
+        mov     ah, ds:[si+4]
+        or      es:[di], ax
+        inc     di
+        inc     di
+        add     si, 8
+        dec     cx
+        jnz     @@Loop
+@@Exit: ret
+@@Odd:  lodsb
+        or      es:[di], al
+        inc     di
+        add     si, 3
+        jcxz    @@Exit
+        jmp     @@Loop
+subOr           ENDP
+;
+subXor          PROC     NEAR
+        shr     cx, 1
+        jc      @@Odd
+@@Loop: mov     al, ds:[si]
+        mov     ah, ds:[si+4]
+        xor     es:[di], ax
+        inc     di
+        inc     di
+        add     si, 8
+        dec     cx
+        jnz     @@Loop
+@@Exit: ret
+@@Odd:  lodsb
+        xor     es:[di], al
+        inc     di
+        add     si, 3
+        jcxz    @@Exit
+        jmp     @@Loop
+subXor          ENDP
+;
+subTrans        PROC     NEAR
+@@Loop: mov     al, ds:[si]
+        cmp     al, ah
+        je      @@Skip
+        mov     es:[di], al
+@@Skip: inc     di
+        add     si, 4
+        dec     cx
+        jnz     @@Loop
+@@Exit: ret
+subTrans        ENDP
+;
+subAdd          PROC     NEAR
+@@Loop: mov     al, ds:[si]
+        add     es:[di], al
+        inc     di
+        add     si, 4
+        dec     cx
+        jnz     @@Loop
+        ret
+subAdd          ENDP
+
+;-----------------------------------------------------------
+;
+; Copies a "raw" image from memory to screen.
+;
+; Input:
+;       Image   = pointer to image
+;       X, Y    = coordinates of destination
+;       Width   = width of image in pixels
+;       Height  = height of image in pixels
+;       Op      = raster op (OP_xxx)
+; Output:
+;       none
+;
+mxPutImage      PROC    FAR
+        ARG     Op:WORD,                \
+                Height:WORD,            \
+                Width:WORD,             \
+                Y:WORD,                 \
+                X:WORD,                 \
+                Image:DWORD             = ARG_SIZE
+        LOCAL   PlaneWidth:WORD:4,      \
+                PixelOffset:WORD,       \
+                MoveFunction:WORD,      \
+                Count:BYTE,             \
+                ReadPlane:BYTE,         \
+                OpInfo:BYTE,            \
+                WritePlane:BYTE         = AUTO_SIZE
+        ASSUME  ds:NOTHING
+        .enter  AUTO_SIZE
+        .push   ds, si, es, di
+
+; Clip image
+        mov     bx, [X]
+        mov     ax, [Y]
+        mov     cx, [Width]
+        mov     dx, [Height]
+        call    subClipImage
+        jc      @@Exit                  ; Full clipped
+        mov     [Height], dx
+        add     WORD PTR Image[0], si   ; Skip clipped pixels
+
+; Get pixel address
+        mul     [mx_BytesPerLine]
+        mov     di, bx
+        shr     di, 1
+        shr     di, 1
+        add     di, ax
+        mov     [PixelOffset], di
+        mov     es, [mx_VideoSegment]   ; ES:DI points to pixel
+        and     bl, 03h
+        mov     [ReadPlane], bl
+
+; Compute extra bytes and width count for each plane
+        mov     bx, cx
+        shr     bx, 1
+        shr     bx, 1                   ; Width for each plane
+        and     cl, 03h
+        mov     al, 00001000b
+        shr     al, cl
+        mov     si, 3 SHL 1
+@@PatchLoop:
+        mov     PlaneWidth[si], bx
+        shr     al, 1
+        adc     bx, 0
+        dec     si
+        dec     si
+        jge     @@PatchLoop
+
+; Setup planes for output to VGA registers
+        mov     cl, [ReadPlane]
+        mov     al, 00010001b
+        shl     al, cl
+        mov     [WritePlane], al
+
+; Install move function
+        mov     bx, [Op]
+        mov     [OpInfo], bh            ; Remember additional info if needed
+        xor     bh, bh
+        cmp     bl, OP_ADD
+        jbe     @@SetMoveFunction
+        xor     bl, bl
+@@SetMoveFunction:
+        shl     bx, 1
+        mov     ax, mxTable[bx]
+        mov     [MoveFunction], ax
+
+; Put image
+        cld
+        mov     [Count], 4              ; Four planes
+        lea     bx, PlaneWidth          ; SS:[BX] = width in bytes for plane
+        mov     ds, WORD PTR Image[2]
+@@PlaneLoop:
+        cmp     WORD PTR ss:[bx], 0     ; Exit if nothing more to do
+        je      @@Exit                  ; (also, never try to move zero bytes!)
+        mov     si, WORD PTR Image[0]
+        mov     ah, [WritePlane]
+        and     ah, 0Fh
+        mov     al, 02h
+        mov     dx, TS
+        out     dx, ax                  ; Select write plane
+        mov     ah, [ReadPlane]
+        and     ah, 03h
+        mov     al, 04h
+        mov     dx, GDC
+        out     dx, ax                  ; Select read plane
+        mov     dx, [Height]
+        mov     di, [PixelOffset]
+@@Loop:
+        push    si
+        push    di
+        mov     cx, WORD PTR ss:[bx]    ; Number of bytes to move
+        mov     ah, [OpInfo]            ; Transparent color for subTrans
+        call    [MoveFunction]
+        pop     di
+        pop     si
+        add     si, [Width]             ; Go to next image line
+        add     di, [mx_BytesPerLine]   ; Go to next screen row
+        dec     dx
+        jnz     @@Loop                  ; Repeat for all lines
+        inc     bx
+        inc     bx                      ; Select width for next plane
+        inc     [ReadPlane]
+        rol     [WritePlane], 1
+        adc     [PixelOffset], 0
+        inc     WORD PTR Image[0]
+        dec     [Count]
+        jnz     @@PlaneLoop             ; Repeat for all planes
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxPutImage      ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXPN.ASM b/16/x/MXPN.ASM
new file mode 100755
index 00000000..eaaf61b4
--- /dev/null
+++ b/16/x/MXPN.ASM
@@ -0,0 +1,60 @@
+;-----------------------------------------------------------
+;
+; MXPN.ASM - Panning function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxPan
+
+EXTRN   mxWaitDisplay   : FAR
+EXTRN   mxStartAddress  : FAR
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_BytesPerLine : WORD
+
+;-----------------------------------------------------------
+;
+; Moves the screen.
+;
+; Input:
+;       X, Y    = new X, Y coordinates of view screen
+; Output:
+;       none
+;
+mxPan           PROC    FAR
+        ARG     Y:WORD,                 \
+                X:WORD                  = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+
+        mov     ax, [Y]
+        mul     [mx_BytesPerLine]
+        mov     dx, [X]
+        shr     dx, 1
+        shr     dx, 1
+        add     ax, dx
+        push    ax                      ; Push the start address
+        call    mxWaitDisplay
+        call    mxStartAddress
+
+        mov     dx, 03DAh               ; Set the pixel pan register
+        in      al, dx
+        mov     dx, 03C0h
+        mov     al, 33h
+        out     dx, al
+        mov     al, BYTE PTR [X]
+        and     al, 3
+        shl     al, 1
+        out     dx, al
+
+        xor     ax, ax
+        .leave  ARG_SIZE
+mxPan           ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXPP.ASM b/16/x/MXPP.ASM
new file mode 100755
index 00000000..fc1755a3
--- /dev/null
+++ b/16/x/MXPP.ASM
@@ -0,0 +1,121 @@
+;-----------------------------------------------------------
+;
+; MXPP.ASM - Get/put pixel functions
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxGetPixel
+PUBLIC  mxPutPixel
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_BytesPerLine : WORD
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_ClipX1       : WORD
+EXTRN   mx_ClipY1       : WORD
+EXTRN   mx_ClipX2       : WORD
+EXTRN   mx_ClipY2       : WORD
+
+;-----------------------------------------------------------
+;
+; Gets a pixel.
+;
+; Input:
+;       X, Y    = pixel coordinates
+; Output:
+;       pixel color
+;
+mxGetPixel      PROC    FAR
+        ARG     Y:WORD,                 \
+                X:WORD                  = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds, si
+
+        xor     ax, ax
+        mov     si, [X]
+        cmp     si, [mx_ClipX1]
+        jl      @@Exit
+        cmp     si, [mx_ClipX2]
+        jg      @@Exit
+        mov     bx, [Y]
+        cmp     bx, [mx_ClipY1]
+        jl      @@Exit
+        cmp     bx, [mx_ClipY2]
+        jg      @@Exit
+
+        mov     al, 04h                 ; Set read plane
+        mov     ah, BYTE PTR [X]
+        and     ah, 3
+        mov     dx, GDC
+        out     dx, ax
+
+        mov     ds, [mx_VideoSegment]
+        mov     ax, bx
+        mul     [mx_BytesPerLine]
+        .shr    si, 2
+        add     si, ax
+
+        mov     al, ds:[si]             ; Get pixel value
+        xor     ah, ah
+
+@@Exit:
+        .pop    ds, si
+        .leave  ARG_SIZE
+mxGetPixel      ENDP
+
+;-----------------------------------------------------------
+;
+; Puts a pixel of the specified color.
+;
+; Input:
+;       X, Y    = pixel coordinates
+;       Color   = pixel color
+; Output:
+;       none
+;
+mxPutPixel      PROC    FAR
+        ARG     Color:BYTE:2,           \
+                Y:WORD,                 \
+                X:WORD                  = ARG_SIZE
+        .enter  0
+        .push   ds, si
+
+        mov     si, [X]
+        cmp     si, [mx_ClipX1]
+        jl      @@Exit
+        cmp     si, [mx_ClipX2]
+        jg      @@Exit
+        mov     ax, [Y]
+        cmp     ax, [mx_ClipY1]
+        jl      @@Exit
+        cmp     ax, [mx_ClipY2]
+        jg      @@Exit
+
+        mov     ds, [mx_VideoSegment]
+        mul     [mx_BytesPerLine]
+        .shr    si, 2
+        add     si, ax
+
+        mov     cl, BYTE PTR [X]        ; Set write plane
+        and     cl, 3
+        mov     ax, 0102h
+        shl     ah, cl
+        mov     dx, TS
+        out     dx, ax
+
+        mov     al, [Color]             ; Write pixel
+        mov     ds:[si], al
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds, si
+        .leave  ARG_SIZE
+mxPutPixel      ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXRA.ASM b/16/x/MXRA.ASM
new file mode 100755
index 00000000..dd8e6839
--- /dev/null
+++ b/16/x/MXRA.ASM
@@ -0,0 +1,37 @@
+;-----------------------------------------------------------
+;
+; MXRA.ASM - Row address
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxRowAddress
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Sets the row address register.
+;
+; Input:
+;       RowAddress      = row size in words
+; Output:
+;       none
+;
+mxRowAddress    PROC    FAR
+        ARG     RowAddress:BYTE:2       = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        mov     dx, CRTC
+        mov     al, 13h
+        mov     ah, [RowAddress]
+        out     dx, ax
+        xor     ax, ax
+        .leave  ARG_SIZE
+mxRowAddress    ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXRP.ASM b/16/x/MXRP.ASM
new file mode 100755
index 00000000..de820c16
--- /dev/null
+++ b/16/x/MXRP.ASM
@@ -0,0 +1,101 @@
+;-----------------------------------------------------------
+;
+; MXRP.ASM - Rotate palette function
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxRotatePalette
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Rotates the palette of the specified number of colors.
+;
+; Input:
+;       Palette = pointer to palette
+;       Count   = number of colors to rotate
+;       Step    = step size
+; Output:
+;       none
+;
+; Note: if Step is positive palette is rotated left to right, otherwise
+;       right to left.
+;
+mxRotatePalette PROC    FAR
+        ARG     Step:WORD,      \
+                Count:WORD,     \
+                Palette:DWORD   = ARG_SIZE
+        LOCAL   Holder:BYTE:768 = AUTO_SIZE
+        ASSUME  ds:NOTHING
+        .enter  AUTO_SIZE
+        .push   ds, si, es, di
+
+        mov     bx, [Count]
+        add     bx, bx
+        add     bx, [Count]             ; BX = Count*3
+
+        lds     si, [Palette]           ; DS:SI -> palette
+        push    ss
+        pop     es
+        lea     di, Holder              ; ES:DI -> local space
+        cld
+
+        mov     ax, [Step]
+        mov     dx, ax
+        test    ax, ax
+        jz      @@Exit                  ; Nothing to do, exit
+        jl      @@RightToLeft
+
+@@LeftToRight:
+        add     ax, ax
+        add     dx, ax                  ; DX = Step*3
+        sub     bx, dx                  ; BX = (Count-Step)*3
+        add     si, bx
+        push    si
+        mov     cx, dx
+        rep     movsb
+        mov     es, WORD PTR Palette[2]
+        mov     di, si
+        dec     di                      ; ES:DI -> last byte of palette
+        pop     si
+        dec     si
+        mov     cx, bx
+        std
+        rep     movsb
+        push    ss
+        pop     ds
+        lea     si, Holder
+        les     di, [Palette]
+        mov     cx, dx
+        cld
+        rep     movsb
+        jmp     @@Exit
+
+@@RightToLeft:
+        add     ax, ax
+        add     dx, ax
+        neg     dx                      ; DX = Step*3
+        sub     bx, dx                  ; BX = (Count-Step)*3
+        mov     cx, dx
+        rep     movsb
+        les     di, [Palette]
+        mov     cx, bx
+        rep     movsb
+        push    ss
+        pop     ds
+        lea     si, Holder
+        mov     cx, dx
+        rep     movsb
+
+@@Exit:
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxRotatePalette ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXSA.ASM b/16/x/MXSA.ASM
new file mode 100755
index 00000000..3ebae67d
--- /dev/null
+++ b/16/x/MXSA.ASM
@@ -0,0 +1,44 @@
+;-----------------------------------------------------------
+;
+; MXSA.ASM - Start address function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxStartAddress
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Modifies the starting address of video memory.
+;
+; Input:
+;       StartAddr       = new start address of video memory
+; Output:
+;       none
+;
+mxStartAddress  PROC    FAR
+        ARG     StartAddr:WORD  = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+
+        mov     bx, [StartAddr]
+        mov     dx, CRTC
+        mov     al, 0Ch                 ; Linear Starting Address high
+        mov     ah, bh
+        cli
+        out     dx, ax
+        mov     al, 0Dh                 ; Linear Starting Address low
+        mov     ah, bl
+        out     dx, ax
+        sti
+
+        .leave  ARG_SIZE
+mxStartAddress  ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXSC.ASM b/16/x/MXSC.ASM
new file mode 100755
index 00000000..bcae45e6
--- /dev/null
+++ b/16/x/MXSC.ASM
@@ -0,0 +1,50 @@
+;-----------------------------------------------------------
+;
+; MXSC.ASM - Set color function
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxSetColor
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Updates the selected DAC register.
+;
+; Input:
+;       Index   = index of color to set
+;       R, G, B = color components
+; Output:
+;       none
+;
+mxSetColor      PROC FAR
+        ARG     B:BYTE:2,       \
+                G:BYTE:2,       \
+                R:BYTE:2,       \
+                Index:WORD      = ARG_SIZE
+        .enter  0
+        .push   ds, si
+
+        mov     ax, [Index]
+        mov     dx, 3C8h                ; PEL write address register
+        out     dx, al
+        inc     dx
+
+        mov     al, [R]
+        out     dx, al
+        mov     al, [G]
+        out     dx, al
+        mov     al, [B]
+        out     dx, al
+
+        .pop    ds, si
+        .leave  ARG_SIZE
+mxSetColor      ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXSI.ASM b/16/x/MXSI.ASM
new file mode 100755
index 00000000..b88d3b11
--- /dev/null
+++ b/16/x/MXSI.ASM
@@ -0,0 +1,317 @@
+;-----------------------------------------------------------
+;
+; MXPI.ASM - Stretch image
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxStretchImage
+
+EXTRN   subClipBox              : NEAR
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_BytesPerLine : WORD
+
+mxTable LABEL   WORD                    ; Raster ops
+        DW      subMove
+        DW      subAnd
+        DW      subOr
+        DW      subXor
+        DW      subTrans
+        DW      subAdd
+
+;-----------------------------------------------------------
+;
+; Stretches and copies a "raw" image from memory to screen.
+;
+; Input:
+;       Image     = pointer to image
+;       X, Y      = coordinates of destination
+;       Width     = width of image in pixels
+;       Height    = height of image in pixels
+;       NewWidth  = new width of image in pixels
+;       NewHeight = new height of image in pixels
+;       Op        = raster op (OP_xxx)
+; Output:
+;       none
+;
+mxStretchImage  PROC    FAR
+        ARG     Op:WORD,                \
+                NewHeight:WORD,         \
+                NewWidth:WORD,          \
+                Height:WORD,            \
+                Width:WORD,             \
+                Y:WORD,                 \
+                X:WORD,                 \
+                Image:DWORD             = ARG_SIZE
+        LOCAL   PixelOffset:WORD,       \
+                MoveFunction:WORD,      \
+                ReadPlane:BYTE,         \
+                OpInfo:BYTE,            \
+                WidthStep:DWORD,        \
+                HeightStep:DWORD,       \
+                ImageLo:WORD,           \
+                WritePlane:BYTE         = AUTO_SIZE
+        ASSUME  ds:NOTHING
+        .enter  AUTO_SIZE
+        .push   ds, si, es, di
+
+; Get width stretch factor
+    IF USE386 EQ TRUE
+        movzx   edx, [Width]
+        xor     eax, eax
+        movzx   ebx, [NewWidth]
+        shl     ebx, 16
+        idiv    ebx
+        mov     [WidthStep], eax
+    ELSE
+        xor     dx, dx                  ; Width stretch factor
+        mov     ax, [Width]
+        mov     bx, [NewWidth]
+        div     bx
+        mov     WORD PTR WidthStep[2], ax
+        xor     ax, ax
+        div     bx
+        mov     WORD PTR WidthStep[0], ax
+    ENDIF
+; Get height stretch factor
+    IF USE386 EQ TRUE
+        movzx   edx, [Height]
+        xor     eax, eax
+        movzx   ebx, [NewHeight]
+        shl     ebx, 16
+        idiv    ebx
+        mov     [HeightStep], eax
+    ELSE
+        xor     dx, dx
+        mov     ax, [Height]
+        mov     bx, [NewHeight]
+        div     bx
+        mov     WORD PTR HeightStep[2], ax
+        xor     ax, ax
+        div     bx
+        mov     WORD PTR HeightStep[0], ax
+   ENDIF
+
+; Clip image
+        mov     bx, [X]
+        mov     ax, [Y]
+        mov     cx, [NewWidth]
+        mov     dx, [NewHeight]
+        call    subClipBox
+        jc      @@Exit                  ; Full clipped
+        mov     [NewWidth], cx
+        mov     [NewHeight], dx
+        sub     [X], bx
+        sub     [Y], ax
+
+; Get pixel address
+        mul     [mx_BytesPerLine]
+        mov     di, bx
+        shr     di, 1
+        shr     di, 1
+        add     di, ax
+        mov     [PixelOffset], di
+        mov     es, [mx_VideoSegment]   ; ES:DI points to pixel
+        and     bl, 03h
+        mov     [ReadPlane], bl         ; Set read plane
+        mov     cl, bl
+        mov     al, 00010001b
+        shl     al, cl
+        mov     [WritePlane], al        ; Set write plane
+
+; Relocate image origin if previously clipped
+        mov     ax, [Y]
+        test    ax, ax
+        jz      @@OriginYDone
+    IF USE386 EQ TRUE
+        shl     eax, 16
+        imul    [HeightStep]
+        mov     ax, [Width]
+        mul     dx
+    ELSE
+        mov     bx, ax
+        mul     WORD PTR HeightStep[0]
+        mov     cx, dx
+        mov     ax, bx
+        mul     WORD PTR HeightStep[2]
+        add     ax, cx
+        mul     [Width]
+    ENDIF
+        add     WORD PTR [Image], ax
+@@OriginYDone:
+        mov     ax, [X]
+        test    ax, ax
+        jz      @@OriginXDone
+    IF USE386 EQ TRUE
+        shl     eax, 16
+        imul    [WidthStep]
+        add     WORD PTR [Image], dx
+    ELSE
+        mov     bx, ax
+        mul     WORD PTR WidthStep[0]
+        mov     cx, dx
+        mov     ax, bx
+        mul     WORD PTR WidthStep[2]
+        add     ax, cx
+        add     WORD PTR [Image], ax
+    ENDIF
+@@OriginXDone:
+        mov     ax, WORD PTR HeightStep[2]
+        mul     [Width]
+        mov     WORD PTR HeightStep[2], ax
+
+; Install move function
+        mov     bx, [Op]
+        mov     [OpInfo], bh            ; Remember additional info if needed
+        xor     bh, bh
+        cmp     bl, OP_ADD
+        jbe     @@SetMoveFunction
+        xor     bl, bl
+@@SetMoveFunction:
+        shl     bx, 1
+        mov     ax, mxTable[bx]
+        mov     [MoveFunction], ax
+
+; Put image
+        mov     ds, WORD PTR Image[2]
+        xor     ax, ax
+        mov     [ImageLo], ax
+@@Loop:
+        mov     si, WORD PTR Image[0]   ; Get pointer to image
+        mov     ah, [WritePlane]
+        and     ah, 0Fh
+        mov     al, 02h
+        mov     dx, TS
+        out     dx, ax                  ; Select write plane
+        mov     ah, [ReadPlane]
+        and     ah, 03h
+        mov     al, 04h
+        mov     dx, GDC
+        out     dx, ax                  ; Select read plane
+        mov     cx, [NewHeight]
+        mov     di, [PixelOffset]       ; ES:DI points to video memory
+        mov     ah, [OpInfo]            ; Additional raster op info
+        xor     bx, bx
+        mov     dx, [mx_BytesPerLine]
+        call    [MoveFunction]          ; Draw column
+        inc     [ReadPlane]             ; Next read plane
+        rol     [WritePlane], 1         ; Next write plane
+        adc     [PixelOffset], 0        ; Update video offset if needed
+        mov     dx, WORD PTR WidthStep[0]
+        mov     ax, WORD PTR WidthStep[2]
+        add     [ImageLo], dx
+        adc     WORD PTR Image[0], ax   ; Next image column
+        dec     [NewWidth]
+        jnz     @@Loop                  ; Repeat for all columns
+
+@@Exit:
+        xor     ax, ax
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+
+;-----------------------------------------------------------
+;
+; Move functions, on entry:
+;       AH = additional raster op info (e.g. transparent color)
+;       BX = 0,
+;       CX = pixel count,
+;       DX = mx_BytesPerLine.
+;
+subMove         PROC    NEAR
+@@Loop: mov     al, ds:[si]
+        mov     es:[di], al
+        add     di, dx
+        dec     cx
+        jz      @@Exit
+        add     si, WORD PTR HeightStep[2]
+        add     bx, WORD PTR HeightStep[0]
+        jnc     @@Loop
+        add     si, [Width]
+        jmp     @@Loop
+@@Exit: ret
+subMove         ENDP
+;
+subAnd          PROC     NEAR
+@@Loop: mov     al, ds:[si]
+        and     es:[di], al
+        add     di, dx
+        dec     cx
+        jz      @@Exit
+        add     si, WORD PTR HeightStep[2]
+        add     bx, WORD PTR HeightStep[0]
+        jnc     @@Loop
+        add     si, [Width]
+        jmp     @@Loop
+@@Exit: ret
+subAnd          ENDP
+;
+subOr           PROC     NEAR
+@@Loop: mov     al, ds:[si]
+        or      es:[di], al
+        add     di, dx
+        dec     cx
+        jz      @@Exit
+        add     si, WORD PTR HeightStep[2]
+        add     bx, WORD PTR HeightStep[0]
+        jnc     @@Loop
+        add     si, [Width]
+        jmp     @@Loop
+@@Exit: ret
+subOr           ENDP
+;
+subXor          PROC     NEAR
+@@Loop: mov     al, ds:[si]
+        xor     es:[di], al
+        add     di, dx
+        dec     cx
+        jz      @@Exit
+        add     si, WORD PTR HeightStep[2]
+        add     bx, WORD PTR HeightStep[0]
+        jnc     @@Loop
+        add     si, [Width]
+        jmp     @@Loop
+@@Exit: ret
+subXor          ENDP
+;
+subTrans        PROC     NEAR
+@@Loop: mov     al, ds:[si]
+        cmp     al, ah
+        je      @@Skip
+        mov     es:[di], al
+@@Skip:
+        add     di, dx
+        dec     cx
+        jz      @@Exit
+        add     si, WORD PTR HeightStep[2]
+        add     bx, WORD PTR HeightStep[0]
+        jnc     @@Loop
+        add     si, [Width]
+        jmp     @@Loop
+@@Exit: ret
+subTrans        ENDP
+;
+subAdd          PROC     NEAR
+@@Loop: mov     al, ds:[si]
+        add     es:[di], al
+        add     di, dx
+        dec     cx
+        jz      @@Exit
+        add     si, WORD PTR HeightStep[2]
+        add     bx, WORD PTR HeightStep[0]
+        jnc     @@Loop
+        add     si, [Width]
+        jmp     @@Loop
+@@Exit: ret
+subAdd          ENDP
+
+mxStretchImage  ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXSL.ASM b/16/x/MXSL.ASM
new file mode 100755
index 00000000..d7908855
--- /dev/null
+++ b/16/x/MXSL.ASM
@@ -0,0 +1,62 @@
+;-----------------------------------------------------------
+;
+; MXLN.ASM - Start line function
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxStartLine
+
+MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'
+        ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_BytesPerLine : WORD
+
+;-----------------------------------------------------------
+;
+; Changes the video start address to the specified line.
+;
+; Input:
+;       Line    = new start line
+; Output:
+;       none
+;
+mxStartLine     PROC FAR
+        ARG     Line:WORD       = ARG_SIZE
+        .enter  0
+        ASSUME  ds:NOTHING
+
+        mov     ax, [Line]              ; Get video offset
+        mul     [mx_BytesPerLine]
+        xchg    ax, bx                  ; Copy it into BX
+
+; Wait display
+        mov     dx, STATUS
+@@1:    in      al, dx
+        test    al, 08h
+        jnz     @@1
+
+; Set starting address
+        mov     dx, CRTC
+        mov     al, 0Ch                 ; Linear Starting Address high
+        mov     ah, bh
+        cli
+        out     dx, ax
+        mov     al, 0Dh                 ; Linear Starting Address low
+        mov     ah, bl
+        out     dx, ax
+        sti
+
+; Wait retrace
+        mov     dx, STATUS
+@@2:    in      al,dx
+        test    al, 08h
+        jz      @@2
+
+        xor     ax, ax
+        .leave  ARG_SIZE
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXSM.ASM b/16/x/MXSM.ASM
new file mode 100755
index 00000000..183fba1e
--- /dev/null
+++ b/16/x/MXSM.ASM
@@ -0,0 +1,508 @@
+;-----------------------------------------------------------
+;
+; MXSM.ASM - Set/change mode functions
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxChangeMode
+PUBLIC  mxGetAspect
+PUBLIC  mxGetScreenSize
+PUBLIC  mxSetMode
+
+PUBLIC  mx_ScreenWidth
+PUBLIC  mx_ScreenHeight
+PUBLIC  mx_BytesPerLine
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mxSetSysClipRegion      : FAR
+
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_CodeSegment  : WORD
+
+mx_ScreenWidth  DW      ?               ; Current screen width
+mx_ScreenHeight DW      ?
+mx_AspectX      DW      ?               ; Aspect ratio for current mode
+mx_AspectY      DW      ?
+mx_BytesPerLine DW      0               ; Bytes per line
+
+;
+; Tables for setting video modes, sources:
+; - MODEX.ASM, Matt Pritchard
+; - Dr. Dobb's Journal, Michael Abrash
+; - Fractint VIDEO.ASM module
+;
+TBL_SingleLine  LABEL   WORD            ; CRTC
+        DW      04009h                  ; Cell height: 1 scan line
+        DW      00014h                  ; Double word mode off
+        DW      0E317h                  ; Byte mode on
+        DW      0
+TBL_DoubleLine  LABEL   WORD            ; CRTC
+        DW      04109h                  ; Cell height: 2 scan lines
+        DW      00014h
+        DW      0E317h
+        DW      0
+TBL_Width320    LABEL   WORD            ; CRTC
+        DW      05F00h                  ; Horizontal total
+        DW      04F01h                  ; Horizontal displayed
+        DW      05002h                  ; Start horizontal blanking
+        DW      08203h                  ; End horizontal blanking
+        DW      05404h                  ; Start horizontal sync
+        DW      08005h                  ; End horizontal sync
+        DW      02813h                  ; Row address
+        DW      0
+TBL_Width360    LABEL   WORD            ; CRTC
+        DW      06B00h                  ; Horizontal total
+        DW      05901h                  ; Horizontal displayed
+        DW      05A02h                  ; Start horizontal blanking
+        DW      08E03h                  ; End horizontal blanking
+        DW      05E04h                  ; Start horizontal sync
+        DW      08A05h                  ; End horizontal sync
+        DW      02D13h                  ; Row address
+        DW      0
+TBL_Height175   LABEL   WORD            ; CRTC
+        DW      0BF06h                  ; Vertical total
+        DW      01F07h                  ; Overflow
+        DW      08310h                  ; Start vertical sync
+        DW      08511h                  ; End vertical sync
+        DW      05D12h                  ; Vertical displayed
+        DW      06315h                  ; Start vertical blanking
+        DW      0BA16h                  ; End vertical blanking
+        DW      0
+TBL_Height200   LABEL   WORD            ; CRTC
+        DW      0BF06h                  ; Vertical total
+        DW      01F07h                  ; Overflow
+        DW      09C10h                  ; Start vertical sync
+        DW      08E11h                  ; End vertical sync
+        DW      08F12h                  ; Vertical displayed
+        DW      09615h                  ; Start vertical blanking
+        DW      0B916h                  ; End vertical blanking
+        DW      0
+TBL_Height240   LABEL   WORD            ; CRTC
+        DW      00D06h                  ; Vertical total
+        DW      03E07h                  ; Overflow
+        DW      0EA10h                  ; Start vertical sync
+        DW      08C11h                  ; End vertical sync
+        DW      0DF12h                  ; Vertical displayed
+        DW      0E715h                  ; Start vertical blanking
+        DW      00616h                  ; End vertical blanking
+        DW      0
+TBL_Tweak400x600:
+        DW      07400h
+        DW      06301h
+        DW      06402h
+        DW      09703h
+        DW      06804h
+        DW      09505h
+        DW      08606h
+        DW      0F007h
+        DW      06009h
+        DW      0310Fh
+        DW      05B10h
+        DW      08D11h
+        DW      05712h
+        DW      03213h
+        DW      00014h
+        DW      06015h
+        DW      08016h
+        DW      0E317h
+        DW      0
+
+TBL_320x200:
+        DB      63h                     ; 400 scan lines, 25 MHz clock
+        DW      6, 5                    ; Aspect: 6/5 = 1.2:1
+        DW      320, 200                ; Size
+        DW      TBL_Width320, TBL_Height200, TBL_DoubleLine, 0
+        DW      819                     ; Max height
+TBL_320x240:
+        DB      0E3h                    ; 400 scan lines, 25 MHz clock
+        DW      1, 1                    ; Aspect: 1/1 = 1:1
+        DW      320, 240                ; Size
+        DW      TBL_Width320, TBL_Height240, TBL_DoubleLine, 0
+        DW      819                     ; Max height
+TBL_320x400:
+        DB      63h                     ; 480 scan lines, 25 MHz clock
+        DW      6, 10                   ; Aspect: 6/10 = 0.6:1
+        DW      320, 400                ; Size
+        DW      TBL_Width320, TBL_Height200, TBL_SingleLine, 0
+        DW      819                     ; Max height
+TBL_320x480:
+        DB      0E3h                    ; 480 scan lines, 25 MHz clock
+        DW      1, 2                    ; Aspect: 1/2 = 0.5:1
+        DW      320, 480                ; Size
+        DW      TBL_Width320, TBL_Height240, TBL_SingleLine, 0
+        DW      819                     ; Max height
+TBL_360x200:
+        DB      067h                    ; 400 scan lines, 28 MHz clock
+        DW      27, 20                  ; Aspect: 27/20 = 1.35:1
+        DW      360, 200                ; Size
+        DW      TBL_Width360, TBL_Height200, TBL_DoubleLine, 0
+        DW      728                     ; Max height
+TBL_360x240:
+        DB      0E7h                    ; 480 scan lines, 28 MHz clock
+        DW      9, 8                    ; Aspect: 9/8 = 1.125:1
+        DW      360, 240                ; Size
+        DW      TBL_Width360, TBL_Height240, TBL_DoubleLine, 0
+        DW      728                     ; Max height
+TBL_360x400:
+        DB      067h                    ; 400 scan lines, 28 MHz clock
+        DW      27, 40                  ; Aspect: 27/40 = 0.675:1
+        DW      360, 400                ; Size
+        DW      TBL_Width360, TBL_Height200, TBL_SingleLine, 0
+        DW      728                     ; Max height
+TBL_360x480:
+        DB      0E7h                    ; 480 scan lines, 28 MHz clock
+        DW      9, 16                   ; Aspect: 9/16 = 0.5625:1
+        DW      360, 480                ; Size
+        DW      TBL_Width360, TBL_Height240, TBL_SingleLine, 0
+        DW      728                     ; Max height
+TBL_320x175:
+        DB      0A3h
+        DW      0, 0                    ; Aspect:
+        DW      320, 175
+        DW      TBL_Width320, TBL_Height175, TBL_DoubleLine, 0
+        DW      819
+TBL_320x350:
+        DB      0A3h
+        DW      0, 0                    ; Aspect:
+        DW      320, 175
+        DW      TBL_Width320, TBL_Height175, TBL_SingleLine, 0
+        DW      819
+TBL_360x175:
+        DB      0A7h
+        DW      0, 0                    ; Aspect:
+        DW      360, 480                ; Size
+        DW      TBL_Width360, TBL_Height175, TBL_DoubleLine, 0
+        DW      728                     ; Max height
+TBL_360x350:
+        DB      0A7h
+        DW      0, 0                    ; Aspect:
+        DW      360, 480                ; Size
+        DW      TBL_Width360, TBL_Height175, TBL_SingleLine, 0
+        DW      728                     ; Max height
+TBL_400x600:
+        DB      0E7h                    ; 28 MHz clock
+        DW      1, 2                    ; Aspect: 1/2 = 0.5:1
+        DW      400, 600                ; Size
+        DW      TBL_Tweak400x600, 0
+        DW      655                     ; Max height
+
+TBL_Mode        LABEL   WORD
+        DW      TBL_320x175
+        DW      TBL_320x200
+        DW      TBL_320x240
+        DW      TBL_320x350
+        DW      TBL_320x400
+        DW      TBL_320x480
+        DW      TBL_360x175
+        DW      TBL_360x200
+        DW      TBL_360x240
+        DW      TBL_360x350
+        DW      TBL_360x400
+        DW      TBL_360x480
+        DW      TBL_400x600
+
+MAXVMODE        EQU     ($-OFFSET TBL_Mode) / 2
+
+;-----------------------------------------------------------
+;
+; Enables 80x25 color text mode
+;
+subText         PROC    NEAR
+        ASSUME  ds:MX_TEXT
+        mov     ax, 0003h
+        int     10h                     ; Call BIOS set mode
+
+        mov     [mx_ScreenHeight], 0
+        mov     [mx_BytesPerLine], 0
+        ret
+subText         ENDP
+
+;-----------------------------------------------------------
+;
+; Enables the selected graphics mode.
+;
+; Input:
+;       Mode    = mode to select (MX_???x???)
+; Output:
+;       none
+;
+mxSetMode       PROC    FAR
+        ARG     Mode:WORD       = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds, si, es, di
+
+; Set DS to code segment alias
+        mov     ds, [mx_CodeSegment]
+        ASSUME  ds:MX_TEXT
+
+        mov     si, [Mode]
+        cmp     si, MAXVMODE            ; Is it a valid mode?
+        ja      @@Exit                  ; No, exit
+        test    si, si                  ; Text mode?
+        jnz     @@Set                   ; No, handle it
+
+        call    subText                 ; Back to text mode
+        jmp     @@Exit                  ; Exit now
+
+; Set video mode
+@@Set:
+        dec     si                      ; Skip text mode
+        shl     si, 1
+        mov     si, TBL_Mode[si]
+        cld
+
+; Use BIOS to set 320x200x256 linear mode
+        push    si                      ; Save SI
+        mov     ax, 0013h
+        int     10h                     ; Use BIOS to set 320x200 linear mode
+        pop     si                      ; Restore SI
+
+        mov     dx, TS
+        mov     ax, 0604h
+        out     dx, ax                  ; Disable chain-4 mode
+        mov     ax, 0100h
+        out     dx, ax                  ; Reset
+        mov     dx, MISC
+        lodsb
+        out     dx, al                  ; New timing/size
+        mov     dx, TS
+        mov     ax, 0300h
+        out     dx, ax                  ; Restart sequencer
+
+; Unlock CRTC registers 0-7
+        mov     dx, CRTC
+        mov     al, 11h
+        out     dx, al                  ; Vertical sync end register
+        inc     dx
+        in      al, dx
+        and     al, 7Fh                 ; Clear write protect bit
+        out     dx, al
+
+        lodsw                           ; Get X aspect
+        mov     [mx_AspectX], ax
+        lodsw                           ; Get Y aspect
+        mov     [mx_AspectY], ax
+        lodsw                           ; Get screen width
+        mov     [mx_ScreenWidth], ax
+        shr     ax, 1
+        shr     ax, 1                   ; Divide by four to get bytes per line
+        mov     [mx_BytesPerLine], ax
+        lodsw                           ; Get screen height
+        mov     [mx_ScreenHeight], ax
+
+; Set CRTC registers
+        mov     bx, si
+        mov     dx, CRTC
+@@TableLoop:
+        mov     si, ds:[bx]             ; DS:SI -> table of CRTC registers
+        inc     bx
+        inc     bx                      ; DS:BX -> offset of next table
+        test    si, si                  ; Last table?
+        jz      @@EndLoop               ; Yes, exit loop
+@@Loop:
+        lodsw                           ; Get CRTC register index and value
+        test    ax, ax                  ; End of table?
+        jz      @@TableLoop             ; Yes, go to next table
+        out     dx, ax                  ; Set register AL to value AH
+        jmp     @@Loop                  ; Get next register/value
+@@EndLoop:
+
+; Set virtual screen and system clip region
+        push    [mx_ScreenWidth]
+        push    WORD PTR ds:[bx]
+        call    mxSetSysClipRegion
+
+; Clear video memory
+        mov     dx, TS
+        mov     ax, 0F02h
+        out     dx, ax                  ; Enable all planes
+        mov     es, [mx_VideoSegment]
+        xor     di, di
+        mov     cx, 8000h
+        xor     ax, ax
+        rep     stosw
+
+@@Done:
+; Lock CRTC registers 0-7 (some cards need this)
+        mov     dx, CRTC
+        mov     al, 11h
+        out     dx, al                  ; Vertical sync end register
+        inc     dx
+        in      al, dx
+        or      al, 80h                 ; Set write protect bit
+        out     dx, al
+
+@@Exit:
+        xor     ax, ax
+        mov     ax, [mx_ScreenWidth]
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxSetMode       ENDP
+
+;-----------------------------------------------------------
+;
+; Changes from the current mode the selected graphics mode.
+;
+; Input:
+;       Mode    = mode to select (MX_???x???)
+; Output:
+;       none
+; Notes:
+;       this function assumes that mxSetMode and mxSetVirtualScreen
+;       have been called first. View size is rearranged to match the
+;       specified mode, but video memory is not cleared.
+;       Differences from mxSetMode:
+;       - video BIOS is not called to initialize graphics;
+;       - row address register is not modified;
+;       - video memory is not cleared;
+;       - mx_BytesPerLine is not modified;
+;       - system clip region is not modified.
+;
+mxChangeMode    PROC    FAR
+        ARG     Mode:WORD       = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds, si, es, di
+
+; Set DS to code segment alias
+        mov     ds, [mx_CodeSegment]
+        ASSUME  ds:MX_TEXT
+
+        mov     si, [Mode]
+        cmp     si, MAXVMODE            ; Is it a valid mode?
+        ja      @@Exit                  ; No, exit
+        test    si, si                  ; Text mode?
+        jz      @@Exit                  ; Yes, exit
+
+        dec     si                      ; Skip text mode
+        shl     si, 1
+        mov     si, TBL_Mode[si]
+        cld
+
+        mov     dx, TS
+        mov     ax, 0604h
+        out     dx, ax                  ; Disable chain-4 mode
+        mov     ax, 0100h
+        out     dx, ax                  ; Reset
+        mov     dx, MISC
+        lodsb
+        out     dx, al                  ; New timing/size
+        mov     dx, TS
+        mov     ax, 0300h
+        out     dx, ax                  ; Restart sequencer
+
+; Unlock CRTC registers 0-7
+        mov     dx, CRTC
+        mov     al, 11h
+        out     dx, al                  ; Vertical sync end register
+        inc     dx
+        in      al, dx
+        and     al, 7Fh                 ; Clear write protect bit
+        out     dx, al
+
+        lodsw                           ; Get X aspect
+        mov     [mx_AspectX], ax
+        lodsw                           ; Get Y aspect
+        mov     [mx_AspectY], ax
+        lodsw                           ; Get screen width
+        mov     [mx_ScreenWidth], ax
+        lodsw                           ; Get screen height
+        mov     [mx_ScreenHeight], ax
+
+; Set CRTC registers
+        mov     bx, si
+        mov     dx, CRTC
+@@TableLoop:
+        mov     si, ds:[bx]             ; DS:SI -> table of CRTC registers
+        inc     bx
+        inc     bx                      ; DS:BX -> offset of next table
+        test    si, si                  ; Last table?
+        jz      @@EndLoop               ; Yes, exit loop
+@@Loop:
+        lodsw                           ; Get CRTC register index and value
+        test    ax, ax                  ; End of table?
+        jz      @@TableLoop             ; Yes, go to next table
+        cmp     al, 13h                 ; Row address register?
+        je      @@Loop                  ; Yes, ignore it
+        out     dx, ax                  ; Set register AL to value AH
+        jmp     @@Loop                  ; Get next register/value
+@@EndLoop:
+
+; Lock CRTC registers 0-7 (some cards need this)
+        mov     dx, CRTC
+        mov     al, 11h
+        out     dx, al                  ; Vertical sync end register
+        inc     dx
+        in      al, dx
+        or      al, 80h                 ; Set write protect bit
+        out     dx, al
+
+@@Exit:
+        xor     ax, ax
+        mov     ax, [mx_ScreenWidth]
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxChangeMode    ENDP
+
+;-----------------------------------------------------------
+;
+; Returns the aspect ratio for the current mode.
+;
+; Input:
+;       AspectX = pointer to aspect X
+;       AspectY = pointer to aspect Y
+;
+; A rectangle of width AspectX and height AspectY looks like a square.
+;
+mxGetAspect     PROC FAR
+        ARG     AspectY:DWORD,  \
+                AspectX:DWORD   = ARG_SIZE
+        .enter  0
+        .push   ds, si
+        ASSUME  ds:NOTHING
+
+        lds     si, [AspectX]
+        mov     ax, [mx_AspectX]
+        mov     ds:[si], ax
+        lds     si, [AspectY]
+        mov     ax, [mx_AspectY]
+        mov     ds:[si], ax
+
+        .pop    ds, si
+        .leave  ARG_SIZE
+mxGetAspect     ENDP
+
+;-----------------------------------------------------------
+;
+; Returns the current screen size.
+;
+; Input:
+;       Width   = pointer to screen width
+;       Height  = pointer to screen height
+;
+mxGetScreenSize PROC FAR
+        ARG     SizeY:DWORD,    \
+                SizeX:DWORD     = ARG_SIZE
+        .enter  0
+        .push   ds, si
+        ASSUME  ds:NOTHING
+
+        lds     si, [SizeX]
+        mov     ax, [mx_ScreenWidth]
+        mov     ds:[si], ax
+        lds     si, [SizeY]
+        mov     ax, [mx_ScreenHeight]
+        mov     ds:[si], ax
+
+        .pop    ds, si
+        .leave  ARG_SIZE
+mxGetScreenSize ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXSP.ASM b/16/x/MXSP.ASM
new file mode 100755
index 00000000..1d08e711
--- /dev/null
+++ b/16/x/MXSP.ASM
@@ -0,0 +1,57 @@
+;-----------------------------------------------------------
+;
+; MXSP.ASM - Set palette function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxSetPalette
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Updates the VGA palette.
+;
+; Input:
+;       Buffer          = pointer to palette data (R,G,B)
+;       Start           = index of first color to set
+;       Count           = number of color to set
+; Output:
+;       none
+;
+mxSetPalette    PROC    FAR
+        ARG     Count:WORD,             \
+                Start:WORD,             \
+                Buffer:DWORD            = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds, si
+
+        lds     si, [Buffer]
+        mov     cx, [Count]
+        mov     ax, [Start]
+        mov     dx, 3C8h                ; PEL write address register
+        out     dx, al
+        inc     dx
+        cld
+        cli                             ; Disable interrupts
+@@Loop:
+        lodsb
+        out     dx, al                  ; Red
+        lodsb
+        out     dx, al                  ; Green
+        lodsb
+        out     dx, al                  ; Blue
+        loop    @@Loop                  ; Loop until done
+        sti                             ; Enable interrupts
+
+        .pop    ds, si
+        .leave  ARG_SIZE
+mxSetPalette    ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXSS.ASM b/16/x/MXSS.ASM
new file mode 100755
index 00000000..97df7366
--- /dev/null
+++ b/16/x/MXSS.ASM
@@ -0,0 +1,72 @@
+;-----------------------------------------------------------
+;
+; MXSS.ASM - Split screen function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxSplitScreen
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Splits the screen.
+;
+; Input:
+;       Line    = scan line at which screen has to be splitted
+; Output:
+;       none
+;
+mxSplitScreen   PROC    FAR
+        ARG     Line:WORD       = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+
+; Modify the line compare value: bits 0-7 are in the Line Compare
+; register (CRTC #18), bit 8 is in the Overflow Low register (CRTC #7)
+; and bit 9 is in the Maximum Row Address register (CRTC #9)
+        mov     ax, [Line]
+        shl     ax, 1                   ; Adjust line for mode "X"
+        mov     bh, ah
+        mov     bl, ah
+        and     bx, 0201h
+        mov     cl, 4
+        shl     bx, cl
+        shl     bh, 1
+        mov     dx, CRTC
+; Write bits 0-7 to line compare register
+        mov     ah, al
+        mov     al, 18h
+        out     dx, ax
+; Write bit 8 to overflow register
+        mov     al, 07h
+        out     dx, al
+        inc     dx
+        in      al, dx
+        dec     dx
+        mov     ah, al
+        and     ah, 11101111b
+        or      ah, bl
+        mov     al, 07h
+        out     dx, ax
+; Write bit 9 to maximum row address register
+        mov     al, 09h
+        out     dx, al
+        inc     dx
+        in      al, dx
+        dec     dx
+        mov     ah, al
+        and     ah, 10111111b
+        or      ah, bh
+        mov     al, 09h
+        out     dx, ax
+
+        .leave  ARG_SIZE
+mxSplitScreen   ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXTL.ASM b/16/x/MXTL.ASM
new file mode 100755
index 00000000..69900c88
--- /dev/null
+++ b/16/x/MXTL.ASM
@@ -0,0 +1,169 @@
+;-----------------------------------------------------------
+;
+; MXTL.ASM - Put tile
+; Copyright (c) 1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxPutTile
+PUBLIC  mxTransPutTile
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_VideoSegment : WORD
+EXTRN   mx_BytesPerLine : WORD
+
+;-----------------------------------------------------------
+;
+; Copies a "mode-x" tile from memory to screen.
+;
+; Input:
+;       Image   = pointer to tile
+;       X, Y    = coordinates of destination
+;       Width   = width of image in pixels (Width and 3 = 0)
+;       Height  = height of image in pixels
+; Output:
+;       none
+; Note:
+;       no clipping is performed on tiles!
+;
+mxPutTile       PROC    FAR
+        ARG     Height:WORD,            \
+                Width:WORD,             \
+                Y:WORD,                 \
+                X:WORD,                 \
+                Image:DWORD             = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds, si, es, di
+
+        mov     ax, [Y]                 ; Get pixel address
+        mul     [mx_BytesPerLine]
+        mov     di, [X]
+        .shr    di, 2
+        add     di, ax
+        mov     es, [mx_VideoSegment]
+
+        lds     si, [Image]             ; Get tile address
+        .shr    [Width], 2              ; Number of bytes per plane
+        mov     cl, BYTE PTR [X]
+        and     cl, 3
+        mov     ah, 11h                 ; AH = plane mask
+        shl     ah, cl                  ; Align mask to first plane
+
+        mov     [Y], 4                  ; Number of planes
+        mov     bx, [mx_BytesPerLine]
+        sub     bx, [Width]             ; Extra bytes per line
+@@Loop:
+        mov     al, 02h
+        mov     dx, TS
+        out     dx, ax                  ; Set write plane
+        mov     [X], di                 ; Save video offset
+        mov     dx, [Height]
+@@Loop2:
+        mov     cx, [Width]             ; Number of bytes to move
+
+        shr     cx, 1                   ; Move line
+        rep     movsw
+        rcl     cx, 1
+        rep     movsb
+
+        add     di, bx                  ; Move video offset to next line
+        dec     dx                      ; Done all lines?
+        jnz     @@Loop2                 ; No, continue
+        mov     di, [X]                 ; Restore video offset
+        rol     ah, 1                   ; Next plane
+        adc     di, 0                   ; Bump video offset if needed
+        dec     [Y]                     ; Any plane left?
+        jnz     @@Loop                  ; Yes, keep looping
+
+        xor     ax, ax
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxPutTile       ENDP
+
+;-----------------------------------------------------------
+;
+; Copies a "mode-x" tile from memory to screen.
+; Skips over color 0.
+;
+; Input:
+;       Image   = pointer to tile
+;       X, Y    = coordinates of destination
+;       Width   = width of image in pixels (Width and 3 = 0)
+;       Height  = height of image in pixels
+; Output:
+;       none
+; Note:
+;       no clipping is performed on tiles!
+;
+mxTransPutTile  PROC    FAR
+        ARG     Height:WORD,            \
+                Width:WORD,             \
+                Y:WORD,                 \
+                X:WORD,                 \
+                Image:DWORD             = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds, si, es, di
+
+        mov     ax, [Y]                 ; Get pixel address
+        mul     [mx_BytesPerLine]
+        mov     di, [X]
+        .shr    di, 2
+        add     di, ax
+        mov     es, [mx_VideoSegment]
+
+        lds     si, [Image]             ; Get tile address
+        .shr    [Width], 2              ; Number of bytes per plane
+        mov     cl, BYTE PTR [X]
+        and     cl, 3
+        mov     ah, 11h                 ; AH = plane mask
+        shl     ah, cl                  ; Align mask to first plane
+
+        mov     [Y], 4                  ; Number of planes
+        mov     bx, [mx_BytesPerLine]
+        sub     bx, [Width]             ; Extra bytes per line
+@@Loop:
+        mov     al, 02h
+        mov     dx, TS
+        out     dx, ax                  ; Set write plane
+        mov     [X], di                 ; Save video offset
+        mov     dx, [Height]
+@@Loop2:
+        mov     cx, [Width]             ; Number of bytes to move
+
+; Move one line
+        jcxz    @@MoveLineDone
+@@MoveLineLoop:
+        mov     al, ds:[si]
+        test    al, al
+        jz      @@MoveLineNext
+        mov     es:[di], al
+@@MoveLineNext:
+        inc     si
+        inc     di
+        dec     cx
+        jnz     @@MoveLineLoop
+@@MoveLineDone:
+
+        add     di, bx                  ; Move video offset to next line
+        dec     dx                      ; Done all lines?
+        jnz     @@Loop2                 ; No, continue
+        mov     di, [X]                 ; Restore video offset
+        rol     ah, 1                   ; Next plane
+        adc     di, 0                   ; Bump video offset if needed
+        dec     [Y]                     ; Any plane left?
+        jnz     @@Loop                  ; Yes, keep looping
+
+        xor     ax, ax
+        .pop    ds, si, es, di
+        .leave  ARG_SIZE
+mxTransPutTile  ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXVS.ASM b/16/x/MXVS.ASM
new file mode 100755
index 00000000..992eabab
--- /dev/null
+++ b/16/x/MXVS.ASM
@@ -0,0 +1,110 @@
+;-----------------------------------------------------------
+;
+; MXVS.ASM - Set/get virtual screen
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+NOWARN  RES
+INCLUDE MODEX.DEF
+
+PUBLIC  mxSetVirtualScreen
+PUBLIC  mxGetVirtualScreen
+
+EXTRN   mxRowAddress            : FAR
+EXTRN   mxSetSysClipRegion      : FAR
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+EXTRN   mx_BytesPerLine : WORD
+EXTRN   mx_CodeSegment  : WORD
+
+mx_VirtualWidth         DW      ?       ; Virtual screen size
+mx_VirtualHeight        DW      ?
+
+;-----------------------------------------------------------
+;
+; Sets the virtual screen.
+;
+; Input:
+;       Width   = virtual screen width
+;       Height  = virtual screen height
+; Output:
+;       0 on success, else invalid parameters
+;
+mxSetVirtualScreen      PROC    FAR
+        ARG     Height:WORD,            \
+                Width:WORD              = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds
+
+; Set DS to code segment
+        mov     ds, [mx_CodeSegment]
+        ASSUME  ds:MX_TEXT
+
+        mov     ax, 1                   ; Assume an error
+        cmp     [Width], 320            ; Check width
+        jb      @@Exit
+        push    ax                      ; Save return code
+        mov     dx, 0004h
+        xor     ax, ax                  ; DX:AX = 256K
+        div     [Width]                 ; Max height in AX
+        cmp     [Height], ax
+        pop     ax                      ; Restore return code
+        ja      @@Exit                  ; Exit if bad heigth
+
+        mov     ax, [Width]
+        and     ax, 0FFF8h              ; Align to byte
+        mov     [mx_VirtualWidth], ax
+        shr     ax, 1
+        shr     ax, 1
+        mov     [mx_BytesPerLine], ax
+        shr     ax, 1
+        push    ax
+        call    mxRowAddress            ; Set row address
+        mov     ax, [Height]
+        mov     [mx_VirtualHeight], ax
+
+        push    [Width]
+        push    [Height]
+        call    mxSetSysClipRegion
+        xor     ax, ax
+
+@@Exit:
+        .pop    ds
+        .leave  ARG_SIZE
+mxSetVirtualScreen      ENDP
+
+;-----------------------------------------------------------
+;
+; Returns the current virtual screen size.
+;
+; Input:
+;       Width   = pointer to virtual screen width
+;       Height  = pointer to virtual screen height
+; Output:
+;       none
+;
+mxGetVirtualScreen      PROC    FAR
+        ARG     Height:DWORD,           \
+                Width:DWORD             = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        .push   ds, si
+
+        mov     ax, [mx_VirtualWidth]
+        lds     si, [Width]
+        mov     ds:[si], ax
+        mov     ax, [mx_VirtualHeight]
+        lds     si, [Height]
+        mov     ds:[si], ax
+
+        xor     ax, ax
+        .pop    ds, si
+        .leave  ARG_SIZE
+mxGetVirtualScreen      ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXWD.ASM b/16/x/MXWD.ASM
new file mode 100755
index 00000000..de55208f
--- /dev/null
+++ b/16/x/MXWD.ASM
@@ -0,0 +1,28 @@
+;-----------------------------------------------------------
+;
+; MXWD.ASM - Wait display function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxWaitDisplay
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Waits for display start.
+;
+mxWaitDisplay   PROC    FAR
+        mov     dx, STATUS
+@@1:    in      al, dx
+        test    al, 08h
+        jnz     @@1
+        ret
+mxWaitDisplay   ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXWM.ASM b/16/x/MXWM.ASM
new file mode 100755
index 00000000..06158859
--- /dev/null
+++ b/16/x/MXWM.ASM
@@ -0,0 +1,39 @@
+;-----------------------------------------------------------
+;
+; MXWM.ASM - Set write mode function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxWriteMode
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Sets the write mode.
+;
+; Input:
+;       Mode    = write mode (0,1,2,3)
+; Output:
+;       none
+;
+mxWriteMode     PROC    FAR
+        ARG     Mode:BYTE:2     = ARG_SIZE
+        .enter  0
+
+        mov     dx, GDC
+        mov     ah, [Mode]
+        and     ah, 00000011b
+        or      ah, 01000000b
+        mov     al, 05h
+        out     dx, ax
+
+        .leave  ARG_SIZE
+mxWriteMode     ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXWP.ASM b/16/x/MXWP.ASM
new file mode 100755
index 00000000..19ca99d0
--- /dev/null
+++ b/16/x/MXWP.ASM
@@ -0,0 +1,62 @@
+;-----------------------------------------------------------
+;
+; MXWP.ASM - Set write/read plane functions
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxWritePlane
+PUBLIC  mxReadPlane
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Sets the write plane(s).
+;
+; Input:
+;       Plane   = write plane(s) to set (bit 0 enables plane 0,
+;                 bit 1 enables plane 1 and so on, different planes
+;                 may be selected at the same time)
+; Output:
+;       none
+;
+mxWritePlane    PROC    FAR
+        ARG     Plane:BYTE:2    = ARG_SIZE
+        .enter  0
+
+        mov     ah, [Plane]
+        and     ah, 00001111b           ; Mask off unused bits
+        mov     al, 02h
+        mov     dx, TS
+        out     dx, ax
+
+        .leave  ARG_SIZE
+mxWritePlane    ENDP
+
+;-----------------------------------------------------------
+;
+; Sets the read plane.
+;
+; Input:
+;       Plane   = read plane to set (0,1,2,3)
+; Output:
+;       none
+;
+mxReadPlane     PROC    FAR
+        ARG     Plane:BYTE:2    = ARG_SIZE
+        ASSUME  ds:NOTHING
+        .enter  0
+        mov     al, 04h
+        mov     ah, [Plane]
+        and     ah, 0000011b            ; Mask off unused bits
+        mov     dx, GDC
+        out     dx, ax
+        .leave  ARG_SIZE
+mxReadPlane     ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/MXWR.ASM b/16/x/MXWR.ASM
new file mode 100755
index 00000000..bd29fe59
--- /dev/null
+++ b/16/x/MXWR.ASM
@@ -0,0 +1,28 @@
+;-----------------------------------------------------------
+;
+; MXWR.ASM - Wait vertical retrace function
+; Copyright (c) 1993,1994 by Alessandro Scotti
+;
+;-----------------------------------------------------------
+WARN    PRO
+INCLUDE MODEX.DEF
+
+PUBLIC  mxWaitRetrace
+
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
+
+;-----------------------------------------------------------
+;
+; Waits for vertical retrace start.
+;
+mxWaitRetrace   PROC    FAR
+        mov     dx, STATUS
+@@1:    in      al,dx
+        test    al, 08h
+        jz      @@1
+        ret
+mxWaitRetrace   ENDP
+
+MX_TEXT         ENDS
+END
diff --git a/16/x/readme.txt b/16/x/readme.txt
new file mode 100755
index 00000000..306e8b9a
--- /dev/null
+++ b/16/x/readme.txt
@@ -0,0 +1,8 @@
+ModeX - A graphical library for DOS programs
+Copyright (c) 1993-1994 Alessandro Scotti
+http://www.ascotti.org/
+
+Please look at the above site in the "Art of..." and
+then in the "Old programs" section for more information.
+
+
-- 
2.39.5