VTXTPRNT.ASM 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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 S T U D I O S **
  20. ;***************************************************************************
  21. ;* *
  22. ;* Project Name : Westwood 32 bit Library *
  23. ;* *
  24. ;* File Name : TXTPRNT.ASM *
  25. ;* *
  26. ;* Programmer : Phil W. Gorrow *
  27. ;* *
  28. ;* Start Date : January 17, 1995 *
  29. ;* *
  30. ;* Last Update : January 17, 1995 [PWG] *
  31. ;* *
  32. ;*-------------------------------------------------------------------------*
  33. ;* Functions: *
  34. ;* VESA_Print -- Assembly VESA text print routine *
  35. ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
  36. IDEAL
  37. P386
  38. MODEL USE32 FLAT
  39. INCLUDE "svgaprim.inc"
  40. INCLUDE ".\gbuffer.inc"
  41. ;*=========================================================================*
  42. ;* Extern the font pointer which is defined by the font class *
  43. ;*=========================================================================*
  44. GLOBAL FontPtr:DWORD
  45. GLOBAL ColorXlat:BYTE
  46. ;*=========================================================================*
  47. ;* Define the necessary equates for structures and bounds checking *
  48. ;*=========================================================================*
  49. ; The header of the font file looks like this:
  50. ; UWORD FontLength; 0
  51. ; BYTE FontCompress; 2
  52. ; BYTE FontDataBlocks; 3
  53. ; UWORD InfoBlockOffset; 4
  54. ; UWORD OffsetBlockOffset; 6
  55. ; UWORD WidthBlockOffset; 8
  56. ; UWORD DataBlockOffset; 10
  57. ; UWORD HeightOffset; 12
  58. ; For this reason the following equates have these values:
  59. FONTINFOBLOCK EQU 4
  60. FONTOFFSETBLOCK EQU 6
  61. FONTWIDTHBLOCK EQU 8
  62. FONTDATABLOCK EQU 10
  63. FONTHEIGHTBLOCK EQU 12
  64. FONTINFOMAXHEIGHT EQU 4
  65. FONTINFOMAXWIDTH EQU 5
  66. LOCALS ??
  67. ;*=========================================================================*
  68. ;* Define the color xlate table in the data segment *
  69. ;*=========================================================================*
  70. CODESEG
  71. ;***************************************************************************
  72. ;* VESA_PRINT -- Assembly VESA text print routine *
  73. ;* *
  74. ;* *
  75. ;* *
  76. ;* INPUT: *
  77. ;* *
  78. ;* OUTPUT: *
  79. ;* *
  80. ;* PROTO: *
  81. ;* *
  82. ;* WARNINGS: *
  83. ;* *
  84. ;* HISTORY: *
  85. ;* 01/17/1995 PWG : Created. *
  86. ;*=========================================================================*
  87. PROC Vesa_Print C near
  88. USES ebx,ecx,edx,esi,edi
  89. ARG this:DWORD
  90. ARG string:DWORD
  91. ARG x_pixel:DWORD
  92. ARG y_pixel:DWORD
  93. ARG fcolor:DWORD
  94. ARG bcolor:DWORD
  95. LOCAL infoblock:DWORD ; pointer to info block
  96. LOCAL offsetblock:DWORD ; pointer to offset block (UWORD *)
  97. LOCAL widthblock:DWORD ; pointer to width block (BYTE *)
  98. LOCAL heightblock:DWORD ; pointer to height block (UWORD *)
  99. LOCAL curline:DWORD ; pointer to first column of current row.
  100. local ptr_string:dword ; pointer to string
  101. LOCAL bufferwidth:DWORD ; width of buffer (vpwidth + Xadd)
  102. LOCAL nextdraw:DWORD ; bufferwidth - width of cur character.
  103. LOCAL startdraw:DWORD ; where next character will start being drawn.
  104. LOCAL char:DWORD ; current character value.
  105. LOCAL maxheight:BYTE ; max height of characters in font.
  106. LOCAL bottomblank:BYTE ; amount of empty space below current character.
  107. LOCAL charheight:BYTE ; true height of current character.
  108. LOCAL vpwidth:DWORD
  109. LOCAL vpheight:DWORD
  110. LOCAL remainder:DWORD
  111. LOCAL fullwidth:DWORD
  112. LOCAL currwidth:DWORD
  113. ;-------------------------------- Where to draw -----------------------------------------------
  114. ; Set up memory location to start drawing.
  115. mov ebx,[this] ; get a pointer to dest
  116. mov eax,[(GraphicViewPort ebx).GVPHeight] ; get height of viewport
  117. mov [vpheight],eax ; save off height of viewport
  118. mov eax,[(GraphicViewPort ebx).GVPWidth] ; get width of viewport
  119. mov [vpwidth],eax ; save it off for later
  120. add eax,[(GraphicViewPort ebx).GVPXAdd] ; add in xadd for bytes_per_line
  121. mov [bufferwidth],eax ; save it off for later use.
  122. mul [y_pixel] ; multiply rowsize * y_pixel start.
  123. mov edi,[(GraphicViewPort ebx).GVPOffset] ; get start of the viewport
  124. add edi,eax ; add y position to start of vp
  125. mov [curline],edi ; save 0,y address for line feed stuff.
  126. add edi,[x_pixel] ; add to get starting column in starting row.
  127. mov [startdraw],edi ; save it off.
  128. ;-------------------------------- Create block pointers ----------------------------------------
  129. ; Get the pointer to the font.
  130. ; We could check for NULL but why waste the time.
  131. ; It is up to programmer to make sure it is set.
  132. mov esi,[FontPtr] ; Get the font pointer
  133. or esi,esi
  134. jz ??done
  135. ; Set up some pointers to the different memory blocks.
  136. ; esi (FontPtr) is added to each to get the true address of each block.
  137. ; Many registers are used for P5 optimizations.
  138. ; ebx is used for InfoBlock which is then used in the next section.
  139. movzx eax,[WORD PTR esi+FONTOFFSETBLOCK] ; get offset to offset block
  140. movzx ebx,[WORD PTR esi+FONTINFOBLOCK] ; get offset to info block (must be ebx for height test)
  141. movzx ecx,[WORD PTR esi+FONTWIDTHBLOCK] ; get offset to width block
  142. movzx edx,[WORD PTR esi+FONTHEIGHTBLOCK] ; get offset to height block
  143. add eax,esi ; add offset of FontPtr to offset block
  144. add ebx,esi ; add offset of FontPtr to info block
  145. add ecx,esi ; add offset of FontPtr to width block
  146. add edx,esi ; add offset of FontPtr to height block
  147. mov [offsetblock],eax ; save offset to offset block
  148. mov [infoblock],ebx ; save offset to info block
  149. mov [widthblock],ecx ; save offset to width block
  150. mov [heightblock],edx ; save offset to height block
  151. ;------------------------------------------ Test for fit ----------------------------------------------
  152. ; Test to make sure the height of the max character will fit on this line
  153. ; and and not fall out of the viewport.
  154. ; remember we set ebx to FONTINFOBLOCK above.
  155. movzx eax,[BYTE PTR ebx + FONTINFOMAXHEIGHT]; get the max height in font.
  156. mov [maxheight],al ; save it for later use.
  157. add eax,[y_pixel] ; add current y_value.
  158. cmp eax,[vpheight] ; are we over the edge?
  159. jg ??done ; if so, we're outa here.
  160. mov [y_pixel],eax ; save for next line feed. y value for next line.
  161. cld ; Make sure we are always forward copying.
  162. ;------------------------ Set palette foreground and background ----------------------------------
  163. mov eax,[fcolor] ; foreground color
  164. mov [ColorXlat+1],al
  165. mov [ColorXlat+16],al
  166. mov eax,[bcolor] ; background color
  167. mov [ColorXlat],al
  168. ;-------------------------------------------------------------------------------------------------
  169. ;----------------------------------------- Main loop ----------------------------------------------
  170. ; Now we go into the main loop of reading each character in the string and doing
  171. ; something with it.
  172. ??next_char:
  173. ; while (*string++)
  174. xor eax,eax ; zero out since we will just load al.
  175. mov esi,[string] ; get address on next character.
  176. lodsb ; load the character into al.
  177. test eax,0FFH ; test to see if character is a NULL
  178. jz ??done ; character is NULL, get outa here.
  179. mov edi,[startdraw] ; Load the starting address.
  180. mov [string],esi ; save index into string. (incremented by lodsb)
  181. cmp eax,10 ; is the character a line feed?
  182. je ??line_feed ; if so, go to special case.
  183. cmp eax,13 ; is the character a line feed?
  184. je ??line_feed ; if so, go to special case.
  185. mov [char],eax ; save the character off for later reference.
  186. mov ebx,eax ; save it in ebx for later use also.
  187. add eax,[widthblock] ; figure address of width of character.
  188. mov ecx,[x_pixel] ; get current x_pixel.
  189. movzx edx,[BYTE PTR eax] ; get the width of the character in dl.
  190. add ecx,edx ; add width of char to current x_pixel.
  191. add [startdraw],edx ; save start draw for next character.
  192. cmp ecx,[vpwidth] ; is the pixel greater then the vp width?
  193. jg ??force_line_feed ; if so, force a line feed.
  194. mov [x_pixel],ecx ; save value of start of next character.
  195. mov ecx,[bufferwidth] ; get amount to next y same x (one row down)
  196. sub ecx,edx ; take the current width off.
  197. mov [nextdraw],ecx ; save it to add to edi when done with a row.
  198. ; At this point we got the character. It is now time to find out specifics
  199. ; about drawing the darn thing.
  200. ; ebx = char so they can be used as an indexes.
  201. ; edx = width of character for loop later.
  202. ; get offset of data for character into esi.
  203. shl ebx,1 ; mult by 2 to later use as a WORD index.
  204. mov esi,[offsetblock] ; get pointer to begining of offset block.
  205. add esi,ebx ; index into offset block.
  206. movzx esi,[WORD PTR esi] ; get true offset into data block from FontPtr.
  207. add esi,[FontPtr] ; Now add FontPtr address to get true address.
  208. ; Get top and bottom blank sizes and the true height of the character.
  209. add ebx,[heightblock] ; point ebx to element in height array.
  210. mov al,[ebx+1] ; load the data height into dl.
  211. mov cl,[ebx] ; load the first data row into cl.
  212. mov bl,[maxheight] ; get the max height of characters.
  213. mov [charheight],al ; get number of rows with data.
  214. add al,cl ; add the two heights.
  215. sub bl,al ; subract topblank + char height from maxheight.
  216. mov [bottomblank],bl ; save off the number of blank rows on the bottom.
  217. ; leaving this section:
  218. ; dl is still the width of the character.
  219. ; cl is the height of the top blank area.
  220. mov ebx,OFFSET ColorXlat ; setup ebx for xlat commands.
  221. mov dh,dl ; save the width of the character to restore each loop.
  222. call Vesa_Asm_Set_Win ; adjust edi & vesa page
  223. cmp cl,0 ; is there any blank rows on top?
  224. jz ??draw_char ; if not go and draw the real character.
  225. xor eax,eax ; get color 0 for background.
  226. xlat [ebx] ; get translated color into al
  227. test al,al ; is it transparent black
  228. jnz ??loop_top ; if not go and write the color
  229. ;----------------------------------------- skip Top blank area ----------------------------------------
  230. ; this case, the top is transparrent, but we need to increase our dest pointer to correct row.
  231. movzx eax,cl ; get number of rows into eax;
  232. mov ecx,edx ; save width since edx will be destroyed by mul.
  233. mul [bufferwidth] ; multiply that by the width of the buffer.
  234. mov edx,ecx ; restore the width
  235. add edi,eax ; update the pointer.
  236. cmp edi,0b0000h ; have we gone over win edge
  237. jl ??draw_char ; if not keep writing to window
  238. add edi , [ cpu_video_page ]
  239. call Vesa_Asm_Set_Win ; instead switch to next window
  240. jmp short ??draw_char ; now go draw the character.
  241. ;----------------------------------------- fill Top blank area ----------------------------------------
  242. ??loop_top:
  243. stosb ; store the value
  244. cmp edi,0b0000h ; have we gone over win edge
  245. jl ??top_no_window_change ; if not keep writing to window
  246. add edi , [ cpu_video_page ]
  247. call Vesa_Asm_Set_Win ; instead switch to next window
  248. ??top_no_window_change:
  249. dec dh ; decrement our width.
  250. jnz ??loop_top ; if more width, continue on.
  251. add edi,[nextdraw] ; add amount for entire row.
  252. cmp edi,0b0000h ; have we gone over win edge
  253. jl ??top2_no_window_change ; if not keep writing to window
  254. add edi , [ cpu_video_page ]
  255. call Vesa_Asm_Set_Win ; instead switch to next window
  256. ??top2_no_window_change:
  257. dec cl ; decrement or row count
  258. mov dh,dl ; restore width in dh for loop.
  259. jz ??draw_char ; we are done here, go draw the character.
  260. jmp short ??loop_top ; go back to top of loop.
  261. ;----------------------------------------- Draw character ----------------------------------------------
  262. ??draw_char:
  263. movzx ecx,[charheight] ; get the height of character to count down rows.
  264. test ecx,ecx ; is there any data? (blank would not have any)
  265. jz ??next_char ; if no data, go on to next character.
  266. ??while_data:
  267. lodsb ; get byte value from font data
  268. mov ah,al ; save hinibble
  269. and eax,0F00FH ; mask of low nibble in al hi nibble in ah.
  270. xlat [ebx] ; get new color
  271. test al,al ; is it a transparent?
  272. jz short ??skiplo ; skip over write
  273. mov [es:edi],al ; write it out
  274. ??skiplo:
  275. inc edi
  276. cmp edi,0b0000h ; have we gone over win edge
  277. jl ??lo_no_window_change ; if not keep writing to window
  278. add edi , [ cpu_video_page ]
  279. call Vesa_Asm_Set_Win ; instead switch to next window
  280. ??lo_no_window_change:
  281. dec dh ; decrement our width.
  282. jz short ??nextrow ; check if done with width of char
  283. mov al,ah ; restore to get
  284. ; test the time difference between looking up in a large table when shr al,4 is not done as
  285. ; compared to using only a 16 byte table when using the shr al,4
  286. ;shr al,4 ; shift the hi nibble down to low nibble
  287. xlat [ebx] ; get new color
  288. test al,al ; is it a transparent?
  289. jz short ??skiphi ; skip over write
  290. mov [edi],al ; write it out
  291. ??skiphi:
  292. inc edi
  293. cmp edi,0b0000h ; have we gone over win edge
  294. jl ??hi_no_window_change ; if not keep writing to window
  295. add edi , [ cpu_video_page ]
  296. call Vesa_Asm_Set_Win ; instead switch to next window
  297. ??hi_no_window_change:
  298. dec dh ; decrement our width.
  299. jnz short ??while_data ; check if done with width of char
  300. ??nextrow:
  301. add edi,[nextdraw] ; go to next line.
  302. cmp edi,0b0000h ; have we gone over win edge
  303. jl ??next_row_no_window_change ; if not keep writing to window
  304. add edi , [ cpu_video_page ]
  305. call Vesa_Asm_Set_Win ; instead switch to next window
  306. ??next_row_no_window_change:
  307. dec ecx ; decrement the number of rows to go
  308. mov dh,dl ; restore our column count for row.
  309. jnz ??while_data ; more data for character.
  310. ; Now it is time to setup for clearing out the bottom of the character.
  311. movzx ecx,[bottomblank] ; get amount on bottom that is blank
  312. cmp ecx,0 ; if there is no blank bottom...
  313. jz ??next_char ; then skip to go to next character
  314. xor eax,eax ; get color 0 for background.
  315. xlat [ebx] ; get translated color into al
  316. test al,al ; is it transparent black
  317. jz ??next_char ; skip the top black section to let the background through
  318. mov dh,dl ; restore width in dh for loop.
  319. ;----------------------------------------- Blank below character -----------------------------------
  320. ??loop_bottom:
  321. stosb ; store the value
  322. cmp edi,0b0000h ; have we gone over win edge
  323. jl ??bottom_no_window_change ; if not keep writing to window
  324. add edi , [ cpu_video_page ]
  325. call Vesa_Asm_Set_Win ; instead switch to next window
  326. ??bottom_no_window_change:
  327. dec dh ; decrement our width.
  328. jnz ??loop_bottom ; if more width, continue on.
  329. add edi,[nextdraw] ; add amount for entire row.
  330. cmp edi,0b0000h ; have we gone over win edge
  331. jl ??bottom2_no_window_change ; if not keep writing to window
  332. add edi , [ cpu_video_page ]
  333. call Vesa_Asm_Set_Win ; instead switch to next window
  334. ??bottom2_no_window_change:
  335. mov dh,dl ; restore width in dh for loop.
  336. dec cl ; decrement or row count
  337. jz ??next_char ; we are done here, go to the next character.
  338. jmp short ??loop_bottom ; go back to top of loop.
  339. ;----------------------------------- end of next_char (main) loop ------------------------------------
  340. ;-------------------------------------------------------------------------------------------------
  341. ;----------------------------------- special case line feeds ----------------------------------------
  342. ; JRJ 05/01/95 This is the problem However made this change introduced
  343. ; a error in the code, this function is not supposed to handle
  344. ; Text wrapping
  345. ??force_line_feed:
  346. ; decrement pointer *string so that it will be back at same character
  347. ; when it goes through the loop.
  348. dec [dword ptr string] ; overflow by one charater
  349. jmp ??done
  350. ??line_feed:
  351. mov edx,[y_pixel] ; get the current y pixel value.
  352. movzx ecx,[maxheight] ; get max height for later use.
  353. add edx,ecx ; add max height to y_pixel
  354. cmp edx,[vpheight] ; are we over the edge?
  355. jg ??done ; if so, we are outa here.
  356. mov eax,[bufferwidth] ; get bytes to next line.
  357. mov edi,[curline] ; get start of current line.
  358. mul ecx ; mult max height * next line.
  359. add edi,eax ; add adjustment to current line.
  360. add [y_pixel],ecx ; increment to our next y position.
  361. mov [curline],edi ; save it off for next line_feed.
  362. mov [startdraw],edi ; save it off so we know where to draw next char.w
  363. mov [x_pixel],0 ; zero out x_pixel
  364. jmp ??next_char
  365. ??done:
  366. mov eax,[string] ; return the number of charaters
  367. sub eax,[ptr_string] ; printed
  368. ret
  369. ENDP Vesa_Print
  370. END