Saturday, December 27, 2014

Showing Remote Image using ImageView in BB10 Cascades

While working on my BB10 App update, I required to show Remote Image using ImageView BB10 cascades API. ImageView or Image component by default does not support loading image from URL on internet. I implemented a custom component which serve the purpose and also easily integrated with ImageView.

Following is implementation for the same, I hope it will be useful to someone.

Let's start by showing how my custom component works. Following code shows how to use ImageDownloader custom component along with ImageView to display Grid of images from internet. Data Model contains two kind of URL, url for low resolution image and url for high resolution image.
import my.library 1.0

ListView {
  id: listView
  
  layout: GridListLayout {}
  dataModel: model;
  
  listItemComponents: [
      ListItemComponent {                        
          ImageView {
              id: imgView
              imageSource: "default_image.jpg"  
                                        
              attachedObjects: [
                  ImageDownloader {
                      id: imageLoader
                      url: ListItemData.mediumImage
                      onImageChanged: {                 
                          if (imageLoader.isVaid) {
                              imgView.image = imageLoader.image
                          }
                      }
                  }
              ]
          }
      }
  ]
}
ImageDownloader component is available in QML because we imported "my.library". We can make any C++ code available to QML by registering it to QML System, folloiwing snippet shows how we can register C++ component to QML system.

#include "ImageDownloader.h"

int main(int argc, char **argv) 
{
 Application app(argc, argv);

 qmlRegisterType<ImageDownloader>("my.library",1, 0, "ImageDownloader");

 QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(&app);

 AbstractPane *root = qml->createRootObject();
 app.setScene(root);

 return Application::exec();
}
Now that custom component is ready to be used with QML, let's see how its implemented. Below if header file for ImageDownloader class. We are defining few properties like url, image and isValid. By setting "url" we can initiate download of image, when "image" download is finished downloaded image can be accessed by using "image" property. We can check if image is valid or not by checking "isValid" property. we are also defining few signal like "urlChanged" and "imageChanged", which are emited when url is changed or image is downloaded. And we are using QNetworkAccessManager to download image from internet.
#ifndef IMAGEDOWNLOADER_H_
#define IMAGEDOWNLOADER_H_

#include 
#include 

class QNetworkAccessManager;

class ImageDownloader: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QVariant image READ image NOTIFY imageChanged)
    Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
    Q_PROPERTY(bool isVaid READ isValid CONSTANT);
public:
    ImageDownloader( QObject* parent = 0);
    virtual ~ImageDownloader();

signals:
    void urlChanged();
    void imageChanged();

private slots:
    QString url() const;
    void setUrl( const QString& url);

    QVariant image() const;
    bool isValid() const;

    void startDownload();
    void onReplyFinished();

private:
    QNetworkAccessManager mNetManager;
    QString mImageUrl;
    bb::cascades::Image mImage;
    bool mIsValid;
};

#endif /* IMAGEDOWNLOADER_H_ */
Implementation is also quite simple, let's see how its implemented. On URL change, we are initiating the image download using QNetworkAccessManager. When download is finished, we are reading image data in to buffer and creating Image using BB10 Image API.
#include "ImageDownloader.h"

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

ImageDownloader::ImageDownloader(QObject* parent):
    QObject(parent), mIsValid(false) {}

ImageDownloader::~ImageDownloader() {}

QString ImageDownloader::url() const {
    return mImageUrl;
}

void ImageDownloader::setUrl( const QString& url)
{
    if(url != mImageUrl) {
        mImageUrl = url;
        mIsValid = false;
        mImage = bb::cascades::Image();
        emit urlChanged();
        emit imageChanged();
        startDownload();
    }
}

QVariant ImageDownloader::image() const {
    return QVariant::fromValue(mImage);
}

bool ImageDownloader::isValid() const {
    return mIsValid;
}

void ImageDownloader::startDownload() {
    QNetworkRequest request(mImageUrl);
    QNetworkReply* reply = mNetManager.get(request);
    connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished()));
}

void ImageDownloader::onReplyFinished() {
    QNetworkReply* reply = qobject_cast(sender());
    QString response;
    if (reply) {
        if (reply->error() == QNetworkReply::NoError) {
            const int available = reply->bytesAvailable();
            if (available > 0) {
                const QByteArray data(reply->readAll());
                mImage = bb::cascades::Image(data);
                mIsValid = true;
                emit imageChanged();
            }
        }
        reply->deleteLater();
    }
}
That's all we have to do to do display remote image in BB10, hope you liked it.

Saturday, December 20, 2014

Resolving "_clock$UNIX2003", referenced from" error

I was trying to build Unity 3D project for simulator SDK. I wanted to get different screen size screen shot. But when I tried to build it I got following build error.
_clock$UNIX2003", referenced from
I found one work around to resolve this issue. We need to add following patch to main.mm file.
#include <time.h>

// "_clock$UNIX2003", referenced from:
//Temporary hack for building Simulator Project for Unity
extern "C"
{
    clock_t
    clock$UNIX2003(void)
    {
        return clock();
    }
}
Once I added above patch build started working fine for me and I was able to run project on Simulator.

Sunday, November 23, 2014

Your Shot Ubuntu Touch Scope

You might have heard about Ubuntu Touch, and one of unique feature of Ubuntu Touch is Scope. Recently they also announced Ubuntu Touch Scope competition. This got me interested, I wanted to learn about Scope development, so I thought to take part as well in the competition.

You can get more information about competition here.

Recently I discovered Your Shot photo community, I like pictures uploaded there and I visit site every day to checkout newly updated photos, so I thought it is good candidate for Scope development and I decided to write score for Your Shot photo community.

Your Shot has nice Jason based web API and I was able to create scope quite easily using Ubuntu Touch socpe's Jason template. In fact I was able to get decent working scope in few hours using template. Documentation is also quite good and rich with API Reference, Guide and Tutorials.

Here is demo for the same running on my desktop.


And Few snapshot.





