1 ;-----------------------------------------------------------
\r
3 ; MXPT.ASM - Convex polygon fill with texture mapping
\r
4 ; Copyright (c) 1994 by Alessandro Scotti
\r
6 ;-----------------------------------------------------------
\r
11 PUBLIC mxTexturePoly
\r
13 ;-----------------------------------------------------------
\r
15 ; "Local" definitions
\r
22 ; Do NOT change order!
\r
32 MAXSCANCOLUMNS EQU POLYSCANBUFSIZE / SIZE TSCAN
\r
34 MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'
\r
35 ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
\r
37 EXTRN mx_VideoSegment : WORD
\r
38 EXTRN mx_CodeSegment : WORD
\r
39 EXTRN mx_BytesPerLine : WORD
\r
40 EXTRN mx_ClipX1 : WORD
\r
41 EXTRN mx_ClipY1 : WORD
\r
42 EXTRN mx_ClipX2 : WORD
\r
43 EXTRN mx_ClipY2 : WORD
\r
44 EXTRN mx_ScanBuffer : NEAR
\r
46 ; Global variables, to optimize allocation of local space
\r
48 mx_TextureWidth DW ?
\r
55 mx_TempX DW 512 DUP(?)
\r
56 mx_TempY DW 512 DUP(?)
\r
58 ;-----------------------------------------------------------
\r
60 ; Scans an edge using the DDA (digital differential analyzer) algorithm.
\r
61 ; Also saves information for the texture scanner.
\r
64 ; DS:BX = pointer to start point (X1, Y1)
\r
65 ; DS:SI = pointer to end point (X2, Y2)
\r
66 ; ES:DI = pointer to edge buffer
\r
68 ; ES:DI = updated pointer to edge buffer
\r
72 sub cx, ds:[bx].X ; Get width
\r
73 mov es:[di].IX1, cx ; Save width
\r
81 sub ax, bx ; Get height
\r
82 jg @@T2B ; Scan top to bottom
\r
83 jl @@B2T ; Scan bottom to top
\r
85 ; Special case: vertical line
\r
94 ; Scan top to bottom
\r
101 xchg ax, bx ; BP:BX = fixed 16:16 step
\r
112 ; Scan bottom to top
\r
135 ;-----------------------------------------------------------
\r
137 ; Scans a texture edge.
\r
140 ; DS:BX = pointer to start point (X1, Y1)
\r
141 ; DS:SI = pointer to end point (X2, Y2)
\r
142 ; ES:DI = pointer to edge buffer
\r
143 ; CX = number of steps
\r
145 ; ES:DI = updated pointer to edge buffer
\r
147 subScanTexture PROC NEAR
\r
149 .push di, bx, cx ; Save registers
\r
150 mov ax, ds:[si].X ; Scan X coordinate first
\r
156 ; Special case: constant
\r
158 mov es:[di].IX1, bx
\r
174 mov es:[di].IX1, ax
\r
193 mov es:[di].IX1, ax
\r
200 ; Now scan the Y coordinate
\r
202 .pop di, bx, cx ; Restore registers
\r
209 ; Special case: constant
\r
212 mov es:[di].IY1, bx
\r
228 mov es:[di].IY1, ax
\r
247 mov es:[di].IY1, ax
\r
257 subScanTexture ENDP
\r
259 ;-----------------------------------------------------------
\r
261 ; Fills a scan column with texture.
\r
264 ; DS:SI = current TSCAN
\r
265 ; ES:DI = address of top pixel
\r
266 ; CX = number of pixels to write
\r
270 ; must preserve DS:SI, texture info in global variables.
\r
272 subFillScan PROC NEAR
\r
274 .push ds, si, bp, cx
\r
276 movzx ecx, cx ; Clear high word of ECX
\r
278 movzx eax, ds:[si].IX2
\r
279 movzx ebx, ds:[si].IX1
\r
283 ;---------------------------------------
\r
284 ; Delta X is negative
\r
286 neg ax ; Make AX positive
\r
287 shl eax, 8 ; Convert 8:8 fixed to 16:16
\r
291 mov ebp, eax ; Save X step into EBP
\r
293 movzx eax, ds:[si].IY2
\r
294 movzx esi, ds:[si].IY1
\r
298 ;-----------------------
\r
299 ; DeltaX < 0, DeltaY < 0
\r
306 mov dx, [mx_TextureWidth]
\r
308 xchg eax, esi ; ESI = Y step
\r
312 add bx, ax ; BX = start offset in texture
\r
313 lds dx, [mx_Texture]
\r
315 add edx, ebx ; EDX = X step lo:texture offset
\r
316 xchg edx, esi ; EDX = Y step
\r
322 add di, [mx_BytesPerLine]
\r
328 sub si, [mx_TextureWidth]
\r
333 ;-----------------------
\r
334 ; DeltaX < 0, DeltaY > 0
\r
340 mov dx, [mx_TextureWidth]
\r
342 xchg eax, esi ; ESI = Y step
\r
346 add bx, ax ; BX = start offset in texture
\r
347 lds dx, [mx_Texture]
\r
349 add edx, ebx ; EDX = X step lo:texture offset
\r
350 xchg edx, esi ; EDX = Y step
\r
356 add di, [mx_BytesPerLine]
\r
362 add si, [mx_TextureWidth]
\r
367 ;---------------------------------------
\r
368 ; Delta X is positive
\r
370 shl eax, 8 ; Convert 8:8 fixed to 16:16
\r
374 mov ebp, eax ; Save X step into EBP
\r
376 movzx eax, ds:[si].IY2
\r
377 movzx esi, ds:[si].IY1
\r
381 ;-----------------------
\r
382 ; DeltaX > 0, DeltaY < 0
\r
389 mov dx, [mx_TextureWidth]
\r
391 xchg eax, esi ; ESI = Y step
\r
395 add bx, ax ; BX = start offset in texture
\r
396 lds dx, [mx_Texture]
\r
398 add edx, ebx ; EDX = X step lo:texture offset
\r
399 xchg edx, esi ; EDX = Y step
\r
405 add di, [mx_BytesPerLine]
\r
411 sub si, [mx_TextureWidth]
\r
416 ;-----------------------
\r
417 ; DeltaX > 0, DeltaY > 0
\r
423 mov dx, [mx_TextureWidth]
\r
425 xchg eax, esi ; ESI = Y step
\r
429 add bx, ax ; BX = start offset in texture
\r
430 lds dx, [mx_Texture]
\r
432 add edx, ebx ; EDX = X step lo:texture offset
\r
433 xchg edx, esi ; EDX = Y step
\r
439 add di, [mx_BytesPerLine]
\r
445 add si, [mx_TextureWidth]
\r
451 .pop ds, si, bp, cx
\r
456 ;-----------------------------------------------------------
\r
458 ; Fills a convex polygon with the specified color.
\r
459 ; Interpolates pixel colors using the Gouraud algorithm.
\r
462 ; Count = number of vertexes
\r
463 ; Map = indexes of points and colors (integer)
\r
464 ; Points = array of points (integer X, Y coordinates)
\r
465 ; TPoints = array of points inside texture (fixed 8:8 coordinates)
\r
466 ; Texture = pointer to texture image
\r
467 ; TWidth = texture width in pixels
\r
471 ; vertexes must be in counterclockwise order, arrays are 0-based.
\r
473 mxTexturePoly PROC FAR
\r
479 Count:WORD = ARG_SIZE
\r
480 LOCAL WritePlane:BYTE:2, \
\r
481 ScanOffsetT:WORD, \
\r
482 ScanOffsetB:WORD, \
\r
493 BoxY2::WORD = AUTO_SIZE
\r
495 .push ds, si, es, di
\r
502 ; Check that at least three vertexes are specified
\r
507 ;------------------------------
\r
508 ; Find bounding box for polygon
\r
509 les di, [Map] ; Point to map table
\r
510 lds si, [Points] ; Point to vertex array
\r
512 mov [BoxX2], -32768
\r
514 mov [BoxY2], -32768
\r
518 mov bx, es:[di] ; Get index of vertex
\r
519 .shl bx, 2 ; Get offset in point array
\r
524 mov ax, ds:[bx].X ; Get X coordinate
\r
547 ; Repeat thru all points
\r
549 add di, 2 ; Next map entry
\r
554 ;---------------------------------
\r
555 ; Check if polygon is full clipped
\r
557 cmp ax, [mx_ClipX1] ; Is poly full clipped?
\r
560 cmp bx, [mx_ClipX2] ; Is poly full clipped?
\r
562 sub ax, bx ; Get width
\r
563 jle @@Exit ; Exit if not positive
\r
565 cmp ax, [mx_ClipY1] ; Is poly full clipped?
\r
568 cmp bx, [mx_ClipY2] ; Is poly full clipped?
\r
570 sub ax, bx ; Get height
\r
571 jle @@Exit ; Exit if not positive
\r
574 shl [Count], 1 ; We'll work with word offsets
\r
576 ;----------------------
\r
577 ; Scan top polygon edge
\r
578 mov es, [mx_CodeSegment]
\r
579 mov di, OFFSET mx_ScanBuffer
\r
580 mov si, [MinIdxT] ; Offset of top point index
\r
583 lds bx, [Map] ; DS:BX -> map table
\r
584 mov ax, ds:[bx+si] ; Index of top point #1
\r
585 dec si ; Next top point
\r
591 mov [MinIdxT], si ; Save new index of bottom point
\r
593 mov si, ds:[bx+si] ; Get index of top point #2
\r
594 .shl ax, 2 ; Convert indexes to offsets
\r
596 shl cx, 1 ; Save map points
\r
599 mov es:[di].IY1, dx
\r
600 lds bx, [Points] ; Get pointer to vertexes
\r
603 call subScan ; Scan poly top edge
\r
605 cmp si, [MaxIdx] ; Reached last vertex?
\r
606 jne @@STLoop ; No, continue
\r
607 mov es:[di].IX1, -1 ; Mark end of scan
\r
609 ;-------------------------
\r
610 ; Scan bottom polygon edge
\r
611 mov di, OFFSET mx_ScanBuffer + OFFSET Y2
\r
615 lds bx, [Map] ; DS:BX -> map table
\r
616 mov ax, ds:[bx+si] ; Index of bottom point #1
\r
617 inc si ; Next bottom point
\r
623 mov [MinIdxB], si ; Save new index of bottom point
\r
625 mov si, ds:[bx+si] ; Get index of bottom point #2
\r
626 .shl ax, 2 ; Convert indexes to offsets
\r
628 shl cx, 1 ; Save map points
\r
631 mov es:[di].IY1, dx
\r
632 lds bx, [Points] ; Get pointer to vertexes
\r
635 call subScan ; Scan poly bottom edge
\r
637 cmp si, [MaxIdx] ; Reached last vertex?
\r
638 jne @@SBLoop ; No, continue
\r
639 mov es:[di].IX1, -1 ; Mark end of scan
\r
641 ;----------------------
\r
642 ; Scan top texture edge
\r
643 mov di, OFFSET mx_ScanBuffer
\r
644 mov ds, WORD PTR [TPoints][2]
\r
646 mov cx, es:[di].IX1
\r
649 mov ax, es:[di].IY1
\r
654 mov bx, WORD PTR [TPoints][0]
\r
657 call subScanTexture ; Scan texture top edge
\r
661 ;-------------------------
\r
662 ; Scan bottom texture edge
\r
663 mov di, OFFSET mx_ScanBuffer + OFFSET Y2
\r
665 mov cx, es:[di].IX1
\r
668 mov ax, es:[di].IY1
\r
673 mov bx, WORD PTR [TPoints][0]
\r
676 call subScanTexture ; Scan texture top edge
\r
680 ;--------------------
\r
681 ; Clip left and right
\r
682 mov si, OFFSET mx_ScanBuffer
\r
686 mov bx, [mx_ClipX1] ; CX = bounding box width
\r
688 jle @@ClipL1 ; No need to clip left
\r
690 add ax, bx ; BoxX1 = mx_ClipX1
\r
692 .shl bx, 2 ; Warning!!! This is an hand-coded
\r
693 add si, bx ; multiply by the size of TSCAN
\r
698 add bx, cx ; Last scan column
\r
699 sub bx, [mx_ClipX2]
\r
700 jle @@ClipL2 ; No need to clip right
\r
701 sub cx, bx ; Clip right
\r
703 test cx, cx ; Is clipped width positive?
\r
704 jle @@Exit ; No, exit
\r
705 mov [ScanCount], cx ; Save number of columns to draw
\r
706 mov [ScanOffsetT], si ; Remember offset of (clipped) buffer
\r
707 mov ds, [mx_CodeSegment] ; DS:SI -> scan buffer
\r
709 ;------------------------------
\r
710 ; Check if Y clipping is needed
\r
712 cmp ax, [mx_ClipY1]
\r
713 jl @@ClipTB ; Need to clip top
\r
715 cmp ax, [mx_ClipY2]
\r
716 jg @@ClipTB ; Need to clip bottom
\r
717 jmp @@ClipYExit ; Skip Y clipping
\r
719 ;--------------------
\r
720 ; Clip top and bottom
\r
722 mov di, cx ; DI = scan count
\r
723 inc di ; Increment count for pre-loop test
\r
726 dec di ; Any column left?
\r
727 jz @@ClipYExit ; No, exit
\r
729 mov ax, ds:[si].Y1 ; Y1
\r
730 mov cx, ds:[si].Y2 ; Y2
\r
731 mov dx, [mx_ClipY2]
\r
732 cmp ax, dx ; Full clipped?
\r
733 jg @@ClipYClip ; Yes, skip this column
\r
734 cmp cx, dx ; Need to clip bottom?
\r
735 jle @@ClipY1 ; No, continue
\r
736 ; Clip bottom, update texture too
\r
739 sub bx, dx ; Number of pixels to clip
\r
740 sub cx, ax ; Height
\r
742 mov ax, ds:[si].IX1 ; Update texture
\r
743 sub ax, ds:[si].IX2
\r
746 add ds:[si].IX2, ax
\r
747 mov ax, ds:[si].IY1
\r
748 sub ax, ds:[si].IY2
\r
751 add ds:[si].IY2, ax
\r
752 mov ax, ds:[si].Y1 ; Reload coordinates
\r
753 mov cx, ds:[si].Y2 ;
\r
755 mov dx, [mx_ClipY1]
\r
756 cmp cx, dx ; Full top clipped?
\r
757 jl @@ClipYClip ; Yes, skip
\r
758 sub cx, ax ; Get height
\r
759 jle @@ClipYClip ; Skip if not positive
\r
760 cmp ax, dx ; Need to clip top?
\r
761 jge @@ClipYLoop ; No, continue
\r
762 ; Clip top, update texture too
\r
763 mov ds:[si].Y1, dx ; Y1 = mx_ClipY1
\r
764 sub dx, ax ; DX = number of pixels clipped
\r
766 jbe @@ClipYClip ; Full clipped, skip
\r
767 mov bx, dx ; Save pixel count
\r
768 mov ax, ds:[si].IX2
\r
769 sub ax, ds:[si].IX1
\r
772 add ds:[si].IX1, ax
\r
773 mov ax, ds:[si].IY2
\r
774 sub ax, ds:[si].IY1
\r
777 add ds:[si].IY1, ax
\r
780 mov ds:[si].Y1, -1 ; Mark column as clipped
\r
786 mov es, [mx_VideoSegment]
\r
788 mov ds:[mx_TextureWidth], ax
\r
789 mov ax, WORD PTR [Texture][0]
\r
790 mov dx, WORD PTR [Texture][2]
\r
791 mov WORD PTR ds:[mx_Texture][0], ax
\r
792 mov WORD PTR ds:[mx_Texture][2], dx
\r
793 mov si, [ScanOffsetT]
\r
794 mov cl, BYTE PTR [BoxX1] ; Init write plane
\r
798 mov [WritePlane], al
\r
802 test ax, ax ; Was column clipped?
\r
803 js @@DrawNext ; Yes, skip
\r
805 sub cx, ax ; CX = height
\r
807 mul [mx_BytesPerLine] ; Get pixel address
\r
810 mov ah, [WritePlane]
\r
816 rol [WritePlane], 1
\r
817 adc [BoxX1], 0 ; Bump pointer to video memory if needed
\r
824 .pop ds, si, es, di
\r