Fix issue in Rocket.lua script.
[Cafu-Engine.git] / Libs / MapFile.cpp
blob66a81c9b149a0a8e2f8cea3d9c3ef6a7156be9af
1 /*
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.
5 */
7 #include "MapFile.hpp"
8 #include "ConsoleCommands/Console.hpp"
9 #include "MaterialSystem/MaterialManager.hpp"
10 #include "TextParser/TextParser.hpp"
13 using namespace cf;
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)
28 SkipGroupDef(TP);
30 while (true)
32 std::string Token=TP.GetNextToken();
34 if (Token=="}") break; // End of brush
36 // Read the three point plane definition.
37 TP.PutBack(Token);
38 MapFilePlaneT MFPlane;
39 Vector3dT Points[3];
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(")");
50 try
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");
78 // Texture shift.
79 MFPlane.ShiftU=TP.GetNextTokenAsFloat();
80 MFPlane.ShiftV=TP.GetNextTokenAsFloat();
82 // The texture rotation is only relevant for CaWE. Just overread it here.
83 TP.GetNextToken();
85 // Texture U axis.
86 TP.AssertAndSkipToken("(");
87 MFPlane.U.x=TP.GetNextTokenAsFloat();
88 MFPlane.U.y=TP.GetNextTokenAsFloat();
89 MFPlane.U.z=TP.GetNextTokenAsFloat();
90 TP.AssertAndSkipToken(")");
92 // Texture V axis.
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("{");
111 SkipGroupDef(TP);
113 const std::string MaterialName=TP.GetNextToken();
114 Material=MaterialManager->GetMaterial(MaterialName);
116 if (Material==NULL)
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);
125 // Dimensions
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("{");
153 SkipGroupDef(TP);
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(")");
174 HeightData.Clear();
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("{");
187 SkipGroupDef(TP);
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("{");
211 SkipGroupDef(TP);
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)
240 : MFIndex(Index)
242 TP.AssertAndSkipToken("{");
243 SkipGroupDef(TP);
245 while (true)
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]));
313 CPs[j + 0] = v.x;
314 CPs[j + 1] = v.y;
315 CPs[j + 2] = v.z;
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)
350 if (TP.IsAtEOF())
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();
362 if (Version != "14")
363 MapFileVersionError("got "+Version);
365 // Skip any group definitions.
366 while (TP.PeekNextToken()=="GroupDef")
368 // Example line:
369 // GroupDef 0 "control room" "rgb(189, 206, 184)" 1 1 0
370 for (unsigned int TokenNr=0; TokenNr<7; TokenNr++) TP.GetNextToken();