home *** CD-ROM | disk | FTP | other *** search
- /*!
- \file SpacePartitioningTree.cpp
- \author Karsten Schwenk
-
- See header for description (sptree.h).
- */
-
- #include "SpacePartitioningTree.h"
- #include "intersection.h"
- #include "matrixmath.h"
- #include "log.h"
- #include "Renderer.h"
- #include "RendererInfo.h"
- #include "Game.h"
-
- #include "Q3bspLoader.h"
-
- SpacePartitioningTree::SpacePartitioningTree(Model* model){
- this->model=model;
- vectorCopy3d(model->min, this->min);
- vectorCopy3d(model->max, this->max);
- /*
- #define EPS 0.01f
- vectorInit3d(model->min[0]-EPS, model->min[1]-EPS, model->min[2]-EPS, min);
- vectorInit3d(model->max[0]+EPS, model->max[1]+EPS, model->max[2]+EPS, max);
- #undef EPS
- */
-
- numNodes=0;
- numLevels=0;
- numFaces=0;
-
- facesDrawn=NULL;
- pvs=NULL;
- q3bspExtension=NULL;
-
- root=NULL;
-
- }
-
- SpacePartitioningTree::~SpacePartitioningTree(){
- if(facesDrawn!=NULL)
- delete facesDrawn;
-
- if(root!=NULL)
- delete root; // this destroys recursively all nodes
-
- delete[] nodes; // this is empty now
-
- if(pvs!=NULL)
- delete pvs;
-
- if(q3bspExtension!=NULL)
- delete q3bspExtension;
- }
-
- SpacePartitioningTreeNode* SpacePartitioningTree::getLeafNodeContainingPoint(vec3_t point){
- int i;
- SpacePartitioningTreeNode* current=root;
- SpacePartitioningTreeNode* child;
-
- // check if point is in root node
- if(!pointIntersectsAABB(point, min, max)){
- return NULL;
- }
-
- // decend into tree
- while(current!=NULL && !current->leafNode){
- for(i=0;i<current->numChilds;i++){
- child=current->childs[i];
- if(pointIntersectsAABB(point, child->min, child->max)){
- current=child;
- break;
- }
- }
- if(i==current->numChilds){ // no suitable child found -> return NULL
- return NULL;
- }
- }
-
- return current;
- }
-
- SpacePartitioningTreeNode* SpacePartitioningTree::getNodeContainingPoint(vec3_t point, int maxLevel){
- int i;
- SpacePartitioningTreeNode* current=root;
- SpacePartitioningTreeNode* child;
-
- // check if point is in root node
- if(!pointIntersectsAABB(point, min, max)){
- return NULL;
- }
-
- // decend into tree
- while(current!=NULL && !current->leafNode && current->level<maxLevel){
- for(i=0;i<current->numChilds;i++){
- child=current->childs[i];
- if(pointIntersectsAABB(point, child->min, child->max)){
- current=child;
- break;
- }
- }
- if(i==current->numChilds){ // THINKABOUTME: was tun, wenn kein nachbar AUF GLEICHEM LEVEL da ist??
- break;
- }
- }
-
- return current;
- }
-
-
- vector<SpacePartitioningTreeNode*> SpacePartitioningTree::getLeafNodesIntersectingAABB(vec3_t min, vec3_t max){
- vector<SpacePartitioningTreeNode*> ret;
-
- root->collectLeafNodesIntersectingAABB(min, max, ret);
-
- return ret;
- }
-
- void SpacePartitioningTree::traceRay(/*vec3_t startPos, vec3_t dir,*/ trace_t* trace){
- // vectorCopy3d(startPos, trace->startPos);
- // vectorCopy3d(dir, trace->dir);
- // trace->traceType=TRACE_TYPE_RAY;
-
- // trace->hits.clear();
- /*
- vector<Face*> faces;
- if( trace->ignoreFlags & COLLISION_FLAG_BACKFACES ){ // ignore backfaces
- root->collectFrontFacingFacesIntersectingRay(trace->startPos, trace->dir, faces);
- }else{
- root->collectFacesIntersectingRay(trace->startPos, trace->dir, faces);
- }
-
- // sortieren und fertisch
- // TODO: calc hits Positions and sort stuff
- for(int i=0;i<faces.size();i++){
- if( !(trace->ignoreFlags & faces[i]->material->collisionFlags) ){
- trace->hitFaces.push_back(faces[i]);
- }
- }
- */
- root->traceRay(trace);
- }
-
- void SpacePartitioningTree::traceLinesegment(/*vec3_t pos1, vec3_t pos2,*/ trace_t* trace){
- // vectorCopy3d(pos1, trace->startPos);
- // vectorCopy3d(pos2, trace->endPos);
- // vectorSub3d(pos2, pos1, trace->dir);
- // trace->traceType=TRACE_TYPE_LINE_SEGMENT;
-
- // trace->hits.clear();
-
- SpacePartitioningTreeNode* pos1Node = getLeafNodeContainingPoint(trace->startPos);
- SpacePartitioningTreeNode* pos2Node = getLeafNodeContainingPoint(trace->endPos);
- if(pos1Node!=pos2Node || pos1Node==NULL || pos2Node==NULL)
- root->traceLinesegment(trace);
- else // start and end in the same node -> test only this node
- pos1Node->traceLinesegment(trace);
-
- // if(trace->hitDistance==FLT_MAX)
- // trace->hitDistance=-1.0f;
- }
-
- void SpacePartitioningTree::traceAABB(/*vec3_t pos1, vec3_t pos2, vec3_t min, vec3_t max, */trace_t* trace){
- unsigned int i;
- bool noHitsHere = true;
-
- // vectorCopy3d(pos1, trace->startPos);
- // vectorCopy3d(pos2, trace->endPos);
- // vectorSub3d(pos2, pos1, trace->dir);
- float hitDistance = vectorLength3d(trace->dir);
- // vectorCopy3d(min, trace->min);
- // vectorCopy3d(max, trace->max);
- // trace->traceType=TRACE_TYPE_AABB;
-
- // trace->hits.clear();
-
- vec3_t minAbs, maxAbs;
- vectorAdd3d(trace->endPos, trace->min, minAbs);
- vectorAdd3d(trace->endPos, trace->max, maxAbs);
-
- if( trace->ignoreFlags & COLLISION_FLAG_SUBSEQUENT_HITS ){ // we want only ONE hit
-
- vector<SpacePartitioningTreeNode*> intersectedLeafNodes;
- root->collectLeafNodesIntersectingAABB(minAbs, maxAbs, intersectedLeafNodes);
-
- // check
- for(i=0;i<intersectedLeafNodes.size();i++){
- Face* f;
- if(trace->ignoreFlags & COLLISION_FLAG_BACKFACES){ // ignore backfaces
- f = intersectedLeafNodes[i]->getFrontFacingFaceIntersectingAABB(minAbs, maxAbs, trace->dir);
- }else{
- f = intersectedLeafNodes[i]->getFaceIntersectingAABB(minAbs, maxAbs);
- }
-
- if(f != NULL && !(trace->ignoreFlags & f->material->collisionFlags)){
- hit_t hit;
- hit.distance = hitDistance;
- vectorCopy3d(trace->endPos, hit.pos);
- hit.node = intersectedLeafNodes[i];
- hit.face = f;
- hit.vehicle = NULL;
-
- trace->hits.push_back(hit);
- noHitsHere = false;
- return;
- }
- }
-
- }else{ // collect all hits
- vector<Face*> faces;
- if(trace->ignoreFlags & COLLISION_FLAG_BACKFACES){ // ignore backfaces
- root->collectFrontFacingFacesIntersectingAABB(minAbs, maxAbs, trace->dir, faces);
- }else{
- root->collectFacesIntersectingAABB(minAbs, maxAbs, faces);
- }
-
- for(unsigned int i=0;i<faces.size();i++){
- if( !(trace->ignoreFlags & faces[i]->material->collisionFlags) ){
- hit_t hit;
- hit.distance = hitDistance;
- vectorCopy3d(trace->endPos, hit.pos);
- hit.node = root; // FIXME: WRONG!!
- hit.face = faces[i];
- hit.vehicle = NULL;
-
- trace->hits.push_back(hit);
- noHitsHere = false;
- }
- }
- }
-
- if( noHitsHere ){ // maybe we "tunneled" a wall...
- root->traceLinesegment(trace);
- }
-
- // if(trace->hitDistance == FLT_MAX)
- // trace->hitDistance=-1.0f;
- }
-
- void SpacePartitioningTree::render(){
- if(Renderer::info.var.renderSPTreeBorders)
- drawBorders();
-
- if(q3bspExtension!=NULL){
- Renderer::renderQ3bspExtension(q3bspExtension);
- return;
- }
-
- if(facesDrawn!=NULL)
- facesDrawn->clearAll();
-
- if(pvs!=NULL){
- SpacePartitioningTreeNode* camNode=getLeafNodeContainingPoint(Game::cam.pos);
- if(camNode!=NULL){
- pvs->setCurrentCluster(camNode->nodeId);
- pvs->enabled=true;
- if(Renderer::info.var.renderPVSBorders)
- pvs->drawClusterBorders();
- }else{
- pvs->enabled=false;
- }
- }
-
- root->render();
- }
-
- void SpacePartitioningTree::drawBorders(){
- Renderer::disableLighting();
- glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
- Renderer::debug_renderAABB(min, max);
- Renderer::enableLighting();
-
- root->drawBorders();
- }
-
-
- void SpacePartitioningTree::importPVS(PotentialVisibilitySet* pvs){
- if(this->pvs!=NULL){
- delete this->pvs;
- }
- this->pvs=new PotentialVisibilitySet(numNodes);
-
- unsigned int i,j,k,l;
- unsigned int import_numClusters=pvs->getNumClusters();
- PVSCluster_t** import_clusters=pvs->getClusters();
- PVSCluster_t** this_clusters=this->pvs->getClusters();
- int* a=new int[numNodes*(import_numClusters+1)];
-
- log("SPTree::importPVS: importing pvs...\n");
-
- for(i=0;i<(unsigned int)numNodes;i++){
- vectorCopy3d(nodes[i]->min, this_clusters[i]->min);
- vectorCopy3d(nodes[i]->max, this_clusters[i]->max);
-
- int counter=0;
- for(j=0;j<import_numClusters;j++){
- if(AABBIntersectsAABB(nodes[i]->min, nodes[i]->max, import_clusters[j]->min, import_clusters[j]->max)){
- a[counter*numNodes + i]=j;
- counter++;
- //break;
- }
- }
- a[counter*numNodes + i]=-1;
- }
-
-
- for(i=0;i<(unsigned int)numNodes;i++){
- for(j=0;j<(unsigned int)numNodes;j++){
- for(k=0;a[k*numNodes + i]!=-1;k++){
- for(l=0;a[l*numNodes + j]!=-1;l++){
- if(pvs->clusterIsVisible(a[k*numNodes + i], a[l*numNodes + j])){
- this_clusters[i]->visibleClusters->set(j);
- //this_clusters[j]->visibleClusters->set(i);
- goto nextNode;
- }
- }
- }
- nextNode: ;
- }
- }
-
- log("SPTree::importPVS: pvs imported: %i clusters converted to %i clusters.\n", import_numClusters, numNodes);
-
- delete[] a;
- }
-
-
-
-
-
-
- SpacePartitioningTreeNode::SpacePartitioningTreeNode(SpacePartitioningTree* tree){
-
- this->tree=tree;
-
- parent=NULL;
-
- childs=NULL;
- numChilds=0;
-
- neighbours=NULL;
- numNeighbours=0;
-
- vectorInit3d(0.0f, 0.0f, 0.0f, min);
- vectorInit3d(0.0f, 0.0f, 0.0f, max);
-
- level=0;
-
- mesh=NULL;
- leafNode=false;
-
- faceIds=NULL;
- }
-
- SpacePartitioningTreeNode::~SpacePartitioningTreeNode(){
- int i;
-
- for(i=0;i<numChilds;i++){ // THINKABOUTME: wirklich alle childs l÷schen?
- if(childs[i]!=NULL){
- delete childs[i];
- }
- }
-
- if(childs!=NULL)
- delete[] childs;
-
- if(neighbours!=NULL)
- delete[] neighbours;
-
- if(mesh!=NULL)
- delete mesh;
-
- if(faceIds!=NULL)
- delete faceIds;
-
- }
-
- Face* SpacePartitioningTreeNode::getFaceIntersectingAABB(vec3_t min, vec3_t max){
- int i;
- Face* f;
-
- if(!AABBIntersectsAABB(min, max, this->min, this->max))
- return NULL;
-
- if(leafNode){
- for(i=0;i<mesh->numFaces;i++){
- f=mesh->faces[i];
- if(triangleIntersectsAABB(&f->vertices[0],&f->vertices[3],&f->vertices[6], min, max)){
- return f;
- }
- }
- }else{
- for(i=0;i<numChilds;i++){
- f=childs[i]->getFaceIntersectingAABB(min, max);
- if(f!=NULL){
- return f;
- }
- }
- }
-
- return NULL;
- }
-
- Face* SpacePartitioningTreeNode::getFrontFacingFaceIntersectingAABB(vec3_t min, vec3_t max, vec3_t dir){
- int i;
- Face* f;
-
- if(!AABBIntersectsAABB(min, max, this->min, this->max))
- return NULL;
-
- if(leafNode){
- for(i=0;i<mesh->numFaces;i++){
- f=mesh->faces[i];
- if(DOT_PRODUCT_3D(f->normal, dir)<0.0f
- && triangleIntersectsAABB(&f->vertices[0],&f->vertices[3],&f->vertices[6], min, max)){
- return f;
- }
- }
- }else{
- for(i=0;i<numChilds;i++){
- f=childs[i]->getFrontFacingFaceIntersectingAABB(min, max, dir);
- if(f!=NULL){
- return f;
- }
- }
- }
-
- return NULL;
- }
-
- void SpacePartitioningTreeNode::collectFacesIntersectingAABB(vec3_t min, vec3_t max, vector<Face*>& ret){
- int i;
- Face* f;
-
- if(!AABBIntersectsAABB(min, max, this->min, this->max)) // aabb not in node
- return;
-
- if(leafNode){
- for(i=0;i<mesh->numFaces;i++){
- f = mesh->faces[i];
- if(triangleIntersectsAABB(&f->vertices[0],&f->vertices[3],&f->vertices[6], min, max)){
- ret.push_back(f);
- }
- }
- }else{
- for(i=0;i<numChilds;i++){
- if( AABBIntersectsAABB(min, max, childs[i]->min, childs[i]->max) ){
- childs[i]->collectFacesIntersectingAABB(min, max, ret);
- }
- }
- }
- }
-
- void SpacePartitioningTreeNode::collectFrontFacingFacesIntersectingAABB(vec3_t min, vec3_t max, vec3_t dir, vector<Face*>& ret){
- int i;
- Face* f;
-
- if( !AABBIntersectsAABB(min, max, this->min, this->max) )
- return;
-
- if(leafNode){
- for(i=0;i<mesh->numFaces;i++){
- f = mesh->faces[i];
- if( DOT_PRODUCT_3D(f->normal, dir) < 0.0f
- && triangleIntersectsAABB(&f->vertices[0],&f->vertices[3],&f->vertices[6], min, max) ){
- ret.push_back(f);
- }
- }
- }else{
- for(i=0;i<numChilds;i++){
- if( AABBIntersectsAABB(min, max, childs[i]->min, childs[i]->max) ){
- childs[i]->collectFrontFacingFacesIntersectingAABB(min, max, dir, ret);
- }
- }
- }
- }
-
-
- void SpacePartitioningTreeNode::collectFacesIntersectingRay(vec3_t startPos, vec3_t dir, vector<Face*>& ret){
- int i;
-
- Face* f;
-
- if( !rayIntersectsAABB(startPos, dir, this->min, this->max) ) // ray not in node
- return;
-
- if(leafNode){
- for(i=0;i<mesh->numFaces;i++){
- f = mesh->faces[i];
- if( rayIntersectsTriangle(startPos, dir, &f->vertices[0],&f->vertices[3],&f->vertices[6]) ){
- ret.push_back(f);
- }
- }
- }else{
- for(i=0;i<numChilds;i++){
- if( rayIntersectsAABB(startPos, dir, childs[i]->min, childs[i]->max) ){
- childs[i]->collectFacesIntersectingRay(startPos, dir, ret);
- }
- }
- }
- }
-
- void SpacePartitioningTreeNode::collectFrontFacingFacesIntersectingRay(vec3_t startPos, vec3_t dir, vector<Face*>& ret){
- int i;
- Face* f;
-
- if( !rayIntersectsAABB(startPos, dir, this->min, this->max) ) // ray not in node
- return;
-
- if(leafNode){
- for(i=0;i<mesh->numFaces;i++){
- f = mesh->faces[i];
- if( rayIntersectsTriangle(startPos, dir, &f->vertices[0],&f->vertices[3],&f->vertices[6])
- && DOT_PRODUCT_3D(f->normal, dir) >= 0.0f ){
- ret.push_back(f);
- }
- }
- }else{
- for(i=0;i<numChilds;i++){
- if( rayIntersectsAABB(startPos, dir, childs[i]->min, childs[i]->max) ){
- childs[i]->collectFacesIntersectingRay(startPos, dir, ret);
- }
- }
- }
- }
-
-
-
- void SpacePartitioningTreeNode::collectLeafNodesIntersectingAABB(vec3_t min, vec3_t max, vector<SpacePartitioningTreeNode*>& ret){
- int i;
-
- if(!AABBIntersectsAABB(min, max, this->min, this->max))
- return;
-
- if(leafNode){
- ret.push_back(this);
- }else{
- for(i=0;i<numChilds;i++){
- childs[i]->collectLeafNodesIntersectingAABB(min, max, ret);
- }
- }
- }
-
-
- void SpacePartitioningTreeNode::traceRay(trace_t* trace){
- int i;
- Face* f;
-
- if(leafNode){
- float dist;
- vec3_t hp;
- for(i=0;i<mesh->numFaces;i++){
- if( ((trace->ignoreFlags & COLLISION_FLAG_BACKFACES) && DOT_PRODUCT_3D(mesh->faces[i]->normal, trace->dir) >= 0.0f)
- || (trace->ignoreFlags & mesh->faces[i]->material->collisionFlags) )
- continue;
-
- f = mesh->faces[i];
- if( rayIntersectsFace(trace->startPos, trace->dir, f, &dist, hp) ){
- vector<hit_t>::iterator hits_iter;
- for (hits_iter = trace->hits.begin(); hits_iter != trace->hits.end(); hits_iter++){
- // if( (*node_iter)->faceIds[i] == this->faceIds[i] ){
- // printf("DOUBLE!\n");
- // f = NULL;
- // }
- if( dist < hits_iter->distance ){
- break;
- }
-
- }
-
- if( f != NULL ){
- hit_t hit;
- hit.distance = dist;
- vectorCopy3d(hp, hit.pos);
- hit.node = this;
- hit.face = f;
- hit.vehicle = NULL;
-
- hits_iter = trace->hits.insert(hits_iter, hit);
- }
- }
- }
-
- }else{
- for(i=0;i<numChilds;i++){
- if(rayIntersectsAABB(trace->startPos, trace->dir, childs[i]->min, childs[i]->max)){
- childs[i]->traceRay(trace);
- }
- }
- }
-
- }
-
- void SpacePartitioningTreeNode::traceLinesegment(trace_t* trace){
- int i;
- Face* f;
-
- if(leafNode){
- float dist;
- vec3_t hp;
- for(i=0;i<mesh->numFaces;i++){
- if( ((trace->ignoreFlags & COLLISION_FLAG_BACKFACES) && DOT_PRODUCT_3D(mesh->faces[i]->normal, trace->dir) >= 0.0f)
- || (trace->ignoreFlags & mesh->faces[i]->material->collisionFlags) )
- continue;
-
- f = mesh->faces[i];
- if( linesegmentIntersectsFace(trace->startPos, trace->endPos, f, &dist, hp) ){
- vector<hit_t>::iterator hits_iter;
- for (hits_iter = trace->hits.begin(); hits_iter != trace->hits.end(); hits_iter++){
- // if( (*node_iter)->faceIds[i] == this->faceIds[i] ){
- // printf("DOUBLE!\n");
- // f = NULL;
- // }
- if( dist < hits_iter->distance ){
- break;
- }
- }
-
- if( f != NULL ){
- hit_t hit;
- hit.distance = dist;
- vectorCopy3d(hp, hit.pos);
- hit.node = this;
- hit.face = f;
- hit.vehicle = NULL;
-
- hits_iter = trace->hits.insert(hits_iter, hit);
- }
- }
- }
- }else{
- for(i=0;i<numChilds;i++){
- if(linesegmentIntersectsAABB(trace->startPos, trace->endPos, childs[i]->min, childs[i]->max)){
- childs[i]->traceLinesegment(trace);
- }
- }
- }
- }
-
- void SpacePartitioningTreeNode::render(){
- //printf("rendering node %i\n", nodeId);
-
- if(Renderer::info.var.useFrustrumCulling && !Game::cam.AABBInFrustum(min, max))
- return;
-
- if(tree->pvs!=NULL && tree->pvs->enabled && !tree->pvs->clusterIsVisible(nodeId)){
- //printf("JUHU!!\n");
- return;
- }
-
- if(!leafNode){
- for(int i=0;i<numChilds;i++){
- childs[i]->render();
- }
- }else{
- Renderer::renderMesh(mesh, this);
- Renderer::info.var.nodeCount++;
- }
- }
-
- void SpacePartitioningTreeNode::drawBorders(){
- if(!(Renderer::info.var.renderSPTreeBorders==2) || leafNode){
- float red=1.0f - level/(float)tree->numLevels;
- Renderer::disableLighting();
- glColor4f(red, 1.0f, 0.0f, 1.0f);
- Renderer::debug_renderAABB(min, max);
- Renderer::enableLighting();
- }
-
- if(leafNode)
- return;
-
- for(int i=0;i<numChilds;i++){
- childs[i]->drawBorders();
- }
- }
-
-