Commits

Anonymous committed 918a26d

bounding box rotation

Comments (0)

Files changed (14)

 level1 = "level.xml"
 level1.displayname = "Test Level v1"
 level2 = "obbtest.xml"
-level2.displayname = "OBBTest Area"
+level2.displayname = "OBBTest Area"
+level3 = "rotationtest.xml"
+level3.displayname = "Rotation Test"

media/leveldata/obbtest.xml

     	</template>
     </templates>
     <levelobjects>
-    	<object type="GiantBox" layer="static" x="35" y="-60" />
+    	<object type="GiantBox" layer="static" x="35" y="-61" />
         <object type="GiantBox" layer="static" x="142.5761" y="-57.0349">
             <material name="Textures/Marmor" />
             <position x="0" y="5" z="0" />
             <orientation w="0.99747" x="-0.0711167" y="0" z="0" />
-            <Collision>
+            <Collision rotation="0">
             	<point x="85" y="-107" />
             	<point x="206" y="-93" />
             	<point x="192" y="6" />

media/leveldata/rotationtest.xml

+<leveldata version="1">
+    <templates />
+    <levelobjects>
+        <object type="CustomAABB" layer="static" x="29.2203" y="-1.53076">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.085821" z="0.858211" />
+            <position x="0" y="0" z="0" />
+            <orientation w="0.992988" x="-0.118231" y="0" z="0" />
+            <Collision rotation="0.237004">
+                <point x="-13.6903" y="-5.82186" />
+                <point x="72.1308" y="-5.82186" />
+                <point x="72.1308" y="2.76024" />
+                <point x="-13.6903" y="2.76024" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="116.366" y="0.897169">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.085821" z="0.858211" />
+            <position x="0" y="0" z="0" />
+            <orientation w="0.992988" x="-0.118231" y="0" z="0" />
+            <Collision rotation="0.237004">
+                <point x="73.4553" y="-3.39387" />
+                <point x="159.276" y="-3.39387" />
+                <point x="159.276" y="5.18822" />
+                <point x="73.4553" y="5.18822" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="197.846" y="0.897169">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.085821" z="0.858211" />
+            <position x="0.579742" y="0" z="0" />
+            <orientation w="0.993587" x="0.113089" y="0" z="0" />
+            <Collision rotation="-0.226237">
+                <point x="154.936" y="-3.39387" />
+                <point x="240.757" y="-3.39387" />
+                <point x="240.757" y="5.18822" />
+                <point x="154.936" y="5.18822" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="279.364" y="0.897169">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.085821" z="0.858211" />
+            <position x="0.23436" y="0" z="0" />
+            <orientation w="0.990944" x="-0.134303" y="0" z="0" />
+            <Collision rotation="0.269477">
+                <point x="236.453" y="-3.39387" />
+                <point x="322.274" y="-3.39387" />
+                <point x="322.274" y="5.18822" />
+                <point x="236.453" y="5.18822" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="7.26606" y="-42.3322">
+            <entity name="cube.mesh" />
+            <material name="Textures/Rockwall" />
+            <scale x="3.30431" y="0.01" z="3.30431" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <AABBextends min_x="-157.95" min_y="-42.8322" max_x="172.482" max_y="-41.8322" />
+        </object>
+        <object type="CustomAABB" layer="static" x="324.674" y="13.5446">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.0586416" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <Collision rotation="0">
+                <point x="320.22" y="9.70682" />
+                <point x="330.22" y="9.70682" />
+                <point x="330.22" y="15.571" />
+                <point x="320.22" y="15.571" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="334.874" y="15.9298">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.0586416" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <Collision rotation="0">
+                <point x="335.073" y="3.2643" />
+                <point x="345.073" y="3.2643" />
+                <point x="345.073" y="9.12845" />
+                <point x="335.073" y="9.12845" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="345.074" y="18.0924">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.0586416" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <Collision rotation="0.185712">
+                <point x="311.727" y="14.6856" />
+                <point x="386.896" y="14.6856" />
+                <point x="386.896" y="20.5498" />
+                <point x="311.727" y="20.5498" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="355.274" y="20.0379">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.0586416" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <Collision rotation="0">
+                <point x="349.477" y="3.25277" />
+                <point x="359.477" y="3.25277" />
+                <point x="359.477" y="9.11692" />
+                <point x="349.477" y="9.11692" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="365.474" y="22.2076">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.0586416" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <Collision rotation="0">
+                <point x="363.587" y="3.22952" />
+                <point x="373.587" y="3.22952" />
+                <point x="373.587" y="9.09368" />
+                <point x="363.587" y="9.09368" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="375.674" y="24.055">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.0586416" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <Collision rotation="0">
+                <point x="374.072" y="3.02785" />
+                <point x="384.072" y="3.02785" />
+                <point x="384.072" y="8.892" />
+                <point x="374.072" y="8.892" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="382.767" y="26.8782">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.01" z="0.1" />
+            <position x="0.429558" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <Collision rotation="0">
+                <point x="385.799" y="26.3674" />
+                <point x="395.799" y="26.3674" />
+                <point x="395.799" y="27.3674" />
+                <point x="385.799" y="27.3674" />
+            </Collision>
+        </object>
+        <object type="CustomAABB" layer="static" x="392.967" y="26.8782">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.01" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <AABBextends min_x="387.967" min_y="26.3782" max_x="397.967" max_y="27.3782" />
+        </object>
+        <object type="CustomAABB" layer="static" x="403.167" y="26.8782">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.01" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <AABBextends min_x="398.167" min_y="26.3782" max_x="408.167" max_y="27.3782" />
+        </object>
+        <object type="CustomAABB" layer="static" x="413.367" y="26.8782">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.01" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <AABBextends min_x="408.367" min_y="26.3782" max_x="418.367" max_y="27.3782" />
+        </object>
+        <object type="CustomAABB" layer="static" x="423.567" y="26.8782">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.01" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <AABBextends min_x="418.567" min_y="26.3782" max_x="428.567" max_y="27.3782" />
+        </object>
+        <object type="CustomAABB" layer="static" x="433.767" y="26.8782">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.01" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <AABBextends min_x="428.767" min_y="26.3782" max_x="438.767" max_y="27.3782" />
+        </object>
+        <object type="CustomAABB" layer="static" x="443.967" y="26.8782">
+            <entity name="cube.mesh" />
+            <material name="Textures/Marmor" />
+            <scale x="0.1" y="0.01" z="0.1" />
+            <position x="0" y="0" z="0" />
+            <orientation w="1" x="0" y="0" z="0" />
+            <AABBextends min_x="438.967" min_y="26.3782" max_x="448.967" max_y="27.3782" />
+        </object>
+    </levelobjects>
+</leveldata>

