/*
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

*/
//
// r_edgea.s
// x86 assembly-language edge-processing code.
//

#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"

	.data
Ltemp:			.long	0
float_1_div_0100000h:	.long	0x35800000	// 1.0/(float)0x100000
float_point_999:	.single	0.999
float_1_point_001:	.single	1.001

	.text

//--------------------------------------------------------------------

#define edgestoadd	4+8	// note odd stack offsets because of
#define edgelist	8+12	// interleaving with pushes

.globl C(R_EdgeCodeStart)
C(R_EdgeCodeStart):

.globl C(R_InsertNewEdges)
C(R_InsertNewEdges):
	pushl	%edi
	pushl	%esi		// preserve register variables
	movl	edgestoadd(%esp),%edx
	pushl	%ebx
	movl	edgelist(%esp),%ecx

LDoNextEdge:
	movl	et_u(%edx),%eax
	movl	%edx,%edi

LContinueSearch:
	movl	et_u(%ecx),%ebx
	movl	et_next(%ecx),%esi
	cmpl	%ebx,%eax
	jle	LAddedge
	movl	et_u(%esi),%ebx
	movl	et_next(%esi),%ecx
	cmpl	%ebx,%eax
	jle	LAddedge2
	movl	et_u(%ecx),%ebx
	movl	et_next(%ecx),%esi
	cmpl	%ebx,%eax
	jle	LAddedge
	movl	et_u(%esi),%ebx
	movl	et_next(%esi),%ecx
	cmpl	%ebx,%eax
	jg	LContinueSearch

LAddedge2:
	movl	et_next(%edx),%edx
	movl	et_prev(%esi),%ebx
	movl	%esi,et_next(%edi)
	movl	%ebx,et_prev(%edi)
	movl	%edi,et_next(%ebx)
	movl	%edi,et_prev(%esi)
	movl	%esi,%ecx

	cmpl	$0,%edx
	jnz	LDoNextEdge
	jmp	LDone

	.align 4
LAddedge:
	movl	et_next(%edx),%edx
	movl	et_prev(%ecx),%ebx
	movl	%ecx,et_next(%edi)
	movl	%ebx,et_prev(%edi)
	movl	%edi,et_next(%ebx)
	movl	%edi,et_prev(%ecx)

	cmpl	$0,%edx
	jnz	LDoNextEdge

LDone:
	popl	%ebx		// restore register variables
	popl	%esi
	popl	%edi

	ret

//--------------------------------------------------------------------

#define predge	4+4

.globl C(R_RemoveEdges)
C(R_RemoveEdges):
	pushl	%ebx
	movl	predge(%esp),%eax

Lre_loop:
	movl	et_next(%eax),%ecx
	movl	et_nextremove(%eax),%ebx
	movl	et_prev(%eax),%edx
	testl	%ebx,%ebx
	movl	%edx,et_prev(%ecx)
	jz		Lre_done
	movl	%ecx,et_next(%edx)

	movl	et_next(%ebx),%ecx
	movl	et_prev(%ebx),%edx
	movl	et_nextremove(%ebx),%eax
	movl	%edx,et_prev(%ecx)
	testl	%eax,%eax
	movl	%ecx,et_next(%edx)
	jnz	Lre_loop

	popl	%ebx
	ret

Lre_done:
	movl	%ecx,et_next(%edx)
	popl	%ebx

	ret

//--------------------------------------------------------------------

#define pedgelist	4+4	// note odd stack offset because of interleaving
				// with pushes

.globl C(R_StepActiveU)
C(R_StepActiveU):
	pushl	%edi
	movl	pedgelist(%esp),%edx
	pushl	%esi		// preserve register variables
	pushl	%ebx

	movl	et_prev(%edx),%esi

LNewEdge:
	movl	et_u(%esi),%edi

LNextEdge:
	movl	et_u(%edx),%eax
	movl	et_u_step(%edx),%ebx
	addl	%ebx,%eax
	movl	et_next(%edx),%esi
	movl	%eax,et_u(%edx)
	cmpl	%edi,%eax
	jl	LPushBack

	movl	et_u(%esi),%edi
	movl	et_u_step(%esi),%ebx
	addl	%ebx,%edi
	movl	et_next(%esi),%edx
	movl	%edi,et_u(%esi)
	cmpl	%eax,%edi
	jl	LPushBack2

	movl	et_u(%edx),%eax
	movl	et_u_step(%edx),%ebx
	addl	%ebx,%eax
	movl	et_next(%edx),%esi
	movl	%eax,et_u(%edx)
	cmpl	%edi,%eax
	jl	LPushBack

	movl	et_u(%esi),%edi
	movl	et_u_step(%esi),%ebx
	addl	%ebx,%edi
	movl	et_next(%esi),%edx
	movl	%edi,et_u(%esi)
	cmpl	%eax,%edi
	jnl	LNextEdge

