Quantcast
Channel: Planet Qt
Viewing all 15410 articles
Browse latest View live

KDAB on Qt: What a mesh!

$
0
0

With all the advances being made in Qt 3D, we wanted to create some new examples showing some of what it can do. To get us started, we decided to use an existing learning framework, so we followed the open source Tower Defence course, which you can find at CGCookie. Being a game, it allows an interactive view of everything at work, which is very useful.

We found it to be so diverse, that we are now implementing Parts 2 and 3 of the game into Qt 3D. However you don’t have to wait for that, you can start now by following the steps we took.

The setup

These instructions will help you setup for Qt 5.11.0 .

To start, turn to your QtCreator and create a new Qt Console Application, set to run on your Qt 5.11.0 kit.

A Qt Console Application doesn’t come with too much ‘plumbing’. A lot of the other options will attempt to give you starting files that aren’t required or in some cases, the wrong type entirely.

Let’s edit it to fit our needs by opening up the .pro file and adding the following:

First remove the QT += core and QT -= gui lines if they are present.

QT += 3dcore 3drender 3dinput 3dquick 3dquickextras qml quick

Then, if the lines CONFIG += c++11 console and CONFIG -= app_bundle are present, remove them too. Now back on the main.cpp file we need to edit our “includes” from the Qt 3D library.

Replace the #include QCoreApplication with #include QGuiApplication and add these lines:

#include 
#include 
#include 

Within the main block we now have to edit QCoreApplication a(argc, argv); to mirror our include change. So change it to:

QGuiApplication a(argc, argv);

Before the first build / run we should add something to look at. Adding the following block of code before the return statement will provide us with a window:

Qt3DExtras::Quick::Qt3DQuickWindow view;
view.setSource(QUrl("qrc:/main.qml"));
view.show();

Commenting out the line referring to main.qml will allow you to build and run what you have already. If everything has gone to plan, you will get a white window appear. Now you can uncomment the line and continue onwards!

QRC creation

Okay, let’s get rid of the boring white scene and get something in there. Right-click the ‘Sources’ folder and select ‘Add New…’. From here select the Qt > QML File (Qt Quick 2) option. We’ve gone and named it main so that after clicking next till the end you should now have a main.qml and a main.cpp.

This QML file is now going to hold our scene, but to do that we need some resources. We will achieve this by adding a Qt Resource File, just as we did for main.qml – assuming you have an obj with accompanying textures placed in an assets folder within the project.

So this time right-click on the project folder and select ‘Add New…’. From the Qt menu, select ‘Qt Resource File’ and name it something fitting. When this opens it will look noticeably different to the qml and cpp files. At the bottom you will see the self-descriptive; Add, Remove and Remove Missing Files buttons. Click the ‘Add’ button and select ‘Add Prefix’. Now remove everything from the Prefix: text input just leaving the ‘/‘. Click the ‘Add’ button again, this time selecting the ‘Add Files’ option.

Navigate to your obj and texture files and add them all to the qrc, save and close it. If everything went to plan, a ‘Resources’ folder will now be visible in the Projects window on the left.

Follow this again and add main.qml to the qrc in the same way.

One last thing we need before playing with the scene is a skymap. With the files placed in your assets folder, go ahead and add the skymap to the qrc file.

Gotcha

We use three dds files for our skymaps, irradiance, radiance and specular. If you are trying this on a Mac, you will have to uncompress them or they will not work. Keep the names similar to their compressed version. For example we simply added ‘-16f’ to the filename. So our files would be ‘wobbly_bridge_4k_cube_irradiance’ vs ‘wobbly_bridge_4k-16f_cube_irradiance’ respectively.

The necessities

Back to the QML file now, rename the Item { } to be an Entity { } and give it the id: scene. Entity is not recognised because we are missing some imports. Hitting F1 with Entity selected shows us that we need to import Qt3D.Core 2.0, so add this to the imports at the top of the file.

There are certain components that a 3D scene must have, a camera and Render settings being two of those. For this example, we’ll throw in a camera controller too so we can move around the scene.

components: [
    RenderSettings {
        activeFrameGraph: ForwardRenderer {
            camera: mainCamera
            clearColor: Qt.rgba(0.1, 0.1, 0.1, 1.0)
        }
    },
    // Event Source will be set by the Qt3DQuickWindow
    InputSettings { }
]

Camera {
    id: mainCamera
    position: Qt.vector3d(30, 30, 30)
    viewCenter: Qt.vector3d(0, 0, 0)
}

FirstPersonCameraController {
    camera: mainCamera
    linearSpeed: 10
    lookSpeed: 50
}

Here we see that Camera is not recognised, so let’s get the missing import.

Gotcha

If you select Camera and hit F1 to find the import, you will in fact be shown the import for the non-Qt3D Camera. The one you will want is: import Qt3D.Render 2.9

The sky is the limit

Let’s put that skymap to use now. Back in the main.cpp file, we need to add code to check if we’re on MAC or not. If you remember, this was due to MAC not supporting compressed files and needing its own versions. After the QGuiApplication line, put in the following:

#if defined(Q_OS_MAC)
    const QString envmapFormat = QLatin1String("-16f");
#else
    const QString envmapFormat = QLatin1String("");
#endif

Then after the Qt3DExtras line, add the following:

auto context = view.engine()->qmlEngine()->rootContext();
context->setContextProperty(QLatin1String("_envmapFormat"), envmapFormat);

If you try to build at this point, you will notice various imports missing. One for FirstPersonCameraController, one for InputSettings and TexturedMetalRoughtMaterial. Hitting F1 on FirstPersonCameraController will give you import Qt3D.Extras 2.0 and F1 on InputSettings will give you import Qt3D.Input 2.0 but then later you’ll hit a snag. TexturedMetalRoughtMaterial may not turn up any documentation but we’ll be kind enough to give you the answer… edit the Qt3D.Extras 2.0 to be 2.9 instead. If this now works you will get a dark grey window.

Barrel of laughs

The final part will be our mesh, we chose a barrel, and the skymap for it to reflect (although this might not be visible).

In main.qml after the InputSettings{}, throw in the following:

EnvironmentLight {
    id: envLight
    irradiance: TextureLoader {
        source: "qrc:/path/to/your/file" + _envmapFormat + "_cube_irradiance.dds"

        minificationFilter: Texture.LinearMipMapLinear
        magnificationFilter: Texture.Linear
        wrapMode {
            x: WrapMode.ClampToEdge
            y: WrapMode.ClampToEdge
        }
        generateMipMaps: false
    }
    specular: TextureLoader {
        source: "qrc:/path/to/your/file" + _envmapFormat + "_cube_specular.dds"
                
        minificationFilter: Texture.LinearMipMapLinear
        magnificationFilter: Texture.Linear
        wrapMode {
            x: WrapMode.ClampToEdge
            y: WrapMode.ClampToEdge
        }
        generateMipMaps: false
    }
}

You can hit build now to check it’s working, but the scene will still be pretty boring. Throw in your obj to get some eye candy. Here is the code we used after EnvironmentLight:

Mesh {
    source: "qrc:/your/model.obj"
},
Transform {
    translation: Qt.vector3d(4, 0, 2)
},
TexturedMetalRoughMaterial {
    baseColor: TextureLoader {
        format: Texture.SRGB8_Alpha8
        source: "qrc:/path/to/your/Base_Color.png"
    }
    metalness: TextureLoader { source: "qrc:/path/to/your/Metallic.png" }
    roughness: TextureLoader { source: "qrc:/path/to/your/Roughness.png" }
    normal: TextureLoader { source: "qrc:/path/to/your/Normal_OpenGL.png" }
    ambientOcclusion: TextureLoader { source: "qrc:/path/to/your/Mixed_AO.png" }
}

Finally, hit build and then run.

Rendered Barrel

The barrel viewed at the end of What A Mesh pt1

The post What a mesh! appeared first on KDAB.


KDAB on Qt: KDAB at Italian C++, Milan

$
0
0

KDAB was sponsor of this annual C++ event run by the C++ Community for the C++ Community in Italy, which was founded some five years ago and is growing fast.

our-roll-upAround 200 people showed up for “++ it”, 50 more than last year, and were treated to an excellent program.

There was a mix of talks in either English or Italian, including ‘Debug C++ Without Running‘ by Anastasia Kazakova, ‘C++ Barbarian Quiz & Introduction to Conan C/C++ Package Manager‘ from Diego Rodriguez-Losada Gonzalez and one from Vittorio Romeo on ‘Zero-allocation & no type erasure futures‘, all of which KDAB particularly enjoyed.

You can see the full program and a post-event report here.

 

 

The post KDAB at Italian C++, Milan appeared first on KDAB.

The Qt Company Blog: Qt for Python available at PyPi

$
0
0

We are glad to announce that finally the technical preview of Qt for Python is available at the Python Package Index (PyPI).

For the past technical preview release, we were still discussing with the PyPi people to be able to upload our wheels to their servers, but now everything is in order, and you can get the PySide2 module with a simple:


pip install PySide2

Keep in mind that we will continue uploading the snapshot wheels to our servers,
so you also can get the latest features of Qt for Python!.

The post Qt for Python available at PyPi appeared first on Qt Blog.

KDAB on Qt: LibreOffice and Plasma

$
0
0

At KDAB, we know that consistency is an important aspect of the User Experience – users don’t want to have to learn different ways to achieve the same thing. In the Linux world, there is a major structural pitfall to this: the applications written for Linux come in at least two major technologies –Qt and GTK. Each of these frameworks deeply influences the experience the user has, and in different ways. As you’d expect, the frameworks have their own helper-dialogs e.g. to open or save a file or for printing. This can make it confusing for users, when the apps they use don’t show the same helper-dialogs for common actions.

Most KDE software is written using the Qt library, and within KDE there are lots of attempts to ease the use of GTK applications on Plasma, the KDE desktop. For example, GTK has been styled by members of the KDE community so its applications are visually consistent with the overall KDE look. Nonetheless a major drawback to these efforts remains: helper-dialogs opened from a GTK application are still GTK dialogs and they function differently.

For the user this inconsistency is annoying. Take file handling for example: KDE offers a lot of support to the user. They can define important places – like favorite folders, drives, cloud storage –  that allow fast access whenever the user needs to handle files. It follows the KDE idea of navigation through the files, which includes how the user navigates, handling file previews and how the files in a folder are filtered. The file open dialog in GTK is not worse than the KDE one, it is just different. It offers almost the same functionality, but is presented in a way the KDE user is not used to. This can be confusing and frustrating, especially in environments where the user has no choice about the system they have to work with.

Perhaps the best known and most commonly used GTK application is LibreOffice. The limitations it has for KDE users due to the use of GTK dialogs is well known to the LibreOffice community. A lot of effort has already been undertaken to fix this problem. Some ideas even went so far as to migrate large parts of LibreOffice to Qt in order to provide a native feeling for KDE users.

KDAB’s contribution

KDAB is a partner for the City of Munich which has installed open source software for all its employees. It runs a KDE-based desktop called Limux for which KDAB provides support. You can see the full story about our work with Limux and the City of Munich here. The City of Munich provides LibreOffice as its Office Suite, so the employees of the City of Munich asked KDAB if we could find a way to fix the problem described above. After some head scratching, we found a successful solution.

The short version is, we found a way to open the KDE dialogs from within LibreOffice so the user experience is seamless – the employees can just get on with their work without being troubled by the software.

How we did it

The overall effort to port LibreOffice to Qt is a huge undertaking. What’s more, actually maintaining the code afterwards, is even more work. Could we do something else instead? Turns out, there is prior art here – the KDE/Plasma integration for Firefox! As such, it was decided to first investigate whether a similar hack could achieve a good-enough solution for the short-term in LibreOffice: Use the well-maintained GTK LibreOffice code base, style it with the above-mentioned KDE widget style for GTK, and then intercept calls to open the GTK file dialogs and instead show the KDE file dialogs.

The latter part is, sadly, not as easy as one may first believe, since running both GTK and Qt within the same application can lead to nasty side-effects: Accessing the clipboard through two distinct X11/xcb connections, once from GTK and once from Qt, from one and the same application, can easily deadlock for example. To work around this problem, we moved the KDE file dialogs into an external helper process. This approach has already proven successful for Firefox in the past. As such, it was mostly a matter of reimplementing it for the specific needs of LibreOffice. And, once again, the approach yielded good results and the patches for LibreOffice were also accepted upstream!

Although this is a bit more of a hack than we would normally do, it works! And we believe that, overall, this integration approach is less work in the long term than porting LibreOffice fully to Qt and maintaining it alongside the GTK layer. What’s more, as this is an open source project, all of our efforts have been upstreamed and will be available for all LibreOffice users under KDE, not only the employees of the Munich City Council.

