Add adjustable gamma

This commit is contained in:
Ryan Baldwin 2022-07-02 13:06:34 -07:00
parent 4e7be6266d
commit e49548ff5a
17 changed files with 28 additions and 5037 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1780,39 +1780,13 @@ int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolea
/****************************************/
//Diabolickal HLBSP start
byte vid_gamma_table[256];
void Build_Gamma_Table (void) {
int i;
float inf;
float in_gamma;
if ((i = COM_CheckParm("-gamma")) != 0 && i+1 < com_argc) {
in_gamma = Q_atof(com_argv[i+1]);
if (in_gamma < 0.3) in_gamma = 0.3;
if (in_gamma > 1) in_gamma = 1.0;
} else {
in_gamma = 1;
}
if (in_gamma != 1) {
for (i=0 ; i<256 ; i++) {
inf = min(255 * pow((i + 0.5) / 255.5, in_gamma) + 0.5, 255);
vid_gamma_table[i] = inf;
}
} else {
for (i=0 ; i<256 ; i++)
vid_gamma_table[i] = i;
}
}
/*
================
GL_LoadTexture32
================
*/
extern byte vid_gamma_table[256];
int GL_LoadTexture32 (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha)
{
qboolean noalpha;
@ -1846,17 +1820,11 @@ int GL_LoadTexture32 (char *identifier, int width, int height, byte *data, qbool
GL_Bind(texture_extension_number );
#if 1
// Baker: this applies our -gamma parameter table
if (1) {
//extern byte vid_gamma_table[256];
for (i = 0; i < image_size; i++){
data[4 * i] = vid_gamma_table[data[4 * i]];
data[4 * i + 1] = vid_gamma_table[data[4 * i + 1]];
data[4 * i + 2] = vid_gamma_table[data[4 * i + 2]];
}
}
#endif
for (i = 0; i < image_size; i++){
data[4 * i] = gammatable[data[4 * i]];
data[4 * i + 1] = gammatable[data[4 * i + 1]];
data[4 * i + 2] = gammatable[data[4 * i + 2]];
}
GL_Upload32 ((unsigned *)data, width, height, mipmap, alpha);

View File

@ -430,7 +430,7 @@ mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model);
int GL_LoadTexture32 (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha); //Diabolickal HLBSP
void Build_Gamma_Table (void); //Diabolickal HLBSP
void BuildGammaTable (float g);
int loadtextureimage (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap); //Diabolickal TGA
#endif // __MODEL__

View File

@ -803,8 +803,9 @@ void R_BlendLightmaps (int specialrender)
float *v;
glRect_t *theRect;
if (r_fullbright.value)
if (r_fullbright.value) {
return;
}
glEnable(GL_MODULATE);
glColor4f(1,1,1,1);

View File

@ -171,6 +171,8 @@ static void Check_Gamma (unsigned char *pal)
else
vid_gamma = Q_atof(com_argv[i+1]);
Con_Printf("in check_gamma: %f\n", vid_gamma);
for (i=0 ; i<768 ; i++)
{
f = pow ( (pal[i]+1)/256.0 , vid_gamma );
@ -184,7 +186,7 @@ static void Check_Gamma (unsigned char *pal)
memcpy (pal, palette, sizeof(palette));
Build_Gamma_Table (); //Diabolickal HLBSP
BuildGammaTable (vid_gamma); //Diabolickal HLBSP
}
void VID_Init (unsigned char *palette)

View File

@ -1,350 +0,0 @@
/*
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];
void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av);
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] + (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;
}
#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] + (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;
}
/*
================
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<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 ();
}
}

View File

@ -1,753 +0,0 @@
/*
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_alias.c: routines for setting up to draw alias models
#include "quakedef.h"
#include "r_local.h"
#include "d_local.h" // FIXME: shouldn't be needed (is needed for patch
// right now, but that should move)
#define LIGHT_MIN 5 // lowest light value we'll allow, to avoid the
// need for inner-loop light clamping
mtriangle_t *ptriangles;
affinetridesc_t r_affinetridesc;
void * acolormap; // FIXME: should go away
trivertx_t *r_apverts;
// TODO: these probably will go away with optimized rasterization
mdl_t *pmdl;
vec3_t r_plightvec;
int r_ambientlight;
float r_shadelight;
aliashdr_t *paliashdr;
finalvert_t *pfinalverts;
auxvert_t *pauxverts;
static float ziscale;
static model_t *pmodel;
static vec3_t alias_forward, alias_right, alias_up;
static maliasskindesc_t *pskindesc;
int r_amodels_drawn;
int a_skinwidth;
int r_anumverts;
float aliastransform[3][4];
typedef struct {
int index0;
int index1;
} aedge_t;
static aedge_t aedges[12] = {
{0, 1}, {1, 2}, {2, 3}, {3, 0},
{4, 5}, {5, 6}, {6, 7}, {7, 4},
{0, 5}, {1, 4}, {2, 7}, {3, 6}
};
#define NUMVERTEXNORMALS 162
float r_avertexnormals[NUMVERTEXNORMALS][3] = {
#include "anorms.h"
};
void R_AliasTransformAndProjectFinalVerts (finalvert_t *fv,
stvert_t *pstverts);
void R_AliasSetUpTransform (int trivial_accept);
void R_AliasTransformVector (vec3_t in, vec3_t out);
void R_AliasTransformFinalVert (finalvert_t *fv, auxvert_t *av,
trivertx_t *pverts, stvert_t *pstverts);
void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av);
/*
================
R_AliasCheckBBox
================
*/
qboolean R_AliasCheckBBox (void)
{
int i, flags, frame, numv;
aliashdr_t *pahdr;
float zi, basepts[8][3], v0, v1, frac;
finalvert_t *pv0, *pv1, viewpts[16];
auxvert_t *pa0, *pa1, viewaux[16];
maliasframedesc_t *pframedesc;
qboolean zclipped, zfullyclipped;
unsigned anyclip, allclip;
int minz;
// expand, rotate, and translate points into worldspace
currententity->trivial_accept = 0;
pmodel = currententity->model;
pahdr = Mod_Extradata (pmodel);
pmdl = (mdl_t *)((byte *)pahdr + pahdr->model);
R_AliasSetUpTransform (0);
// construct the base bounding box for this frame
frame = currententity->frame;
// TODO: don't repeat this check when drawing?
if ((frame >= pmdl->numframes) || (frame < 0))
{
Con_DPrintf ("No such frame %d %s\n", frame,
pmodel->name);
frame = 0;
}
pframedesc = &pahdr->frames[frame];
// x worldspace coordinates
basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] =
(float)pframedesc->bboxmin.v[0];
basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] =
(float)pframedesc->bboxmax.v[0];
// y worldspace coordinates
basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] =
(float)pframedesc->bboxmin.v[1];
basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] =
(float)pframedesc->bboxmax.v[1];
// z worldspace coordinates
basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] =
(float)pframedesc->bboxmin.v[2];
basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] =
(float)pframedesc->bboxmax.v[2];
zclipped = false;
zfullyclipped = true;
minz = 9999;
for (i=0; i<8 ; i++)
{
R_AliasTransformVector (&basepts[i][0], &viewaux[i].fv[0]);
if (viewaux[i].fv[2] < ALIAS_Z_CLIP_PLANE)
{
// we must clip points that are closer than the near clip plane
viewpts[i].flags = ALIAS_Z_CLIP;
zclipped = true;
}
else
{
if (viewaux[i].fv[2] < minz)
minz = viewaux[i].fv[2];
viewpts[i].flags = 0;
zfullyclipped = false;
}
}
if (zfullyclipped)
{
return false; // everything was near-z-clipped
}
numv = 8;
if (zclipped)
{
// organize points by edges, use edges to get new points (possible trivial
// reject)
for (i=0 ; i<12 ; i++)
{
// edge endpoints
pv0 = &viewpts[aedges[i].index0];
pv1 = &viewpts[aedges[i].index1];
pa0 = &viewaux[aedges[i].index0];
pa1 = &viewaux[aedges[i].index1];
// if one end is clipped and the other isn't, make a new point
if (pv0->flags ^ pv1->flags)
{
frac = (ALIAS_Z_CLIP_PLANE - pa0->fv[2]) /
(pa1->fv[2] - pa0->fv[2]);
viewaux[numv].fv[0] = pa0->fv[0] +
(pa1->fv[0] - pa0->fv[0]) * frac;
viewaux[numv].fv[1] = pa0->fv[1] +
(pa1->fv[1] - pa0->fv[1]) * frac;
viewaux[numv].fv[2] = ALIAS_Z_CLIP_PLANE;
viewpts[numv].flags = 0;
numv++;
}
}
}
// project the vertices that remain after clipping
anyclip = 0;
allclip = ALIAS_XY_CLIP_MASK;
// TODO: probably should do this loop in ASM, especially if we use floats
for (i=0 ; i<numv ; i++)
{
// we don't need to bother with vertices that were z-clipped
if (viewpts[i].flags & ALIAS_Z_CLIP)
continue;
zi = 1.0 / viewaux[i].fv[2];
// FIXME: do with chop mode in ASM, or convert to float
v0 = (viewaux[i].fv[0] * xscale * zi) + xcenter;
v1 = (viewaux[i].fv[1] * yscale * zi) + ycenter;
flags = 0;
if (v0 < r_refdef.fvrectx)
flags |= ALIAS_LEFT_CLIP;
if (v1 < r_refdef.fvrecty)
flags |= ALIAS_TOP_CLIP;
if (v0 > r_refdef.fvrectright)
flags |= ALIAS_RIGHT_CLIP;
if (v1 > r_refdef.fvrectbottom)
flags |= ALIAS_BOTTOM_CLIP;
anyclip |= flags;
allclip &= flags;
}
if (allclip)
return false; // trivial reject off one side
currententity->trivial_accept = !anyclip & !zclipped;
if (currententity->trivial_accept)
{
if (minz > (r_aliastransition + (pmdl->size * r_resfudge)))
{
currententity->trivial_accept |= 2;
}
}
return true;
}
/*
================
R_AliasTransformVector
================
*/
void R_AliasTransformVector (vec3_t in, vec3_t out)
{
out[0] = DotProduct(in, aliastransform[0]) + aliastransform[0][3];
out[1] = DotProduct(in, aliastransform[1]) + aliastransform[1][3];
out[2] = DotProduct(in, aliastransform[2]) + aliastransform[2][3];
}
/*
================
R_AliasPreparePoints
General clipped case
================
*/
void R_AliasPreparePoints (void)
{
int i;
stvert_t *pstverts;
finalvert_t *fv;
auxvert_t *av;
mtriangle_t *ptri;
finalvert_t *pfv[3];
pstverts = (stvert_t *)((byte *)paliashdr + paliashdr->stverts);
r_anumverts = pmdl->numverts;
fv = pfinalverts;
av = pauxverts;
for (i=0 ; i<r_anumverts ; i++, fv++, av++, r_apverts++, pstverts++)
{
R_AliasTransformFinalVert (fv, av, r_apverts, pstverts);
if (av->fv[2] < ALIAS_Z_CLIP_PLANE)
fv->flags |= ALIAS_Z_CLIP;
else
{
R_AliasProjectFinalVert (fv, av);
if (fv->v[0] < r_refdef.aliasvrect.x)
fv->flags |= ALIAS_LEFT_CLIP;
if (fv->v[1] < r_refdef.aliasvrect.y)
fv->flags |= ALIAS_TOP_CLIP;
if (fv->v[0] > r_refdef.aliasvrectright)
fv->flags |= ALIAS_RIGHT_CLIP;
if (fv->v[1] > r_refdef.aliasvrectbottom)
fv->flags |= ALIAS_BOTTOM_CLIP;
}
}
//
// clip and draw all triangles
//
r_affinetridesc.numtriangles = 1;
ptri = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
for (i=0 ; i<pmdl->numtris ; i++, ptri++)
{
pfv[0] = &pfinalverts[ptri->vertindex[0]];
pfv[1] = &pfinalverts[ptri->vertindex[1]];
pfv[2] = &pfinalverts[ptri->vertindex[2]];
if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) )
continue; // completely clipped
if ( ! ( (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) &
(ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) )
{ // totally unclipped
r_affinetridesc.pfinalverts = pfinalverts;
r_affinetridesc.ptriangles = ptri;
D_PolysetDraw ();
}
else
{ // partially clipped
R_AliasClipTriangle (ptri);
}
}
}
/*
================
R_AliasSetUpTransform
================
*/
void R_AliasSetUpTransform (int trivial_accept)
{
int i;
float rotationmatrix[3][4], t2matrix[3][4];
static float tmatrix[3][4];
static float viewmatrix[3][4];
vec3_t angles;
// TODO: should really be stored with the entity instead of being reconstructed
// TODO: should use a look-up table
// TODO: could cache lazily, stored in the entity
angles[ROLL] = currententity->angles[ROLL];
angles[PITCH] = -currententity->angles[PITCH];
angles[YAW] = currententity->angles[YAW];
AngleVectors (angles, alias_forward, alias_right, alias_up);
tmatrix[0][0] = pmdl->scale[0];
tmatrix[1][1] = pmdl->scale[1];
tmatrix[2][2] = pmdl->scale[2];
tmatrix[0][3] = pmdl->scale_origin[0];
tmatrix[1][3] = pmdl->scale_origin[1];
tmatrix[2][3] = pmdl->scale_origin[2];
// TODO: can do this with simple matrix rearrangement
for (i=0 ; i<3 ; i++)
{
t2matrix[i][0] = alias_forward[i];
t2matrix[i][1] = -alias_right[i];
t2matrix[i][2] = alias_up[i];
}
t2matrix[0][3] = -modelorg[0];
t2matrix[1][3] = -modelorg[1];
t2matrix[2][3] = -modelorg[2];
// FIXME: can do more efficiently than full concatenation
R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
// TODO: should be global, set when vright, etc., set
VectorCopy (vright, viewmatrix[0]);
VectorCopy (vup, viewmatrix[1]);
VectorInverse (viewmatrix[1]);
VectorCopy (vpn, viewmatrix[2]);
// viewmatrix[0][3] = 0;
// viewmatrix[1][3] = 0;
// viewmatrix[2][3] = 0;
R_ConcatTransforms (viewmatrix, rotationmatrix, aliastransform);
// do the scaling up of x and y to screen coordinates as part of the transform
// for the unclipped case (it would mess up clipping in the clipped case).
// Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y
// correspondingly so the projected x and y come out right
// FIXME: make this work for clipped case too?
if (trivial_accept)
{
for (i=0 ; i<4 ; i++)
{
aliastransform[0][i] *= aliasxscale *
(1.0 / ((float)0x8000 * 0x10000));
aliastransform[1][i] *= aliasyscale *
(1.0 / ((float)0x8000 * 0x10000));
aliastransform[2][i] *= 1.0 / ((float)0x8000 * 0x10000);
}
}
}
/*
================
R_AliasTransformFinalVert
================
*/
void R_AliasTransformFinalVert (finalvert_t *fv, auxvert_t *av,
trivertx_t *pverts, stvert_t *pstverts)
{
int temp;
float lightcos, *plightnormal;
av->fv[0] = DotProduct(pverts->v, aliastransform[0]) +
aliastransform[0][3];
av->fv[1] = DotProduct(pverts->v, aliastransform[1]) +
aliastransform[1][3];
av->fv[2] = DotProduct(pverts->v, aliastransform[2]) +
aliastransform[2][3];
fv->v[2] = pstverts->s;
fv->v[3] = pstverts->t;
fv->flags = pstverts->onseam;
// lighting
plightnormal = r_avertexnormals[pverts->lightnormalindex];
lightcos = DotProduct (plightnormal, r_plightvec);
temp = r_ambientlight;
if (lightcos < 0)
{
temp += (int)(r_shadelight * lightcos);
// clamp; because we limited the minimum ambient and shading light, we
// don't have to clamp low light, just bright
if (temp < 0)
temp = 0;
}
fv->v[4] = temp;
}
#if !id386
/*
================
R_AliasTransformAndProjectFinalVerts
================
*/
void R_AliasTransformAndProjectFinalVerts (finalvert_t *fv, stvert_t *pstverts)
{
int i, temp;
float lightcos, *plightnormal, zi;
trivertx_t *pverts;
pverts = r_apverts;
for (i=0 ; i<r_anumverts ; i++, fv++, pverts++, pstverts++)
{
// transform and project
zi = 1.0 / (DotProduct(pverts->v, aliastransform[2]) +
aliastransform[2][3]);
// x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is
// scaled up by 1/2**31, and the scaling cancels out for x and y in the
// projection
fv->v[5] = zi;
fv->v[0] = ((DotProduct(pverts->v, aliastransform[0]) +
aliastransform[0][3]) * zi) + aliasxcenter;
fv->v[1] = ((DotProduct(pverts->v, aliastransform[1]) +
aliastransform[1][3]) * zi) + aliasycenter;
fv->v[2] = pstverts->s;
fv->v[3] = pstverts->t;
fv->flags = pstverts->onseam;
// lighting
plightnormal = r_avertexnormals[pverts->lightnormalindex];
lightcos = DotProduct (plightnormal, r_plightvec);
temp = r_ambientlight;
if (lightcos < 0)
{
temp += (int)(r_shadelight * lightcos);
// clamp; because we limited the minimum ambient and shading light, we
// don't have to clamp low light, just bright
if (temp < 0)
temp = 0;
}
fv->v[4] = temp;
}
}
#endif
/*
================
R_AliasProjectFinalVert
================
*/
void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av)
{
float zi;
// project points
zi = 1.0 / av->fv[2];
fv->v[5] = zi * ziscale;
fv->v[0] = (av->fv[0] * aliasxscale * zi) + aliasxcenter;
fv->v[1] = (av->fv[1] * aliasyscale * zi) + aliasycenter;
}
/*
================
R_AliasPrepareUnclippedPoints
================
*/
void R_AliasPrepareUnclippedPoints (void)
{
stvert_t *pstverts;
finalvert_t *fv;
pstverts = (stvert_t *)((byte *)paliashdr + paliashdr->stverts);
r_anumverts = pmdl->numverts;
// FIXME: just use pfinalverts directly?
fv = pfinalverts;
R_AliasTransformAndProjectFinalVerts (fv, pstverts);
if (r_affinetridesc.drawtype)
D_PolysetDrawFinalVerts (fv, r_anumverts);
r_affinetridesc.pfinalverts = pfinalverts;
r_affinetridesc.ptriangles = (mtriangle_t *)
((byte *)paliashdr + paliashdr->triangles);
r_affinetridesc.numtriangles = pmdl->numtris;
D_PolysetDraw ();
}
/*
===============
R_AliasSetupSkin
===============
*/
void R_AliasSetupSkin (void)
{
int skinnum;
int i, numskins;
maliasskingroup_t *paliasskingroup;
float *pskinintervals, fullskininterval;
float skintargettime, skintime;
skinnum = currententity->skinnum;
if ((skinnum >= pmdl->numskins) || (skinnum < 0))
{
Con_DPrintf ("R_AliasSetupSkin: no such skin # %d\n", skinnum);
skinnum = 0;
}
pskindesc = ((maliasskindesc_t *)
((byte *)paliashdr + paliashdr->skindesc)) + skinnum;
a_skinwidth = pmdl->skinwidth;
if (pskindesc->type == ALIAS_SKIN_GROUP)
{
paliasskingroup = (maliasskingroup_t *)((byte *)paliashdr +
pskindesc->skin);
pskinintervals = (float *)
((byte *)paliashdr + paliasskingroup->intervals);
numskins = paliasskingroup->numskins;
fullskininterval = pskinintervals[numskins-1];
skintime = cl.time + currententity->syncbase;
// when loading in Mod_LoadAliasSkinGroup, we guaranteed all interval
// values are positive, so we don't have to worry about division by 0
skintargettime = skintime -
((int)(skintime / fullskininterval)) * fullskininterval;
for (i=0 ; i<(numskins-1) ; i++)
{
if (pskinintervals[i] > skintargettime)
break;
}
pskindesc = &paliasskingroup->skindescs[i];
}
r_affinetridesc.pskindesc = pskindesc;
r_affinetridesc.pskin = (void *)((byte *)paliashdr + pskindesc->skin);
r_affinetridesc.skinwidth = a_skinwidth;
r_affinetridesc.seamfixupX16 = (a_skinwidth >> 1) << 16;
r_affinetridesc.skinheight = pmdl->skinheight;
}
/*
================
R_AliasSetupLighting
================
*/
void R_AliasSetupLighting (alight_t *plighting)
{
// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
// to clamp off the bottom
r_ambientlight = plighting->ambientlight;
if (r_ambientlight < LIGHT_MIN)
r_ambientlight = LIGHT_MIN;
r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
if (r_ambientlight < LIGHT_MIN)
r_ambientlight = LIGHT_MIN;
r_shadelight = plighting->shadelight;
if (r_shadelight < 0)
r_shadelight = 0;
r_shadelight *= VID_GRADES;
// rotate the lighting vector into the model's frame of reference
r_plightvec[0] = DotProduct (plighting->plightvec, alias_forward);
r_plightvec[1] = -DotProduct (plighting->plightvec, alias_right);
r_plightvec[2] = DotProduct (plighting->plightvec, alias_up);
}
/*
=================
R_AliasSetupFrame
set r_apverts
=================
*/
void R_AliasSetupFrame (void)
{
int frame;
int i, numframes;
maliasgroup_t *paliasgroup;
float *pintervals, fullinterval, targettime, time;
frame = currententity->frame;
if ((frame >= pmdl->numframes) || (frame < 0))
{
Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
frame = 0;
}
if (paliashdr->frames[frame].type == ALIAS_SINGLE)
{
r_apverts = (trivertx_t *)
((byte *)paliashdr + paliashdr->frames[frame].frame);
return;
}
paliasgroup = (maliasgroup_t *)
((byte *)paliashdr + paliashdr->frames[frame].frame);
pintervals = (float *)((byte *)paliashdr + paliasgroup->intervals);
numframes = paliasgroup->numframes;
fullinterval = pintervals[numframes-1];
time = cl.time + currententity->syncbase;
//
// when loading in Mod_LoadAliasGroup, we guaranteed all interval values
// are positive, so we don't have to worry about division by 0
//
targettime = time - ((int)(time / fullinterval)) * fullinterval;
for (i=0 ; i<(numframes-1) ; i++)
{
if (pintervals[i] > targettime)
break;
}
r_apverts = (trivertx_t *)
((byte *)paliashdr + paliasgroup->frames[i].frame);
}
/*
================
R_AliasDrawModel
================
*/
void R_AliasDrawModel (alight_t *plighting)
{
finalvert_t finalverts[MAXALIASVERTS +
((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1];
auxvert_t auxverts[MAXALIASVERTS];
r_amodels_drawn++;
// cache align
pfinalverts = (finalvert_t *)
(((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
pauxverts = &auxverts[0];
paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);
pmdl = (mdl_t *)((byte *)paliashdr + paliashdr->model);
R_AliasSetupSkin ();
R_AliasSetUpTransform (currententity->trivial_accept);
R_AliasSetupLighting (plighting);
R_AliasSetupFrame ();
if (!currententity->colormap)
Sys_Error ("R_AliasDrawModel: !currententity->colormap");
r_affinetridesc.drawtype = (currententity->trivial_accept == 3) &&
r_recursiveaffinetriangles;
if (r_affinetridesc.drawtype)
{
D_PolysetUpdateTables (); // FIXME: precalc...
}
else
{
#if id386
D_Aff8Patch (currententity->colormap);
#endif
}
acolormap = currententity->colormap;
if (currententity != &cl.viewent)
ziscale = (float)0x8000 * (float)0x10000;
else
ziscale = (float)0x8000 * (float)0x10000 * 3.0;
if (currententity->trivial_accept)
R_AliasPrepareUnclippedPoints ();
else
R_AliasPreparePoints ();
}

View File

@ -1,674 +0,0 @@
/*
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_bsp.c
#include "quakedef.h"
#include "r_local.h"
//
// current entity info
//
qboolean insubmodel;
entity_t *currententity;
vec3_t modelorg, base_modelorg;
// modelorg is the viewpoint reletive to
// the currently rendering entity
vec3_t r_entorigin; // the currently rendering entity in world
// coordinates
float entity_rotation[3][3];
vec3_t r_worldmodelorg;
int r_currentbkey;
typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
#define MAX_BMODEL_VERTS 500 // 6K
#define MAX_BMODEL_EDGES 1000 // 12K
static mvertex_t *pbverts;
static bedge_t *pbedges;
static int numbverts, numbedges;
static mvertex_t *pfrontenter, *pfrontexit;
static qboolean makeclippededge;
//===========================================================================
/*
================
R_EntityRotate
================
*/
void R_EntityRotate (vec3_t vec)
{
vec3_t tvec;
VectorCopy (vec, tvec);
vec[0] = DotProduct (entity_rotation[0], tvec);
vec[1] = DotProduct (entity_rotation[1], tvec);
vec[2] = DotProduct (entity_rotation[2], tvec);
}
/*
================
R_RotateBmodel
================
*/
void R_RotateBmodel (void)
{
float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
// TODO: should use a look-up table
// TODO: should really be stored with the entity instead of being reconstructed
// TODO: could cache lazily, stored in the entity
// TODO: share work with R_SetUpAliasTransform
// yaw
angle = currententity->angles[YAW];
angle = angle * M_PI*2 / 360;
s = sin(angle);
c = cos(angle);
temp1[0][0] = c;
temp1[0][1] = s;
temp1[0][2] = 0;
temp1[1][0] = -s;
temp1[1][1] = c;
temp1[1][2] = 0;
temp1[2][0] = 0;
temp1[2][1] = 0;
temp1[2][2] = 1;
// pitch
angle = currententity->angles[PITCH];
angle = angle * M_PI*2 / 360;
s = sin(angle);
c = cos(angle);
temp2[0][0] = c;
temp2[0][1] = 0;
temp2[0][2] = -s;
temp2[1][0] = 0;
temp2[1][1] = 1;
temp2[1][2] = 0;
temp2[2][0] = s;
temp2[2][1] = 0;
temp2[2][2] = c;
R_ConcatRotations (temp2, temp1, temp3);
// roll
angle = currententity->angles[ROLL];
angle = angle * M_PI*2 / 360;
s = sin(angle);
c = cos(angle);
temp1[0][0] = 1;
temp1[0][1] = 0;
temp1[0][2] = 0;
temp1[1][0] = 0;
temp1[1][1] = c;
temp1[1][2] = s;
temp1[2][0] = 0;
temp1[2][1] = -s;
temp1[2][2] = c;
R_ConcatRotations (temp1, temp3, entity_rotation);
//
// rotate modelorg and the transformation matrix
//
R_EntityRotate (modelorg);
R_EntityRotate (vpn);
R_EntityRotate (vright);
R_EntityRotate (vup);
R_TransformFrustum ();
}
/*
================
R_RecursiveClipBPoly
================
*/
void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
{
bedge_t *psideedges[2], *pnextedge, *ptedge;
int i, side, lastside;
float dist, frac, lastdist;
mplane_t *splitplane, tplane;
mvertex_t *pvert, *plastvert, *ptvert;
mnode_t *pn;
psideedges[0] = psideedges[1] = NULL;
makeclippededge = false;
// transform the BSP plane into model space
// FIXME: cache these?
splitplane = pnode->plane;
tplane.dist = splitplane->dist -
DotProduct(r_entorigin, splitplane->normal);
tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
// clip edges to BSP plane
for ( ; pedges ; pedges = pnextedge)
{
pnextedge = pedges->pnext;
// set the status for the last point as the previous point
// FIXME: cache this stuff somehow?
plastvert = pedges->v[0];
lastdist = DotProduct (plastvert->position, tplane.normal) -
tplane.dist;
if (lastdist > 0)
lastside = 0;
else
lastside = 1;
pvert = pedges->v[1];
dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
if (dist > 0)
side = 0;
else
side = 1;
if (side != lastside)
{
// clipped
if (numbverts >= MAX_BMODEL_VERTS)
return;
// generate the clipped vertex
frac = lastdist / (lastdist - dist);
ptvert = &pbverts[numbverts++];
ptvert->position[0] = plastvert->position[0] +
frac * (pvert->position[0] -
plastvert->position[0]);
ptvert->position[1] = plastvert->position[1] +
frac * (pvert->position[1] -
plastvert->position[1]);
ptvert->position[2] = plastvert->position[2] +
frac * (pvert->position[2] -
plastvert->position[2]);
// split into two edges, one on each side, and remember entering
// and exiting points
// FIXME: share the clip edge by having a winding direction flag?
if (numbedges >= (MAX_BMODEL_EDGES - 1))
{
Con_Printf ("Out of edges for bmodel\n");
return;
}
ptedge = &pbedges[numbedges];
ptedge->pnext = psideedges[lastside];
psideedges[lastside] = ptedge;
ptedge->v[0] = plastvert;
ptedge->v[1] = ptvert;
ptedge = &pbedges[numbedges + 1];
ptedge->pnext = psideedges[side];
psideedges[side] = ptedge;
ptedge->v[0] = ptvert;
ptedge->v[1] = pvert;
numbedges += 2;
if (side == 0)
{
// entering for front, exiting for back
pfrontenter = ptvert;
makeclippededge = true;
}
else
{
pfrontexit = ptvert;
makeclippededge = true;
}
}
else
{
// add the edge to the appropriate side
pedges->pnext = psideedges[side];
psideedges[side] = pedges;
}
}
// if anything was clipped, reconstitute and add the edges along the clip
// plane to both sides (but in opposite directions)
if (makeclippededge)
{
if (numbedges >= (MAX_BMODEL_EDGES - 2))
{
Con_Printf ("Out of edges for bmodel\n");
return;
}
ptedge = &pbedges[numbedges];
ptedge->pnext = psideedges[0];
psideedges[0] = ptedge;
ptedge->v[0] = pfrontexit;
ptedge->v[1] = pfrontenter;
ptedge = &pbedges[numbedges + 1];
ptedge->pnext = psideedges[1];
psideedges[1] = ptedge;
ptedge->v[0] = pfrontenter;
ptedge->v[1] = pfrontexit;
numbedges += 2;
}
// draw or recurse further
for (i=0 ; i<2 ; i++)
{
if (psideedges[i])
{
// draw if we've reached a non-solid leaf, done if all that's left is a
// solid leaf, and continue down the tree if it's not a leaf
pn = pnode->children[i];
// we're done with this branch if the node or leaf isn't in the PVS
if (pn->visframe == r_visframecount)
{
if (pn->contents < 0)
{
if (pn->contents != CONTENTS_SOLID)
{
r_currentbkey = ((mleaf_t *)pn)->key;
R_RenderBmodelFace (psideedges[i], psurf);
}
}
else
{
R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
psurf);
}
}
}
}
}
/*
================
R_DrawSolidClippedSubmodelPolygons
================
*/
void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel)
{
int i, j, lindex;
vec_t dot;
msurface_t *psurf;
int numsurfaces;
mplane_t *pplane;
mvertex_t bverts[MAX_BMODEL_VERTS];
bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
medge_t *pedge, *pedges;
// FIXME: use bounding-box-based frustum clipping info?
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
numsurfaces = pmodel->nummodelsurfaces;
pedges = pmodel->edges;
for (i=0 ; i<numsurfaces ; i++, psurf++)
{
// find which side of the node we are on
pplane = psurf->plane;
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
// draw the polygon
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
{
// FIXME: use bounding-box-based frustum clipping info?
// copy the edges to bedges, flipping if necessary so always
// clockwise winding
// FIXME: if edges and vertices get caches, these assignments must move
// outside the loop, and overflow checking must be done here
pbverts = bverts;
pbedges = bedges;
numbverts = numbedges = 0;
if (psurf->numedges > 0)
{
pbedge = &bedges[numbedges];
numbedges += psurf->numedges;
for (j=0 ; j<psurf->numedges ; j++)
{
lindex = pmodel->surfedges[psurf->firstedge+j];
if (lindex > 0)
{
pedge = &pedges[lindex];
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
}
else
{
lindex = -lindex;
pedge = &pedges[lindex];
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
}
pbedge[j].pnext = &pbedge[j+1];
}
pbedge[j-1].pnext = NULL; // mark end of edges
R_RecursiveClipBPoly (pbedge, currententity->topnode, psurf);
}
else
{
Sys_Error ("no edges in bmodel");
}
}
}
}
/*
================
R_DrawSubmodelPolygons
================
*/
void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags)
{
int i;
vec_t dot;
msurface_t *psurf;
int numsurfaces;
mplane_t *pplane;
// FIXME: use bounding-box-based frustum clipping info?
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
numsurfaces = pmodel->nummodelsurfaces;
for (i=0 ; i<numsurfaces ; i++, psurf++)
{
// find which side of the node we are on
pplane = psurf->plane;
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
// draw the polygon
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
{
r_currentkey = ((mleaf_t *)currententity->topnode)->key;
// FIXME: use bounding-box-based frustum clipping info?
R_RenderFace (psurf, clipflags);
}
}
}
/*
================
R_RecursiveWorldNode
================
*/
void R_RecursiveWorldNode (mnode_t *node, int clipflags)
{
int i, c, side, *pindex;
vec3_t acceptpt, rejectpt;
mplane_t *plane;
msurface_t *surf, **mark;
mleaf_t *pleaf;
double d, dot;
if (node->contents == CONTENTS_SOLID)
return; // solid
if (node->visframe != r_visframecount)
return;
// cull the clipping planes if not trivial accept
// FIXME: the compiler is doing a lousy job of optimizing here; it could be
// twice as fast in ASM
if (clipflags)
{
for (i=0 ; i<4 ; i++)
{
if (! (clipflags & (1<<i)) )
continue; // don't need to clip against it
// generate accept and reject points
// FIXME: do with fast look-ups or integer tests based on the sign bit
// of the floating point values
pindex = pfrustum_indexes[i];
rejectpt[0] = (float)node->minmaxs[pindex[0]];
rejectpt[1] = (float)node->minmaxs[pindex[1]];
rejectpt[2] = (float)node->minmaxs[pindex[2]];
d = DotProduct (rejectpt, view_clipplanes[i].normal);
d -= view_clipplanes[i].dist;
if (d <= 0)
return;
acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
d = DotProduct (acceptpt, view_clipplanes[i].normal);
d -= view_clipplanes[i].dist;
if (d >= 0)
clipflags &= ~(1<<i); // node is entirely on screen
}
}
// if a leaf node, draw stuff
if (node->contents < 0)
{
pleaf = (mleaf_t *)node;
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
if (c)
{
do
{
(*mark)->visframe = r_framecount;
mark++;
} while (--c);
}
// deal with model fragments in this leaf
if (pleaf->efrags)
{
R_StoreEfrags (&pleaf->efrags);
}
pleaf->key = r_currentkey;
r_currentkey++; // all bmodels in a leaf share the same key
}
else
{
// node is just a decision point, so go down the apropriate sides
// find which side of the node we are on
plane = node->plane;
switch (plane->type)
{
case PLANE_X:
dot = modelorg[0] - plane->dist;
break;
case PLANE_Y:
dot = modelorg[1] - plane->dist;
break;
case PLANE_Z:
dot = modelorg[2] - plane->dist;
break;
default:
dot = DotProduct (modelorg, plane->normal) - plane->dist;
break;
}
if (dot >= 0)
side = 0;
else
side = 1;
// recurse down the children, front side first
R_RecursiveWorldNode (node->children[side], clipflags);
// draw stuff
c = node->numsurfaces;
if (c)
{
surf = cl.worldmodel->surfaces + node->firstsurface;
if (dot < -BACKFACE_EPSILON)
{
do
{
if ((surf->flags & SURF_PLANEBACK) &&
(surf->visframe == r_framecount))
{
if (r_drawpolys)
{
if (r_worldpolysbacktofront)
{
if (numbtofpolys < MAX_BTOFPOLYS)
{
pbtofpolys[numbtofpolys].clipflags =
clipflags;
pbtofpolys[numbtofpolys].psurf = surf;
numbtofpolys++;
}
}
else
{
R_RenderPoly (surf, clipflags);
}
}
else
{
R_RenderFace (surf, clipflags);
}
}
surf++;
} while (--c);
}
else if (dot > BACKFACE_EPSILON)
{
do
{
if (!(surf->flags & SURF_PLANEBACK) &&
(surf->visframe == r_framecount))
{
if (r_drawpolys)
{
if (r_worldpolysbacktofront)
{
if (numbtofpolys < MAX_BTOFPOLYS)
{
pbtofpolys[numbtofpolys].clipflags =
clipflags;
pbtofpolys[numbtofpolys].psurf = surf;
numbtofpolys++;
}
}
else
{
R_RenderPoly (surf, clipflags);
}
}
else
{
R_RenderFace (surf, clipflags);
}
}
surf++;
} while (--c);
}
// all surfaces on the same node share the same sequence number
r_currentkey++;
}
// recurse down the back side
R_RecursiveWorldNode (node->children[!side], clipflags);
}
}
/*
================
R_RenderWorld
================
*/
void R_RenderWorld (void)
{
int i;
model_t *clmodel;
btofpoly_t btofpolys[MAX_BTOFPOLYS];
pbtofpolys = btofpolys;
currententity = &cl_entities[0];
VectorCopy (r_origin, modelorg);
clmodel = currententity->model;
r_pcurrentvertbase = clmodel->vertexes;
R_RecursiveWorldNode (clmodel->nodes, 15);
// if the driver wants the polygons back to front, play the visible ones back
// in that order
if (r_worldpolysbacktofront)
{
for (i=numbtofpolys-1 ; i>=0 ; i--)
{
R_RenderPoly (btofpolys[i].psurf, btofpolys[i].clipflags);
}
}
}

View File

@ -1,908 +0,0 @@
/*
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_draw.c
#include "quakedef.h"
#include "r_local.h"
#include "d_local.h" // FIXME: shouldn't need to include this
#define MAXLEFTCLIPEDGES 100
// !!! if these are changed, they must be changed in asm_draw.h too !!!
#define FULLY_CLIPPED_CACHED 0x80000000
#define FRAMECOUNT_MASK 0x7FFFFFFF
unsigned int cacheoffset;
int c_faceclip; // number of faces clipped
zpointdesc_t r_zpointdesc;
polydesc_t r_polydesc;
clipplane_t *entity_clipplanes;
clipplane_t view_clipplanes[4];
clipplane_t world_clipplanes[16];
medge_t *r_pedge;
qboolean r_leftclipped, r_rightclipped;
static qboolean makeleftedge, makerightedge;
qboolean r_nearzionly;
int sintable[SIN_BUFFER_SIZE];
int intsintable[SIN_BUFFER_SIZE];
mvertex_t r_leftenter, r_leftexit;
mvertex_t r_rightenter, r_rightexit;
typedef struct
{
float u,v;
int ceilv;
} evert_t;
int r_emitted;
float r_nearzi;
float r_u1, r_v1, r_lzi1;
int r_ceilv1;
qboolean r_lastvertvalid;
#if !id386
/*
================
R_EmitEdge
================
*/
void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
{
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)
{
u0 = r_u1;
v0 = r_v1;
lzi0 = r_lzi1;
ceilv0 = r_ceilv1;
}
else
{
world = &pv0->position[0];
// transform and project
VectorSubtract (world, modelorg, local);
TransformVector (local, transformed);
if (transformed[2] < NEAR_CLIP)
transformed[2] = NEAR_CLIP;
lzi0 = 1.0 / transformed[2];
// FIXME: build x/yscale into transform?
scale = xscale * lzi0;
u0 = (xcenter + scale*transformed[0]);
if (u0 < r_refdef.fvrectx_adj)
u0 = r_refdef.fvrectx_adj;
if (u0 > r_refdef.fvrectright_adj)
u0 = r_refdef.fvrectright_adj;
scale = yscale * lzi0;
v0 = (ycenter - scale*transformed[1]);
if (v0 < r_refdef.fvrecty_adj)
v0 = r_refdef.fvrecty_adj;
if (v0 > r_refdef.fvrectbottom_adj)
v0 = r_refdef.fvrectbottom_adj;
ceilv0 = (int) ceil(v0);
}
world = &pv1->position[0];
// transform and project
VectorSubtract (world, modelorg, local);
TransformVector (local, transformed);
if (transformed[2] < NEAR_CLIP)
transformed[2] = NEAR_CLIP;
r_lzi1 = 1.0 / transformed[2];
scale = xscale * r_lzi1;
r_u1 = (xcenter + scale*transformed[0]);
if (r_u1 < r_refdef.fvrectx_adj)
r_u1 = r_refdef.fvrectx_adj;
if (r_u1 > r_refdef.fvrectright_adj)
r_u1 = r_refdef.fvrectright_adj;
scale = yscale * r_lzi1;
r_v1 = (ycenter - scale*transformed[1]);
if (r_v1 < r_refdef.fvrecty_adj)
r_v1 = r_refdef.fvrecty_adj;
if (r_v1 > r_refdef.fvrectbottom_adj)
r_v1 = r_refdef.fvrectbottom_adj;
if (r_lzi1 > lzi0)
lzi0 = r_lzi1;
if (lzi0 > r_nearzi) // for mipmap finding
r_nearzi = lzi0;
// for right edges, all we want is the effect on 1/z
if (r_nearzionly)
return;
r_emitted = 1;
r_ceilv1 = (int) ceil(r_v1);
// create the edge
if (ceilv0 == r_ceilv1)
{
// we cache unclipped horizontal edges as fully clipped
if (cacheoffset != 0x7FFFFFFF)
{
cacheoffset = FULLY_CLIPPED_CACHED |
(r_framecount & FRAMECOUNT_MASK);
}
return; // horizontal edge
}
side = ceilv0 > r_ceilv1;
edge = edge_p++;
edge->owner = r_pedge;
edge->nearzi = lzi0;
if (side == 0)
{
// trailing edge (go from p1 to p2)
v = ceilv0;
v2 = r_ceilv1 - 1;
edge->surfs[0] = surface_p - surfaces;
edge->surfs[1] = 0;
u_step = ((r_u1 - u0) / (r_v1 - v0));
u = u0 + ((float)v - v0) * u_step;
}
else
{
// leading edge (go from p2 to p1)
v2 = ceilv0 - 1;
v = r_ceilv1;
edge->surfs[0] = 0;
edge->surfs[1] = surface_p - surfaces;
u_step = ((u0 - r_u1) / (v0 - r_v1));
u = r_u1 + ((float)v - r_v1) * u_step;
}
edge->u_step = u_step*0x100000;
edge->u = u*0x100000 + 0xFFFFF;
// 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;
//
// sort the edge in normally
//
u_check = edge->u;
if (edge->surfs[0])
u_check++; // sort trailers after leaders
if (!newedges[v] || newedges[v]->u >= u_check)
{
edge->next = newedges[v];
newedges[v] = edge;
}
else
{
pcheck = newedges[v];
while (pcheck->next && pcheck->next->u < u_check)
pcheck = pcheck->next;
edge->next = pcheck->next;
pcheck->next = edge;
}
edge->nextremove = removeedges[v2];
removeedges[v2] = edge;
}
/*
================
R_ClipEdge
================
*/
void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
{
float d0, d1, f;
mvertex_t clipvert;
if (clip)
{
do
{
d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
if (d0 >= 0)
{
// point 0 is unclipped
if (d1 >= 0)
{
// both points are unclipped
continue;
}
// only point 1 is clipped
// we don't cache clipped edges
cacheoffset = 0x7FFFFFFF;
f = d0 / (d0 - d1);
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]);
if (clip->leftedge)
{
r_leftclipped = true;
r_leftexit = clipvert;
}
else if (clip->rightedge)
{
r_rightclipped = true;
r_rightexit = clipvert;
}
R_ClipEdge (pv0, &clipvert, clip->next);
return;
}
else
{
// point 0 is clipped
if (d1 < 0)
{
// both points are clipped
// we do cache fully clipped edges
if (!r_leftclipped)
cacheoffset = FULLY_CLIPPED_CACHED |
(r_framecount & FRAMECOUNT_MASK);
return;
}
// only point 0 is clipped
r_lastvertvalid = false;
// we don't cache partially clipped edges
cacheoffset = 0x7FFFFFFF;
f = d0 / (d0 - d1);
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]);
if (clip->leftedge)
{
r_leftclipped = true;
r_leftenter = clipvert;
}
else if (clip->rightedge)
{
r_rightclipped = true;
r_rightenter = clipvert;
}
R_ClipEdge (&clipvert, pv1, clip->next);
return;
}
} while ((clip = clip->next) != NULL);
}
// add the edge
R_EmitEdge (pv0, pv1);
}
#endif // !id386
/*
================
R_EmitCachedEdge
================
*/
void R_EmitCachedEdge (void)
{
edge_t *pedge_t;
pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset);
if (!pedge_t->surfs[0])
pedge_t->surfs[0] = surface_p - surfaces;
else
pedge_t->surfs[1] = surface_p - surfaces;
if (pedge_t->nearzi > r_nearzi) // for mipmap finding
r_nearzi = pedge_t->nearzi;
r_emitted = 1;
}
/*
================
R_RenderFace
================
*/
void R_RenderFace (msurface_t *fa, int clipflags)
{
int i, lindex;
unsigned mask;
mplane_t *pplane;
float distinv;
vec3_t p_normal;
medge_t *pedges, tedge;
clipplane_t *pclip;
// skip out if no more surfs
if ((surface_p) >= surf_max)
{
r_outofsurfaces++;
return;
}
// ditto if not enough edges left, or switch to auxedges if possible
if ((edge_p + fa->numedges + 4) >= edge_max)
{
r_outofedges += fa->numedges;
return;
}
c_faceclip++;
// set up clip planes
pclip = NULL;
for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
{
if (clipflags & mask)
{
view_clipplanes[i].next = pclip;
pclip = &view_clipplanes[i];
}
}
// push the edges through
r_emitted = 0;
r_nearzi = 0;
r_nearzionly = false;
makeleftedge = makerightedge = false;
pedges = currententity->model->edges;
r_lastvertvalid = false;
for (i=0 ; i<fa->numedges ; i++)
{
lindex = currententity->model->surfedges[fa->firstedge + i];
if (lindex > 0)
{
r_pedge = &pedges[lindex];
// if the edge is cached, we can just reuse the edge
if (!insubmodel)
{
if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
{
if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
r_framecount)
{
r_lastvertvalid = false;
continue;
}
}
else
{
if ((((unsigned long)edge_p - (unsigned long)r_edges) >
r_pedge->cachededgeoffset) &&
(((edge_t *)((unsigned long)r_edges +
r_pedge->cachededgeoffset))->owner == r_pedge))
{
R_EmitCachedEdge ();
r_lastvertvalid = false;
continue;
}
}
}
// assume it's cacheable
cacheoffset = (byte *)edge_p - (byte *)r_edges;
r_leftclipped = r_rightclipped = false;
R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
&r_pcurrentvertbase[r_pedge->v[1]],
pclip);
r_pedge->cachededgeoffset = cacheoffset;
if (r_leftclipped)
makeleftedge = true;
if (r_rightclipped)
makerightedge = true;
r_lastvertvalid = true;
}
else
{
lindex = -lindex;
r_pedge = &pedges[lindex];
// if the edge is cached, we can just reuse the edge
if (!insubmodel)
{
if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
{
if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
r_framecount)
{
r_lastvertvalid = false;
continue;
}
}
else
{
// it's cached if the cached edge is valid and is owned
// by this medge_t
if ((((unsigned long)edge_p - (unsigned long)r_edges) >
r_pedge->cachededgeoffset) &&
(((edge_t *)((unsigned long)r_edges +
r_pedge->cachededgeoffset))->owner == r_pedge))
{
R_EmitCachedEdge ();
r_lastvertvalid = false;
continue;
}
}
}
// assume it's cacheable
cacheoffset = (byte *)edge_p - (byte *)r_edges;
r_leftclipped = r_rightclipped = false;
R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
&r_pcurrentvertbase[r_pedge->v[0]],
pclip);
r_pedge->cachededgeoffset = cacheoffset;
if (r_leftclipped)
makeleftedge = true;
if (r_rightclipped)
makerightedge = true;
r_lastvertvalid = true;
}
}
// if there was a clip off the left edge, add that edge too
// FIXME: faster to do in screen space?
// FIXME: share clipped edges?
if (makeleftedge)
{
r_pedge = &tedge;
r_lastvertvalid = false;
R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
}
// if there was a clip off the right edge, get the right r_nearzi
if (makerightedge)
{
r_pedge = &tedge;
r_lastvertvalid = false;
r_nearzionly = true;
R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
}
// if no edges made it out, return without posting the surface
if (!r_emitted)
return;
r_polycount++;
surface_p->data = (void *)fa;
surface_p->nearzi = r_nearzi;
surface_p->flags = fa->flags;
surface_p->insubmodel = insubmodel;
surface_p->spanstate = 0;
surface_p->entity = currententity;
surface_p->key = r_currentkey++;
surface_p->spans = NULL;
pplane = fa->plane;
// FIXME: cache this?
TransformVector (pplane->normal, p_normal);
// FIXME: cache this?
distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
surface_p->d_ziorigin = p_normal[2] * distinv -
xcenter * surface_p->d_zistepu -
ycenter * surface_p->d_zistepv;
//JDC VectorCopy (r_worldmodelorg, surface_p->modelorg);
surface_p++;
}
/*
================
R_RenderBmodelFace
================
*/
void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
{
int i;
unsigned mask;
mplane_t *pplane;
float distinv;
vec3_t p_normal;
medge_t tedge;
clipplane_t *pclip;
// skip out if no more surfs
if (surface_p >= surf_max)
{
r_outofsurfaces++;
return;
}
// ditto if not enough edges left, or switch to auxedges if possible
if ((edge_p + psurf->numedges + 4) >= edge_max)
{
r_outofedges += psurf->numedges;
return;
}
c_faceclip++;
// this is a dummy to give the caching mechanism someplace to write to
r_pedge = &tedge;
// set up clip planes
pclip = NULL;
for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
{
if (r_clipflags & mask)
{
view_clipplanes[i].next = pclip;
pclip = &view_clipplanes[i];
}
}
// push the edges through
r_emitted = 0;
r_nearzi = 0;
r_nearzionly = false;
makeleftedge = makerightedge = false;
// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
// can be used?
r_lastvertvalid = false;
for ( ; pedges ; pedges = pedges->pnext)
{
r_leftclipped = r_rightclipped = false;
R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
if (r_leftclipped)
makeleftedge = true;
if (r_rightclipped)
makerightedge = true;
}
// if there was a clip off the left edge, add that edge too
// FIXME: faster to do in screen space?
// FIXME: share clipped edges?
if (makeleftedge)
{
r_pedge = &tedge;
R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
}
// if there was a clip off the right edge, get the right r_nearzi
if (makerightedge)
{
r_pedge = &tedge;
r_nearzionly = true;
R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
}
// if no edges made it out, return without posting the surface
if (!r_emitted)
return;
r_polycount++;
surface_p->data = (void *)psurf;
surface_p->nearzi = r_nearzi;
surface_p->flags = psurf->flags;
surface_p->insubmodel = true;
surface_p->spanstate = 0;
surface_p->entity = currententity;
surface_p->key = r_currentbkey;
surface_p->spans = NULL;
pplane = psurf->plane;
// FIXME: cache this?
TransformVector (pplane->normal, p_normal);
// FIXME: cache this?
distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
surface_p->d_ziorigin = p_normal[2] * distinv -
xcenter * surface_p->d_zistepu -
ycenter * surface_p->d_zistepv;
//JDC VectorCopy (r_worldmodelorg, surface_p->modelorg);
surface_p++;
}
/*
================
R_RenderPoly
================
*/
void R_RenderPoly (msurface_t *fa, int clipflags)
{
int i, lindex, lnumverts, s_axis, t_axis;
float dist, lastdist, lzi, scale, u, v, frac;
unsigned mask;
vec3_t local, transformed;
clipplane_t *pclip;
medge_t *pedges;
mplane_t *pplane;
mvertex_t verts[2][100]; //FIXME: do real number
polyvert_t pverts[100]; //FIXME: do real number, safely
int vertpage, newverts, newpage, lastvert;
qboolean visible;
// FIXME: clean this up and make it faster
// FIXME: guard against running out of vertices
s_axis = t_axis = 0; // keep compiler happy
// set up clip planes
pclip = NULL;
for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
{
if (clipflags & mask)
{
view_clipplanes[i].next = pclip;
pclip = &view_clipplanes[i];
}
}
// reconstruct the polygon
// FIXME: these should be precalculated and loaded off disk
pedges = currententity->model->edges;
lnumverts = fa->numedges;
vertpage = 0;
for (i=0 ; i<lnumverts ; i++)
{
lindex = currententity->model->surfedges[fa->firstedge + i];
if (lindex > 0)
{
r_pedge = &pedges[lindex];
verts[0][i] = r_pcurrentvertbase[r_pedge->v[0]];
}
else
{
r_pedge = &pedges[-lindex];
verts[0][i] = r_pcurrentvertbase[r_pedge->v[1]];
}
}
// clip the polygon, done if not visible
while (pclip)
{
lastvert = lnumverts - 1;
lastdist = DotProduct (verts[vertpage][lastvert].position,
pclip->normal) - pclip->dist;
visible = false;
newverts = 0;
newpage = vertpage ^ 1;
for (i=0 ; i<lnumverts ; i++)
{
dist = DotProduct (verts[vertpage][i].position, pclip->normal) -
pclip->dist;
if ((lastdist > 0) != (dist > 0))
{
frac = dist / (dist - lastdist);
verts[newpage][newverts].position[0] =
verts[vertpage][i].position[0] +
((verts[vertpage][lastvert].position[0] -
verts[vertpage][i].position[0]) * frac);
verts[newpage][newverts].position[1] =
verts[vertpage][i].position[1] +
((verts[vertpage][lastvert].position[1] -
verts[vertpage][i].position[1]) * frac);
verts[newpage][newverts].position[2] =
verts[vertpage][i].position[2] +
((verts[vertpage][lastvert].position[2] -
verts[vertpage][i].position[2]) * frac);
newverts++;
}
if (dist >= 0)
{
verts[newpage][newverts] = verts[vertpage][i];
newverts++;
visible = true;
}
lastvert = i;
lastdist = dist;
}
if (!visible || (newverts < 3))
return;
lnumverts = newverts;
vertpage ^= 1;
pclip = pclip->next;
}
// transform and project, remembering the z values at the vertices and
// r_nearzi, and extract the s and t coordinates at the vertices
pplane = fa->plane;
switch (pplane->type)
{
case PLANE_X:
case PLANE_ANYX:
s_axis = 1;
t_axis = 2;
break;
case PLANE_Y:
case PLANE_ANYY:
s_axis = 0;
t_axis = 2;
break;
case PLANE_Z:
case PLANE_ANYZ:
s_axis = 0;
t_axis = 1;
break;
}
r_nearzi = 0;
for (i=0 ; i<lnumverts ; i++)
{
// transform and project
VectorSubtract (verts[vertpage][i].position, modelorg, local);
TransformVector (local, transformed);
if (transformed[2] < NEAR_CLIP)
transformed[2] = NEAR_CLIP;
lzi = 1.0 / transformed[2];
if (lzi > r_nearzi) // for mipmap finding
r_nearzi = lzi;
// FIXME: build x/yscale into transform?
scale = xscale * lzi;
u = (xcenter + scale*transformed[0]);
if (u < r_refdef.fvrectx_adj)
u = r_refdef.fvrectx_adj;
if (u > r_refdef.fvrectright_adj)
u = r_refdef.fvrectright_adj;
scale = yscale * lzi;
v = (ycenter - scale*transformed[1]);
if (v < r_refdef.fvrecty_adj)
v = r_refdef.fvrecty_adj;
if (v > r_refdef.fvrectbottom_adj)
v = r_refdef.fvrectbottom_adj;
pverts[i].u = u;
pverts[i].v = v;
pverts[i].zi = lzi;
pverts[i].s = verts[vertpage][i].position[s_axis];
pverts[i].t = verts[vertpage][i].position[t_axis];
}
// build the polygon descriptor, including fa, r_nearzi, and u, v, s, t, and z
// for each vertex
r_polydesc.numverts = lnumverts;
r_polydesc.nearzi = r_nearzi;
r_polydesc.pcurrentface = fa;
r_polydesc.pverts = pverts;
// draw the polygon
D_DrawPoly ();
}
/*
================
R_ZDrawSubmodelPolys
================
*/
void R_ZDrawSubmodelPolys (model_t *pmodel)
{
int i, numsurfaces;
msurface_t *psurf;
float dot;
mplane_t *pplane;
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
numsurfaces = pmodel->nummodelsurfaces;
for (i=0 ; i<numsurfaces ; i++, psurf++)
{
// find which side of the node we are on
pplane = psurf->plane;
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
// draw the polygon
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
{
// FIXME: use bounding-box-based frustum clipping info?
R_RenderPoly (psurf, 15);
}
}
}

