Initial commit.

This commit is contained in:
Jim Gray
2013-04-04 14:32:05 -07:00
parent ba5c81da32
commit d71d53e8ec
2180 changed files with 1393544 additions and 1 deletions

3037
codemp/renderer/glext.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

293
codemp/renderer/matcomp.c Normal file
View File

@@ -0,0 +1,293 @@
#include "matcomp.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <memory.h> // for memcpy
#define MC_MASK_X ((1<<(MC_BITS_X))-1)
#define MC_MASK_Y ((1<<(MC_BITS_Y))-1)
#define MC_MASK_Z ((1<<(MC_BITS_Z))-1)
#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1)
#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2))
#define MC_POS_X (0)
#define MC_SHIFT_X (0)
#define MC_POS_Y ((((MC_BITS_X))/8))
#define MC_SHIFT_Y ((((MC_BITS_X)%8)))
#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8))
#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8)))
#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8))
#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8)))
#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8))
#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8)))
#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8))
#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8)))
#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8))
#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8)))
#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8))
#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8)))
#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8))
#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8)))
#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8))
#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8)))
#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8))
#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8)))
#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8))
#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8)))
void MC_Compress(const float mat[3][4],unsigned char * _comp)
{
char comp[MC_COMP_BYTES*2];
int i,val;
for (i=0;i<MC_COMP_BYTES;i++)
comp[i]=0;
val=(int)(mat[0][3]/MC_SCALE_X);
val+=1<<(MC_BITS_X-1);
if (val>=(1<<MC_BITS_X))
val=(1<<MC_BITS_X)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_X)|=((unsigned int)(val))<<MC_SHIFT_X;
val=(int)(mat[1][3]/MC_SCALE_Y);
val+=1<<(MC_BITS_Y-1);
if (val>=(1<<MC_BITS_Y))
val=(1<<MC_BITS_Y)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_Y)|=((unsigned int)(val))<<MC_SHIFT_Y;
val=(int)(mat[2][3]/MC_SCALE_Z);
val+=1<<(MC_BITS_Z-1);
if (val>=(1<<MC_BITS_Z))
val=(1<<MC_BITS_Z)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_Z)|=((unsigned int)(val))<<MC_SHIFT_Z;
val=(int)(mat[0][0]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V11)|=((unsigned int)(val))<<MC_SHIFT_V11;
val=(int)(mat[0][1]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V12)|=((unsigned int)(val))<<MC_SHIFT_V12;
val=(int)(mat[0][2]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V13)|=((unsigned int)(val))<<MC_SHIFT_V13;
val=(int)(mat[1][0]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V21)|=((unsigned int)(val))<<MC_SHIFT_V21;
val=(int)(mat[1][1]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V22)|=((unsigned int)(val))<<MC_SHIFT_V22;
val=(int)(mat[1][2]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V23)|=((unsigned int)(val))<<MC_SHIFT_V23;
val=(int)(mat[2][0]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V31)|=((unsigned int)(val))<<MC_SHIFT_V31;
val=(int)(mat[2][1]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V32)|=((unsigned int)(val))<<MC_SHIFT_V32;
val=(int)(mat[2][2]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V33)|=((unsigned int)(val))<<MC_SHIFT_V33;
// I added this because the line above actually ORs data into an int at the 22 byte (from 0), and therefore technically
// is writing beyond the 24th byte of the output array. This *should** be harmless if the OR'd-in value doesn't change
// those bytes, but BoundsChecker says that it's accessing undefined memory (which it does, sometimes). This is probably
// bad, so...
memcpy(_comp,comp,MC_COMP_BYTES);
}
void MC_UnCompress(float mat[3][4],const unsigned char * comp)
{
int val;
val=(int)((unsigned short *)(comp))[0];
val-=1<<(MC_BITS_X-1);
mat[0][3]=((float)(val))*MC_SCALE_X;
val=(int)((unsigned short *)(comp))[1];
val-=1<<(MC_BITS_Y-1);
mat[1][3]=((float)(val))*MC_SCALE_Y;
val=(int)((unsigned short *)(comp))[2];
val-=1<<(MC_BITS_Z-1);
mat[2][3]=((float)(val))*MC_SCALE_Z;
val=(int)((unsigned short *)(comp))[3];
val-=1<<(MC_BITS_VECT-1);
mat[0][0]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[4];
val-=1<<(MC_BITS_VECT-1);
mat[0][1]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[5];
val-=1<<(MC_BITS_VECT-1);
mat[0][2]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[6];
val-=1<<(MC_BITS_VECT-1);
mat[1][0]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[7];
val-=1<<(MC_BITS_VECT-1);
mat[1][1]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[8];
val-=1<<(MC_BITS_VECT-1);
mat[1][2]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[9];
val-=1<<(MC_BITS_VECT-1);
mat[2][0]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[10];
val-=1<<(MC_BITS_VECT-1);
mat[2][1]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[11];
val-=1<<(MC_BITS_VECT-1);
mat[2][2]=((float)(val))*MC_SCALE_VECT;
}
void MC_UnCompressQuat(float mat[3][4],const unsigned char * comp)
{
float w,x,y,z,f;
float fTx;
float fTy;
float fTz;
float fTwx;
float fTwy;
float fTwz;
float fTxx;
float fTxy;
float fTxz;
float fTyy;
float fTyz;
float fTzz;
const unsigned short *pwIn = (unsigned short *) comp;
w = *pwIn++;
w/=16383.0f;
w-=2.0f;
x = *pwIn++;
x/=16383.0f;
x-=2.0f;
y = *pwIn++;
y/=16383.0f;
y-=2.0f;
z = *pwIn++;
z/=16383.0f;
z-=2.0f;
fTx = 2.0f*x;
fTy = 2.0f*y;
fTz = 2.0f*z;
fTwx = fTx*w;
fTwy = fTy*w;
fTwz = fTz*w;
fTxx = fTx*x;
fTxy = fTy*x;
fTxz = fTz*x;
fTyy = fTy*y;
fTyz = fTz*y;
fTzz = fTz*z;
// rot...
//
mat[0][0] = 1.0f-(fTyy+fTzz);
mat[0][1] = fTxy-fTwz;
mat[0][2] = fTxz+fTwy;
mat[1][0] = fTxy+fTwz;
mat[1][1] = 1.0f-(fTxx+fTzz);
mat[1][2] = fTyz-fTwx;
mat[2][0] = fTxz-fTwy;
mat[2][1] = fTyz+fTwx;
mat[2][2] = 1.0f-(fTxx+fTyy);
// xlat...
//
f = *pwIn++;
f/=64;
f-=512;
mat[0][3] = f;
f = *pwIn++;
f/=64;
f-=512;
mat[1][3] = f;
f = *pwIn++;
f/=64;
f-=512;
mat[2][3] = f;
}