It looks like now I am ready to write more complex Scope but may be later.

Thursday, October 30, 2014

Creating dynamic QML object asynchronously

We can create QML object dynamically by using createComponent and createObject API.

Like follow,
var component = Qt.createComponent("Button.qml");
if (component.status == Component.Ready)
    component.createObject(parent, {"x": 100, "y": 100});
You can find more information regarding same here.

Latest Qt release added new API named incubateObject. This allows object to be created in asynchronously. You can find more information about this API here.

Following code I written for Ubuntu touch calendar application, which uses the same. Here thing to remember is that incubateObject returns the incubator and not created object itself. You need to get object from incubator by incubator.object call.
var incubator = delegate.incubateObject(bubbleOverLay);
if (incubator.status !== Component.Ready) {
    incubator.onStatusChanged = function(status) {
        if (status === Component.Ready) {
            incubator.object.objectName = children.length;
            assignBubbleProperties( incubator.object, event);
        }
    }
} else {
    incubator.object.objectName = children.length;
    assignBubbleProperties(incubator.object, event);
}

Saturday, September 13, 2014

Creating array of IBOutlet

Sometimes you want to enable/disable bunch of buttons together or perform other such activities on bunch of UI elements created using Interface Builder.

I recently needed to perform similar operation on bunch of button for iOS game I am working on. For this kind of operation, its easier to create array of IBOutlet which can be created using IBOutletCollection. Following is my code, which create IBOutletCollection of UIButtons and then enable/disbale them together.
@interface MyViewController : UIViewController {
    IBOutletCollection(UIButton) NSArray *buttons;
}
in MyViewController.m, we can use buttons as below.
-(void) enableUI:(BOOL) enable {    
    for( UIButton* button in buttons){
        button.enabled = enable;
    }    
}
Only thing missing now is, connecting UIButtons created using Interface Builder to IBoutletCollection. We need to do this from Interface Builder, process is similar to connecting UI Elements from Interface Builder to IBOutlet.

Following snaps describes the required process. I created three buttons on view.


You can connect IBoutletCollection to UIButton as shown in below snap.


And you can repeat above process to connect more UIButton with IBOutletCollection.

That's it.

Wednesday, September 10, 2014

Matching custom NSObject with isEqual and hash

While working on one multiplayer game for iOS using GameKit, I faced issue while comparing object.

For single player version I was not facing this issue but while running multiplayer version I was facing this issue. After debugging a little I realised condition for comparing object's value is failing and it turned out that I was comparing object's address rather then its value. As for Multiplayer game I was creating object using data from server/host, I needed to compare object's value and not its address.

For objectiveC, if you want to compare object's value using "==" operator, you need to overload isEqual and hash method as shown like below.

-(BOOL)isEqual:(id) other {
    if (other == self)
        return YES;
    
    if (!other || ![other isKindOfClass:[self class]])
        return NO;
    
    Card* otherCard = other;
    return ( mSuit == otherCard.mSuit && mRank == otherCard.mRank);
}

- (NSUInteger)hash {
    NSUInteger hash = 0;
    hash += [[NSNumber numberWithInt:mSuit] hash];
    hash += [[NSNumber numberWithInt:mRank] hash];
    return hash;
}
Note that you need to overload both method together, overloading only one will not work. Once I overloaded above method my multiplayer version started working as normal.

Friday, July 4, 2014

Creating simple fade animation with Unity3D

I recently used fade animation or opacity animation with one of my Unity game, it was used to fade then earned points during game play. Initially I struggled a bit to achieve opacity animation due to confusion between using Animation or Animator. Look like from Unity version 4.3 we need to use Animator to animate the properties. I was trying to use Animation instead of Animator, was not able to perform opacity animation properly.
In this post I will show, how I accomplished the Fading animation. below is video of final effect and whole process to achieve animation.
First create a initial setup of scene. Following is how my scene looks like.

I wanted to add fading effect to 3D text, which signifies the points earned during game play. Now scene looks like below.

Now we need to add animator component to text.

Now, that we have added animator, we can go to Animation windows and setup our first key.

First key is from where our animation will start, we need to setup second key where animation will end. Create a second key at desired location and move text at appropriate location.

I also wanted to animate opacity with size and location. So lets add new curve for color animation.

Setup the opacity value for color curve for both first key and second key. Following is how my keys looks like.


Now if you press play button or play animation you will be able to see fade animation. Thanks for reading my blog.

Creating global variable in Unity3D

Sometime you want to create Global object that you can access from whole project. Recently while working on my unity game, I also needed the same.

While method is quite simple to achieve the same, but its quite confusing if you are just started with Unity3D just like me. Finally I now understand the process, and in this post I am describing how we can create global variable with Unity3D.

In Unity we work with Scene and when scene is unloaded all its objects are unloaded as well. To make global variable, we need to create a game object in first scene and attach a script to it which prevent it from unloading when scene is unloaded. Now we can access this game object from newly loaded scene and other scenes as well.

Let's start with simple project and create a scene, I called this scene as first scene.

Now we need to create a empty object which we treat as a global gameobject. This object will not be destroyed when first scene is unloaded.


To preserve this gameobject when First scene is unloading, we need to attach a script, I named it MakeGlobal and added following code to it.


using UnityEngine;
using System.Collections;

public class MakeGlobal : MonoBehaviour {
 void Awake () {
  DontDestroyOnLoad (transform.gameObject);
 }
}
By using DontDestroyOnLoad, we ask Unity engine not to destroy this gameobject when its scene is getting unloaded, now we can assign a new script to this global gameobject, which holds global variables.


This script is simple, it just holds a variable which can be accessed from any scene by any game object.

using UnityEngine;
using System.Collections;

public class GlobalVariables : MonoBehaviour {
 public string globalVar;
}

Now we have a GameObject which we can treat as a Global Object and it has a script which holds global variables. But till now we have not used it. To use it we can assign a script to Background element and that assign some value to globalVar variable.



using UnityEngine;
using System.Collections;

