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