31
codemp/renderer/matcomp.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef __MATCOMP__
#define __MATCOMP__
#ifdef __cplusplus
extern "C"
{
#endif
#define MC_BITS_X (16)
#define MC_BITS_Y (16)
#define MC_BITS_Z (16)
#define MC_BITS_VECT (16)
#define MC_SCALE_X (1.0f/64)
#define MC_SCALE_Y (1.0f/64)
#define MC_SCALE_Z (1.0f/64)
// currently 24 (.875)
#define MC_COMP_BYTES (((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*9)+7)/8)
void MC_Compress(const float mat[3][4],unsigned char * comp);
void MC_UnCompress(float mat[3][4],const unsigned char * comp);
void MC_UnCompressQuat(float mat[3][4],const unsigned char * comp);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,434 @@
// Filename:- mdx_format.h
//
// DO NOT UPDATE THIS FILE IN ANY WAY WHATSOEVER WITHOUT TELLING ME (-Ste),
// BECAUSE THE MASTER COPY IS IN A DIFFERENT SOURCESAFE DATABASE AND WILL
// JUST GET PASTED OVER THIS ONE WHENEVER I CHANGE IT.
//
//
//
// MDX file format (typically uses file extension GLX for mesh, and GLA for anim/skeleton file)
//
// Notes:
//
// - All offset fields are relative to the address of the structure they occur in
// - So far, the only external symbol needed is MAX_QPATH, plus the typedefs for vec3_t, vec2_t etc
#ifndef MDX_FORMAT_H
#define MDX_FORMAT_H
#define MDXM_IDENT (('M'<<24)+('G'<<16)+('L'<<8)+'2')
#define MDXA_IDENT (('A'<<24)+('G'<<16)+('L'<<8)+'2')
#define MAX_TAGNAME_BYTES 32 // matches MDR, can be changed if nec.
//
// normal version numbers...
//
#define MDXM_VERSION 6
#define MDXA_VERSION 6
// (Note that since there is now a "<modelname>_info.txt" file written out by carcass any changes made in here that
// introduce new data should also be reflected in the info-output)
// 32 bit-flags for ghoul2 bone properties... (all undefined fields will be blank)
//
#define G2BONEFLAG_ALWAYSXFORM 0x00000001
// same thing but for surfaces... (Carcass will only generate 1st 2 flags, others are ingame
//
#define G2SURFACEFLAG_ISBOLT 0x00000001
#define G2SURFACEFLAG_OFF 0x00000002 // saves strcmp()ing for "_off" in surface names
#define G2SURFACEFLAG_SPARE0 0x00000004 // future-expansion fields, saves invalidating models if we add more
#define G2SURFACEFLAG_SPARE1 0x00000008 //
#define G2SURFACEFLAG_SPARE2 0x00000010 //
#define G2SURFACEFLAG_SPARE3 0x00000020 //
#define G2SURFACEFLAG_SPARE4 0x00000040 //
#define G2SURFACEFLAG_SPARE5 0x00000080 //
//
#define G2SURFACEFLAG_NODESCENDANTS 0x00000100 // ingame-stuff, never generated by Carcass....
#define G2SURFACEFLAG_GENERATED 0x00000200 //
// triangle side-ordering stuff for tags...
//
#define iG2_TRISIDE_MIDDLE 1
#define iG2_TRISIDE_LONGEST 0
#define iG2_TRISIDE_SHORTEST 2
#define fG2_BONEWEIGHT_RECIPROCAL_MULT ((float)(1.0f/1023.0f))
#define iG2_BITS_PER_BONEREF 5
#define iMAX_G2_BONEREFS_PER_SURFACE (1<<iG2_BITS_PER_BONEREF) // (32)
#define iMAX_G2_BONEWEIGHTS_PER_VERT 4 // can't just be blindly increased, affects cache size etc
#define iG2_BONEWEIGHT_TOPBITS_SHIFT ((iG2_BITS_PER_BONEREF * iMAX_G2_BONEWEIGHTS_PER_VERT) - 8) // 8 bits because of 8 in the BoneWeight[] array entry
#define iG2_BONEWEIGHT_TOPBITS_AND 0x300 // 2 bits, giving 10 total, or 10 bits, for 1023/1024 above
#define sDEFAULT_GLA_NAME "*default" // used when making special simple ghoul2 models, usually from MD3 files
////////////////////////////////////
//
// these structs are defined here purely because of structure dependancy order...
//
/*
#ifdef __cplusplus
struct mdxmWeight_t
#else
typedef struct
#endif
{
int boneIndex; // these are indexes into the surface boneReferences, not the global bone index
float boneWeight; // not the global per-frame bone list
// I'm defining this '<' operator so this struct can be used with an STL <set>...
// (note that I've defined it using '>' internally, so it sorts with higher weights being "less", for distance weight-culling
//
#ifdef __cplusplus
bool operator < (const mdxmWeight_t& _X) const {return (boneWeight>_X.boneWeight);}
#endif
}
#ifndef __cplusplus
mdxmWeight_t
#endif
;
*/
/*
#ifdef __cplusplus
struct mdxaCompBone_t
#else
typedef struct
#endif
{
unsigned char Comp[24]; // MC_COMP_BYTES is in MatComp.h, but don't want to couple
// I'm defining this '<' operator so this struct can be used as an STL <map> key...
//
#ifdef __cplusplus
bool operator < (const mdxaCompBone_t& _X) const {return (memcmp(Comp,_X.Comp,sizeof(Comp))<0);}
#endif
}
#ifndef __cplusplus
mdxaCompBone_t
#endif
;
*/
#ifdef __cplusplus
struct mdxaCompQuatBone_t
#else
typedef struct
#endif
{
unsigned char Comp[14];
// I'm defining this '<' operator so this struct can be used as an STL <map> key...
//
#ifdef __cplusplus
bool operator < (const mdxaCompQuatBone_t& _X) const {return (memcmp(Comp,_X.Comp,sizeof(Comp))<0);}
#endif
}
#ifndef __cplusplus
mdxaCompQuatBone_t
#endif
;
#ifndef MDXABONEDEF
typedef struct {
float matrix[3][4];
} mdxaBone_t;
#endif
////////////////////////////////////
// mdxHeader_t - this contains the header for the file, with sanity checking and version checking, plus number of lod's to be expected
//
typedef struct {
//
// ( first 3 fields are same format as MD3/MDR so we can apply easy model-format-type checks )
//
int ident; // "IDP3" = MD3, "RDM5" = MDR, "2LGM"(GL2 Mesh) = MDX (cruddy char order I know, but I'm following what was there in other versions)
int version; // 1,2,3 etc as per format revision
char name[MAX_QPATH]; // model name (eg "models/players/marine.glm") // note: extension supplied
char animName[MAX_QPATH];// name of animation file this mesh requires // note: extension missing
int animIndex; // filled in by game (carcass defaults it to 0)
int numBones; // (for ingame version-checks only, ensure we don't ref more bones than skel file has)
int numLODs;
int ofsLODs;
int numSurfaces; // now that surfaces are drawn hierarchically, we have same # per LOD
int ofsSurfHierarchy;
int ofsEnd; // EOF, which of course gives overall file size
} mdxmHeader_t;
// for each surface (doesn't actually need a struct for this, just makes source clearer)
// {
typedef struct
{
int offsets[1]; // variable sized (mdxmHeader_t->numSurfaces), each offset points to a mdxmSurfHierarchy_t below
} mdxmHierarchyOffsets_t;
// }
// for each surface... (mdxmHeader_t->numSurfaces)
// {
// mdxmSurfHierarchy_t - contains hierarchical info for surfaces...
typedef struct {
char name[MAX_QPATH];
unsigned int flags;
char shader[MAX_QPATH];
int shaderIndex; // for in-game use (carcass defaults to 0)
int parentIndex; // this points to the index in the file of the parent surface. -1 if null/root
int numChildren; // number of surfaces which are children of this one
int childIndexes[1]; // [mdxmSurfHierarch_t->numChildren] (variable sized)
} mdxmSurfHierarchy_t; // struct size = (int)( &((mdxmSurfHierarch_t *)0)->childIndexes[ mdxmSurfHierarch_t->numChildren ] );
// }
// for each LOD... (mdxmHeader_t->numLODs)
// {
// mdxLOD_t - this contains the header for this LOD. Contains num of surfaces, offset to surfaces and offset to next LOD. Surfaces are shader sorted, so each surface = 1 shader
typedef struct {
// (used to contain numSurface/ofsSurfaces fields, but these are same per LOD level now)
//
int ofsEnd; // offset to next LOD
} mdxmLOD_t;
typedef struct { // added in GLM version 3 for ingame use at Jake's request
int offsets[1]; // variable sized (mdxmHeader_t->numSurfaces), each offset points to surfaces below
} mdxmLODSurfOffset_t;
// for each surface... (mdxmHeader_t->numSurfaces)
// {
// mdxSurface_t - reuse of header format containing surface name, number of bones, offset to poly data and number of polys, offset to vertex information, and number of verts. NOTE offsets are relative to this header.
typedef struct {
int ident; // this one field at least should be kept, since the game-engine may switch-case (but currently=0 in carcass)
int thisSurfaceIndex; // 0...mdxmHeader_t->numSurfaces-1 (because of how ingame renderer works)
int ofsHeader; // this will be a negative number, pointing back to main header
int numVerts;
int ofsVerts;
int numTriangles;
int ofsTriangles;
// Bone references are a set of ints representing all the bones
// present in any vertex weights for this surface. This is
// needed because a model may have surfaces that need to be
// drawn at different sort times, and we don't want to have
// to re-interpolate all the bones for each surface.
//
int numBoneReferences;
int ofsBoneReferences;
int ofsEnd; // next surface follows
} mdxmSurface_t;
// for each triangle... (mdxmSurface_t->numTriangles)
// {
// mdxTriangle_t - contains indexes into verts. One struct entry per poly.
typedef struct {
int indexes[3];
} mdxmTriangle_t;
// }
// for each vert... (mdxmSurface_t->numVerts)
// {
// mdxVertex_t - this is an array with number of verts from the surface definition as its bounds. It contains normal info, texture coors and number of weightings for this bone
// (this is now kept at 32 bytes for cache-aligning)
typedef struct {
#ifdef _XBOX
//short normal[3];
unsigned int normal;
short vertCoords[3];
unsigned int tangent;
#else
vec3_t normal;
vec3_t vertCoords;
#endif
// packed int...
unsigned int uiNmWeightsAndBoneIndexes; // 32 bits. format:
// 31 & 30: 0..3 (= 1..4) weight count
// 29 & 28 (spare)
// 2 bit pairs at 20,22,24,26 are 2-bit overflows from 4 BonWeights below (20=[0], 22=[1]) etc)
// 5-bits each (iG2_BITS_PER_BONEREF) for boneweights
// effectively a packed int, each bone weight converted from 0..1 float to 0..255 int...
// promote each entry to float and multiply by fG2_BONEWEIGHT_RECIPROCAL_MULT to convert.
byte BoneWeightings[iMAX_G2_BONEWEIGHTS_PER_VERT]; // 4
} mdxmVertex_t;
// } vert
#ifdef __cplusplus
// these are convenience functions that I can invoked in code. Do NOT change them (because this is a shared file),
// but if you want to copy the logic out and use your own versions then fine...
//
static inline int G2_GetVertWeights( const mdxmVertex_t *pVert )
{
int iNumWeights = (pVert->uiNmWeightsAndBoneIndexes >> 30)+1; // 1..4 count
return iNumWeights;
}
static inline int G2_GetVertBoneIndex( const mdxmVertex_t *pVert, const int iWeightNum)
{
int iBoneIndex = (pVert->uiNmWeightsAndBoneIndexes>>(iG2_BITS_PER_BONEREF*iWeightNum))&((1<<iG2_BITS_PER_BONEREF)-1);
return iBoneIndex;
}
static inline float G2_GetVertBoneWeight( const mdxmVertex_t *pVert, const int iWeightNum, float &fTotalWeight, int iNumWeights )
{
float fBoneWeight;
if (iWeightNum == iNumWeights-1)
{
fBoneWeight = 1.0f-fTotalWeight;
}
else
{
int iTemp = pVert->BoneWeightings[iWeightNum];
iTemp|= (pVert->uiNmWeightsAndBoneIndexes >> (iG2_BONEWEIGHT_TOPBITS_SHIFT+(iWeightNum*2)) ) & iG2_BONEWEIGHT_TOPBITS_AND;
fBoneWeight = fG2_BONEWEIGHT_RECIPROCAL_MULT * iTemp;
fTotalWeight += fBoneWeight;
}
return fBoneWeight;
}
#endif
// for each vert... (mdxmSurface_t->numVerts) (seperated from mdxmVertex_t struct for cache reasons)
// {
// mdxVertex_t - this is an array with number of verts from the surface definition as its bounds. It contains normal info, texture coors and number of weightings for this bone
typedef struct {
#ifdef _XBOX
short texCoords[2];
#else
vec2_t texCoords;
#endif
} mdxmVertexTexCoord_t;
// } vert
// } surface
// } LOD
//----------------------------------------------------------------------------
// seperate file here for animation data...
//
// mdxaHeader_t - this contains the header for the file, with sanity checking and version checking, plus number of lod's to be expected
//
typedef struct {
//
// ( first 3 fields are same format as MD3/MDR so we can apply easy model-format-type checks )
//
int ident; // "IDP3" = MD3, "RDM5" = MDR, "2LGA"(GL2 Anim) = MDXA
int version; // 1,2,3 etc as per format revision
//
char name[MAX_QPATH]; // GLA name (eg "skeletons/marine") // note: extension missing
float fScale; // will be zero if build before this field was defined, else scale it was built with
// frames and bones are shared by all levels of detail
//
int numFrames;
int ofsFrames; // points at mdxaFrame_t array
int numBones; // (no offset to these since they're inside the frames array)
int ofsCompBonePool; // offset to global compressed-bone pool that all frames use
int ofsSkel; // offset to mdxaSkel_t info
int ofsEnd; // EOF, which of course gives overall file size
} mdxaHeader_t;
// for each bone... (doesn't actually need a struct for this, just makes source clearer)
// {
typedef struct
{
int offsets[1]; // variable sized (mdxaHeader_t->numBones), each offset points to an mdxaSkel_t below
} mdxaSkelOffsets_t;
// }
// for each bone... (mdxaHeader_t->numBones)
// {
// mdxaSkel_t - contains hierarchical info only...
typedef struct {
char name[MAX_QPATH]; // name of bone
unsigned int flags;
int parent; // index of bone that is parent to this one, -1 = NULL/root
mdxaBone_t BasePoseMat; // base pose
mdxaBone_t BasePoseMatInv; // inverse, to save run-time calc
int numChildren; // number of children bones
int children[1]; // [mdxaSkel_t->numChildren] (variable sized)
} mdxaSkel_t; // struct size = (int)( &((mdxaSkel_t *)0)->children[ mdxaSkel_t->numChildren ] );
// }
// (offset @ mdxaHeader_t->ofsFrames)
//
// array of 3 byte indices here (hey, 25% saving over 4-byte really adds up)...
//
//
// access as follows to get the index for a given <iFrameNum, iBoneNum>
//
// (iFrameNum * mdxaHeader_t->numBones * 3) + (iBoneNum * 3)
//
// then read the int at that location and AND it with 0x00FFFFFF. I use the struct below simply for easy searches
typedef struct
{
int iIndex; // this struct for pointing purposes, need to and with 0x00FFFFFF to be meaningful
} mdxaIndex_t;
//
// (note that there's then an alignement-pad here to get the next struct back onto 32-bit alignement)
//
// this index then points into the following...
// Compressed-bone pool that all frames use (mdxaHeader_t->ofsCompBonePool) (defined at end because size unknown until end)
// for each bone in pool (unknown number, no actual total stored at the moment)...
// {
// mdxaCompBone_t (defined at file top because of struct dependancy)
// }
//---------------------------------------------------------------------------
#endif // #ifndef MDX_FORMAT_H
//////////////////////// eof ///////////////////////

310
codemp/renderer/modelmem.h Normal file
View File

@@ -0,0 +1,310 @@
//
// ModelMem.h
//
// OK, here's the deal with this class...
// At game initialization time, this class sets aside a certain amount of memory
// strictly for use by player models. 6 of these slots are of the size of the
// largest jedi player model, and the other 6 are of the size of the largest
// non-jedi player model (since there are only 6 jedi_xx models). Whenever a
// player model is allocated/deallocated, it uses only the memory that is managed
// by this class. This is done to reduce memory fragmentation that would
// normally occour when many players join and leave a multiplayer game.
// Only the first 8 slots are allocated at first (only 8 players in a normal
// multiplayer game), with the other 4 being allocated only if a connection
// to a dedicated server is detected.
//#define MAX_MODEL_JEDI_SIZE 786740 //Amount used for UI slot.
#define MAX_MODEL_SLOTS 11
#include "../client/cl_data.h"
#include "../renderer/qgl_console.h"
extern void RE_RemoveModelFromHash(const char *name);
extern int uiClientNum;
typedef struct modelSlot_s
{
void *memory;
int allocatedSize;
bool inUse;
int modelID;
// int refCount;
char name[64];
}modelSlot_t;
class ModelMemoryManager
{
modelSlot_s modelSlot[MAX_MODEL_SLOTS];
int numUsedSlots;
bool NPCMode;
private:
void FreeModelSlot(int index)
{
assert(index >=0 && index < MAX_MODEL_SLOTS);
if(modelSlot[index].memory) {
HeapFree(GetProcessHeap(), 0, modelSlot[index].memory);
numUsedSlots--;
}
memset(&modelSlot[index], 0, sizeof(modelSlot[index]));
assert(numUsedSlots >= 0);
}
void AllocateModelSlot(int index, int size, int ID, const char *name)
{
assert(index >=0 && index < MAX_MODEL_SLOTS);
if(modelSlot[index].memory) {
FreeModelSlot(index);
}
modelSlot[index].memory = HeapAlloc(GetProcessHeap(), 0, size);
if(!modelSlot[index].memory) {
assert(0);
//Something used all our heap memory. That's bad. Make the
//screen green.
Com_PrintfAlways("Model manager out of memory trying to allocate %d bytes for %s\n", size, name);
for (;;)
{
qglBeginFrame();
qglClearColor(0, 1, 0, 1);
qglClear(GL_COLOR_BUFFER_BIT);
qglEndFrame();
}
}
modelSlot[index].allocatedSize = size;
modelSlot[index].inUse = true;
modelSlot[index].modelID = ID;
// modelSlot[index].refCount = 1;
strcpy(modelSlot[index].name, name);
numUsedSlots++;
assert(numUsedSlots <= MAX_MODEL_SLOTS);
}
public:
char uiName[64];
char uiSkin[64];
ModelMemoryManager(void)
{
memset(modelSlot, 0, sizeof(modelSlot[0]) * MAX_MODEL_SLOTS);
uiName[0] = 0;
uiSkin[0] = 0;
}
void AllocateModelSlots()
{
numUsedSlots = 0;
}
void SetNPCMode(bool npcMode)
{
NPCMode = npcMode;
}
bool IsNPCMode()
{
return NPCMode;
}
void* GetModelMemory(int size, int ID, const char *name)
{
// Find the first non-used slot with enough memory
// Work backwards to try and use smaller slots first
for(int i = 0; i < MAX_MODEL_SLOTS; i++)
{
if((strcmp(name, modelSlot[i].name) == 0) && modelSlot[i].inUse == true)
{
// The only time this will happen is if there is a holdover model
// left from the UI - so don't increase the refcount
return modelSlot[i].memory;
}
}
// No slot found, so scan thru the client info to see if a slot can be killed
bool bFound;
for(i = 0; i < MAX_MODEL_SLOTS; i++)
{
// The server NEVER throws out kyle
if(com_sv_running->integer && !strcmp(modelSlot[i].name, "models/players/kyle/model.glm"))
continue;
bFound = false;
for(int j = 0; j < cgs.maxclients; j++)
{
if(strlen(cgs.clientinfo[j].modelName))
{
if(!strcmp(modelSlot[i].name, va("models/players/%s/model.glm", cgs.clientinfo[j].modelName)))
{
bFound = true;
break;
}
}
}
if(strlen(uiName) && !strcmp(modelSlot[i].name, uiName))
bFound = true;
if(!bFound && modelSlot[i].inUse)
{
// This model slot is not listed in the clientinfo, kill it
RE_RemoveModelFromHash(modelSlot[i].name);
FreeModelSlot(i);
}
}
for(i = 0; i < MAX_MODEL_SLOTS; i++)
{
if(modelSlot[i].inUse == false)
{
AllocateModelSlot(i, size, ID, name);
return modelSlot[i].memory;
}
}
// Something horrible happened if we got here. All model slots are
// in use by active clients and we're trying to allocate another
// one. Find out why and prevent that.
assert(0);
// Make some debug spew with the hopes of finding the problem if it
// gets to QA.
Com_PrintfAlways("Hi, I'm about to crash. Here's why. I was told \
to allocate memory for a new model: %s. But all my model \
slots are already in use. Here's what's using them. Good \
luck!\n\n", name);
for(i=0; i<MAX_MODEL_SLOTS; i++) {
if(modelSlot[i].inUse) {
Com_PrintfAlways("%s\n", modelSlot[i].name);
}
}
Com_PrintfAlways("\nI'm done spewing now. Any future messages didn't \
come from the model manager. Verbose messages are fun!\n");
return NULL;
}
/*
void ModelAddRef(const char *name)
{
for(int i = 0; i < MAX_MODEL_SLOTS; i++)
{
if(strcmp(modelSlot[i].name, name) == 0)
modelSlot[i].refCount++;
}
}
*/
/*
void FreeModelMemory(int ID)
{
for(int i = 0; i < MAX_MODEL_SLOTS; i++)
{
if(modelSlot[i].modelID == ID && modelSlot[i].inUse == true)
{
modelSlot[i].refCount--;
if( modelSlot[i].refCount < 0 )
Com_Error( ERR_DROP, "FreeModelMemory by ID: refCount is negative" );
if(modelSlot[i].refCount < 1)
{
RE_RemoveModelFromHash(modelSlot[i].name);
FreeModelSlot(i);
}
}
}
}
*/
void FreeModelMemory(const char *name)
{
for(int i = 0; i < MAX_MODEL_SLOTS; i++)
{
if((strcmp(name, modelSlot[i].name) == 0) && modelSlot[i].inUse == true)
{
int timesFound = 0;
for( int j = 0; j < cgs.maxclients; ++j )
if(!strcmp(modelSlot[i].name, va("models/players/%s/model.glm", cgs.clientinfo[j].modelName)))
timesFound++;
if( !strcmp(modelSlot[i].name, uiName) )
timesFound++;
if( com_sv_running->integer && !strcmp(modelSlot[i].name, "models/players/kyle/model.glm") )
timesFound++;
if( !timesFound )
Com_Error( ERR_DROP, "FreeModelMemory by name: refCount is negative" );
if( timesFound == 1 )
{
RE_RemoveModelFromHash(name);
FreeModelSlot(i);
}
}
}
}
// Returns a bool to indicate whether or not an erase was done on the map<>
bool ClearModelMemory(int ID)
{
bool bRemovedFromHash = false;
for(int i = 0; i < MAX_MODEL_SLOTS; i++)
{
if(modelSlot[i].modelID == ID && modelSlot[i].inUse == true)
{
RE_RemoveModelFromHash(modelSlot[i].name);
FreeModelSlot(i);
bRemovedFromHash = true;
}
}
return bRemovedFromHash;
}
void SetUIName( const char *name )
{
if( name )
strcpy( uiName, name );
else
uiName[0] = 0;
}
void SetUISkin( const char *name )
{
if( name )
strcpy( uiSkin, name );
else
uiSkin[0] = 0;
}
const char *GetUISkin( void )
{
return uiSkin;
}
void ClearAll()
{
for(int i = 0; i < MAX_MODEL_SLOTS; i++)
{
FreeModelSlot(i);
}
numUsedSlots = 0;
uiName[0] = 0;
uiSkin[0] = 0;
}
};
extern ModelMemoryManager ModelMem;

757
codemp/renderer/qgl.h Normal file
View File

@@ -0,0 +1,757 @@
/*
** QGL.H
*/
#ifndef __QGL_H__
#define __QGL_H__
#if defined( __LINT__ )
#include <GL/gl.h>
#elif defined( _WIN32 )
#pragma warning (disable: 4201)
#pragma warning (disable: 4214)
#pragma warning (disable: 4514)
#pragma warning (disable: 4032)
#pragma warning (disable: 4201)
#pragma warning (disable: 4214)
#include <windows.h>
#include <gl/gl.h>
#elif defined(MACOS_X)
#include "macosx_glimp.h"
#elif defined( __linux__ )
#include <GL/gl.h>
#include <GL/glx.h>
// bk001129 - from cvs1.17 (mkv)
#if defined(__FX__)
#include <GL/fxmesa.h>
#endif
#elif defined( __FreeBSD__ ) // rb010123
#include <GL/gl.h>
#include <GL/glx.h>
#if defined(__FX__)
#include <GL/fxmesa.h>
#endif
#else
#include <gl.h>
#endif
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef WINAPI
#define WINAPI
#endif
//===========================================================================
/*
** multitexture extension definitions
*/
#define GL_ACTIVE_TEXTURE_ARB 0x84E0
#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1
#define GL_MAX_ACTIVE_TEXTURES_ARB 0x84E2
#define GL_TEXTURE0_ARB 0x84C0
#define GL_TEXTURE1_ARB 0x84C1
#define GL_TEXTURE2_ARB 0x84C2
#define GL_TEXTURE3_ARB 0x84C3
#define GL_TEXTURE_RECTANGLE_EXT 0x84F5
// TTimo: FIXME
// linux needs those prototypes
// GL_VERSION_1_2 is defined after #include <gl.h>
#if !defined(GL_VERSION_1_2) || defined(__linux__)
typedef void (APIENTRY * PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
typedef void (APIENTRY * PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
typedef void (APIENTRY * PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
typedef void (APIENTRY * PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
typedef void (APIENTRY * PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
typedef void (APIENTRY * PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
typedef void (APIENTRY * PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
typedef void (APIENTRY * PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
typedef void (APIENTRY * PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
typedef void (APIENTRY * PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
typedef void (APIENTRY * PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
typedef void (APIENTRY * PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
typedef void (APIENTRY * PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
typedef void (APIENTRY * PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
typedef void (APIENTRY * PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
typedef void (APIENTRY * PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRY * PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
typedef void (APIENTRY * PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum target);
typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum target);
#endif
// Steps to adding a new extension:
// - Add the typedef and function pointer externs here.
// - Define the function pointer in tr_init.cpp and possibly add a cvar to track your ext status.
// - Load the extension in win_glimp.cpp.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Register Combiner extension definitions. - AReis
/***********************************************************************************************************/
// NOTE: These are obviously not all the regcom flags. I'm only including the ones I use (to reduce code clutter), so
// if you need any of the other flags, just add them.
#define GL_REGISTER_COMBINERS_NV 0x8522
#define GL_COMBINER0_NV 0x8550
#define GL_COMBINER1_NV 0x8551
#define GL_COMBINER2_NV 0x8552
#define GL_COMBINER3_NV 0x8553
#define GL_COMBINER4_NV 0x8554
#define GL_COMBINER5_NV 0x8555
#define GL_COMBINER6_NV 0x8556
#define GL_COMBINER7_NV 0x8557
#define GL_NUM_GENERAL_COMBINERS_NV 0x854E
#define GL_VARIABLE_A_NV 0x8523
#define GL_VARIABLE_B_NV 0x8524
#define GL_VARIABLE_C_NV 0x8525
#define GL_VARIABLE_D_NV 0x8526
#define GL_VARIABLE_E_NV 0x8527
#define GL_VARIABLE_F_NV 0x8528
#define GL_VARIABLE_G_NV 0x8529
#define GL_DISCARD_NV 0x8530
#define GL_CONSTANT_COLOR0_NV 0x852A
#define GL_CONSTANT_COLOR1_NV 0x852B
#define GL_SPARE0_NV 0x852E
#define GL_SPARE1_NV 0x852F
#define GL_UNSIGNED_IDENTITY_NV 0x8536
#define GL_UNSIGNED_INVERT_NV 0x8537
typedef void (APIENTRY *PFNGLCOMBINERPARAMETERFVNV) (GLenum pname,const GLfloat *params);
typedef void (APIENTRY *PFNGLCOMBINERPARAMETERIVNV) (GLenum pname,const GLint *params);
typedef void (APIENTRY *PFNGLCOMBINERPARAMETERFNV) (GLenum pname,GLfloat param);
typedef void (APIENTRY *PFNGLCOMBINERPARAMETERINV) (GLenum pname,GLint param);
typedef void (APIENTRY *PFNGLCOMBINERINPUTNV) (GLenum stage,GLenum portion,GLenum variable,GLenum input,GLenum mapping,
GLenum componentUsage);
typedef void (APIENTRY *PFNGLCOMBINEROUTPUTNV) (GLenum stage,GLenum portion,GLenum abOutput,GLenum cdOutput,GLenum sumOutput,
GLenum scale, GLenum bias,GLboolean abDotProduct,GLboolean cdDotProduct,
GLboolean muxSum);
typedef void (APIENTRY *PFNGLFINALCOMBINERINPUTNV) (GLenum variable,GLenum input,GLenum mapping,GLenum componentUsage);
typedef void (APIENTRY *PFNGLGETCOMBINERINPUTPARAMETERFVNV) (GLenum stage,GLenum portion,GLenum variable,GLenum pname,GLfloat *params);
typedef void (APIENTRY *PFNGLGETCOMBINERINPUTPARAMETERIVNV) (GLenum stage,GLenum portion,GLenum variable,GLenum pname,GLint *params);
typedef void (APIENTRY *PFNGLGETCOMBINEROUTPUTPARAMETERFVNV) (GLenum stage,GLenum portion,GLenum pname,GLfloat *params);
typedef void (APIENTRY *PFNGLGETCOMBINEROUTPUTPARAMETERIVNV) (GLenum stage,GLenum portion,GLenum pname,GLint *params);
typedef void (APIENTRY *PFNGLGETFINALCOMBINERINPUTPARAMETERFVNV) (GLenum variable,GLenum pname,GLfloat *params);
typedef void (APIENTRY *PFNGLGETFINALCOMBINERINPUTPARAMETERIVNV) (GLenum variable,GLenum pname,GLfloat *params);
/***********************************************************************************************************/
// Declare Register Combiners function pointers.
extern PFNGLCOMBINERPARAMETERFVNV qglCombinerParameterfvNV;
extern PFNGLCOMBINERPARAMETERIVNV qglCombinerParameterivNV;
extern PFNGLCOMBINERPARAMETERFNV qglCombinerParameterfNV;
extern PFNGLCOMBINERPARAMETERINV qglCombinerParameteriNV;
extern PFNGLCOMBINERINPUTNV qglCombinerInputNV;
extern PFNGLCOMBINEROUTPUTNV qglCombinerOutputNV;
extern PFNGLFINALCOMBINERINPUTNV qglFinalCombinerInputNV;
extern PFNGLGETCOMBINERINPUTPARAMETERFVNV qglGetCombinerInputParameterfvNV;
extern PFNGLGETCOMBINERINPUTPARAMETERIVNV qglGetCombinerInputParameterivNV;
extern PFNGLGETCOMBINEROUTPUTPARAMETERFVNV qglGetCombinerOutputParameterfvNV;
extern PFNGLGETCOMBINEROUTPUTPARAMETERIVNV qglGetCombinerOutputParameterivNV;
extern PFNGLGETFINALCOMBINERINPUTPARAMETERFVNV qglGetFinalCombinerInputParameterfvNV;
extern PFNGLGETFINALCOMBINERINPUTPARAMETERIVNV qglGetFinalCombinerInputParameterivNV;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Pixel Format extension definitions. - AReis
/***********************************************************************************************************/
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_ALPHA_BITS_ARB 0x201B
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
/***********************************************************************************************************/
// Declare Pixel Format function pointers.
extern PFNWGLGETPIXELFORMATATTRIBIVARBPROC qwglGetPixelFormatAttribivARB;
extern PFNWGLGETPIXELFORMATATTRIBFVARBPROC qwglGetPixelFormatAttribfvARB;
extern PFNWGLCHOOSEPIXELFORMATARBPROC qwglChoosePixelFormatARB;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Pixel Buffer extension definitions. - AReis
/***********************************************************************************************************/
DECLARE_HANDLE(HPBUFFERARB);
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_DRAW_TO_PBUFFER_ARB 0x202D
#define WGL_PBUFFER_WIDTH_ARB 0x2034
#define WGL_PBUFFER_HEIGHT_ARB 0x2035
#define WGL_RED_BITS_ARB 0x2015
#define WGL_GREEN_BITS_ARB 0x2017
#define WGL_BLUE_BITS_ARB 0x2019
typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer);
typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC);
typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer);
typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue);
/***********************************************************************************************************/
// Declare Pixel Buffer function pointers.
extern PFNWGLCREATEPBUFFERARBPROC qwglCreatePbufferARB;
extern PFNWGLGETPBUFFERDCARBPROC qwglGetPbufferDCARB;
extern PFNWGLRELEASEPBUFFERDCARBPROC qwglReleasePbufferDCARB;
extern PFNWGLDESTROYPBUFFERARBPROC qwglDestroyPbufferARB;
extern PFNWGLQUERYPBUFFERARBPROC qwglQueryPbufferARB;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Render-Texture extension definitions. - AReis
/***********************************************************************************************************/
#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071
#define WGL_TEXTURE_FORMAT_ARB 0x2072
#define WGL_TEXTURE_TARGET_ARB 0x2073
#define WGL_TEXTURE_RGB_ARB 0x2075
#define WGL_TEXTURE_RGBA_ARB 0x2076
#define WGL_TEXTURE_2D_ARB 0x207A
#define WGL_FRONT_LEFT_ARB 0x2083
typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);
typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);
typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int * piAttribList);
/***********************************************************************************************************/
// Declare Render-Texture function pointers.
extern PFNWGLBINDTEXIMAGEARBPROC qwglBindTexImageARB;
extern PFNWGLRELEASETEXIMAGEARBPROC qwglReleaseTexImageARB;
extern PFNWGLSETPBUFFERATTRIBARBPROC qwglSetPbufferAttribARB;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Vertex and Fragment Program extension definitions. - AReis
/***********************************************************************************************************/
#ifndef GL_ARB_fragment_program
#define GL_FRAGMENT_PROGRAM_ARB 0x8804
#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805
#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806
#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807
#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808
#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809
#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A
#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B
#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C
#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D
#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E
#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F
#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810
#define GL_MAX_TEXTURE_COORDS_ARB 0x8871
#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872
#endif
// NOTE: These are obviously not all the vertex program flags (have you seen how many there actually are!). I'm
// only including the ones I use (to reduce code clutter), so if you need any of the other flags, just add them.
#define GL_VERTEX_PROGRAM_ARB 0x8620
#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875
typedef void (APIENTRY * PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string);
typedef void (APIENTRY * PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
typedef void (APIENTRY * PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
typedef void (APIENTRY * PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
typedef void (APIENTRY * PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRY * PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
typedef void (APIENTRY * PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (APIENTRY * PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
typedef void (APIENTRY * PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRY * PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
typedef void (APIENTRY * PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (APIENTRY * PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
typedef void (APIENTRY * PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
typedef void (APIENTRY * PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
typedef void (APIENTRY * PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
typedef void (APIENTRY * PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
typedef void (APIENTRY * PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRY * PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string);
typedef GLboolean (APIENTRY * PFNGLISPROGRAMARBPROC) (GLuint program);
/***********************************************************************************************************/
// Declare Vertex and Fragment Program function pointers.
extern PFNGLPROGRAMSTRINGARBPROC qglProgramStringARB;
extern PFNGLBINDPROGRAMARBPROC qglBindProgramARB;
extern PFNGLDELETEPROGRAMSARBPROC qglDeleteProgramsARB;
extern PFNGLGENPROGRAMSARBPROC qglGenProgramsARB;
extern PFNGLPROGRAMENVPARAMETER4DARBPROC qglProgramEnvParameter4dARB;
extern PFNGLPROGRAMENVPARAMETER4DVARBPROC qglProgramEnvParameter4dvARB;
extern PFNGLPROGRAMENVPARAMETER4FARBPROC qglProgramEnvParameter4fARB;
extern PFNGLPROGRAMENVPARAMETER4FVARBPROC qglProgramEnvParameter4fvARB;
extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC qglProgramLocalParameter4dARB;
extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC qglProgramLocalParameter4dvARB;
extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC qglProgramLocalParameter4fARB;
extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC qglProgramLocalParameter4fvARB;
extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC qglGetProgramEnvParameterdvARB;
extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC qglGetProgramEnvParameterfvARB;
extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC qglGetProgramLocalParameterdvARB;
extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC qglGetProgramLocalParameterfvARB;
extern PFNGLGETPROGRAMIVARBPROC qglGetProgramivARB;
extern PFNGLGETPROGRAMSTRINGARBPROC qglGetProgramStringARB;
extern PFNGLISPROGRAMARBPROC qglIsProgramARB;
/*
** extension constants
*/
// S3TC compression constants
#define GL_RGB_S3TC 0x83A0
#define GL_RGB4_S3TC 0x83A1
// extensions will be function pointers on all platforms
extern void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t );
extern void ( APIENTRY * qglActiveTextureARB )( GLenum texture );
extern void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture );
extern void ( APIENTRY * qglLockArraysEXT) (GLint, GLint);
extern void ( APIENTRY * qglUnlockArraysEXT) (void);
extern void ( APIENTRY * qglPointParameterfEXT)( GLenum, GLfloat);
extern void ( APIENTRY * qglPointParameterfvEXT)( GLenum, GLfloat *);
//3d textures -rww
extern void ( APIENTRY * qglTexImage3DEXT) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
extern void ( APIENTRY * qglTexSubImage3DEXT) (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
//===========================================================================
// non-windows systems will just redefine qgl* to gl*
#if !defined( _WIN32 ) && !defined(MACOS_X) && !defined( __linux__ ) && !defined( __FreeBSD__ ) // rb010123
#include "qgl_linked.h"
#elif defined(MACOS_X)
// This includes #ifdefs for optional logging and GL error checking after every GL call as well as #defines to prevent incorrect usage of the non-'qgl' versions of the GL API.
#include "macosx_qgl.h"
#else
// windows systems use a function pointer for each call so we can load minidrivers
extern void ( APIENTRY * qglAccum )(GLenum op, GLfloat value);
extern void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref);
extern GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences);
extern void ( APIENTRY * qglArrayElement )(GLint i);
extern void ( APIENTRY * qglBegin )(GLenum mode);
extern void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture);
extern void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
extern void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor);
extern void ( APIENTRY * qglCallList )(GLuint list);
extern void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists);
extern void ( APIENTRY * qglClear )(GLbitfield mask);
extern void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
extern void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
extern void ( APIENTRY * qglClearDepth )(GLclampd depth);
extern void ( APIENTRY * qglClearIndex )(GLfloat c);
extern void ( APIENTRY * qglClearStencil )(GLint s);
extern void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation);
extern void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue);
extern void ( APIENTRY * qglColor3bv )(const GLbyte *v);
extern void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue);
extern void ( APIENTRY * qglColor3dv )(const GLdouble *v);
extern void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue);
extern void ( APIENTRY * qglColor3fv )(const GLfloat *v);
extern void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue);
extern void ( APIENTRY * qglColor3iv )(const GLint *v);
extern void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue);
extern void ( APIENTRY * qglColor3sv )(const GLshort *v);
extern void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue);
extern void ( APIENTRY * qglColor3ubv )(const GLubyte *v);
extern void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue);
extern void ( APIENTRY * qglColor3uiv )(const GLuint *v);
extern void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue);
extern void ( APIENTRY * qglColor3usv )(const GLushort *v);
extern void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
extern void ( APIENTRY * qglColor4bv )(const GLbyte *v);
extern void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
extern void ( APIENTRY * qglColor4dv )(const GLdouble *v);
extern void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
extern void ( APIENTRY * qglColor4fv )(const GLfloat *v);
extern void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha);
extern void ( APIENTRY * qglColor4iv )(const GLint *v);
extern void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha);
extern void ( APIENTRY * qglColor4sv )(const GLshort *v);
extern void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
extern void ( APIENTRY * qglColor4ubv )(const GLubyte *v);
extern void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha);
extern void ( APIENTRY * qglColor4uiv )(const GLuint *v);
extern void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha);
extern void ( APIENTRY * qglColor4usv )(const GLushort *v);
extern void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
extern void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode);
extern void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
extern void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
extern void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
extern void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
extern void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
extern void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
extern void ( APIENTRY * qglCullFace )(GLenum mode);
extern void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range);
extern void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures);
extern void ( APIENTRY * qglDepthFunc )(GLenum func);
extern void ( APIENTRY * qglDepthMask )(GLboolean flag);
extern void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar);
extern void ( APIENTRY * qglDisable )(GLenum cap);
extern void ( APIENTRY * qglDisableClientState )(GLenum array);
extern void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count);
extern void ( APIENTRY * qglDrawBuffer )(GLenum mode);
extern void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
extern void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
extern void ( APIENTRY * qglEdgeFlag )(GLboolean flag);
extern void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer);
extern void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag);
extern void ( APIENTRY * qglEnable )(GLenum cap);
extern void ( APIENTRY * qglEnableClientState )(GLenum array);
extern void ( APIENTRY * qglEnd )(void);
extern void ( APIENTRY * qglEndList )(void);
extern void ( APIENTRY * qglEvalCoord1d )(GLdouble u);
extern void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u);
extern void ( APIENTRY * qglEvalCoord1f )(GLfloat u);
extern void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u);
extern void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v);
extern void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u);
extern void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v);
extern void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u);
extern void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2);
extern void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
extern void ( APIENTRY * qglEvalPoint1 )(GLint i);
extern void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j);
extern void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer);
extern void ( APIENTRY * qglFinish )(void);
extern void ( APIENTRY * qglFlush )(void);
extern void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param);
extern void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params);
extern void ( APIENTRY * qglFogi )(GLenum pname, GLint param);
extern void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params);
extern void ( APIENTRY * qglFrontFace )(GLenum mode);
extern void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
extern GLuint ( APIENTRY * qglGenLists )(GLsizei range);
extern void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures);
extern void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params);
extern void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation);
extern void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params);
extern GLenum ( APIENTRY * qglGetError )(void);
extern void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params);
extern void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params);
extern void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params);
extern void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params);
extern void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v);
extern void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v);
extern void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v);
extern void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params);
extern void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params);
extern void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values);
extern void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values);
extern void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values);
extern void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params);
extern void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask);
extern const GLubyte * ( APIENTRY * qglGetString )(GLenum name);
extern void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params);
extern void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params);
extern void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params);
extern void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params);
extern void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params);
extern void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
extern void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params);
extern void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params);
extern void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params);
extern void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params);
extern void ( APIENTRY * qglHint )(GLenum target, GLenum mode);
extern void ( APIENTRY * qglIndexMask )(GLuint mask);
extern void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
extern void ( APIENTRY * qglIndexd )(GLdouble c);
extern void ( APIENTRY * qglIndexdv )(const GLdouble *c);
extern void ( APIENTRY * qglIndexf )(GLfloat c);
extern void ( APIENTRY * qglIndexfv )(const GLfloat *c);
extern void ( APIENTRY * qglIndexi )(GLint c);
extern void ( APIENTRY * qglIndexiv )(const GLint *c);
extern void ( APIENTRY * qglIndexs )(GLshort c);
extern void ( APIENTRY * qglIndexsv )(const GLshort *c);
extern void ( APIENTRY * qglIndexub )(GLubyte c);
extern void ( APIENTRY * qglIndexubv )(const GLubyte *c);
extern void ( APIENTRY * qglInitNames )(void);
extern void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer);
extern GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap);
extern GLboolean ( APIENTRY * qglIsList )(GLuint ilist);
extern GLboolean ( APIENTRY * qglIsTexture )(GLuint texture);
extern void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param);
extern void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params);
extern void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param);
extern void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params);
extern void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param);
extern void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params);
extern void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param);
extern void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params);
extern void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern);
extern void ( APIENTRY * qglLineWidth )(GLfloat width);
extern void ( APIENTRY * qglListBase )(GLuint base);
extern void ( APIENTRY * qglLoadIdentity )(void);
extern void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m);
extern void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m);
extern void ( APIENTRY * qglLoadName )(GLuint name);
extern void ( APIENTRY * qglLogicOp )(GLenum opcode);
extern void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
extern void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
extern void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
extern void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
extern void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2);
extern void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2);
extern void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);
extern void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);
extern void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param);
extern void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params);
extern void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param);
extern void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params);
extern void ( APIENTRY * qglMatrixMode )(GLenum mode);
extern void ( APIENTRY * qglMultMatrixd )(const GLdouble *m);
extern void ( APIENTRY * qglMultMatrixf )(const GLfloat *m);
extern void ( APIENTRY * qglNewList )(GLuint list, GLenum mode);
extern void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz);
extern void ( APIENTRY * qglNormal3bv )(const GLbyte *v);
extern void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz);
extern void ( APIENTRY * qglNormal3dv )(const GLdouble *v);
extern void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz);
extern void ( APIENTRY * qglNormal3fv )(const GLfloat *v);
extern void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz);
extern void ( APIENTRY * qglNormal3iv )(const GLint *v);
extern void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz);
extern void ( APIENTRY * qglNormal3sv )(const GLshort *v);
extern void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
extern void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
extern void ( APIENTRY * qglPassThrough )(GLfloat token);
extern void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values);
extern void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values);
extern void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values);
extern void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param);
extern void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param);
extern void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param);
extern void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param);
extern void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor);
extern void ( APIENTRY * qglPointSize )(GLfloat size);
extern void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode);
extern void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units);
extern void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask);
extern void ( APIENTRY * qglPopAttrib )(void);
extern void ( APIENTRY * qglPopClientAttrib )(void);
extern void ( APIENTRY * qglPopMatrix )(void);
extern void ( APIENTRY * qglPopName )(void);
extern void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities);
extern void ( APIENTRY * qglPushAttrib )(GLbitfield mask);
extern void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask);
extern void ( APIENTRY * qglPushMatrix )(void);
extern void ( APIENTRY * qglPushName )(GLuint name);
extern void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y);
extern void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v);
extern void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y);
extern void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v);
extern void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y);
extern void ( APIENTRY * qglRasterPos2iv )(const GLint *v);
extern void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y);
extern void ( APIENTRY * qglRasterPos2sv )(const GLshort *v);
extern void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z);
extern void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v);
extern void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z);
extern void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v);
extern void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z);
extern void ( APIENTRY * qglRasterPos3iv )(const GLint *v);
extern void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z);
extern void ( APIENTRY * qglRasterPos3sv )(const GLshort *v);
extern void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
extern void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v);
extern void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
extern void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v);
extern void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w);
extern void ( APIENTRY * qglRasterPos4iv )(const GLint *v);
extern void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w);
extern void ( APIENTRY * qglRasterPos4sv )(const GLshort *v);
extern void ( APIENTRY * qglReadBuffer )(GLenum mode);
extern void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
extern void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
extern void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2);
extern void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
extern void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2);
extern void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2);
extern void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2);
extern void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2);
extern void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2);
extern GLint ( APIENTRY * qglRenderMode )(GLenum mode);
extern void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
extern void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
extern void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z);
extern void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z);
extern void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height);
extern void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer);
extern void ( APIENTRY * qglShadeModel )(GLenum mode);
extern void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask);
extern void ( APIENTRY * qglStencilMask )(GLuint mask);
extern void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);
extern void ( APIENTRY * qglTexCoord1d )(GLdouble s);
extern void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v);
extern void ( APIENTRY * qglTexCoord1f )(GLfloat s);
extern void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v);
extern void ( APIENTRY * qglTexCoord1i )(GLint s);
extern void ( APIENTRY * qglTexCoord1iv )(const GLint *v);
extern void ( APIENTRY * qglTexCoord1s )(GLshort s);
extern void ( APIENTRY * qglTexCoord1sv )(const GLshort *v);
extern void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t);
extern void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v);
extern void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t);
extern void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v);
extern void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t);
extern void ( APIENTRY * qglTexCoord2iv )(const GLint *v);
extern void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t);
extern void ( APIENTRY * qglTexCoord2sv )(const GLshort *v);
extern void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r);
extern void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v);
extern void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r);
extern void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v);
extern void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r);
extern void ( APIENTRY * qglTexCoord3iv )(const GLint *v);
extern void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r);
extern void ( APIENTRY * qglTexCoord3sv )(const GLshort *v);
extern void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q);
extern void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v);
extern void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
extern void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v);
extern void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q);
extern void ( APIENTRY * qglTexCoord4iv )(const GLint *v);
extern void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q);
extern void ( APIENTRY * qglTexCoord4sv )(const GLshort *v);
extern void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
extern void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param);
extern void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params);
extern void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param);
extern void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params);
extern void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param);
extern void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params);
extern void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param);
extern void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params);
extern void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param);
extern void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params);
extern void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
extern void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
extern void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param);
extern void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);
extern void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param);
extern void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params);
extern void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
extern void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
extern void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z);
extern void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z);
extern void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y);
extern void ( APIENTRY * qglVertex2dv )(const GLdouble *v);
extern void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y);
extern void ( APIENTRY * qglVertex2fv )(const GLfloat *v);
extern void ( APIENTRY * qglVertex2i )(GLint x, GLint y);
extern void ( APIENTRY * qglVertex2iv )(const GLint *v);
extern void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y);
extern void ( APIENTRY * qglVertex2sv )(const GLshort *v);
extern void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z);
extern void ( APIENTRY * qglVertex3dv )(const GLdouble *v);
extern void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z);
extern void ( APIENTRY * qglVertex3fv )(const GLfloat *v);
extern void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z);
extern void ( APIENTRY * qglVertex3iv )(const GLint *v);
extern void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z);
extern void ( APIENTRY * qglVertex3sv )(const GLshort *v);
extern void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
extern void ( APIENTRY * qglVertex4dv )(const GLdouble *v);
extern void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
extern void ( APIENTRY * qglVertex4fv )(const GLfloat *v);
extern void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w);
extern void ( APIENTRY * qglVertex4iv )(const GLint *v);
extern void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w);
extern void ( APIENTRY * qglVertex4sv )(const GLshort *v);
extern void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
extern void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height);
#if defined( _WIN32 )
extern BOOL ( WINAPI * qwglCopyContext)(HGLRC, HGLRC, UINT);
extern HGLRC ( WINAPI * qwglCreateContext)(HDC);
extern HGLRC ( WINAPI * qwglCreateLayerContext)(HDC, int);
extern BOOL ( WINAPI * qwglDeleteContext)(HGLRC);
extern HGLRC ( WINAPI * qwglGetCurrentContext)(VOID);
extern HDC ( WINAPI * qwglGetCurrentDC)(VOID);
extern PROC ( WINAPI * qwglGetProcAddress)(LPCSTR);
extern BOOL ( WINAPI * qwglMakeCurrent)(HDC, HGLRC);
extern BOOL ( WINAPI * qwglShareLists)(HGLRC, HGLRC);
extern BOOL ( WINAPI * qwglUseFontBitmaps)(HDC, DWORD, DWORD, DWORD);
extern BOOL ( WINAPI * qwglUseFontOutlines)(HDC, DWORD, DWORD, DWORD, FLOAT,
FLOAT, int, LPGLYPHMETRICSFLOAT);
extern BOOL ( WINAPI * qwglDescribeLayerPlane)(HDC, int, int, UINT,
LPLAYERPLANEDESCRIPTOR);
extern int ( WINAPI * qwglSetLayerPaletteEntries)(HDC, int, int, int,
CONST COLORREF *);
extern int ( WINAPI * qwglGetLayerPaletteEntries)(HDC, int, int, int,
COLORREF *);
extern BOOL ( WINAPI * qwglRealizeLayerPalette)(HDC, int, BOOL);
extern BOOL ( WINAPI * qwglSwapLayerBuffers)(HDC, UINT);
extern BOOL ( WINAPI * qwglSwapIntervalEXT)( int interval );
#endif // _WIN32
#if ( (defined __linux__ ) || (defined __FreeBSD__ ) ) // rb010123
//FX Mesa Functions
// bk001129 - from cvs1.17 (mkv)
#if defined (__FX__)
extern fxMesaContext (*qfxMesaCreateContext)(GLuint win, GrScreenResolution_t, GrScreenRefresh_t, const GLint attribList[]);
extern fxMesaContext (*qfxMesaCreateBestContext)(GLuint win, GLint width, GLint height, const GLint attribList[]);
extern void (*qfxMesaDestroyContext)(fxMesaContext ctx);
extern void (*qfxMesaMakeCurrent)(fxMesaContext ctx);
extern fxMesaContext (*qfxMesaGetCurrentContext)(void);
extern void (*qfxMesaSwapBuffers)(void);
#endif
//GLX Functions
extern XVisualInfo * (*qglXChooseVisual)( Display *dpy, int screen, int *attribList );
extern GLXContext (*qglXCreateContext)( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct );
extern void (*qglXDestroyContext)( Display *dpy, GLXContext ctx );
extern Bool (*qglXMakeCurrent)( Display *dpy, GLXDrawable drawable, GLXContext ctx);
extern void (*qglXCopyContext)( Display *dpy, GLXContext src, GLXContext dst, GLuint mask );
extern void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable );
#endif // __linux__ || __FreeBSD__ // rb010123
#endif // _WIN32 && __linux__
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
#include "tr_local.h"
/*
All bones should be an identity orientation to display the mesh exactly
as it is specified.
For all other frames, the bones represent the transformation from the
orientation of the bone in the base frame to the orientation in this
frame.
*/

View File

@@ -0,0 +1,117 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
#include "tr_local.h"
#include "tr_worldeffects.h"
// Patches up the loaded map to handle the parameters passed from the UI
// Remap sky to contents of the cvar ar_sky
// Grab sunlight properties from the indirected sky
void R_RMGInit(void)
{
char newSky[MAX_QPATH];
char newFog[MAX_QPATH];
shader_t *sky;
shader_t *fog;
fog_t *gfog;
mgrid_t *grid;
char temp[MAX_QPATH];
int i;
unsigned short *pos;
Cvar_VariableStringBuffer("RMG_sky", newSky, MAX_QPATH);
// Get sunlight - this should set up all the sunlight data
sky = R_FindShader( newSky, lightmapsNone, stylesDefault, qfalse );
// Remap sky
R_RemapShader("textures/tools/_sky", newSky, NULL);
// Fill in the lightgrid with sunlight
if(tr.world->lightGridData)
{
#ifdef _XBOX
byte *memory = (byte *)tr.world->lightGridData;
byte *array;
array = memory;
memory += 3;
array[0] = (byte)Com_Clamp(0, 255, tr.sunAmbient[0] * 255.0f);
array[1] = (byte)Com_Clamp(0, 255, tr.sunAmbient[1] * 255.0f);
array[2] = (byte)Com_Clamp(0, 255, tr.sunAmbient[2] * 255.0f);
array[3] = (byte)Com_Clamp(0, 255, tr.sunLight[0]);
array[4] = (byte)Com_Clamp(0, 255, tr.sunLight[1]);
array[5] = (byte)Com_Clamp(0, 255, tr.sunLight[2]);
NormalToLatLong(tr.sunDirection, grid->latLong);
#else // _XBOX
grid = tr.world->lightGridData;
grid->ambientLight[0][0] = (byte)Com_Clampi(0, 255, tr.sunAmbient[0] * 255.0f);
grid->ambientLight[0][1] = (byte)Com_Clampi(0, 255, tr.sunAmbient[1] * 255.0f);
grid->ambientLight[0][2] = (byte)Com_Clampi(0, 255, tr.sunAmbient[2] * 255.0f);
R_ColorShiftLightingBytes(grid->ambientLight[0], grid->ambientLight[0]);
grid->directLight[0][0] = (byte)Com_Clampi(0, 255, tr.sunLight[0]);
grid->directLight[0][1] = (byte)Com_Clampi(0, 255, tr.sunLight[1]);
grid->directLight[0][2] = (byte)Com_Clampi(0, 255, tr.sunLight[2]);
R_ColorShiftLightingBytes(grid->directLight[0], grid->directLight[0]);
NormalToLatLong(tr.sunDirection, grid->latLong);
#endif // _XBOX
pos = tr.world->lightGridArray;
for(i=0;i<tr.world->numGridArrayElements;i++)
{
*pos = 0;
pos++;
}
}
// Override the global fog with the defined one
if(tr.world->globalFog != -1)
{
Cvar_VariableStringBuffer("RMG_fog", newFog, MAX_QPATH);
fog = R_FindShader( newFog, lightmapsNone, stylesDefault, qfalse);
if (fog != tr.defaultShader)
{
gfog = tr.world->fogs + tr.world->globalFog;
gfog->parms = *fog->fogParms;
if (gfog->parms.depthForOpaque)
{
gfog->tcScale = 1.0f / ( gfog->parms.depthForOpaque * 8.0f );
tr.distanceCull = gfog->parms.depthForOpaque;
tr.distanceCullSquared = tr.distanceCull * tr.distanceCull;
Cvar_Set("RMG_distancecull", va("%f", tr.distanceCull));
}
else
{
gfog->tcScale = 1.0f;
}
gfog->colorInt = ColorBytes4 ( gfog->parms.color[0],
gfog->parms.color[1],
gfog->parms.color[2], 1.0f );
}
}
Cvar_VariableStringBuffer("RMG_weather", temp, MAX_QPATH);
// Set up any weather effects
switch(atol(temp))
{
case 0:
break;
case 1:
R_WorldEffectCommand("rain init 1000");
R_WorldEffectCommand("rain outside");
break;
case 2:
R_WorldEffectCommand("snow init 1000 outside");
R_WorldEffectCommand("snow outside");
break;
}
}
// end