public class background : MonoBehaviour {
 // Use this for initialization
 void Start () {
  GameObject globalGO = GameObject.Find("global_gameObject");
  GlobalVariables globalVars  = globalGO.GetComponent();
  globalVars.globalVar = "String from 1st Scene";
 }
}

Now our global variable has value which is assigned by script attached to background object. To see its value on screen I created a 3D Text Object and assigned a simple script which update text object's text to global variable.

using UnityEngine;
using System.Collections;

public class TextUpdate : MonoBehaviour {
 // Update is called once per frame
 void Update () {
  GameObject globalGO = GameObject.Find("global_gameObject");
  GlobalVariables globalVars  = globalGO.GetComponent();
  gameObject.GetComponent ().text = globalVars.globalVar;
 }
}

Now if you run first scene, you can see text is displaying global variables value.



To test if global variable really retaining its value, we should create another scene and destroy first scene. So I created a another scene, which has 3D text object which displays global variables value, using the same TextUpdate script. You will can see it still preservs value from first scene and we can use global variable in second scene as well.


That's all, Thanks for reading my blog.

Saturday, June 28, 2014

Resolving Folder reading issue from SD Card in BB10

There was a tricky bug in Audiobook Reader BB10 version for quite a some time which I was trying to resolve. Issue was that, for some folder in SD card, I was not able to browse it using QDir Qt API or Posix API. Though API was showing the folder, but when I try to find out folder's content, it reports folder as empty.

This was causing serious usability issue with Audiobook Reader application, as user were not able to add book from SD card. I debugged it long and tried to use various approach to resolve the issue but could not find any satisfactory solution.

I read it somewhere it causes issue if SD card was formatted with PC software and issue is resolved if you format SD card with BB10 setting. But this also looks hassle to user.

Finally, I decided to see how directory structure looks like and what is folders permission using SSH to device. When I used linux command like ls and cd, I was able to see folder's content fine. And I decide to use those command to resolve directory browsing issue.

Following is my code, if someone else is also facing similar issue. First I am escaping special character in filepath, else linux command will not work. Then I am creating "ls" command with sorting and with output which list directory content in absolute file path. Once we have proper command I am using popen API to run command and then using IO api to read command's output.
QStringList BookListModel::getFileList(const QString& dir) {

 QString filePath(dir);
 filePath.replace(" ","\\ ");
 filePath.replace("'","\\'");
 filePath.replace("`","\\`");
 filePath.replace("!","\\!");
 filePath.replace("$","\\$");
 filePath.replace("&","\\&");
 filePath.replace("*","\\*");
 filePath.replace("\"","\\\"");
 filePath.replace("(","\\(");
 filePath.replace(")","\\)");
 filePath.replace("[","\\[");
 filePath.replace("]","\\]");

 qDebug() << filePath;
 QString cmd = QString("ls -1 %1/*").arg(filePath);
 qDebug() << cmd;

 QStringList files;
 char path[1035];
 FILE* fp = popen(cmd.toStdString().c_str(), "r");
 if (fp == NULL) {
  qDebug() << "Failed to run command";
  return files;
 }

 while (fgets(path, sizeof(path)-1, fp) != NULL) {
  QString file = QString(path).trimmed();
  QFileInfo fileInfo(file);
  if (fileInfo.isFile() && FileModel::isSupportedMedia(fileInfo.fileName()) ){
   files << file;
  }
 }

 qDebug() << files;

 pclose(fp);
}
That's all, hope it will be helpful to someone.

Thursday, June 26, 2014

Audiobook Reader for BB10 now got Built for Blackberry status

Recently I upgraded my Audiobook Reader application pro version for BB10.

This version contains many UI related changes and now it is more aligned to Blackberry design guideline and now it is also awarded Built for Blackberry status.

Apart form UI related changes, this version contains two major changes.

Now it Book auto pauses in case it detect phone call activity.

And there was a very critical bug in application which prevents book to be added from SD card. Though issue was related to BB10 OS, I found one work around and now adding books from SD card works as expected.

Full list of features in current version is as below.
  • Allows adding single file or whole folder with book audio data
  • Supports adding custom bookmark
  • Supports browsing mp3 chapter files and play selected mp3 chapter file
  • Supports chapter skip
  • Supports 2 min, 1 min, 30 sec skip option
  • Supports auto pause on call
  • Supports Play/Pause using HW buttons
  • Supports custom cover art download
  • Advance file browser
  • Supports sleep timer
  • Supports shuffle
  • and some more...
Following is demo for current version.


Hope you will like the updates.

Thursday, June 12, 2014

Using WorkerScript from QML

As you might know, I am contributing to Ubuntu Touch Calendar core application. Those application are pure QML application with no C++ backend or we aim to avoid it as much as possible. This is done to make sure application are portable across device.

For simple use-case you can just use javascript code as backend logic and it should work fine without any problem. but if you need to some intensive calculation in application then its better to move those calculation to WorkerScript.

While working on one calendar feature, Calculating layout for overlapping events, I also needed to use WorkerScript. But one major problem with WorkerScript is that, it does not have access to QML Engine. So you will not be able to send your Declarative object to worker script to offload intensive task to threads.

In calendar application I am getting Events declarative object from model and I needed to process events time to decide position and size of events in view.

As such I can not send those Events to WorkerScript, but to overcome that limitation, I created temporary Javascript object which has required data like start time, end time and id, which I can use to decide position, size and Id can be used to map temp object to original object from model and rest of logic then can be implemented in WorkerScript.

