763 lines
17 KiB
C++
763 lines
17 KiB
C++
|
|
#include "std.h"
|
|
#include "q3bsprep.h"
|
|
|
|
/* Quake3 File format types */
|
|
|
|
#pragma pack(push,1)
|
|
|
|
struct q3_plane{
|
|
Vector normal;
|
|
float distance;
|
|
};
|
|
|
|
struct q3_tex{
|
|
char name[64];
|
|
int flags,contents;
|
|
};
|
|
|
|
struct q3_vertex{
|
|
Vector coords;
|
|
float tex_coords[4];
|
|
Vector normal;
|
|
unsigned char color[4];
|
|
};
|
|
|
|
struct q3_node{
|
|
int plane;
|
|
int children[2];
|
|
int mins[3];
|
|
int maxs[3];
|
|
};
|
|
|
|
struct q3_face{
|
|
int texture;
|
|
int effect;
|
|
int type;
|
|
int vertex;
|
|
int n_verts;
|
|
int meshvert;
|
|
int n_meshverts;
|
|
int lm_index;
|
|
int lm_start[2];
|
|
int lm_size[2];
|
|
float lm_origin[3];
|
|
float lm_vecs[2][3];
|
|
float normal[3];
|
|
int patch_size[2];
|
|
};
|
|
|
|
struct q3_leaf{
|
|
int cluster;
|
|
int area;
|
|
int mins[3];
|
|
int maxs[3];
|
|
int leafface;
|
|
int n_leaffaces;
|
|
int leafbrush;
|
|
int n_leafbrushes;
|
|
};
|
|
|
|
struct q3_brush{
|
|
int brushside;
|
|
int n_brushsides;
|
|
int texture;
|
|
};
|
|
|
|
struct q3_brushside{
|
|
int plane;
|
|
int texture;
|
|
};
|
|
|
|
struct q3_direntry{
|
|
union{
|
|
int offset;
|
|
void *lump;
|
|
};
|
|
int length;
|
|
};
|
|
|
|
struct q3_header{
|
|
unsigned magic;
|
|
int version;
|
|
q3_direntry dir[17];
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
/* Loading reps */
|
|
struct Surf{
|
|
Q3BSPSurf *surf;
|
|
int texture,lm_index;
|
|
vector<int> verts,tris;
|
|
};
|
|
|
|
struct FaceCmp{
|
|
bool operator()( const q3_face *a,const q3_face *b )const{
|
|
if( a->texture<b->texture ) return true;
|
|
if( b->texture<a->texture ) return false;
|
|
if( a->lm_index<b->lm_index ) return true;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
typedef map<q3_face*,Surf*,FaceCmp> FaceMap;
|
|
|
|
/* render reps */
|
|
|
|
struct Q3BSPFace;
|
|
|
|
struct Q3BSPSurf{
|
|
Brush brush;
|
|
gxMesh *mesh;
|
|
vector<Q3BSPFace*> r_faces;
|
|
int texture,lm_index;
|
|
};
|
|
|
|
struct Q3BSPFace{
|
|
union{
|
|
Surf *t_surf;
|
|
Q3BSPSurf *surf;
|
|
};
|
|
int vert,n_verts,tri,n_tris;
|
|
};
|
|
|
|
struct Q3BSPBrush{
|
|
vector<Plane> planes;
|
|
};
|
|
|
|
struct Q3BSPLeaf{
|
|
int cluster;
|
|
Box box;
|
|
vector<Q3BSPFace*> faces;
|
|
};
|
|
|
|
struct Q3BSPNode{
|
|
Box box;
|
|
Plane plane;
|
|
Q3BSPNode *nodes[2];
|
|
Q3BSPLeaf *leafs[2];
|
|
|
|
~Q3BSPNode(){ delete nodes[0];delete nodes[1];delete leafs[0];delete leafs[1]; }
|
|
};
|
|
|
|
static q3_header header;
|
|
static FaceMap face_map;
|
|
static vector<Surf*> t_surfs;
|
|
static vector<q3_vertex> p_verts; //patch vertices
|
|
static vector<Vector> p_coll_verts;
|
|
static vector<MeshCollider::Triangle> coll_tris;
|
|
|
|
static float gamma_adj;
|
|
|
|
static Vector r_eye;
|
|
static int r_cluster;
|
|
static Frustum r_frustum;
|
|
static Vector r_frustedges[12];
|
|
static map<int,Q3BSPFace*> q3face_map;
|
|
|
|
extern gxScene *gx_scene;
|
|
extern gxRuntime *gx_runtime;
|
|
extern gxGraphics *gx_graphics;
|
|
|
|
//#define SWAPTRIS
|
|
Vector static tf( const Vector &v ){
|
|
return Vector( -v.y,v.z,v.x );
|
|
}
|
|
|
|
#ifdef BETA
|
|
static log( const string &t ){
|
|
gx_runtime->debugLog( t.c_str() );
|
|
}
|
|
#else
|
|
static log( const string &t ){}
|
|
#endif
|
|
|
|
static Surf *findSurf( q3_face *f ){
|
|
FaceMap::const_iterator it=face_map.find( f );
|
|
if( it!=face_map.end() ) return it->second;
|
|
Surf *s=d_new Surf;
|
|
s->texture=f->texture;
|
|
s->lm_index=f->lm_index;
|
|
face_map.insert( make_pair( f,s ) );
|
|
t_surfs.push_back( s );
|
|
return s;
|
|
}
|
|
|
|
void Q3BSPRep::createTextures(){
|
|
int n_texs=header.dir[1].length/sizeof(q3_tex);
|
|
q3_tex *q3tex=(q3_tex*)header.dir[1].lump;
|
|
for( int k=0;k<n_texs;++k ){
|
|
string t=string(q3tex->name);
|
|
char fl[32],co[32];
|
|
itoa( q3tex->flags,fl,16 );
|
|
itoa( q3tex->contents,co,16 );
|
|
log( t+", flags=0x"+fl+", contents=0x"+co );
|
|
Texture tex( t+".tga",1 );
|
|
if( !tex.getCanvas(0) ){
|
|
tex=Texture( t+".jpg",1 );
|
|
if( !tex.getCanvas(0) ){
|
|
tex=Texture( t+".png",1 );
|
|
if( !tex.getCanvas(0) ){
|
|
tex=Texture( t+".dds",1 );
|
|
if( !tex.getCanvas(0) ) log( "Failed!" );
|
|
}
|
|
}
|
|
}
|
|
tex.setFlags( 1 );
|
|
textures.push_back( tex );
|
|
++q3tex;
|
|
}
|
|
}
|
|
|
|
void Q3BSPRep::createLightMaps(){
|
|
int n_lmaps=header.dir[14].length/(128*128*3);
|
|
unsigned char *rgb=(unsigned char*)header.dir[14].lump;
|
|
unsigned char adj[256];
|
|
int k;
|
|
for( k=0;k<256;++k ) adj[k]=pow( k/255.0f,gamma_adj )*255.0f;
|
|
|
|
for( k=0;k<n_lmaps;++k ){
|
|
Texture tex( 128,128,1+8+16+32,1 );
|
|
tex.setBlend( gxScene::BLEND_ADD );
|
|
gxCanvas *c=tex.getCanvas(0);
|
|
c->lock();
|
|
for( int y=0;y<128;++y ){
|
|
for( int x=0;x<128;++x ){
|
|
unsigned argb=0xff000000|(adj[rgb[0]]<<16)|(adj[rgb[1]]<<8)|adj[rgb[2]];
|
|
c->setPixelFast( x,y,argb );
|
|
rgb+=3;
|
|
}
|
|
}
|
|
c->unlock();
|
|
light_maps.push_back( tex );
|
|
}
|
|
}
|
|
|
|
void Q3BSPRep::createVis(){
|
|
int *vis=(int*)header.dir[16].lump;
|
|
int n_vecs=*vis++;
|
|
vis_sz=*vis++;
|
|
log( "vis: "+itoa(n_vecs)+","+itoa(vis_sz) );
|
|
vis_data=new char[n_vecs*vis_sz];
|
|
memcpy( vis_data,vis,n_vecs*vis_sz );
|
|
}
|
|
|
|
void Q3BSPRep::createCollider(){
|
|
vector<MeshCollider::Vertex> coll_verts;
|
|
int n_verts=header.dir[10].length/sizeof(q3_vertex);
|
|
q3_vertex *t=(q3_vertex*)header.dir[10].lump;
|
|
MeshCollider::Vertex cv;
|
|
int k;
|
|
for( k=0;k<n_verts;++k ){
|
|
cv.coords=tf( t->coords );
|
|
coll_verts.push_back( cv );
|
|
++t;
|
|
}
|
|
for( k=0;k<p_coll_verts.size();++k ){
|
|
cv.coords=p_coll_verts[k];
|
|
coll_verts.push_back( cv );
|
|
}
|
|
#ifdef SWAPTRIS
|
|
for( k=0;k<coll_tris.size();++k ){
|
|
std::swap( coll_tris[k].verts[1],coll_tris[k].verts[2] );
|
|
}
|
|
#endif
|
|
collider=d_new MeshCollider( coll_verts,coll_tris );
|
|
p_coll_verts.clear();
|
|
coll_verts.clear();
|
|
coll_tris.clear();
|
|
}
|
|
|
|
void Q3BSPRep::createSurfs(){
|
|
int k;
|
|
for( k=0;k<t_surfs.size();++k ){
|
|
Surf *s=t_surfs[k];
|
|
gxMesh *mesh=gx_graphics->createMesh( s->verts.size(),s->tris.size()/3,0 );
|
|
|
|
mesh->lock( true );
|
|
int j;
|
|
for( j=0;j<s->verts.size();++j ){
|
|
q3_vertex *t;
|
|
int n=s->verts[j];
|
|
if( n>=0 ){
|
|
t=(q3_vertex*)header.dir[10].lump+n;
|
|
}else{
|
|
t=&p_verts[-n-1];
|
|
}
|
|
float tex_coords[2][2]={ {t->tex_coords[2],t->tex_coords[3]},{t->tex_coords[0],t->tex_coords[1]}};
|
|
unsigned argb=0xff000000|(t->color[0]<<16)|(t->color[1]<<8)|t->color[2];
|
|
mesh->setVertex( j,tf(t->coords),tf(t->normal),argb,tex_coords );
|
|
}
|
|
for( j=0;j<s->tris.size();j+=3 ){
|
|
#ifdef SWAPTRIS
|
|
mesh->setTriangle( j/3,s->tris[j],s->tris[j+2],s->tris[j+1] );
|
|
#else
|
|
mesh->setTriangle( j/3,s->tris[j],s->tris[j+1],s->tris[j+2] );
|
|
#endif
|
|
}
|
|
mesh->unlock();
|
|
|
|
Q3BSPSurf *surf=d_new Q3BSPSurf;
|
|
surf->texture=s->texture;
|
|
surf->lm_index=s->lm_index;
|
|
surf->mesh=mesh;
|
|
surfs.push_back( surf );
|
|
s->surf=surf;
|
|
}
|
|
for( k=0;k<faces.size();++k ){
|
|
Q3BSPFace *f=faces[k];
|
|
f->surf=f->t_surf->surf;
|
|
f->tri/=3;f->n_tris/=3;
|
|
}
|
|
for( k=0;k<t_surfs.size();++k ){
|
|
delete t_surfs[k];
|
|
}
|
|
face_map.clear();
|
|
t_surfs.clear();
|
|
p_verts.clear();
|
|
}
|
|
|
|
static void average( const q3_vertex &a,const q3_vertex &b,q3_vertex *c ){
|
|
c->coords=(a.coords+b.coords)*.5f;
|
|
c->normal=(a.normal+b.normal)*.5f;
|
|
for( int k=0;k<4;++k ){
|
|
c->color[k]=(a.color[k]+b.color[k]+1)/2;
|
|
c->tex_coords[k]=(a.tex_coords[k]+b.tex_coords[k])*.5f;
|
|
}
|
|
}
|
|
|
|
static void subdivide( vector<q3_vertex> &verts,int level,int index,int step ){
|
|
if( !level ){
|
|
q3_vertex t1,t2;
|
|
average( verts[index],verts[index+step],&t1 );
|
|
average( verts[index+step],verts[index+step*2],&t2 );
|
|
average( t1,t2,&verts[index+step] );
|
|
return;
|
|
}
|
|
average( verts[index],verts[index+step],&verts[index+step/2] );
|
|
average( verts[index+step],verts[index+step*2],&verts[index+step+step/2] );
|
|
average( verts[index+step/2],verts[index+step+step/2],&verts[index+step] );
|
|
subdivide( verts,level-1,index,step/2 );
|
|
subdivide( verts,level-1,index+step,step/2 );
|
|
}
|
|
|
|
static void patchFace( Q3BSPFace *face,q3_face *q3face,bool draw,bool solid,int level ){
|
|
|
|
int k,x,y;
|
|
vector<q3_vertex> verts;
|
|
|
|
if( draw ){
|
|
int step=1<<level;
|
|
int size_x=(q3face->patch_size[0]-1)*step+1;
|
|
int size_y=(q3face->patch_size[1]-1)*step+1;
|
|
verts.resize( size_x*size_y );
|
|
|
|
//seed initial verts
|
|
q3_vertex *t=(q3_vertex*)header.dir[10].lump+q3face->vertex;
|
|
for( y=0;y<size_y;y+=step ){
|
|
for( x=0;x<size_x;x+=step ){
|
|
verts[y*size_x+x]=*t++;
|
|
}
|
|
}
|
|
//subdivide!
|
|
for( y=0;y<size_y;y+=step ){
|
|
for( x=0;x<size_x-1;x+=step*2 ){
|
|
subdivide( verts,level,y*size_x+x,step );
|
|
}
|
|
}
|
|
for( x=0;x<size_x;++x ){
|
|
for( y=0;y<size_y-1;y+=step*2 ){
|
|
subdivide( verts,level,y*size_x+x,size_x*step );
|
|
}
|
|
}
|
|
|
|
Surf *surf=face->t_surf;
|
|
int vert=surf->verts.size()-face->vert;
|
|
|
|
//generate patch verts
|
|
for( k=0;k<size_x*size_y;++k ){
|
|
p_verts.push_back( verts[k] );
|
|
surf->verts.push_back( -p_verts.size() );
|
|
}
|
|
face->n_verts+=size_x*size_y;
|
|
|
|
//generate tris...
|
|
for( y=0;y<size_y-1;++y ){
|
|
int n=y*size_x+vert;
|
|
for( x=0;x<size_x-1;++n,++x ){
|
|
surf->tris.push_back( n );
|
|
surf->tris.push_back( n+size_x );
|
|
surf->tris.push_back( n+1 );
|
|
surf->tris.push_back( n+size_x+1 );
|
|
surf->tris.push_back( n+1 );
|
|
surf->tris.push_back( n+size_x );
|
|
}
|
|
}
|
|
face->n_tris+=(size_x-1)*(size_y-1)*6;
|
|
}
|
|
|
|
if( solid ){
|
|
vector<q3_vertex> verts;
|
|
int step=1;
|
|
int size_x=q3face->patch_size[0];
|
|
int size_y=q3face->patch_size[1];
|
|
verts.resize( size_x*size_y );
|
|
|
|
//seed initial verts
|
|
q3_vertex *t=(q3_vertex*)header.dir[10].lump+q3face->vertex;
|
|
for( k=0;k<size_x*size_y;++k ) verts[k]=*t++;
|
|
//subdivide!
|
|
for( y=0;y<size_y;y+=step ){
|
|
for( x=0;x<size_x-1;x+=step*2 ){
|
|
subdivide( verts,0,y*size_x+x,step );
|
|
}
|
|
}
|
|
for( x=0;x<size_x;++x ){
|
|
for( y=0;y<size_y-1;y+=step*2 ){
|
|
subdivide( verts,0,y*size_x+x,size_x*step );
|
|
}
|
|
}
|
|
|
|
int vert=header.dir[10].length/sizeof(q3_vertex)+p_coll_verts.size();
|
|
|
|
//generate patch verts
|
|
for( k=0;k<size_x*size_y;++k ) p_coll_verts.push_back( tf(verts[k].coords) );
|
|
|
|
MeshCollider::Triangle ct;
|
|
ct.surface=0;ct.index=0;
|
|
//generate tris...
|
|
for( y=0;y<size_y-1;++y ){
|
|
int n=y*size_x+vert;
|
|
for( x=0;x<size_x-1;++n,++x ){
|
|
ct.verts[0]=n;
|
|
ct.verts[1]=n+size_x;
|
|
ct.verts[2]=n+1;
|
|
coll_tris.push_back( ct );
|
|
ct.verts[0]=n+size_x+1;
|
|
ct.verts[1]=n+1;
|
|
ct.verts[2]=n+size_x;
|
|
coll_tris.push_back( ct );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void meshFace( Q3BSPFace *face,q3_face *q3face,bool draw,bool solid ){
|
|
static map<int,int> vert_map;
|
|
vert_map.clear();
|
|
int *meshverts=(int*)header.dir[11].lump+q3face->meshvert;
|
|
MeshCollider::Triangle ct;
|
|
ct.surface=0;ct.index=0;
|
|
for( int j=0;j<q3face->n_meshverts;j+=3 ){
|
|
for( int q=0;q<3;++q ){
|
|
int n=meshverts[j+q]+q3face->vertex;
|
|
if( draw ){
|
|
if( !vert_map.count( n ) ){
|
|
vert_map[n]=face->t_surf->verts.size()-face->vert;
|
|
face->t_surf->verts.push_back(n);
|
|
++face->n_verts;
|
|
}
|
|
face->t_surf->tris.push_back( vert_map[n] );
|
|
++face->n_tris;
|
|
}
|
|
ct.verts[q]=n;
|
|
}
|
|
if( solid ) coll_tris.push_back( ct );
|
|
}
|
|
}
|
|
|
|
static Q3BSPBrush *createBrush( int n ){
|
|
Q3BSPBrush *brush=d_new Q3BSPBrush;
|
|
q3_brush *q3brush=(q3_brush*)header.dir[8].lump+n;
|
|
q3_brushside *q3brushside=(q3_brushside*)header.dir[9].lump+q3brush->brushside;
|
|
Plane p;
|
|
for( int j=0;j<q3brush->n_brushsides;++j ){
|
|
q3_plane *q3plane=(q3_plane*)header.dir[2].lump+q3brushside[j].plane;
|
|
p.n=tf( q3plane->normal );
|
|
p.d=-q3plane->distance;
|
|
brush->planes.push_back( p );
|
|
}
|
|
return brush;
|
|
}
|
|
|
|
Q3BSPLeaf *Q3BSPRep::createLeaf( int n ){
|
|
q3_leaf *q3leaf=(q3_leaf*)header.dir[4].lump+n;
|
|
|
|
Q3BSPLeaf *leaf=d_new Q3BSPLeaf;
|
|
|
|
leaf->cluster=q3leaf->cluster;
|
|
|
|
Vector mins( q3leaf->mins[0],q3leaf->mins[1],q3leaf->mins[2] );
|
|
Vector maxs( q3leaf->maxs[0],q3leaf->maxs[1],q3leaf->maxs[2] );
|
|
leaf->box=Box( tf(mins) );
|
|
leaf->box.update( tf(maxs) );
|
|
int *leaffaces=(int*)header.dir[5].lump+q3leaf->leafface;
|
|
|
|
for( int k=0;k<q3leaf->n_leaffaces;++k ){
|
|
|
|
int face_n=leaffaces[k];
|
|
|
|
map<int,Q3BSPFace*>::const_iterator it=q3face_map.find(face_n);
|
|
if( it!=q3face_map.end() ){
|
|
if( it->second ) leaf->faces.push_back( it->second );
|
|
continue;
|
|
}
|
|
|
|
q3_face *q3face=(q3_face*)header.dir[13].lump+leaffaces[k];
|
|
|
|
if( q3face->type==1 || q3face->type==3 ){
|
|
if( !q3face->n_meshverts || (q3face->n_meshverts%3) ) continue;
|
|
}else if( q3face->type!=2 ) continue;
|
|
|
|
bool draw=true,solid=true;
|
|
|
|
if( q3face->texture>=0 ){
|
|
q3_tex *q3tex=(q3_tex*)header.dir[1].lump+q3face->texture;
|
|
if( !(q3tex->contents & 1) ) continue;
|
|
if( q3tex->flags & 0x84 ) draw=false;
|
|
}
|
|
|
|
if( !draw && !solid ) continue;
|
|
|
|
Q3BSPFace *face=0;
|
|
if( draw ){
|
|
Surf *surf=findSurf( q3face );
|
|
face=d_new Q3BSPFace;
|
|
face->t_surf=surf;
|
|
face->vert=surf->verts.size();
|
|
face->tri=surf->tris.size();
|
|
face->n_verts=face->n_tris=0;
|
|
leaf->faces.push_back( face );
|
|
faces.push_back( face );
|
|
q3face_map.insert( make_pair( face_n,face ) );
|
|
}
|
|
|
|
if( q3face->type==2 ){
|
|
patchFace( face,q3face,draw,solid,1 );
|
|
}else{
|
|
meshFace( face,q3face,draw,solid );
|
|
}
|
|
}
|
|
|
|
return leaf;
|
|
}
|
|
|
|
Q3BSPNode *Q3BSPRep::createNode( int n ){
|
|
q3_node *q3node=(q3_node*)header.dir[3].lump+n;
|
|
q3_plane *q3plane=(q3_plane*)header.dir[2].lump+q3node->plane;
|
|
|
|
Q3BSPNode *node=new Q3BSPNode;
|
|
|
|
Vector mins( q3node->mins[0],q3node->mins[1],q3node->mins[2] );
|
|
Vector maxs( q3node->maxs[0],q3node->maxs[1],q3node->maxs[2] );
|
|
|
|
node->box=Box( tf(mins) );
|
|
node->box.update( tf(maxs) );
|
|
node->plane.n=tf(q3plane->normal);
|
|
node->plane.d=-q3plane->distance;
|
|
|
|
for( int k=0;k<2;++k ){
|
|
if( q3node->children[k]>=0 ){
|
|
node->nodes[k]=createNode( q3node->children[k] );
|
|
node->leafs[k]=0;
|
|
}else{
|
|
node->leafs[k]=createLeaf( -q3node->children[k]-1 );
|
|
node->nodes[k]=0;
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
Q3BSPRep::Q3BSPRep( const string &f,float gam ):root_node(0),vis_sz(0),vis_data(0),use_lmap(true){
|
|
|
|
gamma_adj=1-gam;
|
|
|
|
FILE *buf=fopen( f.c_str(),"rb" );if( !buf ) return;
|
|
|
|
fread( &header,sizeof(header),1,buf );
|
|
if( header.magic!='PSBI' || header.version!=0x2e ){
|
|
fclose( buf );return;
|
|
}
|
|
|
|
log( "Header OK" );
|
|
|
|
int k;
|
|
//load all lumps...
|
|
for( k=0;k<17;++k ){
|
|
if( header.dir[k].offset && header.dir[k].length ){
|
|
fseek( buf,header.dir[k].offset,SEEK_SET );
|
|
header.dir[k].lump=d_new char[header.dir[k].length];
|
|
fread( header.dir[k].lump,header.dir[k].length,1,buf );
|
|
}else{
|
|
header.dir[k].lump=0;
|
|
}
|
|
}
|
|
|
|
//create root of BSP tree
|
|
root_node=createNode( 0 );
|
|
|
|
createCollider();
|
|
|
|
createTextures();
|
|
|
|
createLightMaps();
|
|
|
|
createSurfs();
|
|
|
|
createVis();
|
|
|
|
//unload all lumps...
|
|
for( k=0;k<17;++k ){
|
|
delete[] header.dir[k].lump;
|
|
}
|
|
|
|
fclose( buf );
|
|
|
|
use_lmap=false;
|
|
setLighting( true );
|
|
|
|
q3face_map.clear();
|
|
}
|
|
|
|
Q3BSPRep::~Q3BSPRep(){
|
|
delete root_node;
|
|
delete[] vis_data;
|
|
int k;
|
|
for( k=0;k<surfs.size();++k ){
|
|
gx_graphics->freeMesh( surfs[k]->mesh );
|
|
delete surfs[k];
|
|
}
|
|
for( k=0;k<faces.size();++k ){
|
|
delete faces[k];
|
|
}
|
|
}
|
|
|
|
void Q3BSPRep::vis( Q3BSPNode *n ){
|
|
int i=n->plane.distance( r_eye )<0;
|
|
if( n->nodes[i] ) vis( n->nodes[i] );
|
|
else r_cluster=n->leafs[i]->cluster;
|
|
}
|
|
|
|
static bool cull( const Box &b,int *clip ){
|
|
for( int n=0;n<6;++n ){
|
|
int mask=1<<n;
|
|
if( !(*clip & mask) ) continue;
|
|
const Plane &p=r_frustum.getPlane( n );
|
|
int q=
|
|
(p.distance(b.corner(0))>=0)+(p.distance(b.corner(1))>=0)+
|
|
(p.distance(b.corner(2))>=0)+(p.distance(b.corner(3))>=0)+
|
|
(p.distance(b.corner(4))>=0)+(p.distance(b.corner(5))>=0)+
|
|
(p.distance(b.corner(6))>=0)+(p.distance(b.corner(7))>=0);
|
|
if( !q ) return false;
|
|
if( q==8 ) *clip&=~mask;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Q3BSPRep::render( Q3BSPLeaf *l,int clip ){
|
|
int cluster=l->cluster;
|
|
if( cluster<0 ) return;
|
|
|
|
if( r_cluster>=0 ){
|
|
if( !( vis_data[cluster*vis_sz+r_cluster/8] & (1<<(r_cluster&7))) ) return;
|
|
}
|
|
|
|
if( clip && !cull( l->box,&clip ) ) return;
|
|
|
|
for( int k=0;k<l->faces.size();++k ){
|
|
Q3BSPFace *f=l->faces[k];
|
|
if( Q3BSPSurf *s=f->surf ){
|
|
if( !s->r_faces.size() ) r_surfs.push_back( s );
|
|
s->r_faces.push_back( f );
|
|
f->surf=0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Q3BSPRep::render( Q3BSPNode *n,int clip ){
|
|
if( clip && !cull( n->box,&clip ) ) return;
|
|
|
|
//draw front to back...
|
|
int i=n->plane.distance( r_eye )<0;
|
|
if( n->nodes[i] ) render( n->nodes[i],clip );
|
|
else render( n->leafs[i],clip );
|
|
i^=1;
|
|
if( n->nodes[i] ) render( n->nodes[i],clip );
|
|
else render( n->leafs[i],clip );
|
|
}
|
|
|
|
void Q3BSPRep::render( Model *model,const RenderContext &rc ){
|
|
r_eye=-model->getRenderTform() * rc.getCameraTform().v;
|
|
new( &r_frustum ) Frustum( rc.getWorldFrustum(),-model->getRenderTform() );
|
|
|
|
vis( root_node );
|
|
if( r_cluster==-1 ) log( "No cluster!" );
|
|
render( root_node,0x3f );
|
|
|
|
if( !r_surfs.size() ) return;
|
|
|
|
gx_scene->setAmbient2( &ambient.x );
|
|
gx_scene->setWorldMatrix( (gxScene::Matrix*)&model->getRenderTform() );
|
|
|
|
int k;
|
|
for( k=0;k<r_surfs.size();++k ){
|
|
Q3BSPSurf *s=r_surfs[k];
|
|
gx_scene->setRenderState( s->brush.getRenderState() );
|
|
int j;
|
|
for( j=0;j<s->r_faces.size();++j ){
|
|
Q3BSPFace *f=s->r_faces[j];
|
|
gx_scene->render( s->mesh,f->vert,f->n_verts,f->tri,f->n_tris );
|
|
f->surf=s;
|
|
}
|
|
s->r_faces.clear();
|
|
}
|
|
r_surfs.clear();
|
|
}
|
|
|
|
bool Q3BSPRep::collide( const Line &line,float radius,Collision *curr_coll,const Transform &t ){
|
|
return collider->collide( line,radius,curr_coll,t );
|
|
}
|
|
|
|
void Q3BSPRep::setAmbient( const Vector &t ){
|
|
ambient=t;
|
|
}
|
|
|
|
void Q3BSPRep::setLighting( bool lmap ){
|
|
if( lmap==use_lmap ) return;
|
|
int fx=gxScene::FX_CONDLIGHT;
|
|
if( use_lmap=lmap ){
|
|
int k;
|
|
for( k=0;k<surfs.size();++k ){
|
|
Q3BSPSurf *s=surfs[k];
|
|
if( s->lm_index>=0 ){
|
|
//has a lightmap...
|
|
s->brush.setFX( fx );
|
|
s->brush.setTexture( 0,light_maps[s->lm_index],0 );
|
|
if( s->texture>=0 ){
|
|
s->brush.setTexture( 1,textures[s->texture],0 );
|
|
}
|
|
}else{
|
|
s->brush.setFX( fx|gxScene::FX_EMISSIVE );
|
|
if( s->texture>=0 ){
|
|
s->brush.setTexture( 0,textures[s->texture],0 );
|
|
}
|
|
}
|
|
}
|
|
}else{
|
|
int k;
|
|
Texture tex;
|
|
for( k=0;k<surfs.size();++k ){
|
|
Q3BSPSurf *s=surfs[k];
|
|
s->brush.setFX( fx|gxScene::FX_EMISSIVE );
|
|
if( s->texture>=0 ){
|
|
s->brush.setTexture( 0,textures[s->texture],0 );
|
|
}else{
|
|
s->brush.setTexture( 0,tex,0 );
|
|
}
|
|
s->brush.setTexture( 1,tex,0 );
|
|
}
|
|
}
|
|
}
|