src/GameObjects/CCharacter.cpp

 		GameObjects::PLevelObject temp(new GameObjects::CLevelObject(Ogre::Vector2(GetPosition().z, GetPosition().y)));
 		temp->SetBoundingBox(boundingRect);
 
-/*
-		if (!bJumping) {
-			// EXPERIMENTAL: stairs
-
-			translation = goLevel->ResolveCollision(temp, Ogre::Vector2(0, 4.0f));
-			temp->SetPosition(temp->GetPosition() + translation);
-
-			Ogre::Vector2 trans = goLevel->ResolveCollision(temp, Ogre::Vector2(deltaTime*fSpeed, 0));
-			temp->SetPosition(temp->GetPosition() + trans);
-
-			translation = translation+trans;
-
-			trans = goLevel->ResolveCollision(temp, Ogre::Vector2(0, -translation.y + deltaTime*fVerticalVelocity));
-			translation = translation + trans;
-		} else {*/
-			translation = Ogre::Vector2(deltaTime * fSpeed, deltaTime * fVerticalVelocity);
-			translation = goLevel->ResolveCollision(temp, translation);
-		//}
+		translation = Ogre::Vector2(deltaTime * fSpeed, deltaTime * fVerticalVelocity);
+		translation = goLevel->ResolveCollision(temp, translation);
 
 		ogreBodyNode->translate(0.0f, translation.y, translation.x, Ogre::Node::TS_LOCAL);
 		CheckFloatZero(translation.x); CheckFloatZero(translation.y);

src/GameObjects/CLevelData.cpp

 	return polygon;
 }
 