Code wise using WorkerScript is quite easy. Following code creates WorkerScript object and sends array of events to script.
    WorkerScript {
        id: eventLayoutHelper
        source: "EventLayoutHelper.js"

        onMessage: {
            //recevied process data, which we can use to layout events
            layoutEvents(messageObject.schedules);
        }
    }

    function createEvents() {

        var eventMap = {};
        var allSchs = [];

        var startDate = new Date().midnight();
        var endDate = new Date().endOfDay();
        var items = model.getItems(startDate,endDate);
        for(var i = 0; i < items.length; ++i) {
            var event = items[i];
            var schedule = {"startDateTime": event.startDateTime, "endDateTime": event.endDateTime,"id":event.itemId };
            allSchs.push(schedule);
            eventMap[event.itemId] = event;
        }

        intern.eventMap = eventMap;
        //here we are asking worker script to process all the events
        eventLayoutHelper.sendMessage(allSchs);
    }


Following is script code, it will process these events and will send back location and size information back.
WorkerScript.onMessage = function(events) {

    //do some pre-processing like sorting and converting the data type more comfortable to algorithm
    var allSchs = processEvents(events);

    while( allSchs.length > 0) {
        var sch = allSchs.shift();

        //finds all schedules overlapping with current schedule and remove from original array
        var schs = findOverlappingSchedules(sch, allSchs);

        //insert original schedule first, so array remain sorted
        schs.unshift(sch);

        //send processed events back to GUI thread so we can render it
        WorkerScript.sendMessage({ 'schedules': schs});
    }
}

Saturday, June 7, 2014

Geting Call notification from Cascades QML code in BB10

I was updating my Audiobook Reader application. I wanted to listen to our going or incoming call and pause book accordingly.

BB10 provides nice API to control call and listen to it.

This post will show how we can listen to call from Cascades QML code. First we need to ask for access_phone and control_phone permission in our bar descriptor file.
    <permission>access_phone</permission>
    <permission>control_phone</permission>
Now we need to link system lib to our app.
LIBS += -lbbsystem 
Once this is done, we need to register Phone type to QML system so we can access it from QML.

#include <bb/system/phone/Phone>
...
using namespace bb::system;

int main(int argc, char **argv) {
    qmlRegisterType("bb.system.phone", 1, 0, "Phone");
    ...
}
Now we are ready to use Phone API from QML side. Following is how QML code will look like. In code we are creating Phone object. On any call related event callUpdated signal will be called. So we are handling that signal in onCallUpdated event. Please note that we can not access Call's properties with QML, as its not derived from QObject, so if you need to access properties of Call then you need to forward call to C++ and handle it there.

import bb.system 1.0
import bb.system.phone 1.0

Page {
    attachedObjects: [
        Phone {
            id: phone
            onCallUpdated: {
                console.log(" ############## Phone::onCallUpdated ") ; 
                //do the needful
            }
        }
    ]
}
Thant's it. Hope it will be helpful.

Sunday, April 13, 2014

Creating Custom Swipe handler in QML

I was often request for sample that shows how custom swipe handler can be created in QML. In this post I will show how same can be achieved.

Please note that code is just prototype level code and is not tested well with actual use. It has also lots of hard coded value that assume certain size of application.

But, you should be able to change those according to your use and can try sample with your app.

This sample implement three QML views and you can swipe on that to change view from one to next. This code also implement some parallax effect on view and view transition animation. In addition to swipe you can also change view using keyboard Left/Right arrow key. Following is demo for the sample app.



So let's start with code.

Following code is from SwipeHandler.qml, it extends MouseArea and try to detect swipe based on mouse's x position change. Swipe can be generated by two way, by flicking on view or dragging it.
Flick is detected, if there is large change in mouse x position in less time. In case of drag, if mouse travel certain distance then code consider it as a swipe.

import QtQuick 2.0

MouseArea{
    id: root

    property int oldX: mouseX;
    property int swipeOffset: 100;
    property int originX:mouseX;

    property var gestureStartTime;
    property bool gestureStarted: false;

    signal swipeEnded(var diff);
    signal swipeContinues(var diff);

    anchors.fill: parent

    onReleased: {
        if( gestureStarted ) {
            //swipe canceled
            root.swipeEnded(0);
            resetGesture();
        }
        //else swipe is already ended
    }

    onPressed: {
        gestureStarted =  true;
        gestureStartTime = new Date();
    }

    onMouseXChanged: {
        if( mouseX < parent.x
        || mouseX > parent.width || gestureStarted == false )
            return;

        if( originX == 0 ) {
            originX = mouseX; oldX = mouseX;
            return;
        }

        var diff = (oldX - mouseX);
        if(handleFlick(diff)){
            return;
        }

        if( haldleDrag(mouseX, diff)){
            return;
        }

        oldX = mouseX;
        root.swipeContinues(diff);
    }

    function resetGesture() {
        originX = 0; oldX = 0;
        gestureStarted =  false;
    }

    function haldleDrag(xPos,xPosDiff){
        if(xPosDiff < 0) {
            if( Math.abs(originX-xPos)  > swipeOffset ){
                root.swipeEnded(xPosDiff);
                resetGesture();
                return true;
            }
        } else {
            if( Math.abs(originX-xPos) >  swipeOffset ){
                root.swipeEnded(xPosDiff);
                resetGesture();
                return true;
            }
        }
        return false;
    }

    function handleFlick(xPosDiff){
        var now = new Date();
        var timeDiff = now - gestureStartTime;

        //high velocity and large diff between start end point
        if(timeDiff < 40 && Math.abs(xPosDiff) > 10 ){
            if(xPosDiff < 0) {
                root.swipeEnded(xPosDiff);
                resetGesture();
                return true;
            } else {
                root.swipeEnded(xPosDiff);
                resetGesture();
                return true;
            }
        }
        return false;
    }
}
So, this was SwipeHandler which can detect if swipe is generated or not. To demonstrate its use, I created a small View Management component, that create's three views. On swipe, view changes form one to another base on direction of swipe movement. Here is code for the same.
import QtQuick 2.0

