/* ================== AddAnimatingTextures ================== */ void AddAnimatingTextures (void) { int base; int i, j, k; char name[32]; base = nummiptex; for (i=0 ; i<base ; i++) { if (miptex[i][0] != '+') continue; strcpy (name, miptex[i]); for (j=0 ; j<20 ; j++) { if (j < 10) name[1] = '0'+j; else name[1] = 'A'+j-10; // alternate animation // see if this name exists in the wadfile for (k=0 ; k<wadinfo.numlumps ; k++) if (!strcmp(name, lumpinfo[k].name)) { FindMiptex (name); // add to the miptex list break; } } } printf ("added %i texture frames\n", nummiptex - base); }
void AddAnimatingTextures (void) { int base; int i, j; char name[32]; base = nummiptex; for (i = 0;i < base;i++) { if (miptex[i][0] != '+') continue; CleanupName (miptex[i], name); for (j = 0;j < 20;j++) { if (j < 10) name[1] = j + '0'; else name[1] = j + 'A' - 10; // alternate animation if (!MipTexUsed(name) && FindMipTexFile(name)) FindMiptex (name); } } }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int FindMiptex (char *name) { int i; char path[1024]; miptex_t *mt; for (i = 0; i < nummiptex; i++) { if (!strcmp (name, textureref[i].name)) { return i; } //end if } //end for if (nummiptex == MAX_MAP_TEXTURES) Error ("MAX_MAP_TEXTURES"); strcpy (textureref[i].name, name); // load the miptex to get the flags and values sprintf (path, "%stextures/%s.wal", gamedir, name); if (TryLoadFile (path, (void **)&mt) != -1) { textureref[i].value = LittleLong (mt->value); textureref[i].flags = LittleLong (mt->flags); textureref[i].contents = LittleLong (mt->contents); strcpy (textureref[i].animname, mt->animname); FreeMemory(mt); } //end if nummiptex++; if (textureref[i].animname[0]) FindMiptex (textureref[i].animname); return i; } //end of the function FindMipTex
// ===================================================================================== // AddAnimatingTextures // ===================================================================================== void AddAnimatingTextures() { int base; int i, j, k; char name[MAXWADNAME]; base = nummiptex; for (i = 0; i < base; i++) { if ((miptex[i].name[0] != '+') && (miptex[i].name[0] != '-')) { continue; } safe_strncpy(name, miptex[i].name, MAXWADNAME); for (j = 0; j < 20; j++) { if (j < 10) { name[1] = '0' + j; } else { name[1] = 'A' + j - 10; // alternate animation } // see if this name exists in the wadfile for (k = 0; k < nTexLumps; k++) { if (!strcmp(name, lumpinfo[k].name)) { FindMiptex(name); // add to the miptex list break; } } } } if (nummiptex - base) { Log("added %i additional animating textures.\n", nummiptex - base); } }
static void WADList_AddAnimationFrames(const wad_t *wadlist) { int oldcount, i, j; miptex_t name; oldcount = map.nummiptex; for (i = 0; i < oldcount; i++) { if (map.miptex[i][0] != '+') continue; snprintf(name, sizeof(name), "%s", map.miptex[i]); /* Search for all animations (0-9) and alt-animations (A-J) */ for (j = 0; j < 20; j++) { name[1] = (j < 10) ? '0' + j : 'a' + j - 10; if (WADList_FindTexture(wadlist, name)) FindMiptex(name); } } Message(msgStat, "%8d texture frames added", map.nummiptex - oldcount); }
/** * @brief Parses a brush from the map file * @sa FindMiptex * @param[in] mapent The entity the brush to parse belongs to * @param[in] filename The map filename, used to derive the name for the footsteps file */ static void ParseBrush (entity_t* mapent, const char* filename) { int j, k; brush_texture_t td; vec3_t planepts[3]; const int checkOrFix = config.performMapCheck || config.fixMap ; if (nummapbrushes == MAX_MAP_BRUSHES) Sys_Error("nummapbrushes == MAX_MAP_BRUSHES (%i)", nummapbrushes); mapbrush_t* b = &mapbrushes[nummapbrushes]; OBJZERO(*b); b->original_sides = &brushsides[nummapbrushsides]; b->entitynum = num_entities - 1; b->brushnum = nummapbrushes - mapent->firstbrush; do { if (Q_strnull(GetToken())) break; if (*parsedToken == '}') break; if (nummapbrushsides == MAX_MAP_BRUSHSIDES) Sys_Error("nummapbrushsides == MAX_MAP_BRUSHSIDES (%i)", nummapbrushsides); side_t* side = &brushsides[nummapbrushsides]; /* read the three point plane definition */ for (int i = 0; i < 3; i++) { if (i != 0) GetToken(); if (*parsedToken != '(') Sys_Error("parsing brush"); for (j = 0; j < 3; j++) { GetToken(); planepts[i][j] = atof(parsedToken); } GetToken(); if (*parsedToken != ')') Sys_Error("parsing brush"); } /* read the texturedef */ GetToken(); if (strlen(parsedToken) >= MAX_TEXPATH) { if (config.performMapCheck || config.fixMap) Com_Printf(" ");/* hack to make this look like output from Check_Printf() */ Com_Printf("ParseBrush: texture name too long (limit %i): %s\n", MAX_TEXPATH, parsedToken); if (config.fixMap) Sys_Error("Aborting, as -fix is active and saving might corrupt *.map by truncating texture name"); } Q_strncpyz(td.name, parsedToken, sizeof(td.name)); td.shift[0] = atof(GetToken()); td.shift[1] = atof(GetToken()); td.rotate = atof(GetToken()); td.scale[0] = atof(GetToken()); td.scale[1] = atof(GetToken()); /* find default flags and values */ const int mt = FindMiptex(td.name); side->surfaceFlags = td.surfaceFlags = side->contentFlags = td.value = 0; if (TokenAvailable()) { side->contentFlags = atoi(GetToken()); side->surfaceFlags = td.surfaceFlags = atoi(GetToken()); td.value = atoi(GetToken()); } /* if in check or fix mode, let them choose to do this (with command line options), * and then call is made elsewhere */ if (!checkOrFix) { SetImpliedFlags(side, &td, b); /* if no other content flags are set - make this solid */ if (!checkOrFix && side->contentFlags == 0) side->contentFlags = CONTENTS_SOLID; } /* translucent objects are automatically classified as detail and window */ if (side->surfaceFlags & (SURF_BLEND33 | SURF_BLEND66 | SURF_ALPHATEST)) { side->contentFlags |= CONTENTS_DETAIL; side->contentFlags |= CONTENTS_TRANSLUCENT; side->contentFlags |= CONTENTS_WINDOW; side->contentFlags &= ~CONTENTS_SOLID; } if (config.fulldetail) side->contentFlags &= ~CONTENTS_DETAIL; if (!checkOrFix) { if (!(side->contentFlags & ((LAST_VISIBLE_CONTENTS - 1) | CONTENTS_ACTORCLIP | CONTENTS_WEAPONCLIP | CONTENTS_LIGHTCLIP))) side->contentFlags |= CONTENTS_SOLID; /* hints and skips are never detail, and have no content */ if (side->surfaceFlags & (SURF_HINT | SURF_SKIP)) { side->contentFlags = 0; side->surfaceFlags &= ~CONTENTS_DETAIL; } } /* check whether the flags are ok */ CheckFlags(side, b); /* generate a list of textures that should have footsteps when walking on them */ if (mt > 0 && (side->surfaceFlags & SURF_FOOTSTEP)) GenerateFootstepList(filename, mt); GenerateMaterialFile(filename, mt, side); /* find the plane number */ int planenum = PlaneFromPoints(b, planepts[0], planepts[1], planepts[2]); if (planenum == PLANENUM_LEAF) { Com_Printf("Entity %i, Brush %i: plane with no normal\n", b->entitynum, b->brushnum); continue; } for (j = 0; j < 3; j++) VectorCopy(planepts[j], mapplanes[planenum].planeVector[j]); /* see if the plane has been used already */ for (k = 0; k < b->numsides; k++) { const side_t* s2 = b->original_sides + k; if (s2->planenum == planenum) { Com_Printf("Entity %i, Brush %i: duplicate plane\n", b->entitynum, b->brushnum); break; } if (s2->planenum == (planenum ^ 1)) { Com_Printf("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, side->contentFlags & CONTENTS_TERRAIN); side->brush = b; /* save the td off in case there is an origin brush and we * have to recalculate the texinfo */ side_brushtextures[nummapbrushsides] = td; Verb_Printf(VERB_DUMP, "Brush %i Side %i (%f %f %f) (%f %f %f) (%f %f %f) texinfo:%i[%s] plane:%i\n", nummapbrushes, nummapbrushsides, planepts[0][0], planepts[0][1], planepts[0][2], planepts[1][0], planepts[1][1], planepts[1][2], planepts[2][0], planepts[2][1], planepts[2][2], side->texinfo, td.name, planenum); nummapbrushsides++; b->numsides++; } while (1); /* get the content for the entire brush */ b->contentFlags = BrushContents(b); /* copy all set face contentflags to the brush contentflags */ for (int m = 0; m < b->numsides; m++) b->contentFlags |= b->original_sides[m].contentFlags; /* set DETAIL, TRANSLUCENT contentflags on all faces, if they have been set on any. * called separately, if in check/fix mode */ if (!checkOrFix) CheckPropagateParserContentFlags(b); /* allow detail brushes to be removed */ if (config.nodetail && (b->contentFlags & CONTENTS_DETAIL)) { b->numsides = 0; return; } /* allow water brushes to be removed */ if (config.nowater && (b->contentFlags & CONTENTS_WATER)) { b->numsides = 0; return; } /* create windings for sides and bounds for brush */ MakeBrushWindings(b); Verb_Printf(VERB_DUMP, "Brush %i mins (%f %f %f) maxs (%f %f %f)\n", nummapbrushes, b->mbBox.mins[0], b->mbBox.mins[1], b->mbBox.mins[2], b->mbBox.maxs[0], b->mbBox.maxs[1], b->mbBox.maxs[2]); /* origin brushes are removed, but they set * the rotation origin for the rest of the brushes (like func_door) * in the entity. After the entire entity is parsed, the planenums * and texinfos will be adjusted for the origin brush */ if (!checkOrFix && (b->contentFlags & CONTENTS_ORIGIN)) { char string[32]; vec3_t origin; if (num_entities == 1) { Sys_Error("Entity %i, Brush %i: origin brushes not allowed in world" , b->entitynum, b->brushnum); return; } b->mbBox.getCenter(origin); Com_sprintf(string, sizeof(string), "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); SetKeyValue(&entities[b->entitynum], "origin", string); Verb_Printf(VERB_EXTRA, "Entity %i, Brush %i: set origin to %s\n", b->entitynum, b->brushnum, string); VectorCopy(origin, entities[b->entitynum].origin); /* don't keep this brush */ b->numsides = 0; return; } if (!checkOrFix) AddBrushBevels(b); nummapbrushes++; mapent->numbrushes++; }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int TexinfoForBrushTexture(plane_t *plane, brush_texture_t *bt, vec3_t origin) { vec3_t vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; texinfo_t tx, *tc; int i, j, k; float shift[2]; brush_texture_t anim; int mt; if (!bt->name[0]) return 0; memset (&tx, 0, sizeof(tx)); strcpy (tx.texture, bt->name); TextureAxisFromPlane(plane, vecs[0], vecs[1]); shift[0] = DotProduct (origin, vecs[0]); shift[1] = DotProduct (origin, vecs[1]); if (!bt->scale[0]) bt->scale[0] = 1; if (!bt->scale[1]) bt->scale[1] = 1; // rotate axis if (bt->rotate == 0) { sinv = 0 ; cosv = 1; } else if (bt->rotate == 90) { sinv = 1 ; cosv = 0; } else if (bt->rotate == 180) { sinv = 0 ; cosv = -1; } else if (bt->rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = bt->rotate / 180 * Q_PI; sinv = sin(ang); cosv = cos(ang); } if (vecs[0][0]) sv = 0; else if (vecs[0][1]) sv = 1; else sv = 2; if (vecs[1][0]) tv = 0; else if (vecs[1][1]) tv = 1; else tv = 2; for (i=0 ; i<2 ; i++) { ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; } for (i=0 ; i<2 ; i++) for (j=0 ; j<3 ; j++) tx.vecs[i][j] = vecs[i][j] / bt->scale[i]; tx.vecs[0][3] = bt->shift[0] + shift[0]; tx.vecs[1][3] = bt->shift[1] + shift[1]; tx.flags = bt->flags; tx.value = bt->value; // // find the texinfo // tc = texinfo; for (i=0 ; i<numtexinfo ; i++, tc++) { if (tc->flags != tx.flags) continue; if (tc->value != tx.value) continue; for (j=0 ; j<2 ; j++) { if (strcmp (tc->texture, tx.texture)) goto skip; for (k=0 ; k<4 ; k++) { if (tc->vecs[j][k] != tx.vecs[j][k]) goto skip; } } return i; skip:; } *tc = tx; numtexinfo++; // load the next animation mt = FindMiptex (bt->name); if (textureref[mt].animname[0]) { anim = *bt; strcpy (anim.name, textureref[mt].animname); tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin); } else tc->nexttexinfo = -1; return i; } //end of the function TexinfoForBrushTexture
void ParseBrushFace (entity_t *ent, mbrush_t **brushpointer, brushtype_t brushtype) { int i, j, hltexdef, bpface, brushplane; // int facecontents, faceflags, facevalue, q2brushface, q3brushface; vec_t planepts[3][3], t1[3], t2[3], d, rotate, scale[2], vecs[2][4], ang, sinv, cosv, bp[2][3]; mface_t *f, *f2; plane_t plane; texinfo_t tx; mbrush_t *b; if (brushtype == BRUSHTYPE_PATCHDEF2 || brushtype == BRUSHTYPE_PATCHDEF3) return; // read the three point plane definition if (strcmp (token, "(") ) Error ("parsing brush on line %d\n", scriptline); GetToken (false); planepts[0][0] = atof(token); GetToken (false); planepts[0][1] = atof(token); GetToken (false); planepts[0][2] = atof(token); GetToken (false); if (!strcmp(token, ")")) { brushplane = false; GetToken (false); if (strcmp(token, "(")) Error("parsing brush on line %d\n", scriptline); GetToken (false); planepts[1][0] = atof(token); GetToken (false); planepts[1][1] = atof(token); GetToken (false); planepts[1][2] = atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); GetToken (false); if (strcmp(token, "(")) Error("parsing brush on line %d\n", scriptline); GetToken (false); planepts[2][0] = atof(token); GetToken (false); planepts[2][1] = atof(token); GetToken (false); planepts[2][2] = atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); // convert points to a plane VectorSubtract(planepts[0], planepts[1], t1); VectorSubtract(planepts[2], planepts[1], t2); CrossProduct(t1, t2, plane.normal); VectorNormalize(plane.normal); plane.dist = DotProduct(planepts[1], plane.normal); } else { // oh, it's actually a 4 value plane brushplane = true; plane.normal[0] = planepts[0][0]; plane.normal[1] = planepts[0][1]; plane.normal[2] = planepts[0][2]; plane.dist = -atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); } // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); bpface = false; hltexdef = false; if (!strcmp(token, "(")) { // brush primitives, utterly insane bpface = true; // ( GetToken(false); // ( GetToken(false); bp[0][0] = atof(token); GetToken(false); bp[0][1] = atof(token); GetToken(false); bp[0][2] = atof(token); GetToken(false); // ) GetToken(false); // ( GetToken(false); bp[1][0] = atof(token); GetToken(false); bp[1][1] = atof(token); GetToken(false); bp[1][2] = atof(token); GetToken(false); // ) GetToken (false); GetToken (false); tx.miptex = FindMiptex (token); rotate = 0; scale[0] = 1; scale[1] = 1; } else { // if the texture name contains a / then this is a q2/q3 brushface // strip off the path, wads don't use a path on texture names tx.miptex = FindMiptex (token); GetToken (false); if (!strcmp(token, "[")) { hltexdef = true; // S vector GetToken(false); vecs[0][0] = (vec_t)atof(token); GetToken(false); vecs[0][1] = (vec_t)atof(token); GetToken(false); vecs[0][2] = (vec_t)atof(token); GetToken(false); vecs[0][3] = (vec_t)atof(token); // ] GetToken(false); // [ GetToken(false); // T vector GetToken(false); vecs[1][0] = (vec_t)atof(token); GetToken(false); vecs[1][1] = (vec_t)atof(token); GetToken(false); vecs[1][2] = (vec_t)atof(token); GetToken(false); vecs[1][3] = (vec_t)atof(token); // ] GetToken(false); // rotation (unused - implicit in tex coords) GetToken(false); rotate = 0; } else { vecs[0][3] = (vec_t)atof(token); // LordHavoc: float coords GetToken (false); vecs[1][3] = (vec_t)atof(token); // LordHavoc: float coords GetToken (false); rotate = atof(token); // LordHavoc: float coords } GetToken (false); scale[0] = (vec_t)atof(token); // LordHavoc: was already float coords GetToken (false); scale[1] = (vec_t)atof(token); // LordHavoc: was already float coords bp[0][0] = 1; bp[0][1] = 0; bp[0][2] = 0; bp[1][0] = 0; bp[1][1] = 1; bp[1][2] = 0; } // q3 .map properties, currently unused but parsed // facecontents = 0; // faceflags = 0; // facevalue = 0; // q2brushface = false; // q3brushface = false; if (GetToken (false)) { // q2brushface = true; // facecontents = atoi(token); if (GetToken (false)) { // faceflags = atoi(token); if (GetToken (false)) { // q2brushface = false; // q3brushface = true; // facevalue = atoi(token); } } } // skip trailing info (the 3 q3 .map parameters for example) while (GetToken (false)); if (DotProduct(plane.normal, plane.normal) < 0.1) { printf ("WARNING: line %i: brush plane with no normal\n", scriptline); return; } scale[0] = 1.0 / scale[0]; scale[1] = 1.0 / scale[1]; if (bpface) { // calculate proper texture vectors from GTKRadiant/Doom3 brushprimitives matrix float a, ac, as, bc, bs; a = -atan2(plane.normal[2], sqrt(plane.normal[0]*plane.normal[0]+plane.normal[1]*plane.normal[1])); ac = cos(a); as = sin(a); a = atan2(plane.normal[1], plane.normal[0]); bc = cos(a); bs = sin(a); vecs[0][0] = -bs; vecs[0][1] = bc; vecs[0][2] = 0; vecs[1][0] = -as*bc; vecs[1][1] = -as*bs; vecs[1][2] = -ac; tx.vecs[0][0] = bp[0][0] * vecs[0][0] + bp[0][1] * vecs[1][0]; tx.vecs[0][1] = bp[0][0] * vecs[0][1] + bp[0][1] * vecs[1][1]; tx.vecs[0][2] = bp[0][0] * vecs[0][2] + bp[0][1] * vecs[1][2]; tx.vecs[0][3] = bp[0][0] * vecs[0][3] + bp[0][1] * vecs[1][3] + bp[0][2]; tx.vecs[1][0] = bp[1][0] * vecs[0][0] + bp[1][1] * vecs[1][0]; tx.vecs[1][1] = bp[1][0] * vecs[0][1] + bp[1][1] * vecs[1][1]; tx.vecs[1][2] = bp[1][0] * vecs[0][2] + bp[1][1] * vecs[1][2]; tx.vecs[1][3] = bp[1][0] * vecs[0][3] + bp[1][1] * vecs[1][3] + bp[1][2]; } else if (hltexdef) { // HL texture vectors are almost ready to go for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) tx.vecs[i][j] = vecs[i][j] * scale[i]; tx.vecs[i][3] = vecs[i][3] /*+ DotProduct(origin, tx.vecs[i])*/; // Sajt: ripped the commented out bit from the HL compiler code, not really sure what it is exactly doing // 'origin': origin set on bmodel by origin brush or origin key } } else { // fake proper texture vectors from QuakeEd style // texture rotation around the plane normal if (rotate == 0) {sinv = 0;cosv = 1;} else if (rotate == 90) {sinv = 1;cosv = 0;} else if (rotate == 180) {sinv = 0;cosv = -1;} else if (rotate == 270) {sinv = -1;cosv = 0;} else {ang = rotate * (Q_PI / 180);sinv = sin(ang);cosv = cos(ang);} if (fabs(plane.normal[2]) < fabs(plane.normal[0])) { if (fabs(plane.normal[0]) < fabs(plane.normal[1])) { // Y primary VectorSet4(tx.vecs[0], cosv*scale[0], 0, sinv*scale[0], vecs[0][3]); VectorSet4(tx.vecs[1], sinv*scale[1], 0, -cosv*scale[1], vecs[1][3]); } else { // X primary VectorSet4(tx.vecs[0], 0, cosv*scale[0], sinv*scale[0], vecs[0][3]); VectorSet4(tx.vecs[1], 0, sinv*scale[1], -cosv*scale[1], vecs[1][3]); } } else if (fabs(plane.normal[2]) < fabs(plane.normal[1])) { // Y primary VectorSet4(tx.vecs[0], cosv*scale[0], 0, sinv*scale[0], vecs[0][3]); VectorSet4(tx.vecs[1], sinv*scale[1], 0, -cosv*scale[1], vecs[1][3]); } else { // Z primary VectorSet4(tx.vecs[0], cosv*scale[0], sinv*scale[0], 0, vecs[0][3]); VectorSet4(tx.vecs[1], sinv*scale[1], -cosv*scale[1], 0, vecs[1][3]); } //printf("plane + rotate scale = texture vectors:\n(%f %f %f %f) + [%f %f %f] =\n[%f %f %f %f] [%f %f %f %f]\n", plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, rotate, scale[0], scale[1], tx.vecs[0][0], tx.vecs[0][1], tx.vecs[0][2], tx.vecs[0][3], tx.vecs[1][0], tx.vecs[1][1], tx.vecs[1][2], tx.vecs[1][3]); } for (i = 0;i < 2;i++) { for (j = 0;j < 4;j++) { if (tx.vecs[i][j] > -BOGUS_RANGE && tx.vecs[i][j] < BOGUS_RANGE) continue; printf( "WARNING: line %i: corrupt texture mapping vectors, using defaults\n", scriptline); cosv = 1; sinv = 0; scale[0] = 1; scale[1] = 1; vecs[0][3] = 0; vecs[1][3] = 0; if (fabs(plane.normal[2]) < fabs(plane.normal[0])) { if (fabs(plane.normal[0]) < fabs(plane.normal[1])) { // Y primary VectorSet4(tx.vecs[0], cosv*scale[0], 0, sinv*scale[0], vecs[0][3]); VectorSet4(tx.vecs[1], sinv*scale[1], 0, -cosv*scale[1], vecs[1][3]); } else { // X primary VectorSet4(tx.vecs[0], 0, cosv*scale[0], sinv*scale[0], vecs[0][3]); VectorSet4(tx.vecs[1], 0, sinv*scale[1], -cosv*scale[1], vecs[1][3]); } } else if (fabs(plane.normal[2]) < fabs(plane.normal[1])) { // Y primary VectorSet4(tx.vecs[0], cosv*scale[0], 0, sinv*scale[0], vecs[0][3]); VectorSet4(tx.vecs[1], sinv*scale[1], 0, -cosv*scale[1], vecs[1][3]); } else { // Z primary VectorSet4(tx.vecs[0], cosv*scale[0], sinv*scale[0], 0, vecs[0][3]); VectorSet4(tx.vecs[1], sinv*scale[1], -cosv*scale[1], 0, vecs[1][3]); } break; } } /* // LordHavoc: fix for CheckFace: point off plane errors in some maps (most notably QOOLE ones), // and hopefully preventing most 'portal clipped away' warnings VectorNormalize (plane.normal); for (j = 0;j < 3;j++) plane.normal[j] = (Q_rint((vec_t) plane.normal[j] * (vec_t) 8.0)) * (vec_t) (1.0 / 8.0); VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); d = (Q_rint(plane.dist * 8.0)) * (1.0 / 8.0); //if (fabs(d - plane.dist) >= (0.4 / 8.0)) // printf("WARNING: line %i: correcting minor math errors in brushface\n", scriptline); plane.dist = d; */ /* VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); VectorCopy(plane.normal, v); //for (j = 0;j < 3;j++) // v[j] = (Q_rint((vec_t) v[j] * (vec_t) 32.0)) * (vec_t) (1.0 / 32.0); VectorNormalize (v); d = (Q_rint(DotProduct (t3, v) * 8.0)) * (1.0 / 8.0); // if deviation is too high, warn (frequently happens on QOOLE maps) if (fabs(DotProduct(v, plane.normal) - 1.0) > (0.5 / 32.0) || fabs(d - plane.dist) >= (0.25 / 8.0)) printf("WARNING: line %i: minor misalignment of brushface\n" "normal %f %f %f (l: %f d: %f)\n" "rounded to %f %f %f (l: %f d: %f r: %f)\n", scriptline, (vec_t) plane.normal[0], (vec_t) plane.normal[1], (vec_t) plane.normal[2], (vec_t) sqrt(DotProduct(plane.normal, plane.normal)), (vec_t) DotProduct (t3, plane.normal), (vec_t) v[0], (vec_t) v[1], (vec_t) v[2], (vec_t) sqrt(DotProduct(v, v)), (vec_t) DotProduct(t3, v), (vec_t) d); //VectorCopy(v, plane.normal); //plane.dist = d; */ b = *brushpointer; if (b) { if (brushplane) { for (f2 = b->faces ; f2 ;f2=f2->next) if (VectorCompare(plane.normal, f2->plane.normal) && fabs(plane.dist - f2->plane.dist) < ON_EPSILON) break; if (f2) { printf ("WARNING: line %i: brush with duplicate plane\n", scriptline); return; } } else { // if the three points are all on a previous plane, it is a // duplicate plane for (f2 = b->faces ; f2 ; f2=f2->next) { for (i = 0;i < 3;i++) { d = DotProduct(planepts[i],f2->plane.normal) - f2->plane.dist; if (d < -ON_EPSILON || d > ON_EPSILON) break; } if (i==3) break; } if (f2) { printf ("WARNING: line %i: brush with duplicate plane\n", scriptline); return; } } } else { b = &mapbrushes[nummapbrushes]; nummapbrushes++; b->next = ent->brushes; ent->brushes = b; b->scriptline = scriptline; *brushpointer = b; } f = qmalloc(sizeof(mface_t)); f->next = b->faces; b->faces = f; f->scriptline = scriptline; f->plane = plane; f->texinfo = FindTexinfo (&tx); nummapbrushfaces++; }
/* ================= ParseBrush ================= */ void ParseBrush (void) { mbrush_t *b; mface_t *f, *f2; vec3_t planepts[3]; vec3_t t1, t2, t3; int i,j; texinfo_t tx; vec_t d; float shift[2], rotate, scale[2]; b = &mapbrushes[nummapbrushes]; nummapbrushes++; b->next = mapent->brushes; mapent->brushes = b; do { if (!GetToken (true)) break; if (!strcmp (token, "}") ) break; // read the three point plane definition for (i=0 ; i<3 ; i++) { if (i != 0) GetToken (true); if (strcmp (token, "(") ) Error ("parsing brush"); for (j=0 ; j<3 ; j++) { GetToken (false); planepts[i][j] = atof(token); // LordHavoc: float coords } GetToken (false); if (strcmp (token, ")") ) Error ("parsing brush"); } fflush(stdout); // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); tx.miptex = FindMiptex (token); GetToken (false); shift[0] = atof(token); // LordHavoc: float coords GetToken (false); shift[1] = atof(token); // LordHavoc: float coords GetToken (false); rotate = atof(token); // LordHavoc: float coords GetToken (false); scale[0] = atof(token); // LordHavoc: was already float coords GetToken (false); scale[1] = atof(token); // LordHavoc: was already float coords // if the three points are all on a previous plane, it is a // duplicate plane for (f2 = b->faces ; f2 ; f2=f2->next) { for (i=0 ; i<3 ; i++) { d = DotProduct(planepts[i],f2->plane.normal) - f2->plane.dist; if (d < -ON_EPSILON || d > ON_EPSILON) break; } if (i==3) break; } if (f2) { printf ("WARNING: brush with duplicate plane\n"); continue; } f = malloc(sizeof(mface_t)); f->next = b->faces; b->faces = f; // convert to a vector / dist plane for (j=0 ; j<3 ; j++) { t1[j] = planepts[0][j] - planepts[1][j]; t2[j] = planepts[2][j] - planepts[1][j]; t3[j] = planepts[1][j]; } CrossProduct(t1,t2, f->plane.normal); if (VectorCompare (f->plane.normal, vec3_origin)) { printf ("WARNING: brush plane with no normal\n"); b->faces = f->next; free (f); break; } VectorNormalize (f->plane.normal); f->plane.dist = DotProduct (t3, f->plane.normal); // // fake proper texture vectors from QuakeEd style // { vec3_t vecs[2]; int sv, tv; float ang, sinv, cosv; float ns, nt; TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]); if (!scale[0]) scale[0] = 1; if (!scale[1]) scale[1] = 1; // rotate axis if (rotate == 0) { sinv = 0 ; cosv = 1; } else if (rotate == 90) { sinv = 1 ; cosv = 0; } else if (rotate == 180) { sinv = 0 ; cosv = -1; } else if (rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = rotate / 180 * Q_PI; sinv = sin(ang); cosv = cos(ang); } if (vecs[0][0]) sv = 0; else if (vecs[0][1]) sv = 1; else sv = 2; if (vecs[1][0]) tv = 0; else if (vecs[1][1]) tv = 1; else tv = 2; for (i=0 ; i<2 ; i++) { ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; } for (i=0 ; i<2 ; i++) for (j=0 ; j<3 ; j++) tx.vecs[i][j] = vecs[i][j] / scale[i]; tx.vecs[0][3] = shift[0]; tx.vecs[1][3] = shift[1]; } // unique the texinfo f->texinfo = FindTexinfo (&tx); } while (1); }
// ===================================================================================== // TexinfoForBrushTexture // ===================================================================================== int TexinfoForBrushTexture(const plane_t* const plane, brush_texture_t* bt, const vec3_t origin) { vec3_t vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; texinfo_t tx; texinfo_t* tc; int i, j, k; memset(&tx, 0, sizeof(tx)); if(!strncmp(bt->name,"BEVEL",5)) { tx.flags |= TEX_BEVEL; safe_strncpy(bt->name,"NULL",5); } tx.miptex = FindMiptex(bt->name); // Note: FindMiptex() still needs to be called here to add it to the global miptex array // Very Sleazy Hack 104 - since the tx.miptex index will be bogus after we sort the miptex array later // Put the string name of the miptex in this "index" until after we are done sorting it in WriteMiptex(). tx.miptex = texmap64_store(strdup(bt->name)); // set the special flag if (bt->name[0] == '*' || !strncasecmp(bt->name, "sky", 3) // ===================================================================================== //Cpt_Andrew - Env_Sky Check // ===================================================================================== || !strncasecmp(bt->name, "env_sky", 5) // ===================================================================================== || !strncasecmp(bt->name, "clip", 4) || !strncasecmp(bt->name, "origin", 6) #ifdef ZHLT_NULLTEX // AJM || !strncasecmp(bt->name, "null", 4) #endif || !strncasecmp(bt->name, "aaatrigger", 10) ) { tx.flags |= TEX_SPECIAL; } if (bt->txcommand) { memcpy(tx.vecs, bt->vects.quark.vects, sizeof(tx.vecs)); if (origin[0] || origin[1] || origin[2]) { tx.vecs[0][3] += DotProduct(origin, tx.vecs[0]); tx.vecs[1][3] += DotProduct(origin, tx.vecs[1]); } } else { if (g_nMapFileVersion < 220) { TextureAxisFromPlane(plane, vecs[0], vecs[1]); } if (!bt->vects.valve.scale[0]) { bt->vects.valve.scale[0] = 1; } if (!bt->vects.valve.scale[1]) { bt->vects.valve.scale[1] = 1; } if (g_nMapFileVersion < 220) { // rotate axis if (bt->vects.valve.rotate == 0) { sinv = 0; cosv = 1; } else if (bt->vects.valve.rotate == 90) { sinv = 1; cosv = 0; } else if (bt->vects.valve.rotate == 180) { sinv = 0; cosv = -1; } else if (bt->vects.valve.rotate == 270) { sinv = -1; cosv = 0; } else { ang = bt->vects.valve.rotate / 180 * Q_PI; sinv = sin(ang); cosv = cos(ang); } if (vecs[0][0]) { sv = 0; } else if (vecs[0][1]) { sv = 1; } else { sv = 2; } if (vecs[1][0]) { tv = 0; } else if (vecs[1][1]) { tv = 1; } else { tv = 2; } for (i = 0; i < 2; i++) { ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; } for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { tx.vecs[i][j] = vecs[i][j] / bt->vects.valve.scale[i]; } } } else { vec_t scale; scale = 1 / bt->vects.valve.scale[0]; VectorScale(bt->vects.valve.UAxis, scale, tx.vecs[0]); scale = 1 / bt->vects.valve.scale[1]; VectorScale(bt->vects.valve.VAxis, scale, tx.vecs[1]); } tx.vecs[0][3] = bt->vects.valve.shift[0] + DotProduct(origin, tx.vecs[0]); tx.vecs[1][3] = bt->vects.valve.shift[1] + DotProduct(origin, tx.vecs[1]); } // // find the g_texinfo // ThreadLock(); tc = g_texinfo; for (i = 0; i < g_numtexinfo; i++, tc++) { // Sleazy hack 104, Pt 3 - Use strcmp on names to avoid dups if (strcmp(texmap64_retrieve((tc->miptex)), texmap64_retrieve((tx.miptex))) != 0) { continue; } if (tc->flags != tx.flags) { continue; } for (j = 0; j < 2; j++) { for (k = 0; k < 4; k++) { if (tc->vecs[j][k] != tx.vecs[j][k]) { goto skip; } } } ThreadUnlock(); return i; skip:; } hlassume(g_numtexinfo < MAX_MAP_TEXINFO, assume_MAX_MAP_TEXINFO); *tc = tx; g_numtexinfo++; ThreadUnlock(); return i; }
/* ================= ParseBrush ================= */ void ParseBrush (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]; if (nummapbrushes == MAX_MAP_BRUSHES) Error ("nummapbrushes == MAX_MAP_BRUSHES"); b = &mapbrushes[nummapbrushes]; b->original_sides = &brushsides[nummapbrushsides]; b->entitynum = num_entities-1; b->brushnum = nummapbrushes - mapent->firstbrush; do { if (!GetToken (true)) break; if (!strcmp (token, "}") ) break; if (nummapbrushsides == MAX_MAP_BRUSHSIDES) Error ("MAX_MAP_BRUSHSIDES"); side = &brushsides[nummapbrushsides]; // read the three point plane definition for (i=0 ; i<3 ; i++) { if (i != 0) GetToken (true); if (strcmp (token, "(") ) Error ("parsing brush"); for (j=0 ; j<3 ; j++) { GetToken (false); planepts[i][j] = atoi(token); } GetToken (false); if (strcmp (token, ")") ) Error ("parsing brush"); } // // read the texturedef // GetToken (false); strcpy (td.name, token); GetToken (false); td.shift[0] = atoi(token); GetToken (false); td.shift[1] = atoi(token); GetToken (false); td.rotate = atoi(token); GetToken (false); td.scale[0] = atof(token); GetToken (false); td.scale[1] = atof(token); // 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; if (TokenAvailable()) { GetToken (false); side->contents = atoi(token); GetToken (false); side->surf = td.flags = atoi(token); GetToken (false); td.value = atoi(token); } // 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; } // // find the plane number // planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]); if (planenum == -1) { printf ("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) { printf ("Entity %i, Brush %i: duplicate plane\n" , b->entitynum, b->brushnum); break; } if ( s2->planenum == (planenum^1) ) { printf ("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 = BrushContents (b); // 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++; }
void ParseBrushFace (entity_t *ent, mbrush_t **brushpointer, brushtype_t brushtype) { int i, j, sv, tv, hltexdef, facecontents, faceflags, facevalue, q2brushface, q3brushface, bpface; vec_t planepts[3][3], t1[3], t2[3], d, rotate, scale[2], vecs[2][4], ang, sinv, cosv, ns, nt, bp[2][3]; mface_t *f, *f2; plane_t plane; texinfo_t tx; mbrush_t *b; if (brushtype == BRUSHTYPE_PATCHDEF2 || brushtype == BRUSHTYPE_PATCHDEF3) return; // read the three point plane definition if (strcmp (token, "(") ) Error ("parsing brush on line %d\n", scriptline); GetToken (false); planepts[0][0] = atof(token); GetToken (false); planepts[0][1] = atof(token); GetToken (false); planepts[0][2] = atof(token); GetToken (false); if (!strcmp(token, ")")) { GetToken (false); if (strcmp(token, "(")) Error("parsing brush on line %d\n", scriptline); GetToken (false); planepts[1][0] = atof(token); GetToken (false); planepts[1][1] = atof(token); GetToken (false); planepts[1][2] = atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); GetToken (false); if (strcmp(token, "(")) Error("parsing brush on line %d\n", scriptline); GetToken (false); planepts[2][0] = atof(token); GetToken (false); planepts[2][1] = atof(token); GetToken (false); planepts[2][2] = atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); // convert points to a plane VectorSubtract(planepts[0], planepts[1], t1); VectorSubtract(planepts[2], planepts[1], t2); CrossProduct(t1, t2, plane.normal); VectorNormalize(plane.normal); plane.dist = DotProduct(planepts[1], plane.normal); } else { // oh, it's actually a 4 value plane plane.normal[0] = planepts[0][0]; plane.normal[1] = planepts[0][1]; plane.normal[2] = planepts[0][2]; plane.dist = -atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); } // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); bpface = false; hltexdef = false; if (!strcmp(token, "(")) { // brush primitives, utterly insane bpface = true; // ( GetToken(false); // ( GetToken(false); bp[0][0] = atof(token); GetToken(false); bp[0][1] = atof(token); GetToken(false); bp[0][2] = atof(token); GetToken(false); // ) GetToken(false); // ( GetToken(false); bp[1][0] = atof(token); GetToken(false); bp[1][1] = atof(token); GetToken(false); bp[1][2] = atof(token); GetToken(false); // ) GetToken (false); GetToken (false); tx.miptex = FindMiptex (token); rotate = 0; scale[0] = 1; scale[1] = 1; } else { // if the texture name contains a / then this is a q2/q3 brushface // strip off the path, wads don't use a path on texture names tx.miptex = FindMiptex (token); GetToken (false); if (!strcmp(token, "[")) { hltexdef = true; // S vector GetToken(false); vecs[0][0] = (vec_t)atof(token); GetToken(false); vecs[0][1] = (vec_t)atof(token); GetToken(false); vecs[0][2] = (vec_t)atof(token); GetToken(false); vecs[0][3] = (vec_t)atof(token); // ] GetToken(false); // [ GetToken(false); // T vector GetToken(false); vecs[1][0] = (vec_t)atof(token); GetToken(false); vecs[1][1] = (vec_t)atof(token); GetToken(false); vecs[1][2] = (vec_t)atof(token); GetToken(false); vecs[1][3] = (vec_t)atof(token); // ] GetToken(false); // rotation (unused - implicit in tex coords) GetToken(false); rotate = 0; } else { vecs[0][3] = (vec_t)atof(token); // LordHavoc: float coords GetToken (false); vecs[1][3] = (vec_t)atof(token); // LordHavoc: float coords GetToken (false); rotate = atof(token); // LordHavoc: float coords } GetToken (false); scale[0] = (vec_t)atof(token); // LordHavoc: was already float coords GetToken (false); scale[1] = (vec_t)atof(token); // LordHavoc: was already float coords } // q3 .map properties, currently unused but parsed facecontents = 0; faceflags = 0; facevalue = 0; q2brushface = false; q3brushface = false; if (GetToken (false)) { q2brushface = true; facecontents = atoi(token); if (GetToken (false)) { faceflags = atoi(token); if (GetToken (false)) { q2brushface = false; q3brushface = true; facevalue = atoi(token); } } } // skip trailing info (the 3 q3 .map parameters for example) while (GetToken (false)); if (DotProduct(plane.normal, plane.normal) < 0.1) { printf ("WARNING: brush plane with no normal on line %d\n", scriptline); return; } if (bpface) { // fake proper texture vectors from QuakeEd style TextureAxisFromPlane(&plane, vecs[0], vecs[1], true); // FIXME: deal with the bp stuff here printf("warning: brush primitive texturing not yet supported (line %d)\n", scriptline); // generic texturing tx.vecs[0][0] = vecs[0][0]; tx.vecs[0][1] = vecs[0][1]; tx.vecs[0][2] = vecs[0][2]; tx.vecs[0][3] = vecs[0][3]; tx.vecs[1][0] = vecs[1][0]; tx.vecs[1][1] = vecs[1][1]; tx.vecs[1][2] = vecs[1][2]; tx.vecs[1][3] = vecs[1][3]; } else { if (hltexdef) { for (i = 0; i < 2; i++) { d = 1.0 / (scale[i] ? scale[i] : 1.0); for (j = 0; j < 3; j++) tx.vecs[i][j] = vecs[i][j] * d; tx.vecs[i][3] = vecs[i][3] /*+ DotProduct(origin, tx.vecs[i])*/; // Sajt: ripped the commented out bit from the HL compiler code, not really sure what it is exactly doing // 'origin': origin set on bmodel by origin brush or origin key } } else { // fake proper texture vectors from QuakeEd style TextureAxisFromPlane(&plane, vecs[0], vecs[1], q3brushface); // rotate axis if (rotate == 0) {sinv = 0;cosv = 1;} else if (rotate == 90) {sinv = 1;cosv = 0;} else if (rotate == 180) {sinv = 0;cosv = -1;} else if (rotate == 270) {sinv = -1;cosv = 0;} else {ang = rotate * (Q_PI / 180);sinv = sin(ang);cosv = cos(ang);} // LordHavoc: I don't quite understand this for (sv = 0;sv < 2 && !vecs[0][sv];sv++); for (tv = 0;tv < 2 && !vecs[1][tv];tv++); for (i = 0;i < 2;i++) { // rotate ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; // scale and store into texinfo d = 1.0 / (scale[i] ? scale[i] : 1.0); for (j = 0;j < 3;j++) tx.vecs[i][j] = vecs[i][j] * d; tx.vecs[i][3] = vecs[i][3]; } } } /* // LordHavoc: fix for CheckFace: point off plane errors in some maps (most notably QOOLE ones), // and hopefully preventing most 'portal clipped away' warnings VectorNormalize (plane.normal); for (j = 0;j < 3;j++) plane.normal[j] = (Q_rint((vec_t) plane.normal[j] * (vec_t) 8.0)) * (vec_t) (1.0 / 8.0); VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); d = (Q_rint(plane.dist * 8.0)) * (1.0 / 8.0); //if (fabs(d - plane.dist) >= (0.4 / 8.0)) // printf("WARNING: correcting minor math errors in brushface on line %d\n", scriptline); plane.dist = d; */ /* VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); VectorCopy(plane.normal, v); //for (j = 0;j < 3;j++) // v[j] = (Q_rint((vec_t) v[j] * (vec_t) 32.0)) * (vec_t) (1.0 / 32.0); VectorNormalize (v); d = (Q_rint(DotProduct (t3, v) * 8.0)) * (1.0 / 8.0); // if deviation is too high, warn (frequently happens on QOOLE maps) if (fabs(DotProduct(v, plane.normal) - 1.0) > (0.5 / 32.0) || fabs(d - plane.dist) >= (0.25 / 8.0)) printf("WARNING: minor misalignment of brushface on line %d\n" "normal %f %f %f (l: %f d: %f)\n" "rounded to %f %f %f (l: %f d: %f r: %f)\n", scriptline, (vec_t) plane.normal[0], (vec_t) plane.normal[1], (vec_t) plane.normal[2], (vec_t) sqrt(DotProduct(plane.normal, plane.normal)), (vec_t) DotProduct (t3, plane.normal), (vec_t) v[0], (vec_t) v[1], (vec_t) v[2], (vec_t) sqrt(DotProduct(v, v)), (vec_t) DotProduct(t3, v), (vec_t) d); //VectorCopy(v, plane.normal); //plane.dist = d; */ b = *brushpointer; if (b) { // if the three points are all on a previous plane, it is a // duplicate plane for (f2 = b->faces ; f2 ; f2=f2->next) { for (i = 0;i < 3;i++) { d = DotProduct(planepts[i],f2->plane.normal) - f2->plane.dist; if (d < -ON_EPSILON || d > ON_EPSILON) break; } if (i==3) break; } if (f2) { printf ("WARNING: brush with duplicate plane (first point is at %g %g %g, .map file line number %d)\n", planepts[0][0], planepts[0][1], planepts[0][2], scriptline); return; } } else { b = &mapbrushes[nummapbrushes]; nummapbrushes++; b->next = ent->brushes; ent->brushes = b; *brushpointer = b; } f = qmalloc(sizeof(mface_t)); f->next = b->faces; b->faces = f; f->plane = plane; f->texinfo = FindTexinfo (&tx); nummapbrushfaces++; }
/* ================= 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++; }
/* ================= ParseBrush ================= */ void ParseBrush (entity_t *mapent) { char *tl; mapbrush_t *b; int i,j, k; int mt; side_t *side, *s2; int planenum; brush_texture_t td; float planepts[3][3]; qboolean phongShading; MarkBrushBegin(); if (nummapbrushes == MAX_MAP_BRUSHES) Error ("nummapbrushes == MAX_MAP_BRUSHES"); b = &mapbrushes[nummapbrushes]; b->original_sides = &brushsides[nummapbrushsides]; b->entitynum = num_entities-1; b->brushnum = nummapbrushes - mapent->firstbrush; // Knightmare added b->optimizedDetail = false; b->isTerrain = (!strcmp("func_group", ValueForKey (&entities[b->entitynum], "classname")) && strlen(ValueForKey (&entities[b->entitynum], "terrain")) > 0); b->isGenSurf = (!strcmp("func_group", ValueForKey (&entities[b->entitynum], "classname")) && strlen(ValueForKey (&entities[b->entitynum], "gensurf")) > 0); phongShading = (!strcmp("func_group", ValueForKey (&entities[b->entitynum], "classname")) && strlen(ValueForKey (&entities[b->entitynum], "phongshading")) > 0); //if (b->isTerrain) // printf ("Brush number %i in enitity number %i has terrain flag set.\n", b->brushnum, b->entitynum); //if (b->phongShading) // printf ("Brush number %i in enitity number %i has phong shading flag set.\n", b->brushnum, b->entitynum); if (verbosebrushes) printf ("enitity %i, brush %i\n", b->entitynum, b->brushnum); // end Knightmare do { if (!GetToken (true)) break; if (!strcmp (token, "}") ) break; if (nummapbrushsides == MAX_MAP_BRUSHSIDES) Error ("MAX_MAP_BRUSHSIDES"); side = &brushsides[nummapbrushsides]; // read the three point plane definition for (i=0 ; i<3 ; i++) { if (i != 0) GetToken (true); if (strcmp (token, "(") ) Error ("parsing brush\n Brush: %s", i+1, brush_info); for (j=0 ; j<3 ; j++) { GetToken (false); planepts[i][j] = atof(token); } GetToken (false); if (strcmp (token, ")") ) Error ("parsing brush\n Brush: %s", i+1, brush_info); } // // read the texturedef // GetToken (false); strcpy (td.name, token); tl = td.name; for(tl = td.name; *tl != 0; tl++) *tl = tolower(*tl); GetToken (false); td.shift[0] = atoi(token); GetToken (false); td.shift[1] = atoi(token); GetToken (false); td.rotate = atoi(token); GetToken (false); td.scale[0] = atof(token); GetToken (false); td.scale[1] = atof(token); // 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; if (TokenAvailable()) { GetToken (false); side->contents = atoi(token); GetToken (false); side->surf = td.flags = atoi(token); GetToken (false); td.value = atoi(token); } // translucent objects are automatically classified as detail if (side->surf & (SURF_TRANS33|SURF_TRANS66|SURF_ALPHATEST) ) // Knightmare- added alphatest 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; side->contents &= CONTENTS_DETAIL; // allow only detail content- Geoffery DeWan? } // // find the plane number // planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]); if (planenum == -1) { printf ("Entity %i, Brush %i: plane with no normal\n Brush: %s\n" , b->entitynum, b->brushnum, brush_info); 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) { printf ("Entity %i, Brush %i: duplicate plane\n Brush: %s\n" , b->entitynum, b->brushnum, brush_info); break; } if ( s2->planenum == (planenum^1) ) { printf ("Entity %i, Brush %i: mirrored plane\n Brush: %s\n" , b->entitynum, b->brushnum, brush_info); 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, b->isTerrain); // Knightmare added // 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 = BrushContents (b); // 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; } // Knightmare- check if this is an optimized detail brush (has caulk faces) // also exclude trans brushes and terrain if ((b->contents & CONTENTS_DETAIL) && (b->contents & CONTENTS_SOLID) && !b->isTerrain && !b->isGenSurf) for (i=0; i<b->numsides; i++) { if ( !strcmp(texinfo[b->original_sides[i].texinfo].texture, "system/caulk") || !strcmp(texinfo[b->original_sides[i].texinfo].texture, "common/caulk") ) { b->optimizedDetail = true; //printf ("Entity %i, Brush %i: optimized detail\n", b->entitynum, b->brushnum); break; } } // Knightmare- special handling for terrain brushes if (b->isTerrain || b->isGenSurf || phongShading) for (i=0; i<b->numsides; i++) { s2 = &b->original_sides[i]; // set ArghRad phong shading value (because EasyGen/GTKGenSurf doesn't allow this) if (strcmp(texinfo[b->original_sides[i].texinfo].texture, "system/caulk") && strcmp(texinfo[b->original_sides[i].texinfo].texture, "common/caulk")) { texinfo[s2->texinfo].value = 777 + b->entitynum; // lucky 7's texinfo[s2->texinfo].flags &= ~SURF_LIGHT; // must not be light-emitting } } // create windings for sides and bounds for brush // MEM_LEAK MakeBrushWindings (b); t_w = b->original_sides[0].winding; // 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\n BrushL %s", b->entitynum, b->brushnum, brush_info); 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++; }
// ===================================================================================== // WriteMiptex // ===================================================================================== void WriteMiptex() { int len, texsize, totaltexsize = 0; byte* data; dmiptexlump_t* l; double start, end; g_texdatasize = 0; start = I_FloatTime(); { if (!TEX_InitFromWad()) return; AddAnimatingTextures(); } end = I_FloatTime(); Verbose("TEX_InitFromWad & AddAnimatingTextures elapsed time = %ldms\n", (long)(end - start)); start = I_FloatTime(); { int i; for (i = 0; i < nummiptex; i++) { lumpinfo_t* found; found = FindTexture(miptex + i); if (found) { miptex[i] = *found; } else { miptex[i].iTexFile = miptex[i].filepos = miptex[i].disksize = 0; } } } end = I_FloatTime(); Verbose("FindTextures elapsed time = %ldms\n", (long)(end - start)); start = I_FloatTime(); { int i; texinfo_t* tx = g_texinfo; // Sort them FIRST by wadfile and THEN by name for most efficient loading in the engine. qsort((void*)miptex, (size_t) nummiptex, sizeof(miptex[0]), lump_sorter_by_wad_and_name); // Sleazy Hack 104 Pt 2 - After sorting the miptex array, reset the texinfos to point to the right miptexs for (i = 0; i < g_numtexinfo; i++, tx++) { char* miptex_name = texmap64_retrieve(tx->miptex); tx->miptex = FindMiptex(miptex_name); // Free up the originally strdup()'ed miptex_name free(miptex_name); } } end = I_FloatTime(); Verbose("qsort(miptex) elapsed time = %ldms\n", (long)(end - start)); start = I_FloatTime(); { int i; // Now setup to get the miptex data (or just the headers if using -wadtextures) from the wadfile l = (dmiptexlump_t*)g_dtexdata; data = (byte*) & l->dataofs[nummiptex]; l->nummiptex = nummiptex; for (i = 0; i < nummiptex; i++) { l->dataofs[i] = data - (byte*) l; len = LoadLump(miptex + i, data, &texsize); if (!len) { l->dataofs[i] = -1; // didn't find the texture } else { totaltexsize += texsize; hlassume(totaltexsize < g_max_map_miptex, assume_MAX_MAP_MIPTEX); } data += len; } g_texdatasize = data - g_dtexdata; } end = I_FloatTime(); Log("Texture usage is at %1.2f mb (of %1.2f mb MAX)\n", (float)totaltexsize / (1024 * 1024), (float)g_max_map_miptex / (1024 * 1024)); Verbose("LoadLump() elapsed time = %ldms\n", (long)(end - start)); }
/* ================= ParseBrush ================= */ void ParseBrush (void) { mbrush_t *b; mface_t *f, *f2; vec3_t planepts[3]; vec3_t t1, t2, t3, VAxis[2]; int i, j, Faces; texinfo_t tx; vec_t d; vec_t shift[2], rotate, scale[2]; qboolean ok, Valve220; ExtendArray(mapbrushes, nummapbrushes); b = &mapbrushes[nummapbrushes]; b->Line = scriptline; ok = GetToken (true); while (ok) { txcommand = 0; if (!strcmp (token, "}") ) { if (!options.onlyents) { if (InvalidBrush(b, &Faces)) { // Too few faces in brush or not closed; drop it DropBrush (b); nummapfaces -= Faces; // Note: texinfo array is not corrected here return; } } if (options.SortFace) SortFaces(b); break; } // read the three point plane definition for (i=0 ; i<3 ; i++) { if (i != 0) GetToken (true); if (strcmp (token, "(") ) Message (MSGERR, "Invalid brush plane format on line %d", scriptline); for (j=0 ; j<3 ; j++) { GetToken (false); planepts[i][j] = atof(token); // AR: atof } GetToken (false); if (strcmp (token, ")") ) Message (MSGERR, "Invalid brush plane format on line %d", scriptline); } // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); if (options.Q2Map) Q2ToQ1Tex (token); // Check texture name length if (strlen(token) > sizeof(char16) - 1) Message (MSGERR, "Texture name \"%s\" too long on line %d", token, scriptline); if (options.SolidMap && num_entities == 1 && token[0] == '*' || options.noents && num_entities > 1) { // No liquid worldbrushes or only worldbrushes allowed; drop brush DropBrush (b); while (GetToken(true) && strcmp(token, "}")) ; return; } Valve220 = false; tx.miptex = FindMiptex (token); GetToken (false); if (!strcmp (token, "[")) { // Valve 220 map import Valve220 = true; GetValveTex (VAxis[0]); } shift[0] = atoi(token); GetToken (false); if (Valve220) { // Skip ] GetToken (false); GetValveTex (VAxis[1]); } shift[1] = atoi(token); GetToken (false); if (Valve220) GetToken (false); // Skip ] rotate = atoi(token); GetToken (false); scale[0] = atof(token); GetToken (false); scale[1] = atof(token); if (options.Q2Map) { // Skip extra Q2 style face info GetToken (false); GetToken (false); GetToken (false); } ok = GetToken (true); // Note : scriptline normally gets advanced here // if the three points are all on a previous plane, it is a // duplicate plane for (f2 = b->faces ; f2 ; f2=f2->next) { for (i=0 ; i<3 ; i++) { d = DotProduct(planepts[i],f2->plane.normal) - f2->plane.dist; if (d < -ON_EPSILON || d > ON_EPSILON) break; } if (i==3) break; } if (f2) { Message (MSGWARN, "Brush with duplicate plane on line %d", scriptline - 1); continue; } f = AllocOther(sizeof(mface_t)); // convert to a vector / dist plane for (j=0 ; j<3 ; j++) { t1[j] = planepts[0][j] - planepts[1][j]; t2[j] = planepts[2][j] - planepts[1][j]; t3[j] = planepts[1][j]; } CrossProduct(t1,t2, f->plane.normal); if (VectorCompare (f->plane.normal, vec3_origin)) { Message (MSGWARN, "Brush plane with no normal on line %d", scriptline - 1); FreeOther (f); continue; } VectorNormalize (f->plane.normal); f->plane.dist = DotProduct (t3, f->plane.normal); f->next = b->faces; b->faces = f; if (txcommand=='1' || txcommand=='2') { // from QuArK, the texture vectors are given directly from the three points vec3_t TexPt[2]; int k; vec_t dot22, dot23, dot33, mdet, aa, bb, dd; k = txcommand-'0'; for (j=0; j<3; j++) TexPt[1][j] = (planepts[k][j] - planepts[0][j]) * ScaleCorrection; k = 3-k; for (j=0; j<3; j++) TexPt[0][j] = (planepts[k][j] - planepts[0][j]) * ScaleCorrection; dot22 = DotProduct (TexPt[0], TexPt[0]); dot23 = DotProduct (TexPt[0], TexPt[1]); dot33 = DotProduct (TexPt[1], TexPt[1]); mdet = dot22*dot33-dot23*dot23; if (mdet<1E-6 && mdet>-1E-6) { aa = bb = dd = 0; Message (MSGWARN, "Degenerate QuArK-style brush texture on line %d", scriptline - 1); } else { mdet = 1.0/mdet; aa = dot33*mdet; bb = -dot23*mdet; //cc = -dot23*mdet; // cc = bb dd = dot22*mdet; } for (j=0; j<3; j++) { tx.vecs[0][j] = aa * TexPt[0][j] + bb * TexPt[1][j]; tx.vecs[1][j] = -(/*cc*/ bb * TexPt[0][j] + dd * TexPt[1][j]); } tx.vecs[0][3] = -DotProduct(tx.vecs[0], planepts[0]); tx.vecs[1][3] = -DotProduct(tx.vecs[1], planepts[0]); } else if (Valve220) { // Valve 220 texturedef vec3_t vec; vec_t tscale; // Prevent division by zero if (!scale[0]) scale[0] = 1; if (!scale[1]) scale[1] = 1; // FIXME: If origin brushes are in use, this is where to fix their tex alignment!!! for (i = 0; i < 2; ++i) { tscale = 1 / scale[i]; VectorScale(VAxis[i], tscale, vec); for (j = 0; j < 3; ++j) tx.vecs[i][j] = (float)vec[j]; tx.vecs[i][3] = (float)shift[i] + DotProduct(vec3_origin, vec); } } else // // fake proper texture vectors from QuakeEd style // { vec3_t vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]); if (!scale[0]) scale[0] = 1; if (!scale[1]) scale[1] = 1; // rotate axis if (rotate == 0) { sinv = 0 ; cosv = 1; } else if (rotate == 90) { sinv = 1 ; cosv = 0; } else if (rotate == 180) { sinv = 0 ; cosv = -1; } else if (rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = rotate / 180 * Q_PI; sinv = sin(ang); cosv = cos(ang); } if (vecs[0][0]) sv = 0; else if (vecs[0][1]) sv = 1; else sv = 2; if (vecs[1][0]) tv = 0; else if (vecs[1][1]) tv = 1; else tv = 2; for (i=0 ; i<2 ; i++) { ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; } for (i=0 ; i<2 ; i++) for (j=0 ; j<3 ; j++) tx.vecs[i][j] = vecs[i][j] / scale[i]; tx.vecs[0][3] = shift[0]; tx.vecs[1][3] = shift[1]; } // unique the texinfo f->texinfo = FindTexinfo (&tx); nummapfaces++; }; nummapbrushes++; b->next = mapent->brushes; mapent->brushes = b; }
/* ================= ParseBrush ================= */ void ParseBrush (void) { int i, j, sv, tv, hltexdef; vec_t planepts[3][3], t1[3], t2[3], d, rotate, scale[2], vecs[2][4], ang, sinv, cosv, ns, nt; mbrush_t *b; mface_t *f, *f2; plane_t plane; texinfo_t tx; b = &mapbrushes[nummapbrushes]; nummapbrushes++; b->next = mapent->brushes; mapent->brushes = b; do { if (!GetToken (true)) break; if (!strcmp (token, "}") ) break; // read the three point plane definition for (i = 0;i < 3;i++) { if (i != 0) GetToken (true); if (strcmp (token, "(") ) Error ("parsing brush on line %d\n", scriptline); for (j = 0;j < 3;j++) { GetToken (false); planepts[i][j] = atof(token); // LordHavoc: float coords } GetToken (false); if (strcmp (token, ")") ) Error ("parsing brush on line %d\n", scriptline); } //fflush(stdout); // convert points to a plane VectorSubtract(planepts[0], planepts[1], t1); VectorSubtract(planepts[2], planepts[1], t2); CrossProduct(t1, t2, plane.normal); VectorNormalize(plane.normal); plane.dist = DotProduct(planepts[1], plane.normal); // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); tx.miptex = FindMiptex (token); GetToken (false); if ((hltexdef = !strcmp(token, "["))) { // S vector GetToken(false); vecs[0][0] = atof(token); GetToken(false); vecs[0][1] = atof(token); GetToken(false); vecs[0][2] = atof(token); GetToken(false); vecs[0][3] = atof(token); // ] GetToken(false); // [ GetToken(false); // T vector GetToken(false); vecs[1][0] = atof(token); GetToken(false); vecs[1][1] = atof(token); GetToken(false); vecs[1][2] = atof(token); GetToken(false); vecs[1][3] = atof(token); // ] GetToken(false); } else { vecs[0][3] = atof(token); // LordHavoc: float coords GetToken (false); vecs[1][3] = atof(token); // LordHavoc: float coords } GetToken (false); rotate = atof(token); // LordHavoc: float coords GetToken (false); scale[0] = atof(token); // LordHavoc: was already float coords GetToken (false); scale[1] = atof(token); // LordHavoc: was already float coords // if the three points are all on a previous plane, it is a // duplicate plane for (f2 = b->faces ; f2 ; f2=f2->next) { for (i = 0;i < 3;i++) { d = DotProduct(planepts[i],f2->plane.normal) - f2->plane.dist; if (d < -ON_EPSILON || d > ON_EPSILON) break; } if (i==3) break; } if (f2) { printf ("WARNING: brush with duplicate plane (first point is at %g %g %g, .map file line number %d)\n", planepts[0][0], planepts[0][1], planepts[0][2], scriptline); continue; } if (DotProduct(plane.normal, plane.normal) < 0.1) { printf ("WARNING: brush plane with no normal on line %d\n", scriptline); continue; } /* // LordHavoc: fix for CheckFace: point off plane errors in some maps (most notably QOOLE ones), // and hopefully preventing most 'portal clipped away' warnings VectorNormalize (plane.normal); for (j = 0;j < 3;j++) plane.normal[j] = (Q_rint((vec_t) plane.normal[j] * (vec_t) 8.0)) * (vec_t) (1.0 / 8.0); VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); d = (Q_rint(plane.dist * 8.0)) * (1.0 / 8.0); //if (fabs(d - plane.dist) >= (0.4 / 8.0)) // printf("WARNING: correcting minor math errors in brushface on line %d\n", scriptline); plane.dist = d; */ /* VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); VectorCopy(plane.normal, v); //for (j = 0;j < 3;j++) // v[j] = (Q_rint((vec_t) v[j] * (vec_t) 32.0)) * (vec_t) (1.0 / 32.0); VectorNormalize (v); d = (Q_rint(DotProduct (t3, v) * 8.0)) * (1.0 / 8.0); // if deviation is too high, warn (frequently happens on QOOLE maps) if (fabs(DotProduct(v, plane.normal) - 1.0) > (0.5 / 32.0) || fabs(d - plane.dist) >= (0.25 / 8.0)) printf("WARNING: minor misalignment of brushface on line %d\n" "normal %f %f %f (l: %f d: %f)\n" "rounded to %f %f %f (l: %f d: %f r: %f)\n", scriptline, (vec_t) plane.normal[0], (vec_t) plane.normal[1], (vec_t) plane.normal[2], (vec_t) sqrt(DotProduct(plane.normal, plane.normal)), (vec_t) DotProduct (t3, plane.normal), (vec_t) v[0], (vec_t) v[1], (vec_t) v[2], (vec_t) sqrt(DotProduct(v, v)), (vec_t) DotProduct(t3, v), (vec_t) d); //VectorCopy(v, plane.normal); //plane.dist = d; */ if (!hltexdef) { // fake proper texture vectors from QuakeEd style TextureAxisFromPlane(&plane, vecs[0], vecs[1]); } // rotate axis if (rotate == 0) {sinv = 0;cosv = 1;} else if (rotate == 90) {sinv = 1;cosv = 0;} else if (rotate == 180) {sinv = 0;cosv = -1;} else if (rotate == 270) {sinv = -1;cosv = 0;} else {ang = rotate * (Q_PI / 180);sinv = sin(ang);cosv = cos(ang);} // LordHavoc: I don't quite understand this for (sv = 0;sv < 2 && !vecs[0][sv];sv++); for (tv = 0;tv < 2 && !vecs[1][tv];tv++); for (i = 0;i < 2;i++) { // rotate ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; // scale and store into texinfo d = 1.0 / (scale[i] ? scale[i] : 1.0); for (j = 0;j < 3;j++) tx.vecs[i][j] = vecs[i][j] * d; tx.vecs[i][3] = vecs[i][3]; } f = malloc(sizeof(mface_t)); f->next = b->faces; b->faces = f; f->plane = plane; f->texinfo = FindTexinfo (&tx); nummapbrushfaces++; } while (1); }
static void ParseBrush(void) { vec3_t planepts[3]; vec3_t t1, t2, t3; int i, j; texinfo_t tx; vec_t d; int shift[2], rotate; vec_t scale[2]; int iFace; int tx_type; map.rgBrushes[map.iBrushes].iFaceEnd = map.iFaces + 1; while (ParseToken(PARSE_NORMAL)) { if (!strcmp(token, "}")) break; // read the three point plane definition for (i = 0; i < 3; i++) { if (i != 0) ParseToken(PARSE_NORMAL); if (strcmp(token, "(")) Message(msgError, errInvalidMapPlane, linenum); for (j = 0; j < 3; j++) { ParseToken(PARSE_SAMELINE); planepts[i][j] = atof(token); } ParseToken(PARSE_SAMELINE); if (strcmp(token, ")")) Message(msgError, errInvalidMapPlane, linenum); } // read the texturedef memset(&tx, 0, sizeof(tx)); ParseToken(PARSE_SAMELINE); tx.miptex = FindMiptex(token); ParseToken(PARSE_SAMELINE); shift[0] = atoi(token); ParseToken(PARSE_SAMELINE); shift[1] = atoi(token); ParseToken(PARSE_SAMELINE); rotate = atoi(token); ParseToken(PARSE_SAMELINE); scale[0] = atof(token); ParseToken(PARSE_SAMELINE); scale[1] = atof(token); // if the three points are all on a previous plane, it is a // duplicate plane for (iFace = map.rgBrushes[map.iBrushes].iFaceEnd - 1; iFace > map.iFaces; iFace--) { for (i = 0; i < 3; i++) { d = DotProduct(planepts[i], map.rgFaces[iFace].plane.normal) - map.rgFaces[iFace].plane.dist; if (d < -ON_EPSILON || d > ON_EPSILON) break; } if (i == 3) break; } if (iFace > map.iFaces) { Message(msgWarning, warnBrushDuplicatePlane, linenum); continue; } if (map.iFaces < 0) Message(msgError, errLowFaceCount); // convert to a vector / dist plane for (j = 0; j < 3; j++) { t1[j] = planepts[0][j] - planepts[1][j]; t2[j] = planepts[2][j] - planepts[1][j]; t3[j] = planepts[1][j]; } CrossProduct(t1, t2, map.rgFaces[map.iFaces].plane.normal); if (VectorCompare(map.rgFaces[map.iFaces].plane.normal, vec3_origin)) { Message(msgWarning, warnNoPlaneNormal, linenum); break; } VectorNormalize(map.rgFaces[map.iFaces].plane.normal); map.rgFaces[map.iFaces].plane.dist = DotProduct(t3, map.rgFaces[map.iFaces].plane.normal); tx_type = ParseExtendedTX(); switch (tx_type) { case TX_QUARK_TYPE1: case TX_QUARK_TYPE2: SetTexinfo_QuArK(planepts, tx_type, &tx); break; default: SetTexinfo_QuakeEd(shift, rotate, scale, &tx); break; } // unique the texinfo map.rgFaces[map.iFaces].texinfo = FindTexinfo(&tx); map.iFaces--; Message(msgPercent, map.cFaces - map.iFaces - 1, map.cFaces); } map.rgBrushes[map.iBrushes].iFaceStart = map.iFaces + 1; map.iBrushes--; }
void ParseBrush (void) { mbrush_t *b; mface_t *f, *f2; vec3_t planepts[3]; vec3_t t1, t2, t3; int i,j; texinfo_t tx; double d; float shift[2], rotate, scale[2]; char name[64]; b = &mapbrushes[nummapbrushes]; do { if (!GetToken (true)) break; if (!strcmp (token, "}") ) break; // read the three point plane definition for (i=0 ; i<3 ; i++) { if (i != 0) GetToken (true); if (strcmp (token, "(") ) logerror ("parsing brush"); // jkrige - was Error() for (j=0 ; j<3 ; j++) { GetToken (false); // jkrige - floating point texture support //planepts[i][j] = atoi(token); planepts[i][j] = atof(token); // jkrige - floating point texture support } GetToken (false); if (strcmp (token, ")") ) logerror ("parsing brush"); // jkrige - was Error() } // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); strcpy (name, token); // JDC 8/8/97: for origin texture tx.miptex = FindMiptex (token); GetToken (false); shift[0] = atoi(token); GetToken (false); shift[1] = atoi(token); GetToken (false); rotate = atoi(token); GetToken (false); scale[0] = atof(token); GetToken (false); scale[1] = atof(token); GetToken (false); b->Light = atol(token); // if the three points are all on a previous plane, it is a // duplicate plane for (f2 = b->faces ; f2 ; f2=f2->next) { for (i=0 ; i<3 ; i++) { d = DotProduct(planepts[i],f2->plane.normal) - f2->plane.dist; if (d < -ON_EPSILON || d > ON_EPSILON) break; } if (i==3) break; } if (f2) { logprint ("WARNING: brush with duplicate plane\n"); continue; } f = malloc(sizeof(mface_t)); f->next = b->faces; b->faces = f; // convert to a vector / dist plane for (j=0 ; j<3 ; j++) { t1[j] = planepts[0][j] - planepts[1][j]; t2[j] = planepts[2][j] - planepts[1][j]; t3[j] = planepts[1][j]; } CrossProduct(t1,t2, f->plane.normal); if (VectorCompare (f->plane.normal, vec3_origin)) { logprint ("WARNING: brush plane with no normal\n"); b->faces = f->next; free (f); break; } VectorNormalize (f->plane.normal); f->plane.dist = DotProduct (t3, f->plane.normal); // // fake proper texture vectors from QuakeEd style // { vec3_t vecs[2]; int sv, tv; float ang, sinv, cosv; float ns, nt; TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]); if (!scale[0]) scale[0] = 1; if (!scale[1]) scale[1] = 1; // rotate axis if (rotate == 0) { sinv = 0 ; cosv = 1; } else if (rotate == 90) { sinv = 1 ; cosv = 0; } else if (rotate == 180) { sinv = 0 ; cosv = -1; } else if (rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = rotate / 180 * Q_PI; sinv = sin(ang); cosv = cos(ang); } if (vecs[0][0]) sv = 0; else if (vecs[0][1]) sv = 1; else sv = 2; if (vecs[1][0]) tv = 0; else if (vecs[1][1]) tv = 1; else tv = 2; for (i=0 ; i<2 ; i++) { ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; } for (i=0 ; i<2 ; i++) for (j=0 ; j<3 ; j++) tx.vecs[i][j] = vecs[i][j] / scale[i]; tx.vecs[0][3] = shift[0]; tx.vecs[1][3] = shift[1]; } // unique the texinfo f->texinfo = FindTexinfo (&tx); } while (1); // JDC 8/8/97 // origin brushes are removed, but they set // the rotation origin for the rest of the brushes // in the entity // if (Q_strncasecmp (name, "origin",6)) { // keep it nummapbrushes++; b->next = mapent->brushes; mapent->brushes = b; } else { // don't save the brush, just use as entity origin char string[32]; vec3_t origin; if (num_entities == 1) logerror ("Origin brushes not allowed in world"); // jkrige - was Error() BrushOrigin (b, origin); sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); SetKeyValue (mapent, "origin", string); VectorCopy (origin, mapent->origin); memset (b, 0, sizeof(*b)); } }
static void ParseBrush(parser_t *parser, mapbrush_t *brush) { vec3_t planepts[3]; vec3_t t1, t2, t3; int i, j; texinfo_t tx; vec_t d; int shift[2], rotate; vec_t scale[2]; int tx_type; plane_t *plane; mapface_t *face, *checkface; brush->faces = face = map.faces + map.numfaces; while (ParseToken(parser, PARSE_NORMAL)) { if (!strcmp(parser->token, "}")) break; // read the three point plane definition for (i = 0; i < 3; i++) { if (i != 0) ParseToken(parser, PARSE_NORMAL); if (strcmp(parser->token, "(")) Error(errInvalidMapPlane, parser->linenum); for (j = 0; j < 3; j++) { ParseToken(parser, PARSE_SAMELINE); planepts[i][j] = atof(parser->token); } ParseToken(parser, PARSE_SAMELINE); if (strcmp(parser->token, ")")) Error(errInvalidMapPlane, parser->linenum); } // read the texturedef memset(&tx, 0, sizeof(tx)); ParseToken(parser, PARSE_SAMELINE); tx.miptex = FindMiptex(parser->token); ParseToken(parser, PARSE_SAMELINE); shift[0] = atoi(parser->token); ParseToken(parser, PARSE_SAMELINE); shift[1] = atoi(parser->token); ParseToken(parser, PARSE_SAMELINE); rotate = atoi(parser->token); ParseToken(parser, PARSE_SAMELINE); scale[0] = atof(parser->token); ParseToken(parser, PARSE_SAMELINE); scale[1] = atof(parser->token); // if the three points are all on a previous plane, it is a // duplicate plane for (checkface = brush->faces; checkface < face; checkface++) { plane = &checkface->plane; for (i = 0; i < 3; i++) { d = DotProduct(planepts[i], plane->normal) - plane->dist; if (d < -ON_EPSILON || d > ON_EPSILON) break; } if (i == 3) break; } if (checkface < face) { Message(msgWarning, warnBrushDuplicatePlane, parser->linenum); continue; } if (map.numfaces == map.maxfaces) Error(errLowFaceCount); // convert to a vector / dist plane for (j = 0; j < 3; j++) { t1[j] = planepts[0][j] - planepts[1][j]; t2[j] = planepts[2][j] - planepts[1][j]; t3[j] = planepts[1][j]; } plane = &face->plane; CrossProduct(t1, t2, plane->normal); if (VectorCompare(plane->normal, vec3_origin)) { Message(msgWarning, warnNoPlaneNormal, parser->linenum); continue; } VectorNormalize(plane->normal); plane->dist = DotProduct(t3, plane->normal); tx_type = ParseExtendedTX(parser); switch (tx_type) { case TX_QUARK_TYPE1: case TX_QUARK_TYPE2: SetTexinfo_QuArK(parser, &planepts[0], tx_type, &tx); break; default: SetTexinfo_QuakeEd(plane, shift, rotate, scale, &tx); break; } face->texinfo = FindTexinfo(&tx); face++; map.numfaces++; Message(msgPercent, map.numfaces, map.maxfaces); } brush->numfaces = face - brush->faces; if (!brush->numfaces) brush->faces = NULL; }