mirror of https://github.com/FWGS/xash3d-fwgs
Add 'ref_soft/' from commit '9045657352c7dfd3622cdf2b69462ca33f4262ee'
git-subtree-dir: ref_soft git-subtree-mainline:89ca0dec5e
git-subtree-split:9045657352
This commit is contained in:
commit
7429a6bc8a
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,323 @@
|
||||||
|
/*
|
||||||
|
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_aclip.c: clip routines for drawing Alias models directly to the screen
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
|
||||||
|
static finalvert_t fv[2][8];
|
||||||
|
|
||||||
|
void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
|
||||||
|
void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1,
|
||||||
|
finalvert_t *out);
|
||||||
|
void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
|
||||||
|
finalvert_t *out);
|
||||||
|
void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1,
|
||||||
|
finalvert_t *out);
|
||||||
|
void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
|
||||||
|
finalvert_t *out);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_Alias_clip_z
|
||||||
|
|
||||||
|
pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
|
||||||
|
{
|
||||||
|
float scale;
|
||||||
|
|
||||||
|
scale = (ALIAS_Z_CLIP_PLANE - pfv0->xyz[2]) /
|
||||||
|
(pfv1->xyz[2] - pfv0->xyz[2]);
|
||||||
|
|
||||||
|
out->xyz[0] = pfv0->xyz[0] + (pfv1->xyz[0] - pfv0->xyz[0]) * scale;
|
||||||
|
out->xyz[1] = pfv0->xyz[1] + (pfv1->xyz[1] - pfv0->xyz[1]) * scale;
|
||||||
|
out->xyz[2] = ALIAS_Z_CLIP_PLANE;
|
||||||
|
|
||||||
|
out->s = pfv0->s + (pfv1->s - pfv0->s) * scale;
|
||||||
|
out->t = pfv0->t + (pfv1->t - pfv0->t) * scale;
|
||||||
|
out->l = pfv0->l + (pfv1->l - pfv0->l) * scale;
|
||||||
|
|
||||||
|
R_AliasProjectAndClipTestFinalVert (out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !id386
|
||||||
|
|
||||||
|
void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
|
||||||
|
{
|
||||||
|
float scale;
|
||||||
|
|
||||||
|
if (pfv0->v >= pfv1->v )
|
||||||
|
{
|
||||||
|
scale = (float)(RI.aliasvrect.x - pfv0->u) /
|
||||||
|
(pfv1->u - pfv0->u);
|
||||||
|
out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5f;
|
||||||
|
out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5f;
|
||||||
|
out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5f;
|
||||||
|
out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5f;
|
||||||
|
out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5f;
|
||||||
|
out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scale = (float)(RI.aliasvrect.x - pfv1->u) /
|
||||||
|
(pfv0->u - pfv1->u);
|
||||||
|
out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5f;
|
||||||
|
out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5f;
|
||||||
|
out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5f;
|
||||||
|
out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5f;
|
||||||
|
out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5f;
|
||||||
|
out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
|
||||||
|
{
|
||||||
|
float scale;
|
||||||
|
|
||||||
|
if ( pfv0->v >= pfv1->v )
|
||||||
|
{
|
||||||
|
scale = (float)(RI.aliasvrectright - pfv0->u ) /
|
||||||
|
(pfv1->u - pfv0->u );
|
||||||
|
out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5f;
|
||||||
|
out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5f;
|
||||||
|
out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5f;
|
||||||
|
out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5f;
|
||||||
|
out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5f;
|
||||||
|
out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scale = (float)(RI.aliasvrectright - pfv1->u ) /
|
||||||
|
(pfv0->u - pfv1->u );
|
||||||
|
out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5f;
|
||||||
|
out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5f;
|
||||||
|
out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5f;
|
||||||
|
out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5f;
|
||||||
|
out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5f;
|
||||||
|
out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
|
||||||
|
{
|
||||||
|
float scale;
|
||||||
|
|
||||||
|
if (pfv0->v >= pfv1->v)
|
||||||
|
{
|
||||||
|
scale = (float)(RI.aliasvrect.y - pfv0->v) /
|
||||||
|
(pfv1->v - pfv0->v);
|
||||||
|
out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5f;
|
||||||
|
out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5f;
|
||||||
|
out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5f;
|
||||||
|
out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5f;
|
||||||
|
out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5f;
|
||||||
|
out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scale = (float)(RI.aliasvrect.y - pfv1->v) /
|
||||||
|
(pfv0->v - pfv1->v);
|
||||||
|
out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5f;
|
||||||
|
out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5f;
|
||||||
|
out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5f;
|
||||||
|
out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5f;
|
||||||
|
out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5f;
|
||||||
|
out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
|
||||||
|
finalvert_t *out)
|
||||||
|
{
|
||||||
|
float scale;
|
||||||
|
|
||||||
|
if (pfv0->v >= pfv1->v)
|
||||||
|
{
|
||||||
|
scale = (float)(RI.aliasvrectbottom - pfv0->v) /
|
||||||
|
(pfv1->v - pfv0->v);
|
||||||
|
|
||||||
|
out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5f;
|
||||||
|
out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5f;
|
||||||
|
out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5f;
|
||||||
|
out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5f;
|
||||||
|
out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5f;
|
||||||
|
out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scale = (float)(RI.aliasvrectbottom - pfv1->v) /
|
||||||
|
(pfv0->v - pfv1->v);
|
||||||
|
|
||||||
|
out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5f;
|
||||||
|
out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5f;
|
||||||
|
out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5f;
|
||||||
|
out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5f;
|
||||||
|
out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5f;
|
||||||
|
out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
|
||||||
|
void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) )
|
||||||
|
{
|
||||||
|
int i,j,k;
|
||||||
|
int flags, oldflags;
|
||||||
|
|
||||||
|
j = count-1;
|
||||||
|
k = 0;
|
||||||
|
for (i=0 ; i<count ; j = i, i++)
|
||||||
|
{
|
||||||
|
oldflags = in[j].flags & flag;
|
||||||
|
flags = in[i].flags & flag;
|
||||||
|
|
||||||
|
if (flags && oldflags)
|
||||||
|
continue;
|
||||||
|
if (oldflags ^ flags)
|
||||||
|
{
|
||||||
|
clip (&in[j], &in[i], &out[k]);
|
||||||
|
out[k].flags = 0;
|
||||||
|
if (out[k].u < RI.aliasvrect.x)
|
||||||
|
out[k].flags |= ALIAS_LEFT_CLIP;
|
||||||
|
if (out[k].v < RI.aliasvrect.y)
|
||||||
|
out[k].flags |= ALIAS_TOP_CLIP;
|
||||||
|
if (out[k].u > RI.aliasvrectright)
|
||||||
|
out[k].flags |= ALIAS_RIGHT_CLIP;
|
||||||
|
if (out[k].v > RI.aliasvrectbottom)
|
||||||
|
out[k].flags |= ALIAS_BOTTOM_CLIP;
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
if (!flags)
|
||||||
|
{
|
||||||
|
out[k] = in[i];
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_AliasClipTriangle
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2)
|
||||||
|
{
|
||||||
|
int i, k, pingpong;
|
||||||
|
unsigned clipflags;
|
||||||
|
|
||||||
|
// copy vertexes and fix seam texture coordinates
|
||||||
|
fv[0][0] = *index0;
|
||||||
|
fv[0][1] = *index1;
|
||||||
|
fv[0][2] = *index2;
|
||||||
|
|
||||||
|
// clip
|
||||||
|
clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
|
||||||
|
|
||||||
|
if (clipflags & ALIAS_Z_CLIP)
|
||||||
|
{
|
||||||
|
k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
|
||||||
|
if (k == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pingpong = 1;
|
||||||
|
clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pingpong = 0;
|
||||||
|
k = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clipflags & ALIAS_LEFT_CLIP)
|
||||||
|
{
|
||||||
|
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
|
||||||
|
ALIAS_LEFT_CLIP, k, R_Alias_clip_left);
|
||||||
|
if (k == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pingpong ^= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clipflags & ALIAS_RIGHT_CLIP)
|
||||||
|
{
|
||||||
|
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
|
||||||
|
ALIAS_RIGHT_CLIP, k, R_Alias_clip_right);
|
||||||
|
if (k == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pingpong ^= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clipflags & ALIAS_BOTTOM_CLIP)
|
||||||
|
{
|
||||||
|
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
|
||||||
|
ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom);
|
||||||
|
if (k == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pingpong ^= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clipflags & ALIAS_TOP_CLIP)
|
||||||
|
{
|
||||||
|
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
|
||||||
|
ALIAS_TOP_CLIP, k, R_Alias_clip_top);
|
||||||
|
if (k == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pingpong ^= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0 ; i<k ; i++)
|
||||||
|
{
|
||||||
|
if (fv[pingpong][i].u < RI.aliasvrect.x)
|
||||||
|
fv[pingpong][i].u = RI.aliasvrect.x;
|
||||||
|
else if (fv[pingpong][i].u > RI.aliasvrectright)
|
||||||
|
fv[pingpong][i].u = RI.aliasvrectright;
|
||||||
|
|
||||||
|
if (fv[pingpong][i].v < RI.aliasvrect.y)
|
||||||
|
fv[pingpong][i].v = RI.aliasvrect.y;
|
||||||
|
else if (fv[pingpong][i].v > RI.aliasvrectbottom)
|
||||||
|
fv[pingpong][i].v = RI.aliasvrectbottom;
|
||||||
|
|
||||||
|
fv[pingpong][i].flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw triangles
|
||||||
|
for (i=1 ; i<k-1 ; i++)
|
||||||
|
{
|
||||||
|
aliastriangleparms.a = &fv[pingpong][0];
|
||||||
|
aliastriangleparms.b = &fv[pingpong][i];
|
||||||
|
aliastriangleparms.c = &fv[pingpong][i+1];
|
||||||
|
R_DrawTriangle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,965 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1997-2001 Id Software, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
// r_bsp.c
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// current entity info
|
||||||
|
//
|
||||||
|
qboolean insubmodel;
|
||||||
|
// the currently rendering entity
|
||||||
|
vec3_t r_entorigin; // the currently rendering entity in world
|
||||||
|
// coordinates
|
||||||
|
|
||||||
|
float entity_rotation[3][3];
|
||||||
|
|
||||||
|
int r_currentbkey;
|
||||||
|
|
||||||
|
typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
|
||||||
|
|
||||||
|
#define MAX_BMODEL_VERTS 1000 // 12K
|
||||||
|
#define MAX_BMODEL_EDGES 2000 // 24K
|
||||||
|
|
||||||
|
static mvertex_t *pbverts;
|
||||||
|
static bedge_t *pbedges;
|
||||||
|
static int numbverts, numbedges;
|
||||||
|
|
||||||
|
static mvertex_t *pfrontenter, *pfrontexit;
|
||||||
|
|
||||||
|
static qboolean makeclippededge;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_ConcatRotations
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
|
||||||
|
{
|
||||||
|
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
|
||||||
|
in1[0][2] * in2[2][0];
|
||||||
|
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
|
||||||
|
in1[0][2] * in2[2][1];
|
||||||
|
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
|
||||||
|
in1[0][2] * in2[2][2];
|
||||||
|
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
|
||||||
|
in1[1][2] * in2[2][0];
|
||||||
|
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
|
||||||
|
in1[1][2] * in2[2][1];
|
||||||
|
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
|
||||||
|
in1[1][2] * in2[2][2];
|
||||||
|
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
|
||||||
|
in1[2][2] * in2[2][0];
|
||||||
|
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
|
||||||
|
in1[2][2] * in2[2][1];
|
||||||
|
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
|
||||||
|
in1[2][2] * in2[2][2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_EntityRotate
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_EntityRotate (vec3_t vec)
|
||||||
|
{
|
||||||
|
vec3_t tvec;
|
||||||
|
|
||||||
|
VectorCopy (vec, tvec);
|
||||||
|
vec[0] = DotProduct (entity_rotation[0], tvec);
|
||||||
|
vec[1] = DotProduct (entity_rotation[1], tvec);
|
||||||
|
vec[2] = DotProduct (entity_rotation[2], tvec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_RotateBmodel
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_RotateBmodel (void)
|
||||||
|
{
|
||||||
|
float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
|
||||||
|
|
||||||
|
// TODO: should use a look-up table
|
||||||
|
// TODO: should really be stored with the entity instead of being reconstructed
|
||||||
|
// TODO: could cache lazily, stored in the entity
|
||||||
|
// TODO: share work with R_SetUpAliasTransform
|
||||||
|
|
||||||
|
// yaw
|
||||||
|
angle = RI.currententity->angles[YAW];
|
||||||
|
angle = angle * M_PI_F * 2 / 360.0f;
|
||||||
|
s = sin(angle);
|
||||||
|
c = cos(angle);
|
||||||
|
|
||||||
|
temp1[0][0] = c;
|
||||||
|
temp1[0][1] = s;
|
||||||
|
temp1[0][2] = 0;
|
||||||
|
temp1[1][0] = -s;
|
||||||
|
temp1[1][1] = c;
|
||||||
|
temp1[1][2] = 0;
|
||||||
|
temp1[2][0] = 0;
|
||||||
|
temp1[2][1] = 0;
|
||||||
|
temp1[2][2] = 1;
|
||||||
|
|
||||||
|
|
||||||
|
// pitch
|
||||||
|
angle = RI.currententity->angles[PITCH];
|
||||||
|
angle = angle * M_PI_F * 2 / 360.0f;
|
||||||
|
s = sin(angle);
|
||||||
|
c = cos(angle);
|
||||||
|
|
||||||
|
temp2[0][0] = c;
|
||||||
|
temp2[0][1] = 0;
|
||||||
|
temp2[0][2] = -s;
|
||||||
|
temp2[1][0] = 0;
|
||||||
|
temp2[1][1] = 1;
|
||||||
|
temp2[1][2] = 0;
|
||||||
|
temp2[2][0] = s;
|
||||||
|
temp2[2][1] = 0;
|
||||||
|
temp2[2][2] = c;
|
||||||
|
|
||||||
|
R_ConcatRotations (temp2, temp1, temp3);
|
||||||
|
|
||||||
|
// roll
|
||||||
|
angle = RI.currententity->angles[ROLL];
|
||||||
|
angle = angle * M_PI_F*2 / 360.0f;
|
||||||
|
s = sin(angle);
|
||||||
|
c = cos(angle);
|
||||||
|
|
||||||
|
temp1[0][0] = 1;
|
||||||
|
temp1[0][1] = 0;
|
||||||
|
temp1[0][2] = 0;
|
||||||
|
temp1[1][0] = 0;
|
||||||
|
temp1[1][1] = c;
|
||||||
|
temp1[1][2] = s;
|
||||||
|
temp1[2][0] = 0;
|
||||||
|
temp1[2][1] = -s;
|
||||||
|
temp1[2][2] = c;
|
||||||
|
|
||||||
|
R_ConcatRotations (temp1, temp3, entity_rotation);
|
||||||
|
|
||||||
|
//
|
||||||
|
// rotate modelorg and the transformation matrix
|
||||||
|
//
|
||||||
|
R_EntityRotate (tr.modelorg);
|
||||||
|
R_EntityRotate (RI.vforward);
|
||||||
|
R_EntityRotate (RI.vright);
|
||||||
|
R_EntityRotate (RI.vup);
|
||||||
|
|
||||||
|
R_TransformFrustum ();
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_RecursiveClipBPoly
|
||||||
|
|
||||||
|
Clip a bmodel poly down the world bsp tree
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
|
||||||
|
{
|
||||||
|
bedge_t *psideedges[2], *pnextedge, *ptedge;
|
||||||
|
int i, side, lastside;
|
||||||
|
float dist, frac, lastdist;
|
||||||
|
mplane_t *splitplane, tplane;
|
||||||
|
mvertex_t *pvert, *plastvert, *ptvert;
|
||||||
|
mnode_t *pn;
|
||||||
|
int area;
|
||||||
|
|
||||||
|
psideedges[0] = psideedges[1] = NULL;
|
||||||
|
|
||||||
|
makeclippededge = false;
|
||||||
|
|
||||||
|
// transform the BSP plane into model space
|
||||||
|
// FIXME: cache these?
|
||||||
|
splitplane = pnode->plane;
|
||||||
|
tplane.dist = splitplane->dist -
|
||||||
|
DotProduct(r_entorigin, splitplane->normal);
|
||||||
|
tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
|
||||||
|
tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
|
||||||
|
tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
|
||||||
|
|
||||||
|
// clip edges to BSP plane
|
||||||
|
for ( ; pedges ; pedges = pnextedge)
|
||||||
|
{
|
||||||
|
pnextedge = pedges->pnext;
|
||||||
|
|
||||||
|
// set the status for the last point as the previous point
|
||||||
|
// FIXME: cache this stuff somehow?
|
||||||
|
plastvert = pedges->v[0];
|
||||||
|
lastdist = DotProduct (plastvert->position, tplane.normal) -
|
||||||
|
tplane.dist;
|
||||||
|
|
||||||
|
if (lastdist > 0)
|
||||||
|
lastside = 0;
|
||||||
|
else
|
||||||
|
lastside = 1;
|
||||||
|
|
||||||
|
pvert = pedges->v[1];
|
||||||
|
|
||||||
|
dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
|
||||||
|
|
||||||
|
if (dist > 0)
|
||||||
|
side = 0;
|
||||||
|
else
|
||||||
|
side = 1;
|
||||||
|
|
||||||
|
if (side != lastside)
|
||||||
|
{
|
||||||
|
// clipped
|
||||||
|
if (numbverts >= MAX_BMODEL_VERTS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// generate the clipped vertex
|
||||||
|
frac = lastdist / (lastdist - dist);
|
||||||
|
ptvert = &pbverts[numbverts++];
|
||||||
|
ptvert->position[0] = plastvert->position[0] +
|
||||||
|
frac * (pvert->position[0] -
|
||||||
|
plastvert->position[0]);
|
||||||
|
ptvert->position[1] = plastvert->position[1] +
|
||||||
|
frac * (pvert->position[1] -
|
||||||
|
plastvert->position[1]);
|
||||||
|
ptvert->position[2] = plastvert->position[2] +
|
||||||
|
frac * (pvert->position[2] -
|
||||||
|
plastvert->position[2]);
|
||||||
|
|
||||||
|
// split into two edges, one on each side, and remember entering
|
||||||
|
// and exiting points
|
||||||
|
// FIXME: share the clip edge by having a winding direction flag?
|
||||||
|
if (numbedges >= (MAX_BMODEL_EDGES - 1))
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Printf ("Out of edges for bmodel\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptedge = &pbedges[numbedges];
|
||||||
|
ptedge->pnext = psideedges[lastside];
|
||||||
|
psideedges[lastside] = ptedge;
|
||||||
|
ptedge->v[0] = plastvert;
|
||||||
|
ptedge->v[1] = ptvert;
|
||||||
|
|
||||||
|
ptedge = &pbedges[numbedges + 1];
|
||||||
|
ptedge->pnext = psideedges[side];
|
||||||
|
psideedges[side] = ptedge;
|
||||||
|
ptedge->v[0] = ptvert;
|
||||||
|
ptedge->v[1] = pvert;
|
||||||
|
|
||||||
|
numbedges += 2;
|
||||||
|
|
||||||
|
if (side == 0)
|
||||||
|
{
|
||||||
|
// entering for front, exiting for back
|
||||||
|
pfrontenter = ptvert;
|
||||||
|
makeclippededge = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pfrontexit = ptvert;
|
||||||
|
makeclippededge = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// add the edge to the appropriate side
|
||||||
|
pedges->pnext = psideedges[side];
|
||||||
|
psideedges[side] = pedges;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if anything was clipped, reconstitute and add the edges along the clip
|
||||||
|
// plane to both sides (but in opposite directions)
|
||||||
|
if (makeclippededge)
|
||||||
|
{
|
||||||
|
if (numbedges >= (MAX_BMODEL_EDGES - 2))
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Printf ("Out of edges for bmodel\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptedge = &pbedges[numbedges];
|
||||||
|
ptedge->pnext = psideedges[0];
|
||||||
|
psideedges[0] = ptedge;
|
||||||
|
ptedge->v[0] = pfrontexit;
|
||||||
|
ptedge->v[1] = pfrontenter;
|
||||||
|
|
||||||
|
ptedge = &pbedges[numbedges + 1];
|
||||||
|
ptedge->pnext = psideedges[1];
|
||||||
|
psideedges[1] = ptedge;
|
||||||
|
ptedge->v[0] = pfrontenter;
|
||||||
|
ptedge->v[1] = pfrontexit;
|
||||||
|
|
||||||
|
numbedges += 2;
|
||||||
|
}
|
||||||
|
// draw or recurse further
|
||||||
|
for (i=0 ; i<2 ; i++)
|
||||||
|
{
|
||||||
|
if (psideedges[i])
|
||||||
|
{
|
||||||
|
// draw if we've reached a non-solid leaf, done if all that's left is a
|
||||||
|
// solid leaf, and continue down the tree if it's not a leaf
|
||||||
|
pn = pnode->children[i];
|
||||||
|
|
||||||
|
// we're done with this branch if the node or leaf isn't in the PVS
|
||||||
|
if (pn->visframe == r_visframecount)
|
||||||
|
{
|
||||||
|
if (pn->contents < 0)
|
||||||
|
{
|
||||||
|
if (pn->contents != CONTENTS_SOLID)
|
||||||
|
{
|
||||||
|
r_currentbkey = ((mleaf_t *)pn)->cluster;
|
||||||
|
R_RenderBmodelFace (psideedges[i], psurf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
|
||||||
|
psurf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_RecursiveClipBPoly
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
|
||||||
|
{
|
||||||
|
bedge_t *psideedges[2], *pnextedge, *ptedge;
|
||||||
|
int i, side, lastside;
|
||||||
|
float dist, frac, lastdist;
|
||||||
|
mplane_t *splitplane, tplane;
|
||||||
|
mvertex_t *pvert, *plastvert, *ptvert;
|
||||||
|
mnode_t *pn;
|
||||||
|
|
||||||
|
psideedges[0] = psideedges[1] = NULL;
|
||||||
|
|
||||||
|
makeclippededge = false;
|
||||||
|
|
||||||
|
// transform the BSP plane into model space
|
||||||
|
// FIXME: cache these?
|
||||||
|
splitplane = pnode->plane;
|
||||||
|
tplane.dist = splitplane->dist -
|
||||||
|
DotProduct(r_entorigin, splitplane->normal);
|
||||||
|
tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
|
||||||
|
tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
|
||||||
|
tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
|
||||||
|
|
||||||
|
// clip edges to BSP plane
|
||||||
|
for ( ; pedges ; pedges = pnextedge)
|
||||||
|
{
|
||||||
|
pnextedge = pedges->pnext;
|
||||||
|
|
||||||
|
// set the status for the last point as the previous point
|
||||||
|
// FIXME: cache this stuff somehow?
|
||||||
|
plastvert = pedges->v[0];
|
||||||
|
lastdist = DotProduct (plastvert->position, tplane.normal) -
|
||||||
|
tplane.dist;
|
||||||
|
|
||||||
|
if (lastdist > 0)
|
||||||
|
lastside = 0;
|
||||||
|
else
|
||||||
|
lastside = 1;
|
||||||
|
|
||||||
|
pvert = pedges->v[1];
|
||||||
|
|
||||||
|
dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
|
||||||
|
|
||||||
|
if (dist > 0)
|
||||||
|
side = 0;
|
||||||
|
else
|
||||||
|
side = 1;
|
||||||
|
|
||||||
|
if (side != lastside)
|
||||||
|
{
|
||||||
|
// clipped
|
||||||
|
if (numbverts >= MAX_BMODEL_VERTS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// generate the clipped vertex
|
||||||
|
frac = lastdist / (lastdist - dist);
|
||||||
|
ptvert = &pbverts[numbverts++];
|
||||||
|
ptvert->position[0] = plastvert->position[0] +
|
||||||
|
frac * (pvert->position[0] -
|
||||||
|
plastvert->position[0]);
|
||||||
|
ptvert->position[1] = plastvert->position[1] +
|
||||||
|
frac * (pvert->position[1] -
|
||||||
|
plastvert->position[1]);
|
||||||
|
ptvert->position[2] = plastvert->position[2] +
|
||||||
|
frac * (pvert->position[2] -
|
||||||
|
plastvert->position[2]);
|
||||||
|
|
||||||
|
// split into two edges, one on each side, and remember entering
|
||||||
|
// and exiting points
|
||||||
|
// FIXME: share the clip edge by having a winding direction flag?
|
||||||
|
if (numbedges >= (MAX_BMODEL_EDGES - 1))
|
||||||
|
{
|
||||||
|
//gEngfuncs.Con_Printf ("Out of edges for bmodel\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptedge = &pbedges[numbedges];
|
||||||
|
ptedge->pnext = psideedges[lastside];
|
||||||
|
psideedges[lastside] = ptedge;
|
||||||
|
ptedge->v[0] = plastvert;
|
||||||
|
ptedge->v[1] = ptvert;
|
||||||
|
|
||||||
|
ptedge = &pbedges[numbedges + 1];
|
||||||
|
ptedge->pnext = psideedges[side];
|
||||||
|
psideedges[side] = ptedge;
|
||||||
|
ptedge->v[0] = ptvert;
|
||||||
|
ptedge->v[1] = pvert;
|
||||||
|
|
||||||
|
numbedges += 2;
|
||||||
|
|
||||||
|
if (side == 0)
|
||||||
|
{
|
||||||
|
// entering for front, exiting for back
|
||||||
|
pfrontenter = ptvert;
|
||||||
|
makeclippededge = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pfrontexit = ptvert;
|
||||||
|
makeclippededge = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// add the edge to the appropriate side
|
||||||
|
pedges->pnext = psideedges[side];
|
||||||
|
psideedges[side] = pedges;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if anything was clipped, reconstitute and add the edges along the clip
|
||||||
|
// plane to both sides (but in opposite directions)
|
||||||
|
if (makeclippededge)
|
||||||
|
{
|
||||||
|
if (numbedges >= (MAX_BMODEL_EDGES - 2))
|
||||||
|
{
|
||||||
|
//gEngfuncs.Con_Printf ("Out of edges for bmodel\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptedge = &pbedges[numbedges];
|
||||||
|
ptedge->pnext = psideedges[0];
|
||||||
|
psideedges[0] = ptedge;
|
||||||
|
ptedge->v[0] = pfrontexit;
|
||||||
|
ptedge->v[1] = pfrontenter;
|
||||||
|
|
||||||
|
ptedge = &pbedges[numbedges + 1];
|
||||||
|
ptedge->pnext = psideedges[1];
|
||||||
|
psideedges[1] = ptedge;
|
||||||
|
ptedge->v[0] = pfrontenter;
|
||||||
|
ptedge->v[1] = pfrontexit;
|
||||||
|
|
||||||
|
numbedges += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw or recurse further
|
||||||
|
for (i=0 ; i<2 ; i++)
|
||||||
|
{
|
||||||
|
if (psideedges[i])
|
||||||
|
{
|
||||||
|
// draw if we've reached a non-solid leaf, done if all that's left is a
|
||||||
|
// solid leaf, and continue down the tree if it's not a leaf
|
||||||
|
pn = pnode->children[i];
|
||||||
|
|
||||||
|
// we're done with this branch if the node or leaf isn't in the PVS
|
||||||
|
if (pn->visframe == tr.visframecount)
|
||||||
|
{
|
||||||
|
if (pn->contents < 0)
|
||||||
|
{
|
||||||
|
if (pn->contents != CONTENTS_SOLID)
|
||||||
|
{
|
||||||
|
//r_currentbkey = ((mleaf_t *)pn)->cluster;
|
||||||
|
r_currentbkey = LEAF_KEY (((mleaf_t *)pn));
|
||||||
|
R_RenderBmodelFace (psideedges[i], psurf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
|
||||||
|
psurf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_DrawSolidClippedSubmodelPolygons
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel)
|
||||||
|
{
|
||||||
|
int i, j, lindex;
|
||||||
|
vec_t dot;
|
||||||
|
msurface_t *psurf;
|
||||||
|
int numsurfaces;
|
||||||
|
mplane_t *pplane;
|
||||||
|
mvertex_t bverts[MAX_BMODEL_VERTS];
|
||||||
|
bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
|
||||||
|
medge_t *pedge, *pedges;
|
||||||
|
|
||||||
|
// FIXME: use bounding-box-based frustum clipping info?
|
||||||
|
|
||||||
|
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
|
||||||
|
numsurfaces = pmodel->nummodelsurfaces;
|
||||||
|
pedges = pmodel->edges;
|
||||||
|
|
||||||
|
for (i=0 ; i<numsurfaces ; i++, psurf++)
|
||||||
|
{
|
||||||
|
// find which side of the node we are on
|
||||||
|
pplane = psurf->plane;
|
||||||
|
|
||||||
|
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
|
||||||
|
|
||||||
|
// draw the polygon
|
||||||
|
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
||||||
|
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
|
||||||
|
{
|
||||||
|
// FIXME: use bounding-box-based frustum clipping info?
|
||||||
|
|
||||||
|
// copy the edges to bedges, flipping if necessary so always
|
||||||
|
// clockwise winding
|
||||||
|
// FIXME: if edges and vertices get caches, these assignments must move
|
||||||
|
// outside the loop, and overflow checking must be done here
|
||||||
|
pbverts = bverts;
|
||||||
|
pbedges = bedges;
|
||||||
|
numbverts = numbedges = 0;
|
||||||
|
|
||||||
|
if (psurf->numedges > 0)
|
||||||
|
{
|
||||||
|
pbedge = &bedges[numbedges];
|
||||||
|
numbedges += psurf->numedges;
|
||||||
|
|
||||||
|
for (j=0 ; j<psurf->numedges ; j++)
|
||||||
|
{
|
||||||
|
lindex = pmodel->surfedges[psurf->firstedge+j];
|
||||||
|
|
||||||
|
if (lindex > 0)
|
||||||
|
{
|
||||||
|
pedge = &pedges[lindex];
|
||||||
|
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
|
||||||
|
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lindex = -lindex;
|
||||||
|
pedge = &pedges[lindex];
|
||||||
|
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
|
||||||
|
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
pbedge[j].pnext = &pbedge[j+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
pbedge[j-1].pnext = NULL; // mark end of edges
|
||||||
|
|
||||||
|
R_RecursiveClipBPoly (pbedge, RI.currententity->topnode, psurf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gEngfuncs.Host_Error ("no edges in bmodel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_DrawSubmodelPolygons
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vec_t dot;
|
||||||
|
msurface_t *psurf;
|
||||||
|
int numsurfaces;
|
||||||
|
mplane_t *pplane;
|
||||||
|
|
||||||
|
// FIXME: use bounding-box-based frustum clipping info?
|
||||||
|
|
||||||
|
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
|
||||||
|
numsurfaces = pmodel->nummodelsurfaces;
|
||||||
|
|
||||||
|
for (i=0 ; i<numsurfaces ; i++, psurf++)
|
||||||
|
{
|
||||||
|
// find which side of the node we are on
|
||||||
|
pplane = psurf->plane;
|
||||||
|
|
||||||
|
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
|
||||||
|
|
||||||
|
// draw the polygon
|
||||||
|
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
||||||
|
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
|
||||||
|
{
|
||||||
|
r_currentkey = ((mleaf_t *)RI.currententity->topnode)->cluster;
|
||||||
|
|
||||||
|
// FIXME: use bounding-box-based frustum clipping info?
|
||||||
|
R_RenderFace (psurf, clipflags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_DrawSolidClippedSubmodelPolygons
|
||||||
|
|
||||||
|
Bmodel crosses multiple leafs
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode)
|
||||||
|
{
|
||||||
|
int i, j, lindex;
|
||||||
|
vec_t dot;
|
||||||
|
msurface_t *psurf;
|
||||||
|
int numsurfaces;
|
||||||
|
mplane_t *pplane;
|
||||||
|
mvertex_t bverts[MAX_BMODEL_VERTS];
|
||||||
|
bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
|
||||||
|
medge_t *pedge, *pedges;
|
||||||
|
|
||||||
|
// FIXME: use bounding-box-based frustum clipping info?
|
||||||
|
|
||||||
|
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
|
||||||
|
numsurfaces = pmodel->nummodelsurfaces;
|
||||||
|
pedges = pmodel->edges;
|
||||||
|
|
||||||
|
for (i=0 ; i<numsurfaces ; i++, psurf++)
|
||||||
|
{
|
||||||
|
if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ))
|
||||||
|
{
|
||||||
|
if( psurf->plane->type != PLANE_Z && !FBitSet( RI.currententity->curstate.effects, EF_WATERSIDES ))
|
||||||
|
continue;
|
||||||
|
if( r_entorigin[2] + pmodel->mins[2] + 1.0f >= psurf->plane->dist )
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// find which side of the node we are on
|
||||||
|
pplane = psurf->plane;
|
||||||
|
|
||||||
|
dot = DotProduct (tr.modelorg, pplane->normal) - pplane->dist;
|
||||||
|
|
||||||
|
// draw the polygon
|
||||||
|
if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
||||||
|
((psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// FIXME: use bounding-box-based frustum clipping info?
|
||||||
|
|
||||||
|
// copy the edges to bedges, flipping if necessary so always
|
||||||
|
// clockwise winding
|
||||||
|
// FIXME: if edges and vertices get caches, these assignments must move
|
||||||
|
// outside the loop, and overflow checking must be done here
|
||||||
|
pbverts = bverts;
|
||||||
|
pbedges = bedges;
|
||||||
|
numbverts = numbedges = 0;
|
||||||
|
pbedge = &bedges[numbedges];
|
||||||
|
numbedges += psurf->numedges;
|
||||||
|
|
||||||
|
for (j=0 ; j<psurf->numedges ; j++)
|
||||||
|
{
|
||||||
|
lindex = pmodel->surfedges[psurf->firstedge+j];
|
||||||
|
|
||||||
|
if (lindex > 0)
|
||||||
|
{
|
||||||
|
pedge = &pedges[lindex];
|
||||||
|
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
|
||||||
|
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lindex = -lindex;
|
||||||
|
pedge = &pedges[lindex];
|
||||||
|
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
|
||||||
|
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
pbedge[j].pnext = &pbedge[j+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
pbedge[j-1].pnext = NULL; // mark end of edges
|
||||||
|
|
||||||
|
//if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
|
||||||
|
R_RecursiveClipBPoly (pbedge, topnode, psurf);
|
||||||
|
//else
|
||||||
|
// R_RenderBmodelFace( pbedge, psurf );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_DrawSubmodelPolygons
|
||||||
|
|
||||||
|
All in one leaf
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vec_t dot;
|
||||||
|
msurface_t *psurf;
|
||||||
|
int numsurfaces;
|
||||||
|
mplane_t *pplane;
|
||||||
|
|
||||||
|
// FIXME: use bounding-box-based frustum clipping info?
|
||||||
|
|
||||||
|
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
|
||||||
|
numsurfaces = pmodel->nummodelsurfaces;
|
||||||
|
|
||||||
|
for (i=0 ; i<numsurfaces ; i++, psurf++)
|
||||||
|
{
|
||||||
|
if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ))
|
||||||
|
{
|
||||||
|
if( psurf->plane->type != PLANE_Z && !FBitSet( RI.currententity->curstate.effects, EF_WATERSIDES ))
|
||||||
|
continue;
|
||||||
|
if( r_entorigin[2] + pmodel->mins[2] + 1.0f >= psurf->plane->dist )
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// find which side of the node we are on
|
||||||
|
pplane = psurf->plane;
|
||||||
|
|
||||||
|
dot = DotProduct (tr.modelorg, pplane->normal) - pplane->dist;
|
||||||
|
|
||||||
|
// draw the polygon
|
||||||
|
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
||||||
|
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
|
||||||
|
{
|
||||||
|
r_currentkey = LEAF_KEY(((mleaf_t *)topnode));
|
||||||
|
|
||||||
|
// FIXME: use bounding-box-based frustum clipping info?
|
||||||
|
R_RenderFace (psurf, clipflags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
int c_drawnode;
|
||||||
|
#if XASH_LOW_MEMORY
|
||||||
|
unsigned short r_leafkeys[MAX_MAP_LEAFS];
|
||||||
|
#else
|
||||||
|
int r_leafkeys[MAX_MAP_LEAFS];
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_RecursiveWorldNode
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_RecursiveWorldNode (mnode_t *node, int clipflags)
|
||||||
|
{
|
||||||
|
int i, c, side, *pindex;
|
||||||
|
vec3_t acceptpt, rejectpt;
|
||||||
|
mplane_t *plane;
|
||||||
|
msurface_t *surf, **mark;
|
||||||
|
mleaf_t *pleaf;
|
||||||
|
double d, dot;
|
||||||
|
|
||||||
|
if (node->contents == CONTENTS_SOLID)
|
||||||
|
return; // solid
|
||||||
|
|
||||||
|
if (node->visframe != tr.visframecount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// cull the clipping planes if not trivial accept
|
||||||
|
// FIXME: the compiler is doing a lousy job of optimizing here; it could be
|
||||||
|
// twice as fast in ASM
|
||||||
|
if (clipflags)
|
||||||
|
{
|
||||||
|
for (i=0 ; i<4 ; i++)
|
||||||
|
{
|
||||||
|
if (! (clipflags & (1<<i)) )
|
||||||
|
continue; // don't need to clip against it
|
||||||
|
|
||||||
|
// generate accept and reject points
|
||||||
|
// FIXME: do with fast look-ups or integer tests based on the sign bit
|
||||||
|
// of the floating point values
|
||||||
|
|
||||||
|
pindex = qfrustum.pfrustum_indexes[i];
|
||||||
|
|
||||||
|
rejectpt[0] = (float)node->minmaxs[pindex[0]];
|
||||||
|
rejectpt[1] = (float)node->minmaxs[pindex[1]];
|
||||||
|
rejectpt[2] = (float)node->minmaxs[pindex[2]];
|
||||||
|
|
||||||
|
d = DotProduct (rejectpt, qfrustum.view_clipplanes[i].normal);
|
||||||
|
d -= qfrustum.view_clipplanes[i].dist;
|
||||||
|
|
||||||
|
if (d <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
|
||||||
|
acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
|
||||||
|
acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
|
||||||
|
|
||||||
|
d = DotProduct (acceptpt, qfrustum.view_clipplanes[i].normal);
|
||||||
|
d -= qfrustum.view_clipplanes[i].dist;
|
||||||
|
|
||||||
|
if (d >= 0)
|
||||||
|
clipflags &= ~(1<<i); // node is entirely on screen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if a leaf node, draw stuff
|
||||||
|
if (node->contents < 0)
|
||||||
|
{
|
||||||
|
pleaf = (mleaf_t *)node;
|
||||||
|
|
||||||
|
mark = pleaf->firstmarksurface;
|
||||||
|
c = pleaf->nummarksurfaces;
|
||||||
|
|
||||||
|
if (c)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
(*mark)->visframe = tr.framecount;
|
||||||
|
mark++;
|
||||||
|
} while (--c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// deal with model fragments in this leaf
|
||||||
|
if (pleaf->efrags)
|
||||||
|
{
|
||||||
|
gEngfuncs.R_StoreEfrags(&pleaf->efrags,tr.realframecount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// pleaf->cluster
|
||||||
|
LEAF_KEY(pleaf) = r_currentkey;
|
||||||
|
r_currentkey++; // all bmodels in a leaf share the same key
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// node is just a decision point, so go down the apropriate sides
|
||||||
|
|
||||||
|
// find which side of the node we are on
|
||||||
|
plane = node->plane;
|
||||||
|
|
||||||
|
switch (plane->type)
|
||||||
|
{
|
||||||
|
case PLANE_X:
|
||||||
|
dot = tr.modelorg[0] - plane->dist;
|
||||||
|
break;
|
||||||
|
case PLANE_Y:
|
||||||
|
dot = tr.modelorg[1] - plane->dist;
|
||||||
|
break;
|
||||||
|
case PLANE_Z:
|
||||||
|
dot = tr.modelorg[2] - plane->dist;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dot = DotProduct (tr.modelorg, plane->normal) - plane->dist;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dot >= 0)
|
||||||
|
side = 0;
|
||||||
|
else
|
||||||
|
side = 1;
|
||||||
|
|
||||||
|
// recurse down the children, front side first
|
||||||
|
R_RecursiveWorldNode (node->children[side], clipflags);
|
||||||
|
|
||||||
|
// draw stuff
|
||||||
|
c = node->numsurfaces;
|
||||||
|
|
||||||
|
if (c)
|
||||||
|
{
|
||||||
|
surf = WORLDMODEL->surfaces + node->firstsurface;
|
||||||
|
|
||||||
|
if (dot < -BACKFACE_EPSILON)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if ((surf->flags & SURF_PLANEBACK) &&
|
||||||
|
(surf->visframe == tr.framecount))
|
||||||
|
{
|
||||||
|
R_RenderFace (surf, clipflags);
|
||||||
|
}
|
||||||
|
|
||||||
|
surf++;
|
||||||
|
} while (--c);
|
||||||
|
}
|
||||||
|
else if (dot > BACKFACE_EPSILON)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!(surf->flags & SURF_PLANEBACK) &&
|
||||||
|
(surf->visframe == tr.framecount))
|
||||||
|
{
|
||||||
|
R_RenderFace (surf, clipflags);
|
||||||
|
}
|
||||||
|
|
||||||
|
surf++;
|
||||||
|
} while (--c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// all surfaces on the same node share the same sequence number
|
||||||
|
r_currentkey++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse down the back side
|
||||||
|
R_RecursiveWorldNode (node->children[!side], clipflags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_RenderWorld
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_RenderWorld (void)
|
||||||
|
{
|
||||||
|
|
||||||
|
//if (!r_drawworld->value)
|
||||||
|
// return;
|
||||||
|
if ( !RI.drawWorld )
|
||||||
|
return;
|
||||||
|
|
||||||
|
c_drawnode=0;
|
||||||
|
|
||||||
|
// auto cycle the world frame for texture animation
|
||||||
|
RI.currententity = gEngfuncs.GetEntityByIndex(0);
|
||||||
|
//RI.currententity->frame = (int)(gpGlobals->time*2);
|
||||||
|
|
||||||
|
VectorCopy (RI.vieworg, tr.modelorg);
|
||||||
|
RI.currentmodel = WORLDMODEL;
|
||||||
|
r_pcurrentvertbase = RI.currentmodel->vertexes;
|
||||||
|
|
||||||
|
R_RecursiveWorldNode (RI.currentmodel->nodes, 15);
|
||||||
|
}
|
|
@ -0,0 +1,600 @@
|
||||||
|
/*
|
||||||
|
vid_sdl.c - SDL vid component
|
||||||
|
Copyright (C) 2018 a1batross
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
|
||||||
|
ref_api_t gEngfuncs;
|
||||||
|
ref_globals_t *gpGlobals;
|
||||||
|
ref_instance_t RI;
|
||||||
|
gl_globals_t tr;
|
||||||
|
ref_speeds_t r_stats;
|
||||||
|
byte *r_temppool;
|
||||||
|
cvar_t *gl_emboss_scale;
|
||||||
|
cvar_t *r_drawentities;
|
||||||
|
cvar_t *r_norefresh;
|
||||||
|
cvar_t *vid_gamma;
|
||||||
|
cvar_t *vid_brightness;
|
||||||
|
viddef_t vid;
|
||||||
|
static void GAME_EXPORT R_ClearScreen( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean GAME_EXPORT IsNormalPass( void )
|
||||||
|
{
|
||||||
|
return RP_NORMALPASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAME_EXPORT R_IncrementSpeedsCounter( int type )
|
||||||
|
{
|
||||||
|
switch( type )
|
||||||
|
{
|
||||||
|
case RS_ACTIVE_TENTS:
|
||||||
|
r_stats.c_active_tents_count++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gEngfuncs.Host_Error( "R_IncrementSpeedsCounter: unsupported type %d\n", type );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const byte * GAME_EXPORT R_GetTextureOriginalBuffer( unsigned int idx )
|
||||||
|
{
|
||||||
|
/*gl_texture_t *glt = R_GetTexture( idx );
|
||||||
|
|
||||||
|
if( !glt || !glt->original || !glt->original->buffer )
|
||||||
|
return NULL;*/
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
CL_FillRGBA
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
static void GAME_EXPORT CL_FillRGBA( float _x, float _y, float _w, float _h, int r, int g, int b, int a )
|
||||||
|
{
|
||||||
|
vid.rendermode = kRenderTransAdd;
|
||||||
|
_TriColor4ub(r,g,b,a);
|
||||||
|
Draw_Fill(_x,_y,_w,_h);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
pfnFillRGBABlend
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
static void GAME_EXPORT CL_FillRGBABlend( float _x, float _y, float _w, float _h, int r, int g, int b, int a )
|
||||||
|
{
|
||||||
|
vid.rendermode = kRenderTransAlpha;
|
||||||
|
_TriColor4ub(r,g,b,a);
|
||||||
|
Draw_Fill(_x,_y,_w,_h);
|
||||||
|
}
|
||||||
|
void Mod_UnloadTextures( model_t *mod );
|
||||||
|
|
||||||
|
qboolean GAME_EXPORT Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buf )
|
||||||
|
{
|
||||||
|
qboolean loaded = true;
|
||||||
|
|
||||||
|
if( create )
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
switch( mod->type )
|
||||||
|
{
|
||||||
|
case mod_studio:
|
||||||
|
//Mod_LoadStudioModel( mod, buf, loaded );
|
||||||
|
break;
|
||||||
|
case mod_sprite:
|
||||||
|
Mod_LoadSpriteModel( mod, buf, &loaded, mod->numtexinfo );
|
||||||
|
break;
|
||||||
|
case mod_alias:
|
||||||
|
//Mod_LoadAliasModel( mod, buf, &loaded );
|
||||||
|
break;
|
||||||
|
case mod_brush:
|
||||||
|
// Mod_LoadBrushModel( mod, buf, loaded );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: gEngfuncs.Host_Error( "Mod_LoadModel: unsupported type %d\n", mod->type );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( loaded && gEngfuncs.drawFuncs->Mod_ProcessUserData )
|
||||||
|
gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, create, buf );
|
||||||
|
|
||||||
|
if( !create )
|
||||||
|
Mod_UnloadTextures( mod );
|
||||||
|
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int GL_RefGetParm( int parm, int arg )
|
||||||
|
{
|
||||||
|
image_t *glt;
|
||||||
|
|
||||||
|
switch( parm )
|
||||||
|
{
|
||||||
|
case PARM_TEX_WIDTH:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return glt->width;
|
||||||
|
case PARM_TEX_HEIGHT:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return glt->height;
|
||||||
|
case PARM_TEX_SRC_WIDTH:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return glt->srcWidth;
|
||||||
|
case PARM_TEX_SRC_HEIGHT:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return glt->srcHeight;
|
||||||
|
case PARM_TEX_GLFORMAT:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return 0; //glt->format;
|
||||||
|
case PARM_TEX_ENCODE:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return 0; //glt->encode;
|
||||||
|
case PARM_TEX_MIPCOUNT:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return glt->numMips;
|
||||||
|
case PARM_TEX_DEPTH:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return glt->depth;
|
||||||
|
case PARM_TEX_SKYBOX:
|
||||||
|
Assert( arg >= 0 && arg < 6 );
|
||||||
|
return tr.skyboxTextures[arg];
|
||||||
|
case PARM_TEX_SKYTEXNUM:
|
||||||
|
return 0; //tr.skytexturenum;
|
||||||
|
case PARM_TEX_LIGHTMAP:
|
||||||
|
arg = bound( 0, arg, MAX_LIGHTMAPS - 1 );
|
||||||
|
return tr.lightmapTextures[arg];
|
||||||
|
case PARM_WIDESCREEN:
|
||||||
|
return gpGlobals->wideScreen;
|
||||||
|
case PARM_FULLSCREEN:
|
||||||
|
return gpGlobals->fullScreen;
|
||||||
|
case PARM_SCREEN_WIDTH:
|
||||||
|
return gpGlobals->width;
|
||||||
|
case PARM_SCREEN_HEIGHT:
|
||||||
|
return gpGlobals->height;
|
||||||
|
case PARM_TEX_TARGET:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return 0; //glt->target;
|
||||||
|
case PARM_TEX_TEXNUM:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return 0; //glt->texnum;
|
||||||
|
case PARM_TEX_FLAGS:
|
||||||
|
glt = R_GetTexture( arg );
|
||||||
|
return glt->flags;
|
||||||
|
case PARM_ACTIVE_TMU:
|
||||||
|
return 0; //glState.activeTMU;
|
||||||
|
case PARM_LIGHTSTYLEVALUE:
|
||||||
|
arg = bound( 0, arg, MAX_LIGHTSTYLES - 1 );
|
||||||
|
return tr.lightstylevalue[arg];
|
||||||
|
case PARM_MAX_IMAGE_UNITS:
|
||||||
|
return 0; //GL_MaxTextureUnits();
|
||||||
|
case PARM_REBUILD_GAMMA:
|
||||||
|
return 0;
|
||||||
|
case PARM_SURF_SAMPLESIZE:
|
||||||
|
if( arg >= 0 && arg < WORLDMODEL->numsurfaces )
|
||||||
|
return gEngfuncs.Mod_SampleSizeForFace( &WORLDMODEL->surfaces[arg] );
|
||||||
|
return LM_SAMPLE_SIZE;
|
||||||
|
case PARM_GL_CONTEXT_TYPE:
|
||||||
|
return 0; //glConfig.context;
|
||||||
|
case PARM_GLES_WRAPPER:
|
||||||
|
return 0; //glConfig.wrapper;
|
||||||
|
case PARM_STENCIL_ACTIVE:
|
||||||
|
return 0; //glState.stencilEnabled;
|
||||||
|
case PARM_SKY_SPHERE:
|
||||||
|
return ENGINE_GET_PARM_( parm, arg ) && !tr.fCustomSkybox;
|
||||||
|
default:
|
||||||
|
return ENGINE_GET_PARM_( parm, arg );
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAME_EXPORT R_GetDetailScaleForTexture( int texture, float *xScale, float *yScale )
|
||||||
|
{
|
||||||
|
image_t *glt = R_GetTexture( texture );
|
||||||
|
|
||||||
|
if( xScale ) *xScale = glt->xscale;
|
||||||
|
if( yScale ) *yScale = glt->yscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAME_EXPORT R_GetExtraParmsForTexture( int texture, byte *red, byte *green, byte *blue, byte *density )
|
||||||
|
{
|
||||||
|
image_t *glt = R_GetTexture( texture );
|
||||||
|
|
||||||
|
if( red ) *red = glt->fogParams[0];
|
||||||
|
if( green ) *green = glt->fogParams[1];
|
||||||
|
if( blue ) *blue = glt->fogParams[2];
|
||||||
|
if( density ) *density = glt->fogParams[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void GAME_EXPORT R_SetCurrentEntity( cl_entity_t *ent )
|
||||||
|
{
|
||||||
|
RI.currententity = ent;
|
||||||
|
|
||||||
|
// set model also
|
||||||
|
if( RI.currententity != NULL )
|
||||||
|
{
|
||||||
|
RI.currentmodel = RI.currententity->model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAME_EXPORT R_SetCurrentModel( model_t *mod )
|
||||||
|
{
|
||||||
|
RI.currentmodel = mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float GAME_EXPORT R_GetFrameTime( void )
|
||||||
|
{
|
||||||
|
return tr.frametime;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * GAME_EXPORT GL_TextureName( unsigned int texnum )
|
||||||
|
{
|
||||||
|
return "";//return R_GetTexture( texnum )->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const byte * GAME_EXPORT GL_TextureData( unsigned int texnum )
|
||||||
|
{
|
||||||
|
// rgbdata_t *pic = R_GetTexture( texnum )->original;
|
||||||
|
|
||||||
|
//if( pic != NULL )
|
||||||
|
//return pic->buffer;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod_BrushUnloadTextures( model_t *mod )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
gEngfuncs.Con_Printf("Unloading world\n");
|
||||||
|
tr.map_unload = true;
|
||||||
|
|
||||||
|
for( i = 0; i < mod->numtextures; i++ )
|
||||||
|
{
|
||||||
|
texture_t *tx = mod->textures[i];
|
||||||
|
if( !tx || tx->gl_texturenum == tr.defaultTexture )
|
||||||
|
continue; // free slot
|
||||||
|
|
||||||
|
GL_FreeTexture( tx->gl_texturenum ); // main texture
|
||||||
|
GL_FreeTexture( tx->fb_texturenum ); // luma texture
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod_UnloadTextures( model_t *mod )
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
Assert( mod != NULL );
|
||||||
|
|
||||||
|
switch( mod->type )
|
||||||
|
{
|
||||||
|
case mod_studio:
|
||||||
|
//Mod_StudioUnloadTextures( mod->cache.data );
|
||||||
|
break;
|
||||||
|
case mod_alias:
|
||||||
|
//Mod_AliasUnloadTextures( mod->cache.data );
|
||||||
|
break;
|
||||||
|
case mod_brush:
|
||||||
|
Mod_BrushUnloadTextures( mod );
|
||||||
|
break;
|
||||||
|
case mod_sprite:
|
||||||
|
Mod_SpriteUnloadTextures( mod->cache.data );
|
||||||
|
break;
|
||||||
|
default: gEngfuncs.Host_Error( "Mod_UnloadModel: unsupported type %d\n", mod->type );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT R_ProcessEntData( qboolean allocate )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// stubs
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_SetTexCoordArrayMode( uint mode )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_BackendStartFrame( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_BackendEndFrame( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_SetRenderMode(int mode)
|
||||||
|
{
|
||||||
|
vid.rendermode = mode;
|
||||||
|
/// TODO: table shading/blending???
|
||||||
|
/// maybe, setup block drawing function pointers here
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT R_ShowTextures( void )
|
||||||
|
{
|
||||||
|
// textures undone too
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT R_ShowTree( void )
|
||||||
|
{
|
||||||
|
// do we really need this here???
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT R_SetupSky(const char *skyboxname)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean GAME_EXPORT VID_ScreenShot(const char *filename, int shot_type)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean GAME_EXPORT VID_CubemapShot(const char *base, uint size, const float *vieworg, qboolean skyshot)
|
||||||
|
{
|
||||||
|
// cubemaps? in my softrender???
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void R_InitSkyClouds(mip_t *mt, texture_t *tx, qboolean custom_palette)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_SubdivideSurface(msurface_t *fa)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT DrawSingleDecal(decal_t *pDecal, msurface_t *fa)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_SelectTexture(int texture)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_LoadTexMatrixExt(const float *glmatrix)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_LoadIdentityTexMatrix( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_CleanUpTextureUnits(int last)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_TexGen(unsigned int coord, unsigned int mode)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_TextureTarget(uint target)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_BuildLightmaps( void )
|
||||||
|
{
|
||||||
|
CL_RunLightStyles();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT Mod_SetOrthoBounds(const float *mins, const float *maxs)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean GAME_EXPORT R_SpeedsMessage(char *out, size_t size)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *GAME_EXPORT Mod_GetCurrentVis( void )
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *R_GetConfigName( void )
|
||||||
|
{
|
||||||
|
return "ref_soft"; // software specific cvars will go to ref_soft.cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* GAME_EXPORT R_GetProcAddress( const char *name )
|
||||||
|
{
|
||||||
|
return gEngfuncs.GL_GetProcAddress( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
ref_interface_t gReffuncs =
|
||||||
|
{
|
||||||
|
R_Init,
|
||||||
|
R_Shutdown,
|
||||||
|
R_GetConfigName,
|
||||||
|
R_SetDisplayTransform,
|
||||||
|
|
||||||
|
GL_SetupAttributes,
|
||||||
|
GL_InitExtensions,
|
||||||
|
GL_ClearExtensions,
|
||||||
|
|
||||||
|
R_BeginFrame,
|
||||||
|
R_RenderScene,
|
||||||
|
R_EndFrame,
|
||||||
|
R_PushScene,
|
||||||
|
R_PopScene,
|
||||||
|
GL_BackendStartFrame,
|
||||||
|
GL_BackendEndFrame,
|
||||||
|
|
||||||
|
R_ClearScreen,
|
||||||
|
R_AllowFog,
|
||||||
|
GL_SetRenderMode,
|
||||||
|
|
||||||
|
R_AddEntity,
|
||||||
|
CL_AddCustomBeam,
|
||||||
|
R_ProcessEntData,
|
||||||
|
|
||||||
|
R_ShowTextures,
|
||||||
|
|
||||||
|
R_GetTextureOriginalBuffer,
|
||||||
|
GL_LoadTextureFromBuffer,
|
||||||
|
GL_ProcessTexture,
|
||||||
|
R_SetupSky,
|
||||||
|
|
||||||
|
R_Set2DMode,
|
||||||
|
R_DrawStretchRaw,
|
||||||
|
R_DrawStretchPic,
|
||||||
|
R_DrawTileClear,
|
||||||
|
CL_FillRGBA,
|
||||||
|
CL_FillRGBABlend,
|
||||||
|
|
||||||
|
VID_ScreenShot,
|
||||||
|
VID_CubemapShot,
|
||||||
|
|
||||||
|
R_LightPoint,
|
||||||
|
|
||||||
|
R_DecalShoot,
|
||||||
|
R_DecalRemoveAll,
|
||||||
|
R_CreateDecalList,
|
||||||
|
R_ClearAllDecals,
|
||||||
|
|
||||||
|
R_StudioEstimateFrame,
|
||||||
|
R_StudioLerpMovement,
|
||||||
|
CL_InitStudioAPI,
|
||||||
|
|
||||||
|
R_InitSkyClouds,
|
||||||
|
GL_SubdivideSurface,
|
||||||
|
CL_RunLightStyles,
|
||||||
|
|
||||||
|
R_GetSpriteParms,
|
||||||
|
R_GetSpriteTexture,
|
||||||
|
|
||||||
|
Mod_LoadMapSprite,
|
||||||
|
Mod_ProcessRenderData,
|
||||||
|
Mod_StudioLoadTextures,
|
||||||
|
|
||||||
|
CL_DrawParticles,
|
||||||
|
CL_DrawTracers,
|
||||||
|
CL_DrawBeams,
|
||||||
|
R_BeamCull,
|
||||||
|
|
||||||
|
GL_RefGetParm,
|
||||||
|
R_GetDetailScaleForTexture,
|
||||||
|
R_GetExtraParmsForTexture,
|
||||||
|
R_GetFrameTime,
|
||||||
|
|
||||||
|
R_SetCurrentEntity,
|
||||||
|
R_SetCurrentModel,
|
||||||
|
|
||||||
|
GL_FindTexture,
|
||||||
|
GL_TextureName,
|
||||||
|
GL_TextureData,
|
||||||
|
GL_LoadTexture,
|
||||||
|
GL_CreateTexture,
|
||||||
|
GL_LoadTextureArray,
|
||||||
|
GL_CreateTextureArray,
|
||||||
|
GL_FreeTexture,
|
||||||
|
|
||||||
|
DrawSingleDecal,
|
||||||
|
R_DecalSetupVerts,
|
||||||
|
R_EntityRemoveDecals,
|
||||||
|
|
||||||
|
R_UploadStretchRaw,
|
||||||
|
|
||||||
|
GL_Bind,
|
||||||
|
GL_SelectTexture,
|
||||||
|
GL_LoadTexMatrixExt,
|
||||||
|
GL_LoadIdentityTexMatrix,
|
||||||
|
GL_CleanUpTextureUnits,
|
||||||
|
GL_TexGen,
|
||||||
|
GL_TextureTarget,
|
||||||
|
GL_SetTexCoordArrayMode,
|
||||||
|
GL_UpdateTexSize,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
|
||||||
|
CL_DrawParticlesExternal,
|
||||||
|
R_LightVec,
|
||||||
|
R_StudioGetTexture,
|
||||||
|
|
||||||
|
R_RenderFrame,
|
||||||
|
Mod_SetOrthoBounds,
|
||||||
|
R_SpeedsMessage,
|
||||||
|
Mod_GetCurrentVis,
|
||||||
|
R_NewMap,
|
||||||
|
R_ClearScene,
|
||||||
|
R_GetProcAddress,
|
||||||
|
|
||||||
|
TriRenderMode,
|
||||||
|
TriBegin,
|
||||||
|
TriEnd,
|
||||||
|
_TriColor4f,
|
||||||
|
_TriColor4ub,
|
||||||
|
TriTexCoord2f,
|
||||||
|
TriVertex3fv,
|
||||||
|
TriVertex3f,
|
||||||
|
TriWorldToScreen,
|
||||||
|
TriFog,
|
||||||
|
R_ScreenToWorld,
|
||||||
|
TriGetMatrix,
|
||||||
|
TriFogParams,
|
||||||
|
TriCullFace,
|
||||||
|
|
||||||
|
VGUI_DrawInit,
|
||||||
|
VGUI_DrawShutdown,
|
||||||
|
VGUI_SetupDrawingText,
|
||||||
|
VGUI_SetupDrawingRect,
|
||||||
|
VGUI_SetupDrawingImage,
|
||||||
|
VGUI_BindTexture,
|
||||||
|
VGUI_EnableTexture,
|
||||||
|
VGUI_CreateTexture,
|
||||||
|
VGUI_UploadTexture,
|
||||||
|
VGUI_UploadTextureBlock,
|
||||||
|
VGUI_DrawQuad,
|
||||||
|
VGUI_GetTextureSizes,
|
||||||
|
VGUI_GenerateTexture,
|
||||||
|
};
|
||||||
|
|
||||||
|
int EXPORT GAME_EXPORT GetRefAPI( int version, ref_interface_t *funcs, ref_api_t *engfuncs, ref_globals_t *globals )
|
||||||
|
{
|
||||||
|
if( version != REF_API_VERSION )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// fill in our callbacks
|
||||||
|
memcpy( funcs, &gReffuncs, sizeof( ref_interface_t ));
|
||||||
|
memcpy( &gEngfuncs, engfuncs, sizeof( ref_api_t ));
|
||||||
|
gpGlobals = globals;
|
||||||
|
|
||||||
|
return REF_API_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EXPORT GetRefHumanReadableName( char *out, size_t size )
|
||||||
|
{
|
||||||
|
Q_strncpy( out, "Software", size );
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,428 @@
|
||||||
|
/*
|
||||||
|
gl_draw.c - orthogonal drawing stuff
|
||||||
|
Copyright (C) 2010 Uncle Mike
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
R_GetImageParms
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void R_GetTextureParms( int *w, int *h, int texnum )
|
||||||
|
{
|
||||||
|
image_t *glt;
|
||||||
|
|
||||||
|
glt = R_GetTexture( texnum );
|
||||||
|
if( w ) *w = glt->srcWidth;
|
||||||
|
if( h ) *h = glt->srcHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
R_GetSpriteParms
|
||||||
|
|
||||||
|
same as GetImageParms but used
|
||||||
|
for sprite models
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite )
|
||||||
|
{
|
||||||
|
mspriteframe_t *pFrame;
|
||||||
|
|
||||||
|
if( !pSprite || pSprite->type != mod_sprite ) return; // bad model ?
|
||||||
|
pFrame = R_GetSpriteFrame( pSprite, currentFrame, 0.0f );
|
||||||
|
|
||||||
|
if( frameWidth ) *frameWidth = pFrame->width;
|
||||||
|
if( frameHeight ) *frameHeight = pFrame->height;
|
||||||
|
if( numFrames ) *numFrames = pSprite->numframes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GAME_EXPORT R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame )
|
||||||
|
{
|
||||||
|
if( !m_pSpriteModel || m_pSpriteModel->type != mod_sprite || !m_pSpriteModel->cache.data )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return R_GetSpriteFrame( m_pSpriteModel, frame, 0.0f )->gl_texturenum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
Draw_StretchPicImplementation
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void R_DrawStretchPicImplementation( int x, int y, int w, int h, int s1, int t1, int s2, int t2, image_t *pic )
|
||||||
|
{
|
||||||
|
pixel_t *source, *dest;
|
||||||
|
unsigned int v, u, sv;
|
||||||
|
unsigned int height;
|
||||||
|
unsigned int f, fstep;
|
||||||
|
int skip;
|
||||||
|
qboolean transparent = false;
|
||||||
|
pixel_t *buffer;
|
||||||
|
|
||||||
|
if( x < 0 )
|
||||||
|
{
|
||||||
|
s1 += (-x)*(s2-s1) / w;
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if( x + w > vid.width )
|
||||||
|
{
|
||||||
|
s2 -= (x + w - vid.width) * (s2 - s1)/ w ;
|
||||||
|
w = vid.width - x;
|
||||||
|
}
|
||||||
|
if( y + h > vid.height )
|
||||||
|
{
|
||||||
|
t2 -= (y + h - vid.height) * (t2 - t1) / h;
|
||||||
|
h = vid.height - y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !pic->pixels[0] || s1 >= s2 || t1 >= t2 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
//gEngfuncs.Con_Printf ("pixels is %p\n", pic->pixels[0] );
|
||||||
|
|
||||||
|
height = h;
|
||||||
|
if (y < 0)
|
||||||
|
{
|
||||||
|
skip = -y;
|
||||||
|
height += y;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
skip = 0;
|
||||||
|
|
||||||
|
dest = vid.buffer + y * vid.rowbytes + x;
|
||||||
|
|
||||||
|
if( pic->alpha_pixels )
|
||||||
|
{
|
||||||
|
buffer = pic->alpha_pixels;
|
||||||
|
transparent = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
buffer = pic->pixels[0];
|
||||||
|
|
||||||
|
|
||||||
|
#pragma omp parallel for schedule(static)
|
||||||
|
for (v=0 ; v<height ; v++)
|
||||||
|
{
|
||||||
|
int alpha1 = vid.alpha;
|
||||||
|
#ifdef _OPENMP
|
||||||
|
pixel_t *dest = vid.buffer + (y + v) * vid.rowbytes + x;
|
||||||
|
#endif
|
||||||
|
sv = (skip + v)*(t2-t1)/h + t1;
|
||||||
|
source = buffer + sv*pic->width + s1;
|
||||||
|
|
||||||
|
{
|
||||||
|
f = 0;
|
||||||
|
fstep = ((s2-s1) << 16)/w;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
for (u=0 ; u<w ; u+=4)
|
||||||
|
{
|
||||||
|
dest[u] = source[f>>16];
|
||||||
|
f += fstep;
|
||||||
|
dest[u+1] = source[f>>16];
|
||||||
|
f += fstep;
|
||||||
|
dest[u+2] = source[f>>16];
|
||||||
|
f += fstep;
|
||||||
|
dest[u+3] = source[f>>16];
|
||||||
|
f += fstep;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (u=0 ; u<w ; u++)
|
||||||
|
{
|
||||||
|
pixel_t src = source[f>>16];
|
||||||
|
int alpha = alpha1;
|
||||||
|
f += fstep;
|
||||||
|
|
||||||
|
if( transparent )
|
||||||
|
{
|
||||||
|
alpha &= src >> ( 16 - 3 );
|
||||||
|
src = src << 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( alpha == 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( vid.color != COLOR_WHITE )
|
||||||
|
src = vid.modmap[(src & 0xff00)|(vid.color>>8)] << 8 | (src & vid.color & 0xff) | ((src & 0xff) >> 3);
|
||||||
|
|
||||||
|
if( vid.rendermode == kRenderTransAdd)
|
||||||
|
{
|
||||||
|
pixel_t screen = dest[u];
|
||||||
|
dest[u] = vid.addmap[(src & 0xff00)|(screen>>8)] << 8 | (screen & 0xff) | ((src & 0xff) >> 0);
|
||||||
|
}
|
||||||
|
else if( alpha < 7) // && (vid.rendermode == kRenderTransAlpha || vid.rendermode == kRenderTransTexture ) )
|
||||||
|
{
|
||||||
|
pixel_t screen = dest[u]; // | 0xff & screen & src ;
|
||||||
|
dest[u] = BLEND_ALPHA( alpha, src, screen);//vid.alphamap[( alpha << 16)|(src & 0xff00)|(screen>>8)] << 8 | (screen & 0xff) >> 3 | ((src & 0xff) >> 3);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dest[u] = src;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
dest += vid.rowbytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
R_DrawStretchPic
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum )
|
||||||
|
{
|
||||||
|
image_t *pic = R_GetTexture(texnum);
|
||||||
|
int width = pic->width, height = pic->height;
|
||||||
|
// GL_Bind( XASH_TEXTURE0, texnum );
|
||||||
|
if( s2 > 1.0f || t2 > 1.0f )
|
||||||
|
return;
|
||||||
|
if( s1 < 0.0f || t1 < 0.0f )
|
||||||
|
return;
|
||||||
|
if( w < 1.0f || h < 1.0f )
|
||||||
|
return;
|
||||||
|
R_DrawStretchPicImplementation(x,y,w,h, width * s1, height * t1, width * s2, height * t2, pic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Draw_Fill (int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
pixel_t *dest;
|
||||||
|
unsigned int v, u;
|
||||||
|
unsigned int height;
|
||||||
|
int skip;
|
||||||
|
pixel_t src = vid.color;
|
||||||
|
int alpha = vid.alpha;
|
||||||
|
|
||||||
|
if( x < 0 )
|
||||||
|
x = 0;
|
||||||
|
|
||||||
|
if( x + w > vid.width )
|
||||||
|
w = vid.width - x;
|
||||||
|
|
||||||
|
if( w <= 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( y + h > vid.height )
|
||||||
|
h = vid.height - y;
|
||||||
|
|
||||||
|
if( h <= 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
height = h;
|
||||||
|
if( y < 0 )
|
||||||
|
{
|
||||||
|
if( h <= -y )
|
||||||
|
return;
|
||||||
|
skip = -y;
|
||||||
|
height += y;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
skip = 0;
|
||||||
|
|
||||||
|
dest = vid.buffer + y * vid.rowbytes + x;
|
||||||
|
|
||||||
|
#pragma omp parallel for schedule(static)
|
||||||
|
for (v=0 ; v<height ; v++)
|
||||||
|
{
|
||||||
|
#ifdef _OPENMP
|
||||||
|
pixel_t *dest = vid.buffer + (y + v) * vid.rowbytes + x;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
for (u=0 ; u<w ; u+=4)
|
||||||
|
{
|
||||||
|
dest[u] = source[f>>16];
|
||||||
|
f += fstep;
|
||||||
|
dest[u+1] = source[f>>16];
|
||||||
|
f += fstep;
|
||||||
|
dest[u+2] = source[f>>16];
|
||||||
|
f += fstep;
|
||||||
|
dest[u+3] = source[f>>16];
|
||||||
|
f += fstep;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (u=0 ; u<w ; u++)
|
||||||
|
{
|
||||||
|
if( alpha == 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( vid.rendermode == kRenderTransAdd)
|
||||||
|
{
|
||||||
|
pixel_t screen = dest[u];
|
||||||
|
dest[u] = vid.addmap[(src & 0xff00)|(screen>>8)] << 8 | (screen & 0xff) | ((src & 0xff) >> 0);
|
||||||
|
}
|
||||||
|
else if( alpha < 7) // && (vid.rendermode == kRenderTransAlpha || vid.rendermode == kRenderTransTexture ) )
|
||||||
|
{
|
||||||
|
pixel_t screen = dest[u]; // | 0xff & screen & src ;
|
||||||
|
dest[u] = BLEND_ALPHA( alpha, src, screen);//vid.alphamap[( alpha << 16)|(src & 0xff00)|(screen>>8)] << 8 | (screen & 0xff) >> 3 | ((src & 0xff) >> 3);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dest[u] = src;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
dest += vid.rowbytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
Draw_TileClear
|
||||||
|
|
||||||
|
This repeats a 64*64 tile graphic to fill the screen around a sized down
|
||||||
|
refresh window.
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT R_DrawTileClear( int texnum, int x, int y, int w, int h )
|
||||||
|
{
|
||||||
|
int tw, th, x2, i, j;
|
||||||
|
image_t *pic;
|
||||||
|
pixel_t *psrc, *pdest;
|
||||||
|
|
||||||
|
GL_SetRenderMode( kRenderNormal );
|
||||||
|
_TriColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||||
|
GL_Bind( XASH_TEXTURE0, texnum );
|
||||||
|
|
||||||
|
pic = R_GetTexture( texnum );
|
||||||
|
|
||||||
|
tw = pic->width;
|
||||||
|
th = pic->height;
|
||||||
|
if (x < 0)
|
||||||
|
{
|
||||||
|
w += x;
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if (y < 0)
|
||||||
|
{
|
||||||
|
h += y;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
if (x + w > vid.width)
|
||||||
|
w = vid.width - x;
|
||||||
|
if (y + h > vid.height)
|
||||||
|
h = vid.height - y;
|
||||||
|
if (w <= 0 || h <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
x2 = x + w;
|
||||||
|
pdest = vid.buffer + y*vid.rowbytes;
|
||||||
|
for (i=0 ; i<h ; i++, pdest += vid.rowbytes)
|
||||||
|
{
|
||||||
|
psrc = pic->pixels[0] + tw * ((i+y)&63);
|
||||||
|
for (j=x ; j<x2 ; j++)
|
||||||
|
pdest[j] = psrc[j&63];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
R_DrawStretchRaw
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty )
|
||||||
|
{
|
||||||
|
byte *raw = NULL;
|
||||||
|
image_t *tex;
|
||||||
|
|
||||||
|
raw = (byte *)data;
|
||||||
|
|
||||||
|
//pglDisable( GL_BLEND );
|
||||||
|
//pglDisable( GL_ALPHA_TEST );
|
||||||
|
//pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
|
||||||
|
|
||||||
|
tex = R_GetTexture( tr.cinTexture );
|
||||||
|
GL_Bind( XASH_TEXTURE0, tr.cinTexture );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
R_UploadStretchRaw
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data )
|
||||||
|
{
|
||||||
|
byte *raw = NULL;
|
||||||
|
image_t *tex;
|
||||||
|
raw = (byte *)data;
|
||||||
|
|
||||||
|
tex = R_GetTexture( texture );
|
||||||
|
GL_Bind( GL_KEEP_UNIT, texture );
|
||||||
|
tex->width = cols;
|
||||||
|
tex->height = rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
R_Set2DMode
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT R_Set2DMode( qboolean enable )
|
||||||
|
{
|
||||||
|
vid.color = COLOR_WHITE;
|
||||||
|
vid.is2d = enable;
|
||||||
|
vid.alpha = 7;
|
||||||
|
|
||||||
|
if( enable )
|
||||||
|
{
|
||||||
|
// if( glState.in2DMode )
|
||||||
|
// return;
|
||||||
|
#if 0
|
||||||
|
// set 2D virtual screen size
|
||||||
|
pglViewport( 0, 0, gpGlobals->width, gpGlobals->height );
|
||||||
|
pglMatrixMode( GL_PROJECTION );
|
||||||
|
pglLoadIdentity();
|
||||||
|
pglOrtho( 0, gpGlobals->width, gpGlobals->height, 0, -99999, 99999 );
|
||||||
|
pglMatrixMode( GL_MODELVIEW );
|
||||||
|
pglLoadIdentity();
|
||||||
|
|
||||||
|
GL_Cull( GL_NONE );
|
||||||
|
|
||||||
|
pglDepthMask( GL_FALSE );
|
||||||
|
pglDisable( GL_DEPTH_TEST );
|
||||||
|
pglEnable( GL_ALPHA_TEST );
|
||||||
|
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// glState.in2DMode = true;
|
||||||
|
RI.currententity = NULL;
|
||||||
|
RI.currentmodel = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
pglDepthMask( GL_TRUE );
|
||||||
|
pglEnable( GL_DEPTH_TEST );
|
||||||
|
glState.in2DMode = false;
|
||||||
|
|
||||||
|
pglMatrixMode( GL_PROJECTION );
|
||||||
|
GL_LoadMatrix( RI.projectionMatrix );
|
||||||
|
|
||||||
|
pglMatrixMode( GL_MODELVIEW );
|
||||||
|
GL_LoadMatrix( RI.worldviewMatrix );
|
||||||
|
|
||||||
|
GL_Cull( GL_FRONT );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,771 @@
|
||||||
|
#include "r_local.h"
|
||||||
|
#include "../ref_gl/gl_export.h"
|
||||||
|
|
||||||
|
struct swblit_s
|
||||||
|
{
|
||||||
|
uint stride;
|
||||||
|
uint bpp;
|
||||||
|
uint rmask, gmask, bmask;
|
||||||
|
void *(*pLockBuffer)( void );
|
||||||
|
void (*pUnlockBuffer)( void );
|
||||||
|
qboolean(*pCreateBuffer)( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b );
|
||||||
|
uint rotate;
|
||||||
|
} swblit;
|
||||||
|
|
||||||
|
|
||||||
|
qboolean R_SetDisplayTransform( ref_screen_rotation_t rotate, int offset_x, int offset_y, float scale_x, float scale_y )
|
||||||
|
{
|
||||||
|
qboolean ret = true;
|
||||||
|
if( rotate > 1 )
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Printf("only 0-1 rotation supported\n");
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
swblit.rotate = rotate;
|
||||||
|
|
||||||
|
if( offset_x || offset_y )
|
||||||
|
{
|
||||||
|
// it is possible implement for offset > 0
|
||||||
|
gEngfuncs.Con_Printf("offset transform not supported\n");
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( scale_x != 1.0f || scale_y != 1.0f )
|
||||||
|
{
|
||||||
|
// maybe implement 2x2?
|
||||||
|
gEngfuncs.Con_Printf("scale transform not supported\n");
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================
|
||||||
|
DebugCallback
|
||||||
|
|
||||||
|
For ARB_debug_output
|
||||||
|
========================
|
||||||
|
*/
|
||||||
|
static void APIENTRY GL_DebugOutput( GLuint source, GLuint type, GLuint id, GLuint severity, GLint length, const GLcharARB *message, GLvoid *userParam )
|
||||||
|
{
|
||||||
|
switch( type )
|
||||||
|
{
|
||||||
|
case GL_DEBUG_TYPE_ERROR_ARB:
|
||||||
|
gEngfuncs.Con_Printf( S_OPENGL_ERROR "%s\n", message );
|
||||||
|
break;
|
||||||
|
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
|
||||||
|
gEngfuncs.Con_Printf( S_OPENGL_WARN "%s\n", message );
|
||||||
|
break;
|
||||||
|
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
|
||||||
|
gEngfuncs.Con_Printf( S_OPENGL_WARN "%s\n", message );
|
||||||
|
break;
|
||||||
|
case GL_DEBUG_TYPE_PORTABILITY_ARB:
|
||||||
|
gEngfuncs.Con_Reportf( S_OPENGL_WARN "%s\n", message );
|
||||||
|
break;
|
||||||
|
case GL_DEBUG_TYPE_PERFORMANCE_ARB:
|
||||||
|
gEngfuncs.Con_Printf( S_OPENGL_NOTE "%s\n", message );
|
||||||
|
break;
|
||||||
|
case GL_DEBUG_TYPE_OTHER_ARB:
|
||||||
|
default:
|
||||||
|
gEngfuncs.Con_Printf( S_OPENGL_NOTE "%s\n", message );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned short *glbuf;
|
||||||
|
static int tex;
|
||||||
|
|
||||||
|
#define LOAD(x) p##x = gEngfuncs.GL_GetProcAddress(#x); \
|
||||||
|
gEngfuncs.Con_Printf(#x " : %p\n",p##x)
|
||||||
|
|
||||||
|
|
||||||
|
void GAME_EXPORT GL_SetupAttributes( int safegl )
|
||||||
|
{
|
||||||
|
#if GLDEBUG
|
||||||
|
gEngfuncs.Con_Reportf( "Creating an extended GL context for debug...\n" );
|
||||||
|
gEngfuncs.GL_SetAttribute( REF_GL_CONTEXT_FLAGS, REF_GL_CONTEXT_DEBUG_FLAG );
|
||||||
|
#endif
|
||||||
|
// untill we have any blitter in ref api, setup GL
|
||||||
|
gEngfuncs.GL_SetAttribute( REF_GL_CONTEXT_PROFILE_MASK, REF_GL_CONTEXT_PROFILE_ES );
|
||||||
|
gEngfuncs.GL_SetAttribute( REF_GL_CONTEXT_EGL, 1 );
|
||||||
|
gEngfuncs.GL_SetAttribute( REF_GL_CONTEXT_MAJOR_VERSION, 3 );
|
||||||
|
gEngfuncs.GL_SetAttribute( REF_GL_CONTEXT_MINOR_VERSION, 0 );
|
||||||
|
gEngfuncs.GL_SetAttribute( REF_GL_DOUBLEBUFFER, 1 );
|
||||||
|
|
||||||
|
gEngfuncs.GL_SetAttribute( REF_GL_RED_SIZE, 5 );
|
||||||
|
gEngfuncs.GL_SetAttribute( REF_GL_GREEN_SIZE, 6 );
|
||||||
|
gEngfuncs.GL_SetAttribute( REF_GL_BLUE_SIZE, 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*pglOrthof)(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
|
||||||
|
void GL_FUNCTION( glBindBuffer)(GLenum target, GLuint buffer);
|
||||||
|
|
||||||
|
void GL_FUNCTION( glBufferData )(GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
|
||||||
|
void GL_FUNCTION( glGenBuffers )(GLsizei n, GLuint *buffers);
|
||||||
|
void GL_FUNCTION( glDeleteBuffers )(GLsizei n, const GLuint *buffers);
|
||||||
|
GLvoid* GL_FUNCTION( glMapBuffer )(GLenum target, GLenum access);
|
||||||
|
GLboolean GL_FUNCTION( glUnmapBuffer )(GLenum target);
|
||||||
|
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
|
||||||
|
#define GL_FRAMEBUFFER 0x8D40
|
||||||
|
#define GL_COLOR_ATTACHMENT0 0x8CE0
|
||||||
|
#define GL_READ_FRAMEBUFFER 0x8CA8
|
||||||
|
#define GL_DRAW_FRAMEBUFFER 0x8CA9
|
||||||
|
void GAME_EXPORT GL_InitExtensions( void )
|
||||||
|
{
|
||||||
|
LOAD(glBegin);
|
||||||
|
LOAD(glEnd);
|
||||||
|
LOAD(glTexCoord2f);
|
||||||
|
LOAD(glVertex2f);
|
||||||
|
LOAD(glEnable);
|
||||||
|
LOAD(glDisable);
|
||||||
|
LOAD(glTexImage2D);
|
||||||
|
LOAD(glOrtho);
|
||||||
|
LOAD(glOrthof);
|
||||||
|
LOAD(glMatrixMode);
|
||||||
|
LOAD(glLoadIdentity);
|
||||||
|
LOAD(glViewport);
|
||||||
|
LOAD(glBindTexture);
|
||||||
|
LOAD(glDebugMessageCallbackARB);
|
||||||
|
LOAD(glDebugMessageControlARB);
|
||||||
|
LOAD(glGetError);
|
||||||
|
LOAD(glGenTextures);
|
||||||
|
LOAD(glTexParameteri);
|
||||||
|
LOAD(glEnableClientState);
|
||||||
|
LOAD(glDisableClientState);
|
||||||
|
LOAD(glVertexPointer);
|
||||||
|
LOAD(glTexCoordPointer);
|
||||||
|
LOAD(glDrawElements);
|
||||||
|
LOAD(glClear);
|
||||||
|
LOAD(glClearColor);
|
||||||
|
LOAD(glGetString);
|
||||||
|
LOAD(glColor4f);
|
||||||
|
LOAD(glDrawArrays);
|
||||||
|
LOAD(glBindBuffer);
|
||||||
|
LOAD(glBufferData);
|
||||||
|
LOAD(glGenBuffers);
|
||||||
|
LOAD(glDeleteBuffers);
|
||||||
|
LOAD(glMapBuffer);
|
||||||
|
LOAD(glUnmapBuffer);
|
||||||
|
LOAD(glGenFramebuffers);
|
||||||
|
LOAD(glBindFramebuffer);
|
||||||
|
LOAD(glFramebufferTexture2D);
|
||||||
|
LOAD(glBlitFramebuffer);
|
||||||
|
LOAD(glGenTextures);
|
||||||
|
gEngfuncs.Con_Printf("version:%s\n",pglGetString(GL_VERSION));
|
||||||
|
#if GLDEBUG
|
||||||
|
if( gpGlobals->developer )
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Reportf( "Installing GL_DebugOutput...\n");
|
||||||
|
pglDebugMessageCallbackARB( GL_DebugOutput, NULL );
|
||||||
|
|
||||||
|
// force everything to happen in the main thread instead of in a separate driver thread
|
||||||
|
pglEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB );
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable all the low priority messages
|
||||||
|
pglDebugMessageControlARB( GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, true );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
void GAME_EXPORT GL_ClearExtensions( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *R_Lock_GL1( void )
|
||||||
|
{
|
||||||
|
return glbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void R_Unlock_GL1( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vid.width, vid.height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, glbuf );
|
||||||
|
//gEngfuncs.Con_Printf("%d\n",pglGetError());
|
||||||
|
pglBegin( GL_QUADS );
|
||||||
|
pglTexCoord2f( 0, 0 );
|
||||||
|
pglVertex2f( 0, 0 );
|
||||||
|
|
||||||
|
pglTexCoord2f( 1, 0 );
|
||||||
|
pglVertex2f( 1, 0 );
|
||||||
|
|
||||||
|
pglTexCoord2f( 1, 1 );
|
||||||
|
pglVertex2f( 1, 1 );
|
||||||
|
|
||||||
|
pglTexCoord2f( 0, 1 );
|
||||||
|
pglVertex2f( 0, 1 );
|
||||||
|
pglEnd();
|
||||||
|
gEngfuncs.GL_SwapBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void R_Unlock_GLES1( void )
|
||||||
|
{
|
||||||
|
pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vid.width, vid.height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, glbuf );
|
||||||
|
pglDrawArrays( GL_TRIANGLE_FAN, 0,4 );
|
||||||
|
|
||||||
|
gEngfuncs.GL_SwapBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean R_CreateBuffer_GL1( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
|
||||||
|
{
|
||||||
|
pglViewport( 0, 0, width, height );
|
||||||
|
pglMatrixMode( GL_PROJECTION );
|
||||||
|
pglLoadIdentity();
|
||||||
|
pglOrtho( 0, 1, 1, 0, -99999, 99999 );
|
||||||
|
pglMatrixMode( GL_MODELVIEW );
|
||||||
|
pglLoadIdentity();
|
||||||
|
|
||||||
|
pglEnable( GL_TEXTURE_2D );
|
||||||
|
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
|
if( glbuf )
|
||||||
|
Mem_Free(glbuf);
|
||||||
|
|
||||||
|
glbuf = Mem_Malloc( r_temppool, width*height*2 );
|
||||||
|
|
||||||
|
*stride = width;
|
||||||
|
*bpp = 2;
|
||||||
|
*r = MASK(5) << (6 + 5);
|
||||||
|
*g = MASK(6) << 5;
|
||||||
|
*b = MASK(5);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean R_CreateBuffer_GLES1( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
|
||||||
|
{
|
||||||
|
float data[] = {
|
||||||
|
// quad verts match texcoords
|
||||||
|
0, 0,
|
||||||
|
1, 0,
|
||||||
|
1, 1,
|
||||||
|
0, 1,
|
||||||
|
};
|
||||||
|
int vbo;
|
||||||
|
|
||||||
|
pglViewport( 0, 0, width, height );
|
||||||
|
pglMatrixMode( GL_PROJECTION );
|
||||||
|
pglLoadIdentity();
|
||||||
|
// project 0..1 to screen size
|
||||||
|
pglOrthof( 0, 1, 1, 0, -99999, 99999 );
|
||||||
|
pglMatrixMode( GL_MODELVIEW );
|
||||||
|
pglLoadIdentity();
|
||||||
|
|
||||||
|
pglEnable( GL_TEXTURE_2D );
|
||||||
|
pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
|
||||||
|
pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
|
||||||
|
|
||||||
|
if( vbo )
|
||||||
|
pglDeleteBuffers( 1,&vbo );
|
||||||
|
|
||||||
|
pglGenBuffers( 1,&vbo );
|
||||||
|
pglBindBuffer( GL_ARRAY_BUFFER_ARB, vbo );
|
||||||
|
pglBufferData( GL_ARRAY_BUFFER_ARB, sizeof(data), data, GL_STATIC_DRAW_ARB );
|
||||||
|
|
||||||
|
pglEnableClientState( GL_VERTEX_ARRAY );
|
||||||
|
pglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||||
|
|
||||||
|
pglVertexPointer( 2, GL_FLOAT, 8, 0 );
|
||||||
|
pglTexCoordPointer( 2, GL_FLOAT, 8, 0 );
|
||||||
|
pglBindBuffer( GL_ARRAY_BUFFER_ARB, 0 ) ;
|
||||||
|
pglColor4f( 1, 1, 1, 1 );
|
||||||
|
|
||||||
|
|
||||||
|
if( glbuf )
|
||||||
|
Mem_Free( glbuf );
|
||||||
|
|
||||||
|
glbuf = Mem_Malloc( r_temppool, width*height*2 );
|
||||||
|
|
||||||
|
*stride = width;
|
||||||
|
*bpp = 2;
|
||||||
|
*r = MASK(5) << (6 + 5);
|
||||||
|
*g = MASK(6) << 5;
|
||||||
|
*b = MASK(5);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *R_Lock_GLES3( void )
|
||||||
|
{
|
||||||
|
pglBufferData( GL_PIXEL_UNPACK_BUFFER, vid.width * vid.height * 2, 0, GL_STREAM_DRAW_ARB );
|
||||||
|
return pglMapBuffer( GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY_ARB );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void R_Unlock_GLES3( void )
|
||||||
|
{
|
||||||
|
gEngfuncs.GL_SwapBuffers();
|
||||||
|
pglUnmapBuffer( GL_PIXEL_UNPACK_BUFFER );
|
||||||
|
pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vid.width, vid.height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0 );
|
||||||
|
//pglDrawArrays( GL_TRIANGLE_FAN, 0,4 );
|
||||||
|
pglBlitFramebuffer( 0, vid.height, vid.width, 0, 0, 0, vid.width, vid.height, GL_COLOR_BUFFER_BIT, GL_NEAREST );
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean R_CreateBuffer_GLES3( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
|
||||||
|
{
|
||||||
|
float data[] = {
|
||||||
|
// quad verts match texcoords
|
||||||
|
0, 0,
|
||||||
|
1, 0,
|
||||||
|
1, 1,
|
||||||
|
0, 1,
|
||||||
|
};
|
||||||
|
int vbo, pbo, fbo, to;
|
||||||
|
|
||||||
|
// shitty fbo does not work without texture objects :(
|
||||||
|
pglGenTextures( 1, &to );
|
||||||
|
pglBindTexture( GL_TEXTURE_2D, to );
|
||||||
|
pglViewport( 0, 0, width, height );
|
||||||
|
/*pglMatrixMode( GL_PROJECTION );
|
||||||
|
pglLoadIdentity();
|
||||||
|
// project 0..1 to screen size
|
||||||
|
pglOrtho( 0, 1, 1, 0, -99999, 99999 );
|
||||||
|
pglMatrixMode( GL_MODELVIEW );
|
||||||
|
pglLoadIdentity();
|
||||||
|
|
||||||
|
pglEnable( GL_TEXTURE_2D );
|
||||||
|
pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
|
||||||
|
pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
|
||||||
|
|
||||||
|
if( vbo )
|
||||||
|
pglDeleteBuffers( 1,&vbo );
|
||||||
|
*/
|
||||||
|
|
||||||
|
if( pbo )
|
||||||
|
pglDeleteBuffers( 1,&pbo );
|
||||||
|
|
||||||
|
//pglGenBuffers( 1,&vbo );
|
||||||
|
pglGenBuffers( 1, &pbo );
|
||||||
|
//pglBindBuffer( GL_ARRAY_BUFFER_ARB, vbo );
|
||||||
|
//pglBufferData( GL_ARRAY_BUFFER_ARB, sizeof(data), data, GL_STATIC_DRAW_ARB );
|
||||||
|
|
||||||
|
//pglEnableClientState( GL_VERTEX_ARRAY );
|
||||||
|
//pglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||||
|
|
||||||
|
//pglVertexPointer( 2, GL_FLOAT, 8, 0 );
|
||||||
|
//pglTexCoordPointer( 2, GL_FLOAT, 8, 0 );
|
||||||
|
//pglBindBuffer( GL_ARRAY_BUFFER_ARB, 0 );
|
||||||
|
|
||||||
|
pglBindBuffer( GL_PIXEL_UNPACK_BUFFER, pbo );
|
||||||
|
pglBufferData( GL_PIXEL_UNPACK_BUFFER, width * height * 2, 0, GL_STREAM_DRAW_ARB );
|
||||||
|
pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0 );
|
||||||
|
|
||||||
|
pglGenFramebuffers(1, &fbo);
|
||||||
|
pglBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||||
|
pglFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, to, 0);
|
||||||
|
pglBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
//pglColor4f( 1, 1, 1, 1 );
|
||||||
|
|
||||||
|
|
||||||
|
*stride = width;
|
||||||
|
*bpp = 2;
|
||||||
|
*r = MASK(5) << (6 + 5);
|
||||||
|
*g = MASK(6) << 5;
|
||||||
|
*b = MASK(5);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int FIRST_BIT( uint mask )
|
||||||
|
{
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
for( i = 0; !(BIT(i) & mask); i++ );
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int COUNT_BITS( uint mask )
|
||||||
|
{
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
for( i = 0; mask; mask = mask >> 1 )
|
||||||
|
i += mask & 1;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void R_BuildScreenMap( void )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint rshift = FIRST_BIT(swblit.rmask), gshift = FIRST_BIT(swblit.gmask), bshift = FIRST_BIT(swblit.bmask);
|
||||||
|
uint rbits = COUNT_BITS(swblit.rmask), gbits = COUNT_BITS(swblit.gmask), bbits = COUNT_BITS(swblit.bmask);
|
||||||
|
uint rmult = BIT(rbits), gmult = BIT(gbits), bmult = BIT(bbits);
|
||||||
|
uint rdiv = MASK(5), gdiv = MASK(6), bdiv = MASK(5);
|
||||||
|
|
||||||
|
gEngfuncs.Con_Printf("Blit table: %d %d %d %d %d %d\n", rmult, gmult, bmult, rdiv, gdiv, bdiv );
|
||||||
|
|
||||||
|
#ifdef SEPARATE_BLIT
|
||||||
|
for( i = 0; i < 256; i++ )
|
||||||
|
{
|
||||||
|
unsigned int r,g,b;
|
||||||
|
|
||||||
|
// 332 to 565
|
||||||
|
r = ((i >> (8 - 3) )<< 2 ) & MASK(5);
|
||||||
|
g = ((i >> (8 - 3 - 3)) << 3) & MASK(6);
|
||||||
|
b = ((i >> (8 - 3 - 3 - 2)) << 3) & MASK(5);
|
||||||
|
vid.screen_major[i] = r << (6 + 5) | (g << 5) | b;
|
||||||
|
|
||||||
|
|
||||||
|
// restore minor GBRGBRGB
|
||||||
|
r = MOVE_BIT(i, 5, 1) | MOVE_BIT(i, 2, 0);
|
||||||
|
g = MOVE_BIT(i, 7, 2) | MOVE_BIT(i, 4, 1) | MOVE_BIT(i, 1, 0);
|
||||||
|
b = MOVE_BIT(i, 6, 2) | MOVE_BIT(i, 3, 1) | MOVE_BIT(i, 0, 0);
|
||||||
|
vid.screen_minor[i] = r << (6 + 5) | (g << 5) | b;
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for( i = 0; i < 256; i++ )
|
||||||
|
{
|
||||||
|
unsigned int r,g,b , major, j;
|
||||||
|
|
||||||
|
// 332 to 565
|
||||||
|
r = ((i >> (8 - 3) )<< 2 ) & MASK(5);
|
||||||
|
g = ((i >> (8 - 3 - 3)) << 3) & MASK(6);
|
||||||
|
b = ((i >> (8 - 3 - 3 - 2)) << 3) & MASK(5);
|
||||||
|
//major = r << (6 + 5) | (g << 5) | b;
|
||||||
|
major = (r * rmult / rdiv) << rshift | (g * gmult / gdiv) << gshift | (b * bmult / bdiv) << bshift;
|
||||||
|
|
||||||
|
|
||||||
|
for( j = 0; j < 256; j++ )
|
||||||
|
{
|
||||||
|
uint minor;
|
||||||
|
// restore minor GBRGBRGB
|
||||||
|
r = MOVE_BIT(j, 5, 1) | MOVE_BIT(j, 2, 0);
|
||||||
|
g = MOVE_BIT(j, 7, 2) | MOVE_BIT(j, 4, 1) | MOVE_BIT(j, 1, 0);
|
||||||
|
b = MOVE_BIT(j, 6, 2) | MOVE_BIT(j, 3, 1) | MOVE_BIT(j, 0, 0);
|
||||||
|
//vid.screen[(i<<8)|j] = r << (6 + 5) | (g << 5) | b | major;
|
||||||
|
minor = (r * rmult / rdiv) << rshift | (g * gmult / gdiv) << gshift | (b * bmult / bdiv) << bshift;
|
||||||
|
|
||||||
|
if( swblit.bpp == 2 )
|
||||||
|
vid.screen[(i<<8)|j] = major | minor;
|
||||||
|
else
|
||||||
|
vid.screen32[(i<<8)|j] = major | minor;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FOR_EACH_COLOR(x) for( r##x = 0; r##x < BIT(3); r##x++ ) for( g##x = 0; g##x < BIT(3); g##x++ ) for( b##x = 0; b##x < BIT(2); b##x++ )
|
||||||
|
|
||||||
|
void R_BuildBlendMaps( void )
|
||||||
|
{
|
||||||
|
unsigned int r1, g1, b1;
|
||||||
|
unsigned int r2, g2, b2;
|
||||||
|
unsigned int i, j;
|
||||||
|
|
||||||
|
FOR_EACH_COLOR(1)FOR_EACH_COLOR(2)
|
||||||
|
{
|
||||||
|
unsigned int r, g, b;
|
||||||
|
unsigned short index1 = r1 << (2 + 3) | g1 << 2 | b1;
|
||||||
|
unsigned short index2 = (r2 << (2 + 3) | g2 << 2 | b2) << 8;
|
||||||
|
unsigned int a;
|
||||||
|
|
||||||
|
r = r1 + r2;
|
||||||
|
g = g1 + g2;
|
||||||
|
b = b1 + b2;
|
||||||
|
if( r > MASK(3) )
|
||||||
|
r = MASK(3);
|
||||||
|
if( g > MASK(3) )
|
||||||
|
g = MASK(3);
|
||||||
|
if( b > MASK(2) )
|
||||||
|
b = MASK(2);
|
||||||
|
ASSERT(!vid.addmap[index2|index1]);
|
||||||
|
|
||||||
|
vid.addmap[index2|index1] = r << (2 + 3) | g << 2 | b;
|
||||||
|
r = r1 * r2 / MASK(3);
|
||||||
|
g = g1 * g2 / MASK(3);
|
||||||
|
b = b1 * b2 / MASK(2);
|
||||||
|
|
||||||
|
vid.modmap[index2|index1] = r << (2 + 3) | g << 2 | b;
|
||||||
|
#if 0
|
||||||
|
for( a = 0; a < 8; a++ )
|
||||||
|
{
|
||||||
|
r = r1 * (7 - a) / 7 + r2 * a / 7;
|
||||||
|
g = g1 * (7 - a) / 7 + g2 * a / 7;
|
||||||
|
b = b1 * (7 - a) / 7 + b2 * a / 7;
|
||||||
|
//if( b == 1 ) b = 0;
|
||||||
|
vid.alphamap[a << 16|index2|index1] = r << (2 + 3) | g << 2 | b;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
for( i = 0; i < 8192; i++ )
|
||||||
|
{
|
||||||
|
unsigned int r, g, b;
|
||||||
|
uint color = i << 3;
|
||||||
|
uint m = color >> 8;
|
||||||
|
uint j = color & 0xff;
|
||||||
|
unsigned short index1 = i;
|
||||||
|
|
||||||
|
r1 = ((m >> (8 - 3) )<< 2 ) & MASK(5);
|
||||||
|
g1 = ((m >> (8 - 3 - 3)) << 3) & MASK(6);
|
||||||
|
b1 = ((m >> (8 - 3 - 3 - 2)) << 3) & MASK(5);
|
||||||
|
r1 |= MOVE_BIT(j, 5, 1) | MOVE_BIT(j, 2, 0);
|
||||||
|
g1 |= MOVE_BIT(j, 7, 2) | MOVE_BIT(j, 4, 1) | MOVE_BIT(j, 1, 0);
|
||||||
|
b1 |= MOVE_BIT(j, 6, 2) | MOVE_BIT(j, 3, 1) | MOVE_BIT(j, 0, 0);
|
||||||
|
|
||||||
|
|
||||||
|
for( j = 0; j < 32; j++)
|
||||||
|
{
|
||||||
|
unsigned int index2 = j << 13;
|
||||||
|
unsigned int major, minor;
|
||||||
|
r = r1 * j / 32;
|
||||||
|
g = g1 * j / 32;
|
||||||
|
b = b1 * j / 32;
|
||||||
|
major = (((r >> 2) & MASK(3)) << 5) |( (( (g >> 3) & MASK(3)) << 2 ) )| (((b >> 3) & MASK(2)));
|
||||||
|
|
||||||
|
// save minor GBRGBRGB
|
||||||
|
minor = MOVE_BIT(r,1,5) | MOVE_BIT(r,0,2) | MOVE_BIT(g,2,7) | MOVE_BIT(g,1,4) | MOVE_BIT(g,0,1) | MOVE_BIT(b,2,6)| MOVE_BIT(b,1,3)|MOVE_BIT(b,0,0);
|
||||||
|
|
||||||
|
vid.colormap[index2|index1] = major << 8 | (minor & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 1
|
||||||
|
for( i = 0; i < 1024; i++ )
|
||||||
|
{
|
||||||
|
unsigned int r, g, b;
|
||||||
|
uint color = i << 6 | BIT(5) | BIT(4) | BIT(3);
|
||||||
|
uint m = color >> 8;
|
||||||
|
uint j = color & 0xff;
|
||||||
|
unsigned short index1 = i;
|
||||||
|
|
||||||
|
r1 = ((m >> (8 - 3) )<< 2 ) & MASK(5);
|
||||||
|
g1 = ((m >> (8 - 3 - 3)) << 3) & MASK(6);
|
||||||
|
b1 = ((m >> (8 - 3 - 3 - 2)) << 3) & MASK(5);
|
||||||
|
r1 |= MOVE_BIT(j, 5, 1) | MOVE_BIT(j, 2, 0);
|
||||||
|
g1 |= MOVE_BIT(j, 7, 2) | MOVE_BIT(j, 4, 1) | MOVE_BIT(j, 1, 0);
|
||||||
|
b1 |= MOVE_BIT(j, 6, 2) | MOVE_BIT(j, 3, 1) | MOVE_BIT(j, 0, 0);
|
||||||
|
|
||||||
|
|
||||||
|
FOR_EACH_COLOR(2)
|
||||||
|
{
|
||||||
|
unsigned int index2 = (r2 << (2 + 3) | g2 << 2 | b2) << 10;
|
||||||
|
unsigned int k;
|
||||||
|
for( k = 0; k < 3; k++ )
|
||||||
|
{
|
||||||
|
unsigned int major, minor;
|
||||||
|
unsigned int a = k + 2;
|
||||||
|
|
||||||
|
|
||||||
|
r = r1 * (7 - a) / 7 + (r2 << 2 | BIT(2)) * a / 7;
|
||||||
|
g = g1 * (7 - a) / 7 + (g2 << 3 | MASK(2)) * a / 7;
|
||||||
|
b = b1 * (7 - a) / 7 + (b2 << 3 | MASK(2)) * a / 7;
|
||||||
|
if( r > MASK(5) )
|
||||||
|
r = MASK(5);
|
||||||
|
if( g > MASK(6) )
|
||||||
|
g = MASK(6);
|
||||||
|
if( b > MASK(5) )
|
||||||
|
b = MASK(5);
|
||||||
|
|
||||||
|
|
||||||
|
ASSERT( b < 32 );
|
||||||
|
major = (((r >> 2) & MASK(3)) << 5) |( (( (g >> 3) & MASK(3)) << 2 ) )| (((b >> 3) & MASK(2)));
|
||||||
|
|
||||||
|
// save minor GBRGBRGB
|
||||||
|
minor = MOVE_BIT(r,1,5) | MOVE_BIT(r,0,2) | MOVE_BIT(g,2,7) | MOVE_BIT(g,1,4) | MOVE_BIT(g,0,1) | MOVE_BIT(b,2,6)| MOVE_BIT(b,1,3)|MOVE_BIT(b,0,0);
|
||||||
|
minor = minor & ~0x3f;
|
||||||
|
|
||||||
|
|
||||||
|
vid.alphamap[k << 18|index2|index1] = major << 8 | (minor & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void R_AllocScreen( void );
|
||||||
|
|
||||||
|
void R_InitBlit( qboolean glblit )
|
||||||
|
{
|
||||||
|
R_BuildBlendMaps();
|
||||||
|
|
||||||
|
if( glblit )
|
||||||
|
{
|
||||||
|
swblit.pLockBuffer = R_Lock_GLES3;
|
||||||
|
swblit.pUnlockBuffer = R_Unlock_GLES3;
|
||||||
|
swblit.pCreateBuffer = R_CreateBuffer_GLES3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
swblit.pLockBuffer = gEngfuncs.SW_LockBuffer;
|
||||||
|
swblit.pUnlockBuffer = gEngfuncs.SW_UnlockBuffer;
|
||||||
|
swblit.pCreateBuffer = gEngfuncs.SW_CreateBuffer;
|
||||||
|
}
|
||||||
|
R_AllocScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void R_AllocScreen( void )
|
||||||
|
{
|
||||||
|
int w, h;
|
||||||
|
|
||||||
|
if( gpGlobals->width < 128 )
|
||||||
|
gpGlobals->width = 128;
|
||||||
|
if( gpGlobals->height < 128 )
|
||||||
|
gpGlobals->height = 128;
|
||||||
|
|
||||||
|
R_InitCaches();
|
||||||
|
|
||||||
|
if( swblit.rotate )
|
||||||
|
w = gpGlobals->height, h = gpGlobals->width;
|
||||||
|
else
|
||||||
|
h = gpGlobals->height, w = gpGlobals->width;
|
||||||
|
|
||||||
|
swblit.pCreateBuffer( w, h, &swblit.stride, &swblit.bpp,
|
||||||
|
&swblit.rmask, &swblit.gmask, &swblit.bmask);
|
||||||
|
R_BuildScreenMap();
|
||||||
|
vid.width = gpGlobals->width;
|
||||||
|
vid.height = gpGlobals->height;
|
||||||
|
vid.rowbytes = gpGlobals->width; // rowpixels
|
||||||
|
if( d_pzbuffer )
|
||||||
|
free( d_pzbuffer );
|
||||||
|
d_pzbuffer = malloc( vid.width*vid.height*2 + 64 );
|
||||||
|
if( vid.buffer )
|
||||||
|
free( vid.buffer );
|
||||||
|
|
||||||
|
vid.buffer = malloc( vid.width * vid.height*sizeof( pixel_t ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void R_BlitScreen( void )
|
||||||
|
{
|
||||||
|
int u, v;
|
||||||
|
void *buffer = swblit.pLockBuffer();
|
||||||
|
// gEngfuncs.Con_Printf("blit begin\n");
|
||||||
|
//memset( vid.buffer, 10, vid.width * vid.height );
|
||||||
|
|
||||||
|
if( !buffer || gpGlobals->width != vid.width || gpGlobals->height != vid.height )
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Printf("pre allocscrn\n");
|
||||||
|
R_AllocScreen();
|
||||||
|
gEngfuncs.Con_Printf("post allocscrn\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//return;
|
||||||
|
//byte *buf = vid.buffer;
|
||||||
|
|
||||||
|
//#pragma omp parallel for schedule(static)
|
||||||
|
//gEngfuncs.Con_Printf("swblit %d %d", swblit.bpp, vid.height );
|
||||||
|
if( swblit.rotate )
|
||||||
|
{
|
||||||
|
if( swblit.bpp == 2 )
|
||||||
|
{
|
||||||
|
unsigned short *pbuf = buffer;
|
||||||
|
for( v = 0; v < vid.height;v++)
|
||||||
|
{
|
||||||
|
uint start = vid.rowbytes * v;
|
||||||
|
uint d = swblit.stride - v - 1;
|
||||||
|
|
||||||
|
for( u = 0; u < vid.width; u++ )
|
||||||
|
{
|
||||||
|
unsigned int s = vid.screen[vid.buffer[start + u]];
|
||||||
|
pbuf[d] = s;
|
||||||
|
d += swblit.stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( swblit.bpp == 4 )
|
||||||
|
{
|
||||||
|
unsigned int *pbuf = buffer;
|
||||||
|
|
||||||
|
for( v = 0; v < vid.height;v++)
|
||||||
|
{
|
||||||
|
uint start = vid.rowbytes * v;
|
||||||
|
uint d = swblit.stride - v - 1;
|
||||||
|
|
||||||
|
for( u = 0; u < vid.width; u++ )
|
||||||
|
{
|
||||||
|
unsigned int s = vid.screen32[vid.buffer[start + u]];
|
||||||
|
pbuf[d] = s;
|
||||||
|
d += swblit.stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( swblit.bpp == 3 )
|
||||||
|
{
|
||||||
|
byte *pbuf = buffer;
|
||||||
|
for( v = 0; v < vid.height;v++)
|
||||||
|
{
|
||||||
|
uint start = vid.rowbytes * v;
|
||||||
|
uint d = swblit.stride - v - 1;
|
||||||
|
|
||||||
|
for( u = 0; u < vid.width; u++ )
|
||||||
|
{
|
||||||
|
unsigned int s = vid.screen32[vid.buffer[start + u]];
|
||||||
|
pbuf[(d)*3] = s;
|
||||||
|
s = s >> 8;
|
||||||
|
pbuf[(d)*3+1] = s;
|
||||||
|
s = s >> 8;
|
||||||
|
pbuf[(d)*3+2] = s;
|
||||||
|
d += swblit.stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( swblit.bpp == 2 )
|
||||||
|
{
|
||||||
|
unsigned short *pbuf = buffer;
|
||||||
|
for( v = 0; v < vid.height;v++)
|
||||||
|
{
|
||||||
|
uint start = vid.rowbytes * v;
|
||||||
|
uint dstart = swblit.stride * v;
|
||||||
|
|
||||||
|
for( u = 0; u < vid.width; u++ )
|
||||||
|
{
|
||||||
|
unsigned int s = vid.screen[vid.buffer[start + u]];
|
||||||
|
pbuf[dstart + u] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( swblit.bpp == 4 )
|
||||||
|
{
|
||||||
|
unsigned int *pbuf = buffer;
|
||||||
|
|
||||||
|
for( v = 0; v < vid.height;v++)
|
||||||
|
{
|
||||||
|
uint start = vid.rowbytes * v;
|
||||||
|
uint dstart = swblit.stride * v;
|
||||||
|
|
||||||
|
for( u = 0; u < vid.width; u++ )
|
||||||
|
{
|
||||||
|
unsigned int s = vid.screen32[vid.buffer[start + u]];
|
||||||
|
pbuf[dstart + u] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( swblit.bpp == 3 )
|
||||||
|
{
|
||||||
|
byte *pbuf = buffer;
|
||||||
|
for( v = 0; v < vid.height;v++)
|
||||||
|
{
|
||||||
|
uint start = vid.rowbytes * v;
|
||||||
|
uint dstart = swblit.stride * v;
|
||||||
|
|
||||||
|
for( u = 0; u < vid.width; u++ )
|
||||||
|
{
|
||||||
|
unsigned int s = vid.screen32[vid.buffer[start + u]];
|
||||||
|
pbuf[(dstart+u)*3] = s;
|
||||||
|
s = s >> 8;
|
||||||
|
pbuf[(dstart+u)*3+1] = s;
|
||||||
|
s = s >> 8;
|
||||||
|
pbuf[(dstart+u)*3+2] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swblit.pUnlockBuffer();
|
||||||
|
// gEngfuncs.Con_Printf("blit end\n");
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,501 @@
|
||||||
|
/*
|
||||||
|
gl_rlight.c - dynamic and static lights
|
||||||
|
Copyright (C) 2010 Uncle Mike
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
#include "pm_local.h"
|
||||||
|
#include "studio.h"
|
||||||
|
#include "xash3d_mathlib.h"
|
||||||
|
#include "ref_params.h"
|
||||||
|
|
||||||
|
//unused, need refactor
|
||||||
|
unsigned blocklights[10240];
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============================================================================
|
||||||
|
|
||||||
|
DYNAMIC LIGHTS
|
||||||
|
|
||||||
|
=============================================================================
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
==================
|
||||||
|
CL_RunLightStyles
|
||||||
|
|
||||||
|
==================
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT CL_RunLightStyles( void )
|
||||||
|
{
|
||||||
|
int i, k, flight, clight;
|
||||||
|
float l, lerpfrac, backlerp;
|
||||||
|
float frametime = (gpGlobals->time - gpGlobals->oldtime);
|
||||||
|
float scale;
|
||||||
|
lightstyle_t *ls;
|
||||||
|
|
||||||
|
if( !WORLDMODEL ) return;
|
||||||
|
|
||||||
|
scale = 1; //r_lighting_modulate->value;
|
||||||
|
|
||||||
|
// light animations
|
||||||
|
// 'm' is normal light, 'a' is no light, 'z' is double bright
|
||||||
|
for( i = 0; i < MAX_LIGHTSTYLES; i++ )
|
||||||
|
{
|
||||||
|
ls = gEngfuncs.GetLightStyle( i );
|
||||||
|
if( !WORLDMODEL->lightdata )
|
||||||
|
{
|
||||||
|
tr.lightstylevalue[i] = 256 * 256;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !ENGINE_GET_PARM( PARAM_GAMEPAUSED ) && frametime <= 0.1f )
|
||||||
|
ls->time += frametime; // evaluate local time
|
||||||
|
|
||||||
|
flight = (int)Q_floor( ls->time * 10 );
|
||||||
|
clight = (int)Q_ceil( ls->time * 10 );
|
||||||
|
lerpfrac = ( ls->time * 10 ) - flight;
|
||||||
|
backlerp = 1.0f - lerpfrac;
|
||||||
|
|
||||||
|
if( !ls->length )
|
||||||
|
{
|
||||||
|
tr.lightstylevalue[i] = 256 * scale;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if( ls->length == 1 )
|
||||||
|
{
|
||||||
|
// single length style so don't bother interpolating
|
||||||
|
tr.lightstylevalue[i] = ls->map[0] * 22 * scale;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if( !ls->interp ) // || !CVAR_TO_BOOL( cl_lightstyle_lerping ))
|
||||||
|
{
|
||||||
|
tr.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * scale;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// interpolate animating light
|
||||||
|
// frame just gone
|
||||||
|
k = ls->map[flight % ls->length];
|
||||||
|
l = (float)( k * 22.0f ) * backlerp;
|
||||||
|
|
||||||
|
// upcoming frame
|
||||||
|
k = ls->map[clight % ls->length];
|
||||||
|
l += (float)( k * 22.0f ) * lerpfrac;
|
||||||
|
|
||||||
|
tr.lightstylevalue[i] = (int)l * scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
R_MarkLights
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
|
||||||
|
{
|
||||||
|
float dist;
|
||||||
|
msurface_t *surf;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if( !node || node->contents < 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
dist = PlaneDiff( light->origin, node->plane );
|
||||||
|
|
||||||
|
if( dist > light->radius )
|
||||||
|
{
|
||||||
|
R_MarkLights( light, bit, node->children[0] );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( dist < -light->radius )
|
||||||
|
{
|
||||||
|
R_MarkLights( light, bit, node->children[1] );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark the polygons
|
||||||
|
surf = RI.currentmodel->surfaces + node->firstsurface;
|
||||||
|
|
||||||
|
for( i = 0; i < node->numsurfaces; i++, surf++ )
|
||||||
|
{
|
||||||
|
if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius ))
|
||||||
|
continue; // no intersection
|
||||||
|
|
||||||
|
if( surf->dlightframe != tr.framecount )//tr.dlightframecount )
|
||||||
|
{
|
||||||
|
surf->dlightbits = 0;
|
||||||
|
surf->dlightframe = tr.framecount; //tr.dlightframecount;
|
||||||
|
}
|
||||||
|
surf->dlightbits |= bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
R_MarkLights( light, bit, node->children[0] );
|
||||||
|
R_MarkLights( light, bit, node->children[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
R_PushDlights
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void R_PushDlights( void )
|
||||||
|
{
|
||||||
|
dlight_t *l;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
tr.dlightframecount = tr.framecount;
|
||||||
|
|
||||||
|
RI.currententity = gEngfuncs.GetEntityByIndex( 0 );
|
||||||
|
RI.currentmodel = RI.currententity->model;
|
||||||
|
|
||||||
|
for( i = 0; i < MAX_DLIGHTS; i++, l++ )
|
||||||
|
{
|
||||||
|
l = gEngfuncs.GetDynamicLight( i );
|
||||||
|
|
||||||
|
if( l->die < gpGlobals->time || !l->radius )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//if( GL_FrustumCullSphere( &RI.frustum, l->origin, l->radius, 15 ))
|
||||||
|
//continue;
|
||||||
|
|
||||||
|
R_MarkLights( l, 1<<i, RI.currentmodel->nodes );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
R_CountDlights
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
int R_CountDlights( void )
|
||||||
|
{
|
||||||
|
dlight_t *l;
|
||||||
|
int i, numDlights = 0;
|
||||||
|
|
||||||
|
for( i = 0; i < MAX_DLIGHTS; i++ )
|
||||||
|
{
|
||||||
|
l = gEngfuncs.GetDynamicLight( i );
|
||||||
|
|
||||||
|
if( l->die < gpGlobals->time || !l->radius )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
numDlights++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return numDlights;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
R_CountSurfaceDlights
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
int R_CountSurfaceDlights( msurface_t *surf )
|
||||||
|
{
|
||||||
|
int i, numDlights = 0;
|
||||||
|
|
||||||
|
for( i = 0; i < MAX_DLIGHTS; i++ )
|
||||||
|
{
|
||||||
|
if(!( surf->dlightbits & BIT( i )))
|
||||||
|
continue; // not lit by this light
|
||||||
|
|
||||||
|
numDlights++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return numDlights;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
AMBIENT LIGHTING
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
*/
|
||||||
|
static vec3_t g_trace_lightspot;
|
||||||
|
static vec3_t g_trace_lightvec;
|
||||||
|
static float g_trace_fraction;
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
R_RecursiveLightPoint
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, float p2f, colorVec *cv, const vec3_t start, const vec3_t end )
|
||||||
|
{
|
||||||
|
float front, back, frac, midf;
|
||||||
|
int i, map, side, size;
|
||||||
|
float ds, dt, s, t;
|
||||||
|
int sample_size;
|
||||||
|
color24 *lm, *dm;
|
||||||
|
mextrasurf_t *info;
|
||||||
|
msurface_t *surf;
|
||||||
|
mtexinfo_t *tex;
|
||||||
|
matrix3x4 tbn;
|
||||||
|
vec3_t mid;
|
||||||
|
|
||||||
|
// didn't hit anything
|
||||||
|
if( !node || node->contents < 0 )
|
||||||
|
{
|
||||||
|
cv->r = cv->g = cv->b = cv->a = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate mid point
|
||||||
|
front = PlaneDiff( start, node->plane );
|
||||||
|
back = PlaneDiff( end, node->plane );
|
||||||
|
|
||||||
|
side = front < 0;
|
||||||
|
if(( back < 0 ) == side )
|
||||||
|
return R_RecursiveLightPoint( model, node->children[side], p1f, p2f, cv, start, end );
|
||||||
|
|
||||||
|
frac = front / ( front - back );
|
||||||
|
|
||||||
|
VectorLerp( start, frac, end, mid );
|
||||||
|
midf = p1f + ( p2f - p1f ) * frac;
|
||||||
|
|
||||||
|
// co down front side
|
||||||
|
if( R_RecursiveLightPoint( model, node->children[side], p1f, midf, cv, start, mid ))
|
||||||
|
return true; // hit something
|
||||||
|
|
||||||
|
if(( back < 0 ) == side )
|
||||||
|
{
|
||||||
|
cv->r = cv->g = cv->b = cv->a = 0;
|
||||||
|
return false; // didn't hit anything
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for impact on this node
|
||||||
|
surf = model->surfaces + node->firstsurface;
|
||||||
|
VectorCopy( mid, g_trace_lightspot );
|
||||||
|
|
||||||
|
for( i = 0; i < node->numsurfaces; i++, surf++ )
|
||||||
|
{
|
||||||
|
int smax, tmax;
|
||||||
|
|
||||||
|
tex = surf->texinfo;
|
||||||
|
info = surf->info;
|
||||||
|
|
||||||
|
if( FBitSet( surf->flags, SURF_DRAWTILED ))
|
||||||
|
continue; // no lightmaps
|
||||||
|
|
||||||
|
s = DotProduct( mid, info->lmvecs[0] ) + info->lmvecs[0][3];
|
||||||
|
t = DotProduct( mid, info->lmvecs[1] ) + info->lmvecs[1][3];
|
||||||
|
|
||||||
|
if( s < info->lightmapmins[0] || t < info->lightmapmins[1] )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ds = s - info->lightmapmins[0];
|
||||||
|
dt = t - info->lightmapmins[1];
|
||||||
|
|
||||||
|
if ( ds > info->lightextents[0] || dt > info->lightextents[1] )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cv->r = cv->g = cv->b = cv->a = 0;
|
||||||
|
|
||||||
|
if( !surf->samples )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
sample_size = gEngfuncs.Mod_SampleSizeForFace( surf );
|
||||||
|
smax = (info->lightextents[0] / sample_size) + 1;
|
||||||
|
tmax = (info->lightextents[1] / sample_size) + 1;
|
||||||
|
ds /= sample_size;
|
||||||
|
dt /= sample_size;
|
||||||
|
|
||||||
|
lm = surf->samples + Q_rint( dt ) * smax + Q_rint( ds );
|
||||||
|
g_trace_fraction = midf;
|
||||||
|
size = smax * tmax;
|
||||||
|
dm = NULL;
|
||||||
|
|
||||||
|
if( surf->info->deluxemap )
|
||||||
|
{
|
||||||
|
vec3_t faceNormal;
|
||||||
|
|
||||||
|
if( FBitSet( surf->flags, SURF_PLANEBACK ))
|
||||||
|
VectorNegate( surf->plane->normal, faceNormal );
|
||||||
|
else VectorCopy( surf->plane->normal, faceNormal );
|
||||||
|
|
||||||
|
// compute face TBN
|
||||||
|
#if 1
|
||||||
|
Vector4Set( tbn[0], surf->info->lmvecs[0][0], surf->info->lmvecs[0][1], surf->info->lmvecs[0][2], 0.0f );
|
||||||
|
Vector4Set( tbn[1], -surf->info->lmvecs[1][0], -surf->info->lmvecs[1][1], -surf->info->lmvecs[1][2], 0.0f );
|
||||||
|
Vector4Set( tbn[2], faceNormal[0], faceNormal[1], faceNormal[2], 0.0f );
|
||||||
|
#else
|
||||||
|
Vector4Set( tbn[0], surf->info->lmvecs[0][0], -surf->info->lmvecs[1][0], faceNormal[0], 0.0f );
|
||||||
|
Vector4Set( tbn[1], surf->info->lmvecs[0][1], -surf->info->lmvecs[1][1], faceNormal[1], 0.0f );
|
||||||
|
Vector4Set( tbn[2], surf->info->lmvecs[0][2], -surf->info->lmvecs[1][2], faceNormal[2], 0.0f );
|
||||||
|
#endif
|
||||||
|
VectorNormalize( tbn[0] );
|
||||||
|
VectorNormalize( tbn[1] );
|
||||||
|
VectorNormalize( tbn[2] );
|
||||||
|
dm = surf->info->deluxemap + Q_rint( dt ) * smax + Q_rint( ds );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
|
||||||
|
{
|
||||||
|
uint scale = tr.lightstylevalue[surf->styles[map]];
|
||||||
|
|
||||||
|
if( tr.ignore_lightgamma )
|
||||||
|
{
|
||||||
|
cv->r += lm->r * scale * 2.5; // scale;
|
||||||
|
cv->g += lm->g * scale * 2.5; // scale;
|
||||||
|
cv->b += lm->b * scale * 2.5; // scale;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cv->r += gEngfuncs.LightToTexGamma( lm->r ) * scale;
|
||||||
|
cv->g += gEngfuncs.LightToTexGamma( lm->g ) * scale;
|
||||||
|
cv->b += gEngfuncs.LightToTexGamma( lm->b ) * scale;
|
||||||
|
}
|
||||||
|
lm += size; // skip to next lightmap
|
||||||
|
|
||||||
|
if( dm != NULL )
|
||||||
|
{
|
||||||
|
vec3_t srcNormal, lightNormal;
|
||||||
|
float f = (1.0f / 128.0f);
|
||||||
|
|
||||||
|
VectorSet( srcNormal, ((float)dm->r - 128.0f) * f, ((float)dm->g - 128.0f) * f, ((float)dm->b - 128.0f) * f );
|
||||||
|
Matrix3x4_VectorIRotate( tbn, srcNormal, lightNormal ); // turn to world space
|
||||||
|
VectorScale( lightNormal, (float)scale * -1.0f, lightNormal ); // turn direction from light
|
||||||
|
VectorAdd( g_trace_lightvec, lightNormal, g_trace_lightvec );
|
||||||
|
dm += size; // skip to next deluxmap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// go down back side
|
||||||
|
return R_RecursiveLightPoint( model, node->children[!side], midf, p2f, cv, mid, end );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
R_LightVec
|
||||||
|
|
||||||
|
check bspmodels to get light from
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
colorVec R_LightVecInternal( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec )
|
||||||
|
{
|
||||||
|
float last_fraction;
|
||||||
|
int i, maxEnts = 1;
|
||||||
|
colorVec light, cv;
|
||||||
|
|
||||||
|
if( lspot ) VectorClear( lspot );
|
||||||
|
if( lvec ) VectorClear( lvec );
|
||||||
|
|
||||||
|
if( WORLDMODEL && WORLDMODEL->lightdata )
|
||||||
|
{
|
||||||
|
light.r = light.g = light.b = light.a = 0;
|
||||||
|
last_fraction = 1.0f;
|
||||||
|
|
||||||
|
// get light from bmodels too
|
||||||
|
//if( CVAR_TO_BOOL( r_lighting_extended ))
|
||||||
|
maxEnts = MAX_PHYSENTS;
|
||||||
|
|
||||||
|
// check all the bsp-models
|
||||||
|
for( i = 0; i < maxEnts; i++ )
|
||||||
|
{
|
||||||
|
physent_t *pe = gEngfuncs.EV_GetPhysent( i );
|
||||||
|
vec3_t offset, start_l, end_l;
|
||||||
|
mnode_t *pnodes;
|
||||||
|
matrix4x4 matrix;
|
||||||
|
|
||||||
|
if( !pe )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if( !pe->model || pe->model->type != mod_brush )
|
||||||
|
continue; // skip non-bsp models
|
||||||
|
|
||||||
|
pnodes = &pe->model->nodes[pe->model->hulls[0].firstclipnode];
|
||||||
|
VectorSubtract( pe->model->hulls[0].clip_mins, vec3_origin, offset );
|
||||||
|
VectorAdd( offset, pe->origin, offset );
|
||||||
|
VectorSubtract( start, offset, start_l );
|
||||||
|
VectorSubtract( end, offset, end_l );
|
||||||
|
|
||||||
|
// rotate start and end into the models frame of reference
|
||||||
|
if( !VectorIsNull( pe->angles ))
|
||||||
|
{
|
||||||
|
Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
|
||||||
|
Matrix4x4_VectorITransform( matrix, start, start_l );
|
||||||
|
Matrix4x4_VectorITransform( matrix, end, end_l );
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorClear( g_trace_lightspot );
|
||||||
|
VectorClear( g_trace_lightvec );
|
||||||
|
g_trace_fraction = 1.0f;
|
||||||
|
|
||||||
|
if( !R_RecursiveLightPoint( pe->model, pnodes, 0.0f, 1.0f, &cv, start_l, end_l ))
|
||||||
|
continue; // didn't hit anything
|
||||||
|
|
||||||
|
if( g_trace_fraction < last_fraction )
|
||||||
|
{
|
||||||
|
if( lspot ) VectorCopy( g_trace_lightspot, lspot );
|
||||||
|
if( lvec ) VectorNormalize2( g_trace_lightvec, lvec );
|
||||||
|
light.r = Q_min(( cv.r >> 7 ), 255 );
|
||||||
|
light.g = Q_min(( cv.g >> 7 ), 255 );
|
||||||
|
light.b = Q_min(( cv.b >> 7 ), 255 );
|
||||||
|
last_fraction = g_trace_fraction;
|
||||||
|
|
||||||
|
if(( light.r + light.g + light.b ) != 0 )
|
||||||
|
break; // we get light now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
light.r = light.g = light.b = 255;
|
||||||
|
light.a = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return light;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
R_LightVec
|
||||||
|
|
||||||
|
check bspmodels to get light from
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
colorVec GAME_EXPORT R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec )
|
||||||
|
{
|
||||||
|
colorVec light = R_LightVecInternal( start, end, lspot, lvec );
|
||||||
|
|
||||||
|
//light.r = light.g = light.b = 255;
|
||||||
|
|
||||||
|
if( lspot != NULL && lvec != NULL ) // CVAR_TO_BOOL( r_lighting_extended ) &&
|
||||||
|
{
|
||||||
|
// trying to get light from ceiling (but ignore gradient analyze)
|
||||||
|
if(( light.r + light.g + light.b ) == 0 )
|
||||||
|
return R_LightVecInternal( end, start, lspot, lvec );
|
||||||
|
}
|
||||||
|
|
||||||
|
return light;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
R_LightPoint
|
||||||
|
|
||||||
|
light from floor
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
colorVec GAME_EXPORT R_LightPoint( const vec3_t p0 )
|
||||||
|
{
|
||||||
|
vec3_t p1;
|
||||||
|
|
||||||
|
VectorSet( p1, p0[0], p0[1], p0[2] - 2048.0f );
|
||||||
|
|
||||||
|
return R_LightVec( p0, p1, NULL, NULL );
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,267 @@
|
||||||
|
/*
|
||||||
|
gl_rmath.c - renderer mathlib
|
||||||
|
Copyright (C) 2010 Uncle Mike
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
#include "xash3d_mathlib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================================================================
|
||||||
|
|
||||||
|
Matrix4x4 operations (private to renderer)
|
||||||
|
|
||||||
|
========================================================================
|
||||||
|
*/
|
||||||
|
void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 )
|
||||||
|
{
|
||||||
|
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0] + in1[0][3] * in2[3][0];
|
||||||
|
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1] + in1[0][3] * in2[3][1];
|
||||||
|
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2] + in1[0][3] * in2[3][2];
|
||||||
|
out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3] * in2[3][3];
|
||||||
|
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0] + in1[1][3] * in2[3][0];
|
||||||
|
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1] + in1[1][3] * in2[3][1];
|
||||||
|
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2] + in1[1][3] * in2[3][2];
|
||||||
|
out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3] * in2[3][3];
|
||||||
|
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0] + in1[2][3] * in2[3][0];
|
||||||
|
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1] + in1[2][3] * in2[3][1];
|
||||||
|
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2] + in1[2][3] * in2[3][2];
|
||||||
|
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3] * in2[3][3];
|
||||||
|
out[3][0] = in1[3][0] * in2[0][0] + in1[3][1] * in2[1][0] + in1[3][2] * in2[2][0] + in1[3][3] * in2[3][0];
|
||||||
|
out[3][1] = in1[3][0] * in2[0][1] + in1[3][1] * in2[1][1] + in1[3][2] * in2[2][1] + in1[3][3] * in2[3][1];
|
||||||
|
out[3][2] = in1[3][0] * in2[0][2] + in1[3][1] * in2[1][2] + in1[3][2] * in2[2][2] + in1[3][3] * in2[3][2];
|
||||||
|
out[3][3] = in1[3][0] * in2[0][3] + in1[3][1] * in2[1][3] + in1[3][2] * in2[2][3] + in1[3][3] * in2[3][3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
Matrix4x4_CreateProjection
|
||||||
|
|
||||||
|
NOTE: produce quake style world orientation
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void Matrix4x4_CreateProjection( matrix4x4 out, float xMax, float xMin, float yMax, float yMin, float zNear, float zFar )
|
||||||
|
{
|
||||||
|
out[0][0] = ( 2.0f * zNear ) / ( xMax - xMin );
|
||||||
|
out[1][1] = ( 2.0f * zNear ) / ( yMax - yMin );
|
||||||
|
out[2][2] = -( zFar + zNear ) / ( zFar - zNear );
|
||||||
|
out[3][3] = out[0][1] = out[1][0] = out[3][0] = out[0][3] = out[3][1] = out[1][3] = 0.0f;
|
||||||
|
|
||||||
|
out[2][0] = 0.0f;
|
||||||
|
out[2][1] = 0.0f;
|
||||||
|
out[0][2] = ( xMax + xMin ) / ( xMax - xMin );
|
||||||
|
out[1][2] = ( yMax + yMin ) / ( yMax - yMin );
|
||||||
|
out[3][2] = -1.0f;
|
||||||
|
out[2][3] = -( 2.0f * zFar * zNear ) / ( zFar - zNear );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_CreateOrtho( matrix4x4 out, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar )
|
||||||
|
{
|
||||||
|
out[0][0] = 2.0f / (xRight - xLeft);
|
||||||
|
out[1][1] = 2.0f / (yTop - yBottom);
|
||||||
|
out[2][2] = -2.0f / (zFar - zNear);
|
||||||
|
out[3][3] = 1.0f;
|
||||||
|
out[0][1] = out[0][2] = out[1][0] = out[1][2] = out[3][0] = out[3][1] = out[3][2] = 0.0f;
|
||||||
|
|
||||||
|
out[2][0] = 0.0f;
|
||||||
|
out[2][1] = 0.0f;
|
||||||
|
out[0][3] = -(xRight + xLeft) / (xRight - xLeft);
|
||||||
|
out[1][3] = -(yTop + yBottom) / (yTop - yBottom);
|
||||||
|
out[2][3] = -(zFar + zNear) / (zFar - zNear);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
Matrix4x4_CreateModelview
|
||||||
|
|
||||||
|
NOTE: produce quake style world orientation
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void Matrix4x4_CreateModelview( matrix4x4 out )
|
||||||
|
{
|
||||||
|
out[0][0] = out[1][1] = out[2][2] = 0.0f;
|
||||||
|
out[3][0] = out[0][3] = 0.0f;
|
||||||
|
out[3][1] = out[1][3] = 0.0f;
|
||||||
|
out[3][2] = out[2][3] = 0.0f;
|
||||||
|
out[3][3] = 1.0f;
|
||||||
|
out[1][0] = out[0][2] = out[2][1] = 0.0f;
|
||||||
|
out[2][0] = out[0][1] = -1.0f;
|
||||||
|
out[1][2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] )
|
||||||
|
{
|
||||||
|
out[ 0] = in[0][0];
|
||||||
|
out[ 1] = in[1][0];
|
||||||
|
out[ 2] = in[2][0];
|
||||||
|
out[ 3] = in[3][0];
|
||||||
|
out[ 4] = in[0][1];
|
||||||
|
out[ 5] = in[1][1];
|
||||||
|
out[ 6] = in[2][1];
|
||||||
|
out[ 7] = in[3][1];
|
||||||
|
out[ 8] = in[0][2];
|
||||||
|
out[ 9] = in[1][2];
|
||||||
|
out[10] = in[2][2];
|
||||||
|
out[11] = in[3][2];
|
||||||
|
out[12] = in[0][3];
|
||||||
|
out[13] = in[1][3];
|
||||||
|
out[14] = in[2][3];
|
||||||
|
out[15] = in[3][3];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_FromArrayFloatGL( matrix4x4 out, const float in[16] )
|
||||||
|
{
|
||||||
|
out[0][0] = in[0];
|
||||||
|
out[1][0] = in[1];
|
||||||
|
out[2][0] = in[2];
|
||||||
|
out[3][0] = in[3];
|
||||||
|
out[0][1] = in[4];
|
||||||
|
out[1][1] = in[5];
|
||||||
|
out[2][1] = in[6];
|
||||||
|
out[3][1] = in[7];
|
||||||
|
out[0][2] = in[8];
|
||||||
|
out[1][2] = in[9];
|
||||||
|
out[2][2] = in[10];
|
||||||
|
out[3][2] = in[11];
|
||||||
|
out[0][3] = in[12];
|
||||||
|
out[1][3] = in[13];
|
||||||
|
out[2][3] = in[14];
|
||||||
|
out[3][3] = in[15];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z )
|
||||||
|
{
|
||||||
|
out[0][0] = 1.0f;
|
||||||
|
out[0][1] = 0.0f;
|
||||||
|
out[0][2] = 0.0f;
|
||||||
|
out[0][3] = x;
|
||||||
|
out[1][0] = 0.0f;
|
||||||
|
out[1][1] = 1.0f;
|
||||||
|
out[1][2] = 0.0f;
|
||||||
|
out[1][3] = y;
|
||||||
|
out[2][0] = 0.0f;
|
||||||
|
out[2][1] = 0.0f;
|
||||||
|
out[2][2] = 1.0f;
|
||||||
|
out[2][3] = z;
|
||||||
|
out[3][0] = 0.0f;
|
||||||
|
out[3][1] = 0.0f;
|
||||||
|
out[3][2] = 0.0f;
|
||||||
|
out[3][3] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_CreateRotate( matrix4x4 out, float angle, float x, float y, float z )
|
||||||
|
{
|
||||||
|
float len, c, s;
|
||||||
|
|
||||||
|
len = x * x + y * y + z * z;
|
||||||
|
if( len != 0.0f ) len = 1.0f / sqrt( len );
|
||||||
|
x *= len;
|
||||||
|
y *= len;
|
||||||
|
z *= len;
|
||||||
|
|
||||||
|
angle *= (-M_PI_F / 180.0f);
|
||||||
|
SinCos( angle, &s, &c );
|
||||||
|
|
||||||
|
out[0][0]=x * x + c * (1 - x * x);
|
||||||
|
out[0][1]=x * y * (1 - c) + z * s;
|
||||||
|
out[0][2]=z * x * (1 - c) - y * s;
|
||||||
|
out[0][3]=0.0f;
|
||||||
|
out[1][0]=x * y * (1 - c) - z * s;
|
||||||
|
out[1][1]=y * y + c * (1 - y * y);
|
||||||
|
out[1][2]=y * z * (1 - c) + x * s;
|
||||||
|
out[1][3]=0.0f;
|
||||||
|
out[2][0]=z * x * (1 - c) + y * s;
|
||||||
|
out[2][1]=y * z * (1 - c) - x * s;
|
||||||
|
out[2][2]=z * z + c * (1 - z * z);
|
||||||
|
out[2][3]=0.0f;
|
||||||
|
out[3][0]=0.0f;
|
||||||
|
out[3][1]=0.0f;
|
||||||
|
out[3][2]=0.0f;
|
||||||
|
out[3][3]=1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_CreateScale( matrix4x4 out, float x )
|
||||||
|
{
|
||||||
|
out[0][0] = x;
|
||||||
|
out[0][1] = 0.0f;
|
||||||
|
out[0][2] = 0.0f;
|
||||||
|
out[0][3] = 0.0f;
|
||||||
|
out[1][0] = 0.0f;
|
||||||
|
out[1][1] = x;
|
||||||
|
out[1][2] = 0.0f;
|
||||||
|
out[1][3] = 0.0f;
|
||||||
|
out[2][0] = 0.0f;
|
||||||
|
out[2][1] = 0.0f;
|
||||||
|
out[2][2] = x;
|
||||||
|
out[2][3] = 0.0f;
|
||||||
|
out[3][0] = 0.0f;
|
||||||
|
out[3][1] = 0.0f;
|
||||||
|
out[3][2] = 0.0f;
|
||||||
|
out[3][3] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_CreateScale3( matrix4x4 out, float x, float y, float z )
|
||||||
|
{
|
||||||
|
out[0][0] = x;
|
||||||
|
out[0][1] = 0.0f;
|
||||||
|
out[0][2] = 0.0f;
|
||||||
|
out[0][3] = 0.0f;
|
||||||
|
out[1][0] = 0.0f;
|
||||||
|
out[1][1] = y;
|
||||||
|
out[1][2] = 0.0f;
|
||||||
|
out[1][3] = 0.0f;
|
||||||
|
out[2][0] = 0.0f;
|
||||||
|
out[2][1] = 0.0f;
|
||||||
|
out[2][2] = z;
|
||||||
|
out[2][3] = 0.0f;
|
||||||
|
out[3][0] = 0.0f;
|
||||||
|
out[3][1] = 0.0f;
|
||||||
|
out[3][2] = 0.0f;
|
||||||
|
out[3][3] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_ConcatTranslate( matrix4x4 out, float x, float y, float z )
|
||||||
|
{
|
||||||
|
matrix4x4 base, temp;
|
||||||
|
|
||||||
|
Matrix4x4_Copy( base, out );
|
||||||
|
Matrix4x4_CreateTranslate( temp, x, y, z );
|
||||||
|
Matrix4x4_Concat( out, base, temp );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_ConcatRotate( matrix4x4 out, float angle, float x, float y, float z )
|
||||||
|
{
|
||||||
|
matrix4x4 base, temp;
|
||||||
|
|
||||||
|
Matrix4x4_Copy( base, out );
|
||||||
|
Matrix4x4_CreateRotate( temp, angle, x, y, z );
|
||||||
|
Matrix4x4_Concat( out, base, temp );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_ConcatScale( matrix4x4 out, float x )
|
||||||
|
{
|
||||||
|
matrix4x4 base, temp;
|
||||||
|
|
||||||
|
Matrix4x4_Copy( base, out );
|
||||||
|
Matrix4x4_CreateScale( temp, x );
|
||||||
|
Matrix4x4_Concat( out, base, temp );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix4x4_ConcatScale3( matrix4x4 out, float x, float y, float z )
|
||||||
|
{
|
||||||
|
matrix4x4 base, temp;
|
||||||
|
|
||||||
|
Matrix4x4_Copy( base, out );
|
||||||
|
Matrix4x4_CreateScale3( temp, x, y, z );
|
||||||
|
Matrix4x4_Concat( out, base, temp );
|
||||||
|
}
|
|
@ -0,0 +1,405 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1997-2001 Id Software, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
// r_misc.c
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
|
||||||
|
#define NUM_MIPS 4
|
||||||
|
|
||||||
|
cvar_t *sw_mipcap;
|
||||||
|
cvar_t *sw_mipscale;
|
||||||
|
|
||||||
|
surfcache_t *d_initial_rover;
|
||||||
|
qboolean d_roverwrapped;
|
||||||
|
int d_minmip;
|
||||||
|
float d_scalemip[NUM_MIPS-1];
|
||||||
|
|
||||||
|
static float basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
|
||||||
|
|
||||||
|
|
||||||
|
//int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
|
||||||
|
|
||||||
|
//int d_pix_min, d_pix_max, d_pix_shift;
|
||||||
|
|
||||||
|
int d_scantable[MAXHEIGHT];
|
||||||
|
short *zspantable[MAXHEIGHT];
|
||||||
|
struct qfrustum_s qfrustum;
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
D_Patch
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void D_Patch (void)
|
||||||
|
{
|
||||||
|
#if id386
|
||||||
|
extern void D_Aff8Patch( void );
|
||||||
|
static qboolean protectset8 = false;
|
||||||
|
extern void D_PolysetAff8Start( void );
|
||||||
|
|
||||||
|
if (!protectset8)
|
||||||
|
{
|
||||||
|
Sys_MakeCodeWriteable ((int)D_PolysetAff8Start,
|
||||||
|
(int)D_Aff8Patch - (int)D_PolysetAff8Start);
|
||||||
|
Sys_MakeCodeWriteable ((long)R_Surf8Start,
|
||||||
|
(long)R_Surf8End - (long)R_Surf8Start);
|
||||||
|
protectset8 = true;
|
||||||
|
}
|
||||||
|
colormap = vid.colormap;
|
||||||
|
|
||||||
|
R_Surf8Patch ();
|
||||||
|
D_Aff8Patch();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
D_ViewChanged
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
|
||||||
|
void D_ViewChanged (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
scale_for_mip = xscale;
|
||||||
|
if (yscale > xscale)
|
||||||
|
scale_for_mip = yscale;
|
||||||
|
|
||||||
|
d_zrowbytes = vid.width * 2;
|
||||||
|
d_zwidth = vid.width;
|
||||||
|
|
||||||
|
/*d_pix_min = gpGlobals->width / 320;
|
||||||
|
if (d_pix_min < 1)
|
||||||
|
d_pix_min = 1;
|
||||||
|
|
||||||
|
d_pix_max = (int)((float)gpGlobals->height / (320.0 / 4.0) + 0.5);
|
||||||
|
d_pix_shift = 8 - (int)((float)gpGlobals->height / 320.0 + 0.5);
|
||||||
|
if (d_pix_max < 1)
|
||||||
|
d_pix_max = 1;*/
|
||||||
|
|
||||||
|
//d_vrectx = RI.vrect.x;
|
||||||
|
//d_vrecty = RI.vrect.y;
|
||||||
|
//d_vrectright_particle = gpGlobals->width - d_pix_max;
|
||||||
|
//d_vrectbottom_particle =
|
||||||
|
// gpGlobals->height - d_pix_max;
|
||||||
|
|
||||||
|
for (i=0 ; i<vid.height; i++)
|
||||||
|
{
|
||||||
|
d_scantable[i] = i*r_screenwidth;
|
||||||
|
zspantable[i] = d_pzbuffer + i*d_zwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** clear Z-buffer and color-buffers if we're doing the gallery
|
||||||
|
*/
|
||||||
|
if ( !RI.drawWorld )
|
||||||
|
{
|
||||||
|
memset( d_pzbuffer, 0xff, vid.width * vid.height * sizeof( d_pzbuffer[0] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
D_Patch ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
===================
|
||||||
|
R_TransformFrustum
|
||||||
|
===================
|
||||||
|
*/
|
||||||
|
void R_TransformFrustum (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vec3_t v, v2;
|
||||||
|
|
||||||
|
for (i=0 ; i<4 ; i++)
|
||||||
|
{
|
||||||
|
v[0] = qfrustum.screenedge[i].normal[2];
|
||||||
|
v[1] = -qfrustum.screenedge[i].normal[0];
|
||||||
|
v[2] = qfrustum.screenedge[i].normal[1];
|
||||||
|
|
||||||
|
v2[0] = v[1]*RI.vright[0] + v[2]*RI.vup[0] + v[0]*RI.vforward[0];
|
||||||
|
v2[1] = v[1]*RI.vright[1] + v[2]*RI.vup[1] + v[0]*RI.vforward[1];
|
||||||
|
v2[2] = v[1]*RI.vright[2] + v[2]*RI.vup[2] + v[0]*RI.vforward[2];
|
||||||
|
|
||||||
|
VectorCopy (v2, qfrustum.view_clipplanes[i].normal);
|
||||||
|
|
||||||
|
qfrustum.view_clipplanes[i].dist = DotProduct (tr.modelorg, v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
TransformVector
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void TransformVector (vec3_t in, vec3_t out)
|
||||||
|
{
|
||||||
|
out[0] = DotProduct(in,RI.vright);
|
||||||
|
out[1] = DotProduct(in,RI.vup);
|
||||||
|
out[2] = DotProduct(in,RI.vforward);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_TransformPlane
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_TransformPlane (mplane_t *p, float *normal, float *dist)
|
||||||
|
{
|
||||||
|
float d;
|
||||||
|
|
||||||
|
d = DotProduct (RI.vieworg, p->normal);
|
||||||
|
*dist = p->dist - d;
|
||||||
|
// TODO: when we have rotating entities, this will need to use the view matrix
|
||||||
|
TransformVector (p->normal, normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
R_SetUpFrustumIndexes
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
void R_SetUpFrustumIndexes (void)
|
||||||
|
{
|
||||||
|
int i, j, *pindex;
|
||||||
|
|
||||||
|
pindex = qfrustum.frustum_indexes;
|
||||||
|
|
||||||
|
for (i=0 ; i<4 ; i++)
|
||||||
|
{
|
||||||
|
for (j=0 ; j<3 ; j++)
|
||||||
|
{
|
||||||
|
if (qfrustum.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
|
||||||
|
qfrustum.pfrustum_indexes[i] = pindex;
|
||||||
|
pindex += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
R_ViewChanged
|
||||||
|
|
||||||
|
Called every time the vid structure or r_refdef changes.
|
||||||
|
Guaranteed to be called before the first refresh
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
void R_ViewChanged (vrect_t *vr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
float verticalFieldOfView, horizontalFieldOfView, xOrigin, yOrigin;
|
||||||
|
|
||||||
|
RI.vrect = *vr;
|
||||||
|
|
||||||
|
horizontalFieldOfView = 2*tan((float)RI.fov_x/360.0f * M_PI_F);
|
||||||
|
verticalFieldOfView = 2*tan((float)RI.fov_y/360.0f * M_PI_F);
|
||||||
|
|
||||||
|
RI.fvrectx = (float)RI.vrect.x;
|
||||||
|
RI.fvrectx_adj = (float)RI.vrect.x - 0.5f;
|
||||||
|
RI.vrect_x_adj_shift20 = (RI.vrect.x<<20) + (1<<19) - 1;
|
||||||
|
RI.fvrecty = (float)RI.vrect.y;
|
||||||
|
RI.fvrecty_adj = (float)RI.vrect.y - 0.5f;
|
||||||
|
RI.vrectright = RI.vrect.x + RI.vrect.width;
|
||||||
|
RI.vrectright_adj_shift20 = (RI.vrectright<<20) + (1<<19) - 1;
|
||||||
|
RI.fvrectright = (float)RI.vrectright;
|
||||||
|
RI.fvrectright_adj = (float)RI.vrectright - 0.5f;
|
||||||
|
RI.vrectrightedge = (float)RI.vrectright - 0.99f;
|
||||||
|
RI.vrectbottom = RI.vrect.y + RI.vrect.height;
|
||||||
|
RI.fvrectbottom = (float)RI.vrectbottom;
|
||||||
|
RI.fvrectbottom_adj = (float)RI.vrectbottom - 0.5f;
|
||||||
|
|
||||||
|
RI.aliasvrect.x = (int)(RI.vrect.x * r_aliasuvscale);
|
||||||
|
RI.aliasvrect.y = (int)(RI.vrect.y * r_aliasuvscale);
|
||||||
|
RI.aliasvrect.width = (int)(RI.vrect.width * r_aliasuvscale);
|
||||||
|
RI.aliasvrect.height = (int)(RI.vrect.height * r_aliasuvscale);
|
||||||
|
RI.aliasvrectright = RI.aliasvrect.x +
|
||||||
|
RI.aliasvrect.width;
|
||||||
|
RI.aliasvrectbottom = RI.aliasvrect.y +
|
||||||
|
RI.aliasvrect.height;
|
||||||
|
|
||||||
|
xOrigin = XCENTERING;
|
||||||
|
yOrigin = YCENTERING;
|
||||||
|
#define PLANE_ANYZ 5
|
||||||
|
// values for perspective projection
|
||||||
|
// if math were exact, the values would range from 0.5 to to range+0.5
|
||||||
|
// hopefully they wll be in the 0.000001 to range+.999999 and truncate
|
||||||
|
// the polygon rasterization will never render in the first row or column
|
||||||
|
// but will definately render in the [range] row and column, so adjust the
|
||||||
|
// buffer origin to get an exact edge to edge fill
|
||||||
|
xcenter = ((float)RI.vrect.width * XCENTERING) +
|
||||||
|
RI.vrect.x - 0.5f;
|
||||||
|
aliasxcenter = xcenter * r_aliasuvscale;
|
||||||
|
ycenter = ((float)RI.vrect.height * YCENTERING) +
|
||||||
|
RI.vrect.y - 0.5f;
|
||||||
|
aliasycenter = ycenter * r_aliasuvscale;
|
||||||
|
|
||||||
|
xscale = RI.vrect.width / horizontalFieldOfView;
|
||||||
|
aliasxscale = xscale * r_aliasuvscale;
|
||||||
|
xscaleinv = 1.0f / xscale;
|
||||||
|
|
||||||
|
yscale = xscale;
|
||||||
|
aliasyscale = yscale * r_aliasuvscale;
|
||||||
|
yscaleinv = 1.0f / yscale;
|
||||||
|
//xscaleshrink = (RI.vrect.width-6)/RI.horizontalFieldOfView;
|
||||||
|
//yscaleshrink = xscaleshrink;
|
||||||
|
|
||||||
|
// left side clip
|
||||||
|
qfrustum.screenedge[0].normal[0] = -1.0f / (xOrigin*horizontalFieldOfView);
|
||||||
|
qfrustum.screenedge[0].normal[1] = 0;
|
||||||
|
qfrustum.screenedge[0].normal[2] = 1;
|
||||||
|
qfrustum.screenedge[0].type = PLANE_ANYZ;
|
||||||
|
|
||||||
|
// right side clip
|
||||||
|
qfrustum.screenedge[1].normal[0] =
|
||||||
|
1.0f / ((1.0f-xOrigin)*horizontalFieldOfView);
|
||||||
|
qfrustum.screenedge[1].normal[1] = 0;
|
||||||
|
qfrustum.screenedge[1].normal[2] = 1;
|
||||||
|
qfrustum.screenedge[1].type = PLANE_ANYZ;
|
||||||
|
|
||||||
|
// top side clip
|
||||||
|
qfrustum.screenedge[2].normal[0] = 0;
|
||||||
|
qfrustum.screenedge[2].normal[1] = -1.0f / (yOrigin*verticalFieldOfView);
|
||||||
|
qfrustum.screenedge[2].normal[2] = 1;
|
||||||
|
qfrustum.screenedge[2].type = PLANE_ANYZ;
|
||||||
|
|
||||||
|
// bottom side clip
|
||||||
|
qfrustum.screenedge[3].normal[0] = 0;
|
||||||
|
qfrustum.screenedge[3].normal[1] = 1.0f / ((1.0f-yOrigin)*verticalFieldOfView);
|
||||||
|
qfrustum.screenedge[3].normal[2] = 1;
|
||||||
|
qfrustum.screenedge[3].type = PLANE_ANYZ;
|
||||||
|
|
||||||
|
for (i=0 ; i<4 ; i++)
|
||||||
|
VectorNormalize (qfrustum.screenedge[i].normal);
|
||||||
|
|
||||||
|
D_ViewChanged ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
R_SetupFrame
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
void R_SetupFrameQ (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vrect_t vrect;
|
||||||
|
|
||||||
|
if (r_fullbright->flags & FCVAR_CHANGED)
|
||||||
|
{
|
||||||
|
r_fullbright->flags &= ~FCVAR_CHANGED;
|
||||||
|
D_FlushCaches( ); // so all lighting changes
|
||||||
|
}
|
||||||
|
|
||||||
|
//tr.framecount++;
|
||||||
|
|
||||||
|
|
||||||
|
// build the transformation matrix for the given view angles
|
||||||
|
VectorCopy (RI.vieworg, tr.modelorg);
|
||||||
|
|
||||||
|
//AngleVectors (RI.viewangles, RI.vforward, RI.vright, RI.vup);
|
||||||
|
|
||||||
|
// current viewleaf
|
||||||
|
if ( RI.drawWorld )
|
||||||
|
{
|
||||||
|
RI.viewleaf = gEngfuncs.Mod_PointInLeaf (RI.vieworg, WORLDMODEL->nodes);
|
||||||
|
r_viewcluster = RI.viewleaf->cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) )
|
||||||
|
// r_dowarp = true;
|
||||||
|
// else
|
||||||
|
|
||||||
|
/*vrect.x = 0;//r_newrefdef.x;
|
||||||
|
vrect.y = 0;//r_newrefdef.y;
|
||||||
|
vrect.width = gpGlobals->width;
|
||||||
|
vrect.height = gpGlobals->height;*/
|
||||||
|
vrect.x = RI.viewport[0];
|
||||||
|
vrect.y = RI.viewport[1];
|
||||||
|
vrect.width = RI.viewport[2];
|
||||||
|
vrect.height = RI.viewport[3];
|
||||||
|
|
||||||
|
d_viewbuffer = (void *)vid.buffer;
|
||||||
|
r_screenwidth = vid.rowbytes;
|
||||||
|
|
||||||
|
R_ViewChanged (&vrect);
|
||||||
|
|
||||||
|
// start off with just the four screen edge clip planes
|
||||||
|
R_TransformFrustum ();
|
||||||
|
R_SetUpFrustumIndexes ();
|
||||||
|
|
||||||
|
// save base values
|
||||||
|
VectorCopy (RI.vforward, RI.base_vpn);
|
||||||
|
VectorCopy (RI.vright, RI.base_vright);
|
||||||
|
VectorCopy (RI.vup, RI.base_vup);
|
||||||
|
|
||||||
|
// clear frame counts
|
||||||
|
/* c_faceclip = 0;
|
||||||
|
d_spanpixcount = 0;
|
||||||
|
r_polycount = 0;
|
||||||
|
r_drawnpolycount = 0;
|
||||||
|
r_wholepolycount = 0;
|
||||||
|
r_amodels_drawn = 0;
|
||||||
|
r_outofsurfaces = 0;
|
||||||
|
r_outofedges = 0;*/
|
||||||
|
|
||||||
|
// d_setup
|
||||||
|
d_roverwrapped = false;
|
||||||
|
d_initial_rover = sc_rover;
|
||||||
|
|
||||||
|
d_minmip = sw_mipcap->value;
|
||||||
|
if (d_minmip > 3)
|
||||||
|
d_minmip = 3;
|
||||||
|
else if (d_minmip < 0)
|
||||||
|
d_minmip = 0;
|
||||||
|
|
||||||
|
for (i=0 ; i<(NUM_MIPS-1) ; i++)
|
||||||
|
d_scalemip[i] = basemip[i] * sw_mipscale->value;
|
||||||
|
|
||||||
|
//d_aflatcolor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !id386
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_SurfacePatch
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
/*void R_SurfacePatch (void)
|
||||||
|
{
|
||||||
|
// we only patch code on Intel
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#endif // !id386
|
|
@ -0,0 +1,308 @@
|
||||||
|
/*
|
||||||
|
cl_part.c - particles and tracers
|
||||||
|
Copyright (C) 2010 Uncle Mike
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
#include "r_efx.h"
|
||||||
|
#include "event_flags.h"
|
||||||
|
#include "entity_types.h"
|
||||||
|
#include "triangleapi.h"
|
||||||
|
#include "pm_local.h"
|
||||||
|
#include "cl_tent.h"
|
||||||
|
#include "studio.h"
|
||||||
|
|
||||||
|
static float gTracerSize[11] = { 1.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
|
static color24 gTracerColors[] =
|
||||||
|
{
|
||||||
|
{ 255, 255, 255 }, // White
|
||||||
|
{ 255, 0, 0 }, // Red
|
||||||
|
{ 0, 255, 0 }, // Green
|
||||||
|
{ 0, 0, 255 }, // Blue
|
||||||
|
{ 0, 0, 0 }, // Tracer default, filled in from cvars, etc.
|
||||||
|
{ 255, 167, 17 }, // Yellow-orange sparks
|
||||||
|
{ 255, 130, 90 }, // Yellowish streaks (garg)
|
||||||
|
{ 55, 60, 144 }, // Blue egon streak
|
||||||
|
{ 255, 130, 90 }, // More Yellowish streaks (garg)
|
||||||
|
{ 255, 140, 90 }, // More Yellowish streaks (garg)
|
||||||
|
{ 200, 130, 90 }, // More red streaks (garg)
|
||||||
|
{ 255, 120, 70 }, // Darker red streaks (garg)
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
CL_DrawParticles
|
||||||
|
|
||||||
|
update particle color, position, free expired and draw it
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT CL_DrawParticles( double frametime, particle_t *cl_active_particles, float partsize )
|
||||||
|
{
|
||||||
|
particle_t *p;
|
||||||
|
vec3_t right, up;
|
||||||
|
color24 *pColor;
|
||||||
|
int alpha;
|
||||||
|
float size;
|
||||||
|
|
||||||
|
if( !cl_active_particles )
|
||||||
|
return; // nothing to draw?
|
||||||
|
|
||||||
|
//pglEnable( GL_BLEND );
|
||||||
|
//pglDisable( GL_ALPHA_TEST );
|
||||||
|
//pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||||
|
GL_SetRenderMode( kRenderTransAdd );
|
||||||
|
|
||||||
|
GL_Bind( XASH_TEXTURE0, tr.particleTexture );
|
||||||
|
//pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||||
|
//pglDepthMask( GL_FALSE );
|
||||||
|
|
||||||
|
for( p = cl_active_particles; p; p = p->next )
|
||||||
|
{
|
||||||
|
if(( p->type != pt_blob ) || ( p->packedColor == 255 ))
|
||||||
|
{
|
||||||
|
size = partsize; // get initial size of particle
|
||||||
|
|
||||||
|
// scale up to keep particles from disappearing
|
||||||
|
size += (p->org[0] - RI.vieworg[0]) * RI.cull_vforward[0];
|
||||||
|
size += (p->org[1] - RI.vieworg[1]) * RI.cull_vforward[1];
|
||||||
|
size += (p->org[2] - RI.vieworg[2]) * RI.cull_vforward[2];
|
||||||
|
|
||||||
|
if( size < 20.0f ) size = partsize;
|
||||||
|
else size = partsize + size * 0.002f;
|
||||||
|
|
||||||
|
// scale the axes by radius
|
||||||
|
VectorScale( RI.cull_vright, size, right );
|
||||||
|
VectorScale( RI.cull_vup, size, up );
|
||||||
|
|
||||||
|
p->color = bound( 0, p->color, 255 );
|
||||||
|
pColor = gEngfuncs.CL_GetPaletteColor( p->color );
|
||||||
|
|
||||||
|
alpha = 255 * (p->die - gpGlobals->time) * 16.0f;
|
||||||
|
if( alpha > 255 || p->type == pt_static )
|
||||||
|
alpha = 255;
|
||||||
|
|
||||||
|
//TriColor4ub( gEngfuncs.LightToTexGamma( pColor->r ),
|
||||||
|
// gEngfuncs.LightToTexGamma( pColor->g ),
|
||||||
|
// gEngfuncs.LightToTexGamma( pColor->b ), alpha );
|
||||||
|
//TriBrightness( alpha / 255.0f );
|
||||||
|
_TriColor4f(1.0f*alpha/255/255*pColor->r,1.0f*alpha/255/255*pColor->g,1.0f*alpha/255/255* pColor->b,1.0f );
|
||||||
|
|
||||||
|
TriBegin( TRI_QUADS );
|
||||||
|
TriTexCoord2f( 0.0f, 1.0f );
|
||||||
|
TriVertex3f( p->org[0] - right[0] + up[0], p->org[1] - right[1] + up[1], p->org[2] - right[2] + up[2] );
|
||||||
|
TriTexCoord2f( 0.0f, 0.0f );
|
||||||
|
TriVertex3f( p->org[0] + right[0] + up[0], p->org[1] + right[1] + up[1], p->org[2] + right[2] + up[2] );
|
||||||
|
TriTexCoord2f( 1.0f, 0.0f );
|
||||||
|
TriVertex3f( p->org[0] + right[0] - up[0], p->org[1] + right[1] - up[1], p->org[2] + right[2] - up[2] );
|
||||||
|
TriTexCoord2f( 1.0f, 1.0f );
|
||||||
|
TriVertex3f( p->org[0] - right[0] - up[0], p->org[1] - right[1] - up[1], p->org[2] - right[2] - up[2] );
|
||||||
|
TriEnd();
|
||||||
|
r_stats.c_particle_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
gEngfuncs.CL_ThinkParticle( frametime, p );
|
||||||
|
}
|
||||||
|
|
||||||
|
TriEnd();
|
||||||
|
//pglDepthMask( GL_TRUE );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
CL_CullTracer
|
||||||
|
|
||||||
|
check tracer bbox
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
static qboolean CL_CullTracer( particle_t *p, const vec3_t start, const vec3_t end )
|
||||||
|
{
|
||||||
|
vec3_t mins, maxs;
|
||||||
|
int i;
|
||||||
|
return false;
|
||||||
|
/*
|
||||||
|
// compute the bounding box
|
||||||
|
for( i = 0; i < 3; i++ )
|
||||||
|
{
|
||||||
|
if( start[i] < end[i] )
|
||||||
|
{
|
||||||
|
mins[i] = start[i];
|
||||||
|
maxs[i] = end[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mins[i] = end[i];
|
||||||
|
maxs[i] = start[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't let it be zero sized
|
||||||
|
if( mins[i] == maxs[i] )
|
||||||
|
{
|
||||||
|
maxs[i] += gTracerSize[p->type] * 2.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check bbox
|
||||||
|
return R_CullBox( mins, maxs );*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
CL_DrawTracers
|
||||||
|
|
||||||
|
update tracer color, position, free expired and draw it
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT CL_DrawTracers( double frametime, particle_t *cl_active_tracers )
|
||||||
|
{
|
||||||
|
float scale, atten, gravity;
|
||||||
|
vec3_t screenLast, screen;
|
||||||
|
vec3_t start, end, delta;
|
||||||
|
particle_t *p;
|
||||||
|
|
||||||
|
// update tracer color if this is changed
|
||||||
|
if( FBitSet( tracerred->flags|tracergreen->flags|tracerblue->flags|traceralpha->flags, FCVAR_CHANGED ))
|
||||||
|
{
|
||||||
|
color24 *customColors = &gTracerColors[4];
|
||||||
|
customColors->r = (byte)(tracerred->value * traceralpha->value * 255);
|
||||||
|
customColors->g = (byte)(tracergreen->value * traceralpha->value * 255);
|
||||||
|
customColors->b = (byte)(tracerblue->value * traceralpha->value * 255);
|
||||||
|
ClearBits( tracerred->flags, FCVAR_CHANGED );
|
||||||
|
ClearBits( tracergreen->flags, FCVAR_CHANGED );
|
||||||
|
ClearBits( tracerblue->flags, FCVAR_CHANGED );
|
||||||
|
ClearBits( traceralpha->flags, FCVAR_CHANGED );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !cl_active_tracers )
|
||||||
|
return; // nothing to draw?
|
||||||
|
|
||||||
|
GL_SetRenderMode( kRenderTransAdd );
|
||||||
|
|
||||||
|
if( !TriSpriteTexture( gEngfuncs.GetDefaultSprite( REF_DOT_SPRITE ), 0 ))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//pglEnable( GL_BLEND );
|
||||||
|
//pglBlendFunc( GL_SRC_ALPHA, GL_ONE );
|
||||||
|
//pglDisable( GL_ALPHA_TEST );
|
||||||
|
//pglDepthMask( GL_FALSE );
|
||||||
|
|
||||||
|
gravity = frametime * MOVEVARS->gravity;
|
||||||
|
scale = 1.0 - (frametime * 0.9);
|
||||||
|
if( scale < 0.0f ) scale = 0.0f;
|
||||||
|
|
||||||
|
for( p = cl_active_tracers; p; p = p->next )
|
||||||
|
{
|
||||||
|
atten = (p->die - gpGlobals->time);
|
||||||
|
if( atten > 0.1f ) atten = 0.1f;
|
||||||
|
|
||||||
|
VectorScale( p->vel, ( p->ramp * atten ), delta );
|
||||||
|
VectorAdd( p->org, delta, end );
|
||||||
|
VectorCopy( p->org, start );
|
||||||
|
|
||||||
|
if( !CL_CullTracer( p, start, end ))
|
||||||
|
{
|
||||||
|
vec3_t verts[4], tmp2;
|
||||||
|
vec3_t tmp, normal;
|
||||||
|
color24 *pColor;
|
||||||
|
short alpha = p->packedColor;
|
||||||
|
|
||||||
|
// Transform point into screen space
|
||||||
|
TriWorldToScreen( start, screen );
|
||||||
|
TriWorldToScreen( end, screenLast );
|
||||||
|
|
||||||
|
// build world-space normal to screen-space direction vector
|
||||||
|
VectorSubtract( screen, screenLast, tmp );
|
||||||
|
|
||||||
|
// we don't need Z, we're in screen space
|
||||||
|
tmp[2] = 0;
|
||||||
|
VectorNormalize( tmp );
|
||||||
|
|
||||||
|
// build point along noraml line (normal is -y, x)
|
||||||
|
VectorScale( RI.cull_vup, tmp[0] * gTracerSize[p->type], normal );
|
||||||
|
VectorScale( RI.cull_vright, -tmp[1] * gTracerSize[p->type], tmp2 );
|
||||||
|
VectorSubtract( normal, tmp2, normal );
|
||||||
|
|
||||||
|
// compute four vertexes
|
||||||
|
VectorSubtract( start, normal, verts[0] );
|
||||||
|
VectorAdd( start, normal, verts[1] );
|
||||||
|
VectorAdd( verts[0], delta, verts[2] );
|
||||||
|
VectorAdd( verts[1], delta, verts[3] );
|
||||||
|
|
||||||
|
if( p->color > sizeof( gTracerColors ) / sizeof( color24 ) )
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Printf( S_ERROR "UserTracer with color > %d\n", sizeof( gTracerColors ) / sizeof( color24 ));
|
||||||
|
p->color = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pColor = &gTracerColors[p->color];
|
||||||
|
//TriColor4ub( pColor->r, pColor->g, pColor->b, p->packedColor );
|
||||||
|
_TriColor4f(1.0f*alpha/255/255*pColor->r,1.0f*alpha/255/255*pColor->g,1.0f*alpha/255/255* pColor->b,1.0f );
|
||||||
|
|
||||||
|
|
||||||
|
TriBegin( TRI_QUADS );
|
||||||
|
TriTexCoord2f( 0.0f, 0.8f );
|
||||||
|
TriVertex3fv( verts[2] );
|
||||||
|
TriTexCoord2f( 1.0f, 0.8f );
|
||||||
|
TriVertex3fv( verts[3] );
|
||||||
|
TriTexCoord2f( 1.0f, 0.0f );
|
||||||
|
TriVertex3fv( verts[1] );
|
||||||
|
TriTexCoord2f( 0.0f, 0.0f );
|
||||||
|
TriVertex3fv( verts[0] );
|
||||||
|
TriEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate position
|
||||||
|
VectorMA( p->org, frametime, p->vel, p->org );
|
||||||
|
|
||||||
|
if( p->type == pt_grav )
|
||||||
|
{
|
||||||
|
p->vel[0] *= scale;
|
||||||
|
p->vel[1] *= scale;
|
||||||
|
p->vel[2] -= gravity;
|
||||||
|
|
||||||
|
p->packedColor = 255 * (p->die - gpGlobals->time) * 2;
|
||||||
|
if( p->packedColor > 255 ) p->packedColor = 255;
|
||||||
|
}
|
||||||
|
else if( p->type == pt_slowgrav )
|
||||||
|
{
|
||||||
|
p->vel[2] = gravity * 0.05;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//pglDepthMask( GL_TRUE );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
CL_DrawParticlesExternal
|
||||||
|
|
||||||
|
allow to draw effects from custom renderer
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT CL_DrawParticlesExternal( const ref_viewpass_t *rvp, qboolean trans_pass, float frametime )
|
||||||
|
{
|
||||||
|
ref_instance_t oldRI = RI;
|
||||||
|
|
||||||
|
memcpy( &oldRI, &RI, sizeof( ref_instance_t ));
|
||||||
|
R_SetupRefParams( rvp );
|
||||||
|
R_SetupFrustum();
|
||||||
|
// R_SetupGL( false ); // don't touch GL-states
|
||||||
|
|
||||||
|
// setup PVS for frame
|
||||||
|
memcpy( RI.visbytes, tr.visbytes, gpGlobals->visbytes );
|
||||||
|
tr.frametime = frametime;
|
||||||
|
|
||||||
|
gEngfuncs.CL_DrawEFX( frametime, trans_pass );
|
||||||
|
|
||||||
|
// restore internal state
|
||||||
|
memcpy( &RI, &oldRI, sizeof( ref_instance_t ));
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,870 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1997-2001 Id Software, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
// r_rast.c
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
|
||||||
|
#define MAXLEFTCLIPEDGES 100
|
||||||
|
|
||||||
|
// !!! if these are changed, they must be changed in asm_draw.h too !!!
|
||||||
|
#define FULLY_CLIPPED_CACHED 0x80000000
|
||||||
|
#define FRAMECOUNT_MASK 0x7FFFFFFF
|
||||||
|
|
||||||
|
unsigned int cacheoffset;
|
||||||
|
|
||||||
|
int c_faceclip; // number of faces clipped
|
||||||
|
|
||||||
|
|
||||||
|
clipplane_t *entity_clipplanes;
|
||||||
|
clipplane_t world_clipplanes[16];
|
||||||
|
|
||||||
|
medge_t *r_pedge;
|
||||||
|
|
||||||
|
qboolean r_leftclipped, r_rightclipped;
|
||||||
|
static qboolean makeleftedge, makerightedge;
|
||||||
|
qboolean r_nearzionly;
|
||||||
|
|
||||||
|
int sintable[1280];
|
||||||
|
int intsintable[1280];
|
||||||
|
int blanktable[1280]; // PGM
|
||||||
|
|
||||||
|
mvertex_t r_leftenter, r_leftexit;
|
||||||
|
mvertex_t r_rightenter, r_rightexit;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float u,v;
|
||||||
|
int ceilv;
|
||||||
|
} evert_t;
|
||||||
|
|
||||||
|
int r_emitted;
|
||||||
|
float r_nearzi;
|
||||||
|
float r_u1, r_v1, r_lzi1;
|
||||||
|
int r_ceilv1;
|
||||||
|
|
||||||
|
qboolean r_lastvertvalid;
|
||||||
|
int r_skyframe;
|
||||||
|
|
||||||
|
msurface_t *r_skyfaces;
|
||||||
|
mplane_t r_skyplanes[6];
|
||||||
|
mtexinfo_t r_skytexinfo[6];
|
||||||
|
mvertex_t *r_skyverts;
|
||||||
|
medge_t *r_skyedges;
|
||||||
|
int *r_skysurfedges;
|
||||||
|
|
||||||
|
// I just copied this data from a box map...
|
||||||
|
int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128};
|
||||||
|
|
||||||
|
int box_surfedges[24] = { 1,2,3,4, -1,5,6,7, 8,9,-6,10, -2,-7,-9,11,
|
||||||
|
12,-3,-11,-8, -12,-10,-5,-4};
|
||||||
|
int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4};
|
||||||
|
|
||||||
|
int box_faces[6] = {0,0,2,2,2,0};
|
||||||
|
|
||||||
|
vec3_t box_vecs[6][2] = {
|
||||||
|
{ {0,-1,0}, {-1,0,0} },
|
||||||
|
{ {0,1,0}, {0,0,-1} },
|
||||||
|
{ {0,-1,0}, {1,0,0} },
|
||||||
|
{ {1,0,0}, {0,0,-1} },
|
||||||
|
{ {0,-1,0}, {0,0,-1} },
|
||||||
|
{ {-1,0,0}, {0,0,-1} }
|
||||||
|
};
|
||||||
|
|
||||||
|
float box_verts[8][3] = {
|
||||||
|
{-1,-1,-1},
|
||||||
|
{-1,1,-1},
|
||||||
|
{1,1,-1},
|
||||||
|
{1,-1,-1},
|
||||||
|
{-1,-1,1},
|
||||||
|
{-1,1,1},
|
||||||
|
{1,-1,1},
|
||||||
|
{1,1,1}
|
||||||
|
};
|
||||||
|
|
||||||
|
// down, west, up, north, east, south
|
||||||
|
// {"rt", "bk", "lf", "ft", "up", "dn"};
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_InitSkyBox
|
||||||
|
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_InitSkyBox (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
extern model_t *loadmodel;
|
||||||
|
|
||||||
|
r_skyfaces = loadmodel->surfaces + loadmodel->numsurfaces;
|
||||||
|
loadmodel->numsurfaces += 6;
|
||||||
|
r_skyverts = loadmodel->vertexes + loadmodel->numvertexes;
|
||||||
|
loadmodel->numvertexes += 8;
|
||||||
|
r_skyedges = loadmodel->edges + loadmodel->numedges;
|
||||||
|
loadmodel->numedges += 12;
|
||||||
|
r_skysurfedges = loadmodel->surfedges + loadmodel->numsurfedges;
|
||||||
|
loadmodel->numsurfedges += 24;
|
||||||
|
if (loadmodel->numsurfaces > MAX_MAP_FACES
|
||||||
|
|| loadmodel->numvertexes > MAX_MAP_VERTS
|
||||||
|
|| loadmodel->numedges > MAX_MAP_EDGES)
|
||||||
|
ri.Sys_Error (ERR_DROP, "InitSkyBox: map overflow");
|
||||||
|
|
||||||
|
memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces));
|
||||||
|
for (i=0 ; i<6 ; i++)
|
||||||
|
{
|
||||||
|
r_skyplanes[i].normal[skybox_planes[i*2]] = 1;
|
||||||
|
r_skyplanes[i].dist = skybox_planes[i*2+1];
|
||||||
|
|
||||||
|
VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]);
|
||||||
|
VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]);
|
||||||
|
|
||||||
|
r_skyfaces[i].plane = &r_skyplanes[i];
|
||||||
|
r_skyfaces[i].numedges = 4;
|
||||||
|
r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX;
|
||||||
|
r_skyfaces[i].firstedge = loadmodel->numsurfedges-24+i*4;
|
||||||
|
r_skyfaces[i].texinfo = &r_skytexinfo[i];
|
||||||
|
r_skyfaces[i].texturemins[0] = -128;
|
||||||
|
r_skyfaces[i].texturemins[1] = -128;
|
||||||
|
r_skyfaces[i].extents[0] = 256;
|
||||||
|
r_skyfaces[i].extents[1] = 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0 ; i<24 ; i++)
|
||||||
|
if (box_surfedges[i] > 0)
|
||||||
|
r_skysurfedges[i] = loadmodel->numedges-13 + box_surfedges[i];
|
||||||
|
else
|
||||||
|
r_skysurfedges[i] = - (loadmodel->numedges-13 + -box_surfedges[i]);
|
||||||
|
|
||||||
|
for(i=0 ; i<12 ; i++)
|
||||||
|
{
|
||||||
|
r_skyedges[i].v[0] = loadmodel->numvertexes-9+box_edges[i*2+0];
|
||||||
|
r_skyedges[i].v[1] = loadmodel->numvertexes-9+box_edges[i*2+1];
|
||||||
|
r_skyedges[i].cachededgeoffset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_EmitSkyBox
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_EmitSkyBox (void)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
int oldkey;
|
||||||
|
|
||||||
|
if (insubmodel)
|
||||||
|
return; // submodels should never have skies
|
||||||
|
if (r_skyframe == r_framecount)
|
||||||
|
return; // already set this frame
|
||||||
|
|
||||||
|
r_skyframe = r_framecount;
|
||||||
|
|
||||||
|
// set the eight fake vertexes
|
||||||
|
for (i=0 ; i<8 ; i++)
|
||||||
|
for (j=0 ; j<3 ; j++)
|
||||||
|
r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128;
|
||||||
|
|
||||||
|
// set the six fake planes
|
||||||
|
for (i=0 ; i<6 ; i++)
|
||||||
|
if (skybox_planes[i*2+1] > 0)
|
||||||
|
r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128;
|
||||||
|
else
|
||||||
|
r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128;
|
||||||
|
|
||||||
|
// fix texture offseets
|
||||||
|
for (i=0 ; i<6 ; i++)
|
||||||
|
{
|
||||||
|
r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]);
|
||||||
|
r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// emit the six faces
|
||||||
|
oldkey = r_currentkey;
|
||||||
|
r_currentkey = 0x7ffffff0;
|
||||||
|
for (i=0 ; i<6 ; i++)
|
||||||
|
{
|
||||||
|
R_RenderFace (r_skyfaces + i, 15);
|
||||||
|
}
|
||||||
|
r_currentkey = oldkey; // bsp sorting order
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#if !id386
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_EmitEdge
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
|
||||||
|
{
|
||||||
|
edge_t *edge, *pcheck;
|
||||||
|
int u_check;
|
||||||
|
float u, u_step;
|
||||||
|
vec3_t local, transformed;
|
||||||
|
float *world;
|
||||||
|
int v, v2, ceilv0;
|
||||||
|
float scale, lzi0, u0, v0;
|
||||||
|
int side;
|
||||||
|
|
||||||
|
if (r_lastvertvalid)
|
||||||
|
{
|
||||||
|
u0 = r_u1;
|
||||||
|
v0 = r_v1;
|
||||||
|
lzi0 = r_lzi1;
|
||||||
|
ceilv0 = r_ceilv1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
world = &pv0->position[0];
|
||||||
|
|
||||||
|
// transform and project
|
||||||
|
VectorSubtract (world, tr.modelorg, local);
|
||||||
|
TransformVector (local, transformed);
|
||||||
|
|
||||||
|
if (transformed[2] < NEAR_CLIP)
|
||||||
|
transformed[2] = NEAR_CLIP;
|
||||||
|
|
||||||
|
lzi0 = 1.0f / transformed[2];
|
||||||
|
|
||||||
|
// FIXME: build x/yscale into transform?
|
||||||
|
scale = xscale * lzi0;
|
||||||
|
u0 = (xcenter + scale*transformed[0]);
|
||||||
|
if (u0 < RI.fvrectx_adj)
|
||||||
|
u0 = RI.fvrectx_adj;
|
||||||
|
if (u0 > RI.fvrectright_adj)
|
||||||
|
u0 = RI.fvrectright_adj;
|
||||||
|
|
||||||
|
scale = yscale * lzi0;
|
||||||
|
v0 = (ycenter - scale*transformed[1]);
|
||||||
|
if (v0 < RI.fvrecty_adj)
|
||||||
|
v0 = RI.fvrecty_adj;
|
||||||
|
if (v0 > RI.fvrectbottom_adj)
|
||||||
|
v0 = RI.fvrectbottom_adj;
|
||||||
|
|
||||||
|
ceilv0 = (int) ceil(v0);
|
||||||
|
}
|
||||||
|
|
||||||
|
world = &pv1->position[0];
|
||||||
|
|
||||||
|
// transform and project
|
||||||
|
VectorSubtract (world, tr.modelorg, local);
|
||||||
|
TransformVector (local, transformed);
|
||||||
|
|
||||||
|
if (transformed[2] < NEAR_CLIP)
|
||||||
|
transformed[2] = NEAR_CLIP;
|
||||||
|
|
||||||
|
r_lzi1 = 1.0f / transformed[2];
|
||||||
|
|
||||||
|
scale = xscale * r_lzi1;
|
||||||
|
r_u1 = (xcenter + scale*transformed[0]);
|
||||||
|
if (r_u1 < RI.fvrectx_adj)
|
||||||
|
r_u1 = RI.fvrectx_adj;
|
||||||
|
if (r_u1 > RI.fvrectright_adj)
|
||||||
|
r_u1 = RI.fvrectright_adj;
|
||||||
|
|
||||||
|
scale = yscale * r_lzi1;
|
||||||
|
r_v1 = (ycenter - scale*transformed[1]);
|
||||||
|
if (r_v1 < RI.fvrecty_adj)
|
||||||
|
r_v1 = RI.fvrecty_adj;
|
||||||
|
if (r_v1 > RI.fvrectbottom_adj)
|
||||||
|
r_v1 = RI.fvrectbottom_adj;
|
||||||
|
|
||||||
|
if (r_lzi1 > lzi0)
|
||||||
|
lzi0 = r_lzi1;
|
||||||
|
|
||||||
|
if (lzi0 > r_nearzi) // for mipmap finding
|
||||||
|
r_nearzi = lzi0;
|
||||||
|
|
||||||
|
// for right edges, all we want is the effect on 1/z
|
||||||
|
if (r_nearzionly)
|
||||||
|
return;
|
||||||
|
|
||||||
|
r_emitted = 1;
|
||||||
|
|
||||||
|
r_ceilv1 = (int) ceil(r_v1);
|
||||||
|
|
||||||
|
|
||||||
|
// create the edge
|
||||||
|
if (ceilv0 == r_ceilv1 || ceilv0 < 0 )
|
||||||
|
{
|
||||||
|
// we cache unclipped horizontal edges as fully clipped
|
||||||
|
if (cacheoffset != 0x7FFFFFFF)
|
||||||
|
{
|
||||||
|
cacheoffset = FULLY_CLIPPED_CACHED |
|
||||||
|
(tr.framecount & FRAMECOUNT_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
return; // horizontal edge
|
||||||
|
}
|
||||||
|
|
||||||
|
side = ceilv0 > r_ceilv1;
|
||||||
|
|
||||||
|
edge = edge_p++;
|
||||||
|
|
||||||
|
edge->owner = r_pedge;
|
||||||
|
|
||||||
|
edge->nearzi = lzi0;
|
||||||
|
|
||||||
|
if (side == 0)
|
||||||
|
{
|
||||||
|
// trailing edge (go from p1 to p2)
|
||||||
|
v = ceilv0;
|
||||||
|
v2 = r_ceilv1 - 1;
|
||||||
|
|
||||||
|
if( v < 0 || v > MAXHEIGHT )
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Printf( S_ERROR "trailing edge overflow : %d\n", v );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
edge->surfs[0] = surface_p - surfaces;
|
||||||
|
edge->surfs[1] = 0;
|
||||||
|
|
||||||
|
u_step = ((r_u1 - u0) / (r_v1 - v0));
|
||||||
|
u = u0 + ((float)v - v0) * u_step;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// leading edge (go from p2 to p1)
|
||||||
|
v2 = ceilv0 - 1;
|
||||||
|
v = r_ceilv1;
|
||||||
|
|
||||||
|
if( v < 0 || v > MAXHEIGHT )
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Printf( S_ERROR "leading edge overflow : %d\n", v );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
edge->surfs[0] = 0;
|
||||||
|
edge->surfs[1] = surface_p - surfaces;
|
||||||
|
|
||||||
|
u_step = ((u0 - r_u1) / (v0 - r_v1));
|
||||||
|
u = r_u1 + ((float)v - r_v1) * u_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
edge->u_step = u_step*0x100000;
|
||||||
|
edge->u = u*0x100000 + 0xFFFFF;
|
||||||
|
|
||||||
|
// we need to do this to avoid stepping off the edges if a very nearly
|
||||||
|
// horizontal edge is less than epsilon above a scan, and numeric error causes
|
||||||
|
// it to incorrectly extend to the scan, and the extension of the line goes off
|
||||||
|
// the edge of the screen
|
||||||
|
// FIXME: is this actually needed?
|
||||||
|
/*int r = (gpGlobals->width<<20) + (1<<19) - 1;
|
||||||
|
int x = (1<<20) + (1<<19) - 1;
|
||||||
|
if (edge->u < x)
|
||||||
|
edge->u = x;
|
||||||
|
if (edge->u > r)
|
||||||
|
edge->u = r;*/
|
||||||
|
if (edge->u < RI.vrect_x_adj_shift20)
|
||||||
|
edge->u = RI.vrect_x_adj_shift20;
|
||||||
|
if (edge->u > RI.vrectright_adj_shift20)
|
||||||
|
edge->u = RI.vrectright_adj_shift20;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// sort the edge in normally
|
||||||
|
//
|
||||||
|
u_check = edge->u;
|
||||||
|
if (edge->surfs[0])
|
||||||
|
u_check++; // sort trailers after leaders
|
||||||
|
|
||||||
|
if (!newedges[v] || newedges[v]->u >= u_check)
|
||||||
|
{
|
||||||
|
edge->next = newedges[v];
|
||||||
|
newedges[v] = edge;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pcheck = newedges[v];
|
||||||
|
while (pcheck->next && pcheck->next->u < u_check)
|
||||||
|
pcheck = pcheck->next;
|
||||||
|
edge->next = pcheck->next;
|
||||||
|
pcheck->next = edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
edge->nextremove = removeedges[v2];
|
||||||
|
removeedges[v2] = edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_ClipEdge
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
|
||||||
|
{
|
||||||
|
float d0, d1, f;
|
||||||
|
mvertex_t clipvert;
|
||||||
|
|
||||||
|
if (clip)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
|
||||||
|
d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
|
||||||
|
|
||||||
|
if (d0 >= 0)
|
||||||
|
{
|
||||||
|
// point 0 is unclipped
|
||||||
|
if (d1 >= 0)
|
||||||
|
{
|
||||||
|
// both points are unclipped
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only point 1 is clipped
|
||||||
|
|
||||||
|
// we don't cache clipped edges
|
||||||
|
cacheoffset = 0x7FFFFFFF;
|
||||||
|
|
||||||
|
f = d0 / (d0 - d1);
|
||||||
|
clipvert.position[0] = pv0->position[0] +
|
||||||
|
f * (pv1->position[0] - pv0->position[0]);
|
||||||
|
clipvert.position[1] = pv0->position[1] +
|
||||||
|
f * (pv1->position[1] - pv0->position[1]);
|
||||||
|
clipvert.position[2] = pv0->position[2] +
|
||||||
|
f * (pv1->position[2] - pv0->position[2]);
|
||||||
|
|
||||||
|
if (clip->leftedge)
|
||||||
|
{
|
||||||
|
r_leftclipped = true;
|
||||||
|
r_leftexit = clipvert;
|
||||||
|
}
|
||||||
|
else if (clip->rightedge)
|
||||||
|
{
|
||||||
|
r_rightclipped = true;
|
||||||
|
r_rightexit = clipvert;
|
||||||
|
}
|
||||||
|
|
||||||
|
R_ClipEdge (pv0, &clipvert, clip->next);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// point 0 is clipped
|
||||||
|
if (d1 < 0)
|
||||||
|
{
|
||||||
|
// both points are clipped
|
||||||
|
// we do cache fully clipped edges
|
||||||
|
if (!r_leftclipped)
|
||||||
|
cacheoffset = FULLY_CLIPPED_CACHED |
|
||||||
|
(tr.framecount & FRAMECOUNT_MASK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only point 0 is clipped
|
||||||
|
r_lastvertvalid = false;
|
||||||
|
|
||||||
|
// we don't cache partially clipped edges
|
||||||
|
cacheoffset = 0x7FFFFFFF;
|
||||||
|
|
||||||
|
f = d0 / (d0 - d1);
|
||||||
|
clipvert.position[0] = pv0->position[0] +
|
||||||
|
f * (pv1->position[0] - pv0->position[0]);
|
||||||
|
clipvert.position[1] = pv0->position[1] +
|
||||||
|
f * (pv1->position[1] - pv0->position[1]);
|
||||||
|
clipvert.position[2] = pv0->position[2] +
|
||||||
|
f * (pv1->position[2] - pv0->position[2]);
|
||||||
|
|
||||||
|
if (clip->leftedge)
|
||||||
|
{
|
||||||
|
r_leftclipped = true;
|
||||||
|
r_leftenter = clipvert;
|
||||||
|
}
|
||||||
|
else if (clip->rightedge)
|
||||||
|
{
|
||||||
|
r_rightclipped = true;
|
||||||
|
r_rightenter = clipvert;
|
||||||
|
}
|
||||||
|
|
||||||
|
R_ClipEdge (&clipvert, pv1, clip->next);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} while ((clip = clip->next) != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the edge
|
||||||
|
R_EmitEdge (pv0, pv1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !id386
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_EmitCachedEdge
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_EmitCachedEdge (void)
|
||||||
|
{
|
||||||
|
edge_t *pedge_t;
|
||||||
|
|
||||||
|
pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset);
|
||||||
|
|
||||||
|
if (!pedge_t->surfs[0])
|
||||||
|
pedge_t->surfs[0] = surface_p - surfaces;
|
||||||
|
else
|
||||||
|
pedge_t->surfs[1] = surface_p - surfaces;
|
||||||
|
|
||||||
|
if (pedge_t->nearzi > r_nearzi) // for mipmap finding
|
||||||
|
r_nearzi = pedge_t->nearzi;
|
||||||
|
|
||||||
|
r_emitted = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_RenderFace
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_RenderFace (msurface_t *fa, int clipflags)
|
||||||
|
{
|
||||||
|
int i, lindex;
|
||||||
|
unsigned mask;
|
||||||
|
mplane_t *pplane;
|
||||||
|
float distinv;
|
||||||
|
vec3_t p_normal;
|
||||||
|
medge_t *pedges, tedge;
|
||||||
|
clipplane_t *pclip;
|
||||||
|
|
||||||
|
// translucent surfaces are not drawn by the edge renderer
|
||||||
|
if (fa->flags & (SURF_DRAWTURB|SURF_TRANSPARENT))
|
||||||
|
{
|
||||||
|
//fa->nextalphasurface = r_alpha_surfaces;
|
||||||
|
//r_alpha_surfaces = fa;
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sky surfaces encountered in the world will cause the
|
||||||
|
// environment box surfaces to be emited
|
||||||
|
if ( fa->flags & SURF_DRAWSKY )
|
||||||
|
{
|
||||||
|
//R_EmitSkyBox ();
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip out if no more surfs
|
||||||
|
if ((surface_p) >= surf_max)
|
||||||
|
{
|
||||||
|
// r_outofsurfaces++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ditto if not enough edges left, or switch to auxedges if possible
|
||||||
|
if ((edge_p + fa->numedges + 4) >= edge_max)
|
||||||
|
{
|
||||||
|
//r_outofedges += fa->numedges;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_faceclip++;
|
||||||
|
|
||||||
|
// set up clip planes
|
||||||
|
pclip = NULL;
|
||||||
|
|
||||||
|
for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
|
||||||
|
{
|
||||||
|
if (clipflags & mask)
|
||||||
|
{
|
||||||
|
qfrustum.view_clipplanes[i].next = pclip;
|
||||||
|
pclip = &qfrustum.view_clipplanes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// push the edges through
|
||||||
|
r_emitted = 0;
|
||||||
|
r_nearzi = 0;
|
||||||
|
r_nearzionly = false;
|
||||||
|
makeleftedge = makerightedge = false;
|
||||||
|
pedges = RI.currentmodel->edges;
|
||||||
|
r_lastvertvalid = false;
|
||||||
|
|
||||||
|
for (i=0 ; i<fa->numedges ; i++)
|
||||||
|
{
|
||||||
|
lindex = RI.currentmodel->surfedges[fa->firstedge + i];
|
||||||
|
|
||||||
|
if (lindex > 0)
|
||||||
|
{
|
||||||
|
r_pedge = &pedges[lindex];
|
||||||
|
|
||||||
|
// if the edge is cached, we can just reuse the edge
|
||||||
|
if (!insubmodel)
|
||||||
|
{
|
||||||
|
if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
|
||||||
|
{
|
||||||
|
if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
|
||||||
|
tr.framecount)
|
||||||
|
{
|
||||||
|
r_lastvertvalid = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((((unsigned long)edge_p - (unsigned long)r_edges) >
|
||||||
|
r_pedge->cachededgeoffset) &&
|
||||||
|
(((edge_t *)((unsigned long)r_edges +
|
||||||
|
r_pedge->cachededgeoffset))->owner == r_pedge))
|
||||||
|
{
|
||||||
|
R_EmitCachedEdge ();
|
||||||
|
r_lastvertvalid = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume it's cacheable
|
||||||
|
cacheoffset = (byte *)edge_p - (byte *)r_edges;
|
||||||
|
r_leftclipped = r_rightclipped = false;
|
||||||
|
R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
|
||||||
|
&r_pcurrentvertbase[r_pedge->v[1]],
|
||||||
|
pclip);
|
||||||
|
r_pedge->cachededgeoffset = cacheoffset;
|
||||||
|
|
||||||
|
if (r_leftclipped)
|
||||||
|
makeleftedge = true;
|
||||||
|
if (r_rightclipped)
|
||||||
|
makerightedge = true;
|
||||||
|
r_lastvertvalid = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lindex = -lindex;
|
||||||
|
r_pedge = &pedges[lindex];
|
||||||
|
// if the edge is cached, we can just reuse the edge
|
||||||
|
if (!insubmodel)
|
||||||
|
{
|
||||||
|
if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
|
||||||
|
{
|
||||||
|
if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
|
||||||
|
tr.framecount)
|
||||||
|
{
|
||||||
|
r_lastvertvalid = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// it's cached if the cached edge is valid and is owned
|
||||||
|
// by this medge_t
|
||||||
|
if ((((unsigned long)edge_p - (unsigned long)r_edges) >
|
||||||
|
r_pedge->cachededgeoffset) &&
|
||||||
|
(((edge_t *)((unsigned long)r_edges +
|
||||||
|
r_pedge->cachededgeoffset))->owner == r_pedge))
|
||||||
|
{
|
||||||
|
R_EmitCachedEdge ();
|
||||||
|
r_lastvertvalid = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume it's cacheable
|
||||||
|
cacheoffset = (byte *)edge_p - (byte *)r_edges;
|
||||||
|
r_leftclipped = r_rightclipped = false;
|
||||||
|
R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
|
||||||
|
&r_pcurrentvertbase[r_pedge->v[0]],
|
||||||
|
pclip);
|
||||||
|
r_pedge->cachededgeoffset = cacheoffset;
|
||||||
|
|
||||||
|
if (r_leftclipped)
|
||||||
|
makeleftedge = true;
|
||||||
|
if (r_rightclipped)
|
||||||
|
makerightedge = true;
|
||||||
|
r_lastvertvalid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there was a clip off the left edge, add that edge too
|
||||||
|
// FIXME: faster to do in screen space?
|
||||||
|
// FIXME: share clipped edges?
|
||||||
|
if (makeleftedge)
|
||||||
|
{
|
||||||
|
r_pedge = &tedge;
|
||||||
|
r_lastvertvalid = false;
|
||||||
|
R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there was a clip off the right edge, get the right r_nearzi
|
||||||
|
if (makerightedge)
|
||||||
|
{
|
||||||
|
r_pedge = &tedge;
|
||||||
|
r_lastvertvalid = false;
|
||||||
|
r_nearzionly = true;
|
||||||
|
R_ClipEdge (&r_rightexit, &r_rightenter, qfrustum.view_clipplanes[1].next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no edges made it out, return without posting the surface
|
||||||
|
if (!r_emitted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// r_polycount++;
|
||||||
|
|
||||||
|
surface_p->msurf = fa;
|
||||||
|
surface_p->nearzi = r_nearzi;
|
||||||
|
surface_p->flags = fa->flags;
|
||||||
|
surface_p->insubmodel = insubmodel;
|
||||||
|
surface_p->spanstate = 0;
|
||||||
|
surface_p->entity = RI.currententity;
|
||||||
|
surface_p->key = r_currentkey++;
|
||||||
|
surface_p->spans = NULL;
|
||||||
|
|
||||||
|
pplane = fa->plane;
|
||||||
|
// FIXME: cache this?
|
||||||
|
TransformVector (pplane->normal, p_normal);
|
||||||
|
// FIXME: cache this?
|
||||||
|
distinv = 1.0f / (pplane->dist - DotProduct (tr.modelorg, pplane->normal));
|
||||||
|
|
||||||
|
surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
|
||||||
|
surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
|
||||||
|
surface_p->d_ziorigin = p_normal[2] * distinv -
|
||||||
|
xcenter * surface_p->d_zistepu -
|
||||||
|
ycenter * surface_p->d_zistepv;
|
||||||
|
|
||||||
|
surface_p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_RenderBmodelFace
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned mask;
|
||||||
|
mplane_t *pplane;
|
||||||
|
float distinv;
|
||||||
|
vec3_t p_normal;
|
||||||
|
medge_t tedge;
|
||||||
|
clipplane_t *pclip;
|
||||||
|
|
||||||
|
/*if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
|
||||||
|
{
|
||||||
|
psurf->nextalphasurface = r_alpha_surfaces;
|
||||||
|
r_alpha_surfaces = psurf;
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// skip out if no more surfs
|
||||||
|
if (surface_p >= surf_max)
|
||||||
|
{
|
||||||
|
//r_outofsurfaces++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ditto if not enough edges left, or switch to auxedges if possible
|
||||||
|
if ((edge_p + psurf->numedges + 4) >= edge_max)
|
||||||
|
{
|
||||||
|
//r_outofedges += psurf->numedges;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_faceclip++;
|
||||||
|
|
||||||
|
// this is a dummy to give the caching mechanism someplace to write to
|
||||||
|
r_pedge = &tedge;
|
||||||
|
|
||||||
|
// set up clip planes
|
||||||
|
pclip = NULL;
|
||||||
|
|
||||||
|
for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
|
||||||
|
{
|
||||||
|
if (r_clipflags & mask)
|
||||||
|
{
|
||||||
|
qfrustum.view_clipplanes[i].next = pclip;
|
||||||
|
pclip = &qfrustum.view_clipplanes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// push the edges through
|
||||||
|
r_emitted = 0;
|
||||||
|
r_nearzi = 0;
|
||||||
|
r_nearzionly = false;
|
||||||
|
makeleftedge = makerightedge = false;
|
||||||
|
// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
|
||||||
|
// can be used?
|
||||||
|
r_lastvertvalid = false;
|
||||||
|
|
||||||
|
for ( ; pedges ; pedges = pedges->pnext)
|
||||||
|
{
|
||||||
|
r_leftclipped = r_rightclipped = false;
|
||||||
|
R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
|
||||||
|
|
||||||
|
if (r_leftclipped)
|
||||||
|
makeleftedge = true;
|
||||||
|
if (r_rightclipped)
|
||||||
|
makerightedge = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there was a clip off the left edge, add that edge too
|
||||||
|
// FIXME: faster to do in screen space?
|
||||||
|
// FIXME: share clipped edges?
|
||||||
|
if (makeleftedge)
|
||||||
|
{
|
||||||
|
r_pedge = &tedge;
|
||||||
|
R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there was a clip off the right edge, get the right r_nearzi
|
||||||
|
if (makerightedge)
|
||||||
|
{
|
||||||
|
r_pedge = &tedge;
|
||||||
|
r_nearzionly = true;
|
||||||
|
R_ClipEdge (&r_rightexit, &r_rightenter, qfrustum.view_clipplanes[1].next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no edges made it out, return without posting the surface
|
||||||
|
if (!r_emitted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//r_polycount++;
|
||||||
|
|
||||||
|
surface_p->msurf = psurf;
|
||||||
|
surface_p->nearzi = r_nearzi;
|
||||||
|
surface_p->flags = psurf->flags;
|
||||||
|
surface_p->insubmodel = true;
|
||||||
|
surface_p->spanstate = 0;
|
||||||
|
surface_p->entity = RI.currententity;
|
||||||
|
surface_p->key = r_currentbkey;
|
||||||
|
surface_p->spans = NULL;
|
||||||
|
|
||||||
|
pplane = psurf->plane;
|
||||||
|
// FIXME: cache this?
|
||||||
|
TransformVector (pplane->normal, p_normal);
|
||||||
|
// FIXME: cache this?
|
||||||
|
distinv = 1.0f / (pplane->dist - DotProduct (tr.modelorg, pplane->normal));
|
||||||
|
|
||||||
|
surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
|
||||||
|
surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
|
||||||
|
surface_p->d_ziorigin = p_normal[2] * distinv -
|
||||||
|
xcenter * surface_p->d_zistepu -
|
||||||
|
ycenter * surface_p->d_zistepv;
|
||||||
|
|
||||||
|
surface_p++;
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,294 @@
|
||||||
|
#include "r_local.h"
|
||||||
|
|
||||||
|
// not really draw alias models here, but use this to draw triangles
|
||||||
|
|
||||||
|
|
||||||
|
affinetridesc_t r_affinetridesc;
|
||||||
|
|
||||||
|
|
||||||
|
int r_aliasblendcolor;
|
||||||
|
|
||||||
|
|
||||||
|
float aliastransform[3][4];
|
||||||
|
float aliasworldtransform[3][4];
|
||||||
|
float aliasoldworldtransform[3][4];
|
||||||
|
|
||||||
|
float s_ziscale;
|
||||||
|
static vec3_t s_alias_forward, s_alias_right, s_alias_up;
|
||||||
|
|
||||||
|
|
||||||
|
#define NUMVERTEXNORMALS 162
|
||||||
|
|
||||||
|
float r_avertexnormals[NUMVERTEXNORMALS][3] = {
|
||||||
|
#include "anorms.h"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void R_AliasSetUpTransform (void);
|
||||||
|
void R_AliasTransformVector (vec3_t in, vec3_t out, float m[3][4] );
|
||||||
|
void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
|
||||||
|
|
||||||
|
void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv );
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_AliasCheckBBox
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BBOX_TRIVIAL_ACCEPT 0
|
||||||
|
#define BBOX_MUST_CLIP_XY 1
|
||||||
|
#define BBOX_MUST_CLIP_Z 2
|
||||||
|
#define BBOX_TRIVIAL_REJECT 8
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_AliasTransformVector
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_AliasTransformVector(vec3_t in, vec3_t out, float xf[3][4] )
|
||||||
|
{
|
||||||
|
out[0] = DotProduct(in, xf[0]) + xf[0][3];
|
||||||
|
out[1] = DotProduct(in, xf[1]) + xf[1][3];
|
||||||
|
out[2] = DotProduct(in, xf[2]) + xf[2][3];
|
||||||
|
}
|
||||||
|
|
||||||
|
void VectorInverse (vec3_t v)
|
||||||
|
{
|
||||||
|
v[0] = -v[0];
|
||||||
|
v[1] = -v[1];
|
||||||
|
v[2] = -v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_SetUpWorldTransform
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_SetUpWorldTransform (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
static float viewmatrix[3][4];
|
||||||
|
vec3_t angles;
|
||||||
|
|
||||||
|
// TODO: should really be stored with the entity instead of being reconstructed
|
||||||
|
// TODO: should use a look-up table
|
||||||
|
// TODO: could cache lazily, stored in the entity
|
||||||
|
//
|
||||||
|
|
||||||
|
s_ziscale = (float)0x8000 * (float)0x10000;
|
||||||
|
angles[ROLL] = 0;
|
||||||
|
angles[PITCH] = 0;
|
||||||
|
angles[YAW] = 0;
|
||||||
|
AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up );
|
||||||
|
|
||||||
|
// TODO: can do this with simple matrix rearrangement
|
||||||
|
|
||||||
|
memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) );
|
||||||
|
memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) );
|
||||||
|
|
||||||
|
for (i=0 ; i<3 ; i++)
|
||||||
|
{
|
||||||
|
aliasoldworldtransform[i][0] = aliasworldtransform[i][0] = s_alias_forward[i];
|
||||||
|
aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i];
|
||||||
|
aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
aliasworldtransform[0][3] = -RI.vieworg[0];
|
||||||
|
aliasworldtransform[1][3] = -RI.vieworg[1];
|
||||||
|
aliasworldtransform[2][3] = -RI.vieworg[2];
|
||||||
|
|
||||||
|
//aliasoldworldtransform[0][3] = RI.currententity->oldorigin[0]-r_origin[0];
|
||||||
|
//aliasoldworldtransform[1][3] = RI.currententity->oldorigin[1]-r_origin[1];
|
||||||
|
//aliasoldworldtransform[2][3] = RI.currententity->oldorigin[2]-r_origin[2];
|
||||||
|
|
||||||
|
// FIXME: can do more efficiently than full concatenation
|
||||||
|
// memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) );
|
||||||
|
|
||||||
|
// R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
|
||||||
|
|
||||||
|
// TODO: should be global, set when vright, etc., set
|
||||||
|
VectorCopy (RI.vright, viewmatrix[0]);
|
||||||
|
VectorCopy (RI.vup, viewmatrix[1]);
|
||||||
|
VectorInverse (viewmatrix[1]);
|
||||||
|
//VectorScale(viewmatrix[1], -1, viewmatrix[1]);
|
||||||
|
VectorCopy (RI.vforward, viewmatrix[2]);
|
||||||
|
|
||||||
|
viewmatrix[0][3] = 0;
|
||||||
|
viewmatrix[1][3] = 0;
|
||||||
|
viewmatrix[2][3] = 0;
|
||||||
|
|
||||||
|
// memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) );
|
||||||
|
|
||||||
|
//R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform);
|
||||||
|
Matrix3x4_ConcatTransforms(aliastransform, viewmatrix, aliasworldtransform );
|
||||||
|
|
||||||
|
aliasworldtransform[0][3] = 0;
|
||||||
|
aliasworldtransform[1][3] = 0;
|
||||||
|
aliasworldtransform[2][3] = 0;
|
||||||
|
|
||||||
|
//aliasoldworldtransform[0][3] = RI.currententity->oldorigin[0];
|
||||||
|
//aliasoldworldtransform[1][3] = RI.currententity->oldorigin[1];
|
||||||
|
//aliasoldworldtransform[2][3] = RI.currententity->oldorigin[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_AliasSetUpTransform
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_AliasSetUpTransform (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
static float viewmatrix[3][4];
|
||||||
|
vec3_t angles;
|
||||||
|
|
||||||
|
// TODO: should really be stored with the entity instead of being reconstructed
|
||||||
|
// TODO: should use a look-up table
|
||||||
|
// TODO: could cache lazily, stored in the entity
|
||||||
|
//
|
||||||
|
|
||||||
|
s_ziscale = (float)0x8000 * (float)0x10000;
|
||||||
|
angles[ROLL] = RI.currententity->angles[ROLL];
|
||||||
|
angles[PITCH] = RI.currententity->angles[PITCH];
|
||||||
|
angles[YAW] = RI.currententity->angles[YAW];
|
||||||
|
AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up );
|
||||||
|
|
||||||
|
// TODO: can do this with simple matrix rearrangement
|
||||||
|
|
||||||
|
memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) );
|
||||||
|
memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) );
|
||||||
|
|
||||||
|
for (i=0 ; i<3 ; i++)
|
||||||
|
{
|
||||||
|
aliasoldworldtransform[i][0] = aliasworldtransform[i][0] = s_alias_forward[i];
|
||||||
|
aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i];
|
||||||
|
aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
aliasworldtransform[0][3] = RI.currententity->origin[0]-RI.vieworg[0];
|
||||||
|
aliasworldtransform[1][3] = RI.currententity->origin[1]-RI.vieworg[1];
|
||||||
|
aliasworldtransform[2][3] = RI.currententity->origin[2]-RI.vieworg[2];
|
||||||
|
|
||||||
|
//aliasoldworldtransform[0][3] = RI.currententity->oldorigin[0]-r_origin[0];
|
||||||
|
//aliasoldworldtransform[1][3] = RI.currententity->oldorigin[1]-r_origin[1];
|
||||||
|
//aliasoldworldtransform[2][3] = RI.currententity->oldorigin[2]-r_origin[2];
|
||||||
|
|
||||||
|
// FIXME: can do more efficiently than full concatenation
|
||||||
|
// memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) );
|
||||||
|
|
||||||
|
// R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
|
||||||
|
|
||||||
|
// TODO: should be global, set when vright, etc., set
|
||||||
|
VectorCopy (RI.vright, viewmatrix[0]);
|
||||||
|
VectorCopy (RI.vup, viewmatrix[1]);
|
||||||
|
VectorInverse (viewmatrix[1]);
|
||||||
|
//VectorScale(viewmatrix[1], -1, viewmatrix[1]);
|
||||||
|
VectorCopy (RI.vforward, viewmatrix[2]);
|
||||||
|
|
||||||
|
viewmatrix[0][3] = 0;
|
||||||
|
viewmatrix[1][3] = 0;
|
||||||
|
viewmatrix[2][3] = 0;
|
||||||
|
|
||||||
|
// memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) );
|
||||||
|
|
||||||
|
//R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform);
|
||||||
|
Matrix3x4_ConcatTransforms(aliastransform, viewmatrix, aliasworldtransform );
|
||||||
|
|
||||||
|
aliasworldtransform[0][3] = RI.currententity->origin[0];
|
||||||
|
aliasworldtransform[1][3] = RI.currententity->origin[1];
|
||||||
|
aliasworldtransform[2][3] = RI.currententity->origin[2];
|
||||||
|
|
||||||
|
//aliasoldworldtransform[0][3] = RI.currententity->oldorigin[0];
|
||||||
|
//aliasoldworldtransform[1][3] = RI.currententity->oldorigin[1];
|
||||||
|
//aliasoldworldtransform[2][3] = RI.currententity->oldorigin[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
R_AliasProjectAndClipTestFinalVert
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void R_AliasProjectAndClipTestFinalVert( finalvert_t *fv )
|
||||||
|
{
|
||||||
|
float zi;
|
||||||
|
float x, y, z;
|
||||||
|
|
||||||
|
// project points
|
||||||
|
x = fv->xyz[0];
|
||||||
|
y = fv->xyz[1];
|
||||||
|
z = fv->xyz[2];
|
||||||
|
zi = 1.0f / z;
|
||||||
|
|
||||||
|
fv->zi = zi * s_ziscale;
|
||||||
|
|
||||||
|
fv->u = (x * aliasxscale * zi) + aliasxcenter;
|
||||||
|
fv->v = (y * aliasyscale * zi) + aliasycenter;
|
||||||
|
|
||||||
|
if (fv->u < RI.aliasvrect.x)
|
||||||
|
fv->flags |= ALIAS_LEFT_CLIP;
|
||||||
|
if (fv->v < RI.aliasvrect.y)
|
||||||
|
fv->flags |= ALIAS_TOP_CLIP;
|
||||||
|
if (fv->u > RI.aliasvrectright)
|
||||||
|
fv->flags |= ALIAS_RIGHT_CLIP;
|
||||||
|
if (fv->v > RI.aliasvrectbottom)
|
||||||
|
fv->flags |= ALIAS_BOTTOM_CLIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
void R_AliasWorldToScreen( const float *v, float *out )
|
||||||
|
{
|
||||||
|
out[0] = DotProduct(v, aliastransform[0]) + aliastransform[0][3];
|
||||||
|
out[1] = DotProduct(v, aliastransform[1]) + aliastransform[1][3];
|
||||||
|
out[2] = DotProduct(v, aliastransform[2]) + aliastransform[2][3];
|
||||||
|
}
|
||||||
|
|
||||||
|
void R_SetupFinalVert( finalvert_t *fv, float x, float y, float z, int light, int s, int t )
|
||||||
|
{
|
||||||
|
vec3_t v = {x, y, z};
|
||||||
|
|
||||||
|
fv->xyz[0] = DotProduct(v, aliastransform[0]) + aliastransform[0][3];
|
||||||
|
fv->xyz[1] = DotProduct(v, aliastransform[1]) + aliastransform[1][3];
|
||||||
|
fv->xyz[2] = DotProduct(v, aliastransform[2]) + aliastransform[2][3];
|
||||||
|
|
||||||
|
fv->flags = 0;
|
||||||
|
|
||||||
|
fv->l = light;
|
||||||
|
|
||||||
|
if ( fv->xyz[2] < ALIAS_Z_CLIP_PLANE )
|
||||||
|
{
|
||||||
|
fv->flags |= ALIAS_Z_CLIP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
R_AliasProjectAndClipTestFinalVert( fv );
|
||||||
|
}
|
||||||
|
|
||||||
|
fv->s = s << 16;
|
||||||
|
fv->t = t << 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
void R_RenderTriangle( finalvert_t *fv1, finalvert_t *fv2, finalvert_t *fv3 )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( fv1->flags & fv2->flags & fv3->flags )
|
||||||
|
return ; // completely clipped
|
||||||
|
|
||||||
|
if ( ! (fv1->flags | fv2->flags | fv3->flags) )
|
||||||
|
{ // totally unclipped
|
||||||
|
aliastriangleparms.a = fv1;
|
||||||
|
aliastriangleparms.b = fv2;
|
||||||
|
aliastriangleparms.c = fv3;
|
||||||
|
|
||||||
|
R_DrawTriangle();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // partially clipped
|
||||||
|
R_AliasClipTriangle (fv1, fv2, fv3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,505 @@
|
||||||
|
/*
|
||||||
|
gl_triapi.c - TriAPI draw methods
|
||||||
|
Copyright (C) 2011 Uncle Mike
|
||||||
|
Copyright (C) 2019 a1batross
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
#include "const.h"
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
int renderMode; // override kRenderMode from TriAPI
|
||||||
|
vec4_t triRGBA;
|
||||||
|
} ds;
|
||||||
|
|
||||||
|
finalvert_t triv[3];
|
||||||
|
int vertcount, n;
|
||||||
|
int mode;
|
||||||
|
short s,t;
|
||||||
|
uint light;
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============================================================
|
||||||
|
|
||||||
|
TRIAPI IMPLEMENTATION
|
||||||
|
|
||||||
|
===============================================================
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriRenderMode
|
||||||
|
|
||||||
|
set rendermode
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT TriRenderMode( int mode )
|
||||||
|
{
|
||||||
|
ds.renderMode = vid.rendermode = mode;
|
||||||
|
#if 0
|
||||||
|
switch( mode )
|
||||||
|
{
|
||||||
|
case kRenderNormal:
|
||||||
|
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||||
|
pglDisable( GL_BLEND );
|
||||||
|
pglDepthMask( GL_TRUE );
|
||||||
|
break;
|
||||||
|
case kRenderTransAlpha:
|
||||||
|
pglEnable( GL_BLEND );
|
||||||
|
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||||
|
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||||
|
pglDepthMask( GL_FALSE );
|
||||||
|
break;
|
||||||
|
case kRenderTransColor:
|
||||||
|
case kRenderTransTexture:
|
||||||
|
pglEnable( GL_BLEND );
|
||||||
|
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||||
|
break;
|
||||||
|
case kRenderGlow:
|
||||||
|
case kRenderTransAdd:
|
||||||
|
pglBlendFunc( GL_SRC_ALPHA, GL_ONE );
|
||||||
|
pglEnable( GL_BLEND );
|
||||||
|
pglDepthMask( GL_FALSE );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriBegin
|
||||||
|
|
||||||
|
begin triangle sequence
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT TriBegin( int mode1 )
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
switch( mode )
|
||||||
|
{
|
||||||
|
case TRI_POINTS:
|
||||||
|
mode = GL_POINTS;
|
||||||
|
break;
|
||||||
|
case TRI_TRIANGLES:
|
||||||
|
mode = GL_TRIANGLES;
|
||||||
|
break;
|
||||||
|
case TRI_TRIANGLE_FAN:
|
||||||
|
mode = GL_TRIANGLE_FAN;
|
||||||
|
break;
|
||||||
|
case TRI_QUADS:
|
||||||
|
mode = GL_QUADS;
|
||||||
|
break;
|
||||||
|
case TRI_LINES:
|
||||||
|
mode = GL_LINES;
|
||||||
|
break;
|
||||||
|
case TRI_TRIANGLE_STRIP:
|
||||||
|
mode = GL_TRIANGLE_STRIP;
|
||||||
|
break;
|
||||||
|
case TRI_QUAD_STRIP:
|
||||||
|
mode = GL_QUAD_STRIP;
|
||||||
|
break;
|
||||||
|
case TRI_POLYGON:
|
||||||
|
default:
|
||||||
|
mode = GL_POLYGON;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pglBegin( mode );
|
||||||
|
#endif
|
||||||
|
if( mode1 == TRI_QUADS )
|
||||||
|
mode1 = TRI_TRIANGLE_FAN;
|
||||||
|
mode = mode1;
|
||||||
|
vertcount = n = vertcount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriEnd
|
||||||
|
|
||||||
|
draw triangle sequence
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT TriEnd( void )
|
||||||
|
{
|
||||||
|
//if( vertcount == 3 )
|
||||||
|
//pglEnd( );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
_TriColor4f
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT _TriColor4f( float rr, float gg, float bb, float aa )
|
||||||
|
{
|
||||||
|
//pglColor4f( r, g, b, a );
|
||||||
|
unsigned short r,g,b;
|
||||||
|
unsigned int major, minor;
|
||||||
|
|
||||||
|
if( vid.rendermode == kRenderTransAdd || vid.rendermode == kRenderGlow )
|
||||||
|
rr *= aa, gg *= aa, bb *= aa;
|
||||||
|
|
||||||
|
//gEngfuncs.Con_Printf("%d\n", vid.alpha);
|
||||||
|
|
||||||
|
light = (rr + gg + bb) * 31 / 3;
|
||||||
|
if( light > 31 )
|
||||||
|
light = 31;
|
||||||
|
|
||||||
|
if( !vid.is2d && vid.rendermode == kRenderNormal )
|
||||||
|
return;
|
||||||
|
|
||||||
|
vid.alpha = aa * 7;
|
||||||
|
if( vid.alpha > 7 )
|
||||||
|
vid.alpha = 7;
|
||||||
|
|
||||||
|
if( rr == 1 && gg == 1 && bb == 1 )
|
||||||
|
{
|
||||||
|
vid.color = COLOR_WHITE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r = rr * 31, g = gg * 63, b = bb * 31;
|
||||||
|
if( r > 31 )
|
||||||
|
r = 31;
|
||||||
|
if( g > 63 )
|
||||||
|
g = 63;
|
||||||
|
if( b > 31 )
|
||||||
|
b = 31;
|
||||||
|
|
||||||
|
|
||||||
|
major = (((r >> 2) & MASK(3)) << 5) |( (( (g >> 3) & MASK(3)) << 2 ) )| (((b >> 3) & MASK(2)));
|
||||||
|
|
||||||
|
// save minor GBRGBRGB
|
||||||
|
minor = MOVE_BIT(r,1,5) | MOVE_BIT(r,0,2) | MOVE_BIT(g,2,7) | MOVE_BIT(g,1,4) | MOVE_BIT(g,0,1) | MOVE_BIT(b,2,6)| MOVE_BIT(b,1,3)|MOVE_BIT(b,0,0);
|
||||||
|
|
||||||
|
vid.color = major << 8 | (minor & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriColor4ub
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void TriColor4ub( byte r, byte g, byte b, byte a )
|
||||||
|
{
|
||||||
|
ds.triRGBA[0] = r * (1.0f / 255.0f);
|
||||||
|
ds.triRGBA[1] = g * (1.0f / 255.0f);
|
||||||
|
ds.triRGBA[2] = b * (1.0f / 255.0f);
|
||||||
|
ds.triRGBA[3] = a * (1.0f / 255.0f);
|
||||||
|
|
||||||
|
_TriColor4f( ds.triRGBA[0], ds.triRGBA[1], ds.triRGBA[2], 1.0f );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriColor4ub
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT _TriColor4ub( byte r, byte g, byte b, byte a )
|
||||||
|
{
|
||||||
|
_TriColor4f( r * (1.0f / 255.0f),
|
||||||
|
g * (1.0f / 255.0f),
|
||||||
|
b * (1.0f / 255.0f),
|
||||||
|
a * (1.0f / 255.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
TriColor4f
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
void TriColor4f( float r, float g, float b, float a )
|
||||||
|
{
|
||||||
|
//if( a < 0.5 )
|
||||||
|
// a = 1;
|
||||||
|
if( ds.renderMode == kRenderTransAlpha )
|
||||||
|
TriColor4ub( r * 255.0f, g * 255.0f, b * 255.0f, a * 255.0f );
|
||||||
|
else _TriColor4f( r * a, g * a, b * a, 1.0 );
|
||||||
|
|
||||||
|
ds.triRGBA[0] = r;
|
||||||
|
ds.triRGBA[1] = g;
|
||||||
|
ds.triRGBA[2] = b;
|
||||||
|
ds.triRGBA[3] = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriTexCoord2f
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT TriTexCoord2f( volatile float u, volatile float v )
|
||||||
|
{
|
||||||
|
volatile double u1 = 0, v1 = 0;
|
||||||
|
u = fmodf(u, 10);
|
||||||
|
v = fmodf(v, 10);
|
||||||
|
if( u < 1000 && u > -1000 )
|
||||||
|
u1 = u;
|
||||||
|
if( v < 1000 && v > -1000 )
|
||||||
|
v1 = v;
|
||||||
|
while( u1 < 0 )
|
||||||
|
u1 = u1 + 1;
|
||||||
|
while( v1 < 0 )
|
||||||
|
v1 = v1 + 1;
|
||||||
|
|
||||||
|
while( u1 > 1 )
|
||||||
|
u1 = u1 - 1;
|
||||||
|
while( v1 > 1 )
|
||||||
|
v1 = v1 - 1;
|
||||||
|
|
||||||
|
|
||||||
|
s = r_affinetridesc.skinwidth * bound(0.01,u1,0.99);
|
||||||
|
t = r_affinetridesc.skinheight * bound(0.01,v1,0.99);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriVertex3fv
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT TriVertex3fv( const float *v )
|
||||||
|
{
|
||||||
|
//pglVertex3fv( v );
|
||||||
|
TriVertex3f( v[0], v[1], v[2] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriVertex3f
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT TriVertex3f( float x, float y, float z )
|
||||||
|
{
|
||||||
|
if( mode == TRI_TRIANGLES )
|
||||||
|
{
|
||||||
|
R_SetupFinalVert( &triv[vertcount], x, y, z, light << 8,s,t);
|
||||||
|
vertcount++;
|
||||||
|
if( vertcount == 3 )
|
||||||
|
{
|
||||||
|
R_RenderTriangle( &triv[0], &triv[1], &triv[2] );
|
||||||
|
//R_RenderTriangle( &triv[2], &triv[1], &triv[0] );
|
||||||
|
vertcount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( mode == TRI_TRIANGLE_FAN )
|
||||||
|
{
|
||||||
|
R_SetupFinalVert( &triv[vertcount], x, y, z, light << 8,s,t);
|
||||||
|
vertcount++;
|
||||||
|
if( vertcount >= 3 )
|
||||||
|
{
|
||||||
|
R_RenderTriangle( &triv[0], &triv[1], &triv[2] );
|
||||||
|
//R_RenderTriangle( &triv[2], &triv[1], &triv[0] );
|
||||||
|
triv[1] = triv[2];
|
||||||
|
vertcount = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( mode == TRI_TRIANGLE_STRIP )
|
||||||
|
{
|
||||||
|
R_SetupFinalVert( &triv[n], x, y, z, light << 8,s,t);
|
||||||
|
n++;
|
||||||
|
vertcount++;
|
||||||
|
if( n == 3 )
|
||||||
|
n = 0;
|
||||||
|
if (vertcount >= 3)
|
||||||
|
{
|
||||||
|
if( vertcount & 1 )
|
||||||
|
R_RenderTriangle( &triv[0], &triv[1], &triv[2] );
|
||||||
|
else
|
||||||
|
R_RenderTriangle( &triv[2], &triv[1], &triv[0] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
if( mode == TRI_TRIANGLE_STRIP )
|
||||||
|
{
|
||||||
|
R_SetupFinalVert( &triv[vertcount], x, y, z, 0,s,t);
|
||||||
|
vertcount++;
|
||||||
|
if( vertcount == 3 )
|
||||||
|
{
|
||||||
|
|
||||||
|
R_RenderTriangle( triv );
|
||||||
|
finalvert_t fv = triv[0];
|
||||||
|
|
||||||
|
triv[0] = triv[2];
|
||||||
|
triv[2] = fv;
|
||||||
|
R_RenderTriangle( triv );
|
||||||
|
fv = triv[0];
|
||||||
|
triv[0] = triv[2];
|
||||||
|
triv[2] = fv;
|
||||||
|
triv[0] = triv[1];
|
||||||
|
triv[1] = triv[2];
|
||||||
|
vertcount = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriWorldToScreen
|
||||||
|
|
||||||
|
convert world coordinates (x,y,z) into screen (x, y)
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
int GAME_EXPORT TriWorldToScreen( const float *world, float *screen )
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = R_WorldToScreen( world, screen );
|
||||||
|
|
||||||
|
screen[0] = 0.5f * screen[0] * (float)RI.viewport[2];
|
||||||
|
screen[1] = -0.5f * screen[1] * (float)RI.viewport[3];
|
||||||
|
screen[0] += 0.5f * (float)RI.viewport[2];
|
||||||
|
screen[1] += 0.5f * (float)RI.viewport[3];
|
||||||
|
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriSpriteTexture
|
||||||
|
|
||||||
|
bind current texture
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
int TriSpriteTexture( model_t *pSpriteModel, int frame )
|
||||||
|
{
|
||||||
|
int gl_texturenum;
|
||||||
|
|
||||||
|
if(( gl_texturenum = R_GetSpriteTexture( pSpriteModel, frame )) == 0 )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if( gl_texturenum <= 0 || gl_texturenum > MAX_TEXTURES )
|
||||||
|
gl_texturenum = tr.defaultTexture;
|
||||||
|
|
||||||
|
GL_Bind( XASH_TEXTURE0, gl_texturenum );
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriFog
|
||||||
|
|
||||||
|
enables global fog on the level
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT TriFog( float flFogColor[3], float flStart, float flEnd, int bOn )
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
// overrided by internal fog
|
||||||
|
if( RI.fogEnabled ) return;
|
||||||
|
RI.fogCustom = bOn;
|
||||||
|
|
||||||
|
// check for invalid parms
|
||||||
|
if( flEnd <= flStart )
|
||||||
|
{
|
||||||
|
RI.fogCustom = false;
|
||||||
|
pglDisable( GL_FOG );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( RI.fogCustom )
|
||||||
|
pglEnable( GL_FOG );
|
||||||
|
else pglDisable( GL_FOG );
|
||||||
|
|
||||||
|
// copy fog params
|
||||||
|
RI.fogColor[0] = flFogColor[0] / 255.0f;
|
||||||
|
RI.fogColor[1] = flFogColor[1] / 255.0f;
|
||||||
|
RI.fogColor[2] = flFogColor[2] / 255.0f;
|
||||||
|
RI.fogStart = flStart;
|
||||||
|
RI.fogColor[3] = 1.0f;
|
||||||
|
RI.fogDensity = 0.0f;
|
||||||
|
RI.fogSkybox = true;
|
||||||
|
RI.fogEnd = flEnd;
|
||||||
|
|
||||||
|
pglFogi( GL_FOG_MODE, GL_LINEAR );
|
||||||
|
pglFogfv( GL_FOG_COLOR, RI.fogColor );
|
||||||
|
pglFogf( GL_FOG_START, RI.fogStart );
|
||||||
|
pglFogf( GL_FOG_END, RI.fogEnd );
|
||||||
|
pglHint( GL_FOG_HINT, GL_NICEST );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriGetMatrix
|
||||||
|
|
||||||
|
very strange export
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT TriGetMatrix( const int pname, float *matrix )
|
||||||
|
{
|
||||||
|
//pglGetFloatv( pname, matrix );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriForParams
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT TriFogParams( float flDensity, int iFogSkybox )
|
||||||
|
{
|
||||||
|
//RI.fogDensity = flDensity;
|
||||||
|
//RI.fogSkybox = iFogSkybox;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriCullFace
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT TriCullFace( TRICULLSTYLE mode )
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
int glMode;
|
||||||
|
|
||||||
|
switch( mode )
|
||||||
|
{
|
||||||
|
case TRI_FRONT:
|
||||||
|
glMode = GL_FRONT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
glMode = GL_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL_Cull( mode );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
TriBrightness
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void TriBrightness( float brightness )
|
||||||
|
{
|
||||||
|
float r, g, b;
|
||||||
|
|
||||||
|
//if( brightness < 0.5 )
|
||||||
|
// brightness = 1; //0.5;
|
||||||
|
//ds.triRGBA[3] = 1;
|
||||||
|
r = ds.triRGBA[0] * ds.triRGBA[3] * brightness;
|
||||||
|
g = ds.triRGBA[1] * ds.triRGBA[3] * brightness;
|
||||||
|
b = ds.triRGBA[2] * ds.triRGBA[3] * brightness;
|
||||||
|
|
||||||
|
_TriColor4f( r, g, b, 1.0f );
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
/*
|
||||||
|
gl_vgui.c - OpenGL vgui draw methods
|
||||||
|
Copyright (C) 2011 Uncle Mike
|
||||||
|
Copyright (C) 2019 a1batross
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "r_local.h"
|
||||||
|
|
||||||
|
#define VGUI_MAX_TEXTURES ( MAX_TEXTURES / 2 ) // a half of total textures count
|
||||||
|
|
||||||
|
static int g_textures[VGUI_MAX_TEXTURES];
|
||||||
|
static int g_textureId = 0;
|
||||||
|
static int g_iBoundTexture;
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
VGUI_DrawInit
|
||||||
|
|
||||||
|
Startup VGUI backend
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT VGUI_DrawInit( void )
|
||||||
|
{
|
||||||
|
memset( g_textures, 0, sizeof( g_textures ));
|
||||||
|
g_textureId = g_iBoundTexture = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
VGUI_DrawShutdown
|
||||||
|
|
||||||
|
Release all textures
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT VGUI_DrawShutdown( void )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 1; i < g_textureId; i++ )
|
||||||
|
{
|
||||||
|
GL_FreeTexture( g_textures[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
VGUI_GenerateTexture
|
||||||
|
|
||||||
|
generate unique texture number
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
int GAME_EXPORT VGUI_GenerateTexture( void )
|
||||||
|
{
|
||||||
|
if( ++g_textureId >= VGUI_MAX_TEXTURES )
|
||||||
|
gEngfuncs.Host_Error( "VGUI_GenerateTexture: VGUI_MAX_TEXTURES limit exceeded\n" );
|
||||||
|
return g_textureId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
VGUI_UploadTexture
|
||||||
|
|
||||||
|
Upload texture into video memory
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT VGUI_UploadTexture( int id, const char *buffer, int width, int height )
|
||||||
|
{
|
||||||
|
rgbdata_t r_image;
|
||||||
|
char texName[32];
|
||||||
|
|
||||||
|
if( id <= 0 || id >= VGUI_MAX_TEXTURES )
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_DPrintf( S_ERROR "VGUI_UploadTexture: bad texture %i. Ignored\n", id );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
|
||||||
|
memset( &r_image, 0, sizeof( r_image ));
|
||||||
|
|
||||||
|
r_image.width = width;
|
||||||
|
r_image.height = height;
|
||||||
|
r_image.type = PF_RGBA_32;
|
||||||
|
r_image.size = r_image.width * r_image.height * 4;
|
||||||
|
r_image.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA;
|
||||||
|
r_image.buffer = (byte *)buffer;
|
||||||
|
|
||||||
|
g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
VGUI_CreateTexture
|
||||||
|
|
||||||
|
Create empty rgba texture and upload them into video memory
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT VGUI_CreateTexture( int id, int width, int height )
|
||||||
|
{
|
||||||
|
rgbdata_t r_image;
|
||||||
|
char texName[32];
|
||||||
|
|
||||||
|
if( id <= 0 || id >= VGUI_MAX_TEXTURES )
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Reportf( S_ERROR "VGUI_CreateTexture: bad texture %i. Ignored\n", id );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
|
||||||
|
memset( &r_image, 0, sizeof( r_image ));
|
||||||
|
|
||||||
|
r_image.width = width;
|
||||||
|
r_image.height = height;
|
||||||
|
r_image.type = PF_RGBA_32;
|
||||||
|
r_image.size = r_image.width * r_image.height * 4;
|
||||||
|
r_image.flags = IMAGE_HAS_ALPHA;
|
||||||
|
r_image.buffer = NULL;
|
||||||
|
|
||||||
|
g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE|TF_NEAREST );
|
||||||
|
g_iBoundTexture = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight )
|
||||||
|
{
|
||||||
|
if( id <= 0 || id >= VGUI_MAX_TEXTURES || g_textures[id] == 0 || g_textures[id] == tr.whiteTexture )
|
||||||
|
{
|
||||||
|
gEngfuncs.Con_Reportf( S_ERROR "VGUI_UploadTextureBlock: bad texture %i. Ignored\n", id );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pglTexSubImage2D( GL_TEXTURE_2D, 0, drawX, drawY, blockWidth, blockHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgba );
|
||||||
|
g_iBoundTexture = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT VGUI_SetupDrawingRect( int *pColor )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT VGUI_SetupDrawingText( int *pColor )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT VGUI_SetupDrawingImage( int *pColor )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT VGUI_BindTexture( int id )
|
||||||
|
{
|
||||||
|
if( id > 0 && id < VGUI_MAX_TEXTURES && g_textures[id] )
|
||||||
|
{
|
||||||
|
GL_Bind( XASH_TEXTURE0, g_textures[id] );
|
||||||
|
g_iBoundTexture = id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NOTE: same as bogus index 2700 in GoldSrc
|
||||||
|
id = g_iBoundTexture = 1;
|
||||||
|
GL_Bind( XASH_TEXTURE0, g_textures[id] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
VGUI_GetTextureSizes
|
||||||
|
|
||||||
|
returns wide and tall for currently binded texture
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT VGUI_GetTextureSizes( int *width, int *height )
|
||||||
|
{
|
||||||
|
image_t *glt;
|
||||||
|
int texnum;
|
||||||
|
|
||||||
|
if( g_iBoundTexture )
|
||||||
|
texnum = g_textures[g_iBoundTexture];
|
||||||
|
else texnum = tr.defaultTexture;
|
||||||
|
|
||||||
|
glt = R_GetTexture( texnum );
|
||||||
|
if( width ) *width = glt->srcWidth;
|
||||||
|
if( height ) *height = glt->srcHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
VGUI_EnableTexture
|
||||||
|
|
||||||
|
disable texturemode for fill rectangle
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT VGUI_EnableTexture( qboolean enable )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
VGUI_DrawQuad
|
||||||
|
|
||||||
|
generic method to fill rectangle
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void GAME_EXPORT VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr )
|
||||||
|
{
|
||||||
|
int width, height;
|
||||||
|
float xscale, yscale;
|
||||||
|
|
||||||
|
gEngfuncs.CL_GetScreenInfo( &width, &height );
|
||||||
|
|
||||||
|
xscale = gpGlobals->width / (float)width;
|
||||||
|
yscale = gpGlobals->height / (float)height;
|
||||||
|
|
||||||
|
ASSERT( ul != NULL && lr != NULL );
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
# mittorn, 2018
|
||||||
|
|
||||||
|
from waflib import Logs
|
||||||
|
import os
|
||||||
|
|
||||||
|
top = '.'
|
||||||
|
|
||||||
|
def options(opt):
|
||||||
|
# stub
|
||||||
|
return
|
||||||
|
|
||||||
|
def configure(conf):
|
||||||
|
# check for dedicated server build
|
||||||
|
if conf.options.DEDICATED:
|
||||||
|
return
|
||||||
|
|
||||||
|
if conf.options.SUPPORT_BSP2_FORMAT:
|
||||||
|
conf.env.append_unique('DEFINES', 'SUPPORT_BSP2_FORMAT')
|
||||||
|
|
||||||
|
conf.env.append_unique('DEFINES', 'REF_DLL')
|
||||||
|
|
||||||
|
def build(bld):
|
||||||
|
if bld.env.DEDICATED:
|
||||||
|
return
|
||||||
|
|
||||||
|
libs = [ 'public', 'M' ]
|
||||||
|
|
||||||
|
source = bld.path.ant_glob(['*.c'])
|
||||||
|
|
||||||
|
includes = ['.',
|
||||||
|
'../engine',
|
||||||
|
'../engine/common',
|
||||||
|
'../engine/server',
|
||||||
|
'../engine/client',
|
||||||
|
'../public',
|
||||||
|
'../common',
|
||||||
|
'../pm_shared' ]
|
||||||
|
|
||||||
|
bld.shlib(
|
||||||
|
source = source,
|
||||||
|
target = 'ref_soft',
|
||||||
|
features = 'c',
|
||||||
|
includes = includes,
|
||||||
|
use = libs,
|
||||||
|
install_path = bld.env.LIBDIR,
|
||||||
|
subsystem = bld.env.MSVC_SUBSYSTEM
|
||||||
|
)
|
Loading…
Reference in New Issue