8086汇编中的中点椭圆算法

huangapple go评论101阅读模式
英文:

Midpoint ellipse algorithm in 8086 Assembly

问题

我正在尝试使用8086汇编在VGA(320x200)模式下实现椭圆绘制算法,但对于较大的半径,形状绘制不正确。

如图所示,形状是凹陷的,而不是椭圆形状。当轴的长度较小时,例如(10,15),我得到了可接受的结果,但超过这个范围后,它停止呈现椭圆形状。我使用FPU计算所有值。

  1. SCREEN_WIDTH = 320
  2. SCREEN_HEIGHT = 200
  3. HALF_SCREEN_WIDTH = SCREEN_WIDTH / 2
  4. HALF_SCREEN_HEIGHT = SCREEN_HEIGHT / 2
  5. x_radius dw 40 ;椭圆宽度
  6. y_radius dw 50 ;椭圆高度
  7. x_derivative dw ? ;由椭圆方程计算的导数
  8. y_derivative dw ?
  9. x_squared dw ? ;为方便起见的平方值
  10. y_squared dw ?
  11. decision_param dw ?
  12. four dw 4 ;一些表达式中使用的整数值
  13. two dw 2 ;存储它们以便将它们加载到FPU
  14. calc_x_derivative:
  15. ;x_derivative = 2 * y_squared * x
  16. ;RPN: 2 y_squared x * *
  17. calc_y_derivative:
  18. ;y_derivative = 2 * x_squared * y
  19. ;RPN: 2 x_squared y * *
  20. ellipse:
  21. ;初始化x0yy_radius
  22. ;...
  23. calc_decision_param_1:
  24. ;d1 = y_squared - (x_squared * ry) + (1/4 * x_squared)
  25. ;RPN: y_squared x_squared ry * - x_squared 4 / +
  26. ;...
  27. region_1_loop:
  28. ;...
  29. calc_decision_param_2:
  30. ;decision_param = (y_squared * (x + 1/2) * (x + 1/2)) + (x_squared * (y - 1) * (y - 1)) - (x_squared * y_squared)
  31. ;RPN: y_squared x 1 2 / + * x 1 2 / + * x_squared y 1 - * y 1 - * + x_squared y_squared * -
  32. ;...
  33. region_2_loop:
  34. ;...
  35. end_program:
  36. ;...
  37. clear_screen:
  38. ;...

我尝试了许多不同版本的相同算法,但都没有成功。我认为问题可能出在我的变量上(特别是导数和决策参数),可能是溢出的问题。我尝试通过使用double words而不是words声明变量来修复它,但后来在算法中比较它们时遇到了问题,即使成功编译程序,它仍然不能按预期工作。

英文:

I'm trying to implement an ellipse drawing algorithm with 8086 Assembly in VGA (320x200) mode, but the shape is not drawing properly for bigger radii.

8086汇编中的中点椭圆算法

