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;
 }
示例#2
0
        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;
        }