LPushBack2:
	movl	%edx,%ebx
	movl	%edi,%eax
	movl	%esi,%edx
	movl	%ebx,%esi

LPushBack:
// push it back to keep it sorted
	movl	et_prev(%edx),%ecx
	movl	et_next(%edx),%ebx

// done if the -1 in edge_aftertail triggered this
	cmpl	$(C(edge_aftertail)),%edx
	jz	LUDone

// pull the edge out of the edge list
	movl	et_prev(%ecx),%edi
	movl	%ecx,et_prev(%esi)
	movl	%ebx,et_next(%ecx)

// find out where the edge goes in the edge list
LPushBackLoop:
	movl	et_prev(%edi),%ecx
	movl	et_u(%edi),%ebx
	cmpl	%ebx,%eax
	jnl	LPushBackFound

	movl	et_prev(%ecx),%edi
	movl	et_u(%ecx),%ebx
	cmpl	%ebx,%eax
	jl	LPushBackLoop

	movl	%ecx,%edi

// put the edge back into the edge list
LPushBackFound:
	movl	et_next(%edi),%ebx
	movl	%edi,et_prev(%edx)
	movl	%ebx,et_next(%edx)
	movl	%edx,et_next(%edi)
	movl	%edx,et_prev(%ebx)

	movl	%esi,%edx
	movl	et_prev(%esi),%esi

	cmpl	$(C(edge_tail)),%edx
	jnz	LNewEdge

LUDone:
	popl	%ebx			// restore register variables
	popl	%esi
	popl	%edi

	ret

//--------------------------------------------------------------------

#define surf	4		// note this is loaded before any pushes

	.align 4
TrailingEdge:
    movl    st_flags(%esi),%eax   // if (surf->flags & r_translucent_flags)
    andl    C(r_translucent_flags),%eax
    jnz LFlagged

    pushl   %edi // preserve caller register
	movl	st_spanstate(%esi),%eax	// check for edge inversion
	decl	%eax
	jnz	LInverted

	movl	%eax,st_spanstate(%esi)
	movl	st_insubmodel(%esi),%edi
	movl	0x12345678,%edx		// surfaces[1].st_next
LPatch0:
	movl	C(r_bmodelactive),%eax
	subl	%edi,%eax
	cmpl	%esi,%edx
	movl	%eax,C(r_bmodelactive)
	jnz	LNoEmit		// surface isn't on top, just remove

// emit a span (current top going away)
	movl	et_u(%ebx),%eax
	shrl	$20,%eax		// iu = integral pixel u
	movl	st_last_u(%esi),%edx
	movl	st_next(%esi),%edi
	cmpl	%edx,%eax
	jle	LNoEmit2	// iu <= surf->last_u, so nothing to emit

	movl	%eax,st_last_u(%edi)	// surf->next->last_u = iu;
	subl	%edx,%eax
	movl	%edx,espan_t_u(%ebp)	// span->u = surf->last_u;

	movl	%eax,espan_t_count(%ebp)// span->count = iu - span->u;
	movl	C(current_iv),%eax
	movl	%eax,espan_t_v(%ebp)	// span->v = current_iv;
	movl	st_spans(%esi),%eax
	movl	%eax,espan_t_pnext(%ebp)// span->pnext = surf->spans;
	movl	%ebp,st_spans(%esi)	// surf->spans = span;
	addl	$(espan_t_size),%ebp

	movl	st_next(%esi),%edx	// remove the surface from the surface
	movl	st_prev(%esi),%esi	// stack

	movl	%edx,st_next(%esi)
	movl	%esi,st_prev(%edx)
    popl    %edi
	ret

LNoEmit2:
	movl	%eax,st_last_u(%edi)	// surf->next->last_u = iu;
	movl	st_next(%esi),%edx	// remove the surface from the surface
	movl	st_prev(%esi),%esi	// stack

	movl	%edx,st_next(%esi)
	movl	%esi,st_prev(%edx)
    popl    %edi
	ret