As you can see the shape is concave or straight not elliptical. I get acceptable result when the axis have small lengths i.e (10, 15) but any more then that and it stops resembling an ellipse. I used an FPU to calculate all values.

  1. .387
  2. SCREEN_WIDTH = 320
  3. SCREEN_HEIGHT = 200
  4. HALF_SCREEN_WIDTH = SCREEN_WIDTH / 2
  5. HALF_SCREEN_HEIGHT = SCREEN_HEIGHT / 2
  6. stack1 segment stack
  7. dw 300 dup(?)
  8. stack_top dw ? ;stack_top pointer
  9. stack1 ends
  10. code1 segment
  11. start1:
  12. mov ax,seg stack1
  13. mov ss,ax ; initialize stack
  14. mov sp, offset stack_top
  15. mov al, 13h
  16. mov ah, 0 ; change mode
  17. int 10h ; enter graphics mode
  18. mov byte ptr cs:[color], 10
  19. start_draw:
  20. call clear_screen
  21. call ellipse
  22. wait_key:
  23. in al, 60h ;take keyboard input
  24. cmp al, 1 ;if ESC end
  25. je end_program
  26. jmp wait_key
  27. ;-------------------------------------------------------------
  28. ;-------------------------------------------------------------
  29. x_radius dw 40 ;width of the ellipse
  30. y_radius dw 50 ;height of the ellipse
  31. x_derivative dw ? ;derivates calculated from ellipse equation
  32. y_derivative dw ?
  33. x_squared dw ? ;squared values for convenience
  34. y_squared dw ?
  35. decision_param dw ?
  36. four dw 4 ;int values used in some of the expressions
  37. two dw 2 ;storing them so I can load them to the FPU
  38. ;----------------------
  39. calc_x_derivative:
  40. ;x_derivative = 2 * y_squared * x
  41. ;RPN: 2 y_squared x * *
  42. finit
  43. fild word ptr cs:[y_squared]
  44. fimul word ptr cs:[two] ;instead of multiplying by 2
  45. fimul word ptr cs:[x]
  46. fistp word ptr cs:[x_derivative]
  47. ret
  48. calc_y_derivative:
  49. ;y_derivative = 2 * x_squared * y
  50. ;RPN: 2 x_squared y * *
  51. finit
  52. fild word ptr cs:[x_squared]
  53. fimul word ptr cs:[two]
  54. fimul word ptr cs:[y]
  55. fistp word ptr cs:[y_derivative]
  56. ret
  57. ellipse:
  58. ;initialize x as 0 and y as y_radius
  59. mov word ptr cs:[x], 0
  60. mov ax, word ptr cs:[y_radius]
  61. mov word ptr cs:[y], ax
  62. x_radius_squared:
  63. finit
  64. fild word ptr cs:[y_radius]
  65. fimul word ptr cs:[y_radius]
  66. fistp word ptr cs:[y_squared]
  67. y_radius_squared:
  68. finit
  69. fild word ptr cs:[x_radius]
  70. fimul word ptr cs:[x_radius]
  71. fistp word ptr cs:[x_squared]
  72. derivatives:
  73. call calc_x_derivative
  74. call calc_y_derivative
  75. calc_decision_param_1:
  76. ;d1 = y_squared - (x_squared * ry) + (1/4 * x_squared)
  77. ;RPN: y_squared x_squared ry * - x_squared 4 / +
  78. finit
  79. fild word ptr cs:[y_squared]
  80. fild word ptr cs:[x_squared]
  81. fild word ptr cs:[y_radius]
  82. fmul
  83. fsub
  84. fild word ptr cs:[x_squared]
  85. fidiv word ptr cs:[four]
  86. fadd
  87. fistp word ptr cs:[decision_param]
  88. region_1_loop:
  89. call color_all_symmetries
  90. inc word ptr cs:[x]
  91. call calc_x_derivative
  92. cmp word ptr cs:[decision_param], 0 ;compare decision_param to 0
  93. jge region_1_alternative_next ;if its lower decrement y and calculate alternative decision_param
  94. region_1_next:
  95. ;decision_param = decision_param + x_derivative + (y_squared)
  96. ;RPN: decision_param x_derivative + y_squared +
  97. finit
  98. fild word ptr cs:[decision_param]
  99. fild word ptr cs:[x_derivative]
  100. fadd
  101. fild word ptr cs:[y_squared]
  102. fadd
  103. fistp word ptr cs:[decision_param]
  104. jmp region_1_loop_end
  105. region_1_alternative_next:
  106. ;decision_param = decision_param + x_derivative - y_derivative + (y_squared)
  107. ;RPN: decision_param x_derivative + y_derivative - y_squared +
  108. dec word ptr cs:[y]
  109. call calc_y_derivative
  110. finit
  111. fild word ptr cs:[decision_param]
  112. fild word ptr cs:[x_derivative]
  113. fadd
  114. fild word ptr cs:[y_derivative]
  115. fsub
  116. fild word ptr cs:[y_squared]
  117. fadd
  118. fistp word ptr cs:[decision_param]
  119. region_1_loop_end:
  120. mov ax, word ptr cs:[x_derivative]
  121. cmp ax, word ptr cs:[y_derivative] ;check if x_derivative < y_derivative
  122. jge calc_decision_param_2 ;if it is we are done with region 1
  123. jmp region_1_loop
  124. calc_decision_param_2:
  125. ;decision_param = (y_squared * (x + 1/2) * (x + 1/2)) + (x_squared * (y - 1) * (y - 1)) - (x_squared * y_squared)
  126. ;RPN: y_squared x 1 2 / + * x 1 2 / + * x_squared y 1 - * y 1 - * + x_squared y_squared * -
  127. fild word ptr cs:[y_squared]
  128. fild word ptr cs:[x]
  129. fld1
  130. fidiv word ptr cs:[two]
  131. fadd
  132. fmul
  133. fild word ptr cs:[x]
  134. fld1
  135. fidiv word ptr cs:[two]
  136. fadd
  137. fmul
  138. fild word ptr cs:[x_squared]
  139. fild word ptr cs:[y]
  140. fld1
  141. fsub
  142. fmul
  143. fild word ptr cs:[y]
  144. fld1
  145. fsub
  146. fmul
  147. fadd
  148. fild word ptr cs:[x_squared]
  149. fimul word ptr cs:[y_squared]
  150. fsub
  151. fistp word ptr cs:[decision_param]
  152. region_2_loop:
  153. call color_all_symmetries
  154. dec word ptr cs:[y]
  155. call calc_y_derivative
  156. cmp word ptr cs:[decision_param], 0 ;check if decision_param < 0
  157. jge alternative_region_2_next
  158. region_2_next:
  159. ;decision_param = decision_param + x_squared - y_derivative
  160. ;RPN: decision_param x_squared + y_derivative -
  161. finit
  162. fild word ptr cs:[decision_param]
  163. fild word ptr cs:[x_squared]
  164. fadd
  165. fild word ptr cs:[y_derivative]
  166. fsub
  167. fistp word ptr cs:[decision_param]
  168. jmp region_2_loop_end
  169. alternative_region_2_next:
  170. inc word ptr cs:[x]
  171. call calc_x_derivative
  172. region_2_alternative_decision_param:
  173. ;decision_param = decision_param + x_derivative - y_derivative + (x_squared)
  174. ;RPN: decision_param x_derivative + y_derivative - x_squared +
  175. finit
  176. fild word ptr cs:[decision_param]
  177. fild word ptr cs:[x_derivative]
  178. fadd
  179. fild word ptr cs:[y_derivative]
  180. fsub
  181. fild word ptr cs:[x_squared]
  182. fadd
  183. fistp word ptr cs:[decision_param]
  184. region_2_loop_end:
  185. ;y_derivative = y_derivative - (2 * x_squared)
  186. ;RPN: y_derivative 2 x_squared * -
  187. finit
  188. fild word ptr cs:[y_derivative]
  189. fild word ptr cs:[two]
  190. fild word ptr cs:[x_squared]
  191. fmul
  192. fsub
  193. fistp word ptr cs:[y_derivative]
  194. cmp word ptr cs:[y], 0 ; check if y <= 0
  195. jg region_2_loop
  196. end_ellipse:
  197. ret
  198. ;-------------------------------------------------------------
  199. ;--------------------- color_pixel -------------------------
  200. x dw ?
  201. y dw ?
  202. temp_y dw ?
  203. temp_x dw ?
  204. color db ?
  205. ;---------------------
  206. color_all_symmetries:
  207. ; Coloring points (xc + x, yc + y), (xc - x, yc + y), (xc + x, yc - y), (xc - x, yc - y)
  208. push ax
  209. ;Point (xc + x, yc - y)
  210. mov ax, HALF_SCREEN_HEIGHT
  211. sub ax, word ptr cs:[y]
  212. mov word ptr cs:[temp_y], ax
  213. mov ax, word ptr cs:[x]
  214. add ax, HALF_SCREEN_WIDTH
  215. mov word ptr cs:[temp_x], ax
  216. call color_pixel
  217. ;Point (xc - x, yc - y)
  218. mov ax, HALF_SCREEN_HEIGHT
  219. sub ax, word ptr cs:[y]
  220. mov word ptr cs:[temp_y], ax
  221. mov ax, HALF_SCREEN_WIDTH
  222. sub ax, word ptr cs:[x]
  223. mov word ptr cs:[temp_x], ax
  224. call color_pixel
  225. ;Point (xc + x, yc + y)
  226. mov ax, HALF_SCREEN_HEIGHT
  227. add ax, word ptr cs:[y]
  228. mov word ptr cs:[temp_y], ax
  229. mov ax, word ptr cs:[x]
  230. add ax, HALF_SCREEN_WIDTH
  231. mov word ptr cs:[temp_x], ax
  232. call color_pixel
  233. ;Point (xc - x, yc - y)
  234. mov ax, HALF_SCREEN_HEIGHT
  235. add ax, word ptr cs:[y]
  236. mov word ptr cs:[temp_y], ax
  237. mov ax, HALF_SCREEN_WIDTH
  238. sub ax, word ptr cs:[x]
  239. mov word ptr cs:[temp_x], ax
  240. call color_pixel
  241. pop ax
  242. ret
  243. color_pixel:
  244. push ax
  245. push es
  246. ;position needs to be in a format y*320 + x
  247. mov ax, 0a000h
  248. mov es, ax
  249. mov ax, word ptr cs:[temp_y] ;selecting a row
  250. mov bx, SCREEN_WIDTH
  251. mul bx ;ax multiplying y by 320 to get proper position
  252. mov bx, word ptr cs:[temp_x] ;selecting a column
  253. add bx, ax ;adding to the pixel position
  254. mov al, byte ptr cs:[color] ;adding a color
  255. mov byte ptr es:[bx], al
  256. pop es
  257. pop ax
  258. ret
  259. ;-------------------------------------------------------------
  260. end_program:
  261. mov al, 3h
  262. mov ah, 0
  263. int 10h
  264. mov ax, 4c00h
  265. int 21h
  266. clear_screen:
  267. mov ax, 0a000h
  268. mov es, ax
  269. xor ax, ax
  270. mov di, ax
  271. mov cx, SCREEN_WIDTH * SCREEN_HEIGHT
  272. mov al, 0
  273. cld
  274. rep stosb ;while cx != 0, mov byte ptr es:[di], al; di++; cx--
  275. ret
  276. code1 ends
  277. end start1