File diff suppressed because it is too large Load Diff

2123
codemp/renderer/tr_bsp.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

484
codemp/renderer/tr_cmds.cpp Normal file
View File

@@ -0,0 +1,484 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
#include "tr_local.h"
#ifdef _XBOX
#include "../cgame/cg_local.h"
#include "../client/cl_data.h"
#endif
/*
=====================
R_PerformanceCounters
=====================
*/
void R_PerformanceCounters( void ) {
#ifndef _XBOX
if ( !r_speeds->integer ) {
// clear the counters even if we aren't printing
Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
return;
}
if (r_speeds->integer == 1) {
const float texSize = R_SumOfUsedImages( qfalse )/(8*1048576.0f)*(r_texturebits->integer?r_texturebits->integer:glConfig.colorBits);
Com_Printf ( "%i/%i shdrs/srfs %i leafs %i vrts %i/%i tris %.2fMB tex %.2f dc\n",
backEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes,
backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3,
texSize, backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) );
} else if (r_speeds->integer == 2) {
Com_Printf ( "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out,
tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out );
Com_Printf ( "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out,
tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out );
} else if (r_speeds->integer == 3) {
Com_Printf ( "viewcluster: %i\n", tr.viewCluster );
} else if (r_speeds->integer == 4) {
if ( backEnd.pc.c_dlightVertexes ) {
Com_Printf ( "dlight srf:%i culled:%i verts:%i tris:%i\n",
tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled,
backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 );
}
}
else if (r_speeds->integer == 5 )
{
Com_Printf ("zFar: %.0f\n", tr.viewParms.zFar );
}
else if (r_speeds->integer == 6 )
{
Com_Printf ("flare adds:%i tests:%i renders:%i\n",
backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders );
}
else if (r_speeds->integer == 7) {
const float texSize = R_SumOfUsedImages(qtrue) / (1048576.0f);
const float backBuff= glConfig.vidWidth * glConfig.vidHeight * glConfig.colorBits / (8.0f * 1024*1024);
const float depthBuff= glConfig.vidWidth * glConfig.vidHeight * glConfig.depthBits / (8.0f * 1024*1024);
const float stencilBuff= glConfig.vidWidth * glConfig.vidHeight * glConfig.stencilBits / (8.0f * 1024*1024);
Com_Printf ( "Tex MB %.2f + buffers %.2f MB = Total %.2fMB\n",
texSize, backBuff*2+depthBuff+stencilBuff, texSize+backBuff*2+depthBuff+stencilBuff);
}
#endif
Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
}
/*
====================
R_InitCommandBuffers
====================
*/
void R_InitCommandBuffers( void ) {
}
/*
====================
R_ShutdownCommandBuffers
====================
*/
void R_ShutdownCommandBuffers( void ) {
}
/*
====================
R_IssueRenderCommands
====================
*/
void R_IssueRenderCommands( qboolean runPerformanceCounters ) {
renderCommandList_t *cmdList;
cmdList = &backEndData->commands;
assert(cmdList); // bk001205
// add an end-of-list command
*(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST;
// clear it out, in case this is a sync and not a buffer flip
cmdList->used = 0;
// at this point, the back end thread is idle, so it is ok
// to look at it's performance counters
if ( runPerformanceCounters ) {
R_PerformanceCounters();
}
// actually start the commands going
if ( !r_skipBackEnd->integer ) {
// let it start on the new batch
RB_ExecuteRenderCommands( cmdList->cmds );
}
}
/*
====================
R_SyncRenderThread
Issue any pending commands and wait for them to complete.
After exiting, the render thread will have completed its work
and will remain idle and the main thread is free to issue
OpenGL calls until R_IssueRenderCommands is called.
====================
*/
void R_SyncRenderThread( void ) {
#ifndef _XBOX
if ( !tr.registered ) {
return;
}
R_IssueRenderCommands( qfalse );
#endif
}
/*
============
R_GetCommandBuffer
make sure there is enough command space, waiting on the
render thread if needed.
============
*/
void *R_GetCommandBuffer( int bytes ) {
renderCommandList_t *cmdList;
cmdList = &backEndData->commands;
// always leave room for the end of list command
if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) {
#if defined(_DEBUG) && defined(_XBOX)
Com_Printf(S_COLOR_RED"Command buffer overflow! Tell Brian.\n");
#endif
if ( bytes > MAX_RENDER_COMMANDS - 4 ) {
Com_Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
}
// if we run out of room, just start dropping commands
return NULL;
}
cmdList->used += bytes;
return cmdList->cmds + cmdList->used - bytes;
}
/*
=============
R_AddDrawSurfCmd
=============
*/
void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) {
drawSurfsCommand_t *cmd;
cmd = (drawSurfsCommand_t *) R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_DRAW_SURFS;
cmd->drawSurfs = drawSurfs;
cmd->numDrawSurfs = numDrawSurfs;
cmd->refdef = tr.refdef;
cmd->viewParms = tr.viewParms;
#ifdef _XBOX
cmd->clientNum = ClientManager::ActiveClientNum();
#endif
}
/*
=============
RE_SetColor
Passing NULL will set the color to white
=============
*/
void RE_SetColor( const float *rgba ) {
setColorCommand_t *cmd;
cmd = (setColorCommand_t *) R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_SET_COLOR;
if ( !rgba ) {
static float colorWhite[4] = { 1, 1, 1, 1 };
rgba = colorWhite;
}
cmd->color[0] = rgba[0];
cmd->color[1] = rgba[1];
cmd->color[2] = rgba[2];
cmd->color[3] = rgba[3];
}
/*
=============
RE_StretchPic
=============
*/
void RE_StretchPic ( float x, float y, float w, float h,
float s1, float t1, float s2, float t2, qhandle_t hShader ) {
stretchPicCommand_t *cmd;
cmd = (stretchPicCommand_t *) R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_STRETCH_PIC;
cmd->shader = R_GetShaderByHandle( hShader );
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
cmd->s1 = s1;
cmd->t1 = t1;
cmd->s2 = s2;
cmd->t2 = t2;
}
/*
=============
RE_RotatePic
=============
*/
void RE_RotatePic ( float x, float y, float w, float h,
float s1, float t1, float s2, float t2,float a, qhandle_t hShader ) {
rotatePicCommand_t *cmd;
cmd = (rotatePicCommand_t *) R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_ROTATE_PIC;
cmd->shader = R_GetShaderByHandle( hShader );
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
cmd->s1 = s1;
cmd->t1 = t1;
cmd->s2 = s2;
cmd->t2 = t2;
cmd->a = a;
}
/*
=============
RE_RotatePic2
=============
*/
void RE_RotatePic2 ( float x, float y, float w, float h,
float s1, float t1, float s2, float t2,float a, qhandle_t hShader ) {
rotatePicCommand_t *cmd;
cmd = (rotatePicCommand_t *) R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_ROTATE_PIC2;
cmd->shader = R_GetShaderByHandle( hShader );
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
cmd->s1 = s1;
cmd->t1 = t1;
cmd->s2 = s2;
cmd->t2 = t2;
cmd->a = a;
}
void RE_RenderWorldEffects(void)
{
drawBufferCommand_t *cmd;
cmd = (drawBufferCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_WORLD_EFFECTS;
}
void RE_RenderAutoMap(void)
{
drawBufferCommand_t *cmd;
cmd = (drawBufferCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd )
{
return;
}
cmd->commandId = RC_AUTO_MAP;
}
/*
====================
RE_BeginFrame
If running in stereo, RE_BeginFrame will be called twice
for each RE_EndFrame
====================
*/
void RE_BeginFrame( stereoFrame_t stereoFrame ) {
drawBufferCommand_t *cmd;
if ( !tr.registered ) {
return;
}
glState.finishCalled = qfalse;
tr.frameCount++;
tr.frameSceneNum = 0;
//
// do overdraw measurement
//
#ifndef _XBOX
if ( r_measureOverdraw->integer )
{
if ( glConfig.stencilBits < 4 )
{
Com_Printf ("Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
Cvar_Set( "r_measureOverdraw", "0" );
r_measureOverdraw->modified = qfalse;
}
else if ( r_shadows->integer == 2 )
{
Com_Printf ("Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
Cvar_Set( "r_measureOverdraw", "0" );
r_measureOverdraw->modified = qfalse;
}
else
{
R_SyncRenderThread();
qglEnable( GL_STENCIL_TEST );
qglStencilMask( ~0U );
qglClearStencil( 0U );
qglStencilFunc( GL_ALWAYS, 0U, ~0U );
qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
}
r_measureOverdraw->modified = qfalse;
}
else
{
// this is only reached if it was on and is now off
if ( r_measureOverdraw->modified ) {
R_SyncRenderThread();
qglDisable( GL_STENCIL_TEST );
}
r_measureOverdraw->modified = qfalse;
}
#endif
//
// texturemode stuff
//
if ( r_textureMode->modified || r_ext_texture_filter_anisotropic->modified) {
R_SyncRenderThread();
GL_TextureMode( r_textureMode->string );
r_textureMode->modified = qfalse;
r_ext_texture_filter_anisotropic->modified = qfalse;
}
//
// gamma stuff
//
if ( r_gamma->modified ) {
r_gamma->modified = qfalse;
R_SyncRenderThread();
R_SetColorMappings();
}
// check for errors
if ( !r_ignoreGLErrors->integer ) {
int err;
R_SyncRenderThread();
if ( ( err = qglGetError() ) != GL_NO_ERROR ) {
Com_Error( ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!\n", err );
}
}
//
// draw buffer stuff
//
cmd = (drawBufferCommand_t *) R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_DRAW_BUFFER;
if ( glConfig.stereoEnabled ) {
if ( stereoFrame == STEREO_LEFT ) {
cmd->buffer = (int)GL_BACK_LEFT;
} else if ( stereoFrame == STEREO_RIGHT ) {
cmd->buffer = (int)GL_BACK_RIGHT;
} else {
Com_Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
}
} else {
if ( stereoFrame != STEREO_CENTER ) {
Com_Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
}
// if ( !Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) ) {
// cmd->buffer = (int)GL_FRONT;
// } else
{
cmd->buffer = (int)GL_BACK;
}
}
}
/*
=============
RE_EndFrame
Returns the number of msec spent in the back end
=============
*/
void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
swapBuffersCommand_t *cmd;
if ( !tr.registered ) {
return;
}
cmd = (swapBuffersCommand_t *) R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_SWAP_BUFFERS;
#ifdef _XBOX
if (!qglBeginFrame()) return;
#endif
R_IssueRenderCommands( qtrue );
#ifdef _XBOX
qglEndFrame();
#endif
// use the other buffers next frame, because another CPU
// may still be rendering into the current ones
R_ToggleSmpFrame();
if ( frontEndMsec ) {
*frontEndMsec = tr.frontEndMsec;
}
tr.frontEndMsec = 0;
if ( backEndMsec ) {
*backEndMsec = backEnd.pc.msec;
}
backEnd.pc.msec = 0;
}

View File

@@ -0,0 +1,612 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
#include "tr_local.h"
/*
This file does all of the processing necessary to turn a raw grid of points
read from the map file into a srfGridMesh_t ready for rendering.
The level of detail solution is direction independent, based only on subdivided
distance from the true curve.
Only a single entry point:
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
*/
/*
============
LerpDrawVert
============
*/
static void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out )
{
int k;
out->xyz[0] = 0.5 * (a->xyz[0] + b->xyz[0]);
out->xyz[1] = 0.5 * (a->xyz[1] + b->xyz[1]);
out->xyz[2] = 0.5 * (a->xyz[2] + b->xyz[2]);
out->st[0] = 0.5 * (a->st[0] + b->st[0]);
out->st[1] = 0.5 * (a->st[1] + b->st[1]);
out->normal[0] = 0.5 * (a->normal[0] + b->normal[0]);
out->normal[1] = 0.5 * (a->normal[1] + b->normal[1]);
out->normal[2] = 0.5 * (a->normal[2] + b->normal[2]);
for(k=0;k<MAXLIGHTMAPS;k++)
{
out->lightmap[k][0] = 0.5 * (a->lightmap[k][0] + b->lightmap[k][0]);
out->lightmap[k][1] = 0.5 * (a->lightmap[k][1] + b->lightmap[k][1]);
out->color[k][0] = (a->color[k][0] + b->color[k][0]) >> 1;
out->color[k][1] = (a->color[k][1] + b->color[k][1]) >> 1;
out->color[k][2] = (a->color[k][2] + b->color[k][2]) >> 1;
out->color[k][3] = (a->color[k][3] + b->color[k][3]) >> 1;
}
}
/*
============
Transpose
============
*/
static void Transpose( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
int i, j;
drawVert_t temp;
if ( width > height ) {
for ( i = 0 ; i < height ; i++ ) {
for ( j = i + 1 ; j < width ; j++ ) {
if ( j < height ) {
// swap the value
temp = ctrl[j][i];
ctrl[j][i] = ctrl[i][j];
ctrl[i][j] = temp;
} else {
// just copy
ctrl[j][i] = ctrl[i][j];
}
}
}
} else {
for ( i = 0 ; i < width ; i++ ) {
for ( j = i + 1 ; j < height ; j++ ) {
if ( j < width ) {
// swap the value
temp = ctrl[i][j];
ctrl[i][j] = ctrl[j][i];
ctrl[j][i] = temp;
} else {
// just copy
ctrl[i][j] = ctrl[j][i];
}
}
}
}
}
/*
=================
MakeMeshNormals
Handles all the complicated wrapping and degenerate cases
=================
*/
static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
int i, j, k, dist;
vec3_t normal;
vec3_t sum;
int count;
vec3_t base;
vec3_t delta;
int x, y;
drawVert_t *dv;
vec3_t around[8], temp;
qboolean good[8];
qboolean wrapWidth, wrapHeight;
float len;
static int neighbors[8][2] = {
{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
};
wrapWidth = qfalse;
for ( i = 0 ; i < height ; i++ ) {
VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );
len = VectorLengthSquared( delta );
if ( len > 1.0 ) {
break;
}
}
if ( i == height ) {
wrapWidth = qtrue;
}
wrapHeight = qfalse;
for ( i = 0 ; i < width ; i++ ) {
VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );
len = VectorLengthSquared( delta );
if ( len > 1.0 ) {
break;
}
}
if ( i == width) {
wrapHeight = qtrue;
}
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
count = 0;
dv = &ctrl[j][i];
VectorCopy( dv->xyz, base );
for ( k = 0 ; k < 8 ; k++ ) {
VectorClear( around[k] );
good[k] = qfalse;
for ( dist = 1 ; dist <= 3 ; dist++ ) {
x = i + neighbors[k][0] * dist;
y = j + neighbors[k][1] * dist;
if ( wrapWidth ) {
if ( x < 0 ) {
x = width - 1 + x;
} else if ( x >= width ) {
x = 1 + x - width;
}
}
if ( wrapHeight ) {
if ( y < 0 ) {
y = height - 1 + y;
} else if ( y >= height ) {
y = 1 + y - height;
}
}
if ( x < 0 || x >= width || y < 0 || y >= height ) {
break; // edge of patch
}
VectorSubtract( ctrl[y][x].xyz, base, temp );
if ( VectorNormalize2( temp, temp ) == 0 ) {
continue; // degenerate edge, get more dist
} else {
good[k] = qtrue;
VectorCopy( temp, around[k] );
break; // good edge
}
}
}
VectorClear( sum );
for ( k = 0 ; k < 8 ; k++ ) {
if ( !good[k] || !good[(k+1)&7] ) {
continue; // didn't get two points
}
CrossProduct( around[(k+1)&7], around[k], normal );
if ( VectorNormalize2( normal, normal ) == 0 ) {
continue;
}
VectorAdd( normal, sum, sum );
count++;
}
if ( count == 0 ) {
//printf("bad normal\n");
count = 1;
}
VectorNormalize2( sum, dv->normal );
}
}
}
/*
============
InvertCtrl
============
*/
static void InvertCtrl( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
int i, j;
drawVert_t temp;
for ( i = 0 ; i < height ; i++ ) {
for ( j = 0 ; j < width/2 ; j++ ) {
temp = ctrl[i][j];
ctrl[i][j] = ctrl[i][width-1-j];
ctrl[i][width-1-j] = temp;
}
}
}
/*
=================
InvertErrorTable
=================
*/
static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) {
int i;
float copy[2][MAX_GRID_SIZE];
Com_Memcpy( copy, errorTable, sizeof( copy ) );
for ( i = 0 ; i < width ; i++ ) {
errorTable[1][i] = copy[0][i]; //[width-1-i];
}
for ( i = 0 ; i < height ; i++ ) {
errorTable[0][i] = copy[1][height-1-i];
}
}
/*
==================
PutPointsOnCurve
==================
*/
static void PutPointsOnCurve( drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
int width, int height ) {
int i, j;
drawVert_t prev, next;
for ( i = 0 ; i < width ; i++ ) {
for ( j = 1 ; j < height ; j += 2 ) {
LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev );
LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next );
LerpDrawVert( &prev, &next, &ctrl[j][i] );
}
}
for ( j = 0 ; j < height ; j++ ) {
for ( i = 1 ; i < width ; i += 2 ) {
LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev );
LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next );
LerpDrawVert( &prev, &next, &ctrl[j][i] );
}
}
}
/*
=================
R_CreateSurfaceGridMesh
=================
*/
srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height,
drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) {
int i, j, size;
drawVert_t *vert;
vec3_t tmpVec;
srfGridMesh_t *grid;
// copy the results out to a grid
size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
#ifdef PATCH_STITCHING
grid = (struct srfGridMesh_s *)/*Hunk_Alloc*/ Z_Malloc( size, TAG_GRIDMESH, qfalse );
Com_Memset(grid, 0, size);
grid->widthLodError = (float *)/*Hunk_Alloc*/ Z_Malloc( width * 4, TAG_GRIDMESH, qfalse );
Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
grid->heightLodError = (float *)/*Hunk_Alloc*/ Z_Malloc( height * 4, TAG_GRIDMESH, qfalse );
Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
#else
grid = Hunk_Alloc( size );
Com_Memset(grid, 0, size);
grid->widthLodError = Hunk_Alloc( width * 4 );
Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
grid->heightLodError = Hunk_Alloc( height * 4 );
Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
#endif
grid->width = width;
grid->height = height;
grid->surfaceType = SF_GRID;
ClearBounds( grid->meshBounds[0], grid->meshBounds[1] );
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
vert = &grid->verts[j*width+i];
*vert = ctrl[j][i];
AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] );
}
}
// compute local origin and bounds
VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin );
VectorScale( grid->localOrigin, 0.5f, grid->localOrigin );
VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec );
grid->meshRadius = VectorLength( tmpVec );
VectorCopy( grid->localOrigin, grid->lodOrigin );
grid->lodRadius = grid->meshRadius;
//
return grid;
}
/*
=================
R_FreeSurfaceGridMesh
=================
*/
void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) {
Z_Free(grid->widthLodError);
Z_Free(grid->heightLodError);
Z_Free(grid);
}
/*
=================
R_SubdividePatchToGrid
=================
*/
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
int i, j, k, l;
drawVert_t prev, next, mid;
float len, maxLen;
int dir;
int t;
MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
float errorTable[2][MAX_GRID_SIZE];
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
ctrl[j][i] = points[j*width+i];
}
}
for ( dir = 0 ; dir < 2 ; dir++ ) {
for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
errorTable[dir][j] = 0;
}
// horizontal subdivisions
for ( j = 0 ; j + 2 < width ; j += 2 ) {
// check subdivided midpoints against control points
// FIXME: also check midpoints of adjacent patches against the control points
// this would basically stitch all patches in the same LOD group together.
maxLen = 0;
for ( i = 0 ; i < height ; i++ ) {
vec3_t midxyz;
vec3_t dir;
vec3_t projected;
float d;
// calculate the point on the curve
for ( l = 0 ; l < 3 ; l++ ) {
midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2
+ ctrl[i][j+2].xyz[l] ) * 0.25f;
}
// see how far off the line it is
// using dist-from-line will not account for internal
// texture warping, but it gives a lot less polygons than
// dist-from-midpoint
VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );
VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir );
VectorNormalize( dir );
d = DotProduct( midxyz, dir );
VectorScale( dir, d, projected );
VectorSubtract( midxyz, projected, midxyz);
len = VectorLengthSquared( midxyz ); // we will do the sqrt later
if ( len > maxLen ) {
maxLen = len;
}
}
maxLen = sqrt(maxLen);
// if all the points are on the lines, remove the entire columns
if ( maxLen < 0.1f ) {
errorTable[dir][j+1] = 999;
continue;
}
// see if we want to insert subdivided columns
if ( width + 2 > MAX_GRID_SIZE ) {
errorTable[dir][j+1] = 1.0f/maxLen;
continue; // can't subdivide any more
}
if ( maxLen <= r_subdivisions->value ) {
errorTable[dir][j+1] = 1.0f/maxLen;
continue; // didn't need subdivision
}
errorTable[dir][j+2] = 1.0f/maxLen;
// insert two columns and replace the peak
width += 2;
for ( i = 0 ; i < height ; i++ ) {
LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev );
LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next );
LerpDrawVert( &prev, &next, &mid );
for ( k = width - 1 ; k > j + 3 ; k-- ) {
ctrl[i][k] = ctrl[i][k-2];
}
ctrl[i][j + 1] = prev;
ctrl[i][j + 2] = mid;
ctrl[i][j + 3] = next;
}
// back up and recheck this set again, it may need more subdivision
j -= 2;
}
Transpose( width, height, ctrl );
t = width;
width = height;
height = t;
}
// put all the aproximating points on the curve
PutPointsOnCurve( ctrl, width, height );
// cull out any rows or columns that are colinear
for ( i = 1 ; i < width-1 ; i++ ) {
if ( errorTable[0][i] != 999 ) {
continue;
}
for ( j = i+1 ; j < width ; j++ ) {
for ( k = 0 ; k < height ; k++ ) {
ctrl[k][j-1] = ctrl[k][j];
}
errorTable[0][j-1] = errorTable[0][j];
}
width--;
}
for ( i = 1 ; i < height-1 ; i++ ) {
if ( errorTable[1][i] != 999 ) {
continue;
}
for ( j = i+1 ; j < height ; j++ ) {
for ( k = 0 ; k < width ; k++ ) {
ctrl[j-1][k] = ctrl[j][k];
}
errorTable[1][j-1] = errorTable[1][j];
}
height--;
}
#if 1
// flip for longest tristrips as an optimization
// the results should be visually identical with or
// without this step
if ( height > width ) {
Transpose( width, height, ctrl );
InvertErrorTable( errorTable, width, height );
t = width;
width = height;
height = t;
InvertCtrl( width, height, ctrl );
}
#endif
// calculate normals
MakeMeshNormals( width, height, ctrl );
return R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
}
/*
===============
R_GridInsertColumn
===============
*/
srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) {
int i, j;
int width, height, oldwidth;
MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
float errorTable[2][MAX_GRID_SIZE];
float lodRadius;
vec3_t lodOrigin;
oldwidth = 0;
width = grid->width + 1;
if (width > MAX_GRID_SIZE)
return NULL;
height = grid->height;
for (i = 0; i < width; i++) {
if (i == column) {
//insert new column
for (j = 0; j < grid->height; j++) {
LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] );
if (j == row)
VectorCopy(point, ctrl[j][i].xyz);
}
errorTable[0][i] = loderror;
continue;
}
errorTable[0][i] = grid->widthLodError[oldwidth];
for (j = 0; j < grid->height; j++) {
ctrl[j][i] = grid->verts[j * grid->width + oldwidth];
}
oldwidth++;
}
for (j = 0; j < grid->height; j++) {
errorTable[1][j] = grid->heightLodError[j];
}
// put all the aproximating points on the curve
//PutPointsOnCurve( ctrl, width, height );
// calculate normals
MakeMeshNormals( width, height, ctrl );
VectorCopy(grid->lodOrigin, lodOrigin);
lodRadius = grid->lodRadius;
// free the old grid
R_FreeSurfaceGridMesh(grid);
// create a new grid
grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
grid->lodRadius = lodRadius;
VectorCopy(lodOrigin, grid->lodOrigin);
return grid;
}
/*
===============
R_GridInsertRow
===============
*/
srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) {
int i, j;
int width, height, oldheight;
MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
float errorTable[2][MAX_GRID_SIZE];
float lodRadius;
vec3_t lodOrigin;
oldheight = 0;
width = grid->width;
height = grid->height + 1;
if (height > MAX_GRID_SIZE)
return NULL;
for (i = 0; i < height; i++) {
if (i == row) {
//insert new row
for (j = 0; j < grid->width; j++) {
LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] );
if (j == column)
VectorCopy(point, ctrl[i][j].xyz);
}
errorTable[1][i] = loderror;
continue;
}
errorTable[1][i] = grid->heightLodError[oldheight];
for (j = 0; j < grid->width; j++) {
ctrl[i][j] = grid->verts[oldheight * grid->width + j];
}
oldheight++;
}
for (j = 0; j < grid->width; j++) {
errorTable[0][j] = grid->widthLodError[j];
}
// put all the aproximating points on the curve
//PutPointsOnCurve( ctrl, width, height );
// calculate normals
MakeMeshNormals( width, height, ctrl );
VectorCopy(grid->lodOrigin, lodOrigin);
lodRadius = grid->lodRadius;
// free the old grid
R_FreeSurfaceGridMesh(grid);
// create a new grid
grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
grid->lodRadius = lodRadius;
VectorCopy(lodOrigin, grid->lodOrigin);
return grid;
}

View File