LNoEmit:
	movl	st_next(%esi),%edx	// remove the surface from the surface
	movl	st_prev(%esi),%esi	// stack

	movl	%edx,st_next(%esi)
	movl	%esi,st_prev(%edx)
    popl    %edi
	ret

LInverted:
	movl	%eax,st_spanstate(%esi)
    popl    %edi
	ret

LFlagged:
    orl     %eax,%ecx  // flags |= R_TrailingEdge()
    ret

//--------------------------------------------------------------------

// trailing edge only
Lgs_trailing:
	pushl	$Lgs_nextedge
	jmp	TrailingEdge


.globl C(R_GenerateSpans)
C(R_GenerateSpans):
	pushl	%ebp			// preserve caller's stack frame
	pushl	%edi
	pushl	%esi			// preserve register variables
	pushl	%ebx

// clear active surfaces to just the background surface
	movl	C(surfaces),%eax
	movl	C(edge_head_u_shift20),%edx
	addl	$(st_size),%eax
// %ebp = span_p throughout
	movl	C(span_p),%ebp

    xorl    %ecx,%ecx             // flags = 0; Use ecx, so ax is free FP status
	movl	$0,C(r_bmodelactive)  // r_bmodelactive = 0;

	movl	%eax,st_next(%eax)
	movl	%eax,st_prev(%eax)
	movl	%edx,st_last_u(%eax)
	movl	C(edge_head)+et_next,%ebx // edge=edge_head.next

// generate spans
	cmpl	$(C(edge_tail)),%ebx	// done if empty list
	jz	Lgs_lastspan

Lgs_edgeloop:

        movl    et_surfs(%ebx),%edi
        movl    C(surfaces),%eax
        movl    %edi,%esi
        andl    $0xFFFF0000,%edi
        andl    $0x0000FFFF,%esi
	jz	Lgs_leading		// not a trailing edge

// it has a left surface, so a surface is going away for this span
	shll	$(SURF_T_SHIFT),%esi
	addl	%eax,%esi
	testl	%edi,%edi
	jz		Lgs_trailing

// both leading and trailing
	call	TrailingEdge
	movl	C(surfaces),%eax

// ---------------------------------------------------------------
// handle a leading edge
// ---------------------------------------------------------------

Lgs_leading:
    shrl    $16-SURF_T_SHIFT,%edi
	movl	C(surfaces),%eax
	addl	%eax,%edi
	movl	0x12345678,%esi		// surf2 = surfaces[1].next;
LPatch2:

    // if (surf->flags & r_translucent_flags)
    //     return surf_flags & r_translucent_flags;
    movl    st_flags(%edi),%eax   // if (surf->flags & r_translucent_flags)
    andl    C(r_translucent_flags),%eax
    jnz Lxl_skipsurf

    movl	st_spanstate(%edi),%edx
	movl	st_insubmodel(%edi),%eax
	testl	%eax,%eax
	jnz	Lbmodel_leading

// handle a leading non-bmodel edge

// don't start a span if this is an inverted span, with the end edge preceding
// the start edge (that is, we've already seen the end edge)
	testl	%edx,%edx
	jnz	Lxl_done


// if (surf->key < surf2->key)
//		goto newtop;
	incl	%edx
	movl	st_key(%edi),%eax        // %edi holds surf
	movl	%edx,st_spanstate(%edi)
    cmpl    st_key(%esi),%eax        // %esi holds surf2
	jl	Lnewtop

// main sorting loop to search through surface stack until insertion point
// found. Always terminates because background surface is sentinel
// do
// {
// 		surf2 = surf2->next;
// } while (surf->key >= surf2->key);
Lsortloopnb:
	movl	st_next(%esi),%esi
    cmpl    st_key(%esi),%eax
	jge	Lsortloopnb

	jmp	LInsertAndExit


// handle a leading bmodel edge
	.align	4
Lbmodel_leading:

// don't start a span if this is an inverted span, with the end edge preceding
// the start edge (that is, we've already seen the end edge)
	testl	%edx,%edx
	jnz	Lxl_done

	movl	C(r_bmodelactive),%eax
	incl	%edx
	incl	%eax
	movl	%edx,st_spanstate(%edi)
	movl	%eax,C(r_bmodelactive)

// if (surf->key < surf2->key)
//		goto newtop;
	movl	st_key(%edi),%eax
	cmpl	st_key(%esi),%eax
	jl	Lnewtop

