1 /* 2 Copyright (C) 2010-2014 Kristian Duske 3 4 This file is part of TrenchBroom. 5 6 TrenchBroom is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 TrenchBroom is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "MapFileSerializer.h" 21 #include "Exceptions.h" 22 #include "IO/DiskFileSystem.h" 23 #include "IO/Path.h" 24 #include "Model/BrushFace.h" 25 26 namespace TrenchBroom { 27 namespace IO { 28 class StandardFileSerializer : public MapFileSerializer { 29 private: 30 bool m_longFormat; 31 String FaceFormat; 32 public: StandardFileSerializer(FILE * stream,const bool longFormat)33 StandardFileSerializer(FILE* stream, const bool longFormat) : 34 MapFileSerializer(stream), 35 m_longFormat(longFormat) { 36 StringStream str; 37 str << 38 "( %." << FloatPrecision << "g " << 39 "%." << FloatPrecision << "g " << 40 "%." << FloatPrecision << "g ) " << 41 "( %." << FloatPrecision << "g " << 42 "%." << FloatPrecision << "g " << 43 "%." << FloatPrecision << "g ) " << 44 "( %." << FloatPrecision << "g " << 45 "%." << FloatPrecision << "g " << 46 "%." << FloatPrecision << "g ) " << 47 "%s %.6g %.6g %.6g %.6g %.6g"; 48 if (m_longFormat) 49 str << " %d %d %.6g"; 50 FaceFormat = str.str(); 51 } 52 private: doWriteBrushFace(FILE * stream,Model::BrushFace * face)53 size_t doWriteBrushFace(FILE* stream, Model::BrushFace* face) { 54 const String& textureName = face->textureName().empty() ? Model::BrushFace::NoTextureName : face->textureName(); 55 const Model::BrushFace::Points& points = face->points(); 56 57 if (m_longFormat) { 58 std::fprintf(stream, FaceFormat.c_str(), 59 points[0].x(), 60 points[0].y(), 61 points[0].z(), 62 points[1].x(), 63 points[1].y(), 64 points[1].z(), 65 points[2].x(), 66 points[2].y(), 67 points[2].z(), 68 textureName.c_str(), 69 face->xOffset(), 70 face->yOffset(), 71 face->rotation(), 72 face->xScale(), 73 face->yScale(), 74 face->surfaceContents(), 75 face->surfaceFlags(), 76 face->surfaceValue()); 77 } else { 78 std::fprintf(stream, FaceFormat.c_str(), 79 points[0].x(), 80 points[0].y(), 81 points[0].z(), 82 points[1].x(), 83 points[1].y(), 84 points[1].z(), 85 points[2].x(), 86 points[2].y(), 87 points[2].z(), 88 textureName.c_str(), 89 face->xOffset(), 90 face->yOffset(), 91 face->rotation(), 92 face->xScale(), 93 face->yScale()); 94 } 95 std::fprintf(stream, "\n"); 96 return 1; 97 } 98 }; 99 100 class Hexen2FileSerializer : public MapFileSerializer { 101 private: 102 String FaceFormat; 103 public: Hexen2FileSerializer(FILE * stream)104 Hexen2FileSerializer(FILE* stream) : 105 MapFileSerializer(stream) { 106 StringStream str; 107 str << 108 "( %." << FloatPrecision << "g " << 109 "%." << FloatPrecision << "g " << 110 "%." << FloatPrecision << "g ) " << 111 "( %." << FloatPrecision << "g " << 112 "%." << FloatPrecision << "g " << 113 "%." << FloatPrecision << "g ) " << 114 "( %." << FloatPrecision << "g " << 115 "%." << FloatPrecision << "g " << 116 "%." << FloatPrecision << "g ) " << 117 "%s %.6g %.6g %.6g %.6g %.6g 0\n"; // the extra value is written here 118 119 FaceFormat = str.str(); 120 } 121 private: doWriteBrushFace(FILE * stream,Model::BrushFace * face)122 size_t doWriteBrushFace(FILE* stream, Model::BrushFace* face) { 123 const String& textureName = face->textureName().empty() ? Model::BrushFace::NoTextureName : face->textureName(); 124 const Model::BrushFace::Points& points = face->points(); 125 126 std::fprintf(stream, FaceFormat.c_str(), 127 points[0].x(), 128 points[0].y(), 129 points[0].z(), 130 points[1].x(), 131 points[1].y(), 132 points[1].z(), 133 points[2].x(), 134 points[2].y(), 135 points[2].z(), 136 textureName.c_str(), 137 face->xOffset(), 138 face->yOffset(), 139 face->rotation(), 140 face->xScale(), 141 face->yScale()); 142 return 1; 143 } 144 }; 145 146 class ValveFileSerializer : public MapFileSerializer { 147 private: 148 String FaceFormat; 149 public: ValveFileSerializer(FILE * stream)150 ValveFileSerializer(FILE* stream) : 151 MapFileSerializer(stream) { 152 StringStream str; 153 str << 154 "( %." << FloatPrecision << "g " << 155 "%." << FloatPrecision << "g " << 156 "%." << FloatPrecision << "g ) " << 157 "( %." << FloatPrecision << "g " << 158 "%." << FloatPrecision << "g " << 159 "%." << FloatPrecision << "g ) " << 160 "( %." << FloatPrecision << "g " << 161 "%." << FloatPrecision << "g " << 162 "%." << FloatPrecision << "g ) " << 163 "%s " << 164 "[ %.6g %.6g %.6g %.6g ] " << 165 "[ %.6g %.6g %.6g %.6g ] " << 166 "%.6g %.6g %.6g\n"; 167 168 FaceFormat = str.str(); 169 } 170 private: doWriteBrushFace(FILE * stream,Model::BrushFace * face)171 size_t doWriteBrushFace(FILE* stream, Model::BrushFace* face) { 172 const String& textureName = face->textureName().empty() ? Model::BrushFace::NoTextureName : face->textureName(); 173 const Vec3 xAxis = face->textureXAxis(); 174 const Vec3 yAxis = face->textureYAxis(); 175 const Model::BrushFace::Points& points = face->points(); 176 177 std::fprintf(stream, FaceFormat.c_str(), 178 points[0].x(), 179 points[0].y(), 180 points[0].z(), 181 points[1].x(), 182 points[1].y(), 183 points[1].z(), 184 points[2].x(), 185 points[2].y(), 186 points[2].z(), 187 188 textureName.c_str(), 189 190 xAxis.x(), 191 xAxis.y(), 192 xAxis.z(), 193 face->xOffset(), 194 195 yAxis.x(), 196 yAxis.y(), 197 yAxis.z(), 198 face->yOffset(), 199 200 face->rotation(), 201 face->xScale(), 202 face->yScale()); 203 return 1; 204 } 205 }; 206 create(const Model::MapFormat::Type format,FILE * stream)207 NodeSerializer::Ptr MapFileSerializer::create(const Model::MapFormat::Type format, FILE* stream) { 208 switch (format) { 209 case Model::MapFormat::Standard: 210 return NodeSerializer::Ptr(new StandardFileSerializer(stream, false)); 211 case Model::MapFormat::Quake2: 212 return NodeSerializer::Ptr(new StandardFileSerializer(stream, true)); 213 case Model::MapFormat::Valve: 214 return NodeSerializer::Ptr(new ValveFileSerializer(stream)); 215 case Model::MapFormat::Hexen2: 216 return NodeSerializer::Ptr(new Hexen2FileSerializer(stream)); 217 case Model::MapFormat::Unknown: 218 default: 219 throw new FileFormatException("Unknown map file format"); 220 } 221 } 222 MapFileSerializer(FILE * stream)223 MapFileSerializer::MapFileSerializer(FILE* stream) : 224 m_line(1), 225 m_stream(stream) {} 226 doBeginEntity(const Model::Node * node)227 void MapFileSerializer::doBeginEntity(const Model::Node* node) { 228 m_startLineStack.push_back(m_line); 229 std::fprintf(m_stream, "{\n"); 230 ++m_line; 231 } 232 doEndEntity(Model::Node * node)233 void MapFileSerializer::doEndEntity(Model::Node* node) { 234 std::fprintf(m_stream, "}\n"); 235 ++m_line; 236 setFilePosition(node); 237 } 238 doEntityAttribute(const Model::EntityAttribute & attribute)239 void MapFileSerializer::doEntityAttribute(const Model::EntityAttribute& attribute) { 240 std::fprintf(m_stream, "\"%s\" \"%s\"\n", attribute.name().c_str(), attribute.value().c_str()); 241 ++m_line; 242 } 243 doBeginBrush(const Model::Brush * brush)244 void MapFileSerializer::doBeginBrush(const Model::Brush* brush) { 245 m_startLineStack.push_back(m_line); 246 std::fprintf(m_stream, "{\n"); 247 ++m_line; 248 } 249 doEndBrush(Model::Brush * brush)250 void MapFileSerializer::doEndBrush(Model::Brush* brush) { 251 std::fprintf(m_stream, "}\n"); 252 ++m_line; 253 setFilePosition(brush); 254 } 255 doBrushFace(Model::BrushFace * face)256 void MapFileSerializer::doBrushFace(Model::BrushFace* face) { 257 const size_t lines = doWriteBrushFace(m_stream, face); 258 face->setFilePosition(m_line, lines); 259 m_line += lines; 260 } 261 setFilePosition(Model::Node * node)262 void MapFileSerializer::setFilePosition(Model::Node* node) { 263 const size_t start = startLine(); 264 node->setFilePosition(start, m_line - start); 265 } 266 startLine()267 size_t MapFileSerializer::startLine() { 268 assert(!m_startLineStack.empty()); 269 const size_t result = m_startLineStack.back(); 270 m_startLineStack.pop_back(); 271 return result; 272 } 273 } 274 } 275