@@ -0,0 +1,536 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
#include "tr_local.h"
/*
This file does all of the processing necessary to turn a raw grid of points
read from the map file into a srfGridMesh_t ready for rendering.
The level of detail solution is direction independent, based only on subdivided
distance from the true curve.
Only a single entry point:
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
*/
/*
============
LerpDrawVert
============
*/
static void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) {
int k;
out->xyz[0] = 0.5 * (a->xyz[0] + b->xyz[0]);
out->xyz[1] = 0.5 * (a->xyz[1] + b->xyz[1]);
out->xyz[2] = 0.5 * (a->xyz[2] + b->xyz[2]);
out->dvst[0] = (short)(0.5 * (float)(a->dvst[0] + b->dvst[0]));
out->dvst[1] = (short)(0.5 * (float)(a->dvst[1] + b->dvst[1]));
out->normal[0] = 0.5 * (a->normal[0] + b->normal[0]);
out->normal[1] = 0.5 * (a->normal[1] + b->normal[1]);
out->normal[2] = 0.5 * (a->normal[2] + b->normal[2]);
for(k=0;k<MAXLIGHTMAPS;k++)
{
out->dvlightmap[k][0] = (short)(0.5 * (float)(a->dvlightmap[k][0] + b->dvlightmap[k][0]));
out->dvlightmap[k][1] = (short)(0.5 * (float)(a->dvlightmap[k][1] + b->dvlightmap[k][1]));
// Need to do averaging per every four bits
for (int j = 0; j < 2; ++j)
{
byte ah, al, bh, bl;
ah = a->dvcolor[k][j] >> 4;
al = a->dvcolor[k][j] & 0x0F;
bh = b->dvcolor[k][j] >> 4;
bl = b->dvcolor[k][j] & 0x0F;
out->dvcolor[k][j] = (((ah+bh) / 2) << 4) | ((al+bl) / 2);
}
}
}
/*
============
Transpose
============
*/
static void Transpose( int width, int height, drawVert_t* ctrl/*[MAX_GRID_SIZE][MAX_GRID_SIZE]*/ ) {
int i, j;
drawVert_t temp;
if ( width > height ) {
for ( i = 0 ; i < height ; i++ ) {
for ( j = i + 1 ; j < width ; j++ ) {
if ( j < height ) {
// swap the value
temp = ctrl[j*MAX_GRID_SIZE+i];
ctrl[j*MAX_GRID_SIZE+i] = ctrl[i*MAX_GRID_SIZE+j];
ctrl[i*MAX_GRID_SIZE+j] = temp;
} else {
// just copy
ctrl[j*MAX_GRID_SIZE+i] = ctrl[i*MAX_GRID_SIZE+j];
}
}
}
} else {
for ( i = 0 ; i < width ; i++ ) {
for ( j = i + 1 ; j < height ; j++ ) {
if ( j < width ) {
// swap the value
temp = ctrl[i*MAX_GRID_SIZE+j];
ctrl[i*MAX_GRID_SIZE+j] = ctrl[j*MAX_GRID_SIZE+i];
ctrl[j*MAX_GRID_SIZE+i] = temp;
} else {
// just copy
ctrl[i*MAX_GRID_SIZE+j] = ctrl[j*MAX_GRID_SIZE+i];
}
}
}
}
}
/*
=================
MakeMeshNormals
Handles all the complicated wrapping and degenerate cases
=================
*/
static void MakeMeshNormals( int width, int height, drawVert_t* ctrl/*[MAX_GRID_SIZE][MAX_GRID_SIZE]*/ ) {
int i, j, k, dist;
vec3_t normal;
vec3_t sum;
int count;
vec3_t base;
vec3_t delta;
int x, y;
drawVert_t *dv;
vec3_t around[8], temp;
qboolean good[8];
qboolean wrapWidth, wrapHeight;
float len;
static int neighbors[8][2] = {
{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
};
wrapWidth = qfalse;
for ( i = 0 ; i < height ; i++ ) {
VectorSubtract( ctrl[i*MAX_GRID_SIZE+0].xyz, ctrl[i*MAX_GRID_SIZE+width-1].xyz, delta );
len = VectorLengthSquared( delta );
if ( len > 1.0 ) {
break;
}
}
if ( i == height ) {
wrapWidth = qtrue;
}
wrapHeight = qfalse;
for ( i = 0 ; i < width ; i++ ) {
VectorSubtract( ctrl[0*MAX_GRID_SIZE+i].xyz, ctrl[(height-1)*MAX_GRID_SIZE+i].xyz, delta );
len = VectorLengthSquared( delta );
if ( len > 1.0 ) {
break;
}
}
if ( i == width) {
wrapHeight = qtrue;
}
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
count = 0;
dv = &ctrl[j*MAX_GRID_SIZE+i];
VectorCopy( dv->xyz, base );
for ( k = 0 ; k < 8 ; k++ ) {
VectorClear( around[k] );
good[k] = qfalse;
for ( dist = 1 ; dist <= 3 ; dist++ ) {
x = i + neighbors[k][0] * dist;
y = j + neighbors[k][1] * dist;
if ( wrapWidth ) {
if ( x < 0 ) {
x = width - 1 + x;
} else if ( x >= width ) {
x = 1 + x - width;
}
}
if ( wrapHeight ) {
if ( y < 0 ) {
y = height - 1 + y;
} else if ( y >= height ) {
y = 1 + y - height;
}
}
if ( x < 0 || x >= width || y < 0 || y >= height ) {
break; // edge of patch
}
VectorSubtract( ctrl[y*MAX_GRID_SIZE+x].xyz, base, temp );
if ( VectorNormalize2( temp, temp ) == 0 ) {
continue; // degenerate edge, get more dist
} else {
good[k] = qtrue;
VectorCopy( temp, around[k] );
break; // good edge
}
}
}
VectorClear( sum );
for ( k = 0 ; k < 8 ; k++ ) {
if ( !good[k] || !good[(k+1)&7] ) {
continue; // didn't get two points
}
CrossProduct( around[(k+1)&7], around[k], normal );
if ( VectorNormalize2( normal, normal ) == 0 ) {
continue;
}
VectorAdd( normal, sum, sum );
count++;
}
if ( count == 0 ) {
//printf("bad normal\n");
count = 1;
}
VectorNormalize2( sum, dv->normal );
}
}
}
/*
============
InvertCtrl
============
*/
static void InvertCtrl( int width, int height, drawVert_t* ctrl/*[MAX_GRID_SIZE][MAX_GRID_SIZE]*/ ) {
int i, j;
drawVert_t temp;
for ( i = 0 ; i < height ; i++ ) {
for ( j = 0 ; j < width/2 ; j++ ) {
temp = ctrl[i*MAX_GRID_SIZE+j];
ctrl[i*MAX_GRID_SIZE+j] = ctrl[i*MAX_GRID_SIZE+width-1-j];
ctrl[i*MAX_GRID_SIZE+width-1-j] = temp;
}
}
}
/*
=================
InvertErrorTable
=================
*/
static void InvertErrorTable( float* errorTable/*[2][MAX_GRID_SIZE]*/, int width, int height ) {
int i;
float copy[2][MAX_GRID_SIZE];
memcpy( copy, errorTable, sizeof( copy ) );
for ( i = 0 ; i < width ; i++ ) {
errorTable[1*MAX_GRID_SIZE+i] = copy[0][i]; //[width-1-i];
}
for ( i = 0 ; i < height ; i++ ) {
errorTable[0*MAX_GRID_SIZE+i] = copy[1][height-1-i];
}
}
/*
==================
PutPointsOnCurve
==================
*/
static void PutPointsOnCurve( drawVert_t* ctrl/*[MAX_GRID_SIZE][MAX_GRID_SIZE]*/,
int width, int height ) {
int i, j;
drawVert_t prev, next;
for ( i = 0 ; i < width ; i++ ) {
for ( j = 1 ; j < height ; j += 2 ) {
LerpDrawVert( &ctrl[j*MAX_GRID_SIZE+i], &ctrl[(j+1)*MAX_GRID_SIZE+i], &prev );
LerpDrawVert( &ctrl[j*MAX_GRID_SIZE+i], &ctrl[(j-1)*MAX_GRID_SIZE+i], &next );
LerpDrawVert( &prev, &next, &ctrl[j*MAX_GRID_SIZE+i] );
}
}
for ( j = 0 ; j < height ; j++ ) {
for ( i = 1 ; i < width ; i += 2 ) {
LerpDrawVert( &ctrl[j*MAX_GRID_SIZE+i], &ctrl[j*MAX_GRID_SIZE+i+1], &prev );
LerpDrawVert( &ctrl[j*MAX_GRID_SIZE+i], &ctrl[j*MAX_GRID_SIZE+i-1], &next );
LerpDrawVert( &prev, &next, &ctrl[j*MAX_GRID_SIZE+i] );
}
}
}
/*
=================
R_CreateSurfaceGridMesh
=================
*/
srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height,
drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) {
int i, j, size;
drawVert_t *vert;
vec3_t tmpVec;
srfGridMesh_t *grid;
// copy the results out to a grid
size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
#ifdef PATCH_STITCHING
grid = (struct srfGridMesh_s *)/*Hunk_Alloc*/ Z_Malloc( size, TAG_GRIDMESH, qfalse );
Com_Memset(grid, 0, size);
grid->widthLodError = (float *)/*Hunk_Alloc*/ Z_Malloc( width * 4, TAG_GRIDMESH, qfalse );
Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
grid->heightLodError = (float *)/*Hunk_Alloc*/ Z_Malloc( height * 4, TAG_GRIDMESH, qfalse );
Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
#else
grid = Hunk_Alloc( size );
Com_Memset(grid, 0, size);
grid->widthLodError = Hunk_Alloc( width * 4 );
Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
grid->heightLodError = Hunk_Alloc( height * 4 );
Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
#endif
grid->width = width;
grid->height = height;
grid->surfaceType = SF_GRID;
ClearBounds( grid->meshBounds[0], grid->meshBounds[1] );
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
vert = &grid->verts[j*width+i];
*vert = ctrl[j][i];
AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] );
}
}
// compute local origin and bounds
VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin );
VectorScale( grid->localOrigin, 0.5f, grid->localOrigin );
VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec );
grid->meshRadius = VectorLength( tmpVec );
VectorCopy( grid->localOrigin, grid->lodOrigin );
grid->lodRadius = grid->meshRadius;
//
return grid;
}
/*
=================
R_FreeSurfaceGridMesh
=================
*/
void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) {
Z_Free(grid->widthLodError);
Z_Free(grid->heightLodError);
Z_Free(grid);
}
/*
=================
R_SubdividePatchToGrid
=================
*/
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, drawVert_t* points,
drawVert_t* ctrl, float* errorTable ) {
int i, j, k, l;
drawVert_t prev, next, mid;
float len, maxLen;
int dir;
int t;
srfGridMesh_t *grid;
drawVert_t *vert;
vec3_t tmpVec;
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
ctrl[j*MAX_GRID_SIZE+i] = points[j*width+i];
}
}
for ( dir = 0 ; dir < 2 ; dir++ ) {
for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
errorTable[dir*MAX_GRID_SIZE+j] = 0;
}
// horizontal subdivisions
for ( j = 0 ; j + 2 < width ; j += 2 ) {
// check subdivided midpoints against control points
maxLen = 0;
for ( i = 0 ; i < height ; i++ ) {
vec3_t midxyz;
vec3_t dir;
vec3_t projected;
float d;
// calculate the point on the curve
for ( l = 0 ; l < 3 ; l++ ) {
midxyz[l] = (ctrl[i*MAX_GRID_SIZE+j].xyz[l]
+ ctrl[i*MAX_GRID_SIZE+j+1].xyz[l] * 2
+ ctrl[i*MAX_GRID_SIZE+j+2].xyz[l] ) * 0.25;
}
// see how far off the line it is
// using dist-from-line will not account for internal
// texture warping, but it gives a lot less polygons than
// dist-from-midpoint
VectorSubtract( midxyz, ctrl[i*MAX_GRID_SIZE+j].xyz, midxyz );
VectorSubtract( ctrl[i*MAX_GRID_SIZE+j+2].xyz, ctrl[i*MAX_GRID_SIZE+j].xyz, dir );
VectorNormalize( dir );
d = DotProduct( midxyz, dir );
VectorScale( dir, d, projected );
VectorSubtract( midxyz, projected, midxyz);
len = VectorLengthSquared( midxyz );
if ( len > maxLen ) {
maxLen = len;
}
}
maxLen = sqrt(maxLen);
// if all the points are on the lines, remove the entire columns
if ( maxLen < 0.1 ) {
errorTable[dir*MAX_GRID_SIZE+j+1] = 999;
continue;
}
// see if we want to insert subdivided columns
if ( width + 2 > MAX_GRID_SIZE ) {
errorTable[dir*MAX_GRID_SIZE+j+1] = 1.0/maxLen;
continue; // can't subdivide any more
}
if ( maxLen <= r_subdivisions->value ) {
errorTable[dir*MAX_GRID_SIZE+j+1] = 1.0/maxLen;
continue; // didn't need subdivision
}
errorTable[dir*MAX_GRID_SIZE+j+2] = 1.0/maxLen;
// insert two columns and replace the peak
width += 2;
for ( i = 0 ; i < height ; i++ ) {
LerpDrawVert( &ctrl[i*MAX_GRID_SIZE+j], &ctrl[i*MAX_GRID_SIZE+j+1], &prev );
LerpDrawVert( &ctrl[i*MAX_GRID_SIZE+j+1], &ctrl[i*MAX_GRID_SIZE+j+2], &next );
LerpDrawVert( &prev, &next, &mid );
for ( k = width - 1 ; k > j + 3 ; k-- ) {
ctrl[i*MAX_GRID_SIZE+k] = ctrl[i*MAX_GRID_SIZE+k-2];
}
ctrl[i*MAX_GRID_SIZE+j + 1] = prev;
ctrl[i*MAX_GRID_SIZE+j + 2] = mid;
ctrl[i*MAX_GRID_SIZE+j + 3] = next;
}
// back up and recheck this set again, it may need more subdivision
j -= 2;
}
Transpose( width, height, ctrl );
t = width;
width = height;
height = t;
}
// put all the aproximating points on the curve
PutPointsOnCurve( ctrl, width, height );
// cull out any rows or columns that are colinear
for ( i = 1 ; i < width-1 ; i++ ) {
if ( errorTable[0*MAX_GRID_SIZE+i] != 999 ) {
continue;
}
for ( j = i+1 ; j < width ; j++ ) {
for ( k = 0 ; k < height ; k++ ) {
ctrl[k*MAX_GRID_SIZE+j-1] = ctrl[k*MAX_GRID_SIZE+j];
}
errorTable[0*MAX_GRID_SIZE+j-1] = errorTable[0*MAX_GRID_SIZE+j];
}
width--;
}
for ( i = 1 ; i < height-1 ; i++ ) {
if ( errorTable[1*MAX_GRID_SIZE+i] != 999 ) {
continue;
}
for ( j = i+1 ; j < height ; j++ ) {
for ( k = 0 ; k < width ; k++ ) {
ctrl[(j-1)*MAX_GRID_SIZE+k] = ctrl[j*MAX_GRID_SIZE+k];
}
errorTable[1*MAX_GRID_SIZE+j-1] = errorTable[1*MAX_GRID_SIZE+j];
}
height--;
}
#if 1
// flip for longest tristrips as an optimization
// the results should be visually identical with or
// without this step
if ( height > width ) {
Transpose( width, height, ctrl );
InvertErrorTable( errorTable, width, height );
t = width;
width = height;
height = t;
InvertCtrl( width, height, ctrl );
}
#endif
// calculate normals
MakeMeshNormals( width, height, ctrl );
// copy the results out to a grid
grid = (struct srfGridMesh_s *) Hunk_Alloc( (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid ) + width * 4 + height * 4, h_low );
grid->widthLodError = (float*)(((char*)grid) + (width * height - 1) *
sizeof(drawVert_t) + sizeof(*grid));
memcpy( grid->widthLodError, &errorTable[0*MAX_GRID_SIZE], width * 4 );
grid->heightLodError = (float*)(((char*)grid->widthLodError) + width * 4);
memcpy( grid->heightLodError, &errorTable[1*MAX_GRID_SIZE], height * 4 );
grid->width = width;
grid->height = height;
grid->surfaceType = SF_GRID;
ClearBounds( grid->meshBounds[0], grid->meshBounds[1] );
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
vert = &grid->verts[j*width+i];
*vert = ctrl[j*MAX_GRID_SIZE+i];
AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] );
}
}
// compute local origin and bounds
VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin );
VectorScale( grid->localOrigin, 0.5f, grid->localOrigin );
VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec );
grid->meshRadius = VectorLength( tmpVec );
VectorCopy( grid->localOrigin, grid->lodOrigin );
grid->lodRadius = grid->meshRadius;
return grid;
}

View File

@@ -0,0 +1,433 @@
// tr_flares.c
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
#include "tr_local.h"
/*
=============================================================================
LIGHT FLARES
A light flare is an effect that takes place inside the eye when bright light
sources are visible. The size of the flare reletive to the screen is nearly
constant, irrespective of distance, but the intensity should be proportional to the
projected area of the light source.
A surface that has been flagged as having a light flare will calculate the depth
buffer value that it's midpoint should have when the surface is added.
After all opaque surfaces have been rendered, the depth buffer is read back for
each flare in view. If the point has not been obscured by a closer surface, the
flare should be drawn.
Surfaces that have a repeated texture should never be flagged as flaring, because
there will only be a single flare added at the midpoint of the polygon.
To prevent abrupt popping, the intensity of the flare is interpolated up and
down as it changes visibility. This involves scene to scene state, unlike almost
all other aspects of the renderer, and is complicated by the fact that a single
frame may have multiple scenes.
RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially
up to five or more times in a frame with 3D status bar icons).
=============================================================================
*/
// flare states maintain visibility over multiple frames for fading
// layers: view, mirror, menu
typedef struct flare_s {
struct flare_s *next; // for active chain
int addedFrame;
qboolean inPortal; // true if in a portal view of the scene
int frameSceneNum;
void *surface;
int fogNum;
int fadeTime;
qboolean visible; // state of last test
float drawIntensity; // may be non 0 even if !visible due to fading
int windowX, windowY;
float eyeZ;
vec3_t color;
} flare_t;
#define MAX_FLARES 128
flare_t r_flareStructs[MAX_FLARES];
flare_t *r_activeFlares, *r_inactiveFlares;
/*
==================
R_ClearFlares
==================
*/
void R_ClearFlares( void ) {
int i;
Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) );
r_activeFlares = NULL;
r_inactiveFlares = NULL;
for ( i = 0 ; i < MAX_FLARES ; i++ ) {
r_flareStructs[i].next = r_inactiveFlares;
r_inactiveFlares = &r_flareStructs[i];
}
}
/*
==================
RB_AddFlare
This is called at surface tesselation time
==================
*/
void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) {
int i;
flare_t *f, *oldest;
vec3_t local;
float d;
vec4_t eye, clip, normalized, window;
backEnd.pc.c_flareAdds++;
// if the point is off the screen, don't bother adding it
// calculate screen coordinates and depth
R_TransformModelToClip( point, backEnd.ori.modelMatrix,
backEnd.viewParms.projectionMatrix, eye, clip );
// check to see if the point is completely off screen
for ( i = 0 ; i < 3 ; i++ ) {
if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
return;
}
}
R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );
if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
|| window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
return; // shouldn't happen, since we check the clip[] above, except for FP rounding
}
// see if a flare with a matching surface, scene, and view exists
oldest = r_flareStructs;
for ( f = r_activeFlares ; f ; f = f->next ) {
if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum
&& f->inPortal == backEnd.viewParms.isPortal ) {
break;
}
}
// allocate a new one
if (!f ) {
if ( !r_inactiveFlares ) {
// the list is completely full
return;
}
f = r_inactiveFlares;
r_inactiveFlares = r_inactiveFlares->next;
f->next = r_activeFlares;
r_activeFlares = f;
f->surface = surface;
f->frameSceneNum = backEnd.viewParms.frameSceneNum;
f->inPortal = backEnd.viewParms.isPortal;
f->addedFrame = -1;
}
if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) {
f->visible = qfalse;
f->fadeTime = backEnd.refdef.time - 2000;
}
f->addedFrame = backEnd.viewParms.frameCount;
f->fogNum = fogNum;
VectorCopy( color, f->color );
// fade the intensity of the flare down as the
// light surface turns away from the viewer
if ( normal ) {
VectorSubtract( backEnd.viewParms.ori.origin, point, local );
VectorNormalizeFast( local );
d = DotProduct( local, normal );
VectorScale( f->color, d, f->color );
}
// save info needed to test
f->windowX = backEnd.viewParms.viewportX + window[0];
f->windowY = backEnd.viewParms.viewportY + window[1];
f->eyeZ = eye[2];
}
/*
==================
RB_AddDlightFlares
==================
*/
void RB_AddDlightFlares( void ) {
dlight_t *l;
int i, j, k;
fog_t *fog;
if ( !r_flares->integer ) {
return;
}
l = backEnd.refdef.dlights;
fog = tr.world->fogs;
for (i=0 ; i<backEnd.refdef.num_dlights ; i++, l++) {
// find which fog volume the light is in
for ( j = 1 ; j < tr.world->numfogs ; j++ ) {
fog = &tr.world->fogs[j];
for ( k = 0 ; k < 3 ; k++ ) {
if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) {
break;
}
}
if ( k == 3 ) {
break;
}
}
if ( j == tr.world->numfogs ) {
j = 0;
}
RB_AddFlare( (void *)l, j, l->origin, l->color, NULL );
}
}
/*
===============================================================================
FLARE BACK END
===============================================================================
*/
/*
==================
RB_TestFlare
==================
*/
void RB_TestFlare( flare_t *f ) {
float depth;
qboolean visible;
float fade;
float screenZ;
backEnd.pc.c_flareTests++;
// doing a readpixels is as good as doing a glFinish(), so
// don't bother with another sync
glState.finishCalled = qfalse;
// read back the z buffer contents
qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth );
screenZ = backEnd.viewParms.projectionMatrix[14] /
( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] );
visible = (qboolean)(( -f->eyeZ - -screenZ ) < 24);
if ( visible ) {
if ( !f->visible ) {
f->visible = qtrue;
f->fadeTime = backEnd.refdef.time - 1;
}
fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value;
} else {
if ( f->visible ) {
f->visible = qfalse;
f->fadeTime = backEnd.refdef.time - 1;
}
fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value;
}
if ( fade < 0 ) {
fade = 0;
}
if ( fade > 1 ) {
fade = 1;
}
f->drawIntensity = fade;
}
/*
==================
RB_RenderFlare
==================
*/
void RB_RenderFlare( flare_t *f ) {
float size;
vec3_t color;
int iColor[3];
backEnd.pc.c_flareRenders++;
VectorScale( f->color, f->drawIntensity*tr.identityLight, color );
iColor[0] = color[0] * 255;
iColor[1] = color[1] * 255;
iColor[2] = color[2] * 255;
#ifdef _XBOX
if(glw_state->isWidescreen)
size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/720.0f + 8 / -f->eyeZ );
else
#endif
size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / -f->eyeZ );
RB_BeginSurface( tr.flareShader, f->fogNum );
// FIXME: use quadstamp?
tess.xyz[tess.numVertexes][0] = f->windowX - size;
tess.xyz[tess.numVertexes][1] = f->windowY - size;
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX - size;
tess.xyz[tess.numVertexes][1] = f->windowY + size;
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX + size;
tess.xyz[tess.numVertexes][1] = f->windowY + size;
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX + size;
tess.xyz[tess.numVertexes][1] = f->windowY - size;
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 1;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 3;
RB_EndSurface();
}
/*
==================
RB_RenderFlares
Because flares are simulating an occular effect, they should be drawn after
everything (all views) in the entire frame has been drawn.
Because of the way portals use the depth buffer to mark off areas, the
needed information would be lost after each view, so we are forced to draw
flares after each view.
The resulting artifact is that flares in mirrors or portals don't dim properly
when occluded by something in the main view, and portal flares that should
extend past the portal edge will be overwritten.
==================
*/
void RB_RenderFlares (void) {
flare_t *f;
flare_t **prev;
qboolean draw;
if ( !r_flares->integer ) {
return;
}
// RB_AddDlightFlares();
// perform z buffer readback on each flare in this view
draw = qfalse;
prev = &r_activeFlares;
while ( ( f = *prev ) != NULL ) {
// throw out any flares that weren't added last frame
if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) {
*prev = f->next;
f->next = r_inactiveFlares;
r_inactiveFlares = f;
continue;
}
// don't draw any here that aren't from this scene / portal
f->drawIntensity = 0;
if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
&& f->inPortal == backEnd.viewParms.isPortal ) {
RB_TestFlare( f );
if ( f->drawIntensity ) {
draw = qtrue;
} else {
// this flare has completely faded out, so remove it from the chain
*prev = f->next;
f->next = r_inactiveFlares;
r_inactiveFlares = f;
continue;
}
}
prev = &f->next;
}
if ( !draw ) {
return; // none visible
}
if ( backEnd.viewParms.isPortal ) {
qglDisable (GL_CLIP_PLANE0);
}
qglPushMatrix();
qglLoadIdentity();
qglMatrixMode( GL_PROJECTION );
qglPushMatrix();
qglLoadIdentity();
qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
-99999, 99999 );
for ( f = r_activeFlares ; f ; f = f->next ) {
if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
&& f->inPortal == backEnd.viewParms.isPortal
&& f->drawIntensity ) {
RB_RenderFlare( f );
}
}
qglPopMatrix();
qglMatrixMode( GL_MODELVIEW );
qglPopMatrix();
}

1747
codemp/renderer/tr_font.cpp Normal file

File diff suppressed because it is too large Load Diff

34
codemp/renderer/tr_font.h Normal file
View File

@@ -0,0 +1,34 @@
// Filename:- tr_font.h
//
// font support
// This file is shared in the single and multiplayer codebases, so be CAREFUL WHAT YOU ADD/CHANGE!!!!!
#ifndef TR_FONT_H
#define TR_FONT_H
void R_ShutdownFonts(void);
void R_InitFonts(void);
int RE_RegisterFont(const char *psName);
int RE_Font_StrLenPixels(const char *psText, const int iFontHandle, const float fScale = 1.0f);
int RE_Font_StrLenChars(const char *psText);
int RE_Font_HeightPixels(const int iFontHandle, const float fScale = 1.0f);
void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, const int iFontHandle, int iMaxPixelWidth, const float fScale = 1.0f);
// Dammit, I can't use this more elegant form because of !@#@!$%% VM code... (can't alter passed in ptrs, only contents of)
//
//unsigned int AnyLanguage_ReadCharFromString( const char **ppsText, qboolean *pbIsTrailingPunctuation = NULL);
//
// so instead we have to use this messier method...
//
unsigned int AnyLanguage_ReadCharFromString( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation = NULL);
qboolean Language_IsAsian(void);
qboolean Language_UsesSpaces(void);
#endif // #ifndef TR_FONT_H
// end

File diff suppressed because it is too large Load Diff

3365
codemp/renderer/tr_image.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1554
codemp/renderer/tr_init.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,191 @@
#ifndef _INC_LANDSCAPE_H
#define _INC_LANDSCAPE_H
// Number of TriTreeNodes available
#define POOL_SIZE (50000)
#define TEXTURE_ALPHA_TL 0x000000ff
#define TEXTURE_ALPHA_TR 0x0000ff00
#define TEXTURE_ALPHA_BL 0x00ff0000
#define TEXTURE_ALPHA_BR 0x000000ff
#define INDEX_TL 0
#define INDEX_TR 1
#define INDEX_BL 2
#define INDEX_BR 3
#define VARIANCE_MIN 0.0f
#define VARIANCE_MAX 2000.0f
#define SPLIT_VARIANCE_SIZE 20
#define SPLIT_VARIANCE_STEP (VARIANCE_MAX / SPLIT_VARIANCE_SIZE)
class CTerVert
{
public:
vec3_t coords; // real world coords of terxel
vec3_t normal; // required to calculate lighting and used in physics
color4ub_t tint; // tint at this terxel
float tex[2]; // texture coordinates at this terxel
int height; // Copy of heightmap data
int tessIndex; // Index of the vert in the tess array
int tessRegistration; // ...... for the tess with this registration
CTerVert( void ) { memset(this, 0, sizeof(*this)); }
~CTerVert( void ) { }
};
class CTRHeightDetails
{
private:
qhandle_t mShader;
public:
CTRHeightDetails( void ) { }
~CTRHeightDetails( void ) { }
const qhandle_t GetShader( void ) const { return(mShader); }
void SetShader(const qhandle_t shader) { mShader = shader; }
};
//
// Information of each patch (tessellated area) of a CTRLandScape
//
class CTRPatch
{
private:
class CCMLandScape *owner;
class CTRLandScape *localowner;
CCMPatch *common;
vec3_t mCenter; // Real world center of the patch
// vec3_t mNormal[2];
// float mDistance[2];
CTerVert *mRenderMap; // Modulation value and texture coords per vertex
shader_t *mTLShader; // Dynamically created blended shader for the top left triangle
shader_t *mBRShader; // Dynamically created blended shader for the bottom right triangle
bool misVisible; // Is this patch visible in the current frame?
public:
CTRPatch(void) { }
~CTRPatch(void) { }
// Accessors
const vec3_t &GetWorld(void) const { return(common->GetWorld()); }
const vec3_t &GetMins(void) const { return(common->GetMins()); }
const vec3_t &GetMaxs(void) const { return(common->GetMaxs()); }
const vec3pair_t &GetBounds(void) const { return(common->GetBounds()); }
shader_t *GetTLShader(void) { return mTLShader; }
shader_t *GetBRShader(void) { return mBRShader; }
void SetCommon(CCMPatch *in) { common = in; }
const CCMPatch *GetCommon(void) const { return(common); }
bool isVisible(void) { return(misVisible); }
void SetTLShader(qhandle_t in) { mTLShader = R_GetShaderByHandle(in); }
void SetBRShader(qhandle_t in) { mBRShader = R_GetShaderByHandle(in); }
void SetOwner(CCMLandScape *in) { owner = in; }
void SetLocalOwner(CTRLandScape *in) { localowner = in; }
void Clear(void) { memset(this, 0, sizeof(*this)); }
void SetCenter(void) { VectorAverage(common->GetMins(), common->GetMaxs(), mCenter); }
void CalcNormal(void);
// Prototypes
void SetVisibility(bool visCheck);
void RenderCorner(ivec5_t corner);
void Render(int Part);
void RecurseRender(int depth, ivec5_t left, ivec5_t right, ivec5_t apex);
void SetRenderMap(const int x, const int y);
int RenderWaterVert(int x, int y);
void RenderWater(void);
const bool HasWater(void) const;
};
#define PI_TOP 1
#define PI_BOTTOM 2
#define PI_BOTH 3
typedef struct SPatchInfo
{
CTRPatch *mPatch;
shader_t *mShader;
int mPart;
} TPatchInfo;
//
// The master class used to define an area of terrain
//
class CTRLandScape
{
private:
const CCMLandScape *common;
CTRPatch *mTRPatches; // Local patch info
TPatchInfo *mSortedPatches;
int mPatchMinx, mPatchMaxx;
int mPatchMiny, mPatchMaxy;
int mMaxNode; // terxels * terxels = exit condition for splitting
int mSortedCount;
float mPatchSize;
shader_t *mShader; // shader the terrain got its contents from
CTerVert *mRenderMap; // modulation value and texture coords per vertex
float mTextureScale; // Scale of texture mapped to terrain
float mScalarSize;
shader_t *mWaterShader; // Water shader
qhandle_t mFlatShader; // Flat ground shader
CTRHeightDetails mHeightDetails[HEIGHT_RESOLUTION]; // Array of info specific to height
#if _DEBUG
int mCycleCount;
#endif
public:
CTRLandScape(const char *configstring);
~CTRLandScape(void);
// Accessors
const int GetBlockWidth(void) const { return(common->GetBlockWidth()); }
const int GetBlockHeight(void) const { return(common->GetBlockHeight()); }
const vec3_t &GetMins(void) const { return(common->GetMins()); }
const vec3_t &GetMaxs(void) const { return(common->GetMaxs()); }
const vec3_t &GetTerxelSize(void) const { return(common->GetTerxelSize()); }
const vec3_t &GetPatchSize(void) const { return(common->GetPatchSize()); }
const int GetWidth(void) const { return(common->GetWidth()); }
const int GetHeight(void) const { return(common->GetHeight()); }
const int GetRealWidth(void) const { return(common->GetRealWidth()); }
const int GetRealHeight(void) const { return(common->GetRealHeight()); }
void SetCommon(const CCMLandScape *landscape) { common = landscape; }
const CCMLandScape *GetCommon( void ) const { return(common); }
const thandle_t GetCommonId( void ) const { return(common->GetTerrainId()); }
shader_t *GetShader(void) const { return(mShader); }
CTerVert *GetRenderMap(const int x, const int y) const { return(mRenderMap + x + (y * common->GetRealWidth())); }
CTRPatch *GetPatch(const int x, const int y) const { return(mTRPatches + (common->GetBlockWidth() * y) + x); }
const CTRHeightDetails *GetHeightDetail(int height) const { return(mHeightDetails + height); }
const float GetScalarSize(void) const { return(mScalarSize); }
const int GetMaxNode(void) const { return(mMaxNode); }
// Prototypes
void CalculateRegion(void);
void Reset(bool visCheck = true);
void Render(void);
void CalculateRealCoords(void);
void CalculateNormals(void);
void CalculateTextureCoords(void);
void CalculateLighting(void);
void CalculateShaders(void);
qhandle_t GetBlendedShader(qhandle_t a, qhandle_t b, qhandle_t c, bool surfaceSprites);
void LoadTerrainDef(const char *td);
void CopyHeightMap(void);
void SetShaders(const int height, const qhandle_t shader);
};
void R_CalcTerrainVisBounds(CTRLandScape *landscape);
void R_AddTerrainSurfaces(void);
#endif //INC_LANDSCAPE_H

View File

