Browse Source

ref_soft: Merge some globals

pull/2/head
mittorn 5 years ago
parent
commit
b5e1382232
  1. 43
      r_bsp.c
  2. 2
      r_decals.c
  3. 25
      r_edge.c
  4. 4
      r_light.c
  5. 38
      r_local.h
  6. 66
      r_main.c
  7. 93
      r_misc.c
  8. 2
      r_polyse.c
  9. 29
      r_rast.c
  10. 10
      r_surf.c
  11. 24
      r_trialias.c

43
r_bsp.c

@ -25,7 +25,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// current entity info // current entity info
// //
qboolean insubmodel; qboolean insubmodel;
vec3_t modelorg; // modelorg is the viewpoint reletive to
// the currently rendering entity // the currently rendering entity
vec3_t r_entorigin; // the currently rendering entity in world vec3_t r_entorigin; // the currently rendering entity in world
// coordinates // coordinates
@ -165,10 +164,10 @@ void R_RotateBmodel (void)
// //
// rotate modelorg and the transformation matrix // rotate modelorg and the transformation matrix
// //
R_EntityRotate (modelorg); R_EntityRotate (tr.modelorg);
R_EntityRotate (vpn); R_EntityRotate (RI.vforward);
R_EntityRotate (vright); R_EntityRotate (RI.vright);
R_EntityRotate (vup); R_EntityRotate (RI.vup);
R_TransformFrustum (); R_TransformFrustum ();
} }
@ -495,7 +494,7 @@ void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
pn = pnode->children[i]; pn = pnode->children[i];
// we're done with this branch if the node or leaf isn't in the PVS // we're done with this branch if the node or leaf isn't in the PVS
if (pn->visframe == r_visframecount) if (pn->visframe == tr.visframecount)
{ {
if (pn->contents < 0) if (pn->contents < 0)
{ {
@ -667,7 +666,7 @@ void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode)
// find which side of the node we are on // find which side of the node we are on
pplane = psurf->plane; pplane = psurf->plane;
dot = DotProduct (modelorg, pplane->normal) - pplane->dist; dot = DotProduct (tr.modelorg, pplane->normal) - pplane->dist;
// draw the polygon // draw the polygon
if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
@ -742,7 +741,7 @@ void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode)
// find which side of the node we are on // find which side of the node we are on
pplane = psurf->plane; pplane = psurf->plane;
dot = DotProduct (modelorg, pplane->normal) - pplane->dist; dot = DotProduct (tr.modelorg, pplane->normal) - pplane->dist;
// draw the polygon // draw the polygon
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
@ -779,7 +778,7 @@ void R_RecursiveWorldNode (mnode_t *node, int clipflags)
if (node->contents == CONTENTS_SOLID) if (node->contents == CONTENTS_SOLID)
return; // solid return; // solid
if (node->visframe != r_visframecount) if (node->visframe != tr.visframecount)
return; return;
// cull the clipping planes if not trivial accept // cull the clipping planes if not trivial accept
@ -796,14 +795,14 @@ void R_RecursiveWorldNode (mnode_t *node, int clipflags)
// FIXME: do with fast look-ups or integer tests based on the sign bit // FIXME: do with fast look-ups or integer tests based on the sign bit
// of the floating point values // of the floating point values
pindex = pfrustum_indexes[i]; pindex = qfrustum.pfrustum_indexes[i];
rejectpt[0] = (float)node->minmaxs[pindex[0]]; rejectpt[0] = (float)node->minmaxs[pindex[0]];
rejectpt[1] = (float)node->minmaxs[pindex[1]]; rejectpt[1] = (float)node->minmaxs[pindex[1]];
rejectpt[2] = (float)node->minmaxs[pindex[2]]; rejectpt[2] = (float)node->minmaxs[pindex[2]];
d = DotProduct (rejectpt, view_clipplanes[i].normal); d = DotProduct (rejectpt, qfrustum.view_clipplanes[i].normal);
d -= view_clipplanes[i].dist; d -= qfrustum.view_clipplanes[i].dist;
if (d <= 0) if (d <= 0)
return; return;
@ -812,8 +811,8 @@ void R_RecursiveWorldNode (mnode_t *node, int clipflags)
acceptpt[1] = (float)node->minmaxs[pindex[3+1]]; acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
acceptpt[2] = (float)node->minmaxs[pindex[3+2]]; acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
d = DotProduct (acceptpt, view_clipplanes[i].normal); d = DotProduct (acceptpt, qfrustum.view_clipplanes[i].normal);
d -= view_clipplanes[i].dist; d -= qfrustum.view_clipplanes[i].dist;
if (d >= 0) if (d >= 0)
clipflags &= ~(1<<i); // node is entirely on screen clipflags &= ~(1<<i); // node is entirely on screen
@ -832,7 +831,7 @@ void R_RecursiveWorldNode (mnode_t *node, int clipflags)
{ {
do do
{ {
(*mark)->visframe = r_framecount; (*mark)->visframe = tr.framecount;
mark++; mark++;
} while (--c); } while (--c);
} }
@ -858,16 +857,16 @@ void R_RecursiveWorldNode (mnode_t *node, int clipflags)
switch (plane->type) switch (plane->type)
{ {
case PLANE_X: case PLANE_X:
dot = modelorg[0] - plane->dist; dot = tr.modelorg[0] - plane->dist;
break; break;
case PLANE_Y: case PLANE_Y:
dot = modelorg[1] - plane->dist; dot = tr.modelorg[1] - plane->dist;
break; break;
case PLANE_Z: case PLANE_Z:
dot = modelorg[2] - plane->dist; dot = tr.modelorg[2] - plane->dist;
break; break;
default: default:
dot = DotProduct (modelorg, plane->normal) - plane->dist; dot = DotProduct (tr.modelorg, plane->normal) - plane->dist;
break; break;
} }
@ -891,7 +890,7 @@ void R_RecursiveWorldNode (mnode_t *node, int clipflags)
do do
{ {
if ((surf->flags & SURF_PLANEBACK) && if ((surf->flags & SURF_PLANEBACK) &&
(surf->visframe == r_framecount)) (surf->visframe == tr.framecount))
{ {
R_RenderFace (surf, clipflags); R_RenderFace (surf, clipflags);
} }
@ -904,7 +903,7 @@ void R_RecursiveWorldNode (mnode_t *node, int clipflags)
do do
{ {
if (!(surf->flags & SURF_PLANEBACK) && if (!(surf->flags & SURF_PLANEBACK) &&
(surf->visframe == r_framecount)) (surf->visframe == tr.framecount))
{ {
R_RenderFace (surf, clipflags); R_RenderFace (surf, clipflags);
} }
@ -941,7 +940,7 @@ void R_RenderWorld (void)
RI.currententity = gEngfuncs.GetEntityByIndex(0); RI.currententity = gEngfuncs.GetEntityByIndex(0);
//RI.currententity->frame = (int)(gpGlobals->time*2); //RI.currententity->frame = (int)(gpGlobals->time*2);
VectorCopy (r_origin, modelorg); VectorCopy (RI.vieworg, tr.modelorg);
RI.currentmodel = WORLDMODEL; RI.currentmodel = WORLDMODEL;
r_pcurrentvertbase = RI.currentmodel->vertexes; r_pcurrentvertbase = RI.currentmodel->vertexes;

2
r_decals.c

@ -566,7 +566,7 @@ static void R_AddDecalToSurface( decal_t *pdecal, msurface_t *surf, decalinfo_t
} }
// force surface cache rebuild // force surface cache rebuild
surf->dlightframe = r_framecount + 1; surf->dlightframe = tr.framecount + 1;
// tag surface // tag surface
pdecal->psurface = surf; pdecal->psurface = surf;

25
r_edge.c

@ -78,7 +78,6 @@ static float fv;
static int miplevel; static int miplevel;
float scale_for_mip; float scale_for_mip;
int ubasestep, errorterm, erroradjustup, erroradjustdown;
// FIXME: should go away // FIXME: should go away
extern void R_RotateBmodel (void); extern void R_RotateBmodel (void);
@ -944,9 +943,9 @@ void D_TurbulentSurf (surf_t *s)
RI.currententity = NULL; // &r_worldentity; RI.currententity = NULL; // &r_worldentity;
VectorCopy (world_transformed_modelorg, VectorCopy (world_transformed_modelorg,
transformed_modelorg); transformed_modelorg);
VectorCopy (base_vpn, vpn); VectorCopy (RI.base_vpn, RI.vforward);
VectorCopy (base_vup, vup); VectorCopy (RI.base_vup, RI.vup);
VectorCopy (base_vright, vright); VectorCopy (RI.base_vright, RI.vright);
R_TransformFrustum (); R_TransformFrustum ();
} }
} }
@ -1081,9 +1080,9 @@ void D_AlphaSurf (surf_t *s)
VectorCopy (world_transformed_modelorg, VectorCopy (world_transformed_modelorg,
transformed_modelorg); transformed_modelorg);
VectorCopy (base_vpn, vpn); VectorCopy (RI.base_vpn, RI.vforward);
VectorCopy (base_vup, vup); VectorCopy (RI.base_vup, RI.vup);
VectorCopy (base_vright, vright); VectorCopy (RI.base_vright, RI.vright);
R_TransformFrustum (); R_TransformFrustum ();
} }
@ -1184,9 +1183,9 @@ void D_SolidSurf (surf_t *s)
// //
VectorCopy (world_transformed_modelorg, VectorCopy (world_transformed_modelorg,
transformed_modelorg); transformed_modelorg);
VectorCopy (base_vpn, vpn); VectorCopy (RI.base_vpn, RI.vforward);
VectorCopy (base_vup, vup); VectorCopy (RI.base_vup, RI.vup);
VectorCopy (base_vright, vright); VectorCopy (RI.base_vright, RI.vright);
R_TransformFrustum (); R_TransformFrustum ();
RI.currententity = NULL; //&r_worldentity; RI.currententity = NULL; //&r_worldentity;
} }
@ -1232,8 +1231,8 @@ void D_DrawSurfaces (void)
surf_t *s; surf_t *s;
// currententity = NULL; //&r_worldentity; // currententity = NULL; //&r_worldentity;
VectorSubtract (RI.vieworg, vec3_origin, modelorg); VectorSubtract (RI.vieworg, vec3_origin, tr.modelorg);
TransformVector (modelorg, transformed_modelorg); TransformVector (tr.modelorg, transformed_modelorg);
VectorCopy (transformed_modelorg, world_transformed_modelorg); VectorCopy (transformed_modelorg, world_transformed_modelorg);
if (!sw_drawflat->value) if (!sw_drawflat->value)
@ -1269,7 +1268,7 @@ void D_DrawSurfaces (void)
D_DrawflatSurfaces (); D_DrawflatSurfaces ();
//RI.currententity = NULL; //&r_worldentity; //RI.currententity = NULL; //&r_worldentity;
VectorSubtract (RI.vieworg, vec3_origin, modelorg); VectorSubtract (RI.vieworg, vec3_origin, tr.modelorg);
R_TransformFrustum (); R_TransformFrustum ();
} }