// if ((surf->key == surf2->key) && surf->insubmodel)
// {
	jz	Lzcheck_for_newtop

// main sorting loop to search through surface stack until insertion point
// found. Always terminates because background surface is sentinel
// do
// {
// 		surf2 = surf2->next;
// } while (surf->key > surf2->key);
Lsortloop:
	movl	st_next(%esi),%esi
	cmpl	st_key(%esi),%eax
	jg	Lsortloop

	jne	LInsertAndExit

// Do 1/z sorting to see if we've arrived in the right position
	movl	et_u(%ebx),%eax
	subl	$0xFFFFF,%eax
	movl	%eax,Ltemp
	fildl	Ltemp

	fmuls	float_1_div_0100000h	// fu = (float)(edge->u - 0xFFFFF) *
					//      (1.0 / 0x100000);

	fld	%st(0)			// fu | fu
	fmuls	st_d_zistepu(%edi)	// fu*surf->d_zistepu | fu
	flds	C(fv)			// fv | fu*surf->d_zistepu | fu
	fmuls	st_d_zistepv(%edi)	// fv*surf->d_zistepv | fu*surf->d_zistepu | fu
	fxch	%st(1)			// fu*surf->d_zistepu | fv*surf->d_zistepv | fu
	fadds	st_d_ziorigin(%edi)	// fu*surf->d_zistepu + surf->d_ziorigin |
					//  fv*surf->d_zistepv | fu

	flds	st_d_zistepu(%esi)	// surf2->d_zistepu |
					//  fu*surf->d_zistepu + surf->d_ziorigin |
					//  fv*surf->d_zistepv | fu
	fmul	%st(3),%st(0)		// fu*surf2->d_zistepu |
					//  fu*surf->d_zistepu + surf->d_ziorigin |
					//  fv*surf->d_zistepv | fu
	fxch	%st(1)			// fu*surf->d_zistepu + surf->d_ziorigin |
					//  fu*surf2->d_zistepu |
					//  fv*surf->d_zistepv | fu
	faddp	%st(0),%st(2)		// fu*surf2->d_zistepu | newzi | fu

	flds	C(fv)			// fv | fu*surf2->d_zistepu | newzi | fu
	fmuls	st_d_zistepv(%esi)	// fv*surf2->d_zistepv |
					//  fu*surf2->d_zistepu | newzi | fu
	fld	%st(2)			// newzi | fv*surf2->d_zistepv |
					//  fu*surf2->d_zistepu | newzi | fu
	fmuls	float_point_999		// newzibottom | fv*surf2->d_zistepv |
					//  fu*surf2->d_zistepu | newzi | fu

	fxch	%st(2)			// fu*surf2->d_zistepu | fv*surf2->d_zistepv |
					//  newzibottom | newzi | fu
	fadds	st_d_ziorigin(%esi)	// fu*surf2->d_zistepu + surf2->d_ziorigin |
					//  fv*surf2->d_zistepv | newzibottom | newzi |
					//  fu
	faddp	%st(0),%st(1)		// testzi | newzibottom | newzi | fu
	fxch	%st(1)			// newzibottom | testzi | newzi | fu

// if (newzibottom >= testzi)
//     goto Lgotposition;

	fcomp	%st(1)			// testzi | newzi | fu

	fxch	%st(1)			// newzi | testzi | fu
	fmuls	float_1_point_001	// newzitop | testzi | fu
	fxch	%st(1)			// testzi | newzitop | fu

	fnstsw	%ax
	testb	$0x01,%ah
	jz		Lgotposition_fpop3

// if (newzitop >= testzi)
// {

	fcomp	%st(1)			// newzitop | fu
	fnstsw	%ax
	testb	$0x45,%ah
	jz	Lsortloop_fpop2

// if (surf->d_zistepu >= surf2->d_zistepu)
//     goto newtop;

	flds	st_d_zistepu(%edi)	// surf->d_zistepu | newzitop| fu
	fcomps	st_d_zistepu(%esi)	// newzitop | fu
	fnstsw	%ax
	testb	$0x01,%ah
	jz	Lgotposition_fpop2

	fstp	%st(0)			// clear the FPstack
	fstp	%st(0)
	movl	st_key(%edi),%eax
	jmp	Lsortloop


Lgotposition_fpop3:
	fstp	%st(0)