The post LibreOffice and Plasma appeared first on KDAB.

Cutelyst Framework: Cutelyst 2.5.0 released

$
0
0

Cutelyst a C++ web framework based on Qt got a new release. This release has some important bug fixes so it's really recommended to upgrade to it.

Most of this release fixes came form a side project I started called Cloudlyst, I did some work for the NextCloud client, and due that I became interested into how WebDAV protocol works, so Cloudlyst is a server implementation of WebDAV, it also passes all litmus tests. WebDAV protocol makes heavy use of REST concept, and although it uses XML instead of JSON it's actually a good choice since XML can be parsed progressively which is important for large directories.

Since the path URL now has to deal with file paths it's very important it can deal well with especial characters, and sadly it did not, I had tried to optimize percent encoding decoding using a single QString instead of going back and forth toLatin1() then fromUTF8() and this wasn't working at all, in order to better fix this the URL is parsed a single time at once so the QString path() is fully decoded now, which will be a little faster and avoid allocations. And this is now unit tested :)

Besides that there was:

  • Fix for regression of auto-reloading apps in cutelyst-wsgi
  • Fix csrf token for multipart/form-data (Sebastian Held)
  • Allow compiling WSGI module when Qt was not built with SSL support

The last one and another commit were to fix some build issues I had with buildroot, which I also created a package so soon you will be able to select Cutelyst from buildroot menu.

Have fun https://github.com/cutelyst/cutelyst/releases/tag/v2.5.0

V-Play Engine: Release 2.17.1: Use Qt 3D with Live Reloading and Test Plugin Code Examples from Browser

$
0
0

V-Play 2.17.1 adds a long list of improvements and fixes. You can now also use 3D components with live code reloading in your apps and games. The plugin documentation now includes the example run button. Use it to test code examples for ads, Firebase and more from the browser on your mobile device. You can also learn how to make custom list delegates with 2 new examples in the documentation.

Use Qt 3D in Your Apps and Games, with Live Code Reloading

V-Play and Qt make it easy to add 3D content to your apps or 2D games. With the QML 3D modules, you can embed 3D objects anywhere within your app. This feature is now also available with the Live Clients on desktop, iOS and Android.

Here is a small code example for you to try right away. It displays a 3D cube on your page. The cube rotates depending on the device rotation, using the RotationSensor. You can also change the color of the cube. All that with about than 130 lines of code, without empty lines and comments it’s about 100 lines.

v-play-3d-cube-rotation-sensor-color-select

import VPlayApps 1.0
import QtQuick 2.9
// 3d imports
import QtQuick.Scene3D 2.0
import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Input 2.0
import Qt3D.Extras 2.0
import QtSensors 5.9

App {
  // Set screen to portrait in live client app (not needed for normal deployment)
  onInitTheme: nativeUtils.preferredScreenOrientation = NativeUtils.ScreenOrientationPortrait
          
  RotationSensor {
    id: sensor
    active: true
    // We copy reading to custom property to use behavior on it
    property real readingX: reading ? reading.x : 0
    property real readingY: reading ? reading.y : 0
    // We animate property changes for smoother movement of the cube
    Behavior on readingX {NumberAnimation{duration: 200}}
    Behavior on readingY {NumberAnimation{duration: 200}}
  }
  
  NavigationStack {
    Page {
      title: "3D Cube on Page"
      backgroundColor: Theme.secondaryBackgroundColor
      
      Column {
        padding: dp(15)
        spacing: dp(5)
        
        AppText {
          text: "x-axis " + sensor.readingX.toFixed(2)
        }
        AppText {
          text: "y-axis " + sensor.readingY.toFixed(2)
        }
      }
      
      // 3d object on top of camera
      Scene3D {
        id: scene3d
        anchors.fill: parent
        focus: true
        aspects: ["input", "logic"]
        cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
        
        Entity {
          
          // The camera for the 3d world, to view our cube
          Camera {
            id: camera3D
            projectionType: CameraLens.PerspectiveProjection
            fieldOfView: 45
            nearPlane : 0.1
            farPlane : 1000.0
            position: Qt.vector3d( 0.0, 0.0, 40.0 )
            upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
            viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
          }
          
          components: [
            RenderSettings {
              activeFrameGraph: ForwardRenderer {
                camera: camera3D
                clearColor: "transparent"
              }
            },
            InputSettings { }
          ]
          
          PhongMaterial {
            id: material
            ambient: Theme.tintColor // Also available are diffuse, specular + shininess to control lighting behavior
          }
          
          // The 3d mesh for the cube
          CuboidMesh {
            id: cubeMesh
            xExtent: 8
            yExtent: 8
            zExtent: 8
          }
          
          // Transform (rotate) the cube depending on sensor reading
          Transform {
            id: cubeTransform
            // Create the rotation quaternion from the sensor reading
            rotation: fromAxesAndAngles(Qt.vector3d(1,0,0), sensor.readingX*2, Qt.vector3d(0,1,0), sensor.readingY*2)
          }
          
          // The actuac 3d cube that consist of a mesh, a material and a transform component
          Entity {
            id: sphereEntity
            components: [ cubeMesh, material, cubeTransform ]
          }
        }
      } // Scene3D
      
      // Color selection row
      Row {
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottom: parent.bottom
        spacing: dp(5)
        padding: dp(15)
        
        Repeater {
          model: [Theme.tintColor, "red", "green", "#FFFF9500"]

          Rectangle {
            color: modelData
            width: dp(48)
            height: dp(48)
            radius: dp(5)
            
            MouseArea {
              anchors.fill: parent
              onClicked: {
                material.ambient = modelData
              }
            }
          }
        }
      }
    } // Page
  } // NavigationStack
} // App

Test Code Examples from Plugin Documentation

You can now test the code examples from the plugin documentation. This allows you to run code examples from the documentation on your mobile phone. Just like you are used to from the apps documentation, you can now also test plugins for ads, firebase, analytics and more right from your browser.

You can currently test code examples of the following plugins from the documentation:

 

Here’s a little example for an AdMob advertisement banner:

v-play-admob-banner-ios-live-client

import VPlayApps 1.0
import VPlayPlugins 1.0

App {
  NavigationStack {
    Page {
      title: "Admob Banner"
      
      AdMobBanner {
        adUnitId: "ca-app-pub-3940256099942544/6300978111" // banner test ad by AdMob
        banner: AdMobBanner.Smart
      }
    }
  }
}

New Examples for Custom App List View Delegates

Many of you requested this, so this update adds 2 new examples to the ScollView and ListView documentation. You can check out how to create custom delegate components and display your data with the modelData property.

The second example shows custom foldable delegate components.

applistview-subsections

Improved Handling of Screen Keyboard on iOS and Android

App and GameWindow provide new properties to make the native keyboard handling on Android and iOS easier. You can use keyboardVisible and keyboardHeight to adapt your app layout when the keyboard is shown.

The following example displays a floating action button above the keyboard. It also adapts to size changes of the keyboard:

keyboard-height-floating-action-button


import VPlayApps 1.0
import QtQuick 2.7

App {
  id: app
  
  // We unset the focus from the AppTextField after the keyboard was dismissed from the screen
  onKeyboardVisibleChanged: if(!keyboardVisible) textField.focus = false
  
  NavigationStack {
    
    Page {
      id: page
      title: qsTr("Keyboard Height")
      
      AppTextField {
        id: textField
        width: parent.width
        font.pixelSize: sp(25)
      }
      
      FloatingActionButton {
        // Add the keyboard height as bottom margin, so the button floats above the keyboard
        anchors.bottomMargin: app.keyboardHeight + dp(15)
        // We only show the button if the AppTextField has focus and the keyboard is expanded
        visible: textField.focus && app.keyboardHeight != 0
        icon: IconType.check
        backgroundColor: Theme.tintColor
        iconColor: "white"
        onClicked: textField.focus = false
      }
    }
  }
}

More Features, Improvements and Fixes

Here is a compressed list of improvements with this update:

For a list of additional fixes, please check out the changelog.

How to Update V-Play

Test out these new features by following these steps:

  • Open the V-Play SDK Maintenance Tool in your V-Play SDK directory.
  • Choose “Update components” and finish the update process to get this release as described in the V-Play Update Guide.

V-Play Update in Maintenance Tool

If you haven’t installed V-Play yet, you can do so now with the latest installer from here. Now you can explore all of the new features included in this release!

For a full list of improvements and fixes to V-Play in this update, please check out the change log!

 

 

 

More Posts Like This

 

feature
How to Make Cross-Platform Mobile Apps with Qt – V-Play Apps

vplay-2-17-0-firebase-cloud-storage-downloadable-resources-and-more

Release 2.17.0: Firebase Cloud Storage, Downloadable Resources at Runtime and Native File Access on All Platforms

vplay-update-2.16.1-live-client-module-live-code-reloading-custom-cpp

Release 2.16.1: Live Code Reloading with Custom C++ and Native Code for Qt

teaser-iphonex-support-and-runtime-screen-orientation-change-705px

Release 2.16.0: iPhone X Support and Runtime Screen Orientation Changes

The post Release 2.17.1: Use Qt 3D with Live Reloading and Test Plugin Code Examples from Browser appeared first on V-Play Engine.

KDAB on Qt: The LiMux desktop and the City of Munich

$
0
0

There has been a lot of back and forth around the use of Free Software in public administration. One of the latest initiatives in this area was started by the Free Software Foundation Europe, FSFE. It focuses on the slogan: Public Money – Public Code. There are various usage scenarios for Free Software in public administration. The span ranges from the use of backend technology over user-facing software, e.g. LibreOffice, up to providing a whole free desktop for the administrative staff in a public service entity such as a city council. In this article we will focus on the latter.

When the desktops in an administration are migrated to Linux, the administration becomes a distribution provider. An example for this is the LiMux desktop, that powers the administration of the city of Munich since 2012.

LiMux is a distribution, maintained by the central IT department of the City of Munich. Technically, it builds upon Kubuntu. It provides specific patches, a modified user experience and an automatic distribution system, so all desktops in all departments of the city can be easily administered and offer a consistent user experience.

Distributions in the Free Software ecosystem have different roles, one of them surely being the provider of the finishing touches, especially to important software for its own users. Obviously public administration has special demands. Workflows and documents for example have a totally different importance than for the average Kubuntu user.

In Munich for example, architects in one department complained that Okular, the LiMux and KDE pdf reader, would freeze when they tried to open large construction plans. When the city investigated this issue further, they found out that actually Okular wouldn’t freeze, but loading these large maps would simply occupy Okular for quite a while, making the user think it crashed.

Naturally the City of Munich wanted this issue fixed. But this use case is rather rare for the voluntary Free Software Developer, as only few user groups, like architects, are actually in the situation of having to deal with such large files, so it was unlikely that this bug would be fixed on a voluntary basis.

Since the city does not have enough developer power to fix all such issues themselves, they looked to KDAB for external support. With our KDE and Qt expertise, we were well-positioned to help. Together we identified that, instead of the suggested busy indicator for Okular the City of Munich wanted, progressive loading would be an even better solution. It allows the user to visually follow the loading process and makes it possible for the user to interact with large files as early as possible. And as the City does not want to maintain a patch that fixes this issue for them locally, we also helped them to get all the patches upstream.

This way all efforts are made available for the architects at the City of Munich and also for the general public. In the same spirit we have fixed numerous issues for the City of Munich all around KDE and Qt. As another example: we brought back extended settings to the Qt print dialogue. This allows the City of Munich to make use of all of the functionalities of their high-tech printer, like sorting, stapling and so on. You can read more about KDAB’s work on this here.

Becoming a distribution implies a lot of responsibility for a public administration and KDAB is proud to offer reliable backup for any administration that decides to follow the Linux, Qt and KDE path.

 

Afternote: Recent developments mean that the City has decided to revert the migration back to Microsoft by 2020. The good news is that most changes and adjustments they have made are available upstream and other administrations can build their own solutions upon them.

 

The post The LiMux desktop and the City of Munich appeared first on KDAB.

KDAB on Qt: What a mesh!

$
0
0

With all the advances being made in Qt 3D, we wanted to create some new examples showing some of what it can do. To get us started, we decided to use an existing learning framework, so we followed the open source Tower Defence course, which you can find at CGCookie. Being a game, it allows an interactive view of everything at work, which is very useful.

We found it to be so diverse, that we are now implementing Parts 2 and 3 of the game into Qt 3D. However you don’t have to wait for that, you can start now by following the steps we took.

The setup

These instructions will help you setup for Qt 5.11.0 .

To start, turn to your QtCreator and create a new Qt Console Application, set to run on your Qt 5.11.0 kit.

