View Issue Details

IDProjectCategoryView StatusLast Update
0002332DarkRadiantGeneralpublic29.12.2014 15:47
Reportermattn Assigned To 
PrioritynormalSeveritynormalReproducibilityalways
Status closedResolutionsuspended 
PlatformLinuxOSUbuntuOS Version10.04
Product Version1.4.0 
Summary0002332: MapImporter for Quake2 (Patch attached, Help needed)
DescriptionA quake2 map importer patch is attached to this ticket. I would like to request some help in getting it to work - maybe you are interested in having this in the repo, too (imo importing quake2 maps and resaving them as doom3 might be interesting for mappers, no? - anyway, back to topic)

the map importer does not work right now - currently it's mostly a copy & paste of the q3 primitive parser with some q2 specific changes.

the problem is that running make install or debuild binary does fail to install the module as it should go into /usr/lib make the install stuff wants it to be in /usr/local/lib. I have no idea where to search for this bug.

i've changed the configure.ac and the plugins/Makefile.am, ran autogen.sh and configure. after that i thought it should work on a make clean; make... but it doesn't. help is really more than welcome here. and if you are interested in such a plugin, too - let me know.
TagsNo tags attached.
Attached Files
mapquake2.diff (57,174 bytes)   
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>
mapquake2.diff (57,174 bytes)   

Activities

user81

28.09.2010 15:43

  ~0003209

Last edited: 28.09.2010 15:45

I would say importing from Quake 3 would even better, as there is such much stuff done in Q3 compared to D3.

That said I have found found a few q2 maps/mods that I would love to redecorate in TDM.

AluminumHaste

AluminumHaste

01.10.2010 20:57

updater   ~0003218

I've posted about this before, you can use Q3toD3 converter: http://www.fileplanet.com/209973/200000/fileinfo/Doom-3---Quake-3-Map-Converter

I've used it before, it will also convert textures to the new shader format. Darkmod has issues with the map files, but removing some of the entities in the map file seems to allow it to open in DarkRadiant.
mattn

mattn

02.10.2010 14:57

updater   ~0003219

maybe - but this tracker item is not about external tools. the dr codebase is the best radiant codebase out there. I would like to base our developement on this codebase - and therefore i would really like to know what i am doing wrong with the attached patch.
greebo

greebo

31.12.2013 12:46

administrator   ~0006339

mattn, is this item still relevant? I don't know whether your radiant fork is still active, far ahead, far behind - basically if it's worthwile to add a Q2 map module to DR.
greebo

greebo

31.12.2013 12:47

administrator   ~0006340

Reminder sent to: mattn

Just a reminder

Issue History

Date Modified Username Field Change
01.08.2010 21:22 mattn New Issue
01.08.2010 21:22 mattn File Added: mapquake2.diff
28.09.2010 15:43 user81 Note Added: 0003209
28.09.2010 15:45 user81 Note Edited: 0003209
01.10.2010 20:57 AluminumHaste Note Added: 0003218
02.10.2010 14:57 mattn Note Added: 0003219
31.12.2013 12:46 greebo Note Added: 0006339
31.12.2013 12:47 greebo Note Added: 0006340
29.12.2014 15:47 greebo Status new => closed
29.12.2014 15:47 greebo Resolution open => suspended