Lgotposition_fpop2:
	fstp	%st(0)
	fstp	%st(0)
	jmp	LInsertAndExit


// emit a span (obscures current top)

Lnewtop_fpop3:
	fstp	%st(0)
Lnewtop_fpop2:
	fstp	%st(0)
	fstp	%st(0)
	movl	st_key(%edi),%eax	// reload the sorting key

Lnewtop:
	movl	et_u(%ebx),%eax
	movl	st_last_u(%esi),%edx
	shrl	$20,%eax                // iu = integral pixel u
	movl	%eax,st_last_u(%edi)    // surf->last_u = iu;
	cmpl	%edx,%eax
	jle	LInsertAndExit              // iu <= surf->last_u, so nothing to emit

    movl    st_flags(%esi),%edx     // !(surf2->flags & r_translucent_flags)
    andl    C(r_translucent_flags),%edx
    jnz LInsertAndExit
    movl    st_last_u(%esi),%edx    // Reload surf2->last_u to continue

	subl	%edx,%eax               // %eax contains iu, %edx contains surf2->last_u (i.e. iu - span->u)
	movl	%edx,espan_t_u(%ebp)	// span->u = surf->last_u;

	movl	%eax,espan_t_count(%ebp)// span->count = iu - span->u;
	movl	C(current_iv),%eax
	movl	%eax,espan_t_v(%ebp)	// span->v = current_iv;
	movl	st_spans(%esi),%eax
	movl	%eax,espan_t_pnext(%ebp)// span->pnext = surf->spans;
	movl	%ebp,st_spans(%esi)	// surf->spans = span;
	addl	$(espan_t_size),%ebp

LInsertAndExit:
// insert before surf2
	movl	%esi,st_next(%edi)	// surf->next = surf2;
	movl	st_prev(%esi),%eax
	movl	%eax,st_prev(%edi)	// surf->prev = surf2->prev;
	movl	%edi,st_prev(%esi)	// surf2->prev = surf;
	movl	%edi,st_next(%eax)	// surf2->prev->next = surf;

// ---------------------------------------------------------------
// leading edge done
// ---------------------------------------------------------------

// ---------------------------------------------------------------
// see if there are any more edges
// ---------------------------------------------------------------

Lgs_nextedge:
	movl	et_next(%ebx),%ebx
	cmpl	$(C(edge_tail)),%ebx
	jnz	Lgs_edgeloop

// clean up at the right edge (R_CleanupSpan)
Lgs_lastspan:

// now that we've reached the right edge of the screen, we're done with any
// unfinished surfaces, so emit a span for whatever's on top
	movl	0x12345678,%esi		// surfaces[1].st_next
LPatch3:
	movl	C(edge_tail_u_shift20),%eax  // if (iu > surf->last_u
	xorl	%edi,%edi
	movl	st_last_u(%esi),%edx
	subl	%edx,%eax
	jle	Lgs_resetspanstate

    movl    st_flags(%esi),%ebx          //    && !(surf->flags & r_translucent_flags))
    andl    C(r_translucent_flags),%ebx
    jnz Lgs_resetspanstate

	movl	%edx,espan_t_u(%ebp)
	movl	%eax,espan_t_count(%ebp)
	movl	C(current_iv),%eax
	movl	%eax,espan_t_v(%ebp)
	movl	st_spans(%esi),%eax
	movl	%eax,espan_t_pnext(%ebp)
	movl	%ebp,st_spans(%esi)
	addl	$(espan_t_size),%ebp

// reset spanstate for all surfaces in the surface stack
Lgs_resetspanstate:
	movl	%edi,st_spanstate(%esi)
	movl	st_next(%esi),%esi
	cmpl	$0x12345678,%esi	// &surfaces[1]
LPatch4:
	jnz	Lgs_resetspanstate

// store the final span_p
	movl	%ebp,C(span_p)

	popl	%ebx			// restore caller register variables
	popl	%esi
	popl	%edi
	popl	%ebp			// restore the caller's stack frame
    movl    %ecx,%eax       // place flags into return register
	ret

    .align  4
Lxl_skipsurf:          // The added flag is in %eax
    orl     %eax,%ecx  // flags |= R_LeadingEdge()
    jmp Lgs_nextedge

	.align	4
Lxl_done:
	incl	%edx
	movl	%edx,st_spanstate(%edi)
	jmp	Lgs_nextedge

// ---------------------------------------------------------------
// 1/z sorting for bmodels in the same leaf
// ---------------------------------------------------------------

	.align	4
