Merge branch 'master' into divVerent/farplanedist-sky-fix
[xonotic/netradiant.git] / plugins / mapq3 / parse.cpp
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #include "parse.h"
23
24 #include <list>
25
26 #include "ientity.h"
27 #include "ibrush.h"
28 #include "ipatch.h"
29 #include "ieclass.h"
30 #include "iscriplib.h"
31 #include "scenelib.h"
32 #include "string/string.h"
33 #include "stringio.h"
34 #include "eclasslib.h"
35
36 inline MapImporter* Node_getMapImporter( scene::Node& node ){
37         return NodeTypeCast<MapImporter>::cast( node );
38 }
39
40
41 typedef std::list< std::pair<CopiedString, CopiedString> > KeyValues;
42
43 NodeSmartReference g_nullNode( NewNullNode() );
44
45
46 NodeSmartReference Entity_create( EntityCreator& entityTable, EntityClass* entityClass, const KeyValues& keyValues ){
47         scene::Node& entity( entityTable.createEntity( entityClass ) );
48         for ( KeyValues::const_iterator i = keyValues.begin(); i != keyValues.end(); ++i )
49         {
50                 Node_getEntity( entity )->setKeyValue( ( *i ).first.c_str(), ( *i ).second.c_str() );
51         }
52         return NodeSmartReference( entity );
53 }
54
55 NodeSmartReference Entity_parseTokens( Tokeniser& tokeniser, EntityCreator& entityTable, const PrimitiveParser& parser, int index ){
56         NodeSmartReference entity( g_nullNode );
57         KeyValues keyValues;
58         const char* classname = "";
59
60         int count_primitives = 0;
61         while ( 1 )
62         {
63                 tokeniser.nextLine();
64                 const char* token = tokeniser.getToken();
65                 if ( token == 0 ) {
66                         Tokeniser_unexpectedError( tokeniser, token, "#entity-token" );
67                         return g_nullNode;
68                 }
69                 if ( !strcmp( token, "}" ) ) { // end entity
70                         if ( entity == g_nullNode ) {
71                                 // entity does not have brushes
72                                 entity = Entity_create( entityTable, GlobalEntityClassManager().findOrInsert( classname, false ), keyValues );
73                         }
74                         return entity;
75                 }
76                 else if ( !strcmp( token, "{" ) ) { // begin primitive
77                         if ( entity == g_nullNode ) {
78                                 // entity has brushes
79                                 entity = Entity_create( entityTable, GlobalEntityClassManager().findOrInsert( classname, true ), keyValues );
80                         }
81
82                         tokeniser.nextLine();
83
84                         NodeSmartReference primitive( parser.parsePrimitive( tokeniser ) );
85                         if ( primitive == g_nullNode || !Node_getMapImporter( primitive )->importTokens( tokeniser ) ) {
86                                 globalErrorStream() << "brush " << count_primitives << ": parse error\n";
87                                 return g_nullNode;
88                         }
89
90                         scene::Traversable* traversable = Node_getTraversable( entity );
91                         if ( Node_getEntity( entity )->isContainer() && traversable != 0 ) {
92                                 traversable->insert( primitive );
93                         }
94                         else
95                         {
96                                 globalErrorStream() << "entity " << index << ": type " << classname << ": discarding brush " << count_primitives << "\n";
97                         }
98                         ++count_primitives;
99                 }
100                 else // epair
101                 {
102                         CopiedString key( token );
103                         token = tokeniser.getToken();
104                         if ( token == 0 ) {
105                                 Tokeniser_unexpectedError( tokeniser, token, "#epair-value" );
106                                 return g_nullNode;
107                         }
108                         keyValues.push_back( KeyValues::value_type( key, token ) );
109                         if ( string_equal( key.c_str(), "classname" ) ) {
110                                 classname = keyValues.back().second.c_str();
111                         }
112                 }
113         }
114         // unreachable code
115         return g_nullNode;
116 }
117
118 void Map_Read( scene::Node& root, Tokeniser& tokeniser, EntityCreator& entityTable, const PrimitiveParser& parser ){
119         int count_entities = 0;
120         for (;; )
121         {
122                 tokeniser.nextLine();
123                 if ( !tokeniser.getToken() ) { // { or 0
124                         break;
125                 }
126
127                 NodeSmartReference entity( Entity_parseTokens( tokeniser, entityTable, parser, count_entities ) );
128
129                 if ( entity == g_nullNode ) {
130                         globalErrorStream() << "entity " << count_entities << ": parse error\n";
131                         return;
132                 }
133
134                 Node_getTraversable( root )->insert( entity );
135
136                 ++count_entities;
137         }
138 }