aboutsummaryrefslogtreecommitdiffstats
path: root/QW/client/r_drawa.s
diff options
context:
space:
mode:
Diffstat (limited to 'QW/client/r_drawa.s')
-rw-r--r--QW/client/r_drawa.s838
1 files changed, 838 insertions, 0 deletions
diff --git a/QW/client/r_drawa.s b/QW/client/r_drawa.s
new file mode 100644
index 0000000..3cb2239
--- /dev/null
+++ b/QW/client/r_drawa.s
@@ -0,0 +1,838 @@
+/*
+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_drawa.s
+// x86 assembly-language edge clipping and emission code
+//
+
+#include "asm_i386.h"
+#include "quakeasm.h"
+#include "asm_draw.h"
+#include "d_ifacea.h"
+
+#if id386
+
+// !!! if these are changed, they must be changed in r_draw.c too !!!
+#define FULLY_CLIPPED_CACHED 0x80000000
+#define FRAMECOUNT_MASK 0x7FFFFFFF
+
+ .data
+
+Ld0: .single 0.0
+Ld1: .single 0.0
+Lstack: .long 0
+Lfp_near_clip: .single NEAR_CLIP
+Lceilv0: .long 0
+Lv: .long 0
+Lu0: .long 0
+Lv0: .long 0
+Lzi0: .long 0
+
+ .text
+
+//----------------------------------------------------------------------
+// edge clipping code
+//----------------------------------------------------------------------
+
+#define pv0 4+12
+#define pv1 8+12
+#define clip 12+12
+
+ .align 4
+.globl C(R_ClipEdge)
+C(R_ClipEdge):
+ pushl %esi // preserve register variables
+ pushl %edi
+ pushl %ebx
+ movl %esp,Lstack // for clearing the stack later
+
+// float d0, d1, f;
+// mvertex_t clipvert;
+
+ movl clip(%esp),%ebx
+ movl pv0(%esp),%esi
+ movl pv1(%esp),%edx
+
+// if (clip)
+// {
+ testl %ebx,%ebx
+ jz Lemit
+
+// do
+// {
+
+Lcliploop:
+
+// d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
+// d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
+ flds mv_position+0(%esi)
+ fmuls cp_normal+0(%ebx)
+ flds mv_position+4(%esi)
+ fmuls cp_normal+4(%ebx)
+ flds mv_position+8(%esi)
+ fmuls cp_normal+8(%ebx)
+ fxch %st(1)
+ faddp %st(0),%st(2) // d0mul2 | d0add0
+
+ flds mv_position+0(%edx)
+ fmuls cp_normal+0(%ebx)
+ flds mv_position+4(%edx)
+ fmuls cp_normal+4(%ebx)
+ flds mv_position+8(%edx)
+ fmuls cp_normal+8(%ebx)
+ fxch %st(1)
+ faddp %st(0),%st(2) // d1mul2 | d1add0 | d0mul2 | d0add0
+ fxch %st(3) // d0add0 | d1add0 | d0mul2 | d1mul2
+
+ faddp %st(0),%st(2) // d1add0 | dot0 | d1mul2
+ faddp %st(0),%st(2) // dot0 | dot1
+
+ fsubs cp_dist(%ebx) // d0 | dot1
+ fxch %st(1) // dot1 | d0
+ fsubs cp_dist(%ebx) // d1 | d0
+ fxch %st(1)
+ fstps Ld0
+ fstps Ld1
+
+// if (d0 >= 0)
+// {
+ movl Ld0,%eax
+ movl Ld1,%ecx
+ orl %eax,%ecx
+ js Lp2
+
+// both points are unclipped
+
+Lcontinue:
+
+//
+// R_ClipEdge (&clipvert, pv1, clip->next);
+// return;
+// }
+// } while ((clip = clip->next) != NULL);
+ movl cp_next(%ebx),%ebx
+ testl %ebx,%ebx
+ jnz Lcliploop
+
+// }
+
+//// add the edge
+// R_EmitEdge (pv0, pv1);
+Lemit:
+
+//
+// set integer rounding to ceil mode, set to single precision
+//
+// FIXME: do away with by manually extracting integers from floats?
+// FIXME: set less often
+ fldcw ceil_cw
+
+// edge_t *edge, *pcheck;
+// int u_check;
+// float u, u_step;
+// vec3_t local, transformed;
+// float *world;
+// int v, v2, ceilv0;
+// float scale, lzi0, u0, v0;
+// int side;
+
+// if (r_lastvertvalid)
+// {
+ cmpl $0,C(r_lastvertvalid)
+ jz LCalcFirst
+
+// u0 = r_u1;
+// v0 = r_v1;
+// lzi0 = r_lzi1;
+// ceilv0 = r_ceilv1;
+ movl C(r_lzi1),%eax
+ movl C(r_u1),%ecx
+ movl %eax,Lzi0
+ movl %ecx,Lu0
+ movl C(r_v1),%ecx
+ movl C(r_ceilv1),%eax
+ movl %ecx,Lv0
+ movl %eax,Lceilv0
+ jmp LCalcSecond
+
+// }
+
+LCalcFirst:
+
+// else
+// {
+// world = &pv0->position[0];
+
+ call LTransformAndProject // v0 | lzi0 | u0
+
+ fsts Lv0
+ fxch %st(2) // u0 | lzi0 | v0
+ fstps Lu0 // lzi0 | v0
+ fstps Lzi0 // v0
+
+// ceilv0 = (int)(v0 - 2000) + 2000; // ceil(v0);
+ fistpl Lceilv0
+
+// }
+
+LCalcSecond:
+
+// world = &pv1->position[0];
+ movl %edx,%esi
+
+ call LTransformAndProject // v1 | lzi1 | u1
+
+ flds Lu0 // u0 | v1 | lzi1 | u1
+ fxch %st(3) // u1 | v1 | lzi1 | u0
+ flds Lzi0 // lzi0 | u1 | v1 | lzi1 | u0
+ fxch %st(3) // lzi1 | u1 | v1 | lzi0 | u0
+ flds Lv0 // v0 | lzi1 | u1 | v1 | lzi0 | u0
+ fxch %st(3) // v1 | lzi1 | u1 | v0 | lzi0 | u0
+
+// r_ceilv1 = (int)(r_v1 - 2000) + 2000; // ceil(r_v1);
+ fistl C(r_ceilv1)
+
+ fldcw single_cw // put back normal floating-point state
+
+ fsts C(r_v1)
+ fxch %st(4) // lzi0 | lzi1 | u1 | v0 | v1 | u0
+
+// if (r_lzi1 > lzi0)
+// lzi0 = r_lzi1;
+ fcom %st(1)
+ fnstsw %ax
+ testb $1,%ah
+ jz LP0
+ fstp %st(0)
+ fld %st(0)
+LP0:
+
+ fxch %st(1) // lzi1 | lzi0 | u1 | v0 | v1 | u0
+ fstps C(r_lzi1) // lzi0 | u1 | v0 | v1 | u0
+ fxch %st(1)
+ fsts C(r_u1)
+ fxch %st(1)
+
+// if (lzi0 > r_nearzi) // for mipmap finding
+// r_nearzi = lzi0;
+ fcoms C(r_nearzi)
+ fnstsw %ax
+ testb $0x45,%ah
+ jnz LP1
+ fsts C(r_nearzi)
+LP1:
+
+// // for right edges, all we want is the effect on 1/z
+// if (r_nearzionly)
+// return;
+ movl C(r_nearzionly),%eax
+ testl %eax,%eax
+ jz LP2
+LPop5AndDone:
+ movl C(cacheoffset),%eax
+ movl C(r_framecount),%edx
+ cmpl $0x7FFFFFFF,%eax
+ jz LDoPop
+ andl $(FRAMECOUNT_MASK),%edx
+ orl $(FULLY_CLIPPED_CACHED),%edx
+ movl %edx,C(cacheoffset)
+
+LDoPop:
+ fstp %st(0) // u1 | v0 | v1 | u0
+ fstp %st(0) // v0 | v1 | u0
+ fstp %st(0) // v1 | u0
+ fstp %st(0) // u0
+ fstp %st(0)
+ jmp Ldone
+
+LP2:
+
+// // create the edge
+// if (ceilv0 == r_ceilv1)
+// return; // horizontal edge
+ movl Lceilv0,%ebx
+ movl C(edge_p),%edi
+ movl C(r_ceilv1),%ecx
+ movl %edi,%edx
+ movl C(r_pedge),%esi
+ addl $(et_size),%edx
+ cmpl %ecx,%ebx
+ jz LPop5AndDone
+
+ movl C(r_pedge),%eax
+ movl %eax,et_owner(%edi)
+
+// side = ceilv0 > r_ceilv1;
+//
+// edge->nearzi = lzi0;
+ fstps et_nearzi(%edi) // u1 | v0 | v1 | u0
+
+// if (side == 1)
+// {
+ jc LSide0
+
+LSide1:
+
+// // leading edge (go from p2 to p1)
+
+// u_step = ((u0 - r_u1) / (v0 - r_v1));
+ fsubrp %st(0),%st(3) // v0 | v1 | u0-u1
+ fsub %st(1),%st(0) // v0-v1 | v1 | u0-u1
+ fdivrp %st(0),%st(2) // v1 | ustep
+
+// r_emitted = 1;
+ movl $1,C(r_emitted)
+
+// edge = edge_p++;
+ movl %edx,C(edge_p)
+
+// pretouch next edge
+ movl (%edx),%eax
+
+// v2 = ceilv0 - 1;
+// v = r_ceilv1;
+ movl %ecx,%eax
+ leal -1(%ebx),%ecx
+ movl %eax,%ebx
+
+// edge->surfs[0] = 0;
+// edge->surfs[1] = surface_p - surfaces;
+ movl C(surface_p),%eax
+ movl C(surfaces),%esi
+ subl %edx,%edx
+ subl %esi,%eax
+ shrl $(SURF_T_SHIFT),%eax
+ movl %edx,et_surfs(%edi)
+ movl %eax,et_surfs+2(%edi)
+
+ subl %esi,%esi
+
+// u = r_u1 + ((float)v - r_v1) * u_step;
+ movl %ebx,Lv
+ fildl Lv // v | v1 | ustep
+ fsubp %st(0),%st(1) // v-v1 | ustep
+ fmul %st(1),%st(0) // (v-v1)*ustep | ustep
+ fadds C(r_u1) // u | ustep
+
+ jmp LSideDone
+
+// }
+
+LSide0:
+
+// else
+// {
+// // trailing edge (go from p1 to p2)
+
+// u_step = ((r_u1 - u0) / (r_v1 - v0));
+ fsub %st(3),%st(0) // u1-u0 | v0 | v1 | u0
+ fxch %st(2) // v1 | v0 | u1-u0 | u0
+ fsub %st(1),%st(0) // v1-v0 | v0 | u1-u0 | u0
+ fdivrp %st(0),%st(2) // v0 | ustep | u0
+
+// r_emitted = 1;
+ movl $1,C(r_emitted)
+
+// edge = edge_p++;
+ movl %edx,C(edge_p)
+
+// pretouch next edge
+ movl (%edx),%eax
+
+// v = ceilv0;
+// v2 = r_ceilv1 - 1;
+ decl %ecx
+
+// edge->surfs[0] = surface_p - surfaces;
+// edge->surfs[1] = 0;
+ movl C(surface_p),%eax
+ movl C(surfaces),%esi
+ subl %edx,%edx
+ subl %esi,%eax
+ shrl $(SURF_T_SHIFT),%eax
+ movl %edx,et_surfs+2(%edi)
+ movl %eax,et_surfs(%edi)
+
+ movl $1,%esi
+
+// u = u0 + ((float)v - v0) * u_step;
+ movl %ebx,Lv
+ fildl Lv // v | v0 | ustep | u0
+ fsubp %st(0),%st(1) // v-v0 | ustep | u0
+ fmul %st(1),%st(0) // (v-v0)*ustep | ustep | u0
+ faddp %st(0),%st(2) // ustep | u
+ fxch %st(1) // u | ustep
+
+// }
+
+LSideDone:
+
+// edge->u_step = u_step*0x100000;
+// edge->u = u*0x100000 + 0xFFFFF;
+
+ fmuls fp_1m // u*0x100000 | ustep
+ fxch %st(1) // ustep | u*0x100000
+ fmuls fp_1m // ustep*0x100000 | u*0x100000
+ fxch %st(1) // u*0x100000 | ustep*0x100000
+ fadds fp_1m_minus_1 // u*0x100000 + 0xFFFFF | ustep*0x100000
+ fxch %st(1) // ustep*0x100000 | u*0x100000 + 0xFFFFF
+ fistpl et_u_step(%edi) // u*0x100000 + 0xFFFFF
+ fistpl et_u(%edi)
+
+// // we need to do this to avoid stepping off the edges if a very nearly
+// // horizontal edge is less than epsilon above a scan, and numeric error
+// // causes it to incorrectly extend to the scan, and the extension of the
+// // line goes off the edge of the screen
+// // FIXME: is this actually needed?
+// if (edge->u < r_refdef.vrect_x_adj_shift20)
+// edge->u = r_refdef.vrect_x_adj_shift20;
+// if (edge->u > r_refdef.vrectright_adj_shift20)
+// edge->u = r_refdef.vrectright_adj_shift20;
+ movl et_u(%edi),%eax
+ movl C(r_refdef)+rd_vrect_x_adj_shift20,%edx
+ cmpl %edx,%eax
+ jl LP4
+ movl C(r_refdef)+rd_vrectright_adj_shift20,%edx
+ cmpl %edx,%eax
+ jng LP5
+LP4:
+ movl %edx,et_u(%edi)
+ movl %edx,%eax
+LP5:
+
+// // sort the edge in normally
+// u_check = edge->u;
+//
+// if (edge->surfs[0])
+// u_check++; // sort trailers after leaders
+ addl %esi,%eax
+
+// if (!newedges[v] || newedges[v]->u >= u_check)
+// {
+ movl C(newedges)(,%ebx,4),%esi
+ testl %esi,%esi
+ jz LDoFirst
+ cmpl %eax,et_u(%esi)
+ jl LNotFirst
+LDoFirst:
+
+// edge->next = newedges[v];
+// newedges[v] = edge;
+ movl %esi,et_next(%edi)
+ movl %edi,C(newedges)(,%ebx,4)
+
+ jmp LSetRemove
+
+// }
+
+LNotFirst:
+
+// else
+// {
+// pcheck = newedges[v];
+//
+// while (pcheck->next && pcheck->next->u < u_check)
+// pcheck = pcheck->next;
+LFindInsertLoop:
+ movl %esi,%edx
+ movl et_next(%esi),%esi
+ testl %esi,%esi
+ jz LInsertFound
+ cmpl %eax,et_u(%esi)
+ jl LFindInsertLoop
+
+LInsertFound:
+
+// edge->next = pcheck->next;
+// pcheck->next = edge;
+ movl %esi,et_next(%edi)
+ movl %edi,et_next(%edx)
+
+// }
+
+LSetRemove:
+
+// edge->nextremove = removeedges[v2];
+// removeedges[v2] = edge;
+ movl C(removeedges)(,%ecx,4),%eax
+ movl %edi,C(removeedges)(,%ecx,4)
+ movl %eax,et_nextremove(%edi)
+
+Ldone:
+ movl Lstack,%esp // clear temporary variables from stack
+
+ popl %ebx // restore register variables
+ popl %edi
+ popl %esi
+ ret
+
+// at least one point is clipped
+
+Lp2:
+ testl %eax,%eax
+ jns Lp1
+
+// else
+// {
+// // point 0 is clipped
+
+// if (d1 < 0)
+// {
+ movl Ld1,%eax
+ testl %eax,%eax
+ jns Lp3
+
+// // both points are clipped
+// // we do cache fully clipped edges
+// if (!leftclipped)
+ movl C(r_leftclipped),%eax
+ movl C(r_pedge),%ecx
+ testl %eax,%eax
+ jnz Ldone
+
+// r_pedge->framecount = r_framecount;
+ movl C(r_framecount),%eax
+ andl $(FRAMECOUNT_MASK),%eax
+ orl $(FULLY_CLIPPED_CACHED),%eax
+ movl %eax,C(cacheoffset)
+
+// return;
+ jmp Ldone
+
+// }
+
+Lp1:
+
+// // point 0 is unclipped
+// if (d1 >= 0)
+// {
+// // both points are unclipped
+// continue;
+
+// // only point 1 is clipped
+
+// f = d0 / (d0 - d1);
+ flds Ld0
+ flds Ld1
+ fsubr %st(1),%st(0)
+
+// // we don't cache partially clipped edges
+ movl $0x7FFFFFFF,C(cacheoffset)
+
+ fdivrp %st(0),%st(1)
+
+ subl $(mv_size),%esp // allocate space for clipvert
+
+// clipvert.position[0] = pv0->position[0] +
+// f * (pv1->position[0] - pv0->position[0]);
+// clipvert.position[1] = pv0->position[1] +
+// f * (pv1->position[1] - pv0->position[1]);
+// clipvert.position[2] = pv0->position[2] +
+// f * (pv1->position[2] - pv0->position[2]);
+ flds mv_position+8(%edx)
+ fsubs mv_position+8(%esi)
+ flds mv_position+4(%edx)
+ fsubs mv_position+4(%esi)
+ flds mv_position+0(%edx)
+ fsubs mv_position+0(%esi) // 0 | 1 | 2
+
+// replace pv1 with the clip point
+ movl %esp,%edx
+ movl cp_leftedge(%ebx),%eax
+ testb %al,%al
+
+ fmul %st(3),%st(0)
+ fxch %st(1) // 1 | 0 | 2
+ fmul %st(3),%st(0)
+ fxch %st(2) // 2 | 0 | 1
+ fmulp %st(0),%st(3) // 0 | 1 | 2
+ fadds mv_position+0(%esi)
+ fxch %st(1) // 1 | 0 | 2
+ fadds mv_position+4(%esi)
+ fxch %st(2) // 2 | 0 | 1
+ fadds mv_position+8(%esi)
+ fxch %st(1) // 0 | 2 | 1
+ fstps mv_position+0(%esp) // 2 | 1
+ fstps mv_position+8(%esp) // 1
+ fstps mv_position+4(%esp)
+
+// if (clip->leftedge)
+// {
+ jz Ltestright
+
+// r_leftclipped = true;
+// r_leftexit = clipvert;
+ movl $1,C(r_leftclipped)
+ movl mv_position+0(%esp),%eax
+ movl %eax,C(r_leftexit)+mv_position+0
+ movl mv_position+4(%esp),%eax
+ movl %eax,C(r_leftexit)+mv_position+4
+ movl mv_position+8(%esp),%eax
+ movl %eax,C(r_leftexit)+mv_position+8
+
+ jmp Lcontinue
+
+// }
+
+Ltestright:
+// else if (clip->rightedge)
+// {
+ testb %ah,%ah
+ jz Lcontinue
+
+// r_rightclipped = true;
+// r_rightexit = clipvert;
+ movl $1,C(r_rightclipped)
+ movl mv_position+0(%esp),%eax
+ movl %eax,C(r_rightexit)+mv_position+0
+ movl mv_position+4(%esp),%eax
+ movl %eax,C(r_rightexit)+mv_position+4
+ movl mv_position+8(%esp),%eax
+ movl %eax,C(r_rightexit)+mv_position+8
+
+// }
+//
+// R_ClipEdge (pv0, &clipvert, clip->next);
+// return;
+// }
+ jmp Lcontinue
+
+// }
+
+Lp3:
+
+// // only point 0 is clipped
+// r_lastvertvalid = false;
+
+ movl $0,C(r_lastvertvalid)
+
+// f = d0 / (d0 - d1);
+ flds Ld0
+ flds Ld1
+ fsubr %st(1),%st(0)
+
+// // we don't cache partially clipped edges
+ movl $0x7FFFFFFF,C(cacheoffset)
+
+ fdivrp %st(0),%st(1)
+
+ subl $(mv_size),%esp // allocate space for clipvert
+
+// clipvert.position[0] = pv0->position[0] +
+// f * (pv1->position[0] - pv0->position[0]);
+// clipvert.position[1] = pv0->position[1] +
+// f * (pv1->position[1] - pv0->position[1]);
+// clipvert.position[2] = pv0->position[2] +
+// f * (pv1->position[2] - pv0->position[2]);
+ flds mv_position+8(%edx)
+ fsubs mv_position+8(%esi)
+ flds mv_position+4(%edx)
+ fsubs mv_position+4(%esi)
+ flds mv_position+0(%edx)
+ fsubs mv_position+0(%esi) // 0 | 1 | 2
+
+ movl cp_leftedge(%ebx),%eax
+ testb %al,%al
+
+ fmul %st(3),%st(0)
+ fxch %st(1) // 1 | 0 | 2
+ fmul %st(3),%st(0)
+ fxch %st(2) // 2 | 0 | 1
+ fmulp %st(0),%st(3) // 0 | 1 | 2
+ fadds mv_position+0(%esi)
+ fxch %st(1) // 1 | 0 | 2
+ fadds mv_position+4(%esi)
+ fxch %st(2) // 2 | 0 | 1
+ fadds mv_position+8(%esi)
+ fxch %st(1) // 0 | 2 | 1
+ fstps mv_position+0(%esp) // 2 | 1
+ fstps mv_position+8(%esp) // 1
+ fstps mv_position+4(%esp)
+
+// replace pv0 with the clip point
+ movl %esp,%esi
+
+// if (clip->leftedge)
+// {
+ jz Ltestright2
+
+// r_leftclipped = true;
+// r_leftenter = clipvert;
+ movl $1,C(r_leftclipped)
+ movl mv_position+0(%esp),%eax
+ movl %eax,C(r_leftenter)+mv_position+0
+ movl mv_position+4(%esp),%eax
+ movl %eax,C(r_leftenter)+mv_position+4
+ movl mv_position+8(%esp),%eax
+ movl %eax,C(r_leftenter)+mv_position+8
+
+ jmp Lcontinue
+
+// }
+
+Ltestright2:
+// else if (clip->rightedge)
+// {
+ testb %ah,%ah
+ jz Lcontinue
+
+// r_rightclipped = true;
+// r_rightenter = clipvert;
+ movl $1,C(r_rightclipped)
+ movl mv_position+0(%esp),%eax
+ movl %eax,C(r_rightenter)+mv_position+0
+ movl mv_position+4(%esp),%eax
+ movl %eax,C(r_rightenter)+mv_position+4
+ movl mv_position+8(%esp),%eax
+ movl %eax,C(r_rightenter)+mv_position+8
+
+// }
+ jmp Lcontinue
+
+// %esi = vec3_t point to transform and project
+// %edx preserved
+LTransformAndProject:
+
+// // transform and project
+// VectorSubtract (world, modelorg, local);
+ flds mv_position+0(%esi)
+ fsubs C(modelorg)+0
+ flds mv_position+4(%esi)
+ fsubs C(modelorg)+4
+ flds mv_position+8(%esi)
+ fsubs C(modelorg)+8
+ fxch %st(2) // local[0] | local[1] | local[2]
+
+// TransformVector (local, transformed);
+//
+// if (transformed[2] < NEAR_CLIP)
+// transformed[2] = NEAR_CLIP;
+//
+// lzi0 = 1.0 / transformed[2];
+ fld %st(0) // local[0] | local[0] | local[1] | local[2]
+ fmuls C(vpn)+0 // zm0 | local[0] | local[1] | local[2]
+ fld %st(1) // local[0] | zm0 | local[0] | local[1] |
+ // local[2]
+ fmuls C(vright)+0 // xm0 | zm0 | local[0] | local[1] | local[2]
+ fxch %st(2) // local[0] | zm0 | xm0 | local[1] | local[2]
+ fmuls C(vup)+0 // ym0 | zm0 | xm0 | local[1] | local[2]
+ fld %st(3) // local[1] | ym0 | zm0 | xm0 | local[1] |
+ // local[2]
+ fmuls C(vpn)+4 // zm1 | ym0 | zm0 | xm0 | local[1] |
+ // local[2]
+ fld %st(4) // local[1] | zm1 | ym0 | zm0 | xm0 |
+ // local[1] | local[2]
+ fmuls C(vright)+4 // xm1 | zm1 | ym0 | zm0 | xm0 |
+ // local[1] | local[2]
+ fxch %st(5) // local[1] | zm1 | ym0 | zm0 | xm0 |
+ // xm1 | local[2]
+ fmuls C(vup)+4 // ym1 | zm1 | ym0 | zm0 | xm0 |
+ // xm1 | local[2]
+ fxch %st(1) // zm1 | ym1 | ym0 | zm0 | xm0 |
+ // xm1 | local[2]
+ faddp %st(0),%st(3) // ym1 | ym0 | zm2 | xm0 | xm1 | local[2]
+ fxch %st(3) // xm0 | ym0 | zm2 | ym1 | xm1 | local[2]
+ faddp %st(0),%st(4) // ym0 | zm2 | ym1 | xm2 | local[2]
+ faddp %st(0),%st(2) // zm2 | ym2 | xm2 | local[2]
+ fld %st(3) // local[2] | zm2 | ym2 | xm2 | local[2]
+ fmuls C(vpn)+8 // zm3 | zm2 | ym2 | xm2 | local[2]
+ fld %st(4) // local[2] | zm3 | zm2 | ym2 | xm2 | local[2]
+ fmuls C(vright)+8 // xm3 | zm3 | zm2 | ym2 | xm2 | local[2]
+ fxch %st(5) // local[2] | zm3 | zm2 | ym2 | xm2 | xm3
+ fmuls C(vup)+8 // ym3 | zm3 | zm2 | ym2 | xm2 | xm3
+ fxch %st(1) // zm3 | ym3 | zm2 | ym2 | xm2 | xm3
+ faddp %st(0),%st(2) // ym3 | zm4 | ym2 | xm2 | xm3
+ fxch %st(4) // xm3 | zm4 | ym2 | xm2 | ym3
+ faddp %st(0),%st(3) // zm4 | ym2 | xm4 | ym3
+ fxch %st(1) // ym2 | zm4 | xm4 | ym3
+ faddp %st(0),%st(3) // zm4 | xm4 | ym4
+
+ fcoms Lfp_near_clip
+ fnstsw %ax
+ testb $1,%ah
+ jz LNoClip
+ fstp %st(0)
+ flds Lfp_near_clip
+
+LNoClip:
+
+ fdivrs float_1 // lzi0 | x | y
+ fxch %st(1) // x | lzi0 | y
+
+// // FIXME: build x/yscale into transform?
+// scale = xscale * lzi0;
+// u0 = (xcenter + scale*transformed[0]);
+ flds C(xscale) // xscale | x | lzi0 | y
+ fmul %st(2),%st(0) // scale | x | lzi0 | y
+ fmulp %st(0),%st(1) // scale*x | lzi0 | y
+ fadds C(xcenter) // u0 | lzi0 | y
+
+// if (u0 < r_refdef.fvrectx_adj)
+// u0 = r_refdef.fvrectx_adj;
+// if (u0 > r_refdef.fvrectright_adj)
+// u0 = r_refdef.fvrectright_adj;
+// FIXME: use integer compares of floats?
+ fcoms C(r_refdef)+rd_fvrectx_adj
+ fnstsw %ax
+ testb $1,%ah
+ jz LClampP0
+ fstp %st(0)
+ flds C(r_refdef)+rd_fvrectx_adj
+LClampP0:
+ fcoms C(r_refdef)+rd_fvrectright_adj
+ fnstsw %ax
+ testb $0x45,%ah
+ jnz LClampP1
+ fstp %st(0)
+ flds C(r_refdef)+rd_fvrectright_adj
+LClampP1:
+
+ fld %st(1) // lzi0 | u0 | lzi0 | y
+
+// scale = yscale * lzi0;
+// v0 = (ycenter - scale*transformed[1]);
+ fmuls C(yscale) // scale | u0 | lzi0 | y
+ fmulp %st(0),%st(3) // u0 | lzi0 | scale*y
+ fxch %st(2) // scale*y | lzi0 | u0
+ fsubrs C(ycenter) // v0 | lzi0 | u0
+
+// if (v0 < r_refdef.fvrecty_adj)
+// v0 = r_refdef.fvrecty_adj;
+// if (v0 > r_refdef.fvrectbottom_adj)
+// v0 = r_refdef.fvrectbottom_adj;
+// FIXME: use integer compares of floats?
+ fcoms C(r_refdef)+rd_fvrecty_adj
+ fnstsw %ax
+ testb $1,%ah
+ jz LClampP2
+ fstp %st(0)
+ flds C(r_refdef)+rd_fvrecty_adj
+LClampP2:
+ fcoms C(r_refdef)+rd_fvrectbottom_adj
+ fnstsw %ax
+ testb $0x45,%ah
+ jnz LClampP3
+ fstp %st(0)
+ flds C(r_refdef)+rd_fvrectbottom_adj
+LClampP3:
+ ret
+
+#endif // id386
+