@@ -0,0 +1,475 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
// tr_light.c
#include "tr_local.h"
#define DLIGHT_AT_RADIUS 16
// at the edge of a dlight's influence, this amount of light will be added
#define DLIGHT_MINIMUM_RADIUS 16
// never calculate a range less than this to prevent huge light numbers
/*
===============
R_TransformDlights
Transforms the origins of an array of dlights.
Used by both the front end (for DlightBmodel) and
the back end (before doing the lighting calculation)
===============
*/
void R_TransformDlights( int count, dlight_t *dl, orientationr_t *ori) {
int i;
vec3_t temp;
for ( i = 0 ; i < count ; i++, dl++ ) {
VectorSubtract( dl->origin, ori->origin, temp );
dl->transformed[0] = DotProduct( temp, ori->axis[0] );
dl->transformed[1] = DotProduct( temp, ori->axis[1] );
dl->transformed[2] = DotProduct( temp, ori->axis[2] );
}
}
/*
=============
R_DlightBmodel
Determine which dynamic lights may effect this bmodel
=============
*/
void R_DlightBmodel( bmodel_t *bmodel, bool NoLight )
{ //rwwRMG - modified args
int i, j;
dlight_t *dl;
int mask;
msurface_t *surf;
// transform all the lights
R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.ori );
mask = 0;
if (!NoLight)
{
for ( i=0 ; i<tr.refdef.num_dlights ; i++ ) {
dl = &tr.refdef.dlights[i];
// see if the point is close enough to the bounds to matter
for ( j = 0 ; j < 3 ; j++ ) {
if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {
break;
}
if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {
break;
}
}
if ( j < 3 ) {
continue;
}
// we need to check this light
mask |= 1 << i;
}
}
tr.currentEntity->needDlights = (qboolean)(mask != 0);
tr.currentEntity->dlightBits = mask;
// set the dlight bits in all the surfaces
for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
surf = bmodel->firstSurface + i;
if ( *surf->data == SF_FACE ) {
((srfSurfaceFace_t *)surf->data)->dlightBits = mask;
} else if ( *surf->data == SF_GRID ) {
((srfGridMesh_t *)surf->data)->dlightBits = mask;
} else if ( *surf->data == SF_TRIANGLES ) {
((srfTriangles_t *)surf->data)->dlightBits = mask;
}
}
}
/*
=============================================================================
LIGHT SAMPLING
=============================================================================
*/
extern cvar_t *r_ambientScale;
extern cvar_t *r_directedScale;
extern cvar_t *r_debugLight;
//rwwRMG - VectorScaleVector is now a #define
/*
=================
R_SetupEntityLightingGrid
=================
*/
static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
vec3_t lightOrigin;
int pos[3];
int i, j;
float frac[3];
int gridStep[3];
vec3_t direction;
float totalFactor;
unsigned short *startGridPos;
#ifdef _XBOX
byte zeroArray[3];
byte style;
zeroArray[0] = zeroArray[1] = zeroArray[2] = 0;
#endif
if (r_fullbright->integer)
{
ent->ambientLight[0] = ent->ambientLight[1] = ent->ambientLight[2] = 255.0;
ent->directedLight[0] = ent->directedLight[1] = ent->directedLight[2] = 255.0;
VectorCopy( tr.sunDirection, ent->lightDir );
return;
}
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
// seperate lightOrigins are needed so an object that is
// sinking into the ground can still be lit, and so
// multi-part models can be lit identically
VectorCopy( ent->e.lightingOrigin, lightOrigin );
} else {
VectorCopy( ent->e.origin, lightOrigin );
}
VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
for ( i = 0 ; i < 3 ; i++ ) {
float v;
v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
pos[i] = floor( v );
frac[i] = v - pos[i];
if ( pos[i] < 0 ) {
pos[i] = 0;
} else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
pos[i] = tr.world->lightGridBounds[i] - 1;
}
}
VectorClear( ent->ambientLight );
VectorClear( ent->directedLight );
VectorClear( direction );
// trilerp the light value
gridStep[0] = 1;
gridStep[1] = tr.world->lightGridBounds[0];
gridStep[2] = tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
startGridPos = tr.world->lightGridArray + (pos[0] * gridStep[0] + pos[1] * gridStep[1] + pos[2] * gridStep[2]);
totalFactor = 0;
for ( i = 0 ; i < 8 ; i++ ) {
float factor;
mgrid_t *data;
unsigned short *gridPos;
int lat, lng;
vec3_t normal;
factor = 1.0;
gridPos = startGridPos;
for ( j = 0 ; j < 3 ; j++ ) {
if ( i & (1<<j) ) {
factor *= frac[j];
gridPos += gridStep[j];
} else {
factor *= (1.0 - frac[j]);
}
}
if (gridPos >= tr.world->lightGridArray + tr.world->numGridArrayElements)
{//we've gone off the array somehow
continue;
}
data = tr.world->lightGridData + *gridPos;
#ifdef _XBOX
const byte *memory = (const byte *)tr.world->lightGridData + data->data;
style = data->flags & (1 << 4) ? memory[0] : LS_LSNONE;
if ( style == LS_LSNONE )
{
continue; // ignore samples in walls
}
totalFactor += factor;
const byte *array;
for(j=0;j<MAXLIGHTMAPS;j++)
{
if(data->flags & (1 << (j + 4))) {
style = *memory;
memory++;
} else {
style = LS_LSNONE;
}
if (style != LS_LSNONE)
{
if(data->flags & (1 << j)) {
array = memory;
memory += 3;
} else {
array = zeroArray;
}
ent->ambientLight[0] += factor * array[0] * styleColors[style][0] / 255.0f;
ent->ambientLight[1] += factor * array[1] * styleColors[style][1] / 255.0f;
ent->ambientLight[2] += factor * array[2] * styleColors[style][2] / 255.0f;
if(array != zeroArray) {
array = memory;
memory += 3;
}
ent->directedLight[0] += factor * array[0] * styleColors[style][0] / 255.0f;
ent->directedLight[1] += factor * array[1] * styleColors[style][1] / 255.0f;
ent->directedLight[2] += factor * array[2] * styleColors[style][2] / 255.0f;
}
else
{
break;
}
}
#else // _XBOX
if ( data->styles[0] == LS_LSNONE )
{
continue; // ignore samples in walls
}
totalFactor += factor;
for(j=0;j<MAXLIGHTMAPS;j++)
{
if (data->styles[j] != LS_LSNONE)
{
const byte style= data->styles[j];
ent->ambientLight[0] += factor * data->ambientLight[j][0] * styleColors[style][0] / 255.0f;
ent->ambientLight[1] += factor * data->ambientLight[j][1] * styleColors[style][1] / 255.0f;
ent->ambientLight[2] += factor * data->ambientLight[j][2] * styleColors[style][2] / 255.0f;
ent->directedLight[0] += factor * data->directLight[j][0] * styleColors[style][0] / 255.0f;
ent->directedLight[1] += factor * data->directLight[j][1] * styleColors[style][1] / 255.0f;
ent->directedLight[2] += factor * data->directLight[j][2] * styleColors[style][2] / 255.0f;
}
else
{
break;
}
}
#endif // _XBOX
lat = data->latLong[1];
lng = data->latLong[0];
lat *= (FUNCTABLE_SIZE/256);
lng *= (FUNCTABLE_SIZE/256);
// decode X as cos( lat ) * sin( long )
// decode Y as sin( lat ) * sin( long )
// decode Z as cos( long )
normal[0] = tr.sinTable[(lat + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK] * tr.sinTable[lng];
normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
normal[2] = tr.sinTable[(lng + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK];
VectorMA( direction, factor, normal, direction );
}
if ( totalFactor > 0 && totalFactor < 0.99 )
{
totalFactor = 1.0 / totalFactor;
VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
VectorScale( ent->directedLight, totalFactor, ent->directedLight );
}
VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
VectorNormalize2( direction, ent->lightDir );
}
/*
===============
LogLight
===============
*/
static void LogLight( trRefEntity_t *ent ) {
int max1, max2;
if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) {
return;
}
max1 = ent->ambientLight[0];
if ( ent->ambientLight[1] > max1 ) {
max1 = ent->ambientLight[1];
} else if ( ent->ambientLight[2] > max1 ) {
max1 = ent->ambientLight[2];
}
max2 = ent->directedLight[0];
if ( ent->directedLight[1] > max2 ) {
max2 = ent->directedLight[1];
} else if ( ent->directedLight[2] > max2 ) {
max2 = ent->directedLight[2];
}
Com_Printf ("amb:%i dir:%i\n", max1, max2 );
}
/*
=================
R_SetupEntityLighting
Calculates all the lighting values that will be used
by the Calc_* functions
=================
*/
void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
int i;
dlight_t *dl;
float power;
vec3_t dir;
float d;
vec3_t lightDir;
vec3_t lightOrigin;
// lighting calculations
if ( ent->lightingCalculated ) {
return;
}
ent->lightingCalculated = qtrue;
//
// trace a sample point down to find ambient light
//
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
// seperate lightOrigins are needed so an object that is
// sinking into the ground can still be lit, and so
// multi-part models can be lit identically
VectorCopy( ent->e.lightingOrigin, lightOrigin );
} else {
VectorCopy( ent->e.origin, lightOrigin );
}
// if NOWORLDMODEL, only use dynamic lights (menu system, etc)
if ( !(refdef->rdflags & RDF_NOWORLDMODEL )
&& tr.world->lightGridData ) {
R_SetupEntityLightingGrid( ent );
} else {
ent->ambientLight[0] = ent->ambientLight[1] =
ent->ambientLight[2] = tr.identityLight * 150;
ent->directedLight[0] = ent->directedLight[1] =
ent->directedLight[2] = tr.identityLight * 150;
VectorCopy( tr.sunDirection, ent->lightDir );
}
// bonus items and view weapons have a fixed minimum add
if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) {
// give everything a minimum light add
ent->ambientLight[0] += tr.identityLight * 32;
ent->ambientLight[1] += tr.identityLight * 32;
ent->ambientLight[2] += tr.identityLight * 32;
}
if (ent->e.renderfx & RF_MINLIGHT)
{ //the minlight flag is now for items rotating on their holo thing
if (ent->e.shaderRGBA[0] == 255 &&
ent->e.shaderRGBA[1] == 255 &&
ent->e.shaderRGBA[2] == 0)
{
ent->ambientLight[0] += tr.identityLight * 255;
ent->ambientLight[1] += tr.identityLight * 255;
ent->ambientLight[2] += tr.identityLight * 0;
}
else
{
ent->ambientLight[0] += tr.identityLight * 16;
ent->ambientLight[1] += tr.identityLight * 96;
ent->ambientLight[2] += tr.identityLight * 150;
}
}
//
// modify the light by dynamic lights
//
d = VectorLength( ent->directedLight );
VectorScale( ent->lightDir, d, lightDir );
for ( i = 0 ; i < refdef->num_dlights ; i++ ) {
dl = &refdef->dlights[i];
VectorSubtract( dl->origin, lightOrigin, dir );
d = VectorNormalize( dir );
power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );
if ( d < DLIGHT_MINIMUM_RADIUS ) {
d = DLIGHT_MINIMUM_RADIUS;
}
d = power / ( d * d );
VectorMA( ent->directedLight, d, dl->color, ent->directedLight );
VectorMA( lightDir, d, dir, lightDir );
}
// clamp ambient
for ( i = 0 ; i < 3 ; i++ ) {
if ( ent->ambientLight[i] > tr.identityLightByte ) {
ent->ambientLight[i] = tr.identityLightByte;
}
}
if ( r_debugLight->integer ) {
LogLight( ent );
}
// save out the byte packet version
((byte *)&ent->ambientLightInt)[0] = myftol( ent->ambientLight[0] );
((byte *)&ent->ambientLightInt)[1] = myftol( ent->ambientLight[1] );
((byte *)&ent->ambientLightInt)[2] = myftol( ent->ambientLight[2] );
((byte *)&ent->ambientLightInt)[3] = 0xff;
// transform the direction to local space
VectorNormalize( lightDir );
ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] );
ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] );
ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] );
}
/*
=================
R_LightForPoint
=================
*/
int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )
{
trRefEntity_t ent;
// bk010103 - this segfaults with -nolight maps
if ( tr.world->lightGridData == NULL )
return qfalse;
Com_Memset(&ent, 0, sizeof(ent));
VectorCopy( point, ent.e.origin );
R_SetupEntityLightingGrid( &ent );
VectorCopy(ent.ambientLight, ambientLight);
VectorCopy(ent.directedLight, directedLight);
VectorCopy(ent.lightDir, lightDir);
return qtrue;
}

View File

@@ -0,0 +1,882 @@
/*
** tr_lightmanager.cpp
*/
#ifdef VV_LIGHTING
#include "../server/exe_headers.h"
#include "tr_local.h"
#include "../win32/glw_win_dx8.h"
#include "../win32/win_lighteffects.h"
#include "../cgame/cg_local.h"
#include "modelmem.h"
extern int r_numdlights;
extern int r_firstSceneDlight;
VVLightManager VVLightMan;
VVLightManager::VVLightManager()
{
}
void VVLightManager::RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
VVdlight_t *dl;
if ( !tr.registered ) {
return;
}
if ( r_numdlights >= MAX_DLIGHTS ) {
return;
}
if ( intensity <= 0 ) {
return;
}
dl = &backEndData->dlights[r_numdlights++];
VectorCopy (org, dl->origin);
dl->type = LT_POINT;
dl->radius = intensity;// * 2.0f;
dl->color[0] = r;
dl->color[1] = g;
dl->color[2] = b;
}
void VVLightManager::RE_AddLightToScene( VVdlight_t *light )
{
VVdlight_t *dl;
if ( !tr.registered ) {
return;
}
if( r_numdlights >= MAX_DLIGHTS ) {
return;
}
dl = &backEndData->dlights[r_numdlights++];
VectorCopy(light->origin, dl->origin);
VectorCopy(light->direction, dl->direction);
VectorCopy(light->color, dl->color);
dl->attenuation = light->attenuation;
dl->type = light->type;
dl->radius = light->radius;
}
//void VVLightManager::RE_AddStaticLightToScene( VVslight_t *light )
//{
// VVslight_t *sl;
//
// if( !tr.registered ) {
// return;
// }
//
// if( num_slights >= MAX_NUM_STATIC_LIGHTS ) {
// return;
// }
//
// sl = &slights[num_slights++];
//
// VectorCopy(light->origin, sl->origin);
// VectorCopy(light->color, sl->color);
// sl->radius = light->radius;// * 2.0f;
//}
void VVLightManager::R_TransformDlights( int count, VVdlight_t *dl, orientationr_t *ori) {
int i;
vec3_t temp;
for ( i = 0; i < count; i++ ) {
VectorSubtract( dl->origin, ori->origin, temp );
dl->transformed[0] = DotProduct( temp, ori->axis[0] );
dl->transformed[1] = DotProduct( temp, ori->axis[1] );
dl->transformed[2] = DotProduct( temp, ori->axis[2] );
}
}
/*
=============
R_DlightBmodel
Determine which dynamic lights may effect this bmodel
=============
*/
void VVLightManager::R_DlightBmodel( bmodel_t *bmodel, qboolean NoLight ) {
int i, j;
VVdlight_t *dl;
int mask;
msurface_t *surf;
mask = 0;
// transform all the lights
R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.ori );
if (!NoLight)
{
for ( i = 0; i < tr.refdef.num_dlights; i++ ) {
dl = &tr.refdef.dlights[i];
// see if the point is close enough to the bounds to matter
for ( j = 0 ; j < 3 ; j++ ) {
if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {
break;
}
if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {
break;
}
}
// Directional lights are always considered (MATT - change that?)
if ( j < 3 && dl->type != LT_DIRECTIONAL ) {
continue;
}
// we need to check this light
mask |= 1 << i;
}
}
tr.currentEntity->needDlights = (mask != 0);
// set the dlight bits in all the surfaces
for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
surf = bmodel->firstSurface + i;
if ( *surf->data == SF_FACE ) {
((srfSurfaceFace_t *)surf->data)->dlightBits = mask;
} else if ( *surf->data == SF_GRID ) {
((srfGridMesh_t *)surf->data)->dlightBits = mask;
} else if ( *surf->data == SF_TRIANGLES ) {
((srfTriangles_t *)surf->data)->dlightBits = mask;
}
}
}
int VVLightManager::R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) {
float d;
int i;
VVdlight_t *dl;
for ( i = 0; i < tr.refdef.num_dlights; i++ ) {
if ( ! ( dlightBits & ( 1 << i ) ) ) {
continue;
}
dl = &tr.refdef.dlights[i];
d = DotProduct( dl->origin, face->plane.normal ) - face->plane.dist;
// Directional lights are always considered (MATT - change that?)
if ( d < -dl->radius || d > dl->radius ) {
// dlight doesn't reach the plane
dlightBits &= ~( 1 << i );
}
}
if ( !dlightBits ) {
tr.pc.c_dlightSurfacesCulled++;
}
face->dlightBits = dlightBits;
return dlightBits;
}
//void VVLightManager::R_SlightFace( srfSurfaceFace_t *face ) {
// float d;
// int i, count = 0;
// VVslight_t *sl;
//
// for ( i = 0; i < num_slights; i++ ) {
//
// if(count > MAX_STATIC_LIGHTS_SURFACE - 1)
// break;
//
// sl = &slights[i];
// d = DotProduct( sl->origin, face->plane.normal ) - face->plane.dist;
//
// if ( d > -sl->radius && d < sl->radius ) {
// face->slightBits[count++] = i;
// }
// }
//}
int VVLightManager::R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) {
int i;
VVdlight_t *dl;
for ( i = 0; i < tr.refdef.num_dlights ; i++ ) {
if ( ! ( dlightBits & ( 1 << i ) ) ) {
continue;
}
dl = &tr.refdef.dlights[i];
// Directional lights are always considered (MATT - change that?)
if (( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
|| dl->origin[0] + dl->radius < grid->meshBounds[0][0]
|| dl->origin[1] - dl->radius > grid->meshBounds[1][1]
|| dl->origin[1] + dl->radius < grid->meshBounds[0][1]
|| dl->origin[2] - dl->radius > grid->meshBounds[1][2]
|| dl->origin[2] + dl->radius < grid->meshBounds[0][2] )
&& dl->type != LT_DIRECTIONAL ) {
// dlight doesn't reach the bounds
dlightBits &= ~( 1 << i );
}
dlightBits |= (1 << i );
}
if ( !dlightBits ) {
tr.pc.c_dlightSurfacesCulled++;
}
grid->dlightBits = dlightBits;
return dlightBits;
}
//void VVLightManager::R_SlightGrid( srfGridMesh_t *grid ) {
// int i, count = 0;
// VVslight_t *sl;
//
// for ( i = 0 ; i < num_slights ; i++ ) {
//
// if(count > MAX_STATIC_LIGHTS_SURFACE - 1)
// break;
//
// sl = &slights[i];
//
// if ( sl->origin[0] - sl->radius > grid->meshBounds[1][0]
// || sl->origin[0] + sl->radius < grid->meshBounds[0][0]
// || sl->origin[1] - sl->radius > grid->meshBounds[1][1]
// || sl->origin[1] + sl->radius < grid->meshBounds[0][1]
// || sl->origin[2] - sl->radius > grid->meshBounds[1][2]
// || sl->origin[2] + sl->radius < grid->meshBounds[0][2] ) {
// // slight doesn't reach the bounds
// }
// else
// {
// grid->slightBits[count++]= i;
// }
// }
//}
int VVLightManager::R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) {
// FIXME: more dlight culling to trisurfs...
surf->dlightBits = dlightBits;
return dlightBits;
}
//void VVLightManager::R_SlightTrisurf( srfTriangles_t *surf ) {
// /*int i;
//
// for( i = 0; i < num_slights; i++ )
// {
// slightBits[i] = 1;
// }*/
//}
/*
====================
R_DlightSurface
The given surface is going to be drawn, and it touches a leaf
that is touched by one or more dlights, so try to throw out
more dlights if possible.
====================
*/
int VVLightManager::R_DlightSurface( msurface_t *surf, int dlightBits ) {
if ( *surf->data == SF_FACE ) {
dlightBits = VVLightManager::R_DlightFace( (srfSurfaceFace_t *)surf->data, dlightBits );
} else if ( *surf->data == SF_GRID ) {
dlightBits = VVLightManager::R_DlightGrid( (srfGridMesh_t *)surf->data, dlightBits );
} else if ( *surf->data == SF_TRIANGLES ) {
dlightBits = VVLightManager::R_DlightTrisurf( (srfTriangles_t *)surf->data, dlightBits );
} else {
dlightBits = 0;
}
if ( dlightBits ) {
tr.pc.c_dlightSurfaces++;
}
return dlightBits;
}
/*
=================
R_SetupEntityLighting
Calculates all the lighting values that will be used
by the Calc_* functions
=================
*/
#define DLIGHT_AT_RADIUS 16
#define DLIGHT_MINIMUM_RADIUS 16
void VVLightManager::R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
int i;
VVdlight_t *dl;
float power;
vec3_t dir;
float d;
vec3_t lightDir;
vec3_t lightOrigin;
// lighting calculations
if ( ent->lightingCalculated ) {
return;
}
ent->lightingCalculated = qtrue;
//
// trace a sample point down to find ambient light
//
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
// seperate lightOrigins are needed so an object that is
// sinking into the ground can still be lit, and so
// multi-part models can be lit identically
VectorCopy( ent->e.lightingOrigin, lightOrigin );
} else {
VectorCopy( ent->e.origin, lightOrigin );
}
// if NOWORLDMODEL, only use dynamic lights (menu system, etc)
if ( !(refdef->rdflags & RDF_NOWORLDMODEL )
&& tr.world->lightGridData ) {
R_SetupEntityLightingGrid( ent );
} else {
ent->ambientLight[0] = ent->ambientLight[1] =
ent->ambientLight[2] = tr.identityLight * 150;
ent->directedLight[0] = ent->directedLight[1] =
ent->directedLight[2] = tr.identityLight * 150;
// BTO - Fix for UI model rendering. tr.sunDirection is invalid
// pick an arbitrary light direction
// VectorCopy( tr.sunDirection, ent->lightDir );
ent->lightDir[0] = ent->lightDir[1] = 0.0f;
ent->lightDir[2] = 1.0f;
}
// give everything a minimum light add
ent->ambientLight[0] += tr.identityLight * 32;
ent->ambientLight[1] += tr.identityLight * 32;
ent->ambientLight[2] += tr.identityLight * 32;
if (ent->e.renderfx & RF_MINLIGHT)
{ //the minlight flag is now for items rotating on their holo thing
if (ent->e.shaderRGBA[0] == 255 &&
ent->e.shaderRGBA[1] == 255 &&
ent->e.shaderRGBA[2] == 0)
{
ent->ambientLight[0] += tr.identityLight * 255;
ent->ambientLight[1] += tr.identityLight * 255;
ent->ambientLight[2] += tr.identityLight * 0;
}
else
{
ent->ambientLight[0] += tr.identityLight * 16;
ent->ambientLight[1] += tr.identityLight * 96;
ent->ambientLight[2] += tr.identityLight * 150;
}
}
//
// modify the light by dynamic lights
//
d = VectorLength( ent->directedLight );
VectorScale( ent->lightDir, d, lightDir );
for ( i = 0; i < refdef->num_dlights; i++ ) {
dl = &refdef->dlights[i];
VectorSubtract( dl->origin, lightOrigin, dir );
d = VectorNormalize( dir );
power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );
if ( d < DLIGHT_MINIMUM_RADIUS ) {
d = DLIGHT_MINIMUM_RADIUS;
}
d = power / ( d * d );
VectorMA( ent->directedLight, d, dl->color, ent->directedLight );
VectorMA( lightDir, d, dir, lightDir );
}
// clamp
for ( i = 0 ; i < 3 ; i++ ) {
if ( ent->ambientLight[i] > tr.identityLightByte ) {
ent->ambientLight[i] = tr.identityLightByte;
}
if ( ent->directedLight[i] > tr.identityLightByte ) {
ent->directedLight[i] = tr.identityLightByte;
}
}
// save out the byte packet version
((byte *)&ent->ambientLightInt)[0] = myftol( ent->ambientLight[0] );
((byte *)&ent->ambientLightInt)[1] = myftol( ent->ambientLight[1] );
((byte *)&ent->ambientLightInt)[2] = myftol( ent->ambientLight[2] );
((byte *)&ent->ambientLightInt)[3] = 0xff;
// transform the direction to local space
VectorNormalize( lightDir );
ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] );
ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] );
ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] );
VectorNormalize( ent->lightDir );
}
inline void Short2Float(float *f, const short *s)
{
*f = ((float)*s);
}
void VVLightManager::ShortToVec3(const short in[3], vec3_t &out)
{
Short2Float(&out[0], &in[0]);
Short2Float(&out[1], &in[1]);
Short2Float(&out[2], &in[2]);
}
int VVLightManager::BoxOnPlaneSide (const short emins[3], const short emaxs[3], struct cplane_s *p)
{
vec3_t mins;
vec3_t maxs;
ShortToVec3(emins, mins);
ShortToVec3(emaxs, maxs);
return ::BoxOnPlaneSide(mins, maxs, &tr.viewParms.frustum[0]);
}
void VVLightManager::R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) {
do {
int newDlights[2];
// if the node wasn't marked as potentially visible, exit
if (node->visframe != tr.visCount) {
return;
}
// if the bounding volume is outside the frustum, nothing
// inside can be visible OPTIMIZE: don't do this all the way to leafs?
if ( !r_nocull->integer ) {
int r;
if ( planeBits & 1 ) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
planeBits &= ~1; // all descendants will also be in front
}
}
if ( planeBits & 2 ) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
planeBits &= ~2; // all descendants will also be in front
}
}
if ( planeBits & 4 ) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
planeBits &= ~4; // all descendants will also be in front
}
}
if ( planeBits & 8 ) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
planeBits &= ~8; // all descendants will also be in front
}
}
}
if ( node->contents != -1 ) {
break;
}
// node is just a decision point, so go down both sides
// since we don't care about sort orders, just go positive to negative
// determine which dlights are needed
newDlights[0] = 0;
newDlights[1] = 0;
if ( dlightBits ) {
int i;
for ( i = 0; i < tr.refdef.num_dlights; i++ ) {
VVdlight_t *dl;
float dist;
if ( dlightBits & ( 1 << i ) ) {
dl = &tr.refdef.dlights[i];
dist = DotProduct( dl->origin,
tr.world->planes[node->planeNum].normal ) -
tr.world->planes[node->planeNum].dist;
if ( dist > -dl->radius ) {
newDlights[0] |= ( 1 << i );
}
if ( dist < dl->radius ) {
newDlights[1] |= ( 1 << i );
}
}
}
}
// recurse down the children, front side first
R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] );
// tail recurse
node = node->children[1];
dlightBits = newDlights[1];
} while ( 1 );
{
// leaf node, so add mark surfaces
int c;
msurface_t *surf, **mark;
mleaf_s *leaf;
tr.pc.c_leafs++;
// add to z buffer bounds
if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {
tr.viewParms.visBounds[0][0] = node->mins[0];
}
if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {
tr.viewParms.visBounds[0][1] = node->mins[1];
}
if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {
tr.viewParms.visBounds[0][2] = node->mins[2];
}
if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {
tr.viewParms.visBounds[1][0] = node->maxs[0];
}
if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {
tr.viewParms.visBounds[1][1] = node->maxs[1];
}
if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {
tr.viewParms.visBounds[1][2] = node->maxs[2];
}
// add the individual surfaces
leaf = (mleaf_s*)node;
mark = tr.world->marksurfaces + leaf->firstMarkSurfNum;
c = leaf->nummarksurfaces;
while (c--) {
// the surface may have already been added if it
// spans multiple leafs
surf = *mark;
R_AddWorldSurface( surf, dlightBits );
mark++;
}
}
}
void VVLightManager::RB_CalcDiffuseColor( DWORD *colors )
{
trRefEntity_t *ent;
ent = backEnd.currentEntity;
// Make sure to turn lighting on....
qglEnable(GL_LIGHTING);
qglLightfv(0, GL_AMBIENT, ent->ambientLight);
qglLightfv(0, GL_DIFFUSE, ent->directedLight);
if(VectorLengthSquared(ent->lightDir) <= 0.0001f)
{
ent->lightDir[0] = 0.0f;
ent->lightDir[1] = 1.0f;
ent->lightDir[2] = 0.0f;
}
qglLightfv(0, GL_SPOT_DIRECTION, ent->lightDir);
/*if(VectorLengthSquared(ent->dlightDir) > 0.0f && ModelMem.inUI == false)
{
qglLightfv(1, GL_AMBIENT, ent->ambientLight);
qglLightfv(1, GL_DIFFUSE, ent->dynamicLight);
qglLightfv(1, GL_SPOT_DIRECTION, ent->dlightDir);
}*/
memset(colors, 0xffffffff, sizeof(DWORD) * tess.numVertexes);
}
void VVLightManager::RB_CalcDiffuseEntityColor( DWORD *colors )
{
if ( !backEnd.currentEntity )
{//error, use the normal lighting
RB_CalcDiffuseColor(colors);
}
trRefEntity_t *ent;
ent = backEnd.currentEntity;
// Make sure to turn lighting on....
qglEnable(GL_LIGHTING);
// Modulate ambient by entity color:
vec3_t ambient;
ambient[0] = ent->ambientLight[0] * (ent->e.shaderRGBA[0]/255.0);
ambient[1] = ent->ambientLight[1] * (ent->e.shaderRGBA[1]/255.0);
ambient[2] = ent->ambientLight[2] * (ent->e.shaderRGBA[2]/255.0);
qglLightfv(0, GL_AMBIENT, ambient);
qglLightfv(0, GL_DIFFUSE, ent->directedLight);
VectorNormalize(ent->lightDir);
if(VectorLengthSquared(ent->lightDir) <= 0.0001f)
{
ent->lightDir[0] = 0.0f;
ent->lightDir[1] = 1.0f;
ent->lightDir[2] = 0.0f;
}
qglLightfv(0, GL_SPOT_DIRECTION, ent->lightDir);
/*if(VectorLengthSquared(ent->dlightDir) > 0.0f && ModelMem.inUI == false)
{
qglLightfv(1, GL_AMBIENT, ent->ambientLight);
qglLightfv(1, GL_DIFFUSE, ent->dynamicLight);
qglLightfv(1, GL_SPOT_DIRECTION, ent->dlightDir);
}*/
DWORD color = D3DCOLOR_RGBA(backEnd.currentEntity->e.shaderRGBA[0],
backEnd.currentEntity->e.shaderRGBA[1],
backEnd.currentEntity->e.shaderRGBA[2],
backEnd.currentEntity->e.shaderRGBA[3]);
memset(colors, color, sizeof(DWORD) * tess.numVertexes);
}
//void R_LoadLevelLightdef(const char *filename)
//{
// const char *text;
// const char *curText;
// char *token;
// VVslight_t light;
//
// VVLightMan.num_slights = 0;
//
// if ( ri.FS_ReadFile( filename, (void**)&curText ) <= 0 )
// {
// ri.Printf( PRINT_WARNING, "WARNING: no lightdef file found\n" );
// return;
// }
//
// text = curText;
//
// while(1)
// {
// token = COM_ParseExt( &text, qtrue );
// if(!token[0])
// break;
//
// // Skip to the light's origin
// while(strcmp(token, "origin"))
// {
// token = COM_ParseExt( &text, qtrue );
// if(!token[0])
// break;
// }
//
// // Write the origin
// // X
// token = COM_ParseExt( &text, qtrue );
// if(!token[0])
// break;
// light.origin[0] = atof(token);
//
// // Y
// token = COM_ParseExt( &text, qtrue );
// if(!token[0])
// break;
// light.origin[1] = atof(token);
//
// // Z
// token = COM_ParseExt( &text, qtrue );
// if(!token[0])
// break;
// light.origin[2] = atof(token);
//
// // Skip to the light's range
// while(strcmp(token, "light"))
// {
// token = COM_ParseExt( &text, qtrue );
// if(!token[0])
// break;
// }
//
// // Write the light range
// token = COM_ParseExt( &text, qtrue );
// if(!token[0])
// break;
// light.radius = atof(token);
//
// // Default color for now
// light.color[0] = 1.0f;
// light.color[1] = 1.0f;
// light.color[2] = 1.0f;
//
// VVLightMan.RE_AddStaticLightToScene(&light);
// }
//
// ri.FS_FreeFile( (void*)curText );
//}
#define MAX_LIGHT_TABLE 55
static levelLightParm_t _levelLightParms[MAX_LIGHT_TABLE];
static bool isLightInit = false;
static void ClearLightParmTable(void)
{
memset(_levelLightParms, 0, sizeof(levelLightParm_t) * MAX_LIGHT_TABLE);
isLightInit = false;
}
/*
**
** R_GetLightParmsForLevel
**
*/
void R_GetLightParmsForLevel()
{
if(!isLightInit)
return;
char levelname[64];
COM_StripExtension(tr.world->baseName, levelname);
for(int i = 0; i < MAX_LIGHT_TABLE; i++)
{
if(Q_stricmp(COM_SkipPath(levelname), _levelLightParms[i].levelName) == 0)
{
if(VectorLength(_levelLightParms[i].sundir))
{
Cvar_SetValue("r_sundir_x", _levelLightParms[i].sundir[0]);
Cvar_SetValue("r_sundir_y", _levelLightParms[i].sundir[1]);
Cvar_SetValue("r_sundir_z", _levelLightParms[i].sundir[2]);
}
if(_levelLightParms[i].hdrEnable)
Cvar_Set("r_hdreffect", "1");
else
Cvar_Set("r_hdreffect", "0");
Cvar_SetValue("r_hdrbloom", _levelLightParms[i].hdrBloom);
}
}
}
/*
**
** R_LoadLevelFogTable
**
*/
void R_LoadLevelLightParms()
{
const char *lightText;
const char *curText;
char *token;
int level = 0;
if ( FS_ReadFile( "shaders/lightparms.txt", (void**)&curText ) <= 0 )
{
Com_Printf( "WARNING: no light parms file found\n" );
return;
}
ClearLightParmTable();
lightText = curText;
while(1)
{
// Level name
token = COM_ParseExt( &lightText, qtrue );
if(!token[0])
break;
strcpy( _levelLightParms[level].levelName, token );
// Sun dir X
token = COM_ParseExt( &lightText, qtrue );
if(!token[0])
break;
_levelLightParms[level].sundir[0] = atof(token);
// Sun dir Y
token = COM_ParseExt( &lightText, qtrue );
if(!token[0])
break;
_levelLightParms[level].sundir[1] = atof(token);
// Sun dir Z
token = COM_ParseExt( &lightText, qtrue );
if(!token[0])
break;
_levelLightParms[level].sundir[2] = atof(token);
// HDR enable
token = COM_ParseExt( &lightText, qtrue );
if(!token[0])
break;
_levelLightParms[level].hdrEnable = atof(token);
// HDR bloom
token = COM_ParseExt( &lightText, qtrue );
if(!token[0])
break;
_levelLightParms[level].hdrBloom = atof(token);
level++;
if(level >= MAX_LIGHT_TABLE)
break;
}
isLightInit = true;
FS_FreeFile( (void*)curText );
}
#endif //VV_LIGHTING

View File

