Browse Source
git-subtree-dir: ref_soft git-subtree-mainline:pull/2/head89ca0dec5e
git-subtree-split:9045657352
Alibek Omarov
5 years ago
26 changed files with 26107 additions and 0 deletions
@ -0,0 +1,323 @@
@@ -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(); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,965 @@
@@ -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 @@
@@ -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 ); |
||||
} |
@ -0,0 +1,428 @@
@@ -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 |
||||
} |
||||
} |
@ -0,0 +1,771 @@
@@ -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");
|
||||
} |
@ -0,0 +1,501 @@
@@ -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 ); |
||||
} |
@ -0,0 +1,267 @@
@@ -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 @@
@@ -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 @@
@@ -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 )); |
||||
} |
@ -0,0 +1,870 @@
@@ -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++; |
||||
} |
||||
|
@ -0,0 +1,294 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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