Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
#4328: Add support for loading older Q3 map format
  • Loading branch information
codereader committed May 26, 2016
1 parent 4e9ec69 commit f46c768
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 6 deletions.
12 changes: 10 additions & 2 deletions plugins/mapdoom3/Quake3MapReader.cpp
Expand Up @@ -59,7 +59,8 @@ void Quake3MapReader::initPrimitiveParsers()
if (_primitiveParsers.empty())
{
addPrimitiveParser(PrimitiveParserPtr(new BrushDefParser));
addPrimitiveParser(PrimitiveParserPtr(new PatchDef2ParserQ3));
addPrimitiveParser(PrimitiveParserPtr(new PatchDef2ParserQ3));
addPrimitiveParser(PrimitiveParserPtr(new LegacyBrushDefParser));
}
}

Expand All @@ -72,7 +73,7 @@ void Quake3MapReader::parsePrimitive(parser::DefTokeniser& tok, const scene::INo
{
_primitiveCount++;

std::string primitiveKeyword = tok.nextToken();
std::string primitiveKeyword = tok.peek();

// Get a parser for this keyword
PrimitiveParsers::const_iterator p = _primitiveParsers.find(primitiveKeyword);
Expand All @@ -84,6 +85,13 @@ void Quake3MapReader::parsePrimitive(parser::DefTokeniser& tok, const scene::INo

const PrimitiveParserPtr& parser = p->second;

// All primitive formats except for the legacy brushDef format have a proper keyword
// which should be parsed away before reading in the tokens.
if (primitiveKeyword != "(")
{
tok.nextToken();
}

// Try to parse the primitive, throwing exception if failed
try
{
Expand Down
134 changes: 134 additions & 0 deletions plugins/mapdoom3/primitiveparsers/BrushDef.cpp
Expand Up @@ -133,4 +133,138 @@ scene::INodePtr BrushDefParser::parse(parser::DefTokeniser& tok) const
return node;
}

// Legacy brushDef format
const std::string& LegacyBrushDefParser::getKeyword() const
{
static std::string _keyword("("); // The Q3 map reader will just encounter this opening brace
return _keyword;
}

/*
Example Primitive:
// brush 0
{
( 2224 3952 0 ) ( 1424 3952 0 ) ( 1424 3808 0 ) common/caulk 192 192 0 0.125000 0.125000 0 4 0
( 1424 3808 8 ) ( 1424 3952 8 ) ( 2224 3952 8 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0
( 1416 3776 8 ) ( 2216 3776 8 ) ( 2216 3776 0 ) common/caulk 192 64 0 0.125000 0.125000 0 4 0
( 2944 3808 8 ) ( 2944 3952 8 ) ( 2944 3952 0 ) common/caulk -192 64 0 0.125000 0.125000 0 4 0
( 2224 3968 8 ) ( 1424 3968 8 ) ( 1424 3968 0 ) common/caulk 192 64 0 0.125000 0.125000 0 4 0
( 1340 3952 8 ) ( 1340 3808 8 ) ( 1340 3808 0 ) common/caulk -192 64 0 0.125000 0.125000 0 4 0
}
*/
scene::INodePtr LegacyBrushDefParser::parse(parser::DefTokeniser& tok) const
{
// Create a new brush
scene::INodePtr node = GlobalBrushCreator().createBrush();

// Cast the node, this must succeed
IBrushNodePtr brushNode = std::dynamic_pointer_cast<IBrushNode>(node);
assert(brushNode != NULL);

IBrush& brush = brushNode->getIBrush();

// 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
double x = string::to_float(tok.nextToken());
double y = string::to_float(tok.nextToken());
double z = string::to_float(tok.nextToken());
Vector3 p1(x, y, z);

tok.assertNextToken(")");
tok.assertNextToken("(");

x = string::to_float(tok.nextToken());
y = string::to_float(tok.nextToken());
z = string::to_float(tok.nextToken());
Vector3 p2(x, y, z);

tok.assertNextToken(")");
tok.assertNextToken("(");

x = string::to_float(tok.nextToken());
y = string::to_float(tok.nextToken());
z = string::to_float(tok.nextToken());
Vector3 p3(x, y, z);

tok.assertNextToken(")");

// Construct the plane from the three points
Plane3 plane(p3, p2, p1);

// Parse Shader, brushDef has an implicit "textures/" not written to the map
std::string shader = GlobalTexturePrefix_get() + tok.nextToken();

// Parse texture (shift rotation scale)
float shiftS = string::to_float(tok.nextToken());
float shiftT = string::to_float(tok.nextToken());

float rotation = string::to_float(tok.nextToken());

float scaleS = string::to_float(tok.nextToken());
float scaleT = string::to_float(tok.nextToken());

Matrix4 texdef = getTexDef(shiftS, shiftT, rotation, scaleS, scaleT);

// Parse Flags (usually each brush has all faces detail or all faces structural)
IBrush::DetailFlag flag = static_cast<IBrush::DetailFlag>(
string::convert<std::size_t>(tok.nextToken(), IBrush::Structural));
brush.setDetailFlag(flag);

// Ignore the other two flags
tok.skipTokens(2);

// Finally, add the new face to the brush
/*IFace& face = */brush.addFace(plane, texdef, shader);
}
else
{
std::string text = (boost::format(_("BrushDefParser: invalid token '%s'")) % token).str();
throw parser::ParseException(text);
}
}

return node;
}

Matrix4 LegacyBrushDefParser::getTexDef(float shiftS, float shiftT, float rotation, float scaleS, float scaleT)
{
Matrix4 transform;
double inverse_scale[2];

// I don't care about the correct texture scale, let's just load the matrix
static float DUMMY_WIDTH = 128;
static float DUMMY_HEIGHT = 128;

// transform to texdef shift/scale/rotate
inverse_scale[0] = 1 / (scaleS * DUMMY_WIDTH);
inverse_scale[1] = 1 / (scaleT * -DUMMY_HEIGHT);
transform[12] = shiftS / DUMMY_WIDTH;
transform[13] = -shiftT / -DUMMY_HEIGHT;

double c = cos(degrees_to_radians(-rotation));
double s = sin(degrees_to_radians(-rotation));

transform[0] = c * inverse_scale[0];
transform[1] = s * inverse_scale[1];
transform[4] = -s * inverse_scale[0];
transform[5] = c * inverse_scale[1];
transform[2] = transform[3] = transform[6] = transform[7] = transform[8] = transform[9] = transform[11] = transform[14] = 0;
transform[10] = transform[15] = 1;

return transform;
}

} // namespace map
20 changes: 16 additions & 4 deletions plugins/mapdoom3/primitiveparsers/BrushDef.h
@@ -1,7 +1,7 @@
#ifndef ParserBrushDef_h__
#define ParserBrushDef_h__
#pragma once

#include "imapformat.h"
#include "math/Matrix4.h"

namespace map
{
Expand All @@ -17,6 +17,18 @@ class BrushDefParser :
};
typedef std::shared_ptr<BrushDefParser> BrushDefParserPtr;

}
// For really old map formats, we don't even have the brushDef keyword
class LegacyBrushDefParser :
public PrimitiveParser
{
public:
const std::string& getKeyword() const;

#endif // ParserBrushDef_h__
scene::INodePtr parse(parser::DefTokeniser& tok) const;

private:
static Matrix4 getTexDef(float shiftS, float shiftT, float rotation, float scaleS, float scaleT);
};
typedef std::shared_ptr<LegacyBrushDefParser> LegacyBrushDefParserPtr;

}

0 comments on commit f46c768

Please sign in to comment.