@@ -0,0 +1,34 @@
/*
** tr_lightmanager.h
*/
#ifndef TR_LIGHTMANAGER_H
#define TR_LIGHTMANAGER_H
#include "tr_local.h"
class VVLightManager {
public:
VVLightManager();
void R_TransformDlights( int count, VVdlight_t *dl, orientationr_t *ori);
void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
void RE_AddLightToScene( VVdlight_t *light );
void R_DlightBmodel( bmodel_t *bmodel, qboolean NoLight );
int R_DlightFace( srfSurfaceFace_t *face, int dlightBits );
int R_DlightGrid( srfGridMesh_t *grid, int dlightBits );
int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits );
int R_DlightSurface( msurface_t *surf, int dlightBits );
void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent );
void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits );
void RB_CalcDiffuseColor( DWORD *colors );
void RB_CalcDiffuseEntityColor( DWORD *colors );
void ShortToVec3(const short in[3], vec3_t &out);
int BoxOnPlaneSide (const short emins[3], const short emaxs[3], struct cplane_s *p);
};
extern VVLightManager VVLightMan;
#endif

2351
codemp/renderer/tr_local.h Normal file

File diff suppressed because it is too large Load Diff

1646
codemp/renderer/tr_main.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,449 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
// tr_marks.c -- polygon projection on the world polygons
#include "tr_local.h"
//#include "assert.h"
#define MAX_VERTS_ON_POLY 64
#define MARKER_OFFSET 0 // 1
/*
=============
R_ChopPolyBehindPlane
Out must have space for two more vertexes than in
=============
*/
#define SIDE_FRONT 0
#define SIDE_BACK 1
#define SIDE_ON 2
static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],
int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY],
vec3_t normal, vec_t dist, vec_t epsilon) {
float dists[MAX_VERTS_ON_POLY+4];
int sides[MAX_VERTS_ON_POLY+4];
int counts[3];
float dot;
int i, j;
float *p1, *p2, *clip;
float d;
// don't clip if it might overflow
if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {
*numOutPoints = 0;
return;
}
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for ( i = 0 ; i < numInPoints ; i++ ) {
dot = DotProduct( inPoints[i], normal );
dot -= dist;
dists[i] = dot;
if ( dot > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( dot < -epsilon ) {
sides[i] = SIDE_BACK;
} else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
*numOutPoints = 0;
if ( !counts[0] ) {
return;
}
if ( !counts[1] ) {
*numOutPoints = numInPoints;
Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) );
return;
}
for ( i = 0 ; i < numInPoints ; i++ ) {
p1 = inPoints[i];
clip = outPoints[ *numOutPoints ];
if ( sides[i] == SIDE_ON ) {
VectorCopy( p1, clip );
(*numOutPoints)++;
continue;
}
if ( sides[i] == SIDE_FRONT ) {
VectorCopy( p1, clip );
(*numOutPoints)++;
clip = outPoints[ *numOutPoints ];
}
if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
continue;
}
// generate a split point
p2 = inPoints[ (i+1) % numInPoints ];
d = dists[i] - dists[i+1];
if ( d == 0 ) {
dot = 0;
} else {
dot = dists[i] / d;
}
// clip xyz
for (j=0 ; j<3 ; j++) {
clip[j] = p1[j] + dot * ( p2[j] - p1[j] );
}
(*numOutPoints)++;
}
}
/*
=================
R_BoxSurfaces_r
=================
*/
void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) {
int s, c;
msurface_t *surf, **mark;
// do the tail recursion in a loop
while ( node->contents == -1 ) {
#ifdef _XBOX
s = BoxOnPlaneSide( mins, maxs, tr.world->planes + node->planeNum );
#else
s = BoxOnPlaneSide( mins, maxs, node->plane );
#endif
if (s == 1) {
node = node->children[0];
} else if (s == 2) {
node = node->children[1];
} else {
R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir);
node = node->children[1];
}
}
// add the individual surfaces
#ifdef _XBOX
mleaf_s *leaf = (mleaf_s*)node;
mark = tr.world->marksurfaces + leaf->firstMarkSurfNum;
c = leaf->nummarksurfaces;
#else
mark = node->firstmarksurface;
c = node->nummarksurfaces;
#endif
while (c--) {
//
if (*listlength >= listsize) break;
//
surf = *mark;
// check if the surface has NOIMPACT or NOMARKS set
if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
|| ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
surf->viewCount = tr.viewCount;
}
// extra check for surfaces to avoid list overflows
else if (*(surf->data) == SF_FACE) {
// the face plane should go through the box
s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane );
if (s == 1 || s == 2) {
surf->viewCount = tr.viewCount;
} else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) {
// don't add faces that make sharp angles with the projection direction
surf->viewCount = tr.viewCount;
}
}
else if (*(surfaceType_t *) (surf->data) != SF_GRID) surf->viewCount = tr.viewCount;
// check the viewCount because the surface may have
// already been added if it spans multiple leafs
if (surf->viewCount != tr.viewCount) {
surf->viewCount = tr.viewCount;
list[*listlength] = (surfaceType_t *) surf->data;
(*listlength)++;
}
mark++;
}
}
/*
=================
R_AddMarkFragments
=================
*/
void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
int numPlanes, vec3_t *normals, float *dists,
int maxPoints, vec3_t pointBuffer,
int maxFragments, markFragment_t *fragmentBuffer,
int *returnedPoints, int *returnedFragments,
vec3_t mins, vec3_t maxs) {
int pingPong, i;
markFragment_t *mf;
// chop the surface by all the bounding planes of the to be projected polygon
pingPong = 0;
for ( i = 0 ; i < numPlanes ; i++ ) {
R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
&numClipPoints, clipPoints[!pingPong],
normals[i], dists[i], 0.5 );
pingPong ^= 1;
if ( numClipPoints == 0 ) {
break;
}
}
// completely clipped away?
if ( numClipPoints == 0 ) {
return;
}
// add this fragment to the returned list
if ( numClipPoints + (*returnedPoints) > maxPoints ) {
return; // not enough space for this polygon
}
/*
// all the clip points should be within the bounding box
for ( i = 0 ; i < numClipPoints ; i++ ) {
int j;
for ( j = 0 ; j < 3 ; j++ ) {
if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
}
if (j < 3) break;
}
if (i < numClipPoints) return;
*/
mf = fragmentBuffer + (*returnedFragments);
mf->firstPoint = (*returnedPoints);
mf->numPoints = numClipPoints;
Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
(*returnedPoints) += numClipPoints;
(*returnedFragments)++;
}
/*
=================
R_MarkFragments
=================
*/
int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
int numsurfaces, numPlanes;
int i, j, k, m, n;
surfaceType_t *surfaces[64];
vec3_t mins, maxs;
int returnedFragments;
int returnedPoints;
vec3_t normals[MAX_VERTS_ON_POLY+2];
float dists[MAX_VERTS_ON_POLY+2];
vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
int numClipPoints;
float *v;
srfSurfaceFace_t *surf;
srfGridMesh_t *cv;
drawVert_t *dv;
vec3_t normal;
vec3_t projectionDir;
vec3_t v1, v2;
int *indexes;
//increment view count for double check prevention
tr.viewCount++;
//
VectorNormalize2( projection, projectionDir );
// find all the brushes that are to be considered
ClearBounds( mins, maxs );
for ( i = 0 ; i < numPoints ; i++ ) {
vec3_t temp;
AddPointToBounds( points[i], mins, maxs );
VectorAdd( points[i], projection, temp );
AddPointToBounds( temp, mins, maxs );
// make sure we get all the leafs (also the one(s) in front of the hit surface)
VectorMA( points[i], -20, projectionDir, temp );
AddPointToBounds( temp, mins, maxs );
}
if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
// create the bounding planes for the to be projected polygon
for ( i = 0 ; i < numPoints ; i++ ) {
VectorSubtract(points[(i+1)%numPoints], points[i], v1);
VectorAdd(points[i], projection, v2);
VectorSubtract(points[i], v2, v2);
CrossProduct(v1, v2, normals[i]);
VectorNormalizeFast(normals[i]);
dists[i] = DotProduct(normals[i], points[i]);
}
// add near and far clipping planes for projection
VectorCopy(projectionDir, normals[numPoints]);
dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
VectorCopy(projectionDir, normals[numPoints+1]);
VectorInverse(normals[numPoints+1]);
dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
numPlanes = numPoints + 2;
numsurfaces = 0;
R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
//assert(numsurfaces <= 64);
//assert(numsurfaces != 64);
returnedPoints = 0;
returnedFragments = 0;
for ( i = 0 ; i < numsurfaces ; i++ ) {
if (*surfaces[i] == SF_GRID) {
cv = (srfGridMesh_t *) surfaces[i];
for ( m = 0 ; m < cv->height - 1 ; m++ ) {
for ( n = 0 ; n < cv->width - 1 ; n++ ) {
// We triangulate the grid and chop all triangles within
// the bounding planes of the to be projected polygon.
// LOD is not taken into account, not such a big deal though.
//
// It's probably much nicer to chop the grid itself and deal
// with this grid as a normal SF_GRID surface so LOD will
// be applied. However the LOD of that chopped grid must
// be synced with the LOD of the original curve.
// One way to do this; the chopped grid shares vertices with
// the original curve. When LOD is applied to the original
// curve the unused vertices are flagged. Now the chopped curve
// should skip the flagged vertices. This still leaves the
// problems with the vertices at the chopped grid edges.
//
// To avoid issues when LOD applied to "hollow curves" (like
// the ones around many jump pads) we now just add a 2 unit
// offset to the triangle vertices.
// The offset is added in the vertex normal vector direction
// so all triangles will still fit together.
// The 2 unit offset should avoid pretty much all LOD problems.
numClipPoints = 3;
dv = cv->verts + m * cv->width + n;
VectorCopy(dv[0].xyz, clipPoints[0][0]);
VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
VectorCopy(dv[1].xyz, clipPoints[0][2]);
VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
// check the normal of this triangle
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
CrossProduct(v1, v2, normal);
VectorNormalizeFast(normal);
if (DotProduct(normal, projectionDir) < -0.1) {
// add the fragments of this triangle
R_AddMarkFragments(numClipPoints, clipPoints,
numPlanes, normals, dists,
maxPoints, pointBuffer,
maxFragments, fragmentBuffer,
&returnedPoints, &returnedFragments, mins, maxs);
if ( returnedFragments == maxFragments ) {
return returnedFragments; // not enough space for more fragments
}
}
VectorCopy(dv[1].xyz, clipPoints[0][0]);
VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);
// check the normal of this triangle
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
CrossProduct(v1, v2, normal);
VectorNormalizeFast(normal);
if (DotProduct(normal, projectionDir) < -0.05) {
// add the fragments of this triangle
R_AddMarkFragments(numClipPoints, clipPoints,
numPlanes, normals, dists,
maxPoints, pointBuffer,
maxFragments, fragmentBuffer,
&returnedPoints, &returnedFragments, mins, maxs);
if ( returnedFragments == maxFragments ) {
return returnedFragments; // not enough space for more fragments
}
}
}
}
}
else if (*surfaces[i] == SF_FACE) {
surf = ( srfSurfaceFace_t * ) surfaces[i];
// check the normal of this face
if (DotProduct(surf->plane.normal, projectionDir) > -0.5) {
continue;
}
/*
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
CrossProduct(v1, v2, normal);
VectorNormalize(normal);
if (DotProduct(normal, projectionDir) > -0.5) continue;
*/
#ifdef _XBOX
const unsigned char * const indexes = (unsigned char *)( (byte *)surf + surf->ofsIndices );
int nextSurfPoint = NEXT_SURFPOINT(surf->flags);
#else
indexes = (int *)( (byte *)surf + surf->ofsIndices );
#endif
for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
for ( j = 0 ; j < 3 ; j++ ) {
#ifdef _XBOX
const unsigned short* v = surf->srfPoints + nextSurfPoint * indexes[k+j];
float fVec[3];
Q_CastShort2Float(&fVec[0], (short*)v + 0);
Q_CastShort2Float(&fVec[1], (short*)v + 1);
Q_CastShort2Float(&fVec[2], (short*)v + 2);
VectorMA( fVec, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
#else
v = surf->points[0] + VERTEXSIZE * indexes[k+j];;
VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
#endif
}
// add the fragments of this face
R_AddMarkFragments( 3 , clipPoints,
numPlanes, normals, dists,
maxPoints, pointBuffer,
maxFragments, fragmentBuffer,
&returnedPoints, &returnedFragments, mins, maxs);
if ( returnedFragments == maxFragments ) {
return returnedFragments; // not enough space for more fragments
}
}
continue;
}
else {
// ignore all other world surfaces
// might be cool to also project polygons on a triangle soup
// however this will probably create huge amounts of extra polys
// even more than the projection onto curves
continue;
}
}
return returnedFragments;
}

409
codemp/renderer/tr_mesh.cpp Normal file
View File

@@ -0,0 +1,409 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
// tr_mesh.c: triangle model functions
#include "tr_local.h"
float ProjectRadius( float r, vec3_t location )
{
float pr;
float dist;
float c;
vec3_t p;
float width;
float depth;
c = DotProduct( tr.viewParms.ori.axis[0], tr.viewParms.ori.origin );
dist = DotProduct( tr.viewParms.ori.axis[0], location ) - c;
if ( dist <= 0 )
return 0;
p[0] = 0;
p[1] = Q_fabs( r );
p[2] = -dist;
width = p[0] * tr.viewParms.projectionMatrix[1] +
p[1] * tr.viewParms.projectionMatrix[5] +
p[2] * tr.viewParms.projectionMatrix[9] +
tr.viewParms.projectionMatrix[13];
depth = p[0] * tr.viewParms.projectionMatrix[3] +
p[1] * tr.viewParms.projectionMatrix[7] +
p[2] * tr.viewParms.projectionMatrix[11] +
tr.viewParms.projectionMatrix[15];
pr = width / depth;
#if defined (_XBOX)
pr = -pr;
#endif
if ( pr > 1.0f )
pr = 1.0f;
return pr;
}
#ifndef DEDICATED
/*
=============
R_CullModel
=============
*/
static int R_CullModel( md3Header_t *header, trRefEntity_t *ent ) {
vec3_t bounds[2];
md3Frame_t *oldFrame, *newFrame;
int i;
// compute frame pointers
newFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
oldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe;
// cull bounding sphere ONLY if this is not an upscaled entity
if ( !ent->e.nonNormalizedAxes )
{
if ( ent->e.frame == ent->e.oldframe )
{
switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
{
case CULL_OUT:
tr.pc.c_sphere_cull_md3_out++;
return CULL_OUT;
case CULL_IN:
tr.pc.c_sphere_cull_md3_in++;
return CULL_IN;
case CULL_CLIP:
tr.pc.c_sphere_cull_md3_clip++;
break;
}
}
else
{
int sphereCull, sphereCullB;
sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
if ( newFrame == oldFrame ) {
sphereCullB = sphereCull;
} else {
sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
}
if ( sphereCull == sphereCullB )
{
if ( sphereCull == CULL_OUT )
{
tr.pc.c_sphere_cull_md3_out++;
return CULL_OUT;
}
else if ( sphereCull == CULL_IN )
{
tr.pc.c_sphere_cull_md3_in++;
return CULL_IN;
}
else
{
tr.pc.c_sphere_cull_md3_clip++;
}
}
}
}
// calculate a bounding box in the current coordinate system
for (i = 0 ; i < 3 ; i++) {
bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
}
switch ( R_CullLocalBox( bounds ) )
{
case CULL_IN:
tr.pc.c_box_cull_md3_in++;
return CULL_IN;
case CULL_CLIP:
tr.pc.c_box_cull_md3_clip++;
return CULL_CLIP;
case CULL_OUT:
default:
tr.pc.c_box_cull_md3_out++;
return CULL_OUT;
}
}
/*
=================
RE_GetModelBounds
Returns the bounds of the current model
(qhandle_t)hModel and (int)frame need to be set
=================
*/
//rwwRMG - added
void RE_GetModelBounds(refEntity_t *refEnt, vec3_t bounds1, vec3_t bounds2)
{
md3Frame_t *frame;
md3Header_t *header;
model_t *model;
assert(refEnt);
model = R_GetModelByHandle( refEnt->hModel );
assert(model);
header = model->md3[0];
assert(header);
frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + refEnt->frame;
assert(frame);
VectorCopy(frame->bounds[0], bounds1);
VectorCopy(frame->bounds[1], bounds2);
}
/*
=================
R_ComputeLOD
=================
*/
int R_ComputeLOD( trRefEntity_t *ent ) {
float radius;
float flod, lodscale;
float projectedRadius;
md3Frame_t *frame;
int lod;
if ( tr.currentModel->numLods < 2 )
{
// model has only 1 LOD level, skip computations and bias
lod = 0;
}
else
{
// multiple LODs exist, so compute projected bounding sphere
// and use that as a criteria for selecting LOD
frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
frame += ent->e.frame;
radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );
if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 )
{
lodscale = (r_lodscale->value+r_autolodscalevalue->value);
if ( lodscale > 20 )
{
lodscale = 20;
}
else if ( lodscale < 0 )
{
lodscale = 0;
}
flod = 1.0f - projectedRadius * lodscale;
}
else
{
// object intersects near view plane, e.g. view weapon
flod = 0;
}
flod *= tr.currentModel->numLods;
lod = myftol( flod );
if ( lod < 0 )
{
lod = 0;
}
else if ( lod >= tr.currentModel->numLods )
{
lod = tr.currentModel->numLods - 1;
}
}
lod += r_lodbias->integer;
if ( lod >= tr.currentModel->numLods )
lod = tr.currentModel->numLods - 1;
if ( lod < 0 )
lod = 0;
return lod;
}
/*
=================
R_ComputeFogNum
=================
*/
int R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) {
int i, j;
fog_t *fog;
md3Frame_t *md3Frame;
vec3_t localOrigin;
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
return 0;
}
// FIXME: non-normalized axis issues
md3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
VectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin );
for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
fog = &tr.world->fogs[i];
for ( j = 0 ; j < 3 ; j++ ) {
if ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) {
break;
}
if ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) {
break;
}
}
if ( j == 3 ) {
return i;
}
}
return 0;
}
/*
=================
R_AddMD3Surfaces
=================
*/
void R_AddMD3Surfaces( trRefEntity_t *ent ) {
int i;
md3Header_t *header = 0;
md3Surface_t *surface = 0;
md3Shader_t *md3Shader = 0;
shader_t *shader = 0;
int cull;
int lod;
int fogNum;
qboolean personalModel;
// don't add third_person objects if not in a portal
personalModel = (qboolean)((ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal);
if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
ent->e.frame %= tr.currentModel->md3[0]->numFrames;
ent->e.oldframe %= tr.currentModel->md3[0]->numFrames;
}
//
// Validate the frames so there is no chance of a crash.
// This will write directly into the entity structure, so
// when the surfaces are rendered, they don't need to be
// range checked again.
//
if ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames)
|| (ent->e.frame < 0)
|| (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames)
|| (ent->e.oldframe < 0) ) {
Com_DPrintf (S_COLOR_RED "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n",
ent->e.oldframe, ent->e.frame,
tr.currentModel->name );
ent->e.frame = 0;
ent->e.oldframe = 0;
}
//
// compute LOD
//
lod = R_ComputeLOD( ent );
header = tr.currentModel->md3[lod];
//
// cull the entire model if merged bounding box of both frames
// is outside the view frustum.
//
cull = R_CullModel ( header, ent );
if ( cull == CULL_OUT ) {
return;
}
//
// set up lighting now that we know we aren't culled
//
if ( !personalModel || r_shadows->integer > 1 ) {
R_SetupEntityLighting( &tr.refdef, ent );
}
//
// see if we are in a fog volume
//
fogNum = R_ComputeFogNum( header, ent );
//
// draw all surfaces
//
surface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces );
for ( i = 0 ; i < header->numSurfaces ; i++ ) {
if ( ent->e.customShader ) {
shader = R_GetShaderByHandle( ent->e.customShader );
} else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) {
skin_t *skin;
int j;
skin = R_GetSkinByHandle( ent->e.customSkin );
// match the surface name to something in the skin file
shader = tr.defaultShader;
for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
// the names have both been lowercased
if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
shader = skin->surfaces[j]->shader;
break;
}
}
if (shader == tr.defaultShader) {
Com_DPrintf (S_COLOR_RED "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name);
}
else if (shader->defaultShader) {
Com_DPrintf (S_COLOR_RED "WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
}
} else if ( surface->numShaders <= 0 ) {
shader = tr.defaultShader;
} else {
md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders );
md3Shader += ent->e.skinNum % surface->numShaders;
shader = tr.shaders[ md3Shader->shaderIndex ];
}
// we will add shadows even if the main object isn't visible in the view
// stencil shadows can't do personal models unless I polyhedron clip
if ( !personalModel
&& r_shadows->integer == 2
&& fogNum == 0
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
&& shader->sort == SS_OPAQUE ) {
R_AddDrawSurf( (surfaceType_t *)surface, tr.shadowShader, 0, qfalse );
}
// projection shadows work fine with personal models
if ( r_shadows->integer == 3
&& fogNum == 0
&& (ent->e.renderfx & RF_SHADOW_PLANE )
&& shader->sort == SS_OPAQUE ) {
R_AddDrawSurf( (surfaceType_t *)surface, tr.projectionShadowShader, 0, qfalse );
}
// don't add third_person objects if not viewing through a portal
if ( !personalModel ) {
R_AddDrawSurf( (surfaceType_t *)surface, shader, fogNum, qfalse );
}
surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd );
}
}
#endif // !DEDICATED

2042
codemp/renderer/tr_model.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
// tr_noise.c
#include "tr_local.h"
#define NOISE_SIZE 256
#define NOISE_MASK ( NOISE_SIZE - 1 )
#define VAL( a ) s_noise_perm[ ( a ) & ( NOISE_MASK )]
#define INDEX( x, y, z, t ) VAL( x + VAL( y + VAL( z + VAL( t ) ) ) )
static float s_noise_table[NOISE_SIZE];
static int s_noise_perm[NOISE_SIZE];
#define LERP( a, b, w ) ( a * ( 1.0f - w ) + b * w )
static float GetNoiseValue( int x, int y, int z, int t )
{
int index = INDEX( ( int ) x, ( int ) y, ( int ) z, ( int ) t );
return s_noise_table[index];
}
float GetNoiseTime( int t )
{
int index = VAL( t );
return (1 + s_noise_table[index]);
}
void R_NoiseInit( void )
{
int i;
srand( 1001 );
for ( i = 0; i < NOISE_SIZE; i++ )
{
s_noise_table[i] = ( float ) ( ( ( rand() / ( float ) RAND_MAX ) * 2.0 - 1.0 ) );
s_noise_perm[i] = ( unsigned char ) ( rand() / ( float ) RAND_MAX * 255 );
}
}
float R_NoiseGet4f( float x, float y, float z, float t )
{
int i;
int ix, iy, iz, it;
float fx, fy, fz, ft;
float front[4];
float back[4];
float fvalue, bvalue, value[2], finalvalue;
ix = ( int ) floor( x );
fx = x - ix;
iy = ( int ) floor( y );
fy = y - iy;
iz = ( int ) floor( z );
fz = z - iz;
it = ( int ) floor( t );
ft = t - it;
for ( i = 0; i < 2; i++ )
{
front[0] = GetNoiseValue( ix, iy, iz, it + i );
front[1] = GetNoiseValue( ix+1, iy, iz, it + i );
front[2] = GetNoiseValue( ix, iy+1, iz, it + i );
front[3] = GetNoiseValue( ix+1, iy+1, iz, it + i );
back[0] = GetNoiseValue( ix, iy, iz + 1, it + i );
back[1] = GetNoiseValue( ix+1, iy, iz + 1, it + i );
back[2] = GetNoiseValue( ix, iy+1, iz + 1, it + i );
back[3] = GetNoiseValue( ix+1, iy+1, iz + 1, it + i );
fvalue = LERP( LERP( front[0], front[1], fx ), LERP( front[2], front[3], fx ), fy );
bvalue = LERP( LERP( back[0], back[1], fx ), LERP( back[2], back[3], fx ), fy );
value[i] = LERP( fvalue, bvalue, fz );
}
finalvalue = LERP( value[0], value[1], ft );
return finalvalue;
}

116
codemp/renderer/tr_public.h Normal file
View File

