[Qt] Delivering Embedded Panda3D in Qt (X11 / Windows)

Return to C++ coding using Panda3D

[Qt] Delivering Embedded Panda3D in Qt (X11 / Windows)

Postby plaristote » Wed May 23, 2012 3:28 am

Good morning,

This used to be a question, but it turns out I solved everything : the forum already has clues about how to do this, but no piece of code doing everything for you :) !

So this is what I'm delivering to you : the simplest way to include Panda in Qt, with everything handled (as far as I know).
It works with X11 and Windows too (thanks to Tah for Windows compatibility) ;) !

It is composed of two classes :

- QPandaApplication : reimplementing QApplication and including PandaFramework.
Note: you will need to explicitly terminate your application using the slot method "Close()".
To get the instance of PandaFramework, use the static method Framework.

- QPandaWidget : a QWidget displaying a Panda3D window.
Note: everything is handled transparently by the widget. All you would need to draw is the WindowFramework embedded in the widget. You can get it with the method "Window()".
You can't use the WindowFramework before the widget has been initialized : wait for the Initialized signal to know when you can start drawing meshes all over the place.
This QWidget also supports the mousepress and mouserelease events : you can handle them like in any other QWidget by reimplementing mousePressEvent / mouseReleaseEvent. All the details of the click (except keyboard modifiers) are specified in the QMouseEvent.

qpandaapplication.h
Code: Select all
#ifndef QPANDAAPPLICATION_H
# define QPANDAAPPLICATION_H

# include <QApplication>
# include <panda3d/pandaFramework.h>
# include <panda3d/pandaSystem.h>

class QPandaApplication : public QApplication
{
    Q_OBJECT
public:
    QPandaApplication(int argc, char **argv);
    ~QPandaApplication();

    int                    exec(void);

    static PandaFramework& Framework(void) { return (_framework); }
    static void            Close(void);

public slots:
    void                   Terminate(void) { Close(); }

private:
    static bool           _continue;
    static PandaFramework _framework;
};

#endif // QPANDAAPPLICATION_H



qpandaapplication.cpp
Code: Select all
#include "qpandaapplication.h"

PandaFramework QPandaApplication::_framework;
bool           QPandaApplication::_continue;

QPandaApplication::QPandaApplication(int argc, char **argv) : QApplication(argc, argv)
{
  _framework.open_framework(argc, argv);
  _continue = true;
}

QPandaApplication::~QPandaApplication()
{
  _framework.close_framework();
}

int            QPandaApplication::exec(void)
{
    Thread*    currentThread = Thread::get_current_thread();

    do
    {
        processEvents();
    } while (_continue && _framework.do_frame(currentThread));
    return (0);
}

void           QPandaApplication::Close(void)
{
    _continue = false;
}


qpandawidget.hpp
Code: Select all
#ifndef QPANDAWIDGET_H
# define QPANDAWIDGET_H

# include <QWidget>
# include <panda3d/pandaFramework.h>
# include <panda3d/pandaSystem.h>

class QPandaWidget : public QWidget
{
    Q_OBJECT
public:
    explicit QPandaWidget(QWidget *parent = 0);
    virtual ~QPandaWidget();

    virtual void     resizeEvent(QResizeEvent*);
    virtual void     showEvent(QShowEvent*);

    QPaintEngine*    paintEngine() const { return (0); }
    void             paintEvent(QPaintEvent*) {}
    virtual void     closeEvent(QCloseEvent*);

    WindowFramework* Window(void) const { return (_window); }

signals:
    void             Initialized(void);

private:
    void             UpdateSize(void);
    static void      CallbackMouse(const Event* event, void* ptr);

    WindowFramework* _window;
    QSize            _size;
};

#endif // QPANDAWIDGET_H


qpandawidget.cpp
Code: Select all
#include "qpandawidget.h"
#include <QResizeEvent>
#ifdef Q_WS_X11
# include <Qt/qx11info_x11.h>
# include <X11/Xlib.h>
#endif
#include <iostream>
#include "qpandaapplication.h"

QPandaWidget::QPandaWidget(QWidget *parent) : QWidget(parent)
{
    EventHandler& events = QPandaApplication::Framework().get_event_handler();

    _window = 0;
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_OpaquePaintEvent);
    setFocusPolicy(Qt::StrongFocus);
    events.add_hook("mouse1",    QPandaWidget::CallbackMouse, this);
    events.add_hook("mouse2",    QPandaWidget::CallbackMouse, this);
    events.add_hook("mouse3",    QPandaWidget::CallbackMouse, this);
    events.add_hook("mouse1-up", QPandaWidget::CallbackMouse, this);
    events.add_hook("mouse2-up", QPandaWidget::CallbackMouse, this);
    events.add_hook("mouse3-up", QPandaWidget::CallbackMouse, this);
}

QPandaWidget::~QPandaWidget()
{
    EventHandler& events = QPandaApplication::Framework().get_event_handler();

    events.remove_hooks_with(this);
    if (_window)
      QPandaApplication::Framework().close_window(_window);
}

void QPandaWidget::UpdateSize(void)
{
    if (_window)
    {
        WindowProperties wp;

        _window->get_graphics_window()->request_properties(wp);
        wp.set_size(_size.width(), _size.height());
        wp.set_origin(0, 0);
        _window->get_graphics_window()->set_properties_now(wp);
    }
}

void QPandaWidget::resizeEvent(QResizeEvent* event)
{
    _size = event->size();
    UpdateSize();
    QWidget::resizeEvent(event);
}