Rectangle {
    id: root
    width: 200
    height: 300

    property var delegate: comp;

    property var centralView;
    property var nextView;
    property var prevView;

    focus: true

    Component.onCompleted: {
        var colors = ["red","blue","green"];
        var objs = [];
        for(var i =0; i < 3; ++i){
            var obj = comp.createObject(root);
            obj.text = i+1;
            obj.color = colors[i];
            objs.push(obj);
        }

        centralView = objs[0]
        nextView = objs[1]
        prevView = objs[2]

        setViewPos();
    }

    function setViewPos(oldX){
        centralView.animate(50,0);
        nextView.animate(50,root.width);
        prevView.animate(50,-root.width);

        centralView.z = 1;
        nextView.z = 0;
        prevView.z = 0;
    }

    Keys.onRightPressed: {
        var tempView = centralView;
        centralView = prevView;
        prevView = nextView;
        nextView = tempView;

        centralView.animate(150,0);
        nextView.animate(150,root.width);
        prevView.x = -width
    }

    Keys.onLeftPressed: {
        var tempView = centralView;
        centralView = nextView;
        nextView = prevView;
        prevView = tempView;

        centralView.animate(150,0);
        prevView.animate(150,-root.width);
        nextView.x = width
    }

    SwipeArea{
        onSwipeEnded: {
            if(diff === 0) {
                root.setViewPos();
                return;
            }

            var tempView = centralView;
            if(diff < 0) {
                centralView = prevView;
                prevView = nextView;
                nextView = tempView;
            } else {
                centralView = nextView;
                nextView = prevView;
                prevView = tempView;
            }
            root.setViewPos();
        }

        onSwipeContinues: {
            centralView.x = centralView.x - diff;
            if(diff < 0) {
                prevView.x = prevView.x  + Math.abs(diff*1.6);
                prevView.z = 1
                centralView.z = 0;
            } else {
                nextView.x = nextView.x - Math.abs(diff*1.6) ;
                nextView.z = 1
                centralView.z = 0;
            }
        }
    }

    Component{
        id: comp
        Rectangle{
            id: rect
            property alias text: label.text

            width: parent.width; height: parent.height
            Text{
                id: label; anchors.centerIn: parent
            }

            function animate(duration, to){
                anim.to = to; anim.duration = duration
                anim.running = true
            }

            PropertyAnimation{
                id: anim; target:rect; property: "x";duration: 50
            }
        }
    }
}

Friday, March 7, 2014

Handling Multi Touch in Unity 3D

While working on my Unity Project, I faced some strange problem. I had few buttons on screen and I was handling touch by handling Mouse Event. While it worked fine if you use it with mouse, but when I try same on phone with Touch, I realized that my button can not detect touch if I already touched some other button. So basically in case of multi touch, mouse events do not work. This introduced problem if user is touching button very rapiddly, so to resolve issue, we need to handle multi touch.

Handling multi touch is simple in Unity. You can put the following code in Update method and you will be ready to handle multi touch.

  
  // Check if there is any touch event 
  if (Input.touchCount > 0)
  { 
   //get last touch and its location on screen
   Touch touch = Input.GetTouch(Input.touchCount-1);
   Vector3 wp = Camera.main.ScreenToWorldPoint(touch.position);

   //check if that location collides with our collider
   if (collider2D == Physics2D.OverlapPoint(wp)){    
    if(touch.phase == TouchPhase.Began){
    // Touch just began
    }else if(touch.phase == TouchPhase.Canceled 
              || touch.phase == TouchPhase.Ended ) {
    //Touch canceled or ended
    }
   }
  }
That's it. Thanks for visiting my blog.

Friday, February 21, 2014

Creating Parallax effect in Unity 4.3 2D game

I was checking out Unity3D's 2D workflow and I seen the were able to implement Parallax effect for game background without much effort.

In this post I will show I they achieved parallax effect without single line of code for Unity2D game.

Final effect looks like shown in below video.

First, I created a sample project in 2D mode and imported Sky background in asset and created a sky game object.

This is how it looks after importing Sky background.


I wanted to show clouds moving in the sky, so I created image with clouds and imported those to Unity. Now we need to create a two sprite of cloud image and put those side by side. Once that is done we need to animate both cloud background such that at end of animation second could background image is at the place of first cloud background.

To make this movement process easy, we will create a empty game object and name it Clouds.


Now we will create two object of cloud background image and place those image under empty gameobject which we just created.


We need to arrange those side by side, like below.


We can move Clouds object( the empty gameobject) and both cloud object will move together. This empty gameobject make things easier for movement and its easy way to group object together.

So, now we are ready to make parallax animation, first make sure Animation window is visible, you can make it visible like shown in blow pic.


Select the Clouds empty gameobect, we need to create initial key for animation, which is our current default position.


Once initial animation key is created, right click on time on timeline and select add key, it will add animation key, now you can move Clouds game object to create animation. This key is out intermediate animation key.


Finally, we need to add final animation key, right click on another time on timeline and add key, and move Clouds gameobject such that second cloud image is at place of first one.


We are done, now if you press play button you can see cloud moving continuously as shown in video.

Monday, February 17, 2014

Getting Raw image in ARGB format from Camera using BB10 Native API

Recently I was trying to get Raw image from Camera in BB10, I wanted to display image in Unity3D game and process it. I created a Native Plugin to pass image data from native API to Unity3D script.

I will post more about Native plugin creation process in separate post, in this post I will describe process to get camera frame in ARGB format.

Before we begin, we need to request access to Camera by using following statement in bar_descriptor.xml and we also need to link our source to camapi library in Pro file.
<permission>use_camera</permission>
Following code is for initializing the camera, it opens camera, set proper resolution required by application, then set format and lastly starts the view finder with callback function which will be called once we camera frame is ready.

One thing to notice is, We are setting image format to CAMERA_FRAMETYPE_RGB8888 by using camera_set_videovf_property function, so we will receive image data in ARGB format and we will not need to do any conversion from native format to ARGB our self.

#define DELTA(x,y) ((x>y)?(x-y):(y-x))