Lzcheck_for_newtop:
	movl	et_u(%ebx),%eax
	subl	$0xFFFFF,%eax
	movl	%eax,Ltemp
	fildl	Ltemp

	fmuls	float_1_div_0100000h	// fu = (float)(edge->u - 0xFFFFF) *
					//      (1.0 / 0x100000);

	fld	%st(0)			// fu | fu
	fmuls	st_d_zistepu(%edi)	// fu*surf->d_zistepu | fu
	flds	C(fv)			// fv | fu*surf->d_zistepu | fu
	fmuls	st_d_zistepv(%edi)	// fv*surf->d_zistepv | fu*surf->d_zistepu | fu
	fxch	%st(1)			// fu*surf->d_zistepu | fv*surf->d_zistepv | fu
	fadds	st_d_ziorigin(%edi)	// fu*surf->d_zistepu + surf->d_ziorigin |
					//  fv*surf->d_zistepv | fu

	flds	st_d_zistepu(%esi)	// surf2->d_zistepu |
					//  fu*surf->d_zistepu + surf->d_ziorigin |
					//  fv*surf->d_zistepv | fu
	fmul	%st(3),%st(0)		// fu*surf2->d_zistepu |
					//  fu*surf->d_zistepu + surf->d_ziorigin |
					//  fv*surf->d_zistepv | fu
	fxch	%st(1)			// fu*surf->d_zistepu + surf->d_ziorigin |
					//  fu*surf2->d_zistepu |
					//  fv*surf->d_zistepv | fu
	faddp	%st(0),%st(2)		// fu*surf2->d_zistepu | newzi | fu

	flds	C(fv)			// fv | fu*surf2->d_zistepu | newzi | fu
	fmuls	st_d_zistepv(%esi)	// fv*surf2->d_zistepv |
					//  fu*surf2->d_zistepu | newzi | fu
	fld	%st(2)			// newzi | fv*surf2->d_zistepv |
					//  fu*surf2->d_zistepu | newzi | fu
	fmuls	float_point_999		// newzibottom | fv*surf2->d_zistepv |
					//  fu*surf2->d_zistepu | newzi | fu

	fxch	%st(2)			// fu*surf2->d_zistepu | fv*surf2->d_zistepv |
					//  newzibottom | newzi | fu
	fadds	st_d_ziorigin(%esi)	// fu*surf2->d_zistepu + surf2->d_ziorigin |
					//  fv*surf2->d_zistepv | newzibottom | newzi |
					//  fu
	faddp	%st(0),%st(1)		// testzi | newzibottom | newzi | fu
	fxch	%st(1)			// newzibottom | testzi | newzi | fu

// if (newzibottom >= testzi)
//     goto newtop;

	fcomp	%st(1)			// testzi | newzi | fu

	fxch	%st(1)			// newzi | testzi | fu
	fmuls	float_1_point_001	// newzitop | testzi | fu
	fxch	%st(1)			// testzi | newzitop | fu

	fnstsw	%ax
	testb	$0x01,%ah
	jz	Lnewtop_fpop3

// if (newzitop >= testzi)
// {

	fcomp	%st(1)			// newzitop | fu
	fnstsw	%ax
	testb	$0x45,%ah
	jz	Lsortloop_fpop2

// if (surf->d_zistepu >= surf2->d_zistepu)
//     goto newtop;

	flds	st_d_zistepu(%edi)	// surf->d_zistepu | newzitop | fu
	fcomps	st_d_zistepu(%esi)	// newzitop | fu
	fnstsw	%ax
	testb	$0x01,%ah
	jz	Lnewtop_fpop2

Lsortloop_fpop2:
	fstp	%st(0)			// clear the FP stack
	fstp	%st(0)
	movl	st_key(%edi),%eax
	jmp	Lsortloop


.globl C(R_EdgeCodeEnd)
C(R_EdgeCodeEnd):


//----------------------------------------------------------------------
// Surface array address code patching routine
//----------------------------------------------------------------------

	.align 4
.globl C(R_SurfacePatch)
C(R_SurfacePatch):

	movl	C(surfaces),%eax
	addl	$(st_size),%eax
	movl	%eax,LPatch4-4

	addl	$(st_next),%eax
	movl	%eax,LPatch0-4
	movl	%eax,LPatch2-4
	movl	%eax,LPatch3-4

	ret