4
r_light.c

@ -131,10 +131,10 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius )) if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius ))
continue; // no intersection continue; // no intersection
if( surf->dlightframe != r_framecount )//tr.dlightframecount ) if( surf->dlightframe != tr.framecount )//tr.dlightframecount )
{ {
surf->dlightbits = 0; surf->dlightbits = 0;
surf->dlightframe = r_framecount; //tr.dlightframecount; surf->dlightframe = tr.framecount; //tr.dlightframecount;
} }
surf->dlightbits |= bit; surf->dlightbits |= bit;
} }

38
r_local.h

@ -186,6 +186,11 @@ typedef struct
vec3_t vright; vec3_t vright;
vec3_t vup; vec3_t vup;
vec3_t base_vup;
vec3_t base_vpn;
vec3_t base_vright;
vec3_t cullorigin; vec3_t cullorigin;
vec3_t cull_vforward; vec3_t cull_vforward;
vec3_t cull_vright; vec3_t cull_vright;
@ -232,13 +237,8 @@ typedef struct
float fvrectright_adj, fvrectbottom_adj; float fvrectright_adj, fvrectbottom_adj;
// right and bottom edges, for clamping // right and bottom edges, for clamping
float fvrectright; // rightmost edge, for Alias clamping float fvrectright; // rightmost edge, for Alias clamping
float fvrectbottom; // bottommost edge, for Alias clamping float fvrectbottom; // bottommost edge, for Alias clampin
float horizontalFieldOfView; // at Z = 1.0, this many X is visible
// 2.0 = 90 degrees
float xOrigin; // should probably always be 0.5
float yOrigin; // between be around 0.3 to 0.5
int ambientlight;
} ref_instance_t; } ref_instance_t;
@ -1067,8 +1067,6 @@ VARS
==================================================== ====================================================
*/ */
//extern int d_spanpixcount;
extern int r_framecount; // sequence # of current frame since Quake
// started // started
extern float r_aliasuvscale; // scale-up factor for screen u and v extern float r_aliasuvscale; // scale-up factor for screen u and v
// on Alias vertices passed to driver // on Alias vertices passed to driver
@ -1143,10 +1141,6 @@ extern int sintable[1280];
extern int intsintable[1280]; extern int intsintable[1280];
extern int blanktable[1280]; // PGM extern int blanktable[1280]; // PGM
extern vec3_t vup, base_vup;
extern vec3_t vpn, base_vpn;
extern vec3_t vright, base_vright;
extern surf_t *surfaces, *surface_p, *surf_max; extern surf_t *surfaces, *surface_p, *surf_max;
// surfaces are generated in back to front order by the bsp, so if a surf // surfaces are generated in back to front order by the bsp, so if a surf
@ -1178,15 +1172,11 @@ extern edge_t edge_head;
extern edge_t edge_tail; extern edge_t edge_tail;
extern edge_t edge_aftertail; extern edge_t edge_aftertail;
extern int r_frustum_indexes[4*6];
extern qboolean r_surfsonstack; extern qboolean r_surfsonstack;
extern mleaf_t *r_viewleaf;
extern int r_viewcluster, r_oldviewcluster; extern int r_viewcluster, r_oldviewcluster;
extern int r_clipflags; extern int r_clipflags;
extern int r_dlightframecount;
//extern qboolean r_fov_greater_than_90; //extern qboolean r_fov_greater_than_90;
@ -1215,19 +1205,16 @@ extern cvar_t *tracerblue;
extern cvar_t *traceralpha; extern cvar_t *traceralpha;
extern struct qfrustum_s {
extern vec3_t modelorg; mplane_t screenedge[4];
extern vec3_t r_origin; clipplane_t view_clipplanes[4];
extern mplane_t screenedge[4]; int frustum_indexes[4*6];
int *pfrustum_indexes[4];
} qfrustum;
extern clipplane_t view_clipplanes[4];
extern int *pfrustum_indexes[4];
extern cvar_t *r_fullbright; extern cvar_t *r_fullbright;
#define CACHESPOT(surf) ((surfcache_t**)surf->info->reserved) #define CACHESPOT(surf) ((surfcache_t**)surf->info->reserved)
extern int r_visframecount;
extern int r_currentkey; extern int r_currentkey;
extern int r_currentbkey; extern int r_currentbkey;
extern qboolean insubmodel; extern qboolean insubmodel;
@ -1237,7 +1224,6 @@ extern vec3_t r_entorigin;
extern int r_leafkeys[MAX_MAP_LEAFS]; extern int r_leafkeys[MAX_MAP_LEAFS];
#define LEAF_KEY(pleaf) r_leafkeys[(pleaf - WORLDMODEL->leafs)] #define LEAF_KEY(pleaf) r_leafkeys[(pleaf - WORLDMODEL->leafs)]
extern int ubasestep, errorterm, erroradjustup, erroradjustdown;
extern mvertex_t *r_pcurrentvertbase; extern mvertex_t *r_pcurrentvertbase;

