From 30caae09e5f8684f855c8b24866e2139820f4eac Mon Sep 17 00:00:00 2001 From: Kevin Shanahan Date: Mon, 22 Apr 2013 17:30:42 +0930 Subject: [PATCH] qbsp: re-factor ParseBrush into smaller pieces Factor out some of the processing involved with parsing a brush. When checking for duplicate planes, use the same "PlaneEqual" functions as used in brush.c. Replace the enum style errors with the new Error_ function for all of map.c so the error string is at the call site. Signed-off-by: Kevin Shanahan --- qbsp/brush.c | 4 +- qbsp/globals.c | 11 -- qbsp/map.c | 308 +++++++++++++++++++++++++++---------------------- qbsp/qbsp.h | 2 + qbsp/warnerr.h | 12 +- 5 files changed, 177 insertions(+), 160 deletions(-) diff --git a/qbsp/brush.c b/qbsp/brush.c index 6426913d..e3a756a0 100644 --- a/qbsp/brush.c +++ b/qbsp/brush.c @@ -178,7 +178,7 @@ NormalizePlane(plane_t *p) } -static int +int PlaneEqual(const plane_t *p1, const plane_t *p2) { return (fabs(p1->normal[0] - p2->normal[0]) < NORMAL_EPSILON && @@ -187,7 +187,7 @@ PlaneEqual(const plane_t *p1, const plane_t *p2) fabs(p1->dist - p2->dist) < DIST_EPSILON); } -static int +int PlaneInvEqual(const plane_t *p1, const plane_t *p2) { return (fabs(p1->normal[0] + p2->normal[0]) < NORMAL_EPSILON && diff --git a/qbsp/globals.c b/qbsp/globals.c index ca38b948..0fae77e1 100644 --- a/qbsp/globals.c +++ b/qbsp/globals.c @@ -81,14 +81,6 @@ const char *rgszWarnings[cWarnings] = { const char *rgszErrors[cErrors] = { "No leak node in WriteLeakNode", "Unknown option '%s'", - "line %d: Entity key or value too long", - "line %d: Invalid brush plane format", - "Internal error: face count mismatched during map file parsing", - "line %d: Invalid entity format, { not found", - "Internal error: entity count mismatched during map file parsing", - "Unexpected EOF (no closing brace)", - "Internal error: map.nummiptex > map.maxmiptex", - "Internal error: pWorldEnt->iTexinfo > pWorldEnt->cTexinfo", "%s is version %i, not %i", "No axis found for winding", @@ -144,8 +136,5 @@ const char *rgszErrors[cErrors] = { "Invalid argument to option %s", "Internal error: numleaks > num_visportals", "Clipnodes in map exceed " stringify(MAX_BSP_CLIPNODES), - "Internal error: bad texture coordinate style", - "Internal error: brush count mismatched during map file parsing", "Internal error: Detail cluster mismatch", - "line %d: couldn't parse Valve220 texture info", }; diff --git a/qbsp/map.c b/qbsp/map.c index 50f5b4dd..40c830a6 100644 --- a/qbsp/map.c +++ b/qbsp/map.c @@ -41,7 +41,7 @@ FindMiptex(const char *name) return i; } if (map.nummiptex == map.maxmiptex) - Error(errLowMiptexCount); + Error_("Internal error: map.nummiptex > map.maxmiptex"); strcpy(map.miptex[i], name); map.nummiptex++; @@ -155,11 +155,11 @@ ParseEpair(parser_t *parser, mapentity_t *entity) entity->epairs = epair; if (strlen(parser->token) >= MAX_KEY - 1) - Error(errEpairTooLong, parser->linenum); + goto parse_error; epair->key = copystring(parser->token); ParseToken(parser, PARSE_SAMELINE); if (strlen(parser->token) >= MAX_VALUE - 1) - Error(errEpairTooLong, parser->linenum); + goto parse_error; epair->value = copystring(parser->token); if (!strcasecmp(epair->key, "origin")) { @@ -175,6 +175,10 @@ ParseEpair(parser_t *parser, mapentity_t *entity) rgfStartSpots |= info_player_coop; } } + return; + + parse_error: + Error_("line %d: Entity key or value too long", parser->linenum); } @@ -247,7 +251,7 @@ SetTexinfo_QuakeEd(const plane_t *plane, const vec_t shift[2], vec_t rotate, TextureAxisFromPlane(plane, vecs[0], vecs[1]); /* Rotate axis */ - ang = (vec_t)rotate / 180 * Q_PI; + ang = rotate / 180.0 * Q_PI; sinv = sin(ang); cosv = cos(ang); @@ -282,8 +286,8 @@ SetTexinfo_QuakeEd(const plane_t *plane, const vec_t shift[2], vec_t rotate, } static void -SetTexinfo_QuArK(parser_t *parser, vec3_t planepts[3], texcoord_style_t style, - texinfo_t *out) +SetTexinfo_QuArK(parser_t *parser, vec3_t planepts[3], + texcoord_style_t style, texinfo_t *out) { int i; vec3_t vecs[2]; @@ -305,7 +309,7 @@ SetTexinfo_QuArK(parser_t *parser, vec3_t planepts[3], texcoord_style_t style, VectorSubtract(planepts[2], planepts[0], vecs[1]); break; default: - Error(errBadTXStyle); + Error_("Internal error: bad texture coordinate style"); } VectorScale(vecs[0], 1.0 / 128.0, vecs[0]); VectorScale(vecs[1], 1.0 / 128.0, vecs[1]); @@ -345,34 +349,6 @@ SetTexinfo_QuArK(parser_t *parser, vec3_t planepts[3], texcoord_style_t style, out->vecs[1][3] = -DotProduct(vecs[1], planepts[0]); } -static void -ParseValve220TX(parser_t *parser, vec3_t axis[2], vec_t shift[2], - vec_t *rotate, vec_t scale[2]) -{ - int i, j; - - for (i = 0; i < 2; i++) { - ParseToken(parser, PARSE_SAMELINE); - if (strcmp(parser->token, "[")) - Error(errBadValve220TX, 9999);//parser->linenum); - for (j = 0; j < 3; j++) { - ParseToken(parser, PARSE_SAMELINE); - axis[i][j] = atof(parser->token); - } - ParseToken(parser, PARSE_SAMELINE); - shift[i] = atof(parser->token); - ParseToken(parser, PARSE_SAMELINE); - if (strcmp(parser->token, "]")) - Error(errBadValve220TX, parser->linenum); - } - ParseToken(parser, PARSE_SAMELINE); - rotate[0] = atof(parser->token); - ParseToken(parser, PARSE_SAMELINE); - scale[0] = atof(parser->token); - ParseToken(parser, PARSE_SAMELINE); - scale[1] = atof(parser->token); -} - static void SetTexinfo_Valve220(vec3_t axis[2], const vec_t shift[2], const vec_t scale[2], texinfo_t *out) @@ -387,117 +363,177 @@ SetTexinfo_Valve220(vec3_t axis[2], const vec_t shift[2], const vec_t scale[2], out->vecs[1][3] = shift[1]; } +static void +ParsePlaneDef(parser_t *parser, vec3_t planepts[3]) +{ + int i, j; + + for (i = 0; i < 3; i++) { + if (i != 0) + ParseToken(parser, PARSE_NORMAL); + if (strcmp(parser->token, "(")) + goto parse_error; + + for (j = 0; j < 3; j++) { + ParseToken(parser, PARSE_SAMELINE); + planepts[i][j] = atof(parser->token); + } + + ParseToken(parser, PARSE_SAMELINE); + if (strcmp(parser->token, ")")) + goto parse_error; + } + return; + + parse_error: + Error_("line %d: Invalid brush plane format", parser->linenum); +} + +static void +ParseValve220TX(parser_t *parser, vec3_t axis[2], vec_t shift[2], + vec_t *rotate, vec_t scale[2]) +{ + int i, j; + + for (i = 0; i < 2; i++) { + ParseToken(parser, PARSE_SAMELINE); + if (strcmp(parser->token, "[")) + goto parse_error; + for (j = 0; j < 3; j++) { + ParseToken(parser, PARSE_SAMELINE); + axis[i][j] = atof(parser->token); + } + ParseToken(parser, PARSE_SAMELINE); + shift[i] = atof(parser->token); + ParseToken(parser, PARSE_SAMELINE); + if (strcmp(parser->token, "]")) + goto parse_error; + } + ParseToken(parser, PARSE_SAMELINE); + rotate[0] = atof(parser->token); + ParseToken(parser, PARSE_SAMELINE); + scale[0] = atof(parser->token); + ParseToken(parser, PARSE_SAMELINE); + scale[1] = atof(parser->token); + return; + + parse_error: + Error_("line %d: couldn't parse Valve220 texture info", parser->linenum); +} + +static void +ParseTextureDef(parser_t *parser, texinfo_t *tx, + vec3_t planepts[3], const plane_t *plane) +{ + vec3_t axis[2]; + vec_t shift[2], rotate, scale[2]; + texcoord_style_t tx_type; + + memset(tx, 0, sizeof(*tx)); + ParseToken(parser, PARSE_SAMELINE); + tx->miptex = FindMiptex(parser->token); + ParseToken(parser, PARSE_SAMELINE); + if (!strcmp(parser->token, "[")) { + parser->unget = true; + ParseValve220TX(parser, axis, shift, &rotate, scale); + tx_type = TX_VALVE_220; + } else { + shift[0] = atof(parser->token); + ParseToken(parser, PARSE_SAMELINE); + shift[1] = atof(parser->token); + ParseToken(parser, PARSE_SAMELINE); + rotate = atof(parser->token); + ParseToken(parser, PARSE_SAMELINE); + scale[0] = atof(parser->token); + ParseToken(parser, PARSE_SAMELINE); + scale[1] = atof(parser->token); + tx_type = ParseExtendedTX(parser); + } + + if (!planepts || !plane) + return; + + switch (tx_type) { + case TX_QUARK_TYPE1: + case TX_QUARK_TYPE2: + SetTexinfo_QuArK(parser, &planepts[0], tx_type, tx); + break; + case TX_VALVE_220: + SetTexinfo_Valve220(axis, shift, scale, tx); + break; + case TX_QUAKED: + default: + SetTexinfo_QuakeEd(plane, shift, rotate, scale, tx); + break; + } +} + +static bool +ParseBrushFace(parser_t *parser, mapface_t *face) +{ + vec3_t planepts[3], planevecs[2]; + vec_t length; + plane_t *plane; + texinfo_t tx; + + ParsePlaneDef(parser, planepts); + + /* calculate the normal/dist plane equation */ + VectorSubtract(planepts[0], planepts[1], planevecs[0]); + VectorSubtract(planepts[2], planepts[1], planevecs[1]); + plane = &face->plane; + CrossProduct(planevecs[0], planevecs[1], plane->normal); + length = VectorNormalize(plane->normal); + plane->dist = DotProduct(planepts[1], plane->normal); + + ParseTextureDef(parser, &tx, planepts, plane); + + if (length < NORMAL_EPSILON) { + Message(msgWarning, warnNoPlaneNormal, parser->linenum); + return false; + } + + face->texinfo = FindTexinfo(&tx); + + return true; +} + static void ParseBrush(parser_t *parser, mapbrush_t *brush) { - vec3_t planepts[3], axis[2]; - vec3_t t1, t2, t3; - int i, j; - texinfo_t tx; - vec_t d; - vec_t shift[2], rotate, scale[2]; - int tx_type; - plane_t *plane; - mapface_t *face, *checkface; + const mapface_t *check; + mapface_t *face; + bool faceok; 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); - if (!strcmp(parser->token, "[")) { - parser->unget = true; - ParseValve220TX(parser, axis, shift, &rotate, scale); - tx_type = TX_VALVE_220; - } else { - shift[0] = atof(parser->token); - ParseToken(parser, PARSE_SAMELINE); - shift[1] = atof(parser->token); - ParseToken(parser, PARSE_SAMELINE); - rotate = atof(parser->token); - ParseToken(parser, PARSE_SAMELINE); - scale[0] = atof(parser->token); - ParseToken(parser, PARSE_SAMELINE); - scale[1] = atof(parser->token); - tx_type = ParseExtendedTX(parser); - } - - // 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); + Error_("Internal error: didn't allocate enough faces?"); - // 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); + faceok = ParseBrushFace(parser, face); + if (!faceok) continue; - } - VectorNormalize(plane->normal); - plane->dist = DotProduct(t3, plane->normal); - switch (tx_type) { - case TX_QUARK_TYPE1: - case TX_QUARK_TYPE2: - SetTexinfo_QuArK(parser, &planepts[0], tx_type, &tx); - break; - case TX_VALVE_220: - SetTexinfo_Valve220(axis, shift, scale, &tx); - break; - case TX_QUAKED: - default: - SetTexinfo_QuakeEd(plane, shift, rotate, scale, &tx); - break; + /* Check for duplicate planes */ + for (check = brush->faces; check < face; check++) { + if (PlaneEqual(&check->plane, &face->plane)) { + Message(msgWarning, warnBrushDuplicatePlane, parser->linenum); + continue; + } + if (PlaneInvEqual(&check->plane, &face->plane)) { + /* FIXME - this is actually an invalid brush */ + Message(msgWarning, warnBrushDuplicatePlane, parser->linenum); + continue; + } } - face->texinfo = FindTexinfo(&tx); - face++; + /* Save the face, update progress */ map.numfaces++; Message(msgPercent, map.numfaces, map.maxfaces); + face++; } brush->numfaces = face - brush->faces; @@ -514,20 +550,20 @@ ParseEntity(parser_t *parser, mapentity_t *entity) return false; if (strcmp(parser->token, "{")) - Error(errParseEntity, parser->linenum); + Error_("line %d: Invalid entity format, { not found", parser->linenum); if (map.numentities == map.maxentities) - Error(errLowEntCount); + Error_("Internal error: didn't allocate enough entities?"); entity->mapbrushes = brush = map.brushes + map.numbrushes; do { if (!ParseToken(parser, PARSE_NORMAL)) - Error(errUnexpectedEOF); + Error_("Unexpected EOF (no closing brace)"); if (!strcmp(parser->token, "}")) break; else if (!strcmp(parser->token, "{")) { if (map.numbrushes == map.maxbrushes) - Error(errLowMapbrushCount); + Error_("Internal error: didn't allocate enough brushes?"); ParseBrush(parser, brush++); map.numbrushes++; } else @@ -649,7 +685,7 @@ LoadMapFile(void) /* Double check the entity count matches our pre-parse count */ if (map.numentities != map.maxentities) - Error(errLowEntCount); + Error_("Internal error: mismatched entity count?"); FreeMem(buf, OTHER, length + 1); @@ -663,7 +699,7 @@ LoadMapFile(void) // Clean up texture memory if (map.nummiptex > map.maxfaces) - Error(errLowMiptexCount); + Error_("Internal error: map.nummiptex > map.maxfaces"); else if (map.nummiptex < map.maxfaces) { // For stuff in AddAnimatingTex, make room available pTemp = map.miptex; @@ -675,7 +711,7 @@ LoadMapFile(void) texinfo = &pWorldEnt->lumps[BSPTEXINFO]; if (texinfo->index > texinfo->count) - Error(errLowTexinfoCount); + Error_("Internal error: didn't allocate enough texinfos?"); else if (texinfo->index < texinfo->count) { pTemp = texinfo->data; texinfo->data = AllocMem(BSPTEXINFO, texinfo->index, true); diff --git a/qbsp/qbsp.h b/qbsp/qbsp.h index 37ad4708..4a53a054 100644 --- a/qbsp/qbsp.h +++ b/qbsp/qbsp.h @@ -443,6 +443,8 @@ void FreeBrushes(brush_t *brushlist); void PlaneHash_Init(void); int FindPlane(const plane_t *plane, int *side); +int PlaneEqual(const plane_t *p1, const plane_t *p2); +int PlaneInvEqual(const plane_t *p1, const plane_t *p2); //============================================================================= diff --git a/qbsp/warnerr.h b/qbsp/warnerr.h index bc5e638f..9fb57035 100644 --- a/qbsp/warnerr.h +++ b/qbsp/warnerr.h @@ -52,14 +52,7 @@ enum { enum { errNoLeakNode, errUnknownOption, - errEpairTooLong, - errInvalidMapPlane, - errLowFaceCount, - errParseEntity, - errLowEntCount, - errUnexpectedEOF, - errLowMiptexCount, - errLowTexinfoCount, + errBadVersion, // 10 errNoWindingAxis, errLowPointCount, @@ -110,9 +103,6 @@ enum { errInvalidOption, errLowLeakCount, errTooManyClipnodes, - errBadTXStyle, // 60 - errLowMapbrushCount, errDetailClusterMismatch, - errBadValve220TX, cErrors };