I tried many different version of the same algorithm all to no success. I think it might be an issue with my variables(especially the derivatives and decision parameter) overflowing I tried fixing it by using double words instead of words to declare variables but I had trouble comparing them later in the algorithm, and when I did get the program to compile it still did not work as intended.

答案1

得分: 3

你对变量溢出的猜测是正确的。例如,考虑calc_decision_param_1的计算:

  1. ;d1 = y_squared - (x_squared * ry) + (1/4 * x_squared)

这个计算的结果是(50 * 50) - (40 * 40 * 50) + (40 * 40 / 4) = -77100。这已经不适合一个有符号字了,因此fistp word ptr cs:[decision_param]指令无法将默认的'IntegerIndefinite value 8000h'存储在字大小的目标中。

你应该将一些变量定义为双字整数:x_derivativey_derivativedecision_param。所有其他变量将保持其当前的字大小。

检查是否 decision_param < 0 的代码应该简单地查看双字变量的符号位:

  1. test byte ptr cs:[decision_param+3], 80h
  2. jz alternative_region_2_next

而检查是否 x_derivative < y_derivative 的代码可以使用 ficomp 来比较这些有符号双字整数。根据(冲突的)注释(;check if x_derivative < y_derivative;if it is we are done with region 1),它看起来应该是这样的:

  1. fninit
  2. fild dword ptr cs:[x_derivative]
  3. ficomp dword ptr cs:[y_derivative]
  4. fnstsw ax
  5. sahf
  6. jb calc_decision_param_2 ; done if x_derivative < y_derivative
  7. jmp region_1_loop

