/* 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_aclip.c: clip routines for drawing Alias models directly to the screen #include "quakedef.h" #include "r_local.h" #include "d_local.h" static finalvert_t fv[2][8]; static auxvert_t av[8]; #ifdef USEFPM static auxvert_FPM_t *avFPM[8]; #endif //USEFPM void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av); #ifdef USEFPM void R_AliasProjectFinalVertFPM (finalvert_t *fv, auxvert_FPM_t *av); #endif //USEFPM void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out); void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out); void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out); void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out); /* ================ R_Alias_clip_z pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex ================ */ void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) { float scale; auxvert_t *pav0, *pav1, avout; pav0 = &av[pfv0 - &fv[0][0]]; pav1 = &av[pfv1 - &fv[0][0]]; if (pfv0->v[1] >= pfv1->v[1]) { scale = (ALIAS_Z_CLIP_PLANE - pav0->fv[2]) / (pav1->fv[2] - pav0->fv[2]); avout.fv[0] = pav0->fv[0] + (pav1->fv[0] - pav0->fv[0]) * scale; avout.fv[1] = pav0->fv[1] + (pav1->fv[1] - pav0->fv[1]) * scale; avout.fv[2] = ALIAS_Z_CLIP_PLANE; out->v[2] = pfv0->v[2] + (int)((pfv1->v[2] - pfv0->v[2]) * scale); out->v[3] = pfv0->v[3] + (int)((pfv1->v[3] - pfv0->v[3]) * scale); out->v[4] = pfv0->v[4] + (int)((pfv1->v[4] - pfv0->v[4]) * scale); } else { scale = (ALIAS_Z_CLIP_PLANE - pav1->fv[2]) / (pav0->fv[2] - pav1->fv[2]); avout.fv[0] = pav1->fv[0] + (int)((pav0->fv[0] - pav1->fv[0]) * scale); avout.fv[1] = pav1->fv[1] + (int)((pav0->fv[1] - pav1->fv[1]) * scale); avout.fv[2] = ALIAS_Z_CLIP_PLANE; out->v[2] = pfv1->v[2] + (int)((pfv0->v[2] - pfv1->v[2]) * scale); out->v[3] = pfv1->v[3] + (int)((pfv0->v[3] - pfv1->v[3]) * scale); out->v[4] = pfv1->v[4] + (int)((pfv0->v[4] - pfv1->v[4]) * scale); } R_AliasProjectFinalVert (out, &avout); if (out->v[0] < r_refdef.aliasvrect.x) out->flags |= ALIAS_LEFT_CLIP; if (out->v[1] < r_refdef.aliasvrect.y) out->flags |= ALIAS_TOP_CLIP; if (out->v[0] > r_refdef.aliasvrectright) out->flags |= ALIAS_RIGHT_CLIP; if (out->v[1] > r_refdef.aliasvrectbottom) out->flags |= ALIAS_BOTTOM_CLIP; } #ifdef USEFPM void R_Alias_clip_z_FPM (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) { fixedpoint_t scale; auxvert_FPM_t *pav0, *pav1, avout; pav0 = avFPM[pfv0 - &fv[0][0]]; pav1 = avFPM[pfv1 - &fv[0][0]]; if (pfv0->v[1] >= pfv1->v[1]) { scale = FPM_DIV(FPM_SUB(ALIAS_Z_CLIP_PLANE_FPM, pav0->fv[2]), FPM_SUB(pav1->fv[2], pav0->fv[2])); avout.fv[0] = FPM_TOLONG(FPM_ADD(pav0->fv[0], FPM_MUL(FPM_SUB(pav1->fv[0], pav0->fv[0]),scale))); avout.fv[1] = FPM_TOLONG(FPM_ADD(pav0->fv[1], FPM_MUL(FPM_SUB(pav1->fv[1], pav0->fv[1]), scale))); avout.fv[2] = ALIAS_Z_CLIP_PLANE; out->v[2] = pfv0->v[2] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pfv1->v[2] - pfv0->v[2]), scale)); out->v[3] = pfv0->v[3] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pfv1->v[3] - pfv0->v[3]), scale)); out->v[4] = pfv0->v[4] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pfv1->v[4] - pfv0->v[4]), scale)); } else { scale = FPM_DIV(FPM_SUB(ALIAS_Z_CLIP_PLANE_FPM, pav1->fv[2]), FPM_SUB(pav0->fv[2], pav1->fv[2])); avout.fv[0] = FPM_TOLONG(FPM_ADD(pav1->fv[0], FPM_MUL(FPM_SUB(pav0->fv[0], pav1->fv[0]),scale))); avout.fv[1] = FPM_TOLONG(FPM_ADD(pav1->fv[1], FPM_MUL(FPM_SUB(pav0->fv[1], pav1->fv[1]), scale))); avout.fv[2] = ALIAS_Z_CLIP_PLANE; out->v[2] = pfv1->v[2] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG((pfv0->v[2] - pfv1->v[2])), scale)); out->v[3] = pfv1->v[3] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pfv0->v[3] - pfv1->v[3]), scale)); out->v[4] = pfv1->v[4] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pfv0->v[4] - pfv1->v[4]), scale)); } R_AliasProjectFinalVertFPM (out, &avout); if (out->v[0] < r_refdefFPM.aliasvrect.x) out->flags |= ALIAS_LEFT_CLIP; if (out->v[1] < r_refdefFPM.aliasvrect.y) out->flags |= ALIAS_TOP_CLIP; if (out->v[0] > r_refdefFPM.aliasvrectright) out->flags |= ALIAS_RIGHT_CLIP; if (out->v[1] > r_refdefFPM.aliasvrectbottom) out->flags |= ALIAS_BOTTOM_CLIP; } #endif //USEFPM #if !id386 void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) { float scale; int i; if (pfv0->v[1] >= pfv1->v[1]) { scale = (float)(r_refdef.aliasvrect.x - pfv0->v[0]) / (pfv1->v[0] - pfv0->v[0]); for (i=0 ; i<6 ; i++) out->v[i] = pfv0->v[i] + (int)((pfv1->v[i] - pfv0->v[i])*scale + 0.5); } else { scale = (float)(r_refdef.aliasvrect.x - pfv1->v[0]) / (pfv0->v[0] - pfv1->v[0]); for (i=0 ; i<6 ; i++) out->v[i] = pfv1->v[i] + (int)((pfv0->v[i] - pfv1->v[i])*scale + 0.5); } } #ifdef USEFPM void R_Alias_clip_leftFPM (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) { fixedpoint_t scale; int i; if (pfv0->v[1] >= pfv1->v[1]) { scale = FPM_DIV(FPM_FROMLONG(r_refdef.aliasvrect.x - pfv0->v[0]), FPM_FROMLONG(pfv1->v[0] - pfv0->v[0])); for (i=0 ; i<6 ; i++) out->v[i] = FPM_ADD3(FPM_FROMLONG(pfv0->v[i]), FPM_MUL(FPM_FROMLONG(pfv1->v[i] - pfv0->v[i]),scale), FPM_FROMFLOAT(0.5)); } else { scale = FPM_DIV(FPM_FROMLONG(r_refdef.aliasvrect.x - pfv1->v[0]), FPM_FROMLONG(pfv0->v[0] - pfv1->v[0])); for (i=0 ; i<6 ; i++) out->v[i] = FPM_ADD3(FPM_FROMLONG(pfv1->v[i]), FPM_MUL(FPM_FROMLONG(pfv0->v[i] - pfv1->v[i]),scale), FPM_FROMFLOAT(0.5)); } } #endif //USEFPM void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) { float scale; int i; if (pfv0->v[1] >= pfv1->v[1]) { scale = (float)(r_refdef.aliasvrectright - pfv0->v[0]) / (pfv1->v[0] - pfv0->v[0]); for (i=0 ; i<6 ; i++) out->v[i] = pfv0->v[i] + (int)((pfv1->v[i] - pfv0->v[i])*scale + 0.5); } else { scale = (float)(r_refdef.aliasvrectright - pfv1->v[0]) / (pfv0->v[0] - pfv1->v[0]); for (i=0 ; i<6 ; i++) out->v[i] = pfv1->v[i] + (int)((pfv0->v[i] - pfv1->v[i])*scale + 0.5); } } #ifdef USEFPM void R_Alias_clip_rightFPM (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) { fixedpoint_t scale; int i; if (pfv0->v[1] >= pfv1->v[1]) { scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrectright - pfv0->v[0]), FPM_FROMLONG(pfv1->v[0] - pfv0->v[0])); for (i=0 ; i<6 ; i++) out->v[i] = pfv0->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv1->v[i] - pfv0->v[i]),scale), FPM_FROMFLOAT(0.5))); } else { scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrectright - pfv1->v[0]), FPM_FROMLONG(pfv0->v[0] - pfv1->v[0])); for (i=0 ; i<6 ; i++) out->v[i] = pfv1->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv0->v[i] - pfv1->v[i]),scale), FPM_FROMFLOAT(0.5))); } } #endif //USEFPM void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) { float scale; int i; if (pfv0->v[1] >= pfv1->v[1]) { scale = (float)(r_refdef.aliasvrect.y - pfv0->v[1]) / (pfv1->v[1] - pfv0->v[1]); for (i=0 ; i<6 ; i++) out->v[i] = pfv0->v[i] + (int)((pfv1->v[i] - pfv0->v[i])*scale + 0.5); } else { scale = (float)(r_refdef.aliasvrect.y - pfv1->v[1]) / (pfv0->v[1] - pfv1->v[1]); for (i=0 ; i<6 ; i++) out->v[i] = pfv1->v[i] + (int)((pfv0->v[i] - pfv1->v[i])*scale + 0.5); } } #ifdef USEFPM void R_Alias_clip_topFPM (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) { fixedpoint_t scale; int i; if (pfv0->v[1] >= pfv1->v[1]) { scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrect.y - pfv0->v[1]), FPM_FROMLONG(pfv1->v[1] - pfv0->v[1])); for (i=0 ; i<6 ; i++) out->v[i] = pfv0->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv1->v[i] - pfv0->v[i]),scale), FPM_FROMFLOAT(0.5))); } else { scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrect.y - pfv1->v[1]), FPM_FROMLONG(pfv0->v[1] - pfv1->v[1])); for (i=0 ; i<6 ; i++) out->v[i] = pfv1->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv0->v[i] - pfv1->v[i]),scale), FPM_FROMFLOAT(0.5))); } } #endif //USEFPM void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) { float scale; int i; if (pfv0->v[1] >= pfv1->v[1]) { scale = (float)(r_refdef.aliasvrectbottom - pfv0->v[1]) / (pfv1->v[1] - pfv0->v[1]); for (i=0 ; i<6 ; i++) out->v[i] = pfv0->v[i] + (int)((pfv1->v[i] - pfv0->v[i])*scale + 0.5); } else { scale = (float)(r_refdef.aliasvrectbottom - pfv1->v[1]) / (pfv0->v[1] - pfv1->v[1]); for (i=0 ; i<6 ; i++) out->v[i] = pfv1->v[i] + (int)((pfv0->v[i] - pfv1->v[i])*scale + 0.5); } } #ifdef USEFPM void R_Alias_clip_bottomFPM (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) { fixedpoint_t scale; int i; if (pfv0->v[1] >= pfv1->v[1]) { scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrectbottom - pfv0->v[1]), FPM_FROMLONG(pfv1->v[1] - pfv0->v[1])); for (i=0 ; i<6 ; i++) out->v[i] = pfv0->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv1->v[i] - pfv0->v[i]),scale), FPM_FROMFLOAT(0.5))); } else { scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrectbottom - pfv1->v[1]), FPM_FROMLONG(pfv0->v[1] - pfv1->v[1])); for (i=0 ; i<6 ; i++) out->v[i] = pfv1->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv0->v[i] - pfv1->v[i]),scale), FPM_FROMFLOAT(0.5))); } } #endif //USEFPM #endif int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count, void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) ) { int i,j,k; int flags, oldflags; j = count-1; k = 0; for (i=0 ; i r_refdef.aliasvrectright) out[k].flags |= ALIAS_RIGHT_CLIP; if (out[k].v[1] > r_refdef.aliasvrectbottom) out[k].flags |= ALIAS_BOTTOM_CLIP; k++; } if (!flags) { out[k] = in[i]; k++; } } return k; } #ifdef USEFPM int R_AliasClipFPM (finalvert_t *in, finalvert_t *out, int flag, int count, void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) ) { int i,j,k; int flags, oldflags; j = count-1; k = 0; for (i=0 ; i r_refdefFPM.aliasvrectright) out[k].flags |= ALIAS_RIGHT_CLIP; if (out[k].v[1] > r_refdefFPM.aliasvrectbottom) out[k].flags |= ALIAS_BOTTOM_CLIP; k++; } if (!flags) { out[k] = in[i]; k++; } } return k; } #endif //USEFPM /* ================ R_AliasClipTriangle ================ */ void R_AliasClipTriangle (mtriangle_t *ptri) { int i, k, pingpong; mtriangle_t mtri; unsigned clipflags; // copy vertexes and fix seam texture coordinates if (ptri->facesfront) { fv[0][0] = pfinalverts[ptri->vertindex[0]]; fv[0][1] = pfinalverts[ptri->vertindex[1]]; fv[0][2] = pfinalverts[ptri->vertindex[2]]; } else { for (i=0 ; i<3 ; i++) { fv[0][i] = pfinalverts[ptri->vertindex[i]]; if (!ptri->facesfront && (fv[0][i].flags & ALIAS_ONSEAM) ) fv[0][i].v[2] += r_affinetridesc.seamfixupX16; } } // clip clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags; if (clipflags & ALIAS_Z_CLIP) { for (i=0 ; i<3 ; i++) av[i] = pauxverts[ptri->vertindex[i]]; k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z); if (k == 0) return; pingpong = 1; clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags; } else { pingpong = 0; k = 3; } if (clipflags & ALIAS_LEFT_CLIP) { k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], ALIAS_LEFT_CLIP, k, R_Alias_clip_left); if (k == 0) return; pingpong ^= 1; } if (clipflags & ALIAS_RIGHT_CLIP) { k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], ALIAS_RIGHT_CLIP, k, R_Alias_clip_right); if (k == 0) return; pingpong ^= 1; } if (clipflags & ALIAS_BOTTOM_CLIP) { k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom); if (k == 0) return; pingpong ^= 1; } if (clipflags & ALIAS_TOP_CLIP) { k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], ALIAS_TOP_CLIP, k, R_Alias_clip_top); if (k == 0) return; pingpong ^= 1; } for (i=0 ; i r_refdef.aliasvrectright) fv[pingpong][i].v[0] = r_refdef.aliasvrectright; if (fv[pingpong][i].v[1] < r_refdef.aliasvrect.y) fv[pingpong][i].v[1] = r_refdef.aliasvrect.y; else if (fv[pingpong][i].v[1] > r_refdef.aliasvrectbottom) fv[pingpong][i].v[1] = r_refdef.aliasvrectbottom; fv[pingpong][i].flags = 0; } // draw triangles mtri.facesfront = ptri->facesfront; r_affinetridesc.ptriangles = &mtri; r_affinetridesc.pfinalverts = fv[pingpong]; // FIXME: do all at once as trifan? mtri.vertindex[0] = 0; for (i=1 ; ifacesfront) { fv[0][0] = pfinalverts[ptri->vertindex[0]]; fv[0][1] = pfinalverts[ptri->vertindex[1]]; fv[0][2] = pfinalverts[ptri->vertindex[2]]; } else { for (i=0 ; i<3 ; i++) { fv[0][i] = pfinalverts[ptri->vertindex[i]]; if (!ptri->facesfront && (fv[0][i].flags & ALIAS_ONSEAM) ) fv[0][i].v[2] += r_affinetridesc.seamfixupX16; } } // clip clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags; if (clipflags & ALIAS_Z_CLIP) { for (i=0 ; i<3 ; i++) avFPM[i] = &pauxvertsFPM[ptri->vertindex[i]]; k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z_FPM); if (k == 0) return; pingpong = 1; clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags; } else { pingpong = 0; k = 3; } if (clipflags & ALIAS_LEFT_CLIP) { k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], ALIAS_LEFT_CLIP, k, R_Alias_clip_left); if (k == 0) return; pingpong ^= 1; } if (clipflags & ALIAS_RIGHT_CLIP) { k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], ALIAS_RIGHT_CLIP, k, R_Alias_clip_right); if (k == 0) return; pingpong ^= 1; } if (clipflags & ALIAS_BOTTOM_CLIP) { k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom); if (k == 0) return; pingpong ^= 1; } if (clipflags & ALIAS_TOP_CLIP) { k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], ALIAS_TOP_CLIP, k, R_Alias_clip_top); if (k == 0) return; pingpong ^= 1; } for (i=0 ; i r_refdefFPM.aliasvrectright) fv[pingpong][i].v[0] = r_refdefFPM.aliasvrectright; if (fv[pingpong][i].v[1] < r_refdefFPM.aliasvrect.y) fv[pingpong][i].v[1] = r_refdefFPM.aliasvrect.y; else if (fv[pingpong][i].v[1] > r_refdefFPM.aliasvrectbottom) fv[pingpong][i].v[1] = r_refdefFPM.aliasvrectbottom; fv[pingpong][i].flags = 0; } // draw triangles mtri.facesfront = ptri->facesfront; r_affinetridesc.ptriangles = &mtri; r_affinetridesc.pfinalverts = fv[pingpong]; // FIXME: do all at once as trifan? mtri.vertindex[0] = 0; for (i=1 ; i