STARK: Add mouse picking for 3D items
This works at the bone bounding box level, whereas the original does pixel-perfect picking.
This commit is contained in:
parent
efc23795a1
commit
7e621e13f6
11 changed files with 121 additions and 4 deletions
|
@ -120,6 +120,19 @@ bool RenderEntry::containsPoint(const Common::Point &position, Common::Point &re
|
|||
return false;
|
||||
}
|
||||
|
||||
bool RenderEntry::intersectRay(const Math::Ray &ray) const {
|
||||
if (!_visual || !_clickable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VisualActor *actor = _visual->get<VisualActor>();
|
||||
if (actor) {
|
||||
return actor->intersectRay(ray, _position3D, _direction3D);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
VisualImageXMG *RenderEntry::getImage() const {
|
||||
return _visual->get<VisualImageXMG>();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/ray.h"
|
||||
#include "math/vector3d.h"
|
||||
|
||||
namespace Stark {
|
||||
|
@ -61,8 +62,18 @@ public:
|
|||
/** Obtain the underlying image visual, if any */
|
||||
VisualImageXMG *getImage() const;
|
||||
|
||||
/**
|
||||
* Mouse picking test for 2D items
|
||||
*
|
||||
* @param position game window coordinates to test
|
||||
* @param relativePosition successful hit item relative coordinates
|
||||
* @return successful hit
|
||||
*/
|
||||
bool containsPoint(const Common::Point &position, Common::Point &relativePosition) const;
|
||||
|
||||
/** Mouse picking test for 3D items */
|
||||
bool intersectRay(const Math::Ray &ray) const;
|
||||
|
||||
/** Compare two render entries by their sort keys */
|
||||
static bool compare(const RenderEntry *x, const RenderEntry *y);
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "engines/stark/model/skeleton.h"
|
||||
#include "engines/stark/gfx/texture.h"
|
||||
|
||||
#include "math/aabb.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
Model::Model() :
|
||||
|
@ -133,6 +135,8 @@ void Model::readFromStream(ArchiveReadStream *stream) {
|
|||
|
||||
_meshes.push_back(node);
|
||||
}
|
||||
|
||||
buildBonesBoundingBoxes();
|
||||
}
|
||||
|
||||
void Model::setAnim(SkeletonAnim *anim)
|
||||
|
@ -144,4 +148,49 @@ void Model::setTextureSet(Gfx::TextureSet *texture) {
|
|||
_textureSet = texture;
|
||||
}
|
||||
|
||||
void Model::buildBonesBoundingBoxes() {
|
||||
const Common::Array<BoneNode *> &bones = _skeleton->getBones();
|
||||
|
||||
for (uint i = 0; i < bones.size(); i++) {
|
||||
buildBoneBoundingBox(bones[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::buildBoneBoundingBox(BoneNode *bone) const {
|
||||
bone->_boundingBox.reset();
|
||||
|
||||
// Add all the vertices with a non zero weight for the bone to the bone's bounding box
|
||||
for (uint i = 0; i < _meshes.size(); i++) {
|
||||
MeshNode *mesh = _meshes[i];
|
||||
|
||||
for (uint j = 0; j < mesh->_faces.size(); j++) {
|
||||
FaceNode *face = mesh->_faces[j];
|
||||
|
||||
for (uint k = 0; k < face->_verts.size(); k++) {
|
||||
VertNode *vert = face->_verts[k];
|
||||
|
||||
if (vert->_bone1 == bone->_idx) {
|
||||
bone->_boundingBox.expand(vert->_pos1);
|
||||
}
|
||||
|
||||
if (vert->_bone2 == bone->_idx) {
|
||||
bone->_boundingBox.expand(vert->_pos2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Model::intersectRay(const Math::Ray &ray) const {
|
||||
const Common::Array<BoneNode *> &bones = _skeleton->getBones();
|
||||
|
||||
for (uint i = 0; i < bones.size(); i++) {
|
||||
if (bones[i]->intersectRay(ray)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/ray.h"
|
||||
#include "math/vector3d.h"
|
||||
|
||||
namespace Stark {
|
||||
|
@ -38,6 +39,7 @@ class ArchiveReadStream;
|
|||
class Skeleton;
|
||||
class SkeletonAnim;
|
||||
|
||||
class BoneNode;
|
||||
|
||||
class VertNode {
|
||||
public:
|
||||
|
@ -130,7 +132,13 @@ public:
|
|||
*/
|
||||
void setTextureSet(Gfx::TextureSet *textureSet);
|
||||
|
||||
/** Perform a collision test with a ray */
|
||||
bool intersectRay(const Math::Ray &ray) const;
|
||||
|
||||
private:
|
||||
void buildBonesBoundingBoxes();
|
||||
void buildBoneBoundingBox(BoneNode *bone) const;
|
||||
|
||||
uint32 _u1;
|
||||
float _facingDirection;
|
||||
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
#include "engines/stark/model/skeleton_anim.h"
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
Skeleton::Skeleton() :
|
||||
|
@ -98,4 +96,11 @@ void Skeleton::animate(uint32 time) {
|
|||
}
|
||||
}
|
||||
|
||||
bool BoneNode::intersectRay(const Math::Ray &ray) const {
|
||||
Math::Ray localRay = ray;
|
||||
localRay.translate(-_animPos);
|
||||
localRay.rotate(_animRot.inverse());
|
||||
|
||||
return localRay.intersectAABB(_boundingBox);
|
||||
}
|
||||
} // End of namespace Stark
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/aabb.h"
|
||||
#include "math/quat.h"
|
||||
#include "math/ray.h"
|
||||
#include "math/vector3d.h"
|
||||
|
||||
namespace Stark {
|
||||
|
@ -38,14 +40,21 @@ class BoneNode {
|
|||
public:
|
||||
BoneNode() : _parent(-1) { }
|
||||
~BoneNode() { }
|
||||
|
||||
/** Perform a collision test with the ray */
|
||||
bool intersectRay(const Math::Ray &ray) const;
|
||||
|
||||
Common::String _name;
|
||||
float _u1;
|
||||
Common::Array<uint32> _children;
|
||||
int _parent;
|
||||
int _idx;
|
||||
uint32 _idx;
|
||||
|
||||
Math::Vector3d _animPos;
|
||||
Math::Quaternion _animRot;
|
||||
|
||||
/** Bone space bounding box */
|
||||
Math::AABB _boundingBox;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -281,6 +281,11 @@ Visual *AnimSkeleton::getVisual() {
|
|||
return _visual;
|
||||
}
|
||||
|
||||
int AnimSkeleton::indexForPoint(const Common::Point &point) const {
|
||||
// Skeleton anims only have one hotspot
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AnimSkeleton::readData(Formats::XRCReadStream *stream) {
|
||||
Anim::readData(stream);
|
||||
|
||||
|
|
|
@ -205,6 +205,7 @@ public:
|
|||
void applyToItem(Item *item) override;
|
||||
void removeFromItem(Item *item) override;
|
||||
Visual *getVisual() override;
|
||||
int indexForPoint(const Common::Point &point) const override;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "engines/stark/ui/gamewindow.h"
|
||||
|
||||
#include "engines/stark/cursor.h"
|
||||
#include "engines/stark/scene.h"
|
||||
|
||||
#include "engines/stark/gfx/driver.h"
|
||||
|
||||
|
@ -160,10 +161,13 @@ void GameWindow::checkObjectAtPos(Common::Point pos, int16 selectedInventoryItem
|
|||
singlePossibleAction = -1;
|
||||
isDefaultAction = false;
|
||||
|
||||
Math::Ray ray = StarkScene->makeRayFromMouse(_cursor->getMousePosition(true));
|
||||
|
||||
// Render entries are sorted from the farthest to the camera to the nearest
|
||||
// Loop in reverse order
|
||||
for (int i = _renderEntries.size() - 1; i >= 0; i--) {
|
||||
if (_renderEntries[i]->containsPoint(pos, _objectRelativePosition)) {
|
||||
if (_renderEntries[i]->containsPoint(pos, _objectRelativePosition)
|
||||
|| _renderEntries[i]->intersectRay(ray)) {
|
||||
_objectUnderCursor = _renderEntries[i]->getOwner();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -74,7 +74,17 @@ Math::Matrix4 VisualActor::getModelMatrix(const Math::Vector3d& position, float
|
|||
scale.setValue(2, 2, -1.0f);
|
||||
|
||||
return posMatrix * rot1 * rot2 * scale;
|
||||
}
|
||||
|
||||
bool VisualActor::intersectRay(const Math::Ray &ray, const Math::Vector3d position, float direction) {
|
||||
Math::Matrix4 inverseModelMatrix = getModelMatrix(position, direction);
|
||||
inverseModelMatrix.inverse();
|
||||
|
||||
// Build an object local ray from the world ray
|
||||
Math::Ray localRay = ray;
|
||||
localRay.transform(inverseModelMatrix);
|
||||
|
||||
return _model->intersectRay(localRay);
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "common/str.h"
|
||||
|
||||
#include "math/matrix4.h"
|
||||
#include "math/ray.h"
|
||||
#include "math/vector3d.h"
|
||||
|
||||
#include "engines/stark/visual/visual.h"
|
||||
|
@ -53,6 +54,7 @@ public:
|
|||
void setTexture(Gfx::TextureSet *texture);
|
||||
void setTime(uint32 time);
|
||||
|
||||
bool intersectRay(const Math::Ray &ray, const Math::Vector3d position, float direction);
|
||||
virtual void render(Gfx::Driver *gfx, const Math::Vector3d position, float direction) = 0;
|
||||
|
||||
protected:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue