2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Graphics/TmapScanTiled16x16.cpp $
15 * Routines for drawing tiled 16x16 textues
18 * Revision 1.3 2002/06/09 04:41:18 relnev
19 * added copyright header
21 * Revision 1.2 2002/05/07 03:16:45 theoddone33
22 * The Great Newline Fix
24 * Revision 1.1.1.1 2002/05/03 03:28:09 root
28 * 4 11/30/98 5:31p Dave
29 * Fixed up Fred support for software mode.
31 * 3 11/30/98 1:07p Dave
32 * 16 bit conversion, first run.
34 * 2 10/07/98 10:53a Dave
37 * 1 10/07/98 10:49a Dave
39 * 6 4/23/98 9:55a John
40 * Fixed some bugs in the tiled tmapper causing bright dots to appear all
43 * 5 3/10/98 4:19p John
44 * Cleaned up graphics lib. Took out most unused gr functions. Made D3D
45 * & Glide have popups and print screen. Took out all >8bpp software
46 * support. Made Fred zbuffer. Made zbuffer allocate dynamically to
47 * support Fred. Made zbuffering key off of functions rather than one
50 * 4 1/23/98 5:08p John
51 * Took L out of vertex structure used B (blue) instead. Took all small
52 * fireballs out of fireball types and used particles instead. Fixed some
53 * debris explosion things. Restructured fireball code. Restructured
54 * some lighting code. Made dynamic lighting on by default. Made groups
55 * of lasers only cast one light. Made fireballs not cast light.
57 * 3 12/04/97 10:38a John
58 * Fixed tiled texture mappers that were swapping uvs.
60 * 2 10/14/97 9:19a John
61 * removed fdiv warnings.
63 * 1 6/18/97 4:02p John
64 * added new code for 16x16 and 32x32 tiled tmaps.
72 #include "grinternal.h"
74 #include "tmapscanline.h"
79 // Needed to keep warning 4725 to stay away. See PsTypes.h for details why.
80 void disable_warning_4725_stub_tst16()
84 void tmapscan_pln8_zbuffered_tiled_16x16()
86 Tmap.fx_l = fl2f(Tmap.l.b*32.0);
87 Tmap.fx_l_right = fl2f(Tmap.r.b*32.0);
88 Tmap.fx_dl_dx = fl2f(Tmap.deltas.b*32.0);
90 if ( Tmap.fx_dl_dx < 0 ) {
91 Tmap.fx_dl_dx = -Tmap.fx_dl_dx;
92 Tmap.fx_l = (67*F1_0)-Tmap.fx_l;
93 Tmap.fx_l_right = (67*F1_0)-Tmap.fx_l_right;
94 // Assert( Tmap.fx_l > 31*F1_0 );
95 // Assert( Tmap.fx_l < 66*F1_0 );
96 // Assert( Tmap.fx_dl_dx >= 0 );
97 // Assert( Tmap.fx_dl_dx < 31*F1_0 );
100 Tmap.fl_dudx_wide = Tmap.deltas.u*32.0f;
101 Tmap.fl_dvdx_wide = Tmap.deltas.v*32.0f;
102 Tmap.fl_dwdx_wide = Tmap.deltas.sw*32.0f;
104 Tmap.fx_w = fl2i(Tmap.l.sw * GR_Z_RANGE)+gr_zoffset;
105 Tmap.fx_dwdx = fl2i(Tmap.deltas.sw * GR_Z_RANGE);
107 // Assert(Tmap.fx_w < 65536 );
108 // Assert(Tmap.fx_w >= 0 );
109 // Assert(Tmap.fx_w+Tmap.fx_dwdx*Tmap.loop_count < 65536 );
110 // Assert(Tmap.fx_w+Tmap.fx_dwdx*Tmap.loop_count >= 0 );
125 // Put the FPU in low precision mode
126 fstcw Tmap.OldFPUCW // store copy of CW
127 mov ax,Tmap.OldFPUCW // get it in ax
129 mov Tmap.FPUCW,ax // store it
130 fldcw Tmap.FPUCW // load the FPU
133 mov ecx, Tmap.loop_count // ecx = width
134 mov edi, Tmap.dest_row_data // edi = dest pointer
136 // edi = pointer to start pixel in dest dib
139 mov eax,ecx // eax and ecx = width
140 shr ecx,5 // ecx = width / subdivision length
141 and eax,31 // eax = width mod subdivision length
142 jnz some_left_over // any leftover?
143 dec ecx // no, so special case last span
144 mov eax,32 // it's 8 pixels long
146 mov Tmap.Subdivisions,ecx // store widths
147 mov Tmap.WidthModLength,eax
149 // calculate ULeft and VLeft // FPU Stack (ZL = ZLeft)
150 // st0 st1 st2 st3 st4 st5 st6 st7
152 fld Tmap.l.u // U/ZL V/ZL
153 fld Tmap.l.sw // 1/ZL U/ZL V/ZL
154 fld1 // 1 1/ZL U/ZL V/ZL
155 fdiv st,st(1) // ZL 1/ZL U/ZL V/ZL
156 fld st // ZL ZL 1/ZL U/ZL V/ZL
157 fmul st,st(4) // VL ZL 1/ZL U/ZL V/ZL
158 fxch st(1) // ZL VL 1/ZL U/ZL V/ZL
159 fmul st,st(3) // UL VL 1/ZL U/ZL V/ZL
161 fstp st(5) // VL 1/ZL U/ZL V/ZL UL
162 fstp st(5) // 1/ZL U/ZL V/ZL UL VL
164 // calculate right side OverZ terms ; st0 st1 st2 st3 st4 st5 st6 st7
166 fadd Tmap.fl_dwdx_wide // 1/ZR U/ZL V/ZL UL VL
167 fxch st(1) // U/ZL 1/ZR V/ZL UL VL
168 fadd Tmap.fl_dudx_wide // U/ZR 1/ZR V/ZL UL VL
169 fxch st(2) // V/ZL 1/ZR U/ZR UL VL
170 fadd Tmap.fl_dvdx_wide // V/ZR 1/ZR U/ZR UL VL
172 // calculate right side coords // st0 st1 st2 st3 st4 st5 st6 st7
174 fld1 // 1 V/ZR 1/ZR U/ZR UL VL
175 // @todo overlap this guy
176 fdiv st,st(2) // ZR V/ZR 1/ZR U/ZR UL VL
177 fld st // ZR ZR V/ZR 1/ZR U/ZR UL VL
178 fmul st,st(2) // VR ZR V/ZR 1/ZR U/ZR UL VL
179 fxch st(1) // ZR VR V/ZR 1/ZR U/ZR UL VL
180 fmul st,st(4) // UR VR V/ZR 1/ZR U/ZR UL VL
182 cmp ecx,0 // check for any full spans
183 jle HandleLeftoverPixels
187 // at this point the FPU contains // st0 st1 st2 st3 st4 st5 st6 st7
188 // UR VR V/ZR 1/ZR U/ZR UL VL
190 // convert left side coords
192 fld st(5) ; UL UR VR V/ZR 1/ZR U/ZR UL VL
193 fmul Tmap.FixedScale ; UL16 UR VR V/ZR 1/ZR U/ZR UL VL
194 fistp Tmap.UFixed ; UR VR V/ZR 1/ZR U/ZR UL VL
196 fld st(6) ; VL UR VR V/ZR 1/ZR U/ZR UL VL
197 fmul Tmap.FixedScale ; VL16 UR VR V/ZR 1/ZR U/ZR UL VL
198 fistp Tmap.VFixed ; UR VR V/ZR 1/ZR U/ZR UL VL
200 // calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7
202 fsubr st(5),st ; UR VR V/ZR 1/ZR U/ZR dU VL
203 fxch st(1) ; VR UR V/ZR 1/ZR U/ZR dU VL
204 fsubr st(6),st ; VR UR V/ZR 1/ZR U/ZR dU dV
205 fxch st(6) ; dV UR V/ZR 1/ZR U/ZR dU VR
207 fmul Tmap.FixedScale8 ; dV8 UR V/ZR 1/ZR U/ZR dU VR
208 fistp Tmap.DeltaV ; UR V/ZR 1/ZR U/ZR dU VR
210 fxch st(4) ; dU V/ZR 1/ZR U/ZR UR VR
211 fmul Tmap.FixedScale8 ; dU8 V/ZR 1/ZR U/ZR UR VR
212 fistp Tmap.DeltaU ; V/ZR 1/ZR U/ZR UR VR
214 // increment terms for next span // st0 st1 st2 st3 st4 st5 st6 st7
215 // Right terms become Left terms--->// V/ZL 1/ZL U/ZL UL VL
217 fadd Tmap.fl_dvdx_wide // V/ZR 1/ZL U/ZL UL VL
218 fxch st(1) // 1/ZL V/ZR U/ZL UL VL
219 fadd Tmap.fl_dwdx_wide // 1/ZR V/ZR U/ZL UL VL
220 fxch st(2) // U/ZL V/ZR 1/ZR UL VL
221 fadd Tmap.fl_dudx_wide // U/ZR V/ZR 1/ZR UL VL
222 fxch st(2) // 1/ZR V/ZR U/ZR UL VL
223 fxch st(1) // V/ZR 1/ZR U/ZR UL VL
226 // setup delta values
228 mov eax,Tmap.DeltaV // get v 16.16 step
229 mov ebx,eax // copy it
230 sar eax,16 // get v int step
231 shl ebx,16 // get v frac step
232 mov Tmap.DeltaVFrac,ebx // store it
233 imul eax,Tmap.src_offset // calculate texture step for v int step
235 mov ebx,Tmap.DeltaU // get u 16.16 step
236 mov ecx,ebx // copy it
237 sar ebx,16 // get u int step
238 shl ecx,16 // get u frac step
239 mov Tmap.DeltaUFrac,ecx // store it
240 add eax,ebx // calculate uint + vint step
241 mov Tmap.uv_delta[4],eax // save whole step in non-v-carry slot
242 add eax,Tmap.src_offset // calculate whole step + v carry
243 mov Tmap.uv_delta[0],eax // save in v-carry slot
245 // setup initial coordinates
246 mov esi,Tmap.UFixed // get u 16.16 fixedpoint coordinate
248 mov ebx,esi // copy it
249 sar esi,16 // get integer part
250 shl ebx,16 // get fractional part
252 mov ecx,Tmap.VFixed // get v 16.16 fixedpoint coordinate
254 mov edx,ecx // copy it
255 sar edx,16 // get integer part
256 shl ecx,16 // get fractional part
257 imul edx,Tmap.src_offset // calc texture scanline address
258 add esi,edx // calc texture offset
259 add esi,Tmap.pixptr // calc address
261 // set up affine registers
267 mov ebp, Tmap.fx_dl_dx
278 // calculate right side coords st0 st1 st2 st3 st4 st5 st6 st7
279 fld1 // 1 V/ZR 1/ZR U/ZR UL VL
280 // This divide should happen while the pixel span is drawn.
281 fdiv st,st(2) // ZR V/ZR 1/ZR U/ZR UL VL
285 // edi = dest dib bits at current pixel
286 // esi = texture pointer at current u,v
288 // ebx = u fraction 0.32
289 // ecx = v fraction 0.32
291 // ebp = v carry scratch
293 mov al,[edi] // preread the destination cache line
295 mov Tmap.InnerLooper, 32/4 // Set up loop counter
300 sub eax, Tmap.pScreenBits
304 // Make ESI = DV:DU in 5:11,5:11 format
310 mov Tmap.DeltaUFrac, esi
312 // Make ECX = V:U in 5:11,5:11 format
323 // ecx = V:U in 8.6:10.8
324 // edx = zbuffer pointer
333 cmp esi, [edx+0] // Compare the Z depth of this pixel with zbuffer
334 jle Skip0 // If pixel is covered, skip drawing
336 mov [edx+0], esi // Write z
338 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
339 shr ax, 12 // EAX = V:U in 6.10:16.0
340 rol eax, 4 // EAX = V:U in 0.0:6:6
341 and eax, 0ffh // clear upper bits
342 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
346 and eax, 0ffffh // clear upper bits
347 mov al, gr_fade_table[eax]
350 add ecx, Tmap.DeltaUFrac
351 add esi, Tmap.fx_dwdx
355 cmp esi, [edx+4] // Compare the Z depth of this pixel with zbuffer
356 jle Skip1 // If pixel is covered, skip drawing
358 mov [edx+4], esi // Write z
360 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
361 shr ax, 12 // EAX = V:U in 6.10:16.0
362 rol eax, 4 // EAX = V:U in 0.0:6:6
363 and eax, 0ffh // clear upper bits
364 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
368 and eax, 0ffffh // clear upper bits
369 mov al, gr_fade_table[eax]
372 add ecx, Tmap.DeltaUFrac
373 add esi, Tmap.fx_dwdx
377 cmp esi, [edx+8] // Compare the Z depth of this pixel with zbuffer
378 jle Skip2 // If pixel is covered, skip drawing
380 mov [edx+8], esi // Write z
382 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
383 shr ax, 12 // EAX = V:U in 6.10:16.0
384 rol eax, 4 // EAX = V:U in 0.0:6:6
385 and eax, 0ffh // clear upper bits
386 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
390 and eax, 0ffffh // clear upper bits
391 mov al, gr_fade_table[eax]
394 add ecx, Tmap.DeltaUFrac
395 add esi, Tmap.fx_dwdx
399 cmp esi, [edx+12] // Compare the Z depth of this pixel with zbuffer
400 jle Skip3 // If pixel is covered, skip drawing
402 mov [edx+12], esi // Write z
404 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
405 shr ax, 12 // EAX = V:U in 6.10:16.0
406 rol eax, 4 // EAX = V:U in 0.0:6:6
407 and eax, 0ffh // clear upper bits
408 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
412 and eax, 0ffffh // clear upper bits
413 mov al, gr_fade_table[eax]
416 add ecx, Tmap.DeltaUFrac
417 add esi, Tmap.fx_dwdx
428 // the fdiv is done, finish right // st0 st1 st2 st3 st4 st5 st6 st7
429 // ZR V/ZR 1/ZR U/ZR UL VL
431 fld st // ZR ZR V/ZR 1/ZR U/ZR UL VL
432 fmul st,st(2) // VR ZR V/ZR 1/ZR U/ZR UL VL
433 fxch st(1) // ZR VR V/ZR 1/ZR U/ZR UL VL
434 fmul st,st(4) // UR VR V/ZR 1/ZR U/ZR UL VL
436 dec Tmap.Subdivisions // decrement span count
437 jnz SpanLoop // loop back
440 HandleLeftoverPixels:
442 mov esi,Tmap.pixptr // load texture pointer
444 // edi = dest dib bits
445 // esi = current texture dib bits
446 // at this point the FPU contains ; st0 st1 st2 st3 st4 st5 st6 st7
447 // inv. means invalid numbers ; inv. inv. inv. inv. inv. UL VL
449 cmp Tmap.WidthModLength,0 ; are there remaining pixels to draw?
450 jz FPUReturn ; nope, pop the FPU and bail
452 // convert left side coords ; st0 st1 st2 st3 st4 st5 st6 st7
454 fld st(5) ; UL inv. inv. inv. inv. inv. UL VL
455 fmul Tmap.FixedScale ; UL16 inv. inv. inv. inv. inv. UL VL
456 fistp Tmap.UFixed ; inv. inv. inv. inv. inv. UL VL
458 fld st(6) ; VL inv. inv. inv. inv. inv. UL VL
459 fmul Tmap.FixedScale // VL16 inv. inv. inv. inv. inv. UL VL
460 fistp Tmap.VFixed ; inv. inv. inv. inv. inv. UL VL
462 dec Tmap.WidthModLength ; calc how many steps to take
463 jz OnePixelSpan ; just one, don't do deltas'
465 // calculate right edge coordinates ; st0 st1 st2 st3 st4 st5 st6 st7
468 // @todo rearrange things so we don't need these two instructions
469 fstp Tmap.FloatTemp ; inv. inv. inv. inv. UL VL
470 fstp Tmap.FloatTemp ; inv. inv. inv. UL VL
472 fld Tmap.r.v ; V/Zr inv. inv. inv. UL VL
473 fsub Tmap.deltas.v ; V/ZR inv. inv. inv. UL VL
474 fld Tmap.r.u ; U/Zr V/ZR inv. inv. inv. UL VL
475 fsub Tmap.deltas.u ; U/ZR V/ZR inv. inv. inv. UL VL
476 fld Tmap.r.sw ; 1/Zr U/ZR V/ZR inv. inv. inv. UL VL
477 fsub Tmap.deltas.sw ; 1/ZR U/ZR V/ZR inv. inv. inv. UL VL
479 fdivr Tmap.One ; ZR U/ZR V/ZR inv. inv. inv. UL VL
481 fmul st(1),st ; ZR UR V/ZR inv. inv. inv. UL VL
482 fmulp st(2),st ; UR VR inv. inv. inv. UL VL
484 // calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7
486 fsubr st(5),st ; UR VR inv. inv. inv. dU VL
487 fxch st(1) ; VR UR inv. inv. inv. dU VL
488 fsubr st(6),st ; VR UR inv. inv. inv. dU dV
489 fxch st(6) ; dV UR inv. inv. inv. dU VR
491 fidiv Tmap.WidthModLength ; dv UR inv. inv. inv. dU VR
492 fmul Tmap.FixedScale ; dv16 UR inv. inv. inv. dU VR
493 fistp Tmap.DeltaV ; UR inv. inv. inv. dU VR
495 fxch st(4) ; dU inv. inv. inv. UR VR
496 fidiv Tmap.WidthModLength ; du inv. inv. inv. UR VR
497 fmul Tmap.FixedScale ; du16 inv. inv. inv. UR VR
498 fistp Tmap.DeltaU ; inv. inv. inv. UR VR
500 // @todo gross! these are to line up with the other loop
501 fld st(1) ; inv. inv. inv. inv. UR VR
502 fld st(2) ; inv. inv. inv. inv. inv. UR VR
505 // setup delta values
506 mov eax, Tmap.DeltaV // get v 16.16 step
507 mov ebx, eax // copy it
508 sar eax, 16 // get v int step
509 shl ebx, 16 // get v frac step
510 mov Tmap.DeltaVFrac, ebx // store it
511 imul eax, Tmap.src_offset // calc texture step for v int step
513 mov ebx, Tmap.DeltaU // get u 16.16 step
514 mov ecx, ebx // copy it
515 sar ebx, 16 // get the u int step
516 shl ecx, 16 // get the u frac step
517 mov Tmap.DeltaUFrac, ecx // store it
518 add eax, ebx // calc uint + vint step
519 mov Tmap.uv_delta[4], eax // save whole step in non-v-carry slot
520 add eax, Tmap.src_offset // calc whole step + v carry
521 mov Tmap.uv_delta[0], eax // save in v-carry slot
526 ; setup initial coordinates
527 mov esi, Tmap.UFixed // get u 16.16
528 mov ebx, esi // copy it
529 sar esi, 16 // get integer part
530 shl ebx, 16 // get fractional part
532 mov ecx, Tmap.VFixed // get v 16.16
533 mov edx, ecx // copy it
534 sar edx, 16 // get integer part
535 shl ecx, 16 // get fractional part
536 imul edx, Tmap.src_offset // calc texture scanline address
537 add esi, edx // calc texture offset
538 add esi, Tmap.pixptr // calc address
545 // mov edx, Tmap.DeltaUFrac
549 mov ebx, Tmap.fx_l_right
555 mov eax, Tmap.fx_dl_dx
564 sub eax, Tmap.pScreenBits
569 inc Tmap.WidthModLength
570 mov eax,Tmap.WidthModLength
574 mov Tmap.WidthModLength, eax
578 mov al,[edi] // preread the destination cache line
580 // Make ESI = DV:DU in 6:10,6:10 format
586 mov Tmap.DeltaUFrac, esi
588 // Make ECX = V:U in 6:10,6:10 format
599 // ecx = V:U in 8.6:10.8
600 // edx = zbuffer pointer
609 cmp esi, [edx+0] // Compare the Z depth of this pixel with zbuffer
610 jle Skip0a // If pixel is covered, skip drawing
612 mov [edx+0], esi // Write z
614 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
615 shr ax, 12 // EAX = V:U in 6.10:16.0
616 rol eax, 4 // EAX = V:U in 0.0:6:6
617 and eax, 0ffh // clear upper bits
618 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
622 and eax, 0ffffh // clear upper bits
623 mov al, gr_fade_table[eax]
626 add ecx, Tmap.DeltaUFrac
627 add esi, Tmap.fx_dwdx
631 cmp esi, [edx+4] // Compare the Z depth of this pixel with zbuffer
632 jle Skip1a // If pixel is covered, skip drawing
634 mov [edx+4], esi // Write z
636 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
637 shr ax, 12 // EAX = V:U in 6.10:16.0
638 rol eax, 4 // EAX = V:U in 0.0:6:6
639 and eax, 0ffh // clear upper bits
640 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
644 and eax, 0ffffh // clear upper bits
645 mov al, gr_fade_table[eax]
648 add ecx, Tmap.DeltaUFrac
649 add esi, Tmap.fx_dwdx
656 dec Tmap.WidthModLength
664 cmp esi, [edx+0] // Compare the Z depth of this pixel with zbuffer
665 jle Skip0b // If pixel is covered, skip drawing
667 mov [edx+0], esi // Write z
669 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
670 shr ax, 12 // EAX = V:U in 6.10:16.0
671 rol eax, 4 // EAX = V:U in 0.0:6:6
672 and eax, 0ffh // clear upper bits
673 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
677 and eax, 0ffffh // clear upper bits
678 mov al, gr_fade_table[eax]
681 add ecx, Tmap.DeltaUFrac
682 add esi, Tmap.fx_dwdx
688 // busy FPU registers: // st0 st1 st2 st3 st4 st5 st6 st7
689 // xxx xxx xxx xxx xxx xxx xxx
698 fldcw Tmap.OldFPUCW // restore the FPU
711 void tmapscan_pln8_tiled_16x16()
714 switch(gr_zbuffering_mode) {
717 case GR_ZBUFF_FULL: // both
718 tmapscan_pln8_zbuffered_tiled_16x16();
720 case GR_ZBUFF_WRITE: // write only
721 tmapscan_pln8_zbuffered_tiled_16x16();
723 case GR_ZBUFF_READ: // read only
724 tmapscan_pln8_zbuffered_tiled_16x16();
729 Tmap.fx_l = fl2f(Tmap.l.b*32.0);
730 Tmap.fx_l_right = fl2f(Tmap.r.b*32.0);
731 Tmap.fx_dl_dx = fl2f(Tmap.deltas.b*32.0);
733 if ( Tmap.fx_dl_dx < 0 ) {
734 Tmap.fx_dl_dx = -Tmap.fx_dl_dx;
735 Tmap.fx_l = (67*F1_0)-Tmap.fx_l;
736 Tmap.fx_l_right = (67*F1_0)-Tmap.fx_l_right;
737 // Assert( Tmap.fx_l > 31*F1_0 );
738 // Assert( Tmap.fx_l < 66*F1_0 );
739 // Assert( Tmap.fx_dl_dx >= 0 );
740 // Assert( Tmap.fx_dl_dx < 31*F1_0 );
743 Tmap.fl_dudx_wide = Tmap.deltas.u*32.0f;
744 Tmap.fl_dvdx_wide = Tmap.deltas.v*32.0f;
745 Tmap.fl_dwdx_wide = Tmap.deltas.sw*32.0f;
747 Tmap.fx_w = fl2i(Tmap.l.sw * GR_Z_RANGE)+gr_zoffset;
748 Tmap.fx_dwdx = fl2i(Tmap.deltas.sw * GR_Z_RANGE);
750 // Assert(Tmap.fx_w < 65536 );
751 // Assert(Tmap.fx_w >= 0 );
752 // Assert(Tmap.fx_w+Tmap.fx_dwdx*Tmap.loop_count < 65536 );
753 // Assert(Tmap.fx_w+Tmap.fx_dwdx*Tmap.loop_count >= 0 );
768 // Put the FPU in low precision mode
769 fstcw Tmap.OldFPUCW // store copy of CW
770 mov ax,Tmap.OldFPUCW // get it in ax
772 mov Tmap.FPUCW,ax // store it
773 fldcw Tmap.FPUCW // load the FPU
776 mov ecx, Tmap.loop_count // ecx = width
777 mov edi, Tmap.dest_row_data // edi = dest pointer
779 // edi = pointer to start pixel in dest dib
782 mov eax,ecx // eax and ecx = width
783 shr ecx,5 // ecx = width / subdivision length
784 and eax,31 // eax = width mod subdivision length
785 jnz some_left_over // any leftover?
786 dec ecx // no, so special case last span
787 mov eax,32 // it's 8 pixels long
789 mov Tmap.Subdivisions,ecx // store widths
790 mov Tmap.WidthModLength,eax
792 // calculate ULeft and VLeft // FPU Stack (ZL = ZLeft)
793 // st0 st1 st2 st3 st4 st5 st6 st7
795 fld Tmap.l.u // U/ZL V/ZL
796 fld Tmap.l.sw // 1/ZL U/ZL V/ZL
797 fld1 // 1 1/ZL U/ZL V/ZL
798 fdiv st,st(1) // ZL 1/ZL U/ZL V/ZL
799 fld st // ZL ZL 1/ZL U/ZL V/ZL
800 fmul st,st(4) // VL ZL 1/ZL U/ZL V/ZL
801 fxch st(1) // ZL VL 1/ZL U/ZL V/ZL
802 fmul st,st(3) // UL VL 1/ZL U/ZL V/ZL
804 fstp st(5) // VL 1/ZL U/ZL V/ZL UL
805 fstp st(5) // 1/ZL U/ZL V/ZL UL VL
807 // calculate right side OverZ terms ; st0 st1 st2 st3 st4 st5 st6 st7
809 fadd Tmap.fl_dwdx_wide // 1/ZR U/ZL V/ZL UL VL
810 fxch st(1) // U/ZL 1/ZR V/ZL UL VL
811 fadd Tmap.fl_dudx_wide // U/ZR 1/ZR V/ZL UL VL
812 fxch st(2) // V/ZL 1/ZR U/ZR UL VL
813 fadd Tmap.fl_dvdx_wide // V/ZR 1/ZR U/ZR UL VL
815 // calculate right side coords // st0 st1 st2 st3 st4 st5 st6 st7
817 fld1 // 1 V/ZR 1/ZR U/ZR UL VL
818 // @todo overlap this guy
819 fdiv st,st(2) // ZR V/ZR 1/ZR U/ZR UL VL
820 fld st // ZR ZR V/ZR 1/ZR U/ZR UL VL
821 fmul st,st(2) // VR ZR V/ZR 1/ZR U/ZR UL VL
822 fxch st(1) // ZR VR V/ZR 1/ZR U/ZR UL VL
823 fmul st,st(4) // UR VR V/ZR 1/ZR U/ZR UL VL
825 cmp ecx,0 // check for any full spans
826 jle HandleLeftoverPixels
830 // at this point the FPU contains // st0 st1 st2 st3 st4 st5 st6 st7
831 // UR VR V/ZR 1/ZR U/ZR UL VL
833 // convert left side coords
835 fld st(5) ; UL UR VR V/ZR 1/ZR U/ZR UL VL
836 fmul Tmap.FixedScale ; UL16 UR VR V/ZR 1/ZR U/ZR UL VL
837 fistp Tmap.UFixed ; UR VR V/ZR 1/ZR U/ZR UL VL
839 fld st(6) ; VL UR VR V/ZR 1/ZR U/ZR UL VL
840 fmul Tmap.FixedScale ; VL16 UR VR V/ZR 1/ZR U/ZR UL VL
841 fistp Tmap.VFixed ; UR VR V/ZR 1/ZR U/ZR UL VL
843 // calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7
845 fsubr st(5),st ; UR VR V/ZR 1/ZR U/ZR dU VL
846 fxch st(1) ; VR UR V/ZR 1/ZR U/ZR dU VL
847 fsubr st(6),st ; VR UR V/ZR 1/ZR U/ZR dU dV
848 fxch st(6) ; dV UR V/ZR 1/ZR U/ZR dU VR
850 fmul Tmap.FixedScale8 ; dV8 UR V/ZR 1/ZR U/ZR dU VR
851 fistp Tmap.DeltaV ; UR V/ZR 1/ZR U/ZR dU VR
853 fxch st(4) ; dU V/ZR 1/ZR U/ZR UR VR
854 fmul Tmap.FixedScale8 ; dU8 V/ZR 1/ZR U/ZR UR VR
855 fistp Tmap.DeltaU ; V/ZR 1/ZR U/ZR UR VR
857 // increment terms for next span // st0 st1 st2 st3 st4 st5 st6 st7
858 // Right terms become Left terms--->// V/ZL 1/ZL U/ZL UL VL
860 fadd Tmap.fl_dvdx_wide // V/ZR 1/ZL U/ZL UL VL
861 fxch st(1) // 1/ZL V/ZR U/ZL UL VL
862 fadd Tmap.fl_dwdx_wide // 1/ZR V/ZR U/ZL UL VL
863 fxch st(2) // U/ZL V/ZR 1/ZR UL VL
864 fadd Tmap.fl_dudx_wide // U/ZR V/ZR 1/ZR UL VL
865 fxch st(2) // 1/ZR V/ZR U/ZR UL VL
866 fxch st(1) // V/ZR 1/ZR U/ZR UL VL
869 // setup delta values
871 mov eax,Tmap.DeltaV // get v 16.16 step
872 mov ebx,eax // copy it
873 sar eax,16 // get v int step
874 shl ebx,16 // get v frac step
875 mov Tmap.DeltaVFrac,ebx // store it
876 imul eax,Tmap.src_offset // calculate texture step for v int step
878 mov ebx,Tmap.DeltaU // get u 16.16 step
879 mov ecx,ebx // copy it
880 sar ebx,16 // get u int step
881 shl ecx,16 // get u frac step
882 mov Tmap.DeltaUFrac,ecx // store it
883 add eax,ebx // calculate uint + vint step
884 mov Tmap.uv_delta[4],eax // save whole step in non-v-carry slot
885 add eax,Tmap.src_offset // calculate whole step + v carry
886 mov Tmap.uv_delta[0],eax // save in v-carry slot
888 // setup initial coordinates
889 mov esi,Tmap.UFixed // get u 16.16 fixedpoint coordinate
891 mov ebx,esi // copy it
892 sar esi,16 // get integer part
893 shl ebx,16 // get fractional part
895 mov ecx,Tmap.VFixed // get v 16.16 fixedpoint coordinate
897 mov edx,ecx // copy it
898 sar edx,16 // get integer part
899 shl ecx,16 // get fractional part
900 imul edx,Tmap.src_offset // calc texture scanline address
901 add esi,edx // calc texture offset
902 add esi,Tmap.pixptr // calc address
904 // set up affine registers
910 mov ebp, Tmap.fx_dl_dx
921 // calculate right side coords st0 st1 st2 st3 st4 st5 st6 st7
922 fld1 // 1 V/ZR 1/ZR U/ZR UL VL
923 // This divide should happen while the pixel span is drawn.
924 fdiv st,st(2) // ZR V/ZR 1/ZR U/ZR UL VL
928 // edi = dest dib bits at current pixel
929 // esi = texture pointer at current u,v
931 // ebx = u fraction 0.32
932 // ecx = v fraction 0.32
934 // ebp = v carry scratch
936 mov al,[edi] // preread the destination cache line
938 mov Tmap.InnerLooper, 32/4 // Set up loop counter
943 sub eax, Tmap.pScreenBits
947 // Make ESI = DV:DU in 6:10,6:10 format
953 mov Tmap.DeltaUFrac, esi
955 // Make ECX = V:U in 6:10,6:10 format
965 // ecx = V:U in 8.6:10.8
966 // edx = zbuffer pointer
975 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
976 shr ax, 12 // EAX = V:U in 6.10:16.0
977 rol eax, 4 // EAX = V:U in 0.0:6:6
978 and eax, 0ffh // clear upper bits
979 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
983 and eax, 0ffffh // clear upper bits
984 mov al, gr_fade_table[eax]
986 add ecx, Tmap.DeltaUFrac
990 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
991 shr ax, 12 // EAX = V:U in 6.10:16.0
992 rol eax, 4 // EAX = V:U in 0.0:6:6
993 and eax, 0ffh // clear upper bits
994 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
998 and eax, 0ffffh // clear upper bits
999 mov al, gr_fade_table[eax]
1001 add ecx, Tmap.DeltaUFrac
1005 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
1006 shr ax, 12 // EAX = V:U in 6.10:16.0
1007 rol eax, 4 // EAX = V:U in 0.0:6:6
1008 and eax, 0ffh // clear upper bits
1009 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
1013 and eax, 0ffffh // clear upper bits
1014 mov al, gr_fade_table[eax]
1016 add ecx, Tmap.DeltaUFrac
1020 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
1021 shr ax, 12 // EAX = V:U in 6.10:16.0
1022 rol eax, 4 // EAX = V:U in 0.0:6:6
1023 and eax, 0ffh // clear upper bits
1024 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
1028 and eax, 0ffffh // clear upper bits
1029 mov al, gr_fade_table[eax]
1031 add ecx, Tmap.DeltaUFrac
1036 dec Tmap.InnerLooper
1041 // the fdiv is done, finish right // st0 st1 st2 st3 st4 st5 st6 st7
1042 // ZR V/ZR 1/ZR U/ZR UL VL
1044 fld st // ZR ZR V/ZR 1/ZR U/ZR UL VL
1045 fmul st,st(2) // VR ZR V/ZR 1/ZR U/ZR UL VL
1046 fxch st(1) // ZR VR V/ZR 1/ZR U/ZR UL VL
1047 fmul st,st(4) // UR VR V/ZR 1/ZR U/ZR UL VL
1049 dec Tmap.Subdivisions // decrement span count
1050 jnz SpanLoop // loop back
1053 HandleLeftoverPixels:
1055 mov esi,Tmap.pixptr // load texture pointer
1057 // edi = dest dib bits
1058 // esi = current texture dib bits
1059 // at this point the FPU contains ; st0 st1 st2 st3 st4 st5 st6 st7
1060 // inv. means invalid numbers ; inv. inv. inv. inv. inv. UL VL
1062 cmp Tmap.WidthModLength,0 ; are there remaining pixels to draw?
1063 jz FPUReturn ; nope, pop the FPU and bail
1065 // convert left side coords ; st0 st1 st2 st3 st4 st5 st6 st7
1067 fld st(5) ; UL inv. inv. inv. inv. inv. UL VL
1068 fmul Tmap.FixedScale ; UL16 inv. inv. inv. inv. inv. UL VL
1069 fistp Tmap.UFixed ; inv. inv. inv. inv. inv. UL VL
1071 fld st(6) ; VL inv. inv. inv. inv. inv. UL VL
1072 fmul Tmap.FixedScale // VL16 inv. inv. inv. inv. inv. UL VL
1073 fistp Tmap.VFixed ; inv. inv. inv. inv. inv. UL VL
1075 dec Tmap.WidthModLength ; calc how many steps to take
1076 jz OnePixelSpan ; just one, don't do deltas'
1078 // calculate right edge coordinates ; st0 st1 st2 st3 st4 st5 st6 st7
1081 // @todo rearrange things so we don't need these two instructions
1082 fstp Tmap.FloatTemp ; inv. inv. inv. inv. UL VL
1083 fstp Tmap.FloatTemp ; inv. inv. inv. UL VL
1085 fld Tmap.r.v ; V/Zr inv. inv. inv. UL VL
1086 fsub Tmap.deltas.v ; V/ZR inv. inv. inv. UL VL
1087 fld Tmap.r.u ; U/Zr V/ZR inv. inv. inv. UL VL
1088 fsub Tmap.deltas.u ; U/ZR V/ZR inv. inv. inv. UL VL
1089 fld Tmap.r.sw ; 1/Zr U/ZR V/ZR inv. inv. inv. UL VL
1090 fsub Tmap.deltas.sw ; 1/ZR U/ZR V/ZR inv. inv. inv. UL VL
1092 fdivr Tmap.One ; ZR U/ZR V/ZR inv. inv. inv. UL VL
1094 fmul st(1),st ; ZR UR V/ZR inv. inv. inv. UL VL
1095 fmulp st(2),st ; UR VR inv. inv. inv. UL VL
1097 // calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7
1099 fsubr st(5),st ; UR VR inv. inv. inv. dU VL
1100 fxch st(1) ; VR UR inv. inv. inv. dU VL
1101 fsubr st(6),st ; VR UR inv. inv. inv. dU dV
1102 fxch st(6) ; dV UR inv. inv. inv. dU VR
1104 fidiv Tmap.WidthModLength ; dv UR inv. inv. inv. dU VR
1105 fmul Tmap.FixedScale ; dv16 UR inv. inv. inv. dU VR
1106 fistp Tmap.DeltaV ; UR inv. inv. inv. dU VR
1108 fxch st(4) ; dU inv. inv. inv. UR VR
1109 fidiv Tmap.WidthModLength ; du inv. inv. inv. UR VR
1110 fmul Tmap.FixedScale ; du16 inv. inv. inv. UR VR
1111 fistp Tmap.DeltaU ; inv. inv. inv. UR VR
1113 // @todo gross! these are to line up with the other loop
1114 fld st(1) ; inv. inv. inv. inv. UR VR
1115 fld st(2) ; inv. inv. inv. inv. inv. UR VR
1118 // setup delta values
1119 mov eax, Tmap.DeltaV // get v 16.16 step
1120 mov ebx, eax // copy it
1121 sar eax, 16 // get v int step
1122 shl ebx, 16 // get v frac step
1123 mov Tmap.DeltaVFrac, ebx // store it
1124 imul eax, Tmap.src_offset // calc texture step for v int step
1126 mov ebx, Tmap.DeltaU // get u 16.16 step
1127 mov ecx, ebx // copy it
1128 sar ebx, 16 // get the u int step
1129 shl ecx, 16 // get the u frac step
1130 mov Tmap.DeltaUFrac, ecx // store it
1131 add eax, ebx // calc uint + vint step
1132 mov Tmap.uv_delta[4], eax // save whole step in non-v-carry slot
1133 add eax, Tmap.src_offset // calc whole step + v carry
1134 mov Tmap.uv_delta[0], eax // save in v-carry slot
1139 ; setup initial coordinates
1140 mov esi, Tmap.UFixed // get u 16.16
1141 mov ebx, esi // copy it
1142 sar esi, 16 // get integer part
1143 shl ebx, 16 // get fractional part
1145 mov ecx, Tmap.VFixed // get v 16.16
1146 mov edx, ecx // copy it
1147 sar edx, 16 // get integer part
1148 shl ecx, 16 // get fractional part
1149 imul edx, Tmap.src_offset // calc texture scanline address
1150 add esi, edx // calc texture offset
1151 add esi, Tmap.pixptr // calc address
1158 // mov edx, Tmap.DeltaUFrac
1162 mov ebx, Tmap.fx_l_right
1168 mov eax, Tmap.fx_dl_dx
1177 sub eax, Tmap.pScreenBits
1182 inc Tmap.WidthModLength
1183 mov eax,Tmap.WidthModLength
1187 mov Tmap.WidthModLength, eax
1191 mov al,[edi] // preread the destination cache line
1193 // Make ESI = DV:DU in 6:10,6:10 format
1194 mov eax, Tmap.DeltaV
1196 mov esi, Tmap.DeltaU
1199 mov Tmap.DeltaUFrac, esi
1201 // Make ECX = V:U in 6:10,6:10 format
1202 mov eax, Tmap.VFixed
1204 mov ecx, Tmap.UFixed
1212 // ecx = V:U in 8.6:10.8
1213 // edx = zbuffer pointer
1215 // edi = screen data
1222 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
1223 shr ax, 12 // EAX = V:U in 6.10:16.0
1224 rol eax, 4 // EAX = V:U in 0.0:6:6
1225 and eax, 0ffh // clear upper bits
1226 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
1230 and eax, 0ffffh // clear upper bits
1231 mov al, gr_fade_table[eax]
1233 add ecx, Tmap.DeltaUFrac
1237 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
1238 shr ax, 12 // EAX = V:U in 6.10:16.0
1239 rol eax, 4 // EAX = V:U in 0.0:6:6
1240 and eax, 0ffh // clear upper bits
1241 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
1245 and eax, 0ffffh // clear upper bits
1246 mov al, gr_fade_table[eax]
1248 add ecx, Tmap.DeltaUFrac
1255 dec Tmap.WidthModLength
1263 mov eax, ecx // EAX = V.VF:U.UF in 6.10:6.10
1264 shr ax, 12 // EAX = V:U in 6.10:16.0
1265 rol eax, 4 // EAX = V:U in 0.0:6:6
1266 and eax, 0ffh // clear upper bits
1267 add eax, Tmap.pixptr // EAX = (V*64)+U + Pixptr
1271 and eax, 0ffffh // clear upper bits
1272 mov al, gr_fade_table[eax]
1274 add ecx, Tmap.DeltaUFrac
1280 // busy FPU registers: // st0 st1 st2 st3 st4 st5 st6 st7
1281 // xxx xxx xxx xxx xxx xxx xxx
1290 fldcw Tmap.OldFPUCW // restore the FPU