看起来 x_radius_squared:y_radius_squared: 的功能与它们的名称所告诉我们的恰恰相反!

英文:

> I think it might be an issue with my variables(especially the derivatives and decision parameter) overflowing

Your suspicion about variables overflowing is correct.
As an example, consider the computation for calc_decision_param_1:

> ;d1 = y_squared - (x_squared * ry) + (1/4 * x_squared)

The result for this is (50 * 50) - (40 * 40 * 50) + (40 * 40 / 4) = -77100
This doesn't fit a signed word anymore and therefore the fistp word ptr cs:[decision_param] instruction can't but store the default 'IntegerIndefinite value 8000h' in the word-sized destination.

What you should do is defining some of your variables as dword integers: x_derivative, y_derivative, and decision_param. All other variables will fit their current word size.

> but I had trouble comparing them later in the algorithm

The code that checks whether decision_param &lt; 0 should simply look at the sign bit of the dword variable:

  1. test byte ptr cs:[decision_param+3], 80h
  2. jz alternative_region_2_next

And the code that checks whether x_derivative &lt; y_derivative could use ficomp to compare these signed dword integers. Based on the (conflicting) comments (;check if x_derivative &lt; y_derivative and ;if it is we are done with region 1), it would look like:

  1. fninit
  2. fild dword ptr cs:[x_derivative]
  3. ficomp dword ptr cs:[y_derivative]
  4. fnstsw ax
  5. sahf
  6. jb calc_decision_param_2 ; done if x_derivative &lt; y_derivative
  7. jmp region_1_loop
  8. calc_decision_param_2:

It would seem that x_radius_squared: and y_radius_squared: do exactly the opposite from what their names tell us!

huangapple
  • 本文由 发表于 2023年5月25日 21:10:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76332665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定