quakeforge/libs/video/renderer/sw/sw_raclip.c
2002-11-05 19:12:51 +00:00

318 lines
7.9 KiB
C

/*
r_aclip.c
clip routines for drawing Alias models directly to the screen
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:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
static const char rcsid[] =
"$Id$";
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "QF/render.h"
#include "d_local.h"
#include "r_local.h"
static finalvert_t fv[2][8];
static auxvert_t av[8];
/*
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] + (pfv1->v[2] - pfv0->v[2]) * scale;
out->v[3] = pfv0->v[3] + (pfv1->v[3] - pfv0->v[3]) * scale;
out->v[4] = pfv0->v[4] + (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] + (pav0->fv[0] - pav1->fv[0]) * scale;
avout.fv[1] = pav1->fv[1] + (pav0->fv[1] - pav1->fv[1]) * scale;
avout.fv[2] = ALIAS_Z_CLIP_PLANE;
out->v[2] = pfv1->v[2] + (pfv0->v[2] - pfv1->v[2]) * scale;
out->v[3] = pfv1->v[3] + (pfv0->v[3] - pfv1->v[3]) * scale;
out->v[4] = pfv1->v[4] + (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;
}
#ifndef USE_INTEL_ASM
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] + (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] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
}
}
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] + (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] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
}
}
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] + (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] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
}
}
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] + (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] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
}
}
#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 < count; j = i, i++) {
oldflags = in[j].flags & flag;
flags = in[i].flags & flag;
if (flags && oldflags)
continue;
if (oldflags ^ flags) {
clip (&in[j], &in[i], &out[k]);
out[k].flags = 0;
if (out[k].v[0] < r_refdef.aliasvrect.x)
out[k].flags |= ALIAS_LEFT_CLIP;
if (out[k].v[1] < r_refdef.aliasvrect.y)
out[k].flags |= ALIAS_TOP_CLIP;
if (out[k].v[0] > 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;
}
void
R_AliasClipTriangle (mtriangle_t *ptri)
{
int i, k, pingpong;
mtriangle_t mtri;
unsigned int 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 < k; i++) {
if (fv[pingpong][i].v[0] < r_refdef.aliasvrect.x)
fv[pingpong][i].v[0] = r_refdef.aliasvrect.x;
else if (fv[pingpong][i].v[0] > 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; i < k - 1; i++) {
mtri.vertindex[1] = i;
mtri.vertindex[2] = i + 1;
D_PolysetDraw ();
}
}