divide negative window x-coordinates properly, fixing random crashes
[btb/d2x.git] / texmap / tmap_per.asm
1 ; $Id: tmap_per.asm,v 1.5 2004-08-28 23:17:46 schaffner Exp $
2 ;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 ;SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 ;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 ;IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 ;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 ;FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 ;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 ;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 ;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 ;
13 ;
14 ; Perspective texture mapper inner loop.
15 ;
16 ;
17
18 [BITS 32]
19
20 global  _asm_tmap_scanline_per
21 global  asm_tmap_scanline_per
22
23 %include        "tmap_inc.asm"
24
25 [SECTION .data]
26 align 4
27     ;extern _per2_flag;:dword
28 %ifdef __ELF__
29 ; Cater for ELF compilers...
30 global x
31 %define _loop_count loop_count
32 %define _new_end new_end
33 %define _scan_doubling_flag scan_doubling_flag
34 %define _linear_if_far_flag linear_if_far_flag
35 %endif
36
37         global _x
38         global _loop_count
39         global _new_end
40         global _scan_doubling_flag
41         global _linear_if_far_flag
42
43 ;        global _max_ecx
44 ;        global _min_ecx
45
46     mem_edx dd 0
47     x:
48     _x          dd      0
49     _loop_count dd      0
50
51 ;    _max_ecx    dd      0
52 ;    _min_ecx    dd      55555555h
53     _new_end     dd      1       ; if set, use new, but slower, way of finishing off extra pixels on scanline, 01/10/95 --MK
54
55     _scan_doubling_flag dd 0
56     _linear_if_far_flag dd 0
57
58 ;---------- local variables
59 align 4
60     req_base    dd      0
61     req_size    dd      0
62     U0          dd      0
63     U1          dd      0
64     V0          dd      0
65     V1          dd      0
66     num_left_over   dd  0
67     DU1         dd      0
68     DV1         dd      0
69     DZ1         dd      0
70
71 [SECTION .text]
72
73 ; --------------------------------------------------------------------------------------------------
74 ; Enter:
75 ;       _xleft  fixed point left x coordinate
76 ;       _xright fixed point right x coordinate
77 ;       _y      fixed point y coordinate
78 ;       _pixptr address of source pixel map
79 ;       _u      fixed point initial u coordinate
80 ;       _v      fixed point initial v coordinate
81 ;       _z      fixed point initial z coordinate
82 ;       _du_dx  fixed point du/dx
83 ;       _dv_dx  fixed point dv/dx
84 ;       _dz_dx  fixed point dz/dx
85
86 ;   for (x = (int) xleft; x <= (int) xright; x++) {
87 ;      _setcolor(read_pixel_from_tmap(srcb,((int) (u/z)) & 63,((int) (v/z)) & 63));
88 ;      _setpixel(x,y);
89 ;
90 ;      u += du_dx;
91 ;      v += dv_dx;
92 ;      z += dz_dx;
93 ;   }
94
95
96 align   16
97 _asm_tmap_scanline_per:
98 asm_tmap_scanline_per:
99 ;        push    es
100         pusha
101
102 ;---------------------------- setup for loop ---------------------------------
103 ; Setup for loop:       _loop_count  iterations = (int) xright - (int) xleft
104 ;       esi     source pixel pointer = pixptr
105 ;       edi     initial row pointer = y*320+x
106 ; NOTE: fx_xright and fx_xleft changed from fix to int by mk on 12/01/94.
107
108 ; set esi = pointer to start of texture map data
109
110 ; set edi = address of first pixel to modify
111         mov     edi,[_fx_y]
112 ;        mov     es,[_pixel_data_selector]       ; selector[0*2]
113
114         mov     edi,[_y_pointers+edi*4]
115
116         mov     ebx,[_fx_xleft]
117         test    ebx, ebx
118         jns     ebx_ok
119         xor     ebx, ebx
120 ebx_ok: add     edi,[_write_buffer]
121         add     edi,ebx
122
123 ; set _loop_count = # of iterations
124         mov     eax,[_fx_xright]
125         sub     eax,ebx
126         js      near _none_to_do
127         mov     [_loop_count],eax
128
129 ; lighting values are passed in fixed point, but need to be in 8 bit integer, 8 bit fraction so we can easily
130 ; get the integer by reading %bh
131         sar     dword [_fx_l], 8
132         sar     dword [_fx_dl_dx],8
133         jns     dl_dx_ok
134         inc     dword [_fx_dl_dx]       ; round towards 0 for negative deltas
135 dl_dx_ok:
136
137 ; set initial values
138         mov     ebx,[_fx_u]
139         mov     ebp,[_fx_v]
140         mov     ecx,[_fx_z]
141
142         test    dword [_per2_flag],-1
143         je      tmap_loop
144
145         test    dword [_Lighting_on], -1
146         je     near _tmap_loop_fast_nolight
147         jmp     _tmap_loop_fast
148 ;tmap_loop_fast_nolight_jumper:
149 ;    jmp tmap_loop_fast_nolight
150
151 ;================ PERSPECTIVE TEXTURE MAP INNER LOOPS ========================
152 ;
153 ; Usage in loop:        eax     division, pixel value
154 ;       ebx     u
155 ;       ecx     z
156 ;       edx     division
157 ;       ebp     v
158 ;       esi     source pixel pointer
159 ;       edi     destination pixel pointer
160
161 ;-------------------- NORMAL PERSPECTIVE TEXTURE MAP LOOP -----------------
162 tmap_loop:
163         mov     esi, ebx        ; esi becomes u coordinate
164
165         align   4
166 tmap_loop0:
167
168 ; compute v coordinate
169         mov     eax, ebp        ; get v
170         mov     edx, eax
171         sar     edx, 31
172         idiv    ecx     ; eax = (v/z)
173
174         and     eax,3fh ; mask with height-1
175         mov     ebx,eax
176
177 ; compute u coordinate
178         mov     eax, esi        ; get u
179         mov     edx, eax
180         sar     edx, 31
181         idiv    ecx     ; eax = (u/z)
182
183         shl     eax,26
184         shld    ebx,eax,6       ; esi = v*64+u
185
186 ; read 1 pixel
187         add     ebx, [_pixptr]
188         xor     eax, eax
189         test    dword [_Lighting_on], -1
190         mov     al, [ebx]    ; get pixel from source bitmap
191         je      NoLight1
192
193 ; LIGHTING CODE
194         mov     ebx, [_fx_l]    ; get temp copy of lighting value
195         mov     ah, bh  ; get lighting level
196         add     ebx, [_fx_dl_dx]        ; update lighting value
197         mov     al, [_gr_fade_table+eax]        ; xlat pixel thru lighting tables
198         mov     [_fx_l], ebx    ; save temp copy of lighting value
199
200 ; transparency check
201 NoLight1:       cmp     al,255
202         je      skip1
203
204         mov     [edi],al
205 skip1:  inc     edi
206
207 ; update deltas
208         add     ebp,[_fx_dv_dx]
209         add     esi,[_fx_du_dx]
210         add     ecx,[_fx_dz_dx]
211         je      _div_0_abort    ; would be dividing by 0, so abort
212
213         dec     dword [_loop_count]
214         jns     tmap_loop0
215
216 _none_to_do:
217         popa
218 ;        pop     es
219         ret
220
221 ; We detected a z=0 condition, which seems pretty bogus, don't you think?
222 ; So, we abort, but maybe we want to know about it.
223 _div_0_abort:
224         jmp     _none_to_do
225
226 ;-------------------------- PER/4 TMAPPER ----------------
227 ;
228 ;       x = x1
229 ;       U0 = u/w; V0 = v/w;
230 ;       while ( 1 )
231 ;               u += du_dx*4; v+= dv_dx*4
232 ;               U1 = u/w; V1 = v/w;
233 ;               DUDX = (U1-U0)/4; DVDX = (V1-V0)/4;
234 ;
235 ;       ; Pixel 0
236 ;               pixels = texmap[V0*64+U0];
237 ;               U0 += DUDX; V0 += DVDX
238 ;       ; Pixel 1
239 ;               pixels = (pixels<<8)+texmap[V0*64+U0];
240 ;               U0 += DUDX; V0 += DVDX
241 ;       ; Pixel 2
242 ;               pixels = (pixels<<8)+texmap[V0*64+U0];
243 ;               U0 += DUDX; V0 += DVDX
244 ;       ; Pixel 3
245 ;               pixels = (pixels<<8)+texmap[V0*64+U0];
246 ;
247 ;               screen[x] = pixel
248 ;               x += 4;
249 ;               U0 = U1; V0 = V1
250
251 NBITS equ 4     ; 2^NBITS pixels plotted per divide
252 ZSHIFT equ 4    ; precision used in PDIV macro
253
254
255 ;PDIV MACRO
256 ; Returns EAX/ECX in 16.16 format in EAX. Trashes EDX
257 ;          sig bits   6.3
258 ;       mov     edx,eax
259 ;       shl     eax,ZSHIFT
260 ;       sar     edx,32-ZSHIFT
261 ;       idiv    ecx     ; eax = (v/z)
262 ;   shl eax, 16-ZSHIFT
263 ;ENDM
264
265 global _tmap_loop_fast
266
267 ; -------------------------------------- Start of Getting Dword Aligned ----------------------------------------------
268 ;       ebx     fx_u
269
270 _tmap_loop_fast:
271         mov     esi,ebx
272
273         align   4
274 NotDwordAligned1:
275         test    edi, 11b
276         jz      DwordAligned1
277
278 ; compute v coordinate
279         mov     eax, ebp        ; get v
280         mov     edx, eax
281         sar     edx, 31
282         idiv    ecx     ; eax = (v/z)
283
284         and     eax,3fh ; mask with height-1
285         mov     ebx,eax
286
287 ; compute u coordinate
288         mov     eax, esi        ; get u
289         mov     edx, eax
290         sar     edx, 31
291         idiv    ecx     ; eax = (u/z)
292
293         shl     eax,26
294         shld    ebx,eax,6       ; esi = v*64+u
295
296 ; read 1  pixel
297         add     ebx,[_pixptr]
298         xor     eax, eax
299         mov     al, [ebx]    ; get pixel from source bitmap
300
301 ; lighting code
302         mov     ebx, [_fx_l]    ; get temp copy of lighting value
303         mov     ah, bh  ; get lighting level
304         add     ebx, [_fx_dl_dx]        ; update lighting value
305         mov     [_fx_l], ebx    ; save temp copy of lighting value
306
307 ; transparency check
308         cmp     al,255
309         je      skip2   ; this pixel is transparent, so don't write it (or light it)
310
311         mov     al, [_gr_fade_table+eax]        ; xlat pixel thru lighting tables
312
313 ; write 1 pixel
314         mov     [edi],al
315 skip2:  inc     edi
316
317 ; update deltas
318         add     ebp,[_fx_dv_dx]
319         add     esi,[_fx_du_dx]
320         add     ecx,[_fx_dz_dx]
321         je      _div_0_abort    ; would be dividing by 0, so abort
322
323         dec     dword [_loop_count]
324         jns     NotDwordAligned1
325
326         jmp     _none_to_do
327
328 ; -------------------------------------- End of Getting Dword Aligned ----------------------------------------------
329
330 DwordAligned1:
331
332         mov     eax, [_loop_count]
333         mov     ebx, esi        ; get fx_u [pentium pipelining]
334         inc     eax
335         mov     esi, eax
336         and     esi, (1 << NBITS) - 1
337         sar     eax, NBITS
338         mov     [num_left_over], esi
339         je      near tmap_loop  ; there are no 2^NBITS chunks, do divide/pixel for whole scanline
340         mov     [_loop_count], eax      ; _loop_count = pixels / NPIXS
341
342 ; compute initial v coordinate
343         mov     eax,ebp ; get v
344         mov     edx,ebp
345         shl     eax,ZSHIFT
346         sar     edx,32-ZSHIFT
347         idiv    ecx     ; eax = (v/z)
348         shl     eax, 16-ZSHIFT
349         mov     [V0], eax
350
351 ; compute initial u coordinate
352         mov     eax,ebx ; get u
353         mov     edx,ebx
354         shl     eax,ZSHIFT
355         sar     edx,32-ZSHIFT
356         idiv    ecx     ; eax = (v/z)
357         shl     eax, 16-ZSHIFT
358         mov     [U0], eax
359
360 ; Set deltas to NPIXS pixel increments
361         mov     eax, [_fx_du_dx]
362         shl     eax, NBITS
363         mov     [DU1], eax
364         mov     eax, [_fx_dv_dx]
365         shl     eax, NBITS
366         mov     [DV1], eax
367         mov     eax, [_fx_dz_dx]
368         shl     eax, NBITS
369         mov     [DZ1], eax
370
371         align   4
372 TopOfLoop4:
373         add     ebx, [DU1]
374         add     ebp, [DV1]
375         add     ecx, [DZ1]
376         je      near _div_0_abort       ; would be dividing by 0, so abort
377
378 ; Done with ebx, ebp, ecx until next iteration
379         push    ebx
380         push    ecx
381         push    ebp
382         push    edi
383
384 ; Find fixed U1
385         mov     eax, ebx
386         mov     edx,ebx
387         shl     eax,ZSHIFT
388         sar     edx,32-ZSHIFT
389         idiv    ecx     ; eax = (v/z)
390         shl     eax, 16-ZSHIFT
391         mov     ebx, eax        ; ebx = U1 until pop's
392
393 ; Find fixed V1
394         mov     eax, ebp
395         mov     edx, ebp
396         shl     eax,ZSHIFT
397         sar     edx,32-ZSHIFT
398         idiv    ecx     ; eax = (v/z)
399
400         mov     ecx, [U0]       ; ecx = U0 until pop's
401         mov     edi, [V0]       ; edi = V0 until pop's
402
403         shl     eax, 16-ZSHIFT
404         mov     ebp, eax        ; ebp = V1 until pop's
405
406 ; Make ESI =  V0:U0 in 6:10,6:10 format
407         mov     eax, ecx
408         shr     eax, 6
409         mov     esi, edi
410         shl     esi, 10
411         mov     si, ax
412
413 ; Make EDX = DV:DU in 6:10,6:10 format
414         mov     eax, ebx
415         sub     eax, ecx
416         sar     eax, NBITS+6
417         mov     edx, ebp
418         sub     edx, edi
419         shl     edx, 10-NBITS   ; EDX = V1-V0/ 4 in 6:10 int:frac
420         mov     dx, ax  ; put delta u in low word
421
422 ; Save the U1 and V1 so we don't have to divide on the next iteration
423         mov     [U0], ebx
424         mov     [V0], ebp
425
426         pop     edi     ; Restore EDI before using it
427
428 ; LIGHTING CODE
429         mov     ebx, [_fx_l]
430         mov     ebp, [_fx_dl_dx]
431
432         test    dword [_Transparency_on],-1
433         je      near no_trans1
434
435 %macro repproc1 0
436         mov     eax, esi        ; get u,v
437         shr     eax, 26 ; shift out all but int(v)
438         shld    ax,si,6 ; shift in u, shifting up v
439         add     esi, edx        ; inc u,v
440         add     eax, [_pixptr]
441         movzx   eax, byte [eax]    ; get pixel from source bitmap
442         cmp     al,255
443         je      %%skipa1
444         mov     ah, bh  ; form lighting table lookup value
445         add     ebx, ebp        ; update lighting value
446         mov     al, [_gr_fade_table+eax]        ; xlat thru lighting table into dest buffer
447         mov     [edi],al
448 %%skipa1:
449         inc     edi
450
451 ; Do odd pixel
452         mov     eax, esi        ; get u,v
453         shr     eax, 26 ; shift out all but int(v)
454         shld    ax,si,6 ; shift in u, shifting up v
455         add     esi, edx        ; inc u,v
456         add     eax,[_pixptr]
457         movzx   eax, byte [eax]    ; get pixel from source bitmap
458         cmp     al,255
459         je      %%skipa2
460         mov     ah, bh  ; form lighting table lookup value
461         add     ebx, ebp        ; update lighting value
462         mov     al, [_gr_fade_table+eax]        ; xlat thru lighting table into dest buffer
463         mov     [edi],al
464 %%skipa2:
465         inc     edi
466 %endmacro
467
468
469 %rep (2 << (NBITS-2))
470 ;       local   skip3,no_trans1
471 ;       local   skipa1,skipa2
472     repproc1
473 %endrep
474
475 jmp     cont1
476
477 ; -------------------------------------------------------
478 no_trans1:
479
480 %macro repproc2 0
481         mov     eax, esi        ; get u,v
482         shr     eax, 26 ; shift out all but int(v)
483         shld    ax,si,6 ; shift in u, shifting up v
484         add     esi, edx        ; inc u,v
485         add     eax,[_pixptr]
486         movzx   eax, byte [eax]    ; get pixel from source bitmap
487         mov     ah, bh  ; form lighting table lookup value
488         add     ebx, ebp        ; update lighting value
489         mov     cl, [_gr_fade_table+eax]        ; xlat thru lighting table into dest buffer
490
491 ; Do odd pixel
492         mov     eax, esi        ; get u,v
493         shr     eax, 26 ; shift out all but int(v)
494         shld    ax,si,6 ; shift in u, shifting up v
495         add     esi, edx        ; inc u,v
496         add     eax,[_pixptr]
497         movzx   eax, byte [eax]    ; get pixel from source bitmap
498         mov     ah, bh  ; form lighting table lookup value
499         add     ebx, ebp        ; update lighting value
500         mov     ch, [_gr_fade_table+eax]        ; xlat thru lighting table into dest buffer
501
502 ; ----- This is about 1% faster than the above, and could probably be optimized more.
503 ; ----- Problem is, it gets the u,v coordinates backwards.  What you would need to do
504 ; ----- is switch the packing of the u,v coordinates above (about 95 lines up).
505 ;----------;    mov     eax, esi
506 ;----------;    shr     ax, 10
507 ;----------;    rol     eax, 6
508 ;----------;    mov     dx, ax
509 ;----------;    add     esi, mem_edx
510 ;----------;    mov     dl, es:[edx]
511 ;----------;    mov     dh, bh
512 ;----------;    add     ebx, ebp
513 ;----------;    mov     cl, _gr_fade_table[edx]
514 ;----------;
515 ;----------;    mov     eax, esi
516 ;----------;    shr     ax, 10
517 ;----------;    rol     eax, 6
518 ;----------;    mov     dx, ax
519 ;----------;    add     esi, mem_edx
520 ;----------;    mov     dl, es:[edx]
521 ;----------;    mov     dh, bh
522 ;----------;    add     ebx, ebp
523 ;----------;    mov     ch, _gr_fade_table[edx]
524
525         ror     ecx, 16 ; move to next double dest pixel position
526 %endmacro
527
528 %rep (1 << (NBITS-2))
529
530     repproc2
531     repproc2
532
533         mov     [edi],ecx       ; Draw 4 pixels to display
534         add     edi,4
535 %endrep
536 ;; pop edx
537 cont1:
538
539 ; -------------------------------------------------------
540
541 ; LIGHTING CODE
542         mov     [_fx_l], ebx
543         pop     ebp
544         pop     ecx
545         pop     ebx
546         dec     dword [_loop_count]
547         jnz     near TopOfLoop4
548
549 EndOfLoop4:
550         test    dword [num_left_over], -1
551         je      near _none_to_do
552
553 ; ----------------------------------------- Start of LeftOver Pixels ------------------------------------------
554 DoEndPixels:
555         push    ecx
556
557         mov     eax, ecx
558         lea     eax, [eax*2+eax]
559
560         add     ecx, [DZ1]
561         js      notokhere
562         shl     ecx,2
563         cmp     eax, ecx
564         pop     ecx
565         jl      okhere
566         jmp     bah_bah
567 notokhere:
568         pop     ecx
569 bah_bah:
570         test    dword [_new_end],-1
571         jne     near NewDoEndPixels
572 okhere:
573
574         add     ebx, [DU1]
575         add     ebp, [DV1]
576         add     ecx, [DZ1]
577         je      near _div_0_abort
578         jns     dep_cont
579
580 ; z went negative.
581 ; this can happen because we added DZ1 to the current z, but dz1 represents dz for perhaps 16 pixels
582 ; though we might only plot one more pixel.
583         mov     cl, 1
584
585 dep_loop:       mov     eax, [DU1]
586         sar     eax, cl
587         sub     ebx, eax
588
589         mov     eax, [DV1]
590         sar     eax, cl
591         sub     ebp, eax
592
593         mov     eax, [DZ1]
594         sar     eax, cl
595         sub     ecx, eax
596         je      near _div_0_abort
597         jns     dep_cont
598
599         inc     cl
600         cmp     cl, NBITS
601         jne     dep_loop
602
603 dep_cont:
604         push    edi     ; use edi as a temporary variable
605
606         cmp     ecx,1 << (ZSHIFT+1)
607         jg      ecx_ok
608         mov     ecx, 1 << (ZSHIFT+1)
609 ecx_ok:
610
611 ; Find fixed U1
612         mov     eax, ebx
613         ;PDIV
614         mov     edx,eax
615         shl     eax,ZSHIFT
616         sar     edx,32-ZSHIFT
617         idiv    ecx     ; eax = (v/z)
618         shl     eax, 16-ZSHIFT
619
620         mov     ebx, eax        ; ebx = U1 until pop's
621
622 ; Find fixed V1
623         mov     eax, ebp
624         ;PDIV
625         mov     edx,eax
626         shl     eax,ZSHIFT
627         sar     edx,32-ZSHIFT
628         idiv    ecx     ; eax = (v/z)
629         shl     eax, 16-ZSHIFT
630
631         mov     ebp, eax        ; ebp = V1 until pop's
632
633         mov     ecx, [U0]       ; ecx = U0 until pop's
634         mov     edi, [V0]       ; edi = V0 until pop's
635
636 ; Make ESI =  V0:U0 in 6:10,6:10 format
637         mov     eax, ecx
638         shr     eax, 6
639         mov     esi, edi
640         shl     esi, 10
641         mov     si, ax
642
643 ; Make EDX = DV:DU in 6:10,6:10 format
644         mov     eax, ebx
645         sub     eax, ecx
646         sar     eax, NBITS+6
647         mov     edx, ebp
648         sub     edx, edi
649         shl     edx, 10-NBITS   ; EDX = V1-V0/ 4 in 6:10 int:frac
650         mov     dx, ax  ; put delta u in low word
651
652         pop     edi     ; Restore EDI before using it
653
654         mov     ecx, [num_left_over]
655
656 ; LIGHTING CODE
657         mov     ebx, [_fx_l]
658         mov     ebp, [_fx_dl_dx]
659
660     ITERATION equ 0
661
662 %macro repproc3 0
663 ; Do even pixel
664         mov     eax, esi        ; get u,v
665         shr     eax, 26 ; shift out all but int(v)
666         shld    ax,si,6 ; shift in u, shifting up v
667         add     eax,[_pixptr]
668         movzx   eax, byte [eax]    ; get pixel from source bitmap
669         add     esi, edx        ; inc u,v
670         mov     ah, bh  ; form lighting table lookup value
671         add     ebx, ebp        ; update lighting value
672         cmp     al,255
673         je      %%skip4
674         mov     al, [_gr_fade_table+eax]        ; xlat thru lighting table into dest buffer
675         mov     [edi+ITERATION], al     ; write pixel
676 %%skip4:        dec     ecx
677         jz      near _none_to_do
678
679 ; Do odd pixel
680         mov     eax, esi        ; get u,v
681         shr     eax, 26 ; shift out all but int(v)
682         shld    ax,si,6 ; shift in u, shifting up v
683         add     eax,[_pixptr]
684         movzx   eax, byte [eax]    ; get pixel from source bitmap
685         add     esi, edx        ; inc u,v
686         mov     ah, bh  ; form lighting table lookup value
687         add     ebx, [_fx_dl_dx]        ; update lighting value
688         cmp     al,255
689         je      %%skip5
690         mov     al, [_gr_fade_table+eax]        ; xlat thru lighting table into dest buffer
691         mov     [edi+ITERATION+1], al   ; write pixel
692 %%skip5:        dec     ecx
693         jz      near _none_to_do
694 %endmacro
695
696 %rep (1 << (NBITS-1))
697         ;local  skip4, skip5
698     repproc3
699 %assign ITERATION  ITERATION + 2
700
701 %endrep
702
703 ; Should never get here!!!!
704         int     3
705         jmp     _none_to_do
706
707 ; ----------------------------------------- End of LeftOver Pixels ------------------------------------------
708
709 ; --BUGGY NEW--NewDoEndPixels:
710 ; --BUGGY NEW-- mov     eax, num_left_over
711 ; --BUGGY NEW-- and     num_left_over, 3
712 ; --BUGGY NEW-- shr     eax, 2
713 ; --BUGGY NEW-- je      NDEP_1
714 ; --BUGGY NEW-- mov     _loop_count, eax
715 ; --BUGGY NEW--
716 ; --BUGGY NEW--; do 4 pixels per hunk, not 16, so div deltas by 4 (16/4=4)
717 ; --BUGGY NEW-- shr DU1,2
718 ; --BUGGY NEW-- shr DV1,2
719 ; --BUGGY NEW-- shr DZ1,2
720 ; --BUGGY NEW--
721 ; --BUGGY NEW--NDEP_TopOfLoop4:
722 ; --BUGGY NEW-- add     ebx, DU1
723 ; --BUGGY NEW-- add     ebp, DV1
724 ; --BUGGY NEW-- add     ecx, DZ1
725 ; --BUGGY NEW-- je      _div_0_abort    ; would be dividing by 0, so abort
726 ; --BUGGY NEW--
727 ; --BUGGY NEW--; Done with ebx, ebp, ecx until next iteration
728 ; --BUGGY NEW-- push    ebx
729 ; --BUGGY NEW-- push    ecx
730 ; --BUGGY NEW-- push    ebp
731 ; --BUGGY NEW-- push    edi
732 ; --BUGGY NEW--
733 ; --BUGGY NEW--; Find fixed U1
734 ; --BUGGY NEW-- mov     eax, ebx
735 ; --BUGGY NEW-- mov     edx,ebx
736 ; --BUGGY NEW-- shl     eax,(ZSHIFT-2)
737 ; --BUGGY NEW-- sar     edx,32-(ZSHIFT-2)
738 ; --BUGGY NEW-- idiv    ecx     ; eax = (v/z)
739 ; --BUGGY NEW-- shl     eax, 16-(ZSHIFT-2)
740 ; --BUGGY NEW-- mov     ebx, eax        ; ebx = U1 until pop's
741 ; --BUGGY NEW--
742 ; --BUGGY NEW--; Find fixed V1
743 ; --BUGGY NEW-- mov     eax, ebp
744 ; --BUGGY NEW-- mov     edx, ebp
745 ; --BUGGY NEW-- shl     eax,(ZSHIFT-2)
746 ; --BUGGY NEW-- sar     edx,32-(ZSHIFT-2)
747 ; --BUGGY NEW-- idiv    ecx     ; eax = (v/z)
748 ; --BUGGY NEW--
749 ; --BUGGY NEW-- mov     ecx, U0 ; ecx = U0 until pop's
750 ; --BUGGY NEW-- mov     edi, V0 ; edi = V0 until pop's
751 ; --BUGGY NEW--
752 ; --BUGGY NEW-- shl     eax, 16-(ZSHIFT-2)
753 ; --BUGGY NEW-- mov     ebp, eax        ; ebp = V1 until pop's
754 ; --BUGGY NEW--
755 ; --BUGGY NEW--; Make ESI =  V0:U0 in 6:10,6:10 format
756 ; --BUGGY NEW-- mov     eax, ecx
757 ; --BUGGY NEW-- shr     eax, 6
758 ; --BUGGY NEW-- mov     esi, edi
759 ; --BUGGY NEW-- shl     esi, 10
760 ; --BUGGY NEW-- mov     si, ax
761 ; --BUGGY NEW--
762 ; --BUGGY NEW--; Make EDX = DV:DU in 6:10,6:10 format
763 ; --BUGGY NEW-- mov     eax, ebx
764 ; --BUGGY NEW-- sub     eax, ecx
765 ; --BUGGY NEW-- sar     eax, (NBITS-2)+6
766 ; --BUGGY NEW-- mov     edx, ebp
767 ; --BUGGY NEW-- sub     edx, edi
768 ; --BUGGY NEW-- shl     edx, 10-(NBITS-2)       ; EDX = V1-V0/ 4 in 6:10 int:frac
769 ; --BUGGY NEW-- mov     dx, ax  ; put delta u in low word
770 ; --BUGGY NEW--
771 ; --BUGGY NEW--; Save the U1 and V1 so we don't have to divide on the next iteration
772 ; --BUGGY NEW-- mov     U0, ebx
773 ; --BUGGY NEW-- mov     V0, ebp
774 ; --BUGGY NEW--
775 ; --BUGGY NEW-- pop     edi     ; Restore EDI before using it
776 ; --BUGGY NEW--
777 ; --BUGGY NEW--; LIGHTING CODE
778 ; --BUGGY NEW-- mov     ebx, _fx_l
779 ; --BUGGY NEW-- mov     ebp, _fx_dl_dx
780 ; --BUGGY NEW--
781 ; --BUGGY NEW--;**      test    _Transparency_on,-1
782 ; --BUGGY NEW--;**      je      NDEP_no_trans1
783 ; --BUGGY NEW--
784 ; --BUGGY NEW--        REPT 2
785 ; --BUGGY NEW-- local   NDEP_skipa1, NDEP_skipa2
786 ; --BUGGY NEW--
787 ; --BUGGY NEW-- mov     eax, esi        ; get u,v
788 ; --BUGGY NEW-- shr     eax, 26 ; shift out all but int(v)
789 ; --BUGGY NEW-- shld    ax,si,6 ; shift in u, shifting up v
790 ; --BUGGY NEW-- add     esi, edx        ; inc u,v
791 ; --BUGGY NEW-- mov     al, es:[eax]    ; get pixel from source bitmap
792 ; --BUGGY NEW-- cmp     al,255
793 ; --BUGGY NEW-- je      NDEP_skipa1
794 ; --BUGGY NEW-- mov     ah, bh  ; form lighting table lookup value
795 ; --BUGGY NEW-- add     ebx, ebp        ; update lighting value
796 ; --BUGGY NEW-- mov     al, _gr_fade_table[eax] ; xlat thru lighting table into dest buffer
797 ; --BUGGY NEW-- mov     [edi],al
798 ; --BUGGY NEW--NDEP_skipa1:
799 ; --BUGGY NEW-- inc     edi
800 ; --BUGGY NEW--
801 ; --BUGGY NEW--; Do odd pixel
802 ; --BUGGY NEW-- mov     eax, esi        ; get u,v
803 ; --BUGGY NEW-- shr     eax, 26 ; shift out all but int(v)
804 ; --BUGGY NEW-- shld    ax,si,6 ; shift in u, shifting up v
805 ; --BUGGY NEW-- add     esi, edx        ; inc u,v
806 ; --BUGGY NEW-- mov     al, es:[eax]    ; get pixel from source bitmap
807 ; --BUGGY NEW-- cmp     al,255
808 ; --BUGGY NEW-- je      NDEP_skipa2
809 ; --BUGGY NEW-- mov     ah, bh  ; form lighting table lookup value
810 ; --BUGGY NEW-- add     ebx, ebp        ; update lighting value
811 ; --BUGGY NEW-- mov     al, _gr_fade_table[eax] ; xlat thru lighting table into dest buffer
812 ; --BUGGY NEW-- mov     [edi],al
813 ; --BUGGY NEW--NDEP_skipa2:
814 ; --BUGGY NEW-- inc     edi
815 ; --BUGGY NEW--
816 ; --BUGGY NEW--        ENDM
817 ; --BUGGY NEW--
818 ; --BUGGY NEW-- mov     _fx_l, ebx
819 ; --BUGGY NEW-- pop     ebp
820 ; --BUGGY NEW-- pop     ecx
821 ; --BUGGY NEW-- pop     ebx
822 ; --BUGGY NEW-- dec     _loop_count
823 ; --BUGGY NEW-- jnz     NDEP_TopOfLoop4
824 ; --BUGGY NEW--
825 ; --BUGGY NEW-- test    num_left_over, -1
826 ; --BUGGY NEW-- je      _none_to_do
827 ; --BUGGY NEW--
828 ; --BUGGY NEW--NDEP_1:
829 ; --BUGGY NEW-- mov     esi,ebx
830 ; --BUGGY NEW--
831 ; --BUGGY NEW-- align   4
832 ; --BUGGY NEW--NDEP_loop:
833 ; --BUGGY NEW--
834 ; --BUGGY NEW--; compute v coordinate
835 ; --BUGGY NEW-- mov     eax, ebp        ; get v
836 ; --BUGGY NEW-- mov     edx, eax
837 ; --BUGGY NEW-- sar     edx, 31
838 ; --BUGGY NEW-- idiv    ecx     ; eax = (v/z)
839 ; --BUGGY NEW--
840 ; --BUGGY NEW-- and     eax,3fh ; mask with height-1
841 ; --BUGGY NEW-- mov     ebx,eax
842 ; --BUGGY NEW--
843 ; --BUGGY NEW--; compute u coordinate
844 ; --BUGGY NEW-- mov     eax,    esi     ; get u
845 ; --BUGGY NEW-- mov     edx, eax
846 ; --BUGGY NEW-- sar     edx, 31
847 ; --BUGGY NEW-- idiv    ecx     ; eax = (u/z)
848 ; --BUGGY NEW--
849 ; --BUGGY NEW-- shl     eax,26
850 ; --BUGGY NEW-- shld    ebx,eax,6       ; esi = v*64+u
851 ; --BUGGY NEW--
852 ; --BUGGY NEW--; read 1  pixel
853 ; --BUGGY NEW-- xor     eax, eax
854 ; --BUGGY NEW-- mov     al, es:[ebx]    ; get pixel from source bitmap
855 ; --BUGGY NEW--
856 ; --BUGGY NEW--; lighting code
857 ; --BUGGY NEW-- mov     ebx, _fx_l      ; get temp copy of lighting value
858 ; --BUGGY NEW-- mov     ah, bh  ; get lighting level
859 ; --BUGGY NEW-- add     ebx, _fx_dl_dx  ; update lighting value
860 ; --BUGGY NEW-- mov     _fx_l, ebx      ; save temp copy of lighting value
861 ; --BUGGY NEW--
862 ; --BUGGY NEW--; transparency check
863 ; --BUGGY NEW-- cmp     al,255
864 ; --BUGGY NEW-- je      NDEP_skip2      ; this pixel is transparent, so don't write it (or light it)
865 ; --BUGGY NEW--
866 ; --BUGGY NEW-- mov     al, _gr_fade_table[eax] ; xlat pixel thru lighting tables
867 ; --BUGGY NEW--
868 ; --BUGGY NEW--; write 1 pixel
869 ; --BUGGY NEW-- mov     [edi],al
870 ; --BUGGY NEW--NDEP_skip2:      inc     edi
871 ; --BUGGY NEW--
872 ; --BUGGY NEW--; update deltas
873 ; --BUGGY NEW-- add     ebp,_fx_dv_dx
874 ; --BUGGY NEW-- add     esi,_fx_du_dx
875 ; --BUGGY NEW-- add     ecx,_fx_dz_dx
876 ; --BUGGY NEW-- je      _div_0_abort    ; would be dividing by 0, so abort
877 ; --BUGGY NEW--
878 ; --BUGGY NEW-- dec     num_left_over
879 ; --BUGGY NEW-- jne     NDEP_loop
880 ; --BUGGY NEW--
881 ; --BUGGY NEW-- jmp     _none_to_do
882
883 NewDoEndPixels:
884         mov     esi,ebx
885
886         align   4
887 NDEP_loop:
888
889 ; compute v coordinate
890         mov     eax, ebp        ; get v
891         mov     edx, eax
892         sar     edx, 31
893         idiv    ecx     ; eax = (v/z)
894
895         and     eax,3fh ; mask with height-1
896         mov     ebx,eax
897
898 ; compute u coordinate
899         mov     eax,    esi     ; get u
900         mov     edx, eax
901         sar     edx, 31
902         idiv    ecx     ; eax = (u/z)
903
904         shl     eax,26
905         shld    ebx,eax,6       ; esi = v*64+u
906
907 ; read 1  pixel
908         add     ebx,[_pixptr]
909         xor     eax, eax
910         mov     al, [ebx]    ; get pixel from source bitmap
911
912 ; lighting code
913         mov     ebx, [_fx_l]    ; get temp copy of lighting value
914         mov     ah, bh  ; get lighting level
915         add     ebx, [_fx_dl_dx]        ; update lighting value
916         mov     [_fx_l], ebx    ; save temp copy of lighting value
917
918 ; transparency check
919         cmp     al,255
920         je      NDEP_skip2      ; this pixel is transparent, so don't write it (or light it)
921
922         mov     al, [_gr_fade_table+eax]        ; xlat pixel thru lighting tables
923
924 ; write 1 pixel
925         mov     [edi],al
926 NDEP_skip2:     inc     edi
927
928 ; update deltas
929         add     ebp,[_fx_dv_dx]
930         add     esi,[_fx_du_dx]
931         add     ecx,[_fx_dz_dx]
932         je      near _div_0_abort    ; would be dividing by 0, so abort
933
934         dec     dword [num_left_over]
935         jne     NDEP_loop
936
937         jmp     _none_to_do
938
939 ; ==================================================== No Lighting Code ======================================================
940 global _tmap_loop_fast_nolight
941 _tmap_loop_fast_nolight:
942         mov     esi,ebx
943
944         align   4
945 NotDwordAligned1_nolight:
946         test    edi, 11b
947         jz      DwordAligned1_nolight
948
949 ; compute v coordinate
950         mov     eax,ebp ; get v
951         mov     edx, eax
952         sar     edx, 31
953         idiv    ecx     ; eax = (v/z)
954
955         and     eax,3fh ; mask with height-1
956         mov     ebx,eax
957
958 ; compute u coordinate
959         mov     eax, esi        ; get u
960         mov     edx, eax
961         sar     edx, 31
962         idiv    ecx     ; eax = (u/z)
963
964         shl     eax,26
965         shld    ebx,eax,6       ; esi = v*64+u
966
967 ; read 1  pixel
968         add     ebx,[_pixptr]
969         mov     al,[ebx]     ; get pixel from source bitmap
970
971 ; write 1 pixel
972         cmp     al,255
973         je      skip6
974         mov     [edi],al
975 skip6:  inc     edi
976
977 ; update deltas
978         add     ebp,[_fx_dv_dx]
979         add     esi,[_fx_du_dx]
980         add     ecx,[_fx_dz_dx]
981         je      near _div_0_abort    ; would be dividing by 0, so abort
982
983         dec     dword [_loop_count]
984         jns     NotDwordAligned1_nolight
985         jmp     _none_to_do
986
987 DwordAligned1_nolight:
988         mov     ebx,esi
989
990         mov     eax, [_loop_count]
991         inc     eax
992         mov     [num_left_over], eax
993         shr     eax, NBITS
994
995         test    eax, -1
996         je      near tmap_loop       ; no 2^NBITS chunks, do divide/pixel for whole scanline
997
998         mov     [_loop_count], eax      ; _loop_count = pixels / NPIXS
999         shl     eax, NBITS
1000         sub     [num_left_over], eax    ; num_left_over = obvious
1001
1002 ; compute initial v coordinate
1003         mov     eax,ebp ; get v
1004         ;PDIV
1005         mov     edx,eax
1006         shl     eax,ZSHIFT
1007         sar     edx,32-ZSHIFT
1008         idiv    ecx     ; eax = (v/z)
1009         shl     eax, 16-ZSHIFT
1010
1011         mov     [V0], eax
1012
1013 ; compute initial u coordinate
1014         mov     eax,ebx ; get u
1015         ;PDIV
1016         mov     edx,eax
1017         shl     eax,ZSHIFT
1018         sar     edx,32-ZSHIFT
1019         idiv    ecx     ; eax = (v/z)
1020         shl     eax, 16-ZSHIFT
1021
1022         mov     [U0], eax
1023
1024 ; Set deltas to NPIXS pixel increments
1025         mov     eax, [_fx_du_dx]
1026         shl     eax, NBITS
1027         mov     [DU1], eax
1028         mov     eax, [_fx_dv_dx]
1029         shl     eax, NBITS
1030         mov     [DV1], eax
1031         mov     eax, [_fx_dz_dx]
1032         shl     eax, NBITS
1033         mov     [DZ1], eax
1034
1035         align   4
1036 TopOfLoop4_nolight:
1037         add     ebx, [DU1]
1038         add     ebp, [DV1]
1039         add     ecx, [DZ1]
1040         je      near _div_0_abort
1041
1042 ; Done with ebx, ebp, ecx until next iteration
1043         push    ebx
1044         push    ecx
1045         push    ebp
1046         push    edi
1047
1048 ; Find fixed U1
1049         mov     eax, ebx
1050         ;PDIV
1051         mov     edx,eax
1052         shl     eax,ZSHIFT
1053         sar     edx,32-ZSHIFT
1054         idiv    ecx     ; eax = (v/z)
1055         shl     eax, 16-ZSHIFT
1056
1057         mov     ebx, eax        ; ebx = U1 until pop's
1058
1059 ; Find fixed V1
1060         mov     eax, ebp
1061         ;PDIV
1062         mov     edx,eax
1063         shl     eax,ZSHIFT
1064         sar     edx,32-ZSHIFT
1065         idiv    ecx     ; eax = (v/z)
1066         shl     eax, 16-ZSHIFT
1067
1068         mov     ebp, eax        ; ebp = V1 until pop's
1069
1070         mov     ecx, [U0]       ; ecx = U0 until pop's
1071         mov     edi, [V0]       ; edi = V0 until pop's
1072
1073 ; Make ESI =  V0:U0 in 6:10,6:10 format
1074         mov     eax, ecx
1075         shr     eax, 6
1076         mov     esi, edi
1077         shl     esi, 10
1078         mov     si, ax
1079
1080 ; Make EDX = DV:DU in 6:10,6:10 format
1081         mov     eax, ebx
1082         sub     eax, ecx
1083         sar     eax, NBITS+6
1084         mov     edx, ebp
1085         sub     edx, edi
1086         shl     edx, 10-NBITS   ; EDX = V1-V0/ 4 in 6:10 int:frac
1087         mov     dx, ax  ; put delta u in low word
1088
1089 ; Save the U1 and V1 so we don't have to divide on the next iteration
1090         mov     [U0], ebx
1091         mov     [V0], ebp
1092
1093         pop     edi     ; Restore EDI before using it
1094
1095 %macro repproc4 0
1096 ; Do 1 pixel
1097         mov     eax, esi        ; get u,v
1098         shr     eax, 26 ; shift out all but int(v)
1099         shld    ax,si,6 ; shift in u, shifting up v
1100         add     esi, edx        ; inc u,v
1101         add     eax,[_pixptr]
1102         mov     cl, [eax]    ; load into buffer register
1103
1104         mov     eax, esi        ; get u,v
1105         shr     eax, 26 ; shift out all but int(v)
1106         shld    ax,si,6 ; shift in u, shifting up v
1107         add     eax,[_pixptr]
1108         mov     ch, [eax]    ; load into buffer register
1109         add     esi, edx        ; inc u,v
1110         ror     ecx, 16 ; move to next dest pixel
1111
1112         mov     eax, esi        ; get u,v
1113         shr     eax, 26 ; shift out all but int(v)
1114         shld    ax,si,6 ; shift in u, shifting up v
1115         add     eax,[_pixptr]
1116         mov     cl, [eax]    ; load into buffer register
1117         add     esi, edx        ; inc u,v
1118
1119         mov     eax, esi        ; get u,v
1120         shr     eax, 26 ; shift out all but int(v)
1121         shld    ax,si,6 ; shift in u, shifting up v
1122         add     eax,[_pixptr]
1123         mov     ch, [eax]    ; load into buffer register
1124         add     esi, edx        ; inc u,v
1125         ror     ecx, 16 ;-- can get rid of this, just write in different order below --         ; move to next dest pixel
1126
1127         test    dword [_Transparency_on],-1
1128         je      %%no_trans2
1129         cmp     ecx,-1
1130         je      %%skip7
1131
1132         cmp     cl,255
1133         je      %%skip1q
1134         mov     [edi],cl
1135 %%skip1q:
1136
1137         cmp     ch,255
1138         je      %%skip2q
1139         mov     [edi+1],ch
1140 %%skip2q:
1141         ror     ecx,16
1142
1143         cmp     cl,255
1144         je      %%skip3q
1145         mov     [edi+2],cl
1146 %%skip3q:
1147
1148
1149         cmp     ch,255
1150         je      %%skip4q
1151         mov     [edi+3],ch
1152 %%skip4q:
1153
1154         jmp     %%skip7
1155 %%no_trans2:
1156         mov     [edi],ecx       ; Draw 4 pixels to display
1157 %%skip7:        add     edi,4
1158 %endmacro
1159
1160 %rep (1 << (NBITS-2))
1161         ;local  skip7, no_trans2, skip1q, skip2q, skip3q, skip4q
1162     repproc4
1163
1164 %endrep
1165
1166         pop     ebp
1167         pop     ecx
1168         pop     ebx
1169         dec     dword [_loop_count]
1170         jnz     near TopOfLoop4_nolight
1171
1172 EndOfLoop4_nolight:
1173
1174         test    dword [num_left_over], -1
1175         je      near _none_to_do
1176
1177 DoEndPixels_nolight:
1178         add     ebx, [DU1]
1179         add     ebp, [DV1]
1180         add     ecx, [DZ1]
1181         je      near _div_0_abort
1182         push    edi     ; use edi as a temporary variable
1183
1184 ; Find fixed U1
1185         mov     eax, ebx
1186         mov     edx,eax
1187         shl     eax,ZSHIFT
1188         sar     edx,32-ZSHIFT
1189         idiv    ecx     ; eax = (v/z)
1190         shl     eax, 16-ZSHIFT
1191         mov     ebx, eax        ; ebx = U1 until pop's
1192
1193 ; Find fixed V1
1194         mov     eax, ebp
1195         mov     edx,eax
1196         shl     eax,ZSHIFT
1197         sar     edx,32-ZSHIFT
1198         idiv    ecx     ; eax = (v/z)
1199         shl     eax, 16-ZSHIFT
1200         mov     ebp, eax        ; ebp = V1 until pop's
1201
1202         mov     ecx, [U0]       ; ecx = U0 until pop's
1203         mov     edi, [V0]       ; edi = V0 until pop's
1204
1205 ; Make ESI =  V0:U0 in 6:10,6:10 format
1206         mov     eax, ecx
1207         shr     eax, 6
1208         mov     esi, edi
1209         shl     esi, 10
1210         mov     si, ax
1211
1212 ; Make EDX = DV:DU in 6:10,6:10 format
1213         mov     eax, ebx
1214         sub     eax, ecx
1215         sar     eax, NBITS+6
1216         mov     edx, ebp
1217         sub     edx, edi
1218         shl     edx, 10-NBITS   ; EDX = V1-V0/ 4 in 6:10 int:frac
1219         mov     dx, ax  ; put delta u in low word
1220
1221         pop     edi     ; Restore EDI before using it
1222
1223         mov     ecx, [num_left_over]
1224
1225 %assign ITERATION 0
1226 %macro repproc5 0
1227 ; Do 1 pixel
1228         mov     eax, esi        ; get u,v
1229         shr     eax, 26 ; shift out all but int(v)
1230         shld    ax,si,6 ; shift in u, shifting up v
1231         add     eax,[_pixptr]
1232         movzx   eax, byte [eax]    ; load into buffer register
1233         add     esi, edx        ; inc u,v
1234         cmp     al,255
1235         je      %%skip8
1236         mov     [edi+ITERATION], al     ; write pixel
1237 %%skip8:        dec     ecx
1238         jz      near _none_to_do
1239 %endmacro
1240
1241 %rep (1 << NBITS)
1242         ;local  skip8
1243         repproc5
1244 %assign ITERATION  ITERATION + 1
1245 %endrep
1246
1247 ; Should never get here!!!!!
1248         int     3
1249         jmp     _none_to_do
1250