A Qt Console Application doesn’t come with too much ‘plumbing’. A lot of the other options will attempt to give you starting files that aren’t required or in some cases, the wrong type entirely.

Let’s edit it to fit our needs by opening up the .pro file and adding the following:

First remove the QT += core and QT -= gui lines if they are present.

QT += 3dcore 3drender 3dinput 3dquick 3dquickextras qml quick

Then, if the lines CONFIG += c++11 console and CONFIG -= app_bundle are present, remove them too. Now back on the main.cpp file we need to edit our “includes” from the Qt 3D library.

Replace the #include QCoreApplication with #include QGuiApplication and add these lines:

#include 
#include 
#include 

Within the main block we now have to edit QCoreApplication a(argc, argv); to mirror our include change. So change it to:

QGuiApplication a(argc, argv);

Before the first build / run we should add something to look at. Adding the following block of code before the return statement will provide us with a window:

Qt3DExtras::Quick::Qt3DQuickWindow view;
view.setSource(QUrl("qrc:/main.qml"));
view.show();

Commenting out the line referring to main.qml will allow you to build and run what you have already. If everything has gone to plan, you will get a white window appear. Now you can uncomment the line and continue onwards!

QRC creation

Okay, let’s get rid of the boring white scene and get something in there. Right-click the ‘Sources’ folder and select ‘Add New…’. From here select the Qt > QML File (Qt Quick 2) option. We’ve gone and named it main so that after clicking next till the end you should now have a main.qml and a main.cpp.

This QML file is now going to hold our scene, but to do that we need some resources. We will achieve this by adding a Qt Resource File, just as we did for main.qml – assuming you have an obj with accompanying textures placed in an assets folder within the project.

So this time right-click on the project folder and select ‘Add New…’. From the Qt menu, select ‘Qt Resource File’ and name it something fitting. When this opens it will look noticeably different to the qml and cpp files. At the bottom you will see the self-descriptive; Add, Remove and Remove Missing Files buttons. Click the ‘Add’ button and select ‘Add Prefix’. Now remove everything from the Prefix: text input just leaving the ‘/‘. Click the ‘Add’ button again, this time selecting the ‘Add Files’ option.

Navigate to your obj and texture files and add them all to the qrc, save and close it. If everything went to plan, a ‘Resources’ folder will now be visible in the Projects window on the left.

Follow this again and add main.qml to the qrc in the same way.

One last thing we need before playing with the scene is a skymap. With the files placed in your assets folder, go ahead and add the skymap to the qrc file.

Gotcha

We use three dds files for our skymaps, irradiance, radiance and specular. If you are trying this on a Mac, you will have to uncompress them or they will not work. Keep the names similar to their compressed version. For example we simply added ‘-16f’ to the filename. So our files would be ‘wobbly_bridge_4k_cube_irradiance’ vs ‘wobbly_bridge_4k-16f_cube_irradiance’ respectively.

The necessities

Back to the QML file now, rename the Item { } to be an Entity { } and give it the id: scene. Entity is not recognised because we are missing some imports. Hitting F1 with Entity selected shows us that we need to import Qt3D.Core 2.0, so add this to the imports at the top of the file.

There are certain components that a 3D scene must have, a camera and Render settings being two of those. For this example, we’ll throw in a camera controller too so we can move around the scene.

components: [
    RenderSettings {
        activeFrameGraph: ForwardRenderer {
            camera: mainCamera
            clearColor: Qt.rgba(0.1, 0.1, 0.1, 1.0)
        }
    },
    // Event Source will be set by the Qt3DQuickWindow
    InputSettings { }
]

Camera {
    id: mainCamera
    position: Qt.vector3d(30, 30, 30)
    viewCenter: Qt.vector3d(0, 0, 0)
}

FirstPersonCameraController {
    camera: mainCamera
    linearSpeed: 10
    lookSpeed: 50
}

Here we see that Camera is not recognised, so let’s get the missing import.

Gotcha

If you select Camera and hit F1 to find the import, you will in fact be shown the import for the non-Qt3D Camera. The one you will want is: import Qt3D.Render 2.9

The sky is the limit

Let’s put that skymap to use now. Back in the main.cpp file, we need to add code to check if we’re on MAC or not. If you remember, this was due to MAC not supporting compressed files and needing its own versions. After the QGuiApplication line, put in the following:

#if defined(Q_OS_MAC)
    const QString envmapFormat = QLatin1String("-16f");
#else
    const QString envmapFormat = QLatin1String("");
#endif

Then after the Qt3DExtras line, add the following:

auto context = view.engine()->qmlEngine()->rootContext();
context->setContextProperty(QLatin1String("_envmapFormat"), envmapFormat);

If you try to build at this point, you will notice various imports missing. One for FirstPersonCameraController, one for InputSettings and TexturedMetalRoughtMaterial. Hitting F1 on FirstPersonCameraController will give you import Qt3D.Extras 2.0 and F1 on InputSettings will give you import Qt3D.Input 2.0 but then later you’ll hit a snag. TexturedMetalRoughtMaterial may not turn up any documentation but we’ll be kind enough to give you the answer… edit the Qt3D.Extras 2.0 to be 2.9 instead. If this now works you will get a dark grey window.

Barrel of laughs

The final part will be our mesh, we chose a barrel, and the skymap for it to reflect (although this might not be visible).

In main.qml after the InputSettings{}, throw in the following:

EnvironmentLight {
    id: envLight
    irradiance: TextureLoader {
        source: "qrc:/path/to/your/file" + _envmapFormat + "_cube_irradiance.dds"

        minificationFilter: Texture.LinearMipMapLinear
        magnificationFilter: Texture.Linear
        wrapMode {
            x: WrapMode.ClampToEdge
            y: WrapMode.ClampToEdge
        }
        generateMipMaps: false
    }
    specular: TextureLoader {
        source: "qrc:/path/to/your/file" + _envmapFormat + "_cube_specular.dds"
                
        minificationFilter: Texture.LinearMipMapLinear
        magnificationFilter: Texture.Linear
        wrapMode {
            x: WrapMode.ClampToEdge
            y: WrapMode.ClampToEdge
        }
        generateMipMaps: false
    }
}

You can hit build now to check it’s working, but the scene will still be pretty boring. Throw in your obj to get some eye candy. Here is the code we used after EnvironmentLight:

Mesh {
    source: "qrc:/your/model.obj"
},
Transform {
    translation: Qt.vector3d(4, 0, 2)
},
TexturedMetalRoughMaterial {
    baseColor: TextureLoader {
        format: Texture.SRGB8_Alpha8
        source: "qrc:/path/to/your/Base_Color.png"
    }
    metalness: TextureLoader { source: "qrc:/path/to/your/Metallic.png" }
    roughness: TextureLoader { source: "qrc:/path/to/your/Roughness.png" }
    normal: TextureLoader { source: "qrc:/path/to/your/Normal_OpenGL.png" }
    ambientOcclusion: TextureLoader { source: "qrc:/path/to/your/Mixed_AO.png" }
}

Finally, hit build and then run.

Rendered Barrel

The barrel viewed at the end of What A Mesh pt1

The post What a mesh! appeared first on KDAB.


KDAB on Qt: KDAB at Italian C++, Milan

$
0
0

KDAB was sponsor of this annual C++ event run by the C++ Community for the C++ Community in Italy, which was founded some five years ago and is growing fast.

our-roll-upAround 200 people showed up for “++ it”, 50 more than last year, and were treated to an excellent program.

There was a mix of talks in either English or Italian, including ‘Debug C++ Without Running‘ by Anastasia Kazakova, ‘C++ Barbarian Quiz & Introduction to Conan C/C++ Package Manager‘ from Diego Rodriguez-Losada Gonzalez and one from Vittorio Romeo on ‘Zero-allocation & no type erasure futures‘, all of which KDAB particularly enjoyed.

You can see the full program and a post-event report here.

 

 

The post KDAB at Italian C++, Milan appeared first on KDAB.

Woboq: Integrating QML and Rust: Creating a QMetaObject at Compile Time

$
0
0

In this blog post, I would like to present a research project I have been working on: Trying to use QML from Rust, and in general, using a C++ library from Rust.

The project is a Rust crate which allows to create QMetaObject at compile time from pure Rust code. It is available here: https://github.com/woboq/qmetaobject-rs

Qt and Rust

There were already numerous existing projects that attempt to integrate Qt and Rust. A great GUI toolkit should be working with a great language.

As far back as 2014, the project cxx2rust tried to generate automatic bindings to C++, and in particular to Qt5. The blog post explain all the problems. Another project that automatically generate C++ bindings for Qt is cpp_to_rust. I would not pursue this way of automatically create bindings because it cannot produce a binding that can be used from idiomatic Rust code, without using unsafe.

There is also qmlrs. The idea here is to develop manually a small wrapper C++ library that exposes extern "C" functions. Then a Rust crate with a good and safe API can internally call these wrappers.
Similarly, the project qml-rust does approximately the same, but uses the DOtherSide bindings as the Qt wrapper library. The same used for D and Nim bindings for QML.
These two projects only concentrate on QML and not QtWidget nor the whole of Qt. Since the API is then much smaller, this simplifies a lot the fastidious work of creating the bindings manually. Both these projects generate a QMetaObject at runtime from information given by rust macros. Also you cannot use any type as parameter for your property or method arguments. You are limited to convert to built-in types.

Finally, there is Jos van den Oever's Rust Qt Binding Generator. To use this project, one has to write a JSON description of the interface one wants to expose, then the generator will generate the rust and C++ glue code so that you can easily call rust from your Qt C++/Qml application.
What I think is a problem is that you are still expected to write some C++ and add an additional step in your build system. That is perfectly fine if you want to add Rust to an existing C++ project, but not if you just want a GUI for a Rust application. Also writing this JSON description is a bit alien.

I started the qmetaobject crate mainly because I wanted to create the QMetaObject at rust compile time. The QMetaObject is a data structure which contains all the information about a class deriving from QObject (or Q_GADGET) so the Qt runtime can connect signals with slots, or read and write properties. Normally, the QMetaObject is built at compile time from a C++ file generated by moc, Qt's meta object compiler.
I'm a fan of creating QMetaObject: I am contributing to Qt, and I also wrote moc-ng and Verdigris which are all about creating QMetaObject. Verdigris uses the power of C++ constexpr to create the QMetaObject at compile time, and I wanted to try using Rust to see if it could also be done at compile time.

The qmetaobject crate

The crate uses a custom derive macro to generate the QMetaObject. Custom derive works by adding an annotation in front of a rust struct such as #[derive(QObject)] or #[derive(QGadget)]. Upon seeing this annotation, the rustc compiler will call the function from the qmetaobject_impl crate which implements the custom derive. The function has the signature fn(input : TokenStream) -> TokenStream. It will be called at compile time, and takes as input the source code of the struct it derives and should generate more source code that will then be compiled.
What we do in this custom derive macro is first to parse the content of the struct and find about some annotations. I've used a set of macros such as qt_property!, qt_method! and so on, similar to Qt's C++ macros. I could also have used custom attributes but I chose macros as it seemed more natural coming from the Qt world (but perhaps this should be revised).

Let's simply go over a dummy example of using the crate.

extern crate qmetaobject;
use qmetaobject::*; // For simplicity

// Deriving from QObject will automatically implement the QObject trait and
// generates QMetaObject through the custom derive macro.
// This is equivalent to add the Q_OBJECT in Qt code.
#[derive(QObject,Default)]
struct Greeter {
  // We need to specify a C++ base class. This is done by specifying a
  // QObject-like trait. Here we can specify other QObject-like traits such
  // as QAbstractListModel or QQmlExtensionPlugin.
  // The 'base' field is in fact a pointer to the C++ QObject.
  base : qt_base_class!(trait QObject),
  // We declare the 'name' property using the qt_property! macro.
  name : qt_property!(QString; NOTIFY name_changed),
  // We declare a signal. The custom derive will automatically create
  // a function of the same name that can be called to emit it.
  name_changed : qt_signal!(),
  // We can also declare invokable methods.
  compute_greetings : qt_method!(fn compute_greetings(&self, verb : String) -> QString {
      return (verb + " " + &self.name.to_string()).into()
  })
}

