* 
* Copyright (C) 1996-1997 Id Software, Inc. 
* 
* This program is free software; you can redistribute it and/or 
* modify it under the terms of the GNU General Public License 
* as published by the Free Software Foundation; either version 2 
* of the License, or (at your option) any later version. 
* 
* This program is distributed in the hope that it will be useful, 
* but WITHOUT ANY WARRANTY; without even the implied warranty of 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   
* 
* See the GNU General Public License for more details. 
* 
* You should have received a copy of the GNU General Public License 
* along with this program; if not, write to the Free Software 
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
* 

**
** Quake for AMIGA
** d_sky.c assembler implementations by Frank Wille <frank@phoenix.owl.de>
**

		XREF    _d_viewbuffer
		XREF    _screenwidth
		XREF    _r_refdef
		XREF    _r_skysource
		XREF    _vid
		XREF    _vright
		XREF    _vpn
		XREF    _vup
		XREF    _skytime
		XREF    _skyspeed

		XDEF    _D_DrawSkyScans8

PSPAN_NEXT              =       $C
REFDEF_VRECT_X          =       0
REFDEF_VRECT_Y          =       4
REFDEF_VRECT_WIDTH      =       8
REFDEF_VRECT_HEIGHT     =       12
VID_WIDTH               =       20
VID_HEIGHT              =       24

SKYSHIFT                =       7
SKYSIZE                 =       (1 << SKYSHIFT)
SKYMASK                 =       (SKYSIZE - 1)
SKY_SPAN_SHIFT          =       5
SKY_SPAN_MAX            =       (1 << SKY_SPAN_SHIFT)
R_SKY_SMASK             =       $007f
R_SKY_TMASK             =       $007f




******************************************************************************
*
*       void D_DrawSkyScans8 (espan_t *pspan)
*
*       standard scan drawing function for the sky
*
*       D_Sky_uv_To_st is inlined.
*
*       IMPORTANT!! SKY_SPAN_SHIFT must *NOT* exceed 5 (The ReciprocTable
*       has to be extended)
*
******************************************************************************

		cnop    0,4
_D_DrawSkyScans8


*****   stackframe

		rsreset
.savefp1        rs.x    1
.saved4         rs.l    1
.saved5         rs.l    1
.vr0            rs.s    1
.vr1            rs.s    1
.vr2            rs.s    1
.fpuregs        rs.x    6
.intregs        rs.l    11
		rs.l    1
.pspan          rs.l    1


******  Prologue. Global variables are put into registers or onto the stackframe

		movem.l d2-d7/a2-a6,-(sp)
		fmovem.x        fp2-fp7,-(sp)
		sub.l   #.fpuregs,sp

******  First loop. In every iteration one complete span is drawn


		move.l  .pspan(sp),a6           ;get function parameter

		lea     _r_refdef,a1
		move.l  REFDEF_VRECT_HEIGHT(a1),d0
		move.l  REFDEF_VRECT_WIDTH(a1),d1
		cmp.l   d0,d1                   ;if (r_refdef.vrect.width >= r_...)
		blt.b   .height
		fmove.l d1,fp0                  ;temp = (float)r_refdef.vrect.height
		bra.b   .width
.height
		fmove.l d0,fp0                  ;temp = (float)r_refdef.vrect.width
.width
		fmove.s #8192,fp1
		fdiv    fp0,fp1                 ;fp1 = 8192 / temp
		move.l  _r_skysource,a5
