Initial commit.
This commit is contained in:
3037
codemp/renderer/glext.h
Normal file
3037
codemp/renderer/glext.h
Normal file
File diff suppressed because it is too large
Load Diff
2521
codemp/renderer/glext_console.h
Normal file
2521
codemp/renderer/glext_console.h
Normal file
File diff suppressed because it is too large
Load Diff
293
codemp/renderer/matcomp.c
Normal file
293
codemp/renderer/matcomp.c
Normal 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
31
codemp/renderer/matcomp.h
Normal 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
|
||||
434
codemp/renderer/mdx_format.h
Normal file
434
codemp/renderer/mdx_format.h
Normal 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
310
codemp/renderer/modelmem.h
Normal 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
757
codemp/renderer/qgl.h
Normal 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
|
||||
1205
codemp/renderer/qgl_console.h
Normal file
1205
codemp/renderer/qgl_console.h
Normal file
File diff suppressed because it is too large
Load Diff
16
codemp/renderer/tr_animation.cpp
Normal file
16
codemp/renderer/tr_animation.cpp
Normal 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.
|
||||
|
||||
*/
|
||||
|
||||
117
codemp/renderer/tr_arioche.cpp
Normal file
117
codemp/renderer/tr_arioche.cpp
Normal 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
|
||||
2211
codemp/renderer/tr_backend.cpp
Normal file
2211
codemp/renderer/tr_backend.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2123
codemp/renderer/tr_bsp.cpp
Normal file
2123
codemp/renderer/tr_bsp.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1820
codemp/renderer/tr_bsp_xbox.cpp
Normal file
1820
codemp/renderer/tr_bsp_xbox.cpp
Normal file
File diff suppressed because it is too large
Load Diff
484
codemp/renderer/tr_cmds.cpp
Normal file
484
codemp/renderer/tr_cmds.cpp
Normal 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;
|
||||
}
|
||||
|
||||
612
codemp/renderer/tr_curve.cpp
Normal file
612
codemp/renderer/tr_curve.cpp
Normal 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;
|
||||
}
|
||||
536
codemp/renderer/tr_curve_xbox.cpp
Normal file
536
codemp/renderer/tr_curve_xbox.cpp
Normal 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;
|
||||
}
|
||||
433
codemp/renderer/tr_flares.cpp
Normal file
433
codemp/renderer/tr_flares.cpp
Normal 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
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
34
codemp/renderer/tr_font.h
Normal 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
|
||||
|
||||
5441
codemp/renderer/tr_ghoul2.cpp
Normal file
5441
codemp/renderer/tr_ghoul2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3365
codemp/renderer/tr_image.cpp
Normal file
3365
codemp/renderer/tr_image.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2644
codemp/renderer/tr_image_xbox.cpp
Normal file
2644
codemp/renderer/tr_image_xbox.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1554
codemp/renderer/tr_init.cpp
Normal file
1554
codemp/renderer/tr_init.cpp
Normal file
File diff suppressed because it is too large
Load Diff
191
codemp/renderer/tr_landscape.h
Normal file
191
codemp/renderer/tr_landscape.h
Normal 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
|
||||
475
codemp/renderer/tr_light.cpp
Normal file
475
codemp/renderer/tr_light.cpp
Normal 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;
|
||||
}
|
||||
882
codemp/renderer/tr_lightmanager.cpp
Normal file
882
codemp/renderer/tr_lightmanager.cpp
Normal 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
|
||||
34
codemp/renderer/tr_lightmanager.h
Normal file
34
codemp/renderer/tr_lightmanager.h
Normal 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
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
1646
codemp/renderer/tr_main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
449
codemp/renderer/tr_marks.cpp
Normal file
449
codemp/renderer/tr_marks.cpp
Normal 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
409
codemp/renderer/tr_mesh.cpp
Normal 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
2042
codemp/renderer/tr_model.cpp
Normal file
File diff suppressed because it is too large
Load Diff
84
codemp/renderer/tr_noise.cpp
Normal file
84
codemp/renderer/tr_noise.cpp
Normal 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
116
codemp/renderer/tr_public.h
Normal 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
|
||||
222
codemp/renderer/tr_quicksprite.cpp
Normal file
222
codemp/renderer/tr_quicksprite.cpp
Normal 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;
|
||||
}
|
||||
47
codemp/renderer/tr_quicksprite.h
Normal file
47
codemp/renderer/tr_quicksprite.h
Normal 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_)
|
||||
|
||||
|
||||
883
codemp/renderer/tr_scene.cpp
Normal file
883
codemp/renderer/tr_scene.cpp
Normal 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
2482
codemp/renderer/tr_shade.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1801
codemp/renderer/tr_shade_calc.cpp
Normal file
1801
codemp/renderer/tr_shade_calc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4351
codemp/renderer/tr_shader.cpp
Normal file
4351
codemp/renderer/tr_shader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
724
codemp/renderer/tr_shadows.cpp
Normal file
724
codemp/renderer/tr_shadows.cpp
Normal 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
849
codemp/renderer/tr_sky.cpp
Normal 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;
|
||||
}
|
||||
|
||||
2100
codemp/renderer/tr_surface.cpp
Normal file
2100
codemp/renderer/tr_surface.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1463
codemp/renderer/tr_surfacesprites.cpp
Normal file
1463
codemp/renderer/tr_surfacesprites.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1056
codemp/renderer/tr_terrain.cpp
Normal file
1056
codemp/renderer/tr_terrain.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1939
codemp/renderer/tr_world.cpp
Normal file
1939
codemp/renderer/tr_world.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2025
codemp/renderer/tr_worldeffects.cpp
Normal file
2025
codemp/renderer/tr_worldeffects.cpp
Normal file
File diff suppressed because it is too large
Load Diff
108
codemp/renderer/tr_worldeffects.h
Normal file
108
codemp/renderer/tr_worldeffects.h
Normal 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
|
||||
Reference in New Issue
Block a user