View File

@ -1,774 +0,0 @@
/*
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_edge.c
#include "quakedef.h"
#include "r_local.h"
#if 0
// FIXME
the complex cases add new polys on most lines, so dont optimize for keeping them the same
have multiple free span lists to try to get better coherence?
low depth complexity -- 1 to 3 or so
this breaks spans at every edge, even hidden ones (bad)
have a sentinal at both ends?
#endif
edge_t *auxedges;
edge_t *r_edges, *edge_p, *edge_max;
surf_t *surfaces, *surface_p, *surf_max;
// surfaces are generated in back to front order by the bsp, so if a surf
// pointer is greater than another one, it should be drawn in front
// surfaces[1] is the background, and is used as the active surface stack
edge_t *newedges[MAXHEIGHT];
edge_t *removeedges[MAXHEIGHT];
espan_t *span_p, *max_span_p;
int r_currentkey;
extern int screenwidth;
int current_iv;
int edge_head_u_shift20, edge_tail_u_shift20;
static void (*pdrawfunc)(void);
edge_t edge_head;
edge_t edge_tail;
edge_t edge_aftertail;
edge_t edge_sentinel;
float fv;
void R_GenerateSpans (void);
void R_GenerateSpansBackward (void);
void R_LeadingEdge (edge_t *edge);
void R_LeadingEdgeBackwards (edge_t *edge);
void R_TrailingEdge (surf_t *surf, edge_t *edge);
//=============================================================================
/*
==============
R_DrawCulledPolys
==============
*/
void R_DrawCulledPolys (void)
{
surf_t *s;
msurface_t *pface;
currententity = &cl_entities[0];
if (r_worldpolysbacktofront)
{
for (s=surface_p-1 ; s>&surfaces[1] ; s--)
{
if (!s->spans)
continue;
if (!(s->flags & SURF_DRAWBACKGROUND))
{
pface = (msurface_t *)s->data;
R_RenderPoly (pface, 15);
}
}
}
else
{
for (s = &surfaces[1] ; s<surface_p ; s++)
{
if (!s->spans)
continue;
if (!(s->flags & SURF_DRAWBACKGROUND))
{
pface = (msurface_t *)s->data;
R_RenderPoly (pface, 15);
}
}
}
}
/*
==============
R_BeginEdgeFrame
==============
*/
void R_BeginEdgeFrame (void)
{
int v;
edge_p = r_edges;
edge_max = &r_edges[r_numallocatededges];
surface_p = &surfaces[2]; // background is surface 1,
// surface 0 is a dummy
surfaces[1].spans = NULL; // no background spans yet
surfaces[1].flags = SURF_DRAWBACKGROUND;
// put the background behind everything in the world
if (r_draworder.value)
{
pdrawfunc = R_GenerateSpansBackward;
surfaces[1].key = 0;
r_currentkey = 1;
}
else
{
pdrawfunc = R_GenerateSpans;
surfaces[1].key = 0x7FFFFFFF;
r_currentkey = 0;
}
// FIXME: set with memset
for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
{
newedges[v] = removeedges[v] = NULL;
}
}
#if !id386
/*
==============
R_InsertNewEdges
Adds the edges in the linked list edgestoadd, adding them to the edges in the
linked list edgelist. edgestoadd is assumed to be sorted on u, and non-empty (this is actually newedges[v]). edgelist is assumed to be sorted on u, with a
sentinel at the end (actually, this is the active edge table starting at
edge_head.next).
==============
*/
void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
{
edge_t *next_edge;
do
{
next_edge = edgestoadd->next;
edgesearch:
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
goto edgesearch;
// insert edgestoadd before edgelist
addedge:
edgestoadd->next = edgelist;
edgestoadd->prev = edgelist->prev;
edgelist->prev->next = edgestoadd;
edgelist->prev = edgestoadd;
} while ((edgestoadd = next_edge) != NULL);
}
#endif // !id386
#if !id386
/*
==============
R_RemoveEdges
==============
*/
void R_RemoveEdges (edge_t *pedge)
{
do
{
pedge->next->prev = pedge->prev;
pedge->prev->next = pedge->next;
} while ((pedge = pedge->nextremove) != NULL);
}
#endif // !id386
#if !id386
/*
==============
R_StepActiveU
==============
*/
void R_StepActiveU (edge_t *pedge)
{
edge_t *pnext_edge, *pwedge;
while (1)
{
nextedge:
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
goto nextedge;
pushback:
if (pedge == &edge_aftertail)
return;
// push it back to keep it sorted
pnext_edge = pedge->next;
// pull the edge out of the edge list
pedge->next->prev = pedge->prev;
pedge->prev->next = pedge->next;
// find out where the edge goes in the edge list
pwedge = pedge->prev->prev;
while (pwedge->u > pedge->u)
{
pwedge = pwedge->prev;
}
// put the edge back into the edge list
pedge->next = pwedge->next;
pedge->prev = pwedge;
pedge->next->prev = pedge;
pwedge->next = pedge;
pedge = pnext_edge;
if (pedge == &edge_tail)
return;
}
}
#endif // !id386
/*
==============
R_CleanupSpan
==============
*/
void R_CleanupSpan ()
{
surf_t *surf;
int iu;
espan_t *span;
// 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
surf = surfaces[1].next;
iu = edge_tail_u_shift20;
if (iu > surf->last_u)
{
span = span_p++;
span->u = surf->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf->spans;
surf->spans = span;
}
// reset spanstate for all surfaces in the surface stack
do
{
surf->spanstate = 0;
surf = surf->next;
} while (surf != &surfaces[1]);
}
/*
==============
R_LeadingEdgeBackwards
==============
*/
void R_LeadingEdgeBackwards (edge_t *edge)
{
espan_t *span;
surf_t *surf, *surf2;
int iu;
// it's adding a new surface in, so find the correct place
surf = &surfaces[edge->surfs[1]];
// 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)
if (++surf->spanstate == 1)
{
surf2 = surfaces[1].next;
if (surf->key > surf2->key)
goto newtop;
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (surf->insubmodel && (surf->key == surf2->key))
{
// must be two bmodels in the same leaf; don't care, because they'll
// never be farthest anyway
goto newtop;
}
continue_search:
do
{
surf2 = surf2->next;
} while (surf->key < surf2->key);
if (surf->key == surf2->key)
{
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (!surf->insubmodel)
goto continue_search;
// must be two bmodels in the same leaf; don't care which is really
// in front, because they'll never be farthest anyway
}
goto gotposition;
newtop:
// emit a span (obscures current top)
iu = edge->u >> 20;
if (iu > surf2->last_u)
{
span = span_p++;
span->u = surf2->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf2->spans;
surf2->spans = span;
}
// set last_u on the new span
surf->last_u = iu;
gotposition:
// insert before surf2
surf->next = surf2;
surf->prev = surf2->prev;
surf2->prev->next = surf;
surf2->prev = surf;
}
}
/*
==============
R_TrailingEdge
==============
*/
void R_TrailingEdge (surf_t *surf, edge_t *edge)
{
espan_t *span;
int iu;
// don't generate a span if this is an inverted span, with the end
// edge preceding the start edge (that is, we haven't seen the
// start edge yet)
if (--surf->spanstate == 0)
{
if (surf->insubmodel)
r_bmodelactive--;
if (surf == surfaces[1].next)
{
// emit a span (current top going away)
iu = edge->u >> 20;
if (iu > surf->last_u)
{
span = span_p++;
span->u = surf->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf->spans;
surf->spans = span;
}
// set last_u on the surface below
surf->next->last_u = iu;
}
surf->prev->next = surf->next;
surf->next->prev = surf->prev;
}
}
#if !id386
/*
==============
R_LeadingEdge
==============
*/
void R_LeadingEdge (edge_t *edge)
{
espan_t *span;
surf_t *surf, *surf2;
int iu;
double fu, newzi, testzi, newzitop, newzibottom;
if (edge->surfs[1])
{
// it's adding a new surface in, so find the correct place
surf = &surfaces[edge->surfs[1]];
// 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)
if (++surf->spanstate == 1)
{
if (surf->insubmodel)
r_bmodelactive++;
surf2 = surfaces[1].next;
if (surf->key < surf2->key)
goto newtop;
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (surf->insubmodel && (surf->key == surf2->key))
{
// must be two bmodels in the same leaf; sort on 1/z
fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
newzi = surf->d_ziorigin + fv*surf->d_zistepv +
fu*surf->d_zistepu;
newzibottom = newzi * 0.99;
testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
fu*surf2->d_zistepu;
if (newzibottom >= testzi)
{
goto newtop;
}
newzitop = newzi * 1.01;
if (newzitop >= testzi)
{
if (surf->d_zistepu >= surf2->d_zistepu)
{
goto newtop;
}
}
}
continue_search:
do
{
surf2 = surf2->next;
} while (surf->key > surf2->key);
if (surf->key == surf2->key)
{
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (!surf->insubmodel)
goto continue_search;
// must be two bmodels in the same leaf; sort on 1/z
fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
newzi = surf->d_ziorigin + fv*surf->d_zistepv +
fu*surf->d_zistepu;
newzibottom = newzi * 0.99;
testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
fu*surf2->d_zistepu;
if (newzibottom >= testzi)
{
goto gotposition;
}
newzitop = newzi * 1.01;
if (newzitop >= testzi)
{
if (surf->d_zistepu >= surf2->d_zistepu)
{
goto gotposition;
}
}
goto continue_search;
}
goto gotposition;
newtop:
// emit a span (obscures current top)
iu = edge->u >> 20;
if (iu > surf2->last_u)
{
span = span_p++;
span->u = surf2->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf2->spans;
surf2->spans = span;
}
// set last_u on the new span
surf->last_u = iu;
gotposition:
// insert before surf2
surf->next = surf2;
surf->prev = surf2->prev;
surf2->prev->next = surf;
surf2->prev = surf;
}
}
}
/*
==============
R_GenerateSpans
==============
*/
void R_GenerateSpans (void)
{
edge_t *edge;
surf_t *surf;
r_bmodelactive = 0;
// clear active surfaces to just the background surface
surfaces[1].next = surfaces[1].prev = &surfaces[1];
surfaces[1].last_u = edge_head_u_shift20;
// generate spans
for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
{
if (edge->surfs[0])
{
// it has a left surface, so a surface is going away for this span
surf = &surfaces[edge->surfs[0]];
R_TrailingEdge (surf, edge);
if (!edge->surfs[1])
continue;
}
R_LeadingEdge (edge);
}
R_CleanupSpan ();
}
#endif // !id386
/*
==============
R_GenerateSpansBackward
==============
*/
void R_GenerateSpansBackward (void)
{
edge_t *edge;
r_bmodelactive = 0;
// clear active surfaces to just the background surface
surfaces[1].next = surfaces[1].prev = &surfaces[1];
surfaces[1].last_u = edge_head_u_shift20;
// generate spans
for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
{
if (edge->surfs[0])
R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
if (edge->surfs[1])
R_LeadingEdgeBackwards (edge);
}
R_CleanupSpan ();
}
/*
==============
R_ScanEdges
Input:
newedges[] array
this has links to edges, which have links to surfaces
Output:
Each surface has a linked list of its visible spans
==============
*/
void R_ScanEdges (void)
{
int iv, bottom;
byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
espan_t *basespan_p;
surf_t *s;
basespan_p = (espan_t *)
((long)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
span_p = basespan_p;
// clear active edges to just the background edges around the whole screen
// FIXME: most of this only needs to be set up once
edge_head.u = r_refdef.vrect.x << 20;
edge_head_u_shift20 = edge_head.u >> 20;
edge_head.u_step = 0;
edge_head.prev = NULL;
edge_head.next = &edge_tail;
edge_head.surfs[0] = 0;
edge_head.surfs[1] = 1;
edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF;
edge_tail_u_shift20 = edge_tail.u >> 20;
edge_tail.u_step = 0;
edge_tail.prev = &edge_head;
edge_tail.next = &edge_aftertail;
edge_tail.surfs[0] = 1;
edge_tail.surfs[1] = 0;
edge_aftertail.u = -1; // force a move
edge_aftertail.u_step = 0;
edge_aftertail.next = &edge_sentinel;
edge_aftertail.prev = &edge_tail;
// FIXME: do we need this now that we clamp x in r_draw.c?
edge_sentinel.u = 2000 << 24; // make sure nothing sorts past this
edge_sentinel.prev = &edge_aftertail;
//
// process all scan lines
//
bottom = r_refdef.vrectbottom - 1;
for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
{
current_iv = iv;
fv = (float)iv;
// mark that the head (background start) span is pre-included
surfaces[1].spanstate = 1;
if (newedges[iv])
{
R_InsertNewEdges (newedges[iv], edge_head.next);
}
(*pdrawfunc) ();
// flush the span list if we can't be sure we have enough spans left for
// the next scan
if (span_p >= max_span_p)
{
VID_UnlockBuffer ();
S_ExtraUpdate (); // don't let sound get messed up if going slow
VID_LockBuffer ();
if (r_drawculledpolys)
{
R_DrawCulledPolys ();
}
else
{
D_DrawSurfaces ();
}
// clear the surface span pointers
for (s = &surfaces[1] ; s<surface_p ; s++)
s->spans = NULL;
span_p = basespan_p;
}
if (removeedges[iv])
R_RemoveEdges (removeedges[iv]);
if (edge_head.next != &edge_tail)
R_StepActiveU (edge_head.next);
}
// do the last scan (no need to step or sort or remove on the last scan)
current_iv = iv;
fv = (float)iv;
// mark that the head (background start) span is pre-included
surfaces[1].spanstate = 1;
if (newedges[iv])
R_InsertNewEdges (newedges[iv], edge_head.next);
(*pdrawfunc) ();
// draw whatever's left in the span list
if (r_drawculledpolys)
R_DrawCulledPolys ();
else
D_DrawSurfaces ();
}

View File

@ -1,276 +0,0 @@
/*
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_efrag.c
#include "quakedef.h"
#include "r_local.h"
mnode_t *r_pefragtopnode;
//===========================================================================
/*
===============================================================================
ENTITY FRAGMENT FUNCTIONS
===============================================================================
*/
efrag_t **lastlink;
vec3_t r_emins, r_emaxs;
entity_t *r_addent;
/*
================
R_RemoveEfrags
Call when removing an object from the world or moving it to another position
================
*/
void R_RemoveEfrags (entity_t *ent)
{
efrag_t *ef, *old, *walk, **prev;
ef = ent->efrag;
while (ef)
{
prev = &ef->leaf->efrags;
while (1)
{
walk = *prev;
if (!walk)
break;
if (walk == ef)
{ // remove this fragment
*prev = ef->leafnext;
break;
}
else
prev = &walk->leafnext;
}
old = ef;
ef = ef->entnext;
// put it on the free list
old->entnext = cl.free_efrags;
cl.free_efrags = old;
}
ent->efrag = NULL;
}
/*
===================
R_SplitEntityOnNode
===================
*/
void R_SplitEntityOnNode (mnode_t *node)
{
efrag_t *ef;
mplane_t *splitplane;
mleaf_t *leaf;
int sides;
if (node->contents == CONTENTS_SOLID)
{
return;
}
// add an efrag if the node is a leaf
if ( node->contents < 0)
{
if (!r_pefragtopnode)
r_pefragtopnode = node;
leaf = (mleaf_t *)node;
// grab an efrag off the free list
ef = cl.free_efrags;
if (!ef)
{
Con_Printf ("Too many efrags!\n");
return; // no free fragments...
}
cl.free_efrags = cl.free_efrags->entnext;
ef->entity = r_addent;
// add the entity link
*lastlink = ef;
lastlink = &ef->entnext;
ef->entnext = NULL;
// set the leaf links
ef->leaf = leaf;
ef->leafnext = leaf->efrags;
leaf->efrags = ef;
return;
}
// NODE_MIXED
splitplane = node->plane;
sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
if (sides == 3)
{
// split on this plane
// if this is the first splitter of this bmodel, remember it
if (!r_pefragtopnode)
r_pefragtopnode = node;
}
// recurse down the contacted sides
if (sides & 1)
R_SplitEntityOnNode (node->children[0]);
if (sides & 2)
R_SplitEntityOnNode (node->children[1]);
}
/*
===================
R_SplitEntityOnNode2
===================
*/
void R_SplitEntityOnNode2 (mnode_t *node)
{
mplane_t *splitplane;
int sides;
if (node->visframe != r_visframecount)
return;
if (node->contents < 0)
{
if (node->contents != CONTENTS_SOLID)
r_pefragtopnode = node; // we've reached a non-solid leaf, so it's
// visible and not BSP clipped
return;
}
splitplane = node->plane;
sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
if (sides == 3)
{
// remember first splitter
r_pefragtopnode = node;
return;
}
// not split yet; recurse down the contacted side
if (sides & 1)
R_SplitEntityOnNode2 (node->children[0]);
else
R_SplitEntityOnNode2 (node->children[1]);
}
/*
===========
R_AddEfrags
===========
*/
void R_AddEfrags (entity_t *ent)
{
model_t *entmodel;
int i;
if (!ent->model)
return;
if (ent == cl_entities)
return; // never add the world
r_addent = ent;
lastlink = &ent->efrag;
r_pefragtopnode = NULL;
entmodel = ent->model;
for (i=0 ; i<3 ; i++)
{
r_emins[i] = ent->origin[i] + entmodel->mins[i];
r_emaxs[i] = ent->origin[i] + entmodel->maxs[i];
}
R_SplitEntityOnNode (cl.worldmodel->nodes);
ent->topnode = r_pefragtopnode;
}
/*
================
R_StoreEfrags
// FIXME: a lot of this goes away with edge-based
================
*/
void R_StoreEfrags (efrag_t **ppefrag)
{
entity_t *pent;
model_t *clmodel;
efrag_t *pefrag;
while ((pefrag = *ppefrag) != NULL)
{
pent = pefrag->entity;
clmodel = pent->model;
switch (clmodel->type)
{
case mod_alias:
case mod_brush:
case mod_sprite:
pent = pefrag->entity;
if ((pent->visframe != r_framecount) &&
(cl_numvisedicts < MAX_VISEDICTS))
{
cl_visedicts[cl_numvisedicts++] = pent;
// mark that we've recorded this entity for this frame
pent->visframe = r_framecount;
}
ppefrag = &pefrag->leafnext;
break;
default:
Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
}
}
}

View File

@ -1,523 +0,0 @@
/*
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_misc.c
#include "quakedef.h"
#include "r_local.h"
/*
===============
R_CheckVariables
===============
*/
void R_CheckVariables (void)
{
static float oldbright;
if (r_fullbright.value != oldbright)
{
oldbright = r_fullbright.value;
D_FlushCaches (); // so all lighting changes
}
}
/*
============
Show
Debugging use
============
*/
void Show (void)
{
vrect_t vr;
vr.x = vr.y = 0;
vr.width = vid.width;
vr.height = vid.height;
vr.pnext = NULL;
VID_Update (&vr);
}
/*
====================
R_TimeRefresh_f
For program optimization
====================
*/
void R_TimeRefresh_f (void)
{
int i;
float start, stop, time;
int startangle;
vrect_t vr;
startangle = r_refdef.viewangles[1];
start = Sys_FloatTime ();
for (i=0 ; i<128 ; i++)
{
r_refdef.viewangles[1] = i/128.0*360.0;
VID_LockBuffer ();
R_RenderView ();
VID_UnlockBuffer ();
vr.x = r_refdef.vrect.x;
vr.y = r_refdef.vrect.y;
vr.width = r_refdef.vrect.width;
vr.height = r_refdef.vrect.height;
vr.pnext = NULL;
VID_Update (&vr);
}
stop = Sys_FloatTime ();
time = stop-start;
Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
r_refdef.viewangles[1] = startangle;
}
/*
================
R_LineGraph
Only called by R_DisplayTime
================
*/
void R_LineGraph (int x, int y, int h)
{
int i;
byte *dest;
int s;
// FIXME: should be disabled on no-buffer adapters, or should be in the driver
x += r_refdef.vrect.x;
y += r_refdef.vrect.y;
dest = vid.buffer + vid.rowbytes*y + x;
s = r_graphheight.value;
if (h>s)
h = s;
for (i=0 ; i<h ; i++, dest -= vid.rowbytes*2)
{
dest[0] = 0xff;
*(dest-vid.rowbytes) = 0x30;
}
for ( ; i<s ; i++, dest -= vid.rowbytes*2)
{
dest[0] = 0x30;
*(dest-vid.rowbytes) = 0x30;
}
}
/*
==============
R_TimeGraph
Performance monitoring tool
==============
*/
#define MAX_TIMINGS 100
extern float mouse_x, mouse_y;
void R_TimeGraph (void)
{
static int timex;
int a;
float r_time2;
static byte r_timings[MAX_TIMINGS];
int x;
r_time2 = Sys_FloatTime ();
a = (r_time2-r_time1)/0.01;
//a = fabs(mouse_y * 0.05);
//a = (int)((r_refdef.vieworg[2] + 1024)/1)%(int)r_graphheight.value;
//a = fabs(velocity[0])/20;
//a = ((int)fabs(origin[0])/8)%20;
//a = (cl.idealpitch + 30)/5;
r_timings[timex] = a;
a = timex;
if (r_refdef.vrect.width <= MAX_TIMINGS)
x = r_refdef.vrect.width-1;
else
x = r_refdef.vrect.width -
(r_refdef.vrect.width - MAX_TIMINGS)/2;
do
{
R_LineGraph (x, r_refdef.vrect.height-2, r_timings[a]);
if (x==0)
break; // screen too small to hold entire thing
x--;
a--;
if (a == -1)
a = MAX_TIMINGS-1;
} while (a != timex);
timex = (timex+1)%MAX_TIMINGS;
}
/*
=============
R_PrintTimes
=============
*/
void R_PrintTimes (void)
{
float r_time2;
float ms;
r_time2 = Sys_FloatTime ();
ms = 1000* (r_time2 - r_time1);
Con_Printf ("%5.1f ms %3i/%3i/%3i poly %3i surf\n",
ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
c_surf = 0;
}
/*
=============
R_PrintDSpeeds
=============
*/
void R_PrintDSpeeds (void)
{
float ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, dv_time;
r_time2 = Sys_FloatTime ();
dp_time = (dp_time2 - dp_time1) * 1000;
rw_time = (rw_time2 - rw_time1) * 1000;
db_time = (db_time2 - db_time1) * 1000;
se_time = (se_time2 - se_time1) * 1000;
de_time = (de_time2 - de_time1) * 1000;
dv_time = (dv_time2 - dv_time1) * 1000;
ms = (r_time2 - r_time1) * 1000;
Con_Printf ("%3i %4.1fp %3iw %4.1fb %3is %4.1fe %4.1fv\n",
(int)ms, dp_time, (int)rw_time, db_time, (int)se_time, de_time,
dv_time);
}
/*
=============
R_PrintAliasStats
=============
*/
void R_PrintAliasStats (void)
{
Con_Printf ("%3i polygon model drawn\n", r_amodels_drawn);
}
void WarpPalette (void)
{
int i,j;
byte newpalette[768];
int basecolor[3];
basecolor[0] = 130;
basecolor[1] = 80;
basecolor[2] = 50;
// pull the colors halfway to bright brown
for (i=0 ; i<256 ; i++)
{
for (j=0 ; j<3 ; j++)
{
newpalette[i*3+j] = (host_basepal[i*3+j] + basecolor[j])/2;
}
}
VID_ShiftPalette (newpalette);
}
/*
===================
R_TransformFrustum
===================
*/
void R_TransformFrustum (void)
{
int i;
vec3_t v, v2;
for (i=0 ; i<4 ; i++)
{
v[0] = screenedge[i].normal[2];
v[1] = -screenedge[i].normal[0];
v[2] = screenedge[i].normal[1];
v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
VectorCopy (v2, view_clipplanes[i].normal);
view_clipplanes[i].dist = DotProduct (modelorg, v2);
}
}
#if !id386
/*
================
TransformVector
================
*/
void TransformVector (vec3_t in, vec3_t out)
{
out[0] = DotProduct(in,vright);
out[1] = DotProduct(in,vup);
out[2] = DotProduct(in,vpn);
}
#endif
/*
================
R_TransformPlane
================
*/
void R_TransformPlane (mplane_t *p, float *normal, float *dist)
{
float d;
d = DotProduct (r_origin, p->normal);
*dist = p->dist - d;
// TODO: when we have rotating entities, this will need to use the view matrix
TransformVector (p->normal, normal);
}
/*
===============
R_SetUpFrustumIndexes
===============
*/
void R_SetUpFrustumIndexes (void)
{
int i, j, *pindex;
pindex = r_frustum_indexes;
for (i=0 ; i<4 ; i++)
{
for (j=0 ; j<3 ; j++)
{
if (view_clipplanes[i].normal[j] < 0)
{
pindex[j] = j;
pindex[j+3] = j+3;
}
else
{
pindex[j] = j+3;
pindex[j+3] = j;
}
}
// FIXME: do just once at start
pfrustum_indexes[i] = pindex;
pindex += 6;
}
}
/*
===============
R_SetupFrame
===============
*/
void R_SetupFrame (void)
{
int edgecount;
vrect_t vrect;
float w, h;
// don't allow cheats in multiplayer
if (cl.maxclients > 1)
{
Cvar_Set ("r_draworder", "0");
Cvar_Set ("r_fullbright", "0");
Cvar_Set ("r_ambient", "0");
Cvar_Set ("r_drawflat", "0");
}
if (r_numsurfs.value)
{
if ((surface_p - surfaces) > r_maxsurfsseen)
r_maxsurfsseen = surface_p - surfaces;
Con_Printf ("Used %d of %d surfs; %d max\n", surface_p - surfaces,
surf_max - surfaces, r_maxsurfsseen);
}
if (r_numedges.value)
{
edgecount = edge_p - r_edges;
if (edgecount > r_maxedgesseen)
r_maxedgesseen = edgecount;
Con_Printf ("Used %d of %d edges; %d max\n", edgecount,
r_numallocatededges, r_maxedgesseen);
}
r_refdef.ambientlight = r_ambient.value;
if (r_refdef.ambientlight < 0)
r_refdef.ambientlight = 0;
if (!sv.active)
r_draworder.value = 0; // don't let cheaters look behind walls
R_CheckVariables ();
R_AnimateLight ();
r_framecount++;
numbtofpolys = 0;
// debugging
#if 0
r_refdef.vieworg[0]= 80;
r_refdef.vieworg[1]= 64;
r_refdef.vieworg[2]= 40;
r_refdef.viewangles[0]= 0;
r_refdef.viewangles[1]= 46.763641357;
r_refdef.viewangles[2]= 0;
#endif
// build the transformation matrix for the given view angles
VectorCopy (r_refdef.vieworg, modelorg);
VectorCopy (r_refdef.vieworg, r_origin);
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
// current viewleaf
r_oldviewleaf = r_viewleaf;
r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
r_dowarpold = r_dowarp;
r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= CONTENTS_WATER);
if ((r_dowarp != r_dowarpold) || r_viewchanged || lcd_x.value)
{
if (r_dowarp)
{
if ((vid.width <= vid.maxwarpwidth) &&
(vid.height <= vid.maxwarpheight))
{
vrect.x = 0;
vrect.y = 0;
vrect.width = vid.width;
vrect.height = vid.height;
R_ViewChanged (&vrect, sb_lines, vid.aspect);
}
else
{
w = vid.width;
h = vid.height;
if (w > vid.maxwarpwidth)
{
h *= (float)vid.maxwarpwidth / w;
w = vid.maxwarpwidth;
}
if (h > vid.maxwarpheight)
{
h = vid.maxwarpheight;
w *= (float)vid.maxwarpheight / h;
}
vrect.x = 0;
vrect.y = 0;
vrect.width = (int)w;
vrect.height = (int)h;
R_ViewChanged (&vrect,
(int)((float)sb_lines * (h/(float)vid.height)),
vid.aspect * (h / w) *
((float)vid.width / (float)vid.height));
}
}
else
{
vrect.x = 0;
vrect.y = 0;
vrect.width = vid.width;
vrect.height = vid.height;
R_ViewChanged (&vrect, sb_lines, vid.aspect);
}
r_viewchanged = false;
}
// start off with just the four screen edge clip planes
R_TransformFrustum ();
// save base values
VectorCopy (vpn, base_vpn);
VectorCopy (vright, base_vright);
VectorCopy (vup, base_vup);
VectorCopy (modelorg, base_modelorg);
R_SetSkyFrame ();
R_SetUpFrustumIndexes ();
r_cache_thrash = false;
// clear frame counts
c_faceclip = 0;
d_spanpixcount = 0;
r_polycount = 0;
r_drawnpolycount = 0;
r_wholepolycount = 0;
r_amodels_drawn = 0;
r_outofsurfaces = 0;
r_outofedges = 0;
D_SetupFrame ();
}

View File

@ -1,280 +0,0 @@
/*
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_sky.c
#include "quakedef.h"
#include "r_local.h"
#include "d_local.h"
int iskyspeed = 8;
int iskyspeed2 = 2;
float skyspeed, skyspeed2;
float skytime;
byte *r_skysource;
int r_skymade;
int r_skydirect; // not used?
// TODO: clean up these routines
byte bottomsky[128*131];
byte bottommask[128*131];
byte newsky[128*256]; // newsky and topsky both pack in here, 128 bytes
// of newsky on the left of each scan, 128 bytes
// of topsky on the right, because the low-level
// drawers need 256-byte scan widths
/*
=============
R_InitSky
A sky texture is 256*128, with the right side being a masked overlay
==============
*/
void R_InitSky (texture_t *mt)
{
int i, j;
byte *src;
src = (byte *)mt + mt->offsets[0];
for (i=0 ; i<128 ; i++)
{
for (j=0 ; j<128 ; j++)
{
newsky[(i*256) + j + 128] = src[i*256 + j + 128];
}
}
for (i=0 ; i<128 ; i++)
{
for (j=0 ; j<131 ; j++)
{
if (src[i*256 + (j & 0x7F)])
{
bottomsky[(i*131) + j] = src[i*256 + (j & 0x7F)];
bottommask[(i*131) + j] = 0;
}
else
{
bottomsky[(i*131) + j] = 0;
bottommask[(i*131) + j] = 0xff;
}
}
}
r_skysource = newsky;
}
/*
=================
R_MakeSky
=================
*/
void R_MakeSky (void)
{
int x, y;
int ofs, baseofs;
int xshift, yshift;
unsigned *pnewsky;
static int xlast = -1, ylast = -1;
xshift = skytime*skyspeed;
yshift = skytime*skyspeed;
if ((xshift == xlast) && (yshift == ylast))
return;
xlast = xshift;
ylast = yshift;
pnewsky = (unsigned *)&newsky[0];
for (y=0 ; y<SKYSIZE ; y++)
{
baseofs = ((y+yshift) & SKYMASK) * 131;
// FIXME: clean this up
#if UNALIGNED_OK
for (x=0 ; x<SKYSIZE ; x += 4)
{
ofs = baseofs + ((x+xshift) & SKYMASK);
// PORT: unaligned dword access to bottommask and bottomsky
*pnewsky = (*(pnewsky + (128 / sizeof (unsigned))) &
*(unsigned *)&bottommask[ofs]) |
*(unsigned *)&bottomsky[ofs];
pnewsky++;
}
#else
for (x=0 ; x<SKYSIZE ; x++)
{
ofs = baseofs + ((x+xshift) & SKYMASK);
*(byte *)pnewsky = (*((byte *)pnewsky + 128) &
*(byte *)&bottommask[ofs]) |
*(byte *)&bottomsky[ofs];
pnewsky = (unsigned *)((byte *)pnewsky + 1);
}
#endif
pnewsky += 128 / sizeof (unsigned);
}
r_skymade = 1;
}
/*
=================
R_GenSkyTile
=================
*/
void R_GenSkyTile (void *pdest)
{
int x, y;
int ofs, baseofs;
int xshift, yshift;
unsigned *pnewsky;
unsigned *pd;
xshift = skytime*skyspeed;
yshift = skytime*skyspeed;
pnewsky = (unsigned *)&newsky[0];
pd = (unsigned *)pdest;
for (y=0 ; y<SKYSIZE ; y++)
{
baseofs = ((y+yshift) & SKYMASK) * 131;
// FIXME: clean this up
#if UNALIGNED_OK
for (x=0 ; x<SKYSIZE ; x += 4)
{
ofs = baseofs + ((x+xshift) & SKYMASK);
// PORT: unaligned dword access to bottommask and bottomsky
*pd = (*(pnewsky + (128 / sizeof (unsigned))) &
*(unsigned *)&bottommask[ofs]) |
*(unsigned *)&bottomsky[ofs];
pnewsky++;
pd++;
}
#else
for (x=0 ; x<SKYSIZE ; x++)
{
ofs = baseofs + ((x+xshift) & SKYMASK);
*(byte *)pd = (*((byte *)pnewsky + 128) &
*(byte *)&bottommask[ofs]) |
*(byte *)&bottomsky[ofs];
pnewsky = (unsigned *)((byte *)pnewsky + 1);
pd = (unsigned *)((byte *)pd + 1);
}
#endif
pnewsky += 128 / sizeof (unsigned);
}
}
/*
=================
R_GenSkyTile16
=================
*/
void R_GenSkyTile16 (void *pdest)
{
int x, y;
int ofs, baseofs;
int xshift, yshift;
byte *pnewsky;
unsigned short *pd;
xshift = skytime * skyspeed;
yshift = skytime * skyspeed;
pnewsky = (byte *)&newsky[0];
pd = (unsigned short *)pdest;
for (y=0 ; y<SKYSIZE ; y++)
{
baseofs = ((y+yshift) & SKYMASK) * 131;
// FIXME: clean this up
// FIXME: do faster unaligned version?
for (x=0 ; x<SKYSIZE ; x++)
{
ofs = baseofs + ((x+xshift) & SKYMASK);
*pd = d_8to16table[(*(pnewsky + 128) &
*(byte *)&bottommask[ofs]) |
*(byte *)&bottomsky[ofs]];
pnewsky++;
pd++;
}
pnewsky += TILE_SIZE;
}
}
/*
=============
R_SetSkyFrame
==============
*/
void R_SetSkyFrame (void)
{
int g, s1, s2;
float temp;
skyspeed = iskyspeed;
skyspeed2 = iskyspeed2;
g = GreatestCommonDivisor (iskyspeed, iskyspeed2);
s1 = iskyspeed / g;
s2 = iskyspeed2 / g;
temp = SKYSIZE * s1 * s2;
skytime = cl.time - ((int)(cl.time / temp) * temp);
r_skymade = 0;
}

View File

@ -1,401 +0,0 @@
/*
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_sprite.c
#include "quakedef.h"
#include "r_local.h"
static int clip_current;
static vec5_t clip_verts[2][MAXWORKINGVERTS];
static int sprite_width, sprite_height;
spritedesc_t r_spritedesc;
/*
================
R_RotateSprite
================
*/
void R_RotateSprite (float beamlength)
{
vec3_t vec;
if (beamlength == 0.0)
return;
VectorScale (r_spritedesc.vpn, -beamlength, vec);
VectorAdd (r_entorigin, vec, r_entorigin);
VectorSubtract (modelorg, vec, modelorg);
}
/*
=============
R_ClipSpriteFace
Clips the winding at clip_verts[clip_current] and changes clip_current
Throws out the back side
==============
*/
int R_ClipSpriteFace (int nump, clipplane_t *pclipplane)
{
int i, outcount;
float dists[MAXWORKINGVERTS+1];
float frac, clipdist, *pclipnormal;
float *in, *instep, *outstep, *vert2;
clipdist = pclipplane->dist;
pclipnormal = pclipplane->normal;
// calc dists
if (clip_current)
{
in = clip_verts[1][0];
outstep = clip_verts[0][0];
clip_current = 0;
}
else
{
in = clip_verts[0][0];
outstep = clip_verts[1][0];
clip_current = 1;
}
instep = in;
for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
{
dists[i] = DotProduct (instep, pclipnormal) - clipdist;
}
// handle wraparound case
dists[nump] = dists[0];
Q_memcpy (instep, in, sizeof (vec5_t));
// clip the winding
instep = in;
outcount = 0;
for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
{
if (dists[i] >= 0)
{
Q_memcpy (outstep, instep, sizeof (vec5_t));
outstep += sizeof (vec5_t) / sizeof (float);
outcount++;
}
if (dists[i] == 0 || dists[i+1] == 0)
continue;
if ( (dists[i] > 0) == (dists[i+1] > 0) )
continue;
// split it into a new vertex
frac = dists[i] / (dists[i] - dists[i+1]);
vert2 = instep + sizeof (vec5_t) / sizeof (float);
outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
outstep += sizeof (vec5_t) / sizeof (float);
outcount++;
}
return outcount;
}
/*
================
R_SetupAndDrawSprite
================
*/
void R_SetupAndDrawSprite ()
{
int i, nump;
float dot, scale, *pv;
vec5_t *pverts;
vec3_t left, up, right, down, transformed, local;
emitpoint_t outverts[MAXWORKINGVERTS+1], *pout;
dot = DotProduct (r_spritedesc.vpn, modelorg);
// backface cull
if (dot >= 0)
return;
// build the sprite poster in worldspace
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right);
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up);
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left);
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down);
pverts = clip_verts[0];
pverts[0][0] = r_entorigin[0] + up[0] + left[0];
pverts[0][1] = r_entorigin[1] + up[1] + left[1];
pverts[0][2] = r_entorigin[2] + up[2] + left[2];
pverts[0][3] = 0;
pverts[0][4] = 0;
pverts[1][0] = r_entorigin[0] + up[0] + right[0];
pverts[1][1] = r_entorigin[1] + up[1] + right[1];
pverts[1][2] = r_entorigin[2] + up[2] + right[2];
pverts[1][3] = sprite_width;
pverts[1][4] = 0;
pverts[2][0] = r_entorigin[0] + down[0] + right[0];
pverts[2][1] = r_entorigin[1] + down[1] + right[1];
pverts[2][2] = r_entorigin[2] + down[2] + right[2];
pverts[2][3] = sprite_width;
pverts[2][4] = sprite_height;
pverts[3][0] = r_entorigin[0] + down[0] + left[0];
pverts[3][1] = r_entorigin[1] + down[1] + left[1];
pverts[3][2] = r_entorigin[2] + down[2] + left[2];
pverts[3][3] = 0;
pverts[3][4] = sprite_height;
// clip to the frustum in worldspace
nump = 4;
clip_current = 0;
for (i=0 ; i<4 ; i++)
{
nump = R_ClipSpriteFace (nump, &view_clipplanes[i]);
if (nump < 3)
return;
if (nump >= MAXWORKINGVERTS)
Sys_Error("R_SetupAndDrawSprite: too many points");
}
// transform vertices into viewspace and project
pv = &clip_verts[clip_current][0][0];
r_spritedesc.nearzi = -999999;
for (i=0 ; i<nump ; i++)
{
VectorSubtract (pv, r_origin, local);
TransformVector (local, transformed);
if (transformed[2] < NEAR_CLIP)
transformed[2] = NEAR_CLIP;
pout = &outverts[i];
pout->zi = 1.0 / transformed[2];
if (pout->zi > r_spritedesc.nearzi)
r_spritedesc.nearzi = pout->zi;
pout->s = pv[3];
pout->t = pv[4];
scale = xscale * pout->zi;
pout->u = (xcenter + scale * transformed[0]);
scale = yscale * pout->zi;
pout->v = (ycenter - scale * transformed[1]);
pv += sizeof (vec5_t) / sizeof (*pv);
}
// draw it
r_spritedesc.nump = nump;
r_spritedesc.pverts = outverts;
D_DrawSprite ();
}
/*
================
R_GetSpriteframe
================
*/
mspriteframe_t *R_GetSpriteframe (msprite_t *psprite)
{
mspritegroup_t *pspritegroup;
mspriteframe_t *pspriteframe;
int i, numframes, frame;
float *pintervals, fullinterval, targettime, time;
frame = currententity->frame;
if ((frame >= psprite->numframes) || (frame < 0))
{
Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
frame = 0;
}
if (psprite->frames[frame].type == SPR_SINGLE)
{
pspriteframe = psprite->frames[frame].frameptr;
}
else
{
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
pintervals = pspritegroup->intervals;
numframes = pspritegroup->numframes;
fullinterval = pintervals[numframes-1];
time = cl.time + currententity->syncbase;
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
// are positive, so we don't have to worry about division by 0
targettime = time - ((int)(time / fullinterval)) * fullinterval;
for (i=0 ; i<(numframes-1) ; i++)
{
if (pintervals[i] > targettime)
break;
}
pspriteframe = pspritegroup->frames[i];
}
return pspriteframe;
}
/*
================
R_DrawSprite
================
*/
void R_DrawSprite (void)
{
int i;
msprite_t *psprite;
vec3_t tvec;
float dot, angle, sr, cr;
psprite = currententity->model->cache.data;
r_spritedesc.pspriteframe = R_GetSpriteframe (psprite);
sprite_width = r_spritedesc.pspriteframe->width;
sprite_height = r_spritedesc.pspriteframe->height;
// TODO: make this caller-selectable
if (psprite->type == SPR_FACING_UPRIGHT)
{
// generate the sprite's axes, with vup straight up in worldspace, and
// r_spritedesc.vright perpendicular to modelorg.
// This will not work if the view direction is very close to straight up or
// down, because the cross product will be between two nearly parallel
// vectors and starts to approach an undefined state, so we don't draw if
// the two vectors are less than 1 degree apart
tvec[0] = -modelorg[0];
tvec[1] = -modelorg[1];
tvec[2] = -modelorg[2];
VectorNormalize (tvec);
dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
// r_spritedesc.vup is 0, 0, 1
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
return;
r_spritedesc.vup[0] = 0;
r_spritedesc.vup[1] = 0;
r_spritedesc.vup[2] = 1;
r_spritedesc.vright[0] = tvec[1];
// CrossProduct(r_spritedesc.vup, -modelorg,
r_spritedesc.vright[1] = -tvec[0];
// r_spritedesc.vright)
r_spritedesc.vright[2] = 0;
VectorNormalize (r_spritedesc.vright);
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
r_spritedesc.vpn[2] = 0;
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
// r_spritedesc.vpn)
}
else if (psprite->type == SPR_VP_PARALLEL)
{
// generate the sprite's axes, completely parallel to the viewplane. There
// are no problem situations, because the sprite is always in the same
// position relative to the viewer
for (i=0 ; i<3 ; i++)
{
r_spritedesc.vup[i] = vup[i];
r_spritedesc.vright[i] = vright[i];
r_spritedesc.vpn[i] = vpn[i];
}
}
else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT)
{
// generate the sprite's axes, with vup straight up in worldspace, and
// r_spritedesc.vright parallel to the viewplane.
// This will not work if the view direction is very close to straight up or
// down, because the cross product will be between two nearly parallel
// vectors and starts to approach an undefined state, so we don't draw if
// the two vectors are less than 1 degree apart
dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because
// r_spritedesc.vup is 0, 0, 1
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
return;
r_spritedesc.vup[0] = 0;
r_spritedesc.vup[1] = 0;
r_spritedesc.vup[2] = 1;
r_spritedesc.vright[0] = vpn[1];
// CrossProduct (r_spritedesc.vup, vpn,
r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright)
r_spritedesc.vright[2] = 0;
VectorNormalize (r_spritedesc.vright);
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
r_spritedesc.vpn[2] = 0;
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
// r_spritedesc.vpn)
}
else if (psprite->type == SPR_ORIENTED)
{
// generate the sprite's axes, according to the sprite's world orientation
AngleVectors (currententity->angles, r_spritedesc.vpn,
r_spritedesc.vright, r_spritedesc.vup);
}
else if (psprite->type == SPR_VP_PARALLEL_ORIENTED)
{
// generate the sprite's axes, parallel to the viewplane, but rotated in
// that plane around the center according to the sprite entity's roll
// angle. So vpn stays the same, but vright and vup rotate
angle = currententity->angles[ROLL] * (M_PI*2 / 360);
sr = sin(angle);
cr = cos(angle);
for (i=0 ; i<3 ; i++)
{
r_spritedesc.vpn[i] = vpn[i];
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
}
}
else
{
Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type);
}
R_RotateSprite (psprite->beamlength);
R_SetupAndDrawSprite ();
}