.loop
		fmove.x fp1,.savefp1(sp)
		move.l  _d_viewbuffer,a0
		move.l  _screenwidth,d0
		move.l  (a6)+,d3
		move.l  (a6)+,d2
		fmove.l d2,fp4
		muls    d2,d0                   ;d0 = screenwidth * pspan->v
		add.l   d3,d0
		add.l   d0,a0                   ;pdest = d_viewbuffer + pspan->u + d0

		fmove.s #4096,fp7
		lea     _vpn,a2
		fmove.s (a2)+,fp5
		fmul    fp7,fp5                 ;fp5 = 4096*vpn[0]
		fmove.s (a2)+,fp6
		fmul    fp7,fp6                 ;fp6 = 4096*vpn[1]
		fmul.s  (a2)+,fp7               ;fp7 = 4096*vpn[2]
		lea     _vid,a1
		move.l  VID_WIDTH(a1),d0
		move.l  VID_HEIGHT(a1),d1
		asr.l   #1,d0
		move.l  d0,a2                   ;a2 = vid.width>>1
		asr.l   #1,d1
		fmove.l d1,fp0
		fsub    fp4,fp0                 ;fp0 = ((vid.height>>1)-v)
		fmul    fp1,fp0                 ;wv = 8192 * fp0 / temp
		lea     _vup,a1
		fmove.s (a1)+,fp2
		fmul    fp0,fp2                 ;fp2 = wv*vup[0]
		fadd    fp2,fp5                 ;fp5 = 4096*vpn[0] + wv*vup[0]
		fmove.s (a1)+,fp3
		fmul    fp0,fp3                 ;fp3 = wv*vup[1]
		fadd    fp3,fp6                 ;fp6 = 4096*vpn[1] + wv*vup[0]
		fmul.s  (a1)+,fp0               ;fp0 = wv*vup[2]
		fadd    fp0,fp7                 ;fp7 = 4096*vpn[2] + wv*vup[2]
		lea     _vright,a1
		fmove.s (a1)+,fp2
		fmove.s (a1)+,fp3
		fmove.s (a1)+,fp4
		fmul    fp1,fp2                 ;fp2 = 8192 * vright[0] / temp
		fmul    fp1,fp3                 ;fp3 = 8192 * vright[1] / temp
		fmul    fp1,fp4                 ;fp4 = 8192 * vright[2] / temp
		fmove.s fp2,.vr0(sp)
		fmove.s fp3,.vr1(sp)
		fmove.s #3,fp1
		fmul    fp1,fp7                 ;multiply by 3
		fmul    fp1,fp4
		fmove.s fp4,.vr2(sp)
		move.l  (a6)+,d1                ;count = pspan->count
		fmove.s _skytime,fp0
		fmul.s  _skyspeed,fp0
		fmul.s  #65536,fp0
		fmove.l fp0,d0                  ;d0 = skytime*skyspeed*$10000
		move.l  d0,a4

******  D_Sky_uv_To_st (inlined)

		move.l  d3,d0
		sub.l   a2,d0
		fmove.l d0,fp0                  ;fp0 = (float(u-(vid.width>>1)))
		fmove   fp0,fp2
		fmul.s  .vr0(sp),fp2            ;fp2 = wu*vright[0]
		fadd    fp5,fp2                 ;fp2 = end[0]
		fmove   fp2,fp1
		fmul    fp2,fp2
		fmove   fp0,fp3
		fmul.s  .vr1(sp),fp3            ;fp3 = wu*vright[1]
		fadd    fp6,fp3                 ;fp3 = end[1]
		fmove   fp3,fp4
		fmul    fp3,fp3
		fadd    fp3,fp2
		fmul.s  .vr2(sp),fp0            ;fp0 = wu*vright[2]
		fadd    fp7,fp0                 ;fp0 = end[2]
		fmul    fp0,fp0
		fadd    fp0,fp2
		fsqrt   fp2                     ;fp2 = length(end)
		fmove.s #(65536*6*(SKYSIZE/2-1)),fp0
		fdiv    fp2,fp0
		fmul    fp0,fp1                 ;fp1 = 6*(SKYSIZE/2-1)*end[0]
		fmul    fp0,fp4                 ;fp4 = 6*(SKYSIZE/2-1)*end[1]
		fmove.l fp1,d6
		add.l   a4,d6                   ;d6 = s
		fmove.l fp4,d7
		add.l   a4,d7                   ;d7 = t

******  end of D_Sky_uv_To_st

******  Second loop. In every iteration one part of the whole span is drawn
******  d2 gets the value (spancount-1)! [NOT spancount]

******  d1 = count