+float GetTranslationFactorFromDirection(const Ogre::Vector2& translation, const Ogre::Vector2& direction) {
+	if (approximatelyEqual(direction.y, 0.0f))
+		return translation.x / direction.x;
+	else if (approximatelyEqual(direction.x, 0.0f))
+		return translation.y / direction.y;
+	else {
+		if (fabs(translation.x) > fabs(translation.y))
+			return translation.x / direction.x;
+		else
+			return translation.y / direction.y;
+	}
+}
+
 Ogre::Vector2 CLevelData::ResolveCollision(PLevelObject object, const Ogre::Vector2& translation) {
 
 	// TODO: Make sure that length of resulting translation does not exceed the lenght of the translation
 		// find separating axis
 		Ogre::Vector2 separatingAxis(0.0f, 0.0f);
 
-//		bool knownFace = visitedFaces.find(nearestFace) != visitedFaces.end();
-
 		int separatingAxisIndex = -1;
 		float maxDp = 0.0f;
 		for (int i = 0; i < separatingAxes.size(); i++) {
-			// if we already moved along this face, dont use the same axis twice
-//			if (knownFace && LinearlyDependent(visitedFaces[nearestFace], separatingAxes[i]) )
-//				continue;
 
 			SATResult satResult = objectPolygon.IsSeparatingAxis(facePoly, separatingAxes[i]);
 
 
 			if (satResult.IsSeparating || approximatelyEqual(satResult.MinimumOverlap, 0.0f)) {
 				float dp = currentTranslation.dotProduct(separatingAxes[i]);
-				if (fabs(maxDp) < fabs(dp)) {
+				if (fabs(maxDp) <= fabs(dp)) {
 					maxDp = dp;
 					separatingAxis = separatingAxes[i].normalisedCopy();
 					TEST_LOG("^ choose");
 
 		separatingAxes.erase(separatingAxes.begin() + separatingAxisIndex);
 
-		/*if (approximatelyEqual(separatingAxis.dotProduct(currentTranslation), 0.0f)) {
-			TEST_LOG("dotproduct = 0");
-			bResolveFinished = true;
-			continue;
-		}*/
-
 		// make separatingAxis face in same direction as translation
 		if (separatingAxis.dotProduct(currentTranslation) < 0.0f)
 			separatingAxis = -separatingAxis;
 		// calculate maximum allowed translation along separatingAxis
 		float maxFactor = separatingAxis.dotProduct(translation);
 
+		// dont allow movement against translation direction
 		if (maxFactor < 0.0f || approximatelyEqual(maxFactor, 0.0f)) {
-			TEST_LOG("maxFactor <= 0");
+			TEST_LOG("maxFactor <= 0  ("<< maxFactor <<")");
 			bResolveFinished = true;
 			continue;
 		}
 				// get minimum translation vector in direction of currentTranslation
 				Ogre::Vector2 axisNormal = LeftHandNormal(separatingAxes[i]);
 				Ogre::Vector2 MTV = satResult.MinimumOverlap * axisNormal;
-//				if (MTV.dotProduct(translation) < 0)
-//					MTV = satResult.MaximumOverlap * axisNormal;
 
 				MTV *= (1.0f + TOLERANCE);
-
 				TEST_LOG("MTV: "<<MTV);
 
-				float factor;
-				if (approximatelyEqual(separatingAxis.y, 0.0f))
-					factor = MTV.x / separatingAxis.x;
-				else if (approximatelyEqual(separatingAxis.x, 0.0f))
-					factor = MTV.y / separatingAxis.y;
-				else {
-					if (fabs(MTV.x) > fabs(MTV.y))
-						factor = MTV.x / separatingAxis.x;
-					else
-						factor = MTV.y / separatingAxis.y;
-				}
+				float factor = GetTranslationFactorFromDirection(MTV, separatingAxis);
 
 				if (factor < 0.0f) {
 					MTV = satResult.MaximumOverlap * axisNormal;
 					MTV *= (1.0f + TOLERANCE);
-
 					TEST_LOG("MTV: "<<MTV);
 
-					if (approximatelyEqual(separatingAxis.y, 0.0f))
-						factor = MTV.x / separatingAxis.x;
-					else if (approximatelyEqual(separatingAxis.x, 0.0f))
-						factor = MTV.y / separatingAxis.y;
-					else {
-						if (fabs(MTV.x) > fabs(MTV.y))
-							factor = MTV.x / separatingAxis.x;
-						else
-							factor = MTV.y / separatingAxis.y;
-					}
+					factor = GetTranslationFactorFromDirection(MTV, separatingAxis);
 				}
 
 				TEST_LOG("->factor="<<factor);

src/GameObjects/Geometry.cpp

 	return result;
 }
 
+float Polygon::CalculateArea() const {
+	if (Points.size() < 3)
+		return 0.0f;
+
+    // A = \frac{1}{2}\sum_{i=0}^{N-1} (x_i\ y_{i+1} - x_{i+1}\ y_i)
+	float area = 0.0f;
+
+	for (int i = 0; i < Points.size(); i++) {
+		int iplusone = i+1;
+		if (iplusone >= Points.size())
+			iplusone = 0;
+		area += Points[i].x * Points[iplusone].y - Points[iplusone].x * Points[i].y;
+	}
+
+	return 0.5f * area;
+}
+
+Ogre::Vector2 Polygon::CalculateCenter() const {
+	if (Points.size() <= 0)
+		return Ogre::Vector2::ZERO;
+	if (Points.size() == 1)
+		return Points[0];
+	if (Points.size() == 2)
+		return 0.5f * (Points[0] + Points[1]);
+
+	float area = CalculateArea();
+	if (area == 0.0f)
+		return Points[0];
+
+	Ogre::Vector2 center(0.0f, 0.0f);
+	for (int i = 0; i < Points.size(); i++) {
+		int iplusone = i+1;
+		if (iplusone >= Points.size())
+			iplusone = 0;
+
+		//  C_x = \frac{1}{6A}\sum_{i=0}^{N-1}(x_i+x_{i+1})(x_i\ y_{i+1} - x_{i+1}\ y_i)
+		center.x += (Points[i].x + Points[iplusone].x) * (Points[i].x*Points[iplusone].y - Points[iplusone].x*Points[i].y);
+
+		// C_y = \frac{1}{6A}\sum_{i=0}^{N-1}(y_i+y_{i+1})(x_i\ y_{i+1} - x_{i+1}\ y_i)
+		center.y += (Points[i].y + Points[iplusone].y) * (Points[i].x*Points[iplusone].y - Points[iplusone].x*Points[i].y);
+	}
+
+	return ( 1.0f / (6.0f * area) ) * center;
+}
+
+void Polygon::Rotate(float angle) {
+	if (Points.size() <= 1)
+		return;
+
+	if (angle == 0.0f)
+		return;
+
+	Ogre::Vector2 center = CalculateCenter();
+
+	float sine = sin(angle);
+	float cosine = cos(angle);
+
+	// translate origin to center, rotate, translate back
+	for (int i = 0; i < Points.size(); i++) {
+		Ogre::Vector2 v = Points[i];
+		v -= center;
+		float x = cosine*v.x - sine*v.y;
+		float y = sine*v.x + cosine*v.y;
+		v.x = x; v.y = y;
+		v += center;
+		Points[i] = v;
+	}
+}
+
 std::ostream& operator<< (std::ostream& os, const Polygon& polygon) {
 	os << "Polygon(";
 

src/GameObjects/Geometry.h

 	std::vector<Face> GetFaces(bool NoNormals = false) const;
 	/** Get Points*/
 	const std::vector<Ogre::Vector2>& GetPoints() const { return Points; }
-	/** Moves all Points by translation */
+
+	/** Move all Points by translation */
 	void Translate(const Ogre::Vector2& translation);
 
+	/** Calculates Area */
+	float CalculateArea() const;
+	/** Calculates Center */
+	Ogre::Vector2 CalculateCenter() const;
+
+	/** Rotate by angle around center */
+	void Rotate(float angle);
+
+
 	/** Get Minimum Enclosing Rectangle */
 	Game::Rectangle GetMinimumEnclosingRectangle() const;
 

src/GameObjects/LevelDataReader.cpp

 
 	ticpp::Element* collision = node.FirstChildElement("Collision", false);
 	if (collision) {
+		object->SetRotation(collision->GetAttribute<float>("rotation"));
 		object->SetCollisionPolygon(ReadPolygon(*collision));
 	}
 }

src/GameObjects/LevelDataWriter.cpp

 	WriteQuaternion(*element, "orientation", view->GetOrientation());
 	if (object->BoundingBoxCollisionEnabled())
 		WriteRectangle(*element, "AABBextends", object->GetBoundingBox());
-	else
-		WritePolygon(*element, "Collision", object->GetCollisionPolygon());
+	else {
+		Element* collision = WritePolygon(*element, "Collision", object->GetCleanCollisionPolygon());
+		collision->SetAttribute("rotation", object->GetRotation());
+	}
 
 	levelobjects->LinkEndChild(element);
 }
 	node.LinkEndChild(element);
 }
 
-void CXMLWriter::WritePolygon(ticpp::Element& node, const std::string& name, const Game::Polygon& poly) {
+Element* CXMLWriter::WritePolygon(ticpp::Element& node, const std::string& name, const Game::Polygon& poly) {
 	Element* element = new Element(name);
 	std::vector<Ogre::Vector2> points = poly.GetPoints();
 
 	for (std::vector<Ogre::Vector2>::iterator it = points.begin(); it != points.end(); ++it) {
-		WriteVector2(node, "point", *it);
+		WriteVector2(*element, "point", *it);
 	}
 
 	node.LinkEndChild(element);
+	return element;
 }
 
 }

src/GameObjects/LevelDataWriter.h

 	void WriteAABB(ticpp::Element& node, const std::string& name, const Ogre::AxisAlignedBox& box);
 	void WriteRectangle(ticpp::Element& node, const std::string& name, const Game::Rectangle& rect);
 	void WriteString(ticpp::Element& node, const std::string& name, const std::string& value);
-	void WritePolygon(ticpp::Element& node, const std::string& name, const Game::Polygon& poly);
+	ticpp::Element* WritePolygon(ticpp::Element& node, const std::string& name, const Game::Polygon& poly);
 
 	ticpp::Document document;
 	ticpp::Element *root, *templates, *levelobjects;

src/GameObjects/LevelObjects.cpp

 	// don't copy listeners
 	aabBounds = obj.aabBounds;
 	collisionData = obj.collisionData;
+	cachedCollisionData = obj.cachedCollisionData;
+	angle = obj.angle;
 	vPosition = obj.vPosition;
 	collisionType = obj.collisionType;
+	BoundingBoxCollision = obj.BoundingBoxCollision;
 }
 
 PLevelObject CLevelObject::Copy() {
 
 void CLevelObject::EnableBoundingBoxCollision() {
 	collisionData = Game::Polygon(aabBounds);
+	cachedCollisionData = collisionData;
+	angle = 0.0f;
 	BoundingBoxCollision = true;
 	notifyBoundsChanged();
 }
 void CLevelObject::SetCollisionPolygon(const Game::Polygon& polygon) {
 	if (collisionData != polygon) {
 		collisionData = polygon;
+		cachedCollisionData = polygon;
+		cachedCollisionData.Rotate(this->angle);
 		BoundingBoxCollision = false;
-		aabBounds = polygon.GetMinimumEnclosingRectangle();
+		aabBounds = cachedCollisionData.GetMinimumEnclosingRectangle();
 		notifyBoundsChanged();
 	}
 }
 	if (vPosition != position) {
 		Ogre::Vector2 translate = position - vPosition;
 		aabBounds.Translate(translate);
-		collisionData.Translate(position);
+		collisionData.Translate(translate);
+		cachedCollisionData = collisionData;
+		cachedCollisionData.Rotate(angle);
 		vPosition = position;
 		notifyPositionChanged();
 		notifyBoundsChanged();
 	if (aabBounds != newRect) {
 		aabBounds = newRect;
 		if (BoundingBoxCollision)
-			collisionData = Game::Polygon(aabBounds);
+			collisionData = cachedCollisionData = Game::Polygon(aabBounds);
 		notifyBoundsChanged();
 	}
 }
 	if (aabBounds != box) {
 		aabBounds = box;
 		if (BoundingBoxCollision)
-			collisionData = Game::Polygon(aabBounds);
+			collisionData = cachedCollisionData = Game::Polygon(aabBounds);
+		notifyBoundsChanged();
+	}
+}
+
+void CLevelObject::SetRotation(float angle) {
+	if (this->angle != angle) {
+		this->angle = angle;
+		cachedCollisionData = collisionData;
+		if (angle != 0.0f) {
+			BoundingBoxCollision = false;
+			cachedCollisionData.Rotate(angle);
+		}
+		if (!BoundingBoxCollision) {
+			aabBounds = cachedCollisionData.GetMinimumEnclosingRectangle();
+		}
 		notifyBoundsChanged();
 	}
 }
 
 void COgreBoundsView::UpdateGeometry() {
 	PLevelObject model = Model.lock();
+	float angle = 0.0f;
 	if (model) {
 		Game::Rectangle bounds = model->GetBoundingBox();
 		Ogre::Vector2 center = 0.5f*(bounds.GetMaximum() + bounds.GetMinimum());
-		this->vPositionOffset = Ogre::Vector3(0.0f, center.y, center.x);
+		Ogre::Vector2 scale2d =  bounds.GetMaximum() - bounds.GetMinimum();
+
+		std::vector<Ogre::Vector2> poly = model->GetCleanCollisionPolygon().GetPoints();
+		// assume it's a oriented bounding box
+		if (poly.size() == 4) {
+			center = model->GetCleanCollisionPolygon().CalculateCenter();
+			scale2d = poly[2] - poly[0];
+			angle = model->GetRotation();
+		}
 
 		// cube.mesh is 100x100x100
 		this->vScale.x = 1.0f * 0.01f;
-		Ogre::Vector2 scale2d =  bounds.GetMaximum() - bounds.GetMinimum();
 		this->vScale.y = scale2d.y * 0.01f;
 		this->vScale.z = scale2d.x * 0.01f;
+
+		this->vPositionOffset = Ogre::Vector3(0.0f, center.y, center.x);
 	}
 
 	if (oScene) {
 			}
 			oNode->setPosition(vPositionOffset);
 			oNode->setScale(vScale);
-			oNode->setOrientation(qOrientation);
+			oNode->setOrientation(Ogre::Quaternion(Ogre::Radian(angle), Ogre::Vector3::NEGATIVE_UNIT_X));
 		}
 	}
 

