2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
8 #include "ConsoleCommands/Console.hpp"
9 #include "MaterialSystem/MaterialManager.hpp"
10 #include "TextParser/TextParser.hpp"
16 static void SkipGroupDef(TextParserT
& TP
)
18 if (TP
.PeekNextToken()=="Group")
20 TP
.GetNextToken(); // The "Group" keyword.
21 TP
.GetNextToken(); // The group number.
26 MapFileBrushT::MapFileBrushT(TextParserT
& TP
, unsigned long BrushNr
)
32 std::string Token
=TP
.GetNextToken();
34 if (Token
=="}") break; // End of brush
36 // Read the three point plane definition.
38 MapFilePlaneT MFPlane
;
41 for (char PointNr
=0; PointNr
<3; PointNr
++)
43 TP
.AssertAndSkipToken("(");
44 Points
[PointNr
].x
=TP
.GetNextTokenAsFloat();
45 Points
[PointNr
].y
=TP
.GetNextTokenAsFloat();
46 Points
[PointNr
].z
=TP
.GetNextTokenAsFloat();
47 TP
.AssertAndSkipToken(")");
52 // Die Reihenfolge der Punkte (im Uhrzeigersinn) ist wichtig, damit die Normalenvektoren stets aus dem Brush HERAUS zeigen!
53 MFPlane
.Plane
=Plane3T
<double>(Points
[0], Points
[1], Points
[2], 0.1);
55 catch (const DivisionByZeroE
&)
57 Console
->Warning(cf::va("Entity ??, brush %lu: plane %lu has colinear points.\n", BrushNr
, MFPlanes
.Size()));
58 throw TextParserT::ParseError();
62 // Read the texture definition.
63 const std::string MaterialName
=TP
.GetNextToken();
64 MFPlane
.Material
=MaterialManager
->GetMaterial(MaterialName
);
66 if (MFPlane
.Material
==NULL
)
68 Console
->Warning(cf::va("Entity ??, Brush %lu, plane %lu: Unknown material \"%s\".", BrushNr
, MFPlanes
.Size(), MaterialName
.c_str()));
69 throw TextParserT::ParseError();
72 // Begin of surface information.
73 TP
.AssertAndSkipToken("(");
75 // Texture generation mode has to be PlaneProj (==2) for all faces of a brush.
76 TP
.AssertAndSkipToken("2");
79 MFPlane
.ShiftU
=TP
.GetNextTokenAsFloat();
80 MFPlane
.ShiftV
=TP
.GetNextTokenAsFloat();
82 // The texture rotation is only relevant for CaWE. Just overread it here.
86 TP
.AssertAndSkipToken("(");
87 MFPlane
.U
.x
=TP
.GetNextTokenAsFloat();
88 MFPlane
.U
.y
=TP
.GetNextTokenAsFloat();
89 MFPlane
.U
.z
=TP
.GetNextTokenAsFloat();
90 TP
.AssertAndSkipToken(")");
93 TP
.AssertAndSkipToken("(");
94 MFPlane
.V
.x
=TP
.GetNextTokenAsFloat();
95 MFPlane
.V
.y
=TP
.GetNextTokenAsFloat();
96 MFPlane
.V
.z
=TP
.GetNextTokenAsFloat();
97 TP
.AssertAndSkipToken(")");
99 // End of surface information.
100 TP
.AssertAndSkipToken(")");
102 // Store plane in brush.
103 MFPlanes
.PushBack(MFPlane
);
108 MapFileBezierPatchT::MapFileBezierPatchT(TextParserT
& TP
)
110 TP
.AssertAndSkipToken("{");
113 const std::string MaterialName
=TP
.GetNextToken();
114 Material
=MaterialManager
->GetMaterial(MaterialName
);
118 Console
->Warning("Bezier Patch: Unknown material \""+MaterialName
+"\".\n");
119 throw TextParserT::ParseError();
122 // Skip additional surface information, as it is only relevant for CaWE.
123 TP
.SkipBlock("(", ")", false);
126 TP
.AssertAndSkipToken("(");
127 SizeX
=TP
.GetNextTokenAsInt();
128 SizeY
=TP
.GetNextTokenAsInt();
129 SubdivsHorz
=TP
.GetNextTokenAsInt();
130 SubdivsVert
=TP
.GetNextTokenAsInt();
131 TP
.AssertAndSkipToken(")");
133 for (unsigned long y
=0; y
<SizeY
; y
++)
134 for (unsigned long x
=0; x
<SizeX
; x
++)
136 TP
.AssertAndSkipToken("(");
138 for (unsigned long Coord
=0; Coord
<5; Coord
++)
140 ControlPoints
.PushBack(TP
.GetNextTokenAsFloat());
143 TP
.AssertAndSkipToken(")");
146 TP
.AssertAndSkipToken("}");
150 MapFileTerrainT::MapFileTerrainT(TextParserT
& TP
)
152 TP
.AssertAndSkipToken("{");
155 const std::string MaterialName
=TP
.GetNextToken();
156 Material
=MaterialManager
->GetMaterial(MaterialName
);
158 TP
.AssertAndSkipToken("(");
159 Bounds
.Min
.x
=TP
.GetNextTokenAsFloat();
160 Bounds
.Min
.y
=TP
.GetNextTokenAsFloat();
161 Bounds
.Min
.z
=TP
.GetNextTokenAsFloat();
162 TP
.AssertAndSkipToken(")");
164 TP
.AssertAndSkipToken("(");
165 Bounds
.Max
.x
=TP
.GetNextTokenAsFloat();
166 Bounds
.Max
.y
=TP
.GetNextTokenAsFloat();
167 Bounds
.Max
.z
=TP
.GetNextTokenAsFloat();
168 TP
.AssertAndSkipToken(")");
170 TP
.AssertAndSkipToken("(");
171 SideLength
=TP
.GetNextTokenAsInt();
172 TP
.AssertAndSkipToken(")");
175 HeightData
.PushBackEmpty(SideLength
*SideLength
);
177 for (unsigned long i
=0; i
<HeightData
.Size(); i
++)
178 HeightData
[i
]=TP
.GetNextTokenAsInt();
180 TP
.AssertAndSkipToken("}");
184 MapFilePlantT::MapFilePlantT(TextParserT
& TP
)
186 TP
.AssertAndSkipToken("{");
189 DescrFileName
=TP
.GetNextToken();
190 RandomSeed
=TP
.GetNextTokenAsInt();
192 TP
.AssertAndSkipToken("(");
193 Position
.x
=TP
.GetNextTokenAsFloat();
194 Position
.y
=TP
.GetNextTokenAsFloat();
195 Position
.z
=TP
.GetNextTokenAsFloat();
196 TP
.AssertAndSkipToken(")");
198 TP
.AssertAndSkipToken("(");
199 Angles
.x
=TP
.GetNextTokenAsFloat();
200 Angles
.y
=TP
.GetNextTokenAsFloat();
201 Angles
.z
=TP
.GetNextTokenAsFloat();
202 TP
.AssertAndSkipToken(")");
204 TP
.AssertAndSkipToken("}");
208 MapFileModelT::MapFileModelT(TextParserT
& TP
)
210 TP
.AssertAndSkipToken("{");
213 Model
=TP
.GetNextToken();
214 CollModel
=TP
.GetNextToken();
215 Label
=TP
.GetNextToken();
217 TP
.AssertAndSkipToken("(");
218 Origin
.x
=TP
.GetNextTokenAsFloat();
219 Origin
.y
=TP
.GetNextTokenAsFloat();
220 Origin
.z
=TP
.GetNextTokenAsFloat();
221 TP
.AssertAndSkipToken(")");
223 TP
.AssertAndSkipToken("(");
224 Angles
.x
=TP
.GetNextTokenAsFloat();
225 Angles
.y
=TP
.GetNextTokenAsFloat();
226 Angles
.z
=TP
.GetNextTokenAsFloat();
227 TP
.AssertAndSkipToken(")");
229 Scale
=TP
.GetNextTokenAsFloat();
230 SeqNumber
=TP
.GetNextTokenAsInt();
231 FrameOffset
=TP
.GetNextTokenAsFloat();
232 FrameTimeScale
=TP
.GetNextTokenAsFloat();
233 Animate
=(TP
.GetNextTokenAsInt()!=0);
235 TP
.AssertAndSkipToken("}");
239 MapFileEntityT::MapFileEntityT(unsigned long Index
, TextParserT
& TP
)
242 TP
.AssertAndSkipToken("{");
247 std::string Token
=TP
.GetNextToken();
249 if (Token
=="}") break; // End of Entity.
251 if (Token
=="{") // Begin of Brush.
253 MFBrushes
.PushBack(MapFileBrushT(TP
, MFBrushes
.Size()));
255 else if (Token
=="PatchDef") // Patch definition.
257 MFPatches
.PushBack(MapFileBezierPatchT(TP
));
259 else if (Token
=="TerrainDef") // Terrain definition.
261 MFTerrains
.PushBack(MapFileTerrainT(TP
));
263 else if (Token
=="PlantDef") // Plant definition.
265 MFPlants
.PushBack(MapFilePlantT(TP
));
267 else if (Token
=="ModelDef") // Model definition.
269 MFModels
.PushBack(MapFileModelT(TP
));
271 else // Property Pair.
273 const std::string Key
=Token
;
274 const std::string Value
=TP
.GetNextToken();
276 if (Key
=="{" || Key
=="}" || Key
=="(" || Key
==")") throw TextParserT::ParseError();
278 MFProperties
[Key
]=Value
;
284 void MapFileEntityT::Transform(const MatrixT
& Mat
)
286 for (unsigned int i
= 0; i
< MFBrushes
.Size(); i
++)
288 for (unsigned int p
= 0; p
< MFBrushes
[i
].MFPlanes
.Size(); p
++)
290 MapFilePlaneT
& MFP
= MFBrushes
[i
].MFPlanes
[p
];
291 const Vector3dT St
= Mat
.Mul1(MFP
.Plane
.Normal
* MFP
.Plane
.Dist
); // A point on the transformed plane ("Stützvektor").
293 MFP
.Plane
.Normal
= normalizeOr0(Mat
.Mul0(MFP
.Plane
.Normal
), 0.0001);
294 MFP
.Plane
.Dist
= dot(St
, MFP
.Plane
.Normal
);
296 MFP
.U
= Mat
.Mul0(MFP
.U
);
297 MFP
.V
= Mat
.Mul0(MFP
.V
);
299 // This follows the code in FaceNodeT::InitRenderMeshesAndMats().
300 MFP
.ShiftU
-= dot(Vector3dT(Mat
[0][3], Mat
[1][3], Mat
[2][3]), MFP
.U
) / dot(MFP
.U
, MFP
.U
);
301 MFP
.ShiftV
-= dot(Vector3dT(Mat
[0][3], Mat
[1][3], Mat
[2][3]), MFP
.V
) / dot(MFP
.V
, MFP
.V
);
305 for (unsigned int i
= 0; i
< MFPatches
.Size(); i
++)
307 ArrayT
<float>& CPs
= MFPatches
[i
].ControlPoints
;
309 for (unsigned long j
= 0; j
< CPs
.Size(); j
+= 5)
311 const Vector3fT v
= Mat
.Mul1(Vector3fT(CPs
[j
+ 0], CPs
[j
+ 1], CPs
[j
+ 2]));
319 for (unsigned int i
= 0; i
< MFTerrains
.Size(); i
++)
321 MFTerrains
[i
].Bounds
.Min
= Mat
.Mul1(MFTerrains
[i
].Bounds
.Min
);
322 MFTerrains
[i
].Bounds
.Max
= Mat
.Mul1(MFTerrains
[i
].Bounds
.Max
);
325 for (unsigned int i
= 0; i
< MFPlants
.Size(); i
++)
327 MFPlants
[i
].Position
= Mat
.Mul1(MFPlants
[i
].Position
);
330 for (unsigned int i
= 0; i
< MFModels
.Size(); i
++)
332 MFModels
[i
].Origin
= Mat
.Mul1(MFModels
[i
].Origin
);
337 static void MapFileVersionError(const std::string
& Msg
)
339 Console
->Print("Bad map file version: Expected 14, " + Msg
+ ".\n");
340 Console
->Print("To fix this, you can load your cmap file into CaWE and re-save it.\n");
341 Console
->Print("This will automatically update your file to the required version!\n");
343 Console
->Warning("Bad map file version: Expected 14, " + Msg
+ ".\n");
344 throw TextParserT::ParseError();
348 void cf::MapFileReadHeader(TextParserT
& TP
)
352 Console
->Warning("Unable to open map file.\n");
353 throw TextParserT::ParseError();
356 if (TP
.PeekNextToken()!="Version")
357 MapFileVersionError("but could not find the \"Version\" keyword");
359 TP
.AssertAndSkipToken("Version");
360 const std::string Version
=TP
.GetNextToken();
363 MapFileVersionError("got "+Version
);
365 // Skip any group definitions.
366 while (TP
.PeekNextToken()=="GroupDef")
369 // GroupDef 0 "control room" "rgb(189, 206, 184)" 1 1 0
370 for (unsigned int TokenNr
=0; TokenNr
<7; TokenNr
++) TP
.GetNextToken();