2 Fixed-point math functions and 3D transforms
\r
3 Copyright (c) 1993,94 by Alessandro Scotti
\r
15 PUBLIC tdGetSurfaceLight
\r
17 PUBLIC tdSetRotation
\r
18 PUBLIC tdSetTranslation
\r
20 PUBLIC tdTransformToImage
\r
21 PUBLIC tdTransformLight
\r
22 PUBLIC tdBackPlaneCull
\r
23 PUBLIC tdSetPerspective
\r
25 ;-----------------------------------------------------------
\r
29 MATH_DATA SEGMENT USE16 PARA PUBLIC 'DATA'
\r
32 INCLUDE SINCOS.INC ; Fixed 8:24 sin/cos table
\r
34 XRotation TPOINT <> ; 3x3 rotation matrix
\r
38 Translation TPOINT <> ; Translation vector
\r
40 Light TPOINT <> ; Light vector
\r
41 AmbientLight DW 00 ; Ambient light
\r
43 XScale DD 10000h ; Scaling factor for X coordinate
\r
44 YScale DD 10000h ; Scaling factor for Y coordinate
\r
45 PerspectiveDistance DD 20000000h
\r
49 ;-----------------------------------------------------------
\r
53 MATH_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'
\r
54 ASSUME cs:MATH_TEXT, es:NOTHING, fs:NOTHING
\r
56 tdSetPerspective PROC PASCAL FAR
\r
57 ARG Perspective:DWORD, \
\r
62 mov ax, SEG MATH_DATA
\r
66 mov eax, [Perspective]
\r
67 mov [PerspectiveDistance], eax
\r
74 tdSetPerspective ENDP
\r
77 ;-----------------------------------------------------------
\r
79 ; Sets the rotation matrix.
\r
82 ; RX = X-axis rotation angle
\r
83 ; RY = X-axis rotation angle
\r
84 ; RZ = X-axis rotation angle
\r
88 tdSetRotation PROC PASCAL FAR
\r
94 mov ax, SEG MATH_DATA
\r
105 push ebp ; We use EBP as a scratch register
\r
108 mov eax, tblCos[bx]
\r
110 mov [XRotation.X], edx
\r
112 mov eax, tblSin[bx]
\r
114 mov [XRotation.Y], edx
\r
116 mov eax, tblSin[si]
\r
117 sar eax, 8 ; Convert fixed 8:24 to fixed 16:16
\r
118 mov [XRotation.Z], eax
\r
121 mov eax, tblCos[bx]
\r
122 imul tblSin[si] ; EDX:EAX = fixed 16:48
\r
123 shrd eax, edx, 24 ; EAX = fixed 8:24
\r
124 imul tblSin[di] ; EDX:EAX = fixed 16:48
\r
127 mov eax, tblSin[bx]
\r
130 adc edx, ecx ; EDX:EAX = fixed 16:48
\r
132 mov [YRotation.X], edx
\r
134 mov eax, tblSin[bx]
\r
140 mov eax, tblCos[bx]
\r
144 mov [YRotation.Y], edx
\r
146 mov eax, tblCos[si]
\r
148 mov [YRotation.Z], edx
\r
151 mov eax, tblCos[bx]
\r
157 mov eax, tblSin[bx]
\r
161 mov [ZRotation.X], edx
\r
163 mov eax, tblSin[bx]
\r
169 mov eax, tblCos[bx]
\r
174 mov [ZRotation.Y], edx
\r
176 mov eax, tblCos[si]
\r
178 mov [ZRotation.Z], edx
\r
180 pop ebp ; Restore EBP
\r
185 ;-----------------------------------------------------------
\r
187 ; Sets the translation vector.
\r
190 ; TV = pointer to translation vector
\r
194 tdSetTranslation PROC PASCAL FAR
\r
198 mov ax, SEG MATH_DATA
\r
200 ASSUME ds:MATH_DATA
\r
204 mov [Translation.X], eax
\r
206 mov [Translation.Y], eax
\r
208 mov [Translation.Z], eax
\r
211 tdSetTranslation ENDP
\r
213 ;-----------------------------------------------------------
\r
215 ; Transforms an array of TPOINT.
\r
218 ; Source = pointer to source array of TPOINT
\r
219 ; Dest = pointer to destination array of TPOINT
\r
220 ; Count = number of entries to transform
\r
224 tdTransform PROC PASCAL FAR
\r
225 ARG Source:DWORD, \
\r
229 USES ds, si, es, di, fs
\r
231 mov ax, SEG MATH_DATA
\r
233 ASSUME ds:MATH_DATA
\r
240 ; Transform Z coordinate
\r
255 add eax, [Translation.Z] ; EAX = new Z coord (fixed 16:16)
\r
257 ; Get perspective factor
\r
258 mov ebx, [PerspectiveDistance]
\r
260 neg eax ; EAX = PD - Z
\r
264 idiv ebx ; EAX = fixed 16:16 result
\r
267 ; Transform X coordinate
\r
281 add eax, [Translation.X]
\r
286 ; Transform Y coordinate
\r
300 add eax, [Translation.Y]
\r
305 add si, SIZE TPOINT
\r
306 add di, SIZE TPOINT
\r
313 ;-----------------------------------------------------------
\r
315 ; Transforms an array of TPOINT into an array of TIMAGEPOINT.
\r
318 ; Source = pointer to source array of TPOINT
\r
319 ; Dest = pointer to destination array of TIMAGEPOINT
\r
320 ; Count = number of entries to transform
\r
321 ; DeltaX = translation distance for the X coordinate
\r
322 ; DeltaY = translation distance for the Y coordinate
\r
324 ; the maximum Z value
\r
326 tdTransformToImage PROC PASCAL FAR
\r
327 ARG Source:DWORD, \
\r
332 LOCAL Adjust:DWORD, \
\r
334 USES ds, si, es, di, fs
\r
336 mov ax, SEG MATH_DATA
\r
338 ASSUME ds:MATH_DATA
\r
342 mov [Max], 80000000h
\r
352 ; Transform X coordinate
\r
353 mov ax, WORD PTR fs:[si].X[2]
\r
357 ; Transform Y coordinate
\r
358 mov ax, WORD PTR fs:[si].Y[2]
\r
362 add si, SIZE TPOINT
\r
363 add di, SIZE TIMAGEPOINT
\r
370 tdTransformToImage ENDP
\r
372 ;-----------------------------------------------------------
\r
374 ; Sets the light source.
\r
377 ; Light = pointer to light vector
\r
381 tdSetLight PROC PASCAL FAR
\r
385 mov ax, SEG MATH_DATA
\r
387 ASSUME ds:MATH_DATA
\r
400 ;-----------------------------------------------------------
\r
402 ; Computes light intensity for an array of surfaces.
\r
405 ; Normals = pointer to an array of surface normals
\r
406 ; Lights = pointer to an array of integer to be filled with
\r
408 ; Count = number of elements to transform
\r
412 tdTransformLight PROC PASCAL FAR
\r
413 ARG Normals:DWORD, \
\r
416 USES ds, si, es, di, fs
\r
418 mov ax, SEG MATH_DATA
\r
420 ASSUME fs:MATH_DATA
\r
426 ; Intensity is given by the dot product between the Light vector and
\r
427 ; the surface normal
\r
440 adc edx, ecx ; EDX:EAX = fixed 32:32 intensity
\r
441 add dx, [AmbientLight]
\r
444 xor dx, dx ; Return 0 for no light
\r
449 add si, SIZE TPOINT
\r
455 tdTransformLight ENDP
\r
457 ;-----------------------------------------------------------
\r
459 ; Returns the light value given the normal to a surface.
\r
462 ; Normal = pointer to TPOINT surface normal vector
\r
464 ; AX = light intensity (>=0)
\r
466 ; the normal is rotated according to the current setting.
\r
468 tdGetSurfaceLight PROC PASCAL FAR
\r
470 USES ds, esi, es, di
\r
472 mov ax, SEG MATH_DATA
\r
474 ASSUME ds:MATH_DATA
\r
478 ; Transform Z coordinate
\r
496 ; Transform X coordinate
\r
514 ; Transform Y coordinate
\r
533 ; Add ambient light
\r
534 add ax, [AmbientLight]
\r
541 tdGetSurfaceLight ENDP
\r
543 ;-----------------------------------------------------------
\r
545 ; Rotates an array of TPOINT.
\r
548 ; Source = pointer to source array of TPOINT
\r
549 ; Dest = pointer to destination array of TPOINT
\r
550 ; Count = number of entries to transform
\r
554 tdRotate PROC PASCAL FAR
\r
555 ARG Source:DWORD, \
\r
558 USES ds, si, es, di, fs
\r
560 mov ax, SEG MATH_DATA
\r
562 ASSUME ds:MATH_DATA
\r
568 ; Transform Z coordinate
\r
584 ; Transform X coordinate
\r
600 ; Transform Y coordinate
\r
616 add si, SIZE TPOINT
\r
617 add di, SIZE TPOINT
\r
624 tdFixedMul PROC PASCAL FAR
\r
635 ;-----------------------------------------------------------
\r
637 ; Returns in EAX the square root of EDX:EAX.
\r
645 mov eax, edx ; Just discard the low bits
\r
670 ;-----------------------------------------------------------
\r
672 ; Finds the unitary normal to a given surface.
\r
675 ; Dest = pointer to TPOINT (vector) result
\r
676 ; P1, P2, P3 = pointer to TPOINT points on surface
\r
680 ; the normal is given by the cross-product between (P3-P1) and
\r
681 ; (P2-P1), so its orientation depends on the parameters order.
\r
683 tdGetNormal PROC PASCAL FAR
\r
691 USES ds, si, es, di
\r
718 ; Get normal vector (V1 x V2)
\r
752 ; Get normal length
\r
764 adc edx, ecx ; EDX:EAX = N.X*N.X + N.Y*N.Y + N.Z*N.Z
\r
765 call subSqrt ; EAX = normal length
\r
768 ; Adjust vector and save it
\r
796 ;-----------------------------------------------------------
\r
798 ; Performs surface removal on an array of polygons.
\r
801 ; Poly = pointer to an array of TPOLY
\r
802 ; Vertex = pointer to an array of TPOINT
\r
803 ; Dest = pointer to an array of integer
\r
804 ; Count = number of polygons to check
\r
805 ; Step = size of TPOLY structure
\r
807 ; if the n-th polygon is invisible the n-th entry of the
\r
808 ; Dest array is set to -1, other entries are not modified
\r
809 ; (so it's possible to use the Light array for Dest, because
\r
810 ; the light intensity is always >= 0)
\r
812 tdBackPlaneCull PROC PASCAL FAR
\r
818 USES ds, si, es, di, fs
\r
821 mov ds, WORD PTR Vertex[2]
\r
823 mov fs, WORD PTR Dest[2]
\r
826 mov ax, es:[di].Vtx[2] ; Index of 2nd vertex
\r
830 add bx, ax ; BX = index*SIZE TPOINT
\r
831 add bx, WORD PTR [Vertex] ; BX = offset of 2nd vertex
\r
832 mov ax, es:[di].Vtx[4] ; Index of 3rd vertex
\r
837 add si, WORD PTR [Vertex] ; SI = offset of 3rd vertex
\r
839 sub ecx, ds:[bx].X ; ECX = V3.X-V2.X
\r
841 sub edx, ds:[bx].Y ; EDX = V3.Y-V2.Y
\r
842 mov ax, es:[di].Vtx[0] ; Index of 1st vertex
\r
847 add si, WORD PTR [Vertex] ; SI = offset of 1st vertex
\r
849 sub eax, ds:[bx].X ; EAX = V1.X-V2.X
\r
851 sub esi, ds:[bx].Y ; ESI = V1.Y-V2.Y
\r
854 xchg ecx, edx ; ECX:EBX = (V1.X-V2.X)*(V3.Y-V2.Y)
\r
856 imul edx ; EDX:EAX = (V1.Y-V2.Y)*(V3.X-V2.X)
\r
859 jl @@Next ; Polygon is visible
\r
860 mov bx, WORD PTR [Dest] ; FS:BX -> current Dest entry
\r
861 mov WORD PTR fs:[bx], -1 ; Remove polygon
\r
863 add WORD PTR [Dest], 2 ; Next entry for dest
\r
864 add di, [Step] ; Next polygon
\r
869 tdBackPlaneCull ENDP
\r