66
r_main.c

@ -30,10 +30,6 @@ ref_instance_t RI;
// view origin // view origin
// //
vec3_t vup, base_vup;
vec3_t vpn, base_vpn;
vec3_t vright, base_vright;
vec3_t r_origin;
// //
// screen size info // screen size info
@ -46,26 +42,18 @@ float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
int r_screenwidth; int r_screenwidth;
float verticalFieldOfView;
float xOrigin, yOrigin;
mplane_t screenedge[4];
// //
// refresh flags // refresh flags
// //
int r_framecount = 1; // so frame counts initialized to 0 don't match
int r_visframecount;
//int d_spanpixcount; //int d_spanpixcount;
//int r_polycount; //int r_polycount;
//int r_drawnpolycount; //int r_drawnpolycount;
//int r_wholepolycount; //int r_wholepolycount;
int *pfrustum_indexes[4];
int r_frustum_indexes[4*6];
mleaf_t *r_viewleaf;
int r_viewcluster, r_oldviewcluster; int r_viewcluster, r_oldviewcluster;
cvar_t *r_lefthand; cvar_t *r_lefthand;
@ -1152,14 +1140,14 @@ int R_BmodelCheckBBox (float *minmaxs)
// FIXME: do with fast look-ups or integer tests based on the sign bit // FIXME: do with fast look-ups or integer tests based on the sign bit
// of the floating point values // of the floating point values
pindex = pfrustum_indexes[i]; pindex = qfrustum.pfrustum_indexes[i];
rejectpt[0] = minmaxs[pindex[0]]; rejectpt[0] = minmaxs[pindex[0]];
rejectpt[1] = minmaxs[pindex[1]]; rejectpt[1] = minmaxs[pindex[1]];
rejectpt[2] = minmaxs[pindex[2]]; rejectpt[2] = minmaxs[pindex[2]];
d = DotProduct (rejectpt, view_clipplanes[i].normal); d = DotProduct (rejectpt, qfrustum.view_clipplanes[i].normal);
d -= view_clipplanes[i].dist; d -= qfrustum.view_clipplanes[i].dist;
if (d <= 0) if (d <= 0)
return BMODEL_FULLY_CLIPPED; return BMODEL_FULLY_CLIPPED;
@ -1168,8 +1156,8 @@ int R_BmodelCheckBBox (float *minmaxs)
acceptpt[1] = minmaxs[pindex[3+1]]; acceptpt[1] = minmaxs[pindex[3+1]];
acceptpt[2] = minmaxs[pindex[3+2]]; acceptpt[2] = minmaxs[pindex[3+2]];
d = DotProduct (acceptpt, view_clipplanes[i].normal); d = DotProduct (acceptpt, qfrustum.view_clipplanes[i].normal);
d -= view_clipplanes[i].dist; d -= qfrustum.view_clipplanes[i].dist;
if (d <= 0) if (d <= 0)
clipflags |= (1<<i); clipflags |= (1<<i);
@ -1193,7 +1181,7 @@ mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
while (1) while (1)
{ {
if (node->visframe != r_visframecount) if (node->visframe != tr.visframecount)
return NULL; // not visible at all return NULL; // not visible at all
if (node->contents < 0) if (node->contents < 0)
@ -1293,7 +1281,7 @@ void R_DrawBEntitiesOnList (void)
float minmaxs[6]; float minmaxs[6];
mnode_t *topnode; mnode_t *topnode;
VectorCopy (modelorg, oldorigin); VectorCopy (tr.modelorg, oldorigin);
insubmodel = true; insubmodel = true;
//r_dlightframecount = r_framecount; //r_dlightframecount = r_framecount;
@ -1335,7 +1323,7 @@ void R_DrawBEntitiesOnList (void)
continue; // no part in a visible leaf continue; // no part in a visible leaf
VectorCopy (RI.currententity->origin, r_entorigin); VectorCopy (RI.currententity->origin, r_entorigin);
VectorSubtract (r_origin, r_entorigin, modelorg); VectorSubtract (RI.vieworg, r_entorigin, tr.modelorg);
//VectorSubtract (r_origin, RI.currententity->origin, modelorg); //VectorSubtract (r_origin, RI.currententity->origin, modelorg);
r_pcurrentvertbase = RI.currentmodel->vertexes; r_pcurrentvertbase = RI.currentmodel->vertexes;
@ -1394,10 +1382,10 @@ void R_DrawBEntitiesOnList (void)
// put back world rotation and frustum clipping // put back world rotation and frustum clipping
// FIXME: R_RotateBmodel should just work off base_vxx // FIXME: R_RotateBmodel should just work off base_vxx
VectorCopy (base_vpn, vpn); VectorCopy (RI.base_vpn, RI.vforward);
VectorCopy (base_vup, vup); VectorCopy (RI.base_vup, RI.vup);
VectorCopy (base_vright, vright); VectorCopy (RI.base_vright, RI.vright);
VectorCopy (oldorigin, modelorg); VectorCopy (oldorigin, tr.modelorg);
R_TransformFrustum (); R_TransformFrustum ();
} }
@ -1451,7 +1439,7 @@ void R_DrawBrushModel(cl_entity_t *pent)
R_BeginEdgeFrame(); R_BeginEdgeFrame();
VectorCopy (modelorg, oldorigin); VectorCopy (tr.modelorg, oldorigin);
insubmodel = true; insubmodel = true;
//r_dlightframecount = r_framecount; //r_dlightframecount = r_framecount;
@ -1489,7 +1477,7 @@ void R_DrawBrushModel(cl_entity_t *pent)
alphaspans = true; alphaspans = true;
VectorCopy (RI.currententity->origin, r_entorigin); VectorCopy (RI.currententity->origin, r_entorigin);
VectorSubtract (r_origin, r_entorigin, modelorg); VectorSubtract (RI.vieworg, r_entorigin, tr.modelorg);
//VectorSubtract (r_origin, RI.currententity->origin, modelorg); //VectorSubtract (r_origin, RI.currententity->origin, modelorg);
r_pcurrentvertbase = RI.currentmodel->vertexes; r_pcurrentvertbase = RI.currentmodel->vertexes;
@ -1548,10 +1536,10 @@ void R_DrawBrushModel(cl_entity_t *pent)
// put back world rotation and frustum clipping // put back world rotation and frustum clipping
// FIXME: R_RotateBmodel should just work off base_vxx // FIXME: R_RotateBmodel should just work off base_vxx
VectorCopy (base_vpn, vpn); VectorCopy (RI.base_vpn, RI.vforward);
VectorCopy (base_vup, vup); VectorCopy (RI.base_vup, RI.vup);
VectorCopy (base_vright, vright); VectorCopy (RI.base_vright, RI.vright);
VectorCopy (oldorigin, modelorg); VectorCopy (oldorigin, tr.modelorg);
R_TransformFrustum (); R_TransformFrustum ();
@ -1704,7 +1692,7 @@ void R_MarkLeaves (void)
if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1) if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
return; return;
r_visframecount++; tr.visframecount++;
r_oldviewcluster = r_viewcluster; r_oldviewcluster = r_viewcluster;
gEngfuncs.R_FatPVS( RI.pvsorigin, REFPVS_RADIUS, RI.visbytes, FBitSet( RI.params, RP_OLDVIEWLEAF ), false ); gEngfuncs.R_FatPVS( RI.pvsorigin, REFPVS_RADIUS, RI.visbytes, FBitSet( RI.params, RP_OLDVIEWLEAF ), false );
@ -1717,9 +1705,9 @@ void R_MarkLeaves (void)
node = (mnode_t *) &WORLDMODEL->leafs[i+1]; node = (mnode_t *) &WORLDMODEL->leafs[i+1];
do do
{ {
if (node->visframe == r_visframecount) if (node->visframe == tr.visframecount)
break; break;
node->visframe = r_visframecount; node->visframe = tr.visframecount;
node = node->parent; node = node->parent;
} while (node); } while (node);
} }
@ -2098,12 +2086,10 @@ qboolean R_Init()
// init draw stack // init draw stack
tr.draw_list = &tr.draw_stack[0]; tr.draw_list = &tr.draw_stack[0];
tr.draw_stack_pos = 0; tr.draw_stack_pos = 0;
RI.yOrigin = YCENTERING; qfrustum.view_clipplanes[0].leftedge = true;
RI.xOrigin = XCENTERING; qfrustum.view_clipplanes[1].rightedge = true;
view_clipplanes[0].leftedge = true; qfrustum.view_clipplanes[1].leftedge = qfrustum.view_clipplanes[2].leftedge =qfrustum.view_clipplanes[3].leftedge = false;
view_clipplanes[1].rightedge = true; qfrustum.view_clipplanes[0].rightedge = qfrustum.view_clipplanes[2].rightedge = qfrustum.view_clipplanes[3].rightedge = false;
view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =view_clipplanes[3].leftedge = false;
view_clipplanes[0].rightedge = view_clipplanes[2].rightedge = view_clipplanes[3].rightedge = false;
R_StudioInit(); R_StudioInit();
R_SpriteInit(); R_SpriteInit();
R_InitTurb(); R_InitTurb();

93
r_misc.c

@ -40,7 +40,7 @@ static float basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
int d_scantable[MAXHEIGHT]; int d_scantable[MAXHEIGHT];
short *zspantable[MAXHEIGHT]; short *zspantable[MAXHEIGHT];
struct qfrustum_s qfrustum;
/* /*
================ ================
D_Patch D_Patch
@ -132,17 +132,17 @@ void R_TransformFrustum (void)
for (i=0 ; i<4 ; i++) for (i=0 ; i<4 ; i++)
{ {
v[0] = screenedge[i].normal[2]; v[0] = qfrustum.screenedge[i].normal[2];
v[1] = -screenedge[i].normal[0]; v[1] = -qfrustum.screenedge[i].normal[0];
v[2] = screenedge[i].normal[1]; v[2] = qfrustum.screenedge[i].normal[1];
v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0]; v2[0] = v[1]*RI.vright[0] + v[2]*RI.vup[0] + v[0]*RI.vforward[0];
v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1]; v2[1] = v[1]*RI.vright[1] + v[2]*RI.vup[1] + v[0]*RI.vforward[1];
v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2]; v2[2] = v[1]*RI.vright[2] + v[2]*RI.vup[2] + v[0]*RI.vforward[2];
VectorCopy (v2, view_clipplanes[i].normal); VectorCopy (v2, qfrustum.view_clipplanes[i].normal);
view_clipplanes[i].dist = DotProduct (modelorg, v2); qfrustum.view_clipplanes[i].dist = DotProduct (tr.modelorg, v2);
} }
} }
@ -154,9 +154,9 @@ TransformVector
*/ */
void TransformVector (vec3_t in, vec3_t out) void TransformVector (vec3_t in, vec3_t out)
{ {
out[0] = DotProduct(in,vright); out[0] = DotProduct(in,RI.vright);
out[1] = DotProduct(in,vup); out[1] = DotProduct(in,RI.vup);
out[2] = DotProduct(in,vpn); out[2] = DotProduct(in,RI.vforward);
} }
/* /*
@ -184,13 +184,13 @@ void R_SetUpFrustumIndexes (void)
{ {
int i, j, *pindex; int i, j, *pindex;
pindex = r_frustum_indexes; pindex = qfrustum.frustum_indexes;
for (i=0 ; i<4 ; i++) for (i=0 ; i<4 ; i++)
{ {
for (j=0 ; j<3 ; j++) for (j=0 ; j<3 ; j++)
{ {
if (view_clipplanes[i].normal[j] < 0) if (qfrustum.view_clipplanes[i].normal[j] < 0)
{ {
pindex[j] = j; pindex[j] = j;
pindex[j+3] = j+3; pindex[j+3] = j+3;
@ -203,7 +203,7 @@ void R_SetUpFrustumIndexes (void)
} }
// FIXME: do just once at start // FIXME: do just once at start
pfrustum_indexes[i] = pindex; qfrustum.pfrustum_indexes[i] = pindex;
pindex += 6; pindex += 6;
} }
} }
@ -219,11 +219,11 @@ Guaranteed to be called before the first refresh
void R_ViewChanged (vrect_t *vr) void R_ViewChanged (vrect_t *vr)
{ {
int i; int i;
float verticalFieldOfView, xOrigin, yOrigin; float verticalFieldOfView, horizontalFieldOfView, xOrigin, yOrigin;
RI.vrect = *vr; RI.vrect = *vr;
RI.horizontalFieldOfView = 2*tan((float)RI.fov_x/360*M_PI); horizontalFieldOfView = 2*tan((float)RI.fov_x/360*M_PI);
verticalFieldOfView = 2*tan((float)RI.fov_y/360*M_PI); verticalFieldOfView = 2*tan((float)RI.fov_y/360*M_PI);
RI.fvrectx = (float)RI.vrect.x; RI.fvrectx = (float)RI.vrect.x;
@ -249,8 +249,8 @@ void R_ViewChanged (vrect_t *vr)
RI.aliasvrectbottom = RI.aliasvrect.y + RI.aliasvrectbottom = RI.aliasvrect.y +
RI.aliasvrect.height; RI.aliasvrect.height;
xOrigin = RI.xOrigin;// = r_origin[0]; xOrigin = XCENTERING;
yOrigin = RI.yOrigin;// = r_origin[1]; yOrigin = YCENTERING;
#define PLANE_ANYZ 5 #define PLANE_ANYZ 5
// values for perspective projection // values for perspective projection
// if math were exact, the values would range from 0.5 to to range+0.5 // if math were exact, the values would range from 0.5 to to range+0.5
@ -265,7 +265,7 @@ void R_ViewChanged (vrect_t *vr)
RI.vrect.y - 0.5; RI.vrect.y - 0.5;
aliasycenter = ycenter * r_aliasuvscale; aliasycenter = ycenter * r_aliasuvscale;
xscale = RI.vrect.width / RI.horizontalFieldOfView; xscale = RI.vrect.width / horizontalFieldOfView;
aliasxscale = xscale * r_aliasuvscale; aliasxscale = xscale * r_aliasuvscale;
xscaleinv = 1.0 / xscale; xscaleinv = 1.0 / xscale;
@ -276,32 +276,32 @@ void R_ViewChanged (vrect_t *vr)
//yscaleshrink = xscaleshrink; //yscaleshrink = xscaleshrink;
// left side clip // left side clip
screenedge[0].normal[0] = -1.0 / (xOrigin*RI.horizontalFieldOfView); qfrustum.screenedge[0].normal[0] = -1.0 / (xOrigin*horizontalFieldOfView);
screenedge[0].normal[1] = 0; qfrustum.screenedge[0].normal[1] = 0;
screenedge[0].normal[2] = 1; qfrustum.screenedge[0].normal[2] = 1;
screenedge[0].type = PLANE_ANYZ; qfrustum.screenedge[0].type = PLANE_ANYZ;
// right side clip // right side clip
screenedge[1].normal[0] = qfrustum.screenedge[1].normal[0] =
1.0 / ((1.0-xOrigin)*RI.horizontalFieldOfView); 1.0 / ((1.0-xOrigin)*horizontalFieldOfView);
screenedge[1].normal[1] = 0; qfrustum.screenedge[1].normal[1] = 0;
screenedge[1].normal[2] = 1; qfrustum.screenedge[1].normal[2] = 1;
screenedge[1].type = PLANE_ANYZ; qfrustum.screenedge[1].type = PLANE_ANYZ;
// top side clip // top side clip
screenedge[2].normal[0] = 0; qfrustum.screenedge[2].normal[0] = 0;
screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView); qfrustum.screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
screenedge[2].normal[2] = 1; qfrustum.screenedge[2].normal[2] = 1;
screenedge[2].type = PLANE_ANYZ; qfrustum.screenedge[2].type = PLANE_ANYZ;
// bottom side clip // bottom side clip
screenedge[3].normal[0] = 0; qfrustum.screenedge[3].normal[0] = 0;
screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView); qfrustum.screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
screenedge[3].normal[2] = 1; qfrustum.screenedge[3].normal[2] = 1;
screenedge[3].type = PLANE_ANYZ; qfrustum.screenedge[3].type = PLANE_ANYZ;
for (i=0 ; i<4 ; i++) for (i=0 ; i<4 ; i++)
VectorNormalize (screenedge[i].normal); VectorNormalize (qfrustum.screenedge[i].normal);
D_ViewChanged (); D_ViewChanged ();
} }
@ -323,20 +323,19 @@ void R_SetupFrameQ (void)
D_FlushCaches( false ); // so all lighting changes D_FlushCaches( false ); // so all lighting changes
} }
r_framecount++; //tr.framecount++;
// build the transformation matrix for the given view angles // build the transformation matrix for the given view angles
VectorCopy (RI.vieworg, modelorg); VectorCopy (RI.vieworg, tr.modelorg);
VectorCopy (RI.vieworg, r_origin);
AngleVectors (RI.viewangles, vpn, vright, vup); //AngleVectors (RI.viewangles, RI.vforward, RI.vright, RI.vup);
// current viewleaf // current viewleaf
if ( RI.drawWorld ) if ( RI.drawWorld )
{ {
r_viewleaf = gEngfuncs.Mod_PointInLeaf (r_origin, WORLDMODEL->nodes); RI.viewleaf = gEngfuncs.Mod_PointInLeaf (RI.vieworg, WORLDMODEL->nodes);
r_viewcluster = r_viewleaf->cluster; r_viewcluster = RI.viewleaf->cluster;
} }
// if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) ) // if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) )
@ -372,9 +371,9 @@ void R_SetupFrameQ (void)
R_SetUpFrustumIndexes (); R_SetUpFrustumIndexes ();
// save base values // save base values
VectorCopy (vpn, base_vpn); VectorCopy (RI.vforward, RI.base_vpn);
VectorCopy (vright, base_vright); VectorCopy (RI.vright, RI.base_vright);
VectorCopy (vup, base_vup); VectorCopy (RI.vup, RI.base_vup);
// clear frame counts // clear frame counts
/* c_faceclip = 0; /* c_faceclip = 0;

2
r_polyse.c

@ -90,6 +90,8 @@ int d_sfracbasestep, d_tfracbasestep;
int d_ziextrastep, d_zibasestep; int d_ziextrastep, d_zibasestep;
int d_pzextrastep, d_pzbasestep; int d_pzextrastep, d_pzbasestep;
static int ubasestep, errorterm, erroradjustup, erroradjustdown;
typedef struct { typedef struct {
int quotient; int quotient;
int remainder; int remainder;

29
r_rast.c

@ -35,7 +35,6 @@ int c_faceclip; // number of faces clipped
clipplane_t *entity_clipplanes; clipplane_t *entity_clipplanes;
clipplane_t view_clipplanes[4];
clipplane_t world_clipplanes[16]; clipplane_t world_clipplanes[16];
medge_t *r_pedge; medge_t *r_pedge;
@ -239,7 +238,7 @@ void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
world = &pv0->position[0]; world = &pv0->position[0];
// transform and project // transform and project
VectorSubtract (world, modelorg, local); VectorSubtract (world, tr.modelorg, local);
TransformVector (local, transformed); TransformVector (local, transformed);
if (transformed[2] < NEAR_CLIP) if (transformed[2] < NEAR_CLIP)
@ -268,7 +267,7 @@ void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
world = &pv1->position[0]; world = &pv1->position[0];
// transform and project // transform and project
VectorSubtract (world, modelorg, local); VectorSubtract (world, tr.modelorg, local);
TransformVector (local, transformed); TransformVector (local, transformed);
if (transformed[2] < NEAR_CLIP) if (transformed[2] < NEAR_CLIP)
@ -312,7 +311,7 @@ void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
if (cacheoffset != 0x7FFFFFFF) if (cacheoffset != 0x7FFFFFFF)
{ {
cacheoffset = FULLY_CLIPPED_CACHED | cacheoffset = FULLY_CLIPPED_CACHED |
(r_framecount & FRAMECOUNT_MASK); (tr.framecount & FRAMECOUNT_MASK);
} }
return; // horizontal edge return; // horizontal edge
@ -471,7 +470,7 @@ void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
// we do cache fully clipped edges // we do cache fully clipped edges
if (!r_leftclipped) if (!r_leftclipped)
cacheoffset = FULLY_CLIPPED_CACHED | cacheoffset = FULLY_CLIPPED_CACHED |
(r_framecount & FRAMECOUNT_MASK); (tr.framecount & FRAMECOUNT_MASK);
return; return;
} }
@ -590,8 +589,8 @@ void R_RenderFace (msurface_t *fa, int clipflags)
{ {
if (clipflags & mask) if (clipflags & mask)
{ {
view_clipplanes[i].next = pclip; qfrustum.view_clipplanes[i].next = pclip;
pclip = &view_clipplanes[i]; pclip = &qfrustum.view_clipplanes[i];
} }
} }
@ -617,7 +616,7 @@ void R_RenderFace (msurface_t *fa, int clipflags)
if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
{ {
if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
r_framecount) tr.framecount)
{ {
r_lastvertvalid = false; r_lastvertvalid = false;
continue; continue;
@ -661,7 +660,7 @@ void R_RenderFace (msurface_t *fa, int clipflags)
if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
{ {
if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
r_framecount) tr.framecount)
{ {
r_lastvertvalid = false; r_lastvertvalid = false;
continue; continue;
@ -715,7 +714,7 @@ void R_RenderFace (msurface_t *fa, int clipflags)
r_pedge = &tedge; r_pedge = &tedge;
r_lastvertvalid = false; r_lastvertvalid = false;
r_nearzionly = true; r_nearzionly = true;
R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next); R_ClipEdge (&r_rightexit, &r_rightenter, qfrustum.view_clipplanes[1].next);
} }
// if no edges made it out, return without posting the surface // if no edges made it out, return without posting the surface
@ -737,7 +736,7 @@ void R_RenderFace (msurface_t *fa, int clipflags)
// FIXME: cache this? // FIXME: cache this?
TransformVector (pplane->normal, p_normal); TransformVector (pplane->normal, p_normal);
// FIXME: cache this? // FIXME: cache this?
distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal)); distinv = 1.0 / (pplane->dist - DotProduct (tr.modelorg, pplane->normal));
surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv; surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv; surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
@ -797,8 +796,8 @@ void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
{ {
if (r_clipflags & mask) if (r_clipflags & mask)
{ {
view_clipplanes[i].next = pclip; qfrustum.view_clipplanes[i].next = pclip;
pclip = &view_clipplanes[i]; pclip = &qfrustum.view_clipplanes[i];
} }
} }
@ -836,7 +835,7 @@ void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
{ {
r_pedge = &tedge; r_pedge = &tedge;
r_nearzionly = true; r_nearzionly = true;
R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next); R_ClipEdge (&r_rightexit, &r_rightenter, qfrustum.view_clipplanes[1].next);
} }
// if no edges made it out, return without posting the surface // if no edges made it out, return without posting the surface
@ -858,7 +857,7 @@ void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
// FIXME: cache this? // FIXME: cache this?
TransformVector (pplane->normal, p_normal); TransformVector (pplane->normal, p_normal);
// FIXME: cache this? // FIXME: cache this?
distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal)); distinv = 1.0 / (pplane->dist - DotProduct (tr.modelorg, pplane->normal));
surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv; surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv; surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;

10
r_surf.c

@ -217,7 +217,7 @@ static void R_BuildLightMap( )
} }
// add all the dynamic lights // add all the dynamic lights
if( surf->dlightframe == r_framecount ) if( surf->dlightframe == tr.framecount )
R_AddDynamicLights( surf ); R_AddDynamicLights( surf );
// Put into texture format // Put into texture format
@ -1148,12 +1148,12 @@ surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
{ {
if( tr.lightstylevalue[surface->styles[maps]] != surface->cached_light[maps] ) if( tr.lightstylevalue[surface->styles[maps]] != surface->cached_light[maps] )
{ {
surface->dlightframe = r_framecount; surface->dlightframe = tr.framecount;
} }
} }
if (cache && !cache->dlight && surface->dlightframe != r_framecount if (cache && !cache->dlight && surface->dlightframe != tr.framecount
&& cache->image == r_drawsurf.image && cache->image == r_drawsurf.image
&& cache->lightadj[0] == r_drawsurf.lightadj[0] && cache->lightadj[0] == r_drawsurf.lightadj[0]
&& cache->lightadj[1] == r_drawsurf.lightadj[1] && cache->lightadj[1] == r_drawsurf.lightadj[1]
@ -1161,7 +1161,7 @@ surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
&& cache->lightadj[3] == r_drawsurf.lightadj[3] ) && cache->lightadj[3] == r_drawsurf.lightadj[3] )
return cache; return cache;
if( surface->dlightframe == r_framecount ) if( surface->dlightframe == tr.framecount )
{ {
int i; int i;
// invalidate dlight cache // invalidate dlight cache
@ -1193,7 +1193,7 @@ surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
cache->mipscale = surfscale; cache->mipscale = surfscale;
} }
if (surface->dlightframe == r_framecount) if (surface->dlightframe == tr.framecount)
cache->dlight = 1; cache->dlight = 1;
else else
cache->dlight = 0; cache->dlight = 0;

24
r_trialias.c

@ -96,9 +96,9 @@ void R_SetUpWorldTransform (void)
aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i]; aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i];
} }
aliasworldtransform[0][3] = -r_origin[0]; aliasworldtransform[0][3] = -RI.vieworg[0];
aliasworldtransform[1][3] = -r_origin[1]; aliasworldtransform[1][3] = -RI.vieworg[1];
aliasworldtransform[2][3] = -r_origin[2]; aliasworldtransform[2][3] = -RI.vieworg[2];
//aliasoldworldtransform[0][3] = RI.currententity->oldorigin[0]-r_origin[0]; //aliasoldworldtransform[0][3] = RI.currententity->oldorigin[0]-r_origin[0];
//aliasoldworldtransform[1][3] = RI.currententity->oldorigin[1]-r_origin[1]; //aliasoldworldtransform[1][3] = RI.currententity->oldorigin[1]-r_origin[1];
@ -110,11 +110,11 @@ void R_SetUpWorldTransform (void)
// R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix); // R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
// TODO: should be global, set when vright, etc., set // TODO: should be global, set when vright, etc., set
VectorCopy (vright, viewmatrix[0]); VectorCopy (RI.vright, viewmatrix[0]);
VectorCopy (vup, viewmatrix[1]); VectorCopy (RI.vup, viewmatrix[1]);
VectorInverse (viewmatrix[1]); VectorInverse (viewmatrix[1]);
//VectorScale(viewmatrix[1], -1, viewmatrix[1]); //VectorScale(viewmatrix[1], -1, viewmatrix[1]);
VectorCopy (vpn, viewmatrix[2]); VectorCopy (RI.vforward, viewmatrix[2]);
viewmatrix[0][3] = 0; viewmatrix[0][3] = 0;
viewmatrix[1][3] = 0; viewmatrix[1][3] = 0;
@ -169,9 +169,9 @@ void R_AliasSetUpTransform (void)
aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i]; aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i];
} }
aliasworldtransform[0][3] = RI.currententity->origin[0]-r_origin[0]; aliasworldtransform[0][3] = RI.currententity->origin[0]-RI.vieworg[0];
aliasworldtransform[1][3] = RI.currententity->origin[1]-r_origin[1]; aliasworldtransform[1][3] = RI.currententity->origin[1]-RI.vieworg[1];
aliasworldtransform[2][3] = RI.currententity->origin[2]-r_origin[2]; aliasworldtransform[2][3] = RI.currententity->origin[2]-RI.vieworg[2];
//aliasoldworldtransform[0][3] = RI.currententity->oldorigin[0]-r_origin[0]; //aliasoldworldtransform[0][3] = RI.currententity->oldorigin[0]-r_origin[0];
//aliasoldworldtransform[1][3] = RI.currententity->oldorigin[1]-r_origin[1]; //aliasoldworldtransform[1][3] = RI.currententity->oldorigin[1]-r_origin[1];
@ -183,11 +183,11 @@ void R_AliasSetUpTransform (void)
// R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix); // R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
// TODO: should be global, set when vright, etc., set // TODO: should be global, set when vright, etc., set
VectorCopy (vright, viewmatrix[0]); VectorCopy (RI.vright, viewmatrix[0]);
VectorCopy (vup, viewmatrix[1]); VectorCopy (RI.vup, viewmatrix[1]);
VectorInverse (viewmatrix[1]); VectorInverse (viewmatrix[1]);
//VectorScale(viewmatrix[1], -1, viewmatrix[1]); //VectorScale(viewmatrix[1], -1, viewmatrix[1]);
VectorCopy (vpn, viewmatrix[2]); VectorCopy (RI.vforward, viewmatrix[2]);
viewmatrix[0][3] = 0; viewmatrix[0][3] = 0;
viewmatrix[1][3] = 0; viewmatrix[1][3] = 0;

Loading…
Cancel
Save