HORIZON.ASM 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. ; THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  2. ; SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
  3. ; END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  4. ; ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  5. ; IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  6. ; SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  7. ; FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  8. ; CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
  9. ; AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  10. ; COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
  11. .386
  12. option oldstructs
  13. .nolist
  14. include pstypes.inc
  15. include psmacros.inc
  16. include gr.inc
  17. include 3d.inc
  18. .list
  19. assume cs:_TEXT, ds:_DATA
  20. _DATA segment dword public USE32 'DATA'
  21. rcsid db "$Id: horizon.asm 1.6 1996/01/08 14:59:09 matt Exp $"
  22. align 4
  23. sky_color dd ?
  24. ground_color dd ?
  25. top_color dd ?
  26. bot_color dd ?
  27. color_swap dw ? ;flag for if we swapped
  28. sky_ground_flag dw ? ;0=both, 1=all sky, -1=all gnd
  29. horizon_vec vms_vector <> ;unscaled up vector
  30. up_right fix ?
  31. down_right fix ?
  32. down_left fix ?
  33. up_left fix ?
  34. left_point fix ?,? ;coords of left point
  35. left_point_edge dd ? ;which edge point is on
  36. right_point fix ?,? ;coords of right point
  37. right_point_edge dd ? ;which edge point is on
  38. ;the coordinates of the four corners of the screen (values are placeholders)
  39. corners fix 0,0 ;up left
  40. fix 319,0 ;up right
  41. fix 319,199 ;down right
  42. fix 0,199 ;down left
  43. horizon_poly dw 5 dup (?,?) ;max of 5 points
  44. ;for g3_compute_horz_vecs
  45. xfrac fix ?
  46. yfrac fix ?
  47. vec_ptr dd ?
  48. corner_num dd ?
  49. ;for compute corner vec
  50. m13 fix ? ;m1-m3
  51. m46 fix ?
  52. m79 fix ?
  53. m56 fix ?
  54. m23 fix ?
  55. m89 fix ?
  56. _DATA ends
  57. _TEXT segment dword public USE32 'CODE'
  58. extn gr_setcolor_,gr_clear_canvas_
  59. extn gr_upoly_tmap_
  60. ;draws a horizon. takes eax=sky_color, edx=ground_color
  61. g3_draw_horizon: pushm eax,ebx,ecx,edx,esi,edi
  62. mov sky_color,eax
  63. mov ground_color,edx
  64. mov color_swap,0 ;assume no swap
  65. mov sky_ground_flag,0 ;assume both
  66. test View_matrix.uvec.y,-1 ;check up
  67. jg sky_up
  68. js swap_colors
  69. ;y is zero. check x
  70. test View_matrix.uvec.x,-1
  71. js sky_up
  72. swap_colors: xchg eax,edx ;make sky down
  73. mov color_swap,-1 ;we swapped
  74. sky_up: mov top_color,eax
  75. mov bot_color,edx
  76. ;compute horizon_vector
  77. mov eax,Unscaled_matrix.rvec.y
  78. fixmul Matrix_scale.y
  79. fixmul Matrix_scale.z
  80. mov horizon_vec.x,eax
  81. mov esi,eax
  82. mov eax,Unscaled_matrix.uvec.y
  83. fixmul Matrix_scale.x
  84. fixmul Matrix_scale.z
  85. mov horizon_vec.y,eax
  86. mov edi,eax
  87. mov eax,Unscaled_matrix.fvec.y
  88. fixmul Matrix_scale.x
  89. fixmul Matrix_scale.y
  90. mov horizon_vec.z,eax
  91. ;now compute values & flag for 4 corners. eax = z componant
  92. mov ebx,0ff00h ;and/or flags
  93. add eax,esi
  94. add eax,edi ;eax = x+y+z
  95. mov up_right,eax
  96. cdq
  97. and bh,dl ;flags_and
  98. or bl,dl ;flags_or
  99. sal esi,1
  100. sal edi,1 ;get x*2, y*2
  101. sub eax,edi ;eax = x-y+z
  102. mov down_right,eax
  103. cdq
  104. and bh,dl ;flags_and
  105. or bl,dl ;flags_or
  106. sub eax,esi ;eax = -x-y+z
  107. mov down_left,eax
  108. cdq
  109. and bh,dl ;flags_and
  110. or bl,dl ;flags_or
  111. add eax,edi ;eax = -x+y+z
  112. mov up_left,eax
  113. cdq
  114. ;; debug "u: %x %x %x c: %x %x %x %x\n",unscaled_matrix.uvec.y,unscaled_matrix.uvec.z,unscaled_matrix.uvec.x,up_left,up_right,down_right,down_left
  115. ;check flags for all sky or all ground. dl=flag from last corner
  116. and bh,dl ;flags_and
  117. jnz all_ground
  118. or bl,dl ;flags_or
  119. jz all_sky
  120. ;fill in values for corners
  121. mov eax,Canvas_width
  122. sal eax,16 ;make a fix
  123. mov corners+8,eax
  124. mov corners+16,eax
  125. mov eax,Canvas_height
  126. sal eax,16 ;make a fix
  127. mov corners+20,eax
  128. mov corners+28,eax
  129. ;check for intesection with each of four edges & compute horizon line
  130. lea ebx,left_point
  131. ;check intersection with left edge
  132. mov eax,up_left
  133. xor eax,down_left ;signs different?
  134. jns not_left ;..no, so no isect with left
  135. mov eax,corners+20
  136. fixmuldiv up_left,edi ;eax = up_left * height / y*2
  137. abs_eax
  138. mov 4[ebx],eax ;y
  139. xor eax,eax
  140. mov [ebx],eax ;x=0
  141. mov 8[ebx],eax ;edge 0
  142. add ebx,12
  143. not_left:
  144. ;check intersection with top edge
  145. mov eax,up_left
  146. xor eax,up_right ;signs different?
  147. jns not_top ;..no, so no isect with left
  148. mov eax,corners+16
  149. fixmuldiv up_left,esi ;eax = up_right * width / x*2
  150. abs_eax
  151. mov [ebx],eax ;x
  152. xor eax,eax
  153. mov 4[ebx],eax ;y=0
  154. inc eax
  155. mov 8[ebx],eax ;edge 1
  156. add ebx,12
  157. not_top:
  158. ;check intersection with right edge
  159. mov eax,up_right
  160. xor eax,down_right ;signs different?
  161. jns not_right ;..no, so no isect with left
  162. mov eax,corners+20
  163. fixmuldiv up_right,edi ;eax = up_right * height / y*2
  164. abs_eax
  165. ;neg eax
  166. ;add eax,corners+20
  167. mov 4[ebx],eax ;y
  168. mov eax,corners+16
  169. mov [ebx],eax ;x=width-1
  170. mov eax,2
  171. mov 8[ebx],eax ;edge 2
  172. add ebx,12
  173. not_right:
  174. ;check intersection with bottom edge
  175. mov eax,down_right
  176. xor eax,down_left ;signs different?
  177. jns not_bot ;..no, so no isect with left
  178. mov eax,corners+16
  179. fixmuldiv down_left,esi ;eax = down_right * width / x*2
  180. abs_eax
  181. mov [ebx],eax ;x
  182. mov eax,corners+20
  183. mov 4[ebx],eax ;y=height-1
  184. mov eax,3
  185. mov 8[ebx],eax ;edge 3
  186. add ebx,12
  187. not_bot:
  188. ;make sure we wrote two and only two ends of horizon line
  189. ifndef NDEBUG
  190. cmp ebx,offset left_point+24
  191. break_if ne,'Wrong number of values for horizon_line'
  192. endif
  193. ;make sure first edge is left
  194. mov eax,left_point
  195. cmp eax,right_point
  196. jle line_ok
  197. ;swap left and right
  198. xchg eax,right_point
  199. mov left_point,eax
  200. mov eax,left_point+4
  201. xchg eax,right_point+4
  202. mov left_point+4,eax
  203. mov eax,left_point+8
  204. xchg eax,right_point+8
  205. mov left_point+8,eax
  206. line_ok:
  207. ;draw two polygons from horizon line
  208. mov eax,top_color
  209. cmp eax,-1 ;no draw?
  210. je no_draw_top
  211. call gr_setcolor_
  212. lea esi,left_point
  213. lea edi,right_point
  214. call draw_horz_poly
  215. no_draw_top:
  216. mov eax,bot_color
  217. cmp eax,-1 ;no draw?
  218. je no_draw_bot
  219. call gr_setcolor_
  220. lea esi,right_point
  221. lea edi,left_point
  222. call draw_horz_poly
  223. no_draw_bot:
  224. ;draw lines for diagnostics
  225. ;; xor eax,eax
  226. ;; call gr_setcolor_
  227. ;; mov eax,left_point
  228. ;; mov edx,left_point+4
  229. ;; mov ebx,right_point
  230. ;; mov ecx,right_point+4
  231. ;; call gr_line_
  232. done_horizon: popm eax,ebx,ecx,edx,esi,edi
  233. ret
  234. ;we see all sky or all ground. clear screen with appropriate color
  235. all_ground: mov eax,ground_color
  236. mov sky_ground_flag,-1 ;all ground
  237. jmp do_clear
  238. all_sky: mov eax,sky_color
  239. mov sky_ground_flag,1 ;all sky
  240. do_clear: call gr_clear_canvas_
  241. jmp done_horizon
  242. ;draw a polygon (one half of horizon) from the horizon line
  243. draw_horz_poly: lea ebx,horizon_poly
  244. ;copy horizon line as first points in poly
  245. mov eax,[edi]
  246. mov [ebx],eax
  247. mov eax,4[edi]
  248. mov 4[ebx],eax
  249. mov eax,[esi]
  250. mov 8[ebx],eax
  251. mov eax,4[esi]
  252. mov 12[ebx],eax
  253. ;add corners to polygon
  254. mov eax,8[esi] ;edge number of start edge
  255. mov ecx,8[edi] ;edge number of end point
  256. sub ecx,eax ;number of edges
  257. jns edgenum_ok
  258. add ecx,4
  259. edgenum_ok:
  260. mov edx,ecx ;save count
  261. sal eax,3 ;edge * 8
  262. lea esi,corners[eax] ;first corner
  263. lea edi,16[ebx] ;rest of poly
  264. corner_loop: movsd
  265. movsd ;copy a corner
  266. cmp esi,offset corners+8*4 ;end of list?
  267. jne no_wrap
  268. lea esi,corners
  269. no_wrap: loop corner_loop
  270. ;now draw the polygon
  271. mov eax,edx ;get corner count
  272. add eax,2 ;..plus horz line end points
  273. lea edx,horizon_poly ;get the points
  274. ;; call gr_poly_ ;draw it!
  275. call gr_upoly_tmap_
  276. ret
  277. ;return information on the polygon that is the sky.
  278. ;takes ebx=ptr to x,y pairs, ecx=ptr to vecs for each point
  279. ;returns eax=number of points
  280. ;IMPORTANT: g3_draw_horizon() must be called before this routine.
  281. g3_compute_sky_polygon:
  282. test sky_ground_flag,-1 ;what was drawn
  283. js was_all_ground
  284. jg was_all_sky
  285. pushm ebx,ecx,edx,esi,edi
  286. lea esi,left_point
  287. lea edi,right_point
  288. test color_swap,-1
  289. jz no_swap_ends
  290. xchg esi,edi ;sky isn't top
  291. no_swap_ends:
  292. ;copy horizon line as first points in poly
  293. mov eax,[edi] ;copy end point
  294. mov [ebx],eax
  295. mov eax,4[edi]
  296. mov 4[ebx],eax
  297. mov eax,[esi] ;copy start point
  298. mov 8[ebx],eax
  299. mov eax,4[esi]
  300. mov 12[ebx],eax
  301. pushm ebx,ecx
  302. push edi ;save end point
  303. push esi ;save start point
  304. mov esi,edi ;end point is first point
  305. mov edi,ecx ;dest buffer
  306. call compute_horz_end_vec
  307. pop esi ;get back start point
  308. add edi,12 ;2nd vec
  309. call compute_horz_end_vec
  310. pop edi ;get back end point
  311. popm ebx,ecx
  312. add ebx,16 ;past two x,y pairs
  313. add ecx,24 ;past two vectors
  314. mov vec_ptr,ecx
  315. ;add corners to polygon
  316. mov eax,8[esi] ;edge number of start edge
  317. mov corner_num,eax
  318. mov ecx,8[edi] ;edge number of end point
  319. sub ecx,eax ;number of edges
  320. jns edgenum_ok2
  321. add ecx,4
  322. edgenum_ok2:
  323. push ecx ;save count
  324. sal eax,3 ;edge * 8
  325. lea esi,corners[eax] ;first corner
  326. mov edi,ebx ;rest of poly 2d points
  327. corner_loop2:
  328. movsd
  329. movsd ;copy a corner
  330. cmp esi,offset corners+8*4 ;end of list?
  331. jne no_wrap2
  332. lea esi,corners
  333. no_wrap2:
  334. pushm ecx,esi,edi
  335. mov edi,vec_ptr
  336. mov eax,corner_num
  337. call compute_corner_vec
  338. add vec_ptr,12
  339. inc corner_num
  340. popm ecx,esi,edi
  341. loop corner_loop2
  342. ;now return with count
  343. pop eax ;get corner count
  344. add eax,2 ;..plus horz line end points
  345. popm ebx,ecx,edx,esi,edi
  346. ret
  347. ;we drew all ground, so there was no horizon drawn
  348. was_all_ground: xor eax,eax ;no points in poly
  349. ret
  350. ;we drew all sky, so find 4 corners
  351. was_all_sky: pushm ebx,ecx,edx,esi,edi
  352. push ecx
  353. lea esi,corners
  354. mov edi,ebx
  355. mov ecx,8
  356. rep movsd
  357. pop edi
  358. mov ecx,4
  359. xor eax,eax ;start corner 0
  360. sky_loop: pushm eax,ecx,edi
  361. call compute_corner_vec
  362. popm eax,ecx,edi
  363. add edi,12
  364. inc eax
  365. loop sky_loop
  366. mov eax,4 ;4 corners
  367. popm ebx,ecx,edx,esi,edi
  368. ret
  369. ;compute vector describing horizon intersection with a point.
  370. ;takes esi=2d point, edi=vec. trashes eax,ebx,ecx,edx
  371. compute_horz_end_vec:
  372. ;compute rotated x/z & y/z ratios
  373. mov eax,[esi] ;get x coord
  374. sub eax,Canv_w2
  375. fixdiv Canv_w2
  376. mov xfrac,eax ;save
  377. mov eax,4[esi] ;get y coord
  378. sub eax,Canv_h2
  379. fixdiv Canv_h2
  380. neg eax ;y inversion
  381. mov yfrac,eax ;save
  382. ;compute fraction unrotated x/z
  383. mov eax,xfrac
  384. add eax,yfrac
  385. mov ecx,eax ;save
  386. fixmul View_matrix.m9
  387. sub eax,View_matrix.m7
  388. sub eax,View_matrix.m8
  389. mov ebx,eax ;save numerator
  390. mov eax,ecx
  391. fixmul View_matrix.m3
  392. mov ecx,eax
  393. mov eax,View_matrix.m1
  394. add eax,View_matrix.m2
  395. sub eax,ecx
  396. ;now eax/ebx = z/x. do divide in way to give result < 0
  397. pushm eax,ebx
  398. abs_eax
  399. xchg eax,ebx
  400. abs_eax
  401. cmp eax,ebx ;which is bigger?
  402. popm eax,ebx
  403. jl do_xz
  404. ;x is bigger, so do as z/x
  405. fixdiv ebx
  406. ;now eax = z/x ratio. Compute vector by normalizing and correcting sign
  407. push eax ;save ratio
  408. imul eax ;compute z*z
  409. inc edx ;+ x*x (x==1)
  410. call quad_sqrt
  411. mov ecx,eax ;mag in ecx
  412. pop eax ;get ratio, x part
  413. fixdiv ecx
  414. mov [edi].z,eax
  415. mov eax,f1_0
  416. fixdiv ecx
  417. mov [edi].x,eax
  418. jmp finish_end
  419. ;z is bigger, so do as x/z
  420. do_xz:
  421. xchg eax,ebx
  422. fixdiv ebx
  423. ;now eax = x/z ratio. Compute vector by normalizing and correcting sign
  424. push eax ;save ratio
  425. imul eax ;compute x*x
  426. inc edx ;+ z*z (z==1)
  427. call quad_sqrt
  428. mov ecx,eax ;mag in ecx
  429. pop eax ;get ratio, x part
  430. fixdiv ecx
  431. mov [edi].x,eax
  432. mov eax,f1_0
  433. fixdiv ecx
  434. mov [edi].z,eax
  435. finish_end: xor eax,eax ;y = 0
  436. mov [edi].y,eax
  437. ;now make sure that this vector is in front of you, not behind
  438. mov eax,[edi].x
  439. imul View_matrix.m3
  440. mov ebx,eax
  441. mov ecx,edx
  442. mov eax,[edi].z
  443. imul View_matrix.m9
  444. add eax,ebx
  445. adc edx,ecx
  446. jns vec_ok ;has positive z, ok
  447. ;z is neg, flip vector
  448. neg [edi].x
  449. neg [edi].z
  450. vec_ok:
  451. ret
  452. MIN_DEN equ 7fffh
  453. sub2 macro dest,src
  454. mov eax,src
  455. sal eax,1
  456. sub dest,eax
  457. endm
  458. ;compute vector decribing a corner of the screen.
  459. ;takes edi=vector, eax=corner num
  460. compute_corner_vec:
  461. cmp eax,4
  462. jl num_ok
  463. sub eax,4
  464. num_ok:
  465. ;compute all deltas
  466. mov ebx,View_matrix.m1
  467. mov ecx,View_matrix.m4
  468. mov edx,View_matrix.m7
  469. or eax,eax
  470. jz neg_x
  471. cmp eax,3
  472. jne no_neg_x
  473. neg_x:
  474. neg ebx
  475. neg ecx
  476. neg edx
  477. no_neg_x:
  478. sub ebx,View_matrix.m3
  479. mov m13,ebx ;m1-m3
  480. sub ecx,View_matrix.m6
  481. mov m46,ecx ;m4-m6
  482. sub edx,View_matrix.m9
  483. mov m79,edx ;m7-m9
  484. mov ebx,View_matrix.m5
  485. mov ecx,View_matrix.m2
  486. mov edx,View_matrix.m8
  487. cmp eax,2
  488. jl no_neg_y
  489. neg_y:
  490. neg ebx
  491. neg ecx
  492. neg edx
  493. no_neg_y:
  494. sub ebx,View_matrix.m6
  495. mov m56,ebx ;m5-m6
  496. sub ecx,View_matrix.m3
  497. mov m23,ecx ;m2-m3
  498. sub edx,View_matrix.m9
  499. mov m89,edx ;m8-m9
  500. ;compute x/z ratio
  501. ;compute denomonator
  502. mov eax,m46
  503. fixmul m23
  504. mov ebx,eax ;save
  505. mov eax,m56
  506. fixmul m13
  507. sub eax,ebx ;eax = denominator
  508. ;now we have the denominator. If it is too small, try x/y, z/y or z/x, y/x
  509. mov ecx,eax ;save den
  510. abs_eax
  511. cmp eax,MIN_DEN
  512. jl z_too_small
  513. z_too_small:
  514. ;now do x/z numerator
  515. mov eax,m79
  516. fixmul m56 ;* (m5-m6)
  517. mov ebx,eax
  518. mov eax,m89
  519. fixmul m46 ;* (m4-m6)
  520. sub eax,ebx
  521. ;now, eax/ecx = x/z ratio
  522. fixdiv ecx ;eax = x/z
  523. mov [edi].x,eax ;save x
  524. ;now do y/z
  525. mov eax,m89
  526. fixmul m13
  527. mov ebx,eax
  528. mov eax,m79
  529. fixmul m23
  530. sub eax,ebx
  531. ;now eax/ecx = y/z ratio
  532. fixdiv ecx
  533. mov [edi].y,eax
  534. mov [edi].z,f1_0
  535. mov esi,edi
  536. call vm_vec_normalize
  537. ;make sure this vec is pointing in right direction
  538. lea edi,View_matrix.fvec
  539. call vm_vec_dotprod
  540. or eax,eax ;check sign
  541. jg vec_sign_ok
  542. neg [esi].x
  543. neg [esi].y
  544. neg [esi].z
  545. vec_sign_ok:
  546. ret
  547. _TEXT ends
  548. end