//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_FlipFace(tmp_face_t *face) { tmp_area_t *frontarea, *backarea; winding_t *w; frontarea = face->frontarea; backarea = face->backarea; //must have an area at both sides before flipping is allowed if(!frontarea || !backarea) { return; } //flip the face winding w = face->winding; face->winding = ReverseWinding(w); FreeWinding(w); //flip the face plane face->planenum ^= 1; //flip the face areas AAS_RemoveFaceFromArea(face, frontarea); AAS_RemoveFaceFromArea(face, backarea); AAS_AddFaceSideToArea(face, 1, frontarea); AAS_AddFaceSideToArea(face, 0, backarea); } //end of the function AAS_FlipFace
//=========================================================================== // create a tmp AAS area from a leaf node // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== tmp_node_t *AAS_CreateArea(node_t *node) { int pside; int areafaceflags; portal_t *p; tmp_face_t *tmpface; tmp_area_t *tmparea; tmp_node_t *tmpnode; //create an area from this leaf tmparea = AAS_AllocTmpArea(); tmparea->tmpfaces = NULL; //clear the area face flags areafaceflags = 0; //make aas faces from the portals for (p = node->portals; p; p = p->next[pside]) { pside = (p->nodes[1] == node); //don't create faces from very small portals // if (WindingArea(p->winding) < 1) continue; //if there's already a face created for this portal if (p->tmpface) { //add the back side of the face to the area AAS_AddFaceSideToArea(p->tmpface, 1, tmparea); } //end if else { tmpface = AAS_AllocTmpFace(); //set the face pointer at the portal so we can see from //the portal there's a face created for it p->tmpface = tmpface; //FIXME: test this change //tmpface->planenum = (p->planenum & ~1) | pside; tmpface->planenum = p->planenum ^ pside; if (pside) tmpface->winding = ReverseWinding(p->winding); else tmpface->winding = CopyWinding(p->winding); #ifdef L_DEBUG // AAS_CheckFaceWindingPlane(tmpface); #endif //L_DEBUG //if there's solid at the other side of the portal if (p->nodes[!pside]->contents & (CONTENTS_SOLID | CONTENTS_PLAYERCLIP)) { tmpface->faceflags |= FACE_SOLID; } //end if //else there is no solid at the other side and if there //is a liquid at this side else if (node->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) { tmpface->faceflags |= FACE_LIQUID; //if there's no liquid at the other side if (!(p->nodes[!pside]->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) { tmpface->faceflags |= FACE_LIQUIDSURFACE; } //end if } //end else //if there's ladder contents at other side of the portal if ((p->nodes[pside]->contents & CONTENTS_LADDER) || (p->nodes[!pside]->contents & CONTENTS_LADDER)) { //NOTE: doesn't have to be solid at the other side because // when standing one can use a crouch area (which is not solid) // as a ladder // imagine a ladder one can walk underthrough, // under the ladder against the ladder is a crouch area // the (vertical) sides of this crouch area area also used as // ladder sides when standing (not crouched) tmpface->faceflags |= FACE_LADDER; } //end if //if it is possible to stand on the face if (AAS_GroundFace(tmpface)) { tmpface->faceflags |= FACE_GROUND; } //end if // areafaceflags |= tmpface->faceflags; //no aas face number yet (zero is a dummy in the aasworld faces) tmpface->aasfacenum = 0; //add the front side of the face to the area AAS_AddFaceSideToArea(tmpface, 0, tmparea); } //end else } //end for qprintf("\r%6d", tmparea->areanum); //presence type in the area tmparea->presencetype = ~node->expansionbboxes & cfg.allpresencetypes; // tmparea->contents = 0; if (node->contents & CONTENTS_CLUSTERPORTAL) tmparea->contents |= AREACONTENTS_CLUSTERPORTAL; if (node->contents & CONTENTS_MOVER) tmparea->contents |= AREACONTENTS_MOVER; if (node->contents & CONTENTS_TELEPORTER) tmparea->contents |= AREACONTENTS_TELEPORTER; if (node->contents & CONTENTS_JUMPPAD) tmparea->contents |= AREACONTENTS_JUMPPAD; if (node->contents & CONTENTS_DONOTENTER) tmparea->contents |= AREACONTENTS_DONOTENTER; if (node->contents & CONTENTS_WATER) tmparea->contents |= AREACONTENTS_WATER; if (node->contents & CONTENTS_LAVA) tmparea->contents |= AREACONTENTS_LAVA; if (node->contents & CONTENTS_SLIME) tmparea->contents |= AREACONTENTS_SLIME; if (node->contents & CONTENTS_NOTTEAM1) tmparea->contents |= AREACONTENTS_NOTTEAM1; if (node->contents & CONTENTS_NOTTEAM2) tmparea->contents |= AREACONTENTS_NOTTEAM2; //store the bsp model that's inside this node tmparea->modelnum = node->modelnum; //sorta check for flipped area faces (remove??) AAS_FlipAreaFaces(tmparea); //check if the area is ok (remove??) AAS_CheckArea(tmparea); // tmpnode = AAS_AllocTmpNode(); tmpnode->planenum = 0; tmpnode->children[0] = 0; tmpnode->children[1] = 0; tmpnode->tmparea = tmparea; // return tmpnode; } //end of the function AAS_CreateArea
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_SplitArea( tmp_area_t *tmparea, int planenum, tmp_area_t **frontarea, tmp_area_t **backarea ) { int side; tmp_area_t *facefrontarea, *facebackarea, *faceotherarea; tmp_face_t *face, *frontface, *backface, *splitface, *nextface; winding_t *splitwinding; plane_t *splitplane; /* #ifdef AW_DEBUG int facesplits, groundsplits, epsilonface; Log_Print("\n----------------------\n"); Log_Print("splitting area %d\n", areanum); Log_Print("with normal = \'%f %f %f\', dist = %f\n", normal[0], normal[1], normal[2], dist); AAS_TestSplitPlane(areanum, normal, dist, &facesplits, &groundsplits, &epsilonface); Log_Print("face splits = %d\nground splits = %d\n", facesplits, groundsplits); if (epsilonface) Log_Print("aaahh epsilon face\n"); #endif //AW_DEBUG*/ //the original area AAS_FlipAreaFaces( tmparea ); AAS_CheckArea( tmparea ); // splitplane = &mapplanes[planenum]; /* //create a split winding, first base winding for plane splitwinding = BaseWindingForPlane(splitplane->normal, splitplane->dist); //chop with all the faces of the area for (face = tmparea->tmpfaces; face && splitwinding; face = face->next[side]) { //side of the face the original area was on side = face->frontarea != tmparea->areanum; plane = &mapplanes[face->planenum ^ side]; ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0); // PLANESIDE_EPSILON); } //end for*/ splitwinding = AAS_SplitWinding( tmparea, planenum ); if ( !splitwinding ) { /* #ifdef DEBUG AAS_TestSplitPlane(areanum, normal, dist, &facesplits, &groundsplits, &epsilonface); Log_Print("\nface splits = %d\nground splits = %d\n", facesplits, groundsplits); if (epsilonface) Log_Print("aaahh epsilon face\n"); #endif //DEBUG*/ Error( "AAS_SplitArea: no split winding when splitting area %d\n", tmparea->areanum ); } //end if //create a split face splitface = AAS_AllocTmpFace(); //get the map plane splitface->planenum = planenum; //store the split winding splitface->winding = splitwinding; //the new front area ( *frontarea ) = AAS_AllocTmpArea(); ( *frontarea )->presencetype = tmparea->presencetype; ( *frontarea )->contents = tmparea->contents; ( *frontarea )->modelnum = tmparea->modelnum; ( *frontarea )->tmpfaces = NULL; //the new back area ( *backarea ) = AAS_AllocTmpArea(); ( *backarea )->presencetype = tmparea->presencetype; ( *backarea )->contents = tmparea->contents; ( *backarea )->modelnum = tmparea->modelnum; ( *backarea )->tmpfaces = NULL; //add the split face to the new areas AAS_AddFaceSideToArea( splitface, 0, ( *frontarea ) ); AAS_AddFaceSideToArea( splitface, 1, ( *backarea ) ); //split all the faces of the original area for ( face = tmparea->tmpfaces; face; face = nextface ) { //side of the face the original area was on side = face->frontarea != tmparea; //next face of the original area nextface = face->next[side]; //front area of the face facefrontarea = face->frontarea; //back area of the face facebackarea = face->backarea; //remove the face from both the front and back areas if ( facefrontarea ) { AAS_RemoveFaceFromArea( face, facefrontarea ); } if ( facebackarea ) { AAS_RemoveFaceFromArea( face, facebackarea ); } //split the face AAS_SplitFace( face, splitplane->normal, splitplane->dist, &frontface, &backface ); //free the original face AAS_FreeTmpFace( face ); //get the number of the area at the other side of the face if ( side ) { faceotherarea = facefrontarea; } else { faceotherarea = facebackarea;} //if there is an area at the other side of the original face if ( faceotherarea ) { if ( frontface ) { AAS_AddFaceSideToArea( frontface, !side, faceotherarea ); } if ( backface ) { AAS_AddFaceSideToArea( backface, !side, faceotherarea ); } } //end if //add the front and back part left after splitting the original face to the new areas if ( frontface ) { AAS_AddFaceSideToArea( frontface, side, ( *frontarea ) ); } if ( backface ) { AAS_AddFaceSideToArea( backface, side, ( *backarea ) ); } } //end for if ( !( *frontarea )->tmpfaces ) { Log_Print( "AAS_SplitArea: front area without faces\n" ); } if ( !( *backarea )->tmpfaces ) { Log_Print( "AAS_SplitArea: back area without faces\n" ); } tmparea->invalid = true; /* #ifdef AW_DEBUG for (i = 0, face = frontarea->tmpfaces; face; face = face->next[side]) { side = face->frontarea != frontarea->areanum; i++; } //end for Log_Print("created front area %d with %d faces\n", frontarea->areanum, i); for (i = 0, face = backarea->tmpfaces; face; face = face->next[side]) { side = face->frontarea != backarea->areanum; i++; } //end for Log_Print("created back area %d with %d faces\n", backarea->areanum, i); #endif //AW_DEBUG*/ AAS_FlipAreaFaces( ( *frontarea ) ); AAS_FlipAreaFaces( ( *backarea ) ); // AAS_CheckArea( ( *frontarea ) ); AAS_CheckArea( ( *backarea ) ); } //end of the function AAS_SplitArea
tmp_node_t *AAS_CreateArea( node_t *node ) { int pside; int areafaceflags; portal_t *p; tmp_face_t *tmpface; tmp_area_t *tmparea; tmp_node_t *tmpnode; vec3_t up = {0, 0, 1}; // vec3_t mins, maxs; // qboolean allowFreeIfSmall = 1; // VectorClear( mins ); // VectorClear( maxs ); //create an area from this leaf tmparea = AAS_AllocTmpArea(); tmparea->tmpfaces = NULL; //clear the area face flags areafaceflags = 0; //make aas faces from the portals for ( p = node->portals; p; p = p->next[pside] ) { pside = ( p->nodes[1] == node ); //don't create faces from very small portals // if (WindingArea(p->winding) < 1) continue; //if there's already a face created for this portal if ( p->tmpface ) { //add the back side of the face to the area AAS_AddFaceSideToArea( p->tmpface, 1, tmparea ); } //end if else { tmpface = AAS_AllocTmpFace(); //set the face pointer at the portal so we can see from //the portal there's a face created for it p->tmpface = tmpface; //FIXME: test this change //tmpface->planenum = (p->planenum & ~1) | pside; tmpface->planenum = p->planenum ^ pside; if ( pside ) { tmpface->winding = ReverseWinding( p->winding ); } else { tmpface->winding = CopyWinding( p->winding );} #ifdef L_DEBUG // AAS_CheckFaceWindingPlane( tmpface ); #endif //L_DEBUG //if there's solid at the other side of the portal if ( p->nodes[!pside]->contents & ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP ) ) { tmpface->faceflags |= FACE_SOLID; } //end if //else there is no solid at the other side and if there //is a liquid at this side else if ( node->contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { tmpface->faceflags |= FACE_LIQUID; //if there's no liquid at the other side if ( !( p->nodes[!pside]->contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) { tmpface->faceflags |= FACE_LIQUIDSURFACE; } //end if } //end else //if there's ladder contents at other side of the portal if ( ( p->nodes[pside]->contents & CONTENTS_LADDER ) || ( p->nodes[!pside]->contents & CONTENTS_LADDER ) ) { //NOTE: doesn't have to be solid at the other side because // when standing one can use a crouch area (which is not solid) // as a ladder // imagine a ladder one can walk underthrough, // under the ladder against the ladder is a crouch area // the (vertical) sides of this crouch area area also used as // ladder sides when standing (not crouched) tmpface->faceflags |= FACE_LADDER; } //end if //if it is possible to stand on the face if ( AAS_GroundFace( tmpface ) ) { tmpface->faceflags |= FACE_GROUND; } //end if // areafaceflags |= tmpface->faceflags; //no aas face number yet (zero is a dummy in the aasworld faces) tmpface->aasfacenum = 0; //add the front side of the face to the area AAS_AddFaceSideToArea( tmpface, 0, tmparea ); } //end else /* // RF, add this face to the bounds if (p->tmpface->faceflags & FACE_GROUND) { WindingBounds( p->winding, mins, maxs ); } // RF, if this face has a solid at the other side, and it is not a GROUND, then we cannot free if its too small if (allowFreeIfSmall && (p->tmpface->faceflags & FACE_SOLID) && !(p->tmpface->faceflags & FACE_GROUND)) { // make sure it's not a ceiling if (!(DotProduct(cfg.phys_gravitydirection, mapplanes[p->tmpface->planenum].normal) > cfg.phys_maxsteepness)) { allowFreeIfSmall = 0; } } */ } //end for qprintf( "\r%6d", tmparea->areanum ); //presence type in the area tmparea->presencetype = ~node->expansionbboxes & cfg.allpresencetypes; // tmparea->contents = 0; if ( node->contents & CONTENTS_CLUSTERPORTAL ) { tmparea->contents |= AREACONTENTS_CLUSTERPORTAL; } if ( node->contents & CONTENTS_MOVER ) { tmparea->contents |= AREACONTENTS_MOVER; } if ( node->contents & CONTENTS_TELEPORTER ) { tmparea->contents |= AREACONTENTS_TELEPORTER; } if ( node->contents & CONTENTS_JUMPPAD ) { tmparea->contents |= AREACONTENTS_JUMPPAD; } if ( node->contents & CONTENTS_DONOTENTER ) { tmparea->contents |= AREACONTENTS_DONOTENTER; } if ( node->contents & CONTENTS_DONOTENTER_LARGE ) { tmparea->contents |= AREACONTENTS_DONOTENTER_LARGE; } if ( node->contents & CONTENTS_WATER ) { tmparea->contents |= AREACONTENTS_WATER; } if ( node->contents & CONTENTS_LAVA ) { tmparea->contents |= AREACONTENTS_LAVA; } if ( node->contents & CONTENTS_SLIME ) { tmparea->contents |= AREACONTENTS_SLIME; } /* // RF, if we are using only ground areas, then ignore areas that arent grounded or attached to ladders, or underwater if (groundonly && !(areafaceflags & (FACE_GROUND|FACE_LADDER)) && !(tmparea->contents & (AREACONTENTS_WATER|AREACONTENTS_SLIME|AREACONTENTS_LAVA))) { numGroundOnlyFreed++; tmparea->invalid = true; } */ /* // RF, if this is a really small area, and it is surrounded by non-solid portals, then nuke it if (allowFreeIfSmall && !(areafaceflags & (FACE_LADDER)) && VectorDistance( mins, maxs ) < 32) { numTinyFreed++; tmparea->invalid = true; } */ //store the bsp model that's inside this node tmparea->modelnum = node->modelnum; //sorta check for flipped area faces (remove??) AAS_FlipAreaFaces( tmparea ); //check if the area is ok (remove??) AAS_CheckArea( tmparea ); // tmpnode = AAS_AllocTmpNode(); tmpnode->planenum = 0; tmpnode->children[0] = 0; tmpnode->children[1] = 0; tmpnode->tmparea = tmparea; // return tmpnode; } //end of the function AAS_CreateArea
//=========================================================================== // try to merge the areas at both sides of the given face // // Parameter: seperatingface : face that seperates two areas // Returns: - // Changes Globals: - //=========================================================================== int AAS_TryMergeFaceAreas( tmp_face_t *seperatingface ) { int side1, side2, area1faceflags, area2faceflags; tmp_area_t *tmparea1, *tmparea2, *newarea; tmp_face_t *face1, *face2, *nextface1, *nextface2; tmparea1 = seperatingface->frontarea; tmparea2 = seperatingface->backarea; //areas must have the same presence type if ( tmparea1->presencetype != tmparea2->presencetype ) { return false; } //areas must have the same area contents if ( tmparea1->contents != tmparea2->contents ) { return false; } //areas must have the same bsp model inside (or both none) if ( tmparea1->modelnum != tmparea2->modelnum ) { return false; } area1faceflags = 0; area2faceflags = 0; for ( face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side1] ) { side1 = ( face1->frontarea != tmparea1 ); //debug: check if the area belongs to the area if ( face1->frontarea != tmparea1 && face1->backarea != tmparea1 ) { Error( "face does not belong to area1" ); } //just continue if the face is seperating the two areas //NOTE: a result of this is that ground and gap areas can // be merged if the seperating face is the gap if ( ( face1->frontarea == tmparea1 && face1->backarea == tmparea2 ) || ( face1->frontarea == tmparea2 && face1->backarea == tmparea1 ) ) { continue; } //get area1 face flags area1faceflags |= face1->faceflags; if ( AAS_GapFace( face1, side1 ) ) { area1faceflags |= FACE_GAP; } // for ( face2 = tmparea2->tmpfaces; face2; face2 = face2->next[side2] ) { side2 = ( face2->frontarea != tmparea2 ); //debug: check if the area belongs to the area if ( face2->frontarea != tmparea2 && face2->backarea != tmparea2 ) { Error( "face does not belong to area2" ); } //just continue if the face is seperating the two areas //NOTE: a result of this is that ground and gap areas can // be merged if the seperating face is the gap if ( ( face2->frontarea == tmparea1 && face2->backarea == tmparea2 ) || ( face2->frontarea == tmparea2 && face2->backarea == tmparea1 ) ) { continue; } //get area2 face flags area2faceflags |= face2->faceflags; if ( AAS_GapFace( face2, side2 ) ) { area2faceflags |= FACE_GAP; } //if the two faces would create a non-convex area if ( NonConvex( face1, face2, side1, side2 ) ) { return false; } } //end for } //end for //if one area has gap faces (that aren't seperating the two areas) //and the other has ground faces (that aren't seperating the two areas), //the areas can't be merged if ( ( ( area1faceflags & FACE_GROUND ) && ( area2faceflags & FACE_GAP ) ) || ( ( area2faceflags & FACE_GROUND ) && ( area1faceflags & FACE_GAP ) ) ) { // Log_Print(" can't merge: ground/gap\n"); return false; } //end if // Log_Print("merged area %d & %d to %d with %d faces\n", tmparea1->areanum, tmparea2->areanum, newarea->areanum, numfaces); // return false; // //AAS_CheckArea(tmparea1); //AAS_CheckArea(tmparea2); //create the new area newarea = AAS_AllocTmpArea(); newarea->presencetype = tmparea1->presencetype; newarea->contents = tmparea1->contents; newarea->modelnum = tmparea1->modelnum; newarea->tmpfaces = NULL; //add all the faces (except the seperating ones) from the first area //to the new area for ( face1 = tmparea1->tmpfaces; face1; face1 = nextface1 ) { side1 = ( face1->frontarea != tmparea1 ); nextface1 = face1->next[side1]; //don't add seperating faces if ( ( face1->frontarea == tmparea1 && face1->backarea == tmparea2 ) || ( face1->frontarea == tmparea2 && face1->backarea == tmparea1 ) ) { continue; } //end if // AAS_RemoveFaceFromArea( face1, tmparea1 ); AAS_AddFaceSideToArea( face1, side1, newarea ); } //end for //add all the faces (except the seperating ones) from the second area //to the new area for ( face2 = tmparea2->tmpfaces; face2; face2 = nextface2 ) { side2 = ( face2->frontarea != tmparea2 ); nextface2 = face2->next[side2]; //don't add seperating faces if ( ( face2->frontarea == tmparea1 && face2->backarea == tmparea2 ) || ( face2->frontarea == tmparea2 && face2->backarea == tmparea1 ) ) { continue; } //end if // AAS_RemoveFaceFromArea( face2, tmparea2 ); AAS_AddFaceSideToArea( face2, side2, newarea ); } //end for //free all shared faces for ( face1 = tmparea1->tmpfaces; face1; face1 = nextface1 ) { side1 = ( face1->frontarea != tmparea1 ); nextface1 = face1->next[side1]; // AAS_RemoveFaceFromArea( face1, face1->frontarea ); AAS_RemoveFaceFromArea( face1, face1->backarea ); AAS_FreeTmpFace( face1 ); } //end for // tmparea1->mergedarea = newarea; tmparea1->invalid = true; tmparea2->mergedarea = newarea; tmparea2->invalid = true; // AAS_CheckArea( newarea ); AAS_FlipAreaFaces( newarea ); // Log_Print("merged area %d & %d to %d with %d faces\n", tmparea1->areanum, tmparea2->areanum, newarea->areanum); return true; } //end of the function AAS_TryMergeFaceAreas