src/GameObjects/LevelObjects.h

 	/** Resets collision data to bounding box */
 	virtual void EnableBoundingBoxCollision();
 	virtual bool BoundingBoxCollisionEnabled() const { return BoundingBoxCollision; }
+
 	/** Set collision polygon */
 	virtual void SetCollisionPolygon(const Game::Polygon& polygon);
-	/** Returns Collision Polygon */
-	virtual const Game::Polygon& GetCollisionPolygon() const { return collisionData; }
+	/** Returns Collision Polygon with applied rotation (cached) */
+	virtual const Game::Polygon& GetCollisionPolygon() const { return cachedCollisionData; }
+	/** Returns Collision Polygon without applied rotation */
+	virtual const Game::Polygon& GetCleanCollisionPolygon() const { return collisionData; }
+
+	/** Set Rotation; disables bounding box collision */
+	virtual void SetRotation(float angle);
+	/** Get Rotation */
+	virtual float GetRotation() const { return angle; }
 
 	virtual CollisionType GetCollisionType() const { return collisionType; };
 	virtual void SetCollisionType(CollisionType collisionType);
 	CollisionType collisionType;
 	/** Collision Polygon */
 	Game::Polygon collisionData;
+	/** Cached rotated collision polygon */
+	Game::Polygon cachedCollisionData;
+	/** Rotation */
+	float angle;
 
 	bool BoundingBoxCollision;
 

