0,0 → 1,750 |
/* |
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. |
|
*/ |
// |
// r_edgea.s |
// x86 assembly-language edge-processing code. |
// |
|
#include "asm_i386.h" |
#include "quakeasm.h" |
#include "asm_draw.h" |
|
#if id386 |
|
.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 interleaving |
#define edgelist 8+12 // 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_spanstate(%esi),%eax // check for edge inversion |
decl %eax |
jnz LInverted |
|
movl %eax,st_spanstate(%esi) |
movl st_insubmodel(%esi),%ecx |
movl 0x12345678,%edx // surfaces[1].st_next |
LPatch0: |
movl C(r_bmodelactive),%eax |
subl %ecx,%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),%ecx |
cmpl %edx,%eax |
jle LNoEmit2 // iu <= surf->last_u, so nothing to emit |
|
movl %eax,st_last_u(%ecx) // 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) |
ret |
|
LNoEmit2: |
movl %eax,st_last_u(%ecx) // 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) |
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) |
ret |
|
LInverted: |
movl %eax,st_spanstate(%esi) |
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 |
|
movl $0,C(r_bmodelactive) |
|
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 $0xFFFF,%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: |
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 |
movl %edx,st_spanstate(%edi) |
movl st_key(%esi),%ecx |
cmpl %ecx,%eax |
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 |
movl st_key(%esi),%ecx |
cmpl %ecx,%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),%ecx |
incl %edx |
incl %ecx |
movl %edx,st_spanstate(%edi) |
movl %ecx,C(r_bmodelactive) |
|
// if (surf->key < surf2->key) |
// goto newtop; |
movl st_key(%edi),%eax |
movl st_key(%esi),%ecx |
cmpl %ecx,%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 |
movl st_key(%esi),%ecx |
cmpl %ecx,%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 |
|
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 |
|
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 |
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 |
xorl %ecx,%ecx |
movl st_last_u(%esi),%edx |
subl %edx,%eax |
jle 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 %ecx,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 register variables |
popl %esi |
popl %edi |
popl %ebp // restore the caller's stack frame |
ret |
|
|
// --------------------------------------------------------------- |
// 1/z sorting for bmodels in the same leaf |
// --------------------------------------------------------------- |
.align 4 |
Lxl_done: |
incl %edx |
movl %edx,st_spanstate(%edi) |
|
jmp Lgs_nextedge |
|
|
.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 |
|
#endif // id386 |
|