void QPandaWidget::showEvent(QShowEvent* event)
{
    if (_window == 0)
    {
        WindowProperties wp;

#ifdef Q_WS_X11
        XFlush(QX11Info::display());
#endif
        QPandaApplication::Framework().get_default_window_props(wp);
        wp.set_parent_window((size_t)this->winId());
        _window = QPandaApplication::Framework().open_window(wp, 0);
        UpdateSize();
        Initialized();
    }
    QWidget::showEvent(event);
}

void QPandaWidget::closeEvent(QCloseEvent*)
{
    QPandaApplication::Close();
}

// MOUSE MANAGEMENT
void QPandaWidget::CallbackMouse(const Event* event, void* ptr)
{
    QPandaWidget*     instance = reinterpret_cast<QPandaWidget*>(ptr);
    MouseData         data     = instance->_window->get_graphics_window()->get_pointer(0);

    if (data.get_in_window())
    {
        QPoint            pos(data.get_x(), data.get_y());
        std::string       name     = event->get_name();
        Qt::MouseButton   button;
        QMouseEvent::Type type;
        char              buttonN;

        if (name.substr(name.size() - 2) == "up")
        {
            type = QMouseEvent::MouseButtonRelease;
            name = name.substr(0, name.size() - 3);
        }
        else
            type = QMouseEvent::MouseButtonPress;

        buttonN  = name[name.size() - 1];
        name = name.substr(0, name.size() - 1);

        switch (buttonN)
        {
        default:
        case '1':
            button = Qt::LeftButton;
            break ;
        case '2':
            button = Qt::RightButton;
            break ;
        case '3':
            button = Qt::MiddleButton;
            break ;
        }

        if (type == QMouseEvent::MouseButtonPress)
        {
          QMouseEvent event(type, pos, button, 0, Qt::NoModifier);

          instance->mousePressEvent(&event);
        }
        else
        {
          QMouseEvent event(type, pos, button, 0, Qt::NoModifier);

          instance->mouseReleaseEvent(&event);
        }
    }
}


Here you go folks ! I really hope this will help !
Last edited by plaristote on Sat May 26, 2012 6:06 am, edited 1 time in total.
Potato.
plaristote
 
Posts: 74
Joined: Sat May 12, 2012 2:02 pm

Postby tah » Thu May 24, 2012 8:09 pm

Hi

Hey, good work !
I got it running on windows, just a few little mods to get it to fill the window.
I replaced the wp.set_fullscreen(true); with wp.set_origin(0,0);

Added a QPandaWidget::closeEvent so when the user clicks on the close "x" on upper right of window to shuts everything down.
And had to make _continue a static bool and void Close(void); a static void (in qpandaapplication.h )

here is the QPandaWidget::closeEvent
Code: Select all
void QPandaWidget::closeEvent(QCloseEvent *e)
{

    QPandaApplication::Close();

}


just add void closeEvent(QCloseEvent *ev); to the .h file in private part.

here is a basic main:


Code: Select all
#include "qpandaapplication.h"
#include "qpandawidget.h"

int main(int argc, char *argv[])
{

  QPandaApplication a(argc, argv);

  // get the PandaFramework from the QPandaApplication !!!!
  PandaFramework framework = a.Framework();

  // create a QPandaWidget
  QPandaWidget *panda =  new QPandaWidget;
  panda->show();

  // get the WindowFramework from the QPandaWidget !!!!
  WindowFramework* window = panda->Window();

  //set the window title to my Panda3D window
  framework.set_window_title("My Panda3D Window");

  // here is room for your own code
  // load the environment model,  basic Panda land demo
  NodePath environ=window->load_model(framework.get_models(),"models/environment");

  // reparent the model to render
  environ.reparent_to(window->get_render());

  //apply scale and position transforms to the model
  environ.set_scale(0.25, 0.25, 0.25);
  environ.set_pos(-8, 42, 0);

  window->setup_trackball();

  return a.exec();

}


This can help make new Panda tools
Thanks again
tah
 
Posts: 173
Joined: Fri Oct 29, 2010 3:25 pm
Location: Torrance, CA.

Postby plaristote » Fri May 25, 2012 3:23 pm

\o/ ! Thanks !
I added those changes to the next version. Which will also include support for QMouseEvents (mousePressEvent and mouseReleaseEvent from QWidget will be called properly).

Well, that is, if I manage to find out why the EventHandler doesn't call my hooks. I'll update as soon as this problem is solved.
Potato.
plaristote
 
Posts: 74
Joined: Sat May 12, 2012 2:02 pm

Postby tah » Fri May 25, 2012 9:56 pm

I had some problems with QEvents in the Panda part of the window, the Panda seems to be very territorial..ha
I've been working on a type of scene viewer/editor, but I do things in another way than you do. I make a QMainWindow and set the Panda WindowProperties parent to the QMainWindow centralWidget, then I have the Panda main loop that calls qApp.processEvents();

I'm okay with this since I wanted to use the Panda events in the Panda window.

There is a post, started by someone else who wanted to use Panda with Qt and I made some comments there about how I was doing things and problems.

perhaps you have seen it already...
http://www.panda3d.org/forums/viewtopic.php?t=10871

edit
Ha... I just looked over the all of that post again and I see you had already found it and replied there
tah
 
Posts: 173
Joined: Fri Oct 29, 2010 3:25 pm
Location: Torrance, CA.


Return to C++ coding using Panda3D

Who is online

Users browsing this forum: No registered users and 1 guest