XORDELTA.ASM 18 KB

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