updated at 2021-03-28 by wojtek at bitologia.org (index)
A comprehensive study of the outstanding code example from 1993 - the martian landscape renderer by Tim J. Clarke.
Original code has been disassembled, rewritten and reduced from 5649 bytes to... 1517 bytes! :)
Tim, if you read this, please contact me! I was trying to reach you, but I couldn't...
get raw data with [enhanced] DEBUG
:
-u06ca:0000 ; confirm beginning of the code (might be different segment:offset) -n mars.asm ; file name -rcx -ffff ; file size - here entire segment for simplicity -w0000 ; save data
and then decode binaries with, eg. HVIEW.EXE
, but be careful, not all instructions are properly understood!
Actually, it is better to operate in DEBUG all the time.
0000: b8d607 mov ax, 07d6 ; ALL NUMBERS ARE IN BASE-16! 0003: 8ed8 mov dx, ax ; PREFIX 'h' IS INTENTIONALLY SKIPPED 0005: 8ec0 mov es, ax 0007: fc cld 0008: 32e4 xor ah, ah 000a: cd1a int 1a 000c: 80e67f and dh, 7f 000f: 89165d03 mov [035d], dx 0013: b81300 mov ax, 0013 0016: cd10 int 10 0018: 33c0 xor ax, ax 001a: cd33 int 33 001c: 3dffff cmp ax, ffff 001f: 0f94065b03 setz [035b] 0024: be0a02 mov si, 020a 0027: fa cli 0028: bac803 mov dx, 03c8 002b: 32c0 xor al, al 002d: ee out dx, al 002e: 42 inc dx 002f: b90003 mov cx, 0300 0032: f36e rep outsb 0034: fb sti 0035: 8e263d03 mov fs, [033d] 0039: 64c606fff960 mov byte ptr fs:[f9ff], 60 ; ### ### ### 003f: 64c606fef960 mov byte ptr fs:[f9fe], 60 ; # # # 0045: 64c606fdf960 mov byte ptr fs:[f9fd], 60 ; # ## ### 004b: 64c606bdf860 mov byte ptr fs:[f8bd], 60 0051: 64c6067df760 mov byte ptr fs:[f77d], 60 0057: 64c6067ef760 mov byte ptr fs:[f77e], 60 005d: 64c6067ff760 mov byte ptr fs:[f77f], 60 0063: 64c6067bf760 mov byte ptr fs:[f77b], 60 0069: 64c6067af760 mov byte ptr fs:[f77a], 60 006f: 64c60679f760 mov byte ptr fs:[f779], 60 0075: 64c606baf860 mov byte ptr fs:[f8ba], 60 007b: 64c606faf960 mov byte ptr fs:[f9fa], 60 0081: 64c606f9f960 mov byte ptr fs:[f9f9], 60 0087: 64c60677f760 mov byte ptr fs:[f777], 60 008d: 64c60676f760 mov byte ptr fs:[f776], 60 0093: 64c60675f760 mov byte ptr fs:[f775], 60 0099: 64c606b6f860 mov byte ptr fs:[f8b6], 60 009f: 64c606f6f960 mov byte ptr fs:[f9f6], 60 00a5: e84b00 call 00f3 00a8: e8a800 call 0153 00ab: c6065f0300 mov byte ptr [035f], 00 00b0: c7065103e803 mov word ptr [0351], 03e8 00b6: c7065303e803 mov word ptr [0353], 03e8 00bc: e84903 call 0408 00bf: e89703 call 0459 00c2: e85a09 call 0a1f 00c5: beaa07 mov si 07aa 00c8: 8e063d03 mov es, [033d] 00cc: bf2000 mov di, 0020 00cf: b3c8 mov bl, c8 00d1: b94000 mov cx, 0040 00d4: f366a5 rep movsd 00d7: 83c740 add di, 40 00da: fecb dec bl 00dc: 75f3 jne 00d1 00de: 8e064503 mov es, [0345] 00e2: 803e5f0300 cmp byte ptr [035f], 00 00e7: 74d3 je 00bc ; MAIN LOOP 00e9: b80300 mov ax, 0003 00ec: cd10 int 10 00ee: b8004c mov ax, 4c00 00f1: cd21 int 21 ================================================================================ 00f3: 8e064b03 mov es, [034b] 00f7: 33ff xor di, di 00f9: 66b8ffffffff mov eax, ffffffff 00ff: b90040 mov cx, 4000 0102: f366ab rep stosd 0105: b8ab00 mov ax, 00ab 0108: f7265d03 mul word ptr [035d] 010c: 05cd2b add ax, 2bcd 010f: 83d200 adc dx, 00 0112: f7364d03 div word ptr [034d] 0116: 89165d03 mov [035d], dx 011a: 8bf2 mov si, dx 011c: 26c606000000 mov byte ptr es:[0000], 00 0122: 26c6068000fe mov byte ptr es:[0080], fe 0128: 26c6060080fe mov byte ptr es:[8000], fe 012e: 26c606808000 mov byte ptr es:[8080], 00 0134: 6a00 push 00 0136: 680001 push 0100 0139: e8dd00 call 0219 013c: 83c404 add sp, 04 013f: 33ff xor di, di 0141: 268a05 mov al, es:[di] 0144: c0e803 shr al, 03 0147: 0440 add al, 0040 0149: aa stosb 014a: 0bff or di, di 014c: 75f3 jne 0141 014e: 8e064503 mov es, [0345] 0152: c3 ret ; called from one place -------------------------------------------------------------------------------- 0153: 8e064703 mov es:[0347] 0157: 8e264903 mov fs,[0349] 015b: 33ff xor di, di 015d: 66b8ffffffff mov eax, ffffffff 0163: b90040 mov cx, 4000 0166: f366ab rep stosd 0169: b8ab00 mov ax, 00ab 016c: f7265d03 mul word ptr [035d] 0170: 05cd2b add ax, 2bcd 0173: 83d200 adc dx, 00 0176: f7364d03 div word ptr [034d] 017a: 89165d03 mov [035d], dx 017e: 8bf2 mov si, dx 0180: 26c606000080 mov byte ptr, es:[0000], 0080 0186: 6a00 push 00 0188: 680001 push 0100 018b: e88b00 call 0219 018e: 83c404 add sp, 04 0191: 33f6 xor si, si 0193: 8b3e4f03 mov di, [034f] 0197: c1e704 shl di, 04 019a: 8b9d1f03 mov bx, [di + 031f] 019e: 268a00 mov al, es:[bx + si] 01a1: 32e4 xor ah, ah 01a3: 8b9d2103 mov bx, [di + 0321] 01a7: 260200 add al, es:[bx + si] 01aa: 80d400 adc ah, 00 01ad: 8b9d2303 mov bx, [di + 0323] 01b1: 260200 add al, es:[bx + si] 01b4: 80d400 adc ah, 00 01b7: 8b9d2503 mov bx, [di + 0325] 01bb: 260200 add al, es:[bx + si] 01be: 80d400 adc ah, 00 01c1: c1e802 shr ax, 02 01c4: 268804 mov es:[si], al 01c7: 46 inc si 01c8: 75d0 jne 019a 01ca: 33f6 xor si, si 01cc: 268a04 mov al, es:[si] 01cf: 32e4 xor ah, ah 01d1: 262a4403 sub al, es:[si + 03] 01d5: 80dc00 sbb ah, 00 01d8: 052000 add ax, 0020 01db: 7902 jns 01df 01dd: 33c0 xor ax, ax 01df: 3d3f00 cmp ax, 003f 01e2: 7603 jbe 01e7 01e4: b83f00 mov ax, 003f 01e7: 648804 mov fs:[si], al 01ea: 46 inc si 01eb: 75df jne 01cc 01ed: 33f6 xor si, si 01ef: 268a04 mov al, es:[si] 01f2: 32e4 xor ah, ah 01f4: 26024401 add al, es:[si + 0001] 01f8: 80d400 adc ah, 00 01fb: 2602840001 add al, es:[si + 0100] 0200: 80d400 adc ah, 00 0203: 2602840101 add al, es:[si + 0101] 0208: 80d400 adc ah, 00 020b: c1e802 shr ax, 02 020e: 268804 mov es:[si], al 0211: 46 inc si 0212: 75db jne 01ef 0214: 8e064503 mov es, [0345] 0218: c3 ret ; called from one place -------------------------------------------------------------------------------- 0219: 8bec mov bp, sp ; plasma algorithm 021b: 8b5e04 mov bx, [bp + 04] 021e: 8b4e02 mov cx, [bp + 02] 0221: d1e9 shr cx, 01 0223: 268a17 mov dl, es:[bx] 0226: 02d9 add bl, cl 0228: 8bfb mov di, bx 022a: 02d9 add bl, cl 022c: 26803dff cmp byte ptr es:[di], ff 0230: 7544 jnz 0276 0232: 32f6 xor dh, dh 0234: 260217 add dl, es:[bx] 0237: 80d600 adc dh, 00 023a: d1ea shr dx, 01 023c: 8aea mov ch, dl 023e: b8ab00 mov ax, 00ab 0241: f7e6 mul si 0243: 05cd2b add ax, 2bcd 0246: 83d200 adc dx, 00 0249: f7364d03 div word ptr [034d] 024d: 8bf2 mov si, dx 024f: 81eac267 sub dx, 67c2 0253: 8ac1 mov al, cl 0255: 32e4 xor ah, ah 0257: f7ea imul dx 0259: 8ac4 mov al, ah 025b: 8ae2 mov ah, dl 025d: c1f805 sar ax, 05 0260: 98 cbw 0261: 02c5 add al, ch 0263: 80d400 adc ah, 00 0266: 7809 js 0271 0268: 3dfe00 cmp ax 00fe 026b: 7606 jbe 0273 026d: b0fe mov al, fe 026f: eb02 jmp 0273 0271: 32c0 xor al, al 0273: 268805 mov es:[di], al 0276: 268a17 mov dl, es:[bx] 0279: 02f9 add bh, cl 027b: 8bfb mov di, bx 027d: 02f9 add bh, cl 027f: 26803dff cmp byte ptr, es:[di], 0ff 0283: 7544 jne 02c9 0285: 32f6 xor dh, dh 0287: 260217 add dl, es:[bx] 028a: 80d600 adc dh, 00 028d: d1ea shr dx, 01 028f: 8aea mov ch, dl 0291: b8ab00 mov ax, 00ab 0294: f7e6 mul si 0296: 05cd2b add ax, 2bcd 0299: 83d200 adc dx, 00 029c: f7364d03 div word ptr, [034d] 02a0: 8bf2 mov si, dx 02a2: 81eac267 sub dx, 67c2 02a6: 8ac1 mov al, cl 02a8: 32e4 xor ah, ah 02aa: f7ea imul dx 02ac: 8ac4 mov al, ah 02ae: 8ae2 mov ah, dl 02b0: c1f805 sar ax, 05 02b3: 98 cbw 02b4: 02c5 add al, ch 02b6: 80d400 adc ah, 00 02b9: 7809 js 02c4 02bb: 3dfe00 cmp ax, 00fe 02be: 7606 jbe 02c6 02c0: b0fe mov al, 0fe 02c2: eb02 jmp 02c6 02c4: 32c0 xor al, al 02c6: 268805 mov es:[di], al 02c9: 268a17 mov dl, es:[bx] 02cc: 2ad9 sub bl, cl 02ce: 8bfb mov di, bx 02d0: 2ad9 sub bl, cl 02d2: 26803dff cmp byte ptr es:[di], ff 02d6: 7544 jnz 031c 02d8: 32f6 xor dh, dh 02da: 260217 add dl, es:[bx] 02dd: 80d600 adc dh, 00 02e0: d1ea shr dx, 1 02e2: 8aea mov ch, dl 02e4: b8ab00 mov ax, 00ab 02e7: f7e6 mul si 02e9: 05cd2b add ax, 2bcd 02ec: 83d200 adc dx, 00 02ef: f7364d03 div word ptr [034d] 02f3: 8bf2 mov si, dx 02f5: 81eac267 sub dx, 67c2 02f9: 8ac1 mov al, cl 02fb: 32e4 xor ah, ah 02fd: f7ea imul dx 02ff: 8ac4 mov al, ah 0301: 8ae2 mov ah, dl 0303: c1f805 sar ax, 05 0306: 98 cbw 0307: 02c5 add al, ch 0309: 80d400 adc ah, 00 030c: 7809 js 0317 030e: 3dfe00 cmp ax, 00fe 0311: 7606 jbe 0319 0313: b0fe mov al, fe 0315: eb02 jmp 0319 0317: 32c0 xor al, al 0319: 268805 mov es:[di], al 031c: 268a17 mov dl, es:[bx] 031f: 2af9 sub bh, cl 0321: 8bfb mov di, bx 0323: 2af9 sub bh, cl 0325: 26803dff cmp byte ptr es:[di], ff 0329: 7544 jnz 036f 032b: 32f6 xor dh, dh 032d: 260217 add dl, es:[bx] 0330: 80d600 adc dh, 00 0333: d1ea shr dx, 01 0335: 8aea mov ch, dl 0337: b8ab00 mov ax, 00ab 033a: f7e6 mul si 033c: 05cd2b add ax, 2bcd 033f: 83d200 adc dx, 00 0342: f7364d03 div word ptr [034d] 0346: 8bf2 mov si, dx 0348: 81eac267 sub dx, 67c2 034c: 8ac1 mov al, cl 034e: 32e4 xor ah, ah 0350: f7ea imul dx 0352: 8ac4 mov al, ah 0354: 8ae2 mov ah, dl 0356: c1f805 sar ax, 05 0359: 98 cbw 035a: 02c5 add al, ch 035c: 80d400 adc ah, 00 035f: 7809 js 036a 0361: 3dfe00 cmp ax, 00fe 0364: 7606 jbe 036c 0366: b0fe mov al, fe 0368: eb02 jmp 036c 036a: 32c0 xor al, al 036c: 268805 mov es:[di], al 036f: 268a17 mov dl, es:[bx] 0372: 32f6 xor dh, dh 0374: 02d9 add bl, cl 0376: 02d9 add bl, cl 0378: 260217 add dl, es:[bx] 037b: 80d600 adc dh, 00 037e: 02f9 add bh, cl 0380: 02f9 add bh, cl 0382: 260217 add dl, es:[bx] 0385: 80d600 adc dh, 00 0388: 2ad9 sub bl, cl 038a: 2ad9 sub bl, cl 038c: 260217 add dl, es:[bx] 038f: 80d600 adc dh, 00 0392: c1ea02 shr dx, 02 0395: 8aea mov ch, dl 0397: b8ab00 mov ax, 00ab 039a: f7e6 mul si 039c: 05cd2b add ax, 2bcd 039f: 83d200 adc dx, 00 03a2: f7364d03 div word ptr [034d] 03a6: 8bf2 mov si, dx 03a8: 81eac267 sub dx, 67c2 03ac: 8ac1 mov al, cl 03ae: 32e4 xor ah, ah 03b0: f7ea imul dx 03b2: 8ac4 mov al, ah 03b4: 8ae2 mov ah, dl 03b6: c1f805 sar ax, 05 03b9: 98 cbw 03ba: 02c5 add al, ch 03bc: 80d400 adc ah, 00 03bf: 7809 js 03ca 03c1: d3fe00 cmp ax, 00fe 03c4: 7606 jbe 03cc 03c6: b0fe mov al, fe 03c8: eb02 jmp 03cc 03ca: 32c0 xor al, al 03cc: 02d9 add bl, cl 03ce: 2af9 sub bh, cl 03d0: 268807 mov es:[bx], al 03d3: 80f901 cmp cl, 01 03d6: 742f jz 0407 03d8: 32ed xor ch, ch 03da: 2ad9 sub bl, cl 03dc: 2af9 sub bh, cl 03de: 53 push bx 03df: 51 push cx 03e0: e836fe call 0219 ; self call 03e3: 8bec mov bp, sp 03e5: 8a4e00 mov cl, [bp + 00] 03e8: 004e02 add [bp + 02], cl 03eb: e82bfe call 0219 ; self call 03ee: 8bec mov bp, sp 03f0: 8a4e00 mov cl, [bp + 00] 03f3: 004e03 add [bp + 03], cl 03f6: e820fe call 0219 ; self call 03f9: 8bec mov bp, sp 03fb: 8a4e00 mov cl, [bp + 00] 03fe: 284e02 sub [bp + 02], cl 0401: e815fe call 0219 ; self call 0404: 83c404 add sp, 04 ; stack adjustment 0407: c3 ret ; called from many places including itself (recursion) -------------------------------------------------------------------------------- 0408: 33c9 xor cx, cx 040a: 33d2 xor dx, dx 040c: 33c0 xor ax, ax 040e: 803e5b0300 cmp byte ptr [035b], 00 0413: 740e jz 0423 0415: b80b00 mov ax, 000b 0418: cd33 int 33 041a: 51 push cx 041b: 52 push dx 041c: b80500 mov ax, 0005 041f: cd33 int 33 0421: 5a pop dx 0422: 59 pop cx 0423: 010e5103 add [0351], cx 0427: 29165303 sub [0353], dx 042b: 8b0e5103 mov cx, [0351] 042f: 8b165303 mov dx, [0353] 0433: 890e5503 mov [0355], cx 0437: 89165703 mov [0357], dx 043b: e81e0c call 105c 043e: 80c419 add ah, 19 0441: 7303 jae 0446 0443: b8ffff mov ax, ffff 0446: a35903 mov [0359], ax 0449: b401 mov ah, 01 044b: cd16 int 16 044d: 7409 jz 0458 044f: c6065f0301 mov byte ptr [035f], 01 0454: 32e4 xor ah, ah 0456: cd16 int 16 0458: c3 ret ; called from one place -------------------------------------------------------------------------------- 0459: bfaa07 mov di, 07aa 045c: 66b963000000 mov ecx, 00000063 0462: 6633c0 xor eax, eax 0465: a15903 mov ax, [0359] 0468: f7d8 neg ax 046a: c1e803 shr ax, 03 046d: 050040 add ax, 4000 0470: 66c1e00d shl eax, 0d 0474: 66a36003 mov [0360], eax 0478: 6633c0 xor eax, eax 047b: a15503 mov ax, [0355] 047e: 66c1e009 shl eax, 09 0482: 66a36403 mov [0364], eax 0486: 6633c0 xor eax, eax 0489: a15703 mov ax, [0357] 048c: 66c1e009 shl eax, 09 0490: 66a36803 mov [0368], eax 0494: 1e push ds 0495: 8e2e4503 mov gs, [0345] 0499: 8e1e4b03 mov dx, [034b] 049d: 6665a16003 mov eax, gs:[0360] 04a2: 6633d2 xor edx, edx 04a5: 66f7f1 div ecx 04a8: 66658b366403 mov esi, gs:[0364] 04ae: 66658b2e6803 mov ebp, gs:[0368] 04b4: 662bf0 sub esi, eax 04b7: 6603e8 add ebp, eax 04ba: 66c1e807 shr eax, 07 04be: 8bde mov bx, si 04c0: 66c1ee10 shr esi, 10 04c4: 81e6ff00 and si, 00ff 04c8: 66c1ed08 shr ebp, 08 04cc: 81e500ff and bp, ff00 04d0: 0bf5 or si, bp 04d2: 668be8 mov ebp, eax 04d5: 66c1ed10 shr ebp, 10 04d9: 4d dec bp 04da: a4 movsb ; #0001 04db: 03d8 add bx, ax 04dd: 13f5 adc si, bp 04df: a4 movsb ; #0002 04e0: 03d8 add bx, ax 04e2: 13f5 adc si, bp : : : 09d0: a4 movsb ; #00ff 09d1: 03d8 add bx, ax 09d3: 13f5 adc si, bp 09d5: a4 movsb ; #0100 09d6: fec9 dec cl 09d8: 0f85c1fa jnz 049d 09dc: 1f pop ds 09dd: 66b850505050 mov eax, 50505050 09e3: b94000 mov cx, 0040 09e6: f366ab rep stosd 09e9: 8b365903 mov si, [0359] 09ed: d1ee shr si, 01 09ef: 83c60a add si, 0a 09f2: bb0400 mov bx, 0004 09f5: 8bc6 mov ax, si 09f7: 33d2 xor dx, dx 09f9: f7f3 div bx 09fb: c1e807 shr ax, 07 09fe: 3d3f00 cmp ax, 003f 0a01: 7602 jbe 0a05 0a03: b03f mov al, 3f 0a05: 8ae0 mov ah, al 0a07: 8ad0 mov dl, al 0a09: 66c1e010 shl eax, 10 0a0d: 8ac2 mov al, dl 0a0f: 8ae0 mov ah, al 0a11: b94000 mov cx, 0040 0a15: f366ab rep stosd 0a17: fec3 inc bl 0a19: 80fb2c cmp bl, 2c 0a1c: 75d7 jnz 09f5 0a1e: c3 ret ; called from one place -------------------------------------------------------------------------------- 0a1f: 8e264703 mov fs, [0347] 0a23: 8e2e4903 mov gs, [0349] 0a27: 66b8007d007d mov eax, 7d007d00 0a2d: bfaa03 mov di, 03aa 0a30: b98000 mov cx, 0080 0a33: f366ab rep stosd 0a36: 6633c0 xor eax, eax 0a39: bfaa05 mov di, 05aa 0a3c: b98000 mov cx, 0080 0a3f: f366ab rep stosd 0a42: c706a0037800 mov word ptr [03a0], 0078 0a48: 8b36a003 mov si, [03a0] 0a4c: 8bb49001 mov si, [si + 0190] 0a50: c1e604 shl si, 04 0a53: a15703 mov ax, [0357] 0a56: 250f00 and ax, 000f 0a59: 340f xor al, 0f 0a5b: 03f0 add si, ax 0a5d: a15903 mov ax, [0359] 0a60: 33d2 xor dx, dx 0a62: f7f6 div si 0a64: 056400 add ax, 0064 0a67: a3a203 mov [03a2], ax 0a6a: 6633c0 xor eax, eax 0a6d: 8bc6 mov ax, si 0a6f: 66c1e006 shl eax, 06 0a73: 66a3a603 mov [03a6], eax 0a77: 833ea00302 cmp word ptr [03a0], 02 0a7c: 750e jne 0a8c 0a7e: c706a203007d mov word ptr [03a2], 7d00 0a84: c706a4030000 mov word ptr [03a4], 0000 0a8a: eb0a jmp 0a96 0a8c: 33c0 xor ax, ax 0a8e: ba0100 mov dx, 0001 0a91: f7f6 div si 0a93: a3a403 mov [03a4], ax 0a96: 6633c9 xor ecx, ecx 0a99: 8b0e5503 mov cx, [0355] 0a9d: 66c1e10c shl ecx, 0ch 0aa1: 66a1a603 mov eax, [03a6] 0aa5: 66c1e007 shl eax, 07 0aa9: 662bc8 sub ecx, eax 0aac: 8b165703 mov dx, [0357] 0ab0: c1e204 shl dx, 04 0ab3: 668bd9 mov ebx, ecx 0ab6: 66c1eb10 shr ebx, 10h 0aba: 8afe mov bh, dh 0abc: 8bc6 mov ax, si 0abe: c1e804 shr ax, 04 0ac1: 02f8 add bh, al 0ac3: d1e9 shr cx, 01 0ac5: befe01 mov si, 01fe 0ac8: c7066403aa07 mov word ptr [0364], 07aa 0ace: d1e1 shl cx, 01 0ad0: 030ea603 add cx, [03a6] 0ad4: 121ea803 adc bl, [03a8] 0ad8: d1e9 shr cx, 01 0ada: 648a4701 mov al, fs:[bx + 01] 0ade: 32e4 xor ah, ah 0ae0: 642a07 sub al, fs:[bx] 0ae3: 80dc00 sbb ah, 00 0ae6: f7e9 imul cx 0ae8: 0facd007 shrd ax, dx, 07 0aec: 640227 add ah, fs:[bx] 0aef: f726a403 mul word ptr [03a4] 0af3: 8b3ea203 mov di, [03a2] 0af7: 2bfa sub di, dx 0af9: 7903 jns 0afe 0afb: bfffff mov di, ffff 0afe: 81ffc800 cmp di, 00c8 0b02: 7c03 jl 0b07 0b04: bfc700 mov di, 00c7 0b07: 8bacaa03 mov bp, [si + 03aa] 0b0b: 89bcaa03 mov [si + 03aa], di 0b0f: 2bef sub bp, di 0b11: 0f890505 jns 101a 0b15: c1e708 shl di, 08 0b18: 033e6403 add di, [0364] 0b1c: 658a4701 mov al, gs:[bx + 01] 0b20: 652a07 sub al, gs:[bx] 0b23: f6ed imul ch 0b25: d1e0 shl ax, 01 0b27: 650227 add ah, gs:[bx] 0b2a: 8bd0 mov dx, ax 0b2c: 8784aa05 xchg ax, [si + 05aa] 0b30: 50 push ax 0b31: 2bc2 sub ax, dx 0b33: 99 cwd 0b34: f7fd idiv bp 0b36: 5a pop dx 0b37: d1e5 shl bp, 1 0b39: 3effa69001 jmp word ptr ds:[bp + 0190] 0b3e: 88b50039 mov [di + 03900h], dh 0b42: 03d0 add dx, ax 0b44: 88b5003a mov [di + 03a00h], dh 0b48: 03d0 add dx, ax : : : 0f86: 03d0 add dx, ax 0f88: 88b500f0 mov [di + 0f000h], dh 0f8c: 03d0 add dx, ax 0f8e: 88b500f1 mov [di + 0f100h], dh 0f92: 03d0 add dx, ax 0f94: 88b500f2 mov [di + 0f200h], dh 0f98: 03d0 add dx, ax 0f9a: 88b500f3 mov [di + 0f300h], dh 0f9e: 03d0 add dx, ax 0fa0: 88b500f4 mov [di + 0f400h], dh 0fa4: 03d0 add dx, ax 0fa6: 88b500f5 mov [di + 0f500h], dh 0faa: 03d0 add dx, ax 0fac: 88b500f6 mov [di + 0f600h], dh 0fb0: 03d0 add dx, ax 0fb2: 88b500f7 mov [di + 0f700h], dh 0fb6: 03d0 add dx, ax 0fb8: 88b500f8 mov [di + 0f800h], dh 0fbc: 03d0 add dx, ax 0fbe: 88b500f9 mov [di + 0f900h], dh 0fc2: 03d0 add dx, ax 0fc4: 88b500fa mov [di + 0fa00h], dh 0fc8: 03d0 add dx, ax 0fca: 88b500fb mov [di + 0fb00h], dh 0fce: 03d0 add dx, ax 0fd0: 88b500fc mov [di + 0fc00h], dh 0fd4: 03d0 add dx, ax 0fd6: 88b500fd mov [di + 0fd00h], dh 0fda: 03d0 add dx, ax 0fdc: 88b500fe mov [di + 0fe00h], dh 0fe0: 03d0 add dx, ax 0fe2: 88b500ff mov [di + 0ff00h], dh 0fe6: 03d0 add dx, ax 0fe8: 8835 mov [di], dh 0fea: ff066403 inc word ptr [0364] 0fee: 83ee02 sub si, 02 0ff1: 0f89d9fa jns 0ace 0ff5: 832ea00302 sub word ptr [03a0], 02 0ffa: 8b36a003 mov si, [03a0] 0ffe: 8bb49001 mov si, [si + 0190] 1002: f7c60300 test si, 0003 1006: 7508 jnz 1010 1008: c1ee02 shr si, 02 100b: 83fe0f cmp si, 0fh 100e: 7700 ja 1010 1010: 833ea00300 cmp word ptr [03a0], 00 1015: 0f852ffa jnz 0a48 1019: c3 ret ; called from one place -------------------------------------------------------------------------------- 101a: 658a4701 mov al, gs:[bx + 01] 101e: 652a07 sub al, gs:[bx] 1021: f6ed imul ch 1023: d1e0 shl ax, 01 1025: 650227 add ah, gs:[bx] 1028: 8984aa05 mov [si + 05aa], ax 102c: ff066403 inc word ptr [0364] 1030: 83ee02 sub si, 02 1033: 0f8997fa jns 0ace 1037: 832ea00302 sub word ptr [03a0], 02 103c: 8b36a003 mov si, [03a0] 1040: 8bb49001 mov si, [si + 0190] 1044: f7c60300 test si, 0003 1048: 7508 jnz 1052 104a: c1ee02 shr si, 02 104d: 83fe0f cmp si, 0f 1050: 7700 ja 1052 1052: 833ea00300 cmp word ptr [03a0], 00 1057: 0f85edf9 jnz 0a48 105b: c3 ret ; called from one place -------------------------------------------------------------------------------- 105c: 8e264703 mov fs, [0347] 1060: c1c904 ror cx, 04 1063: c1ca04 ror dx, 04 1066: 8ad9 mov bl, cl 1068: 8afa mov bh, dl 106a: c1e90c shr cx, 0c 106d: c1ea0c shr dx, 0c 1070: fec3 inc bl 1072: 648a07 mov al, fs:[bx] 1075: 32e4 xor ah, ah 1077: fecb dec bl 1079: 642a07 sub al, fs:[bx] 107c: 80dc00 sbb ah, 00 107f: 52 push dx 1080: f7e9 imul cx 1082: 648a17 mov dl, fs:[bx] 1085: 32f6 xor dh, dh 1087: c1e204 shl dx, 04 108a: 03c2 add ax, dx 108c: 5a pop dx 108d: 8bf0 mov si, ax 108f: fec7 inc bh 1091: fec3 inc bl 1093: 648a07 mov al, fs:[bx] 1096: 32e4 xor ah, ah 1098: fecb dec bl 109a: 642a07 sub al, fs:[bx] 109d: 80dc00 sbb ah, 00 10a0: 52 push dx 10a1: f7e9 imul cx 10a3: 648a17 mov dl, fs:[bx] 10a6: 32f6 xor dh, dh 10a8: c1e204 shl dx, 04 10ab: 03c2 add ax, dx 10ad: 5a pop dx 10ae: 8bf8 mov di, ax 10b0: 8bc7 mov ax, di 10b2: 2bc6 sub ax, si 10b4: f7ea imul dx 10b6: c1e604 shl si, 04 10b9: 03c6 add ax, si 10bb: c3 ret ; called from one place
+0 +1 +2 +3 +4 +5 +6 +7|+8 +9 +a +b +c +d +e +f -----------------------------+----------------------- 07d6:0000: 3e 0b 44 0b 4a 0b 50 0b|56 0b 5c 0b 62 0b 68 0b : "jump" offsets #1 (Δ = 6) : 0010: 6e 0b 74 0b 7a 0b 80 0b|86 0b 8c 0b 92 0b 98 0b 0020: 9e 0b a4 0b aa 0b b0 0b|b6 0b bc 0b c2 0b c8 0b 0030: ce 0b d4 0b da 0b e0 0b|e6 0b ec 0b f2 0b f8 0b 0040: fe 0b 04 0c 0a 0c 10 0c|16 0c 1c 0c 22 0c 28 0c 0050: 2e 0c 34 0c 3a 0c 40 0c|46 0c 4c 0c 52 0c 58 0c 0060: 5e 0c 64 0c 6a 0c 70 0c|76 0c 7c 0c 82 0c 88 0c 0070: 8e 0c 94 0c 9a 0c a0 0c|a6 0c ac 0c b2 0c b8 0c 0080: be 0c c4 0c ca 0c d0 0c|d6 0c dc 0c e2 0c e8 0c 0090: ee 0c f4 0c fa 0c 00 0d|06 0d 0c 0d 12 0d 18 0d 00a0: 1e 0d 24 0d 2a 0d 30 0d|36 0d 3c 0d 42 0d 48 0d 00b0: 4e 0d 54 0d 5a 0d 60 0d|66 0d 6c 0d 72 0d 78 0d 00c0: 7e 0d 84 0d 8a 0d 90 0d|96 0d 9c 0d a2 0d a8 0d 00d0: ae 0d b4 0d ba 0d c0 0d|c6 0d cc 0d d2 0d d8 0d 00e0: de 0d e4 0d ea 0d f0 0d|f6 0d fc 0d 02 0e 08 0e 00f0: 0e 0e 14 0e 1a 0e 20 0e|26 0e 2c 0e 32 0e 38 0e 0100: 3e 0e 44 0e 4a 0e 50 0e|56 0e 5c 0e 62 0e 68 0e 0110: 6e 0e 74 0e 7a 0e 80 0e|86 0e 8c 0e 92 0e 98 0e 0120: 9e 0e a4 0e aa 0e b0 0e|b6 0e bc 0e c2 0e c8 0e 0130: ce 0e d4 0e da 0e e0 0e|e6 0e ec 0e f2 0e f8 0e 0140: fe 0e 04 0f 0a 0f 10 0f|16 0f 1c 0f 22 0f 28 0f 0150: 2e 0f 34 0f 3a 0f 40 0f|46 0f 4c 0f 52 0f 58 0f 0160: 5e 0f 64 0f 6a 0f 70 0f|76 0f 7c 0f 82 0f 88 0f 0170: 8e 0f 94 0f 9a 0f a0 0f|a6 0f ac 0f b2 0f b7 0f 0180: be 0f c4 0f ca 0f d0 0f|d6 0f dc 0f e2 0f e8 0f : -- -- -- -- -- -- -- --|-- -- -- -- -- -- -- -- 07d6:0190: 00 00 01 00 02 00 03 00|04 00 05 00 06 00 07 00 : "jump" offsets #2 : 01a0: 08 00 09 00 0a 00 0b 00|0c 00 0d 00 0e 00 0f 00 01b0: 10 00 11 00 12 00 13 00|14 00 15 00 16 00 17 00 01c0: 18 00 19 00 1a 00 1b 00|1c 00 1d 00 1e 00 1f 00 01d0: 20 00 21 00 22 00 23 00|24 00 25 00 26 00 27 00 01e0: 28 00 2a 00 2c 00 2e 00|30 00 32 00 34 00 36 00 01f0: 38 00 3a 00 3c 00 40 00|44 00 48 00 4c 00 50 00 : 0200: 54 00 58 00 5c 00 60 00|64 00 -- -- -- -- -- -- 07d6:020a: -- -- -- -- -- -- -- --|-- -- 00 00 00 01 00 00 : palette : 0210: 02 00 00 03 00 00 03 01|00 04 00 00 05 00 00 06 ; <------ 01?! 0220: 00 00 07 00 00 08 00 00|09 00 00 0a 00 00 0b 00 0230: 00 0c 00 00 0d 00 00 0e|00 00 0f 00 00 10 00 00 0240: 11 00 00 12 00 00 13 00|00 14 00 00 15 00 00 16 0250: 00 00 17 00 00 18 00 00|19 00 00 1a 00 00 1b 00 0260: 00 1c 00 00 1d 01 00 1e|02 00 1f 03 00 20 04 00 0270: 21 05 00 22 06 00 23 07|01 24 08 02 25 09 03 26 0280: 0a 04 27 0b 05 28 0c 06|29 0d 07 2a 0e 08 2b 0f 0290: 09 2c 10 0a 2d 11 0b 2e|12 0c 2f 13 0d 30 14 0e 02a0: 31 15 0f 32 16 10 33 17|11 34 18 12 35 19 13 36 02b0: 1a 14 37 1b 15 38 1c 16|39 1d 17 3a 1e 18 3b 1f 02c0: 19 3c 20 1a 3d 21 1b 3e|22 1c 32 0a 0a 32 0b 0b 02d0: 32 0c 0c 32 0d 0d 32 0e|0e 32 0f 0f 32 10 10 32 02e0: 11 11 32 12 12 32 13 13|32 14 14 32 15 15 32 16 02f0: 16 32 17 17 32 18 18 32|19 19 32 1a 1a 32 1b 1b 0300: 32 1c 1c 32 1d 1d 32 1e|1e 32 1f 1f 32 20 20 32 0310: 21 21 32 22 22 32 23 23|32 24 24 32 25 25 32 26 0320: 26 32 27 27 32 28 28 32|29 29 -- -- -- -- -- -- : 032a -- -- -- -- -- -- -- --|-- -- 3f 3f 3f 9d 30 00 : data 07d6:0330: 00 04 00 02 02 ff fe 00|00 00 00 00 00 00 a0 00 07d6:0340: 00 40 00 ca 06 d6 07 d1|14 d1 24 d1 34 85 cf 01 07d6:0350: 00 e8 03 e8 03 e8 03 e8|03 00 00 01 00 27 b7 00 07d6:0360: 00 00 d4 0a aa 08 07 00|00 d0 07 00 00 00 00 00 07d6:0370: | : these 07d6:0380: | : three 07d6:0390: | : paragraphs are apparently unused... 07d6:03a0: ** ** ** ** ** ** ** **|** ** -- -- -- -- -- -- 07d6:03aa: -- -- -- -- -- -- -- --|-- -- ** ** ** ** ** ** : data : : | 07d6:05aa: -- -- -- -- -- -- -- --|-- -- ** ** ** ** ** ** : data : : | 07d6:07aa: -- -- -- -- -- -- -- --|-- -- ** ** ** ** ** ** : data : : |
in particular (little endian)
ds:[032f/w] = 0000 ; constant value ds:[0331/w] = 0004 ; constant value ds:[0333/w] = 0202 ; constant value ds:[0335/w] = feff ; constant value ds:[034f/w] = 0001 ; constant value ds:[033d/w] = a000 ; constant VGA address ds:[0345/w] = 07d6 ; offset of generated landscape view ds:[0347/w] = 14d1 ; offset of aux. map ds:[0349/w] = 24d1 ; offset of terra - lower half of the view ds:[034b/w] = 34d1 ; offset of cloudy sky - upper half of the view ds:[034d/w] = cf85 ; constant value this parameter is roughly responsible for the camera elevation ds:[035d/w] = .... ; random value from "int 1a" ds:[0355/w] = .... ; mouse state ds:[035f/b] = .... ; k/b state ds:[0360/d] = .... ; address recalculation variables ds:[0364/d] = .... ds:[0368/d] = .... ds:[03a0/d] = .... ; address recalculation variables ds:[03a2/d] = .... ds:[03a4/d] = .... ds:[03a6/d] = ds:[03a6/w] + ds:[03a8/w]and some others which are not so crucial. It seems, only seven cells hold constant values:
[032f-0335]
, [034f]
, [033d/w]
and [034d/w]
, others
are run-time dependent.
Offsets at 03aa
, 05aa
and 07aa
are of special use, see the code.
The flow is quite easy and well organised. There are five main procedures. Two initial:
00a5: e84b00 call 00f3 ; prepare cloudy sky 00a8: e8a800 call 0153 ; prepare martian terrain
and three others in the main loop:
00bc: e84903 call 0408 ; mouse handling 00bf: e89703 call 0459 ; refresh (recalculate) sky (background) 00c2: e85a09 call 0a1f ; refresh (recalculate) terra
The following snippet
-a00ab ....:00AB mov es, [033d] ....:00AF mov ds, [034b] ....:00B3 xor di, di ....:00B5 mov si, 07aa ....:00B8 mov cx, 0100 ....:00BB rep movsb ....:00BD add di, 40 ....:00C0 cmp di, fe00 ....:00C4 jbe 00b8 ....:00C6 in al, 60 ....:00C8 cmp al, 1 ....:00CA jne 00c6 ....:00CC mov ax,03 ....:00CF int 10 ....:00D1 mov ah, 4c ....:00D3 int 21 ....:00D5 -g
injected after the second call, here at 00AB
, retrieves the sky;
(the image is not centered)
If the address [034b]
in the second line (at 00AF
)
is replaced by [0349]
, another familiar picture appears:
Recall, that [034b]
and
[0349]
are offsets for the sky and terra, respectively.
By the way, this is the original colour's gamut:
Once there was a blue sky... :)
Now, all the "magic" is to divide the window 256 × 200 onto two parts. The upper one for the projection of the sky and the lower one for the 3-D-like simulation of the terra by means of voxel graphics. Using mouse, one can wander on the Martian mountains under the reddish sky.
Tim Clarke, whose 18-pixels-initials TJC
can be seen in the original screen at the bottom-right corner, describes
the project in his words:
Martian terrain renderer ------------------------ Here is a small demo to draw fractal voxel-based terrains in real time... If you have a 386 or better with VGA graphics, run mars and use the mouse to move around the landscape. Press any key to quit. A different map is calculated each time the program is run. This code may form the basis of a forthcoming game... taken from: http://archive.gamedev.net/archive/reference/articles/article655.html at 2021-03-24 Voxel landscapes and How I did it --------------------------------- This document describes the method I used in my demo of a Martian terrain, which can be found at garbo.uwasa.fi:/pc/demo/mars10.zip. It's similar to a floating horizon hidden line removal algorithm, so you'll find discussion of the salient points in many computer graphics books. The difference is the vertical line interpolation. First, some general points: --------------------------- The map is a 256x256 grid of points, each having and 8-bit integer height and a colour. The map wraps round such that, calling w(u,v) the height at (u,v), then w(0,0)=w(256,0)=w(0,256)=w(256,256). w(1,1)=w(257,257), etc. Map co-ords: (u,v) co-ordinates that describe a position on the map. The map can be thought of as a height function w=f(u,v) sampled discretely. Screen co-ords: (x,y) co-ordinates for a pixel on the screen. To generate the map: -------------------- This is a recursive subdivision, or plasma, fractal. You start of with a random height at (0,0) and therefore also at (256,0), (0,256), (256,256). Call a routine that takes as input the size and position of a square, in the first case the entire map. This routine get the heights from the corners of the square it gets given. Across each edge (if the map has not been written to at the point halfway along that edge), it takes the average of the heights of the 2 corners on that edge, applies some noise proportional to the length of the edge, and writes the result into the map at a position halfway along the edge. The centre of the square is the average of the four corners+noise. The routine then calls itself recursively, splitting each square into four quadrants, calling itself for each quadrant until the length of the side is 2 pixels. This is probably old-hat to many people, but the map is made more realistic by blurring: w(u,v)=k1*w(u,v)+k2*w(u+3,v-2)+k3*w(u-2,v+4) or something. Choose k1,k2,k3 such that k1+k2+k3=1. The points at which the map is sampled for the blurring filter do not really matter - they give different effects, and you don't need any theoretical reason to choose one lot as long as it looks good. Of course do everything in fixed point integer arithmetic. The colours are done so that the sun is on the horizon to the East: Colour=A*[ w(u+1,v)-w(u,v) ]+B with A and B chosen so that the full range of the palette is used. The sky is a similar fractal but without the colour transformation. How to draw each frame ---------------------- First, draw the sky, and blank off about 50 or so scan lines below the horizon since the routine may not write to all of them (eg. if you are on top of a high mountain looking onto a flat plane, the plane will not go to the horizon). Now, down to business. The screen is as follows: --------------------------- # # # # # Sky # # # # # #a------------------------# Horizon # # # # Point (a)=screen co-ords (0,0) # Ground # x increases horizontally # # y increases downwards # # --------------------------- Imagine the viewpoint is at a position (p,q,r) where (p,q) are the (u,v) map co-ordinates and r is the altitude. Now, for each horizontal (constant v) line of map from v=r+100 (say) down to v=r, do this: 1. Calculate the y co-ordinate of map co-ord (p,v,0) (perspective transform) 2. Calculate scale factor f which is how many screen pixels high a mountain of constant height would be if at distance v from q. Therefore, f is small for map co-ords far away (v>>r) and gets bigger as v comes down towards r. 3. Work out the map u co-ord corresponding to (0,y). v is constant along each line. 4. Starting at the calculated (u,v), traverse the screen, incrementing the x co-ordinate and adding on a constant, c, to u such that (u+c,v) are the map co-ords corresponding to the screen co-ords (1,y). You then have 256 map co-ords along a line of constant v. Get the height, w, at each map co-ord and draw a spot at (x,y-w*f) for all x. Sorry, but that probably doesn't make much sense. Here's an example: Imagine sometime in the middle of drawing the frame, everything behind a point (say v=q+50) will have been drawn: --------------------------- # # # # # # # **** # # ********* # <- A mountain half-drawn. #-----**************------# #*************************# #********* *********# #****** ******# #.........................# <- The row of dots is at screen co-ord y # # corresponding to an altitude of 0 for that --------------------------- particular distance v. Now the screen-scanning routine will get called for v=q+50. It draws in a point for every x corresponding to heights at map positions (u,v) where u goes from p-something to p+something, v constant. The routine would put points at these positions: (ignoring what was there before) --------------------------- # # # # # # # # # # #-------------------------# # ***** # # *** *** # #******* *******# #.........................# # # --------------------------- So, you can see that the screen gets drawn from the back, one vertical section after another. In fact, there's more to it than drawing one pixel at every x during the scan - you need to draw a vertical line between (x,y old) to (x,y new), so you have to have a buffer containing the y values for every x that were calculated in the previous pass. You interpolate along this line (Gouraud style) from the old colour to the new colour also, so you have to keep a buffer of the colours done in the last pass. Only draw the vertical lines if they are visible (ie. going down, y new>y old). The screen is drawn from the back so that objects can be drawn inbetween drawing each vertical section at the appropriate time. [...] Tim Clarke, tjc1005 at hermes.cam.ac.uk
Note that there are: eax
, ecx
, shrd
,
fs:
, gs:
, ... instructions in the original code
which means it was designed only for .386
+. This is in accordance
with what author says: "If you have a 386 or better with VGA graphics, run [MARS.EXE] and use the mouse to
move around the landscape.". This architecture is going to be preserved in the next steps.
1. I'd like to have a MARS.COM
file with all segments equalized to one.
To this end I introduce four blocks of 64k (ffffh) for each image:
cs:[_0345] = 241d0 for the landscape cs:[_0347] = 341d0 for the auxiliary map cs:[_0349] = 441d0 for the terrain cs:[_034b] = 541d0 for the sky
and another one at 641d0
for the stack ss:sp
which is extensively used
during the recursive plasma-like algorithm for the sky and terra generation;
see 0219
.
2. Eighteen commands from 0039
to 009f
drawing the TJC
signature are to be removed (for a moment). For I'd like to reach the smallest possible volume!
3. Some (not all) block operations eg. movsd
, stosd
, ... on 32-bits e-registers
can be rewritten to 16-bits version.
This slightly slows down the performance, but also reduces the file volume. A trade-off must be chosen.
4. Mouse button is completely unused here, so the lines between 0418
and 0423
shall be dropped immediately.
5. Five constants at [032f-0335/w]
and [034f/w]
are just hardcoded
for some reason (code obfuscation, or remnants of some general structure from the higher-level code),
so the fragment between
0191
and 01bb
can be significantly reduced and optimized.
6. Between 04da
and 09d5
there is a long sequence of (256) commands
responsible for the "sky mechanics":
: movsb add bx, ax adc si, bp :
which can be compressed into a single loop:
: push cx mov cx, 00ff _04df: add bx, ax adc si, bp movsb ; caution here! proper values of ds and es must be set! loop _04df pop cx :
7. The last huge improvement is between 0b39
and 0fe8
. Without much explanation, one can replace it with:
: push bx push ax push dx xor dx, dx mov ax, word ptr ds:[bp + 0190] ; again, watch ds here... sub ax, 0b3e mov bx, 0006 div bx shl ax, 8 add ax, 3900 mov bx, ax pop dx pop ax fill_hills: mov ds:[di + bx], dh ; ...and here! add dx, ax add bx, 0100 cmp bx, 0100 ; actually we must stop at fe00, but we let it overflow to avoid glitches jne fill_hills pop bx :
together with a dynamically generated array of offsets at 0000
and 0190
.
Let it be a simple exercise for the reader, what is going on at ds:[0190
] and before... :) OK, roughly
speaking, this part of the code performs smooth filling of the hilly martian surface in the lower part of the picture. One
observes that the consecutive addresses:
0b3e ; = j .... 0b44 ; btw, these values can be fished out of "jmp word ptr ds:[bp + 0190]" .... 0b4a ; one readily sees that Δ(bp) = 2 while Δ([bp + 0190]) = 6 :) .... :
correspond to an increasing sequence of offsets:
3900 3a00 3b00 :
that can be expressed in a single and compact formula:
f(j) = offset = 3900 + 0100 * (j - 0b32) / 6
8. I decided to remove original palette and, instead, I generate it dynamically to save additional space. Colours have changed a bit, though, nevertheless it still resembles Mars:
9. There are some other minor optimizations including removal of empty conditions, trivial jumps and code repetition. They are not mentioned here.
Finally, after recalculation of new segments and offsets one obtains:
; ; wojtek[at]bitologia.org ; ; ************************************************* ; * MARS.EXE from 1993 by Tim J. Clarke REVISITED * ; ************************************************* ; ; ----------------------------------------------------------------------------- ; 2021-03-14 playing with MARS_WWP.EXE from the old resources (1995-05-09) ; WWP is an executable files packer ; by Piotr Warężak and Rafał Wierzbicki ; https://www.wwpack32.venti.pl ; ----------------------------------------------------------------------------- ; 2021-03-16 1st serious attempt to disassembling original MARS.EXE ; it is also possible to disassemble MARS_WWP, although ; this is really exhausting job ; ----------------------------------------------------------------------------- ; 2021-03-19 disassembling MARS.EXE ; 2021-03-20 disassembling MARS.EXE ; 2021-03-21 disassembling MARS.EXE ; 2021-03-22 sky and terra are now correctly generated in 2-D ; problems with the "ladder" before 0fe8h ; sky is smoothly moving when the 5th call (@0a1fh) is off ; ----------------------------------------------------------------------------- ; 2021-03-23 to avoid a big mess segments are realigned ; to four 65535 blocks at 24d1, 34d1, 44d1, 54d1 ; and one extra for ss at 64d1 (eventually abandoned) ; of course I do not care about RAM allocation ; --> "640K ought to be enough for anybody" ; ----------------------------------------------------------------------------- ; 2021-03-24 recovering "missing" data in the "ds" segment ; contour of hills is being drawn ; 2021-03-24 almost done - hills are filled ; althouhgh there are some artifacts in the vicinity of 0b3eh :/ ; ----------------------------------------------------------------------------- ; 2021-03-25 1st final fix: ; _03a6 dd ? ; _03a8 db ? ; for "adc bl, ..." ; the issue was in "adc" of the lower part of "double-word" variable ; now it is taken directly from the run-time memory ; but there is still a little glitch when drawing highest hills... ; 2021-03-25 2nd final fix: ; no glitches at all! DONE AGAIN AFTER 28 YEARS :) ; (well, the original algorithm is not so perfect either, sometimes ; one can see little anomalies...) ; remember, when under DOSBOX, always use ; $ DOSBOX . -machine vgaonly ; ----------------------------------------------------------------------------- ; 2021-03-26 clean code ; data compression ; MARS.COM has 2126 bytes and still can be reduced far below 2.0kB! ; ----------------------------------------------------------------------------- ; 2021-03-27 palette compression ; MARS.COM has 1828 bytes and still can be reduced far below 1.5kB! ; 2021-03-27 plasma algorithm compression and other repetitions removed ; MARS.COM has 1517 bytes and still can be reduced below 1.5kB! ; ----------------------------------------------------------------------------- ; references: ; https://hornet.org/cgi-bin/scene-search.cgi?search=Tim%20Clarke ; https://www.youtube.com/watch?v=_zSjpIyMt0k ; https://www.shadertoy.com/view/XdsGWH ; helpful links: ; http://www.os2museum.com/wp/who-needs-the-address-wraparound-anyway/ ; https://en.wikipedia.org/wiki/X86_memory_segmentation ; https://www.aldeid.com/wiki/X86-assembly/Instructions/or ; https://www.calculator.net/hex-calculator.html?b2dnumber1=20&calctype=b2d&x=0&y=0#hex2decimal ; https://www.csie.ntu.edu.tw/~acpang/course/asm_2004/slides/chapt_07_PartISolve.pdf ; https://stanislavs.org/helppc/int_33-5.html ; https://8086assembly.blogspot.com/2017/11/logical-instructions-and-or-xor-not.html ; ; pictorial ASCII table: ; http://maettig.com/media/dos/system-tools/basic-snippets-power-test-ascii-table.png ; ; ; ------------------------------------------------------------------------------ .model tiny .code .386 org 100h start: ; mov ax, 064d1h ; without stack relocation... ; mov ss, ax ; mov sp, 0400h mov es, cs:[_0345] xor di, di mov ax, 0b3eh ; load data to [_0345]:0000 mov cx, 00c8h ; from 0b3e to 0fe8 _load1: stosw ; see _fill below... add ax, 0006 loop _load1 xor ax, ax mov cl, 0029h _load2: stosw inc ax loop _load2 inc ax ; ax = 029h inc ax ; ax = 02ah mov cl, 000ah _load3: stosw inc ax inc ax loop _load3 mov al, 0040h mov cl, 000ah _load4: stosw add al, 04 loop _load4 ; cld xor ah, ah int 1ah and dh, 7fh mov cs:[_035d], dx mov ax, 0013h int 10h xor ax, ax int 33h cmp ax, 0ffffh setz byte ptr cs:[mouse] ; lea si, cs:[palette] ; try -1 or +1 to get green or blue shades cli ; mov dx, 03c8h ; original palette ; xor al, al ; out dx, al ; inc dx ; mov cx, 0300h ; rep outsb ; [ds:si++] ---> [dx] (cx--) xor bx, bx ; new shades of terra xor ax, ax p1: push ax mov cl, 0040h p2: mov dx, 03c8h out dx, al inc dx push ax mov al, bl out dx, al inc bl mov al, bh out dx, al out dx, al pop ax inc al loop p2 pop ax add bx, 941eh ; new shades of sky add al, 40h cmp al, 80h jne p1 sti call _00f3 ; prepare cloudy sky call _0153 ; prepare terrain mov byte ptr cs:[key_pressed], 00 mov word ptr cs:[_0351], 03e8h mov word ptr cs:[_0353], 03e8h _00bc: mov es, cs:[_0345] call _0408 call _0459 call _0a1f mov si, 07aah mov ax, 0a000h mov es, ax mov di, 0020h mov bl, 0c8h push ds mov ds, cs:[_0345] _00d1: mov cx, 0040h rep movsd add di, 40h dec bl jne short _00d1 pop ds cmp byte ptr cs:[key_pressed], 00 je short _00bc mov ax, 0003 int 10h mov ah, 4ch int 21h ;------------------------------------------------------------------------------- _00f3: mov es, cs:[_034b] xor di, di mov ax, 0ffffh ; clear the sky mov cx, 8000h rep stosw mov ax, 00abh mul word ptr cs:[_035d] add ax, 2bcdh adc dx, +00 div word ptr cs:[_034d] mov cs:[_035d], dx mov si, dx mov byte ptr es:[0000h], 0 mov byte ptr es:[0080h], 0feh mov byte ptr es:[8000h], 0feh mov byte ptr es:[8080h], 0 push +00 push 0100h call _0219 add sp, +04 xor di, di _0141: mov al, es:[di] shr al, 03 add al, 40h stosb ; ax ---> [es:di++] (cx--) or di, di ; ZF | SF | result ; 0 | 0 | di > 0 ; 1 | 0 | di = 0 ; 0 | 1 | di < 0 jnz short _0141 ret ;------------------------------------------------------------------------------- _0153: mov es, cs:[_0347] mov fs, cs:[_0349] xor di, di mov ax, 0ffffh mov cx, 8000h rep stosw mov ax, 00abh mul word ptr cs:[_035d] add ax, 2bcdh adc dx, +00 div word ptr cs:[_034d] mov cs:[_035d], dx mov si, dx mov byte ptr es:[0000], 0080h push +00 push 0100h call _0219 add sp, +04 xor si, si _019a: mov al, es:[si] xor ah, ah add al, es:[si+4] adc ah, 00 add al, es:[si+0202h] adc ah, 00 add al, es:[si+0feffh] adc ah, 00 shr ax, 02 mov es:[si], al inc si jnz _019a xor si, si _01cc: mov al, es:[si] xor ah, ah sub al, es:[si + 03] sbb ah, 00 add ax, 0020h jns short _01df xor ax, ax _01df: cmp ax, 003fh jbe short _01e7 mov ax, 003fh _01e7: mov fs:[si], al inc si jnz short _01cc xor si, si _01ef: mov al, es:[si] xor ah, ah add al, es:[si + 01] adc ah, 00 add al, es:[si + 0100h] adc ah, 00 add al, es:[si + 0101h] adc ah, 00 shr ax, 02 mov es:[si], al inc si jnz short _01ef ret ;------------------------------------------------------------------------------- _0219: mov bp, sp mov bx, ss:[bp + 04] mov cx, ss:[bp + 02] shr cx, 1 mov dl, es:[bx] add bl, cl mov di, bx add bl, cl call _cr03 add bh, cl mov di, bx add bh, cl call _cr03 sub bl, cl mov di, bx sub bl, cl call _cr03 sub bh, cl mov di, bx sub bh, cl call _cr03 xor dh, dh add bl, cl add bl, cl add dl, es:[bx] adc dh, 00 add bh, cl add bh, cl add dl, es:[bx] adc dh, 00 sub bl, cl sub bl, cl add dl, es:[bx] adc dh, 00 shr dx, 02 call _cr05 js short _03ca cmp ax, 00feh jbe short _03cc mov al, 0feh jmp short _03cc _03ca: xor al, al _03cc: add bl, cl sub bh, cl mov es:[bx], al cmp cl, 01 jz short _0407 xor ch, ch sub bl, cl sub bh, cl push bx push cx call _0219 mov bp, sp mov cl, ss:[bp + 00] add ss:[bp + 02], cl call _0219 mov bp, sp mov cl, ss:[bp + 00] add ss:[bp + 03], cl call _0219 mov bp, sp mov cl, ss:[bp + 00] sub ss:[bp + 02], cl call _0219 add sp, +04 _0407: ret _cr03: cmp byte ptr es:[di], 0ffh jnz short _0276 xor dh, dh add dl, es:[bx] adc dh, 00 shr dx, 1 call _cr05 js short _0271 cmp ax, 00feh jbe short _0273 mov al, 0feh jmp short _0273 _0271: xor al, al _0273: mov es:[di], al _0276: mov dl, es:[bx] ret _cr05: mov ch, dl mov ax, 00abh mul si add ax, 2bcdh adc dx, +00 div word ptr cs:[_034d] mov si, dx sub dx, 67c2h mov al, cl xor ah, ah imul dx mov al, ah mov ah, dl sar ax, 05 cbw add al, ch adc ah, 00 ret ;------------------------------------------------------------------------------- _0408: cmp byte ptr cs:[mouse], 00 jz short _0423 mov ax, 000bh int 33h _0423: add cs:[_0351], cx sub cs:[_0353], dx mov cx, cs:[_0351] mov dx, cs:[_0353] mov cs:[_0355], cx mov cs:[_0357], dx call _105c add ah, 19h jae short _0446 mov ax, 0ffffh _0446: mov cs:[_0359], ax mov ah, 01 int 16h jz short _0458 mov byte ptr cs:[key_pressed], 01 xor ah, ah int 16h _0458: ret ;------------------------------------------------------------------------------- _105c: mov fs, cs:[_0347] ror cx, 04 ror dx, 04 mov bl, cl mov bh, dl shr cx, 0ch shr dx, 0ch inc bl mov al, fs:[bx] xor ah, ah dec bl sub al, fs:[bx] sbb ah, 00 push dx imul cx mov dl, fs:[bx] xor dh, dh shl dx, 04 add ax, dx pop dx mov si, ax inc bh inc bl mov al, fs:[bx] xor ah, ah dec bl sub al, fs:[bx] sbb ah, 00 push dx imul cx mov dl, fs:[bx] xor dh, dh shl dx, 04 add ax, dx pop dx mov di, ax mov ax, di sub ax, si imul dx shl si, 04 add ax, si ret ;------------------------------------------------------------------------------- _0459: mov di, 07aah mov ecx, 00000063h xor eax, eax mov ax, cs:[_0359] neg ax shr ax, 03 add ax, 4000h shl eax, 0dh mov cs:[_0360], eax xor eax, eax mov ax, cs:[_0355] shl eax, 09 mov cs:[_0364], eax xor eax, eax mov ax, cs:[_0357] shl eax, 09 mov cs:[_0368], eax push ds mov ds, cs:[_034b] _049d: mov eax, cs:[_0360] xor edx, edx div ecx mov esi, cs:[_0364] mov ebp, cs:[_0368] sub esi, eax add ebp, eax shr eax, 07 mov bx, si shr esi, 10h and si, 00ffh shr ebp, 08 and bp, 0ff00h or si, bp mov ebp, eax shr ebp, 10h dec bp movsb push cx mov cx, 00ffh _04df: add bx, ax adc si, bp movsb loop _04df pop cx dec cl jnz _049d pop ds mov ax, 5050h ; this is horizon :) mov cx, 0080h rep stosw mov si, cs:[_0359] shr si, 1 add si, +0ah mov bx, 0004 _09f5: mov ax, si xor dx, dx div bx shr ax, 07 cmp ax, 003fh jbe short _0a05 mov al, 3fh _0a05: mov ah, al mov dl, al shl ax, 10h mov al, dl mov ah, al mov cx, 80h rep stosw inc bl cmp bl, 2ch jnz _09f5 ret ;------------------------------------------------------------------------------- _0a1f: mov fs, cs:[_0347] mov gs, cs:[_0349] mov eax, 7d007d00h mov di, 03aah mov cx, 0080h rep stosd xor eax, eax mov di, 05aah mov cx, 0080h rep stosd mov word ptr cs:[_03a0], 0078h _0a48: mov si, cs:[_03a0] mov ds, cs:[_0345] mov si, ds:[si + 0190h] shl si, 04 mov ax, cs:[_0357] and ax, 000fh xor al, 0fh add si, ax mov ax, cs:[_0359] xor dx, dx div si add ax, 0064h mov cs:[_03a2], ax xor eax, eax mov ax, si shl eax, 06 mov ds:[03a6h], eax cmp word ptr cs:[_03a0], +02 jnz short _0a8c mov word ptr cs:[_03a2], 7d00h mov word ptr cs:[_03a4], 0000 jmp short _0a96 _0a8c: xor ax, ax mov dx, 0001 div si mov cs:[_03a4], ax _0a96: xor ecx, ecx mov cx, cs:[_0355] shl ecx, 0ch mov eax, ds:[03a6h] shl eax, 07 sub ecx, eax mov dx, cs:[_0357] shl dx, 04 mov ebx, ecx shr ebx, 10h mov bh, dh mov ax, si shr ax, 04 add bh, al shr cx, 1 mov si, 01feh mov word ptr cs:[_0364], 07aah _0ace: shl cx, 1 add cx, ds:[03a6h] adc bl, ds:[03a8h] shr cx, 1 mov al, fs:[bx + 01] xor ah, ah sub al, fs:[bx] sbb ah, 00 imul cx shrd ax, dx, 07 add ah, fs:[bx] mul word ptr cs:[_03a4] mov di, cs:[_03a2] sub di, dx jns short _0afe mov di, 0ffffh _0afe: cmp di, 00c8h jl short _0b07 mov di, 00c7h _0b07: mov bp, ds:[si + 03aah] mov ds:[si + 03aah], di sub bp, di jns short _101a shl di, 08 add di, word ptr cs:[_0364] call _cr02 mov dx, ax xchg ax, ds:[si + 05aah] push ax sub ax, dx cwd idiv bp pop dx shl bp, 1 comment # _0b39: jmp word ptr ds:[bp + 0190h] _0b3e: mov [di + 03900h], dh # push bx push ax push dx xor dx, dx mov ax, word ptr ds:[bp + 0190h] sub ax, 0b3eh mov bx, 0006 div bx shl ax, 8 add ax, 3900h mov bx, ax pop dx pop ax _fill: mov ds:[di + bx], dh add dx, ax add bx, 0100h cmp bx, 0100h jne _fill pop bx _0fe8: mov ds:[di], dh _cr01: inc word ptr cs:[_0364] sub si,+02 jns _0ace sub word ptr cs:[_03a0],+02 mov si, cs:[_03a0] mov si, ds:[si + 0190h] test si, 0003 jnz short _1010 shr si, 02 _1010: cmp word ptr cs:[_03a0], +00 jnz _0a48 ret _101a: call _cr02 mov ds:[si + 05aah], ax jmp short _cr01 _cr02: mov al, gs:[bx + 01] sub al, gs:[bx] imul ch shl ax, 1 add ah, gs:[bx] ret ;=============================================================================== _0345 dw 024d1h ; offset of landscape _0347 dw 034d1h ; offset of aux. array _0349 dw 044d1h ; offset of terra _034b dw 054d1h ; offset of sky _034d dw 0cf85h _0351 dw ? _0353 dw ? _0355 dw ? _0357 dw ? _0359 dw ? _035d dw ? _0360 dd ? _0364 dd ? _0368 dd ? _03a0 dw ? _03a2 dw ? _03a4 dw ? key_pressed db ? mouse dw ? comment # palette db 00h, 00h, 00h ; 1st part db 01h, 00h, 00h db 02h, 00h, 00h db 03h, 00h, 00h db 03h, 00h, 00h ; 03 _01_ 00 in the original data db 04h, 00h, 00h db 05h, 00h, 00h db 06h, 00h, 00h db 07h, 00h, 00h db 08h, 00h, 00h ; 10 db 09h, 00h, 00h db 0ah, 00h, 00h db 0bh, 00h, 00h db 0ch, 00h, 00h db 0dh, 00h, 00h db 0eh, 00h, 00h db 0fh, 00h, 00h db 10h, 00h, 00h db 11h, 00h, 00h db 12h, 00h, 00h ; 20 db 13h, 00h, 00h db 14h, 00h, 00h db 15h, 00h, 00h db 16h, 00h, 00h db 17h, 00h, 00h db 18h, 00h, 00h db 19h, 00h, 00h db 1ah, 00h, 00h db 1bh, 00h, 00h db 1ch, 00h, 00h ; 30 db 1dh, 01h, 00h db 1eh, 02h, 00h db 1fh, 03h, 00h db 20h, 04h, 00h db 21h, 05h, 00h db 22h, 06h, 00h db 23h, 07h, 01h db 24h, 08h, 02h db 25h, 09h, 03h db 26h, 0ah, 04h ; 40 db 27h, 0bh, 05h db 28h, 0ch, 06h db 29h, 0dh, 07h db 2ah, 0eh, 08h db 2bh, 0fh, 09h db 2ch, 10h, 0ah db 2dh, 11h, 0bh db 2eh, 12h, 0ch db 2fh, 13h, 0dh db 30h, 14h, 0eh ; 50 db 31h, 15h, 0fh db 32h, 16h, 10h db 33h, 17h, 11h db 34h, 18h, 12h db 35h, 19h, 13h db 36h, 1ah, 14h db 37h, 1bh, 15h db 38h, 1ch, 16h db 39h, 1dh, 17h db 3ah, 1eh, 18h ; 60 db 3bh, 1fh, 19h db 3ch, 20h, 1ah db 3dh, 21h, 1bh db 3eh, 22h, 1ch db 32h, 0ah, 0ah ; 2nd part db 32h, 0bh, 0bh db 32h, 0ch, 0ch db 32h, 0dh, 0dh db 32h, 0eh, 0eh db 32h, 0fh, 0fh ; 70 db 32h, 10h, 10h db 32h, 11h, 11h db 32h, 12h, 12h db 32h, 13h, 13h db 32h, 14h, 14h db 32h, 15h, 15h db 32h, 16h, 16h db 32h, 17h, 17h db 32h, 18h, 18h db 32h, 19h, 19h ; 80 db 32h, 1ah, 1ah db 32h, 1bh, 1bh db 32h, 1ch, 1ch db 32h, 1dh, 1dh db 32h, 1eh, 1eh db 32h, 1fh, 1fh db 32h, 20h, 20h db 32h, 21h, 21h db 32h, 22h, 22h db 32h, 23h, 23h ; 90 db 32h, 24h, 24h db 32h, 25h, 25h db 32h, 26h, 26h db 32h, 27h, 27h db 32h, 28h, 28h db 32h, 29h, 29h # end start
which perfectly compiles using TASM (2.0) and TLINK under DOSBOX and on real 386+ machines!
The output COM-file weights only ≈1.5kB which is incredibly small number in comparison with the final effect.