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++; }
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++; }
/* ================= 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); }
/* ================= 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; }