mirror of
https://github.com/nzp-team/glquake.git
synced 2024-11-10 06:31:35 +00:00
Add adjustable gamma
This commit is contained in:
parent
4e7be6266d
commit
e49548ff5a
17 changed files with 28 additions and 5037 deletions
BIN
nzportable.3dsx
BIN
nzportable.3dsx
Binary file not shown.
BIN
nzportable.elf
BIN
nzportable.elf
Binary file not shown.
|
@ -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);
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
350
source/r_aclip.c
350
source/r_aclip.c
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
753
source/r_alias.c
753
source/r_alias.c
|
@ -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 ();
|
||||
}
|
||||
|
674
source/r_bsp.c
674
source/r_bsp.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
908
source/r_draw.c
908
source/r_draw.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
774
source/r_edge.c
774
source/r_edge.c
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
276
source/r_efrag.c
276
source/r_efrag.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
523
source/r_misc.c
523
source/r_misc.c
|
@ -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 ();
|
||||
}
|
||||
|
280
source/r_sky.c
280
source/r_sky.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue