mirror of
https://git.code.sf.net/p/quake/quakeforge-old
synced 2024-11-28 22:52:01 +00:00
merge qw_client/r_misc.c and uquake/r_misc.c int common/r_misc.c
merge qw_client/r_sprite.c and uquake/r_sprite.c int common/r_sprite.c
This commit is contained in:
parent
981acbc014
commit
0196064c51
4 changed files with 36 additions and 957 deletions
|
@ -1,4 +1,5 @@
|
|||
/*
|
||||
r_misc.c
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
Portions Copyright (C) 1999,2000 Nelson Rush.
|
||||
Copyright (C) 1999,2000 contributors of the QuakeForge project
|
||||
|
@ -20,16 +21,19 @@ along with this program; if not, write to the Free Software
|
|||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_misc.c
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "r_local.h"
|
||||
#include <quakedef.h>
|
||||
#include <r_local.h>
|
||||
#include <mathlib.h>
|
||||
#include <sys.h>
|
||||
#include <console.h>
|
||||
#include <cvar.h>
|
||||
#include <cvars.h>
|
||||
#include <view.h>
|
||||
#include <sbar.h>
|
||||
#include <menu.h>
|
||||
#include <draw.h>
|
||||
#include <mathlib.h>
|
||||
#include <console.h>
|
||||
#include <server.h>
|
||||
|
||||
|
||||
/*
|
||||
|
@ -39,7 +43,7 @@ R_CheckVariables
|
|||
*/
|
||||
void R_CheckVariables (void)
|
||||
{
|
||||
#if 0
|
||||
#ifdef UQUAKE
|
||||
static float oldbright;
|
||||
|
||||
if (r_fullbright.value != oldbright)
|
||||
|
@ -125,10 +129,10 @@ void R_LineGraph (int x, int y, int h)
|
|||
int color;
|
||||
|
||||
// FIXME: should be disabled on no-buffer adapters, or should be in the driver
|
||||
|
||||
// x += r_refdef.vrect.x;
|
||||
// y += r_refdef.vrect.y;
|
||||
|
||||
#ifdef UQUAKE
|
||||
x += r_refdef.vrect.x;
|
||||
y += r_refdef.vrect.y;
|
||||
#endif
|
||||
dest = vid.buffer + vid.rowbytes*y + x;
|
||||
|
||||
s = r_graphheight.value;
|
||||
|
@ -144,13 +148,15 @@ void R_LineGraph (int x, int y, int h)
|
|||
|
||||
if (h>s)
|
||||
h = s;
|
||||
|
||||
|
||||
for (i=0 ; i<h ; i++, dest -= vid.rowbytes*2)
|
||||
{
|
||||
dest[0] = color;
|
||||
// *(dest-vid.rowbytes) = 0x30;
|
||||
#ifdef UQUAKE
|
||||
*(dest-vid.rowbytes) = 0x30;
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
#ifdef UQUAKE
|
||||
for ( ; i<s ; i++, dest -= vid.rowbytes*2)
|
||||
{
|
||||
dest[0] = 0x30;
|
||||
|
@ -455,10 +461,13 @@ void R_SetupFrame (void)
|
|||
float w, h;
|
||||
|
||||
// don't allow cheats in multiplayer
|
||||
r_draworder.value = 0;
|
||||
r_fullbright.value = 0;
|
||||
r_ambient.value = 0;
|
||||
r_drawflat.value = 0;
|
||||
if (cl.maxclients > 1)
|
||||
{
|
||||
r_draworder.value = 0;
|
||||
r_fullbright.value = 0;
|
||||
r_ambient.value = 0;
|
||||
r_drawflat.value = 0;
|
||||
}
|
||||
|
||||
if (r_numsurfs.value)
|
||||
{
|
||||
|
@ -484,8 +493,9 @@ r_drawflat.value = 0;
|
|||
|
||||
if (r_refdef.ambientlight < 0)
|
||||
r_refdef.ambientlight = 0;
|
||||
|
||||
// if (!sv.active)
|
||||
#ifdef UQUAKE
|
||||
if (!sv.active)
|
||||
#endif
|
||||
r_draworder.value = 0; // don't let cheaters look behind walls
|
||||
|
||||
R_CheckVariables ();
|
||||
|
@ -519,7 +529,11 @@ r_refdef.viewangles[2]= 0;
|
|||
r_dowarpold = r_dowarp;
|
||||
r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= CONTENTS_WATER);
|
||||
|
||||
if ((r_dowarp != r_dowarpold) || r_viewchanged)
|
||||
if ((r_dowarp != r_dowarpold)
|
||||
#ifdef UQUAKE
|
||||
|| lcd_x.value
|
||||
#endif
|
||||
|| r_viewchanged)
|
||||
{
|
||||
if (r_dowarp)
|
||||
{
|
|
@ -24,7 +24,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "quakedef.h"
|
||||
#include "r_local.h"
|
||||
#include <mathlib.h>
|
||||
#include <lib_replace.h>
|
||||
#include <console.h>
|
||||
#include <sys.h>
|
||||
|
||||
static int clip_current;
|
||||
static vec5_t clip_verts[2][MAXWORKINGVERTS];
|
532
uquake/r_misc.c
532
uquake/r_misc.c
|
@ -1,532 +0,0 @@
|
|||
/*
|
||||
r_misc.c
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include <quakedef.h>
|
||||
#include <r_local.h>
|
||||
#include <mathlib.h>
|
||||
#include <sys.h>
|
||||
#include <console.h>
|
||||
#include <cvar.h>
|
||||
#include <cvars.h>
|
||||
#include <view.h>
|
||||
#include <sbar.h>
|
||||
#include <console.h>
|
||||
#include <server.h>
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_CheckVariables
|
||||
===============
|
||||
*/
|
||||
void R_CheckVariables (void)
|
||||
{
|
||||
static float oldbright;
|
||||
|
||||
if (r_fullbright.value != oldbright)
|
||||
{
|
||||
oldbright = r_fullbright.value;
|
||||
D_FlushCaches (); // so all lighting changes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Show
|
||||
|
||||
Debugging use
|
||||
============
|
||||
*/
|
||||
void Show (void)
|
||||
{
|
||||
vrect_t vr;
|
||||
|
||||
vr.x = vr.y = 0;
|
||||
vr.width = vid.width;
|
||||
vr.height = vid.height;
|
||||
vr.pnext = NULL;
|
||||
VID_Update (&vr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
R_TimeRefresh_f
|
||||
|
||||
For program optimization
|
||||
====================
|
||||
*/
|
||||
void R_TimeRefresh_f (void)
|
||||
{
|
||||
int i;
|
||||
float start, stop, time;
|
||||
int startangle;
|
||||
vrect_t vr;
|
||||
|
||||
startangle = r_refdef.viewangles[1];
|
||||
|
||||
start = Sys_DoubleTime ();
|
||||
for (i=0 ; i<128 ; i++)
|
||||
{
|
||||
r_refdef.viewangles[1] = i/128.0*360.0;
|
||||
|
||||
VID_LockBuffer ();
|
||||
|
||||
R_RenderView ();
|
||||
|
||||
VID_UnlockBuffer ();
|
||||
|
||||
vr.x = r_refdef.vrect.x;
|
||||
vr.y = r_refdef.vrect.y;
|
||||
vr.width = r_refdef.vrect.width;
|
||||
vr.height = r_refdef.vrect.height;
|
||||
vr.pnext = NULL;
|
||||
VID_Update (&vr);
|
||||
}
|
||||
stop = Sys_DoubleTime ();
|
||||
time = stop-start;
|
||||
Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
|
||||
|
||||
r_refdef.viewangles[1] = startangle;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_LineGraph
|
||||
|
||||
Only called by R_DisplayTime
|
||||
================
|
||||
*/
|
||||
void R_LineGraph (int x, int y, int h)
|
||||
{
|
||||
int i;
|
||||
byte *dest;
|
||||
int s;
|
||||
|
||||
// FIXME: should be disabled on no-buffer adapters, or should be in the driver
|
||||
|
||||
x += r_refdef.vrect.x;
|
||||
y += r_refdef.vrect.y;
|
||||
|
||||
dest = vid.buffer + vid.rowbytes*y + x;
|
||||
|
||||
s = r_graphheight.value;
|
||||
|
||||
if (h>s)
|
||||
h = s;
|
||||
|
||||
for (i=0 ; i<h ; i++, dest -= vid.rowbytes*2)
|
||||
{
|
||||
dest[0] = 0xff;
|
||||
*(dest-vid.rowbytes) = 0x30;
|
||||
}
|
||||
for ( ; i<s ; i++, dest -= vid.rowbytes*2)
|
||||
{
|
||||
dest[0] = 0x30;
|
||||
*(dest-vid.rowbytes) = 0x30;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
R_TimeGraph
|
||||
|
||||
Performance monitoring tool
|
||||
==============
|
||||
*/
|
||||
#define MAX_TIMINGS 100
|
||||
extern float mouse_x, mouse_y;
|
||||
void R_TimeGraph (void)
|
||||
{
|
||||
static int timex;
|
||||
int a;
|
||||
float r_time2;
|
||||
static byte r_timings[MAX_TIMINGS];
|
||||
int x;
|
||||
|
||||
r_time2 = Sys_DoubleTime ();
|
||||
|
||||
a = (r_time2-r_time1)/0.01;
|
||||
//a = fabs(mouse_y * 0.05);
|
||||
//a = (int)((r_refdef.vieworg[2] + 1024)/1)%(int)r_graphheight.value;
|
||||
//a = fabs(velocity[0])/20;
|
||||
//a = ((int)fabs(origin[0])/8)%20;
|
||||
//a = (cl.idealpitch + 30)/5;
|
||||
r_timings[timex] = a;
|
||||
a = timex;
|
||||
|
||||
if (r_refdef.vrect.width <= MAX_TIMINGS)
|
||||
x = r_refdef.vrect.width-1;
|
||||
else
|
||||
x = r_refdef.vrect.width -
|
||||
(r_refdef.vrect.width - MAX_TIMINGS)/2;
|
||||
do
|
||||
{
|
||||
R_LineGraph (x, r_refdef.vrect.height-2, r_timings[a]);
|
||||
if (x==0)
|
||||
break; // screen too small to hold entire thing
|
||||
x--;
|
||||
a--;
|
||||
if (a == -1)
|
||||
a = MAX_TIMINGS-1;
|
||||
} while (a != timex);
|
||||
|
||||
timex = (timex+1)%MAX_TIMINGS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PrintTimes
|
||||
=============
|
||||
*/
|
||||
void R_PrintTimes (void)
|
||||
{
|
||||
float r_time2;
|
||||
float ms;
|
||||
|
||||
r_time2 = Sys_DoubleTime ();
|
||||
|
||||
ms = 1000* (r_time2 - r_time1);
|
||||
|
||||
Con_Printf ("%5.1f ms %3i/%3i/%3i poly %3i surf\n",
|
||||
ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
|
||||
c_surf = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PrintDSpeeds
|
||||
=============
|
||||
*/
|
||||
void R_PrintDSpeeds (void)
|
||||
{
|
||||
float ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, dv_time;
|
||||
|
||||
r_time2 = Sys_DoubleTime ();
|
||||
|
||||
dp_time = (dp_time2 - dp_time1) * 1000;
|
||||
rw_time = (rw_time2 - rw_time1) * 1000;
|
||||
db_time = (db_time2 - db_time1) * 1000;
|
||||
se_time = (se_time2 - se_time1) * 1000;
|
||||
de_time = (de_time2 - de_time1) * 1000;
|
||||
dv_time = (dv_time2 - dv_time1) * 1000;
|
||||
ms = (r_time2 - r_time1) * 1000;
|
||||
|
||||
Con_Printf ("%3i %4.1fp %3iw %4.1fb %3is %4.1fe %4.1fv\n",
|
||||
(int)ms, dp_time, (int)rw_time, db_time, (int)se_time, de_time,
|
||||
dv_time);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PrintAliasStats
|
||||
=============
|
||||
*/
|
||||
void R_PrintAliasStats (void)
|
||||
{
|
||||
Con_Printf ("%3i polygon model drawn\n", r_amodels_drawn);
|
||||
}
|
||||
|
||||
|
||||
void WarpPalette (void)
|
||||
{
|
||||
int i,j;
|
||||
byte newpalette[768];
|
||||
int basecolor[3];
|
||||
|
||||
basecolor[0] = 130;
|
||||
basecolor[1] = 80;
|
||||
basecolor[2] = 50;
|
||||
|
||||
// pull the colors halfway to bright brown
|
||||
for (i=0 ; i<256 ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
newpalette[i*3+j] = (host_basepal[i*3+j] + basecolor[j])/2;
|
||||
}
|
||||
}
|
||||
|
||||
VID_ShiftPalette (newpalette);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
R_TransformFrustum
|
||||
===================
|
||||
*/
|
||||
void R_TransformFrustum (void)
|
||||
{
|
||||
int i;
|
||||
vec3_t v, v2;
|
||||
|
||||
for (i=0 ; i<4 ; i++)
|
||||
{
|
||||
v[0] = screenedge[i].normal[2];
|
||||
v[1] = -screenedge[i].normal[0];
|
||||
v[2] = screenedge[i].normal[1];
|
||||
|
||||
v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
|
||||
v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
|
||||
v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
|
||||
|
||||
VectorCopy (v2, view_clipplanes[i].normal);
|
||||
|
||||
view_clipplanes[i].dist = DotProduct (modelorg, v2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !id386
|
||||
|
||||
/*
|
||||
================
|
||||
TransformVector
|
||||
================
|
||||
*/
|
||||
void TransformVector (vec3_t in, vec3_t out)
|
||||
{
|
||||
out[0] = DotProduct(in,vright);
|
||||
out[1] = DotProduct(in,vup);
|
||||
out[2] = DotProduct(in,vpn);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_TransformPlane
|
||||
================
|
||||
*/
|
||||
void R_TransformPlane (mplane_t *p, float *normal, float *dist)
|
||||
{
|
||||
float d;
|
||||
|
||||
d = DotProduct (r_origin, p->normal);
|
||||
*dist = p->dist - d;
|
||||
// TODO: when we have rotating entities, this will need to use the view matrix
|
||||
TransformVector (p->normal, normal);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_SetUpFrustumIndexes
|
||||
===============
|
||||
*/
|
||||
void R_SetUpFrustumIndexes (void)
|
||||
{
|
||||
int i, j, *pindex;
|
||||
|
||||
pindex = r_frustum_indexes;
|
||||
|
||||
for (i=0 ; i<4 ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
if (view_clipplanes[i].normal[j] < 0)
|
||||
{
|
||||
pindex[j] = j;
|
||||
pindex[j+3] = j+3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pindex[j] = j+3;
|
||||
pindex[j+3] = j;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: do just once at start
|
||||
pfrustum_indexes[i] = pindex;
|
||||
pindex += 6;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_SetupFrame
|
||||
===============
|
||||
*/
|
||||
void R_SetupFrame (void)
|
||||
{
|
||||
int edgecount;
|
||||
vrect_t vrect;
|
||||
float w, h;
|
||||
|
||||
// don't allow cheats in multiplayer
|
||||
if (cl.maxclients > 1)
|
||||
{
|
||||
Cvar_Set ("r_draworder", "0");
|
||||
Cvar_Set ("r_fullbright", "0");
|
||||
Cvar_Set ("r_ambient", "0");
|
||||
Cvar_Set ("r_drawflat", "0");
|
||||
}
|
||||
|
||||
if (r_numsurfs.value)
|
||||
{
|
||||
if ((surface_p - surfaces) > r_maxsurfsseen)
|
||||
r_maxsurfsseen = surface_p - surfaces;
|
||||
|
||||
Con_Printf ("Used %d of %d surfs; %d max\n", surface_p - surfaces,
|
||||
surf_max - surfaces, r_maxsurfsseen);
|
||||
}
|
||||
|
||||
if (r_numedges.value)
|
||||
{
|
||||
edgecount = edge_p - r_edges;
|
||||
|
||||
if (edgecount > r_maxedgesseen)
|
||||
r_maxedgesseen = edgecount;
|
||||
|
||||
Con_Printf ("Used %d of %d edges; %d max\n", edgecount,
|
||||
r_numallocatededges, r_maxedgesseen);
|
||||
}
|
||||
|
||||
r_refdef.ambientlight = r_ambient.value;
|
||||
|
||||
if (r_refdef.ambientlight < 0)
|
||||
r_refdef.ambientlight = 0;
|
||||
|
||||
if (!sv.active)
|
||||
r_draworder.value = 0; // don't let cheaters look behind walls
|
||||
|
||||
R_CheckVariables ();
|
||||
|
||||
R_AnimateLight ();
|
||||
|
||||
r_framecount++;
|
||||
|
||||
numbtofpolys = 0;
|
||||
|
||||
// debugging
|
||||
#if 0
|
||||
r_refdef.vieworg[0]= 80;
|
||||
r_refdef.vieworg[1]= 64;
|
||||
r_refdef.vieworg[2]= 40;
|
||||
r_refdef.viewangles[0]= 0;
|
||||
r_refdef.viewangles[1]= 46.763641357;
|
||||
r_refdef.viewangles[2]= 0;
|
||||
#endif
|
||||
|
||||
// build the transformation matrix for the given view angles
|
||||
VectorCopy (r_refdef.vieworg, modelorg);
|
||||
VectorCopy (r_refdef.vieworg, r_origin);
|
||||
|
||||
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
|
||||
|
||||
// current viewleaf
|
||||
r_oldviewleaf = r_viewleaf;
|
||||
r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
|
||||
|
||||
r_dowarpold = r_dowarp;
|
||||
r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= CONTENTS_WATER);
|
||||
|
||||
if ((r_dowarp != r_dowarpold) || r_viewchanged || lcd_x.value)
|
||||
{
|
||||
if (r_dowarp)
|
||||
{
|
||||
if ((vid.width <= vid.maxwarpwidth) &&
|
||||
(vid.height <= vid.maxwarpheight))
|
||||
{
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = vid.width;
|
||||
vrect.height = vid.height;
|
||||
|
||||
R_ViewChanged (&vrect, sb_lines, vid.aspect);
|
||||
}
|
||||
else
|
||||
{
|
||||
w = vid.width;
|
||||
h = vid.height;
|
||||
|
||||
if (w > vid.maxwarpwidth)
|
||||
{
|
||||
h *= (float)vid.maxwarpwidth / w;
|
||||
w = vid.maxwarpwidth;
|
||||
}
|
||||
|
||||
if (h > vid.maxwarpheight)
|
||||
{
|
||||
h = vid.maxwarpheight;
|
||||
w *= (float)vid.maxwarpheight / h;
|
||||
}
|
||||
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = (int)w;
|
||||
vrect.height = (int)h;
|
||||
|
||||
R_ViewChanged (&vrect,
|
||||
(int)((float)sb_lines * (h/(float)vid.height)),
|
||||
vid.aspect * (h / w) *
|
||||
((float)vid.width / (float)vid.height));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = vid.width;
|
||||
vrect.height = vid.height;
|
||||
|
||||
R_ViewChanged (&vrect, sb_lines, vid.aspect);
|
||||
}
|
||||
|
||||
r_viewchanged = false;
|
||||
}
|
||||
|
||||
// start off with just the four screen edge clip planes
|
||||
R_TransformFrustum ();
|
||||
|
||||
// save base values
|
||||
VectorCopy (vpn, base_vpn);
|
||||
VectorCopy (vright, base_vright);
|
||||
VectorCopy (vup, base_vup);
|
||||
VectorCopy (modelorg, base_modelorg);
|
||||
|
||||
R_SetSkyFrame ();
|
||||
|
||||
R_SetUpFrustumIndexes ();
|
||||
|
||||
r_cache_thrash = false;
|
||||
|
||||
// clear frame counts
|
||||
c_faceclip = 0;
|
||||
d_spanpixcount = 0;
|
||||
r_polycount = 0;
|
||||
r_drawnpolycount = 0;
|
||||
r_wholepolycount = 0;
|
||||
r_amodels_drawn = 0;
|
||||
r_outofsurfaces = 0;
|
||||
r_outofedges = 0;
|
||||
|
||||
D_SetupFrame ();
|
||||
}
|
||||
|
|
@ -1,405 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_sprite.c
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "r_local.h"
|
||||
#include <mathlib.h>
|
||||
#include <lib_replace.h>
|
||||
#include <console.h>
|
||||
#include <sys.h>
|
||||
|
||||
static int clip_current;
|
||||
static vec5_t clip_verts[2][MAXWORKINGVERTS];
|
||||
static int sprite_width, sprite_height;
|
||||
|
||||
spritedesc_t r_spritedesc;
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RotateSprite
|
||||
================
|
||||
*/
|
||||
void R_RotateSprite (float beamlength)
|
||||
{
|
||||
vec3_t vec;
|
||||
|
||||
if (beamlength == 0.0)
|
||||
return;
|
||||
|
||||
VectorScale (r_spritedesc.vpn, -beamlength, vec);
|
||||
VectorAdd (r_entorigin, vec, r_entorigin);
|
||||
VectorSubtract (modelorg, vec, modelorg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_ClipSpriteFace
|
||||
|
||||
Clips the winding at clip_verts[clip_current] and changes clip_current
|
||||
Throws out the back side
|
||||
==============
|
||||
*/
|
||||
int R_ClipSpriteFace (int nump, clipplane_t *pclipplane)
|
||||
{
|
||||
int i, outcount;
|
||||
float dists[MAXWORKINGVERTS+1];
|
||||
float frac, clipdist, *pclipnormal;
|
||||
float *in, *instep, *outstep, *vert2;
|
||||
|
||||
clipdist = pclipplane->dist;
|
||||
pclipnormal = pclipplane->normal;
|
||||
|
||||
// calc dists
|
||||
if (clip_current)
|
||||
{
|
||||
in = clip_verts[1][0];
|
||||
outstep = clip_verts[0][0];
|
||||
clip_current = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
in = clip_verts[0][0];
|
||||
outstep = clip_verts[1][0];
|
||||
clip_current = 1;
|
||||
}
|
||||
|
||||
instep = in;
|
||||
for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
|
||||
{
|
||||
dists[i] = DotProduct (instep, pclipnormal) - clipdist;
|
||||
}
|
||||
|
||||
// handle wraparound case
|
||||
dists[nump] = dists[0];
|
||||
Q_memcpy (instep, in, sizeof (vec5_t));
|
||||
|
||||
|
||||
// clip the winding
|
||||
instep = in;
|
||||
outcount = 0;
|
||||
|
||||
for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
|
||||
{
|
||||
if (dists[i] >= 0)
|
||||
{
|
||||
Q_memcpy (outstep, instep, sizeof (vec5_t));
|
||||
outstep += sizeof (vec5_t) / sizeof (float);
|
||||
outcount++;
|
||||
}
|
||||
|
||||
if (dists[i] == 0 || dists[i+1] == 0)
|
||||
continue;
|
||||
|
||||
if ( (dists[i] > 0) == (dists[i+1] > 0) )
|
||||
continue;
|
||||
|
||||
// split it into a new vertex
|
||||
frac = dists[i] / (dists[i] - dists[i+1]);
|
||||
|
||||
vert2 = instep + sizeof (vec5_t) / sizeof (float);
|
||||
|
||||
outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
|
||||
outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
|
||||
outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
|
||||
outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
|
||||
outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
|
||||
|
||||
outstep += sizeof (vec5_t) / sizeof (float);
|
||||
outcount++;
|
||||
}
|
||||
|
||||
return outcount;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_SetupAndDrawSprite
|
||||
================
|
||||
*/
|
||||
void R_SetupAndDrawSprite ()
|
||||
{
|
||||
int i, nump;
|
||||
float dot, scale, *pv;
|
||||
vec5_t *pverts;
|
||||
vec3_t left, up, right, down, transformed, local;
|
||||
emitpoint_t outverts[MAXWORKINGVERTS+1], *pout;
|
||||
|
||||
dot = DotProduct (r_spritedesc.vpn, modelorg);
|
||||
|
||||
// backface cull
|
||||
if (dot >= 0)
|
||||
return;
|
||||
|
||||
// build the sprite poster in worldspace
|
||||
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right);
|
||||
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up);
|
||||
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left);
|
||||
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down);
|
||||
|
||||
pverts = clip_verts[0];
|
||||
|
||||
pverts[0][0] = r_entorigin[0] + up[0] + left[0];
|
||||
pverts[0][1] = r_entorigin[1] + up[1] + left[1];
|
||||
pverts[0][2] = r_entorigin[2] + up[2] + left[2];
|
||||
pverts[0][3] = 0;
|
||||
pverts[0][4] = 0;
|
||||
|
||||
pverts[1][0] = r_entorigin[0] + up[0] + right[0];
|
||||
pverts[1][1] = r_entorigin[1] + up[1] + right[1];
|
||||
pverts[1][2] = r_entorigin[2] + up[2] + right[2];
|
||||
pverts[1][3] = sprite_width;
|
||||
pverts[1][4] = 0;
|
||||
|
||||
pverts[2][0] = r_entorigin[0] + down[0] + right[0];
|
||||
pverts[2][1] = r_entorigin[1] + down[1] + right[1];
|
||||
pverts[2][2] = r_entorigin[2] + down[2] + right[2];
|
||||
pverts[2][3] = sprite_width;
|
||||
pverts[2][4] = sprite_height;
|
||||
|
||||
pverts[3][0] = r_entorigin[0] + down[0] + left[0];
|
||||
pverts[3][1] = r_entorigin[1] + down[1] + left[1];
|
||||
pverts[3][2] = r_entorigin[2] + down[2] + left[2];
|
||||
pverts[3][3] = 0;
|
||||
pverts[3][4] = sprite_height;
|
||||
|
||||
// clip to the frustum in worldspace
|
||||
nump = 4;
|
||||
clip_current = 0;
|
||||
|
||||
for (i=0 ; i<4 ; i++)
|
||||
{
|
||||
nump = R_ClipSpriteFace (nump, &view_clipplanes[i]);
|
||||
if (nump < 3)
|
||||
return;
|
||||
if (nump >= MAXWORKINGVERTS)
|
||||
Sys_Error("R_SetupAndDrawSprite: too many points");
|
||||
}
|
||||
|
||||
// transform vertices into viewspace and project
|
||||
pv = &clip_verts[clip_current][0][0];
|
||||
r_spritedesc.nearzi = -999999;
|
||||
|
||||
for (i=0 ; i<nump ; i++)
|
||||
{
|
||||
VectorSubtract (pv, r_origin, local);
|
||||
TransformVector (local, transformed);
|
||||
|
||||
if (transformed[2] < NEAR_CLIP)
|
||||
transformed[2] = NEAR_CLIP;
|
||||
|
||||
pout = &outverts[i];
|
||||
pout->zi = 1.0 / transformed[2];
|
||||
if (pout->zi > r_spritedesc.nearzi)
|
||||
r_spritedesc.nearzi = pout->zi;
|
||||
|
||||
pout->s = pv[3];
|
||||
pout->t = pv[4];
|
||||
|
||||
scale = xscale * pout->zi;
|
||||
pout->u = (xcenter + scale * transformed[0]);
|
||||
|
||||
scale = yscale * pout->zi;
|
||||
pout->v = (ycenter - scale * transformed[1]);
|
||||
|
||||
pv += sizeof (vec5_t) / sizeof (*pv);
|
||||
}
|
||||
|
||||
// draw it
|
||||
r_spritedesc.nump = nump;
|
||||
r_spritedesc.pverts = outverts;
|
||||
D_DrawSprite ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_GetSpriteframe
|
||||
================
|
||||
*/
|
||||
mspriteframe_t *R_GetSpriteframe (msprite_t *psprite)
|
||||
{
|
||||
mspritegroup_t *pspritegroup;
|
||||
mspriteframe_t *pspriteframe;
|
||||
int i, numframes, frame;
|
||||
float *pintervals, fullinterval, targettime, time;
|
||||
|
||||
frame = currententity->frame;
|
||||
|
||||
if ((frame >= psprite->numframes) || (frame < 0))
|
||||
{
|
||||
Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
|
||||
frame = 0;
|
||||
}
|
||||
|
||||
if (psprite->frames[frame].type == SPR_SINGLE)
|
||||
{
|
||||
pspriteframe = psprite->frames[frame].frameptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
|
||||
pintervals = pspritegroup->intervals;
|
||||
numframes = pspritegroup->numframes;
|
||||
fullinterval = pintervals[numframes-1];
|
||||
|
||||
time = cl.time + currententity->syncbase;
|
||||
|
||||
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
|
||||
// are positive, so we don't have to worry about division by 0
|
||||
targettime = time - ((int)(time / fullinterval)) * fullinterval;
|
||||
|
||||
for (i=0 ; i<(numframes-1) ; i++)
|
||||
{
|
||||
if (pintervals[i] > targettime)
|
||||
break;
|
||||
}
|
||||
|
||||
pspriteframe = pspritegroup->frames[i];
|
||||
}
|
||||
|
||||
return pspriteframe;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSprite
|
||||
================
|
||||
*/
|
||||
void R_DrawSprite (void)
|
||||
{
|
||||
int i;
|
||||
msprite_t *psprite;
|
||||
vec3_t tvec;
|
||||
float dot, angle, sr, cr;
|
||||
|
||||
psprite = currententity->model->cache.data;
|
||||
|
||||
r_spritedesc.pspriteframe = R_GetSpriteframe (psprite);
|
||||
|
||||
sprite_width = r_spritedesc.pspriteframe->width;
|
||||
sprite_height = r_spritedesc.pspriteframe->height;
|
||||
|
||||
// TODO: make this caller-selectable
|
||||
if (psprite->type == SPR_FACING_UPRIGHT)
|
||||
{
|
||||
// generate the sprite's axes, with vup straight up in worldspace, and
|
||||
// r_spritedesc.vright perpendicular to modelorg.
|
||||
// This will not work if the view direction is very close to straight up or
|
||||
// down, because the cross product will be between two nearly parallel
|
||||
// vectors and starts to approach an undefined state, so we don't draw if
|
||||
// the two vectors are less than 1 degree apart
|
||||
tvec[0] = -modelorg[0];
|
||||
tvec[1] = -modelorg[1];
|
||||
tvec[2] = -modelorg[2];
|
||||
VectorNormalize (tvec);
|
||||
dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
|
||||
// r_spritedesc.vup is 0, 0, 1
|
||||
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
|
||||
return;
|
||||
r_spritedesc.vup[0] = 0;
|
||||
r_spritedesc.vup[1] = 0;
|
||||
r_spritedesc.vup[2] = 1;
|
||||
r_spritedesc.vright[0] = tvec[1];
|
||||
// CrossProduct(r_spritedesc.vup, -modelorg,
|
||||
r_spritedesc.vright[1] = -tvec[0];
|
||||
// r_spritedesc.vright)
|
||||
r_spritedesc.vright[2] = 0;
|
||||
VectorNormalize (r_spritedesc.vright);
|
||||
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
|
||||
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
|
||||
r_spritedesc.vpn[2] = 0;
|
||||
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
|
||||
// r_spritedesc.vpn)
|
||||
}
|
||||
else if (psprite->type == SPR_VP_PARALLEL)
|
||||
{
|
||||
// generate the sprite's axes, completely parallel to the viewplane. There
|
||||
// are no problem situations, because the sprite is always in the same
|
||||
// position relative to the viewer
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
r_spritedesc.vup[i] = vup[i];
|
||||
r_spritedesc.vright[i] = vright[i];
|
||||
r_spritedesc.vpn[i] = vpn[i];
|
||||
}
|
||||
}
|
||||
else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT)
|
||||
{
|
||||
// generate the sprite's axes, with vup straight up in worldspace, and
|
||||
// r_spritedesc.vright parallel to the viewplane.
|
||||
// This will not work if the view direction is very close to straight up or
|
||||
// down, because the cross product will be between two nearly parallel
|
||||
// vectors and starts to approach an undefined state, so we don't draw if
|
||||
// the two vectors are less than 1 degree apart
|
||||
dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because
|
||||
// r_spritedesc.vup is 0, 0, 1
|
||||
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
|
||||
return;
|
||||
r_spritedesc.vup[0] = 0;
|
||||
r_spritedesc.vup[1] = 0;
|
||||
r_spritedesc.vup[2] = 1;
|
||||
r_spritedesc.vright[0] = vpn[1];
|
||||
// CrossProduct (r_spritedesc.vup, vpn,
|
||||
r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright)
|
||||
r_spritedesc.vright[2] = 0;
|
||||
VectorNormalize (r_spritedesc.vright);
|
||||
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
|
||||
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
|
||||
r_spritedesc.vpn[2] = 0;
|
||||
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
|
||||
// r_spritedesc.vpn)
|
||||
}
|
||||
else if (psprite->type == SPR_ORIENTED)
|
||||
{
|
||||
// generate the sprite's axes, according to the sprite's world orientation
|
||||
AngleVectors (currententity->angles, r_spritedesc.vpn,
|
||||
r_spritedesc.vright, r_spritedesc.vup);
|
||||
}
|
||||
else if (psprite->type == SPR_VP_PARALLEL_ORIENTED)
|
||||
{
|
||||
// generate the sprite's axes, parallel to the viewplane, but rotated in
|
||||
// that plane around the center according to the sprite entity's roll
|
||||
// angle. So vpn stays the same, but vright and vup rotate
|
||||
angle = currententity->angles[ROLL] * (M_PI*2 / 360);
|
||||
sr = sin(angle);
|
||||
cr = cos(angle);
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
r_spritedesc.vpn[i] = vpn[i];
|
||||
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
||||
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type);
|
||||
}
|
||||
|
||||
R_RotateSprite (psprite->beamlength);
|
||||
|
||||
R_SetupAndDrawSprite ();
|
||||
}
|
||||
|
Loading…
Reference in a new issue