]> 4ch.mooo.com Git - 16.git/commitdiff
readded modex library
authorsparky4 <sparky4@cock.li>
Thu, 19 Nov 2015 18:12:28 +0000 (12:12 -0600)
committersparky4 <sparky4@cock.li>
Thu, 19 Nov 2015 18:12:28 +0000 (12:12 -0600)
47 files changed:
16/x/DEFAULT.FNT [new file with mode: 0755]
16/x/MAKEFILE [new file with mode: 0755]
16/x/MODEX.BAK [new file with mode: 0755]
16/x/MODEX.DEF [new file with mode: 0755]
16/x/MODEX.H [new file with mode: 0755]
16/x/MODEX.LBR [new file with mode: 0755]
16/x/MODEX.PAS [new file with mode: 0755]
16/x/MXBB.ASM [new file with mode: 0755]
16/x/MXCC.ASM [new file with mode: 0755]
16/x/MXCG.ASM [new file with mode: 0755]
16/x/MXCL.ASM [new file with mode: 0755]
16/x/MXCR.ASM [new file with mode: 0755]
16/x/MXEL.ASM [new file with mode: 0755]
16/x/MXFB.ASM [new file with mode: 0755]
16/x/MXFP.ASM [new file with mode: 0755]
16/x/MXGC.ASM [new file with mode: 0755]
16/x/MXGI.ASM [new file with mode: 0755]
16/x/MXGM.ASM [new file with mode: 0755]
16/x/MXGP.ASM [new file with mode: 0755]
16/x/MXGV.ASM [new file with mode: 0755]
16/x/MXHL.ASM [new file with mode: 0755]
16/x/MXIT.ASM [new file with mode: 0755]
16/x/MXLL.ASM [new file with mode: 0755]
16/x/MXLN.ASM [new file with mode: 0755]
16/x/MXOT.ASM [new file with mode: 0755]
16/x/MXPB.ASM [new file with mode: 0755]
16/x/MXPF.ASM [new file with mode: 0755]
16/x/MXPG.ASM [new file with mode: 0755]
16/x/MXPI.ASM [new file with mode: 0755]
16/x/MXPN.ASM [new file with mode: 0755]
16/x/MXPP.ASM [new file with mode: 0755]
16/x/MXRA.ASM [new file with mode: 0755]
16/x/MXRP.ASM [new file with mode: 0755]
16/x/MXSA.ASM [new file with mode: 0755]
16/x/MXSC.ASM [new file with mode: 0755]
16/x/MXSI.ASM [new file with mode: 0755]
16/x/MXSL.ASM [new file with mode: 0755]
16/x/MXSM.ASM [new file with mode: 0755]
16/x/MXSP.ASM [new file with mode: 0755]
16/x/MXSS.ASM [new file with mode: 0755]
16/x/MXTL.ASM [new file with mode: 0755]
16/x/MXVS.ASM [new file with mode: 0755]
16/x/MXWD.ASM [new file with mode: 0755]
16/x/MXWM.ASM [new file with mode: 0755]
16/x/MXWP.ASM [new file with mode: 0755]
16/x/MXWR.ASM [new file with mode: 0755]
16/x/readme.txt [new file with mode: 0755]

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