View File

@ -1,39 +0,0 @@
/*
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_vars.c: global refresh variables
#include "quakedef.h"
#if !id386
// all global and static refresh variables are collected in a contiguous block
// to avoid cache conflicts.
//-------------------------------------------------------
// global refresh variables
//-------------------------------------------------------
// FIXME: make into one big structure, like cl or sv
// FIXME: do separately for refresh engine and driver
int r_bmodelactive;
#endif // !id386

View File

@ -338,29 +338,27 @@ cshift_t cshift_water = { {130,80,50}, 128 };
cshift_t cshift_slime = { {0,25,5}, 150 };
cshift_t cshift_lava = { {255,80,0}, 150 };
cvar_t v_gamma = {"gamma", "2", true};
cvar_t v_gamma = {"gamma", "1.0", true};
byte gammatable[256]; // palette is sent through this
#ifdef GLQUAKE
byte ramps[3][256];
float v_blend[4]; // rgba 0.0 - 1.0
#endif // GLQUAKE
void BuildGammaTable (float g)
{
int i, inf;
if (g == 1.0)
{
for (i=0 ; i<256 ; i++)
gammatable[i] = i;
return;
}
for (i=0 ; i<256 ; i++)
{
inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
inf = 255 * powf ( (i+0.5f)/255.5f , g ) + 0.5;
if (inf < 0)
inf = 0;
if (inf > 255)
@ -569,13 +567,13 @@ void V_CalcBlend (void)
b = 0;
a = 0;
for (j=0 ; j<NUM_CSHIFTS ; j++)
for (j=0 ; j<NUM_CSHIFTS ; j++)
{
if (!gl_cshiftpercent.value)
if (!gl_polyblend.value) {
continue;
}
a2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0;
a2 = cl.cshifts[j].percent / 255.0;
// a2 = cl.cshifts[j].percent/255.0;
if (!a2)
continue;
@ -612,10 +610,10 @@ void V_UpdatePalette (void)
int ir, ig, ib;
qboolean force;
//V_CalcPowerupCshift ();
//V_HealthCshift ();
new = false;
for (i=0 ; i<NUM_CSHIFTS ; i++)
{
if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
@ -667,21 +665,21 @@ void V_UpdatePalette (void)
basepal = host_basepal;
newpal = pal;
for (i=0 ; i<256 ; i++)
{
ir = basepal[0];
ig = basepal[1];
ib = basepal[2];
basepal += 3;
newpal[0] = ramps[0][ir];
newpal[1] = ramps[1][ig];
newpal[2] = ramps[2][ib];
newpal += 3;
}
VID_ShiftPalette (pal);
VID_ShiftPalette (pal);
}
@ -1735,8 +1733,8 @@ void V_Init (void)
Cvar_RegisterVariable (&v_kickroll);
Cvar_RegisterVariable (&v_kickpitch);
BuildGammaTable (1.0); // no gamma yet
Cvar_RegisterVariable (&v_gamma);
BuildGammaTable (v_gamma.value); // no gamma yet
}