size_t MapWriter::writeBrush(Model::Brush& brush, const size_t lineNumber, FILE* stream) { size_t lineCount = 0; std::fprintf(stream, "{\n"); lineCount++; const Model::FaceList& faces = brush.faces(); Model::FaceList::const_iterator faceIt, faceEnd; for (faceIt = faces.begin(), faceEnd = faces.end(); faceIt != faceEnd; ++faceIt) { lineCount += writeFace(**faceIt, lineNumber + lineCount, stream); } std::fprintf(stream, "}\n"); lineCount++; brush.setFilePosition(lineNumber, lineCount); return lineCount; }
Model::Brush* MapParser::parseBrush(const BBox& worldBounds, Utility::ProgressIndicator* indicator) { Token token = m_tokenizer.nextToken(); if (token.type() == TokenType::Eof) return NULL; expect(TokenType::OBrace | TokenType::CBrace, token); if (token.type() == TokenType::CBrace) return NULL; Model::Brush* brush = new Model::Brush(worldBounds); brush->setFilePosition(token.line()); while ((token = m_tokenizer.nextToken()).type() != TokenType::Eof) { switch (token.type()) { case TokenType::OParenthesis: { m_tokenizer.pushToken(token); Model::Face* face = parseFace(worldBounds); if (face != NULL && brush != NULL) { if (!brush->addFace(face)) { m_console.warn("Skipping malformed brush at line %i", brush->filePosition()); delete brush; brush = NULL; } } else { delete face; } break; } case TokenType::CBrace: if (indicator != NULL) indicator->update(static_cast<int>(token.position())); if (brush != NULL && !brush->closed()) { m_console.warn("Non-closed brush at line %i", brush->filePosition()); // delete brush; // brush = NULL; } return brush; default: delete brush; throw MapParserException(token, TokenType::OParenthesis | TokenType::CParenthesis); } } return NULL; }
Model::Brush* MapParser::parseBrush(const BBox& worldBounds, Utility::ProgressIndicator* indicator) { Token token = m_tokenizer.nextToken(); if (token.type() == TokenType::Eof) return NULL; expect(TokenType::OBrace | TokenType::CBrace, token); if (token.type() == TokenType::CBrace) return NULL; const size_t firstLine = token.line(); Model::FaceList faces; while ((token = m_tokenizer.nextToken()).type() != TokenType::Eof) { switch (token.type()) { case TokenType::OParenthesis: { m_tokenizer.pushToken(token); Model::Face* face = parseFace(worldBounds); if (face != NULL) faces.push_back(face); break; } case TokenType::CBrace: { if (indicator != NULL) indicator->update(static_cast<int>(token.position())); Model::Brush* brush = new Model::Brush(worldBounds); // sort the faces by the weight of their plane normals like QBSP does Model::FaceList sortedFaces = faces; std::sort(sortedFaces.begin(), sortedFaces.end(), Model::Face::WeightOrder(Plane::WeightOrder(true))); std::sort(sortedFaces.begin(), sortedFaces.end(), Model::Face::WeightOrder(Plane::WeightOrder(false))); Model::FaceList::iterator faceIt = sortedFaces.begin(); Model::FaceList::iterator faceEnd = sortedFaces.end(); while (faceIt != faceEnd) { Model::Face* face = *faceIt++; if (!brush->addFace(face)) { m_console.warn("Skipping malformed brush at line %i", firstLine); delete brush; brush = NULL; break; } } // if something went wrong, we must delete all faces that have not been added to the brush yet if (faceIt != faceEnd) Utility::deleteAll(sortedFaces, faceIt); if (brush != NULL) { brush->setFilePosition(firstLine, token.line() - firstLine); if (!brush->closed()) m_console.warn("Non-closed brush at line %i", firstLine); } return brush; } default: { Utility::deleteAll(faces); throw MapParserException(token, TokenType::OParenthesis | TokenType::CParenthesis); } } } return NULL; }