root/cafu/trunk/CaWE/Load_D3_map.cpp

Revision 455, 14.8 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 "Options.hpp"
25#include "ParentFrame.hpp"
26#include "Load_MatReplMan.hpp"
27#include "MapDocument.hpp"
28#include "MapEntity.hpp"
29#include "MapFace.hpp"
30#include "MapBrush.hpp"
31#include "MapBezierPatch.hpp"
32#include "Math3D/Vector3.hpp"
33#include "Math3D/Plane3.hpp"
34#include "TextParser/TextParser.hpp"
35#include "SceneGraph/LightMapMan.hpp"
36
37#include "wx/wx.h"
38#include "wx/progdlg.h"
39
40
41static MatReplaceManT* g_MatReplaceMan=NULL;
42
43
44MapFaceT MapFaceT::Create_D3_map(TextParserT& TP, const Vector3fT& Origin, EditorMatManT& MatMan)
45{
46    MapFaceT Face;
47
48    TP.AssertAndSkipToken("(");
49    Face.m_Plane.Normal.x= TP.GetNextTokenAsFloat();
50    Face.m_Plane.Normal.y= TP.GetNextTokenAsFloat();
51    Face.m_Plane.Normal.z= TP.GetNextTokenAsFloat();
52    Face.m_Plane.Dist    =-TP.GetNextTokenAsFloat();    // Yes, D3's plane equation has Dist on the other side of the = than mine.
53    TP.AssertAndSkipToken(")");
54
55    // Materials are normally plane projected on faces.
56    Face.m_SurfaceInfo.TexCoordGenMode=PlaneProj;
57
58    // Translate the Face.m_Plane according to Origin.
59    // This is done by getting a point on the plane (e.g. the Stuetzvektor),
60    // offsetting it by Origin, and then recomputing the Face.m_Plane.Dist.
61    Face.m_Plane.Dist=dot(Face.m_Plane.Normal*Face.m_Plane.Dist + Origin, Face.m_Plane.Normal);
62
63
64    Vector3fT Span1;
65    Vector3fT Span2;
66
67    Face.m_Plane.GetSpanVectorsByRotation(Span1, Span2);
68
69    // Assert that the output is as expected.
70    wxASSERT(fabs(dot(Face.m_Plane.Normal, Span1))<0.01);
71    wxASSERT(fabs(dot(Face.m_Plane.Normal, Span2))<0.01);
72    wxASSERT(fabs(dot(Span1, Span2))<0.01);
73
74    Face.m_PlanePoints[0]=Face.m_Plane.Normal*Face.m_Plane.Dist;
75
76#if 1
77    // We need to find three linear independent points in Face.m_Plane, which is pretty straightforward given Span1 and Span2.
78    Face.m_PlanePoints[1]=Face.m_PlanePoints[0]+Span1*1000.0;
79    Face.m_PlanePoints[2]=Face.m_PlanePoints[0]+Span2*1000.0;
80#else
81    // This method does not rely on Span1 and Span2.
82    Vector3dT AbsNorm(fabs(Normal.x), fabs(Normal.y), fabs(Normal.z));
83
84    // Note that the ">=" (vs. ">") are very important here!
85    if (AbsNorm.x>=AbsNorm.y && AbsNorm.x>=AbsNorm.z)
86    {
87        // The x-component has the biggest magnitude.
88        Face.m_PlanePoints[1][1]=Face.m_PlanePoints[0][1]+1000;
89        Face.m_PlanePoints[1][2]=Face.m_PlanePoints[0][2];
90        Face.m_PlanePoints[1][0]=(Dist-Normal.y*Face.m_PlanePoints[1][1]-Normal.z*Face.m_PlanePoints[1][2])/Normal.x;
91
92        Face.m_PlanePoints[2][1]=Face.m_PlanePoints[0][1];
93        Face.m_PlanePoints[2][2]=Face.m_PlanePoints[0][2]+1000;
94        Face.m_PlanePoints[2][0]=(Dist-Normal.y*Face.m_PlanePoints[2][1]-Normal.z*Face.m_PlanePoints[2][2])/Normal.x;
95    }
96    else if (AbsNorm.y>=AbsNorm.x && AbsNorm.y>=AbsNorm.z)
97    {
98        // The y-component has the biggest magnitude.
99        Face.m_PlanePoints[1][0]=Face.m_PlanePoints[0][0]+1000;
100        Face.m_PlanePoints[1][2]=Face.m_PlanePoints[0][2];
101        Face.m_PlanePoints[1][1]=(Dist-Normal.x*Face.m_PlanePoints[1][0]-Normal.z*Face.m_PlanePoints[1][2])/Normal.y;
102
103        Face.m_PlanePoints[2][0]=Face.m_PlanePoints[0][0];
104        Face.m_PlanePoints[2][2]=Face.m_PlanePoints[0][2]+1000;
105        Face.m_PlanePoints[2][1]=(Dist-Normal.x*Face.m_PlanePoints[2][0]-Normal.z*Face.m_PlanePoints[2][2])/Normal.y;
106    }
107    else
108    {
109        // The z-component has the biggest magnitude.
110        Face.m_PlanePoints[1][0]=Face.m_PlanePoints[0][0]+1000;
111        Face.m_PlanePoints[1][1]=Face.m_PlanePoints[0][1];
112        Face.m_PlanePoints[1][2]=(Dist-Normal.x*Face.m_PlanePoints[1][0]-Normal.y*Face.m_PlanePoints[1][1])/Normal.z;
113
114        Face.m_PlanePoints[2][0]=Face.m_PlanePoints[0][0];
115        Face.m_PlanePoints[2][1]=Face.m_PlanePoints[0][1]+1000;
116        Face.m_PlanePoints[2][2]=(Dist-Normal.x*Face.m_PlanePoints[2][0]-Normal.y*Face.m_PlanePoints[2][1])/Normal.z;
117    }
118#endif
119
120#ifndef NDEBUG
121    // Verify the correctness of the planepts!
122    Plane3fT CheckPlane(Face.m_PlanePoints[0], Face.m_PlanePoints[1], Face.m_PlanePoints[2], 0.1f);
123
124    wxASSERT(dot(CheckPlane.Normal, Face.m_Plane.Normal)>=0.999 && fabs(CheckPlane.Dist-Face.m_Plane.Dist)<0.1);
125#endif
126
127
128    // Read the 2x3 texture matrix.
129    TP.AssertAndSkipToken("(");
130
131    Vector3dT Row1;
132    TP.AssertAndSkipToken("(");
133    Row1.x=TP.GetNextTokenAsFloat();
134    Row1.y=TP.GetNextTokenAsFloat();
135    Face.m_SurfaceInfo.Trans[0]=TP.GetNextTokenAsFloat();     // Texture offset (translation) in U-direction.
136    TP.AssertAndSkipToken(")");
137
138    Vector3dT Row2;
139    TP.AssertAndSkipToken("(");
140    Row2.x=TP.GetNextTokenAsFloat();
141    Row2.y=TP.GetNextTokenAsFloat();
142    Face.m_SurfaceInfo.Trans[1]=TP.GetNextTokenAsFloat();     // Texture offset (translation) in V-direction.
143    TP.AssertAndSkipToken(")");
144
145    TP.AssertAndSkipToken(")");
146
147
148    // Read the material name and the remaining three zeros.
149    wxString MatName=TP.GetNextToken();
150
151    MatName=g_MatReplaceMan->GetReplacement(MatName);
152
153    if (TP.GetNextToken()!="0") throw TextParserT::ParseError();
154    if (TP.GetNextToken()!="0") throw TextParserT::ParseError();
155    if (TP.GetNextToken()!="0") throw TextParserT::ParseError();
156
157
158    Face.m_SurfaceInfo.Rotate=0;     // Maybe that's one of the above trailing zeros?
159
160
161    // Compute the scales from the axis lengths.
162    Vector3fT UAxis_=Span1*Row1.x + Span2*Row1.y; float LenU=length(UAxis_);
163    Vector3fT VAxis_=Span1*Row2.x + Span2*Row2.y; float LenV=length(VAxis_);
164
165    if (LenU<0.000001 || LenV<0.000001)
166    {
167        // The Row1 or Row2 components might all be zero.
168        // I've seen this for example with the Doom3 "textures/common/caulk" material.
169        UAxis_=Span1; LenU=1.0;
170        VAxis_=Span2; LenV=1.0;
171    }
172
173    Face.m_SurfaceInfo.Scale[0]=LenU;
174    Face.m_SurfaceInfo.Scale[1]=LenV;
175
176    // Normalize the axes lengths.
177    Face.m_SurfaceInfo.UAxis=UAxis_/LenU;
178    Face.m_SurfaceInfo.VAxis=VAxis_/LenV;
179
180    Face.m_Material=MatMan.FindMaterial(MatName, true /*return dummy if not found*/);
181
182    return Face;
183}
184
185
186MapBrushT* MapBrushT::Create_D3_map(TextParserT& TP, const Vector3fT& Origin, unsigned long EntityNr, unsigned long PrimitiveNr, EditorMatManT& MatMan)
187{
188    MapBrushT* Brush=new MapBrushT();
189
190    if (TP.GetNextToken()!="{") throw TextParserT::ParseError();
191
192    Brush->m_Faces.Clear();
193
194    while (true)
195    {
196        std::string Token=TP.GetNextToken();
197        TP.PutBack(Token);
198
199        if (Token!="(") break;
200
201        Brush->m_Faces.PushBack(MapFaceT::Create_D3_map(TP, Origin, MatMan));
202    }
203
204    if (TP.GetNextToken()!="}") throw TextParserT::ParseError();
205
206    Brush->CompleteFaceVertices();
207
208    if (!Brush->IsValid())
209    {
210        wxLogWarning("Entity %lu, primitive %lu: The brush could not be created from its planes.\n", EntityNr, PrimitiveNr);
211    }
212
213    wxASSERT(Brush->IsValid());
214    return Brush;
215}
216
217
218void MapBezierPatchT::Load_D3_map(TextParserT& TP, unsigned long patchDef, EditorMatManT& MatMan)
219{
220    if (patchDef!=2 && patchDef!=3) throw TextParserT::ParseError();
221
222    if (TP.GetNextToken()!="{") throw TextParserT::ParseError();
223
224    wxString texname = TP.GetNextToken();
225    texname=g_MatReplaceMan->GetReplacement(texname);
226    SetMaterial(MatMan.FindMaterial(texname, true /*Create dummy if not found.*/));
227
228    // Bezier patches have custom texture coordinates per default.
229    SurfaceInfo.TexCoordGenMode=Custom;
230
231    TP.AssertAndSkipToken("(");
232
233    unsigned long width =TP.GetNextTokenAsInt();
234    unsigned long height=TP.GetNextTokenAsInt();
235
236    SetSize(width, height);
237
238    // "patchDef3"s seem to *always* specify explicit number of subdivisions... will they obsolete or complement "patchDef2"s?
239    SubdivsHorz=(patchDef==3) ? TP.GetNextTokenAsInt() : -1;
240    SubdivsVert=(patchDef==3) ? TP.GetNextTokenAsInt() : -1;
241
242    TP.GetNextToken();  // "Contents" (unused - skip).
243    TP.GetNextToken();  // "Flags"    (unused - skip).
244    TP.GetNextToken();  // "Value"    (unused - skip).
245
246    TP.AssertAndSkipToken(")");
247
248
249    TP.AssertAndSkipToken("(");
250
251    // js todo: D3 patch loading: d3 patches and cawe patches are defined and saved differently, shoudl I revert to the D3 representation of a patch?
252    for (unsigned long x=0; x<cv_Width; x++)
253    {
254        TP.AssertAndSkipToken("(");
255
256        for (int y=int(cv_Height)-1; y>=0; y--)
257        {
258            TP.AssertAndSkipToken("(");
259
260            Vector3fT Pos;
261            Pos.x=TP.GetNextTokenAsFloat();
262            Pos.y=TP.GetNextTokenAsFloat();
263            Pos.z=TP.GetNextTokenAsFloat();
264            SetCvPos(x, y, Pos);
265
266            Vector3fT TexCoord;
267            TexCoord.x=TP.GetNextTokenAsFloat();
268            TexCoord.y=TP.GetNextTokenAsFloat();
269            SetCvUV(x, y, TexCoord);
270
271            TP.AssertAndSkipToken(")");
272        }
273
274        TP.AssertAndSkipToken(")");
275    }
276
277    TP.AssertAndSkipToken(")");
278    if (TP.GetNextToken()!="}") throw TextParserT::ParseError();
279}
280
281
282void MapEntityBaseT::Load_D3_map(TextParserT& TP, MapDocumentT& MapDoc, wxProgressDialog* ProgressDialog, unsigned long EntityNr)
283{
284    EditorMatManT& MatMan=MapDoc.GetGameConfig()->GetMatMan();
285    static MatReplaceManT MatReplaceMan("Doom 3", MatMan.GetMaterials());
286
287    if (EntityNr==0)
288    {
289        g_MatReplaceMan=&MatReplaceMan;
290
291        // See if the Doom3 map file begins with "Version 2".
292        if (TP.GetNextToken()!="Version") throw TextParserT::ParseError();
293        const int MapFileVersion=TP.GetNextTokenAsInt();
294
295        if (MapFileVersion!=2)
296        {
297            wxMessageBox(wxString::Format("Expected Doom3 map file version 2, but found version %i.", MapFileVersion), "Could not import the D3 map file.");
298            throw TextParserT::ParseError();
299        }
300    }
301
302    TP.AssertAndSkipToken("{");
303
304    while (true)
305    {
306        std::string Token=TP.GetNextToken();
307        TP.PutBack(Token);
308
309        if (Token=="{") break;  // This is the beginning of a primitive - done reading properties.
310        if (Token=="}") break;  // This is the end of the entity - done reading properties, too.
311
312        std::string Key  =TP.GetNextToken();
313        std::string Value=TP.GetNextToken();
314
315        if (Key=="angle")
316        {
317            Key="angles";
318
319                 if (Value=="-1") Value="-90 0 0";
320            else if (Value=="-2") Value="90 0 0";
321            else                  Value="0 "+Value+" 0";
322        }
323
324        // Add the property to the entity.
325        m_Properties.PushBack(EntPropertyT(Key, Value));
326    }
327
328    Vector3fT     OriginVec;
329    EntPropertyT* OriginProp=FindProperty("origin");
330
331    if (OriginProp) OriginVec=OriginProp->GetVector3f();
332
333    unsigned long NrOfPrims=0;
334
335    while (true)
336    {
337        std::string Token=TP.GetNextToken();
338
339        if (Token!="{")
340        {
341            TP.PutBack(Token);
342            break;
343        }
344
345        // The "{" signals the begin of a primitive.
346        Token=TP.GetNextToken();
347
348        if (Token=="brushDef3")
349        {
350            // It seems that in D3 map files, brushes are offset by the "origin" property of the entity they are in.
351            AddPrim(MapBrushT::Create_D3_map(TP, OriginVec, EntityNr, NrOfPrims, MatMan));
352        }
353        else if (Token=="patchDef2")
354        {
355            MapBezierPatchT* BP=new MapBezierPatchT(MatMan.GetDefaultMaterial(), MapDoc.GetLightMapMan());
356
357            BP->Load_D3_map(TP, 2, MatMan);
358            AddPrim(BP);
359        }
360        else if (Token=="patchDef3")
361        {
362            MapBezierPatchT* BP=new MapBezierPatchT(MatMan.GetDefaultMaterial(), MapDoc.GetLightMapMan());
363
364            BP->Load_D3_map(TP, 3, MatMan);
365            AddPrim(BP);
366        }
367        else throw TextParserT::ParseError();
368
369        // The "}" signals the end of the primitive.
370        if (TP.GetNextToken()!="}") throw TextParserT::ParseError();
371
372
373        if (ProgressDialog!=NULL && (NrOfPrims % 5)==0) ProgressDialog->Update(int(TP.GetReadPosPercent()*100.0));
374
375        NrOfPrims++;
376    }
377
378    TP.AssertAndSkipToken("}");
379
380
381    // "Post-process" the entity properties.
382    if (EntityNr>0)
383    {
384        int Index=-1;
385
386        // Set our origin from the "origin" property, then remove it from the properties list:
387        // the origin is a special-case that is not defined by the EntityClassDefs.lua scripts.
388        MapEntityT*   Ent =dynamic_cast<MapEntityT*>(this);
389        EntPropertyT* Prop=FindProperty("origin", &Index);
390        const bool    FoundOrigin=(Prop!=NULL);
391
392        if (Ent!=NULL && Prop!=NULL)
393        {
394            Ent->SetOrigin(Prop->GetVector3f());
395            m_Properties.RemoveAtAndKeepOrder(Index);
396        }
397
398        // Set our class from the "classname" property, and remove it as well:
399        // just like the "origin" property, it is a special case wrt. the EntityClassDefs.lua scripts.
400        Prop=FindProperty("classname", &Index);
401
402        if (Prop!=NULL && Prop->Value!="")
403        {
404            const wxString      ClassName  =Prop->Value;
405            const EntityClassT* EntityClass=MapDoc.GetGameConfig()->FindClass(ClassName);
406
407            SetClass(EntityClass!=NULL ? EntityClass : MapDoc.FindOrCreateUnknownClass(ClassName, FoundOrigin));
408        }
409        else
410        {
411            SetClass(MapDoc.FindOrCreateUnknownClass("undefined", FoundOrigin));
412        }
413    }
414
415    // Remove our "classname" property, no matter which value it has.
416    // For worlds, we've set our entity class to "worldspawn" in the constructor already, the map file cannot override this.
417    // For entities, the proper class has been set above.
418    int Index;
419    if (FindProperty("classname", &Index)!=NULL)
420        m_Properties.RemoveAtAndKeepOrder(Index);
421}
Note: See TracBrowser for help on using the browser.