src/States/CEditorState.cpp

 			if (!bAxisY) diff.y = 0;
 			if (!bAxisZ) diff.z = 0;
 
-			if (bBoundingBoxes) {
-				Game::Rectangle bbox = objSelected->GetModel()->GetBoundingBox();
-				bbox.Translate(Ogre::Vector2(diff.z, diff.y));
-				objSelected->GetModel()->SetBoundingBox(bbox);
-			} else {
+			if (!bBoundingBoxes) {
 				objSelected->SetPositionOffset(objSelected->GetPositionOffset() + Ogre::Vector3(diff.x, 0.0f, 0.0f));
 
 				Ogre::Vector2 pos = objSelected->GetModel()->GetPosition();
 				pos.x += diff.z;
 				pos.y += diff.y;
 				objSelected->GetModel()->SetPosition(pos);
+			} else {
+				Game::Polygon poly = objSelected->GetModel()->GetCleanCollisionPolygon();
+				poly.Translate(Ogre::Vector2(diff.z, diff.y));
+				objSelected->GetModel()->SetCollisionPolygon(poly);
 			}
 		} else if (ActiveMode == emScale) {
 			Ogre::Vector3 position = objSelected->GetPositionOffset();
 			position.y += objSelected->GetModel()->GetPosition().y;
 			position.z += objSelected->GetModel()->GetPosition().x;
 
-			if (bBoundingBoxes) {
-				Game::Rectangle bbox = objSelected->GetModel()->GetBoundingBox();
-				Ogre::Vector2 center = 0.5f* (bbox.GetMaximum() + bbox.GetMinimum());
-				position.x = 0.0f;
-				position.y = center.y;
-				position.z = center.x;
-			}
+			float angle = objSelected->GetModel()->GetRotation();
+			objSelected->GetModel()->SetRotation(0.0f);
+			Game::Rectangle bbox = objSelected->GetModel()->GetBoundingBox();
+			Ogre::Vector2 center = 0.5f* (bbox.GetMaximum() + bbox.GetMinimum());
+			Ogre::Vector3 positionBB;
+			positionBB.x = 0.0f;
+			positionBB.y = center.y;
+			positionBB.z = center.x;
 
 			Ogre::Vector3 pointCpy = point;
 			Ogre::Vector3 intPointCpy = intersectionPoint;
 
-			if (!bAxisX) position.x = pointCpy.x = intPointCpy.x = 0.0f;
-			if (!bAxisY) position.y = pointCpy.y = intPointCpy.y = 0.0f;
-			if (!bAxisZ) position.z = pointCpy.z = intPointCpy.z = 0.0f;
+			if (!bAxisX) position.x = positionBB.z = pointCpy.x = intPointCpy.x = 0.0f;
+			if (!bAxisY) position.y = positionBB.y = pointCpy.y = intPointCpy.y = 0.0f;
+			if (!bAxisZ) position.z = positionBB.x = pointCpy.z = intPointCpy.z = 0.0f;
+
+
+			Ogre::Vector3 vScale;
 
 			float distanceNew = pointCpy.squaredDistance(position);
 			float distanceOld = intPointCpy.squaredDistance(position);
 			float scaleFactor = sqrt(distanceNew / distanceOld);
 
-			Ogre::Vector3 vScale = Ogre::Vector3::UNIT_SCALE * scaleFactor;
+			vScale = Ogre::Vector3::UNIT_SCALE * scaleFactor;
 			if (!bAxisX) vScale.x = 1.0f;
 			if (!bAxisY) vScale.y = 1.0f;
 			if (!bAxisZ) vScale.z = 1.0f;
 
-			Ogre::Vector3 vScaleRel(vScale);
-
 			if (!bBoundingBoxes) {
-				objSelected->SetScale(vScale);
-				vScale.x *= objSelected->GetScale().x;
-				vScale.y *= objSelected->GetScale().y;
-				vScale.z *= objSelected->GetScale().z;
+				Ogre::Vector3 objScale(vScale);
+				objScale.x *= objSelected->GetScale().x;
+				objScale.y *= objSelected->GetScale().y;
+				objScale.z *= objSelected->GetScale().z;
+				objSelected->SetScale(objScale);
 			}
 
-			Game::Rectangle bbox = objSelected->GetModel()->GetBoundingBox();
-			Ogre::Vector2 center = 0.5f* (bbox.GetMaximum() + bbox.GetMinimum());
 			bbox.Translate(-center);
 			Ogre::Vector2 vMin = bbox.GetMinimum();
 			Ogre::Vector2 vMax = bbox.GetMaximum();
-			vMin.x *= vScale.x; vMin.y *= vScale.y;
-			vMax.x *= vScale.x; vMax.y *= vScale.y;
+			vMin.x *= vScale.z; vMin.y *= vScale.y;
+			vMax.x *= vScale.z; vMax.y *= vScale.y;
 			if (vScale.x < 0)
 				std::swap(vMin.x, vMax.x);
 			if (vScale.y < 0)
 			bbox.Translate(center);
 			objSelected->GetModel()->SetBoundingBox(bbox);
 
+			objSelected->GetModel()->EnableBoundingBoxCollision();
+			objSelected->GetModel()->SetRotation(angle);
+
 		} else if (ActiveMode == emRotate) {
 			if (!bBoundingBoxes) {
 				Ogre::Vector3 position = objSelected->GetPositionOffset();
 
 				Ogre::Vector3 vOld = intersectionPoint - position;
 				Ogre::Vector3 vNew = point - position;
+
 				if (bAxisX) vOld.x = vNew.x = 0.0f;
 				if (bAxisY) vOld.y = vNew.y = 0.0f;
 				if (bAxisZ) vOld.z = vNew.z = 0.0f;
 				vOld.normalise(); vNew.normalise();
 				Ogre::Quaternion angle = vOld.getRotationTo(vNew);
+
 				objSelected->SetOrientation(angle*objSelected->GetOrientation());
+				if (bAxisX) {
+					Ogre::Radian oAngle;
+					Ogre::Vector3 axis;
+					angle.ToAngleAxis(oAngle, axis);
+					float radian = oAngle.valueRadians();
+					if (axis.x > 0.0f)
+						radian = -radian;
+					objSelected->GetModel()->SetRotation(objSelected->GetModel()->GetRotation() + radian);
+				}
+			} else {
+				Game::Rectangle bbox = objSelected->GetModel()->GetBoundingBox();
+				Ogre::Vector2 center = 0.5f* (bbox.GetMaximum() + bbox.GetMinimum());
+				Ogre::Vector3 position;
+				position.x = 0.0f;
+				position.y = center.y;
+				position.z = center.x;
+
+				Ogre::Vector3 vOld = intersectionPoint - position;
+				Ogre::Vector3 vNew = point - position;
+
+				if (bAxisX && !bAxisY && !bAxisZ) {
+					vOld.x = vNew.x = 0.0f;
+					vOld.normalise(); vNew.normalise();
+					Ogre::Quaternion angle = vOld.getRotationTo(vNew);
+					Ogre::Radian oAngle;
+					Ogre::Vector3 axis;
+					angle.ToAngleAxis(oAngle, axis);
+					float radian = oAngle.valueRadians();
+					if (axis.x > 0.0f)
+						radian = -radian;
+
+					objSelected->GetModel()->SetRotation(objSelected->GetModel()->GetRotation() + radian);
+				}
 			}
 		}
 