@@ -0,0 +1,116 @@
#ifndef __TR_PUBLIC_H
#define __TR_PUBLIC_H
#include "../cgame/tr_types.h"
#define REF_API_VERSION 8
//
// these are the functions exported by the refresh module
//
#ifdef _XBOX
template <class T> class SPARC;
#endif
typedef struct {
// called before the library is unloaded
// if the system is just reconfiguring, pass destroyWindow = qfalse,
// which will keep the screen from flashing to the desktop.
void (*Shutdown)( qboolean destroyWindow );
// All data that will be used in a level should be
// registered before rendering any frames to prevent disk hits,
// but they can still be registered at a later time
// if necessary.
//
// BeginRegistration makes any existing media pointers invalid
// and returns the current gl configuration, including screen width
// and height, which can be used by the client to intelligently
// size display elements
void (*BeginRegistration)( glconfig_t *config );
qhandle_t (*RegisterModel)( const char *name );
qhandle_t (*RegisterSkin)( const char *name );
qhandle_t (*RegisterShader)( const char *name );
qhandle_t (*RegisterShaderNoMip)( const char *name );
const char *(*ShaderNameFromIndex)( int index );
void (*LoadWorld)( const char *name );
// the vis data is a large enough block of data that we go to the trouble
// of sharing it with the clipmodel subsystem
#ifdef _XBOX
void (*SetWorldVisData)( SPARC<byte> *vis );
#else
void (*SetWorldVisData)( const byte *vis );
#endif
// EndRegistration will draw a tiny polygon with each texture, forcing
// them to be loaded into card memory
void (*EndRegistration)( void );
// a scene is built up by calls to R_ClearScene and the various R_Add functions.
// Nothing is drawn until R_RenderScene is called.
void (*ClearScene)( void );
void (*ClearDecals) ( void );
void (*AddRefEntityToScene)( const refEntity_t *re );
void (*AddMiniRefEntityToScene)( const miniRefEntity_t *re );
void (*AddPolyToScene)( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
void (*AddDecalToScene)(qhandle_t shader, const vec3_t origin, const vec3_t dir, float orientation, float r, float g, float b, float a, qboolean alphaFade, float radius, qboolean temporary );
int (*LightForPoint)( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
void (*AddLightToScene)( const vec3_t org, float intensity, float r, float g, float b );
void (*AddAdditiveLightToScene)( const vec3_t org, float intensity, float r, float g, float b );
void (*RenderScene)( const refdef_t *fd );
void (*SetColor)( const float *rgba ); // NULL = 1,1,1,1
void (*DrawStretchPic) ( float x, float y, float w, float h,
float s1, float t1, float s2, float t2, qhandle_t hShader ); // 0 = white
void (*DrawRotatePic) ( float x, float y, float w, float h,
float s1, float t1, float s2, float t2, float a1, qhandle_t hShader ); // 0 = white
void (*DrawRotatePic2) ( float x, float y, float w, float h,
float s1, float t1, float s2, float t2, float a1, qhandle_t hShader ); // 0 = white
// Draw images for cinematic rendering, pass as 32 bit rgba
void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
void (*UploadCinematic) (int cols, int rows, const byte *data, int client, qboolean dirty);
void (*BeginFrame)( stereoFrame_t stereoFrame );
// if the pointers are not NULL, timing info will be returned
void (*EndFrame)( int *frontEndMsec, int *backEndMsec );
int (*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection,
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
int (*LerpTag)( orientation_t *tag, qhandle_t model, int startFrame, int endFrame,
float frac, const char *tagName );
void (*ModelBounds)( qhandle_t model, vec3_t mins, vec3_t maxs );
#ifdef __USEA3D
void (*A3D_RenderGeometry) (void *pVoidA3D, void *pVoidGeom, void *pVoidMat, void *pVoidGeomStatus);
#endif
qhandle_t (*RegisterFont)( const char *fontName );
int (*Font_StrLenPixels) (const char *text, const int iFontIndex, const float scale);
int (*Font_StrLenChars) (const char *text);
int (*Font_HeightPixels)(const int iFontIndex, const float scale);
void (*Font_DrawString)(int ox, int oy, const char *text, const float *rgba, const int setIndex, int iCharLimit, const float scale);
qboolean (*Language_IsAsian)(void);
qboolean (*Language_UsesSpaces)(void);
unsigned int (*AnyLanguage_ReadCharFromString)( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation/* = NULL*/ );
void (*RemapShader)(const char *oldShader, const char *newShader, const char *offsetTime);
qboolean (*GetEntityToken)( char *buffer, int size );
qboolean (*inPVS)( const vec3_t p1, const vec3_t p2, byte *mask );
void (*GetLightStyle)(int style, color4ub_t color);
void (*SetLightStyle)(int style, int color);
void (*GetBModelVerts)( int bmodelIndex, vec3_t *vec, vec3_t normal );
} refexport_t;
// this is the only function actually exported at the linker level
// If the module can't init to a valid rendering state, NULL will be
// returned.
refexport_t*GetRefAPI( int apiVersion );
#endif // __TR_PUBLIC_H

View File

@@ -0,0 +1,222 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
// tr_QuickSprite.cpp: implementation of the CQuickSpriteSystem class.
//
//////////////////////////////////////////////////////////////////////
//#include "../server/exe_headers.h"
#include "tr_local.h"
#include "tr_QuickSprite.h"
void R_BindAnimatedImage( textureBundle_t *bundle );
//////////////////////////////////////////////////////////////////////
// Singleton System
//////////////////////////////////////////////////////////////////////
CQuickSpriteSystem SQuickSprite;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CQuickSpriteSystem::CQuickSpriteSystem()
{
int i;
for (i=0; i<SHADER_MAX_VERTEXES; i+=4)
{
// Bottom right
mTextureCoords[i+0][0] = 1.0;
mTextureCoords[i+0][1] = 1.0;
// Top right
mTextureCoords[i+1][0] = 1.0;
mTextureCoords[i+1][1] = 0.0;
// Top left
mTextureCoords[i+2][0] = 0.0;
mTextureCoords[i+2][1] = 0.0;
// Bottom left
mTextureCoords[i+3][0] = 0.0;
mTextureCoords[i+3][1] = 1.0;
}
}
CQuickSpriteSystem::~CQuickSpriteSystem()
{
}
void CQuickSpriteSystem::Flush(void)
{
if (mNextVert==0)
{
return;
}
/*
if (mUseFog && r_drawfog->integer == 2 &&
mFogIndex == tr.world->globalFog)
{ //enable hardware fog when we draw this thing if applicable -rww
fog_t *fog = tr.world->fogs + mFogIndex;
#ifdef _XBOX
qglFogi(GL_FOG_MODE, GL_EXP2);
#else
qglFogf(GL_FOG_MODE, GL_EXP2);
#endif
qglFogf(GL_FOG_DENSITY, logtestExp2 / fog->parms.depthForOpaque);
qglFogfv(GL_FOG_COLOR, fog->parms.color);
qglEnable(GL_FOG);
}
*/
//this should not be needed, since I just wait to disable fog for the surface til after surface sprites are done
//
// render the main pass
//
R_BindAnimatedImage( mTexBundle );
GL_State(mGLStateBits);
//
// set arrays and lock
//
qglTexCoordPointer( 2, GL_FLOAT, 0, mTextureCoords );
qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
qglEnableClientState( GL_COLOR_ARRAY);
qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, mColors );
qglVertexPointer (3, GL_FLOAT, 16, mVerts);
if ( qglLockArraysEXT )
{
qglLockArraysEXT(0, mNextVert);
GLimp_LogComment( "glLockArraysEXT\n" );
}
qglDrawArrays(GL_QUADS, 0, mNextVert);
backEnd.pc.c_vertexes += mNextVert;
backEnd.pc.c_indexes += mNextVert;
backEnd.pc.c_totalIndexes += mNextVert;
//only for software fog pass (global soft/volumetric) -rww
if (mUseFog && (r_drawfog->integer != 2 || mFogIndex != tr.world->globalFog))
{
fog_t *fog = tr.world->fogs + mFogIndex;
//
// render the fog pass
//
GL_Bind( tr.fogImage );
GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
//
// set arrays and lock
//
qglTexCoordPointer( 2, GL_FLOAT, 0, mFogTextureCoords);
// qglEnableClientState( GL_TEXTURE_COORD_ARRAY); // Done above
qglDisableClientState( GL_COLOR_ARRAY );
qglColor4ubv((GLubyte *)&fog->colorInt);
// qglVertexPointer (3, GL_FLOAT, 16, mVerts); // Done above
qglDrawArrays(GL_QUADS, 0, mNextVert);
// Second pass from fog
backEnd.pc.c_totalIndexes += mNextVert;
}
//
// unlock arrays
//
if (qglUnlockArraysEXT)
{
qglUnlockArraysEXT();
GLimp_LogComment( "glUnlockArraysEXT\n" );
}
mNextVert=0;
}
void CQuickSpriteSystem::StartGroup(textureBundle_t *bundle, unsigned long glbits, int fogIndex )
{
mNextVert = 0;
mTexBundle = bundle;
mGLStateBits = glbits;
if (fogIndex != -1)
{
mUseFog = qtrue;
mFogIndex = fogIndex;
}
else
{
mUseFog = qfalse;
}
qglDisable(GL_CULL_FACE);
}
void CQuickSpriteSystem::EndGroup(void)
{
Flush();
qglColor4ub(255,255,255,255);
qglEnable(GL_CULL_FACE);
}
void CQuickSpriteSystem::Add(float *pointdata, color4ub_t color, vec2_t fog)
{
float *curcoord;
float *curfogtexcoord;
unsigned long *curcolor;
if (mNextVert>SHADER_MAX_VERTEXES-4)
{
Flush();
}
curcoord = mVerts[mNextVert];
memcpy(curcoord, pointdata, 4*sizeof(vec4_t));
// Set up color
curcolor = &mColors[mNextVert];
*curcolor++ = *(unsigned long *)color;
*curcolor++ = *(unsigned long *)color;
*curcolor++ = *(unsigned long *)color;
*curcolor++ = *(unsigned long *)color;
if (fog)
{
curfogtexcoord = &mFogTextureCoords[mNextVert][0];
*curfogtexcoord++ = fog[0];
*curfogtexcoord++ = fog[1];
*curfogtexcoord++ = fog[0];
*curfogtexcoord++ = fog[1];
*curfogtexcoord++ = fog[0];
*curfogtexcoord++ = fog[1];
*curfogtexcoord++ = fog[0];
*curfogtexcoord++ = fog[1];
mUseFog=qtrue;
}
else
{
mUseFog=qfalse;
}
mNextVert+=4;
}

View File

@@ -0,0 +1,47 @@
// this include must remain at the top of every CPP file
//#include "../game/q_math.h"
//#include "tr_headers.h"
// tr_QuickSprite.h: interface for the CQuickSprite class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_TR_QUICKSPRITE_H__6F05EB85_A1ED_4537_9EC0_9F5D82A5D99A__INCLUDED_)
#define AFX_TR_QUICKSPRITE_H__6F05EB85_A1ED_4537_9EC0_9F5D82A5D99A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CQuickSpriteSystem
{
private:
textureBundle_t *mTexBundle;
unsigned long mGLStateBits;
int mFogIndex;
qboolean mUseFog;
vec4_t mVerts[SHADER_MAX_VERTEXES];
unsigned int mIndexes[SHADER_MAX_VERTEXES]; // Ideally this would be static, cause it never changes
vec2_t mTextureCoords[SHADER_MAX_VERTEXES]; // Ideally this would be static, cause it never changes
vec2_t mFogTextureCoords[SHADER_MAX_VERTEXES];
unsigned long mColors[SHADER_MAX_VERTEXES];
int mNextVert;
void Flush(void);
public:
CQuickSpriteSystem();
virtual ~CQuickSpriteSystem();
void StartGroup(textureBundle_t *bundle, unsigned long glbits, int fogIndex = -1);
void EndGroup(void);
void Add(float *pointdata, color4ub_t color, vec2_t fog=NULL);
};
extern CQuickSpriteSystem SQuickSprite;
#endif // !defined(AFX_TR_QUICKSPRITE_H__6F05EB85_A1ED_4537_9EC0_9F5D82A5D99A__INCLUDED_)

View File

@@ -0,0 +1,883 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
#include "tr_local.h"
#if !defined(G2_H_INC)
#include "../ghoul2/G2.h"
#endif
#include "../ghoul2/G2_local.h"
#include "MatComp.h"
#ifdef _XBOX
#include "../cgame/cg_local.h"
#include "../client/cl_data.h"
#endif
#pragma warning (disable: 4512) //default assignment operator could not be gened
#include "../qcommon/disablewarnings.h"
static int r_firstSceneDrawSurf;
int r_numdlights;
int r_firstSceneDlight;
static int r_numentities;
static int r_firstSceneEntity;
static int r_numminientities;
static int r_firstSceneMiniEntity;
static int refEntParent = -1;
static int r_numpolys;
static int r_firstScenePoly;
static int r_numpolyverts;
int skyboxportal;
int drawskyboxportal;
/*
====================
R_ToggleSmpFrame
====================
*/
void R_ToggleSmpFrame( void ) {
backEndData->commands.used = 0;
r_firstSceneDrawSurf = 0;
r_numdlights = 0;
r_firstSceneDlight = 0;
r_numentities = 0;
r_firstSceneEntity = 0;
refEntParent = -1;
r_numminientities = 0;
r_firstSceneMiniEntity = 0;
r_numpolys = 0;
r_firstScenePoly = 0;
r_numpolyverts = 0;
}
/*
====================
RE_ClearScene
====================
*/
void RE_ClearScene( void ) {
r_firstSceneDlight = r_numdlights;
r_firstSceneEntity = r_numentities;
r_firstScenePoly = r_numpolys;
refEntParent = -1;
r_firstSceneMiniEntity = r_numminientities;
}
/*
===========================================================================
DISCRETE POLYS
===========================================================================
*/
/*
=====================
R_AddPolygonSurfaces
Adds all the scene's polys into this view's drawsurf list
=====================
*/
void R_AddPolygonSurfaces( void ) {
int i;
shader_t *sh;
srfPoly_t *poly;
tr.currentEntityNum = TR_WORLDENT;
tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;
for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
sh = R_GetShaderByHandle( poly->hShader );
R_AddDrawSurf( (surfaceType_t *)poly, sh, poly->fogIndex, qfalse );
}
}
/*
=====================
RE_AddPolyToScene
=====================
*/
void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
srfPoly_t *poly;
int i, j;
int fogIndex;
fog_t *fog;
vec3_t bounds[2];
if ( !tr.registered ) {
return;
}
if ( !hShader ) {
Com_Printf (S_COLOR_YELLOW "WARNING: RE_AddPolyToScene: NULL poly shader\n");
return;
}
for ( j = 0; j < numPolys; j++ ) {
if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) {
Com_Printf (S_COLOR_YELLOW "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n");
return;
}
poly = &backEndData->polys[r_numpolys];
poly->surfaceType = SF_POLY;
poly->hShader = hShader;
poly->numVerts = numVerts;
poly->verts = &backEndData->polyVerts[r_numpolyverts];
Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) );
// done.
r_numpolys++;
r_numpolyverts += numVerts;
// if no world is loaded
if ( tr.world == NULL ) {
fogIndex = 0;
}
// see if it is in a fog volume
else if ( tr.world->numfogs == 1 ) {
fogIndex = 0;
} else {
// find which fog volume the poly is in
VectorCopy( poly->verts[0].xyz, bounds[0] );
VectorCopy( poly->verts[0].xyz, bounds[1] );
for ( i = 1 ; i < poly->numVerts ; i++ ) {
AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
}
for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
fog = &tr.world->fogs[fogIndex];
if ( bounds[1][0] >= fog->bounds[0][0]
&& bounds[1][1] >= fog->bounds[0][1]
&& bounds[1][2] >= fog->bounds[0][2]
&& bounds[0][0] <= fog->bounds[1][0]
&& bounds[0][1] <= fog->bounds[1][1]
&& bounds[0][2] <= fog->bounds[1][2] ) {
break;
}
}
if ( fogIndex == tr.world->numfogs ) {
fogIndex = 0;
}
}
poly->fogIndex = fogIndex;
}
}
//=================================================================================
/*
=====================
RE_AddRefEntityToScene
=====================
*/
void RE_AddRefEntityToScene( const refEntity_t *ent ) {
if ( !tr.registered ) {
return;
}
assert(!ent || ent->renderfx >= 0);
if (ent->reType == RT_ENT_CHAIN)
{ //minirefents must die.
return;
}
#ifdef _DEBUG
if (ent->reType == RT_MODEL)
{
assert(ent->hModel || ent->ghoul2 || ent->customShader);
}
#endif
if ( r_numentities >= TR_WORLDENT )
{
#ifndef FINAL_BUILD
Com_Printf( "WARNING: RE_AddRefEntityToScene: too many entities\n");
#endif
return;
}
if ( ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
Com_Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
}
backEndData->entities[r_numentities].e = *ent;
backEndData->entities[r_numentities].lightingCalculated = qfalse;
if (ent->ghoul2)
{
CGhoul2Info_v &ghoul2 = *((CGhoul2Info_v *)ent->ghoul2);
if (!ghoul2[0].mModel)
{
#ifdef _DEBUG
CGhoul2Info &g2 = ghoul2[0];
#endif
//DebugBreak();
Com_Printf("Your ghoul2 instance has no model!\n");
}
}
/*
if (ent->reType == RT_ENT_CHAIN)
{
refEntParent = r_numentities;
backEndData->entities[r_numentities].e.uRefEnt.uMini.miniStart = r_numminientities - r_firstSceneMiniEntity;
backEndData->entities[r_numentities].e.uRefEnt.uMini.miniCount = 0;
}
else
{
*/
refEntParent = -1;
//}
r_numentities++;
}
/************************************************************************************************
* RE_AddMiniRefEntityToScene *
* Adds a mini ref ent to the scene. If the input parameter is null, it signifies the end *
* of the chain. Otherwise, if there is a valid chain parent, it will be added to that. *
* If there is no parent, it will be added as a regular ref ent. *
* *
* Input *
* ent: the mini ref ent to be added *
* *
* Output / Return *
* none *
* *
************************************************************************************************/
void RE_AddMiniRefEntityToScene( const miniRefEntity_t *ent )
{
#if 0
refEntity_t *parent;
#endif
if ( !tr.registered )
{
return;
}
if (!ent)
{
refEntParent = -1;
return;
}
#if 1 //i hate you minirefent!
refEntity_t tempEnt;
memcpy(&tempEnt, ent, sizeof(*ent));
memset(((char *)&tempEnt)+sizeof(*ent), 0, sizeof(tempEnt) - sizeof(*ent));
#ifdef _XBOX
if(ClientManager::splitScreenMode == qtrue && ClientManager::ActiveClientNum() == 0)
tempEnt.skipForPlayer2 = true;
#endif
RE_AddRefEntityToScene(&tempEnt);
#else
if ( ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE )
{
Com_Error( ERR_DROP, "RE_AddMiniRefEntityToScene: bad reType %i", ent->reType );
}
if (!r_numentities || refEntParent == -1 || r_numminientities >= MAX_MINI_ENTITIES)
{ //rww - add it as a refent also if we run out of minis
// Com_Error( ERR_DROP, "RE_AddMiniRefEntityToScene: mini without parent ref ent");
refEntity_t tempEnt;
memcpy(&tempEnt, ent, sizeof(*ent));
memset(((char *)&tempEnt)+sizeof(*ent), 0, sizeof(tempEnt) - sizeof(*ent));
RE_AddRefEntityToScene(&tempEnt);
return;
}
parent = &backEndData->entities[refEntParent].e;
parent->uRefEnt.uMini.miniCount++;
backEndData->miniEntities[r_numminientities].e = *ent;
r_numminientities++;
#endif
}
/*
=====================
RE_AddDynamicLightToScene
=====================
*/
void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) {
dlight_t *dl;
if ( !tr.registered ) {
return;
}
if ( r_numdlights >= MAX_DLIGHTS ) {
return;
}
if ( intensity <= 0 ) {
return;
}
dl = &backEndData->dlights[r_numdlights++];
VectorCopy (org, dl->origin);
dl->radius = intensity;
dl->color[0] = r;
dl->color[1] = g;
dl->color[2] = b;
dl->additive = additive;
}
/*
=====================
RE_AddLightToScene
=====================
*/
void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse );
}
/*
=====================
RE_AddAdditiveLightToScene
=====================
*/
void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue );
}
enum
{
DECALPOLY_TYPE_NORMAL,
DECALPOLY_TYPE_FADE,
DECALPOLY_TYPE_MAX
};
#define DECAL_FADE_TIME 1000
decalPoly_t* RE_AllocDecal ( int type );
static decalPoly_t re_decalPolys[DECALPOLY_TYPE_MAX][MAX_DECAL_POLYS];
static int re_decalPolyHead[DECALPOLY_TYPE_MAX];
static int re_decalPolyTotal[DECALPOLY_TYPE_MAX];
/*
===================
RE_ClearDecals
This is called to remove all decals from the world
===================
*/
void RE_ClearDecals ( void )
{
memset( re_decalPolys, 0, sizeof(re_decalPolys) );
memset( re_decalPolyHead, 0, sizeof(re_decalPolyHead) );
memset( re_decalPolyTotal, 0, sizeof(re_decalPolyTotal) );
}
void R_InitDecals ( void )
{
RE_ClearDecals ( );
}
void RE_FreeDecal ( int type, int index )
{
if ( !re_decalPolys[type][index].time )
{
return;
}
if ( type == DECALPOLY_TYPE_NORMAL )
{
decalPoly_t* fade;
fade = RE_AllocDecal ( DECALPOLY_TYPE_FADE );
memcpy ( fade, &re_decalPolys[type][index], sizeof(decalPoly_t) );
fade->time = tr.refdef.time;
fade->fadetime = tr.refdef.time + DECAL_FADE_TIME;
}
re_decalPolys[type][index].time = 0;
re_decalPolyTotal[type]--;
}
/*
===================
RE_AllocDecal
Will allways succeed, even if it requires freeing an old active mark
===================
*/
decalPoly_t* RE_AllocDecal( int type )
{
decalPoly_t *le;
// See if the cvar changed
if ( re_decalPolyTotal[type] > r_markcount->integer )
{
RE_ClearDecals ( );
}
le = &re_decalPolys[type][re_decalPolyHead[type]];
// If it has no time its the first occasion its been used
if ( le->time )
{
if ( le->time != tr.refdef.time )
{
int i = re_decalPolyHead[type];
// since we are killing one that existed before, make sure we
// kill all the other marks that belong to the group
do
{
i++;
if ( i >= r_markcount->integer )
{
i = 0;
}
// Break out on the first one thats not part of the group
if ( re_decalPolys[type][i].time != le->time )
{
break;
}
RE_FreeDecal ( type, i );
}
while ( i != re_decalPolyHead[type] );
RE_FreeDecal ( type, re_decalPolyHead[type] );
}
else
{
RE_FreeDecal ( type, re_decalPolyHead[type] );
}
}
memset ( le, 0, sizeof(decalPoly_t) );
le->time = tr.refdef.time;
re_decalPolyTotal[type]++;
// Move on to the next decal poly and wrap around if need be
re_decalPolyHead[type]++;
if ( re_decalPolyHead[type] >= r_markcount->integer )
{
re_decalPolyHead[type] = 0;
}
return le;
}
/*
=================
RE_AddDecalToScene
origin should be a point within a unit of the plane
dir should be the plane normal
temporary marks will not be stored or randomly oriented, but immediately
passed to the renderer.
=================
*/
#define MAX_DECAL_FRAGMENTS 128
#define MAX_DECAL_POINTS 384
void RE_AddDecalToScene ( qhandle_t decalShader, const vec3_t origin, const vec3_t dir, float orientation, float red, float green, float blue, float alpha, qboolean alphaFade, float radius, qboolean temporary )
{
vec3_t axis[3];
float texCoordScale;
vec3_t originalPoints[4];
byte colors[4];
int i, j;
int numFragments;
markFragment_t markFragments[MAX_DECAL_FRAGMENTS], *mf;
vec3_t markPoints[MAX_DECAL_POINTS];
vec3_t projection;
assert(decalShader);
if ( r_markcount->integer <= 0 && !temporary )
{
return;
}
if ( radius <= 0 )
{
Com_Error( ERR_FATAL, "RE_AddDecalToScene: called with <= 0 radius" );
}
// create the texture axis
VectorNormalize2( dir, axis[0] );
PerpendicularVector( axis[1], axis[0] );
RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
CrossProduct( axis[0], axis[2], axis[1] );
texCoordScale = 0.5 * 1.0 / radius;
// create the full polygon
for ( i = 0 ; i < 3 ; i++ )
{
originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
}
// get the fragments
VectorScale( dir, -20, projection );
numFragments = R_MarkFragments( 4, (const vec3_t*)originalPoints,
projection, MAX_DECAL_POINTS, markPoints[0],
MAX_DECAL_FRAGMENTS, markFragments );
colors[0] = red * 255;
colors[1] = green * 255;
colors[2] = blue * 255;
colors[3] = alpha * 255;
for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ )
{
polyVert_t *v;
polyVert_t verts[MAX_VERTS_ON_DECAL_POLY];
decalPoly_t *decal;
// we have an upper limit on the complexity of polygons
// that we store persistantly
if ( mf->numPoints > MAX_VERTS_ON_DECAL_POLY )
{
mf->numPoints = MAX_VERTS_ON_DECAL_POLY;
}
for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ )
{
vec3_t delta;
VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
VectorSubtract( v->xyz, origin, delta );
v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
*(int *)v->modulate = *(int *)colors;
}
// if it is a temporary (shadow) mark, add it immediately and forget about it
if ( temporary )
{
RE_AddPolyToScene( decalShader, mf->numPoints, verts, 1 );
continue;
}
// otherwise save it persistantly
decal = RE_AllocDecal( DECALPOLY_TYPE_NORMAL );
decal->time = tr.refdef.time;
decal->shader = decalShader;
decal->poly.numVerts = mf->numPoints;
decal->color[0] = red;
decal->color[1] = green;
decal->color[2] = blue;
decal->color[3] = alpha;
memcpy( decal->verts, verts, mf->numPoints * sizeof( verts[0] ) );
}
}
/*
===============
R_AddDecals
===============
*/
static inline void R_AddDecals ( void )
{
int decalPoly;
int type;
static int lastMarkCount = -1;
if ( r_markcount->integer != lastMarkCount )
{
if ( lastMarkCount != -1 )
{
RE_ClearDecals ( );
}
lastMarkCount = r_markcount->integer;
}
if ( r_markcount->integer <= 0 )
{
return;
}
for ( type = DECALPOLY_TYPE_NORMAL; type < DECALPOLY_TYPE_MAX; type ++ )
{
decalPoly = re_decalPolyHead[type];
do
{
decalPoly_t* p = &re_decalPolys[type][decalPoly];
if ( p->time )
{
if ( p->fadetime )
{
int t;
// fade all marks out with time
t = tr.refdef.time - p->time;
if ( t < DECAL_FADE_TIME )
{
float fade;
int j;
fade = 255.0f * (1.0f - ((float)t / DECAL_FADE_TIME));
for ( j = 0 ; j < p->poly.numVerts ; j++ )
{
p->verts[j].modulate[3] = fade;
}
RE_AddPolyToScene( p->shader, p->poly.numVerts, p->verts, 1 );
}
else
{
RE_FreeDecal ( type, decalPoly );
}
}
else
{
RE_AddPolyToScene( p->shader, p->poly.numVerts, p->verts, 1 );
}
}
decalPoly++;
if ( decalPoly >= r_markcount->integer )
{
decalPoly = 0;
}
}
while ( decalPoly != re_decalPolyHead[type] );
}
}
/*
@@@@@@@@@@@@@@@@@@@@@
RE_RenderScene
Draw a 3D view into a part of the window, then return
to 2D drawing.
Rendering a scene may require multiple views to be rendered
to handle mirrors,
@@@@@@@@@@@@@@@@@@@@@
*/
void RE_RenderWorldEffects(void);
void RE_RenderAutoMap(void);
void RE_RenderScene( const refdef_t *fd ) {
viewParms_t parms;
int startTime;
static int lastTime = 0;
if ( !tr.registered ) {
return;
}
GLimp_LogComment( "====== RE_RenderScene =====\n" );
if ( r_norefresh->integer ) {
return;
}
startTime = Sys_Milliseconds()*com_timescale->value;
if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
Com_Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
}
Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
tr.refdef.x = fd->x;
tr.refdef.y = fd->y;
tr.refdef.width = fd->width;
tr.refdef.height = fd->height;
tr.refdef.fov_x = fd->fov_x;
tr.refdef.fov_y = fd->fov_y;
VectorCopy( fd->vieworg, tr.refdef.vieworg );
VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
tr.refdef.time = fd->time;
tr.refdef.frametime = fd->time - lastTime;
lastTime = fd->time;
if (fd->rdflags & RDF_SKYBOXPORTAL)
{
skyboxportal = 1;
}
if (fd->rdflags & RDF_DRAWSKYBOX)
{
drawskyboxportal = 1;
}
else
{
drawskyboxportal = 0;
}
if (tr.refdef.frametime > 500)
{
tr.refdef.frametime = 500;
}
else if (tr.refdef.frametime < 0)
{
tr.refdef.frametime = 0;
}
tr.refdef.rdflags = fd->rdflags;
// copy the areamask data over and note if it has changed, which
// will force a reset of the visible leafs even if the view hasn't moved
tr.refdef.areamaskModified = qfalse;
if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) {
int areaDiff;
int i;
// compare the area bits
areaDiff = 0;
for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) {
areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];
((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];
}
if ( areaDiff ) {
// a door just opened or something
tr.refdef.areamaskModified = qtrue;
}
}
// derived info
tr.refdef.floatTime = tr.refdef.time * 0.001f;
tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
tr.refdef.drawSurfs = backEndData->drawSurfs;
tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
tr.refdef.entities = &backEndData->entities[r_firstSceneEntity];
tr.refdef.miniEntities = &backEndData->miniEntities[r_firstSceneMiniEntity];
tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight];
// Add the decals here because decals add polys and we need to ensure
// that the polys are added before the the renderer is prepared
if ( !(tr.refdef.rdflags & RDF_NOWORLDMODEL) )
{
R_AddDecals ( );
}
tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
tr.refdef.polys = &backEndData->polys[r_firstScenePoly];
// turn off dynamic lighting globally by clearing all the
// dlights if it needs to be disabled or if vertex lighting is enabled
if ( r_dynamiclight->integer == 0 ||
r_vertexLight->integer == 1 ) {
tr.refdef.num_dlights = 0;
}
// a single frame may have multiple scenes draw inside it --
// a 3D game view, 3D status bar renderings, 3D menus, etc.
// They need to be distinguished by the light flare code, because
// the visibility state for a given surface may be different in
// each scene / view.
tr.frameSceneNum++;
tr.sceneCount++;
// setup view parms for the initial view
//
// set up viewport
// The refdef takes 0-at-the-top y coordinates, so
// convert to GL's 0-at-the-bottom space
//
Com_Memset( &parms, 0, sizeof( parms ) );
parms.viewportX = tr.refdef.x;
parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
parms.viewportWidth = tr.refdef.width;
parms.viewportHeight = tr.refdef.height;
parms.isPortal = qfalse;
parms.fovX = tr.refdef.fov_x;
parms.fovY = tr.refdef.fov_y;
VectorCopy( fd->vieworg, parms.ori.origin );
VectorCopy( fd->viewaxis[0], parms.ori.axis[0] );
VectorCopy( fd->viewaxis[1], parms.ori.axis[1] );
VectorCopy( fd->viewaxis[2], parms.ori.axis[2] );
VectorCopy( fd->vieworg, parms.pvsOrigin );
R_RenderView( &parms );
// the next scene rendered in this frame will tack on after this one
r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
#ifdef _XBOX
const char *cstr = CG_ConfigString(CS_SKYBOXORG);
if(ClientManager::splitScreenMode == qfalse ||
(ClientManager::splitScreenMode == qtrue && (cstr && cstr[0])))
#endif
r_firstSceneEntity = r_numentities;
r_firstSceneMiniEntity = r_numminientities;
r_firstSceneDlight = r_numdlights;
r_firstScenePoly = r_numpolys;
refEntParent = -1;
tr.frontEndMsec += Sys_Milliseconds()*com_timescale->value - startTime;
RE_RenderWorldEffects();
if (tr.refdef.rdflags & RDF_AUTOMAP)
{
RE_RenderAutoMap();
}
}
#if 0 //rwwFIXMEFIXME: Disable this before release!!!!!! I am just trying to find a crash bug.
int R_GetRNumEntities(void)
{
return r_numentities;
}
void R_SetRNumEntities(int num)
{
r_numentities = num;
}
#endif

