home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_02_03 / 2n03047a < prev    next >
Text File  |  1991-01-15  |  15KB  |  532 lines

  1.  
  2. ;-------------------------------------------------------------------
  3. ; BEZ.ASM -- Logic to quickly compute the points along a bezier curve.
  4. ;
  5. ;      Assembly :  TASM BEZ;
  6. ;
  7. ;      Should be linked with Turbo-C V2.0 small memory model.
  8. ;
  9. ; Author : Bob Zigon
  10. ; Date   : July 23, 1989
  11. ;-------------------------------------------------------------------
  12.  
  13. ;
  14. ; NOTE : This code is assembled with the .287 directive to avoid the 
  15. ;        generation of the unnecessary FWAITS on an AT or '386 class 
  16. ;        machine. If this code is to be executed on an 8087, the
  17. ;       .287 directive must be commented out.
  18. ;
  19.         .287
  20.  
  21.         dosseg
  22.         .model small
  23.  
  24. ;-------------------------------------------------------------------
  25. ;                          EQUATES
  26. ;-------------------------------------------------------------------
  27. MaxControl   equ 10               ; Max number of control points
  28. MaxDivisions equ 151              ; Max number of divisions for t
  29.  
  30. ;-------------------------------------------------------------------
  31. ;                        VARIABLE DECLARATIONS
  32. ;-------------------------------------------------------------------
  33.         .data
  34.         extrn _XvpMin:word,_XvpMax:word,_YvpMin:word,_YvpMax:word
  35.         extrn _XCpMin:qword,_XCpMax:qword,_YCpMin:qword,_YCpMax:qword
  36.         extrn _XCpScr:word,_YCpScr:word,_XCp:qword,_YCp:qword
  37.         extrn _XCurve:qword,_YCurve:qword
  38.  
  39. K1        dq ?                      ; Coefficient for transforming X
  40. Q1        dq ?
  41. K2        dq ?                      ; Coefficient for transforming Y
  42. Q2        dq ?
  43.  
  44. T         dq MaxControl dup (?)
  45. BCoef     dq MaxControl dup (?)     ; Double Prec array of Binomial Coefficients
  46. OneMinusT dq MaxControl dup (?)
  47. NumTerms  dw ?                      ; Number of terms in the summations
  48.  
  49.         .code
  50.         public _Binomial, _BezierToScreen, _WToVConst
  51.         public XformWXtoScr, XformWYtoScr
  52.  
  53. ; -------------------------------------------------------------------
  54. ; Binomial  -- This routine precomputes the table of binomial coefficients
  55. ;              for a given number of control points.
  56. ;
  57. ;    The table of N coefficients is computed according to the
  58. ; following recursive formula :
  59. ;
  60. ;         N       N-1       N-1
  61. ;        C   =  C      +  C
  62. ;         i       i         i-1
  63. ; C Prototype :
  64. ;
  65. ;        void Binomial(short int NumControl)
  66. ;
  67. ; Input    : 4[BP] -- Number of control points > 1
  68. ; Output   : The BCoef array is filled with the coefficients.
  69. ; -------------------------------------------------------------------
  70. NumControl  equ  4[bp]
  71.  
  72. _Binomial proc near
  73.       push bp
  74.       mov bp,sp
  75.       push si
  76.       push di                     ; Save in case Register Variables = ON
  77.  
  78.       mov ax,NumControl
  79.       mov NumTerms,ax
  80. ;
  81. ; Begin by initializing the BCoef array to
  82. ;
  83. ;   1.0   0  0  0 .... 0
  84. ;         <--- N-1 ---->
  85. ;
  86.       fld1
  87.       fstp qword ptr BCoef        ; Store the 1.0
  88.       fwait
  89.       lea di,BCoef+8
  90.       mov cx,ax
  91.       dec cx
  92.       shl cx,1
  93.       shl cx,1
  94.       cld
  95.       xor ax,ax
  96.       push ds
  97.       pop es                      ; Init ES for the STOSW
  98.       rep stosw                   ; Now store lots of Zeros
  99.  
  100.       mov ax,NumTerms
  101.       cmp ax,MaxControl           ; Number of control points > Number allocated?
  102.       jle Bi10
  103.          xor ax,ax
  104.          mov NumTerms,ax
  105.          jmp short Bi80
  106. ;
  107. ; Now begin the recursive generation of the BCoef array in situ.
  108. ;
  109. ; The equivalent C code is :
  110. ;
  111. ;    for (j = 1; j < NumTerms; j++)
  112. ;    {
  113. ;       Last = 0.0
  114. ;       for (k = 0; k<=j; k++)
  115. ;       {
  116. ;          Temp     = BCoef[k]+Last
  117. ;          Last     = BCoef[k]
  118. ;          BCoef[k] = Temp
  119. ;       }
  120. ;    }
  121. ;
  122.  
  123. Bi10: mov ax,1                    ; AX is j
  124. Bi20: cmp ax,NumTerms
  125.       je Bi80
  126.          fldz                     ; Last is on the stack
  127.          xor bx,bx                ; BX is k
  128.          lea di,BCoef
  129. Bi30:    cmp bx,ax
  130.          ja Bi40
  131.             fld qword ptr [di]    ; Load BCoef[k]
  132.             fld st                ; Duplicate top of stack
  133.             fadd st,st(2)         ; Temp = BCoef[k]+Last
  134.             fxch                  ; Temp <-> BCoef[k]
  135.             fstp st(2)            ; Store BCoef[k] to Last and pop
  136.             fstp qword ptr [di]   ; Store Temp out to BCoef[k]
  137.             add di,8              ; Adv to next BCeof
  138.             inc bx
  139.             jmp Bi30
  140. Bi40:    fstp st                  ; Clean up the coprocessor stack
  141.          fwait
  142.          inc ax
  143.       jmp Bi20
  144.  
  145. Bi80: pop di
  146.       pop si
  147.       mov sp,bp                   ; Pop of the local variables
  148.       pop bp                      ; Reset BP
  149.       ret
  150. _Binomial endp
  151.  
  152. ; -------------------------------------------------------------------
  153. ; _BezierToScreen -- Compute the points along the Bezier curve and
  154. ;                    transform them to screen coordinates.
  155. ;
  156. ; C Prototype :
  157. ;
  158. ;    void BezierToScreen(short int, short int, short int *, short int *)
  159. ;
  160. ; Input  :  4[BP] -- Number of divisions of the parameter
  161. ;           6[BP] -- Number of Control Points
  162. ;           8[bp] -- Ptr to X Screen Coordinates
  163. ;          10[bp] -- Ptr to Y Screen Coordinates
  164. ;
  165. ; Output : The array of X and Y screen coordinates.
  166. ; -------------------------------------------------------------------
  167. TDivisions   equ 4[bp]
  168. NP           equ 6[bp]
  169. XV           equ 8[bp]
  170. YV           equ 10[bp]
  171.  
  172. _BezierToScreen proc near
  173.       local u:qword,du:qword
  174.       local XCurvePtr:word,YCurvePtr:word
  175.       local NumCurvePts:word=AutoSize
  176.       push bp
  177.       mov bp,sp
  178.       sub sp,AutoSize             ; Allocate some local variables
  179.       push si
  180.       push di                     ; Save in case Register Variables = ON
  181.  
  182.       mov ax,NP
  183.       lea si,_XCp
  184.       lea di,_XCpScr
  185.       call XformWXtoScr           ; Convert XCp to screen coordinates
  186.  
  187.       mov ax,NP
  188.       lea si,_YCp
  189.       lea di,_YCpScr
  190.       call XformWYtoScr           ; Convert YCp to screen coordinates
  191. ;
  192. ; Now, compute the coordinates of the curve.
  193. ;
  194.       mov ax,word ptr TDivisions
  195.       inc ax
  196.       mov NumCurvePts,ax          ; Number of points on the curve
  197.  
  198.       fld1
  199.       fidiv word ptr TDivisions
  200.       fstp du                     ; du = 1/TDivisions
  201.       fldz
  202.       fstp u                      ; u = 0.0
  203.       fwait
  204.       lea ax,_XCurve
  205.       mov XCurvePtr,ax
  206.       lea ax,_YCurve
  207.       mov YCurvePtr,ax
  208.  
  209. ;
  210. ; Since the address of _XCp and _YCp doesn't change, why push them
  211. ; on the stack every time you need to call Bezier. Push them
  212. ; once here, and clean up on exit.
  213. ;
  214.       lea ax,_YCp
  215.       push ax
  216.       lea ax,_XCp
  217.       push ax
  218.  
  219. BS10: mov ax,NumCurvePts
  220.       or ax,ax                    ; EXIT when no more points to compute
  221.       jz BS20
  222.          mov ax, word ptr u+6
  223.          push ax
  224.          mov ax, word ptr u+4
  225.          push ax
  226.          mov ax, word ptr u+2
  227.          push ax
  228.          mov ax, word ptr u
  229.          push ax
  230.  
  231.          call Bezier              ; Compute X(t) and Y(t)
  232.          add sp,2*4               ; Pop the t parameter
  233.  
  234.          mov si,YCurvePtr
  235.          fstp qword ptr [si]      ; Save and pop Y(t)
  236.          add si,8
  237.          mov YCurvePtr,si
  238.  
  239.          mov si,XCurvePtr
  240.          fstp qword ptr [si]      ; Save and pop X(t)
  241.          add si,8
  242.          mov XCurvePtr,si
  243.  
  244.          fld u
  245.          fadd du
  246.          fstp u                   ; Increment u by du
  247.          fwait
  248.  
  249.          dec NumCurvePts          ; 1 less point to consider
  250.       jmp short BS10
  251.  
  252.  
  253. BS20: add sp,2*2                  ; Pop address of _XCp and _YCp
  254.       mov ax,TDivisions
  255.       inc ax
  256.       lea si,_XCurve
  257.       mov di,XV
  258.       call XformWXtoScr           ; Convert X curve values to screen coordinates
  259.  
  260.       mov ax,TDivisions
  261.       inc ax
  262.       lea si,_YCurve
  263.       mov di,YV
  264.       call XformWYtoScr           ; Convert Y curve values to screen coordinates
  265.  
  266.       pop di
  267.       pop si
  268.       mov sp,bp                   ; Pop of the local variables
  269.       pop bp                      ; Reset BP
  270.       ret
  271. _BezierToScreen endp
  272.  
  273. ; -------------------------------------------------------------------
  274. ; XformWXtoScr -- transform world X coordinates to X screen coordinates.
  275. ;
  276. ; Input  :  AX -- Number of points
  277. ;           SI -- Ptr to Double Precision World X values
  278. ;           DI -- Ptr to Word Screen X values
  279. ;
  280. ; Transform is :
  281. ;
  282. ;   X' = Q1 + K1*X
  283. ;
  284. ;   K1 = (XvpMax-XvpMin)/(XCpMax-XCpMin)
  285. ;   Q1 = XvpMin - K1*XCpMin
  286. ;
  287. ; -------------------------------------------------------------------
  288. XformWXtoScr proc near
  289.       fld Q1
  290.       fld K1
  291. XFX10:
  292.       or ax,ax
  293.       jz XFX20                    ; Exit when AX = 0
  294.          fld st                   ; Dup the top of stack
  295.          fmul qword ptr [si]      ; X*K
  296.          add si,8
  297.          fadd st,st(2)            ; X*K+Q
  298.          fistp word ptr [di]      ; Store the Screen coordinate
  299.          add di,2
  300.          dec ax                   ; 1 less point to consider
  301.       jmp short XFX10
  302.  
  303. XFX20:
  304.       fstp st
  305.       fstp st                     ; Clean up the stack
  306.       ret
  307. XformWXtoScr endp
  308.  
  309. ; -------------------------------------------------------------------
  310. ; XformWYtoScr -- transform world Y coordinates to Y screen coordinates.
  311. ;
  312. ; Input  :  AX -- Number of points
  313. ;           SI -- Ptr to Double Precision World Y values
  314. ;           DI -- Ptr to Word Screen Y values
  315. ;
  316. ; Transform is :
  317. ;
  318. ;   Y' = Q2 - K2*Y
  319. ;
  320. ;   K2 = (YvpMax-YvpMin)/(YCpMax-YCpMin)
  321. ;   Q2 = K2*YCpMax + YsMin
  322. ;
  323. ; Note : Since the screen values for Y start in the upper left hand
  324. ;        corner instead of the lower left hand corner, this routine
  325. ;        inverts the Y coordinate.
  326. ; -------------------------------------------------------------------
  327. XformWYtoScr proc near
  328.       fld Q2
  329.       fld K2
  330. XFY10:
  331.       or ax,ax
  332.       jz XFY20                    ; Exit when AX = 0
  333.          fld st                   ; Dup the top of stack
  334.          fmul qword ptr [si]      ; Y*K
  335.          add si,8
  336.          fsubr st,st(2)           ; Q-Y*K
  337.          fistp word ptr [di]
  338.          add di,2
  339.          dec ax                   ; 1 less point to consider
  340.       jmp short XFY10
  341.  
  342. XFY20:
  343.       fstp st
  344.       fstp st                     ; Clean up the stack
  345.       ret
  346. XformWYtoScr endp
  347.  
  348. ; -------------------------------------------------------------------
  349. ; WToVConst -- Calculate the constants used to perform the window
  350. ;              to viewport transformations in XformWXtoScr and
  351. ;              XformWYtoScr.
  352. ;
  353. ; C Prototype :
  354. ;
  355. ;     void WToVConst(void);
  356. ;
  357. ; -------------------------------------------------------------------
  358. _WToVConst proc near
  359.      fild _XvpMax
  360.      fisub _XvpMin
  361.      fld _XCpMax
  362.      fsub _XCpMin
  363.      fdiv
  364.      fst K1                  ; K1 = (XvpMax-XvpMin)/(XCpMax-XCpMin)
  365.      fmul _XCpMin
  366.      fisubr _XvpMin
  367.      fstp Q1                 ; Q1 = XvpMin - K1*XCpMin
  368.  
  369.      fild _YvpMax
  370.      fisub _YvpMin
  371.      fld _YCpMax
  372.      fsub _YCpMin
  373.      fdiv
  374.      fst K2                  ; K2 = (YvpMax-YvpMin)/(YCpMax-YCpMin)
  375.      fmul _YCpMax
  376.      fiadd _YvpMin
  377.      fstp Q2                 ; Q2 = K2*YcpMax + YvpMin
  378.      ret
  379. _WToVConst endp
  380.  
  381. ; -------------------------------------------------------------------
  382. ; Bezier -- local subroutine used to compute the actual value of
  383. ;              X(t) and Y(t).
  384. ;
  385. ; Input  :  4[BP] -- Double Precision value of t, the parameter
  386. ;        : 12[BP] -- Ptr to X Control Points.
  387. ;          14[bp] -- Ptr to Y Control Points.
  388. ;
  389. ; Output : ST(1) -- Double Precision X when the polynomial is
  390. ;                      evaluated at t and the X Control Points.
  391. ;          ST(0) -- Double Precision Y when the polynomial is
  392. ;                      evaluated at t and the Y Control Points.
  393. ; -------------------------------------------------------------------
  394. ParamT   equ qword ptr 4[bp]
  395. XCp      equ 12[bp]
  396. YCp      equ 14[bp]
  397.  
  398. Bezier proc near
  399.       push bp
  400.       mov bp,sp
  401.  
  402.       lea di,T
  403.       mov ax,NumTerms
  404.       mov bx,ax
  405. ;
  406. ; Compute the T array.
  407. ;
  408. ; 1   T   T**2   T**3   T**4    T**5 ....
  409. ;
  410.       fld ParamT
  411.       fld1
  412. B10:     fst qword ptr [di]
  413.          dec ax
  414.          or ax,ax
  415.          jz B50                   ; EXIT when AX = 0
  416.          fmul st,st(1)
  417.          add di,8
  418.       jmp B10
  419.  
  420. B50:  fstp st                     ; Clean up the stack
  421.       fstp st
  422.       lea di,OneMinusT
  423. ;
  424. ; Compute the OneMinusT array.
  425. ;
  426. ; 1   1-T   (1-T)**2   (1-T)**3   (1-T)**4    (1-T)**5 ....
  427. ;
  428.       fld1
  429.       fld ParamT
  430.       fsub
  431.       fld1
  432. B60:     fst qword ptr [di]
  433.          dec bx
  434.          or bx,bx
  435.          jz B70                   ; EXIT when BX = 0
  436.          fmul st,st(1)
  437.          add di,8
  438.       jmp B60
  439.  
  440. B70:  lea di,T
  441.       fst qword ptr [di]          ; Copy (1-T)**N to T**0
  442.       fstp st
  443.       fstp st
  444. ;
  445. ; Now multiply the T array by the OneMinusT array.
  446. ;
  447.       add di,8
  448.       mov ax,NumTerms
  449.       sub ax,2
  450.       mov bl,8
  451.       mul bl
  452.       lea si,OneMinusT
  453.       add si,ax                   ; SI points to (1-T)**(N-1)
  454.  
  455.       mov ax,NumTerms
  456.       sub ax,2
  457.  
  458. B80:  or ax,ax
  459.       jz B90
  460.          fld qword ptr [si]      ; Get element from 1-T
  461.          fmul qword ptr [di]     ; Multiply by T**i
  462.          fstp qword ptr [di]     ; Save product back to T
  463.          sub si,8
  464.          add di,8
  465.          dec ax
  466.       jmp B80
  467.  
  468. ;
  469. ; Now form the term by term product of the T array and the BCoef array.
  470. ;
  471. B90:  lea si,T
  472.       lea di,BCoef
  473.       mov ax,NumTerms
  474.  
  475. B100: or ax,ax
  476.       jz B120
  477.          fld qword ptr [si]       ; Get a T element
  478.          fmul qword ptr [di]      ; Multiply by a binomial coefficient
  479.          fstp qword ptr [si]
  480.          add si,8
  481.          add di,8
  482.          dec ax
  483.       jmp B100
  484.  
  485. ;
  486. ; Now that the T array has the product of the T array, the OneMinusT array,
  487. ;   and the Binomial coefficients, form the dot product of the T array
  488. ;   with the XCp array to produce X(t).
  489. ;
  490. B120: lea si,T
  491.       mov di,XCp
  492.       mov ax,NumTerms
  493.       fldz
  494.  
  495. B200: or ax,ax
  496.       jz B210
  497.          fld qword ptr [si]       ; Load a term from T
  498.          fmul qword ptr [di]      ; Multiply by an XCp
  499.          faddp                    ; Accumulate in stack top
  500.          add si,8
  501.          add di,8
  502.          dec ax
  503.       jmp B200
  504.  
  505. B210:
  506. ;
  507. ;   Now form the dot product of the T array with the YCp array to
  508. ;   produce Y(t).
  509. ;
  510.       lea si,T
  511.       mov di,YCp
  512.       mov ax,NumTerms
  513.       fldz
  514.  
  515. B220: or ax,ax
  516.       jz B230
  517.          fld qword ptr [si]       ; Load a term from T
  518.          fmul qword ptr [di]      ; Multiply by an YCp
  519.          faddp                    ; Accumulate in stack top
  520.          add si,8
  521.          add di,8
  522.          dec ax
  523.       jmp B220
  524.  
  525. B230:
  526.       mov sp,bp                   ; Pop of the local variables
  527.       pop bp                      ; Reset BP
  528.       ret
  529. Bezier endp
  530.        end
  531.