int initCamera()
{
    //Open camera
    if (camera_open(CAMERA_UNIT_REAR, CAMERA_MODE_RW, &handle)){
        //camera_open fails...
        return -1;
    }

    //Camera_open success...
    unsigned int orientation = 0;
    camera_get_native_orientation(handle, &orientation);

    // going to run a query here to find a 480P 16:9 resolution
    unsigned int num;
    camera_get_video_vf_resolutions(handle, 0, &num, NULL);
    camera_res_t res[num];
    camera_get_video_vf_resolutions(handle, num, &num, res);
    unsigned int best = 0;
    unsigned int i;
    for (i=0; i < num; i++) {
        fprintf(stderr, "Supported resolution: %d x %d\n", res[i].width, res[i].height);
        if ((orientation % 180) == 0) {
            if ((DELTA(res[i].height, 480) <= DELTA(res[best].height, 480)) &&
            (DELTA(res[i].width, 480*16/9) <= DELTA(res[best].width, 480*16/9))) 
            {
                best = i;
            }
        } else {
            if ((DELTA(res[i].width, 480) <= DELTA(res[best].width, 480)) &&
           (DELTA(res[i].height, 480*16/9) <= DELTA(res[best].height, 480*16/9))) 
            {
                best = i;
            }
        }
    }
    fprintf(stderr, "Selecting resolution %d x %d\n", 
            res[best].width, res[best].height);

    // get camera running
    if (camera_set_videovf_property(handle,
            CAMERA_IMGPROP_CREATEWINDOW, 0,
            CAMERA_IMGPROP_FORMAT, CAMERA_FRAMETYPE_RGB8888,
            CAMERA_IMGPROP_FRAMERATE, 30.0,
            // note: using the rotation value corresponding to the native orientation
            // gives the best performance since the output from the sensor will not be
            // passed through a rotation stage on devices that require such a step.
            CAMERA_IMGPROP_ROTATION, (360-orientation) % 360,
            CAMERA_IMGPROP_WIDTH, res[best].width,
            CAMERA_IMGPROP_HEIGHT, res[best].height)) {
        return -1;
    }
    //camera_set_videovf_property done...

    if (camera_start_video_viewfinder(handle, 
        &viewfinder_callback, 
        &status_callback, NULL)) {
        return -1;
    }

    //camera_start_video_viewfinder started...
    return 0;
}
Following function is called by viewfinder once frame is ready. Once you receive callback from viewfinder with image data, you can either show it or process further it by applying some filter and do something with it.
static void viewfinder_callback(camera_handle_t handle,camera_buffer_t* buf,void* arg)
{
    if (buf->frametype != CAMERA_FRAMETYPE_RGB8888) {
        //viewfinder_callback, format not CAMERA_FRAMETYPE_RGB8888");
        return;
    }

    fprintf(stderr,"frame %d(%d) x %d\n",
            buf->framedesc.rgb8888.width,
            buf->framedesc.rgb8888.stride,
            buf->framedesc.rgb8888.height);

    cameraBuffer = buf;
}
Following function is called when viewfinder wanted to deliver error message.
static void status_callback(camera_handle_t handle,
                camera_devstatus_t status,
                uint16_t extra,
                void* arg)
{
    fprintf(stderr, "status notification: %d, %d\n", status, extra);
}
While working on this code, I referred this link, please check out that link as well. Hope this post will be helpful.

Saturday, February 1, 2014

Handling GamePad events in BB10 Cascades App

I added GamePad support to my CrazyFlight game for BB10. You can see demo here.



In this post I will describe, how we can add GamePad support to BB10 cascades or Qt app.

First we should add use_gamepad permission to bar-descriptor.xml file. This is not necessary to enable gamepad support but its necessary for AppWorld to detect that your game supports GamePad, this helps in app discovery process.
 <permission>use_gamepad</permission>
We should also add libscreen dependency to our .pro file.
LIBS += -lscreen
As far as I know there is no Cascades API for handling GamePad events, we need to rely on native API to get GamePad events. I created a Helper class that handles Native API call back and send events to Cascades QML items.

Here is definition of my helper class's (GamePadObserver.h) header file.
#ifndef GAMEPADOBSERVER_H_
#define GAMEPADOBSERVER_H_

class GamePadObserver: public QObject {
 Q_OBJECT
 Q_ENUMS(GamePadButton)

 // Structure representing a game controller.
 struct GameController {
  // Static device info.
  screen_device_t handle;
  int type;
  int analogCount;
  int buttonCount;
  char id[64];

  // Current state.
  int buttons;
  int analog0[3];
  int analog1[3];

  // Text to display to the user about this controller.
  char deviceString[256];
 };

public:
 //Enum which we will use to send signal when GamePad event is detected
 enum GamePadButton{
   A_BUTTON=0,
   B_BUTTON,
   C_BUTTON,
   X_BUTTON,
   Y_BUTTON,
   Z_BUTTON,
   MENU1_BUTTON,
   MENU2_BUTTON,
   MENU3_BUTTON,
   MENU4_BUTTON,
   L1_BUTTON,
   L2_BUTTON,
   L3_BUTTON,
   R1_BUTTON,
   R2_BUTTON,
   R3_BUTTON,
   DPAD_UP_BUTTON,
   DPAD_DOWN_BUTTON,
   DPAD_LEFT_BUTTON,
   DPAD_RIGHT_BUTTON,
   NO_BUTTON
 };

public:
 GamePadObserver(QObject* parent = 0);
 virtual ~GamePadObserver();

 //Main event loop should send event to this handler if it can not handle event by itself
 //This handler will try to handle event if its related to GamePad
 void handleScreenEvent(bps_event_t *event);

signals:
        //Signals will be emitted when Gamepad events is detected
 void buttonReleased(int button);
 void buttonPressed(int button);

private:
 //Helper methods to discover the GamePad and device connection
 void discoverControllers();
 void initController(GameController* controller, int player);
 void loadController(GameController* controller);
 void handleDeviceConnection(screen_event_t screen_event);
       
