예제 #1
0
bool SnapToMovement::testSnapTo(const WFMath::Point<3>& position, const WFMath::Quaternion& orientation, WFMath::Vector<3>& adjustment, EmberEntity* snappedToEntity)
{
	try {
		for (std::vector<Ogre::SceneNode*>::iterator I = mDebugNodes.begin(); I != mDebugNodes.end(); ++I) {
			Ogre::SceneNode* node = *I;
			node->setVisible(false);
			Ogre::Entity* sphereEntity = static_cast<Ogre::Entity*> (node->getAttachedObject(0));
			sphereEntity->setMaterialName("/global/authoring/point");
		}
	} catch (const std::exception& ex) {
		S_LOG_WARNING("Error when setting up debug nodes for snapping." << ex);
	}

	std::vector<Ogre::SceneNode*>::iterator nodeIterator = mDebugNodes.begin();

	//Use an auto pointer to allow both for undefined values and automatic cleanup when exiting the method.
	std::auto_ptr<SnapPointCandidate> closestSnapping(0);

	WFMath::AxisBox<3> currentBbox = mEntity.getBBox();
	//Translate the bbox into a rotbox
	WFMath::RotBox<3> currentRotbox;
	currentRotbox.size() = currentBbox.highCorner() - currentBbox.lowCorner();
	currentRotbox.corner0() = currentBbox.lowCorner();
	currentRotbox.orientation().identity();
	currentRotbox.rotatePoint(orientation, WFMath::Point<3>(0, 0, 0));
	currentRotbox.shift(WFMath::Vector<3>(position));

	//See if we should visualize debug nodes for the moved entity
	for (size_t j = 0; j < currentRotbox.numCorners(); ++j) {
		WFMath::Point<3> currentPoint = currentRotbox.getCorner(j);
		if (currentPoint.isValid() && nodeIterator != mDebugNodes.end()) {

			Ogre::SceneNode* node = *nodeIterator;
			node->setPosition(Convert::toOgre(currentPoint));
			node->setVisible(true);
			nodeIterator++;
		}
	}

	//First find all entities which are close enough
	//Then try to do a snap movement based on the points of the eris bounding boxes. I.e. we only provide support for snapping one corner of a bounding box to another corner (for now).
	WFMath::Ball<3> boundingSphere = mEntity.getBBox().boundingSphere();
	Ogre::Sphere sphere(mNode._getDerivedPosition(), boundingSphere.radius() * 2);
	Ogre::SphereSceneQuery* query = mSceneManager.createSphereQuery(sphere);
	Ogre::SceneQueryResult& result = query->execute();
	for (Ogre::SceneQueryResultMovableList::const_iterator I = result.movables.begin(); I != result.movables.end(); ++I) {
		Ogre::MovableObject* movable = *I;
		if (movable->getUserAny().getType() == typeid(EmberEntityUserObject::SharedPtr)) {
			EmberEntityUserObject* anUserObject = Ogre::any_cast<EmberEntityUserObject::SharedPtr>(movable->getUserAny()).get();
			EmberEntity& entity = anUserObject->getEmberEntity();
			if (&entity != &mEntity && entity.hasBBox()) {
				//Ok, we have an entity which is close to our entity. Now check if any of the points of the bounding box is close.
				WFMath::AxisBox<3> bbox = entity.getBBox();
				if (bbox.isValid()) {
					WFMath::RotBox<3> rotbox;
					rotbox.size() = bbox.highCorner() - bbox.lowCorner();
					rotbox.corner0() = bbox.lowCorner();
					rotbox.orientation().identity();
					rotbox.rotatePoint(entity.getViewOrientation(), WFMath::Point<3>(0, 0, 0));
					rotbox.shift(WFMath::Vector<3>(entity.getViewPosition()));

					for (size_t i = 0; i < rotbox.numCorners(); ++i) {
						WFMath::Point<3> point = rotbox.getCorner(i);
						Ogre::SceneNode* currentNode(0);
						//If there is any unclaimed debug node left we'll use it to visualize the corner
						if (nodeIterator != mDebugNodes.end()) {
							currentNode = *nodeIterator;
							currentNode->setPosition(Convert::toOgre(point));
							currentNode->setVisible(true);
							nodeIterator++;
						}
						point.z() = 0;
						for (size_t j = 0; j < currentRotbox.numCorners(); ++j) {
							WFMath::Point<3> currentPoint = currentRotbox.getCorner(j);
							currentPoint.z() = 0;
							WFMath::CoordType distance = WFMath::Distance(currentPoint, point);
							if (distance <= mSnapThreshold) {
								if (currentNode) {
									Ogre::Entity* sphereEntity = static_cast<Ogre::Entity*> (currentNode->getAttachedObject(0));
									if (sphereEntity) {
										try {
											sphereEntity->setMaterialName("/global/authoring/point/moved");
										} catch (const std::exception& ex) {
											S_LOG_WARNING("Error when setting material for point." << ex);
										}
									}
								}
								if (!closestSnapping.get()) {
									closestSnapping = std::auto_ptr<SnapPointCandidate>(new SnapPointCandidate());
									closestSnapping->entity = &entity;
									closestSnapping->distance = distance;
									closestSnapping->adjustment = point - currentPoint;
								} else if (distance < closestSnapping->distance) {
									closestSnapping->entity = &entity;
									closestSnapping->distance = distance;
									closestSnapping->adjustment = point - currentPoint;
								}
							}
						}
					}
				}
			}
		}
	}
	mSceneManager.destroyQuery(query);
	if (closestSnapping.get()) {
		adjustment = closestSnapping->adjustment;
		snappedToEntity = closestSnapping->entity;
		return true;
	}
	return false;
}
예제 #2
0
void EntityWorldPickListener::processPickResult(bool& continuePicking, Ogre::RaySceneQueryResultEntry& entry, Ogre::Ray& cameraRay, const MousePickerArgs& mousePickerArgs)
{
	if (!mContinuePickingThisContext) {
		return;
	}

	if (entry.worldFragment) {
		//this is terrain
		//a position of -1, -1, -1 is not valid terrain
		Ogre::SceneQuery::WorldFragment* wf = entry.worldFragment;
		static const Ogre::Vector3 invalidPos(-1, -1, -1);
		if (wf->singleIntersection != invalidPos) {

			if (mFurthestPickingDistance == 0 || mResult.empty()) {
				EntityPickResult result;
				result.entity = findTerrainEntity();
				result.position = wf->singleIntersection;
				result.distance = entry.distance;
				result.isTransparent = false;
				mResult.push_back(result);
				mContinuePickingThisContext = false;
			} else {
				if (entry.distance < mResult[mResult.size() - 1].distance) {
					//If the last result is transparent, add another result, but if it's not replace it.
					if (mResult.size() && !mResult[mResult.size() - 1].isTransparent) {
						mResult.pop_back();
					}
					EntityPickResult result;
					result.entity = findTerrainEntity();
					result.position = wf->singleIntersection;
					result.distance = entry.distance;
					result.isTransparent = false;
					mResult.push_back(result);
					mContinuePickingThisContext = false;
				}
			}
		}
		/*		std::stringstream ss;
		 ss << wf->singleIntersection;
		 S_LOG_VERBOSE("Picked in terrain: " << ss.str() << " distance: " << mResult.distance);*/

	} else if (entry.movable) {
		Ogre::MovableObject* pickedMovable = entry.movable;
		if (pickedMovable->isVisible() && pickedMovable->getUserObjectBindings().getUserAny().getType() == typeid(EmberEntityUserObject::SharedPtr)) {
			EmberEntityUserObject* anUserObject = Ogre::any_cast<EmberEntityUserObject::SharedPtr>(pickedMovable->getUserObjectBindings().getUserAny()).get();
			//refit the opcode mesh to adjust for changes in the mesh (for example animations)
			anUserObject->refit();

			ICollisionDetector* collisionDetector = anUserObject->getCollisionDetector();
			if (collisionDetector) {
				CollisionResult collisionResult;
				collisionResult.collided = false;
				collisionResult.isTransparent = false;
				collisionDetector->testCollision(cameraRay, collisionResult);
				if (collisionResult.collided) {
					if (mFurthestPickingDistance == 0) {
						//If the current collision is transparent, also check for entities which are further away.
						if (!collisionResult.isTransparent) {
							//test all objects that fall into this distance
							mFurthestPickingDistance = (pickedMovable->getParentNode()->_getDerivedPosition() - cameraRay.getOrigin()).length() + pickedMovable->getBoundingRadius();
						}
					} else {
						if (collisionResult.distance > mFurthestPickingDistance) {
							mContinuePickingThisContext = false;
							return;
						} else {
							if (!mResult.empty() && mResult[mResult.size() - 1].distance > collisionResult.distance) {
								//If the last result is transparent, add another result, but if it's not replace it.
								if (!mResult[mResult.size() - 1].isTransparent) {
									mResult.pop_back();
								}
							} else {
								return;
							}
						}
					}
					EmberEntity& pickedEntity = anUserObject->getEmberEntity();

					std::list<EmberEntity*> entities;
					entities.push_front(&pickedEntity);
					EmberEntity* entity = pickedEntity.getEmberLocation();
					while (entity) {
						if (entity->getCompositionMode() == EmberEntity::CM_COMPOSITION) {
							entities.push_front(entity);
						} else if (entity->getCompositionMode() == EmberEntity::CM_COMPOSITION_EXCLUSIVE) {
							entities.clear();
							entities.push_front(entity);
						}
						entity = entity->getEmberLocation();
					}

					for (std::list<EmberEntity*>::const_iterator I = entities.begin(); I != entities.end(); ++I) {
						EntityPickResult result;
						result.entity = *I;
						result.position = collisionResult.position;
						result.distance = collisionResult.distance;
						result.isTransparent = collisionResult.isTransparent;
						mResult.push_back(result);
					}
				}
			}
		}
	}
}