*                do
*                {
*                        if (count >= SKY_SPAN_MAX)
*                                spancount = SKY_SPAN_MAX;
*                        else
*                                spancount = count;
*
*                        count -= spancount;
*
*                        if (count)
*                        {

.loop2
		move.l  #SKY_SPAN_MAX-1,d2      ;spancount = SKY_SPAN_MAX
		cmp.l   #SKY_SPAN_MAX,d1        ;if (count >= SKY_SPAN_MAX)
		bgt.b   .cont
		move.l  d1,d2                   ;spancount = count
		subq.l  #1,d2
		moveq   #0,d1                   ;count -= spancount
		bra.w   .finalpart
.cont
		sub.l   #SKY_SPAN_MAX,d1        ;count -= spancount;


******  Evaluation of the values for the inner loop. This version is used for
******  span size = SKY_SPAN_MAX

*                        // calculate s and t at far end of span,
*                        // calculate s and t steps across span by shifting
*                                u += spancount;
*
*                                D_Sky_uv_To_st (u, v, &snext, &tnext);
*
*                                sstep = (snext - s) >> SKY_SPAN_SHIFT;
*                                tstep = (tnext - t) >> SKY_SPAN_SHIFT;
*                        }


		add.l   d2,d3
		addq.l  #1,d3

******  D_Sky_uv_To_st (inlined)

		move.l  d3,d0
		sub.l   a2,d0
		fmove.l d0,fp0                  ;fp0 = (float(u-(vid.width>>1)))
		fmove   fp0,fp2
		fmul.s  .vr0(sp),fp2            ;fp2 = wu*vright[0]
		fadd    fp5,fp2                 ;fp2 = end[0]
		fmove   fp2,fp1
		fmul    fp2,fp2
		fmove   fp0,fp3
		fmul.s  .vr1(sp),fp3            ;fp3 = wu*vright[1]
		fadd    fp6,fp3                 ;fp3 = end[1]
		fmove   fp3,fp4
		fmul    fp3,fp3
		fadd    fp3,fp2
		fmul.s  .vr2(sp),fp0            ;fp0 = wu*vright[2]
		fadd    fp7,fp0                 ;fp0 = end[2]
		fmul    fp0,fp0
		fadd    fp0,fp2
		fsqrt   fp2                     ;fp2 = length(end)
		fmove.s #(65536*6*(SKYSIZE/2-1)),fp0
		fdiv    fp2,fp0
		fmul    fp0,fp1                 ;fp1 = 6*(SKYSIZE/2-1)*end[0]
		fmul    fp0,fp4                 ;fp4 = 6*(SKYSIZE/2-1)*end[1]
		fmove.l fp1,d4
		add.l   a4,d4                   ;d6 = snext
		fmove.l fp4,d5
		add.l   a4,d5                   ;d7 = tnext

******  end of D_Sky_uv_To_st

		move.l  d4,.saved4(sp)          ;save snext
		move.l  d5,.saved5(sp)          ;save tnext
		sub.l   d6,d4                   ;d4 = snext - s
		sub.l   d7,d5                   ;d5 = tnext - t
		asr.l   #SKY_SPAN_SHIFT,d4      ;sstep = d4 >> SKY_SPAN_SHIFT
		asr.l   #SKY_SPAN_SHIFT,d5      ;tstep = d5 >> SKY_SPAN_SHIFT
		bra.w   .mainloop


.finalpart
		add.l   d2,d3

******  D_Sky_uv_To_st (inlined)

		move.l  d3,d0
		sub.l   a2,d0
		fmove.l d0,fp0                  ;fp0 = (float(u-(vid.width>>1)))
		fmove   fp0,fp2
		fmul.s  .vr0(sp),fp2            ;fp2 = wu*vright[0]
		fadd    fp5,fp2                 ;fp2 = end[0]
		fmove   fp2,fp1
		fmul    fp2,fp2
		fmove   fp0,fp3
		fmul.s  .vr1(sp),fp3            ;fp3 = wu*vright[1]
		fadd    fp6,fp3                 ;fp3 = end[1]
		fmove   fp3,fp4
		fmul    fp3,fp3
		fadd    fp3,fp2
		fmul.s  .vr2(sp),fp0            ;fp0 = wu*vright[2]
		fadd    fp7,fp0                 ;fp0 = end[2]
		fmul    fp0,fp0
		fadd    fp0,fp2
		fsqrt   fp2                     ;fp2 = length(end)
		fmove.s #(65536*6*(SKYSIZE/2-1)),fp0
		fdiv    fp2,fp0
		fmul    fp0,fp1                 ;fp1 = 6*(SKYSIZE/2-1)*end[0]
		fmul    fp0,fp4                 ;fp4 = 6*(SKYSIZE/2-1)*end[1]
		fmove.l fp1,d4
		add.l   a4,d4                   ;d6 = snext
		fmove.l fp4,d5
		add.l   a4,d5                   ;d7 = tnext

******  end of D_Sky_uv_To_st

		move.l  d4,.saved4(sp)          ;save snext
		move.l  d5,.saved5(sp)          ;save tnext
		sub.l   d6,d4                   ;d4 = snext - s
		sub.l   d7,d5                   ;d5 = tnext - t
		cmp     #5,d2                   ;(spancount-1) < 5?
		blt.b   .special                ;yes -> special case
.qdiv
		asr.l   #7,d4                   ;d4 >> 7
		asr.l   #7,d5                   ;d5 >> 7
		lea     ReciprocTable,a3        ;a3 -> reciprocal table
		move    0(a3,d2.w*2),d0         ;d0 = (1/(spancount-1))<<16
		muls    d0,d4                   ;d4 = d4 / (spancount-1)
		asr.l   #7,d4                   ;sstep = d4 >> 7
		muls    d0,d5                   ;d5 = d5 / (spancount-1)
		asr.l   #7,d5                   ;tstep = d5 >> 7
		bra.b   .mainloop
.special
		cmp     #1,d2                   ;switch (spancount-1)
		ble.b   .mainloop               ;0,1 -> no scaling needed
		cmp     #3,d2                   ;3 -> standard qdiv
		beq.b   .qdiv
		blt.b   .spec_2
		asr.l   #2,d4                   ;4 -> scale by shifting right
		asr.l   #2,d5
		bra.b   .mainloop
.spec_2
		asr.l   #1,d4                   ;2 -> scale by shifting right
		asr.l   #1,d5


******  Main drawing loop.

******  d2 : spancount
******  d4 : sstep
******  d5 : tstep
******  d6 : s
******  d7 : t
******  a0 : pdest
******  a5 : r_skysource

*                        do
*                        {
*                                *pdest++ = r_skysource[((t & R_SKY_TMASK) >> 8) +
*                                                ((s & R_SKY_SMASK) >> 16)];
*                                s += sstep;
*                                t += tstep;
*                        } while (--spancount > 0);


.mainloop
		move.l  d1,-(sp)
		swap    d4
		swap    d5
		swap    d6
		swap    d7
		move    d5,d1                   ;d2 = tstep integer part
		move    d4,d0                   ;d0 = sstep integer part
		clr     d5                      ;d5 = tstep fractional part
		clr     d4                      ;d4 = sstep fractional part
.loop3
		and     #R_SKY_TMASK,d7
		asl     #8,d7
		lea     0(a5,d7.w),a3
		asr     #8,d7
		and     #R_SKY_SMASK,d6
		move.b  0(a3,d6.w),(a0)+
		add.l   d4,d6
		addx.w  d0,d6
		add.l   d5,d7
		addx.w  d1,d7
		dbra    d2,.loop3
		move.l  (sp)+,d1

******  loop terminations


		move.l   .saved5(sp),d7         ;t = tnext
		move.l   .saved4(sp),d6         ;s = snext

		tst.l   d1                      ;while (count > 0)
		bgt.w   .loop2
		fmove.x .savefp1(sp),fp1

		move.l  (a6)+,a6
		tst.l   a6
		bne.w   .loop
		add.l   #.fpuregs,sp
		fmovem.x        (sp)+,fp2-fp7
		movem.l (sp)+,d2-d7/a2-a6
		rts

ReciprocTable
		dc.w    0
		dc.w    0
		dc.w    0
		dc.w    16384/3
		dc.w    0
		dc.w    16384/5
		dc.w    16384/6
		dc.w    16384/7
		dc.w    16384/8
		dc.w    16384/9
		dc.w    16384/10
		dc.w    16384/11
		dc.w    16384/12
		dc.w    16384/13
		dc.w    16384/14
		dc.w    16384/15
		dc.w    16384/16
		dc.w    16384/17
		dc.w    16384/18
		dc.w    16384/19
		dc.w    16384/20
		dc.w    16384/21
		dc.w    16384/22
		dc.w    16384/23
		dc.w    16384/24
		dc.w    16384/25
		dc.w    16384/26
		dc.w    16384/27
		dc.w    16384/28
		dc.w    16384/29
		dc.w    16384/30
		dc.w    16384/31

