Xrasher/ref/soft/r_edge.c

1158 lines
25 KiB
C
Raw Normal View History

/*
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_edge.c
#include "r_local.h"
edge_t *auxedges;
edge_t *r_edges, *edge_p, *edge_max;
surf_t *surfaces, *surface_p, *surf_max;
// surfaces are generated in back to front order by the bsp, so if a surf
// pointer is greater than another one, it should be drawn in front
// surfaces[1] is the background, and is used as the active surface stack
edge_t *newedges[MAXHEIGHT];
edge_t *removeedges[MAXHEIGHT];
espan_t *span_p, *max_span_p;
int r_currentkey;
int current_iv;
int edge_head_u_shift20, edge_tail_u_shift20;
static void (*pdrawfunc)(void);
edge_t edge_head;
edge_t edge_tail;
edge_t edge_aftertail;
edge_t edge_sentinel;
2019-03-31 02:05:08 +07:00
static float fv;
static int miplevel;
float scale_for_mip;
// FIXME: should go away
extern void R_RotateBmodel (void);
extern void R_TransformFrustum (void);
void R_GenerateSpans (void);
void R_GenerateSpansBackward (void);
void R_LeadingEdge (edge_t *edge);
void R_LeadingEdgeBackwards (edge_t *edge);
void R_TrailingEdge (surf_t *surf, edge_t *edge);
/*
===============================================================================
EDGE SCANNING
===============================================================================
*/
/*
==============
R_BeginEdgeFrame
==============
*/
void R_BeginEdgeFrame (void)
{
int v;
edge_p = r_edges;
edge_max = &r_edges[r_numallocatededges];
surface_p = &surfaces[2]; // background is surface 1,
// surface 0 is a dummy
surfaces[1].spans = NULL; // no background spans yet
surfaces[1].flags = 0; // SURF_DRAWBACKGROUND;
// put the background behind everything in the world
if (sw_draworder.value)
{
pdrawfunc = R_GenerateSpansBackward;
surfaces[1].key = 0;
r_currentkey = 1;
}
else
{
pdrawfunc = R_GenerateSpans;
surfaces[1].key = 0x7FFfFFFF;
r_currentkey = 0;
}
// FIXME: set with memset
2019-03-23 05:39:45 +07:00
for (v=RI.vrect.y ; v<RI.vrectbottom ; v++)
{
newedges[v] = removeedges[v] = NULL;
}
}
/*
==============
R_InsertNewEdges
Adds the edges in the linked list edgestoadd, adding them to the edges in the
linked list edgelist. edgestoadd is assumed to be sorted on u, and non-empty (this is actually newedges[v]). edgelist is assumed to be sorted on u, with a
sentinel at the end (actually, this is the active edge table starting at
edge_head.next).
==============
*/
2024-01-27 20:18:17 +03:00
static void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
{
edge_t *next_edge;
do
{
next_edge = edgestoadd->next;
edgesearch:
if( !edgelist )
{
// gEngfuncs.Con_Printf("NULL edgelist!\n");
//return;
}
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
goto edgesearch;
// insert edgestoadd before edgelist
addedge:
edgestoadd->next = edgelist;
edgestoadd->prev = edgelist->prev;
edgelist->prev->next = edgestoadd;
edgelist->prev = edgestoadd;
} while ((edgestoadd = next_edge) != NULL);
}
/*
==============
R_RemoveEdges
==============
*/
2024-01-27 20:18:17 +03:00
static void R_RemoveEdges (edge_t *pedge)
{
do
{
pedge->next->prev = pedge->prev;
pedge->prev->next = pedge->next;
} while ((pedge = pedge->nextremove) != NULL);
}
/*
==============
R_StepActiveU
==============
*/
2024-01-27 20:18:17 +03:00
static void R_StepActiveU (edge_t *pedge)
{
edge_t *pnext_edge, *pwedge;
while (1)
{
nextedge:
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
goto nextedge;
pushback:
if (pedge == &edge_aftertail)
return;
// push it back to keep it sorted
pnext_edge = pedge->next;
// pull the edge out of the edge list
pedge->next->prev = pedge->prev;
pedge->prev->next = pedge->next;
// find out where the edge goes in the edge list
pwedge = pedge->prev->prev;
// if( !pwedge )
// return;
while (pwedge->u > pedge->u)
{
pwedge = pwedge->prev;
//if( !pwedge )
//return;
}
// put the edge back into the edge list
pedge->next = pwedge->next;
pedge->prev = pwedge;
pedge->next->prev = pedge;
pwedge->next = pedge;
pedge = pnext_edge;
if (pedge == &edge_tail)
return;
}
}
/*
==============
R_CleanupSpan
==============
*/
2024-01-27 20:18:17 +03:00
static void R_CleanupSpan (void)
{
surf_t *surf;
int iu;
espan_t *span;
// now that we've reached the right edge of the screen, we're done with any
// unfinished surfaces, so emit a span for whatever's on top
surf = surfaces[1].next;
iu = edge_tail_u_shift20;
if (iu > surf->last_u)
{
span = span_p++;
span->u = surf->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf->spans;
surf->spans = span;
}
// reset spanstate for all surfaces in the surface stack
do
{
surf->spanstate = 0;
surf = surf->next;
} while (surf != &surfaces[1]);
}
/*
==============
R_LeadingEdgeBackwards
==============
*/
void R_LeadingEdgeBackwards (edge_t *edge)
{
espan_t *span;
surf_t *surf, *surf2;
int iu;
// it's adding a new surface in, so find the correct place
surf = &surfaces[edge->surfs[1]];
// don't start a span if this is an inverted span, with the end
// edge preceding the start edge (that is, we've already seen the
// end edge)
if (++surf->spanstate == 1)
{
surf2 = surfaces[1].next;
if (surf->key > surf2->key)
goto newtop;
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (surf->insubmodel && (surf->key == surf2->key))
{
// must be two bmodels in the same leaf; don't care, because they'll
// never be farthest anyway
goto newtop;
}
continue_search:
do
{
surf2 = surf2->next;
} while (surf->key < surf2->key);
if (surf->key == surf2->key)
{
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (!surf->insubmodel)
goto continue_search;
// must be two bmodels in the same leaf; don't care which is really
// in front, because they'll never be farthest anyway
}
goto gotposition;
newtop:
// emit a span (obscures current top)
iu = edge->u >> 20;
if (iu > surf2->last_u)
{
span = span_p++;
span->u = surf2->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf2->spans;
surf2->spans = span;
}
// set last_u on the new span
surf->last_u = iu;
gotposition:
// insert before surf2
surf->next = surf2;
surf->prev = surf2->prev;
surf2->prev->next = surf;
surf2->prev = surf;
}
}
/*
==============
R_TrailingEdge
==============
*/
void R_TrailingEdge (surf_t *surf, edge_t *edge)
{
espan_t *span;
int iu;
// don't generate a span if this is an inverted span, with the end
// edge preceding the start edge (that is, we haven't seen the
// start edge yet)
if (--surf->spanstate == 0)
{
if (surf == surfaces[1].next)
{
// emit a span (current top going away)
iu = edge->u >> 20;
if (iu > surf->last_u)
{
span = span_p++;
span->u = surf->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf->spans;
surf->spans = span;
}
// set last_u on the surface below
surf->next->last_u = iu;
}
surf->prev->next = surf->next;
surf->next->prev = surf->prev;
}
}
/*
==============
R_LeadingEdge
==============
*/
void R_LeadingEdge (edge_t *edge)
{
espan_t *span;
surf_t *surf, *surf2;
int iu;
float fu, newzi, testzi, newzitop, newzibottom;
if (edge->surfs[1])
{
// it's adding a new surface in, so find the correct place
surf = &surfaces[edge->surfs[1]];
// don't start a span if this is an inverted span, with the end
// edge preceding the start edge (that is, we've already seen the
// end edge)
if (++surf->spanstate == 1)
{
surf2 = surfaces[1].next;
if (surf->key < surf2->key)
goto newtop;
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (surf->insubmodel && (surf->key == surf2->key))
{
// must be two bmodels in the same leaf; sort on 1/z
2019-10-10 06:23:57 +03:00
fu = (float)(edge->u - 0xFFFFF) * (1.0f / 0x100000);
newzi = surf->d_ziorigin + fv*surf->d_zistepv +
fu*surf->d_zistepu;
2019-10-10 06:23:57 +03:00
newzibottom = newzi * 0.99f;
testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
fu*surf2->d_zistepu;
if (newzibottom >= testzi)
{
goto newtop;
}
2019-10-10 06:23:57 +03:00
newzitop = newzi * 1.01f;
if (newzitop >= testzi)
{
if (surf->d_zistepu >= surf2->d_zistepu)
{
goto newtop;
}
}
}
continue_search:
do
{
surf2 = surf2->next;
} while (surf->key > surf2->key);
if (surf->key == surf2->key)
{
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (!surf->insubmodel)
goto continue_search;
// must be two bmodels in the same leaf; sort on 1/z
2019-10-10 06:23:57 +03:00
fu = (float)(edge->u - 0xFFFFF) * (1.0f / 0x100000);
newzi = surf->d_ziorigin + fv*surf->d_zistepv +
fu*surf->d_zistepu;
2019-10-10 06:23:57 +03:00
newzibottom = newzi * 0.99f;
testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
fu*surf2->d_zistepu;
if (newzibottom >= testzi)
{
goto gotposition;
}
2019-10-10 06:23:57 +03:00
newzitop = newzi * 1.01f;
if (newzitop >= testzi)
{
if (surf->d_zistepu >= surf2->d_zistepu)
{
goto gotposition;
}
}
goto continue_search;
}
goto gotposition;
newtop:
// emit a span (obscures current top)
iu = edge->u >> 20;
if (iu > surf2->last_u)
{
span = span_p++;
span->u = surf2->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf2->spans;
surf2->spans = span;
}
// set last_u on the new span
surf->last_u = iu;
gotposition:
// insert before surf2
surf->next = surf2;
surf->prev = surf2->prev;
surf2->prev->next = surf;
surf2->prev = surf;
}
}
}
/*
==============
R_GenerateSpans
==============
*/
void R_GenerateSpans (void)
{
edge_t *edge;
surf_t *surf;
// clear active surfaces to just the background surface
surfaces[1].next = surfaces[1].prev = &surfaces[1];
surfaces[1].last_u = edge_head_u_shift20;
// generate spans
for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
{
if (edge->surfs[0])
{
// it has a left surface, so a surface is going away for this span
surf = &surfaces[edge->surfs[0]];
R_TrailingEdge (surf, edge);
if (!edge->surfs[1])
continue;
}
R_LeadingEdge (edge);
}
R_CleanupSpan ();
}
/*
==============
R_GenerateSpansBackward
==============
*/
void R_GenerateSpansBackward (void)
{
edge_t *edge;
// clear active surfaces to just the background surface
surfaces[1].next = surfaces[1].prev = &surfaces[1];
surfaces[1].last_u = edge_head_u_shift20;
// generate spans
for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
{
if (edge->surfs[0])
R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
if (edge->surfs[1])
R_LeadingEdgeBackwards (edge);
}
R_CleanupSpan ();
}
/*
==============
R_ScanEdges
Input:
newedges[] array
this has links to edges, which have links to surfaces
Output:
Each surface has a linked list of its visible spans
==============
*/
void R_ScanEdges (void)
{
int iv, bottom;
byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
espan_t *basespan_p;
surf_t *s;
basespan_p = (espan_t *)
((uintptr_t)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
2019-03-23 05:39:45 +07:00
max_span_p = &basespan_p[MAXSPANS - RI.vrect.width];
span_p = basespan_p;
// clear active edges to just the background edges around the whole screen
// FIXME: most of this only needs to be set up once
2019-03-23 05:39:45 +07:00
edge_head.u = RI.vrect.x << 20;
edge_head_u_shift20 = edge_head.u >> 20;
edge_head.u_step = 0;
edge_head.prev = NULL;
edge_head.next = &edge_tail;
edge_head.surfs[0] = 0;
edge_head.surfs[1] = 1;
2019-03-23 05:39:45 +07:00
edge_tail.u =(RI.vrectright << 20) + 0xFFFFF; // (r_refdef.vrectright << 20) + 0xFFFFF;
edge_tail_u_shift20 = edge_tail.u >> 20;
edge_tail.u_step = 0;
edge_tail.prev = &edge_head;
edge_tail.next = &edge_aftertail;
edge_tail.surfs[0] = 1;
edge_tail.surfs[1] = 0;
edge_aftertail.u = -1; // force a move
edge_aftertail.u_step = 0;
edge_aftertail.next = &edge_sentinel;
edge_aftertail.prev = &edge_tail;
// FIXME: do we need this now that we clamp x in r_draw.c?
edge_sentinel.u = 2000 << 20; // make sure nothing sorts past this
edge_sentinel.prev = &edge_aftertail;
//
// process all scan lines
//
2019-03-23 05:39:45 +07:00
bottom = RI.vrectbottom - 1;
for (iv=0 ; iv<bottom ; iv++)
{
current_iv = iv;
fv = (float)iv;
// mark that the head (background start) span is pre-included
surfaces[1].spanstate = 1;
if (newedges[iv])
{
R_InsertNewEdges (newedges[iv], edge_head.next);
}
(*pdrawfunc) ();
// flush the span list if we can't be sure we have enough spans left for
// the next scan
if (span_p > max_span_p)
{
D_DrawSurfaces ();
// clear the surface span pointers
for (s = &surfaces[1] ; s<surface_p ; s++)
s->spans = NULL;
span_p = basespan_p;
}
if (removeedges[iv])
R_RemoveEdges (removeedges[iv]);
if (edge_head.next != &edge_tail)
R_StepActiveU (edge_head.next);
}
// do the last scan (no need to step or sort or remove on the last scan)
current_iv = iv;
fv = (float)iv;
// mark that the head (background start) span is pre-included
surfaces[1].spanstate = 1;
if (newedges[iv])
R_InsertNewEdges (newedges[iv], edge_head.next);
(*pdrawfunc) ();
// draw whatever's left in the span list
D_DrawSurfaces ();
}
/*
=========================================================================
SURFACE FILLING
=========================================================================
*/
msurface_t *pface;
surfcache_t *pcurrentcache;
vec3_t transformed_modelorg;
vec3_t world_transformed_modelorg;
vec3_t local_modelorg;
/*
=============
D_MipLevelForScale
=============
*/
2024-01-27 20:18:17 +03:00
static int D_MipLevelForScale (float scale)
{
int lmiplevel;
if (scale >= d_scalemip[0] )
lmiplevel = 0;
else if (scale >= d_scalemip[1] )
lmiplevel = 1;
else if (scale >= d_scalemip[2] )
lmiplevel = 2;
else
lmiplevel = 3;
if (lmiplevel < d_minmip)
lmiplevel = d_minmip;
return lmiplevel;
}
/*
==============
D_FlatFillSurface
Simple single color fill with no texture mapping
==============
*/
2024-01-27 20:18:17 +03:00
static void D_FlatFillSurface (surf_t *surf, int color)
{
espan_t *span;
pixel_t *pdest;
int u, u2;
for (span=surf->spans ; span ; span=span->pnext)
{
pdest = d_viewbuffer + r_screenwidth*span->v;
u = span->u;
u2 = span->u + span->count - 1;
for ( ; u <= u2 ; u++)
pdest[u] = color;
}
}
/*
==============
D_CalcGradients
==============
*/
2024-01-27 20:18:17 +03:00
static void D_CalcGradients (msurface_t *pface)
{
mplane_t *pplane;
float mipscale;
vec3_t p_temp1;
vec3_t p_saxis, p_taxis;
float t;
pplane = pface->plane;
2019-10-10 06:23:57 +03:00
mipscale = 1.0f / (float)(1 << miplevel);
2019-04-14 00:58:14 +07:00
if( pface->texinfo->flags & TEX_WORLD_LUXELS )
{
TransformVector (pface->texinfo->vecs[0], p_saxis);
TransformVector (pface->texinfo->vecs[1], p_taxis);
}
else
{
2019-10-10 06:23:57 +03:00
TransformVector (pface->info->lmvecs[0], p_saxis);
TransformVector (pface->info->lmvecs[1], p_taxis);
2019-04-14 00:58:14 +07:00
}
t = xscaleinv * mipscale;
d_sdivzstepu = p_saxis[0] * t;
d_tdivzstepu = p_taxis[0] * t;
t = yscaleinv * mipscale;
d_sdivzstepv = -p_saxis[1] * t;
d_tdivzstepv = -p_taxis[1] * t;
d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
ycenter * d_sdivzstepv;
d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
ycenter * d_tdivzstepv;
VectorScale (transformed_modelorg, mipscale, p_temp1);
t = 0x10000*mipscale;
2019-04-14 00:58:14 +07:00
if( pface->texinfo->flags & TEX_WORLD_LUXELS )
{
2019-10-10 06:23:57 +03:00
sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5f)) -
2019-04-14 00:58:14 +07:00
((pface->texturemins[0] << 16) >> miplevel)
+ pface->texinfo->vecs[0][3]*t;
2019-10-10 06:23:57 +03:00
tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5f)) -
2019-04-14 00:58:14 +07:00
((pface->texturemins[1] << 16) >> miplevel)
+ pface->texinfo->vecs[1][3]*t;
}
else
{
2019-10-10 06:23:57 +03:00
sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5f)) -
2019-04-13 19:15:26 +07:00
((pface->info->lightmapmins[0] << 16) >> miplevel)
+ pface->info->lmvecs[0][3]*t;
2019-10-10 06:23:57 +03:00
tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5f)) -
2019-04-13 19:15:26 +07:00
((pface->info->lightmapmins[1] << 16) >> miplevel)
+ pface->info->lmvecs[1][3]*t;
2019-04-14 00:58:14 +07:00
}
// PGM - changing flow speed for non-warping textures.
if (pface->flags & SURF_CONVEYOR)
{
if(pface->flags & SURF_DRAWTURB)
sadjust += 0x10000 * (-128 * ( (gp_cl->time * 0.25f) - (int)(gp_cl->time * 0.25f) ));
else
sadjust += 0x10000 * (-128 * ( (gp_cl->time * 0.77f) - (int)(gp_cl->time * 0.77f) ));
bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
}
else
bbextents = ((pface->info->lightextents[0] << 16) >> miplevel) - 1;
2019-04-13 19:15:26 +07:00
bbextentt = ((pface->info->lightextents[1] << 16) >> miplevel) - 1;
2019-04-14 00:58:14 +07:00
if( pface->texinfo->flags & TEX_WORLD_LUXELS )
{
bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
}
}
/*
==============
D_BackgroundSurf
The grey background filler seen when there is a hole in the map
==============
*/
2024-01-27 20:18:17 +03:00
static void D_BackgroundSurf (surf_t *s)
{
// set up a gradient for the background surface that places it
// effectively at infinity distance from the viewpoint
d_zistepu = 0;
d_zistepv = 0;
d_ziorigin = -0.9;
D_FlatFillSurface (s, (int)sw_clearcolor.value & 0xFFFF);
D_DrawZSpans (s->spans);
}
/*
=================
D_TurbulentSurf
=================
*/
2024-01-27 20:18:17 +03:00
static void D_TurbulentSurf (surf_t *s)
{
d_zistepu = s->d_zistepu;
d_zistepv = s->d_zistepv;
d_ziorigin = s->d_ziorigin;
pface = s->msurf;
miplevel = 0;
cacheblock = R_GetTexture(pface->texinfo->texture->gl_texturenum)->pixels[0];
cachewidth = 64;
if (s->insubmodel)
{
// FIXME: we don't want to do all this for every polygon!
// TODO: store once at start of frame
RI.currententity = s->entity; //FIXME: make this passed in to
// R_RotateBmodel ()
VectorSubtract (RI.vieworg, RI.currententity->origin,
local_modelorg);
TransformVector (local_modelorg, transformed_modelorg);
R_RotateBmodel (); // FIXME: don't mess with the frustum,
// make entity passed in
}
D_CalcGradients (pface);
//============
//PGM
// textures that aren't warping are just flowing. Use NonTurbulent8 instead
if(!(pface->flags & SURF_DRAWTURB))
NonTurbulent8 (s->spans);
else
Turbulent8 (s->spans);
//PGM
//============
D_DrawZSpans (s->spans);
if (s->insubmodel)
{
//
// restore the old drawing state
// FIXME: we don't want to do this every time!
// TODO: speed up
//
RI.currententity = NULL; // &r_worldentity;
VectorCopy (world_transformed_modelorg,
transformed_modelorg);
2019-04-04 00:12:57 +07:00
VectorCopy (RI.base_vpn, RI.vforward);
VectorCopy (RI.base_vup, RI.vup);
VectorCopy (RI.base_vright, RI.vright);
R_TransformFrustum ();
}
}
qboolean alphaspans;
/*
==============
D_SolidSurf
Normal surface cached, texture mapped surface
==============
*/
2024-01-27 20:18:17 +03:00
static void D_AlphaSurf (surf_t *s)
{
2019-04-04 10:27:18 +07:00
int alpha;
d_zistepu = s->d_zistepu;
d_zistepv = s->d_zistepv;
d_ziorigin = s->d_ziorigin;
if(s->flags & SURF_DRAWSKY)
return;
if (!s->insubmodel) // wtf? how it is possible?
return;
// FIXME: we don't want to do all this for every polygon!
// TODO: store once at start of frame
RI.currententity = s->entity; //FIXME: make this passed in to
// R_RotateBmodel ()
VectorSubtract (RI.vieworg, RI.currententity->origin, local_modelorg);
TransformVector (local_modelorg, transformed_modelorg);
R_RotateBmodel (); // FIXME: don't mess with the frustum,
// make entity passed in
pface = s->msurf;
if( !pface )
return;
if( pface->flags & SURF_CONVEYOR )
miplevel = 1;
else
miplevel = 0;
2019-04-04 10:27:18 +07:00
alpha = RI.currententity->curstate.renderamt * 7 / 255;
if( alpha <= 0 && RI.currententity->curstate.renderamt > 0 )
alpha = 1;
if (s->flags & SURF_DRAWTURB )
{
cacheblock = R_GetTexture(pface->texinfo->texture->gl_texturenum)->pixels[0];
cachewidth = 64;
D_CalcGradients (pface);
2019-04-04 10:27:18 +07:00
TurbulentZ8( s->spans, alpha);
}
else
{
// FIXME: make this passed in to D_CacheSurface
pcurrentcache = D_CacheSurface (pface, miplevel);
cacheblock = (pixel_t *)pcurrentcache->data;
cachewidth = pcurrentcache->width;
D_CalcGradients (pface);
2019-04-04 10:27:18 +07:00
if( RI.currententity->curstate.rendermode == kRenderTransAlpha )
D_AlphaSpans16(s->spans);
else if( RI.currententity->curstate.rendermode == kRenderTransAdd )
D_AddSpans16(s->spans);
else
2019-04-04 10:27:18 +07:00
D_BlendSpans16(s->spans, alpha );
}
VectorCopy (world_transformed_modelorg,
transformed_modelorg);
2019-04-04 00:12:57 +07:00
VectorCopy (RI.base_vpn, RI.vforward);
VectorCopy (RI.base_vup, RI.vup);
VectorCopy (RI.base_vright, RI.vright);
R_TransformFrustum ();
}
/*
==============
D_SolidSurf
Normal surface cached, texture mapped surface
==============
*/
2024-01-27 20:18:17 +03:00
static void D_SolidSurf (surf_t *s)
{
d_zistepu = s->d_zistepu;
d_zistepv = s->d_zistepv;
d_ziorigin = s->d_ziorigin;
if(s->flags & SURF_DRAWSKY)
return;
if (s->flags & SURF_DRAWTURB )
return;
if (s->insubmodel)
{
// FIXME: we don't want to do all this for every polygon!
// TODO: store once at start of frame
RI.currententity = s->entity; //FIXME: make this passed in to
// R_RotateBmodel ()
VectorSubtract (RI.vieworg, RI.currententity->origin, local_modelorg);
TransformVector (local_modelorg, transformed_modelorg);
R_RotateBmodel (); // FIXME: don't mess with the frustum,
// make entity passed in
// setup dlight transform
if( s->msurf && s->msurf->dlightframe == tr.framecount )
{
Matrix4x4_CreateFromEntity( RI.objectMatrix, RI.currententity->angles, RI.currententity->origin, 1 );
tr.modelviewIdentity = false;
}
}
else
{
if( alphaspans )
return;
RI.currententity = CL_GetEntityByIndex(0); //r_worldentity;
tr.modelviewIdentity = true;
}
pface = s->msurf;
if( !pface )
return;
if( pface->flags & SURF_CONVEYOR )
miplevel = 1;
else
miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip );
2019-04-13 19:15:26 +07:00
while( 1 << miplevel > gEngfuncs.Mod_SampleSizeForFace(pface))
miplevel--;
// FIXME: make this passed in to D_CacheSurface
pcurrentcache = D_CacheSurface (pface, miplevel);
cacheblock = (pixel_t *)pcurrentcache->data;
cachewidth = pcurrentcache->width;
D_CalcGradients (pface);
D_DrawSpans16 (s->spans);
D_DrawZSpans (s->spans);
if (s->insubmodel)
{
//
// restore the old drawing state
// FIXME: we don't want to do this every time!
// TODO: speed up
//
VectorCopy (world_transformed_modelorg,
transformed_modelorg);
2019-04-04 00:12:57 +07:00
VectorCopy (RI.base_vpn, RI.vforward);
VectorCopy (RI.base_vup, RI.vup);
VectorCopy (RI.base_vright, RI.vright);
R_TransformFrustum ();
RI.currententity = NULL; //&r_worldentity;
}
}
/*
=============
D_DrawflatSurfaces
To allow developers to see the polygon carving of the world
=============
*/
2024-01-27 20:18:17 +03:00
static void D_DrawflatSurfaces (void)
{
surf_t *s;
for (s = &surfaces[1] ; s<surface_p ; s++)
{
if (!s->spans)
continue;
d_zistepu = s->d_zistepu;
d_zistepv = s->d_zistepv;
d_ziorigin = s->d_ziorigin;
// make a stable color for each surface by taking the low
// bits of the msurface pointer
2021-07-20 16:03:35 +03:00
D_FlatFillSurface (s, (uintptr_t)s->msurf & 0xFFFF);
D_DrawZSpans (s->spans);
}
}
/*
==============
D_DrawSurfaces
Rasterize all the span lists. Guaranteed zero overdraw.
May be called more than once a frame if the surf list overflows (higher res)
==============
*/
void D_DrawSurfaces (void)
{
surf_t *s;
// currententity = NULL; //&r_worldentity;
2019-04-04 00:12:57 +07:00
VectorSubtract (RI.vieworg, vec3_origin, tr.modelorg);
TransformVector (tr.modelorg, transformed_modelorg);
VectorCopy (transformed_modelorg, world_transformed_modelorg);
if (!sw_drawflat.value)
{
for (s = &surfaces[1] ; s<surface_p ; s++)
{
if (!s->spans)
continue;
if( alphaspans )
D_AlphaSurf (s);
else if(s->flags & SURF_DRAWSKY)
D_BackgroundSurf (s);
else if (s->flags & SURF_DRAWTURB )
D_TurbulentSurf (s);
else
D_SolidSurf (s);
}
}
else
D_DrawflatSurfaces ();
//RI.currententity = NULL; //&r_worldentity;
2019-04-04 00:12:57 +07:00
VectorSubtract (RI.vieworg, vec3_origin, tr.modelorg);
R_TransformFrustum ();
}