Christian Fischer avatar Christian Fischer committed 95a7b10

some vector math and touchhandler fixes, node2d hit-detection

Comments (0)

Files changed (11)

src/base/wiesel/geometry.cpp

 }
 
 
+bool rect::contains(float x, float y) const {
+	if (
+			x >= getMinX()
+		&&	x <= getMaxX()
+		&&	y >= getMinY()
+		&&	y <= getMaxY()
+	) {
+		return true;
+	}
+
+	return false;
+}
+
+bool rect::contains(const vector2d& v) const {
+	return contains(v.x, v.y);
+}
+
+
 
 std::ostream& wiesel::operator <<(std::ostream &o, const dimension &dim) {
 	o << '[' << dim.width << 'x' << dim.height << ']';

src/base/wiesel/geometry.h

 		/// get the centre y-position
 		float getCenterY() const;
 
+	// tests
+	public:
+		/// tests, if this rectangle contains a specific point.
+		bool contains(float x, float y) const;
+
+		/// tests, if this rectangle contains a specific point.
+		bool contains(const vector2d &v) const;
+
 	public:
 		vector2d		position;		//!< Position of the rect.
 		dimension		size;			//!< Size of the rect.

src/base/wiesel/math/vector2d.cpp

 	const float w = 1.0f;
 
 	return vector2d(
-			(v.x * m.m11) + (v.y * m.m21) + (z * m.m31) + (w * m.m41),
-			(v.x * m.m12) + (v.y * m.m22) + (z * m.m32) + (w * m.m42)
+			(v.x * m.m11) + (v.y * m.m12) + (z * m.m13) + (w * m.m14),
+			(v.x * m.m21) + (v.y * m.m22) + (z * m.m23) + (w * m.m24)
 	);
 }
 
 	const float w = 1.0f;
 
 	v = vector2d(
-			(v.x * m.m11) + (v.y * m.m21) + (z * m.m31) + (w * m.m41),
-			(v.x * m.m12) + (v.y * m.m22) + (z * m.m32) + (w * m.m42)
+			(v.x * m.m11) + (v.y * m.m12) + (z * m.m13) + (w * m.m14),
+			(v.x * m.m21) + (v.y * m.m22) + (z * m.m23) + (w * m.m24)
 	);
 
 	return v;

src/base/wiesel/math/vector3d.cpp

 	const float w = 1.0f;
 
 	return vector3d(
-			(v.x * m.m11) + (v.y * m.m21) + (v.z * m.m31) + (w * m.m41),
-			(v.x * m.m12) + (v.y * m.m22) + (v.z * m.m32) + (w * m.m42),
-			(v.x * m.m13) + (v.y * m.m23) + (v.z * m.m33) + (w * m.m43)
+			(v.x * m.m11) + (v.y * m.m12) + (v.z * m.m13) + (w * m.m14),
+			(v.x * m.m21) + (v.y * m.m22) + (v.z * m.m23) + (w * m.m24),
+			(v.x * m.m31) + (v.y * m.m32) + (v.z * m.m33) + (w * m.m34)
 	);
 }
 
 	const float w = 1.0f;
 
 	v = vector3d(
-			(v.x * m.m11) + (v.y * m.m21) + (v.z * m.m31) + (w * m.m41),
-			(v.x * m.m12) + (v.y * m.m22) + (v.z * m.m32) + (w * m.m42),
-			(v.x * m.m13) + (v.y * m.m23) + (v.z * m.m33) + (w * m.m43)
+			(v.x * m.m11) + (v.y * m.m12) + (v.z * m.m13) + (w * m.m14),
+			(v.x * m.m21) + (v.y * m.m22) + (v.z * m.m23) + (w * m.m24),
+			(v.x * m.m31) + (v.y * m.m32) + (v.z * m.m33) + (w * m.m34)
 	);
 
 	return v;

src/common/wiesel/graph/2d/node2d.cpp

 	local_transform = matrix4x4::identity;
 
 	local_transform.translate(+bounds.position.x, +bounds.position.y);
-	local_transform.scale(scale_x, scale_y, 0.0f);
+	local_transform.scale(scale_x, scale_y, 1.0f);
 	local_transform.rotateZ(rotation * M_PI / 180.0f);
 	local_transform.translate(position.x, position.y);
 
 	return;
 }
 
+
+bool Node2D::hitBy(const vector2d& local) const {
+	// when 'local' is already in local coordinate space,
+	// the pivot offset is already included in the 'local' coordinate
+	if (
+			local.x >= 0
+		&&	local.y >= 0
+		&&	local.x <= getContentSize().width
+		&&	local.y <= getContentSize().height
+	) {
+		return true;
+	}
+
+	return false;
+}
+

src/common/wiesel/graph/2d/node2d.h

 		void updateTransform();
 
 
+	public:
+		/// Tests, if a point is within this node.
+		/// The point should already be transformed into the node's coordinate system.
+		virtual bool hitBy(const vector2d &local) const;
+
+
 	// overridables
 	protected:
 

src/common/wiesel/graph/2d/sprite_node.cpp

 	this->shader		= NULL;
 	this->vbo			= NULL;
 	this->vbo_dirty		= true;
+	this->hit_detection	= SpriteHitDetection_InnerBounds;
 
 	return;
 }
 	this->shader		= NULL;
 	this->vbo			= NULL;
 	this->vbo_dirty		= true;
+	this->hit_detection	= SpriteHitDetection_InnerBounds;
 
 	setTexture(texture);
 	setTextureRect(rect(texture->getOriginalSize()));
 	this->shader		= NULL;
 	this->vbo			= NULL;
 	this->vbo_dirty		= true;