2482
codemp/renderer/tr_shade.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,724 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
#include "tr_local.h"
/*
for a projection shadow:
point[x] += light vector * ( z - shadow plane )
point[y] +=
point[z] = shadow plane
1 0 light[x] / light[z]
*/
#ifndef _XBOX
#define _STENCIL_REVERSE
typedef struct {
int i2;
int facing;
} edgeDef_t;
#define MAX_EDGE_DEFS 32
static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
static int numEdgeDefs[SHADER_MAX_VERTEXES];
static int facing[SHADER_MAX_INDEXES/3];
void R_AddEdgeDef( int i1, int i2, int facing ) {
int c;
c = numEdgeDefs[ i1 ];
if ( c == MAX_EDGE_DEFS ) {
return; // overflow
}
edgeDefs[ i1 ][ c ].i2 = i2;
edgeDefs[ i1 ][ c ].facing = facing;
numEdgeDefs[ i1 ]++;
}
void R_RenderShadowEdges( void ) {
int i;
int c;
int j;
int i2;
int c_edges, c_rejected;
#if 0
int c2, k;
int hit[2];
#endif
#ifdef _STENCIL_REVERSE
int numTris;
int o1, o2, o3;
#endif
// an edge is NOT a silhouette edge if its face doesn't face the light,
// or if it has a reverse paired edge that also faces the light.
// A well behaved polyhedron would have exactly two faces for each edge,
// but lots of models have dangling edges or overfanned edges
c_edges = 0;
c_rejected = 0;
for ( i = 0 ; i < tess.numVertexes ; i++ ) {
c = numEdgeDefs[ i ];
for ( j = 0 ; j < c ; j++ ) {
if ( !edgeDefs[ i ][ j ].facing ) {
continue;
}
//with this system we can still get edges shared by more than 2 tris which
//produces artifacts including seeing the shadow through walls. So for now
//we are going to render all edges even though it is a tiny bit slower. -rww
#if 1
i2 = edgeDefs[ i ][ j ].i2;
qglBegin( GL_TRIANGLE_STRIP );
qglVertex3fv( tess.xyz[ i ] );
qglVertex3fv( tess.xyz[ i + tess.numVertexes ] );
qglVertex3fv( tess.xyz[ i2 ] );
qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] );
qglEnd();
#else
hit[0] = 0;
hit[1] = 0;
i2 = edgeDefs[ i ][ j ].i2;
c2 = numEdgeDefs[ i2 ];
for ( k = 0 ; k < c2 ; k++ ) {
if ( edgeDefs[ i2 ][ k ].i2 == i ) {
hit[ edgeDefs[ i2 ][ k ].facing ]++;
}
}
// if it doesn't share the edge with another front facing
// triangle, it is a sil edge
if (hit[1] != 1)
{
qglBegin( GL_TRIANGLE_STRIP );
qglVertex3fv( tess.xyz[ i ] );
qglVertex3fv( tess.xyz[ i + tess.numVertexes ] );
qglVertex3fv( tess.xyz[ i2 ] );
qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] );
qglEnd();
c_edges++;
} else {
c_rejected++;
}
#endif
}
}
#ifdef _STENCIL_REVERSE
//Carmack Reverse<tm> method requires that volumes
//be capped properly -rww
numTris = tess.numIndexes / 3;
for ( i = 0 ; i < numTris ; i++ )
{
if ( !facing[i] )
{
continue;
}
o1 = tess.indexes[ i*3 + 0 ];
o2 = tess.indexes[ i*3 + 1 ];
o3 = tess.indexes[ i*3 + 2 ];
qglBegin(GL_TRIANGLES);
qglVertex3fv(tess.xyz[o1]);
qglVertex3fv(tess.xyz[o2]);
qglVertex3fv(tess.xyz[o3]);
qglEnd();
qglBegin(GL_TRIANGLES);
qglVertex3fv(tess.xyz[o3 + tess.numVertexes]);
qglVertex3fv(tess.xyz[o2 + tess.numVertexes]);
qglVertex3fv(tess.xyz[o1 + tess.numVertexes]);
qglEnd();
}
#endif
}
//#define _DEBUG_STENCIL_SHADOWS
/*
=================
RB_ShadowTessEnd
triangleFromEdge[ v1 ][ v2 ]
set triangle from edge( v1, v2, tri )
if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {
}
=================
*/
void RB_DoShadowTessEnd( vec3_t lightPos );
void RB_ShadowTessEnd( void )
{
#if 0
if (backEnd.currentEntity &&
(backEnd.currentEntity->directedLight[0] ||
backEnd.currentEntity->directedLight[1] ||
backEnd.currentEntity->directedLight[2]))
{ //an ent that has its light set for it
RB_DoShadowTessEnd(NULL);
return;
}
// if (!tess.dlightBits)
// {
// return;
// }
int i = 0;
dlight_t *dl;
R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori );
/* while (i < tr.refdef.num_dlights)
{
if (tess.dlightBits & (1 << i))
{
dl = &tr.refdef.dlights[i];
RB_DoShadowTessEnd(dl->transformed);
}
i++;
}
*/
dl = &tr.refdef.dlights[0];
RB_DoShadowTessEnd(dl->transformed);
#else //old ents-only way
RB_DoShadowTessEnd(NULL);
#endif
}
void RB_DoShadowTessEnd( vec3_t lightPos )
{
int i;
int numTris;
vec3_t lightDir;
// we can only do this if we have enough space in the vertex buffers
if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) {
return;
}
if ( glConfig.stencilBits < 4 ) {
return;
}
#if 1 //controlled method - try to keep shadows in range so they don't show through so much -rww
vec3_t worldxyz;
vec3_t entLight;
float groundDist;
VectorCopy( backEnd.currentEntity->lightDir, entLight );
entLight[2] = 0.0f;
VectorNormalize(entLight);
//Oh well, just cast them straight down no matter what onto the ground plane.
//This presets no chance of screwups and still looks better than a stupid
//shader blob.
VectorSet(lightDir, entLight[0]*0.3f, entLight[1]*0.3f, 1.0f);
// project vertexes away from light direction
for ( i = 0 ; i < tess.numVertexes ; i++ ) {
//add or.origin to vert xyz to end up with world oriented coord, then figure
//out the ground pos for the vert to project the shadow volume to
VectorAdd(tess.xyz[i], backEnd.ori.origin, worldxyz);
groundDist = worldxyz[2] - backEnd.currentEntity->e.shadowPlane;
groundDist += 16.0f; //fudge factor
VectorMA( tess.xyz[i], -groundDist, lightDir, tess.xyz[i+tess.numVertexes] );
}
#else
if (lightPos)
{
for ( i = 0 ; i < tess.numVertexes ; i++ )
{
tess.xyz[i+tess.numVertexes][0] = tess.xyz[i][0]+(( tess.xyz[i][0]-lightPos[0] )*128.0f);
tess.xyz[i+tess.numVertexes][1] = tess.xyz[i][1]+(( tess.xyz[i][1]-lightPos[1] )*128.0f);
tess.xyz[i+tess.numVertexes][2] = tess.xyz[i][2]+(( tess.xyz[i][2]-lightPos[2] )*128.0f);
}
}
else
{
VectorCopy( backEnd.currentEntity->lightDir, lightDir );
// project vertexes away from light direction
for ( i = 0 ; i < tess.numVertexes ; i++ ) {
VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] );
}
}
#endif
// decide which triangles face the light
Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes );
numTris = tess.numIndexes / 3;
for ( i = 0 ; i < numTris ; i++ ) {
int i1, i2, i3;
vec3_t d1, d2, normal;
float *v1, *v2, *v3;
float d;
i1 = tess.indexes[ i*3 + 0 ];
i2 = tess.indexes[ i*3 + 1 ];
i3 = tess.indexes[ i*3 + 2 ];
v1 = tess.xyz[ i1 ];
v2 = tess.xyz[ i2 ];
v3 = tess.xyz[ i3 ];
if (!lightPos)
{
VectorSubtract( v2, v1, d1 );
VectorSubtract( v3, v1, d2 );
CrossProduct( d1, d2, normal );
d = DotProduct( normal, lightDir );
}
else
{
float planeEq[4];
planeEq[0] = v1[1]*(v2[2]-v3[2]) + v2[1]*(v3[2]-v1[2]) + v3[1]*(v1[2]-v2[2]);
planeEq[1] = v1[2]*(v2[0]-v3[0]) + v2[2]*(v3[0]-v1[0]) + v3[2]*(v1[0]-v2[0]);
planeEq[2] = v1[0]*(v2[1]-v3[1]) + v2[0]*(v3[1]-v1[1]) + v3[0]*(v1[1]-v2[1]);
planeEq[3] = -( v1[0]*( v2[1]*v3[2] - v3[1]*v2[2] ) +
v2[0]*(v3[1]*v1[2] - v1[1]*v3[2]) +
v3[0]*(v1[1]*v2[2] - v2[1]*v1[2]) );
d = planeEq[0]*lightPos[0]+
planeEq[1]*lightPos[1]+
planeEq[2]*lightPos[2]+
planeEq[3];
}
if ( d > 0 ) {
facing[ i ] = 1;
} else {
facing[ i ] = 0;
}
// create the edges
R_AddEdgeDef( i1, i2, facing[ i ] );
R_AddEdgeDef( i2, i3, facing[ i ] );
R_AddEdgeDef( i3, i1, facing[ i ] );
}
GL_Bind( tr.whiteImage );
//qglEnable( GL_CULL_FACE );
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
#ifndef _DEBUG_STENCIL_SHADOWS
qglColor3f( 0.2f, 0.2f, 0.2f );
// don't write to the color buffer
qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
qglEnable( GL_STENCIL_TEST );
qglStencilFunc( GL_ALWAYS, 1, 255 );
#else
qglColor3f( 1.0f, 0.0f, 0.0f );
qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//qglDisable(GL_DEPTH_TEST);
#endif
#ifdef _STENCIL_REVERSE
qglDepthFunc(GL_LESS);
//now using the Carmack Reverse<tm> -rww
if ( backEnd.viewParms.isMirror ) {
//qglCullFace( GL_BACK );
GL_Cull(CT_BACK_SIDED);
qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP );
R_RenderShadowEdges();
//qglCullFace( GL_FRONT );
GL_Cull(CT_FRONT_SIDED);
qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP );
R_RenderShadowEdges();
} else {
//qglCullFace( GL_FRONT );
GL_Cull(CT_FRONT_SIDED);
qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP );
R_RenderShadowEdges();
//qglCullFace( GL_BACK );
GL_Cull(CT_BACK_SIDED);
qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP );
R_RenderShadowEdges();
}
qglDepthFunc(GL_LEQUAL);
#else
// mirrors have the culling order reversed
if ( backEnd.viewParms.isMirror ) {
qglCullFace( GL_FRONT );
qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
R_RenderShadowEdges();
qglCullFace( GL_BACK );
qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
R_RenderShadowEdges();
} else {
qglCullFace( GL_BACK );
qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
R_RenderShadowEdges();
qglCullFace( GL_FRONT );
qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
R_RenderShadowEdges();
}
#endif
// reenable writing to the color buffer
qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
#ifdef _DEBUG_STENCIL_SHADOWS
qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
}
/*
=================
RB_ShadowFinish
Darken everything that is is a shadow volume.
We have to delay this until everything has been shadowed,
because otherwise shadows from different body parts would
overlap and double darken.
=================
*/
void RB_ShadowFinish( void ) {
if ( r_shadows->integer != 2 ) {
return;
}
if ( glConfig.stencilBits < 4 ) {
return;
}
#ifdef _DEBUG_STENCIL_SHADOWS
return;
#endif
qglEnable( GL_STENCIL_TEST );
qglStencilFunc( GL_NOTEQUAL, 0, 255 );
qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
bool planeZeroBack = false;
if (qglIsEnabled(GL_CLIP_PLANE0))
{
planeZeroBack = true;
qglDisable (GL_CLIP_PLANE0);
}
GL_Cull(CT_TWO_SIDED);
//qglDisable (GL_CULL_FACE);
GL_Bind( tr.whiteImage );
qglPushMatrix();
qglLoadIdentity ();
// qglColor3f( 0.6f, 0.6f, 0.6f );
// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );
// qglColor3f( 1, 0, 0 );
// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
qglColor4f( 0.0f, 0.0f, 0.0f, 0.5f );
//GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
qglBegin( GL_QUADS );
qglVertex3f( -100, 100, -10 );
qglVertex3f( 100, 100, -10 );
qglVertex3f( 100, -100, -10 );
qglVertex3f( -100, -100, -10 );
qglEnd ();
qglColor4f(1,1,1,1);
qglDisable( GL_STENCIL_TEST );
if (planeZeroBack)
{
qglEnable (GL_CLIP_PLANE0);
}
qglPopMatrix();
}
/*
=================
RB_ProjectionShadowDeform
=================
*/
void RB_ProjectionShadowDeform( void ) {
float *xyz;
int i;
float h;
vec3_t ground;
vec3_t light;
float groundDist;
float d;
vec3_t lightDir;
xyz = ( float * ) tess.xyz;
ground[0] = backEnd.ori.axis[0][2];
ground[1] = backEnd.ori.axis[1][2];
ground[2] = backEnd.ori.axis[2][2];
groundDist = backEnd.ori.origin[2] - backEnd.currentEntity->e.shadowPlane;
VectorCopy( backEnd.currentEntity->lightDir, lightDir );
d = DotProduct( lightDir, ground );
// don't let the shadows get too long or go negative
if ( d < 0.5 ) {
VectorMA( lightDir, (0.5 - d), ground, lightDir );
d = DotProduct( lightDir, ground );
}
d = 1.0 / d;
light[0] = lightDir[0] * d;
light[1] = lightDir[1] * d;
light[2] = lightDir[2] * d;
for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
h = DotProduct( xyz, ground ) + groundDist;
xyz[0] -= light[0] * h;
xyz[1] -= light[1] * h;
xyz[2] -= light[2] * h;
}
}
#endif // _XBOX
//update tr.screenImage
void RB_CaptureScreenImage(void)
{
int radX = 2048;
int radY = 2048;
int x = glConfig.vidWidth/2;
int y = glConfig.vidHeight/2;
int cX, cY;
GL_Bind( tr.screenImage );
//using this method, we could pixel-filter the texture and all sorts of crazy stuff.
//but, it is slow as hell.
/*
static byte *tmp = NULL;
if (!tmp)
{
tmp = (byte *)Z_Malloc((sizeof(byte)*4)*(glConfig.vidWidth*glConfig.vidHeight), TAG_ICARUS, qtrue);
}
qglReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGBA, GL_UNSIGNED_BYTE, tmp);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, tmp);
*/
if (radX > glConfig.maxTextureSize)
{
radX = glConfig.maxTextureSize;
}
if (radY > glConfig.maxTextureSize)
{
radY = glConfig.maxTextureSize;
}
while (glConfig.vidWidth < radX)
{
radX /= 2;
}
while (glConfig.vidHeight < radY)
{
radY /= 2;
}
cX = x-(radX/2);
cY = y-(radY/2);
if (cX+radX > glConfig.vidWidth)
{ //would it go off screen?
cX = glConfig.vidWidth-radX;
}
else if (cX < 0)
{ //cap it off at 0
cX = 0;
}
if (cY+radY > glConfig.vidHeight)
{ //would it go off screen?
cY = glConfig.vidHeight-radY;
}
else if (cY < 0)
{ //cap it off at 0
cY = 0;
}
#ifndef _XBOX
qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, cX, cY, radX, radY, 0);
#else
qglCopyBackBufferToTexEXT(radX, radY, cX, cY, (cX + radX), (cY + radY));
#endif // _XBOX
}
//yeah.. not really shadow-related.. but it's stencil-related. -rww
float tr_distortionAlpha = 1.0f; //opaque
float tr_distortionStretch = 0.0f; //no stretch override
qboolean tr_distortionPrePost = qfalse; //capture before postrender phase?
qboolean tr_distortionNegate = qfalse; //negative blend mode
void RB_DistortionFill(void)
{
float alpha = tr_distortionAlpha;
float spost = 0.0f;
float spost2 = 0.0f;
if ( glConfig.stencilBits < 4 )
{
return;
}
//ok, cap the stupid thing now I guess
if (!tr_distortionPrePost)
{
RB_CaptureScreenImage();
}
qglEnable(GL_STENCIL_TEST);
qglStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
qglDisable (GL_CLIP_PLANE0);
GL_Cull( CT_TWO_SIDED );
//reset the view matrices and go into ortho mode
qglMatrixMode(GL_PROJECTION);
qglPushMatrix();
qglLoadIdentity();
qglOrtho(0, glConfig.vidWidth, glConfig.vidHeight, 32, -1, 1);
qglMatrixMode(GL_MODELVIEW);
qglPushMatrix();
qglLoadIdentity();
if (tr_distortionStretch)
{ //override
spost = tr_distortionStretch;
spost2 = tr_distortionStretch;
}
else
{ //do slow stretchy effect
spost = sin(tr.refdef.time*0.0005f);
if (spost < 0.0f)
{
spost = -spost;
}
spost *= 0.2f;
spost2 = sin(tr.refdef.time*0.0005f);
if (spost2 < 0.0f)
{
spost2 = -spost2;
}
spost2 *= 0.08f;
}
if (alpha != 1.0f)
{ //blend
GL_State(GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_SRC_ALPHA);
}
else
{ //be sure to reset the draw state
GL_State(0);
}
#ifdef _XBOX
qglBeginEXT(GL_QUADS, 4, 0, 0, 4, 0);
#else
qglBegin(GL_QUADS);
#endif // _XBOX
qglColor4f(1.0f, 1.0f, 1.0f, alpha);
qglTexCoord2f(0+spost2, 1-spost);
qglVertex2f(0, 0);
qglTexCoord2f(0+spost2, 0+spost);
qglVertex2f(0, glConfig.vidHeight);
qglTexCoord2f(1-spost2, 0+spost);
qglVertex2f(glConfig.vidWidth, glConfig.vidHeight);
qglTexCoord2f(1-spost2, 1-spost);
qglVertex2f(glConfig.vidWidth, 0);
qglEnd();
if (tr_distortionAlpha == 1.0f && tr_distortionStretch == 0.0f)
{ //no overrides
if (tr_distortionNegate)
{ //probably the crazy alternate saber trail
alpha = 0.8f;
GL_State(GLS_SRCBLEND_ZERO|GLS_DSTBLEND_ONE_MINUS_SRC_COLOR);
}
else
{
alpha = 0.5f;
GL_State(GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_SRC_ALPHA);
}
spost = sin(tr.refdef.time*0.0008f);
if (spost < 0.0f)
{
spost = -spost;
}
spost *= 0.08f;
spost2 = sin(tr.refdef.time*0.0008f);
if (spost2 < 0.0f)
{
spost2 = -spost2;
}
spost2 *= 0.2f;
#ifdef _XBOX
qglBeginEXT(GL_QUADS, 4, 0, 0, 4, 0);
#else
qglBegin(GL_QUADS);
#endif // _XBOX
qglColor4f(1.0f, 1.0f, 1.0f, alpha);
qglTexCoord2f(0+spost2, 1-spost);
qglVertex2f(0, 0);
qglTexCoord2f(0+spost2, 0+spost);
qglVertex2f(0, glConfig.vidHeight);
qglTexCoord2f(1-spost2, 0+spost);
qglVertex2f(glConfig.vidWidth, glConfig.vidHeight);
qglTexCoord2f(1-spost2, 1-spost);
qglVertex2f(glConfig.vidWidth, 0);
qglEnd();
}
//pop the view matrices back
qglMatrixMode(GL_PROJECTION);
qglPopMatrix();
qglMatrixMode(GL_MODELVIEW);
qglPopMatrix();
qglDisable( GL_STENCIL_TEST );
}

849
codemp/renderer/tr_sky.cpp Normal file
View File

@@ -0,0 +1,849 @@
//Anything above this #include will be ignored by the compiler
#include "../qcommon/exe_headers.h"
// tr_sky.c
#include "tr_local.h"
#define SKY_SUBDIVISIONS 8
#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2)
static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
extern bool g_bRenderGlowingObjects;
/*
===================================================================================
POLYGON TO BOX SIDE PROJECTION
===================================================================================
*/
static vec3_t sky_clip[6] =
{
{1,1,0},
{1,-1,0},
{0,-1,1},
{0,1,1},
{1,0,1},
{-1,0,1}
};
static float sky_mins[2][6], sky_maxs[2][6];
static float sky_min, sky_max;
/*
================
AddSkyPolygon
================
*/
static void AddSkyPolygon (int nump, vec3_t vecs)
{
int i,j;
vec3_t v, av;
float s, t, dv;
int axis;
float *vp;
// s = [0]/[2], t = [1]/[2]
static int vec_to_st[6][3] =
{
{-2,3,1},
{2,3,-1},
{1,3,2},
{-1,3,-2},
{-2,-1,3},
{-2,1,-3}
// {-1,2,3},
// {1,2,-3}
};
// decide which face it maps to
VectorCopy (vec3_origin, v);
for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
{
VectorAdd (vp, v, v);
}
av[0] = fabs(v[0]);
av[1] = fabs(v[1]);
av[2] = fabs(v[2]);
if (av[0] > av[1] && av[0] > av[2])
{
if (v[0] < 0)
axis = 1;
else
axis = 0;
}
else if (av[1] > av[2] && av[1] > av[0])
{
if (v[1] < 0)
axis = 3;
else
axis = 2;
}
else
{
if (v[2] < 0)
axis = 5;
else
axis = 4;
}
// project new texture coords
for (i=0 ; i<nump ; i++, vecs+=3)
{
j = vec_to_st[axis][2];
if (j > 0)
dv = vecs[j - 1];
else
dv = -vecs[-j - 1];
if (dv < 0.001)
continue; // don't divide by zero
j = vec_to_st[axis][0];
if (j < 0)
s = -vecs[-j -1] / dv;
else
s = vecs[j-1] / dv;
j = vec_to_st[axis][1];
if (j < 0)
t = -vecs[-j -1] / dv;
else
t = vecs[j-1] / dv;
if (s < sky_mins[0][axis])
sky_mins[0][axis] = s;
if (t < sky_mins[1][axis])
sky_mins[1][axis] = t;
if (s > sky_maxs[0][axis])
sky_maxs[0][axis] = s;
if (t > sky_maxs[1][axis])
sky_maxs[1][axis] = t;
}
}
#define ON_EPSILON 0.1f // point on plane side epsilon
#define MAX_CLIP_VERTS 64
/*
================
ClipSkyPolygon
================
*/
static void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
{
float *norm;
float *v;
qboolean front, back;
float d, e;
float dists[MAX_CLIP_VERTS];
int sides[MAX_CLIP_VERTS];
vec3_t newv[2][MAX_CLIP_VERTS];
int newc[2];
int i, j;
if (nump > MAX_CLIP_VERTS-2)
Com_Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
if (stage == 6)
{ // fully clipped, so draw it
AddSkyPolygon (nump, vecs);
return;
}
front = back = qfalse;
norm = sky_clip[stage];
for (i=0, v = vecs ; i<nump ; i++, v+=3)
{
d = DotProduct (v, norm);
if (d > ON_EPSILON)
{
front = qtrue;
sides[i] = SIDE_FRONT;
}
else if (d < -ON_EPSILON)
{
back = qtrue;
sides[i] = SIDE_BACK;
}
else
sides[i] = SIDE_ON;
dists[i] = d;
}
if (!front || !back)
{ // not clipped
ClipSkyPolygon (nump, vecs, stage+1);
return;
}
// clip it
sides[i] = sides[0];
dists[i] = dists[0];
VectorCopy (vecs, (vecs+(i*3)) );
newc[0] = newc[1] = 0;
for (i=0, v = vecs ; i<nump ; i++, v+=3)
{
switch (sides[i])
{
case SIDE_FRONT:
VectorCopy (v, newv[0][newc[0]]);
newc[0]++;
break;
case SIDE_BACK:
VectorCopy (v, newv[1][newc[1]]);
newc[1]++;
break;
case SIDE_ON:
VectorCopy (v, newv[0][newc[0]]);
newc[0]++;
VectorCopy (v, newv[1][newc[1]]);
newc[1]++;
break;
}
if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
d = dists[i] / (dists[i] - dists[i+1]);
for (j=0 ; j<3 ; j++)
{
e = v[j] + d*(v[j+3] - v[j]);
newv[0][newc[0]][j] = e;
newv[1][newc[1]][j] = e;
}
newc[0]++;
newc[1]++;
}
// continue
ClipSkyPolygon (newc[0], newv[0][0], stage+1);
ClipSkyPolygon (newc[1], newv[1][0], stage+1);
}
/*
==============
ClearSkyBox
==============
*/
static void ClearSkyBox (void) {
int i;
for (i=0 ; i<6 ; i++) {
sky_mins[0][i] = sky_mins[1][i] = 9999;
sky_maxs[0][i] = sky_maxs[1][i] = -9999;
}
}
/*
================
RB_ClipSkyPolygons
================
*/
void RB_ClipSkyPolygons( shaderCommands_t *input )
{
vec3_t p[5]; // need one extra point for clipping
int i, j;
ClearSkyBox();
for ( i = 0; i < input->numIndexes; i += 3 )
{
for (j = 0 ; j < 3 ; j++)
{
VectorSubtract( input->xyz[input->indexes[i+j]],
backEnd.viewParms.ori.origin,
p[j] );
}
ClipSkyPolygon( 3, p[0], 0 );
}
}
/*
===================================================================================
CLOUD VERTEX GENERATION
===================================================================================
*/
/*
** MakeSkyVec
**
** Parms: s, t range from -1 to 1
*/
static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ )
{
// 1 = s, 2 = t, 3 = 2048
static int st_to_vec[6][3] =
{
{3,-1,2},
{-3,1,2},
{1,3,2},
{-1,-3,2},
{-2,-1,3}, // 0 degrees yaw, look straight up
{2,-1,-3} // look straight down
};
vec3_t b;
int j, k;
float boxSize;
boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
b[0] = s*boxSize;
b[1] = t*boxSize;
b[2] = boxSize;
for (j=0 ; j<3 ; j++)
{
k = st_to_vec[axis][j];
if (k < 0)
{
outXYZ[j] = -b[-k - 1];
}
else
{
outXYZ[j] = b[k - 1];
}
}
// avoid bilerp seam
s = (s+1)*0.5;
t = (t+1)*0.5;
if (s < sky_min)
{
s = sky_min;
}
else if (s > sky_max)
{
s = sky_max;
}
if (t < sky_min)
{
t = sky_min;
}
else if (t > sky_max)
{
t = sky_max;
}
t = 1.0 - t;
if ( outSt )
{
outSt[0] = s;
outSt[1] = t;
}
}
static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
{
int s, t;
GL_Bind( image );
#ifdef _XBOX
int verts = ((maxs[0]+HALF_SKY_SUBDIVISIONS) - (mins[0]+HALF_SKY_SUBDIVISIONS)) * 2 + 2;
#endif
for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
#ifdef _XBOX
qglBeginEXT( GL_TRIANGLE_STRIP, verts, 0, 0, verts, 0);
#else
qglBegin( GL_TRIANGLE_STRIP );
#endif
for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
qglTexCoord2fv( s_skyTexCoords[t][s] );
qglVertex3fv( s_skyPoints[t][s] );
qglTexCoord2fv( s_skyTexCoords[t+1][s] );
qglVertex3fv( s_skyPoints[t+1][s] );
}
qglEnd();
}
}
static void DrawSkyBox( shader_t *shader )
{
int i;
sky_min = 0;
sky_max = 1;
Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
for (i=0 ; i<6 ; i++)
{
int sky_mins_subd[2], sky_maxs_subd[2];
int s, t;
sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
( sky_mins[1][i] >= sky_maxs[1][i] ) )
{
continue;
}
sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS )
sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
//
// iterate through the subdivisions
//
for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
i,
s_skyTexCoords[t][s],
s_skyPoints[t][s] );
}
}
DrawSkySide( shader->sky->outerbox[i],
sky_mins_subd,
sky_maxs_subd );
}
}
static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes )
{
int s, t;
int vertexStart = tess.numVertexes;
int tHeight, sWidth;
tHeight = maxs[1] - mins[1] + 1;
sWidth = maxs[0] - mins[0] + 1;
for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
VectorAdd( s_skyPoints[t][s], backEnd.viewParms.ori.origin, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];
tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];
tess.numVertexes++;
if ( tess.numVertexes >= SHADER_MAX_VERTEXES )
{
Com_Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()\n" );
}
}
}
// only add indexes for one pass, otherwise it would draw multiple times for each pass
if ( addIndexes ) {
for ( t = 0; t < tHeight-1; t++ )
{
for ( s = 0; s < sWidth-1; s++ )
{
tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
tess.numIndexes++;
}
}
}
}
static void FillCloudBox( const shader_t *shader, int stage )
{
int i;
for ( i =0; i < 6; i++ )
{
int sky_mins_subd[2], sky_maxs_subd[2];
int s, t;
float MIN_T;
if ( 1 ) // FIXME? shader->sky->fullClouds )
{
MIN_T = -HALF_SKY_SUBDIVISIONS;
// still don't want to draw the bottom, even if fullClouds
if ( i == 5 )
continue;
}
else
{
switch( i )
{
case 0:
case 1:
case 2:
case 3:
MIN_T = -1;
break;
case 5:
// don't draw clouds beneath you
continue;
case 4: // top
default:
MIN_T = -HALF_SKY_SUBDIVISIONS;
break;
}
}
sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
( sky_mins[1][i] >= sky_maxs[1][i] ) )
{
continue;
}
sky_mins_subd[0] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS );
sky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS );
sky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS );
sky_maxs_subd[1] = myftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS );
if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_mins_subd[1] < MIN_T )
sky_mins_subd[1] = MIN_T;
else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[1] < MIN_T )
sky_maxs_subd[1] = MIN_T;
else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
//
// iterate through the subdivisions
//
for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
i,
NULL,
s_skyPoints[t][s] );
s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
}
}
// only add indexes for first stage
FillCloudySkySide( sky_mins_subd, sky_maxs_subd, (qboolean)( stage == 0 ) );
}
}
/*
** R_BuildCloudData
*/
void R_BuildCloudData( shaderCommands_t *input )
{
int i;
shader_t *shader;
shader = input->shader;
assert( shader->sky );
sky_min = 1.0 / 256.0f; // FIXME: not correct?
sky_max = 255.0 / 256.0f;
// set up for drawing
tess.numIndexes = 0;
tess.numVertexes = 0;
if ( input->shader->sky->cloudHeight )
{
for ( i = 0; i < input->shader->numUnfoggedPasses; i++ )
{
FillCloudBox( input->shader, i );
}
}
}
/*
** R_InitSkyTexCoords
** Called when a sky shader is parsed
*/
#define SQR( a ) ((a)*(a))
void R_InitSkyTexCoords( float heightCloud )
{
int i, s, t;
float radiusWorld = 4096;
float p;
float sRad, tRad;
vec3_t skyVec;
vec3_t v;
// init zfar so MakeSkyVec works even though
// a world hasn't been bounded
backEnd.viewParms.zFar = 1024;
for ( i = 0; i < 6; i++ )
{
for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
{
for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
{
// compute vector from view origin to sky side integral point
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
i,
NULL,
skyVec );
// compute parametric value 'p' that intersects with cloud layer
p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
( -2 * skyVec[2] * radiusWorld +
2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) +
2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
SQR( skyVec[0] ) * SQR( heightCloud ) +
2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
SQR( skyVec[1] ) * SQR( heightCloud ) +
2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
SQR( skyVec[2] ) * SQR( heightCloud ) ) );
s_cloudTexP[i][t][s] = p;
// compute intersection point based on p
VectorScale( skyVec, p, v );
v[2] += radiusWorld;
// compute vector from world origin to intersection point 'v'
VectorNormalize( v );
sRad = Q_acos( v[0] );
tRad = Q_acos( v[1] );
s_cloudTexCoords[i][t][s][0] = sRad;
s_cloudTexCoords[i][t][s][1] = tRad;
}
}
}
}
//======================================================================================
/*
** RB_DrawSun
*/
void RB_DrawSun( void ) {
float size;
float dist;
vec3_t origin, vec1, vec2;
vec3_t temp;
if ( !backEnd.skyRenderedThisView ) {
return;
}
if ( !r_drawSun->integer ) {
return;
}
qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
qglTranslatef (backEnd.viewParms.ori.origin[0], backEnd.viewParms.ori.origin[1], backEnd.viewParms.ori.origin[2]);
dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
size = dist * 0.4;
VectorScale( tr.sunDirection, dist, origin );
PerpendicularVector( vec1, tr.sunDirection );
CrossProduct( tr.sunDirection, vec1, vec2 );
VectorScale( vec1, size, vec1 );
VectorScale( vec2, size, vec2 );
// farthest depth range
qglDepthRange( 1.0, 1.0 );
// FIXME: use quad stamp
RB_BeginSurface( tr.sunShader, tess.fogNum );
VectorCopy( origin, temp );
VectorSubtract( temp, vec1, temp );
VectorSubtract( temp, vec2, temp );
VectorCopy( temp, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255;
tess.vertexColors[tess.numVertexes][1] = 255;
tess.vertexColors[tess.numVertexes][2] = 255;
tess.numVertexes++;
VectorCopy( origin, temp );
VectorAdd( temp, vec1, temp );
VectorSubtract( temp, vec2, temp );
VectorCopy( temp, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255;
tess.vertexColors[tess.numVertexes][1] = 255;
tess.vertexColors[tess.numVertexes][2] = 255;
tess.numVertexes++;
VectorCopy( origin, temp );
VectorAdd( temp, vec1, temp );
VectorAdd( temp, vec2, temp );
VectorCopy( temp, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255;
tess.vertexColors[tess.numVertexes][1] = 255;
tess.vertexColors[tess.numVertexes][2] = 255;
tess.numVertexes++;
VectorCopy( origin, temp );
VectorSubtract( temp, vec1, temp );
VectorAdd( temp, vec2, temp );
VectorCopy( temp, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255;
tess.vertexColors[tess.numVertexes][1] = 255;
tess.vertexColors[tess.numVertexes][2] = 255;
tess.numVertexes++;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 1;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 3;
RB_EndSurface();
// back to normal depth range
qglDepthRange( 0.0, 1.0 );
}
/*
================
RB_StageIteratorSky
All of the visible sky triangles are in tess
Other things could be stuck in here, like birds in the sky, etc
================
*/
void RB_StageIteratorSky( void )
{
if ( g_bRenderGlowingObjects )
return;
if ( r_fastsky->integer ) {
return;
}
if (skyboxportal && !(backEnd.refdef.rdflags & RDF_SKYBOXPORTAL))
{
return;
}
// go through all the polygons and project them onto
// the sky box to see which blocks on each side need
// to be drawn
RB_ClipSkyPolygons( &tess );
// r_showsky will let all the sky blocks be drawn in
// front of everything to allow developers to see how
// much sky is getting sucked in
if ( r_showsky->integer ) {
qglDepthRange( 0.0, 0.0 );
} else {
#ifdef _XBOX
qglDepthRange( 0.99, 1.0 );
#else
qglDepthRange( 1.0, 1.0 );
#endif
}
// draw the outer skybox
if ( tess.shader->sky->outerbox[0] && tess.shader->sky->outerbox[0] != tr.defaultImage ) {
qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
qglPushMatrix ();
GL_State( 0 );
qglTranslatef (backEnd.viewParms.ori.origin[0], backEnd.viewParms.ori.origin[1], backEnd.viewParms.ori.origin[2]);
DrawSkyBox( tess.shader );
qglPopMatrix();
}
// generate the vertexes for all the clouds, which will be drawn
// by the generic shader routine
R_BuildCloudData( &tess );
if (tess.numIndexes && tess.numVertexes)
{
RB_StageIteratorGeneric();
}
// draw the inner skybox
// back to normal depth range
qglDepthRange( 0.0, 1.0 );
// note that sky was drawn so we will draw a sun later
backEnd.skyRenderedThisView = qtrue;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1939
codemp/renderer/tr_world.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
#if defined (_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif
#if !defined __TR_WORLDEFFECTS_H
#define __TR_WORLDEFFECTS_H
class CWorldEffectsSystem;
#define PARTICLE_FLAG_RENDER 0x00000001
struct SParticle
{
vec3_t pos;
vec3_t velocity;
unsigned flags;
};
class CWorldEffect
{
protected:
CWorldEffect *mNext, *mSlave, *mOwner;
bool mEnabled, mIsSlave;
public:
enum
{
WORLDEFFECT_ENABLED = 0,
WORLDEFFECT_PARTICLES,
WORLDEFFECT_PARTICLE_COUNT,
WORLDEFFECT_END
};
public:
CWorldEffect(CWorldEffect *owner = 0);
virtual ~CWorldEffect(void);
void SetNext(CWorldEffect *next) { mNext = next; }
CWorldEffect *GetNext(void) { return mNext; }
void SetSlave(CWorldEffect *slave) { mSlave = slave; }
CWorldEffect *GetSlave(void) { return mSlave; }
void AddSlave(CWorldEffect *slave);
void SetIsSlave(bool isSlave) { mIsSlave = isSlave; }
void SetOwner(CWorldEffect *owner) { mOwner = owner; }
virtual bool Command(const char *command);
virtual void ParmUpdate(CWorldEffectsSystem *system, int which);
virtual void ParmUpdate(CWorldEffect *effect, int which);
virtual void SetVariable(int which, bool newValue, bool doSlave = false);
virtual void SetVariable(int which, float newValue, bool doSlave = false);
virtual void SetVariable(int which, int newValue, bool doSlave = false);
virtual void SetVariable(int which, vec3_t newValue, bool doSlave = false);
virtual int GetIntVariable(int which) { return 0; }
virtual SParticle *GetParticleVariable(int which) { return 0; }
virtual void Update(CWorldEffectsSystem *system, float elapseTime);
virtual void Render(CWorldEffectsSystem *system);
};
class CWorldEffectsSystem
{
protected:
CWorldEffect *mList, *mLast;
public:
CWorldEffectsSystem(void);
virtual ~CWorldEffectsSystem(void);
void AddWorldEffect(CWorldEffect *effect);
virtual int GetIntVariable(int which) { return 0; }
virtual SParticle *GetParticleVariable(int which) { return 0; }
virtual float GetFloatVariable(int which) { return 0.0; }
virtual float *GetVecVariable(int which) { return 0; }
virtual bool Command(const char *command);
virtual void Update(float elapseTime);
virtual void ParmUpdate(int which);
virtual void Render(void);
};
void R_InitWorldEffects(void);
void R_ShutdownWorldEffects(void);
void RB_RenderWorldEffects(void);
void R_WorldEffectCommand(const char *command);
void R_WorldEffect_f(void);
bool R_GetWindVector(vec3_t windVector);
bool R_GetWindSpeed(float &windSpeed);
bool R_IsRaining();
//bool R_IsSnowing();
bool R_IsPuffing();
void R_AddWeatherZone(vec3_t mins, vec3_t maxs);
#endif // __TR_WORLDEFFECTS_H