- Radiant is now Vista compatible (Aero must be disabled)
[xonotic/netradiant.git] / contrib / brushexport / export.cpp
1 #include "export.h"\r
2 #include "debugging/debugging.h"\r
3 #include "ibrush.h"\r
4 #include "iscenegraph.h"\r
5 #include "iselection.h"\r
6 #include "stream/stringstream.h"\r
7 #include "stream/textfilestream.h"\r
8 \r
9 // this is very evil, but right now there is no better way\r
10 #include "../../radiant/brush.h"\r
11 \r
12 /*\r
13         Abstract baseclass for modelexporters\r
14         the class collects all the data which then gets\r
15         exported through the WriteToFile method.\r
16 */\r
17 class ExportData\r
18 {\r
19 public:\r
20         ExportData(const std::set<std::string>& ignorelist, collapsemode mode);\r
21         virtual ~ExportData(void);\r
22         \r
23         virtual void BeginBrush(Brush& b);\r
24         virtual void AddBrushFace(Face& f);\r
25         virtual void EndBrush(void);\r
26         \r
27         virtual bool WriteToFile(const std::string& path) const = 0;\r
28         \r
29 protected:\r
30 \r
31         // a group of faces\r
32         class group\r
33         {\r
34         public:\r
35                 std::string name;\r
36                 std::list<const Face*> faces;\r
37         };\r
38         \r
39         std::list<group> groups;\r
40         \r
41 private:\r
42 \r
43         // "textures/common/caulk" -> "caulk"\r
44         void GetShaderNameFromShaderPath(const char* path, std::string& name);\r
45 \r
46         group* current; \r
47         collapsemode mode;\r
48         const std::set<std::string>& ignorelist;\r
49 };\r
50 \r
51 ExportData::ExportData(const std::set<std::string>& _ignorelist, collapsemode _mode)\r
52         :       mode(_mode),\r
53                 ignorelist(_ignorelist)\r
54 {\r
55         current = 0;\r
56         \r
57         // in this mode, we need just one group\r
58         if(mode == COLLAPSE_ALL)\r
59         {\r
60                 groups.push_back(group());\r
61                 current = &groups.back();\r
62                 current->name = "all";\r
63         }\r
64 }\r
65 \r
66 ExportData::~ExportData(void)\r
67 {\r
68         \r
69 }\r
70 \r
71 void ExportData::BeginBrush(Brush& b)\r
72 {\r
73         // create a new group for each brush\r
74         if(mode == COLLAPSE_NONE)\r
75         {\r
76                 groups.push_back(group());\r
77                 current = &groups.back();\r
78                 \r
79                 StringOutputStream str(256);\r
80                 str << "Brush" << (const unsigned int)groups.size();\r
81                 current->name = str.c_str();\r
82         }\r
83 }\r
84 \r
85 void ExportData::EndBrush(void)\r
86 {\r
87         // all faces of this brush were on the ignorelist, discard the emptygroup\r
88         if(mode == COLLAPSE_NONE)\r
89         {\r
90                 ASSERT_NOTNULL(current);\r
91                 if(current->faces.empty())\r
92                 {\r
93                         groups.pop_back();\r
94                         current = 0;\r
95                 }\r
96         }\r
97 }\r
98 \r
99 void ExportData::AddBrushFace(Face& f)\r
100 {\r
101         std::string shadername;\r
102         GetShaderNameFromShaderPath(f.GetShader(), shadername);\r
103         \r
104         // faces mit materials auf der ignoreliste ignorieren\r
105         if(ignorelist.find(shadername) != ignorelist.end())\r
106                 return;\r
107                 \r
108         if(mode == COLLAPSE_BY_MATERIAL)\r
109         {\r
110                 // find a group for this material\r
111                 current = 0;\r
112                 const std::list<group>::iterator end(groups.end());\r
113                 for(std::list<group>::iterator it(groups.begin()); it != end; ++it)\r
114                 {\r
115                         if(it->name == shadername)\r
116                                 current = &(*it);\r
117                 }\r
118                 \r
119                 // no group found, create one\r
120                 if(!current)\r
121                 {\r
122                         groups.push_back(group());\r
123                         current = &groups.back();\r
124                         current->name = shadername;\r
125                 }\r
126         }\r
127         \r
128         ASSERT_NOTNULL(current);\r
129         \r
130         // add face to current group\r
131         current->faces.push_back(&f);\r
132         \r
133 #ifdef _DEBUG\r
134         globalOutputStream() << "Added Face to group " << current->name.c_str() << "\n";\r
135 #endif\r
136 }\r
137 \r
138 void ExportData::GetShaderNameFromShaderPath(const char* path, std::string& name)\r
139 {\r
140         std::string tmp(path);\r
141 \r
142         size_t last_slash = tmp.find_last_of("/");\r
143         \r
144         if(last_slash != std::string::npos && last_slash == (tmp.length() - 1))\r
145                 name = path;\r
146         else\r
147                 name = tmp.substr(last_slash + 1, tmp.length() - last_slash);\r
148                 \r
149         globalOutputStream() << "Last: " << last_slash << " " << "lenght: " << (const unsigned int)tmp.length() << "Name: " << name.c_str() << "\n";\r
150 }\r
151 \r
152 /*\r
153         Exporter writing facedata as wavefront object\r
154 */\r
155 class ExportDataAsWavefront : public ExportData\r
156 {\r
157 public:\r
158         ExportDataAsWavefront(const std::set<std::string>& _ignorelist, collapsemode _mode)\r
159                 : ExportData(_ignorelist, _mode)\r
160         {\r
161         }\r
162         \r
163         bool WriteToFile(const std::string& path) const;\r
164 };\r
165 \r
166 bool ExportDataAsWavefront::WriteToFile(const std::string& path) const\r
167 {\r
168         TextFileOutputStream out(path.c_str());\r
169         \r
170         if(out.failed())\r
171         {\r
172                 globalErrorStream() << "Unable to open file\n";\r
173                 return false;\r
174         }\r
175                 \r
176         out << "# Wavefront Objectfile exported with radiants brushexport plugin 2.0 by Thomas 'namespace' Nitschke, spam@codecreator.net\n\n";\r
177         \r
178         unsigned int vertex_count = 0;\r
179 \r
180         const std::list<ExportData::group>::const_iterator gend(groups.end());\r
181         for(std::list<ExportData::group>::const_iterator git(groups.begin()); git != gend; ++git)\r
182         {\r
183                 const std::list<const Face*>::const_iterator end(git->faces.end());\r
184                 \r
185                 // submesh starts here\r
186                 out << "\ng " << git->name.c_str() << "\n";\r
187                 \r
188                 for(std::list<const Face*>::const_iterator it(git->faces.begin()); it != end; ++it)\r
189                 {\r
190                         const Winding& w((*it)->getWinding());\r
191                         \r
192                         // vertices\r
193                         for(size_t i = 0; i < w.numpoints; ++i)\r
194                         out << "v " << w[i].vertex.x() << " " << w[i].vertex.y() << " " << w[i].vertex.z() << "\n";\r
195                 }\r
196                 out << "\n";    \r
197                 \r
198                 for(std::list<const Face*>::const_iterator it(git->faces.begin()); it != end; ++it)\r
199                 {\r
200                         const Winding& w((*it)->getWinding());\r
201                         \r
202                         // texcoords\r
203                         for(size_t i = 0; i < w.numpoints; ++i)\r
204                         out << "vt " << w[i].texcoord.x() << " " << w[i].texcoord.y() << "\n";\r
205                 }\r
206                 \r
207                 for(std::list<const Face*>::const_iterator it(git->faces.begin()); it != end; ++it)\r
208                 {\r
209                         const Winding& w((*it)->getWinding());\r
210                         \r
211                         // faces\r
212                         out << "\nf";\r
213                         for(size_t i = 0; i < w.numpoints; ++i, ++vertex_count)\r
214                         {\r
215                                 out << " " << vertex_count+1 << "/" << vertex_count+1;\r
216                         }\r
217                 }\r
218                 out << "\n";\r
219         }\r
220         \r
221         return true;\r
222 }\r
223 \r
224 \r
225 class ForEachFace : public BrushVisitor\r
226 {\r
227 public:\r
228         ForEachFace(ExportData& _exporter)\r
229                 : exporter(_exporter)\r
230         {}\r
231         \r
232         void visit(Face& face) const\r
233         {\r
234                 exporter.AddBrushFace(face);\r
235         }\r
236         \r
237 private:\r
238         ExportData& exporter;\r
239 };\r
240 \r
241 class ForEachSelected : public SelectionSystem::Visitor\r
242 {\r
243 public:\r
244         ForEachSelected(ExportData& _exporter)\r
245                 : exporter(_exporter)\r
246         {}\r
247         \r
248         void visit(scene::Instance& instance) const\r
249     {\r
250                 BrushInstance* bptr = InstanceTypeCast<BrushInstance>::cast(instance);\r
251                 if(bptr)\r
252                 {\r
253                         Brush& brush(bptr->getBrush());\r
254                         \r
255                         exporter.BeginBrush(brush);\r
256                                 ForEachFace face_vis(exporter);\r
257                                 brush.forEachFace(face_vis);\r
258                         exporter.EndBrush();\r
259                 }\r
260     }\r
261     \r
262 private:\r
263         ExportData& exporter;\r
264 };\r
265  \r
266 bool ExportSelection(const std::set<std::string>& ignorelist, collapsemode m, const std::string& path)\r
267 {\r
268         ExportDataAsWavefront exporter(ignorelist, m);\r
269         \r
270         ForEachSelected vis(exporter);\r
271         GlobalSelectionSystem().foreachSelected(vis);\r
272         \r
273         return exporter.WriteToFile(path);\r
274 }\r