mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-29 23:52:22 +00:00
db7f8a461e
While the libraries are probably getting a little out of hand, the separation into its own directory is probably a good thing as an ECS should not be tied to scenes. This should make the ECS more generally useful.
272 lines
6.8 KiB
C
272 lines
6.8 KiB
C
/*
|
|
sw_rsprite.c
|
|
|
|
(description)
|
|
|
|
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:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <string.h>
|
|
#endif
|
|
|
|
#include <math.h>
|
|
|
|
#include "QF/render.h"
|
|
#include "QF/sys.h"
|
|
|
|
#include "QF/scene/entity.h"
|
|
|
|
#include "r_internal.h"
|
|
|
|
static int clip_current;
|
|
static vec5_t clip_verts[2][MAXWORKINGVERTS];
|
|
static int sprite_width, sprite_height;
|
|
|
|
spritedesc_t r_spritedesc;
|
|
|
|
|
|
static void
|
|
R_RotateSprite (vec4f_t relvieworg, float beamlength, vec3_t org)
|
|
{
|
|
vec3_t vec;
|
|
|
|
VectorCopy (relvieworg, org);
|
|
if (beamlength == 0.0)
|
|
return;
|
|
|
|
VectorScale (r_spritedesc.vfwd, -beamlength, vec);
|
|
VectorAdd (r_entorigin, vec, r_entorigin);
|
|
VectorSubtract (relvieworg, vec, org);
|
|
}
|
|
|
|
|
|
/*
|
|
R_ClipSpriteFace
|
|
|
|
Clips the winding at clip_verts[clip_current] and changes clip_current
|
|
Throws out the back side
|
|
*/
|
|
static 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];
|
|
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) {
|
|
memcpy (outstep, instep, sizeof (vec5_t));
|
|
outstep += sizeof (vec5_t) / sizeof (float);
|
|
outcount++;
|
|
}
|
|
|
|
if (dists[i] == 0 || dists[i + 1] == 0)
|
|
continue;
|
|
#if __APPLE_CC__ <= 1175
|
|
// bug in gcc (GCC) 3.1 20020420 (prerelease) for darwin
|
|
if ((dists[i] > 0) && (dists[i + 1] > 0))
|
|
continue;
|
|
if ((dists[i] <= 0) && (dists[i + 1] <= 0))
|
|
continue;
|
|
#else
|
|
if ((dists[i] > 0) == (dists[i + 1] > 0))
|
|
continue;
|
|
#endif
|
|
|
|
// 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;
|
|
}
|
|
|
|
|
|
static void
|
|
R_SetupAndDrawSprite (const vec3_t relvieworg)
|
|
{
|
|
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.vfwd, relvieworg);
|
|
|
|
// 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_refdef.frame.position, 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 (relvieworg);
|
|
}
|
|
|
|
void
|
|
R_DrawSprite (entity_t ent)
|
|
{
|
|
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg);
|
|
msprite_t *sprite = renderer->model->cache.data;
|
|
|
|
animation_t *animation = Ent_GetComponent (ent.id, scene_animation,
|
|
ent.reg);
|
|
r_spritedesc.pspriteframe = R_GetSpriteFrame (sprite, animation);
|
|
|
|
sprite_width = r_spritedesc.pspriteframe->width;
|
|
sprite_height = r_spritedesc.pspriteframe->height;
|
|
|
|
vec4f_t up = {}, right = {}, fwd = {};
|
|
vec4f_t cameravec = r_refdef.frame.position - r_entorigin;
|
|
transform_t transform = Entity_Transform (ent);
|
|
if (!R_BillboardFrame (transform, sprite->type, cameravec,
|
|
&up, &right, &fwd)) {
|
|
// the orientation is undefined so can't draw the sprite
|
|
return;
|
|
}
|
|
VectorCopy (up, r_spritedesc.vup);//FIXME
|
|
VectorCopy (right, r_spritedesc.vright);
|
|
VectorCopy (fwd, r_spritedesc.vfwd);
|
|
|
|
vec3_t org;
|
|
R_RotateSprite (cameravec, sprite->beamlength, org);
|
|
|
|
R_SetupAndDrawSprite (org);
|
|
}
|