diff --git a/examples/labs/orientation/README b/examples/labs/orientation/README index 1a57e8b6..526955f8 100644 --- a/examples/labs/orientation/README +++ b/examples/labs/orientation/README @@ -1,12 +1,33 @@ +This example demonstrates rendering the PS Move controller orientation in 3D using Qt5/Qt6 + modern Qt3D. -This application expects that the PS Move API has been -build in "build/" in the root source folder. +Requirements -After you have built the PS Move API in this way, you can -use "qmake" to generate a Makefile and then "make" to build -the application. +Qt 5.15+ or Qt 6.x with these modules: -Additional requirements: +Core, Gui, Widgets - This requires Qt 4.8.2 + Qt3D 1.0. +3DCore, 3DRender, 3DInput, 3DLogic, 3DExtras +Optional: OpenCV 4 if you want to show tracker camera frames. + +Building + +From the orientation/ directory: + +``` +qmake +make -j +``` + +Running +``` +./orientation +``` + +Notes + +- This example has been ported from the old Qt 4.8 + Qt3D 1.0 API (QGLView, QGLTeapot) to modern Qt3D. + +- The rendered object is a torus (QTorusMesh) by default, but you can switch to a sphere, cube, or a custom mesh. + +- The camera frame preview (cvShowImage) is disabled by default. To enable, replace it with OpenCV4 cv::imshow. \ No newline at end of file diff --git a/examples/labs/orientation/main.cpp b/examples/labs/orientation/main.cpp index 16698a7a..1d23d9ff 100644 --- a/examples/labs/orientation/main.cpp +++ b/examples/labs/orientation/main.cpp @@ -1,5 +1,4 @@ - - /** +/** * PS Move API - An interface for the PS Move Motion Controller * Copyright (c) 2012 Thomas Perl * All rights reserved. @@ -27,26 +26,25 @@ * POSSIBILITY OF SUCH DAMAGE. **/ - -#include +#include #include "orientationview.h" #include "orientation.h" int main(int argc, char **argv) { QApplication app(argc, argv); - OrientationView view; + OrientationView view; // QWidget that embeds a Qt3D window Orientation orientation; orientation.start(); QObject::connect(&orientation, - SIGNAL(orientation(qreal,qreal,qreal,qreal,qreal,qreal,qreal)), - &view, - SLOT(orientation(qreal,qreal,qreal,qreal,qreal,qreal,qreal))); + &Orientation::orientation, // new function-pointer syntax + &view, + &OrientationView::orientation); + view.resize(900, 700); view.show(); return app.exec(); } - diff --git a/examples/labs/orientation/orientation.h b/examples/labs/orientation/orientation.h index ece34fa4..726c6ba8 100644 --- a/examples/labs/orientation/orientation.h +++ b/examples/labs/orientation/orientation.h @@ -1,5 +1,4 @@ - - /** +/** * PS Move API - An interface for the PS Move Motion Controller * Copyright (c) 2012 Thomas Perl * All rights reserved. @@ -27,10 +26,11 @@ * POSSIBILITY OF SUCH DAMAGE. **/ +#ifndef ORIENTATION_H +#define ORIENTATION_H #include #include -#include "qglscenenode.h" #include #include @@ -42,70 +42,70 @@ #include "psmove_tracker.h" #include "psmove_tracker_opencv.h" -extern "C" { - void cvShowImage(const char *, void*); -}; - class Orientation : public QThread { Q_OBJECT +signals: + void orientation(qreal a, qreal b, qreal c, qreal d, + qreal scale, qreal x, qreal y); + +public: + Orientation() : QThread() {} + + void run() override + { + PSMove *move = psmove_connect(); + int quit = 0; + float q0, q1, q2, q3; + + if (move == NULL) { + fprintf(stderr, "Could not connect to controller.\n"); + QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection); + return; + } - signals: - void orientation(qreal a, qreal b, qreal c, qreal d, - qreal scale, qreal x, qreal y); - - public: - Orientation() : QThread() {} - - void run() - { - PSMove *move = psmove_connect(); - int quit = 0; - float q0, q1, q2, q3; - - if (move == NULL) { - fprintf(stderr, "Could not connect to controller.\n"); - QApplication::quit(); - } - - PSMoveTracker *tracker = psmove_tracker_new(); - - while (psmove_tracker_enable(tracker, move) != Tracker_CALIBRATED) { - // Retry calibration until it works - } - - psmove_enable_orientation(move, true); - - while (!quit) { - while (psmove_poll(move)) { - if (psmove_get_buttons(move) & Btn_PS) { - quit = 1; - break; - } + PSMoveTracker *tracker = psmove_tracker_new(); - if (psmove_get_buttons(move) & Btn_MOVE) { - psmove_reset_orientation(move); - } + while (psmove_tracker_enable(tracker, move) != Tracker_CALIBRATED) { + // retry until calibrated + } - psmove_get_orientation(move, &q0, &q1, &q2, &q3); + psmove_enable_orientation(move, true); - float x, y, radius; - psmove_tracker_get_position(tracker, move, &x, &y, &radius); - emit this->orientation(q0, q1, q2, q3, - 1.-((qreal)radius/150.), - 1.-((qreal)x/640.)*2., - 1.-((qreal)y/480.)*2.); + while (!quit) { + while (psmove_poll(move)) { + if (psmove_get_buttons(move) & Btn_PS) { + quit = 1; + break; } + if (psmove_get_buttons(move) & Btn_MOVE) { + psmove_reset_orientation(move); + } + + psmove_get_orientation(move, &q0, &q1, &q2, &q3); - psmove_tracker_update_image(tracker); - psmove_tracker_update(tracker, NULL); + float x, y, radius; + psmove_tracker_get_position(tracker, move, &x, &y, &radius); - cvShowImage("asdf", psmove_tracker_opencv_get_frame(tracker)); + emit orientation(q0, q1, q2, q3, + 1. - (qreal)radius / 150., + 1. - ((qreal)x / 640.) * 2., + 1. - ((qreal)y / 480.) * 2.); } - psmove_tracker_free(tracker); - psmove_disconnect(move); - QApplication::quit(); + psmove_tracker_update_image(tracker); + psmove_tracker_update(tracker, NULL); + + // Legacy C API display removed. If you want it back: + // cv::Mat frame = cv::cvarrToMat((IplImage*)psmove_tracker_opencv_get_frame(tracker)); + // cv::imshow("tracker", frame); + // cv::waitKey(1); } + + psmove_tracker_free(tracker); + psmove_disconnect(move); + QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection); + } }; +#endif // ORIENTATION_H diff --git a/examples/labs/orientation/orientation.pro b/examples/labs/orientation/orientation.pro index afbab6cf..88b558eb 100644 --- a/examples/labs/orientation/orientation.pro +++ b/examples/labs/orientation/orientation.pro @@ -1,19 +1,35 @@ - TEMPLATE = app -DEPENDPATH += . -INCLUDEPATH += . - -CONFIG += qt3d +TARGET = orientation -SOURCES += main.cpp +CONFIG += c++17 +QT += core gui widgets 3dcore 3drender 3dinput 3dextras 3dlogic -SOURCES += orientationview.cpp -HEADERS += orientationview.h +# Sources / headers +SOURCES += \ + main.cpp \ + orientationview.cpp -HEADERS += orientation.h +HEADERS += \ + orientationview.h \ + orientation.h +# PS Move include/lib layout as before +DEPENDPATH += . +INCLUDEPATH += . DEPENDPATH += ../../../include INCLUDEPATH += ../../../include -LIBS += -L../../../build/ -lpsmoveapi -lpsmoveapi_tracker -lopencv_highgui +# NEW: where your psmove landed +INCLUDEPATH += /usr/local/include +# Sometimes headers live in a nested folder, add this too if needed: +INCLUDEPATH += /usr/local/include/psmoveapi + +# Link PS Move and tracker +LIBS += -L../../../build/ -lpsmoveapi -lpsmoveapi_tracker + +# Optional: OpenCV (comment out if not available) +CONFIG += link_pkgconfig +PKGCONFIG += opencv4 +# On some distros you might need pthread explicitly +unix:LIBS += -lpthread diff --git a/examples/labs/orientation/orientationview.cpp b/examples/labs/orientation/orientationview.cpp index c4760a46..ffd19835 100644 --- a/examples/labs/orientation/orientationview.cpp +++ b/examples/labs/orientation/orientationview.cpp @@ -1,5 +1,4 @@ - - /** +/** * PS Move API - An interface for the PS Move Motion Controller * Copyright (c) 2012 Thomas Perl * All rights reserved. @@ -27,42 +26,100 @@ * POSSIBILITY OF SUCH DAMAGE. **/ - #include "orientationview.h" -#include "qglbuilder.h" -#include "qglscenenode.h" -#include "qglteapot.h" -#include "qquaternion.h" -#include "math.h" -#include +#include +#include +#include -void OrientationView::initializeGL(QGLPainter *painter) -{ - painter->setStandardEffect(QGL::LitMaterial); - QGLBuilder builder; - builder << QGLTeapot(); - teapot = builder.finalizedSceneNode(); -} -OrientationView::~OrientationView() +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +OrientationView::OrientationView(QWidget *parent) + : QWidget(parent) { - delete teapot; + // 3D window + m_view = new Qt3DExtras::Qt3DWindow(); + auto *fg = qobject_cast(m_view->defaultFrameGraph()); + if (fg) fg->setClearColor(QColor(30, 30, 35)); + m_container = QWidget::createWindowContainer(m_view, this); + m_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + auto *layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(m_container); + setLayout(layout); + + // Root entity + m_root = new Qt3DCore::QEntity(); + + // Camera + Qt3DRender::QCamera *camera = m_view->camera(); + camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f); + camera->setPosition(QVector3D(0.0f, 0.0f, 6.0f)); + camera->setViewCenter(QVector3D(0.0f, 0.0f, 0.0f)); + + // Camera controls + auto *camController = new Qt3DExtras::QOrbitCameraController(m_root); + camController->setLinearSpeed( 50.0f ); + camController->setLookSpeed( 180.0f ); + camController->setCamera(camera); + + // Visual geometry (torus looks nicer than a cube) + auto *mesh = new Qt3DExtras::QTorusMesh(); + mesh->setRadius(1.0f); + mesh->setMinorRadius(0.3f); + mesh->setRings(64); + mesh->setSlices(32); + + // Transform we’ll update from PS Move orientation + m_transform = new Qt3DCore::QTransform(); + m_transform->setScale(1.0f); + + // Material + auto *material = new Qt3DExtras::QPhongMaterial(); + material->setShininess(80.0f); + + // Entity + m_objectEntity = new Qt3DCore::QEntity(m_root); + m_objectEntity->addComponent(mesh); + m_objectEntity->addComponent(m_transform); + m_objectEntity->addComponent(material); + + // Set the scene + m_view->setRootEntity(m_root); } -void OrientationView::paintGL(QGLPainter *painter) +OrientationView::~OrientationView() { - teapot->draw(painter); + // Qt3D objects parented under m_root will be freed automatically } void OrientationView::orientation(qreal a, qreal b, qreal c, qreal d, - qreal scale, qreal x, qreal y) + qreal scale, qreal x, qreal y) { - QMatrix4x4 mat; - mat.translate(QVector3D(x*2, y*1.5, 0)); - mat.scale(scale); - mat.rotate(QQuaternion(a, b, c, d)); - teapot->setLocalTransform(mat); - update(); -} + if (!m_transform) return; + + // Map original example’s 2D offsets to world translation + // Original used translate(QVector3D(x*2, y*1.5, 0)) + const QVector3D pos(x * 2.0f, y * 1.5f, 0.0f); + m_transform->setTranslation(pos); + // Scale + m_transform->setScale(std::max(0.05, scale)); // clamp to avoid disappearing + + // Orientation: PS Move provides quaternion (w, x, y, z) in example order (a,b,c,d) + // Qt expects (scalar, x, y, z) too, matching QQuaternion(a,b,c,d). + const QQuaternion q(a, b, c, d); + m_transform->setRotation(q); +} diff --git a/examples/labs/orientation/orientationview.h b/examples/labs/orientation/orientationview.h index 44402d65..cb9f3424 100644 --- a/examples/labs/orientation/orientationview.h +++ b/examples/labs/orientation/orientationview.h @@ -1,5 +1,4 @@ - - /** +/** * PS Move API - An interface for the PS Move Motion Controller * Copyright (c) 2012 Thomas Perl * All rights reserved. @@ -30,27 +29,37 @@ #ifndef ORIENTATIONVIEW_H #define ORIENTATIONVIEW_H -#include "Qt3D/qglview.h" +#include +#include +#include + +#include +#include -class QGLSceneNode; +#include +#include +#include +#include // use a torus for a nice visual +#include // alt: sphere +#include -class OrientationView : public QGLView +class OrientationView : public QWidget { Q_OBJECT public: - OrientationView(QWidget *parent = 0) : QGLView(parent), teapot(0) {} + explicit OrientationView(QWidget *parent = nullptr); ~OrientationView(); -protected: - void initializeGL(QGLPainter *painter); - void paintGL(QGLPainter *painter); - -private: - QGLSceneNode *teapot; - public slots: void orientation(qreal a, qreal b, qreal c, qreal d, - qreal scale, qreal x, qreal y); + qreal scale, qreal x, qreal y); + +private: + Qt3DExtras::Qt3DWindow *m_view = nullptr; + QWidget *m_container = nullptr; + Qt3DCore::QEntity *m_root = nullptr; + Qt3DCore::QEntity *m_objectEntity = nullptr; + Qt3DCore::QTransform *m_transform = nullptr; }; -#endif +#endif // ORIENTATIONVIEW_H