mittorn
6 years ago
12 changed files with 6975 additions and 108 deletions
@ -0,0 +1,626 @@
@@ -0,0 +1,626 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 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 "r_local.h" |
||||
|
||||
//
|
||||
// current entity info
|
||||
//
|
||||
qboolean insubmodel; |
||||
vec3_t 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]; |
||||
|
||||
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 = RI.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 = RI.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 = RI.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 |
||||
|
||||
Clip a bmodel poly down the world bsp tree |
||||
================ |
||||
*/ |
||||
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; |
||||
int area; |
||||
|
||||
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)) |
||||
{ |
||||
gEngfuncs.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)) |
||||
{ |
||||
gEngfuncs.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)->cluster; |
||||
R_RenderBmodelFace (psideedges[i], psurf); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
R_RecursiveClipBPoly (psideedges[i], pnode->children[i], |
||||
psurf); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
/*
|
||||
================ |
||||
R_DrawSolidClippedSubmodelPolygons |
||||
|
||||
Bmodel crosses multiple leafs |
||||
================ |
||||
*/ |
||||
void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode) |
||||
{ |
||||
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))) |
||||
continue; |
||||
|
||||
// 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; |
||||
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
|
||||
|
||||
//if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
|
||||
R_RecursiveClipBPoly (pbedge, topnode, psurf); |
||||
//else
|
||||
// R_RenderBmodelFace( pbedge, psurf );
|
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
================ |
||||
R_DrawSubmodelPolygons |
||||
|
||||
All in one leaf |
||||
================ |
||||
*/ |
||||
void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode) |
||||
{ |
||||
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 *)topnode)->cluster; |
||||
|
||||
// FIXME: use bounding-box-based frustum clipping info?
|
||||
R_RenderFace (psurf, clipflags); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
int c_drawnode; |
||||
|
||||
/*
|
||||
================ |
||||
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) |
||||
{ |
||||
gEngfuncs.R_StoreEfrags(&pleaf->efrags,tr.realframecount); |
||||
} |
||||
|
||||
pleaf->cluster = 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 = WORLDMODEL->surfaces + node->firstsurface; |
||||
|
||||
if (dot < -BACKFACE_EPSILON) |
||||
{ |
||||
do |
||||
{ |
||||
if ((surf->flags & SURF_PLANEBACK) && |
||||
(surf->visframe == r_framecount)) |
||||
{ |
||||
R_RenderFace (surf, clipflags); |
||||
} |
||||
|
||||
surf++; |
||||
} while (--c); |
||||
} |
||||
else if (dot > BACKFACE_EPSILON) |
||||
{ |
||||
do |
||||
{ |
||||
if (!(surf->flags & SURF_PLANEBACK) && |
||||
(surf->visframe == r_framecount)) |
||||
{ |
||||
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) |
||||
{ |
||||
|
||||
//if (!r_drawworld->value)
|
||||
// return;
|
||||
if ( !RI.drawWorld ) |
||||
return; |
||||
|
||||
c_drawnode=0; |
||||
|
||||
// auto cycle the world frame for texture animation
|
||||
RI.currententity = gEngfuncs.GetEntityByIndex(0); |
||||
//RI.currententity->frame = (int)(gpGlobals->time*2);
|
||||
|
||||
VectorCopy (r_origin, modelorg); |
||||
RI.currentmodel = WORLDMODEL; |
||||
r_pcurrentvertbase = RI.currentmodel->vertexes; |
||||
|
||||
R_RecursiveWorldNode (RI.currentmodel->nodes, 15); |
||||
} |
||||
|
||||
|
@ -0,0 +1,499 @@
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
gl_rlight.c - dynamic and static lights |
||||
Copyright (C) 2010 Uncle Mike |
||||
|
||||
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 3 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. |
||||
*/ |
||||
|
||||
#include "r_local.h" |
||||
#include "pm_local.h" |
||||
#include "studio.h" |
||||
#include "mathlib.h" |
||||
#include "ref_params.h" |
||||
|
||||
//unused, need refactor
|
||||
unsigned blocklights[1024]; |
||||
|
||||
/*
|
||||
============================================================================= |
||||
|
||||
DYNAMIC LIGHTS |
||||
|
||||
============================================================================= |
||||
*/ |
||||
/*
|
||||
================== |
||||
CL_RunLightStyles |
||||
|
||||
================== |
||||
*/ |
||||
void CL_RunLightStyles( void ) |
||||
{ |
||||
int i, k, flight, clight; |
||||
float l, lerpfrac, backlerp; |
||||
float frametime = (gpGlobals->time - gpGlobals->oldtime); |
||||
float scale; |
||||
lightstyle_t *ls; |
||||
|
||||
if( !WORLDMODEL ) return; |
||||
|
||||
scale = 1; //r_lighting_modulate->value;
|
||||
|
||||
// light animations
|
||||
// 'm' is normal light, 'a' is no light, 'z' is double bright
|
||||
for( i = 0; i < MAX_LIGHTSTYLES; i++ ) |
||||
{ |
||||
ls = gEngfuncs.GetLightStyle( i ); |
||||
if( !WORLDMODEL->lightdata ) |
||||
{ |
||||
tr.lightstylevalue[i] = 256 * 256; |
||||
continue; |
||||
} |
||||
|
||||
if( !gEngfuncs.CL_GetRenderParm( PARAM_GAMEPAUSED, 0 ) && frametime <= 0.1f ) |
||||
ls->time += frametime; // evaluate local time
|
||||
|
||||
flight = (int)Q_floor( ls->time * 10 ); |
||||
clight = (int)Q_ceil( ls->time * 10 ); |
||||
lerpfrac = ( ls->time * 10 ) - flight; |
||||
backlerp = 1.0f - lerpfrac; |
||||
|
||||
if( !ls->length ) |
||||
{ |
||||
tr.lightstylevalue[i] = 256 * scale; |
||||
continue; |
||||
} |
||||
else if( ls->length == 1 ) |
||||
{ |
||||
// single length style so don't bother interpolating
|
||||
tr.lightstylevalue[i] = ls->map[0] * 22 * scale; |
||||
continue; |
||||
} |
||||
else if( !ls->interp ) // || !CVAR_TO_BOOL( cl_lightstyle_lerping ))
|
||||
{ |
||||
tr.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * scale; |
||||
continue; |
||||
} |
||||
|
||||
// interpolate animating light
|
||||
// frame just gone
|
||||
k = ls->map[flight % ls->length]; |
||||
l = (float)( k * 22.0f ) * backlerp; |
||||
|
||||
// upcoming frame
|
||||
k = ls->map[clight % ls->length]; |
||||
l += (float)( k * 22.0f ) * lerpfrac; |
||||
|
||||
tr.lightstylevalue[i] = (int)l * scale; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
============= |
||||
R_MarkLights |
||||
============= |
||||
*/ |
||||
void R_MarkLights( dlight_t *light, int bit, mnode_t *node ) |
||||
{ |
||||
float dist; |
||||
msurface_t *surf; |
||||
int i; |
||||
|
||||
if( !node || node->contents < 0 ) |
||||
return; |
||||
|
||||
dist = PlaneDiff( light->origin, node->plane ); |
||||
|
||||
if( dist > light->radius ) |
||||
{ |
||||
R_MarkLights( light, bit, node->children[0] ); |
||||
return; |
||||
} |
||||
if( dist < -light->radius ) |
||||
{ |
||||
R_MarkLights( light, bit, node->children[1] ); |
||||
return; |
||||
} |
||||
|
||||
// mark the polygons
|
||||
surf = RI.currentmodel->surfaces + node->firstsurface; |
||||
|
||||
for( i = 0; i < node->numsurfaces; i++, surf++ ) |
||||
{ |
||||
if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius )) |
||||
continue; // no intersection
|
||||
|
||||
if( surf->dlightframe != tr.dlightframecount ) |
||||
{ |
||||
surf->dlightbits = 0; |
||||
surf->dlightframe = tr.dlightframecount; |
||||
} |
||||
surf->dlightbits |= bit; |
||||
} |
||||
|
||||
R_MarkLights( light, bit, node->children[0] ); |
||||
R_MarkLights( light, bit, node->children[1] ); |
||||
} |
||||
|
||||
/*
|
||||
============= |
||||
R_PushDlights |
||||
============= |
||||
*/ |
||||
void R_PushDlights( void ) |
||||
{ |
||||
dlight_t *l; |
||||
int i; |
||||
|
||||
tr.dlightframecount = tr.framecount; |
||||
|
||||
RI.currententity = gEngfuncs.GetEntityByIndex( 0 ); |
||||
RI.currentmodel = RI.currententity->model; |
||||
|
||||
for( i = 0; i < MAX_DLIGHTS; i++, l++ ) |
||||
{ |
||||
l = gEngfuncs.GetDynamicLight( i ); |
||||
|
||||
if( l->die < gpGlobals->time || !l->radius ) |
||||
continue; |
||||
|
||||
//if( GL_FrustumCullSphere( &RI.frustum, l->origin, l->radius, 15 ))
|
||||
//continue;
|
||||
|
||||
R_MarkLights( l, 1<<i, RI.currentmodel->nodes ); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
============= |
||||
R_CountDlights |
||||
============= |
||||
*/ |
||||
int R_CountDlights( void ) |
||||
{ |
||||
dlight_t *l; |
||||
int i, numDlights = 0; |
||||
|
||||
for( i = 0; i < MAX_DLIGHTS; i++ ) |
||||
{ |
||||
l = gEngfuncs.GetDynamicLight( i ); |
||||
|
||||
if( l->die < gpGlobals->time || !l->radius ) |
||||
continue; |
||||
|
||||
numDlights++; |
||||
} |
||||
|
||||
return numDlights; |
||||
} |
||||
|
||||
/*
|
||||
============= |
||||
R_CountSurfaceDlights |
||||
============= |
||||
*/ |
||||
int R_CountSurfaceDlights( msurface_t *surf ) |
||||
{ |
||||
int i, numDlights = 0; |
||||
|
||||
for( i = 0; i < MAX_DLIGHTS; i++ ) |
||||
{ |
||||
if(!( surf->dlightbits & BIT( i ))) |
||||
continue; // not lit by this light
|
||||
|
||||
numDlights++; |
||||
} |
||||
|
||||
return numDlights; |
||||
} |
||||
|
||||
/*
|
||||
======================================================================= |
||||
|
||||
AMBIENT LIGHTING |
||||
|
||||
======================================================================= |
||||
*/ |
||||
static vec3_t g_trace_lightspot; |
||||
static vec3_t g_trace_lightvec; |
||||
static float g_trace_fraction; |
||||
|
||||
/*
|
||||
================= |
||||
R_RecursiveLightPoint |
||||
================= |
||||
*/ |
||||
static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, float p2f, colorVec *cv, const vec3_t start, const vec3_t end ) |
||||
{ |
||||
float front, back, frac, midf; |
||||
int i, map, side, size; |
||||
float ds, dt, s, t; |
||||
int sample_size; |
||||
color24 *lm, *dm; |
||||
mextrasurf_t *info; |
||||
msurface_t *surf; |
||||
mtexinfo_t *tex; |
||||
matrix3x4 tbn; |
||||
vec3_t mid; |
||||
|
||||
// didn't hit anything
|
||||
if( !node || node->contents < 0 ) |
||||
{ |
||||
cv->r = cv->g = cv->b = cv->a = 0; |
||||
return false; |
||||
} |
||||
|
||||
// calculate mid point
|
||||
front = PlaneDiff( start, node->plane ); |
||||
back = PlaneDiff( end, node->plane ); |
||||
|
||||
side = front < 0; |
||||
if(( back < 0 ) == side ) |
||||
return R_RecursiveLightPoint( model, node->children[side], p1f, p2f, cv, start, end ); |
||||
|
||||
frac = front / ( front - back ); |
||||
|
||||
VectorLerp( start, frac, end, mid ); |
||||
midf = p1f + ( p2f - p1f ) * frac; |
||||
|
||||
// co down front side
|
||||
if( R_RecursiveLightPoint( model, node->children[side], p1f, midf, cv, start, mid )) |
||||
return true; // hit something
|
||||
|
||||
if(( back < 0 ) == side ) |
||||
{ |
||||
cv->r = cv->g = cv->b = cv->a = 0; |
||||
return false; // didn't hit anything
|
||||
} |
||||
|
||||
// check for impact on this node
|
||||
surf = model->surfaces + node->firstsurface; |
||||
VectorCopy( mid, g_trace_lightspot ); |
||||
|
||||
for( i = 0; i < node->numsurfaces; i++, surf++ ) |
||||
{ |
||||
int smax, tmax; |
||||
|
||||
tex = surf->texinfo; |
||||
info = surf->info; |
||||
|
||||
if( FBitSet( surf->flags, SURF_DRAWTILED )) |
||||
continue; // no lightmaps
|
||||
|
||||
s = DotProduct( mid, info->lmvecs[0] ) + info->lmvecs[0][3]; |
||||
t = DotProduct( mid, info->lmvecs[1] ) + info->lmvecs[1][3]; |
||||
|
||||
if( s < info->lightmapmins[0] || t < info->lightmapmins[1] ) |
||||
continue; |
||||
|
||||
ds = s - info->lightmapmins[0]; |
||||
dt = t - info->lightmapmins[1]; |
||||
|
||||
if ( ds > info->lightextents[0] || dt > info->lightextents[1] ) |
||||
continue; |
||||
|
||||
cv->r = cv->g = cv->b = cv->a = 0; |
||||
|
||||
if( !surf->samples ) |
||||
return true; |
||||
|
||||
sample_size = gEngfuncs.Mod_SampleSizeForFace( surf ); |
||||
smax = (info->lightextents[0] / sample_size) + 1; |
||||
tmax = (info->lightextents[1] / sample_size) + 1; |
||||
ds /= sample_size; |
||||
dt /= sample_size; |
||||
|
||||
lm = surf->samples + Q_rint( dt ) * smax + Q_rint( ds ); |
||||
g_trace_fraction = midf; |
||||
size = smax * tmax; |
||||
dm = NULL; |
||||
|
||||
if( surf->info->deluxemap ) |
||||
{ |
||||
vec3_t faceNormal; |
||||
|
||||
if( FBitSet( surf->flags, SURF_PLANEBACK )) |
||||
VectorNegate( surf->plane->normal, faceNormal ); |
||||
else VectorCopy( surf->plane->normal, faceNormal ); |
||||
|
||||
// compute face TBN
|
||||
#if 1 |
||||
Vector4Set( tbn[0], surf->info->lmvecs[0][0], surf->info->lmvecs[0][1], surf->info->lmvecs[0][2], 0.0f ); |
||||
Vector4Set( tbn[1], -surf->info->lmvecs[1][0], -surf->info->lmvecs[1][1], -surf->info->lmvecs[1][2], 0.0f ); |
||||
Vector4Set( tbn[2], faceNormal[0], faceNormal[1], faceNormal[2], 0.0f ); |
||||
#else |
||||
Vector4Set( tbn[0], surf->info->lmvecs[0][0], -surf->info->lmvecs[1][0], faceNormal[0], 0.0f ); |
||||
Vector4Set( tbn[1], surf->info->lmvecs[0][1], -surf->info->lmvecs[1][1], faceNormal[1], 0.0f ); |
||||
Vector4Set( tbn[2], surf->info->lmvecs[0][2], -surf->info->lmvecs[1][2], faceNormal[2], 0.0f ); |
||||
#endif |
||||
VectorNormalize( tbn[0] ); |
||||
VectorNormalize( tbn[1] ); |
||||
VectorNormalize( tbn[2] ); |
||||
dm = surf->info->deluxemap + Q_rint( dt ) * smax + Q_rint( ds ); |
||||
} |
||||
|
||||
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ ) |
||||
{ |
||||
uint scale = tr.lightstylevalue[surf->styles[map]]; |
||||
|
||||
if( tr.ignore_lightgamma ) |
||||
{ |
||||
cv->r += lm->r * scale; |
||||
cv->g += lm->g * scale; |
||||
cv->b += lm->b * scale; |
||||
} |
||||
else |
||||
{ |
||||
cv->r += gEngfuncs.LightToTexGamma( lm->r ) * scale; |
||||
cv->g += gEngfuncs.LightToTexGamma( lm->g ) * scale; |
||||
cv->b += gEngfuncs.LightToTexGamma( lm->b ) * scale; |
||||
} |
||||
lm += size; // skip to next lightmap
|
||||
|
||||
if( dm != NULL ) |
||||
{ |
||||
vec3_t srcNormal, lightNormal; |
||||
float f = (1.0f / 128.0f); |
||||
|
||||
VectorSet( srcNormal, ((float)dm->r - 128.0f) * f, ((float)dm->g - 128.0f) * f, ((float)dm->b - 128.0f) * f ); |
||||
Matrix3x4_VectorIRotate( tbn, srcNormal, lightNormal ); // turn to world space
|
||||
VectorScale( lightNormal, (float)scale * -1.0f, lightNormal ); // turn direction from light
|
||||
VectorAdd( g_trace_lightvec, lightNormal, g_trace_lightvec ); |
||||
dm += size; // skip to next deluxmap
|
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
// go down back side
|
||||
return R_RecursiveLightPoint( model, node->children[!side], midf, p2f, cv, mid, end ); |
||||
} |
||||
|
||||
/*
|
||||
================= |
||||
R_LightVec |
||||
|
||||
check bspmodels to get light from |
||||
================= |
||||
*/ |
||||
colorVec R_LightVecInternal( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec ) |
||||
{ |
||||
float last_fraction; |
||||
int i, maxEnts = 1; |
||||
colorVec light, cv; |
||||
|
||||
if( lspot ) VectorClear( lspot ); |
||||
if( lvec ) VectorClear( lvec ); |
||||
|
||||
if( WORLDMODEL && WORLDMODEL->lightdata ) |
||||
{ |
||||
light.r = light.g = light.b = light.a = 0; |
||||
last_fraction = 1.0f; |
||||
|
||||
// get light from bmodels too
|
||||
//if( CVAR_TO_BOOL( r_lighting_extended ))
|
||||
maxEnts = MAX_PHYSENTS; |
||||
|
||||
// check all the bsp-models
|
||||
for( i = 0; i < maxEnts; i++ ) |
||||
{ |
||||
physent_t *pe = gEngfuncs.EV_GetPhysent( i ); |
||||
vec3_t offset, start_l, end_l; |
||||
mnode_t *pnodes; |
||||
matrix4x4 matrix; |
||||
|
||||
if( !pe ) |
||||
break; |
||||
|
||||
if( !pe->model || pe->model->type != mod_brush ) |
||||
continue; // skip non-bsp models
|
||||
|
||||
pnodes = &pe->model->nodes[pe->model->hulls[0].firstclipnode]; |
||||
VectorSubtract( pe->model->hulls[0].clip_mins, vec3_origin, offset ); |
||||
VectorAdd( offset, pe->origin, offset ); |
||||
VectorSubtract( start, offset, start_l ); |
||||
VectorSubtract( end, offset, end_l ); |
||||
|
||||
// rotate start and end into the models frame of reference
|
||||
if( !VectorIsNull( pe->angles )) |
||||
{ |
||||
Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f ); |
||||
Matrix4x4_VectorITransform( matrix, start, start_l ); |
||||
Matrix4x4_VectorITransform( matrix, end, end_l ); |
||||
} |
||||
|
||||
VectorClear( g_trace_lightspot ); |
||||
VectorClear( g_trace_lightvec ); |
||||
g_trace_fraction = 1.0f; |
||||
|
||||
if( !R_RecursiveLightPoint( pe->model, pnodes, 0.0f, 1.0f, &cv, start_l, end_l )) |
||||
continue; // didn't hit anything
|
||||
|
||||
if( g_trace_fraction < last_fraction ) |
||||
{ |
||||
if( lspot ) VectorCopy( g_trace_lightspot, lspot ); |
||||
if( lvec ) VectorNormalize2( g_trace_lightvec, lvec ); |
||||
light.r = Q_min(( cv.r >> 7 ), 255 ); |
||||
light.g = Q_min(( cv.g >> 7 ), 255 ); |
||||
light.b = Q_min(( cv.b >> 7 ), 255 ); |
||||
last_fraction = g_trace_fraction; |
||||
|
||||
if(( light.r + light.g + light.b ) != 0 ) |
||||
break; // we get light now
|
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
light.r = light.g = light.b = 255; |
||||
light.a = 0; |
||||
} |
||||
|
||||
return light; |
||||
} |
||||
|
||||
/*
|
||||
================= |
||||
R_LightVec |
||||
|
||||
check bspmodels to get light from |
||||
================= |
||||
*/ |
||||
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec ) |
||||
{ |
||||
colorVec light = R_LightVecInternal( start, end, lspot, lvec ); |
||||
|
||||
if( lspot != NULL && lvec != NULL ) // CVAR_TO_BOOL( r_lighting_extended ) &&
|
||||
{ |
||||
// trying to get light from ceiling (but ignore gradient analyze)
|
||||
if(( light.r + light.g + light.b ) == 0 ) |
||||
return R_LightVecInternal( end, start, lspot, lvec ); |
||||
} |
||||
|
||||
return light; |
||||
} |
||||
|
||||
/*
|
||||
================= |
||||
R_LightPoint |
||||
|
||||
light from floor |
||||
================= |
||||
*/ |
||||
colorVec R_LightPoint( const vec3_t p0 ) |
||||
{ |
||||
vec3_t p1; |
||||
|
||||
VectorSet( p1, p0[0], p0[1], p0[2] - 2048.0f ); |
||||
|
||||
return R_LightVec( p0, p1, NULL, NULL ); |
||||
} |
@ -0,0 +1,421 @@
@@ -0,0 +1,421 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 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 "r_local.h" |
||||
|
||||
#define NUM_MIPS 4 |
||||
|
||||
cvar_t *sw_mipcap; |
||||
cvar_t *sw_mipscale; |
||||
|
||||
surfcache_t *d_initial_rover; |
||||
qboolean d_roverwrapped; |
||||
int d_minmip; |
||||
float d_scalemip[NUM_MIPS-1]; |
||||
|
||||
static float basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8}; |
||||
|
||||
extern int d_aflatcolor; |
||||
|
||||
int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle; |
||||
|
||||
int d_pix_min, d_pix_max, d_pix_shift; |
||||
|
||||
int d_scantable[MAXHEIGHT]; |
||||
short *zspantable[MAXHEIGHT]; |
||||
|
||||
/*
|
||||
================ |
||||
D_Patch |
||||
================ |
||||
*/ |
||||
void D_Patch (void) |
||||
{ |
||||
#if id386 |
||||
extern void D_Aff8Patch( void ); |
||||
static qboolean protectset8 = false; |
||||
extern void D_PolysetAff8Start( void ); |
||||
|
||||
if (!protectset8) |
||||
{ |
||||
Sys_MakeCodeWriteable ((int)D_PolysetAff8Start, |
||||
(int)D_Aff8Patch - (int)D_PolysetAff8Start); |
||||
Sys_MakeCodeWriteable ((long)R_Surf8Start, |
||||
(long)R_Surf8End - (long)R_Surf8Start); |
||||
protectset8 = true; |
||||
} |
||||
colormap = vid.colormap; |
||||
|
||||
R_Surf8Patch (); |
||||
D_Aff8Patch(); |
||||
#endif |
||||
} |
||||
/*
|
||||
================ |
||||
D_ViewChanged |
||||
================ |
||||
*/ |
||||
unsigned char *alias_colormap; |
||||
|
||||
void D_ViewChanged (void) |
||||
{ |
||||
int i; |
||||
|
||||
scale_for_mip = xscale; |
||||
if (yscale > xscale) |
||||
scale_for_mip = yscale; |
||||
|
||||
d_zrowbytes = vid.width * 2; |
||||
d_zwidth = vid.width; |
||||
|
||||
d_pix_min = gpGlobals->width / 320; |
||||
if (d_pix_min < 1) |
||||
d_pix_min = 1; |
||||
|
||||
d_pix_max = (int)((float)gpGlobals->height / (320.0 / 4.0) + 0.5); |
||||
d_pix_shift = 8 - (int)((float)gpGlobals->height / 320.0 + 0.5); |
||||
if (d_pix_max < 1) |
||||
d_pix_max = 1; |
||||
|
||||
d_vrectx = 0;//r_refdef.vrect.x;
|
||||
d_vrecty = 0;//r_refdef.vrect.y;
|
||||
d_vrectright_particle = gpGlobals->width - d_pix_max; |
||||
d_vrectbottom_particle = |
||||
gpGlobals->height - d_pix_max; |
||||
|
||||
for (i=0 ; i<vid.height; i++) |
||||
{ |
||||
d_scantable[i] = i*r_screenwidth; |
||||
zspantable[i] = d_pzbuffer + i*d_zwidth; |
||||
} |
||||
|
||||
/*
|
||||
** clear Z-buffer and color-buffers if we're doing the gallery |
||||
*/ |
||||
if ( !RI.drawWorld ) |
||||
{ |
||||
memset( d_pzbuffer, 0xff, vid.width * vid.height * sizeof( d_pzbuffer[0] ) ); |
||||
// newrefdef
|
||||
Draw_Fill( 0, 0, gpGlobals->width, gpGlobals->height,( int ) sw_clearcolor->value & 0xff ); |
||||
} |
||||
|
||||
alias_colormap = vid.colormap; |
||||
|
||||
D_Patch (); |
||||
} |
||||
|
||||
|
||||
|
||||
/*
|
||||
=================== |
||||
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); |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
================ |
||||
TransformVector |
||||
================ |
||||
*/ |
||||
void TransformVector (vec3_t in, vec3_t out) |
||||
{ |
||||
out[0] = DotProduct(in,vright); |
||||
out[1] = DotProduct(in,vup); |
||||
out[2] = DotProduct(in,vpn); |
||||
} |
||||
|
||||
/*
|
||||
================ |
||||
R_TransformPlane |
||||
================ |
||||
*/ |
||||
void R_TransformPlane (mplane_t *p, float *normal, float *dist) |
||||
{ |
||||
float d; |
||||
|
||||
d = DotProduct (RI.vieworg, 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_ViewChanged |
||||
|
||||
Called every time the vid structure or r_refdef changes. |
||||
Guaranteed to be called before the first refresh |
||||
=============== |
||||
*/ |
||||
void R_ViewChanged (vrect_t *vr) |
||||
{ |
||||
int i; |
||||
#if 0 |
||||
r_refdef.vrect = *vr; |
||||
|
||||
r_refdef.horizontalFieldOfView = 2*tan((float)r_newrefdef.fov_x/360*M_PI);; |
||||
verticalFieldOfView = 2*tan((float)r_newrefdef.fov_y/360*M_PI); |
||||
|
||||
r_refdef.fvrectx = (float)r_refdef.vrect.x; |
||||
r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5; |
||||
r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1; |
||||
r_refdef.fvrecty = (float)r_refdef.vrect.y; |
||||
r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5; |
||||
r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width; |
||||
r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1; |
||||
r_refdef.fvrectright = (float)r_refdef.vrectright; |
||||
r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5; |
||||
r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99; |
||||
r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height; |
||||
r_refdef.fvrectbottom = (float)r_refdef.vrectbottom; |
||||
r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5; |
||||
|
||||
r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale); |
||||
r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale); |
||||
r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale); |
||||
r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale); |
||||
r_refdef.aliasvrectright = r_refdef.aliasvrect.x + |
||||
r_refdef.aliasvrect.width; |
||||
r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y + |
||||
r_refdef.aliasvrect.height; |
||||
|
||||
xOrigin = r_refdef.xOrigin; |
||||
yOrigin = r_refdef.yOrigin; |
||||
|
||||
// values for perspective projection
|
||||
// if math were exact, the values would range from 0.5 to to range+0.5
|
||||
// hopefully they wll be in the 0.000001 to range+.999999 and truncate
|
||||
// the polygon rasterization will never render in the first row or column
|
||||
// but will definately render in the [range] row and column, so adjust the
|
||||
// buffer origin to get an exact edge to edge fill
|
||||
xcenter = ((float)r_refdef.vrect.width * XCENTERING) + |
||||
r_refdef.vrect.x - 0.5; |
||||
aliasxcenter = xcenter * r_aliasuvscale; |
||||
ycenter = ((float)r_refdef.vrect.height * YCENTERING) + |
||||
r_refdef.vrect.y - 0.5; |
||||
aliasycenter = ycenter * r_aliasuvscale; |
||||
|
||||
xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView; |
||||
aliasxscale = xscale * r_aliasuvscale; |
||||
xscaleinv = 1.0 / xscale; |
||||
|
||||
yscale = xscale; |
||||
aliasyscale = yscale * r_aliasuvscale; |
||||
yscaleinv = 1.0 / yscale; |
||||
xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView; |
||||
yscaleshrink = xscaleshrink; |
||||
|
||||
// left side clip
|
||||
screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView); |
||||
screenedge[0].normal[1] = 0; |
||||
screenedge[0].normal[2] = 1; |
||||
screenedge[0].type = PLANE_ANYZ; |
||||
|
||||
// right side clip
|
||||
screenedge[1].normal[0] = |
||||
1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView); |
||||
screenedge[1].normal[1] = 0; |
||||
screenedge[1].normal[2] = 1; |
||||
screenedge[1].type = PLANE_ANYZ; |
||||
|
||||
// top side clip
|
||||
screenedge[2].normal[0] = 0; |
||||
screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView); |
||||
screenedge[2].normal[2] = 1; |
||||
screenedge[2].type = PLANE_ANYZ; |
||||
|
||||
// bottom side clip
|
||||
screenedge[3].normal[0] = 0; |
||||
screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView); |
||||
screenedge[3].normal[2] = 1; |
||||
screenedge[3].type = PLANE_ANYZ; |
||||
#endif |
||||
for (i=0 ; i<4 ; i++) |
||||
VectorNormalize (screenedge[i].normal); |
||||
|
||||
D_ViewChanged (); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
=============== |
||||
R_SetupFrame |
||||
=============== |
||||
*/ |
||||
void R_SetupFrameQ (void) |
||||
{ |
||||
int i; |
||||
vrect_t vrect; |
||||
|
||||
if (r_fullbright->flags & FCVAR_CHANGED) |
||||
{ |
||||
r_fullbright->flags &= ~FCVAR_CHANGED; |
||||
D_FlushCaches (); // so all lighting changes
|
||||
} |
||||
|
||||
r_framecount++; |
||||
|
||||
|
||||
// build the transformation matrix for the given view angles
|
||||
VectorCopy (RI.vieworg, modelorg); |
||||
VectorCopy (RI.vieworg, r_origin); |
||||
|
||||
AngleVectors (RI.viewangles, vpn, vright, vup); |
||||
|
||||
// current viewleaf
|
||||
if ( RI.drawWorld ) |
||||
{ |
||||
r_viewleaf = gEngfuncs.Mod_PointInLeaf (r_origin, WORLDMODEL->nodes); |
||||
r_viewcluster = r_viewleaf->cluster; |
||||
} |
||||
|
||||
// if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) )
|
||||
// r_dowarp = true;
|
||||
// else
|
||||
r_dowarp = false; |
||||
|
||||
if (r_dowarp) |
||||
{ // warp into off screen buffer
|
||||
vrect.x = 0; |
||||
vrect.y = 0; |
||||
//vrect.width = r_newrefdef.width < WARP_WIDTH ? r_newrefdef.width : WARP_WIDTH;
|
||||
//vrect.height = r_newrefdef.height < WARP_HEIGHT ? r_newrefdef.height : WARP_HEIGHT;
|
||||
|
||||
d_viewbuffer = r_warpbuffer; |
||||
r_screenwidth = WARP_WIDTH; |
||||
} |
||||
else |
||||
{ |
||||
vrect.x = 0;//r_newrefdef.x;
|
||||
vrect.y = 0;//r_newrefdef.y;
|
||||
vrect.width = gpGlobals->width; |
||||
vrect.height = gpGlobals->height; |
||||
|
||||
d_viewbuffer = (void *)vid.buffer; |
||||
r_screenwidth = vid.rowbytes; |
||||
} |
||||
|
||||
R_ViewChanged (&vrect); |
||||
|
||||
// start off with just the four screen edge clip planes
|
||||
R_TransformFrustum (); |
||||
R_SetUpFrustumIndexes (); |
||||
|
||||
// save base values
|
||||
VectorCopy (vpn, base_vpn); |
||||
VectorCopy (vright, base_vright); |
||||
VectorCopy (vup, base_vup); |
||||
|
||||
// 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_setup
|
||||
d_roverwrapped = false; |
||||
d_initial_rover = sc_rover; |
||||
|
||||
d_minmip = sw_mipcap->value; |
||||
if (d_minmip > 3) |
||||
d_minmip = 3; |
||||
else if (d_minmip < 0) |
||||
d_minmip = 0; |
||||
|
||||
for (i=0 ; i<(NUM_MIPS-1) ; i++) |
||||
d_scalemip[i] = basemip[i] * sw_mipscale->value; |
||||
|
||||
//d_aflatcolor = 0;
|
||||
} |
||||
|
||||
|
||||
#if !id386 |
||||
|
||||
/*
|
||||
================ |
||||
R_SurfacePatch |
||||
================ |
||||
*/ |
||||
/*void R_SurfacePatch (void)
|
||||
{ |
||||
// we only patch code on Intel
|
||||
} |
||||
*/ |
||||
#endif // !id386
|
@ -0,0 +1,852 @@
@@ -0,0 +1,852 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 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_rast.c
|
||||
|
||||
#include <assert.h> |
||||
|
||||
#include "r_local.h" |
||||
|
||||
#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
|
||||
|
||||
|
||||
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[1280]; |
||||
int intsintable[1280]; |
||||
int blanktable[1280]; // PGM
|
||||
|
||||
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; |
||||
int r_skyframe; |
||||
|
||||
msurface_t *r_skyfaces; |
||||
mplane_t r_skyplanes[6]; |
||||
mtexinfo_t r_skytexinfo[6]; |
||||
mvertex_t *r_skyverts; |
||||
medge_t *r_skyedges; |
||||
int *r_skysurfedges; |
||||
|
||||
// I just copied this data from a box map...
|
||||
int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128}; |
||||
|
||||
int box_surfedges[24] = { 1,2,3,4, -1,5,6,7, 8,9,-6,10, -2,-7,-9,11, |
||||
12,-3,-11,-8, -12,-10,-5,-4}; |
||||
int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4}; |
||||
|
||||
int box_faces[6] = {0,0,2,2,2,0}; |
||||
|
||||
vec3_t box_vecs[6][2] = { |
||||
{ {0,-1,0}, {-1,0,0} }, |
||||
{ {0,1,0}, {0,0,-1} }, |
||||
{ {0,-1,0}, {1,0,0} }, |
||||
{ {1,0,0}, {0,0,-1} }, |
||||
{ {0,-1,0}, {0,0,-1} }, |
||||
{ {-1,0,0}, {0,0,-1} } |
||||
}; |
||||
|
||||
float box_verts[8][3] = { |
||||
{-1,-1,-1}, |
||||
{-1,1,-1}, |
||||
{1,1,-1}, |
||||
{1,-1,-1}, |
||||
{-1,-1,1}, |
||||
{-1,1,1}, |
||||
{1,-1,1}, |
||||
{1,1,1} |
||||
}; |
||||
|
||||
// down, west, up, north, east, south
|
||||
// {"rt", "bk", "lf", "ft", "up", "dn"};
|
||||
#if 0 |
||||
/*
|
||||
================ |
||||
R_InitSkyBox |
||||
|
||||
================ |
||||
*/ |
||||
void R_InitSkyBox (void) |
||||
{ |
||||
int i; |
||||
extern model_t *loadmodel; |
||||
|
||||
r_skyfaces = loadmodel->surfaces + loadmodel->numsurfaces; |
||||
loadmodel->numsurfaces += 6; |
||||
r_skyverts = loadmodel->vertexes + loadmodel->numvertexes; |
||||
loadmodel->numvertexes += 8; |
||||
r_skyedges = loadmodel->edges + loadmodel->numedges; |
||||
loadmodel->numedges += 12; |
||||
r_skysurfedges = loadmodel->surfedges + loadmodel->numsurfedges; |
||||
loadmodel->numsurfedges += 24; |
||||
if (loadmodel->numsurfaces > MAX_MAP_FACES |
||||
|| loadmodel->numvertexes > MAX_MAP_VERTS |
||||
|| loadmodel->numedges > MAX_MAP_EDGES) |
||||
ri.Sys_Error (ERR_DROP, "InitSkyBox: map overflow"); |
||||
|
||||
memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces)); |
||||
for (i=0 ; i<6 ; i++) |
||||
{ |
||||
r_skyplanes[i].normal[skybox_planes[i*2]] = 1; |
||||
r_skyplanes[i].dist = skybox_planes[i*2+1]; |
||||
|
||||
VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]); |
||||
VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]); |
||||
|
||||
r_skyfaces[i].plane = &r_skyplanes[i]; |
||||
r_skyfaces[i].numedges = 4; |
||||
r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX; |
||||
r_skyfaces[i].firstedge = loadmodel->numsurfedges-24+i*4; |
||||
r_skyfaces[i].texinfo = &r_skytexinfo[i]; |
||||
r_skyfaces[i].texturemins[0] = -128; |
||||
r_skyfaces[i].texturemins[1] = -128; |
||||
r_skyfaces[i].extents[0] = 256; |
||||
r_skyfaces[i].extents[1] = 256; |
||||
} |
||||
|
||||
for (i=0 ; i<24 ; i++) |
||||
if (box_surfedges[i] > 0) |
||||
r_skysurfedges[i] = loadmodel->numedges-13 + box_surfedges[i]; |
||||
else |
||||
r_skysurfedges[i] = - (loadmodel->numedges-13 + -box_surfedges[i]); |
||||
|
||||
for(i=0 ; i<12 ; i++) |
||||
{ |
||||
r_skyedges[i].v[0] = loadmodel->numvertexes-9+box_edges[i*2+0]; |
||||
r_skyedges[i].v[1] = loadmodel->numvertexes-9+box_edges[i*2+1]; |
||||
r_skyedges[i].cachededgeoffset = 0; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
================ |
||||
R_EmitSkyBox |
||||
================ |
||||
*/ |
||||
void R_EmitSkyBox (void) |
||||
{ |
||||
int i, j; |
||||
int oldkey; |
||||
|
||||
if (insubmodel) |
||||
return; // submodels should never have skies
|
||||
if (r_skyframe == r_framecount) |
||||
return; // already set this frame
|
||||
|
||||
r_skyframe = r_framecount; |
||||
|
||||
// set the eight fake vertexes
|
||||
for (i=0 ; i<8 ; i++) |
||||
for (j=0 ; j<3 ; j++) |
||||
r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128; |
||||
|
||||
// set the six fake planes
|
||||
for (i=0 ; i<6 ; i++) |
||||
if (skybox_planes[i*2+1] > 0) |
||||
r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128; |
||||
else |
||||
r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128; |
||||
|
||||
// fix texture offseets
|
||||
for (i=0 ; i<6 ; i++) |
||||
{ |
||||
r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]); |
||||
r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]); |
||||
} |
||||
|
||||
// emit the six faces
|
||||
oldkey = r_currentkey; |
||||
r_currentkey = 0x7ffffff0; |
||||
for (i=0 ; i<6 ; i++) |
||||
{ |
||||
R_RenderFace (r_skyfaces + i, 15); |
||||
} |
||||
r_currentkey = oldkey; // bsp sorting order
|
||||
} |
||||
|
||||
#endif |
||||
#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 < 0) |
||||
u0 = 0; |
||||
if (u0 > gpGlobals->width) |
||||
u0 = gpGlobals->width; |
||||
|
||||
scale = yscale * lzi0; |
||||
v0 = (ycenter - scale*transformed[1]); |
||||
if (v0 < 0) |
||||
v0 = 0; |
||||
if (v0 > gpGlobals->height) |
||||
v0 = gpGlobals->height; |
||||
|
||||
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 < 0) |
||||
r_u1 = 0; |
||||
if (r_u1 > gpGlobals->width) |
||||
r_u1 = gpGlobals->width; |
||||
|
||||
scale = yscale * r_lzi1; |
||||
r_v1 = (ycenter - scale*transformed[1]); |
||||
if (r_v1 < 0) |
||||
r_v1 = 0; |
||||
if (r_v1 > gpGlobals->height) |
||||
r_v1 = gpGlobals->height; |
||||
|
||||
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; |
||||
|
||||
// translucent surfaces are not drawn by the edge renderer
|
||||
/* if (fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
|
||||
{ |
||||
fa->nextalphasurface = r_alpha_surfaces; |
||||
r_alpha_surfaces = fa; |
||||
return; |
||||
}*/ |
||||
|
||||
// sky surfaces encountered in the world will cause the
|
||||
// environment box surfaces to be emited
|
||||
/* if ( fa->texinfo->flags & SURF_SKY )
|
||||
{ |
||||
R_EmitSkyBox (); |
||||
return; |
||||
}*/ |
||||
|
||||
// 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 = RI.currentmodel->edges; |
||||
r_lastvertvalid = false; |
||||
|
||||
for (i=0 ; i<fa->numedges ; i++) |
||||
{ |
||||
lindex = RI.currentmodel->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->msurf = fa; |
||||
surface_p->nearzi = r_nearzi; |
||||
surface_p->flags = fa->flags; |
||||
//surface_p->insubmodel = insubmodel;
|
||||
surface_p->spanstate = 0; |
||||
surface_p->entity = RI.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; |
||||
|
||||
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; |
||||
|
||||
/*if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
|
||||
{ |
||||
psurf->nextalphasurface = r_alpha_surfaces; |
||||
r_alpha_surfaces = psurf; |
||||
return; |
||||
}*/ |
||||
|
||||
// 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->msurf = psurf; |
||||
surface_p->nearzi = r_nearzi; |
||||
surface_p->flags = psurf->flags; |
||||
surface_p->insubmodel = true; |
||||
surface_p->spanstate = 0; |
||||
surface_p->entity = RI.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; |
||||
|
||||
surface_p++; |
||||
} |
||||
|
@ -0,0 +1,593 @@
@@ -0,0 +1,593 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 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. |
||||
|
||||
*/ |
||||
// d_scan.c
|
||||
//
|
||||
// Portable C scan-level rasterization code, all pixel depths.
|
||||
|
||||
#include "r_local.h" |
||||
|
||||
unsigned char *r_turb_pbase, *r_turb_pdest; |
||||
fixed16_t r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep; |
||||
int *r_turb_turb; |
||||
int r_turb_spancount; |
||||
|
||||
void D_DrawTurbulent8Span (void); |
||||
|
||||
|
||||
/*
|
||||
============= |
||||
D_WarpScreen |
||||
|
||||
this performs a slight compression of the screen at the same time as |
||||
the sine warp, to keep the edges from wrapping |
||||
============= |
||||
*/ |
||||
void D_WarpScreen (void) |
||||
{ |
||||
#if 0 |
||||
int w, h; |
||||
int u,v, u2, v2; |
||||
byte *dest; |
||||
int *turb; |
||||
int *col; |
||||
byte **row; |
||||
|
||||
static int cached_width, cached_height; |
||||
static byte *rowptr[1200+AMP2*2]; |
||||
static int column[1600+AMP2*2]; |
||||
|
||||
//
|
||||
// these are constant over resolutions, and can be saved
|
||||
//
|
||||
w = r_newrefdef.width; |
||||
h = r_newrefdef.height; |
||||
if (w != cached_width || h != cached_height) |
||||
{ |
||||
cached_width = w; |
||||
cached_height = h; |
||||
for (v=0 ; v<h+AMP2*2 ; v++) |
||||
{ |
||||
v2 = (int)((float)v/(h + AMP2 * 2) * r_refdef.vrect.height); |
||||
rowptr[v] = r_warpbuffer + (WARP_WIDTH * v2); |
||||
} |
||||
|
||||
for (u=0 ; u<w+AMP2*2 ; u++) |
||||
{ |
||||
u2 = (int)((float)u/(w + AMP2 * 2) * r_refdef.vrect.width); |
||||
column[u] = u2; |
||||
} |
||||
} |
||||
|
||||
turb = intsintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1)); |
||||
dest = vid.buffer + r_newrefdef.y * vid.rowbytes + r_newrefdef.x; |
||||
|
||||
for (v=0 ; v<h ; v++, dest += vid.rowbytes) |
||||
{ |
||||
col = &column[turb[v]]; |
||||
row = &rowptr[v]; |
||||
for (u=0 ; u<w ; u+=4) |
||||
{ |
||||
dest[u+0] = row[turb[u+0]][col[u+0]]; |
||||
dest[u+1] = row[turb[u+1]][col[u+1]]; |
||||
dest[u+2] = row[turb[u+2]][col[u+2]]; |
||||
dest[u+3] = row[turb[u+3]][col[u+3]]; |
||||
} |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
|
||||
#if !id386 |
||||
|
||||
/*
|
||||
============= |
||||
D_DrawTurbulent8Span |
||||
============= |
||||
*/ |
||||
void D_DrawTurbulent8Span (void) |
||||
{ |
||||
int sturb, tturb; |
||||
|
||||
do |
||||
{ |
||||
sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63; |
||||
tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63; |
||||
*r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb); |
||||
r_turb_s += r_turb_sstep; |
||||
r_turb_t += r_turb_tstep; |
||||
} while (--r_turb_spancount > 0); |
||||
} |
||||
|
||||
#endif // !id386
|
||||
|
||||
|
||||
/*
|
||||
============= |
||||
Turbulent8 |
||||
============= |
||||
*/ |
||||
void Turbulent8 (espan_t *pspan) |
||||
{ |
||||
int count; |
||||
fixed16_t snext, tnext; |
||||
float sdivz, tdivz, zi, z, du, dv, spancountminus1; |
||||
float sdivz16stepu, tdivz16stepu, zi16stepu; |
||||
|
||||
r_turb_turb = sintable + ((int)(gpGlobals->time*SPEED)&(CYCLE-1)); |
||||
|
||||
r_turb_sstep = 0; // keep compiler happy
|
||||
r_turb_tstep = 0; // ditto
|
||||
|
||||
r_turb_pbase = (unsigned char *)cacheblock; |
||||
|
||||
sdivz16stepu = d_sdivzstepu * 16; |
||||
tdivz16stepu = d_tdivzstepu * 16; |
||||
zi16stepu = d_zistepu * 16; |
||||
|
||||
do |
||||
{ |
||||
r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer + |
||||
(r_screenwidth * pspan->v) + pspan->u); |
||||
|
||||
count = pspan->count; |
||||
|
||||
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
|
||||
du = (float)pspan->u; |
||||
dv = (float)pspan->v; |
||||
|
||||
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; |
||||
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; |
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; |
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
r_turb_s = (int)(sdivz * z) + sadjust; |
||||
if (r_turb_s > bbextents) |
||||
r_turb_s = bbextents; |
||||
else if (r_turb_s < 0) |
||||
r_turb_s = 0; |
||||
|
||||
r_turb_t = (int)(tdivz * z) + tadjust; |
||||
if (r_turb_t > bbextentt) |
||||
r_turb_t = bbextentt; |
||||
else if (r_turb_t < 0) |
||||
r_turb_t = 0; |
||||
|
||||
do |
||||
{ |
||||
// calculate s and t at the far end of the span
|
||||
if (count >= 16) |
||||
r_turb_spancount = 16; |
||||
else |
||||
r_turb_spancount = count; |
||||
|
||||
count -= r_turb_spancount; |
||||
|
||||
if (count) |
||||
{ |
||||
// calculate s/z, t/z, zi->fixed s and t at far end of span,
|
||||
// calculate s and t steps across span by shifting
|
||||
sdivz += sdivz16stepu; |
||||
tdivz += tdivz16stepu; |
||||
zi += zi16stepu; |
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
snext = (int)(sdivz * z) + sadjust; |
||||
if (snext > bbextents) |
||||
snext = bbextents; |
||||
else if (snext < 16) |
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust; |
||||
if (tnext > bbextentt) |
||||
tnext = bbextentt; |
||||
else if (tnext < 16) |
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
r_turb_sstep = (snext - r_turb_s) >> 4; |
||||
r_turb_tstep = (tnext - r_turb_t) >> 4; |
||||
} |
||||
else |
||||
{ |
||||
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
|
||||
// can't step off polygon), clamp, calculate s and t steps across
|
||||
// span by division, biasing steps low so we don't run off the
|
||||
// texture
|
||||
spancountminus1 = (float)(r_turb_spancount - 1); |
||||
sdivz += d_sdivzstepu * spancountminus1; |
||||
tdivz += d_tdivzstepu * spancountminus1; |
||||
zi += d_zistepu * spancountminus1; |
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
snext = (int)(sdivz * z) + sadjust; |
||||
if (snext > bbextents) |
||||
snext = bbextents; |
||||
else if (snext < 16) |
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust; |
||||
if (tnext > bbextentt) |
||||
tnext = bbextentt; |
||||
else if (tnext < 16) |
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
if (r_turb_spancount > 1) |
||||
{ |
||||
r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1); |
||||
r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1); |
||||
} |
||||
} |
||||
|
||||
r_turb_s = r_turb_s & ((CYCLE<<16)-1); |
||||
r_turb_t = r_turb_t & ((CYCLE<<16)-1); |
||||
|
||||
D_DrawTurbulent8Span (); |
||||
|
||||
r_turb_s = snext; |
||||
r_turb_t = tnext; |
||||
|
||||
} while (count > 0); |
||||
|
||||
} while ((pspan = pspan->pnext) != NULL); |
||||
} |
||||
|
||||
//====================
|
||||
//PGM
|
||||
/*
|
||||
============= |
||||
NonTurbulent8 - this is for drawing scrolling textures. they're warping water textures |
||||
but the turbulence is automatically 0. |
||||
============= |
||||
*/ |
||||
void NonTurbulent8 (espan_t *pspan) |
||||
{ |
||||
int count; |
||||
fixed16_t snext, tnext; |
||||
float sdivz, tdivz, zi, z, du, dv, spancountminus1; |
||||
float sdivz16stepu, tdivz16stepu, zi16stepu; |
||||
|
||||
// r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
|
||||
r_turb_turb = blanktable; |
||||
|
||||
r_turb_sstep = 0; // keep compiler happy
|
||||
r_turb_tstep = 0; // ditto
|
||||
|
||||
r_turb_pbase = (unsigned char *)cacheblock; |
||||
|
||||
sdivz16stepu = d_sdivzstepu * 16; |
||||
tdivz16stepu = d_tdivzstepu * 16; |
||||
zi16stepu = d_zistepu * 16; |
||||
|
||||
do |
||||
{ |
||||
r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer + |
||||
(r_screenwidth * pspan->v) + pspan->u); |
||||
|
||||
count = pspan->count; |
||||
|
||||
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
|
||||
du = (float)pspan->u; |
||||
dv = (float)pspan->v; |
||||
|
||||
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; |
||||
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; |
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; |
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
r_turb_s = (int)(sdivz * z) + sadjust; |
||||
if (r_turb_s > bbextents) |
||||
r_turb_s = bbextents; |
||||
else if (r_turb_s < 0) |
||||
r_turb_s = 0; |
||||
|
||||
r_turb_t = (int)(tdivz * z) + tadjust; |
||||
if (r_turb_t > bbextentt) |
||||
r_turb_t = bbextentt; |
||||
else if (r_turb_t < 0) |
||||
r_turb_t = 0; |
||||
|
||||
do |
||||
{ |
||||
// calculate s and t at the far end of the span
|
||||
if (count >= 16) |
||||
r_turb_spancount = 16; |
||||
else |
||||
r_turb_spancount = count; |
||||
|
||||
count -= r_turb_spancount; |
||||
|
||||
if (count) |
||||
{ |
||||
// calculate s/z, t/z, zi->fixed s and t at far end of span,
|
||||
// calculate s and t steps across span by shifting
|
||||
sdivz += sdivz16stepu; |
||||
tdivz += tdivz16stepu; |
||||
zi += zi16stepu; |
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
snext = (int)(sdivz * z) + sadjust; |
||||
if (snext > bbextents) |
||||
snext = bbextents; |
||||
else if (snext < 16) |
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust; |
||||
if (tnext > bbextentt) |
||||
tnext = bbextentt; |
||||
else if (tnext < 16) |
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
r_turb_sstep = (snext - r_turb_s) >> 4; |
||||
r_turb_tstep = (tnext - r_turb_t) >> 4; |
||||
} |
||||
else |
||||
{ |
||||
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
|
||||
// can't step off polygon), clamp, calculate s and t steps across
|
||||
// span by division, biasing steps low so we don't run off the
|
||||
// texture
|
||||
spancountminus1 = (float)(r_turb_spancount - 1); |
||||
sdivz += d_sdivzstepu * spancountminus1; |
||||
tdivz += d_tdivzstepu * spancountminus1; |
||||
zi += d_zistepu * spancountminus1; |
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
snext = (int)(sdivz * z) + sadjust; |
||||
if (snext > bbextents) |
||||
snext = bbextents; |
||||
else if (snext < 16) |
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust; |
||||
if (tnext > bbextentt) |
||||
tnext = bbextentt; |
||||
else if (tnext < 16) |
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
if (r_turb_spancount > 1) |
||||
{ |
||||
r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1); |
||||
r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1); |
||||
} |
||||
} |
||||
|
||||
r_turb_s = r_turb_s & ((CYCLE<<16)-1); |
||||
r_turb_t = r_turb_t & ((CYCLE<<16)-1); |
||||
|
||||
D_DrawTurbulent8Span (); |
||||
|
||||
r_turb_s = snext; |
||||
r_turb_t = tnext; |
||||
|
||||
} while (count > 0); |
||||
|
||||
} while ((pspan = pspan->pnext) != NULL); |
||||
} |
||||
//PGM
|
||||
//====================
|
||||
|
||||
|
||||
#if !id386 |
||||
|
||||
/*
|
||||
============= |
||||
D_DrawSpans16 |
||||
|
||||
FIXME: actually make this subdivide by 16 instead of 8!!! |
||||
============= |
||||
*/ |
||||
void D_DrawSpans16 (espan_t *pspan) |
||||
{ |
||||
int count, spancount; |
||||
unsigned char *pbase, *pdest; |
||||
fixed16_t s, t, snext, tnext, sstep, tstep; |
||||
float sdivz, tdivz, zi, z, du, dv, spancountminus1; |
||||
float sdivz8stepu, tdivz8stepu, zi8stepu; |
||||
|
||||
sstep = 0; // keep compiler happy
|
||||
tstep = 0; // ditto
|
||||
|
||||
pbase = (unsigned char *)cacheblock; |
||||
|
||||
sdivz8stepu = d_sdivzstepu * 8; |
||||
tdivz8stepu = d_tdivzstepu * 8; |
||||
zi8stepu = d_zistepu * 8; |
||||
|
||||
do |
||||
{ |
||||
pdest = (unsigned char *)((byte *)d_viewbuffer + |
||||
(r_screenwidth * pspan->v) + pspan->u); |
||||
|
||||
count = pspan->count; |
||||
|
||||
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
|
||||
du = (float)pspan->u; |
||||
dv = (float)pspan->v; |
||||
|
||||
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; |
||||
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; |
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; |
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
s = (int)(sdivz * z) + sadjust; |
||||
if (s > bbextents) |
||||
s = bbextents; |
||||
else if (s < 0) |
||||
s = 0; |
||||
|
||||
t = (int)(tdivz * z) + tadjust; |
||||
if (t > bbextentt) |
||||
t = bbextentt; |
||||
else if (t < 0) |
||||
t = 0; |
||||
|
||||
do |
||||
{ |
||||
// calculate s and t at the far end of the span
|
||||
if (count >= 8) |
||||
spancount = 8; |
||||
else |
||||
spancount = count; |
||||
|
||||
count -= spancount; |
||||
|
||||
if (count) |
||||
{ |
||||
// calculate s/z, t/z, zi->fixed s and t at far end of span,
|
||||
// calculate s and t steps across span by shifting
|
||||
sdivz += sdivz8stepu; |
||||
tdivz += tdivz8stepu; |
||||
zi += zi8stepu; |
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
snext = (int)(sdivz * z) + sadjust; |
||||
if (snext > bbextents) |
||||
snext = bbextents; |
||||
else if (snext < 8) |
||||
snext = 8; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust; |
||||
if (tnext > bbextentt) |
||||
tnext = bbextentt; |
||||
else if (tnext < 8) |
||||
tnext = 8; // guard against round-off error on <0 steps
|
||||
|
||||
sstep = (snext - s) >> 3; |
||||
tstep = (tnext - t) >> 3; |
||||
} |
||||
else |
||||
{ |
||||
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
|
||||
// can't step off polygon), clamp, calculate s and t steps across
|
||||
// span by division, biasing steps low so we don't run off the
|
||||
// texture
|
||||
spancountminus1 = (float)(spancount - 1); |
||||
sdivz += d_sdivzstepu * spancountminus1; |
||||
tdivz += d_tdivzstepu * spancountminus1; |
||||
zi += d_zistepu * spancountminus1; |
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
snext = (int)(sdivz * z) + sadjust; |
||||
if (snext > bbextents) |
||||
snext = bbextents; |
||||
else if (snext < 8) |
||||
snext = 8; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust; |
||||
if (tnext > bbextentt) |
||||
tnext = bbextentt; |
||||
else if (tnext < 8) |
||||
tnext = 8; // guard against round-off error on <0 steps
|
||||
|
||||
if (spancount > 1) |
||||
{ |
||||
sstep = (snext - s) / (spancount - 1); |
||||
tstep = (tnext - t) / (spancount - 1); |
||||
} |
||||
} |
||||
|
||||
do |
||||
{ |
||||
*pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth); |
||||
s += sstep; |
||||
t += tstep; |
||||
} while (--spancount > 0); |
||||
|
||||
s = snext; |
||||
t = tnext; |
||||
|
||||
} while (count > 0); |
||||
|
||||
} while ((pspan = pspan->pnext) != NULL); |
||||
} |
||||
|
||||
#endif |
||||
|
||||
|
||||
#if !id386 |
||||
|
||||
/*
|
||||
============= |
||||
D_DrawZSpans |
||||
============= |
||||
*/ |
||||
void D_DrawZSpans (espan_t *pspan) |
||||
{ |
||||
int count, doublecount, izistep; |
||||
int izi; |
||||
short *pdest; |
||||
unsigned ltemp; |
||||
float zi; |
||||
float du, dv; |
||||
|
||||
// FIXME: check for clamping/range problems
|
||||
// we count on FP exceptions being turned off to avoid range problems
|
||||
izistep = (int)(d_zistepu * 0x8000 * 0x10000); |
||||
|
||||
do |
||||
{ |
||||
pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; |
||||
|
||||
count = pspan->count; |
||||
|
||||
// calculate the initial 1/z
|
||||
du = (float)pspan->u; |
||||
dv = (float)pspan->v; |
||||
|
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; |
||||
// we count on FP exceptions being turned off to avoid range problems
|
||||
izi = (int)(zi * 0x8000 * 0x10000); |
||||
|
||||
if ((long)pdest & 0x02) |
||||
{ |
||||
*pdest++ = (short)(izi >> 16); |
||||
izi += izistep; |
||||
count--; |
||||
} |
||||
|
||||
if ((doublecount = count >> 1) > 0) |
||||
{ |
||||
do |
||||
{ |
||||
ltemp = izi >> 16; |
||||
izi += izistep; |
||||
ltemp |= izi & 0xFFFF0000; |
||||
izi += izistep; |
||||
*(int *)pdest = ltemp; |
||||
pdest += 2; |
||||
} while (--doublecount > 0); |
||||
} |
||||
|
||||
if (count & 1) |
||||
*pdest = (short)(izi >> 16); |
||||
|
||||
} while ((pspan = pspan->pnext) != NULL); |
||||
} |
||||
|
||||
#endif |
||||
|
@ -0,0 +1,753 @@
@@ -0,0 +1,753 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 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_surf.c: surface-related refresh code
|
||||
|
||||
#include "r_local.h" |
||||
|
||||
drawsurf_t r_drawsurf; |
||||
|
||||
int lightleft, sourcesstep, blocksize, sourcetstep; |
||||
int lightdelta, lightdeltastep; |
||||
int lightright, lightleftstep, lightrightstep, blockdivshift; |
||||
unsigned blockdivmask; |
||||
void *prowdestbase; |
||||
unsigned char *pbasesource; |
||||
int surfrowbytes; // used by ASM files
|
||||
unsigned *r_lightptr; |
||||
int r_stepback; |
||||
int r_lightwidth; |
||||
int r_numhblocks, r_numvblocks; |
||||
unsigned char *r_source, *r_sourcemax; |
||||
|
||||
void R_DrawSurfaceBlock8_mip0 (void); |
||||
void R_DrawSurfaceBlock8_mip1 (void); |
||||
void R_DrawSurfaceBlock8_mip2 (void); |
||||
void R_DrawSurfaceBlock8_mip3 (void); |
||||
|
||||
static void (*surfmiptable[4])(void) = { |
||||
R_DrawSurfaceBlock8_mip0, |
||||
R_DrawSurfaceBlock8_mip1, |
||||
R_DrawSurfaceBlock8_mip2, |
||||
R_DrawSurfaceBlock8_mip3 |
||||
}; |
||||
|
||||
void R_BuildLightMap (void); |
||||
extern unsigned blocklights[1024]; // allow some very large lightmaps
|
||||
|
||||
float surfscale; |
||||
qboolean r_cache_thrash; // set if surface cache is thrashing
|
||||
|
||||
int sc_size; |
||||
surfcache_t *sc_rover, *sc_base; |
||||
|
||||
static int rtable[MOD_FRAMES][MOD_FRAMES]; |
||||
|
||||
void R_InitRandomTable( void ) |
||||
{ |
||||
int tu, tv; |
||||
|
||||
// make random predictable
|
||||
gEngfuncs.COM_SetRandomSeed( 255 ); |
||||
|
||||
for( tu = 0; tu < MOD_FRAMES; tu++ ) |
||||
{ |
||||
for( tv = 0; tv < MOD_FRAMES; tv++ ) |
||||
{ |
||||
rtable[tu][tv] = gEngfuncs.COM_RandomLong( 0, 0x7FFF ); |
||||
} |
||||
} |
||||
|
||||
gEngfuncs.COM_SetRandomSeed( 0 ); |
||||
} |
||||
|
||||
/*
|
||||
=============== |
||||
R_TextureAnim |
||||
|
||||
Returns the proper texture for a given time and base texture, do not process random tiling |
||||
=============== |
||||
*/ |
||||
texture_t *R_TextureAnim( texture_t *b ) |
||||
{ |
||||
texture_t *base = b; |
||||
int count, reletive; |
||||
|
||||
if( RI.currententity->curstate.frame ) |
||||
{ |
||||
if( base->alternate_anims ) |
||||
base = base->alternate_anims; |
||||
} |
||||
|
||||
if( !base->anim_total ) |
||||
return base; |
||||
if( base->name[0] == '-' ) |
||||
{ |
||||
return b; // already tiled
|
||||
} |
||||
else |
||||
{ |
||||
int speed; |
||||
|
||||
// Quake1 textures uses 10 frames per second
|
||||
if( FBitSet( R_GetTexture( base->gl_texturenum )->flags, TF_QUAKEPAL )) |
||||
speed = 10; |
||||
else speed = 20; |
||||
|
||||
reletive = (int)(gpGlobals->time * speed) % base->anim_total; |
||||
} |
||||
|
||||
|
||||
count = 0; |
||||
|
||||
while( base->anim_min > reletive || base->anim_max <= reletive ) |
||||
{ |
||||
base = base->anim_next; |
||||
|
||||
if( !base || ++count > MOD_FRAMES ) |
||||
return b; |
||||
} |
||||
|
||||
return base; |
||||
} |
||||
|
||||
/*
|
||||
=============== |
||||
R_TextureAnimation |
||||
|
||||
Returns the proper texture for a given time and surface |
||||
=============== |
||||
*/ |
||||
texture_t *R_TextureAnimation( msurface_t *s ) |
||||
{ |
||||
texture_t *base = s->texinfo->texture; |
||||
int count, reletive; |
||||
|
||||
if( RI.currententity && RI.currententity->curstate.frame ) |
||||
{ |
||||
if( base->alternate_anims ) |
||||
base = base->alternate_anims; |
||||
} |
||||
|
||||
if( !base->anim_total ) |
||||
return base; |
||||
|
||||
if( base->name[0] == '-' ) |
||||
{ |
||||
int tx = (int)((s->texturemins[0] + (base->width << 16)) / base->width) % MOD_FRAMES; |
||||
int ty = (int)((s->texturemins[1] + (base->height << 16)) / base->height) % MOD_FRAMES; |
||||
|
||||
reletive = rtable[tx][ty] % base->anim_total; |
||||
} |
||||
else |
||||
{ |
||||
int speed; |
||||
|
||||
// Quake1 textures uses 10 frames per second
|
||||
if( FBitSet( R_GetTexture( base->gl_texturenum )->flags, TF_QUAKEPAL )) |
||||
speed = 10; |
||||
else speed = 20; |
||||
|
||||
reletive = (int)(gpGlobals->time * speed) % base->anim_total; |
||||
} |
||||
|
||||
count = 0; |
||||
|
||||
while( base->anim_min > reletive || base->anim_max <= reletive ) |
||||
{ |
||||
base = base->anim_next; |
||||
|
||||
if( !base || ++count > MOD_FRAMES ) |
||||
return s->texinfo->texture; |
||||
} |
||||
|
||||
return base; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
=============== |
||||
R_DrawSurface |
||||
=============== |
||||
*/ |
||||
void R_DrawSurface (void) |
||||
{ |
||||
unsigned char *basetptr; |
||||
int smax, tmax, twidth; |
||||
int u; |
||||
int soffset, basetoffset, texwidth; |
||||
int horzblockstep; |
||||
unsigned char *pcolumndest; |
||||
void (*pblockdrawer)(void); |
||||
image_t *mt; |
||||
|
||||
surfrowbytes = r_drawsurf.rowbytes; |
||||
|
||||
mt = r_drawsurf.image; |
||||
|
||||
r_source = mt->pixels[r_drawsurf.surfmip]; |
||||
|
||||
// the fractional light values should range from 0 to (VID_GRADES - 1) << 16
|
||||
// from a source range of 0 - 255
|
||||
|
||||
texwidth = mt->width >> r_drawsurf.surfmip; |
||||
|
||||
blocksize = 16 >> r_drawsurf.surfmip; |
||||
blockdivshift = 4 - r_drawsurf.surfmip; |
||||
blockdivmask = (1 << blockdivshift) - 1; |
||||
|
||||
r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1; |
||||
|
||||
r_numhblocks = r_drawsurf.surfwidth >> blockdivshift; |
||||
r_numvblocks = r_drawsurf.surfheight >> blockdivshift; |
||||
|
||||
//==============================
|
||||
|
||||
pblockdrawer = surfmiptable[r_drawsurf.surfmip]; |
||||
// TODO: only needs to be set when there is a display settings change
|
||||
horzblockstep = blocksize; |
||||
|
||||
smax = mt->width >> r_drawsurf.surfmip; |
||||
twidth = texwidth; |
||||
tmax = mt->height >> r_drawsurf.surfmip; |
||||
sourcetstep = texwidth; |
||||
r_stepback = tmax * twidth; |
||||
|
||||
r_sourcemax = r_source + (tmax * smax); |
||||
|
||||
soffset = r_drawsurf.surf->texturemins[0]; |
||||
basetoffset = r_drawsurf.surf->texturemins[1]; |
||||
|
||||
// << 16 components are to guarantee positive values for %
|
||||
soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax; |
||||
basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip) |
||||
+ (tmax << 16)) % tmax) * twidth)]; |
||||
|
||||
pcolumndest = r_drawsurf.surfdat; |
||||
|
||||
for (u=0 ; u<r_numhblocks; u++) |
||||
{ |
||||
r_lightptr = blocklights + u; |
||||
|
||||
prowdestbase = pcolumndest; |
||||
|
||||
pbasesource = basetptr + soffset; |
||||
|
||||
(*pblockdrawer)(); |
||||
|
||||
soffset = soffset + blocksize; |
||||
if (soffset >= smax) |
||||
soffset = 0; |
||||
|
||||
pcolumndest += horzblockstep; |
||||
} |
||||
} |
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
#if !id386 |
||||
|
||||
/*
|
||||
================ |
||||
R_DrawSurfaceBlock8_mip0 |
||||
================ |
||||
*/ |
||||
void R_DrawSurfaceBlock8_mip0 (void) |
||||
{ |
||||
int v, i, b, lightstep, lighttemp, light; |
||||
unsigned char pix, *psource, *prowdest; |
||||
|
||||
psource = pbasesource; |
||||
prowdest = prowdestbase; |
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++) |
||||
{ |
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0]; |
||||
lightright = r_lightptr[1]; |
||||
r_lightptr += r_lightwidth; |
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 4; |
||||
lightrightstep = (r_lightptr[1] - lightright) >> 4; |
||||
|
||||
for (i=0 ; i<16 ; i++) |
||||
{ |
||||
lighttemp = lightleft - lightright; |
||||
lightstep = lighttemp >> 4; |
||||
|
||||
light = lightright; |
||||
|
||||
for (b=15; b>=0; b--) |
||||
{ |
||||
pix = psource[b]; |
||||
prowdest[b] = ((unsigned char *)vid.colormap) |
||||
[(light & 0xFF00) + pix]; |
||||
light += lightstep; |
||||
} |
||||
|
||||
psource += sourcetstep; |
||||
lightright += lightrightstep; |
||||
lightleft += lightleftstep; |
||||
prowdest += surfrowbytes; |
||||
} |
||||
|
||||
if (psource >= r_sourcemax) |
||||
psource -= r_stepback; |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
================ |
||||
R_DrawSurfaceBlock8_mip1 |
||||
================ |
||||
*/ |
||||
void R_DrawSurfaceBlock8_mip1 (void) |
||||
{ |
||||
int v, i, b, lightstep, lighttemp, light; |
||||
unsigned char pix, *psource, *prowdest; |
||||
|
||||
psource = pbasesource; |
||||
prowdest = prowdestbase; |
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++) |
||||
{ |
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0]; |
||||
lightright = r_lightptr[1]; |
||||
r_lightptr += r_lightwidth; |
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 3; |
||||
lightrightstep = (r_lightptr[1] - lightright) >> 3; |
||||
|
||||
for (i=0 ; i<8 ; i++) |
||||
{ |
||||
lighttemp = lightleft - lightright; |
||||
lightstep = lighttemp >> 3; |
||||
|
||||
light = lightright; |
||||
|
||||
for (b=7; b>=0; b--) |
||||
{ |
||||
pix = psource[b]; |
||||
prowdest[b] = ((unsigned char *)vid.colormap) |
||||
[(light & 0xFF00) + pix]; |
||||
light += lightstep; |
||||
} |
||||
|
||||
psource += sourcetstep; |
||||
lightright += lightrightstep; |
||||
lightleft += lightleftstep; |
||||
prowdest += surfrowbytes; |
||||
} |
||||
|
||||
if (psource >= r_sourcemax) |
||||
psource -= r_stepback; |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
================ |
||||
R_DrawSurfaceBlock8_mip2 |
||||
================ |
||||
*/ |
||||
void R_DrawSurfaceBlock8_mip2 (void) |
||||
{ |
||||
int v, i, b, lightstep, lighttemp, light; |
||||
unsigned char pix, *psource, *prowdest; |
||||
|
||||
psource = pbasesource; |
||||
prowdest = prowdestbase; |
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++) |
||||
{ |
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0]; |
||||
lightright = r_lightptr[1]; |
||||
r_lightptr += r_lightwidth; |
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 2; |
||||
lightrightstep = (r_lightptr[1] - lightright) >> 2; |
||||
|
||||
for (i=0 ; i<4 ; i++) |
||||
{ |
||||
lighttemp = lightleft - lightright; |
||||
lightstep = lighttemp >> 2; |
||||
|
||||
light = lightright; |
||||
|
||||
for (b=3; b>=0; b--) |
||||
{ |
||||
pix = psource[b]; |
||||
prowdest[b] = ((unsigned char *)vid.colormap) |
||||
[(light & 0xFF00) + pix]; |
||||
light += lightstep; |
||||
} |
||||
|
||||
psource += sourcetstep; |
||||
lightright += lightrightstep; |
||||
lightleft += lightleftstep; |
||||
prowdest += surfrowbytes; |
||||
} |
||||
|
||||
if (psource >= r_sourcemax) |
||||
psource -= r_stepback; |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
================ |
||||
R_DrawSurfaceBlock8_mip3 |
||||
================ |
||||
*/ |
||||
void R_DrawSurfaceBlock8_mip3 (void) |
||||
{ |
||||
int v, i, b, lightstep, lighttemp, light; |
||||
unsigned char pix, *psource, *prowdest; |
||||
|
||||
psource = pbasesource; |
||||
prowdest = prowdestbase; |
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++) |
||||
{ |
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0]; |
||||
lightright = r_lightptr[1]; |
||||
r_lightptr += r_lightwidth; |
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 1; |
||||
lightrightstep = (r_lightptr[1] - lightright) >> 1; |
||||
|
||||
for (i=0 ; i<2 ; i++) |
||||
{ |
||||
lighttemp = lightleft - lightright; |
||||
lightstep = lighttemp >> 1; |
||||
|
||||
light = lightright; |
||||
|
||||
for (b=1; b>=0; b--) |
||||
{ |
||||
pix = psource[b]; |
||||
prowdest[b] = ((unsigned char *)vid.colormap) |
||||
[(light & 0xFF00) + pix]; |
||||
light += lightstep; |
||||
} |
||||
|
||||
psource += sourcetstep; |
||||
lightright += lightrightstep; |
||||
lightleft += lightleftstep; |
||||
prowdest += surfrowbytes; |
||||
} |
||||
|
||||
if (psource >= r_sourcemax) |
||||
psource -= r_stepback; |
||||
} |
||||
} |
||||
|
||||
#endif |
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
/*
|
||||
================ |
||||
R_InitCaches |
||||
|
||||
================ |
||||
*/ |
||||
void R_InitCaches (void) |
||||
{ |
||||
int size; |
||||
int pix; |
||||
|
||||
// calculate size to allocate
|
||||
if (sw_surfcacheoverride->value) |
||||
{ |
||||
size = sw_surfcacheoverride->value; |
||||
} |
||||
else |
||||
{ |
||||
size = SURFCACHE_SIZE_AT_320X240; |
||||
|
||||
pix = vid.width*vid.height; |
||||
if (pix > 64000) |
||||
size += (pix-64000)*3; |
||||
} |
||||
|
||||
// round up to page size
|
||||
size = (size + 8191) & ~8191; |
||||
|
||||
gEngfuncs.Con_Printf ("%ik surface cache\n", size/1024); |
||||
|
||||
sc_size = size; |
||||
sc_base = (surfcache_t *)malloc(size); |
||||
sc_rover = sc_base; |
||||
|
||||
sc_base->next = NULL; |
||||
sc_base->owner = NULL; |
||||
sc_base->size = sc_size; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
================== |
||||
D_FlushCaches |
||||
================== |
||||
*/ |
||||
void D_FlushCaches (void) |
||||
{ |
||||
surfcache_t *c; |
||||
|
||||
if (!sc_base) |
||||
return; |
||||
|
||||
for (c = sc_base ; c ; c = c->next) |
||||
{ |
||||
if (c->owner) |
||||
*c->owner = NULL; |
||||
} |
||||
|
||||
sc_rover = sc_base; |
||||
sc_base->next = NULL; |
||||
sc_base->owner = NULL; |
||||
sc_base->size = sc_size; |
||||
} |
||||
|
||||
/*
|
||||
================= |
||||
D_SCAlloc |
||||
================= |
||||
*/ |
||||
surfcache_t *D_SCAlloc (int width, int size) |
||||
{ |
||||
surfcache_t *new; |
||||
qboolean wrapped_this_time; |
||||
|
||||
if ((width < 0) || (width > 256)) |
||||
gEngfuncs.Host_Error ("D_SCAlloc: bad cache width %d\n", width); |
||||
|
||||
if ((size <= 0) || (size > 0x10000)) |
||||
gEngfuncs.Host_Error ("D_SCAlloc: bad cache size %d\n", size); |
||||
|
||||
size = (int)&((surfcache_t *)0)->data[size]; |
||||
size = (size + 3) & ~3; |
||||
if (size > sc_size) |
||||
gEngfuncs.Host_Error ("D_SCAlloc: %i > cache size of %i",size, sc_size); |
||||
|
||||
// if there is not size bytes after the rover, reset to the start
|
||||
wrapped_this_time = false; |
||||
|
||||
if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size) |
||||
{ |
||||
if (sc_rover) |
||||
{ |
||||
wrapped_this_time = true; |
||||
} |
||||
sc_rover = sc_base; |
||||
} |
||||
|
||||
// colect and free surfcache_t blocks until the rover block is large enough
|
||||
new = sc_rover; |
||||
if (sc_rover->owner) |
||||
*sc_rover->owner = NULL; |
||||
|
||||
while (new->size < size) |
||||
{ |
||||
// free another
|
||||
sc_rover = sc_rover->next; |
||||
if (!sc_rover) |
||||
gEngfuncs.Host_Error ("D_SCAlloc: hit the end of memory"); |
||||
if (sc_rover->owner) |
||||
*sc_rover->owner = NULL; |
||||
|
||||
new->size += sc_rover->size; |
||||
new->next = sc_rover->next; |
||||
} |
||||
|
||||
// create a fragment out of any leftovers
|
||||
if (new->size - size > 256) |
||||
{ |
||||
sc_rover = (surfcache_t *)( (byte *)new + size); |
||||
sc_rover->size = new->size - size; |
||||
sc_rover->next = new->next; |
||||
sc_rover->width = 0; |
||||
sc_rover->owner = NULL; |
||||
new->next = sc_rover; |
||||
new->size = size; |
||||
} |
||||
else |
||||
sc_rover = new->next; |
||||
|
||||
new->width = width; |
||||
// DEBUG
|
||||
if (width > 0) |
||||
new->height = (size - sizeof(*new) + sizeof(new->data)) / width; |
||||
|
||||
new->owner = NULL; // should be set properly after return
|
||||
|
||||
if (d_roverwrapped) |
||||
{ |
||||
if (wrapped_this_time || (sc_rover >= d_initial_rover)) |
||||
r_cache_thrash = true; |
||||
} |
||||
else if (wrapped_this_time) |
||||
{ |
||||
d_roverwrapped = true; |
||||
} |
||||
|
||||
return new; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
================= |
||||
D_SCDump |
||||
================= |
||||
*/ |
||||
void D_SCDump (void) |
||||
{ |
||||
surfcache_t *test; |
||||
|
||||
for (test = sc_base ; test ; test = test->next) |
||||
{ |
||||
if (test == sc_rover) |
||||
gEngfuncs.Con_Printf ("ROVER:\n"); |
||||
gEngfuncs.Con_Printf ("%p : %i bytes %i width\n",test, test->size, test->width); |
||||
} |
||||
} |
||||
|
||||
//=============================================================================
|
||||
|
||||
// if the num is not a power of 2, assume it will not repeat
|
||||
|
||||
int MaskForNum (int num) |
||||
{ |
||||
if (num==128) |
||||
return 127; |
||||
if (num==64) |
||||
return 63; |
||||
if (num==32) |
||||
return 31; |
||||
if (num==16) |
||||
return 15; |
||||
return 255; |
||||
} |
||||
|
||||
int D_log2 (int num) |
||||
{ |
||||
int c; |
||||
|
||||
c = 0; |
||||
|
||||
while (num>>=1) |
||||
c++; |
||||
return c; |
||||
} |
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
================ |
||||
D_CacheSurface |
||||
================ |
||||
*/ |
||||
surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel) |
||||
{ |
||||
surfcache_t *cache; |
||||
|
||||
//
|
||||
// if the surface is animating or flashing, flush the cache
|
||||
//
|
||||
r_drawsurf.image = R_GetTexture(R_TextureAnimation (surface->texinfo->texture->gl_texturenum)); |
||||
|
||||
/// todo: port this
|
||||
//r_drawsurf.lightadj[0] = r_newrefdef.lightstyles[surface->styles[0]].white*128;
|
||||
//r_drawsurf.lightadj[1] = r_newrefdef.lightstyles[surface->styles[1]].white*128;
|
||||
//r_drawsurf.lightadj[2] = r_newrefdef.lightstyles[surface->styles[2]].white*128;
|
||||
//r_drawsurf.lightadj[3] = r_newrefdef.lightstyles[surface->styles[3]].white*128;
|
||||
|
||||
//
|
||||
// see if the cache holds apropriate data
|
||||
//
|
||||
cache = CACHESPOT(surface)[miplevel]; |
||||
|
||||
|
||||
if (cache && !cache->dlight && surface->dlightframe != r_framecount |
||||
&& cache->image == r_drawsurf.image |
||||
&& cache->lightadj[0] == r_drawsurf.lightadj[0] |
||||
&& cache->lightadj[1] == r_drawsurf.lightadj[1] |
||||
&& cache->lightadj[2] == r_drawsurf.lightadj[2] |
||||
&& cache->lightadj[3] == r_drawsurf.lightadj[3] ) |
||||
return cache; |
||||
|
||||
//
|
||||
// determine shape of surface
|
||||
//
|
||||
surfscale = 1.0 / (1<<miplevel); |
||||
r_drawsurf.surfmip = miplevel; |
||||
r_drawsurf.surfwidth = surface->extents[0] >> miplevel; |
||||
r_drawsurf.rowbytes = r_drawsurf.surfwidth; |
||||
r_drawsurf.surfheight = surface->extents[1] >> miplevel; |
||||
|
||||
//
|
||||
// allocate memory if needed
|
||||
//
|
||||
if (!cache) // if a texture just animated, don't reallocate it
|
||||
{ |
||||
cache = D_SCAlloc (r_drawsurf.surfwidth, |
||||
r_drawsurf.surfwidth * r_drawsurf.surfheight); |
||||
CACHESPOT(surface)[miplevel] = cache; |
||||
cache->owner = &CACHESPOT(surface)[miplevel]; |
||||
cache->mipscale = surfscale; |
||||
} |
||||
|
||||
if (surface->dlightframe == r_framecount) |
||||
cache->dlight = 1; |
||||
else |
||||
cache->dlight = 0; |
||||
|
||||
r_drawsurf.surfdat = (pixel_t *)cache->data; |
||||
|
||||
cache->image = r_drawsurf.image; |
||||
cache->lightadj[0] = r_drawsurf.lightadj[0]; |
||||
cache->lightadj[1] = r_drawsurf.lightadj[1]; |
||||
cache->lightadj[2] = r_drawsurf.lightadj[2]; |
||||
cache->lightadj[3] = r_drawsurf.lightadj[3]; |
||||
|
||||
//
|
||||
// draw and light the surface texture
|
||||
//
|
||||
r_drawsurf.surf = surface; |
||||
|
||||
c_surf++; |
||||
|
||||
// calculate the lightings
|
||||
//R_BuildLightMap ();
|
||||
|
||||
// rasterize the surface into the cache
|
||||
R_DrawSurface (); |
||||
|
||||
return cache; |
||||
} |
||||
|
||||
|
Loading…
Reference in new issue