+	this->hit_detection	= SpriteHitDetection_InnerBounds;
 
 	setTexture(texture);
 	setTextureRect(texture_rect);
 	this->shader		= NULL;
 	this->vbo			= NULL;
 	this->vbo_dirty		= true;
+	this->hit_detection	= SpriteHitDetection_InnerBounds;
 
 	setSpriteFrame(sprite);
 
 }
 
 
+bool SpriteNode::hitBy(const vector2d& local) const {
+	switch(getSpriteHitDetection()) {
+		default:
+		case SpriteHitDetection_OuterBounds: {
+			return Node2D::hitBy(local);
+		}
+
+		case SpriteHitDetection_InnerBounds: {
+			if (sprite && sprite->getInnerRect().contains(local)) {
+				return true;
+			}
+
+			break;
+		}
+	}
+
+	return false;
+}
+
+
 void SpriteNode::onDraw() {
 	if (texture) {
 		if (vbo_dirty) {

src/common/wiesel/graph/2d/sprite_node.h

 	class SpriteFrame;
 
 
+
+	enum SpriteHitDetection {
+		/**
+		 * Checks the collision against the outer bounds of the node.
+		 * This includes the sprite's image with any transparent border.
+		 */
+		SpriteHitDetection_OuterBounds,
+
+		/**
+		 * Checks the collision against the inner bounds of the node.
+		 * This only contains the image area of the sprite.
+		 * Only available when using SpriteFrames.
+		 */
+		SpriteHitDetection_InnerBounds,
+	};
+
+
+
 	/**
 	 * @brief A Node for displaying a single sprite.
 	 */
 	// getter / setter
 	public:
 		/**
+		 * @brief Set the hit detection method for this sprite.
+		 */
+		void setSpriteHitDetection(SpriteHitDetection hit);
+
+		/**
 		 * @brief Set the Shader to be used for rendering.
 		 */
 		void setShader(ShaderProgram *shader);
 		void setTextureRect(const rect &texture_rect);
 
 		/**
+		 * @brief Get the hit detection method, currently used by this sprite.
+		 */
+		inline SpriteHitDetection getSpriteHitDetection() const {
+			return hit_detection;
+		}
+
+		/**
 		 * @brief Get the currently used shader.
 		 */
 		inline ShaderProgram *getShader() {
 			return texture_rect;
 		}
 
+	// node2s stuff
+	public:
+		virtual bool hitBy(const vector2d &local) const;
+
 	// overridables
 	protected:
 		virtual void onDraw();
 		virtual void rebuildVertexBuffer();
 
 	protected:
+		SpriteHitDetection	hit_detection;
+
 		SpriteFrame*		sprite;
 		Texture*			texture;
 		rect				texture_rect;

src/common/wiesel/graph/node.cpp

  */
 #include "node.h"
 
+#include "wiesel/engine.h"
+
 #include <assert.h>
 #include <algorithm>
 
 }
 
 
+vector2d Node::convertScreenToLocal(const vector2d& screen) {
+	// at first, convert into OpenGL coordinate space
+	vector2d transformed = vector2d(
+			+(screen.x / Engine::getCurrent()->getScreen()->getSize().width  - 0.5f) * 2,
+			-(screen.y / Engine::getCurrent()->getScreen()->getSize().height - 0.5f) * 2
+	);
+
+	// then use the projection- and modelview matrix to get the actual coordinate system
+	return
+			transformed
+		/	Engine::getCurrent()->getScreen()->getProjectionMatrix()
+		/	this->getWorldTransform()
+	;
+}
+
+
 void Node::render() {
 	bool this_drawn = false;
 

src/common/wiesel/graph/node.h

 
 #include <wiesel/util/shared_object.h>
 #include <wiesel/math/matrix.h>
+#include <wiesel/math/vector2d.h>
 
 #include <vector>
 
 			return transform_dirty;
 		}
 
+	// coordinate conversion
+	public:
+		/**
+		 * @brief Converts a screen-location (for example the location of a touch event) into
+		 * the local coordinate system of this node.
+		 */
+		vector2d convertScreenToLocal(const vector2d &screen);
+
 	// public functions
 	public:
 		/**

src/common/wiesel/ui/touchhandler.cpp

 
 
 static Node* recursive_findNode(Touch *touch, Node *node) {
-	NodeList::const_iterator it = node->getChildren()->begin();
+	NodeList::const_reverse_iterator it = node->getChildren()->rbegin();
 
 	// ask all children in front
-	for(; it!=node->getChildren()->end() && (*it)->getOrderKey() >= 0; it++) {
-		recursive_findNode(touch, *it);
+	for(; (it!=node->getChildren()->rend()) && ((*it)->getOrderKey() >= 0); it++) {
+		Node *node = recursive_findNode(touch, *it);
+
+		if (node) {
+			return node;
+		}
 	}
 
 	// check, if the current node is hit by the touch
 		}
 	}
 
+	// start from beginning (the list may have been modified!)
+	it = node->getChildren()->rbegin();
+	for(; (it!=node->getChildren()->rend()) && ((*it)->getOrderKey() >= 0); it++) {
+	}
+
 	// ask all children below the current node
-	for(; it!=node->getChildren()->end() && (*it)->getOrderKey() >= 0; it++) {
-		recursive_findNode(touch, *it);
+	for(; it!=node->getChildren()->rend(); it++) {
+		Node *node = recursive_findNode(touch, *it);
+
+		if (node) {
+			return node;
+		}
 	}
 
 	return NULL;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.