root/cafu/trunk/CaWE/Load_HL2_vmf.cpp

Revision 455, 11.5 KB (checked in by Carsten, 4 months ago)

Updated copyright banners (in C++ files).

Line 
1/*
2=================================================================================
3This file is part of Cafu, the open-source game engine and graphics engine
4for multiplayer, cross-platform, real-time 3D action.
5Copyright (C) 2002-2012 Carsten Fuchs Software.
6
7Cafu is free software: you can redistribute it and/or modify it under the terms
8of the GNU General Public License as published by the Free Software Foundation,
9either version 3 of the License, or (at your option) any later version.
10
11Cafu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with Cafu. If not, see <http://www.gnu.org/licenses/>.
17
18For support and more information about Cafu, visit us at <http://www.cafu.de>.
19=================================================================================
20*/
21
22#include "EntityClass.hpp"
23#include "GameConfig.hpp"
24#include "Load_MatReplMan.hpp"
25#include "MapBrush.hpp"
26#include "MapDocument.hpp"
27#include "MapEntity.hpp"
28#include "MapFace.hpp"
29
30#include "TextParser/TextParser.hpp"
31
32#include "wx/wx.h"
33#include "wx/progdlg.h"
34
35
36static MatReplaceManT* g_MatReplaceMan=NULL;
37
38
39// This function reads a "side" chunk.
40// The chunk name has already been read from TP, next token must be the opening "{".
41MapFaceT MapFaceT::Create_HL2_vmf(TextParserT& TP, EditorMatManT& MatMan)
42{
43    MapFaceT Face;
44    wxString MaterialName;
45
46    Face.m_SurfaceInfo.TexCoordGenMode=PlaneProj;
47
48    TP.AssertAndSkipToken("{");
49
50    while (TP.PeekNextToken()!="}")
51    {
52        const std::string Key=TP.GetNextToken();
53
54        if (Key=="plane")
55        {
56            TextParserT ValueTP(TP.GetNextToken().c_str(), "()", false);
57
58            if (ValueTP.GetNextToken()!="(") throw TextParserT::ParseError();
59            Face.m_PlanePoints[0].x=ValueTP.GetNextTokenAsFloat();
60            Face.m_PlanePoints[0].y=ValueTP.GetNextTokenAsFloat();
61            Face.m_PlanePoints[0].z=ValueTP.GetNextTokenAsFloat();
62            if (ValueTP.GetNextToken()!=")") throw TextParserT::ParseError();
63
64            if (ValueTP.GetNextToken()!="(") throw TextParserT::ParseError();
65            Face.m_PlanePoints[1].x=ValueTP.GetNextTokenAsFloat();
66            Face.m_PlanePoints[1].y=ValueTP.GetNextTokenAsFloat();
67            Face.m_PlanePoints[1].z=ValueTP.GetNextTokenAsFloat();
68            if (ValueTP.GetNextToken()!=")") throw TextParserT::ParseError();
69
70            if (ValueTP.GetNextToken()!="(") throw TextParserT::ParseError();
71            Face.m_PlanePoints[2].x=ValueTP.GetNextTokenAsFloat();
72            Face.m_PlanePoints[2].y=ValueTP.GetNextTokenAsFloat();
73            Face.m_PlanePoints[2].z=ValueTP.GetNextTokenAsFloat();
74            if (ValueTP.GetNextToken()!=")") throw TextParserT::ParseError();
75
76            Face.m_Plane=Plane3fT(Face.m_PlanePoints[0], Face.m_PlanePoints[1], Face.m_PlanePoints[2], 0.1f);
77        }
78        else if (Key=="material")
79        {
80            MaterialName=g_MatReplaceMan->GetReplacement(TP.GetNextToken());
81        }
82        else if (Key=="uaxis")
83        {
84            TextParserT ValueTP(TP.GetNextToken().c_str(), "[]", false);
85
86            if (ValueTP.GetNextToken()!="[") throw TextParserT::ParseError();
87            Face.m_SurfaceInfo.UAxis.x=ValueTP.GetNextTokenAsFloat();
88            Face.m_SurfaceInfo.UAxis.y=ValueTP.GetNextTokenAsFloat();
89            Face.m_SurfaceInfo.UAxis.z=ValueTP.GetNextTokenAsFloat();
90            Face.m_SurfaceInfo.Trans[0]=ValueTP.GetNextTokenAsFloat();
91            if (ValueTP.GetNextToken()!="]") throw TextParserT::ParseError();
92
93            // Should use the true texture width here, which is unfortunately impossible to know...
94            Face.m_SurfaceInfo.Scale[0]=1.0f/(ValueTP.GetNextTokenAsFloat()*256.0f);
95        }
96        else if (Key=="vaxis")
97        {
98            TextParserT ValueTP(TP.GetNextToken().c_str(), "[]", false);
99
100            if (ValueTP.GetNextToken()!="[") throw TextParserT::ParseError();
101            Face.m_SurfaceInfo.VAxis.x=ValueTP.GetNextTokenAsFloat();
102            Face.m_SurfaceInfo.VAxis.y=ValueTP.GetNextTokenAsFloat();
103            Face.m_SurfaceInfo.VAxis.z=ValueTP.GetNextTokenAsFloat();
104            Face.m_SurfaceInfo.Trans[1]=ValueTP.GetNextTokenAsFloat();
105            if (ValueTP.GetNextToken()!="]") throw TextParserT::ParseError();
106
107            // Should use the true texture height here, which is unfortunately impossible to know...
108            Face.m_SurfaceInfo.Scale[1]=1.0f/(ValueTP.GetNextTokenAsFloat()*256.0f);
109        }
110        else if (Key=="rotation")
111        {
112            Face.m_SurfaceInfo.Rotate=TP.GetNextTokenAsFloat();
113        }
114        else
115        {
116            // It's a sub-chunk or a property that we don't know and thus knowingly don't handle.
117            const std::string Value=TP.GetNextToken();
118
119            if (Value=="{") TP.SkipBlock("{", "}", true);
120
121            if (Key!="dispinfo" && Key!="id" && Key!="lightmapscale" && Key!="smoothing_groups")
122            {
123                // If Key has a value that I've never seen during development, log the occurrence.
124                wxLogWarning(wxString("Unknown property or sub-chunk \"")+Key.c_str()+"\" in chunk \"side\".\n");
125            }
126        }
127    }
128
129    TP.AssertAndSkipToken("}");
130
131    Face.m_Material=MatMan.FindMaterial(MaterialName, true /*return dummy if not found*/);
132    return Face;
133}
134
135
136// This function reads a "solid" chunk.
137// The chunk name has already been read from TP, next token must be the opening "{".
138MapBrushT* MapBrushT::Create_HL2_vmf(TextParserT& TP, EditorMatManT& MatMan)
139{
140    MapBrushT* Brush=new MapBrushT();
141
142    TP.AssertAndSkipToken("{");
143
144    Brush->m_Faces.Clear();
145
146    while (TP.PeekNextToken()!="}")
147    {
148        const std::string SubChName=TP.GetNextToken();
149
150        if (SubChName=="side")
151        {
152            Brush->m_Faces.PushBack(MapFaceT::Create_HL2_vmf(TP, MatMan));
153        }
154        else
155        {
156            // It's a sub-chunk or a property that we don't know and thus knowingly don't handle.
157            const std::string Value=TP.GetNextToken();
158
159            if (Value=="{") TP.SkipBlock("{", "}", true);
160
161            if (SubChName!="editor" && SubChName!="id")
162            {
163                // If Key has a value that I've never seen during development, log the occurrence.
164                wxLogWarning(wxString("Unknown property or sub-chunk \"")+SubChName.c_str()+"\" in chunk \"solid\".\n");
165            }
166        }
167    }
168
169    TP.AssertAndSkipToken("}");
170
171    Brush->CompleteFaceVertices();
172
173    // Create the brush using the planes that were read from the vmf file.
174    if (!Brush->IsValid())
175    {
176     // wxLogWarning(wxString::Format("Entity %lu, Primitive %lu: The brush could not be created from its planes.\n", EntityNr, PrimitiveNr));
177        wxLogWarning(wxString::Format("A brush could not be created from its planes.\n"));
178    }
179
180    wxASSERT(Brush->IsValid());
181    return Brush;
182}
183
184
185/// This method reads a "world" or "entity" chunk.
186/// The chunk name has already been read from TP, next token must be the opening "{".
187void MapEntityBaseT::Load_HL2_vmf(TextParserT& TP, MapDocumentT& MapDoc, wxProgressDialog* ProgressDialog, unsigned long EntityNr)
188{
189    static MatReplaceManT MatReplaceMan("HL2", MapDoc.GetGameConfig()->GetMatMan().GetMaterials());
190
191    if (EntityNr==0)
192    {
193        g_MatReplaceMan=&MatReplaceMan;
194    }
195
196    TP.AssertAndSkipToken("{");
197
198    while (TP.PeekNextToken()!="}")
199    {
200        const std::string SubChName=TP.GetNextToken();
201
202        if (SubChName=="solid")
203        {
204            if (TP.PeekNextToken()!="{")
205            {
206                // Yes, I've seen entities that contained lines like: "solid" "6"
207                TP.GetNextToken();
208                continue;
209            }
210
211            AddPrim(MapBrushT::Create_HL2_vmf(TP, MapDoc.GetGameConfig()->GetMatMan()));
212        }
213        else
214        {
215            // Ok, SubChName is likely the key of a property, and the next token is the value,
216            // *unless* it's a sub-chunk that we don't know about.
217            const std::string Value=TP.GetNextToken();
218
219            if (Value=="{")
220            {
221                // It's a sub-chunk that we don't know and thus knowingly don't handle.
222                // The best we can do is ignore (skip) it, but also record it,
223                // because I'd like to know which chunk type I don't know.
224                TP.SkipBlock("{", "}", true);
225
226                if (SubChName!="editor" && SubChName!="group" && SubChName!="connections")
227                {
228                    wxLogWarning(wxString("Unknown sub-chunk \"")+SubChName+"\" in entity %lu.\n", EntityNr);
229                }
230            }
231            else
232            {
233                // Add the property to the entity.
234                if (EntityNr>0 && SubChName=="angle")
235                {
236                    // Convert an "angle" key into a triple of "angles".
237                    // (Do "angle" keys actually still occur in VMF files btw.??)
238                         if (Value=="-1") m_Properties.PushBack(EntPropertyT("angles", "-90 0 0"));
239                    else if (Value=="-2") m_Properties.PushBack(EntPropertyT("angles", "90 0 0"));
240                    else                  m_Properties.PushBack(EntPropertyT("angles", "0 "+Value+" 0"));
241                }
242                else
243                {
244                    m_Properties.PushBack(EntPropertyT(SubChName, Value));
245                }
246            }
247        }
248
249        if (ProgressDialog!=NULL) ProgressDialog->Update(int(TP.GetReadPosPercent()*100.0));
250    }
251
252    TP.AssertAndSkipToken("}");
253
254
255    // "Post-process" the entity properties.
256    if (EntityNr>0)
257    {
258        int Index=-1;
259
260        // Set our origin from the "origin" property, then remove it from the properties list:
261        // the origin is a special-case that is not defined by the EntityClassDefs.lua scripts.
262        MapEntityT*   Ent =dynamic_cast<MapEntityT*>(this);
263        EntPropertyT* Prop=FindProperty("origin", &Index);
264        const bool    FoundOrigin=(Prop!=NULL);
265
266        if (Ent!=NULL && Prop!=NULL)
267        {
268            Ent->SetOrigin(Prop->GetVector3f());
269            m_Properties.RemoveAtAndKeepOrder(Index);
270        }
271
272        // Set our class from the "classname" property, and remove it as well:
273        // just like the "origin" property, it is a special case wrt. the EntityClassDefs.lua scripts.
274        Prop=FindProperty("classname", &Index);
275
276        if (Prop!=NULL && Prop->Value!="")
277        {
278            const wxString      ClassName  =Prop->Value;
279            const EntityClassT* EntityClass=MapDoc.GetGameConfig()->FindClass(ClassName);
280
281            SetClass(EntityClass!=NULL ? EntityClass : MapDoc.FindOrCreateUnknownClass(ClassName, FoundOrigin));
282        }
283        else
284        {
285            SetClass(MapDoc.FindOrCreateUnknownClass("undefined", FoundOrigin));
286        }
287    }
288
289    // Remove our "classname" property, no matter which value it has.
290    // For worlds, we've set our entity class to "worldspawn" in the constructor already, the map file cannot override this.
291    // For entities, the proper class has been set above.
292    int Index;
293    if (FindProperty("classname", &Index)!=NULL)
294        m_Properties.RemoveAtAndKeepOrder(Index);
295}
Note: See TracBrowser for help on using the browser.