//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void Q3_BSPBrushToMapBrush(q3_dbrush_t *bspbrush, entity_t *mapent) { mapbrush_t *b; int i, k, n; side_t *side, *s2; int planenum; q3_dbrushside_t *bspbrushside; q3_dplane_t *bspplane; int contentFlags = 0; if(nummapbrushes >= MAX_MAPFILE_BRUSHES) { Error("nummapbrushes >= MAX_MAPFILE_BRUSHES"); } b = &mapbrushes[nummapbrushes]; b->original_sides = &brushsides[nummapbrushsides]; b->entitynum = mapent - entities; b->brushnum = nummapbrushes - mapent->firstbrush; b->leafnum = dbrushleafnums[bspbrush - q3_dbrushes]; for(n = 0; n < bspbrush->numSides; n++) { //pointer to the bsp brush side bspbrushside = &q3_dbrushsides[bspbrush->firstSide + n]; if(nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES) { Error("MAX_MAPFILE_BRUSHSIDES"); } //end if //pointer to the map brush side side = &brushsides[nummapbrushsides]; //if the BSP brush side is textured if(q3_dbrushsidetextured[bspbrush->firstSide + n]) { side->flags |= SFL_TEXTURED | SFL_VISIBLE; } else { side->flags &= ~SFL_TEXTURED; } //NOTE: all Quake3 sides are assumed textured //side->flags |= SFL_TEXTURED|SFL_VISIBLE; // if(bspbrushside->shaderNum < 0) { side->contents = 0; side->surf = 0; } //end if else { side->contents = q3_dshaders[bspbrushside->shaderNum].contentFlags; side->surf = q3_dshaders[bspbrushside->shaderNum].surfaceFlags; if(strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/hint")) { //Log_Print("found hint side\n"); side->surf |= SURF_HINT; } //end if // Ridah, mark ladder brushes if(cfg.rs_allowladders && strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/ladder")) { //Log_Print("found ladder side\n"); side->contents |= CONTENTS_LADDER; contentFlags |= CONTENTS_LADDER; } //end if // done. } //end else // if(!(strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/slip"))) { side->flags |= SFL_VISIBLE; } else if(side->surf & SURF_NODRAW) { side->flags |= SFL_TEXTURED | SFL_VISIBLE; } //end if /* if (side->contents & (CONTENTS_TRANSLUCENT|CONTENTS_STRUCTURAL)) { side->flags |= SFL_TEXTURED|SFL_VISIBLE; } //end if*/ // hints and skips are never detail, and have no content if(side->surf & (SURF_HINT | SURF_SKIP)) { side->contents = 0; //Log_Print("found hint brush side\n"); } /* if ((side->surf & SURF_NODRAW) && (side->surf & SURF_NOIMPACT)) { side->contents = 0; side->surf &= ~CONTENTS_DETAIL; Log_Print("probably found hint brush in a BSP without hints being used\n"); } //end if*/ /* // RF, ignore slick brushes (causes ladder issues) if (strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/slick")) { //Log_Print("found hint side\n"); b->numsides = 0; b->contents = 0; return; // get out of here } //end if */ //ME: get a plane for this side bspplane = &q3_dplanes[bspbrushside->planeNum]; planenum = FindFloatPlane(bspplane->normal, bspplane->dist); // // see if the plane has been used already // //ME: this really shouldn't happen!!! //ME: otherwise the bsp file is corrupted?? //ME: still it seems to happen, maybe Johny Boy's //ME: brush bevel adding is crappy ? for(k = 0; k < b->numsides; k++) { s2 = b->original_sides + k; // if (DotProduct (mapplanes[s2->planenum].normal, mapplanes[planenum].normal) > 0.999 // && fabs(mapplanes[s2->planenum].dist - mapplanes[planenum].dist) < 0.01 ) if(s2->planenum == planenum) { Log_Print("Entity %i, Brush %i: duplicate plane\n" , b->entitynum, b->brushnum); break; } if(s2->planenum == (planenum ^ 1)) { Log_Print("Entity %i, Brush %i: mirrored plane\n" , b->entitynum, b->brushnum); break; } } if(k != b->numsides) { continue; // duplicated } // // keep this side // //ME: reset pointer to side, why? hell I dunno (pointer is set above already) side = b->original_sides + b->numsides; //ME: store the plane number side->planenum = planenum; //ME: texinfo is already stored when bsp is loaded //NOTE: check for TEXINFO_NODE, otherwise crash in Q3_BrushContents //if (bspbrushside->texinfo < 0) side->texinfo = 0; //else side->texinfo = bspbrushside->texinfo; // save the td off in case there is an origin brush and we // have to recalculate the texinfo // ME: don't need to recalculate because it's already done // (for non-world entities) in the BSP file // side_brushtextures[nummapbrushsides] = td; nummapbrushsides++; b->numsides++; } //end for // get the content for the entire brush //Quake3 bsp brushes don't have a contents b->contents = q3_dshaders[bspbrush->shaderNum].contentFlags | contentFlags; // Ridah, Wolf has ladders (if we call Q3_BrushContents(), we'll get the solid area bug b->contents &= ~(/*CONTENTS_LADDER|*/ CONTENTS_FOG | CONTENTS_STRUCTURAL); //b->contents = Q3_BrushContents(b); // // Ridah, CONTENTS_MOSTERCLIP should prevent AAS from being created, but not clip players/AI in the game if(b->contents & CONTENTS_MONSTERCLIP) { b->contents |= CONTENTS_PLAYERCLIP; } // func_explosive's not solid if(!strcmp("func_explosive", ValueForKey(&entities[b->entitynum], "classname")) || !strcmp("func_invisible_user", ValueForKey(&entities[b->entitynum], "classname")) || !strcmp("script_mover", ValueForKey(&entities[b->entitynum], "classname")) || !strcmp("func_static", ValueForKey(&entities[b->entitynum], "classname"))) { Log_Print("Ignoring %s brush..\n", ValueForKey(&entities[b->entitynum], "classname")); b->numsides = 0; b->contents = 0; return; } if(BrushExists(b)) { c_squattbrushes++; b->numsides = 0; return; } //end if //if we're creating AAS if(create_aas) { //create the AAS brushes from this brush, don't add brush bevels AAS_CreateMapBrushes(b, mapent, false); return; } //end if // allow detail brushes to be removed if(nodetail && (b->contents & CONTENTS_DETAIL)) { b->numsides = 0; return; } //end if // allow water brushes to be removed if(nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER))) { b->numsides = 0; return; } //end if // create windings for sides and bounds for brush MakeBrushWindings(b); //mark brushes without winding or with a tiny window as bevels MarkBrushBevels(b); // brushes that will not be visible at all will never be // used as bsp splitters if(b->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP)) { c_clipbrushes++; for(i = 0; i < b->numsides; i++) b->original_sides[i].texinfo = TEXINFO_NODE; } //end for // // origin brushes are removed, but they set // the rotation origin for the rest of the brushes // in the entity. After the entire entity is parsed, // the planenums and texinfos will be adjusted for // the origin brush // //ME: not needed because the entities in the BSP file already // have an origin set // if (b->contents & CONTENTS_ORIGIN) // { // char string[32]; // vec3_t origin; // // if (num_entities == 1) // { // Error ("Entity %i, Brush %i: origin brushes not allowed in world" // , b->entitynum, b->brushnum); // return; // } // // VectorAdd (b->mins, b->maxs, origin); // VectorScale (origin, 0.5, origin); // // sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); // SetKeyValue (&entities[b->entitynum], "origin", string); // // VectorCopy (origin, entities[b->entitynum].origin); // // // don't keep this brush // b->numsides = 0; // // return; // } //ME: the bsp brushes already have bevels, so we won't try to // add them again (especially since Johny Boy's bevel adding might // be crappy) // AddBrushBevels(b); nummapbrushes++; mapent->numbrushes++; } //end of the function Q3_BSPBrushToMapBrush
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void Sin_BSPBrushToMapBrush(sin_dbrush_t *bspbrush, entity_t *mapent) { mapbrush_t *b; int i, k, n; side_t *side, *s2; int planenum; sin_dbrushside_t *bspbrushside; sin_dplane_t *bspplane; if (nummapbrushes >= MAX_MAPFILE_BRUSHES) { Error("nummapbrushes >= MAX_MAPFILE_BRUSHES"); } b = &mapbrushes[nummapbrushes]; b->original_sides = &brushsides[nummapbrushsides]; b->entitynum = mapent - entities; b->brushnum = nummapbrushes - mapent->firstbrush; b->leafnum = dbrushleafnums[bspbrush - sin_dbrushes]; for (n = 0; n < bspbrush->numsides; n++) { //pointer to the bsp brush side bspbrushside = &sin_dbrushsides[bspbrush->firstside + n]; if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES) { Error("MAX_MAPFILE_BRUSHSIDES"); } //end if //pointer to the map brush side side = &brushsides[nummapbrushsides]; //if the BSP brush side is textured if (sin_dbrushsidetextured[bspbrush->firstside + n]) { side->flags |= SFL_TEXTURED; } else { side->flags &= ~SFL_TEXTURED; } //ME: can get side contents and surf directly from BSP file side->contents = bspbrush->contents; //if the texinfo is TEXINFO_NODE if (bspbrushside->texinfo < 0) { side->surf = 0; } else { side->surf = sin_texinfo[bspbrushside->texinfo].flags; } // translucent objects are automatically classified as detail // if (side->surf & (SURF_TRANS33|SURF_TRANS66) ) // side->contents |= CONTENTS_DETAIL; if (side->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP)) { side->contents |= CONTENTS_DETAIL; } if (fulldetail) { side->contents &= ~CONTENTS_DETAIL; } if (!(side->contents & ((LAST_VISIBLE_CONTENTS - 1) | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP | CONTENTS_MIST))) { side->contents |= CONTENTS_SOLID; } // hints and skips are never detail, and have no content if (side->surf & (SURF_HINT | SURF_SKIP)) { side->contents = 0; side->surf &= ~CONTENTS_DETAIL; } //ME: get a plane for this side bspplane = &sin_dplanes[bspbrushside->planenum]; planenum = FindFloatPlane(bspplane->normal, bspplane->dist, 0, NULL); // // see if the plane has been used already // //ME: this really shouldn't happen!!! //ME: otherwise the bsp file is corrupted?? //ME: still it seems to happen, maybe Johny Boy's //ME: brush bevel adding is crappy ? for (k = 0; k < b->numsides; k++) { s2 = b->original_sides + k; if (s2->planenum == planenum) { Log_Print("Entity %i, Brush %i: duplicate plane\n" , b->entitynum, b->brushnum); break; } if (s2->planenum == (planenum ^ 1)) { Log_Print("Entity %i, Brush %i: mirrored plane\n" , b->entitynum, b->brushnum); break; } } if (k != b->numsides) { continue; // duplicated } // // keep this side // //ME: reset pointer to side, why? hell I dunno (pointer is set above already) side = b->original_sides + b->numsides; //ME: store the plane number side->planenum = planenum; //ME: texinfo is already stored when bsp is loaded //NOTE: check for TEXINFO_NODE, otherwise crash in Sin_BrushContents if (bspbrushside->texinfo < 0) { side->texinfo = 0; } else { side->texinfo = bspbrushside->texinfo; } // save the td off in case there is an origin brush and we // have to recalculate the texinfo // ME: don't need to recalculate because it's already done // (for non-world entities) in the BSP file // side_brushtextures[nummapbrushsides] = td; nummapbrushsides++; b->numsides++; } //end for // get the content for the entire brush b->contents = bspbrush->contents; Sin_BrushContents(b); if (BrushExists(b)) { c_squattbrushes++; b->numsides = 0; return; } //end if //if we're creating AAS if (create_aas) { //create the AAS brushes from this brush, don't add brush bevels AAS_CreateMapBrushes(b, mapent, false); return; } //end if // allow detail brushes to be removed if (nodetail && (b->contents & CONTENTS_DETAIL)) { b->numsides = 0; return; } //end if // allow water brushes to be removed if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER))) { b->numsides = 0; return; } //end if // create windings for sides and bounds for brush MakeBrushWindings(b); //mark brushes without winding or with a tiny window as bevels MarkBrushBevels(b); // brushes that will not be visible at all will never be // used as bsp splitters if (b->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP)) { c_clipbrushes++; for (i = 0; i < b->numsides; i++) b->original_sides[i].texinfo = TEXINFO_NODE; } //end for // // origin brushes are removed, but they set // the rotation origin for the rest of the brushes // in the entity. After the entire entity is parsed, // the planenums and texinfos will be adjusted for // the origin brush // //ME: not needed because the entities in the BSP file already // have an origin set // if (b->contents & CONTENTS_ORIGIN) // { // char string[32]; // vec3_t origin; // // if (num_entities == 1) // { // Error ("Entity %i, Brush %i: origin brushes not allowed in world" // , b->entitynum, b->brushnum); // return; // } // // VectorAdd (b->mins, b->maxs, origin); // VectorScale (origin, 0.5, origin); // // sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); // SetKeyValue (&entities[b->entitynum], "origin", string); // // VectorCopy (origin, entities[b->entitynum].origin); // // // don't keep this brush // b->numsides = 0; // // return; // } //ME: the bsp brushes already have bevels, so we won't try to // add them again (especially since Johny Boy's bevel adding might // be crappy) // AddBrushBevels(b); nummapbrushes++; mapent->numbrushes++; } //end of the function Sin_BSPBrushToMapBrush
/* ================= Q2_ParseBrush ================= */ void Q2_ParseBrush(script_t *script, entity_t *mapent) { mapbrush_t *b; int i, j, k; int mt; side_t *side, *s2; int planenum; brush_texture_t td; int planepts[3][3]; token_t token; if (nummapbrushes >= MAX_MAPFILE_BRUSHES) { Error("nummapbrushes == MAX_MAPFILE_BRUSHES"); } b = &mapbrushes[nummapbrushes]; b->original_sides = &brushsides[nummapbrushsides]; b->entitynum = num_entities - 1; b->brushnum = nummapbrushes - mapent->firstbrush; b->leafnum = -1; do { if (!PS_ReadToken(script, &token)) { break; } if (!strcmp(token.string, "}")) { break; } //IDBUG: mixed use of MAX_MAPFILE_? and MAX_MAP_? this could // lead to out of bound indexing of the arrays if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES) { Error("MAX_MAPFILE_BRUSHSIDES"); } side = &brushsides[nummapbrushsides]; //read the three point plane definition for (i = 0; i < 3; i++) { if (i != 0) { PS_ExpectTokenString(script, "("); } for (j = 0; j < 3; j++) { PS_ExpectAnyToken(script, &token); planepts[i][j] = atof(token.string); } //end for PS_ExpectTokenString(script, ")"); } //end for // //read the texturedef // PS_ExpectAnyToken(script, &token); strcpy(td.name, token.string); PS_ExpectAnyToken(script, &token); td.shift[0] = atol(token.string); PS_ExpectAnyToken(script, &token); td.shift[1] = atol(token.string); PS_ExpectAnyToken(script, &token); td.rotate = atol(token.string); PS_ExpectAnyToken(script, &token); td.scale[0] = atof(token.string); PS_ExpectAnyToken(script, &token); td.scale[1] = atof(token.string); //find default flags and values mt = FindMiptex(td.name); td.flags = textureref[mt].flags; td.value = textureref[mt].value; side->contents = textureref[mt].contents; side->surf = td.flags = textureref[mt].flags; //check if there's a number available if (PS_CheckTokenType(script, TT_NUMBER, 0, &token)) { side->contents = token.intvalue; PS_ExpectTokenType(script, TT_NUMBER, 0, &token); side->surf = td.flags = token.intvalue; PS_ExpectTokenType(script, TT_NUMBER, 0, &token); td.value = token.intvalue; } // translucent objects are automatically classified as detail // if (side->surf & (SURF_TRANS33|SURF_TRANS66) ) // side->contents |= CONTENTS_DETAIL; if (side->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP)) { side->contents |= CONTENTS_DETAIL; } if (fulldetail) { side->contents &= ~CONTENTS_DETAIL; } if (!(side->contents & ((LAST_VISIBLE_CONTENTS - 1) | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP | CONTENTS_MIST))) { side->contents |= CONTENTS_SOLID; } // hints and skips are never detail, and have no content // if (side->surf & (SURF_HINT|SURF_SKIP) ) // { // side->contents = 0; // side->surf &= ~CONTENTS_DETAIL; // } #ifdef ME //for creating AAS... this side is textured side->flags |= SFL_TEXTURED; #endif //ME // // find the plane number // planenum = PlaneFromPoints(planepts[0], planepts[1], planepts[2]); if (planenum == -1) { Log_Print("Entity %i, Brush %i: plane with no normal\n" , b->entitynum, b->brushnum); continue; } // // see if the plane has been used already // for (k = 0 ; k < b->numsides ; k++) { s2 = b->original_sides + k; if (s2->planenum == planenum) { Log_Print("Entity %i, Brush %i: duplicate plane\n" , b->entitynum, b->brushnum); break; } if (s2->planenum == (planenum ^ 1)) { Log_Print("Entity %i, Brush %i: mirrored plane\n" , b->entitynum, b->brushnum); break; } } if (k != b->numsides) { continue; // duplicated } // // keep this side // side = b->original_sides + b->numsides; side->planenum = planenum; side->texinfo = TexinfoForBrushTexture(&mapplanes[planenum], &td, vec3_origin); // save the td off in case there is an origin brush and we // have to recalculate the texinfo side_brushtextures[nummapbrushsides] = td; nummapbrushsides++; b->numsides++; } while (1); // get the content for the entire brush b->contents = Q2_BrushContents(b); #ifdef ME if (BrushExists(b)) { c_squattbrushes++; b->numsides = 0; return; } //end if if (create_aas) { //create AAS brushes, and add brush bevels AAS_CreateMapBrushes(b, mapent, true); //NOTE: if we return here then duplicate plane errors occur for the non world entities return; } //end if #endif //ME // allow detail brushes to be removed if (nodetail && (b->contents & CONTENTS_DETAIL)) { b->numsides = 0; return; } // allow water brushes to be removed if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER))) { b->numsides = 0; return; } // create windings for sides and bounds for brush MakeBrushWindings(b); // brushes that will not be visible at all will never be // used as bsp splitters if (b->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP)) { c_clipbrushes++; for (i = 0 ; i < b->numsides ; i++) b->original_sides[i].texinfo = TEXINFO_NODE; } // // origin brushes are removed, but they set // the rotation origin for the rest of the brushes // in the entity. After the entire entity is parsed, // the planenums and texinfos will be adjusted for // the origin brush // if (b->contents & CONTENTS_ORIGIN) { char string[32]; vec3_t origin; if (num_entities == 1) { Error("Entity %i, Brush %i: origin brushes not allowed in world" , b->entitynum, b->brushnum); return; } VectorAdd(b->mins, b->maxs, origin); VectorScale(origin, 0.5, origin); sprintf(string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); SetKeyValue(&entities[b->entitynum], "origin", string); VectorCopy(origin, entities[b->entitynum].origin); // don't keep this brush b->numsides = 0; return; } AddBrushBevels(b); nummapbrushes++; mapent->numbrushes++; }