 // Methods to handle gamepad events
 void handleGamePadInput(screen_event_t screen_event);
 QString gamePadButtonAsString(GamePadButton button);

private:
 screen_context_t _screen_ctx;
 GameController _controllers[2];
 bool _conneted;
 GamePadButton _lastButton;
};
#endif /* GAMEPADOBSERVER_H_ */
Now let's see source file.
In constructor we are creating screen context and then trying to discover if there is GamePad connected to device already.
#define SCREEN_API(x, y) rc = x; \
    if (rc)  printf("\n%s in %s: %d, %d", y, __FUNCTION__,__LINE__, errno)

GamePadObserver::GamePadObserver( QObject* parent)
: QObject(parent),_screen_ctx(0),_conneted(false)
{
 // Create a screen context that will be used to create an EGL surface to receive libscreen events.
 SCREEN_API(screen_create_context(&_screen_ctx, SCREEN_APPLICATION_CONTEXT), "create_context");
 discoverControllers();
}

void GamePadObserver::discoverControllers()
{
    // Get an array of all available devices.
    int deviceCount = 0;
    SCREEN_API(screen_get_context_property_iv(_screen_ctx, SCREEN_PROPERTY_DEVICE_COUNT, &deviceCount), "SCREEN_PROPERTY_DEVICE_COUNT");
    screen_device_t* devices = (screen_device_t*) calloc(deviceCount, sizeof(screen_device_t));
    SCREEN_API(screen_get_context_property_pv(_screen_ctx, SCREEN_PROPERTY_DEVICES, (void**)devices), "SCREEN_PROPERTY_DEVICES");

    // Scan the list for gamepad and joystick devices.
    int controllerIndex = 0;
    for (int i = 0; i < deviceCount; i++) {
        int type;
        SCREEN_API(screen_get_device_property_iv(devices[i], SCREEN_PROPERTY_TYPE, &type), "SCREEN_PROPERTY_TYPE");

        if ( !rc && (type == SCREEN_EVENT_GAMEPAD || type == SCREEN_EVENT_JOYSTICK)) {
            // Assign this device to control Player 1 or Player 2.
            GameController* controller = &_controllers[controllerIndex];
            controller->handle = devices[i];
            loadController(controller);

            // We'll just use the first compatible devices we find.
            controllerIndex++;
            if (controllerIndex == MAX_CONTROLLERS) {
                break;
            }
        }
    }
    free(devices);
}
On destructor we should release screen context.
GamePadObserver::~GamePadObserver()
{
 screen_destroy_context(_screen_ctx);
}
loadController setup our GameController structure, that we will use to store currently pressed buttons while handling the events.
void GamePadObserver::loadController(GameController* controller)
{
    // Query libscreen for information about this device.
    SCREEN_API(screen_get_device_property_iv(controller->handle, SCREEN_PROPERTY_TYPE, &controller->type), "SCREEN_PROPERTY_TYPE");
    SCREEN_API(screen_get_device_property_cv(controller->handle, SCREEN_PROPERTY_ID_STRING, sizeof(controller->id), controller->id), "SCREEN_PROPERTY_ID_STRING");
    SCREEN_API(screen_get_device_property_iv(controller->handle, SCREEN_PROPERTY_BUTTON_COUNT, &controller->buttonCount), "SCREEN_PROPERTY_BUTTON_COUNT");

    // Check for the existence of analog sticks.
    if (!screen_get_device_property_iv(controller->handle, SCREEN_PROPERTY_ANALOG0, controller->analog0)) {
     ++controller->analogCount;
    }

    if (!screen_get_device_property_iv(controller->handle, SCREEN_PROPERTY_ANALOG1, controller->analog1)) {
     ++controller->analogCount;
    }

    if (controller->type == SCREEN_EVENT_GAMEPAD) {
        sprintf( controller->deviceString, "Gamepad device ID: %s", controller->id);
        qDebug() << "Gamepad device ID" <<  controller->id;
    } else {
        sprintf( controller->deviceString, "Joystick device: %s", controller->id);
        qDebug() << "Joystick device ID" <<  controller->id;
    }
}
handleScreenEvent function should be called from main event loop when event is related to screen domain. This function check if event type is GamePad device connection or its GamePad button event and handle it accordingly.
void GamePadObserver::handleScreenEvent(bps_event_t *event)
{
    int eventType;

    screen_event_t screen_event = screen_event_get_event(event);
    screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &eventType);

    switch (eventType) {
        case SCREEN_EVENT_GAMEPAD:
        case SCREEN_EVENT_JOYSTICK:
        {
         handleGamePadInput(screen_event);
         break;
        }
        case SCREEN_EVENT_DEVICE:
        {
         // A device was attached or removed.
         handleDeviceConnection(screen_event);
         break;
        }
    }
}
handleDeviceConnection handles GamePad device connection. If it detects new connection then it loads new device, in case of device disconnection it remove device.
void GamePadObserver::handleDeviceConnection(screen_event_t screen_event)
{
    // A device was attached or removed.
    screen_device_t device;
    int attached;
    int type;

    SCREEN_API(screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_DEVICE, (void**)&device), "SCREEN_PROPERTY_DEVICE");
    SCREEN_API(screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_ATTACHED, &attached), "SCREEN_PROPERTY_ATTACHED");

    if ( attached ) {
        SCREEN_API(screen_get_device_property_iv(device, SCREEN_PROPERTY_TYPE, &type), "SCREEN_PROPERTY_TYPE");
    }

    int i;
    if (attached && (type == SCREEN_EVENT_GAMEPAD || type == SCREEN_EVENT_JOYSTICK)) {
        for (i = 0; i < MAX_CONTROLLERS; ++i) {
            if (!_controllers[i].handle) {
                _controllers[i].handle = device;
                loadController(&_controllers[i]);
                break;
            }
        }
    } else {
        for (i = 0; i < MAX_CONTROLLERS; ++i) {
            if (device == _controllers[i].handle) {
                initController(&_controllers[i], i);
                break;
            }
        }
    }
}

