--- /dev/null
+COMMENT /\r
+ Fixed-point math functions and 3D transforms\r
+ Copyright (c) 1993,94 by Alessandro Scotti\r
+/\r
+WARN PRO\r
+P386\r
+JUMPS\r
+LOCALS\r
+\r
+INCLUDE MATH.INC\r
+\r
+PUBLIC tdFixedMul\r
+PUBLIC tdGetNormal\r
+PUBLIC tdRotate\r
+PUBLIC tdGetSurfaceLight\r
+PUBLIC tdSetLight\r
+PUBLIC tdSetRotation\r
+PUBLIC tdSetTranslation\r
+PUBLIC tdTransform\r
+PUBLIC tdTransformToImage\r
+PUBLIC tdTransformLight\r
+PUBLIC tdBackPlaneCull\r
+PUBLIC tdSetPerspective\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Data segment\r
+;\r
+MATH_DATA SEGMENT USE16 PARA PUBLIC 'DATA'\r
+ ASSUME ds:MATH_DATA\r
+\r
+INCLUDE SINCOS.INC ; Fixed 8:24 sin/cos table\r
+\r
+XRotation TPOINT <> ; 3x3 rotation matrix\r
+YRotation TPOINT <>\r
+ZRotation TPOINT <>\r
+\r
+Translation TPOINT <> ; Translation vector\r
+\r
+Light TPOINT <> ; Light vector\r
+AmbientLight DW 00 ; Ambient light\r
+\r
+XScale DD 10000h ; Scaling factor for X coordinate\r
+YScale DD 10000h ; Scaling factor for Y coordinate\r
+PerspectiveDistance DD 20000000h\r
+\r
+MATH_DATA ENDS\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Code segment\r
+;\r
+MATH_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'\r
+ ASSUME cs:MATH_TEXT, es:NOTHING, fs:NOTHING\r
+\r
+tdSetPerspective PROC PASCAL FAR\r
+ ARG Perspective:DWORD, \\r
+ ScaleX:DWORD, \\r
+ ScaleY:DWORD\r
+ USES ds\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ mov eax, [Perspective]\r
+ mov [PerspectiveDistance], eax\r
+ mov eax, [ScaleX]\r
+ mov [XScale], eax\r
+ mov eax, [ScaleY]\r
+ mov [YScale], eax\r
+\r
+ ret\r
+tdSetPerspective ENDP\r
+\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Sets the rotation matrix.\r
+;\r
+; Input:\r
+; RX = X-axis rotation angle\r
+; RY = X-axis rotation angle\r
+; RZ = X-axis rotation angle\r
+; Output:\r
+; none\r
+;\r
+tdSetRotation PROC PASCAL FAR\r
+ ARG RX:WORD, \\r
+ RY:WORD, \\r
+ RZ:WORD\r
+ USES ds, si, di\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ mov bx, [RZ]\r
+ mov si, [RY]\r
+ mov di, [RX]\r
+ shl bx, 2\r
+ shl si, 2\r
+ shl di, 2\r
+\r
+ push ebp ; We use EBP as a scratch register\r
+\r
+; Set X rotation\r
+ mov eax, tblCos[bx]\r
+ imul tblCos[si]\r
+ mov [XRotation.X], edx\r
+\r
+ mov eax, tblSin[bx]\r
+ imul tblCos[si]\r
+ mov [XRotation.Y], edx\r
+\r
+ mov eax, tblSin[si]\r
+ sar eax, 8 ; Convert fixed 8:24 to fixed 16:16\r
+ mov [XRotation.Z], eax\r
+\r
+; Set Y rotation\r
+ mov eax, tblCos[bx]\r
+ imul tblSin[si] ; EDX:EAX = fixed 16:48\r
+ shrd eax, edx, 24 ; EAX = fixed 8:24\r
+ imul tblSin[di] ; EDX:EAX = fixed 16:48\r
+ mov ebp, eax\r
+ mov ecx, edx\r
+ mov eax, tblSin[bx]\r
+ imul tblCos[di]\r
+ add eax, ebp\r
+ adc edx, ecx ; EDX:EAX = fixed 16:48\r
+ neg edx\r
+ mov [YRotation.X], edx\r
+\r
+ mov eax, tblSin[bx]\r
+ imul tblSin[si]\r
+ shrd eax, edx, 24\r
+ imul tblSin[di]\r
+ mov ebp, eax\r
+ mov ecx, edx\r
+ mov eax, tblCos[bx]\r
+ imul tblCos[di]\r
+ sub eax, ebp\r
+ sbb edx, ecx\r
+ mov [YRotation.Y], edx\r
+\r
+ mov eax, tblCos[si]\r
+ imul tblSin[di]\r
+ mov [YRotation.Z], edx\r
+\r
+; Set Z rotation\r
+ mov eax, tblCos[bx]\r
+ imul tblSin[si]\r
+ shrd eax, edx, 24\r
+ imul tblCos[di]\r
+ mov ebp, eax\r
+ mov ecx, edx\r
+ mov eax, tblSin[bx]\r
+ imul tblSin[di]\r
+ sub eax, ebp\r
+ sbb edx, ecx\r
+ mov [ZRotation.X], edx\r
+\r
+ mov eax, tblSin[bx]\r
+ imul tblSin[si]\r
+ shrd eax, edx, 24\r
+ imul tblCos[di]\r
+ mov ebp, eax\r
+ mov ecx, edx\r
+ mov eax, tblCos[bx]\r
+ imul tblSin[di]\r
+ add eax, ebp\r
+ add edx, ecx\r
+ neg edx\r
+ mov [ZRotation.Y], edx\r
+\r
+ mov eax, tblCos[si]\r
+ imul tblCos[di]\r
+ mov [ZRotation.Z], edx\r
+\r
+ pop ebp ; Restore EBP\r
+\r
+ ret\r
+tdSetRotation ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Sets the translation vector.\r
+;\r
+; Input:\r
+; TV = pointer to translation vector\r
+; Output:\r
+; none\r
+;\r
+tdSetTranslation PROC PASCAL FAR\r
+ ARG TV:DWORD\r
+ USES ds, es, di\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ les di, [TV]\r
+ mov eax, es:[di].X\r
+ mov [Translation.X], eax\r
+ mov eax, es:[di].Y\r
+ mov [Translation.Y], eax\r
+ mov eax, es:[di].Z\r
+ mov [Translation.Z], eax\r
+\r
+ ret\r
+tdSetTranslation ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Transforms an array of TPOINT.\r
+;\r
+; Input:\r
+; Source = pointer to source array of TPOINT\r
+; Dest = pointer to destination array of TPOINT\r
+; Count = number of entries to transform\r
+; Output:\r
+; none\r
+;\r
+tdTransform PROC PASCAL FAR\r
+ ARG Source:DWORD, \\r
+ Dest:DWORD, \\r
+ Count:WORD\r
+ LOCAL Adjust:DWORD\r
+ USES ds, si, es, di, fs\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ lfs si, [Source]\r
+ les di, [Dest]\r
+\r
+ ALIGN DWORD\r
+@@Loop:\r
+; Transform Z coordinate\r
+ mov eax, fs:[si].X\r
+ imul [ZRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [ZRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [ZRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ mov ebx, eax\r
+ shrd eax, edx, 16\r
+ add eax, [Translation.Z] ; EAX = new Z coord (fixed 16:16)\r
+ mov es:[di].Z, eax\r
+; Get perspective factor\r
+ mov ebx, [PerspectiveDistance]\r
+ sub eax, ebx\r
+ neg eax ; EAX = PD - Z\r
+ xor edx, edx\r
+ shld edx, eax, 16\r
+ shl eax, 16\r
+ idiv ebx ; EAX = fixed 16:16 result\r
+ mov [Adjust], eax\r
+\r
+; Transform X coordinate\r
+ mov eax, fs:[si].X\r
+ imul [XRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [XRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [XRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ add eax, [Translation.X]\r
+ imul [Adjust]\r
+ shrd eax, edx, 16\r
+ mov es:[di].X, eax\r
+\r
+; Transform Y coordinate\r
+ mov eax, fs:[si].X\r
+ imul [YRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [YRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [YRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ add eax, [Translation.Y]\r
+ imul [Adjust]\r
+ shrd eax, edx, 16\r
+ mov es:[di].Y, eax\r
+\r
+ add si, SIZE TPOINT\r
+ add di, SIZE TPOINT\r
+ dec [Count]\r
+ jnz @@Loop\r
+\r
+ ret\r
+tdTransform ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Transforms an array of TPOINT into an array of TIMAGEPOINT.\r
+;\r
+; Input:\r
+; Source = pointer to source array of TPOINT\r
+; Dest = pointer to destination array of TIMAGEPOINT\r
+; Count = number of entries to transform\r
+; DeltaX = translation distance for the X coordinate\r
+; DeltaY = translation distance for the Y coordinate\r
+; Output:\r
+; the maximum Z value\r
+;\r
+tdTransformToImage PROC PASCAL FAR\r
+ ARG Source:DWORD, \\r
+ Dest:DWORD, \\r
+ Count:WORD, \\r
+ DeltaX:WORD, \\r
+ DeltaY:WORD\r
+ LOCAL Adjust:DWORD, \\r
+ Max:DWORD\r
+ USES ds, si, es, di, fs\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ lfs si, [Source]\r
+ les di, [Dest]\r
+ mov [Max], 80000000h\r
+\r
+@@Loop:\r
+; Check max Z\r
+ mov eax, fs:[si].Z\r
+ cmp eax, [Max]\r
+ jle @@1\r
+ mov [Max], eax\r
+@@1:\r
+\r
+; Transform X coordinate\r
+ mov ax, WORD PTR fs:[si].X[2]\r
+ add ax, [DeltaX]\r
+ mov es:[di].IX, ax\r
+\r
+; Transform Y coordinate\r
+ mov ax, WORD PTR fs:[si].Y[2]\r
+ add ax, [DeltaY]\r
+ mov es:[di].IY, ax\r
+\r
+ add si, SIZE TPOINT\r
+ add di, SIZE TIMAGEPOINT\r
+ dec [Count]\r
+ jnz @@Loop\r
+\r
+ mov eax, [Max]\r
+ shld edx, eax, 16\r
+ ret\r
+tdTransformToImage ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Sets the light source.\r
+;\r
+; Input:\r
+; Light = pointer to light vector\r
+; Output:\r
+; none\r
+;\r
+tdSetLight PROC PASCAL FAR\r
+ ARG L:DWORD\r
+ USES ds, es, di\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ les di, [L]\r
+ mov eax, es:[di].X\r
+ mov [Light.X], eax\r
+ mov eax, es:[di].Y\r
+ mov [Light.Y], eax\r
+ mov eax, es:[di].Z\r
+ mov [Light.Z], eax\r
+\r
+ ret\r
+tdSetLight ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Computes light intensity for an array of surfaces.\r
+;\r
+; Input:\r
+; Normals = pointer to an array of surface normals\r
+; Lights = pointer to an array of integer to be filled with\r
+; light intensity\r
+; Count = number of elements to transform\r
+; Output:\r
+; none\r
+;\r
+tdTransformLight PROC PASCAL FAR\r
+ ARG Normals:DWORD, \\r
+ Lights:DWORD, \\r
+ Count:WORD\r
+ USES ds, si, es, di, fs\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov fs, ax\r
+ ASSUME fs:MATH_DATA\r
+\r
+ lds si, [Normals]\r
+ les di, [Lights]\r
+ ASSUME ds:NOTHING\r
+\r
+; Intensity is given by the dot product between the Light vector and\r
+; the surface normal\r
+@@Loop:\r
+ mov eax, ds:[si].Z\r
+ imul [Light.Z]\r
+ mov ebx, eax\r
+ mov ecx, edx\r
+ mov eax, ds:[si].Y\r
+ imul [Light.Y]\r
+ add ebx, eax\r
+ adc ecx, edx\r
+ mov eax, ds:[si].X\r
+ imul [Light.X]\r
+ add eax, ebx\r
+ adc edx, ecx ; EDX:EAX = fixed 32:32 intensity\r
+ add dx, [AmbientLight]\r
+ test dx, dx\r
+ jg @@1\r
+ xor dx, dx ; Return 0 for no light\r
+@@1:\r
+ mov es:[di], dx\r
+ inc di\r
+ inc di\r
+ add si, SIZE TPOINT\r
+ dec [Count]\r
+ jnz @@Loop\r
+\r
+ ASSUME fs:NOTHING\r
+ ret\r
+tdTransformLight ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Returns the light value given the normal to a surface.\r
+;\r
+; Input:\r
+; Normal = pointer to TPOINT surface normal vector\r
+; Output:\r
+; AX = light intensity (>=0)\r
+; Notes:\r
+; the normal is rotated according to the current setting.\r
+;\r
+tdGetSurfaceLight PROC PASCAL FAR\r
+ ARG Normal:DWORD\r
+ USES ds, esi, es, di\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ les di, [Normal]\r
+\r
+; Transform Z coordinate\r
+ mov eax, es:[di].X\r
+ imul [ZRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, es:[di].Y\r
+ imul [ZRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, es:[di].Z\r
+ imul [ZRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ imul [Light.Z]\r
+ shrd eax, edx, 16\r
+ mov esi, eax\r
+\r
+; Transform X coordinate\r
+ mov eax, es:[di].X\r
+ imul [XRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, es:[di].Y\r
+ imul [XRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, es:[di].Z\r
+ imul [XRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ imul [Light.X]\r
+ shrd eax, edx, 16\r
+ add esi, eax\r
+\r
+; Transform Y coordinate\r
+ mov eax, es:[di].X\r
+ imul [YRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, es:[di].Y\r
+ imul [YRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, es:[di].Z\r
+ imul [YRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ imul [Light.X]\r
+ shrd eax, edx, 16\r
+ add eax, esi\r
+ shr eax, 16\r
+\r
+; Add ambient light\r
+ add ax, [AmbientLight]\r
+ test ax, ax\r
+ jge @@Exit\r
+ xor ax, ax\r
+\r
+@@Exit:\r
+ ret\r
+tdGetSurfaceLight ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Rotates an array of TPOINT.\r
+;\r
+; Input:\r
+; Source = pointer to source array of TPOINT\r
+; Dest = pointer to destination array of TPOINT\r
+; Count = number of entries to transform\r
+; Output:\r
+; none\r
+;\r
+tdRotate PROC PASCAL FAR\r
+ ARG Source:DWORD, \\r
+ Dest:DWORD, \\r
+ Count:WORD\r
+ USES ds, si, es, di, fs\r
+\r
+ mov ax, SEG MATH_DATA\r
+ mov ds, ax\r
+ ASSUME ds:MATH_DATA\r
+\r
+ lfs si, [Source]\r
+ les di, [Dest]\r
+\r
+@@Loop:\r
+; Transform Z coordinate\r
+ mov eax, fs:[si].X\r
+ imul [ZRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [ZRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [ZRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ mov es:[di].Z, eax\r
+\r
+; Transform X coordinate\r
+ mov eax, fs:[si].X\r
+ imul [XRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [XRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [XRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ mov es:[di].X, eax\r
+\r
+; Transform Y coordinate\r
+ mov eax, fs:[si].X\r
+ imul [YRotation.X]\r
+ mov ecx, eax\r
+ mov ebx, edx\r
+ mov eax, fs:[si].Y\r
+ imul [YRotation.Y]\r
+ add ecx, eax\r
+ adc ebx, edx\r
+ mov eax, fs:[si].Z\r
+ imul [YRotation.Z]\r
+ add eax, ecx\r
+ adc edx, ebx\r
+ shrd eax, edx, 16\r
+ mov es:[di].Y, eax\r
+\r
+ add si, SIZE TPOINT\r
+ add di, SIZE TPOINT\r
+ dec [Count]\r
+ jnz @@Loop\r
+\r
+ ret\r
+tdRotate ENDP\r
+\r
+tdFixedMul PROC PASCAL FAR\r
+ ARG F1:DWORD, \\r
+ F2:DWORD\r
+\r
+ mov eax, [F1]\r
+ imul [F2]\r
+ shr eax, 16\r
+\r
+ ret\r
+tdFixedMul ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Returns in EAX the square root of EDX:EAX.\r
+;\r
+subSqrt PROC NEAR\r
+ push esi\r
+ push edi\r
+\r
+ add eax, eax\r
+ adc edx, 0\r
+ mov eax, edx ; Just discard the low bits\r
+\r
+ mov esi, eax\r
+ xor edi, edi\r
+ shld edi, esi, 16\r
+ shl esi, 16\r
+@@Loop:\r
+ mov ebx, eax\r
+ mul eax\r
+ add eax, esi\r
+ adc edx, edi\r
+ shrd eax, edx, 1\r
+ shr edx, 1\r
+ div ebx\r
+ cmp eax, ebx\r
+ jne @@Loop\r
+\r
+; Adjust EAX\r
+ shl eax, 8\r
+\r
+ pop edi\r
+ pop esi\r
+ ret\r
+subSqrt ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Finds the unitary normal to a given surface.\r
+;\r
+; Input:\r
+; Dest = pointer to TPOINT (vector) result\r
+; P1, P2, P3 = pointer to TPOINT points on surface\r
+; Output:\r
+; none\r
+; Notes:\r
+; the normal is given by the cross-product between (P3-P1) and\r
+; (P2-P1), so its orientation depends on the parameters order.\r
+;\r
+tdGetNormal PROC PASCAL FAR\r
+ ARG Dest:DWORD, \\r
+ P1:DWORD, \\r
+ P2:DWORD, \\r
+ P3:DWORD\r
+ LOCAL V1:TPOINT, \\r
+ V2:TPOINT, \\r
+ N:TPOINT\r
+ USES ds, si, es, di\r
+\r
+; Get vector V1\r
+ lds si, [P1]\r
+ les di, [P3]\r
+ mov eax, es:[di].X\r
+ sub eax, ds:[si].X\r
+ mov [V1.X], eax\r
+ mov eax, es:[di].Y\r
+ sub eax, ds:[si].Y\r
+ mov [V1.Y], eax\r
+ mov eax, es:[di].Z\r
+ sub eax, ds:[si].Z\r
+ mov [V1.Z], eax\r
+\r
+; Get vector V2\r
+ les di, [P2]\r
+ mov eax, es:[di].X\r
+ sub eax, ds:[si].X\r
+ mov [V2.X], eax\r
+ mov eax, es:[di].Y\r
+ sub eax, ds:[si].Y\r
+ mov [V2.Y], eax\r
+ mov eax, es:[di].Z\r
+ sub eax, ds:[si].Z\r
+ mov [V2.Z], eax\r
+\r
+; Get normal vector (V1 x V2)\r
+ mov eax, [V1.Z]\r
+ imul [V2.Y]\r
+ mov ebx, eax\r
+ mov ecx, edx\r
+ mov eax, [V1.Y]\r
+ imul [V2.Z]\r
+ sub eax, ebx\r
+ sbb edx, ecx\r
+ shrd eax, edx, 16\r
+ mov [N.X], eax\r
+\r
+ mov eax, [V1.X]\r
+ imul [V2.Z]\r
+ mov ebx, eax\r
+ mov ecx, edx\r
+ mov eax, [V1.Z]\r
+ imul [V2.X]\r
+ sub eax, ebx\r
+ sbb edx, ecx\r
+ shrd eax, edx, 16\r
+ mov [N.Y], eax\r
+\r
+ mov eax, [V1.Y]\r
+ imul [V2.X]\r
+ mov ebx, eax\r
+ mov ecx, edx\r
+ mov eax, [V1.X]\r
+ imul [V2.Y]\r
+ sub eax, ebx\r
+ sbb edx, ecx\r
+ shrd eax, edx, 16\r
+ mov [N.Z], eax\r
+\r
+; Get normal length\r
+ mov eax, [N.X]\r
+ imul eax\r
+ mov ebx, eax\r
+ mov ecx, edx\r
+ mov eax, [N.Y]\r
+ imul eax\r
+ add ebx, eax\r
+ adc ecx, edx\r
+ mov eax, [N.Z]\r
+ imul eax\r
+ add eax, ebx\r
+ adc edx, ecx ; EDX:EAX = N.X*N.X + N.Y*N.Y + N.Z*N.Z\r
+ call subSqrt ; EAX = normal length\r
+ mov ebx, eax\r
+\r
+; Adjust vector and save it\r
+ les di, [Dest]\r
+ mov eax, [N.X]\r
+ cdq\r
+ shld edx, eax, 16\r
+ shl eax, 16\r
+ idiv ebx\r
+ mov es:[di].X, eax\r
+ mov eax, [N.Y]\r
+ cdq\r
+ shld edx, eax, 16\r
+ shl eax, 16\r
+ idiv ebx\r
+ mov es:[di].Y, eax\r
+ mov eax, [N.Z]\r
+ cdq\r
+ shld edx, eax, 16\r
+ shl eax, 16\r
+ idiv ebx\r
+ mov es:[di].Z, eax\r
+\r
+ ret\r
+tdGetNormal ENDP\r
+\r
+TPOLY STRUC\r
+ Vtx DW 4 DUP(?)\r
+TPOLY ENDS\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Performs surface removal on an array of polygons.\r
+;\r
+; Input:\r
+; Poly = pointer to an array of TPOLY\r
+; Vertex = pointer to an array of TPOINT\r
+; Dest = pointer to an array of integer\r
+; Count = number of polygons to check\r
+; Step = size of TPOLY structure\r
+; Output:\r
+; if the n-th polygon is invisible the n-th entry of the\r
+; Dest array is set to -1, other entries are not modified\r
+; (so it's possible to use the Light array for Dest, because\r
+; the light intensity is always >= 0)\r
+;\r
+tdBackPlaneCull PROC PASCAL FAR\r
+ ARG Step:WORD, \\r
+ Poly:DWORD, \\r
+ Vertex:DWORD, \\r
+ Dest:DWORD, \\r
+ Count:WORD\r
+ USES ds, si, es, di, fs\r
+ ASSUME ds:NOTHING\r
+\r
+ mov ds, WORD PTR Vertex[2]\r
+ les di, [Poly]\r
+ mov fs, WORD PTR Dest[2]\r
+\r
+@@Loop:\r
+ mov ax, es:[di].Vtx[2] ; Index of 2nd vertex\r
+ shl ax, 2\r
+ mov bx, ax\r
+ shl ax, 1\r
+ add bx, ax ; BX = index*SIZE TPOINT\r
+ add bx, WORD PTR [Vertex] ; BX = offset of 2nd vertex\r
+ mov ax, es:[di].Vtx[4] ; Index of 3rd vertex\r
+ shl ax, 2\r
+ mov si, ax\r
+ shl ax, 1\r
+ add si, ax\r
+ add si, WORD PTR [Vertex] ; SI = offset of 3rd vertex\r
+ mov ecx, ds:[si].X\r
+ sub ecx, ds:[bx].X ; ECX = V3.X-V2.X\r
+ mov edx, ds:[si].Y\r
+ sub edx, ds:[bx].Y ; EDX = V3.Y-V2.Y\r
+ mov ax, es:[di].Vtx[0] ; Index of 1st vertex\r
+ shl ax, 2\r
+ mov si, ax\r
+ shl ax, 1\r
+ add si, ax\r
+ add si, WORD PTR [Vertex] ; SI = offset of 1st vertex\r
+ mov eax, ds:[si].X\r
+ sub eax, ds:[bx].X ; EAX = V1.X-V2.X\r
+ mov esi, ds:[si].Y\r
+ sub esi, ds:[bx].Y ; ESI = V1.Y-V2.Y\r
+ imul edx\r
+ mov ebx, eax\r
+ xchg ecx, edx ; ECX:EBX = (V1.X-V2.X)*(V3.Y-V2.Y)\r
+ mov eax, esi\r
+ imul edx ; EDX:EAX = (V1.Y-V2.Y)*(V3.X-V2.X)\r
+ sub eax, ebx\r
+ sbb edx, ecx\r
+ jl @@Next ; Polygon is visible\r
+ mov bx, WORD PTR [Dest] ; FS:BX -> current Dest entry\r
+ mov WORD PTR fs:[bx], -1 ; Remove polygon\r
+@@Next:\r
+ add WORD PTR [Dest], 2 ; Next entry for dest\r
+ add di, [Step] ; Next polygon\r
+ dec [Count]\r
+ jnz @@Loop\r
+\r
+ ret\r
+tdBackPlaneCull ENDP\r
+\r
+MATH_TEXT ENDS\r
+END\r