Sunday 28 April 2013

Moving Around a 3D cube with Mouse and Keyboard (Part 1)

I never got the hang of XBox controllers

So moving on from a painfully coloured 3D spinning cube created in OpenGL and Qt (see here), I now want to add user input via a mouse and keyboard. The first part of this will be fairy easy and just result in being able to rotate the cube when ever the middle mouse button is pressed - 'mouse look' for those in the know.

So, first up, we need to put an additional function in for checking mouse movement. Qt makes this very easy (not surprisingly) as all widgets can catch mouse events by overriding the mouseMoveEvent. So after adding the following:

header file: 

protected:
   void mouseMoveEvent(QMouseEvent *event);

cpp file:

void OGLWidget::mouseMoveEvent(QMouseEvent *event)
{

}

We now have a function that will catch any mouse movement. Or mostly, anyway. This will only work with movement when a button is pressed (dragging basically) which won't quite work for this. You therefore should add the following to the constructor of the widget:

setMouseTracking(true);

This will set the widget to track ALL mouse movements.

So now, how do we ensure the cube moves around with the mouse and stops when we release the button? We need to keep two 'temporary' (but member) variables that record the rotation of the cube and mouse coords. The new rotation is then calculated based on the difference between this mouse position and the current one, which is then added to the stored rotation when the mouse button was pressed. As with pictures, code is often worth a thousand words so all of that can probably more easily be understood by viewing the following:

void OGLWidget::mouseMoveEvent(QMouseEvent *event)
{
    // is the middle mouse button down?
    if (event->buttons() == Qt::MidButton)
    {
        // was it already down? If not, store the current coords
        if (!mouseLook_)
        {
            tmpMousePos_ = event->pos();
            tmpRotValue_ = rotValue_;
            mouseLook_ = true;
        }

        // update the rotation values depending on the relative mouse position
        rotValue_.setX( tmpRotValue_.x() + (tmpMousePos_.x() - event->pos().x()) * 0.2 );
        rotValue_.setY( tmpRotValue_.y() + (tmpMousePos_.y() - event->pos().y()) * -0.2 );
    }
    else
    {
        // turn off mouse look
        mouseLook_ = false;
    }
}

Things to note:
  • I've got an additional flag showing whether mouse look is on or not - I could have set one of the other tmp variables to a special value but this is almost never a good idea and variables are (generally) cheap.
  • I've applied a factor of 0.2 to each mouse movement. This is basically the mouse speed and should be configurable an ideal world
  • To incorporate two axis rotation, I've changed rotValue_ to a QPoint type where x stores the y-axis rotation and y stores the x axis rotation.

So you can now rotate the cube when holding down the middle mouse button. Next time, we try to actually move the camera using the WASD keys. This will require a few more changes to the rendering code.

Find the code at:

https://github.com/doc-sparks/Interface/tree/v0.2

Saturday 27 April 2013

Fixing a Broken DNS in Linux Mint 13

Clearly I just have to start remembering more IP addresses

So last week I needed to go abroad (to CERN as it happens) and when I got there, my Mint 13 running laptop decided to throw a paddy and stop talking to the DNS. I could ping usual Google IPs (8.8.8.8 for example) but DNS just hung despite being reported to correctly (and pingable) in the Network Settings. Having a look at my resolv.conf, I could see that my DNS settings were set to my Uni one. I couldn't remember if these were put in automatically by the ethernet connection in my office or I'd just dumped that there randomly for some reason, but tellingly, these DNSs were NOT pingable (I guess they had fallen over or something).

So, I thought, not a problem - just change the DNSs to Google's and all should be well. Except it wasn't. The laptop was still refusing to talk to anyone by name. Luckily, my phone was not having these troubles and some frantic searching led me to the following Blog. It appears someone in Ubuntu land was trying to be clever and started using dnsmasq instead of resolv.conf. I don't know why this was done and really can't be bothered to find out, but in this occasion it meant I could not find whatever black magic was needed to force the Google DNS to be used.

By *mostly* following the blog, I discovered the following worked like a charm to get control of the DNS back to resolv.conf where (in my humble - and probably naive - opinion) it should still reside. First up, (and be aware, this should all be done under su/root), stop Mint from using dnsmasq by going to:

/etc/NetworkManager/NetworkManager.conf

And commenting out the dns line:

#dns=dnsmasq

Next, get resolvconf to sort out it's links and bring back resolv.conf:

dpkg-reconfigure resolvconf

Just to be sure, do a few more housekeeping bits and pieces and follow up with a restart:

resolvconf --create-runtime-directories
resolvconf --enable-updates
reboot

And now you should be able to edit /etc/resolv.conf as usual and have Mint listen to you. Note that you may want to also change:

/etc/resolvconf/resolv.conf.d/original

for a more permanent setting as I believe on restart resolvconf will recreate the resolv.conf with this. 

Last thing to note: While messing around, I tried to select 'Automatic (DHCP) addresses only' under IPv4 Settings for the wireless I was using. THIS WAS A BAD IDEA! It stopped the above working for other reasons I didn't understand. I plan to revisit all this at some point to try to better understand how DNS is handled in Mint/Ubuntu as I'm sure there was probably a better way around this...