XORDELTA.ASM (18679B)
1 ; 2 ; Copyright 2020 Electronic Arts Inc. 3 ; 4 ; TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 ; software: you can redistribute it and/or modify it under the terms of 6 ; the GNU General Public License as published by the Free Software Foundation, 7 ; either version 3 of the License, or (at your option) any later version. 8 9 ; TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 ; in the hope that it will be useful, but with permitted additional restrictions 11 ; under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 ; distributed with this program. You should have received a copy of the 13 ; GNU General Public License along with permitted additional restrictions 14 ; with this program. If not, see [https://github.com/electronicarts/CnC_Remastered_Collection]>. 15 16 ; ************************************************************************** 17 ; ** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S * 18 ; ************************************************************************** 19 ; * * 20 ; * Project Name : WSA Support routines * 21 ; * * 22 ; * File Name : XORDELTA.ASM * 23 ; * * 24 ; * Programmer : Scott K. Bowen * 25 ; * * 26 ; * Last Update :May 23, 1994 [SKB] * 27 ; * * 28 ; *------------------------------------------------------------------------* 29 ; * Functions: * 30 ;* Apply_XOR_Delta -- Apply XOR delta data to a buffer. * 31 ;* Apply_XOR_Delta_To_Page_Or_Viewport -- Calls the copy or the XOR funti* 32 ;* Copy_Delta_buffer -- Copies XOR Delta Data to a section of a page. * 33 ;* XOR_Delta_Buffer -- Xor's the data in a XOR Delta format to a page. * 34 ; * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -* 35 36 ;IDEAL 37 ;P386 38 ;MODEL USE32 FLAT 39 .model flat 40 41 42 43 ;LOCALS ?? 44 45 ; These are used to call Apply_XOR_Delta_To_Page_Or_Viewport() to setup flags parameter. If 46 ; These change, make sure and change their values in wsa.cpp. 47 DO_XOR equ 0 48 DO_COPY equ 1 49 TO_VIEWPORT equ 0 50 TO_PAGE equ 2 51 52 ; 53 ; Routines defined in this module 54 ; 55 ; 56 ; UWORD Apply_XOR_Delta(UWORD page_seg, BYTE *delta_ptr); 57 ; PUBLIC Apply_XOR_Delta_To_Page_Or_Viewport(UWORD page_seg, BYTE *delta_ptr, WORD width, WORD copy) 58 ; 59 ; PROC C XOR_Delta_Buffer 60 ; PROC C Copy_Delta_Buffer 61 ; 62 63 externdef C Apply_XOR_Delta:NEAR 64 externdef C Apply_XOR_Delta_To_Page_Or_Viewport:NEAR 65 66 67 68 ;CODESEG 69 .code 70 71 72 ;*************************************************************************** 73 ;* APPLY_XOR_DELTA -- Apply XOR delta data to a linear buffer. * 74 ;* AN example of this in C is at the botton of the file commented out. * 75 ;* * 76 ;* INPUT: BYTE *target - destination buffer. * 77 ;* BYTE *delta - xor data to be delta uncompress. * 78 ;* * 79 ;* OUTPUT: * 80 ;* * 81 ;* WARNINGS: * 82 ;* * 83 ;* HISTORY: * 84 ;* 05/23/1994 SKB : Created. * 85 ;*=========================================================================* 86 Apply_XOR_Delta proc C public USES ebx ecx edx esi edi target:DWORD, delta:DWORD 87 88 ;USES ebx,ecx,edx,edi,esi 89 ;ARG target:DWORD ; pointers. 90 ;ARG delta:DWORD ; pointers. 91 92 ; Optimized for 486/pentium by rearanging instructions. 93 mov edi,[target] ; get our pointers into offset registers. 94 mov esi,[delta] 95 96 cld ; make sure we go forward 97 xor ecx,ecx ; use cx for loop 98 99 top_loop: 100 xor eax,eax ; clear out eax. 101 mov al,[esi] ; get delta source byte 102 inc esi 103 104 test al,al ; check for a SHORTDUMP ; check al incase of sign value. 105 je short_run 106 js check_others 107 108 ; 109 ; SHORTDUMP 110 ; 111 mov ecx,eax ; stick count in cx 112 113 dump_loop: 114 mov al,[esi] ;get delta XOR byte 115 xor [edi],al ; xor that byte on the dest 116 inc esi 117 inc edi 118 dec ecx 119 jnz dump_loop 120 jmp top_loop 121 122 ; 123 ; SHORTRUN 124 ; 125 126 short_run: 127 mov cl,[esi] ; get count 128 inc esi ; inc delta source 129 130 do_run: 131 mov al,[esi] ; get XOR byte 132 inc esi 133 134 run_loop: 135 xor [edi],al ; xor that byte. 136 137 inc edi ; go to next dest pixel 138 dec ecx ; one less to go. 139 jnz run_loop 140 jmp top_loop 141 142 ; 143 ; By now, we know it must be a LONGDUMP, SHORTSKIP, LONGRUN, or LONGSKIP 144 ; 145 146 check_others: 147 sub eax,080h ; opcode -= 0x80 148 jnz do_skip ; if zero then get next word, otherwise use remainder. 149 150 mov ax,[esi] 151 lea esi,[esi+2] ; get word code in ax 152 test ax,ax ; set flags. (not 32bit register so neg flag works) 153 jle not_long_skip 154 155 ; 156 ; SHORTSKIP AND LONGSKIP 157 ; 158 do_skip: 159 add edi,eax ; do the skip. 160 jmp top_loop 161 162 163 not_long_skip: 164 jz stop ; long count of zero means stop 165 sub eax,08000h ; opcode -= 0x8000 166 test eax,04000h ; is it a LONGRUN (code & 0x4000)? 167 je long_dump 168 169 ; 170 ; LONGRUN 171 ; 172 sub eax,04000h ; opcode -= 0x4000 173 mov ecx,eax ; use cx as loop count 174 jmp do_run ; jump to run code. 175 176 177 ; 178 ; LONGDUMP 179 ; 180 181 long_dump: 182 mov ecx,eax ; use cx as loop count 183 jmp dump_loop ; go to the dump loop. 184 185 stop: 186 187 ret 188 189 Apply_XOR_Delta endp 190 191 192 ;---------------------------------------------------------------------------- 193 194 195 ;*************************************************************************** 196 ;* APPLY_XOR_DELTA_To_Page_Or_Viewport -- Calls the copy or the XOR funtion. * 197 ;* * 198 ;* * 199 ;* This funtion is call to either xor or copy XOR_Delta data onto a * 200 ;* page instead of a buffer. The routine will set up the registers * 201 ;* need for the actual routines that will perform the copy or xor. * 202 ;* * 203 ;* The registers are setup as follows : * 204 ;* es:edi - destination segment:offset onto page. * 205 ;* ds:esi - source buffer segment:offset of delta data. * 206 ;* dx,cx,ax - are all zeroed out before entry. * 207 ;* * 208 ;* INPUT: * 209 ;* * 210 ;* OUTPUT: * 211 ;* * 212 ;* WARNINGS: * 213 ;* * 214 ;* HISTORY: * 215 ;* 03/09/1992 SB : Created. * 216 ;*=========================================================================* 217 218 219 Apply_XOR_Delta_To_Page_Or_Viewport proc C public USES ebx ecx edx esi edi target:DWORD, delta:DWORD, xwidth:DWORD, nextrow:DWORD, copy:DWORD 220 221 ;USES ebx,ecx,edx,edi,esi 222 ;ARG target:DWORD ; pointer to the destination buffer. 223 ;ARG delta:DWORD ; pointer to the delta buffer. 224 ;ARG width:DWORD ; width of animation. 225 ;ARG nextrow:DWORD ; Page/Buffer width - anim width. 226 ;ARG copy:DWORD ; should it be copied or xor'd? 227 228 229 mov edi,[target] ; Get the target pointer. 230 mov esi,[delta] ; Get the destination pointer. 231 232 xor eax,eax ; clear eax, later put them into ecx and edx. 233 234 cld ; make sure we go forward 235 236 mov ebx,[nextrow] ; get the amount to add to get to next row from end. push it later... 237 238 mov ecx,eax ; use cx for loop 239 mov edx,eax ; use dx to count the relative column. 240 241 push ebx ; push nextrow onto the stack for Copy/XOR_Delta_Buffer. 242 mov ebx,[xwidth] ; bx will hold the max column for speed compares 243 244 ; At this point, all the registers have been set up. Now call the correct function 245 ; to either copy or xor the data. 246 247 cmp [copy],DO_XOR ; Do we want to copy or XOR 248 je xorfunct ; Jump to XOR if not copy 249 call Copy_Delta_Buffer ; Call the function to copy the delta buffer. 250 jmp didcopy ; jump past XOR 251 xorfunct: 252 call XOR_Delta_Buffer ; Call funtion to XOR the deltat buffer. 253 didcopy: 254 pop ebx ; remove the push done to pass a value. 255 256 ret 257 258 Apply_XOR_Delta_To_Page_Or_Viewport ENDP 259 ;---------------------------------------------------------------------------- 260 261 262 ;*************************************************************************** 263 ;* XOR_DELTA_BUFFER -- Xor's the data in a XOR Delta format to a page. * 264 ;* This will only work right if the page has the previous data on it. * 265 ;* This function should only be called by XOR_Delta_Buffer_To_Page_Or_Viewport. * 266 ;* The registers must be setup as follows : * 267 ;* * 268 ;* INPUT: * 269 ;* es:edi - destination segment:offset onto page. * 270 ;* ds:esi - source buffer segment:offset of delta data. * 271 ;* edx,ecx,eax - are all zeroed out before entry. * 272 ;* * 273 ;* OUTPUT: * 274 ;* * 275 ;* WARNINGS: * 276 ;* * 277 ;* HISTORY: * 278 ;* 03/09/1992 SB : Created. * 279 ;*=========================================================================* 280 281 XOR_Delta_Buffer proc C nextrow:DWORD 282 283 top_loop2: 284 xor eax,eax ; clear out eax. 285 mov al,[esi] ; get delta source byte 286 inc esi 287 288 test al,al ; check for a SHORTDUMP ; check al incase of sign value. 289 je short_run2 290 js check_others2 291 292 ; 293 ; SHORTDUMP 294 ; 295 mov ecx,eax ; stick count in cx 296 297 dump_loop2: 298 mov al,[esi] ; get delta XOR byte 299 xor [edi],al ; xor that byte on the dest 300 inc esi 301 inc edx ; increment our count on current column 302 inc edi 303 cmp edx,ebx ; are we at the final column 304 jne end_col1 ; if not the jmp over the code 305 306 sub edi,edx ; get our column back to the beginning. 307 xor edx,edx ; zero out our column counter 308 add edi,[nextrow] ; jump to start of next row 309 end_col1: 310 311 dec ecx 312 jnz dump_loop2 313 jmp top_loop2 314 315 ; 316 ; SHORTRUN 317 ; 318 319 short_run2: 320 mov cl,[esi] ; get count 321 inc esi ; inc delta source 322 323 do_run2: 324 mov al,[esi] ; get XOR byte 325 inc esi 326 327 run_loop2: 328 xor [edi],al ; xor that byte. 329 330 inc edx ; increment our count on current column 331 inc edi ; go to next dest pixel 332 cmp edx,ebx ; are we at the final column 333 jne end_col2 ; if not the jmp over the code 334 335 sub edi,ebx ; get our column back to the beginning. 336 xor edx,edx ; zero out our column counter 337 add edi,[nextrow] ; jump to start of next row 338 end_col2: 339 340 341 dec ecx 342 jnz run_loop2 343 jmp top_loop2 344 345 ; 346 ; By now, we know it must be a LONGDUMP, SHORTSKIP, LONGRUN, or LONGSKIP 347 ; 348 349 check_others2: 350 sub eax,080h ; opcode -= 0x80 351 jnz do_skip2 ; if zero then get next word, otherwise use remainder. 352 353 mov ax,[esi] ; get word code in ax 354 lea esi,[esi+2] 355 test ax,ax ; set flags. (not 32bit register so neg flag works) 356 jle not_long_skip2 357 358 ; 359 ; SHORTSKIP AND LONGSKIP 360 ; 361 do_skip2: 362 sub edi,edx ; go back to beginning or row. 363 add edx,eax ; incriment our count on current row 364 recheck2: 365 cmp edx,ebx ; are we past the end of the row 366 jb end_col3 ; if not the jmp over the code 367 368 sub edx,ebx ; Subtract width from the col counter 369 add edi,[nextrow] ; jump to start of next row 370 jmp recheck2 ; jump up to see if we are at the right row 371 end_col3: 372 add edi,edx ; get to correct position in row. 373 jmp top_loop2 374 375 376 not_long_skip2: 377 jz stop2 ; long count of zero means stop 378 sub eax,08000h ; opcode -= 0x8000 379 test eax,04000h ; is it a LONGRUN (code & 0x4000)? 380 je long_dump2 381 382 ; 383 ; LONGRUN 384 ; 385 sub eax,04000h ; opcode -= 0x4000 386 mov ecx,eax ; use cx as loop count 387 jmp do_run2 ; jump to run code. 388 389 390 ; 391 ; LONGDUMP 392 ; 393 394 long_dump2: 395 mov ecx,eax ; use cx as loop count 396 jmp dump_loop2 ; go to the dump loop. 397 398 stop2: 399 400 ret 401 402 403 XOR_Delta_Buffer ENDP 404 405 ;---------------------------------------------------------------------------- 406 407 408 ;*************************************************************************** 409 ;* COPY_DELTA_BUFFER -- Copies XOR Delta Data to a section of a page. * 410 ;* This function should only be called by XOR_Delta_Buffer_To_Page_Or_Viewport. * 411 ;* The registers must be setup as follows : * 412 ;* * 413 ;* INPUT: * 414 ;* es:edi - destination segment:offset onto page. * 415 ;* ds:esi - source buffer segment:offset of delta data. * 416 ;* dx,cx,ax - are all zeroed out before entry. * 417 ;* * 418 ;* OUTPUT: * 419 ;* * 420 ;* WARNINGS: * 421 ;* * 422 ;* HISTORY: * 423 ;* 03/09/1992 SB : Created. * 424 ;*=========================================================================* 425 Copy_Delta_Buffer proc C nextrow:DWORD 426 427 ;ARG nextrow:DWORD 428 429 top_loop3: 430 xor eax,eax ; clear out eax. 431 mov al,[esi] ; get delta source byte 432 inc esi 433 434 test al,al ; check for a SHORTDUMP ; check al incase of sign value. 435 je short_run3 436 js check_others3 437 438 ; 439 ; SHORTDUMP 440 ; 441 mov ecx,eax ; stick count in cx 442 443 dump_loop3: 444 mov al,[esi] ; get delta XOR byte 445 446 mov [edi],al ; store that byte on the dest 447 448 inc edx ; increment our count on current column 449 inc esi 450 inc edi 451 cmp edx,ebx ; are we at the final column 452 jne end_col1_3 ; if not the jmp over the code 453 454 sub edi,edx ; get our column back to the beginning. 455 xor edx,edx ; zero out our column counter 456 add edi,[nextrow] ; jump to start of next row 457 end_col1_3: 458 459 dec ecx 460 jnz dump_loop3 461 jmp top_loop3 462 463 ; 464 ; SHORTRUN 465 ; 466 467 short_run3: 468 mov cl,[esi] ; get count 469 inc esi ; inc delta source 470 471 do_run3: 472 mov al,[esi] ; get XOR byte 473 inc esi 474 475 run_loop3: 476 mov [edi],al ; store the byte (instead of XOR against current color) 477 478 inc edx ; increment our count on current column 479 inc edi ; go to next dest pixel 480 cmp edx,ebx ; are we at the final column 481 jne end_col2_3 ; if not the jmp over the code 482 483 sub edi,ebx ; get our column back to the beginning. 484 xor edx,edx ; zero out our column counter 485 add edi,[nextrow] ; jump to start of next row 486 end_col2_3: 487 488 489 dec ecx 490 jnz run_loop3 491 jmp top_loop3 492 493 ; 494 ; By now, we know it must be a LONGDUMP, SHORTSKIP, LONGRUN, or LONGSKIP 495 ; 496 497 check_others3: 498 sub eax,080h ; opcode -= 0x80 499 jnz do_skip3 ; if zero then get next word, otherwise use remainder. 500 501 mov ax,[esi] ; get word code in ax 502 lea esi,[esi+2] 503 test ax,ax ; set flags. (not 32bit register so neg flag works) 504 jle not_long_skip3 505 506 ; 507 ; SHORTSKIP AND LONGSKIP 508 ; 509 do_skip3: 510 sub edi,edx ; go back to beginning or row. 511 add edx,eax ; incriment our count on current row 512 recheck3: 513 cmp edx,ebx ; are we past the end of the row 514 jb end_col3_3 ; if not the jmp over the code 515 516 sub edx,ebx ; Subtract width from the col counter 517 add edi,[nextrow] ; jump to start of next row 518 jmp recheck3 ; jump up to see if we are at the right row 519 end_col3_3: 520 add edi,edx ; get to correct position in row. 521 jmp top_loop3 522 523 524 not_long_skip3: 525 jz stop3 ; long count of zero means stop 526 sub eax,08000h ; opcode -= 0x8000 527 test eax,04000h ; is it a LONGRUN (code & 0x4000)? 528 je long_dump3 529 530 ; 531 ; LONGRUN 532 ; 533 sub eax,04000h ; opcode -= 0x4000 534 mov ecx,eax ; use cx as loop count 535 jmp do_run3 ; jump to run code. 536 537 538 ; 539 ; LONGDUMP 540 ; 541 542 long_dump3: 543 mov ecx,eax ; use cx as loop count 544 jmp dump_loop3 ; go to the dump loop. 545 546 stop3: 547 548 ret 549 550 Copy_Delta_Buffer ENDP 551 552 ;---------------------------------------------------------------------------- 553 554 END 555 556 557 ;---------------------------------------------------------------------------- 558 ; 559 ;PUBLIC UWORD Apply_XOR_Delta(UWORD page_seg, BYTE *delta_ptr) 560 ;{ 561 ; 562 ; register UWORD loop; 563 ; BYTE opcode, xor_byte; 564 ; UWORD bytes_to_uncompress = 64000U; 565 ; 566 ; 567 ; /* Make our buffer pointer */ 568 ; 569 ; to = MK_FP(page_seg, 0); 570 ; delta = Normalize_Pointer(delta_ptr); 571 ; 572 ; 573 ; while (bytes_to_uncompress) { 574 ; 575 ; opcode = *delta++; 576 ; 577 ; 578 ; /* Check for SHORTDUMP */ 579 ; 580 ; if (opcode > 0) { 581 ; 582 ; 583 ; bytes_to_uncompress -= opcode; 584 ; 585 ; for (loop = 0; loop < opcode; loop++) { 586 ; xor_byte = *delta++; 587 ; *to++ ^= xor_byte; 588 ; } 589 ; continue; 590 ; } 591 ; 592 ; /* Check for SHORTRUN */ 593 ; 594 ; if (opcode == 0) { 595 ; 596 ; word_count = *delta++; 597 ; xor_byte = *delta++; 598 ; 599 ; bytes_to_uncompress -= word_count; 600 ; 601 ; for (loop = 0; loop < word_count; loop++) { 602 ; *to++ ^= xor_byte; 603 ; } 604 ; continue; 605 ; } 606 ; 607 ; /* By now, we know it must be a LONGDUMP, SHORTSKIP, or LONGSKIP */ 608 ; 609 ; opcode -= 0x80; 610 ; 611 ; 612 ; /* Is it a SHORTSKIP? */ 613 ; 614 ; if (opcode != 0) { 615 ; 616 ; to += opcode; 617 ; bytes_to_uncompress -= (WORD) opcode; 618 ; continue; 619 ; } 620 ; 621 ; 622 ; word_count = *((UWORD *) delta)++; 623 ; 624 ; /* Is it a LONGSKIP? */ 625 ; 626 ; if ((WORD) word_count > 0) { 627 ; 628 ; to += word_count; 629 ; bytes_to_uncompress -= (WORD) word_count; 630 ; continue; 631 ; } 632 ; 633 ; 634 ; word_count -= 0x8000; 635 ; 636 ; /* Is it a LONGRUN? */ 637 ; 638 ; if (word_count & 0x4000) { 639 ; 640 ; word_count -= 0x4000; 641 ; 642 ; bytes_to_uncompress -= word_count; 643 ; 644 ; xor_byte = *delta++; 645 ; 646 ; for (loop = 0; loop < word_count; loop++) { 647 ; *to++ ^= xor_byte; 648 ; } 649 ; continue; 650 ; } 651 ; 652 ; 653 ; /* It must be a LONGDUMP */ 654 ; 655 ; bytes_to_uncompress -= word_count; 656 ; 657 ; for (loop = 0; loop < word_count; loop++) { 658 ; xor_byte = *delta++; 659 ; *to++ ^= xor_byte; 660 ; } 661 ; } 662 ; 663 ; 664 ; return(64000U); 665 ;} 666 ; 667 668