fn main() {
  // We then use qml_register_type as an equivalent to qmlRegisterType
  qml_register_type::(cstr!("Greeter"), 1, 0, cstr!("Greeter"));
  let mut engine = QmlEngine::new();
  engine.load_data(r#"
    import QtQuick 2.6; import QtQuick.Window 2.0; import Greeter 1.0;
    Window {
      visible: true;
      // We can instantiate our rust object here.
      Greeter { id: greeter; name: 'World'; }
      // and use it by accessing its property or method.
      Text { text: greeter.compute_greetings('hello'); }
    }"#.into());
  engine.exec();
}

In this example, we used qml_register_type to register the type to QML, but we can also also set properties on the global context. An example with this model, which also demonstrate QGadget

// derive(QGadget) is the equivalent of Q_GADGET.
#[derive(QGadget,Clone,Default)]
struct Point {
  x: qt_property!(i32),
  y: qt_property!(i32),
}

#[derive(QObject, Default)]
struct Model {
  // Here the C++ class will derive from QAbstractListModel
  base: qt_base_class!(trait QAbstractListModel),
  data: Vec
}

// But we still need to implement the QAbstractListModel manually
impl QAbstractListModel for Model {
  fn row_count(&self) -> i32 {
    self.data.len() as i32
  }
  fn data(&self, index: QModelIndex, role:i32) -> QVariant {
    if role != USER_ROLE { return QVariant::default(); }
    // We use the QGadget::to_qvariant function
    self.data.get(index.row() as usize).map(|x|x.to_qvariant()).unwrap_or_default()
  }
  fn role_names(&self) -> std::collections::HashMap {
    vec![(USER_ROLE, QByteArray::from("value"))].into_iter().collect()
  }
}

fn main() {
  let mut model = Model { data: vec![ Point{x:1,y:2} , Point{x:3, y:4} ], ..Default::default() };
  let mut engine = QmlEngine::new();
  // Registers _model as a context property.
  engine.set_object_property("_model".into(), &mut model);
  engine.load_data(r#"
    import QtQuick 2.6; import QtQuick.Window 2.0;
    Window {
      visible: true;
      ListView {
        anchors.fill: parent;
        model: _model;  // We reference our Model object
        // And we can access the property or method of our gadget
        delegate: Text{ text: value.x + ','+value.y; } }
    }"#.into());
  engine.exec();

Other implemented features include the creation of Qt plugins such as QQmlExtensionPlugin without writing a line of C++, only using rust and cargo. (See the qmlextensionplugins example.)

QMetaObject generation

The QMetaObject consists in a bunch of tables in the data section of the binary: a table of string and a table of integer. And there is also a function pointer with code used to read/write the properties or call the methods.

The custom derive macro will generate the tables as &'static[u8]. The moc generated code contains QByteArrayData, built in C++, but since we don't want to use a C++ compiler to generate the QMetaObject, we have to layout all the bytes of the QByteArrayData one by one. Another tricky part is the creation of the Qt binary JSON for the plugin metadata. The Qt binary JSON is also an undocumented data structure which needs to be built byte by byte, respecting many invariants such as alignment and order of the fields.

The code from the static_metacall is just an extern "C" fn. Then we can assemble all these pointers in a QMetaObject. We cannot create const static structure containing pointers. This is then implemented using the lazy_static! macro.

QObject Creation

Qt needs a QObject* pointer for our object. It has virtual methods to get the QMetaObject. The same applies for QAbstractListModel or any other class we could like to inherit from, which has many virtual methods that we wish to override.

We will then have to materialize an actual C++ object on the heap. This C++ counterpart is created by some of the C++ glue code. We will store a pointer to this C++ counterpart in the field annotated with the qt_base_class! macro. The glue code will instantiate a RustObject . It is a class that inherits from QObject (or any other QObject derivative) and overrides the virtual to forward them to a callback in rust which will then be able to call the right function on the rust object.

One of the big problems is that in rust, contrary to C++, objects can be moved in memory at will. This is a big problem, as the C++ object contains a pointer to the rust object. So the rust object needs somehow to be fixed in memory. This can be achieved by putting it into a Box or a Rc, but even then, it is still possible to move the object in safe code. This problem is not entirely fixed, but the interface takes the object by value and moves it to an immutable location. Then the object can still be accessed safely from a QJSValue object.

Note that QGadget does not need a C++ counter-part.

C++ Glue code

For this project I need a bit of C++ glue code to create the C++ counter part of my object, or to access the C++ API for Qt types or QML API. I am using the cpp! macro from the cpp crate. This macro allows embedding C++ code directly into rust code with very little boiler plate compared to manually creating callbacks and declaring extern "C" functions.
I even contributed a cpp_class macro which allows wrapping C++ classes from rust.

Should an API be missing, it is easy to add the missing wrapper function. Also when we want to inherit from a class, we just need to imitate what is done for QAbstractListView, that is override all the virtual functions we want to override, and forward them to the function from the trait.

Final Words

My main goal with this crate was to try to see if we can integrate QML with idiomatic and safe Rust code. Without requiring to use of C++ or any other alien tool for the developer. I also had performance in mind and wanted to create the QMetaObject at compile time and limit the amount of conversions or heap allocations.
Although there are still some problems to solve, and that the exposed API is far from complete, this is already a beginning.

You can get the metaobject crate at this URL: https://github.com/woboq/qmetaobject-rs

The Qt Company Blog: Qt Creator 4.6.2 released

$
0
0

We are happy to announce the release of Qt Creator 4.6.2!

This fixes reparsing of QMake projects, for example when project files change, and a couple of other issues.
Have a look at our change log for more details.

Get Qt Creator 4.6.2

The opensource version is available on the Qt download page, and you find commercially licensed packages on the Qt Account Portal. Qt Creator 4.6.2 is also available through an update in the online installer. Please post issues in our bug tracker. You can also find us on IRC on #qt-creator on chat.freenode.net, and on the Qt Creator mailing list.

The post Qt Creator 4.6.2 released appeared first on Qt Blog.

KDAB on Qt: LibreOffice and Plasma

$
0
0

At KDAB, we know that consistency is an important aspect of the User Experience – users don’t want to have to learn different ways to achieve the same thing. In the Linux world, there is a major structural pitfall to this: the applications written for Linux come in at least two major technologies –Qt and GTK. Each of these frameworks deeply influences the experience the user has, and in different ways. As you’d expect, the frameworks have their own helper-dialogs e.g. to open or save a file or for printing. This can make it confusing for users, when the apps they use don’t show the same helper-dialogs for common actions.

Most KDE software is written using the Qt library, and within KDE there are lots of attempts to ease the use of GTK applications on Plasma, the KDE desktop. For example, GTK has been styled by members of the KDE community so its applications are visually consistent with the overall KDE look. Nonetheless a major drawback to these efforts remains: helper-dialogs opened from a GTK application are still GTK dialogs and they function differently.

For the user this inconsistency is annoying. Take file handling for example: KDE offers a lot of support to the user. They can define important places – like favorite folders, drives, cloud storage –  that allow fast access whenever the user needs to handle files. It follows the KDE idea of navigation through the files, which includes how the user navigates, handling file previews and how the files in a folder are filtered. The file open dialog in GTK is not worse than the KDE one, it is just different. It offers almost the same functionality, but is presented in a way the KDE user is not used to. This can be confusing and frustrating, especially in environments where the user has no choice about the system they have to work with.

Perhaps the best known and most commonly used GTK application is LibreOffice. The limitations it has for KDE users due to the use of GTK dialogs is well known to the LibreOffice community. A lot of effort has already been undertaken to fix this problem. Some ideas even went so far as to migrate large parts of LibreOffice to Qt in order to provide a native feeling for KDE users.

KDAB’s contribution

KDAB is a partner for the City of Munich which has installed open source software for all its employees. It runs a KDE-based desktop called Limux for which KDAB provides support. You can see the full story about our work with Limux and the City of Munich here. The City of Munich provides LibreOffice as its Office Suite, so the employees of the City of Munich asked KDAB if we could find a way to fix the problem described above. After some head scratching, we found a successful solution.

The short version is, we found a way to open the KDE dialogs from within LibreOffice so the user experience is seamless – the employees can just get on with their work without being troubled by the software.

How we did it

The overall effort to port LibreOffice to Qt is a huge undertaking. What’s more, actually maintaining the code afterwards, is even more work. Could we do something else instead? Turns out, there is prior art here – the KDE/Plasma integration for Firefox! As such, it was decided to first investigate whether a similar hack could achieve a good-enough solution for the short-term in LibreOffice: Use the well-maintained GTK LibreOffice code base, style it with the above-mentioned KDE widget style for GTK, and then intercept calls to open the GTK file dialogs and instead show the KDE file dialogs.

The latter part is, sadly, not as easy as one may first believe, since running both GTK and Qt within the same application can lead to nasty side-effects: Accessing the clipboard through two distinct X11/xcb connections, once from GTK and once from Qt, from one and the same application, can easily deadlock for example. To work around this problem, we moved the KDE file dialogs into an external helper process. This approach has already proven successful for Firefox in the past. As such, it was mostly a matter of reimplementing it for the specific needs of LibreOffice. And, once again, the approach yielded good results and the patches for LibreOffice were also accepted upstream!

Although this is a bit more of a hack than we would normally do, it works! And we believe that, overall, this integration approach is less work in the long term than porting LibreOffice fully to Qt and maintaining it alongside the GTK layer. What’s more, as this is an open source project, all of our efforts have been upstreamed and will be available for all LibreOffice users under KDE, not only the employees of the Munich City Council.

The post LibreOffice and Plasma appeared first on KDAB.

The Qt Company Blog: Qt Creator 4.7.0 released

$
0
0

We are happy to announce the release of Qt Creator 4.7.0!

C++ Support

We decided that it is time to turn the Clang code model on by default. It made huge progress during the last releases, and at some point we need to do this switch. The built-in model cannot keep up with the developments in the C++ language, nor with the development of the available tooling around it. We nowadays regularly close bug reports with the comment “works with Clang code model”. Also, the Clang code model provides much better information about issues in code without going through the edit-compile-analyze cycle explicitly. Please also have a look at Nikolai’s blog post on the Clang code model and the history of C/C++ support in Qt Creator.

There can be situations where the built-in model still works better for you than the Clang code model, and you continue to have the option to use it instead, by disabling the ClangCodeModel plugin. The global symbol index is also still created with the built-in model.

Project wide diagnostics and fixits in Qt Creator by clang-tidy and clazy

We upgraded the Clang code model to Clang 6.0. It now provides the information for the overview of the current document, which is used for the symbols dropdown, outline pane and “.” locator filter. You also have more freedom in deciding which Clang-Tidy and Clazy checks you want to run while editing, and have the option to run checks over your whole code base through a new tool in Debug mode (Analyze>Clang-Tidy and Clazy). The warnings and errors from the code model are now also optionally shown in the Issues pane.

Test Integration

If your text cursor in the C++ editor is currently inside a test function, you can directly run that individual test with the new Run Test Under Cursor action. The test integration now also marks the location of failed tests in the editor. For Google Test we added support for filtering.

Windows Hosts

On Windows we improved the scanning for MSVC compilers, which previously could block Qt Creator. We also fixed an issue which could lead to short term freezes while Qt Creator was listening to the global, shared Windows debug stream. And saving files on network drives should work again in all configurations.

Other Improvements

The kit options are one of the most important settings that you might need to adapt for your projects in Qt Creator. So we put them in their own top-level entry in the preferences dialog, which is also the very first one in the list.

If you have a HiDPI screen on Windows or Linux, you can now easily choose if you want Qt’s automatic scaling or not, by enabling or disabling the new option in Environment>Interface.

The File System view got new options for showing folders on top as opposed to integrated into the alphabetic sorting, and for turning off the synchronization of the base folder with the current document’s project. You can also create new folders directly in the File System view now.

There have been many more improvements and fixes. Please refer to our changes file for a more comprehensive list.

Get Qt Creator 4.7.0

The opensource version is available on the Qt download page, and you find commercially licensed packages on the Qt Account Portal. Qt Creator 4.7.0 is also available through an update in the online installer. Please post issues in our bug tracker. You can also find us on IRC on #qt-creator on chat.freenode.net, and on the Qt Creator mailing list.

The post Qt Creator 4.7.0 released appeared first on Qt Blog.

V-Play Engine: Release 2.17.0: Firebase Cloud Storage, Downloadable Resources at Runtime and Native File Access on All Platforms

$
0
0

V-Play 2.17.0 introduces Firebase Cloud Storage to store local files in the cloud easily & fast. You can use it to create photo or document sharing apps without any server-side code, or even the next Facebook? It also adds downloadable resources at runtime to reduce initial package size, or to load specific resources only on demand. FileUtils give you convenient access to the native device file system. You can check out two new app demos for using C++ with QML, use new Qt modules with V-Play Live and much more. This is a big update, don’t miss it!

New Firebase Storage to Upload Local Files to the Cloud

With the new FirebaseStorage item you can upload files to the Firebase Cloud Storage. It uploads local files to the cloud file system and returns the public download URL. With Firebase, you can create content sharing apps like Facebook or Snapchat without additional server-side code.

Examples for local files you can upload are:

Here is a code example, that shows how to upload an image taken with the camera. After the image is uploaded, we display it in the app.

vplay-camera-picker-and-firebase-cloud-storage-upload

NOTE: This example uses a public Firebase storage instance, don’t upload any sensitive data!

import QtQuick 2.0
import VPlayApps 1.0
import VPlayPlugins 1.0

App {
  
  NavigationStack {
    Page {
      title: "Firebase Storage"
      
      FirebaseStorage {
        id: storage
        
        config: FirebaseConfig {
          id: customConfig
          
          projectId: "v-play-live-client-test-db"
          databaseUrl: "https://v-play-live-client-test-db.firebaseio.com"
          storageBucket: "v-play-live-client-test-db.appspot.com"
          
          //platform dependent - get these values from the google-services.json / GoogleService-info.plist
          apiKey: Qt.platform.os === "android" ? "AIzaSyD3Pmw89NHhdG9nGIQWwaOB55FuWjcDSS8" : "AIzaSyCheT6ZNFI4mUwfrPRB098a08dVzlhZNME"
          applicationId: Qt.platform.os === "android" ? "1:40083798422:android:ed7cffdd1548a7fa"  : "1:40083798422:ios:ed7cffdd1548a7fa"
          
        }
      }
      
      AppFlickable {
        anchors.fill: parent
        
        Column {
          width: parent.width
          anchors.margins: dp(12)
          
          AppButton {
            text: "Capture image + upload"
            onClicked: nativeUtils.displayCameraPicker()
          }
          
          AppText {
            id: status
            text: "Idle"
          }
          
          // this will display the image after it's uploaded
          AppImage {
            id: img
            width: parent.width
            fillMode: AppImage.PreserveAspectFit
            autoTransform: true
          }
        }
      }
    }
  }
  
  Connections {
    target: nativeUtils
    onCameraPickerFinished: {
      if(accepted) {
        //picture taken with camera is stored at path - upload to Firebase Storage
        storage.uploadFile(path, "test-image" + Date.now() + ".png", function(progress, finished, success, downloadUrl) {
          if(!finished) {
            status.text = "Uploading... " + progress.toFixed(2) + "%"
          } else if(success) {
            img.source = downloadUrl
            status.text = "Upload completed."
          } else {
            status.text = "Upload failed."
          }
        })
      }
    }
  }
}

Download Resources at Runtime

DownloadableResource allows downloading app and game assets on demand during runtime. You no longer need to include all resources like images or videos in the app binary. This results in smaller downloads from the app stores. Cut down your 500MB training app to e.g. only 30MB, and let the user download your workout videos on demand!

The most popular use cases for downloadable packages are:

  • You want to keep your app store binary as small as possible for the first download, to increase the download numbers of your app or game with a smaller download size.
  • You want to download additional content packages after in-app purchases.
  • Keep your initial app size below the store limits:
    • On Google Play, your initial apk size must be below 100MB, after that you need to use Android expansion files. To avoid that, you can just use DownloadableResource and download the additional files at a later time.
    • On iOS, your initial binary size limit is 150MB for mobile network downloads. If your binary is bigger, the user can only download your app over WiFi. Downloading additional resources later also helps you to avoid this limit.
    • With the V-Play DownloadableResource component, you can create a cross-platform solution to work with downloadable resources, that works for both iOS AND Android. It even works on Desktop too, with a single source code for all platforms! This way, you do not need to deal with Android expansion files and can create a working solution for all platforms instead.

Here is a small example how you could use it: it downloads and extracts a zip archive including an image to the default location after 5 seconds. Then it replaces the placeholder image with the downloaded image:

import VPlayApps 1.0
import QtQuick 2.0
import VPlay 2.0

App {
  
  // uncomment this to remove the resources on startup, so you can test the downloading again
  //Component.onCompleted: resource1.remove()
  
  // after 5 seconds, we download the resources
  Timer {
    running: true
    interval: 5000
    onTriggered: {
      resource1.download()
    }
  }
  
  NavigationStack {
    Page {
      title: "Downloadable Resource"
      
      DownloadableResource {
        id: resource1
        
        extractAsPackage: true // true for zip archives
        source: "https://v-play.net/web-assets/girl.zip"
      }
      
      AppImage {
        width: parent.width
        fillMode: AppImage.PreserveAspectFit
        // as long as the resource file is not available, we use a placeholder image
        // (the example placeholder is actually also from a web url, to be usable with the web editor)
        // if the resource is available, we get the extracted file url and set it as new image source
        // on your next app start (or live reload) the resource will be available immediately and not downloaded again
        source: resource1.available ? resource1.getExtractedFileUrl("girl.jpg") : "https://v-play.net/web-assets/balloon.png"
      }
    }
  }
}

You have full information about the download, with properties like status, progress and available. You know exactly when resources are available or when to show a loading indicator.

DownloadableResource can load files from any HTTP(S) web addresses. You can add a secret to protect and restricts downloads to your app or game only. You can download single files or entire .zip-archives, which are automatically extracted.

Once a resource is downloaded, you can use it like any other asset. On your next app start, the resource will be available right away.

FileUtils Class for Cross-Platform Native File Access

You can use the new FileUtils context property to open, read, copy or delete files and folders on any device.

This is an example to download a PDF file and then open it with the native PDF viewer application, using FileUtils::openFile():

vplay-download-pdf-and-open-native-viewer

import VPlayApps 1.0
import QtQuick 2.0
import VPlay 2.0

App {
  id: app
  // uncomment this to remove the resources on startup, so you can test the downloading again
  //Component.onCompleted: pdfResource.remove()
  NavigationStack {
    Page {
      title: "Download PDF"
      
      Column {
        anchors.centerIn: parent
        
        AppButton {
          text: "Download / Open"
          onClicked: {
            if(pdfResource.available) openPdf()
            else pdfResource.download()
          }
        }
        AppText {
          text: "Status: " + pdfResource.status
        }
      }
    }
  }
  DownloadableResource {
    id: pdfResource
    source: "http://www.orimi.com/pdf-test.pdf"
    storageLocation: FileUtils.DocumentsLocation
    storageName: "pdf-test.pdf"
    extractAsPackage: false
    // if the download is competed, available will be set to true
    onAvailableChanged: if(available) openPdf()
  }
  function openPdf() {
    // you can also open files with nativeUtils.openUrl() now (for paths starting with "file://")
    //nativeUtils.openUrl(pdfResource.storagePath)
    // with V-Play 2.17.0 you can also use fileUtils.openFile()
    fileUtils.openFile(pdfResource.storagePath)
  }
}

Two New App Examples How to Integrate C++ with QML

You can check out and copy parts from two brand-new app demos that show how to integrate C++ with QML!

Exposing a C++ Class to QML

The first example shows the different forms of C++ and QML integrations. This example is the tutorial result from How to Expose a Qt C++ Class with Signals and Slots to QML.

Path to the app demo: /Examples/V-Play/appdemos/cpp-qml-integration

Display Data from C++ Models with Qt Charts

The second example shows how to combine a C++ backend that provides the model data for a frontend created in QML. The data is displayed with QML with Qt Charts for both 2D and 3D charts. It also includes shader effects, because, why not?

vplay-cpp-backed-charts-example

Path to the app demo: /Examples/V-Play/appdemos/cpp-backend-charts-qml

Live Client Support for Bluetooth, NFC and Pointer Handlers

The V-Play Live Client now supports the Qt modules for Bluetooth, NFC and Pointer Handlers.

Network Adapter Selection in Live Server

You can now change the used network adapter in the Live Server. This fixes a possible issue that the mobile Live Client stalls in the “Connected – Loading Project” screen. If you also face this issue, here is how to fix it.

Open the settings screen from the lower left corner of your Live Server:

vplay-live-server-settings-icon

Now you can change the selected network adapter:

vplay-live-server-network-adapter-settings

This IP is sent to the Live Client to establish the connection. You can try to select different adapters, the IP of the Live Server and Live Client should be in the same network.

More Features, Improvements and Fixes

How to Update V-Play

Test out these new features by following these steps:

  • Open the V-Play SDK Maintenance Tool in your V-Play SDK directory.
  • Choose “Update components” and finish the update process to get this release as described in the V-Play Update Guide.

V-Play Update in Maintenance Tool

If you haven’t installed V-Play yet, you can do so now with the latest installer from here. Now you can explore all of the new features included in this release!

For a full list of improvements and fixes to V-Play in this update, please check out the change log!

 

 

 

More Posts Like This

 

feature
How to Make Cross-Platform Mobile Apps with Qt – V-Play Apps

vplay-update-2.16.1-live-client-module-live-code-reloading-custom-cpp

Release 2.16.1: Live Code Reloading with Custom C++ and Native Code for Qt

teaser-iphonex-support-and-runtime-screen-orientation-change-705px

Release 2.16.0: iPhone X Support and Runtime Screen Orientation Changes

new-firebase-qt-features-live-code-reloading-qt-5-10-1-vplay-release-2-15-1
Release 2.15.1: New Firebase Features and New Live Code Reloading Apps | Upgrade to Qt 5.10.1 & Qt Creator 4.5.1

The post Release 2.17.0: Firebase Cloud Storage, Downloadable Resources at Runtime and Native File Access on All Platforms appeared first on V-Play Engine.

V-Play Engine: How to Expose a Qt C++ Class with Signals and Slots to QML

$
0
0

Application Development with QML is simple and powerful. But Qt C++ can be more performant, offers many features and is less error-prone. This post shows you how to create apps that take advantage of both languages.

How to Communicate between C++ and QML

It is important to choose the right language for different features of your app. Integrate C++ components with QML to take your mobile app development to the next level.

Advantages of Coding in QML

V-Play Engine for Qt-based mobile apps and games uses the power of Qt Quick (QML + Javascript). This declarative scripting language is so powerful that it saves up to 60% lines of code compared to other programming languages.

Coding in QML has several advantages over development with C++:

  • Coding with QML + JavaScript is very easy to learn and allows to reduce the required amount of code a lot.
  • Language concepts like states, signals or property bindings are a huge time-saver.
  • QML makes adding animations simple. You can animate every property of your QML types with simple Animation components.
  • QML is extensible and flexible. For example, you can extend objects with new properties and features in-line. No need to create a new re-usable type for small extensions.
  • The QML Rendering Engine offers a great performance. The renderer uses C++ Qt and relies on a hardware accelerated scene graph. This makes it fast enough to power even high-performance games.

When to use C++ Instead

Qt app development with C++ has advantages as well. For some scenarios you need features that are only available with Qt C++. Also, C++ is fast and type-safe. This allows to provide the best possible performance for long-running and data-intense calculations.

For these examples, you would choose C++ over QML:

  • Native C++ code is the right choice for data-intense operations. It will outperform interpreted QML/JavaScript code.
  • C++ code is type-safe and compiled into object code. For parts where stability and security are important, using C++ helps to make your app less error-prone.
  • The Qt C++ components offer different and in some cases more features than the QML types. For example, advanced networking features.
  • It is also possible to mix C++ with native code for Android (over JNI) or iOS (Obj-C or Swift). This allows to provide such native functionality for QML as well.

V-Play Engine extends Qt for mobile app and game development. It already covers tasks like accessing native device features – so you don’t have to worry about going deep into C++ or Java and Obj-C.

Still, to get the most out of your application you can use the advantages of both languages. The full example of this guide is also available on GitHub:

How to Access a C++ Object from QML

Before we go into any details, let us start by creating a simple V-Play Apps project with Qt Creator. If you are new to V-Play and don’t know how, please consider having a look at the Getting Started Tutorial or the V-Play Designer Tutorial Video.

To sign-up and install V-Play, see the download page of the V-Play website.

Note: Adding custom C++ code is not supported when testing with QML Live. Please build your project with the classic RUN button to test the examples below.

Create a C++ Class in your V-Play Project

1. After creating a new app project, first replace the code in Main.qml with this basic structure:

import VPlayApps 1.0
import QtQuick 2.5

App {

 NavigationStack {
   Page {
     title: "Integrate C++ and QML"
   }
 }
}

It only includes the main App window and a Page within NavigationStack to show a navigation bar that holds the page title:

V-Play App with a Page

2. This is enough for our basic QML setup. Let’s go on by creating a new C++ class. First, right-click the C++ “Sources” folder of your project in Qt Creator, select “Add New…” and choose the “C++ Class” template in the C++ section:

Add a new C++ Class

3. Then set “MyGlobalObject” as Class Name and select “Include QObject” to include the QObject type, as the main requirement to prepare our class for usage with QML is to derive from QObject.

Derive C++ class from QObject

After completing the wizard, your project contains the class definition myglobalobject.h in the “Headers” folder and the implementation myglobalobject.cpp in the “Sources” folder of the project.

Qt Creator C++ type header and source files

Note that the *.pro configuration now also includes the new files in the HEADERS and SOURCES configuration.

Implement the C++ Class with Signals and Slots for Usage with QML

1. Open myglobalobject.h and add some code to derive from QObject– the required include statement is already in place:

#ifndef MYGLOBALOBJECT_H
#define MYGLOBALOBJECT_H

#include 

class MyGlobalObject : public QObject
{
 Q_OBJECT

public:
 MyGlobalObject();
};

#endif // MYGLOBALOBJECT_H

Do not forget to also add the Q_OBJECT preprocessor macro within the class definition.

2. Now that we have a new QObject, let’s add a simple method we will later call from QML. To make the method available in QML, it is required to mark it as a public slot:

class MyGlobalObject : public QObject
{
 Q_OBJECT

public:
 MyGlobalObject();

public slots: // slots are public methods available in QML
 void doSomething(const QString &text);
};

3. To complete our basic class, open myglobalobject.cpp and add the method implementation for doSomething(). We keep it simple and only print the given text to the debug output.

#include "myglobalobject.h"
#include 

MyGlobalObject::MyGlobalObject()
{
 // perform custom initialization steps here
}

void MyGlobalObject::doSomething(const QString &text) {
 qDebug() << "MyGlobalObject doSomething called with" << text;
}

Expose an Object to QML as a Context Property

One possible way to work with a C++ object in QML is to add the object as a property to the root context of the QML tree. You can decide on a name for the property, which is then globally available in your QML code.

1. To create a new object of our class and add it as a property, we extend the main.cpp code:

// keep existing includes here
// include qml context, required to add a context property
#include 

// include custom class
#include "myglobalobject.h"

int main(int argc, char *argv[])
{
 // V-Play initialization ...

 // add global c++ object to the QML context as a property
 MyGlobalObject* myGlobal = new MyGlobalObject();
 myGlobal->doSomething("TEXT FROM C++");
 engine.rootContext()->setContextProperty("myGlobalObject", myGlobal); // the object will be available in QML with name "myGlobalObject"

 engine.load(QUrl(vplay.mainQmlFileName()));
 return app.exec();
}

Note: It is possible to fully use the object also in C++. The above code example already includes a test-call to our doSomething method.

2. In the Main.qml of our project, we extend our Page with a Column and a first AppButton, which calls the doSomething() method when clicked:

   Page {
     title: "Integrate C++ and QML"

     // Example 1 - Global Context Property
     // NOTE: myGlobalObject is available here because it is set as a context property in main.cpp
     Column {

       // 1.1: Calling myGlobalObject.doSomething() function
       AppButton {
         text: "myGlobalObject.doSomething()"
         onClicked: myGlobalObject.doSomething("TEXT FROM QML")
       }

     }
   }

Button to call the c++ function

3. Let’s hit the green run button in Qt Creator to see how it works. The debug output shows the initial method call from main.cpp and with a click on the button another message appears:
MyGlobalObject doSomething called with “TEXT FROM QML”

Qt Creator C++ function log from QML

That’s all we need to call methods of a C++ Object from QML. This already allows simple communication from QML to C++, but there’s even more we can do. QML supports many amazing concepts like value-changed listeners of properties and property bindings, which make development a lot easier. So let’s add a full-featured QML property to our C++ class!

Add a Class Property with Full QML Support

1. Open mylgobalobject.h and add a private counter property with a public getter and setter method.

class MyGlobalObject : public QObject
{
// …


public:
 int counter() const;
 void setCounter(int value);

private:
 int m_counter;
};

2. Implement the required methods and initialize the counter property in myglobalobject.cpp

MyGlobalObject::MyGlobalObject() : m_counter(0)
{
 // perform custom initialization steps here
}

int MyGlobalObject::counter() const {
 return m_counter;
}

void MyGlobalObject::setCounter(int value) {
 if(m_counter != value) {
   m_counter = value;
 }
}

3. Similar to other properties in QML, we also want to be able to dynamically react to property changes in our QML code. In other words, we want to trigger functions in QML when the C++ property changes. Unlike the slots, which make C++ methods callable in QML, signals can be used to trigger QML code from C++. So the data flow looks like this:

C++ and QML data flow with signals and slots

Let’s add a signal counterChanged and trigger it in our setCounter implementation:

myglobalobject.h:

class MyGlobalObject : public QObject
{
//  ...

signals:
 void counterChanged();
};

myglobalobject.cpp:

void MyGlobalObject::setCounter(int value) {
 if(m_counter != value) {
   m_counter = value;
   counterChanged(); // trigger signal of counter change
 }
}

4. This simple change already allows us to add handler functions for the counterChanged() signal in QML. However, our counter property is still a normal C++ property with a getter and setter method. We can take care of that with an additional preprocessor macro:

class MyGlobalObject : public QObject
{
 Q_OBJECT
 Q_PROPERTY(int counter READ counter WRITE setCounter NOTIFY counterChanged) // this makes counter available as a QML property

// ...
};

The Q_PROPERTY macro defines a property counter and configures the methods for reading and writing the property, as well as the signal that notifies property changes. This configuration is used by QML to work with the property.

5. Let’s extend our Main.qml and use our new counter property. The following snippet adds a new button to increase the counter and a text item to display the value:

     Column {

       // ...

       // 1.2: Increasing myGlobalObject.counter property
       // NOTE: the defined setter function of the property is used automatically and triggers the counterChanged signal
       AppButton {
         text: "myGlobalObject.counter + 1"
         onClicked: {
           myGlobalObject.counter = myGlobalObject.counter + 1
         }
       }

       // 1.3: Showing myGlobalObject counter value in a QML text
       // NOTE: property bindings are supported, as the counter property definition includes the counterChanged signal, which is fired in the implementation of MyGlobalObject::setCounter() for each property change
       AppText {
         text: "Global Context Property Counter: " + myGlobalObject.counter
       }
     } // Example 1

Our property is usable like any other property in QML. Thanks to the counterChanged we prepared, the text even updates automatically every time we change the counter.

This is how the final example looks like:

Access C++ class property from QML

How to Register your C++ Class as a QML Type

The second possibility to use C++ components in QML is to register the class as a QML type. This allows to create objects (= instances) of your type directly in QML instead of C++. And the best thing is, the concepts with signals, slots and properties we used in the previous example still apply.

When to Use a Context Property and when a QML Object

If there’s only a single object instance you want to work with in QML you can add the object as a context property. When there can be multiple instances of your class, register it as a QML type and create the objects directly in QML where you need it.

1. For this example, we will create a new type we can use in QML. Let’s start with adding a new C++ Class named MyQMLType

Create a QML type with C++

2. Replace the code in myqmltype.h with this implementation:

#ifndef MYQMLTYPE_H
#define MYQMLTYPE_H

#include 

class MyQMLType : public QObject
{
 Q_OBJECT
 Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged) // this makes message available as a QML property

public:
 MyQMLType();

public slots: // slots are public methods available in QML
 int increment(int value);

signals:
 void messageChanged();

public:
 QString message() const;
 void setMessage(const QString& value);

private:
 QString m_message;

};

#endif // MYQMLTYPE_H

Similar to the previous example, this type will have one public slot and a full-featured property with a getter method, a setter method and a property changed signal. The increment method increases a given integer value by one and the message property will store a string value.

3. To complete the class, add the following code for myqmltype.cpp:

#include "myqmltype.h"

MyQMLType::MyQMLType() : m_message("")
{

}

int MyQMLType::increment(int value) {
 return value + 1;
}

QString MyQMLType::message() const {
 return m_message;
}

void MyQMLType::setMessage(const QString& value) {
 if(m_message != value) {
   m_message = value;
   messageChanged(); // trigger signal of property change
 }
}

Which Parameters Can you Pass between C++ and QML

In contrast to the previous example, our new class also uses a return value for the increment slot. No further adjustments are required to receive the return value in QML. Qt automatically maps basic C++ types to QML types for all method parameters and return values.

For more information about available Qt types and corresponding QML types, please see Data Type Conversion Between QML and C++.

Register and Use your C++ QML Type

1. In your main.cpp, first add an include statement for the new class:

#include "myqmltype.h"

2. Then use qmlRegisterType to add the class as a QML Type.

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

 // register a QML type made with C++
 qmlRegisterType("com.yourcompany.xyz", 1, 0, "MyQMLType"); // MyQMLType will be usable with: import com.yourcompany.xyz 1.0

 engine.load(QUrl(vplay.mainQmlFileName()));
 return app.exec();
}

The method takes several parameters: The module identifier and version define the required QML import to use the type. The last parameter holds the name of the QML type, which can be different from the actual C++ class name.

3. Add the import which matches the used configuration of qmlRegisterType to your Main.qml:

// NOTE: the import identifier, version and QML type name are set in main.cpp at qmlRegisterType(...)
import com.yourcompany.xyz 1.0

4. For an example usage of our new QML Type, add the following snippet below the first example:

   Page {
     title: "Integrate C++ and QML"
 
     Column {
       // ...      

     // Example 2: Custom QML Type implemented with C++
     // NOTE: This type is declared in main.cpp and available after using "import com.yourcompany.xyz 1.0"
     MyQMLType {
       id: typeFromCpp

       // 2.1: Property Binding for MyQMLType::message property
       // NOTE: Similar to types created purely with QML, you may use property bindings to keep your property values updated
       message: "counter / 2 = " + Math.floor(myGlobalObject.counter / 2)

       // 2.2: Reacting to property changes
       // NOTE: With the onMessageChanged signal, you can add code to handle property changes
       onMessageChanged: console.log("typeFromCpp message changed to '" + typeFromCpp.message+"'")

       // 2.3: Run code at creation of the QML component
       // NOTE: The Component.onCompleted signal is available for every QML item, even for items defined with C++.
       // The signal is fired when the QML Engine creates the item at runtime.
       Component.onCompleted: myGlobalObject.counter = typeFromCpp.increment(myGlobalObject.counter)
     }

     // 2.1: Show typeFromCpp.message value, which is calculated automatically based on the myGlobalObject.counter value
     AppText {
       text: "Custom QML Type Message:\n" + typeFromCpp.message
     }
   }

The code shows that we can now use MyQMLType like any other QML item. The message property is initialized inline with a property binding, that shows the integer result of dividing myGlobalObject.counter by two. Whenever the counter changes, this expression is re-evaluated automatically.

In addition, when in turn the message changes (every 2 counter steps), we use the onMessageChanged signal to display the new message in the log output.

Similar to other QML Items, the Component.onCompleted signal is available to perform initialization steps when the QML engine creates the object. In this example, we use the increment slot to increase the counter by 1.

The AppText at the bottom simply displays the message property:

cpp-qml-2-2-use-qml-type-created-with-cpp

 

Use a Property, Signal or Slot?

As we’ve already seen in the previous examples, properties, signals and slots offer different types of communication between C++ and QML:

  • Slots allow communication from QML to C++: Slots are used to trigger C++ code from QML. You can use parameters and return values to pass data to and from C++.
  • Signals allow communication from C++ to QML: Signals are used to run QML code when certain events occur C++. You can pass parameters from C++ to QML. However, you can not return data from QML.
    In contrast to slots, signals may be handled by none, one or many components. There is no guarantee that triggering a signal in C++ will actually run QML code, unless there’s a handler defined.

Properties work both ways: Properties are read- and write-able from both C++ and QML. To support property bindings in QML, make sure to add a changed-signal for the property and do not forget to trigger the signal in C++ whenever the value changes.

C++ and QML data flow with properties, signals or slots

How to Start Long-running C++ Operations from QML

The above example already fully covers slots and properties, but only uses a signal as part of the property configuration. To complete the example, let’s add a new slot startCppTask(), a new method doCppTask() and a new signal cppTaskFinished() to myqmltype.h:

public slots: 
 int increment(int value);
 void startCppTask(); // starts internal calculations of doCppTask()

signals:
 void messageChanged();
 void cppTaskFinished(); // triggered after calculations in doCppTask()

public:
 QString message() const;
 void setMessage(const QString& value);

private:
 void doCppTask(); // method for internal calculations
 QString m_message;

We will later call the slot startCppTask() from QML, which executes the internal doCppTask() method. You can e.g. run calculations in another thread at this point to avoid blocking the QML UI while performing the task. This is useful for any cpu-intense or long-lasting operation you want to handle in C++. By adding the implementation for the methods to myqmltype.cpp, we are fnished with the C++ part.

void MyQMLType::startCppTask() {
 this->doCppTask();
}

void MyQMLType::doCppTask() {
 // NOTE: you can do calculations here in another thread, this may be used to perform
 // cpu-intense operations for e.g. AI (artificial itelligence), Machine Learning or similar purposes
 // When the work is done, we can trigger the cppTaskFinished signal and react anyhwhere in C++ or QML
 cppTaskFinished();
}

As everything is prepared now, we can add another AppButton that starts our C++ task:

// 2.4: Button to start cpp task
AppButton {
  text: "typeFromCpp.startCppTask()"
  onClicked: {
      typeFromCpp.startCppTask()
  }
}

The onCppTaskFinished() signal will notify us when the C++ part has finished calculations:

MyQMLType {
  // ...

  // 2.4: Handling a custom signal
  onCppTaskFinished: {
    myGlobalObject.counter = 0 // reset counter to zero, this will also update the message
  }
}

In this example, we simply reset our global counter to zero when the signal fires, which will also update the message property of MyQMLType.

This is how the final example looks like after executing the cpp task:

Run asynchronous C++ task with QML

Note: To handle custom signals in QML when using a context property, use the Connections QML Type. The following snippet adds a handler to the counterChanged() signal of myGlobalObject:

// 2.5: Connections allow to add signal handlers for global context property objects
Connections {
    target: myGlobalObject
    onCounterChanged: console.log("Counter changed to " + myGlobalObject.counter)
}

When to Derive from QQuickItem instead of QObject

In all used examples, we created a C++ Class which extends QObject. However there are some limitations to QObjects: QObjects do not have a visual representation. This means, they can not hold any child items and properties regarding visual features like size, position, visibility are not available.

A QObject only holds data and logic you can use in QML as properties, signals and slots. When registering a QObject class as a type for QML, keep this restriction in mind. To create a QML Item with C++ which should support a visual representation with all default properties, derive from QQuickItem instead.

As this short introduction does not cover implementing QQuickItems, please see the the Qt documentation for more information. The overview page about Integrating QML and C++ is found here.

The full source code of the project created in this guide can be found on GitHub:

 

 

More Posts Like This

 

Add Chat Service and Cross-Platform Leaderboard with User Profiles to Your iOS or Android App
Add Chat Service and Cross-Platform Leaderboard with User Profiles to Your iOS or Android App

Release 2.14.1: Update to Qt 5.9.3 | Use Live Code Reloading on macOS and Linux
V-Play Update 2.12.1: Qt Quick Designer Improvements

How to Make Cross-Platform Mobile Apps with Qt – V-Play Apps

How to Make a Qt app

The post How to Expose a Qt C++ Class with Signals and Slots to QML appeared first on V-Play Engine.


The Qt Company Blog: qbs 1.12 released

$
0
0

We are happy to announce version 1.12.0 of the Qbs build tool.

What’s new?

Generating Interfaces for Qbs and pkg-config

When distributing software components such as libraries, you’d like to make it as simple as possible for other projects to make use of them. To this end, we have added two new modules: The Exporter.qbs module creates a Qbs module from a product, while the Exporter.pkgconfig module generates a .pc file.

For example:

DynamicLibrary {
    name: "mylib"
    version: "1.0"
    Depends { name: "cpp" }
    Depends { name: "Exporter.qbs" }
    Depends { name: "Exporter.pkgconfig" }
    files: "mylib.cpp"
    Group { 
        fileTagsFilter: "dynamiclibrary"
        qbs.install: true
        qbs.installDir: "lib"
    }
    Group { 
        fileTagsFilter: "Exporter.qbs.module"
        qbs.installDir: "lib/qbs/modules/mylib" 
    }
    Group {
        fileTagsFilter: "Exporter.pkgconfig.pc"
        qbs.install: true
        qbs.installDir: "lib/pkgconfig"
    }
}

When building this project, a Qbs module file mylib.qbs and a pkg-config file mylib.pc will be generated. They contain the information that is necessary to build against this library using the respective tools. The mylib.qbs file might look like this (the concrete content depends on the target platform):

Module {
    Group {
        filesAreTargets: true
        fileTags: "dynamiclibrary"
        files: "../../../libmylib.so.1.0.0"
    }
}

As you can see, the library file is specified using relative paths in order to make the installation relocatable.

Now anyone who wants to make use of the mylib library in their Qbs project can simply do so by declaring a dependency on it: Depends { name: "mylib" }.

System-level Settings

Until now, Qbs settings were always per-user. However, some settings should be shared between all users, for instance global search paths. Therefore, Qbs now supports system-level settings as well. These are considered in addition to the user-level ones, which take precedence in the case of conflicts. System-level settings can be written using the new --system option of the qbs-config tool. This operation usually requires administrator rights.

Language Improvements

We have added a new property type varList for lists of objects. You could already have those by using var properties, but the new type has proper list semantics, that is, values from different modules accumulate.

The FileInfo extension has two new functions suffix and completeSuffix.

Two changes have been done to the Rule item:

C/C++ Support

The cLanguageVersion and cxxLanguageVersion properties are now arrays. If they contain more than one value, then the one corresponding to the highest version of the respective language standard is chosen. This allows different modules to declare different minimum requirements.

Autotest Support

The AutotestRunner item has a new property auxiliaryInputs that can help ensuring that additional resources needed for autotest execution (such as helper applications) are built before the autotests run.

The working directory of an autotest is now the directory in which the respective test executable is located or AutotestRunner.workingDirectory, if it is specified. In the future, it will also be possible to set this directory per test executable.

Various things

All command descriptions now list the product name to which the generated artifact belongs. This is particularly helpful for larger projects where several products contain files of the same name, or even use the same source file.

The vcs module no longer requires a repository to create the header file. If the project is not in a repository, then the VCS_REPO_STATE macro will evaluate to a placeholder string.

It is now possible to generate Makefiles from Qbs projects. While it is unlikely that complex Qbs projects are completely representable in the Makefile format, this feature might still be helpful for debugging purposes.

Try It!

The Open Source version is available on the download page, and you can find commercially licensed packages on the Qt Account Portal. Please post issues in our bug tracker. You can also find us on IRC in #qbs on chat.freenode.net, and on the mailing list. The documentation and wiki are also good places to get started.

Qbs is also available on a number of packaging systems (Chocolatey, MacPorts, Homebrew) and updated on each release by the Qbs development team. It can also be installed through the native package management system on a number of Linux distributions including but not limited to Debian, Ubuntu, Fedora, and Arch Linux.

Qbs 1.12.0 is also included in Qt Creator 4.7.0, which was released this week as well.

The post qbs 1.12 released appeared first on Qt Blog.

KDAB on Qt: The LiMux desktop and the City of Munich

$
0
0

There has been a lot of back and forth around the use of Free Software in public administration. One of the latest initiatives in this area was started by the Free Software Foundation Europe, FSFE. It focuses on the slogan: Public Money – Public Code. There are various usage scenarios for Free Software in public administration. The span ranges from the use of backend technology over user-facing software, e.g. LibreOffice, up to providing a whole free desktop for the administrative staff in a public service entity such as a city council. In this article we will focus on the latter.

When the desktops in an administration are migrated to Linux, the administration becomes a distribution provider. An example for this is the LiMux desktop, that powers the administration of the city of Munich since 2012.

LiMux is a distribution, maintained by the central IT department of the City of Munich. Technically, it builds upon Kubuntu. It provides specific patches, a modified user experience and an automatic distribution system, so all desktops in all departments of the city can be easily administered and offer a consistent user experience.

Distributions in the Free Software ecosystem have different roles, one of them surely being the provider of the finishing touches, especially to important software for its own users. Obviously public administration has special demands. Workflows and documents for example have a totally different importance than for the average Kubuntu user.

In Munich for example, architects in one department complained that Okular, the LiMux and KDE pdf reader, would freeze when they tried to open large construction plans. When the city investigated this issue further, they found out that actually Okular wouldn’t freeze, but loading these large maps would simply occupy Okular for quite a while, making the user think it crashed.

Naturally the City of Munich wanted this issue fixed. But this use case is rather rare for the voluntary Free Software Developer, as only few user groups, like architects, are actually in the situation of having to deal with such large files, so it was unlikely that this bug would be fixed on a voluntary basis.

Since the city does not have enough developer power to fix all such issues themselves, they looked to KDAB for external support. With our KDE and Qt expertise, we were well-positioned to help. Together we identified that, instead of the suggested busy indicator for Okular the City of Munich wanted, progressive loading would be an even better solution. It allows the user to visually follow the loading process and makes it possible for the user to interact with large files as early as possible. And as the City does not want to maintain a patch that fixes this issue for them locally, we also helped them to get all the patches upstream.

This way all efforts are made available for the architects at the City of Munich and also for the general public. In the same spirit we have fixed numerous issues for the City of Munich all around KDE and Qt. As another example: we brought back extended settings to the Qt print dialogue. This allows the City of Munich to make use of all of the functionalities of their high-tech printer, like sorting, stapling and so on. You can read more about KDAB’s work on this here.

Becoming a distribution implies a lot of responsibility for a public administration and KDAB is proud to offer reliable backup for any administration that decides to follow the Linux, Qt and KDE path.

 

Afternote: Recent developments mean that the City has decided to revert the migration back to Microsoft by 2020. The good news is that most changes and adjustments they have made are available upstream and other administrations can build their own solutions upon them.

 

The post The LiMux desktop and the City of Munich appeared first on KDAB.

KDAB on Qt: What a mesh!

$
0
0

With all the advances being made in Qt 3D, we wanted to create some new examples showing some of what it can do. To get us started, we decided to use an existing learning framework, so we followed the open source Tower Defence course, which you can find at CGCookie. Being a game, it allows an interactive view of everything at work, which is very useful.

We found it to be so diverse, that we are now implementing Parts 2 and 3 of the game into Qt 3D. However you don’t have to wait for that, you can start now by following the steps we took.

The setup

These instructions will help you setup for Qt 5.11.0 .

To start, turn to your QtCreator and create a new Qt Console Application, set to run on your Qt 5.11.0 kit.

A Qt Console Application doesn’t come with too much ‘plumbing’. A lot of the other options will attempt to give you starting files that aren’t required or in some cases, the wrong type entirely.

Let’s edit it to fit our needs by opening up the .pro file and adding the following:

First remove the QT += core and QT -= gui lines if they are present.

QT += 3dcore 3drender 3dinput 3dquick 3dquickextras qml quick

Then, if the lines CONFIG += c++11 console and CONFIG -= app_bundle are present, remove them too. Now back on the main.cpp file we need to edit our “includes” from the Qt 3D library.

Replace the #include QCoreApplication with #include QGuiApplication and add these lines:

#include 
#include 
#include 

Within the main block we now have to edit QCoreApplication a(argc, argv); to mirror our include change. So change it to:

QGuiApplication a(argc, argv);

Before the first build / run we should add something to look at. Adding the following block of code before the return statement will provide us with a window:

Qt3DExtras::Quick::Qt3DQuickWindow view;
view.setSource(QUrl("qrc:/main.qml"));
view.show();

Commenting out the line referring to main.qml will allow you to build and run what you have already. If everything has gone to plan, you will get a white window appear. Now you can uncomment the line and continue onwards!

QRC creation

Okay, let’s get rid of the boring white scene and get something in there. Right-click the ‘Sources’ folder and select ‘Add New…’. From here select the Qt > QML File (Qt Quick 2) option. We’ve gone and named it main so that after clicking next till the end you should now have a main.qml and a main.cpp.

This QML file is now going to hold our scene, but to do that we need some resources. We will achieve this by adding a Qt Resource File, just as we did for main.qml – assuming you have an obj with accompanying textures placed in an assets folder within the project.

So this time right-click on the project folder and select ‘Add New…’. From the Qt menu, select ‘Qt Resource File’ and name it something fitting. When this opens it will look noticeably different to the qml and cpp files. At the bottom you will see the self-descriptive; Add, Remove and Remove Missing Files buttons. Click the ‘Add’ button and select ‘Add Prefix’. Now remove everything from the Prefix: text input just leaving the ‘/‘. Click the ‘Add’ button again, this time selecting the ‘Add Files’ option.

Navigate to your obj and texture files and add them all to the qrc, save and close it. If everything went to plan, a ‘Resources’ folder will now be visible in the Projects window on the left.

Follow this again and add main.qml to the qrc in the same way.

One last thing we need before playing with the scene is a skymap. With the files placed in your assets folder, go ahead and add the skymap to the qrc file.

Gotcha

We use three dds files for our skymaps, irradiance, radiance and specular. If you are trying this on a Mac, you will have to uncompress them or they will not work. Keep the names similar to their compressed version. For example we simply added ‘-16f’ to the filename. So our files would be ‘wobbly_bridge_4k_cube_irradiance’ vs ‘wobbly_bridge_4k-16f_cube_irradiance’ respectively.

The necessities

Back to the QML file now, rename the Item { } to be an Entity { } and give it the id: scene. Entity is not recognised because we are missing some imports. Hitting F1 with Entity selected shows us that we need to import Qt3D.Core 2.0, so add this to the imports at the top of the file.

There are certain components that a 3D scene must have, a camera and Render settings being two of those. For this example, we’ll throw in a camera controller too so we can move around the scene.

components: [
    RenderSettings {
        activeFrameGraph: ForwardRenderer {
            camera: mainCamera
            clearColor: Qt.rgba(0.1, 0.1, 0.1, 1.0)
        }
    },
    // Event Source will be set by the Qt3DQuickWindow
    InputSettings { }
]

Camera {
    id: mainCamera
    position: Qt.vector3d(30, 30, 30)
    viewCenter: Qt.vector3d(0, 0, 0)
}

FirstPersonCameraController {
    camera: mainCamera
    linearSpeed: 10
    lookSpeed: 50
}

Here we see that Camera is not recognised, so let’s get the missing import.

Gotcha

If you select Camera and hit F1 to find the import, you will in fact be shown the import for the non-Qt3D Camera. The one you will want is: import Qt3D.Render 2.9

The sky is the limit

Let’s put that skymap to use now. Back in the main.cpp file, we need to add code to check if we’re on MAC or not. If you remember, this was due to MAC not supporting compressed files and needing its own versions. After the QGuiApplication line, put in the following:

#if defined(Q_OS_MAC)
    const QString envmapFormat = QLatin1String("-16f");
#else
    const QString envmapFormat = QLatin1String("");
#endif

Then after the Qt3DExtras line, add the following:

auto context = view.engine()->qmlEngine()->rootContext();
context->setContextProperty(QLatin1String("_envmapFormat"), envmapFormat);

If you try to build at this point, you will notice various imports missing. One for FirstPersonCameraController, one for InputSettings and TexturedMetalRoughtMaterial. Hitting F1 on FirstPersonCameraController will give you import Qt3D.Extras 2.0 and F1 on InputSettings will give you import Qt3D.Input 2.0 but then later you’ll hit a snag. TexturedMetalRoughtMaterial may not turn up any documentation but we’ll be kind enough to give you the answer… edit the Qt3D.Extras 2.0 to be 2.9 instead. If this now works you will get a dark grey window.

Barrel of laughs

The final part will be our mesh, we chose a barrel, and the skymap for it to reflect (although this might not be visible).

In main.qml after the InputSettings{}, throw in the following:

EnvironmentLight {
    id: envLight
    irradiance: TextureLoader {
        source: "qrc:/path/to/your/file" + _envmapFormat + "_cube_irradiance.dds"

        minificationFilter: Texture.LinearMipMapLinear
        magnificationFilter: Texture.Linear
        wrapMode {
            x: WrapMode.ClampToEdge
            y: WrapMode.ClampToEdge
        }
        generateMipMaps: false
    }
    specular: TextureLoader {
        source: "qrc:/path/to/your/file" + _envmapFormat + "_cube_specular.dds"
                
        minificationFilter: Texture.LinearMipMapLinear
        magnificationFilter: Texture.Linear
        wrapMode {
            x: WrapMode.ClampToEdge
            y: WrapMode.ClampToEdge
        }
        generateMipMaps: false
    }
}

You can hit build now to check it’s working, but the scene will still be pretty boring. Throw in your obj to get some eye candy. Here is the code we used after EnvironmentLight:

Mesh {
    source: "qrc:/your/model.obj"
},
Transform {
    translation: Qt.vector3d(4, 0, 2)
},
TexturedMetalRoughMaterial {
    baseColor: TextureLoader {
        format: Texture.SRGB8_Alpha8
        source: "qrc:/path/to/your/Base_Color.png"
    }
    metalness: TextureLoader { source: "qrc:/path/to/your/Metallic.png" }
    roughness: TextureLoader { source: "qrc:/path/to/your/Roughness.png" }
    normal: TextureLoader { source: "qrc:/path/to/your/Normal_OpenGL.png" }
    ambientOcclusion: TextureLoader { source: "qrc:/path/to/your/Mixed_AO.png" }
}

Finally, hit build and then run.

Rendered Barrel

The barrel viewed at the end of What A Mesh pt1

The post What a mesh! appeared first on KDAB.

KDAB on Qt: KDAB at Italian C++, Milan

$
0
0

KDAB was sponsor of this annual C++ event run by the C++ Community for the C++ Community in Italy, which was founded some five years ago and is growing fast.

our-roll-upAround 200 people showed up for “++ it”, 50 more than last year, and were treated to an excellent program.

There was a mix of talks in either English or Italian, including ‘Debug C++ Without Running‘ by Anastasia Kazakova, ‘C++ Barbarian Quiz & Introduction to Conan C/C++ Package Manager‘ from Diego Rodriguez-Losada Gonzalez and one from Vittorio Romeo on ‘Zero-allocation & no type erasure futures‘, all of which KDAB particularly enjoyed.

You can see the full program and a post-event report here.

 

 

The post KDAB at Italian C++, Milan appeared first on KDAB.

KDAB on Qt: Python – Tron Demo

$
0
0

For SIGGRAPH, KDAB has been working on a new Qt 3D based demo. We decided that instead of using C++, it would be interesting to try out PySide2 and harness Python to drive the application.

The idea behind this demo is to do with data acquisition of a car’s surrounding environment. Once the data is acquired it can be processed and used to display a 3D scene.

The application is structured in two main parts. On the one hand, we use QtQuick and the Qt 3D QML API to declare the UI and instantiate the 3D scene. On the other hand we use Python for the backend logic, data processing and models and definition of the custom Qt 3D meshes elements we’ll need to use in the UI.

Simulating Data Acquisition

Since this is a demo, we simulate the data that we acquire rather than rely on real data acquisition through sensors.

We simulate only two things:

  • Car position and orientation
  • Road lines

The information for these is obtained by looping around a generated set of road sections.

To define a fake road track, we’ve used cubic bezier curves, each bezier curve defining a road section.

A cubic bezier curve is defined as 2 end points + 2 control points. This allows for a rather compact description of the road section we want our car to travel on.

 

Going from one curve to a full road track

 

Using this tool, we generated the bezier curves with these values:

bezier_curves = [
    [(318, 84), (479, 18), (470, 233), (472, 257)],
    [(472, 257), (473, 272), (494, 459), (419, 426)],
    [(419, 426), (397, 417), (354, 390), (324, 396)],
    [(324, 396), (309, 399), (217, 416), (202, 415)],
    [(202, 415), (157, 412), (116, 278), (114, 263)],
    [(114, 263), (119, 219), (151, 190), (182, 192)],
    [(182, 192), (277, 192), (216, 128), (318, 84)]
]

Notice how each bezier curve starts at the position of the last point of the previous curve. That’s because we want no discontinuation between our road sections.

On each curve, we sample 250 subdivisions to generate raw position data. Given we have 7 curves, that gives us a total of 1750 positions.

In real life our car is only aware of the immediately surrounding environment. In our case, we’ve decided that would be about 100 positions in front of the car and 50 positions at the rear.

Every 16ms, we increase a global index (which goes from 0 to 1750) and select 150 entries starting at our index. From these 150 positions we extrude 4 lines (to make 3 road lanes).

The 50th entry we’ve selected is where we assume our car is.

  • Road section start is positions[0]
  • Road section end is positions[149]
  • Car position is positions[50]

 

Making our track visible through the camera

 

In the 3D view we assume the car is placed in (0, 0, 0). The camera is placed slightly being the car, its view center being the car. So if positions[49] is where our car actually is in the real world, we actually need to translate back all our positions to minus positions[49]. We also want our car and our camera to rotate as we are going along curves. For that we know that our camera is looking toward -Z (0, 0, -1). We can compute a vector u (car position – road section start) and then find the angle between u and -z using the dot product.

 

In code this translates to simply creating a transform matrix:

road_start_position = self.m_points_at_position[0]
screen_origin_position = self.m_points_at_position[50]

def compute_angle_between_road_section_and_z():
    # We want to look toward -Z
    target_dir = QVector3D(0.0, 0.0, -1.0)
    # Our current dir
    current_dir = (screen_origin_position - road_start_position).normalized()
    # Angle between our two vectors is acos(dot, current_dir, target_dir)
    dot = QVector3D.dotProduct(target_dir, current_dir)
    return acos(dot)

rot_angle = compute_angle_between_road_section_and_z()
self.m_road_to_world_matrix = QMatrix4x4()
# Rotate of rot_angle around +Y
self.m_road_to_world_matrix.rotate(degrees(rot_angle), QVector3D(0.0, 1.0, 0.0))
# Translate points back to origin
self.m_road_to_world_matrix.translate(-screen_origin_position)

 

Then, it’s just a matter of transforming all these positions using the transformation matrix.

3D Rendering

Drawing the road

 

To render the road lines, we have created a new Qt 3D QGeometry subclass.

The python backend generates new buffer data for the road every frame, based on the 150 transformed positions that have been computed. Basically for each 2 positions, a quad made up of 2 triangles is generated to make up one part of a road line. This process is repeated 4 times with an offset on the x-axis for each road line. In turn, this is repeated 150 times so that we have quads for each position and for each line to make up our 3 road lanes.

We just upload these buffers to the GPU by using a Qt 3D QBuffer and setting its data property.

from PySide2.QtCore import Property, Signal, QByteArray
from PySide2.Qt3DCore import Qt3DCore
from PySide2.Qt3DRender import Qt3DRender
from array import array

class RoadLineGeometry(Qt3DRender.QGeometry):

    def __init__(self, parent=None):
        Qt3DRender.QGeometry.__init__(self, parent)
        self.m_position_buffer = Qt3DRender.QBuffer(self)
        self.m_position_buffer.setUsage(Qt3DRender.QBuffer.StaticDraw)

        self.m_position_attribute = Qt3DRender.QAttribute(self)
        self.m_position_attribute.setAttributeType(Qt3DRender.QAttribute.VertexAttribute)
        self.m_position_attribute.setDataType(Qt3DRender.QAttribute.Float)
        self.m_position_attribute.setDataSize(3)
        self.m_position_attribute.setName(Qt3DRender.QAttribute.defaultPositionAttributeName())
        self.m_position_attribute.setBuffer(self.m_position_buffer)

        self.addAttribute(self.m_position_attribute)

    def update(self, data, width):
        # Data is a QByteArray of floats as vec3
        float_data = array('f', data.data())
        transformed_point = [v for i in range(0, len(float_data), 3)
                             for v in [float_data[i] - width / 2.0, 0.0, float_data[i + 2],
                                       float_data[i] + width / 2.0, 0.0, float_data[i + 2]]]
        self.m_position_buffer.setData(QByteArray(array('f', transformed_point).tobytes()))
        self.m_position_attribute.setCount(len(transformed_point) / 3)

Note: in Python the QGeometry::geometryFactory API is unavailable, meaning that we need to update directly our QBuffer data in the frontend.

Drawing the car

 

As for the car, it is a .obj model we load and then scale and rotate with a transformation matrix. The scale and rotations are updated as we move through the track so that the car always aligns with the road.

To load the geometry, a custom .obj loader was written. Regular wireframing techniques usually display triangles if the mesh was exported as triangles (which was the case for us). Our custom loader works around that by analyzing faces described in the .obj file and generating lines to match the faces (we have square faces in our case).

In addition, the car uses a special FrameGraph. I won’t highlight it in details but instead just give you a rough idea of what it does:

  1.  A first pass is rendered into a texture.
  2. A loop is made
    1. An input texture is then used as a base for a multi pass gaussian blur.
    2. The fragment color is summed up with the previous blur output which ends up creating a Bloom Effect.
    3. input texture for next pass = output texture of this pass

The Tron-like appearance is simply a result of this FrameGraph Bloom effect.

What about PySide2 and Qt 3D?

Using Python and PySide2 instead of C++ to create a Qt3D based application has quite a few advantages but also a couple of disadvantages:

  • Pros:
    • You can leverage 90% of the C++ API through the Python bindings
    • You can still use QML for the UI
    • A lot of C++ boilerplate is avoided, prototyping faster
    • Deployment is easy on desktop (pip install pyside2)
  • Cons
    • Qt 3D documentation for the Python is still lacking, tricky to find how to import the namespaces
    • Conversion of some Qt types to Python types is tricky (QByteArray, QVector…)
    • Deployment is hard on embedded (no arm pyside2 pip release yet)
    • Some odd behaviors and queue invocations (variable having to be printed for some changes to be take into account).

 

Overall it was an enjoyable experience and with the bindings, Python is a real alternative to C++ for most of what regular users might wish to do with Qt 3D.

The post Python – Tron Demo appeared first on KDAB.

Viewing all 15410 articles
Browse latest View live