1 ;-----------------------------------------------------------
\r
3 ; MXPG.ASM - Convex polygon fill with Gouraud shading
\r
4 ; Copyright (c) 1994 by Alessandro Scotti
\r
6 ;-----------------------------------------------------------
\r
11 PUBLIC mxGouraudPoly
\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 ;-----------------------------------------------------------
\r
48 ; Scans an edge using the DDA (digital differential analyzer) algorithm.
\r
49 ; Also interpolates color for shading.
\r
52 ; DS:BX = pointer to start point (X1, Y1)
\r
53 ; DS:SI = pointer to end point (X2, Y2)
\r
54 ; ES:DI = pointer to edge buffer
\r
58 ; ES:DI = updated pointer to edge buffer
\r
60 ; must preserve DS:SI.
\r
64 sub cx, ds:[bx].X ; Get width
\r
69 push di ; Save scan info offset
\r
70 push cx ; Save height
\r
71 push ax ; Save colors
\r
76 sub ax, bx ; Get height
\r
77 jg @@T2B ; Scan top to bottom
\r
78 jl @@B2T ; Scan bottom to top
\r
80 ; Special case: vertical line
\r
89 ; Scan top to bottom
\r
96 xchg ax, bx ; BP:BX = fixed 16:16 step
\r
107 ; Scan bottom to top
\r
125 ; Now get the color info
\r
127 pop bx ; Restore colors
\r
130 pop di ; ES:DI -> scan info
\r
132 sub ax, bx ; Get color range
\r
136 ; Special case: same color
\r
140 mov WORD PTR es:[di].E1, ax
\r
146 ; Scan left to right
\r
153 xchg ax, bx ; BP:BX = fixed 16:16 step
\r
165 ; Scan right to left
\r
190 ;-----------------------------------------------------------
\r
192 ; Fills a scan column.
\r
195 ; DS:SI = current TSCAN
\r
196 ; ES:DI = address of top pixel
\r
197 ; CX = number of pixels to write
\r
202 subFillScan PROC NEAR
\r
203 mov ax, WORD PTR ds:[si].E2
\r
204 mov bx, WORD PTR ds:[si].E1
\r
206 jg @@L2R ; Color increases
\r
207 jl @@R2L ; Color decreases
\r
209 ; Special case: color doesn't change
\r
211 mov dx, [mx_BytesPerLine]
\r
223 add si, dx ; Relocate color
\r
227 mov bp, ax ; BP = color step, integer part
\r
230 mov bx, ax ; BX = color step, fractional part
\r
232 mov ax, [mx_BytesPerLine]
\r
248 add si, dx ; Relocate color
\r
253 mov bp, ax ; BP = color step, integer part
\r
256 mov bx, ax ; BX = color step, fractional part
\r
258 mov ax, [mx_BytesPerLine]
\r
271 ;-----------------------------------------------------------
\r
273 ; Fills a convex polygon with the specified color.
\r
274 ; Interpolates pixel colors using the Gouraud algorithm.
\r
277 ; Count = number of vertexes
\r
278 ; Map = indexes of points and colors (integer)
\r
279 ; Points = array of points (integer X, Y coordinates)
\r
280 ; Colors = array of colors (integer)
\r
281 ; Color = base color
\r
285 ; vertexes must be in counterclockwise order, arrays are 0-based.
\r
287 mxGouraudPoly PROC FAR
\r
292 Count:WORD = ARG_SIZE
\r
293 LOCAL WritePlane:BYTE:2, \
\r
294 ScanOffsetT:WORD, \
\r
295 ScanOffsetB:WORD, \
\r
306 BoxY2::WORD = AUTO_SIZE
\r
308 .push ds, si, es, di
\r
311 ; Check that at least three vertexes are specified
\r
316 ;------------------------------
\r
317 ; Find bounding box for polygon
\r
319 lds si, [Points] ; Pointer to vertex array
\r
321 mov [BoxX2], -32768
\r
323 mov [BoxY2], -32768
\r
327 mov bx, es:[di] ; Get index of vertex
\r
328 .shl bx, 2 ; Get offset in point array
\r
333 mov ax, ds:[bx].X ; Get X coordinate
\r
356 ; Repeat thru all points
\r
358 inc di ; Next map entry
\r
365 ;---------------------------------
\r
366 ; Check if polygon is full clipped
\r
368 cmp ax, [mx_ClipX1] ; Is poly full clipped?
\r
371 cmp bx, [mx_ClipX2] ; Is poly full clipped?
\r
373 sub ax, bx ; Get width
\r
374 jle @@Exit ; Exit if not positive
\r
376 cmp ax, [mx_ClipY1] ; Is poly full clipped?
\r
379 cmp bx, [mx_ClipY2] ; Is poly full clipped?
\r
381 sub ax, bx ; Get height
\r
382 jle @@Exit ; Exit if not positive
\r
385 shl [Count], 1 ; We'll work with word offsets
\r
386 mov es, [mx_CodeSegment]
\r
390 mov ax, OFFSET mx_ScanBuffer
\r
391 mov [ScanOffsetT], ax
\r
392 mov si, [MinIdxT] ; Offset of bottom point index
\r
394 lds bx, [Map] ; DS:BX -> map table
\r
395 mov di, ds:[bx+si] ; Index of top point #1
\r
396 dec si ; Next point
\r
402 mov [MinIdxT], si ; Save new index of top point
\r
403 mov si, ds:[bx+si] ; Get index of top point #2
\r
404 lds bx, [Colors] ; Get pointer to color array
\r
405 shl di, 1 ; Convert indexes to offsets
\r
407 mov ax, ds:[bx+si] ; Get colors
\r
409 lds bx, [Points] ; DS:BX -> point array
\r
412 add si, bx ; DS:SI -> top point #2
\r
413 add bx, di ; DS:BX -> top point #1
\r
414 mov di, [ScanOffsetT]
\r
415 call subScan ; Scan edge
\r
416 mov [ScanOffsetT], di
\r
418 cmp si, [MaxIdx] ; End of edge?
\r
419 jne @@STLoop ; No, continue
\r
423 mov ax, OFFSET mx_ScanBuffer + OFFSET Y2
\r
424 mov [ScanOffsetB], ax
\r
425 mov si, [MinIdxB] ; Offset of bottom point index
\r
427 lds bx, [Map] ; DS:BX -> map table
\r
428 mov di, ds:[bx+si] ; Index of bottom point #1
\r
429 inc si ; Next bottom point
\r
435 mov [MinIdxB], si ; Save new index of bottom point
\r
436 mov si, ds:[bx+si] ; Get index of bottom point #2
\r
437 lds bx, [Colors] ; Get pointer to color array
\r
438 shl di, 1 ; Convert indexes to offsets
\r
440 mov ax, ds:[bx+si] ; Get colors
\r
442 lds bx, [Points] ; DS:BX -> point array
\r
445 add si, bx ; DS:SI -> top point #2
\r
446 add bx, di ; DS:BX -> top point #1
\r
447 mov di, [ScanOffsetB]
\r
448 call subScan ; Scan edge
\r
449 mov [ScanOffsetB], di
\r
451 cmp si, [MaxIdx] ; End of edge?
\r
452 jne @@SBLoop ; No, continue
\r
454 ;--------------------
\r
455 ; Clip left and right
\r
456 mov si, OFFSET mx_ScanBuffer
\r
459 sub cx, ax ; CX = bounding box width
\r
460 mov bx, [mx_ClipX1]
\r
462 jle @@ClipL1 ; No need to clip left
\r
463 sub cx, bx ; Update width
\r
464 add ax, bx ; BoxX1 = mx_ClipX1
\r
466 .shl bx, 3 ; Warning!!! This is an hand-coded
\r
467 add si, bx ; multiply by the size of TSCAN
\r
470 add bx, cx ; Last scan column
\r
471 sub bx, [mx_ClipX2]
\r
472 jle @@ClipL2 ; No need to clip right
\r
473 sub cx, bx ; Clip right
\r
475 test cx, cx ; Is clipped width positive?
\r
476 jle @@Exit ; No, exit
\r
477 mov [ScanCount], cx ; Save number of columns to draw
\r
478 mov [ScanOffsetT], si ; Remember offset of (clipped) buffer
\r
479 mov ds, [mx_CodeSegment] ; DS:SI -> scan buffer
\r
481 ;------------------------------
\r
482 ; Check if Y clipping is needed
\r
484 cmp ax, [mx_ClipY1]
\r
485 jl @@ClipTB ; Need to clip top
\r
487 cmp ax, [mx_ClipY2]
\r
488 jg @@ClipTB ; Need to clip bottom
\r
489 jmp @@ClipYExit ; Skip Y clipping
\r
491 ;--------------------
\r
492 ; Clip top and bottom
\r
494 mov di, cx ; DI = scan count
\r
495 inc di ; Increment count for pre-loop test
\r
498 dec di ; Any column left?
\r
499 jz @@ClipYExit ; No, exit
\r
501 mov ax, ds:[si].Y1 ; Y1
\r
502 mov cx, ds:[si].Y2 ; Y2
\r
503 mov dx, [mx_ClipY2]
\r
504 cmp ax, dx ; Full clipped?
\r
505 jg @@ClipYClip ; Yes, skip this column
\r
506 cmp cx, dx ; Need to clip bottom?
\r
507 jle @@ClipY1 ; No, continue
\r
508 ; Clip bottom, need to scale colors too
\r
511 sub bx, dx ; Clip distance
\r
512 sub cx, ax ; Height
\r
514 mov ax, WORD PTR ds:[si].E1
\r
515 sub ax, WORD PTR ds:[si].E2
\r
518 add WORD PTR ds:[si].E2, ax
\r
519 mov ax, ds:[si].Y1 ; Restore AX and CX
\r
522 mov dx, [mx_ClipY1]
\r
523 cmp cx, dx ; Full top clipped?
\r
524 jl @@ClipYClip ; Yes, skip
\r
525 sub cx, ax ; Get height
\r
526 jle @@ClipYClip ; Skip if not positive
\r
527 cmp ax, dx ; Need to clip top?
\r
528 jge @@ClipYLoop ; No, continue
\r
529 ; Clip top, need to scale colors too
\r
530 mov ds:[si].Y1, dx ; Y1 = mx_ClipY1
\r
531 sub dx, ax ; DX = number of pixels clipped
\r
533 jbe @@ClipYClip ; Full clipped, skip
\r
534 mov ax, WORD PTR ds:[si].E2
\r
535 sub ax, WORD PTR ds:[si].E1 ; AX = color distance
\r
538 add WORD PTR ds:[si].E1, ax ; Update starting color
\r
541 mov ds:[si].Y1, -1 ; Mark column as clipped
\r
547 mov es, [mx_VideoSegment]
\r
548 mov si, [ScanOffsetT]
\r
549 mov cl, BYTE PTR [BoxX1] ; Init write plane
\r
553 mov [WritePlane], al
\r
555 mov ax, [Color] ; Make 8:8 fixed color
\r
561 test ax, ax ; Was column clipped?
\r
562 js @@DrawNext ; Yes, skip
\r
564 sub cx, ax ; CX = height
\r
566 mul [mx_BytesPerLine] ; Get pixel address
\r
569 mov ah, [WritePlane]
\r
576 rol [WritePlane], 1
\r
577 adc [BoxX1], 0 ; Bump pointer to video memory if needed
\r
584 .pop ds, si, es, di
\r