Fading Memories

About

Ramblings about books and other things that will soon fade from my memory.

Boudewijn Rempt

index | rss1.0

Check out my sculpture website: www.boudewijnrempt.nl.

There's more...

Creative Commons License
The original artwork is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License.

Roundabout through identi.ca

    follow me on Identi.ca

    Categories, too

    Find


    Archives

    Other things here at valdyas.org

    2013-05-16

    Porting Krita to OpenGL 3.1/ES 2.0

    Krita was the first painting application with an OpenGL accelerated canvas. We had that before Photoshop... Which also meant that the code was getting quite old fashioned. These days, life is supposed to be better. More flexible in any case. However, even though a 2D canvas is a simple thing, once you factor in rotation, zooming, panning and so on, the potential for bugs is quite big, and we've been fixing bugs for ages in the old code.

    So I didn't want to throw that away, but have as clean and straightforward as possible a port from the old code to start with. The old code mostly looked like this (for painting the transparency checkers background):

    KisCoordinatesConverter *converter = coordinatesConverter();
    
    QTransform textureTransform;
    QTransform modelTransform;
    QRectF textureRect;
    QRectF modelRect;
    
    converter->getOpenGLCheckersInfo(&textureTransform, &modelTransform, &textureRect, &modelRect);
    
    KisConfig cfg;
    GLfloat checkSizeScale = KisOpenGLImageTextures::BACKGROUND_TEXTURE_CHECK_SIZE / static_cast(cfg.checkSize());
    
    textureTransform *= QTransform::fromScale(checkSizeScale / KisOpenGLImageTextures::BACKGROUND_TEXTURE_SIZE,
                                                checkSizeScale / KisOpenGLImageTextures::BACKGROUND_TEXTURE_SIZE);
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glViewport(0, 0, width(), height());
    glOrtho(0, width(), height(), 0, NEAR_VAL, FAR_VAL);
    
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    loadQTransform(textureTransform);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    loadQTransform(modelTransform);
    
    glBindTexture(GL_TEXTURE_2D, m_d->openGLImageTextures->backgroundTexture());
    glEnable(GL_TEXTURE_2D);
    
    glBegin(GL_TRIANGLES);
    
    glTexCoord2f(textureRect.left(), textureRect.bottom());
    glVertex2f(modelRect.left(), modelRect.bottom());
    
    glTexCoord2f(textureRect.left(), textureRect.top());
    glVertex2f(modelRect.left(), modelRect.top());
    
    glTexCoord2f(textureRect.right(), textureRect.bottom());
    glVertex2f(modelRect.right(), modelRect.bottom());
    
    glTexCoord2f(textureRect.left(), textureRect.top());
    glVertex2f(modelRect.left(), modelRect.top());
    
    glTexCoord2f(textureRect.right(), textureRect.top();
    glVertex2f(modelRect.right(), modelRect.top());
    
    glTexCoord2f(textureRect.right(), textureRect.bottom());
    glVertex2f(modelRect.right(), modelRect.bottom());
    
    glEnd();
    
    glBindTexture(GL_TEXTURE_2D, 0);
    glDisable(GL_TEXTURE_2D);
    

    In other words, we set a projection, a transformation matrix for the texture and for the model/view and then start drawing the vertices. Pretty simple. I was rather surprised when I did not find any clear tutorial on converting code like this through google. I've read a bunch of modern opengl books and tutorials by now, and they pretty much all have the same order of explanation, the same things they emphasize and the same "advanced" topics. But I couldn't figure out how to draw my checkers or the tiles for my image. Yeah, I'm a linguist, not a mathematician, and I probable read these tutorials wrong or something.

    In any case, after going through the Qt OpenGL examples, the tutorials on Wikibooks, the Red, Orange and Blue books, the Matt Gattis' notes on porting to WebGL and more confused questions and more confusing answers on Stack Overflow than I care to count, I finally got something that works, and is as straight a translation of the old code as possible.

    Purists will cavil at my use of attribute arrays and glDrawArrays -- but the alternative, as far as I can tell, would be to redo all the matrix calculation and use matrices to place my tiles in the right location or to update and send new vertex buffer objects all the times. This works -- and in the future it might even be pretty.

    So, for posterity, and because there might be others in the same spot as me (to wit, tasked with porting OpenGL 1.3 code to OpenGL ES 2.0 or OpenGL 3.1 without compatibility profile), here's a summary of my current code.

    The vertex shader:

    uniform mat4 modelViewProjection;
    uniform mat4 textureMatrix;
    
    attribute highp vec4 a_vertexPosition;
    attribute mediump vec4 a_textureCoordinate;
    
    varying vec4 v_textureCoordinate;
    
    void main()
    {
        gl_Position = modelViewProjection * a_vertexPosition;
        v_textureCoordinate = textureMatrix * a_textureCoordinate;
    }
    

    The fragment shader (needs to be expanded to handle color correction):

    uniform sampler2D texture0;
    
    varying mediump vec4 v_textureCoordinate;
    
    void main() {
        gl_FragColor = texture2D(texture0, v_textureCoordinate.st);
    }
    

    And finally the code. The shader programs are all done using Qt's shader classes, and I don't show that code here -- it's in the calligra git repo anyway.

    KisCoordinatesConverter *converter = coordinatesConverter();
    
    QTransform textureTransform;
    QTransform modelTransform;
    QRectF textureRect;
    QRectF modelRect;
    
    converter->getOpenGLCheckersInfo(&textureTransform, &modelTransform, &textureRect, &modelRect);
    
    // XXX: getting a config object every time we draw the checkers is bad for performance!
    KisConfig cfg;
    GLfloat checkSizeScale = KisOpenGLImageTextures::BACKGROUND_TEXTURE_CHECK_SIZE / static_cast(cfg.checkSize());
    
    textureTransform *= QTransform::fromScale(checkSizeScale / KisOpenGLImageTextures::BACKGROUND_TEXTURE_SIZE,
                                                checkSizeScale / KisOpenGLImageTextures::BACKGROUND_TEXTURE_SIZE);
    
    m_d->checkerShader->bind();
    
    QMatrix4x4 projectionMatrix;
    projectionMatrix.setToIdentity();
    projectionMatrix.ortho(0, width(), height(), 0, NEAR_VAL, FAR_VAL);
    
    // Set view/projection matrices
    QMatrix4x4 modelMatrix(modelTransform);
    modelMatrix.optimize();
    modelMatrix = projectionMatrix * modelMatrix;
    m_d->checkerShader->setUniformValue("modelViewProjection", modelMatrix);
    
    QMatrix4x4 textureMatrix(textureTransform);
    m_d->checkerShader->setUniformValue("textureMatrix", textureMatrix);
    
    //Setup the geometry for rendering
    QVector vertices;
    vertices << QVector3D(modelRect.left(),  modelRect.bottom(), 0.f)
                << QVector3D(modelRect.left(),  modelRect.top(),    0.f)
                << QVector3D(modelRect.right(), modelRect.bottom(), 0.f)
                << QVector3D(modelRect.left(),  modelRect.top(), 0.f)
                << QVector3D(modelRect.right(), modelRect.top(), 0.f)
                << QVector3D(modelRect.right(), modelRect.bottom(),    0.f);
    
    m_d->checkerShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
    m_d->checkerShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, vertices.constData());
    
    QVector texCoords;
    texCoords << QVector2D(textureRect.left(), textureRect.bottom())
                << QVector2D(textureRect.left(), textureRect.top())
                << QVector2D(textureRect.right(), textureRect.bottom())
                << QVector2D(textureRect.left(), textureRect.top())
                << QVector2D(textureRect.right(), textureRect.top())
                << QVector2D(textureRect.right(), textureRect.bottom());
    
    m_d->checkerShader->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
    m_d->checkerShader->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, texCoords.constData());
    
        // render checkers
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_d->openGLImageTextures->checkerTexture());
    
    glDrawArrays(GL_TRIANGLES, 0, 6);
    
    glBindTexture(GL_TEXTURE_2D, 0);
    m_d->checkerShader->release();
    

    For Krita, there are quite a few todo's left:

    • Restore the opengl outline cursor -- now we use the qpainter one
    • Render onto a framebuffer object so this code can be integrated in Krita Sketch
    • Update the image texture tiles in a thread
    • Update the projection in a thread
    • Restore the colormanagement using OCIO
    • Check whether it runs on Windows, OSX (and Android)
    • Maybe move the layer composition to OpenGL using the GPUImage shader code?

    Especially the testing on Windows is interesting, since the old opengl canvas never worked on Windows.


    2013-01-07

    The Ghost of

    Christmas Past.


    2012-12-31

    More Vacation Fun: smoother lines in Krita

    Ever since sigetch created a smooth inking pen for Gimp Painter, artists have been asking us to implement something similar in Krita. It's a feature particularly in demand for inking comics, and since comics is one of Krita's focus areas...

    It basicaly works by looking at the history of the stroke -- the last twenty or fifty of positions or so, the speed with which you paint and then calculates a new position, one that makes the line smoother. I don't pretend to understand the mathematics -- but it was pretty easy to figure out from Alexia Death's clean and clear implementation in Gimp 2.8, so I took that as a model. Free software rocks more!

    I actually couldn't believe it when I was done, and Timothee Giet reported that it worked as per spec... But here's a sketch from his hand that proves it!


    2012-12-27

    A New Krita Feature: Flipbooks

    I'm on vacation, but I cannot stop hacking... But instead of soul-destroying Windows build work, detective work implementing PSD export support or some hair-pulling bug-fixing, I wanted to have some clean, innocent fun...

    Create a nice new feature. So over the past couple of days, I've implemented a flipbook.

    It's quite full-featured already, with flipbooks being available in the recent files list in Krita's startup screen, a page for creating new flipbooks and finally a docker that shows the images and allows the user to flip between images in the flipbook, or save the current set of images as a flipbook.

    There are bound to be some rough edges, and I'm wondering what kind of feature requests our users will think up to make the flipbook even more useful, but really, it's already quite usable.


    2012-09-26

    New Laptop!

    When we started KO GmbH I proposed that the default laptops for our company would be thinkpads, with a choice between small or big, depending on people's needs. My first company Thinkpad was a W500 -- 15", 1900x1200 screen. It was my main development workstation until I got an additional desktop machine, but even then, I used it a lot.

    It always had one big problem: the screen simply wasn't bright enough. And when it aged, the screen problem became worse. It could take up to an hour for the backlight to warm up until the screen became properly readable, and I often had to move windows away from the right-hand side because that always remained darker than the rest.

    And then the unbelievable happened. The right hinge snapped! Thinkpads are famous for being sturdy enough that you can pick them up by the screen, no matter the size of the laptop. I didn't do that, but even so, the metal hinge thingy inside the plastic of the screen broke and forced the plast of the screen apart -- and then the screen didn't stay upright anymore without some kind of support.

    Time to get a new Thinkpad...

    I got me a T430, because I've got the desktop with a big screen now to do development, and the W500 really is too big and clumsy to travel with. I didn't want to go with an X230 because, well, my eyes are bad and those screens are just too small.

    Today the T430 arrived. I swapped the disk from the old laptop and I was ready to go. Pretty much everything works fine, that I can see. Wifi (except for a bug, I think in OpenSUSE, where I need to disable and then re-enable the wifi support to make it work, same problem occurred on my W500, so it might even be a local settings issue). It's fast, the screen is bright and the resolution at 1600x900 not too bad. It's not too heavy, there's plenty of memory and the CPU is well capable of compiling Calligra, and it doesn't get too hot in the process.

    There are two gotcha's that I haven't solved yet: the fan is always running, and OpenSUSE doesn't seem to have the thinkpad packages you can find for *buntu that can handle that. That needs a bit of investigation.

    The other gotcha is the keyboard. Lenovo has decided to go with the flow and use a flat, separated keys style keyboard. It's not horrible, but it's worse than the old style keyboards. And they changed the layout... No longer the escape key over the F1 key, no longer the top-right island with insert, delete, home, end, pgup, pgdn. For some reason, the prtsc button now is placed between right alt and right ctrl. This will take more time getting used to. Not cool, Lenovo, not an improvement!


    2012-09-23

    Ubuntu to provide Amazon search

    It's kinda weird to read all the stories doing the rounds right now about how Ubuntu is selling its soul to Amazon by providing a way to search Amazon from the desktop.

    And it's weird because KDE has been providing just that for ages: type "amz:python qt rempt" in the krunner popup and you get linked to my book. If you explore the systesettings web shortcuts module you;ll find many more useful shortcuts.


    2012-08-06

    KDE on Windows

    From Friday to Sunday, I attended the KDE on Windows sprint, hosted by Intevation, in Osnabrück. There were seven attendants, making it a nice and hacking-focussed sprint. Sure, there were discussions about improvements to the system and so on, as you can read on the meeting wiki page.

    Important items are changing the versioning of the portage system by removing the version from the package names, improving the sandboxing of KDE applications (so they don't overwrite each other settings, system configuration cache and so on) and integration of creatsing nsis installers in the emerge system.

    We had some non-keyboard time as well, when on Friday, KDAB sponsored a german-style dinner, and on Saturday, KO an Arabian-style dinner, followed by drinks in the "unikeller". Some pretty obscure German beer was had there, very tasty. And then some of us went back to the office of an all-night hack session...

    See also Patrik SPendrin's blog, with group picture....

    Builds

    Currently, I'm working with three or four build trees: one with Microsoft Visual C++, one mixed Microsoft Visual C++ and Intel Composer, one with Mingw, all natively on Windows. Dominik Schmidt demonstrated how easy it is to create 32 and 64 bit builds on Linux using Tomahawk as an example. I hadn't heard of Tomahawk before, since my media player of choice is ogg123... But the build system looks very simple to use, and Tomahawk is pretty cool, too. Dominik spent a large part of the weekend integrating kdelibs, kde-runtime and kdepim into this cross-compiling system. This system depends heavily on the OpenSUSE build system, which I need to investigate anyway to make my CentOS packages easier to generate.

    Check the tomahawk wiki for a basic cross-compiling howto: it really is utterly simple, once you realize that you need to do the same trick as tomahawk with a toolchain file for cmake definitions. That needs to be in order; from that point onwards, everything should just work. I'll give it a try with Krita soon: the only dependencies still missing are exiv2 and eigen2.

    This generates NSIS-based installers, but I also heard that other people have had success generating WIX-based MSI installers using mono on Linux and OSX, so that's worth investigating as well.

    Packages

    Being a newcomer to the KDE Windows scene, I did some simple stuff, like creating a calligra package for the emerge system. If you put an emerge checkout on your windows system and follow the basic setup steps (really, just get the checkout, install python3, create an etc directory with copy of kdesettings.bat), you should be able to do an "emerge calligra" and get a working calligra installation. Of course, there might be problems along the way, but the nice people in #kde-windows know most of the answers!

    I also started on packaging ilmbase, the basic dependency for OpenEXR. This was trickier, since ilmbase is an autotools-based package, so we had to add a CMake-based build system. That basically worked, so I added the package to emerge's portage tree, and Patrick Spendrin then finished up and added OpenEXR. Maybe we should try to get the CMake system for those libraries upstreamed, though. The upshot of this is that Krita on Windows, once I've made new installers, will be able to handle 32-bits floating point/channel images. Not 16 bit floating point, though, since LittleCMS cannot handle that yet. But Marti has promised that for the next release...


    2012-08-03

    On my way to the KDE on Windows Sprint

    With all the work of putting Krita on Windows, it has become sort of imperative for me to join the KDE on Windows hackers. Besides, Osnabrück is only two hours by train from my home.

    I'm currently trying to make a build of qt and kdelibs that doesn't start any of the usual daemons: dbus, kded and so on. That seems to have succeeded, I now just need to fix some runtime errors!

    This is also the first time in years that I'm travelling without any real Linux device. I've got a nice ultrabook prototype that's running a build of Windows 8. I'm sort of disappointed in Windows 8. I was hoping it would be bad enough that we'd have another Vista-like opportunity, but it isn't that bad!

    Anyway... If you are a graphics designer and reading this, I have a job for you... We need someone to design Krita Sketch! If you have what it takes to design a wonderful, professional touch-based paint application, contact boud@kogmbh.com.


    2012-07-28

    Recommending Hettes

    So the twins needed a new laptop. Their previous laptops dated from 2007 and were broken in various ways. They had been making do with some netbooks, but that didn't really made them happy. But both have got a job now, one is assistant in a butcher's shop, the other in a delicatessen. So, flush with money they asked me to help them choose a good laptop that would run OpenSUSE. Yes, they know Windows, have used it at school, and prefer KDE.

    I've got a sort of Lenovo-only policy which hasn't failed me, ever since our Dell 5150 laptops turned out to be such lemons. The Acer and Toshiba laptops we've had were just as bad as Dell. Lenovo it was.

    So we were looking around for nice models and checking whether there were any reports about Linux compatibility.

    Then we found Hettes. They had the laptops we wanted, with OpenSUSE pre-installed. Wow! Maybe a little bit more expensive than finding them at the cheapest webshop, but then, to have everything working out of the box, that's worth something. So I told my daughters to buy there and I would pay that trifling difference. Of course, then one of them wanted a model that wasn't yet available in Europe...

    So I've had plenty of contact with the people from Hettes. They told me that the other laptop was going to be a bit delayed because they had found a way to improve the wifi driver, which means that they actuallyt test what they sell!

    This week the laptops arrived, and the twins are totally happy. Both models work perfectly, out of the box. The red E325 has a gorgeous screen and, very cute, the dots on the i of "thinkpad" glow red. More importantly, all the hardware works, OpenSUSE was ready on them.

    I would recommend this shop to everyone who wants a laptop, desktop, tablet or netbook with Linux pre-installed. Great outfit!


    Sculpture Update

    Apart from too much hacking on Krita, I do some other things. Sculpture is one of them, and I've blogged about that before, about a year ago. I haven't been idle since then, though, but I did leave the sculpture class I joined some years ago. I felt I wasn't really learning the technical stuff I really needed, and then the whole building got redecorated with the result that the room was too dim for me to actually work in. I've got a better place to work at home now!

    Click on the link to see pictures...

    Read more ...