test/GeometryTest.cpp

 	FLOAT_CHECK_EQUAL( result.second, 0.5f );
 }
 
+BOOST_AUTO_TEST_CASE( polygon_misc_test ) {
+	Game::Rectangle rect(-1, -1, 1, 1);
+	Game::Polygon poly(rect);
+
+	FLOAT_CHECK_EQUAL( poly.CalculateArea(), 4.0f);
+	FLOAT_CHECK_EQUAL( poly.CalculateCenter(), 0.5f*(rect.GetMinimum() + rect.GetMaximum()) );
+
+	rect = Game::Rectangle(1, 1, 5, 4);
+	poly = Game::Polygon(rect);
+	FLOAT_CHECK_EQUAL( poly.CalculateArea(), 12.0f);
+	FLOAT_CHECK_EQUAL( poly.CalculateCenter(), 0.5f*(rect.GetMinimum() + rect.GetMaximum()) );
+
+	rect = Game::Rectangle(-1, -1, 1, 1);
+	poly = Game::Polygon(rect);
+
+	FLOAT_CHECK_EQUAL(poly.CalculateCenter(), Ogre::Vector2::ZERO);
+
+	poly.Rotate(M_PI / 2.0f);
+	std::vector<Ogre::Vector2> points = poly.GetPoints();
+
+	FLOAT_CHECK_EQUAL(poly.CalculateCenter(), Ogre::Vector2::ZERO);
+
+	FLOAT_CHECK_EQUAL(points[0], Ogre::Vector2( 1.0f, -1.0f));
+	FLOAT_CHECK_EQUAL(points[1], Ogre::Vector2( 1.0f,  1.0f));
+	FLOAT_CHECK_EQUAL(points[2], Ogre::Vector2(-1.0f,  1.0f));
+	FLOAT_CHECK_EQUAL(points[3], Ogre::Vector2(-1.0f, -1.0f));
+
+	poly = Game::Polygon(rect);
+	poly.Rotate(M_PI / 4.0f);
+	points = poly.GetPoints();
+	FLOAT_CHECK_EQUAL(points[0], sqrt(2.0f) * Ogre::Vector2::NEGATIVE_UNIT_Y);
+	FLOAT_CHECK_EQUAL(points[1], sqrt(2.0f) * Ogre::Vector2::UNIT_X);
+	FLOAT_CHECK_EQUAL(points[2], sqrt(2.0f) * Ogre::Vector2::UNIT_Y);
+	FLOAT_CHECK_EQUAL(points[3], sqrt(2.0f) * Ogre::Vector2::NEGATIVE_UNIT_X);
+}
+
 BOOST_AUTO_TEST_CASE( ray_ray_intersection_test )
 {
 	Game::Ray ray1( Ogre::Vector2::ZERO, Ogre::Vector2::UNIT_Y );