--- /dev/null
+;\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
--- /dev/null
+#\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
--- /dev/null
+;------------------------------------------------------------\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
--- /dev/null
+/*\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
--- /dev/null
++-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
--- /dev/null
+(*\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
--- /dev/null
+(*\r
+ DEMO01 - Sprites, page flipping and palette rotation\r
+ Copyright (c) 1994 Alessandro Scotti\r
+*)\r
+uses Crt, Modex;\r
+\r
+const\r
+ MAX_SPRITE = 100;\r
+type\r
+ (* Sprite structure *)\r
+ TSprite = record\r
+ X, Y : integer; (* Sprite coordinates *)\r
+ DX,DY: integer; (* Deltas for sprite movement *)\r
+ W, H : integer; (* Sprite width and height *)\r
+ Image: array[ 1..16, 1..16 ] of byte; (* Sprite image data *)\r
+ end;\r
+ (* RGB color structure *)\r
+ TRgb = record\r
+ R, G, B: byte;\r
+ end;\r
+var\r
+ S : array[ 1..MAX_SPRITE ] of TSprite; (* An array of sprites *)\r
+ Palette: array[ byte ] of TRgb; (* Palette *)\r
+ Page : word; (* Page offset *)\r
+ I : word;\r
+\r
+(* Initializes a sprite structure *)\r
+procedure sxInit( var S: TSprite );\r
+var\r
+ I: word;\r
+begin\r
+ S.X := Random( 320 ); (* Initialize position with random values *)\r
+ S.Y := Random( 240 );\r
+ S.DX := Random( 7 )-3; (* Initialize speed with random values *)\r
+ S.DY := Random( 7 )-3;\r
+ S.W := 16; (* Size is fixed in this program *)\r
+ S.H := 16;\r
+ (* The image is a square with a hole inside *)\r
+ FillChar( S.Image, SizeOf(S.Image), Random(15)+1 );\r
+ for I:=5 to 12 do FillChar( S.Image[ I, 5 ], 8, 0 );\r
+end;\r
+\r
+(* Moves a sprite *)\r
+procedure sxMove( var S: TSprite );\r
+begin\r
+ Inc( S.X, S.DX ); (* Get new position *)\r
+ Inc( S.Y, S.DY );\r
+ (* Check sprite position, change delta if needed *)\r
+ if( S.X > 320 ) then begin\r
+ S.X := 320;\r
+ S.DX := -S.DX;\r
+ end;\r
+ if( S.X < -16 ) then begin\r
+ S.X := -16;\r
+ S.DX := -S.DX;\r
+ end;\r
+ if( S.Y > 240 ) then begin\r
+ S.Y := 240;\r
+ S.DY := -S.DY;\r
+ end;\r
+ if( S.Y < -16 ) then begin\r
+ S.Y := -16;\r
+ S.DY := -S.DY;\r
+ end;\r
+ (* Draw the sprite, note the Page offset added to the *)\r
+ (* Y coordinate of the image *)\r
+ mxPutImage( @S.Image, S.X, Page+S.Y, S.W, S.H, OP_TRANS );\r
+end;\r
+\r
+begin\r
+ (* Initialize library *)\r
+ mxInit;\r
+\r
+ (* Enter graphics mode *)\r
+ mxSetMode( MX_320x240 );\r
+\r
+ (* Print initialization message *)\r
+ mxSetTextColor( 15, OP_TRANS );\r
+ mxOutStr( 4, 4, 'Initializing...' );\r
+\r
+ (* Initialize sprites *)\r
+ for I:=1 to MAX_SPRITE do sxInit( S[I] );\r
+\r
+ (* Draw background *)\r
+ for I:=1 to 192 do begin\r
+ mxCircle( 160, 480+120, I, I+63 );\r
+ mxCircle( 161, 480+120, I, I+63 );\r
+ end;\r
+\r
+ (* Compute and set palette *)\r
+ for I:=1 to 192 do with Palette[I+63] do begin\r
+ R := 0;\r
+ G := 0;\r
+ B := 0;\r
+ if( I < 64 ) then\r
+ R := I shr 1+31\r
+ else if( I < 128 ) then\r
+ G := (I-64) shr 1+31\r
+ else\r
+ B := (I-128) shr 1+31;\r
+ end;\r
+ mxSetPalette( @Palette[64], 64, 192 );\r
+\r
+ (* Main loop *)\r
+ Page := 240;\r
+ while( not KeyPressed ) do begin\r
+ (* Set clip region to current page *)\r
+ mxSetClipRegion( 0, Page, 320, 240 );\r
+ mxSetClip( TRUE );\r
+ (* Restore background *)\r
+ mxBitBlt( 0, 480, 320, 240, 0, Page );\r
+ (* Draw sprites *)\r
+ for I:=1 to MAX_SPRITE do sxMove( S[I] );\r
+ (* Print message *)\r
+ mxOutStr( 4, Page+4, 'Some sprites moving...' );\r
+ (* Flip page *)\r
+ mxStartLine( Page );\r
+ Page := 240-Page;\r
+ (* Animate palette *)\r
+ mxSetPalette( @Palette[64], 64, 192 );\r
+ mxRotatePalette( @Palette[64], 192, 3 );\r
+ end;\r
+\r
+ mxSetMode( MX_TEXT );\r
+ mxTerm;\r
+end.\r
--- /dev/null
+(*\r
+ DEMO02 - Texture mapping and palette rotation\r
+ (c) 1994 by Alessandro Scotti\r
+*)\r
+uses Crt, Modex, Plasma, Threed;\r
+\r
+const\r
+ LSIZE = 85;\r
+ Trans : TPoint = ( X:0; Y:0; Z:0 );\r
+type\r
+ T2DPoint = record\r
+ X, Y: integer;\r
+ end;\r
+ TTexture = record\r
+ Desc : array[ 0..3 ] of T2DPoint;\r
+ Width : word;\r
+ Data : array[ 1..64*64 ] of byte;\r
+ end;\r
+ TQuad = record\r
+ VtxCnt : word;\r
+ Vtx : array[ 0..3 ] of word;\r
+ Texture: word;\r
+ end;\r
+var\r
+ Vtx : array[ 0..7 ] of TPoint;\r
+ XVtx : array[ 0..7 ] of TPoint;\r
+ VVtx : array[ 0..7 ] of T2DPoint;\r
+ Face : array[ 0..5 ] of TQuad;\r
+ Txts : array[ 0..5 ] of TTexture;\r
+ Nrm : array[ 0..5 ] of TPoint;\r
+ XNrm : array[ 0..5 ] of TPoint;\r
+ Page : word;\r
+ Palette: array[ byte ] of record R, G, B: byte; end;\r
+\r
+(* Make a 64x64 plasma to be used as texture *)\r
+procedure MakeTexture( Idx: word );\r
+var\r
+ I: word;\r
+begin\r
+ mxFillBox( 0, 0, 64, 64, 0, OP_SET );\r
+ MakePlasma( 0, 0, 64, 64, 96, Random(192)+1, Random(192)+1, Random(192)+1 );\r
+ mxGetImage( @Txts[Idx].Data, 0, 0, 64, 64 );\r
+ (* Texture vertexes are 8:8 fixed, add $80 (0.5) for best results *)\r
+ with Txts[Idx] do begin\r
+ Desc[0].X := $80; Desc[0].Y := $80;\r
+ Desc[1].X := $80; Desc[1].Y := $3F80;\r
+ Desc[2].X := $3F80; Desc[2].Y := $3F80;\r
+ Desc[3].X := $3F80; Desc[3].Y := $80;\r
+ Width := 64;\r
+ end;\r
+end;\r
+\r
+procedure Init;\r
+var\r
+ I: integer;\r
+begin\r
+ (* Build vertexes for a cube *)\r
+ with Vtx[0] do begin X:=-LSIZE; Y:=-LSIZE; Z:=-LSIZE; end;\r
+ with Vtx[1] do begin X:=+LSIZE; Y:=-LSIZE; Z:=-LSIZE; end;\r
+ with Vtx[2] do begin X:=-LSIZE; Y:=+LSIZE; Z:=-LSIZE; end;\r
+ with Vtx[3] do begin X:=+LSIZE; Y:=+LSIZE; Z:=-LSIZE; end;\r
+ with Vtx[4] do begin X:=-LSIZE; Y:=-LSIZE; Z:=+LSIZE; end;\r
+ with Vtx[5] do begin X:=+LSIZE; Y:=-LSIZE; Z:=+LSIZE; end;\r
+ with Vtx[6] do begin X:=-LSIZE; Y:=+LSIZE; Z:=+LSIZE; end;\r
+ with Vtx[7] do begin X:=+LSIZE; Y:=+LSIZE; Z:=+LSIZE; end;\r
+ for I:=0 to 7 do begin (* Make points 16:16 fixed *)\r
+ Vtx[I].X := Vtx[I].X*$10000;\r
+ Vtx[I].Y := Vtx[I].Y*$10000;\r
+ Vtx[I].Z := Vtx[I].Z*$10000;\r
+ end;\r
+ (* Build faces *)\r
+ with Face[0] do begin Vtx[0]:=0; Vtx[1]:=2; Vtx[2]:=3; Vtx[3]:=1; end;\r
+ with Face[1] do begin Vtx[0]:=4; Vtx[1]:=5; Vtx[2]:=7; Vtx[3]:=6; end;\r
+ with Face[2] do begin Vtx[0]:=0; Vtx[1]:=1; Vtx[2]:=5; Vtx[3]:=4; end;\r
+ with Face[3] do begin Vtx[0]:=1; Vtx[1]:=3; Vtx[2]:=7; Vtx[3]:=5; end;\r
+ with Face[4] do begin Vtx[0]:=2; Vtx[1]:=0; Vtx[2]:=4; Vtx[3]:=6; end;\r
+ with Face[5] do begin Vtx[0]:=7; Vtx[1]:=3; Vtx[2]:=2; Vtx[3]:=6; end;\r
+ for I:=0 to 5 do Face[I].Texture := I;\r
+ (* Build textures and palette *)\r
+ Randomize;\r
+ FillChar( Palette, SizeOf(Palette), 0 );\r
+ MakePlasmaPalette( Palette, PAL_RGB );\r
+ mxSetPalette( @Palette, 0, 193 );\r
+ for I:=0 to 5 do MakeTexture( I );\r
+end;\r
+\r
+var\r
+ AX, AY, AZ: byte;\r
+ I: word;\r
+begin\r
+ mxInit;\r
+ mxSetMode( MX_320x240 );\r
+ Init;\r
+ Page := 240; (* Start with hidden page *)\r
+\r
+ AX := 0;\r
+ AY := 0;\r
+ AZ := 0;\r
+ (* Init 3D transforms, perspective is intentionally exaggerated *)\r
+ tdSetTranslation( Trans );\r
+ tdSetPerspective( 400*$10000, $10000, $10000 );\r
+ (* Main loop, all magic here! *)\r
+ while( not KeyPressed ) do begin\r
+ tdSetRotation( AX, AY, AZ ); (* Set new angles *)\r
+ tdTransform( Vtx, XVtx, 8 ); (* 3D transform points *)\r
+ tdTransformToImage( XVtx, VVtx, 8, 160, 120+Page );\r
+ Inc( AX, 1 ); (* Bump angles *)\r
+ Inc( AY, 1 );\r
+ Inc( AZ, 2 );\r
+ mxSetClipRegion( 0, Page, 320, 240 ); (* Set clip to new page *)\r
+ mxSetClip( TRUE );\r
+ mxFillBox( 0, Page, 320, 240, 0, OP_MOVE ); (* Clear screen *)\r
+ mxRotatePalette( @Palette[1], 192, 3 ); (* Rotate palette *)\r
+ (* Draw cube: backface culling is straighforward in this case, so *)\r
+ (* it can be handled by the polygon filling procedure *)\r
+ for I:=0 to 5 do\r
+ mxTexturePoly( 4, Face[I].Vtx, VVtx, Txts[I].Desc, Txts[I].Data, Txts[I].Width );\r
+ mxStartLine( Page ); (* Flip pages *)\r
+ mxSetPalette( @Palette[1], 1, 192 ); (* Set new palette *)\r
+ Page := 240-Page;\r
+ end;\r
+\r
+ mxSetMode( MX_TEXT );\r
+ mxTerm;\r
+end.\r
--- /dev/null
+(*\r
+ DEMO03 - Simple star animation, morphs between a cube and a sphere\r
+ (c) 1994 by Alessandro Scotti\r
+*)\r
+uses Crt, Modex, Threed;\r
+\r
+const\r
+ MAXVTX = 1000; (* Number of points *)\r
+ EDGE = 70; (* Length of cube edge *)\r
+ RADIUS = 90; (* Radius of sphere *)\r
+ WAITCOUNT = 192; (* Frames to wait for non-morphing shapes *)\r
+ MS = 32; (* Number of steps for morphing *)\r
+ Trans : TPoint = ( X:0; Y:0; Z:0 );\r
+ InitMorph1: array[ 0..3 ] of integer = ( 0, MS, 0, 0 );\r
+ InitMorph2: array[ 0..3 ] of integer = ( 0, 0, 0, MS );\r
+ InitDelta1: array[ 0..3 ] of integer = ( 0, -1, 0, +1 );\r
+ InitDelta2: array[ 0..3 ] of integer = ( 0, +1, 0, -1 );\r
+type\r
+ T2DPoint = record\r
+ X, Y: integer;\r
+ end;\r
+ T3DPointArray = array[ 0..MAXVTX-1 ] of TPoint;\r
+ P3DPointArray = ^T3DPointArray;\r
+var\r
+ CubeVtx, SphereVtx, Vtx, XVtx: P3DPointArray;\r
+ VVtx : array[ 0..MAXVTX-1 ] of T2DPoint;\r
+ Page : word;\r
+ Status, Count, Delta1, Delta2, Morph1, Morph2: integer;\r
+\r
+procedure Swap( var A, B: longint );\r
+var\r
+ L: longint;\r
+begin\r
+ L := A; A := B; B := L;\r
+end;\r
+\r
+function Toggle( A: longint ): longint;\r
+begin\r
+ Toggle := A;\r
+ if( Random(2) = 0 ) then Toggle := -A;\r
+end;\r
+\r
+procedure Init;\r
+label Retry;\r
+var\r
+ I: integer;\r
+begin\r
+ New( CubeVtx );\r
+ New( SphereVtx );\r
+ New( Vtx );\r
+ New( XVtx );\r
+ (* Build vertexes (yes, I know this piece of code is terrible) *)\r
+ Randomize;\r
+ for I:=0 to MAXVTX-1 do begin\r
+ with CubeVtx^[I] do begin\r
+ (* Build cube *)\r
+ X := (longint(Random(2*EDGE))-EDGE)*$10000;\r
+ Y := (longint(Random(2*EDGE))-EDGE)*$10000;\r
+ Z := Toggle( EDGE*$10000 );\r
+ case Random(3) of\r
+ 0: Swap( X, Z );\r
+ 1: Swap( Y, Z );\r
+ end;\r
+ end;\r
+ with SphereVtx^[I] do begin\r
+ (* Build sphere *)\r
+Retry:\r
+ X := (longint(Random(2*RADIUS))-RADIUS);\r
+ Y := (longint(Random(2*RADIUS))-RADIUS);\r
+ if( X*X+Y*Y > RADIUS*RADIUS ) then goto Retry;\r
+ Z := Toggle( Round( Sqrt( Abs( RADIUS*RADIUS-X*X-Y*Y ) ) ) );\r
+ case Random(3) of\r
+ 0: Swap( X, Z );\r
+ 1: Swap( Y, Z );\r
+ end;\r
+ X := X * $10000; Y := Y * $10000; Z := Z * $10000;\r
+ end;\r
+ end;\r
+ (* Initialize morphing *)\r
+ Move( CubeVtx^, Vtx^, SizeOf(Vtx^) );\r
+ Status := 0;\r
+ Count := WAITCOUNT;\r
+end;\r
+\r
+procedure Morph;\r
+var\r
+ I: integer;\r
+begin\r
+ (* Fully unoptimized, slowest loop I could think of! *)\r
+ for I:=0 to MAXVTX-1 do begin\r
+ Vtx^[I].X := ((CubeVtx^[I].X * Morph1)+(SphereVtx^[I].X * Morph2)) div MS;\r
+ Vtx^[I].Y := ((CubeVtx^[I].Y * Morph1)+(SphereVtx^[I].Y * Morph2)) div MS;\r
+ Vtx^[I].Z := ((CubeVtx^[I].Z * Morph1)+(SphereVtx^[I].Z * Morph2)) div MS;\r
+ end;\r
+end;\r
+\r
+var\r
+ AX, AY, AZ: byte;\r
+ I: word;\r
+ C: char;\r
+begin\r
+ mxInit;\r
+ mxSetMode( MX_320x240 );\r
+ Init;\r
+ Page := 240; (* Start with hidden page *)\r
+\r
+ AX := 0;\r
+ AY := 0;\r
+ AZ := 0;\r
+ (* Init 3D transforms, perspective is intentionally exaggerated *)\r
+ tdSetTranslation( Trans );\r
+ tdSetPerspective( 400*$10000, $10000, $10000 );\r
+ C := #0;\r
+ repeat\r
+ tdSetRotation( AX, AY, AZ ); (* Set new angles *)\r
+ tdTransform( Vtx^, XVtx^, MAXVTX ); (* 3D transform points *)\r
+ tdTransformToImage( XVtx^, VVtx, MAXVTX, 160, 120+Page );\r
+ Inc( AX, 1 ); (* Bump angles *)\r
+ Inc( AY, 1 );\r
+ Inc( AZ, 2 );\r
+ mxSetClipRegion( 0, Page, 320, 240 ); (* Set clip to new page *)\r
+ mxSetClip( TRUE );\r
+ mxFillBox( 0, Page, 320, 240, 0, OP_MOVE ); (* Clear screen *)\r
+ (* Draw points *)\r
+ for I:=0 to MAXVTX-1 do\r
+ mxPutPixel( VVtx[I].X, VVtx[I].Y, 128 + XVtx^[I].Z shr 18 );\r
+ mxStartLine( Page ); (* Flip pages *)\r
+ Page := 240-Page;\r
+ (* Morph *)\r
+ if( Odd(Status) ) then begin\r
+ Morph;\r
+ Inc( Morph1, Delta1 );\r
+ Inc( Morph2, Delta2 );\r
+ if( Morph1 < 0 )or( Morph2 < 0 ) then Inc( Status );\r
+ if( Status = 4 ) then Status := 0;\r
+ end\r
+ else begin\r
+ Dec( Count );\r
+ if( Count < 0 ) then begin\r
+ Inc( Status );\r
+ Count := WAITCOUNT;\r
+ Morph1 := InitMorph1[Status];\r
+ Morph2 := InitMorph2[Status];\r
+ Delta1 := InitDelta1[Status];\r
+ Delta2 := InitDelta2[Status];\r
+ end;\r
+ end;\r
+ until( KeyPressed );\r
+\r
+ mxSetMode( MX_TEXT );\r
+ mxTerm;\r
+end.\r
--- /dev/null
+(*\r
+ DEMO04 - Multiple textures and triple buffering (3 pages)\r
+ (c) 1994 by Alessandro Scotti\r
+*)\r
+uses Crt, Modex, Threed;\r
+\r
+const\r
+ MAXVTX = 256;\r
+ MAXCUB = 2;\r
+ MAXTXT = 2;\r
+ Trans : TPoint = ( X:0; Y:0; Z:0 );\r
+ TxtSunDial: array[ 0..7 ] of word = (\r
+ $7F80,$0080, $0080,$0080, $0080,$7E80, $7F80,$7E80 );\r
+ TxtSapphire : array[ 0..7 ] of word = (\r
+ $0080,$0080, $0080,$1F80, $1F80,$1F80, $1F80,$0080 );\r
+ TxtMarble: array[ 0..7 ] of word = (\r
+ $0080,$8080, $0080,$FD80, $7F80,$FD80, $7F80,$8080 );\r
+type\r
+ T2DPoint = record\r
+ X, Y: integer;\r
+ end;\r
+ TTexture = record\r
+ Desc : array[ 0..3 ] of record X, Y: word end;\r
+ Width : word;\r
+ Data : pointer;\r
+ end;\r
+ TQuad = record\r
+ Vtx : array[ 0..3 ] of word;\r
+ Texture: word;\r
+ end;\r
+ TCube = record\r
+ Face : array[ 0..5 ] of TQuad;\r
+ Base : integer;\r
+ end;\r
+var\r
+ Vtx, XVtx: array[ 0..MAXVTX ] of TPoint;\r
+ VVtx : array[ 0..MAXVTX ] of T2DPoint;\r
+ Cube : array[ 0..MAXCUB ] of TCube;\r
+ ZList : array[ 0..MAXCUB ] of integer;\r
+ VtxCnt : word;\r
+ Txts : array[ 0..MAXTXT ] of TTexture;\r
+ Page : word;\r
+ Palette : array[ byte ] of record R, G, B: byte; end;\r
+ TxtDat1, TxtDat2: pointer;\r
+\r
+(* Add a new entry to the vertex array *)\r
+procedure AddVtx( PX, PY, PZ: longint );\r
+begin\r
+ with Vtx[VtxCnt] do begin X:=PX*$10000; Y:=PY*$10000; Z:=PZ*$10000; end;\r
+ Inc( VtxCnt );\r
+end;\r
+\r
+procedure MakeCube( var C: TCube; X1,Y1,Z1, X2,Y2,Z2, TX,TY,TZ, Texture: integer );\r
+const\r
+ FaceIdx: array[ 0..23 ] of integer = (\r
+ 0,1,2,3, 0,4,5,1, 1,5,6,2, 2,6,7,3, 3,7,4,0, 6,5,4,7 );\r
+var\r
+ I, VC: integer;\r
+begin\r
+ VC := VtxCnt;\r
+ C.Base := VC;\r
+ AddVtx( X1+TX, Y1+TY, Z1+TZ );\r
+ AddVtx( X2+TX, Y1+TY, Z1+TZ );\r
+ AddVtx( X2+TX, Y2+TY, Z1+TZ );\r
+ AddVtx( X1+TX, Y2+TY, Z1+TZ );\r
+ AddVtx( X1+TX, Y1+TY, Z2+TZ );\r
+ AddVtx( X2+TX, Y1+TY, Z2+TZ );\r
+ AddVtx( X2+TX, Y2+TY, Z2+TZ );\r
+ AddVtx( X1+TX, Y2+TY, Z2+TZ );\r
+ for I:=0 to 23 do C.Face[I shr 2].Vtx[I and 3] := VC+FaceIdx[I];\r
+ for I:=0 to 5 do C.Face[I].Texture := Texture;\r
+end;\r
+\r
+procedure MakeTexture( Idx: integer; var VtxData );\r
+var\r
+ P: ^word;\r
+ I: integer;\r
+begin\r
+ P := @VtxData;\r
+ with Txts[Idx] do begin\r
+ for I:=0 to 3 do begin\r
+ Desc[I].X := P^; Inc( P );\r
+ Desc[I].Y := P^; Inc( P );\r
+ end;\r
+ Width := 129;\r
+ Data := TxtDat1;\r
+ end;\r
+end;\r
+\r
+procedure Init;\r
+var\r
+ I: integer;\r
+ V: integer;\r
+ F: file;\r
+ P: array[ 1..768 ] of byte;\r
+begin\r
+ (* Initialize objects *)\r
+ VtxCnt := 0;\r
+ MakeCube( Cube[0], -64,-64,8, 64,64,-8, 0,0,0, 1 ); (* Sundial *)\r
+ Cube[0].Face[0].Texture := 0;\r
+ V := VtxCnt;\r
+ MakeCube( Cube[1], -16,-16,16, 16,16,-16, 0,0,0, 2 ); (* Sapphire *)\r
+ tdSetTranslation( Trans );\r
+ tdSetRotation( 32, 32, 00 );\r
+ tdRotate( Vtx[V], XVtx[V], 8 ); (* Got to rotate this cube *)\r
+ for I:=V to V+7 do begin\r
+ Vtx[I].X := XVtx[I].X;\r
+ Vtx[I].Y := XVtx[I].Y;\r
+ Vtx[I].Z := XVtx[I].Z + 100*$10000;\r
+ end;\r
+ MakeCube( Cube[2], -64,-4,48, 64,4,-48, 0,68,56, 1 ); (* Marble *)\r
+ (* Load texture and palette *)\r
+ Assign( F, 'DEMO04.DAT' );\r
+ Reset( F, 1 );\r
+ BlockRead( F, P, SizeOf(P) );\r
+ mxSetPalette( @P, 0, 256 );\r
+ GetMem( TxtDat1, 63*1024 );\r
+ BlockRead( F, TxtDat1^, 129*286 );\r
+ Close( F );\r
+ TxtDat2 := Ptr( Seg(TxtDat1^), Ofs(TxtDat1^)+129*254 );\r
+ (* Init textures *)\r
+ MakeTexture( 0, TxtSundial );\r
+ MakeTexture( 1, TxtMarble );\r
+ MakeTexture( 2, TxtSapphire );\r
+ Txts[2].Data := TxtDat2;\r
+end;\r
+\r
+(* Sort procedure, not worth optimizing with only a few objects *)\r
+procedure SortObjects;\r
+var\r
+ I, J, K: integer;\r
+ ZMax: array[ 0..MAXCUB ] of longint;\r
+ ZI: integer;\r
+ L: longint;\r
+begin\r
+ for I:=0 to MAXCUB do begin\r
+ L := XVtx[Cube[I].Base].Z;\r
+ for J:=1 to 7 do\r
+ if( L > XVtx[Cube[I].Base+J].Z ) then L := XVtx[Cube[I].Base+J].Z;\r
+ ZMax[I] := L;\r
+ ZList[I] := I;\r
+ end;\r
+ for I:=0 to MAXCUB-1 do begin\r
+ ZI := I;\r
+ for J:=I+1 to MAXCUB do\r
+ if( ZMax[ZList[J]] > ZMax[ZList[ZI]] ) then ZI := J;\r
+ if( ZI <> I ) then begin\r
+ K := ZList[I];\r
+ ZList[I] := ZList[ZI];\r
+ ZList[ZI] := K;\r
+ end;\r
+ end;\r
+end;\r
+\r
+var\r
+ AX, AY, AZ: byte;\r
+ I, J, K: word;\r
+begin\r
+ mxInit;\r
+ mxSetMode( MX_320x240 );\r
+ Init;\r
+ Page := 240; (* Start with hidden page *)\r
+\r
+ (* Init 3D transforms, perspective is intentionally exaggerated *)\r
+ AX := 0; AY := 0; AZ := 0;\r
+ tdSetTranslation( Trans );\r
+ tdSetPerspective( 600*$10000, $10000, $10000 );\r
+ (* Main loop, all magic here! *)\r
+ while( not KeyPressed ) do begin\r
+ tdSetRotation( AX, AY, AZ ); (* Set new angles *)\r
+ tdTransform( Vtx, XVtx, VtxCnt ); (* 3D transform points *)\r
+ tdTransformToImage( XVtx, VVtx, VtxCnt, 160, 120+Page );\r
+ Inc( AX, 1 ); (* Bump angles *)\r
+ Inc( AY, 2 );\r
+ Inc( AZ, 1 );\r
+ mxSetClipRegion( 0, Page, 320, 240 ); (* Set clip to new page *)\r
+ mxSetClip( TRUE );\r
+ mxFillBox( 0, Page, 320, 240, 0, OP_MOVE ); (* Clear screen *)\r
+ (* Draw objects *)\r
+ SortObjects;\r
+ for I:=0 to MAXCUB do with Cube[ZList[I]] do begin\r
+ for J:=0 to 5 do begin\r
+ K := Face[J].Texture;\r
+ mxTexturePoly( 4, Face[J].Vtx, VVtx, Txts[K].Desc, Txts[K].Data^, Txts[K].Width );\r
+ end;\r
+ end;\r
+ (* Flip page: at 320x240 the Start Address Register Low is always zero *)\r
+ case Page of\r
+ 0 : begin PortW[$3D4] := $000C; Page := 240; end;\r
+ 240: begin PortW[$3D4] := $4B0C; Page := 480; end;\r
+ 480: begin PortW[$3D4] := $960C; Page := 0; end;\r
+ end;\r
+ mxWaitRetrace; (* If the frame rate seems low, try to remove this line *)\r
+ end;\r
+\r
+ mxSetMode( MX_TEXT );\r
+ mxTerm;\r
+end.\r
--- /dev/null
+(*\r
+ DEMO05 - A Gouraud-shaded rotating torus\r
+ (c) 1994 Alessandro Scotti\r
+*)\r
+uses Crt, Modex, Threed;\r
+\r
+(* Define ALTPAL for alternate palette *)\r
+{$define ALTPAL}\r
+\r
+const\r
+ MAXVTX1 = 15; RADIUS1 = 70; (* MAXVTX1+1 must be multiple of 4 *)\r
+ MAXVTX2 = 15; RADIUS2 = 30;\r
+ MAXVTX = (MAXVTX1+1)*(MAXVTX2+1)-1;\r
+ MAXFACE = MAXVTX;\r
+ Trans : TPoint = ( X:0; Y:0; Z:0 ); (* Object translation *)\r
+ Light : TPoint = ( X:0; Y:0; Z:-63*$10000 ); (* Light direction *)\r
+type\r
+ TQuad = record\r
+ QVtx : array[ 0..3 ] of integer;\r
+ end;\r
+var\r
+ Vtx, XVtx : array[ 0..MAXVTX ] of TPoint; (* Points *)\r
+ VVtx : array[ 0..MAXVTX ] of record X, Y: integer end;\r
+ Face : array[ 0..MAXFACE ] of TQuad; (* Polys *)\r
+ Culled : array[ 0..MAXFACE ] of integer;\r
+ GNrm,XGNrm: array[ 0..MAXVTX ] of TVector; (* Gouraud normals *)\r
+ VtxLight : array[ 0..MAXVTX ] of integer; (* Points brightness *)\r
+ Page : word;\r
+\r
+function GetVtx( I1, I2: integer ): integer;\r
+begin\r
+ GetVtx := (I1 mod (MAXVTX1+1))*(MAXVTX2+1) + I2 mod (MAXVTX2+1);\r
+end;\r
+\r
+procedure Init;\r
+var\r
+ R, N, X, Y, Z: real;\r
+ I, J, K, V: integer;\r
+begin\r
+ (* Build vertexes *)\r
+ for I:=0 to MAXVTX1 do begin\r
+ K := (I + (MAXVTX1+1) shr 2) mod (MAXVTX1+1);\r
+ R := RADIUS1 + RADIUS2*Cos( 2*K*Pi / (MAXVTX1+1) );\r
+ for J:=0 to MAXVTX2 do begin\r
+ V := I*(MAXVTX2+1)+J; (* Index of current vertex *)\r
+ (* Compute coordinates of current vertex *)\r
+ X := R*Cos(2*J*Pi / (MAXVTX2+1)); (* Get coordinates *)\r
+ Y := R*Sin(2*J*Pi / (MAXVTX2+1));\r
+ Z := RADIUS2*Sin(2*K*Pi / (MAXVTX1+1));\r
+ Vtx[V].X := Round( X )*$10000; (* Save coordinates *)\r
+ Vtx[V].Y := Round( Y )*$10000;\r
+ Vtx[V].Z := Round( Z )*$10000;\r
+ (* Compute direction of Gouraud normal thru current vertex *)\r
+ X := X - RADIUS1*Cos(2*J*Pi / (MAXVTX2+1));\r
+ Y := Y - RADIUS1*Sin(2*J*Pi / (MAXVTX2+1));\r
+ N := Sqrt( X*X + Y*Y + Z*Z ); (* Get vector length *)\r
+ GNrm[V].X := Trunc( X*$10000/N ); (* Save normal vector *)\r
+ GNrm[V].Y := Trunc( Y*$10000/N );\r
+ GNrm[V].Z := Trunc( Z*$10000/N );\r
+ end;\r
+ end;\r
+ (* Generate faces so that depth-sorting is not needed: there are still *)\r
+ (* some *very* little errors, but this is the best I could devise *)\r
+ J := 0;\r
+ K := 0;\r
+ for I:=0 to MAXFACE do with Face[I] do begin\r
+ QVtx[0] := GetVtx( J, K );\r
+ QVtx[1] := GetVtx( J, K+1 );\r
+ QVtx[2] := GetVtx( J+1, K+1 );\r
+ QVtx[3] := GetVtx( J+1, K );\r
+ Inc( K );\r
+ if( K > MAXVTX2 ) then begin\r
+ K := 0;\r
+ Inc( J );\r
+ end;\r
+ end;\r
+{$ifndef ALTPAL}\r
+ for I:=0 to 63 do mxSetColor( I+64, 0, 0, I ); (* Blue palette *)\r
+{$else}\r
+ for I:=0 to 31 do mxSetColor(I+64, 0, I shl 1, 0); (* Green neon palette *)\r
+ for I:=32 to 63 do mxSetColor ( I+64, (I-32) shl 1, 63, (I-32) shl 1 );\r
+{$endif}\r
+end;\r
+\r
+var\r
+ AX, AY, AZ: byte;\r
+ I: word;\r
+begin\r
+ mxInit;\r
+ mxSetMode( MX_320x240 );\r
+ Init;\r
+ Page := 240; (* Start with hidden page *)\r
+\r
+ AX := 0;\r
+ AY := 0;\r
+ AZ := 0;\r
+ (* Init 3D transforms, perspective is intentionally exaggerated *)\r
+ tdSetTranslation( Trans );\r
+ tdSetLight( Light );\r
+ tdSetPerspective( 400*$10000, $10000, $10000 );\r
+ (* Main loop, all magic here! *)\r
+ while( not KeyPressed ) do begin\r
+ tdSetRotation( AX, AY, AZ ); (* Set new angles *)\r
+ tdTransform( Vtx, XVtx, MAXVTX+1 ); (* 3D transform points *)\r
+ tdTransformToImage( XVtx, VVtx, MAXVTX+1, 160, 120+Page );\r
+ tdRotate( GNrm, XGNrm, MAXVTX+1 ); (* Rotate Gouraud normals *)\r
+ tdTransformLight( XGNrm, VtxLight, MAXVTX+1 );\r
+ (* Backplane culling is not really needed here! *)\r
+ FillChar( Culled, SizeOf(Culled), 0 );\r
+ tdBackPlaneCull( Face, XVtx, Culled, MAXFACE+1, SizeOf(TQuad) );\r
+ Inc( AX, 1 ); (* Bump angles *)\r
+ Inc( AY, 2 );\r
+ Inc( AZ, 3 );\r
+ mxSetClipRegion( 0, Page, 320, 240 ); (* Set clip to new page *)\r
+ mxSetClip( TRUE );\r
+ mxFillBox( 0, Page, 320, 240, 0, OP_MOVE ); (* Clear screen *)\r
+ (* Draw polygons *)\r
+ for I:=0 to MAXFACE do with Face[I] do\r
+ if( Culled[I] >= 0 ) then mxGouraudPoly( 4, QVtx, VVtx, VtxLight, 64 );\r
+ (* Flip page: at 320x240 the Start Address Register Low is always zero *)\r
+ case Page of\r
+ 0 : begin PortW[$3D4] := $000C; Page := 240; end;\r
+ 240: begin PortW[$3D4] := $4B0C; Page := 480; end;\r
+ 480: begin PortW[$3D4] := $960C; Page := 0; end;\r
+ end;\r
+ mxWaitRetrace; (* Uncomment this instruction if screen flickers *)\r
+ end;\r
+\r
+ mxSetMode( MX_TEXT );\r
+ mxTerm;\r
+end.\r
--- /dev/null
+(*\r
+ DEMO06 - Magnifying glass\r
+ (c) 1994 Alessandro Scotti\r
+*)\r
+uses Crt, Modex;\r
+\r
+const\r
+ R = 40; (* Lens radius *)\r
+ K : real = 1.8; (* Magnifying factor, less makes a stronger lens *)\r
+type\r
+ TLine = array[ 0..319 ] of byte;\r
+ PLine = ^TLine;\r
+ TScreen = array[ 0..239 ] of PLine;\r
+var\r
+ VScreen: TScreen; (* Virtual screen *)\r
+ BallX : array[ 0..R, 0..R ] of integer;\r
+ BallY : array[ 0..R, 0..R ] of integer;\r
+ Sprite : array[ -R..R, -R..R ] of byte;\r
+ Page : word;\r
+\r
+(* Returns "lens-view" coordinates of X,Y *)\r
+procedure GetCoords( var X, Y: integer );\r
+var\r
+ LR, Z, SinA, SinB, TgB, Q: real;\r
+begin\r
+ LR := Sqrt( X*X + Y*Y );\r
+ if( LR = 0 ) then Exit;\r
+ if( LR < R ) then begin\r
+ Z := Sqrt( R*R - LR*LR );\r
+ SinA := LR / R;\r
+ SinB := SinA / K;\r
+ TgB := SinB / Sqrt( 1-SinB*SinB );\r
+ Q := LR - TgB*Z;\r
+ X := Round( X * ( Q/LR ) );\r
+ Y := Round( Y * ( Q/LR ) );\r
+ end;\r
+end;\r
+\r
+procedure Init;\r
+var\r
+ F : file;\r
+ Palette: array[ 0..767 ] of record R, G, B: byte; end;\r
+ X, Y,\r
+ X2, Y2 : integer;\r
+begin\r
+ (* Load background image *)\r
+ Assign( F, 'demo06.dat' );\r
+ Reset( F, 1 );\r
+ BlockRead( F, Palette, 768 );\r
+ mxSetPalette( @Palette, 0, 256 );\r
+ for Y:=0 to 239 do begin\r
+ New( VScreen[Y] );\r
+ BlockRead( F, VScreen[Y]^, 320 );\r
+ mxPutImage( VScreen[Y], 0, 480+Y, 320, 1, OP_MOVE );\r
+ end;\r
+ Close( F );\r
+ (* Build lens *)\r
+ for X:=0 to R do begin\r
+ for Y:=0 to R do begin\r
+ X2 := X;\r
+ Y2 := Y;\r
+ GetCoords( X2, Y2 );\r
+ BallX[X, Y] := X2;\r
+ BallY[X, Y] := Y2;\r
+ end;\r
+ end;\r
+end;\r
+\r
+procedure PutLens( OX, OY: integer );\r
+var\r
+ X, Y: integer;\r
+begin\r
+ for X:=0 to R do begin\r
+ for Y:=0 to R do begin\r
+ Sprite[Y][X] := VScreen[ OY+BallY[X,Y] ]^[ OX+BallX[X,Y] ];\r
+ Sprite[Y][-X] := VScreen[ OY+BallY[X,Y] ]^[ OX-BallX[X,Y] ];\r
+ Sprite[-Y][X] := VScreen[ OY-BallY[X,Y] ]^[ OX+BallX[X,Y] ];\r
+ Sprite[-Y][-X] := VScreen[ OY-BallY[X,Y] ]^[ OX-BallX[X,Y] ];\r
+ end;\r
+ end;\r
+ (* Draw the sprite *)\r
+ mxPutImage( @Sprite, OX-R, OY-R+Page, 2*R+1, 2*R+1, OP_MOVE );\r
+end;\r
+\r
+function Delta: integer;\r
+begin\r
+ Delta := Random(3)+2;\r
+end;\r
+\r
+procedure Check( Cond: boolean; var Coord, DeltaC: integer; NewCoord, Sign: integer );\r
+begin\r
+ if( Cond ) then begin\r
+ Coord := NewCoord;\r
+ DeltaC := Sign*Delta;\r
+ end;\r
+end;\r
+\r
+var\r
+ X, Y, DX, DY: integer;\r
+ C: char;\r
+begin\r
+ mxInit;\r
+ mxSetMode( MX_320x240 );\r
+ Init;\r
+ Page := 240;\r
+ X := R;\r
+ Y := R;\r
+ Randomize;\r
+ DX := Delta;\r
+ DY := Delta;\r
+\r
+ (* Main loop *)\r
+ repeat\r
+ (* Update video *)\r
+ mxBitBlt( 0, 480, 320, 240, 0, Page );\r
+ PutLens( X, Y );\r
+ mxCircle( X, Page+Y, R, 0 );\r
+ (* Update lens coordinates *)\r
+ Inc( X, DX );\r
+ Check( X+R >= 319, X, DX, 319-R, -1 );\r
+ Check( X <= R, X, DX, R, +1 );\r
+ Inc( Y, DY );\r
+ Check( Y+R >= 239, Y, DY, 239-R, -1 );\r
+ Check( Y <= R, Y, DY, R, +1 );\r
+ (* Flip pages: double buffering, avoid wait for display *)\r
+ case Page of\r
+ 0 : begin PortW[$3D4] := $000C; Page := 240; end;\r
+ 240: begin PortW[$3D4] := $4B0C; Page := 0; end;\r
+ end;\r
+ mxWaitRetrace; (* Wait for hidden page to show *)\r
+ until( KeyPressed );\r
+\r
+ mxSetMode( MX_TEXT );\r
+ mxTerm;\r
+end.\r
--- /dev/null
+(*\r
+ DEMO07 - Hardware scrolling\r
+ Copyright (c) 1994 Alessandro Scotti\r
+*)\r
+uses Crt, Modex;\r
+\r
+const\r
+ (* Change this if scrolling seems jerky (this simple program does *)\r
+ (* not handle vertical retrace/display very well) *)\r
+ STEPS = 5;\r
+\r
+procedure Check( Cond: boolean; var Coord, DeltaC: integer; NewCoord, Sign: integer );\r
+begin\r
+ if( Cond ) then begin\r
+ Coord := NewCoord;\r
+ DeltaC := Sign*(Random(3)+2);\r
+ end;\r
+end;\r
+\r
+var\r
+ I, X, Y, DX, DY: integer;\r
+begin\r
+ (* Initialize library and graphics mode *)\r
+ mxInit;\r
+ mxSetMode( MX_320x200 );\r
+ (* Set a 640x400 virtual screen *)\r
+ mxSetVirtualScreen( 640, 400 );\r
+ mxSetClip( TRUE );\r
+\r
+ X := 0;\r
+ Y := 0;\r
+ DX := 1;\r
+ DY := 1;\r
+\r
+ (* Main loop: draw lines, circles, points and rectangles in separate *)\r
+ (* 320x200 windows, while smoothly panning virtual screen *)\r
+ while( not KeyPressed ) do begin\r
+ (* Points *)\r
+ mxSetClipRegion( 0, 0, 320, 200 );\r
+ for I:=1 to STEPS do\r
+ mxPutPixel( Random(320), Random(200), Random(16) );\r
+ (* Lines *)\r
+ mxSetClipRegion( 0, 200, 320, 200 );\r
+ for I:=1 to STEPS do\r
+ mxLine( Random(320), Random(200)+200, Random(320), Random(200)+200, Random(16), OP_SET );\r
+ (* Circles *)\r
+ mxSetClipRegion( 320, 0, 320, 200 );\r
+ for I:=1 to STEPS do\r
+ mxCircle( Random(320)+320, Random(200), Random(100), Random(16) );\r
+ (* Boxes *)\r
+ mxSetClipRegion( 320, 200, 320, 200 );\r
+ for I:=1 to STEPS do\r
+ mxFillBox( Random(320)+320, Random(200)+200, Random(100)+1, Random(100)+1, Random(16), OP_SET );\r
+ (* Pan *)\r
+ Inc( X, DX );\r
+ Check( X+320 >= 639, X, DX, 319, -1 );\r
+ Check( X < 0, X, DX, 0, +1 );\r
+ Inc( Y, DY );\r
+ Check( Y+200 >= 399, Y, DY, 199, -1 );\r
+ Check( Y < 0, Y, DY, 0, +1 );\r
+ mxPan( X, Y );\r
+ mxWaitRetrace;\r
+ end;\r
+\r
+ (* Shutdown *)\r
+ mxSetMode( MX_TEXT );\r
+ mxTerm;\r
+end.\r
--- /dev/null
+;\r
+; MATH.INC - Include file for THREED.ASM\r
+;\r
+\r
+; 3-dimensional point, coordinates in fixed format (16:16)\r
+;\r
+TPOINT STRUC\r
+ X DD ?\r
+ Y DD ?\r
+ Z DD ?\r
+TPOINT ENDS\r
+\r
+; 2-dimensional point, coordinates in integer format\r
+;\r
+TIMAGEPOINT STRUC\r
+ IX DW ?\r
+ IY DW ?\r
+TIMAGEPOINT ENDS\r
+\r
+; Fixed-point divide: EAX = EAX / arg\r
+;\r
+.xdiv MACRO arg\r
+ xor edx, edx\r
+ shld edx, eax, 16\r
+ shl eax, 16\r
+ idiv arg\r
+ENDM\r
+\r
+; Fixed-point multiply: EAX = EAX * arg\r
+;\r
+.xmul MACRO arg\r
+ imul arg\r
+ shrd eax, edx, 16\r
+ENDM\r
--- /dev/null
+unit Plasma;\r
+interface\r
+\r
+const\r
+ PAL_RGB = 0;\r
+ PAL_CLOUDS = 1;\r
+ PAL_LANDSCAPE = 2;\r
+\r
+procedure MakePlasma( X, Y: integer; W, H: word; C1, C2, C3, C4: byte );\r
+procedure MakePlasmaPalette( var Palette; What: word );\r
+\r
+implementation uses Modex;\r
+\r
+procedure NewColor( XA, YA, X, Y, XB, YB: integer );\r
+var\r
+ Color: longint;\r
+begin\r
+ Color := Abs( XA-XB )+Abs( YA-YB );\r
+ Color := Random( Color shl 1 )-Color;\r
+ Color := (Color+mxGetPixel( XA, YA )+mxGetPixel( XB, YB )+1) shr 1;\r
+ if( Color < 1 ) then Color := 1;\r
+ if( Color > 192 ) then Color := 192;\r
+ if( mxGetPixel( X, Y ) = 0 ) then\r
+ mxPutPixel( X, Y, Lo(Color) );\r
+end;\r
+\r
+procedure Divide( X1, Y1, X2, Y2: integer );\r
+var\r
+ X, Y, Color: integer;\r
+begin\r
+ if not( (X2-X1<2)and(Y2-Y1<2) ) then begin\r
+ X := (X1+X2) shr 1;\r
+ Y := (Y1+Y2) shr 1;\r
+ NewColor( X1, Y1, X, Y1, X2, Y1 );\r
+ NewColor( X2, Y1, X2, Y, X2, Y2 );\r
+ NewColor( X1, Y2, X, Y2, X2, Y2 );\r
+ NewColor( X1, Y1, X1, Y, X1, Y2 );\r
+ Color := (mxGetPixel( X1, Y1 )+mxGetPixel( X2, Y1 )+\r
+ mxGetPixel( X2, Y2 )+mxGetPixel( X1, Y2 )) shr 2;\r
+ mxPutPixel( X, Y, Color );\r
+ Divide( X1, Y1, X, Y );\r
+ Divide( X, Y1, X2, Y );\r
+ Divide( X, Y, X2, Y2 );\r
+ Divide( X1, Y, X, Y2 );\r
+ end;\r
+end;\r
+\r
+procedure MakePlasma;\r
+begin\r
+ Dec( W );\r
+ Dec( H );\r
+ mxPutPixel( X, Y, C1 );\r
+ mxPutPixel( X, Y+H, C2 );\r
+ mxPutPixel( X+W, Y+H, C3 );\r
+ mxPutPixel( X+W, Y, C4 );\r
+ Divide( X, Y, X+W, Y+H );\r
+end;\r
+\r
+procedure MakePlasmaPalette;\r
+type\r
+ TPal = array[ byte ] of record R, G, B: byte end;\r
+var\r
+ I: word;\r
+begin\r
+ FillChar( TPal(Palette)[1], 192*3, 0 );\r
+ case What of\r
+ PAL_CLOUDS:\r
+ for I:=1 to 192 do begin\r
+ TPal(Palette)[I].R := Abs( I-96 )*63 div 96;\r
+ TPal(Palette)[I].G := Abs( I-96 )*63 div 96;\r
+ TPal(Palette)[I].B := 63;\r
+ end;\r
+ PAL_LANDSCAPE:\r
+ begin\r
+ for I:=0 to 31 do begin\r
+ TPal(Palette)[I+1].R := I;\r
+ TPal(Palette)[I+1].G := I;\r
+ TPal(Palette)[I+1].B := I + I shr 1+15;\r
+ end;\r
+ for I:=32 to 63 do begin\r
+ TPal(Palette)[I+1].R := 0;\r
+ TPal(Palette)[I+1].G := I;\r
+ TPal(Palette)[I+1].B := 0;\r
+ end;\r
+ for I:=64 to 191 do begin\r
+ TPal(Palette)[I+1].R := (I-64) div 3 + 15;\r
+ TPal(Palette)[I+1].G := (I-64) div 3 + 15;\r
+ TPal(Palette)[I+1].B := (I-64) div 3 + 15;\r
+ end;\r
+ end;\r
+ else\r
+ for I:=1 to 64 do begin\r
+ TPal(Palette)[I].G := I-1;\r
+ TPal(Palette)[I].B := 64-I;\r
+ TPal(Palette)[I+64].R := I-1;\r
+ TPal(Palette)[I+64].G := 64-I;\r
+ TPal(Palette)[I+128].B := I-1;\r
+ TPal(Palette)[I+128].R := 64-I;\r
+ end;\r
+ end;\r
+end;\r
+\r
+end.
\ No newline at end of file
--- /dev/null
+{$E-,N+}\r
+uses Crt, Modex;\r
+\r
+const\r
+ DEFVERT = 12; (* Vertex count *)\r
+ DEFREPL = 3; (* Repetition count *)\r
+ DEFQIXS = 2; (* Qixs *)\r
+ FADESPEED = 48;\r
+type\r
+ TPoint = record\r
+ X, Y : integer;\r
+ end;\r
+ TRGB = record\r
+ R, G, B: byte;\r
+ end;\r
+ TQix = record\r
+ Color: integer;\r
+ Vert : array[ 0..DEFVERT-1, 0..DEFREPL-1 ] of TPoint;\r
+ Delta: array[ 0..DEFVERT-1 ] of TPoint;\r
+ end;\r
+var\r
+ Page : integer;\r
+ MaxX,\r
+ MaxY : word;\r
+ Qix : array[ 0..DEFQIXS-1 ] of TQix;\r
+ Pal : array[ byte ] of TRGB;\r
+\r
+type\r
+ TReal = double;\r
+ TRPoint = record\r
+ X, Y: TReal;\r
+ end;\r
+ TMatrix = array[ 0..3, 0..3 ] of TReal;\r
+var\r
+ M: TMatrix;\r
+ G: array[ 0..DEFVERT-1 ] of TRPoint;\r
+ C: array[ 0..DEFVERT-1 ] of TRPoint;\r
+\r
+procedure BumpPal( Idx, DR, DG, DB, Steps: integer );\r
+var\r
+ I: integer;\r
+begin\r
+ for I:=1 to Steps do begin\r
+ Pal[Idx+1].R := Pal[Idx].R + DR;\r
+ Pal[Idx+1].G := Pal[Idx].G + DG;\r
+ Pal[Idx+1].B := Pal[Idx].B + DB;\r
+ Inc( Idx );\r
+ end;\r
+end;\r
+\r
+procedure InitPalette;\r
+begin\r
+ with Pal[0] do begin R:=0; G:=0; B:=0; end;\r
+ with Pal[1] do begin R:=0; G:=0; B:=62; end;\r
+ BumpPal( 1, 0, 2, -2, 31 );\r
+ BumpPal( 32, 2, -2, 0, 31 );\r
+ BumpPal( 63, -2, 2, 2, 31 );\r
+ BumpPal( 94, 2, 0, -2, 31 );\r
+ BumpPal( 125, -2, -2, 2, 31 );\r
+end;\r
+\r
+procedure Init( var Qix: TQix; Color: integer );\r
+var\r
+ I: integer;\r
+begin\r
+ FillChar( Qix.Vert, SizeOf(Qix.Vert), 0 );\r
+ for I:=0 to DEFVERT-1 do begin\r
+ Qix.Vert[I, DEFREPL-1].X := Random( MaxX );\r
+ Qix.Vert[I, DEFREPL-1].Y := Random( MaxY );\r
+ Qix.Delta[I].X := Random(5)+1;\r
+ Qix.Delta[I].Y := Random(5)+1;\r
+ end;\r
+ Qix.Color := Color;\r
+\r
+ (* Initialize matrix (Catmull-Rom) *)\r
+ M[0,0] := -1/2; M[0,1] := 3/2; M[0,2] := -3/2; M[0,3] := 1/2;\r
+ M[1,0] := 1; M[1,1] := -5/2; M[1,2] := 2; M[1,3] := -1/2;\r
+ M[2,0] := -1/2; M[2,1] := 0; M[2,2] := 1/2; M[2,3] := 0;\r
+ M[3,0] := 0; M[3,1] := 1; M[3,2] := 0; M[3,3] := 0;\r
+end;\r
+\r
+procedure mxBezier( var Qix: TQix; I0, Idx, N: integer );\r
+var\r
+ I, J: integer;\r
+ T, T2, T3: TReal;\r
+ X0, Y0, X, Y: TReal;\r
+ Delta: TReal;\r
+begin\r
+ (* Compute coefficients *)\r
+ for I:=0 to 3 do begin\r
+ C[I].X := 0;\r
+ for J:=0 to 3 do C[I].X := C[I].X + M[I,J]*Qix.Vert[(I0+J) mod DEFVERT,Idx].X;\r
+ C[I].Y := 0;\r
+ for J:=0 to 3 do C[I].Y := C[I].Y + M[I,J]*Qix.Vert[(I0+J) mod DEFVERT,Idx].Y;\r
+ end;\r
+ X0 := C[3].X;\r
+ Y0 := C[3].Y;\r
+ Delta := 1 / N;\r
+ T := 0;\r
+ for I:=1 to N do begin\r
+ T := T + Delta;\r
+ T2 := T*T;\r
+ T3 := T*T2;\r
+ X := C[0].X*T3 + C[1].X*T2 + C[2].X*T + C[3].X;\r
+ Y := C[0].Y*T3 + C[1].Y*T2 + C[2].Y*T + C[3].Y;\r
+ mxLine( Round(X0), Page+Round(Y0), Round(X), Page+Round(Y), Qix.Color, OP_SET );\r
+ X0 := X;\r
+ Y0 := Y;\r
+ end;\r
+end;\r
+\r
+procedure Plot( var Qix: TQix; Idx: integer );\r
+var\r
+ I, J: integer;\r
+begin\r
+ for I:=0 to DEFVERT-1 do begin\r
+ mxBezier( Qix, I, Idx, 12 );\r
+ end;\r
+end;\r
+\r
+procedure Update( var Qix: TQix; Idx: integer );\r
+var\r
+ I: integer;\r
+begin\r
+ for I:=0 to DEFVERT-1 do with Qix do begin\r
+ Inc( Vert[I,Idx].X, Delta[I].X );\r
+ if( Vert[I,Idx].X < 0 ) then begin\r
+ Vert[I,Idx].X := 0;\r
+ Delta[I].X := Random( 5 )+1;\r
+ end;\r
+ if( Vert[I,Idx].X > MaxX ) then begin\r
+ Vert[I,Idx].X := MaxX;\r
+ Delta[I].X := -Random( 5 )-1;\r
+ end;\r
+ Inc( Vert[I,Idx].Y, Delta[I].Y );\r
+ if( Vert[I,Idx].Y < 0 ) then begin\r
+ Vert[I,Idx].Y := 0;\r
+ Delta[I].Y := Random( 5 )+1;\r
+ end;\r
+ if( Vert[I,Idx].Y > MaxY ) then begin\r
+ Vert[I,Idx].Y := MaxY;\r
+ Delta[I].Y := -Random( 5 )-1;\r
+ end;\r
+ end;\r
+end;\r
+\r
+procedure Copy( var Qix: TQix; Dest, Src: integer );\r
+var\r
+ I: integer;\r
+begin\r
+ for I:=0 to DEFVERT-1 do with Qix do begin\r
+ Vert[I,Dest].X := Vert[I,Src].X;\r
+ Vert[I,Dest].Y := Vert[I,Src].Y;\r
+ end;\r
+end;\r
+\r
+procedure AnimateQix;\r
+var\r
+ Q, Idx, I, J, P, Count: integer;\r
+begin\r
+ Count := 0;\r
+ P := DEFREPL-1;\r
+ I := 0;\r
+ J := 1;\r
+ repeat\r
+ mxSetClipRegion( 0, Page, MaxX+1, MaxY+1 );\r
+ mxSetClip( TRUE );\r
+ mxFillBox( 0, Page, MaxX+1, MaxY+1, 0, OP_SET );\r
+ for Q:=0 to DEFQIXS-1 do begin\r
+ Copy( Qix[Q], I, P );\r
+ Update( Qix[Q], I );\r
+ for Idx:=0 to DEFREPL-1 do begin\r
+ Plot( Qix[Q], Idx );\r
+ end;\r
+ end;\r
+ I := (I+1) mod DEFREPL;\r
+ J := (J+1) mod DEFREPL;\r
+ P := (P+1) mod DEFREPL;\r
+ Inc( Count );\r
+ mxStartLine( Page );\r
+ if( Count >= FADESPEED ) then begin\r
+ for Q:=0 to DEFQIXS-1 do begin\r
+ Inc( Qix[Q].Color );\r
+ if( Qix[Q].Color > 156 ) then\r
+ Qix[Q].Color := 1;\r
+ end;\r
+ Count := 0;\r
+ end;\r
+ Page := 240-Page;\r
+ until( KeyPressed );\r
+end;\r
+\r
+var\r
+ I: integer;\r
+begin\r
+ Randomize;\r
+ mxInit;\r
+ mxSetMode( MX_320x240 );\r
+ mxGetScreenSize( MaxX, MaxY );\r
+ for I:=0 to DEFQIXS-1 do\r
+ Init( Qix[I], (I*(155 div DEFQIXS)) mod 155 + 1 );\r
+ InitPalette;\r
+ mxSetPalette( @Pal, 0, 157 );\r
+ Page := 240;\r
+ Dec( MaxX );\r
+ Dec( MaxY );\r
+ AnimateQix;\r
+ mxSetMode( MX_TEXT );\r
+ mxTerm;\r
+end.\r
--- /dev/null
+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
--- /dev/null
+;\r
+; SINCOS.INC - Sin/cos tables for THREED.ASM\r
+;\r
+\r
+tblSin LABEL DWORD\r
+ DD 0\r
+ DD 411733\r
+ DD 823219\r
+ DD 1234209\r
+ DD 1644455\r
+ DD 2053710\r
+ DD 2461729\r
+ DD 2868265\r
+ DD 3273072\r
+ DD 3675909\r
+ DD 4076531\r
+ DD 4474698\r
+ DD 4870169\r
+ DD 5262706\r
+ DD 5652074\r
+ DD 6038037\r
+ DD 6420363\r
+ DD 6798821\r
+ DD 7173184\r
+ DD 7543226\r
+ DD 7908725\r
+ DD 8269459\r
+ DD 8625213\r
+ DD 8975771\r
+ DD 9320922\r
+ DD 9660458\r
+ DD 9994176\r
+ DD 10321873\r
+ DD 10643353\r
+ DD 10958422\r
+ DD 11266890\r
+ DD 11568571\r
+ DD 11863283\r
+ DD 12150850\r
+ DD 12431097\r
+ DD 12703856\r
+ DD 12968963\r
+ DD 13226258\r
+ DD 13475586\r
+ DD 13716797\r
+ DD 13949745\r
+ DD 14174291\r
+ DD 14390298\r
+ DD 14597637\r
+ DD 14796184\r
+ DD 14985817\r
+ DD 15166424\r
+ DD 15337895\r
+ DD 15500126\r
+ DD 15653022\r
+ DD 15796488\r
+ DD 15930439\r
+ DD 16054795\r
+ DD 16169479\r
+ DD 16274424\r
+ DD 16369565\r
+ DD 16454846\r
+ DD 16530216\r
+ DD 16595628\r
+ DD 16651044\r
+ DD 16696429\r
+ DD 16731757\r
+ DD 16757007\r
+ DD 16772163\r
+ DD 16777216\r
+ DD 16772163\r
+ DD 16757007\r
+ DD 16731757\r
+ DD 16696429\r
+ DD 16651044\r
+ DD 16595628\r
+ DD 16530216\r
+ DD 16454846\r
+ DD 16369565\r
+ DD 16274424\r
+ DD 16169479\r
+ DD 16054795\r
+ DD 15930439\r
+ DD 15796488\r
+ DD 15653022\r
+ DD 15500126\r
+ DD 15337895\r
+ DD 15166424\r
+ DD 14985817\r
+ DD 14796184\r
+ DD 14597637\r
+ DD 14390298\r
+ DD 14174291\r
+ DD 13949745\r
+ DD 13716797\r
+ DD 13475586\r
+ DD 13226258\r
+ DD 12968963\r
+ DD 12703856\r
+ DD 12431097\r
+ DD 12150850\r
+ DD 11863283\r
+ DD 11568571\r
+ DD 11266890\r
+ DD 10958422\r
+ DD 10643353\r
+ DD 10321873\r
+ DD 9994176\r
+ DD 9660458\r
+ DD 9320922\r
+ DD 8975771\r
+ DD 8625213\r
+ DD 8269459\r
+ DD 7908725\r
+ DD 7543226\r
+ DD 7173184\r
+ DD 6798821\r
+ DD 6420363\r
+ DD 6038037\r
+ DD 5652074\r
+ DD 5262706\r
+ DD 4870169\r
+ DD 4474698\r
+ DD 4076531\r
+ DD 3675909\r
+ DD 3273072\r
+ DD 2868265\r
+ DD 2461729\r
+ DD 2053710\r
+ DD 1644455\r
+ DD 1234209\r
+ DD 823219\r
+ DD 411733\r
+ DD 0\r
+ DD -411733\r
+ DD -823219\r
+ DD -1234209\r
+ DD -1644455\r
+ DD -2053710\r
+ DD -2461729\r
+ DD -2868265\r
+ DD -3273072\r
+ DD -3675909\r
+ DD -4076531\r
+ DD -4474698\r
+ DD -4870169\r
+ DD -5262706\r
+ DD -5652074\r
+ DD -6038037\r
+ DD -6420363\r
+ DD -6798821\r
+ DD -7173184\r
+ DD -7543226\r
+ DD -7908725\r
+ DD -8269459\r
+ DD -8625213\r
+ DD -8975771\r
+ DD -9320922\r
+ DD -9660458\r
+ DD -9994176\r
+ DD -10321873\r
+ DD -10643353\r
+ DD -10958422\r
+ DD -11266890\r
+ DD -11568571\r
+ DD -11863283\r
+ DD -12150850\r
+ DD -12431097\r
+ DD -12703856\r
+ DD -12968963\r
+ DD -13226258\r
+ DD -13475586\r
+ DD -13716797\r
+ DD -13949745\r
+ DD -14174291\r
+ DD -14390298\r
+ DD -14597637\r
+ DD -14796184\r
+ DD -14985817\r
+ DD -15166424\r
+ DD -15337895\r
+ DD -15500126\r
+ DD -15653022\r
+ DD -15796488\r
+ DD -15930439\r
+ DD -16054795\r
+ DD -16169479\r
+ DD -16274424\r
+ DD -16369565\r
+ DD -16454846\r
+ DD -16530216\r
+ DD -16595628\r
+ DD -16651044\r
+ DD -16696429\r
+ DD -16731757\r
+ DD -16757007\r
+ DD -16772163\r
+ DD -16777216\r
+ DD -16772163\r
+ DD -16757007\r
+ DD -16731757\r
+ DD -16696429\r
+ DD -16651044\r
+ DD -16595628\r
+ DD -16530216\r
+ DD -16454846\r
+ DD -16369565\r
+ DD -16274424\r
+ DD -16169479\r
+ DD -16054795\r
+ DD -15930439\r
+ DD -15796488\r
+ DD -15653022\r
+ DD -15500126\r
+ DD -15337895\r
+ DD -15166424\r
+ DD -14985817\r
+ DD -14796184\r
+ DD -14597637\r
+ DD -14390298\r
+ DD -14174291\r
+ DD -13949745\r
+ DD -13716797\r
+ DD -13475586\r
+ DD -13226258\r
+ DD -12968963\r
+ DD -12703856\r
+ DD -12431097\r
+ DD -12150850\r
+ DD -11863283\r
+ DD -11568571\r
+ DD -11266890\r
+ DD -10958422\r
+ DD -10643353\r
+ DD -10321873\r
+ DD -9994176\r
+ DD -9660458\r
+ DD -9320922\r
+ DD -8975771\r
+ DD -8625213\r
+ DD -8269459\r
+ DD -7908725\r
+ DD -7543226\r
+ DD -7173184\r
+ DD -6798821\r
+ DD -6420363\r
+ DD -6038037\r
+ DD -5652074\r
+ DD -5262706\r
+ DD -4870169\r
+ DD -4474698\r
+ DD -4076531\r
+ DD -3675909\r
+ DD -3273072\r
+ DD -2868265\r
+ DD -2461729\r
+ DD -2053710\r
+ DD -1644455\r
+ DD -1234209\r
+ DD -823219\r
+ DD -411733\r
+tblCos LABEL DWORD\r
+ DD 16777216\r
+ DD 16772163\r
+ DD 16757007\r
+ DD 16731757\r
+ DD 16696429\r
+ DD 16651044\r
+ DD 16595628\r
+ DD 16530216\r
+ DD 16454846\r
+ DD 16369565\r
+ DD 16274424\r
+ DD 16169479\r
+ DD 16054795\r
+ DD 15930439\r
+ DD 15796488\r
+ DD 15653022\r
+ DD 15500126\r
+ DD 15337895\r
+ DD 15166424\r
+ DD 14985817\r
+ DD 14796184\r
+ DD 14597637\r
+ DD 14390298\r
+ DD 14174291\r
+ DD 13949745\r
+ DD 13716797\r
+ DD 13475586\r
+ DD 13226258\r
+ DD 12968963\r
+ DD 12703856\r
+ DD 12431097\r
+ DD 12150850\r
+ DD 11863283\r
+ DD 11568571\r
+ DD 11266890\r
+ DD 10958422\r
+ DD 10643353\r
+ DD 10321873\r
+ DD 9994176\r
+ DD 9660458\r
+ DD 9320922\r
+ DD 8975771\r
+ DD 8625213\r
+ DD 8269459\r
+ DD 7908725\r
+ DD 7543226\r
+ DD 7173184\r
+ DD 6798821\r
+ DD 6420363\r
+ DD 6038037\r
+ DD 5652074\r
+ DD 5262706\r
+ DD 4870169\r
+ DD 4474698\r
+ DD 4076531\r
+ DD 3675909\r
+ DD 3273072\r
+ DD 2868265\r
+ DD 2461729\r
+ DD 2053710\r
+ DD 1644455\r
+ DD 1234209\r
+ DD 823219\r
+ DD 411733\r
+ DD 0\r
+ DD -411733\r
+ DD -823219\r
+ DD -1234209\r
+ DD -1644455\r
+ DD -2053710\r
+ DD -2461729\r
+ DD -2868265\r
+ DD -3273072\r
+ DD -3675909\r
+ DD -4076531\r
+ DD -4474698\r
+ DD -4870169\r
+ DD -5262706\r
+ DD -5652074\r
+ DD -6038037\r
+ DD -6420363\r
+ DD -6798821\r
+ DD -7173184\r
+ DD -7543226\r
+ DD -7908725\r
+ DD -8269459\r
+ DD -8625213\r
+ DD -8975771\r
+ DD -9320922\r
+ DD -9660458\r
+ DD -9994176\r
+ DD -10321873\r
+ DD -10643353\r
+ DD -10958422\r
+ DD -11266890\r
+ DD -11568571\r
+ DD -11863283\r
+ DD -12150850\r
+ DD -12431097\r
+ DD -12703856\r
+ DD -12968963\r
+ DD -13226258\r
+ DD -13475586\r
+ DD -13716797\r
+ DD -13949745\r
+ DD -14174291\r
+ DD -14390298\r
+ DD -14597637\r
+ DD -14796184\r
+ DD -14985817\r
+ DD -15166424\r
+ DD -15337895\r
+ DD -15500126\r
+ DD -15653022\r
+ DD -15796488\r
+ DD -15930439\r
+ DD -16054795\r
+ DD -16169479\r
+ DD -16274424\r
+ DD -16369565\r
+ DD -16454846\r
+ DD -16530216\r
+ DD -16595628\r
+ DD -16651044\r
+ DD -16696429\r
+ DD -16731757\r
+ DD -16757007\r
+ DD -16772163\r
+ DD -16777216\r
+ DD -16772163\r
+ DD -16757007\r
+ DD -16731757\r
+ DD -16696429\r
+ DD -16651044\r
+ DD -16595628\r
+ DD -16530216\r
+ DD -16454846\r
+ DD -16369565\r
+ DD -16274424\r
+ DD -16169479\r
+ DD -16054795\r
+ DD -15930439\r
+ DD -15796488\r
+ DD -15653022\r
+ DD -15500126\r
+ DD -15337895\r
+ DD -15166424\r
+ DD -14985817\r
+ DD -14796184\r
+ DD -14597637\r
+ DD -14390298\r
+ DD -14174291\r
+ DD -13949745\r
+ DD -13716797\r
+ DD -13475586\r
+ DD -13226258\r
+ DD -12968963\r
+ DD -12703856\r
+ DD -12431097\r
+ DD -12150850\r
+ DD -11863283\r
+ DD -11568571\r
+ DD -11266890\r
+ DD -10958422\r
+ DD -10643353\r
+ DD -10321873\r
+ DD -9994176\r
+ DD -9660458\r
+ DD -9320922\r
+ DD -8975771\r
+ DD -8625213\r
+ DD -8269459\r
+ DD -7908725\r
+ DD -7543226\r
+ DD -7173184\r
+ DD -6798821\r
+ DD -6420363\r
+ DD -6038037\r
+ DD -5652074\r
+ DD -5262706\r
+ DD -4870169\r
+ DD -4474698\r
+ DD -4076531\r
+ DD -3675909\r
+ DD -3273072\r
+ DD -2868265\r
+ DD -2461729\r
+ DD -2053710\r
+ DD -1644455\r
+ DD -1234209\r
+ DD -823219\r
+ DD -411733\r
+ DD 0\r
+ DD 411733\r
+ DD 823219\r
+ DD 1234209\r
+ DD 1644455\r
+ DD 2053710\r
+ DD 2461729\r
+ DD 2868265\r
+ DD 3273072\r
+ DD 3675909\r
+ DD 4076531\r
+ DD 4474698\r
+ DD 4870169\r
+ DD 5262706\r
+ DD 5652074\r
+ DD 6038037\r
+ DD 6420363\r
+ DD 6798821\r
+ DD 7173184\r
+ DD 7543226\r
+ DD 7908725\r
+ DD 8269459\r
+ DD 8625213\r
+ DD 8975771\r
+ DD 9320922\r
+ DD 9660458\r
+ DD 9994176\r
+ DD 10321873\r
+ DD 10643353\r
+ DD 10958422\r
+ DD 11266890\r
+ DD 11568571\r
+ DD 11863283\r
+ DD 12150850\r
+ DD 12431097\r
+ DD 12703856\r
+ DD 12968963\r
+ DD 13226258\r
+ DD 13475586\r
+ DD 13716797\r
+ DD 13949745\r
+ DD 14174291\r
+ DD 14390298\r
+ DD 14597637\r
+ DD 14796184\r
+ DD 14985817\r
+ DD 15166424\r
+ DD 15337895\r
+ DD 15500126\r
+ DD 15653022\r
+ DD 15796488\r
+ DD 15930439\r
+ DD 16054795\r
+ DD 16169479\r
+ DD 16274424\r
+ DD 16369565\r
+ DD 16454846\r
+ DD 16530216\r
+ DD 16595628\r
+ DD 16651044\r
+ DD 16696429\r
+ DD 16731757\r
+ DD 16757007\r
+ DD 16772163\r
--- /dev/null
+COMMENT /\r
+ Fixed-point math functions and 3D transforms\r
+ Copyright (c) 1993,94 by Alessandro Scotti\r
+/\r
+WARN PRO\r
+P386\r
+JUMPS\r
+LOCALS\r
+\r
+INCLUDE MATH.INC\r
+\r
+PUBLIC tdFixedMul\r
+PUBLIC tdGetNormal\r
+PUBLIC tdRotate\r
+PUBLIC tdGetSurfaceLight\r
+PUBLIC tdSetLight\r
+PUBLIC tdSetRotation\r
+PUBLIC tdSetTranslation\r
+PUBLIC tdTransform\r
+PUBLIC tdTransformToImage\r
+PUBLIC tdTransformLight\r
+PUBLIC tdBackPlaneCull\r
+PUBLIC tdSetPerspective\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Data segment\r
+;\r
+MATH_DATA SEGMENT USE16 PARA PUBLIC 'DATA'\r
+ ASSUME ds:MATH_DATA\r
+\r
+INCLUDE SINCOS.INC ; Fixed 8:24 sin/cos table\r
+\r
+XRotation TPOINT <> ; 3x3 rotation matrix\r
+YRotation TPOINT <>\r
+ZRotation TPOINT <>\r
+\r
+Translation TPOINT <> ; Translation vector\r
+\r
+Light TPOINT <> ; Light vector\r
+AmbientLight DW 00 ; Ambient light\r
+\r
+XScale DD 10000h ; Scaling factor for X coordinate\r
+YScale DD 10000h ; Scaling factor for Y coordinate\r
+PerspectiveDistance DD 20000000h\r
+\r
+MATH_DATA ENDS\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Code segment\r
+;\r
+MATH_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'\r
+ ASSUME cs:MATH_TEXT, es:NOTHING, fs:NOTHING\r
+\r
+tdSetPerspective PROC PASCAL FAR\r
+ ARG Perspective:DWORD, \\r
+ ScaleX:DWORD, \\r
+ ScaleY:DWORD\r
+ USES ds\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ mov eax, [Perspective]\r
+ mov [PerspectiveDistance], eax\r
+ mov eax, [ScaleX]\r
+ mov [XScale], eax\r
+ mov eax, [ScaleY]\r
+ mov [YScale], eax\r
+\r
+ ret\r
+tdSetPerspective ENDP\r
+\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Sets the rotation matrix.\r
+;\r
+; Input:\r
+; RX = X-axis rotation angle\r
+; RY = X-axis rotation angle\r
+; RZ = X-axis rotation angle\r
+; Output:\r
+; none\r
+;\r
+tdSetRotation PROC PASCAL FAR\r
+ ARG RX:WORD, \\r
+ RY:WORD, \\r
+ RZ:WORD\r
+ USES ds, si, di\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ mov bx, [RZ]\r
+ mov si, [RY]\r
+ mov di, [RX]\r
+ shl bx, 2\r
+ shl si, 2\r
+ shl di, 2\r
+\r
+ push ebp ; We use EBP as a scratch register\r
+\r
+; Set X rotation\r
+ mov eax, tblCos[bx]\r
+ imul tblCos[si]\r
+ mov [XRotation.X], edx\r
+\r
+ mov eax, tblSin[bx]\r
+ imul tblCos[si]\r
+ mov [XRotation.Y], edx\r
+\r
+ mov eax, tblSin[si]\r
+ sar eax, 8 ; Convert fixed 8:24 to fixed 16:16\r
+ mov [XRotation.Z], eax\r
+\r
+; Set Y rotation\r
+ mov eax, tblCos[bx]\r
+ imul tblSin[si] ; EDX:EAX = fixed 16:48\r
+ shrd eax, edx, 24 ; EAX = fixed 8:24\r
+ imul tblSin[di] ; EDX:EAX = fixed 16:48\r
+ mov ebp, eax\r
+ mov ecx, edx\r
+ mov eax, tblSin[bx]\r
+ imul tblCos[di]\r
+ add eax, ebp\r
+ adc edx, ecx ; EDX:EAX = fixed 16:48\r
+ neg edx\r
+ mov [YRotation.X], edx\r
+\r
+ mov eax, tblSin[bx]\r
+ imul tblSin[si]\r
+ shrd eax, edx, 24\r
+ imul tblSin[di]\r
+ mov ebp, eax\r
+ mov ecx, edx\r
+ mov eax, tblCos[bx]\r
+ imul tblCos[di]\r
+ sub eax, ebp\r
+ sbb edx, ecx\r
+ mov [YRotation.Y], edx\r
+\r
+ mov eax, tblCos[si]\r
+ imul tblSin[di]\r
+ mov [YRotation.Z], edx\r
+\r
+; Set Z rotation\r
+ mov eax, tblCos[bx]\r
+ imul tblSin[si]\r
+ shrd eax, edx, 24\r
+ imul tblCos[di]\r
+ mov ebp, eax\r
+ mov ecx, edx\r
+ mov eax, tblSin[bx]\r
+ imul tblSin[di]\r
+ sub eax, ebp\r
+ sbb edx, ecx\r
+ mov [ZRotation.X], edx\r
+\r
+ mov eax, tblSin[bx]\r
+ imul tblSin[si]\r
+ shrd eax, edx, 24\r
+ imul tblCos[di]\r
+ mov ebp, eax\r
+ mov ecx, edx\r
+ mov eax, tblCos[bx]\r
+ imul tblSin[di]\r
+ add eax, ebp\r
+ add edx, ecx\r
+ neg edx\r
+ mov [ZRotation.Y], edx\r
+\r
+ mov eax, tblCos[si]\r
+ imul tblCos[di]\r
+ mov [ZRotation.Z], edx\r
+\r
+ pop ebp ; Restore EBP\r
+\r
+ ret\r
+tdSetRotation ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Sets the translation vector.\r
+;\r
+; Input:\r
+; TV = pointer to translation vector\r
+; Output:\r
+; none\r
+;\r
+tdSetTranslation PROC PASCAL FAR\r
+ ARG TV:DWORD\r
+ USES ds, es, di\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ les di, [TV]\r
+ mov eax, es:[di].X\r
+ mov [Translation.X], eax\r
+ mov eax, es:[di].Y\r
+ mov [Translation.Y], eax\r
+ mov eax, es:[di].Z\r
+ mov [Translation.Z], eax\r
+\r
+ ret\r
+tdSetTranslation ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Transforms an array of TPOINT.\r
+;\r
+; Input:\r
+; Source = pointer to source array of TPOINT\r
+; Dest = pointer to destination array of TPOINT\r
+; Count = number of entries to transform\r
+; Output:\r
+; none\r
+;\r
+tdTransform PROC PASCAL FAR\r
+ ARG Source:DWORD, \\r
+ Dest:DWORD, \\r
+ Count:WORD\r
+ LOCAL Adjust:DWORD\r
+ USES ds, si, es, di, fs\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ lfs si, [Source]\r
+ les di, [Dest]\r
+\r
+ ALIGN DWORD\r
+@@Loop:\r
+; Transform Z coordinate\r
+ mov eax, fs:[si].X\r
+ imul [ZRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [ZRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [ZRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ mov ebx, eax\r
+ shrd eax, edx, 16\r
+ add eax, [Translation.Z] ; EAX = new Z coord (fixed 16:16)\r
+ mov es:[di].Z, eax\r
+; Get perspective factor\r
+ mov ebx, [PerspectiveDistance]\r
+ sub eax, ebx\r
+ neg eax ; EAX = PD - Z\r
+ xor edx, edx\r
+ shld edx, eax, 16\r
+ shl eax, 16\r
+ idiv ebx ; EAX = fixed 16:16 result\r
+ mov [Adjust], eax\r
+\r
+; Transform X coordinate\r
+ mov eax, fs:[si].X\r
+ imul [XRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [XRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [XRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ add eax, [Translation.X]\r
+ imul [Adjust]\r
+ shrd eax, edx, 16\r
+ mov es:[di].X, eax\r
+\r
+; Transform Y coordinate\r
+ mov eax, fs:[si].X\r
+ imul [YRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [YRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [YRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ add eax, [Translation.Y]\r
+ imul [Adjust]\r
+ shrd eax, edx, 16\r
+ mov es:[di].Y, eax\r
+\r
+ add si, SIZE TPOINT\r
+ add di, SIZE TPOINT\r
+ dec [Count]\r
+ jnz @@Loop\r
+\r
+ ret\r
+tdTransform ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Transforms an array of TPOINT into an array of TIMAGEPOINT.\r
+;\r
+; Input:\r
+; Source = pointer to source array of TPOINT\r
+; Dest = pointer to destination array of TIMAGEPOINT\r
+; Count = number of entries to transform\r
+; DeltaX = translation distance for the X coordinate\r
+; DeltaY = translation distance for the Y coordinate\r
+; Output:\r
+; the maximum Z value\r
+;\r
+tdTransformToImage PROC PASCAL FAR\r
+ ARG Source:DWORD, \\r
+ Dest:DWORD, \\r
+ Count:WORD, \\r
+ DeltaX:WORD, \\r
+ DeltaY:WORD\r
+ LOCAL Adjust:DWORD, \\r
+ Max:DWORD\r
+ USES ds, si, es, di, fs\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ lfs si, [Source]\r
+ les di, [Dest]\r
+ mov [Max], 80000000h\r
+\r
+@@Loop:\r
+; Check max Z\r
+ mov eax, fs:[si].Z\r
+ cmp eax, [Max]\r
+ jle @@1\r
+ mov [Max], eax\r
+@@1:\r
+\r
+; Transform X coordinate\r
+ mov ax, WORD PTR fs:[si].X[2]\r
+ add ax, [DeltaX]\r
+ mov es:[di].IX, ax\r
+\r
+; Transform Y coordinate\r
+ mov ax, WORD PTR fs:[si].Y[2]\r
+ add ax, [DeltaY]\r
+ mov es:[di].IY, ax\r
+\r
+ add si, SIZE TPOINT\r
+ add di, SIZE TIMAGEPOINT\r
+ dec [Count]\r
+ jnz @@Loop\r
+\r
+ mov eax, [Max]\r
+ shld edx, eax, 16\r
+ ret\r
+tdTransformToImage ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Sets the light source.\r
+;\r
+; Input:\r
+; Light = pointer to light vector\r
+; Output:\r
+; none\r
+;\r
+tdSetLight PROC PASCAL FAR\r
+ ARG L:DWORD\r
+ USES ds, es, di\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ les di, [L]\r
+ mov eax, es:[di].X\r
+ mov [Light.X], eax\r
+ mov eax, es:[di].Y\r
+ mov [Light.Y], eax\r
+ mov eax, es:[di].Z\r
+ mov [Light.Z], eax\r
+\r
+ ret\r
+tdSetLight ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Computes light intensity for an array of surfaces.\r
+;\r
+; Input:\r
+; Normals = pointer to an array of surface normals\r
+; Lights = pointer to an array of integer to be filled with\r
+; light intensity\r
+; Count = number of elements to transform\r
+; Output:\r
+; none\r
+;\r
+tdTransformLight PROC PASCAL FAR\r
+ ARG Normals:DWORD, \\r
+ Lights:DWORD, \\r
+ Count:WORD\r
+ USES ds, si, es, di, fs\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov fs, ax\r
+ ASSUME fs:MATH_DATA\r
+\r
+ lds si, [Normals]\r
+ les di, [Lights]\r
+ ASSUME ds:NOTHING\r
+\r
+; Intensity is given by the dot product between the Light vector and\r
+; the surface normal\r
+@@Loop:\r
+ mov eax, ds:[si].Z\r
+ imul [Light.Z]\r
+ mov ebx, eax\r
+ mov ecx, edx\r
+ mov eax, ds:[si].Y\r
+ imul [Light.Y]\r
+ add ebx, eax\r
+ adc ecx, edx\r
+ mov eax, ds:[si].X\r
+ imul [Light.X]\r
+ add eax, ebx\r
+ adc edx, ecx ; EDX:EAX = fixed 32:32 intensity\r
+ add dx, [AmbientLight]\r
+ test dx, dx\r
+ jg @@1\r
+ xor dx, dx ; Return 0 for no light\r
+@@1:\r
+ mov es:[di], dx\r
+ inc di\r
+ inc di\r
+ add si, SIZE TPOINT\r
+ dec [Count]\r
+ jnz @@Loop\r
+\r
+ ASSUME fs:NOTHING\r
+ ret\r
+tdTransformLight ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Returns the light value given the normal to a surface.\r
+;\r
+; Input:\r
+; Normal = pointer to TPOINT surface normal vector\r
+; Output:\r
+; AX = light intensity (>=0)\r
+; Notes:\r
+; the normal is rotated according to the current setting.\r
+;\r
+tdGetSurfaceLight PROC PASCAL FAR\r
+ ARG Normal:DWORD\r
+ USES ds, esi, es, di\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ les di, [Normal]\r
+\r
+; Transform Z coordinate\r
+ mov eax, es:[di].X\r
+ imul [ZRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, es:[di].Y\r
+ imul [ZRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, es:[di].Z\r
+ imul [ZRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ imul [Light.Z]\r
+ shrd eax, edx, 16\r
+ mov esi, eax\r
+\r
+; Transform X coordinate\r
+ mov eax, es:[di].X\r
+ imul [XRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, es:[di].Y\r
+ imul [XRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, es:[di].Z\r
+ imul [XRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ imul [Light.X]\r
+ shrd eax, edx, 16\r
+ add esi, eax\r
+\r
+; Transform Y coordinate\r
+ mov eax, es:[di].X\r
+ imul [YRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, es:[di].Y\r
+ imul [YRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, es:[di].Z\r
+ imul [YRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ imul [Light.X]\r
+ shrd eax, edx, 16\r
+ add eax, esi\r
+ shr eax, 16\r
+\r
+; Add ambient light\r
+ add ax, [AmbientLight]\r
+ test ax, ax\r
+ jge @@Exit\r
+ xor ax, ax\r
+\r
+@@Exit:\r
+ ret\r
+tdGetSurfaceLight ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Rotates an array of TPOINT.\r
+;\r
+; Input:\r
+; Source = pointer to source array of TPOINT\r
+; Dest = pointer to destination array of TPOINT\r
+; Count = number of entries to transform\r
+; Output:\r
+; none\r
+;\r
+tdRotate PROC PASCAL FAR\r
+ ARG Source:DWORD, \\r
+ Dest:DWORD, \\r
+ Count:WORD\r
+ USES ds, si, es, di, fs\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ lfs si, [Source]\r
+ les di, [Dest]\r
+\r
+@@Loop:\r
+; Transform Z coordinate\r
+ mov eax, fs:[si].X\r
+ imul [ZRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [ZRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [ZRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ mov es:[di].Z, eax\r
+\r
+; Transform X coordinate\r
+ mov eax, fs:[si].X\r
+ imul [XRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [XRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [XRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ mov es:[di].X, eax\r
+\r
+; Transform Y coordinate\r
+ mov eax, fs:[si].X\r
+ imul [YRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [YRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [YRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ mov es:[di].Y, eax\r
+\r
+ add si, SIZE TPOINT\r
+ add di, SIZE TPOINT\r
+ dec [Count]\r
+ jnz @@Loop\r
+\r
+ ret\r
+tdRotate ENDP\r
+\r
+tdFixedMul PROC PASCAL FAR\r
+ ARG F1:DWORD, \\r
+ F2:DWORD\r
+\r
+ mov eax, [F1]\r
+ imul [F2]\r
+ shr eax, 16\r
+\r
+ ret\r
+tdFixedMul ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Returns in EAX the square root of EDX:EAX.\r
+;\r
+subSqrt PROC NEAR\r
+ push esi\r
+ push edi\r
+\r
+ add eax, eax\r
+ adc edx, 0\r
+ mov eax, edx ; Just discard the low bits\r
+\r
+ mov esi, eax\r
+ xor edi, edi\r
+ shld edi, esi, 16\r
+ shl esi, 16\r
+@@Loop:\r
+ mov ebx, eax\r
+ mul eax\r
+ add eax, esi\r
+ adc edx, edi\r
+ shrd eax, edx, 1\r
+ shr edx, 1\r
+ div ebx\r
+ cmp eax, ebx\r
+ jne @@Loop\r
+\r
+; Adjust EAX\r
+ shl eax, 8\r
+\r
+ pop edi\r
+ pop esi\r
+ ret\r
+subSqrt ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Finds the unitary normal to a given surface.\r
+;\r
+; Input:\r
+; Dest = pointer to TPOINT (vector) result\r
+; P1, P2, P3 = pointer to TPOINT points on surface\r
+; Output:\r
+; none\r
+; Notes:\r
+; the normal is given by the cross-product between (P3-P1) and\r
+; (P2-P1), so its orientation depends on the parameters order.\r
+;\r
+tdGetNormal PROC PASCAL FAR\r
+ ARG Dest:DWORD, \\r
+ P1:DWORD, \\r
+ P2:DWORD, \\r
+ P3:DWORD\r
+ LOCAL V1:TPOINT, \\r
+ V2:TPOINT, \\r
+ N:TPOINT\r
+ USES ds, si, es, di\r
+\r
+; Get vector V1\r
+ lds si, [P1]\r
+ les di, [P3]\r
+ mov eax, es:[di].X\r
+ sub eax, ds:[si].X\r
+ mov [V1.X], eax\r
+ mov eax, es:[di].Y\r
+ sub eax, ds:[si].Y\r
+ mov [V1.Y], eax\r
+ mov eax, es:[di].Z\r
+ sub eax, ds:[si].Z\r
+ mov [V1.Z], eax\r
+\r
+; Get vector V2\r
+ les di, [P2]\r
+ mov eax, es:[di].X\r
+ sub eax, ds:[si].X\r
+ mov [V2.X], eax\r
+ mov eax, es:[di].Y\r
+ sub eax, ds:[si].Y\r
+ mov [V2.Y], eax\r
+ mov eax, es:[di].Z\r
+ sub eax, ds:[si].Z\r
+ mov [V2.Z], eax\r
+\r
+; Get normal vector (V1 x V2)\r
+ mov eax, [V1.Z]\r
+ imul [V2.Y]\r
+ mov ebx, eax\r
+ mov ecx, edx\r
+ mov eax, [V1.Y]\r
+ imul [V2.Z]\r
+ sub eax, ebx\r
+ sbb edx, ecx\r
+ shrd eax, edx, 16\r
+ mov [N.X], eax\r
+\r
+ mov eax, [V1.X]\r
+ imul [V2.Z]\r
+ mov ebx, eax\r
+ mov ecx, edx\r
+ mov eax, [V1.Z]\r
+ imul [V2.X]\r
+ sub eax, ebx\r
+ sbb edx, ecx\r
+ shrd eax, edx, 16\r
+ mov [N.Y], eax\r
+\r
+ mov eax, [V1.Y]\r
+ imul [V2.X]\r
+ mov ebx, eax\r
+ mov ecx, edx\r
+ mov eax, [V1.X]\r
+ imul [V2.Y]\r
+ sub eax, ebx\r
+ sbb edx, ecx\r
+ shrd eax, edx, 16\r
+ mov [N.Z], eax\r
+\r
+; Get normal length\r
+ mov eax, [N.X]\r
+ imul eax\r
+ mov ebx, eax\r
+ mov ecx, edx\r
+ mov eax, [N.Y]\r
+ imul eax\r
+ add ebx, eax\r
+ adc ecx, edx\r
+ mov eax, [N.Z]\r
+ imul eax\r
+ add eax, ebx\r
+ adc edx, ecx ; EDX:EAX = N.X*N.X + N.Y*N.Y + N.Z*N.Z\r
+ call subSqrt ; EAX = normal length\r
+ mov ebx, eax\r
+\r
+; Adjust vector and save it\r
+ les di, [Dest]\r
+ mov eax, [N.X]\r
+ cdq\r
+ shld edx, eax, 16\r
+ shl eax, 16\r
+ idiv ebx\r
+ mov es:[di].X, eax\r
+ mov eax, [N.Y]\r
+ cdq\r
+ shld edx, eax, 16\r
+ shl eax, 16\r
+ idiv ebx\r
+ mov es:[di].Y, eax\r
+ mov eax, [N.Z]\r
+ cdq\r
+ shld edx, eax, 16\r
+ shl eax, 16\r
+ idiv ebx\r
+ mov es:[di].Z, eax\r
+\r
+ ret\r
+tdGetNormal ENDP\r
+\r
+TPOLY STRUC\r
+ Vtx DW 4 DUP(?)\r
+TPOLY ENDS\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Performs surface removal on an array of polygons.\r
+;\r
+; Input:\r
+; Poly = pointer to an array of TPOLY\r
+; Vertex = pointer to an array of TPOINT\r
+; Dest = pointer to an array of integer\r
+; Count = number of polygons to check\r
+; Step = size of TPOLY structure\r
+; Output:\r
+; if the n-th polygon is invisible the n-th entry of the\r
+; Dest array is set to -1, other entries are not modified\r
+; (so it's possible to use the Light array for Dest, because\r
+; the light intensity is always >= 0)\r
+;\r
+tdBackPlaneCull PROC PASCAL FAR\r
+ ARG Step:WORD, \\r
+ Poly:DWORD, \\r
+ Vertex:DWORD, \\r
+ Dest:DWORD, \\r
+ Count:WORD\r
+ USES ds, si, es, di, fs\r
+ ASSUME ds:NOTHING\r
+\r
+ mov ds, WORD PTR Vertex[2]\r
+ les di, [Poly]\r
+ mov fs, WORD PTR Dest[2]\r
+\r
+@@Loop:\r
+ mov ax, es:[di].Vtx[2] ; Index of 2nd vertex\r
+ shl ax, 2\r
+ mov bx, ax\r
+ shl ax, 1\r
+ add bx, ax ; BX = index*SIZE TPOINT\r
+ add bx, WORD PTR [Vertex] ; BX = offset of 2nd vertex\r
+ mov ax, es:[di].Vtx[4] ; Index of 3rd vertex\r
+ shl ax, 2\r
+ mov si, ax\r
+ shl ax, 1\r
+ add si, ax\r
+ add si, WORD PTR [Vertex] ; SI = offset of 3rd vertex\r
+ mov ecx, ds:[si].X\r
+ sub ecx, ds:[bx].X ; ECX = V3.X-V2.X\r
+ mov edx, ds:[si].Y\r
+ sub edx, ds:[bx].Y ; EDX = V3.Y-V2.Y\r
+ mov ax, es:[di].Vtx[0] ; Index of 1st vertex\r
+ shl ax, 2\r
+ mov si, ax\r
+ shl ax, 1\r
+ add si, ax\r
+ add si, WORD PTR [Vertex] ; SI = offset of 1st vertex\r
+ mov eax, ds:[si].X\r
+ sub eax, ds:[bx].X ; EAX = V1.X-V2.X\r
+ mov esi, ds:[si].Y\r
+ sub esi, ds:[bx].Y ; ESI = V1.Y-V2.Y\r
+ imul edx\r
+ mov ebx, eax\r
+ xchg ecx, edx ; ECX:EBX = (V1.X-V2.X)*(V3.Y-V2.Y)\r
+ mov eax, esi\r
+ imul edx ; EDX:EAX = (V1.Y-V2.Y)*(V3.X-V2.X)\r
+ sub eax, ebx\r
+ sbb edx, ecx\r
+ jl @@Next ; Polygon is visible\r
+ mov bx, WORD PTR [Dest] ; FS:BX -> current Dest entry\r
+ mov WORD PTR fs:[bx], -1 ; Remove polygon\r
+@@Next:\r
+ add WORD PTR [Dest], 2 ; Next entry for dest\r
+ add di, [Step] ; Next polygon\r
+ dec [Count]\r
+ jnz @@Loop\r
+\r
+ ret\r
+tdBackPlaneCull ENDP\r
+\r
+MATH_TEXT ENDS\r
+END\r
--- /dev/null
+typedef struct {\r
+ long x, y, z;\r
+} TVECTOR;\r
+\r
+#define PVECTOR TVECTOR far *\r
+\r
+#define TPOINT TVECTOR\r
+#define PPOINT PVECTOR\r
+\r
+#define VPTR void far *\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+long far pascal tdFixedMul( long, long );\r
+int far pascal tdGetSurfaceLight( PPOINT );\r
+long far pascal tdTransformToImage( VPTR, VPTR, short, short, short );\r
+\r
+void far pascal tdBackPlaneCull( VPTR, VPTR, VPTR, short, short );\r
+void far pascal tdGetNormal( VPTR, PPOINT, PPOINT, PPOINT );\r
+void far pascal tdRotate( VPTR, VPTR, short );\r
+void far pascal tdSetLight( PVECTOR );\r
+void far pascal tdSetRotation( short, short, short );\r
+void far pascal tdSetTranslation( PVECTOR );\r
+void far pascal tdSetPerspective( long, long, long );\r
+void far pascal tdTransform( VPTR, VPTR, short );\r
+void far pascal tdTransformLight( VPTR, VPTR, short );\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
--- /dev/null
+unit ThreeD;\r
+interface\r
+\r
+type\r
+ TVector = record\r
+ X, Y, Z : longint;\r
+ end;\r
+ TPoint = TVector;\r
+\r
+function tdFixedMul( F1, F2: longint ): longint;\r
+function tdGetSurfaceLight( var Normal: TPoint ): integer;\r
+function tdTransformToImage( var Source, Dest; Count, DeltaX, DeltaY: integer ): longint;\r
+\r
+procedure tdBackPlaneCull( var Poly, Vertex, Dest; Count, Step: word );\r
+procedure tdGetNormal( var Dest, P1, P2, P3: TVector );\r
+procedure tdRotate( var Source, Dest; Count: word );\r
+procedure tdSetLight( var Light: TVector );\r
+procedure tdSetRotation( RX, RY, RZ: word );\r
+procedure tdSetTranslation( var TV: TVector );\r
+procedure tdSetPerspective( PD, XF, YF: longint );\r
+procedure tdTransform( var Source, Dest; Count: word );\r
+procedure tdTransformLight( var Source, Dest; Count: word );\r
+\r
+implementation\r
+\r
+function tdGetSurfaceLight; external;\r
+procedure tdSetRotation( RX, RY, RZ: word ); external;\r
+procedure tdGetNormal; external;\r
+procedure tdSetTranslation( var TV: TVector ); external;\r
+procedure tdTransform( var Source, Dest; Count: word ); external;\r
+procedure tdRotate; external;\r
+function tdTransformToImage; external;\r
+procedure tdSetLight( var Light: TVector ); external;\r
+procedure tdSetPerspective; external;\r
+procedure tdTransformLight; external;\r
+function tdFixedMul( F1, F2: longint ): longint; external;\r
+procedure tdBackPlaneCull; external;\r
+{$L THREED}\r
+\r
+end.\r
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+;-----------------------------------------------------------\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
--- /dev/null
+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