Index: darkradiant/configure.ac
===================================================================
--- darkradiant/configure.ac	(Revision 5765)
+++ darkradiant/configure.ac	(Arbeitskopie)
@@ -221,6 +221,7 @@
                  plugins/grid/Makefile
                  plugins/image/Makefile
                  plugins/mapdoom3/Makefile
+                 plugins/mapquake2/Makefile
                  plugins/md5model/Makefile
                  plugins/model/Makefile
                  plugins/particles/Makefile
Index: darkradiant/plugins/Makefile.am
===================================================================
--- darkradiant/plugins/Makefile.am	(Revision 5765)
+++ darkradiant/plugins/Makefile.am	(Arbeitskopie)
@@ -11,6 +11,7 @@
           grid \
           image \
           mapdoom3 \
+          mapquake2 \
           md5model \
           model \
           particles \
Index: darkradiant/plugins/mapquake2/Quake2MapFormat.cpp
===================================================================
--- darkradiant/plugins/mapquake2/Quake2MapFormat.cpp	(Revision 0)
+++ darkradiant/plugins/mapquake2/Quake2MapFormat.cpp	(Revision 0)
@@ -0,0 +1,92 @@
+#include "Quake2MapFormat.h"
+
+#include "ifiletypes.h"
+#include "ieclass.h"
+#include "ibrush.h"
+#include "ipatch.h"
+#include "iregistry.h"
+#include "igroupnode.h"
+
+#include "parser/DefTokeniser.h"
+
+#include "Quake2NodeImporter.h"
+#include "Quake2NodeExporter.h"
+#include "scenelib.h"
+
+#include "i18n.h"
+#include "Tokens.h"
+#include "MapImportInfo.h"
+#include "MapExportInfo.h"
+
+#include <boost/lexical_cast.hpp>
+#include "primitiveparsers/Brush.h"
+
+namespace map {
+
+	namespace {
+		const std::string RKEY_PRECISION = "game/mapFormat/floatPrecision";
+	}
+
+// RegisterableModule implementation
+const std::string& Quake2MapFormat::getName() const {
+	static std::string _name("Quake2MapLoader");
+	return _name;
+}
+
+const StringSet& Quake2MapFormat::getDependencies() const {
+	static StringSet _dependencies;
+
+	if (_dependencies.empty()) {
+		_dependencies.insert(MODULE_FILETYPES);
+		_dependencies.insert(MODULE_ECLASSMANAGER);
+		_dependencies.insert(MODULE_LAYERSYSTEM);
+		_dependencies.insert(MODULE_BRUSHCREATOR);
+		_dependencies.insert(MODULE_XMLREGISTRY);
+		_dependencies.insert(MODULE_MAPFORMATMANAGER);
+	}
+
+	return _dependencies;
+}
+
+void Quake2MapFormat::initialiseModule(const ApplicationContext& ctx)
+{
+	globalOutputStream() << getName() << ": initialiseModule called." << std::endl;
+
+	// Add our primitive parsers to the global format registry
+	GlobalMapFormatManager().registerPrimitiveParser(BrushParserPtr(new BrushParser));
+	
+	GlobalFiletypes().addType(
+		"map", getName(), FileTypePattern(_("Quake2 map"), "*.map"));
+	GlobalFiletypes().addType(
+		"prefab", getName(), FileTypePattern(_("Quake2 map"), "*.map"));
+}
+
+bool Quake2MapFormat::readGraph(const MapImportInfo& importInfo) const
+{
+	assert(importInfo.root != NULL);
+
+	// Construct a MapImporter that will do the map parsing
+	Quake2NodeImporter importer(importInfo);
+
+	if (importer.parse())
+	{
+		return true;
+	}
+	else
+	{
+		// Importer return FALSE, propagate this failure
+		return false;
+	}
+}
+
+void Quake2MapFormat::writeGraph(const MapExportInfo& exportInfo) const {
+
+	int precision = GlobalRegistry().getInt(RKEY_PRECISION);
+	exportInfo.mapStream.precision(precision);
+
+	// Instantiate a Quake2NodeExporter class and call the traverse function
+	Quake2NodeExporter exporter(exportInfo.mapStream);
+	exportInfo.traverse(exportInfo.root, exporter);
+}
+
+} // namespace map
Index: darkradiant/plugins/mapquake2/Quake2NodeImporter.cpp
===================================================================
--- darkradiant/plugins/mapquake2/Quake2NodeImporter.cpp	(Revision 0)
+++ darkradiant/plugins/mapquake2/Quake2NodeImporter.cpp	(Revision 0)
@@ -0,0 +1,301 @@
+#include "Quake2NodeImporter.h"
+
+#include "imap.h"
+#include "iradiant.h"
+#include "imainframe.h"
+#include "iregistry.h"
+#include "ieclass.h"
+#include "string/string.h"
+
+#include "gtkutil/dialog.h"
+#include "MapImportInfo.h"
+#include "scenelib.h"
+
+#include "Tokens.h"
+#include "Quake2MapFormat.h"
+
+#include "i18n.h"
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace map {
+
+	namespace {
+		const std::string RKEY_MAP_LOAD_STATUS_INTERLEAVE = "user/ui/map/loadStatusInterleave";
+	}
+
+// Constructor
+Quake2NodeImporter::Quake2NodeImporter(const MapImportInfo& importInfo)
+: _root(importInfo.root),
+  _inputStream(importInfo.inputStream),
+  _fileSize(importInfo.inputStreamSize),
+  _tok(_inputStream),
+  _entityCount(0),
+  _primitiveCount(0),
+  _dialogEventLimiter(GlobalRegistry().getInt(RKEY_MAP_LOAD_STATUS_INTERLEAVE)),
+  _debug(GlobalRegistry().get("user/debug") == "1")
+{
+	bool showProgressDialog = (GlobalRegistry().get(RKEY_MAP_SUPPRESS_LOAD_STATUS_DIALOG) != "1");
+
+	if (showProgressDialog) 
+	{
+		_dialog = gtkutil::ModalProgressDialogPtr(
+			new gtkutil::ModalProgressDialog(
+				GlobalMainFrame().getTopLevelWindow(), _("Loading map")
+			)
+		);
+	}
+}
+
+bool Quake2NodeImporter::parse() {
+	// Read each entity in the map, until EOF is reached
+	while (_tok.hasMoreTokens()) 
+   {
+		// Update the dialog text. This will throw an exception if the cancel
+		// button is clicked, which we must catch and handle.
+		if (_dialog && _dialogEventLimiter.readyForEvent()) 
+		{
+			try 
+			{
+				std::string text = (boost::format(_("Loading entity %d")) % _entityCount).str();
+				_dialog->setTextAndFraction(text, getProgressFraction());
+			}
+			catch (gtkutil::ModalProgressDialog::OperationAbortedException&)
+			{
+				gtkutil::errorDialog(
+					_("Map loading cancelled"), 
+					GlobalMainFrame().getTopLevelWindow()
+				);
+
+				// Clear out the root node, otherwise we end up with half a map
+				scene::NodeRemover remover;
+				_root->traverse(remover); 
+
+				return false;	
+			}
+		}
+
+		// Create an entity node by parsing from the stream. If there is an
+		// exception, display it and return
+		try {
+			parseEntity();
+		}
+		catch (std::runtime_error& e)
+		{
+			std::string text = (boost::format(_("Failed on entity %d")) % _entityCount).str();
+			gtkutil::errorDialog(
+				text + "\n\n" + e.what(), 
+				GlobalMainFrame().getTopLevelWindow()
+			);
+
+			// Clear out the root node, otherwise we end up with half a map
+			scene::NodeRemover remover;
+			_root->traverse(remover); 
+
+			return false;			
+		}
+
+		_entityCount++;
+	}
+
+	// EOF reached, return success
+	return true;
+}
+
+void Quake2NodeImporter::parsePrimitive(const scene::INodePtr& parentEntity)
+{
+    // Update the dialog
+    if (_dialog && _dialogEventLimiter.readyForEvent()) 
+    {
+        _dialog->setTextAndFraction(
+            _dlgEntityText + "\nPrimitive " + sizetToStr(_primitiveCount),
+			getProgressFraction()
+        );
+    }
+
+    _primitiveCount++;
+
+	std::string primitiveKeyword = _tok.nextToken();
+
+	// Get a parser for this keyword
+	PrimitiveParserPtr parser = GlobalMapFormatManager().getPrimitiveParser(primitiveKeyword);
+
+	if (parser == NULL)
+	{
+		throw parser::ParseException("Unknown primitive type: " + primitiveKeyword);
+	}
+
+	// Try to parse the primitive, throwing exception if failed
+    scene::INodePtr primitive = parser->parse(_tok);
+
+    if (!primitive)
+	{
+		std::string text = (boost::format(_("Primitive #%d: parse error")) % _primitiveCount).str();
+        throw std::runtime_error(text + "\n");
+    }
+    
+    // Now add the primitive as a child of the entity
+    if (Node_getEntity(parentEntity)->isContainer())
+	{
+        parentEntity->addChildNode(primitive);
+    }
+}
+
+scene::INodePtr Quake2NodeImporter::createEntity(const EntityKeyValues& keyValues) {
+    // Get the classname from the EntityKeyValues
+    EntityKeyValues::const_iterator found = keyValues.find("classname");
+
+    if (found == keyValues.end()) {
+		throw std::runtime_error("Quake2NodeImporter::createEntity(): could not find classname.");
+    }
+    
+    // Otherwise create the entity and add all of the properties
+    std::string className = found->second;
+	IEntityClassPtr classPtr = GlobalEntityClassManager().findClass(className);
+
+	if (classPtr == NULL) {
+		globalErrorStream() << "[mapquake2]: Could not find entity class: "
+			<< className << std::endl;
+
+		// greebo: EntityClass not found, insert a brush-based one
+		classPtr = GlobalEntityClassManager().findOrInsert(className, true);
+	}
+    
+	// Create the actual entity node
+    scene::INodePtr entity(GlobalEntityCreator().createEntity(classPtr));
+
+	Entity* ent = Node_getEntity(entity);
+	assert(ent != NULL); // entity cast must not fail
+
+    for (EntityKeyValues::const_iterator i = keyValues.begin(); 
+         i != keyValues.end(); 
+         ++i)
+    {
+        ent->setKeyValue(i->first, i->second);
+    }
+
+    return entity;
+}
+
+void Quake2NodeImporter::parseEntity() {
+	// Set up the progress dialog text
+	_dlgEntityText = (boost::format(_("Loading entity %d")) % _entityCount).str();
+	
+    // Map of keyvalues for this entity
+    EntityKeyValues keyValues;
+
+    // The actual entity. This is initially null, and will be created when
+    // primitives start or the end of the entity is reached
+    scene::INodePtr entity;
+
+	// Start parsing, first token must be an open brace
+	_tok.assertNextToken("{");
+
+	std::string token = _tok.nextToken();
+
+	// Reset the primitive counter, we're starting a new entity
+	_primitiveCount = 0;
+	
+	while (true) {
+	    // Token must be either a key, a "{" to indicate the start of a 
+	    // primitive, or a "}" to indicate the end of the entity
+
+	    if (token == "{") { // PRIMITIVE
+			// Create the entity right now, if not yet done
+			if (entity == NULL) {
+				entity = createEntity(keyValues);
+			}
+
+			// Parse the primitive block, and pass the parent entity
+			parsePrimitive(entity);
+	    }
+	    else if (token == "}") { // END OF ENTITY
+            // Create the entity if necessary and return it
+	        if (entity == NULL) {
+	            entity = createEntity(keyValues);
+	        }
+			break;
+	    }
+	    else { // KEY
+	        std::string value = _tok.nextToken();
+
+	        // Sanity check (invalid number of tokens will get us out of sync)
+	        if (value == "{" || value == "}")
+			{
+				std::string text = (boost::format(_("Parsed invalid value '%s' for key '%s'")) % value % token).str();
+	            throw std::runtime_error(text);
+	        }
+	        
+	        // Otherwise add the keyvalue pair to our map
+	        keyValues.insert(EntityKeyValues::value_type(token, value));
+	    }
+	    
+	    // Get the next token
+	    token = _tok.nextToken();
+	}
+
+	// Insert the entity
+	insertEntity(entity);
+}
+
+bool Quake2NodeImporter::checkEntityClass(const scene::INodePtr& entity) {
+	// Obtain list of entityclasses to skip
+	static xml::NodeList skipLst = 
+		GlobalRegistry().findXPath("debug/mapquake2//discardEntityClass");
+
+	// Obtain the entity class of this node
+	IEntityClassConstPtr entityClass = 
+			Node_getEntity(entity)->getEntityClass();
+
+	// Skip this entity class if it is in the list
+	for (xml::NodeList::const_iterator i = skipLst.begin();
+		 i != skipLst.end();
+		 ++i)
+	{
+		if (i->getAttributeValue("value") == entityClass->getName()) {
+			std::cout << "DEBUG: discarding entity class " 
+					  << entityClass->getName() << std::endl;
+			return false;
+		}
+	}
+
+	return true;
+}
+
+bool Quake2NodeImporter::checkEntityNum() {
+	// Entity range XPath
+	static xml::NodeList entityRange = 
+					GlobalRegistry().findXPath("debug/mapquake2/entityRange");
+	static xml::NodeList::iterator i = entityRange.begin();
+	
+	// Test the entity number is in the range
+	if (i != entityRange.end()) {
+		static std::size_t lower = strToSizet(i->getAttributeValue("start"));
+		static std::size_t upper = strToSizet(i->getAttributeValue("end"));
+	
+		if (_entityCount < lower || _entityCount > upper) {
+			std::cout << "DEBUG: Discarding entity " << _entityCount << ", out of range"
+					  << std::endl;
+			return false;
+		}
+	}
+	return true;
+}
+
+void Quake2NodeImporter::insertEntity(const scene::INodePtr& entity) {
+	// Abort if any of the tests fail
+	if (_debug && (!checkEntityClass(entity) || !checkEntityNum())) {
+		return;
+	}
+	
+	// Insert the node into the given root
+	_root->addChildNode(entity);
+}
+
+double Quake2NodeImporter::getProgressFraction()
+{
+	long readBytes = static_cast<long>(_inputStream.tellg());
+	return static_cast<double>(readBytes) / _fileSize;
+}
+
+} // namespace map
Index: darkradiant/plugins/mapquake2/mapquake2.def
===================================================================
--- darkradiant/plugins/mapquake2/mapquake2.def	(Revision 0)
+++ darkradiant/plugins/mapquake2/mapquake2.def	(Revision 0)
@@ -0,0 +1,7 @@
+; mapquake2.def : Declares the module parameters for the DLL.
+
+LIBRARY      "MAPQUAKE2"
+
+EXPORTS
+    ; Explicit exports can go here
+	RegisterModule @1
Index: darkradiant/plugins/mapquake2/Quake2MapFormat.h
===================================================================
--- darkradiant/plugins/mapquake2/Quake2MapFormat.h	(Revision 0)
+++ darkradiant/plugins/mapquake2/Quake2MapFormat.h	(Revision 0)
@@ -0,0 +1,29 @@
+#ifndef QUAKE2MAPFORMAT_H_
+#define QUAKE2MAPFORMAT_H_
+
+#include "imapformat.h"
+
+namespace map {
+
+class Quake2MapFormat :
+	public MapFormat
+{
+public:
+	// RegisterableModule implementation
+	virtual const std::string& getName() const;
+	virtual const StringSet& getDependencies() const;
+	virtual void initialiseModule(const ApplicationContext& ctx);
+	
+    /**
+     * Read tokens from a map stream and create entities accordingly.
+     */
+    virtual bool readGraph(const MapImportInfo& importInfo) const;
+
+	// Write scene graph to an ostream
+	virtual void writeGraph(const MapExportInfo& exportInfo) const;
+};
+typedef boost::shared_ptr<Quake2MapFormat> Quake2MapFormatPtr;
+
+} // namespace map
+
+#endif /* QUAKE2MAPFORMAT_H_ */
Index: darkradiant/plugins/mapquake2/Quake2NodeImporter.h
===================================================================
--- darkradiant/plugins/mapquake2/Quake2NodeImporter.h	(Revision 0)
+++ darkradiant/plugins/mapquake2/Quake2NodeImporter.h	(Revision 0)
@@ -0,0 +1,81 @@
+#ifndef QUAKE2_NODE_IMPORTER_H_
+#define QUAKE2_NODE_IMPORTER_H_
+
+#include <map>
+#include "inode.h"
+#include "imapformat.h"
+#include "parser/DefTokeniser.h"
+#include "gtkutil/ModalProgressDialog.h"
+#include "EventRateLimiter.h"
+
+namespace map {
+
+class Quake2NodeImporter {
+
+	// The map type for one entity's keyvalues (spawnargs)
+	typedef std::map<std::string, std::string> EntityKeyValues;
+
+	// The container which will hold the imported nodes
+	scene::INodePtr _root;
+	
+	std::istream& _inputStream;
+
+	// The size of the input file
+	long _fileSize;
+
+	// The tokeniser used to split the stream into pieces
+	parser::BasicDefTokeniser<std::istream> _tok;
+
+	// The number of entities found in this map file so far
+	std::size_t _entityCount;
+
+	// The number of primitives of the currently parsed entity
+	std::size_t _primitiveCount;
+
+	// The progress dialog
+	gtkutil::ModalProgressDialogPtr _dialog;
+
+	// The progress dialog text for the current entity
+	std::string _dlgEntityText;
+
+	// Event rate limiter for the progress dialog
+	EventRateLimiter _dialogEventLimiter;
+
+	// TRUE if we're in debugging parse mode
+	bool _debug;
+
+public:
+	Quake2NodeImporter(const MapImportInfo& importInfo);
+
+	// Start parsing, this should not "leak" any exceptions
+	// Returns TRUE if the parsing succeeded without errors or exceptions.
+	bool parse();
+
+private:
+	// Parses an entity plus all child primitives
+	void parseEntity();
+
+	// Parse the primitive block and insert the child into the given parent
+	void parsePrimitive(const scene::INodePtr& parentEntity);
+
+	// Create an entity with the given properties and layers
+	scene::INodePtr createEntity(const EntityKeyValues& keyValues);
+
+	// Inserts the entity into the root (and performs a couple of checks beforehand)
+	void insertEntity(const scene::INodePtr& entity);
+
+	// Check if the given node is excluded based on entity class (debug code). 
+	// Return true if not excluded, false otherwise
+	bool checkEntityClass(const scene::INodePtr& entity);
+
+	// Check if the entity with the given number should be inserted (debug)
+	bool checkEntityNum();
+
+private:
+	// Gets the ratio of read bytes vs. total bytes in the input stream
+	double getProgressFraction();
+};
+
+} // namespace map
+
+#endif /* QUAKE2_NODE_IMPORTER_H_ */
Index: darkradiant/plugins/mapquake2/mapquake2.cpp
===================================================================
--- darkradiant/plugins/mapquake2/mapquake2.cpp	(Revision 0)
+++ darkradiant/plugins/mapquake2/mapquake2.cpp	(Revision 0)
@@ -0,0 +1,40 @@
+/*
+Copyright (C) 2001-2006, William Joseph.
+All Rights Reserved.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "Quake2MapFormat.h"
+
+#include "imapformat.h"
+#include "itextstream.h"
+#include "debugging/debugging.h"
+
+extern "C" void DARKRADIANT_DLLEXPORT RegisterModule(IModuleRegistry& registry)
+{
+	registry.registerModule(map::Quake2MapFormatPtr(new map::Quake2MapFormat));
+	
+	// Initialise the streams using the given application context
+	module::initialiseStreams(registry.getApplicationContext());
+	
+	// Remember the reference to the ModuleRegistry
+	module::RegistryReference::Instance().setRegistry(registry);
+
+	// Set up the assertion handler
+	GlobalErrorHandler() = registry.getApplicationContext().getErrorHandlingFunction();
+}
Index: darkradiant/plugins/mapquake2/primitivewriters/BrushExporter.h
===================================================================
--- darkradiant/plugins/mapquake2/primitivewriters/BrushExporter.h	(Revision 0)
+++ darkradiant/plugins/mapquake2/primitivewriters/BrushExporter.h	(Revision 0)
@@ -0,0 +1,116 @@
+#ifndef BrushExporter_h__
+#define BrushExporter_h__
+
+#include "ibrush.h"
+#include "math/Plane3.h"
+#include "math/matrix.h"
+
+namespace map
+{
+
+namespace
+{
+	// Writes a double to the given stream and checks for NaN and infinity
+	inline void writeDoubleSafe(const double d, std::ostream& os)
+	{
+		if (isValid(d))
+		{
+			if (d == -0.0)
+			{
+				os << 0; // convert -0 to 0
+			}
+			else
+			{
+				os << d;
+			}
+		}
+		else
+		{
+			// Is infinity or NaN, write 0
+			os << "0";
+		}
+	} 
+}
+
+class BrushExporter
+{
+public:
+
+	// Writes a brush definition from the given brush to the given stream
+	static void exportBrush(std::ostream& stream, IBrush& brush)
+	{
+		if (!brush.hasContributingFaces()) {
+			return;
+		}
+
+		// Brush decl header
+		stream << "{\n";
+		stream << "brush\n";
+		stream << "{\n";
+
+		// Iterate over each brush face, exporting the tokens from all faces
+		for (std::size_t i = 0; i < brush.getNumFaces(); ++i)
+		{
+			writeFace(stream, brush.getFace(i));
+		}
+
+		// Close brush contents and header
+		stream << "}\n}\n";
+	}
+
+	static void writeFace(std::ostream& stream, const IFace& face)
+	{
+		// Write the plane equation
+		const Plane3& plane = face.getPlane3();
+
+		stream << "( ";
+		writeDoubleSafe(plane.normal().x(), stream);
+		stream << " ";
+		writeDoubleSafe(plane.normal().y(), stream);
+		stream << " ";
+		writeDoubleSafe(plane.normal().z(), stream);
+		stream << " ";
+		writeDoubleSafe(-plane.dist(), stream); // negate d
+		stream << " ";
+		stream << ") ";
+
+		// Write TexDef
+		Matrix4 texdef = face.getTexDefMatrix();
+		stream << "( ";
+
+		stream << "( ";
+		writeDoubleSafe(texdef.xx(), stream);
+		stream << " ";
+		writeDoubleSafe(texdef.yx(), stream);
+		stream << " ";
+		writeDoubleSafe(texdef.tx(), stream);
+		stream << " ) ";
+
+		stream << "( ";
+		writeDoubleSafe(texdef.xy(), stream);
+		stream << " ";
+		writeDoubleSafe(texdef.yy(), stream);
+		stream << " ";
+		writeDoubleSafe(texdef.ty(), stream);
+		stream << " ) ";
+
+		stream << ") ";
+
+		// Write Shader
+		const std::string& shaderName = face.getShader();
+
+		if (shaderName.empty()) {
+			stream << "\"tex_common/nodraw\" ";
+		}
+		else {
+			stream << "\"" << shaderName << "\" ";
+		}
+
+		// Export (dummy) contents/flags
+		stream << "0 0 0\n";
+	}
+};
+
+}
+
+#endif // BrushExporter_h__
Index: darkradiant/plugins/mapquake2/primitiveparsers/Brush.cpp
===================================================================
--- darkradiant/plugins/mapquake2/primitiveparsers/Brush.cpp	(Revision 0)
+++ darkradiant/plugins/mapquake2/primitiveparsers/Brush.cpp	(Revision 0)
@@ -0,0 +1,126 @@
+#include "Brush.h"
+
+#include "imap.h"
+#include "ibrush.h"
+#include "parser/DefTokeniser.h"
+#include "math/matrix.h"
+#include "shaderlib.h"
+#include "i18n.h"
+#include <boost/format.hpp>
+
+namespace map
+{
+
+const std::string& BrushParser::getKeyword() const
+{
+	static std::string _keyword("brush");
+	return _keyword;
+}
+
+/* 
+// Example Primitive
+{
+brush
+{
+( -1216 -464 232 ) ( -1088 -464 232 ) ( -1088 -80 120 ) ( ( 0.031250 0 14 ) ( -0.000009 0.031250 4.471550 ) ) common/caulk 134217728 4 0
+( -1088 -464 248 ) ( -1216 -464 248 ) ( -1216 -80 136 ) ( ( 0 -0.031373 -0.147059 ) ( 0.007812 0 0.049020 ) ) common/caulk 134217728 0 0
+( -1088 -560 120 ) ( -1088 -560 136 ) ( -1088 -80 136 ) ( ( 0.031250 0 16.500000 ) ( 0 0.031250 0.250000 ) ) common/caulk 134217728 4 0
+( -1088 -80 136 ) ( -1216 -80 136 ) ( -1216 -80 8 ) ( ( 0.031250 0 2 ) ( 0 0.031250 0.250000 ) ) common/caulk 134217728 4 0
+( -1216 -400 136 ) ( -1216 -400 120 ) ( -1216 -80 120 ) ( ( 0.031250 0 -16.500000 ) ( 0 0.031250 0.250000 ) ) common/caulk 134217728 4 0
+( -1088 -464 232 ) ( -1216 -464 232 ) ( -1216 -464 248 ) ( ( 0.031250 0 -2 ) ( 0 0.031250 0.250000 ) ) common/caulk 134217728 4 0
+}
+}
+
+
+// brush 0
+{
+( -64 -160 4 ) ( 320 0 64 ) ( 320 -160 64 ) tex_streets/street001 0 0 0 0.4 0.4 65280 0 0
+( 816 -80 64 ) ( 760 -80 64 ) ( 816 -80 -64 ) tex_common/nodraw 236 0 0 0.4 0.4 65280 128 0
+( 320 1344 64 ) ( 320 1344 144 ) ( 320 1368 144 ) tex_common/nodraw 0 0 0 0.4 0.4 65280 128 0
+( -96 -192 0 ) ( -224 -192 0 ) ( -224 -352 0 ) tex_common/nodraw 0 0 0 0.4 0.4 65280 128 0
+( 1024 -160 62 ) ( 672 -160 190 ) ( 1024 -160 190 ) tex_streets/street001 0 0 0 0.4 0.4 65280 0 0
+( -64 -32 0 ) ( -64 96 0 ) ( -64 -32 128 ) tex_common/nodraw 0 0 0 0.4 0.4 65280 128 0
+}
+*/
+scene::INodePtr BrushParser::parse(parser::DefTokeniser& tok) const
+{
+	// Create a new brush
+	scene::INodePtr node = GlobalBrushCreator().createBrush();
+
+	// Cast the node, this must succeed
+	IBrushNodePtr brushNode = boost::dynamic_pointer_cast<IBrushNode>(node);
+	assert(brushNode != NULL);
+
+	IBrush& brush = brushNode->getIBrush();
+
+	tok.assertNextToken("{");
+
+	// Parse face tokens until a closing brace is encountered
+	while (1)
+	{
+		std::string token = tok.nextToken();
+
+		// Token should be either a "(" (start of face) or "}" (end of brush)
+		if (token == "}") 
+		{
+			break; // end of brush
+		}
+		else if (token == "(") // FACE
+		{ 
+			// Parse three 3D points to construct a plane
+			Vector3 p1(strToDouble(tok.nextToken()), strToDouble(tok.nextToken()), strToDouble(tok.nextToken()));
+			tok.assertNextToken(")");
+			tok.assertNextToken("(");
+			
+			Vector3 p2(strToDouble(tok.nextToken()), strToDouble(tok.nextToken()), strToDouble(tok.nextToken()));
+			tok.assertNextToken(")");
+			tok.assertNextToken("(");
+
+			Vector3 p3(strToDouble(tok.nextToken()), strToDouble(tok.nextToken()), strToDouble(tok.nextToken()));
+			tok.assertNextToken(")");
+
+			// Construct the plane from the three points
+			Plane3 plane(p1, p2, p3);
+
+			// Parse TexDef
+			Matrix4 texdef;
+			tok.assertNextToken("(");
+
+			tok.assertNextToken("(");
+			texdef.xx() = strToDouble(tok.nextToken());
+			texdef.yx() = strToDouble(tok.nextToken());
+			texdef.tx() = strToDouble(tok.nextToken());
+			tok.assertNextToken(")");
+
+			tok.assertNextToken("(");
+			texdef.xy() = strToDouble(tok.nextToken());
+			texdef.yy() = strToDouble(tok.nextToken());
+			texdef.ty() = strToDouble(tok.nextToken());
+			tok.assertNextToken(")");
+
+			tok.assertNextToken(")");
+
+			// Parse texture, face has an implicit "textures/" not written to the map
+			std::string shader = "textures/" + tok.nextToken();
+
+			// Parse Contents Flags (and ignore them)
+			// TODO: Q2 uses them
+			tok.skipTokens(3);
+
+			// Finally, add the new face to the brush
+			IFace& face = brush.addFace(plane, texdef, shader);
+		}
+		else
+		{
+			std::string text = (boost::format(_("BrushParser: invalid token '%s'")) % token).str();
+			throw parser::ParseException(text);
+		}
+	}
+
+	// Final outer "}"
+	tok.assertNextToken("}");
+
+	return node;
+}
+
+} // namespace map
Index: darkradiant/plugins/mapquake2/primitiveparsers/Brush.h
===================================================================
--- darkradiant/plugins/mapquake2/primitiveparsers/Brush.h	(Revision 0)
+++ darkradiant/plugins/mapquake2/primitiveparsers/Brush.h	(Revision 0)
@@ -0,0 +1,22 @@
+#ifndef ParserBrush_h__
+#define ParserBrush_h__
+
+#include "imapformat.h"
+
+namespace map
+{
+
+// A primitive parser for the brush format
+class BrushParser :
+	public PrimitiveParser
+{
+public:
+	const std::string& getKeyword() const;
+
+    scene::INodePtr parse(parser::DefTokeniser& tok) const;
+};
+typedef boost::shared_ptr<BrushParser> BrushParserPtr;
+
+}
+
+#endif // ParserBrush_h__
Index: darkradiant/plugins/mapquake2/Quake2NodeExporter.cpp
===================================================================
--- darkradiant/plugins/mapquake2/Quake2NodeExporter.cpp	(Revision 0)
+++ darkradiant/plugins/mapquake2/Quake2NodeExporter.cpp	(Revision 0)
@@ -0,0 +1,121 @@
+#include "Quake2NodeExporter.h"
+
+#include "itextstream.h"
+#include "iregistry.h"
+#include "ieclass.h"
+#include "ibrush.h"
+#include "ipatch.h"
+#include "ientity.h"
+#include "ilayer.h"
+#include "imodel.h"
+
+#include "Tokens.h"
+#include "Quake2MapFormat.h"
+#include "primitivewriters/BrushExporter.h"
+
+namespace map {
+
+Quake2NodeExporter::Quake2NodeExporter(std::ostream& mapStream) :
+	_mapStream(mapStream), 
+	_entityCount(0),
+	_primitiveCount(0)
+{
+	// Check the game file to see whether we need dummy brushes or not
+	if (GlobalRegistry().get("game/mapFormat/compatibility/addDummyBrushes") == "true")
+		_writeDummyBrushes = true;
+	else
+		_writeDummyBrushes = false;
+}
+
+Quake2NodeExporter::~Quake2NodeExporter() {
+}
+
+// Pre-descent callback
+bool Quake2NodeExporter::pre(const scene::INodePtr& node) {
+	// Check whether we are have a brush or an entity. We might get 
+	// called at either level.
+    Entity* entity = Node_getEntity(node);
+
+	if (entity != NULL)
+	{
+		// Push the entity
+		_entityStack.push_back(entity);
+
+    	// Write out the entity number comment
+		_mapStream << "// entity " << _entityCount++ << std::endl;
+
+		// Entity opening brace
+		_mapStream << "{\n";
+
+		// Entity key values
+		exportEntity(*entity);
+
+		// Reset the primitive count 
+		_primitiveCount = 0;
+
+		return true; // traverse deeper
+    }
+    else // Primitive
+	{
+		// No entity flag to stack
+		_entityStack.push_back(NULL);
+
+		// Check if node is a brush or a patch
+		IBrushNodePtr brushNode = boost::dynamic_pointer_cast<IBrushNode>(node);
+
+		if (brushNode != NULL)
+		{
+			// Primitive count comment
+			_mapStream << "// brush " << _primitiveCount++ << std::endl;
+
+			// Export brush here _mapStream
+			BrushExporter::exportBrush(_mapStream, brushNode->getIBrush());
+
+			return false; // don't traverse brushes
+		}
+    }
+
+    return true;
+}
+  
+// Post-descent callback
+void Quake2NodeExporter::post(const scene::INodePtr& node)
+{
+	// Check if we are popping an entity
+	Entity* ent = _entityStack.back();
+
+	if (ent != NULL) {
+		// Write the closing brace for the entity
+		_mapStream << "}" << std::endl;
+	}
+
+	// Pop the stack
+	_entityStack.pop_back();
+}
+
+void Quake2NodeExporter::exportEntity(const Entity& entity) {
+	// Create a local Entity visitor class to export the keyvalues
+	// to the output stream	
+	class WriteKeyValue : public Entity::Visitor
+	{
+		// Stream to write to
+		std::ostream& _os;
+	public:
+	
+		// Constructor
+		WriteKeyValue(std::ostream& os)
+	    : _os(os)
+	    {}
+
+		// Required visit function
+    	void visit(const std::string& key, const std::string& value) {
+			_os << "\"" << key << "\" \"" << value << "\"\n";
+		}
+
+	} visitor(_mapStream);
+
+	// Visit the entity
+	entity.forEachKeyValue(visitor);
+}
+
+} // namespace map
Index: darkradiant/plugins/mapquake2/Makefile.am
===================================================================
--- darkradiant/plugins/mapquake2/Makefile.am	(Revision 0)
+++ darkradiant/plugins/mapquake2/Makefile.am	(Revision 0)
@@ -0,0 +1,15 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libs \
+			  $(XML_CFLAGS) $(GTK_CFLAGS)
+
+modulesdir = $(pkglibdir)/modules
+modules_LTLIBRARIES = mapquake2.la
+
+mapquake2_la_LIBADD = $(top_builddir)/libs/gtkutil/libgtkutil.la \
+					 $(top_builddir)/libs/xmlutil/libxmlutil.la
+mapquake2_la_LDFLAGS = -module -avoid-version $(GTK_LIBS) $(XML_LIBS)
+mapquake2_la_SOURCES = Quake2MapFormat.cpp \
+                      Quake2NodeImporter.cpp \
+                      mapquake2.cpp \
+                      Quake2NodeExporter.cpp \
+					  primitiveparsers/Brush.cpp
+
Index: darkradiant/plugins/mapquake2/Tokens.h
===================================================================
--- darkradiant/plugins/mapquake2/Tokens.h	(Revision 0)
+++ darkradiant/plugins/mapquake2/Tokens.h	(Revision 0)
@@ -0,0 +1,24 @@
+#ifndef QUAKE2_TOKENS_H_
+#define QUAKE2_TOKENS_H_
+
+#include <string>
+
+namespace map {
+
+const std::string DUMMY_BRUSH =
+	"// dummy brush 0\n\
+	{\n\
+	brush\n\
+	{\n\
+	( 0 0 -1 0 ) ( ( 0.125 0 0 ) ( 0 0.125 0 ) ) \"_default\" 0 0 0\n\
+	( 0 0 1 -8 ) ( ( 0.125 0 0 ) ( 0 0.125 0 ) ) \"_default\" 0 0 0\n\
+	( 0 -1 0 -16 ) ( ( 0.125 0 0 ) ( 0 0.125 0 ) ) \"_default\" 0 0 0\n\
+	( 1 0 0 -16 ) ( ( 0.125 0 0 ) ( 0 0.125 0 ) ) \"_default\" 0 0 0\n\
+	( 0 1 0 -16 ) ( ( 0.125 0 0 ) ( 0 0.125 0 ) ) \"_default\" 0 0 0\n\
+	( -1 0 0 -16 ) ( ( 0.125 0 0 ) ( 0 0.125 0 ) ) \"_default\" 0 0 0\n\
+	}\n\
+	}\n";
+
+} // namespace map
+
+#endif /* QUAKE2_TOKENS_H_ */
Index: darkradiant/plugins/mapquake2/Quake2NodeExporter.h
===================================================================
--- darkradiant/plugins/mapquake2/Quake2NodeExporter.h	(Revision 0)
+++ darkradiant/plugins/mapquake2/Quake2NodeExporter.h	(Revision 0)
@@ -0,0 +1,56 @@
+#ifndef QUAKE2_NODEEXPORTER_H_
+#define QUAKE2_NODEEXPORTER_H_
+
+#include "inode.h"
+#include "imap.h"
+#include <vector>
+#include <ostream>
+
+class Entity;
+
+namespace map {
+
+/* Walker class to traverse the scene graph and write each entity
+ * out to the token stream, including its member brushes.
+ */
+
+class Quake2NodeExporter :
+	public scene::NodeVisitor
+{
+	// Stack to hold the parent entity when writing a brush. Either
+	// the parent Entity is pushed, or a NULL pointer.
+	std::vector<Entity*> _entityStack;
+
+	// Output stream to write to
+	std::ostream& _mapStream;
+  
+	// Number of entities written (map global)
+	std::size_t _entityCount;
+	
+	// Number of primitives written for the current entity (entity local)
+	std::size_t _primitiveCount;
+
+	// Are we writing dummy brushes to brushless entities?
+	bool _writeDummyBrushes;
+	
+public:
+	// Constructor
+	Quake2NodeExporter(std::ostream& mapStream);
+
+	// Destructor
+	virtual ~Quake2NodeExporter();
+	
+	// Pre-descent callback
+	virtual bool pre(const scene::INodePtr& node);
+  
+	// Post-descent callback
+	virtual void post(const scene::INodePtr& node);
+
+private:
+	// Export all of the keyvalues from the given entity.
+	void exportEntity(const Entity& entity);
+};
+
+} // namespace map
+
+#endif /* QUAKE2_NODEEXPORTER_H_ */
Index: darkradiant/tools/vcprojects/mapquake2.vcproj
===================================================================
--- darkradiant/tools/vcprojects/mapquake2.vcproj	(Revision 0)
+++ darkradiant/tools/vcprojects/mapquake2.vcproj	(Revision 0)
@@ -0,0 +1,476 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9,00"
+	Name="mapquake2"
+	ProjectGUID="{3425D3E8-F025-448A-94C8-7EBA6F7A52E5}"
+	RootNamespace="archivezip"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)\..\..\install\modules"
+			IntermediateDirectory="$(SolutionDir)\..\..\build\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+				Description=""
+				CommandLine=""
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/EHs  /MP"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(SolutionDir)/../../include&quot;;&quot;$(SolutionDir)/../../libs&quot;;&quot;$(SolutionDir)/../../w32deps/boost/include&quot;;&quot;$(SolutionDir)/../../w32deps/libxml2/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/gtk-2.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/atk-1.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/glib-2.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/cairo&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/pango-1.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/lib/glib-2.0/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/lib/gtk-2.0/include&quot;;&quot;$(SolutionDir)/../../w32deps/win_iconv/include&quot;;&quot;$(SolutionDir)/../../w32deps/glew/include&quot;"
+				PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;WIN32;"
+				StringPooling="true"
+				MinimalRebuild="false"
+				ExceptionHandling="0"
+				BasicRuntimeChecks="0"
+				RuntimeLibrary="3"
+				BufferSecurityCheck="false"
+				ForceConformanceInForLoopScope="true"
+				UsePrecompiledHeader="0"
+				ProgramDataBaseFileName="$(IntDir)\vc80.pdb"
+				BrowseInformation="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4610;4510;4512;4505;4100;4127;4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="gtkutillib.lib xmlutillib.lib libxml2.lib glib-2.0.lib gtk-win32-2.0.lib gdk-win32-2.0.lib gobject-2.0.lib gdk_pixbuf-2.0.lib"
+				OutputFile="$(OutDir)/$(ProjectName).dll"
+				LinkIncremental="1"
+				SuppressStartupBanner="true"
+				AdditionalLibraryDirectories="&quot;$(SolutionDir)\..\..\build\libs\$(PlatformName)\$(ConfigurationName)&quot;;&quot;$(SolutionDir)\..\..\build\libs\$(PlatformName)&quot;;&quot;$(SolutionDir)\..\..\w32deps/gtk2\lib&quot;"
+				IgnoreDefaultLibraryNames=""
+				ModuleDefinitionFile="$(SolutionDir)/../../plugins/$(ProjectName)/$(ProjectName).def"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
+				SubSystem="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				ImportLibrary=""
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				CommandLine=""
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)\..\..\install\modules"
+			IntermediateDirectory="$(SolutionDir)\..\..\build\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+				Description=""
+				CommandLine=""
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/EHs /MP"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(SolutionDir)/../../include&quot;;&quot;$(SolutionDir)/../../libs&quot;;&quot;$(SolutionDir)/../../w32deps/boost/include&quot;;&quot;$(SolutionDir)/../../w32deps/libxml2/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/gtk-2.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/atk-1.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/glib-2.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/cairo&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/pango-1.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/lib/glib-2.0/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/lib/gtk-2.0/include&quot;;&quot;$(SolutionDir)/../../w32deps/win_iconv/include&quot;;&quot;$(SolutionDir)/../../w32deps/glew/include&quot;"
+				PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;WIN32;"
+				StringPooling="true"
+				ExceptionHandling="0"
+				BasicRuntimeChecks="0"
+				RuntimeLibrary="3"
+				BufferSecurityCheck="false"
+				ForceConformanceInForLoopScope="true"
+				UsePrecompiledHeader="0"
+				ProgramDataBaseFileName="$(IntDir)\vc80.pdb"
+				BrowseInformation="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4610;4510;4512;4505;4100;4127;4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="gtkutillib.lib xmlutillib.lib libxml2.lib glib-2.0.lib gtk-win32-2.0.lib gdk-win32-2.0.lib gobject-2.0.lib gdk_pixbuf-2.0.lib"
+				OutputFile="$(OutDir)/$(ProjectName).dll"
+				LinkIncremental="1"
+				SuppressStartupBanner="true"
+				AdditionalLibraryDirectories="&quot;$(SolutionDir)\..\..\build\libs\$(PlatformName)\$(ConfigurationName)&quot;;&quot;$(SolutionDir)\..\..\build\libs\$(PlatformName)&quot;;&quot;$(SolutionDir)\..\..\w64deps/gtk2\lib&quot;"
+				IgnoreDefaultLibraryNames=""
+				ModuleDefinitionFile="$(SolutionDir)/../../plugins/$(ProjectName)/$(ProjectName).def"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
+				SubSystem="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				ImportLibrary=""
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				CommandLine=""
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)\..\..\install\modules"
+			IntermediateDirectory="$(SolutionDir)\..\..\build\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+				Description=""
+				CommandLine=""
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/EHsc /MP"
+				InlineFunctionExpansion="2"
+				EnableIntrinsicFunctions="true"
+				FavorSizeOrSpeed="1"
+				AdditionalIncludeDirectories="&quot;$(SolutionDir)/../../include&quot;;&quot;$(SolutionDir)/../../libs&quot;;&quot;$(SolutionDir)/../../w32deps/boost/include&quot;;&quot;$(SolutionDir)/../../w32deps/libxml2/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/gtk-2.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/atk-1.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/glib-2.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/cairo&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/pango-1.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/lib/glib-2.0/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/lib/gtk-2.0/include&quot;;&quot;$(SolutionDir)/../../w32deps/win_iconv/include&quot;;&quot;$(SolutionDir)/../../w32deps/glew/include&quot;"
+				PreprocessorDefinitions="NDEBUG;_CRT_SECURE_NO_DEPRECATE;WIN32"
+				StringPooling="true"
+				ExceptionHandling="0"
+				RuntimeLibrary="2"
+				BufferSecurityCheck="false"
+				ForceConformanceInForLoopScope="true"
+				UsePrecompiledHeader="0"
+				ProgramDataBaseFileName="$(IntDir)\vc80.pdb"
+				WarningLevel="4"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4610;4510;4512;4505;4100;4127;4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="gtkutillib.lib xmlutillib.lib libxml2.lib glib-2.0.lib gtk-win32-2.0.lib gdk-win32-2.0.lib gobject-2.0.lib gdk_pixbuf-2.0.lib"
+				OutputFile="$(OutDir)/$(ProjectName).dll"
+				LinkIncremental="1"
+				SuppressStartupBanner="true"
+				AdditionalLibraryDirectories="&quot;$(SolutionDir)\..\..\build\libs\$(PlatformName)\$(ConfigurationName)&quot;;&quot;$(SolutionDir)\..\..\build\libs\$(PlatformName)&quot;;&quot;$(SolutionDir)\..\..\w32deps/gtk2\lib&quot;"
+				IgnoreDefaultLibraryNames=""
+				ModuleDefinitionFile="$(SolutionDir)/../../plugins/$(ProjectName)/$(ProjectName).def"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				FixedBaseAddress="0"
+				DataExecutionPrevention="0"
+				ImportLibrary=""
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				CommandLine=""
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)\..\..\install\modules"
+			IntermediateDirectory="$(SolutionDir)\..\..\build\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+				Description=""
+				CommandLine=""
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/EHsc /MP"
+				InlineFunctionExpansion="2"
+				EnableIntrinsicFunctions="true"
+				FavorSizeOrSpeed="1"
+				AdditionalIncludeDirectories="&quot;$(SolutionDir)/../../include&quot;;&quot;$(SolutionDir)/../../libs&quot;;&quot;$(SolutionDir)/../../w32deps/boost/include&quot;;&quot;$(SolutionDir)/../../w32deps/libxml2/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/gtk-2.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/atk-1.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/glib-2.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/cairo&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/include/pango-1.0&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/lib/glib-2.0/include&quot;;&quot;$(SolutionDir)/../../w32deps/gtk2/lib/gtk-2.0/include&quot;;&quot;$(SolutionDir)/../../w32deps/win_iconv/include&quot;;&quot;$(SolutionDir)/../../w32deps/glew/include&quot;"
+				PreprocessorDefinitions="NDEBUG;_CRT_SECURE_NO_DEPRECATE;WIN32"
+				StringPooling="true"
+				ExceptionHandling="0"
+				RuntimeLibrary="2"
+				BufferSecurityCheck="false"
+				ForceConformanceInForLoopScope="true"
+				UsePrecompiledHeader="0"
+				ProgramDataBaseFileName="$(IntDir)\vc80.pdb"
+				WarningLevel="4"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4610;4510;4512;4505;4100;4127;4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="gtkutillib.lib xmlutillib.lib libxml2.lib glib-2.0.lib gtk-win32-2.0.lib gdk-win32-2.0.lib gobject-2.0.lib gdk_pixbuf-2.0.lib"
+				OutputFile="$(OutDir)/$(ProjectName).dll"
+				LinkIncremental="1"
+				SuppressStartupBanner="true"
+				AdditionalLibraryDirectories="&quot;$(SolutionDir)\..\..\build\libs\$(PlatformName)\$(ConfigurationName)&quot;;&quot;$(SolutionDir)\..\..\build\libs\$(PlatformName)&quot;;&quot;$(SolutionDir)\..\..\w64deps/gtk2\lib&quot;"
+				IgnoreDefaultLibraryNames=""
+				ModuleDefinitionFile="$(SolutionDir)/../../plugins/$(ProjectName)/$(ProjectName).def"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				FixedBaseAddress="0"
+				DataExecutionPrevention="0"
+				ImportLibrary=""
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				CommandLine=""
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="src"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\plugins\mapquake2\Quake2MapFormat.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\plugins\mapquake2\Quake2MapFormat.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\plugins\mapquake2\mapquake2.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\plugins\mapquake2\Quake2NodeExporter.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\plugins\mapquake2\Quake2NodeExporter.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\plugins\mapquake2\Quake2NodeImporter.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\plugins\mapquake2\Quake2NodeImporter.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\plugins\mapquake2\Tokens.h"
+				>
+			</File>
+			<Filter
+				Name="primitiveparsers"
+				>
+				<File
+					RelativePath="..\..\plugins\mapquake2\primitiveparsers\Brush.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\plugins\mapquake2\primitiveparsers\Brush.h"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="primitivewriters"
+				>
+				<File
+					RelativePath="..\..\plugins\mapquake2\primitivewriters\BrushExporter.h"
+					>
+				</File>
+			</Filter>
+		</Filter>
+		<File
+			RelativePath="..\..\plugins\mapquake2\mapquake2.def"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
Index: darkradiant/tools/codeblocks/mapquake2.cbp
===================================================================
--- darkradiant/tools/codeblocks/mapquake2.cbp	(Revision 0)
+++ darkradiant/tools/codeblocks/mapquake2.cbp	(Revision 0)
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+	<FileVersion major="1" minor="6" />
+	<Project>
+		<Option title="mapquake2" />
+		<Option pch_mode="2" />
+		<Option compiler="msvc8" />
+		<Build>
+			<Target title="Debug Win32">
+				<Option platforms="Windows;" />
+				<Option output="..\..\install\modules\$(PROJECT_NAME)" prefix_auto="1" extension_auto="1" />
+				<Option object_output="..\..\build\$(PROJECT_NAME)\$(TARGET_NAME)" />
+				<Option external_deps="..\..\build\libs\$(TARGET_NAME)\gtkutillib.lib;..\..\build\libs\$(TARGET_NAME)\libxml2.lib;..\..\build\libs\$(TARGET_NAME)\xmlutillib.lib;" />
+				<Option type="3" />
+				<Option compiler="msvc8" />
+				<Option createDefFile="1" />
+				<Option createStaticLib="1" />
+				<Compiler>
+					<Add option="/MDd" />
+					<Add option="/TP" />
+					<Add option="/Gd" />
+					<Add option="/Gm" />
+					<Add option="/fp:precise" />
+					<Add option="/EHs" />
+					<Add option="/GF" />
+					<Add option="/Od" />
+					<Add option="/W3" />
+					<Add option="/Zi /D_DEBUG" />
+					<Add option="/GS-" />
+					<Add option='/Fd&quot;..\..\build\$(PROJECT_NAME)\$(TARGET_NAME)\vc80.pdb&quot;' />
+					<Add option="/wd4610 /wd4510 /wd4512 /wd4505 /wd4100 /wd4127 /wd4996" />
+					<Add option="/D_CRT_SECURE_NO_DEPRECATE" />
+					<Add option="/DWIN32" />
+					<Add option="/D_WINDLL" />
+					<Add option="/D_MBCS" />
+				</Compiler>
+				<Linker>
+					<Add option="/DEBUG" />
+					<Add option="/INCREMENTAL:NO" />
+					<Add option="/NOLOGO" />
+					<Add option="/DLL" />
+					<Add option="/MANIFEST" />
+					<Add option='/MANIFESTFILE:&quot;..\..\build\$(PROJECT_NAME)\$(TARGET_NAME)\$(PROJECT_NAME).dll.intermediate.manifest&quot;' />
+					<Add option='/DEF:&quot;../../plugins/$(PROJECT_NAME)/$(PROJECT_NAME).def&quot;' />
+					<Add option='/pdb:&quot;..\..\install\modules\$(PROJECT_NAME).pdb&quot;' />
+					<Add option="/SUBSYSTEM:WINDOWS" />
+					<Add option="/MACHINE:X86" />
+					<Add option="/ERRORREPORT:PROMPT" />
+					<Add library="gtkutillib" />
+					<Add library="xmlutillib" />
+					<Add library="libxml2" />
+					<Add library="glib-2.0" />
+					<Add library="gtk-win32-2.0" />
+					<Add library="gdk-win32-2.0" />
+					<Add library="gobject-2.0" />
+					<Add library="gdk_pixbuf-2.0" />
+				</Linker>
+			</Target>
+			<Target title="Release Win32">
+				<Option platforms="Windows;" />
+				<Option output="..\..\install\modules\$(PROJECT_NAME)" prefix_auto="1" extension_auto="1" />
+				<Option object_output="..\..\build\$(PROJECT_NAME)\$(TARGET_NAME)" />
+				<Option external_deps="..\..\build\libs\$(TARGET_NAME)\gtkutillib.lib;..\..\build\libs\$(TARGET_NAME)\libxml2.lib;..\..\build\libs\$(TARGET_NAME)\xmlutillib.lib;" />
+				<Option type="3" />
+				<Option compiler="msvc8" />
+				<Option createDefFile="1" />
+				<Option createStaticLib="1" />
+				<Compiler>
+					<Add option="/MD" />
+					<Add option="/TP" />
+					<Add option="/Gd" />
+					<Add option="/GL" />
+					<Add option="/fp:precise" />
+					<Add option="/EHc" />
+					<Add option="/EHs" />
+					<Add option="/GF" />
+					<Add option="/Ob" />
+					<Add option="/Oi" />
+					<Add option="/Ot" />
+					<Add option="/O2" />
+					<Add option="/W4" />
+					<Add option="/Zi" />
+					<Add option="/GS-" />
+					<Add option='/Fd&quot;..\..\build\$(PROJECT_NAME)\$(TARGET_NAME)\vc80.pdb&quot;' />
+					<Add option="/wd4610 /wd4510 /wd4512 /wd4505 /wd4100 /wd4127 /wd4996" />
+					<Add option="/D_CRT_SECURE_NO_DEPRECATE" />
+					<Add option="/DWIN32" />
+					<Add option="/D_WINDLL" />
+					<Add option="/D_MBCS" />
+				</Compiler>
+				<Linker>
+					<Add option="/INCREMENTAL:NO" />
+					<Add option="/NOLOGO" />
+					<Add option="/DLL" />
+					<Add option="/MANIFEST" />
+					<Add option='/MANIFESTFILE:&quot;..\..\build\$(PROJECT_NAME)\$(TARGET_NAME)\$(PROJECT_NAME).dll.intermediate.manifest&quot;' />
+					<Add option='/DEF:&quot;../../plugins/$(PROJECT_NAME)/$(PROJECT_NAME).def&quot;' />
+					<Add option='/pdb:&quot;..\..\install\modules\$(PROJECT_NAME).pdb&quot;' />
+					<Add option="/SUBSYSTEM:WINDOWS" />
+					<Add option="/OPT:REF" />
+					<Add option="/OPT:ICF" />
+					<Add option="/LTCG" />
+					<Add option="/MACHINE:X86" />
+					<Add option="/ERRORREPORT:PROMPT" />
+					<Add library="gtkutillib" />
+					<Add library="xmlutillib" />
+					<Add library="libxml2" />
+					<Add library="glib-2.0" />
+					<Add library="gtk-win32-2.0" />
+					<Add library="gdk-win32-2.0" />
+					<Add library="gobject-2.0" />
+					<Add library="gdk_pixbuf-2.0" />
+				</Linker>
+			</Target>
+			<Target title="Clean Install Win32">
+				<Option platforms="Windows;" />
+				<Option type="4" />
+				<Option compiler="msvc8" />
+				<ExtraCommands>
+					<Add before='cmd /C &quot;del ..\..\install\modules\$(PROJECT_NAME).* /F /Q &amp; exit 0&quot;' />
+				</ExtraCommands>
+			</Target>
+		</Build>
+		<Compiler>
+			<Add directory="..\..\include" />
+			<Add directory="..\..\libs" />
+			<Add directory="$(#boost.include)" />
+			<Add directory="$(#libxml2.include)" />
+			<Add directory="$(#gtk2.include)\gtk-2.0" />
+			<Add directory="$(#gtk2.include)\atk-1.0" />
+			<Add directory="$(#gtk2.include)\glib-2.0" />
+			<Add directory="$(#gtk2.include)\cairo" />
+			<Add directory="$(#gtk2.include)\pango-1.0" />
+			<Add directory="$(#gtk2.lib)\glib-2.0\include" />
+			<Add directory="$(#gtk2.lib)\gtk-2.0\include" />
+			<Add directory="$(#win_iconv.include)" />
+			<Add directory="$(#glew.include)" />
+		</Compiler>
+		<Linker>
+			<Add directory="..\..\build\libs\$(TARGET_NAME)" />
+			<Add directory="$(#gtk2.lib)" />
+			<Add directory="$(#libxml2.lib)" />
+		</Linker>
+		<Unit filename="..\..\plugins\mapquake2\Quake2MapFormat.cpp">
+			<Option target="Debug Win32" />
+			<Option target="Release Win32" />
+		</Unit>
+		<Unit filename="..\..\plugins\mapquake2\Quake2MapFormat.h">
+			<Option target="Debug Win32" />
+			<Option target="Release Win32" />
+		</Unit>
+		<Unit filename="..\..\plugins\mapquake2\Quake2NodeExporter.cpp">
+			<Option target="Debug Win32" />
+			<Option target="Release Win32" />
+		</Unit>
+		<Unit filename="..\..\plugins\mapquake2\Quake2NodeExporter.h">
+			<Option target="Debug Win32" />
+			<Option target="Release Win32" />
+		</Unit>
+		<Unit filename="..\..\plugins\mapquake2\Quake2NodeImporter.cpp">
+			<Option target="Debug Win32" />
+			<Option target="Release Win32" />
+		</Unit>
+		<Unit filename="..\..\plugins\mapquake2\Quake2NodeImporter.h">
+			<Option target="Debug Win32" />
+			<Option target="Release Win32" />
+		</Unit>
+		<Unit filename="..\..\plugins\mapquake2\Tokens.h">
+			<Option target="Debug Win32" />
+			<Option target="Release Win32" />
+		</Unit>
+		<Unit filename="..\..\plugins\mapquake2\mapquake2.cpp">
+			<Option target="Debug Win32" />
+			<Option target="Release Win32" />
+		</Unit>
+		<Unit filename="..\..\plugins\mapquake2\mapquake2.def">
+			<Option target="Debug Win32" />
+			<Option target="Release Win32" />
+		</Unit>
+		<Extensions>
+			<code_completion />
+			<debugger />
+			<envvars />
+		</Extensions>
+	</Project>
+</CodeBlocks_project_file>