void GamePadObserver::initController(GameController* controller, int player)
{
    // Initialize controller values.
    controller->handle = 0;
    controller->type = 0;
    controller->analogCount = 0;
    controller->buttonCount = 0;
    controller->buttons = 0;
    controller->analog0[0] = controller->analog0[1] = controller->analog0[2] = 0;
    controller->analog1[0] = controller->analog1[1] = controller->analog1[2] = 0;
    sprintf(controller->deviceString, "Player %d: No device detected.", player + 1);
}
handleGamePadInput function that handles GamePad events.
void GamePadObserver::handleGamePadInput(screen_event_t /*screen_event*/)
{
    int i;
    for (i = 0; i < MAX_CONTROLLERS; i++) {
        GameController* controller = &_controllers[i];

        if ( controller->handle ) {
            GamePadButton gamePadButton = NO_BUTTON;

            // Get the current state of a gamepad device.
            SCREEN_API(screen_get_device_property_iv(controller->handle, SCREEN_PROPERTY_BUTTONS, &controller->buttons), "SCREEN_PROPERTY_BUTTONS");

            if (controller->analogCount > 0) {
             SCREEN_API(screen_get_device_property_iv(controller->handle, SCREEN_PROPERTY_ANALOG0, controller->analog0), "SCREEN_PROPERTY_ANALOG0");
            }

            if (controller->analogCount == 2) {
             SCREEN_API(screen_get_device_property_iv(controller->handle, SCREEN_PROPERTY_ANALOG1, controller->analog1), "SCREEN_PROPERTY_ANALOG1");
            }

            for(int i = A_BUTTON ; i < NO_BUTTON ; ++i) {
             if( controller->buttons & (1 << i) ) {
              gamePadButton = (GamePadButton)(i);
              break;
             }
            }

            if( gamePadButton == NO_BUTTON ) {
             emit buttonReleased( _lastButton );
             _lastButton = NO_BUTTON;
            }
            else if( _lastButton != gamePadButton ) {
             emit buttonReleased(_lastButton);
             emit buttonPressed(gamePadButton);
             _lastButton = gamePadButton;
            }
        }
    }
}
Now we have all necessary implementation to handle the GamePad connection and GamePad button events. But we should pass events related to GamePad to our helper class when we receive it in our main event handler. To do that, In our main function we should register main bps event loop or filter as below and can use GamePadObserver as described.
#include "GamePadObserver.h"

static QAbstractEventDispatcher::EventFilter previousEventFilter = 0;
static GamePadObserver _gamePadObserver;

static bool bpsEventFilter(void *message)
{
    bps_event_t * const event = static_cast(message);

    if( event && bps_event_get_domain(event) == screen_get_domain()) {
     _gamePadObserver.handleScreenEvent(event);
    }

    if (previousEventFilter)
        return previousEventFilter(message);
    else
        return false;
}

int main(int argc, char **argv)
{
    // Register GamePadObserver so we can use it in QML code
    qmlRegisterUncreatableType("GamePadObserver", 1, 0,"GamePadObserver", "");

    QApplication app(argc, argv);

    previousEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(bpsEventFilter);

    QScopedPointer view(new QDeclarativeView());
    view->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    view->setResizeMode( QDeclarativeView::SizeRootObjectToView );

    QDeclarativeContext *ctxt = view->rootContext();
    view->setSource(QUrl("app/native/assets/main.qml"));

    ctxt->setContextProperty("GamePad",&_gamePadObserver);
    view->showFullScreen();

    return app.exec();
}
And finally, out GamePadObserver class is ready to deliver GamePad events. To handle GamePad events in QML you can use GamePadObaserver class as below.
        
        Connections{
            target: GamePad
            onButtonPressed: {
                                
                if(button == GamePadObserver.DPAD_UP_BUTTON
                || button == GamePadObserver.DPAD_DOWN_BUTTON ){
                    handleUpButton();
                }else if(button ==  GamePadObserver.DPAD_LEFT_BUTTON 
                || button ==  GamePadObserver.DPAD_RIGHT_BUTTON) {
                    handleLeftButton();
                }          
                else if(button == GamePadObserver.MENU1_BUTTON                 
                || button == GamePadObserver.MENU2_BUTTON
                || button == GamePadObserver.X_BUTTON
                || button == GamePadObserver.Y_BUTTON 
                || button == GamePadObserver.A_BUTTON 
                || button == GamePadObserver.B_BUTTON ) {
                    handleButtonSelection();
                } 
            }        
        }
So, I hope this will help to utilize GamePad events in your games.

Monday, January 6, 2014

Defining Callback in Unity3D C Plugin and C# Script

Lately I am working on one Unity3d Game and for using some platform specific feature I required to create a native plugin in C.

I am not done with creating complete plug-in yet and will post more about creating plug-in in separate post. But while I am working on plug-in creation for Unity3D, I required to use callback or notification from C code to Unity c# script.

Following is How we can use callback between C based plugin and C# unity script.

Following is definition of callback function/function pointer which will call C# function.
typedef void ( *CALLBACK )( const char* );
static CALLBACK cb; 
This is how we are going to set and use defined callback function.
void runEventLoop(CALLBACK test) {
    cb = test; 
    cb("hello plugin...");
}
Following is complete C code.
extern "C"
{ 
 typedef void ( *CALLBACK )( const char* );
 static CALLBACK cb;
 
 void runEventLoop(CALLBACK test) {
  cb = test;
  cb("hello plugin...");
 }
}

Now we have required C code for sending notification or providing the callback. But we need to create C# script, which define function which will be called on notification from plug-in.

Following is C# script.
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;

public class PluginImport : MonoBehaviour {

 public delegate void callbackDelegate( string str );

 [DllImport ("Plugin")]
 private static extern void runEventLoop(callbackDelegate test);

 void callback(string str) {
    Debug.Log(str);
 }

 void Start () { 
    runEventLoop(new callbackDelegate( this.callback ));
 }
}

This should be enough to get notification from C code to C# script.