1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20//
21// r_edgea.s
22// x86 assembly-language edge-processing code.
23//
24
25#include "asm_i386.h"
26#include "quakeasm.h"
27#include "asm_draw.h"
28
29#if	id386
30
31	.data
32Ltemp:					.long	0
33float_1_div_0100000h:	.long	0x35800000	// 1.0/(float)0x100000
34float_point_999:		.single	0.999
35float_1_point_001:		.single	1.001
36
37	.text
38
39//--------------------------------------------------------------------
40
41#define edgestoadd	4+8		// note odd stack offsets because of interleaving
42#define edgelist	8+12	// with pushes
43
44.globl C(R_EdgeCodeStart)
45C(R_EdgeCodeStart):
46
47.globl C(R_InsertNewEdges)
48C(R_InsertNewEdges):
49	pushl	%edi
50	pushl	%esi				// preserve register variables
51	movl	edgestoadd(%esp),%edx
52	pushl	%ebx
53	movl	edgelist(%esp),%ecx
54
55LDoNextEdge:
56	movl	et_u(%edx),%eax
57	movl	%edx,%edi
58
59LContinueSearch:
60	movl	et_u(%ecx),%ebx
61	movl	et_next(%ecx),%esi
62	cmpl	%ebx,%eax
63	jle		LAddedge
64	movl	et_u(%esi),%ebx
65	movl	et_next(%esi),%ecx
66	cmpl	%ebx,%eax
67	jle		LAddedge2
68	movl	et_u(%ecx),%ebx
69	movl	et_next(%ecx),%esi
70	cmpl	%ebx,%eax
71	jle		LAddedge
72	movl	et_u(%esi),%ebx
73	movl	et_next(%esi),%ecx
74	cmpl	%ebx,%eax
75	jg		LContinueSearch
76
77LAddedge2:
78	movl	et_next(%edx),%edx
79	movl	et_prev(%esi),%ebx
80	movl	%esi,et_next(%edi)
81	movl	%ebx,et_prev(%edi)
82	movl	%edi,et_next(%ebx)
83	movl	%edi,et_prev(%esi)
84	movl	%esi,%ecx
85
86	cmpl	$0,%edx
87	jnz		LDoNextEdge
88	jmp		LDone
89
90	.align 4
91LAddedge:
92	movl	et_next(%edx),%edx
93	movl	et_prev(%ecx),%ebx
94	movl	%ecx,et_next(%edi)
95	movl	%ebx,et_prev(%edi)
96	movl	%edi,et_next(%ebx)
97	movl	%edi,et_prev(%ecx)
98
99	cmpl	$0,%edx
100	jnz		LDoNextEdge
101
102LDone:
103	popl	%ebx				// restore register variables
104	popl	%esi
105	popl	%edi
106
107	ret
108
109//--------------------------------------------------------------------
110
111#define predge	4+4
112
113.globl C(R_RemoveEdges)
114C(R_RemoveEdges):
115	pushl	%ebx
116	movl	predge(%esp),%eax
117
118Lre_loop:
119	movl	et_next(%eax),%ecx
120	movl	et_nextremove(%eax),%ebx
121	movl	et_prev(%eax),%edx
122	testl	%ebx,%ebx
123	movl	%edx,et_prev(%ecx)
124	jz		Lre_done
125	movl	%ecx,et_next(%edx)
126
127	movl	et_next(%ebx),%ecx
128	movl	et_prev(%ebx),%edx
129	movl	et_nextremove(%ebx),%eax
130	movl	%edx,et_prev(%ecx)
131	testl	%eax,%eax
132	movl	%ecx,et_next(%edx)
133	jnz		Lre_loop
134
135	popl	%ebx
136	ret
137
138Lre_done:
139	movl	%ecx,et_next(%edx)
140	popl	%ebx
141
142	ret
143
144//--------------------------------------------------------------------
145
146#define pedgelist	4+4		// note odd stack offset because of interleaving
147							// with pushes
148
149.globl C(R_StepActiveU)
150C(R_StepActiveU):
151	pushl	%edi
152	movl	pedgelist(%esp),%edx
153	pushl	%esi				// preserve register variables
154	pushl	%ebx
155
156	movl	et_prev(%edx),%esi
157
158LNewEdge:
159	movl	et_u(%esi),%edi
160
161LNextEdge:
162	movl	et_u(%edx),%eax
163	movl	et_u_step(%edx),%ebx
164	addl	%ebx,%eax
165	movl	et_next(%edx),%esi
166	movl	%eax,et_u(%edx)
167	cmpl	%edi,%eax
168	jl		LPushBack
169
170	movl	et_u(%esi),%edi
171	movl	et_u_step(%esi),%ebx
172	addl	%ebx,%edi
173	movl	et_next(%esi),%edx
174	movl	%edi,et_u(%esi)
175	cmpl	%eax,%edi
176	jl		LPushBack2
177
178	movl	et_u(%edx),%eax
179	movl	et_u_step(%edx),%ebx
180	addl	%ebx,%eax
181	movl	et_next(%edx),%esi
182	movl	%eax,et_u(%edx)
183	cmpl	%edi,%eax
184	jl		LPushBack
185
186	movl	et_u(%esi),%edi
187	movl	et_u_step(%esi),%ebx
188	addl	%ebx,%edi
189	movl	et_next(%esi),%edx
190	movl	%edi,et_u(%esi)
191	cmpl	%eax,%edi
192	jnl		LNextEdge
193
194LPushBack2:
195	movl	%edx,%ebx
196	movl	%edi,%eax
197	movl	%esi,%edx
198	movl	%ebx,%esi
199
200LPushBack:
201// push it back to keep it sorted
202	movl	et_prev(%edx),%ecx
203	movl	et_next(%edx),%ebx
204
205// done if the -1 in edge_aftertail triggered this
206	cmpl	$(C(edge_aftertail)),%edx
207	jz		LUDone
208
209// pull the edge out of the edge list
210	movl	et_prev(%ecx),%edi
211	movl	%ecx,et_prev(%esi)
212	movl	%ebx,et_next(%ecx)
213
214// find out where the edge goes in the edge list
215LPushBackLoop:
216	movl	et_prev(%edi),%ecx
217	movl	et_u(%edi),%ebx
218	cmpl	%ebx,%eax
219	jnl		LPushBackFound
220
221	movl	et_prev(%ecx),%edi
222	movl	et_u(%ecx),%ebx
223	cmpl	%ebx,%eax
224	jl		LPushBackLoop
225
226	movl	%ecx,%edi
227
228// put the edge back into the edge list
229LPushBackFound:
230	movl	et_next(%edi),%ebx
231	movl	%edi,et_prev(%edx)
232	movl	%ebx,et_next(%edx)
233	movl	%edx,et_next(%edi)
234	movl	%edx,et_prev(%ebx)
235
236	movl	%esi,%edx
237	movl	et_prev(%esi),%esi
238
239	cmpl	$(C(edge_tail)),%edx
240	jnz		LNewEdge
241
242LUDone:
243	popl	%ebx				// restore register variables
244	popl	%esi
245	popl	%edi
246
247	ret
248
249//--------------------------------------------------------------------
250
251#define surf	4		// note this is loaded before any pushes
252
253	.align 4
254TrailingEdge:
255	movl	st_spanstate(%esi),%eax	// check for edge inversion
256	decl	%eax
257	jnz		LInverted
258
259	movl	%eax,st_spanstate(%esi)
260	movl	st_insubmodel(%esi),%ecx
261	movl	0x12345678,%edx		// surfaces[1].st_next
262LPatch0:
263	movl	C(r_bmodelactive),%eax
264	subl	%ecx,%eax
265	cmpl	%esi,%edx
266	movl	%eax,C(r_bmodelactive)
267	jnz		LNoEmit				// surface isn't on top, just remove
268
269// emit a span (current top going away)
270	movl	et_u(%ebx),%eax
271	shrl	$20,%eax				// iu = integral pixel u
272	movl	st_last_u(%esi),%edx
273	movl	st_next(%esi),%ecx
274	cmpl	%edx,%eax
275	jle		LNoEmit2				// iu <= surf->last_u, so nothing to emit
276
277	movl	%eax,st_last_u(%ecx)	// surf->next->last_u = iu;
278	subl	%edx,%eax
279	movl	%edx,espan_t_u(%ebp)		// span->u = surf->last_u;
280
281	movl	%eax,espan_t_count(%ebp)	// span->count = iu - span->u;
282	movl	C(current_iv),%eax
283	movl	%eax,espan_t_v(%ebp)		// span->v = current_iv;
284	movl	st_spans(%esi),%eax
285	movl	%eax,espan_t_pnext(%ebp)	// span->pnext = surf->spans;
286	movl	%ebp,st_spans(%esi)			// surf->spans = span;
287	addl	$(espan_t_size),%ebp
288
289	movl	st_next(%esi),%edx		// remove the surface from the surface
290	movl	st_prev(%esi),%esi		// stack
291
292	movl	%edx,st_next(%esi)
293	movl	%esi,st_prev(%edx)
294	ret
295
296LNoEmit2:
297	movl	%eax,st_last_u(%ecx)	// surf->next->last_u = iu;
298	movl	st_next(%esi),%edx		// remove the surface from the surface
299	movl	st_prev(%esi),%esi		// stack
300
301	movl	%edx,st_next(%esi)
302	movl	%esi,st_prev(%edx)
303	ret
304
305LNoEmit:
306	movl	st_next(%esi),%edx		// remove the surface from the surface
307	movl	st_prev(%esi),%esi		// stack
308
309	movl	%edx,st_next(%esi)
310	movl	%esi,st_prev(%edx)
311	ret
312
313LInverted:
314	movl	%eax,st_spanstate(%esi)
315	ret
316
317//--------------------------------------------------------------------
318
319// trailing edge only
320Lgs_trailing:
321	pushl	$Lgs_nextedge
322	jmp		TrailingEdge
323
324
325.globl C(R_GenerateSpans)
326C(R_GenerateSpans):
327	pushl	%ebp				// preserve caller's stack frame
328	pushl	%edi
329	pushl	%esi				// preserve register variables
330	pushl	%ebx
331
332// clear active surfaces to just the background surface
333	movl	C(surfaces),%eax
334	movl	C(edge_head_u_shift20),%edx
335	addl	$(st_size),%eax
336// %ebp = span_p throughout
337	movl	C(span_p),%ebp
338
339	movl	$0,C(r_bmodelactive)
340
341	movl	%eax,st_next(%eax)
342	movl	%eax,st_prev(%eax)
343	movl	%edx,st_last_u(%eax)
344	movl	C(edge_head)+et_next,%ebx		// edge=edge_head.next
345
346// generate spans
347	cmpl	$(C(edge_tail)),%ebx		// done if empty list
348	jz		Lgs_lastspan
349
350Lgs_edgeloop:
351
352	movl	et_surfs(%ebx),%edi
353	movl	C(surfaces),%eax
354	movl	%edi,%esi
355	andl	$0xFFFF0000,%edi
356	andl	$0xFFFF,%esi
357	jz		Lgs_leading		// not a trailing edge
358
359// it has a left surface, so a surface is going away for this span
360	shll	$(SURF_T_SHIFT),%esi
361	addl	%eax,%esi
362	testl	%edi,%edi
363	jz		Lgs_trailing
364
365// both leading and trailing
366	call	TrailingEdge
367	movl	C(surfaces),%eax
368
369// ---------------------------------------------------------------
370// handle a leading edge
371// ---------------------------------------------------------------
372
373Lgs_leading:
374	shrl	$16-SURF_T_SHIFT,%edi
375	movl	C(surfaces),%eax
376	addl	%eax,%edi
377	movl	0x12345678,%esi		// surf2 = surfaces[1].next;
378LPatch2:
379	movl	st_spanstate(%edi),%edx
380	movl	st_insubmodel(%edi),%eax
381	testl	%eax,%eax
382	jnz		Lbmodel_leading
383
384// handle a leading non-bmodel edge
385
386// don't start a span if this is an inverted span, with the end edge preceding
387// the start edge (that is, we've already seen the end edge)
388	testl	%edx,%edx
389	jnz		Lxl_done
390
391
392// if (surf->key < surf2->key)
393//		goto newtop;
394	incl	%edx
395	movl	st_key(%edi),%eax
396	movl	%edx,st_spanstate(%edi)
397	movl	st_key(%esi),%ecx
398	cmpl	%ecx,%eax
399	jl		Lnewtop
400
401// main sorting loop to search through surface stack until insertion point
402// found. Always terminates because background surface is sentinel
403// do
404// {
405// 		surf2 = surf2->next;
406// } while (surf->key >= surf2->key);
407Lsortloopnb:
408	movl	st_next(%esi),%esi
409	movl	st_key(%esi),%ecx
410	cmpl	%ecx,%eax
411	jge		Lsortloopnb
412
413	jmp		LInsertAndExit
414
415
416// handle a leading bmodel edge
417	.align	4
418Lbmodel_leading:
419
420// don't start a span if this is an inverted span, with the end edge preceding
421// the start edge (that is, we've already seen the end edge)
422	testl	%edx,%edx
423	jnz		Lxl_done
424
425	movl	C(r_bmodelactive),%ecx
426	incl	%edx
427	incl	%ecx
428	movl	%edx,st_spanstate(%edi)
429	movl	%ecx,C(r_bmodelactive)
430
431// if (surf->key < surf2->key)
432//		goto newtop;
433	movl	st_key(%edi),%eax
434	movl	st_key(%esi),%ecx
435	cmpl	%ecx,%eax
436	jl		Lnewtop
437
438// if ((surf->key == surf2->key) && surf->insubmodel)
439// {
440	jz		Lzcheck_for_newtop
441
442// main sorting loop to search through surface stack until insertion point
443// found. Always terminates because background surface is sentinel
444// do
445// {
446// 		surf2 = surf2->next;
447// } while (surf->key > surf2->key);
448Lsortloop:
449	movl	st_next(%esi),%esi
450	movl	st_key(%esi),%ecx
451	cmpl	%ecx,%eax
452	jg		Lsortloop
453
454	jne		LInsertAndExit
455
456// Do 1/z sorting to see if we've arrived in the right position
457	movl	et_u(%ebx),%eax
458	subl	$0xFFFFF,%eax
459	movl	%eax,Ltemp
460	fildl	Ltemp
461
462	fmuls	float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) *
463								//      (1.0 / 0x100000);
464
465	fld		%st(0)				// fu | fu
466	fmuls	st_d_zistepu(%edi)	// fu*surf->d_zistepu | fu
467	flds	C(fv)					// fv | fu*surf->d_zistepu | fu
468	fmuls	st_d_zistepv(%edi)	// fv*surf->d_zistepv | fu*surf->d_zistepu | fu
469	fxch	%st(1)				// fu*surf->d_zistepu | fv*surf->d_zistepv | fu
470	fadds	st_d_ziorigin(%edi)	// fu*surf->d_zistepu + surf->d_ziorigin |
471								//  fv*surf->d_zistepv | fu
472
473	flds	st_d_zistepu(%esi)	// surf2->d_zistepu |
474								//  fu*surf->d_zistepu + surf->d_ziorigin |
475								//  fv*surf->d_zistepv | fu
476	fmul	%st(3),%st(0)		// fu*surf2->d_zistepu |
477								//  fu*surf->d_zistepu + surf->d_ziorigin |
478								//  fv*surf->d_zistepv | fu
479	fxch	%st(1)				// fu*surf->d_zistepu + surf->d_ziorigin |
480								//  fu*surf2->d_zistepu |
481								//  fv*surf->d_zistepv | fu
482	faddp	%st(0),%st(2)		// fu*surf2->d_zistepu | newzi | fu
483
484	flds	C(fv)					// fv | fu*surf2->d_zistepu | newzi | fu
485	fmuls	st_d_zistepv(%esi)	// fv*surf2->d_zistepv |
486								//  fu*surf2->d_zistepu | newzi | fu
487	fld		%st(2)				// newzi | fv*surf2->d_zistepv |
488								//  fu*surf2->d_zistepu | newzi | fu
489	fmuls	float_point_999		// newzibottom | fv*surf2->d_zistepv |
490								//  fu*surf2->d_zistepu | newzi | fu
491
492	fxch	%st(2)				// fu*surf2->d_zistepu | fv*surf2->d_zistepv |
493								//  newzibottom | newzi | fu
494	fadds	st_d_ziorigin(%esi)	// fu*surf2->d_zistepu + surf2->d_ziorigin |
495								//  fv*surf2->d_zistepv | newzibottom | newzi |
496								//  fu
497	faddp	%st(0),%st(1)		// testzi | newzibottom | newzi | fu
498	fxch	%st(1)				// newzibottom | testzi | newzi | fu
499
500// if (newzibottom >= testzi)
501//     goto Lgotposition;
502
503	fcomp	%st(1)				// testzi | newzi | fu
504
505	fxch	%st(1)				// newzi | testzi | fu
506	fmuls	float_1_point_001	// newzitop | testzi | fu
507	fxch	%st(1)				// testzi | newzitop | fu
508
509	fnstsw	%ax
510	testb	$0x01,%ah
511	jz		Lgotposition_fpop3
512
513// if (newzitop >= testzi)
514// {
515
516	fcomp	%st(1)				// newzitop | fu
517	fnstsw	%ax
518	testb	$0x45,%ah
519	jz		Lsortloop_fpop2
520
521// if (surf->d_zistepu >= surf2->d_zistepu)
522//     goto newtop;
523
524	flds	st_d_zistepu(%edi)	// surf->d_zistepu | newzitop| fu
525	fcomps	st_d_zistepu(%esi)	// newzitop | fu
526	fnstsw	%ax
527	testb	$0x01,%ah
528	jz		Lgotposition_fpop2
529
530	fstp	%st(0)				// clear the FPstack
531	fstp	%st(0)
532	movl	st_key(%edi),%eax
533	jmp		Lsortloop
534
535
536Lgotposition_fpop3:
537	fstp	%st(0)
538Lgotposition_fpop2:
539	fstp	%st(0)
540	fstp	%st(0)
541	jmp		LInsertAndExit
542
543
544// emit a span (obscures current top)
545
546Lnewtop_fpop3:
547	fstp	%st(0)
548Lnewtop_fpop2:
549	fstp	%st(0)
550	fstp	%st(0)
551	movl	st_key(%edi),%eax		// reload the sorting key
552
553Lnewtop:
554	movl	et_u(%ebx),%eax
555	movl	st_last_u(%esi),%edx
556	shrl	$20,%eax				// iu = integral pixel u
557	movl	%eax,st_last_u(%edi)	// surf->last_u = iu;
558	cmpl	%edx,%eax
559	jle		LInsertAndExit			// iu <= surf->last_u, so nothing to emit
560
561	subl	%edx,%eax
562	movl	%edx,espan_t_u(%ebp)		// span->u = surf->last_u;
563
564	movl	%eax,espan_t_count(%ebp)	// span->count = iu - span->u;
565	movl	C(current_iv),%eax
566	movl	%eax,espan_t_v(%ebp)		// span->v = current_iv;
567	movl	st_spans(%esi),%eax
568	movl	%eax,espan_t_pnext(%ebp)	// span->pnext = surf->spans;
569	movl	%ebp,st_spans(%esi)			// surf->spans = span;
570	addl	$(espan_t_size),%ebp
571
572LInsertAndExit:
573// insert before surf2
574	movl	%esi,st_next(%edi)		// surf->next = surf2;
575	movl	st_prev(%esi),%eax
576	movl	%eax,st_prev(%edi)		// surf->prev = surf2->prev;
577	movl	%edi,st_prev(%esi)		// surf2->prev = surf;
578	movl	%edi,st_next(%eax)		// surf2->prev->next = surf;
579
580// ---------------------------------------------------------------
581// leading edge done
582// ---------------------------------------------------------------
583
584// ---------------------------------------------------------------
585// see if there are any more edges
586// ---------------------------------------------------------------
587
588Lgs_nextedge:
589	movl	et_next(%ebx),%ebx
590	cmpl	$(C(edge_tail)),%ebx
591	jnz		Lgs_edgeloop
592
593// clean up at the right edge
594Lgs_lastspan:
595
596// now that we've reached the right edge of the screen, we're done with any
597// unfinished surfaces, so emit a span for whatever's on top
598	movl	0x12345678,%esi		// surfaces[1].st_next
599LPatch3:
600	movl	C(edge_tail_u_shift20),%eax
601	xorl	%ecx,%ecx
602	movl	st_last_u(%esi),%edx
603	subl	%edx,%eax
604	jle		Lgs_resetspanstate
605
606	movl	%edx,espan_t_u(%ebp)
607	movl	%eax,espan_t_count(%ebp)
608	movl	C(current_iv),%eax
609	movl	%eax,espan_t_v(%ebp)
610	movl	st_spans(%esi),%eax
611	movl	%eax,espan_t_pnext(%ebp)
612	movl	%ebp,st_spans(%esi)
613	addl	$(espan_t_size),%ebp
614
615// reset spanstate for all surfaces in the surface stack
616Lgs_resetspanstate:
617	movl	%ecx,st_spanstate(%esi)
618	movl	st_next(%esi),%esi
619	cmpl	$0x12345678,%esi		// &surfaces[1]
620LPatch4:
621	jnz		Lgs_resetspanstate
622
623// store the final span_p
624	movl	%ebp,C(span_p)
625
626	popl	%ebx				// restore register variables
627	popl	%esi
628	popl	%edi
629	popl	%ebp				// restore the caller's stack frame
630	ret
631
632
633// ---------------------------------------------------------------
634// 1/z sorting for bmodels in the same leaf
635// ---------------------------------------------------------------
636	.align	4
637Lxl_done:
638	incl	%edx
639	movl	%edx,st_spanstate(%edi)
640
641	jmp		Lgs_nextedge
642
643
644	.align	4
645Lzcheck_for_newtop:
646	movl	et_u(%ebx),%eax
647	subl	$0xFFFFF,%eax
648	movl	%eax,Ltemp
649	fildl	Ltemp
650
651	fmuls	float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) *
652								//      (1.0 / 0x100000);
653
654	fld		%st(0)				// fu | fu
655	fmuls	st_d_zistepu(%edi)	// fu*surf->d_zistepu | fu
656	flds	C(fv)				// fv | fu*surf->d_zistepu | fu
657	fmuls	st_d_zistepv(%edi)	// fv*surf->d_zistepv | fu*surf->d_zistepu | fu
658	fxch	%st(1)				// fu*surf->d_zistepu | fv*surf->d_zistepv | fu
659	fadds	st_d_ziorigin(%edi)	// fu*surf->d_zistepu + surf->d_ziorigin |
660								//  fv*surf->d_zistepv | fu
661
662	flds	st_d_zistepu(%esi)	// surf2->d_zistepu |
663								//  fu*surf->d_zistepu + surf->d_ziorigin |
664								//  fv*surf->d_zistepv | fu
665	fmul	%st(3),%st(0)		// fu*surf2->d_zistepu |
666								//  fu*surf->d_zistepu + surf->d_ziorigin |
667								//  fv*surf->d_zistepv | fu
668	fxch	%st(1)				// fu*surf->d_zistepu + surf->d_ziorigin |
669								//  fu*surf2->d_zistepu |
670								//  fv*surf->d_zistepv | fu
671	faddp	%st(0),%st(2)		// fu*surf2->d_zistepu | newzi | fu
672
673	flds	C(fv)				// fv | fu*surf2->d_zistepu | newzi | fu
674	fmuls	st_d_zistepv(%esi)	// fv*surf2->d_zistepv |
675								//  fu*surf2->d_zistepu | newzi | fu
676	fld		%st(2)				// newzi | fv*surf2->d_zistepv |
677								//  fu*surf2->d_zistepu | newzi | fu
678	fmuls	float_point_999		// newzibottom | fv*surf2->d_zistepv |
679								//  fu*surf2->d_zistepu | newzi | fu
680
681	fxch	%st(2)				// fu*surf2->d_zistepu | fv*surf2->d_zistepv |
682								//  newzibottom | newzi | fu
683	fadds	st_d_ziorigin(%esi)	// fu*surf2->d_zistepu + surf2->d_ziorigin |
684								//  fv*surf2->d_zistepv | newzibottom | newzi |
685								//  fu
686	faddp	%st(0),%st(1)		// testzi | newzibottom | newzi | fu
687	fxch	%st(1)				// newzibottom | testzi | newzi | fu
688
689// if (newzibottom >= testzi)
690//     goto newtop;
691
692	fcomp	%st(1)				// testzi | newzi | fu
693
694	fxch	%st(1)				// newzi | testzi | fu
695	fmuls	float_1_point_001	// newzitop | testzi | fu
696	fxch	%st(1)				// testzi | newzitop | fu
697
698	fnstsw	%ax
699	testb	$0x01,%ah
700	jz		Lnewtop_fpop3
701
702// if (newzitop >= testzi)
703// {
704
705	fcomp	%st(1)				// newzitop | fu
706	fnstsw	%ax
707	testb	$0x45,%ah
708	jz		Lsortloop_fpop2
709
710// if (surf->d_zistepu >= surf2->d_zistepu)
711//     goto newtop;
712
713	flds	st_d_zistepu(%edi)	// surf->d_zistepu | newzitop | fu
714	fcomps	st_d_zistepu(%esi)	// newzitop | fu
715	fnstsw	%ax
716	testb	$0x01,%ah
717	jz		Lnewtop_fpop2
718
719Lsortloop_fpop2:
720	fstp	%st(0)				// clear the FP stack
721	fstp	%st(0)
722	movl	st_key(%edi),%eax
723	jmp		Lsortloop
724
725
726.globl C(R_EdgeCodeEnd)
727C(R_EdgeCodeEnd):
728
729
730//----------------------------------------------------------------------
731// Surface array address code patching routine
732//----------------------------------------------------------------------
733
734	.align 4
735.globl C(R_SurfacePatch)
736C(R_SurfacePatch):
737
738	movl	C(surfaces),%eax
739	addl	$(st_size),%eax
740	movl	%eax,LPatch4-4
741
742	addl	$(st_next),%eax
743	movl	%eax,LPatch0-4
744	movl	%eax,LPatch2-4
745	movl	%eax,LPatch3-4
746
747	ret
748
749#endif	// id386
750
751