Cross-compiling Krita using MXE

Writing code that builds with multiple compilers is good way to catch errors, improve code quality and conformance. Or so I have always been taught. Hence, when we ported Krita to Windows, we ported it to the native compiler for Windows, Microsoft Visual C++. That took some doing, but in the process we found lots of little things that, once fixed, improved Krita’s code. When we ported Krita to OSX, where the native compiler is clang, the same happened.

And then we added two dependencies to Krita that have trouble with Visual C++: G’Mic and Vc. G’Mic implements a parser for a custom scripting language for writing filters, and that parser is written in a way that makes life really hard for Visual C++. Basically, the 32 bits builds never worked and the 64 bits builds need a stack of about a gigabyte to parse the scripts. And Vc, a library to add vectorization/simd support easily, from version 1.0 and up just doesn’t build at all on Windows.

It’s probably not a coincidence that both are heavy users of templates, and in the case of Vc, of C++11. But Krita needs both libraries: our users love all the filters and tools the G’Mic plugin gives them, and without Vc, our brushes and pixel compositing code becomes really slow.

What could we do? Hair was liberally pulled and not a few not unmanly tears shed. We could try to build Krita on Windows using one of the GCC ports, or we could try to build Krita on Windows using clang. We already tried to use Intel’s icc to build Krita, but that broke already when trying to build Qt. (Though that was in the early Qt 4 days, so maybe things are better now.)

But building on Windows will always be slower, because of the slow terminal and the slow file system, and we know that the Windows releases of Gimp and LibreOffice are actually built on Linux. Cross-compiled for Windows. If complex projects like those can manage, we should be able to manage too.

Unfortunately, I’m a bear^Wdeveloper of very little brain, and figuring out which blogs and articles are up to date and relevant for OpenSUSE Leap was already quite hard, and when I saw that the mingw packages for Leap were a year old, I wasn’t prepared to even put a lot of time into that.

Enter MXE. It’s a kind of KDE’s emerge, but for Linux, a bunch of Makefiles that can make a cross-platform build. It comes with a huge bunch of pre-configured libraries, though Unfortunately not everything we need.

So, using MXE, I built Qt and most dependencies. Still missing are Vc, OpenColorIO, GSL, Poppler-qt5 and openjpeg. I also needed to remove some of the hacks we did to make Krita compile with MSVC: we had added a couple of dummy header files to provide things like nothl and friends (these days superseded by QtEndian). A 3rd-party library we embed, xcftools, had its own equivalent of that stuff. But apart from that…

Everything mostly built out of the box, and the result runs in Wine (as evidenced by the “native” file dialog:

What’s left to do? Build the remaining dependencies, add translations, create a packaging script (where’s windeployqt?), and test.

Krita AppImages

Years and years ago, before Krita had even had one single official or unofficial release, we created something called “klik” packages. Basically, an iso that would contain Krita and all its dependencies and that could be used to run Krita on any Linux distribution. The klik packages were quite hard to maintain and hard-ish to use, though. It was easier than trying to build rpm’s for SuSE, Redhat, Mandrake, debs for Debian, PKG for Slackware and whatever else was out there, though.

Fast-forward a decade. Despite advances like Launchpad and the OpenSuse OBS, it’s still hard to create Krita packages for every distribution. There are more distributions, more versions, more architectures… Just maintaining the Krita Lime PPA for Ubuntu and derivatives takes a serious amount of time. Basically, the problem of distributing ones application to Linux users is still a problem.

And if you’re working on even a moderately popular application that has a moderate development velocity, if it’s an application that users rely on to do their job, you really want to provide your work in a binary form.

Distributions do a good job combining all the software we free software developers write into distribution releases; distributions really make it easy and convenient to install a wide range of applications. But there is a big mis-match between what users need and what they get:

Most users want a stable, unchanging operating system that they can install and use without upgrading for a couple of years. On top of that, some users don’t want to be bothered by desktop upgrades, others cannot live without the latest desktop. That’s often a personal preference, or a matter of not caring about the desktop as long as it can launch their work applications. And those work applications, the production tools they use to earn their money with, those need to be the very latest version.

So, Krita users often still use Ubuntu 12.04. It’s the oldest LTS release that’s still supported. But Ubuntu doesn’t support it by providing the latest productivity applications on top of the stable base, not even through backport ppa’s and if you use the Ubuntu-provided Krita, you’re stuck in what now feels like the dark ages.

Enter the spiritual successor of Klik: AppImage. AppImages sprang into the limelight when they got Linus Torvalds’ Seal of Approval. That distributing software on Linux is problematical has been a thorn in his eye for a long time, and when particularly when he started working on an end-user application: Subsurface. When the person behind AppImage created a SubSurface package, that resulted in a lot of publicity.

And I contacted Simon to ask for help creating a Krita AppImage. After all, we are in the middle of working up to a 3.0 release, and I’d like to be able to produce regular development builds, not just for Windows and OSX, but also for Linux.

Krita’s AppImage is built on CentOS 6.5 using a long bash script. It updates CentOS using the Epel repository so we get a reasonably recent Qt5, then installs an updated compiler, gets Krita, installs dependencies, builds dependencies, builds krita, checks all the output for their dependencies, copies them into a tree, edits eveyrthing to look for dependencies locally instead of on the system and packages it up with a small executable that runs the Krita executable. The one thing that was really hard was figuring out how to integrate with the GPU drivers.

You can get the recipe here: https://github.com/boudewijnrempt/AppImages/blob/master/recipes/krita/Recipe.

There are some refinements possible: AppImage offers a way to update AppImages by only downloading and applying a delta, which we don’t support yet. It’s possible to setup a system where we can generate nightly builds, but I haven’t figured out the combination of docker, travis and github that supports that yet, either. And Simon is working on an improved first-run script that would ask the user whether they would like to have some desktop integration, for instance for file handling or menu integration. All of that is in the future. There are also a handful of distributions that disable fuse by default, or close it for non-root users. Unfortunately, CentOS is one of them…

For now, though, it’s really easy to generate binaries that seem to run quite well on a wide variety of Linux distributions, that performs just like native (well, the packages is native), are easy to download and run. So I’m ready to declare “problem solved!”

A Week in the Life of a Krita Maintainer

Sunday, 10th of January

Gah… I shouldn’t have walked that much yesterday… It was fun, to see A’s newborn daughter, A, and then we went to Haarlem to buy tea and have dinner. But with a nasty foot infection, that wasn’t wise. So, no chance of serving in church today. Which means… More Krita time! Around 9:30 started the first OSX build, CentOS build and Windows build, time to try and figure out some bug fixes. Also, reply to forum posts and mails to foundation@krita.org… And prepare review requests for making Krita .kra and OpenRaster .ora images visible in all Qt applications, as images and thumbnails. Fix warnings in the OSX build. Fix deprecated function calls everywhere. Yay! Wolthera and Scott start cleaning up color stuff and the assistants gui. Dinner.

Monday, 11th of January.

Dammit, still cannot walk. But that means… More Krita time! I’m missing a whole day of income, being a small, independent enterpreneur, but I’ve got a better chance of fixing those Windows, OSX and Linux builds. Looks like OSX works fine now, Windows sometimes, but there’s still something wrong with the Linux builds. I think we need more people in our project, people who like making builds and packages, so I can go back to bug fixing. Bug fixes… Let’s fix the CentOS build issue by dropping the desktop file to json file conversion build-time. Fix a memory leak in the jpeg filter, been there for ages. Make it possible to load and save GBR and GIH brushes! Kickstarter feature lands! Not with the big rewrite of our import/export system I’d wanted to do, but it’s better now than it was, import/export can specify a mapping from filename extension to mimetype, so we can load files that the shared desktop’s mime database doesn’t know about yet. Break selecting the right style and theme — oops! Finally fix the unreadable Close button on the splash screen (when the user used a light-colored theme). User-support mail, forum posts, irc chat… Dmitry adds cut, copy and paste of layers, another kickstarter feature! Yay!!! Tonight is roleplaying night, need to prepare the adventure for my players, with maps. (Session report is here.)

Tuesday, 12th of January

Six-forty-effing-five. Alarm clock. I was dreaming of Qt builds going awry, so probably a good time to get up. Erm… Mail, more mail, and forum posts during breakfast. Orange juice, coffee, tea. Off to the railway station around 7:40. Do a couple of Italian lessons with Duolingo while waiting for the train to arrive, interspersed with Facebook Page Manager community management moments. On the train. Sleepy! Time to start working on our OSX port. Beelzy did an awesome job providing me with lots of patches, now they need to be integrated. Cool, Dmitry doing lots of cleanups! But where did Nimmy go? We really need his patch to make Krita work on OSX… Ah! And there’s the bad boy, we accidentally had the wrong application icon. Let’s remove that one, and use ours instead. And then 9:12, arrival in Duivendrecht. 9:25, arrival at the day job — Krita cannot pay my bills yet, so I’m working on a QtQuick1 to QtQuick2 port for a Dutch home automation company. Work, work, work, without a break, until 17:30, when it’s time to go back to the train. Dinner — and yay! Smjert has got his setup fixed and is fixing bugs again. Users keep mailing foundation@krita.org with support questions, and I’m just too nice… Answered. Time to go to bed, around midnight.

Wednesday, January the 13th

Exciting! Windows builds and OSX builds were working last Sunday, and today the Linux appimage builds are working on most systems! We might be able to release the pre-pre-pre-pre-pre-alpha tomorrow! And we’re creating the correct OSX application bundles, with icon! And Timothee has fixed the icon, and Jouni has started implementing importing image sequences as animations! And the alarm clock buzzed me at 6:45. Wait, that’s not yay-worthy. Refactor the PNG export dialog a bit. Work, work, work. I realize that after three months I’m one of the people at this office who’s been here longest. There are ten people who’ve been here for more than six months, twenty who’ve been here for six to three months and it seems there’s a legion who’ve just started… Fix the top toolbar sliders. And I’ve got extra-double-plus long hacking time on the train because the track is blocked and I have to make a detour via Zwolle. No, tonight I’m not going to finish the release notes or the fixed Windows (OpenGL is broken. wth), OSX and Linux packages. Time for dinner, a bath and bed. And all kickstarter rewards except for some shirts have arrived!

Thursday, January the 14th.

Gah, six colon four five. Time to get up. And I was dreaming of a bunch of kittens playing in a hay-loft that was being converted into yuppie student housing. Must be significant or something. At least I wasn’t trying to form keys out of my pillow cover so I could type “./configure” in the qt source directory, which is what my mind tried to make me do last night. Oooh! Ben Cooksley has enabled docs.krita.org, our new manual home! Exciting! People having trouble with preset files, photoshop files, krita files. Let’s try to offer a helping hand, while guzzling orange juice, tea and coffee. Dmitry adds multi-node editing of layer properties, Wolthera fixes canvas rotation. A british VFX studio tries Krita and the artists are excited — must not forget to follow-up Layer property shortcuts, drag&drop in tabbed mode and more gets pushed by Dmitry. At work, there are meetings, and more meetings. The train home fortunately isn’t delayed, because we’ve got our priest and his wife for dinner. After dinner, I go out for a beer with our priest. The barlady wonders what kind of a monk he is, is put right, and later on, after choir practice, our wives join us. No more coding tonight, I’ve had two beers.

Friday, January 15.

My last day on my current contract, but my agenda is full with meetings and things for next week. Next week is also the mini-sprint to prepare the next kickstarter. I’m guessing they’ll want to keep me, we’ll see on Monday. Breakfast. Forum posts. This guy is a bit agressive, though no doubt well-meaning. Mail. Time to get started with the spriter plugin! Jouni fixes the build… I’m fixing OSX stuff left and right, and trying to figure out howto make builds faster, and get them tested. Maybe we can release on Sunday? It’s only a pre-alpha, but still exciting! More forum posts. More work — meetings, it’s the end of our sprint, so sprint review, sprint retrospective, sprint planning…

Saturday, 16 January

I sleep until 9:30. Well, I wake up at seven, but then go back to snoozing and dreaming of the comic book scenario that’s been whirling around my mind for a while now. It’s going to be cool, if I can sit down and do something about. Fried eggs and bacon. Coffee. Orange juice. Tea. Time to fire up some more builds. Things are falling together! Some preliminary tests by other OSX users shows that my packages are okay, on recent hard, with a range of OSX versions. Figuring out the Linux and Windows builds. Some more bug fixing. Jouni pushes an even more advanced image sequence importer. In the evening, guests, but I’m too tired to go down for the Vigil service, and my foot is aching again. But I did buy new, better shoes and some pullovers, because my old shoes and pullovers were completely gone and tattered. That should help…

Sunday, January 17th.

Getting up at 8:45. Time to check a bit of mail, forward an enquiry about a Secrets of Krita download to Irina. Forum posts. This guy sure posts a lot, but it’s all bug reports. Liturgy, fortunately I can serve. Coffee afterwards, then upstairs and switch on the desktop, the windows laptop and the OSX laptop. Ah! The problem with Intel drivers and OpenGL is the same problem we’ve got on OSX: insufficient support for the Compatibily Profile of OpenGL, which breaks Qt’s OpenGL QPainter engine. Good… There’s a way forward. But first…

RELEASE!!!

Release date for Krita 2.9

After a short discussion, we came up with a release date for Krita 2.9! It’s going to be… February 26th, Deo volente. Lots and lots and lots of new stuff, and even the old stuff in Krita is still amazing (lovely article, the author mentions a few features I didn’t know about).

Then it’s time for the port to Qt5, while Dmitry will be working on Photoshop-style layer styles — a kickstarter feature that didn’t make it for 2.9.0, but will be in 2.9.x. A new fundraiser for the next set of amazing features is also necessary.

Of course, there are still over 130 open bugs, and we’ve got a lot to do still, but then the bugs will always be with us, and after 2.9.0 a 2.9.1 will surely follow. But I do care about our bug reports.

Some people feel that in many projects, bugreports are often being discarded in an administrative way, but honestly, we try to do better! Because without user testing and bug reporting, we won’t be able to improve Krita. After all, hacking on Krita takes so much time that I hardly get to use Krita for more than ten, twenty minutes a week!

We fixed, closed or de-duplicated 91 bugs in the past seven days. Of course, we also got a bunch of new bug reports: 25.

So, I want to take a bit of time to give a public thank-you to all our bug reporters. We’ve got an awesome bunch of testers!

For example, one tester has reported 46 bugs against the 2.9 betas: that is a pretty amazing level of activity! And we have by now fixed 33 of these 46 bugs. By testing betas and painstakingly carefully reporting bugs, often with videos to help us reproduce the issue, Krita has become so much better.

If you use Krita and notice an issue, don’t think that you’ll hurt us when you report the issue as a bug — the only thing we ask from you is that you do a cursory check whether your bug has already been reported (if it isn’t immediately obvious, report away, and if it’s been reported before, no problem), and that we can come back to you with questions, if necessary.

Master builds for OSX and Windows, an update

So I spent three full days trying to make working builds for OSX and Windows. Mostly OSX, with a side-dish of Windows. Here’s a short update. I’m using this git repository as a build system. It’s basically a set of cmake extern projects, one for each dependency. It’s still a mess, there are definitions for dependencies we no longer need, like glew.

Both on Windows and on OSX, I setup a development tree with this repo, a build directory for the dependencies, an install directory, a download directory and a second build directory for doing Krita development.

I’m using Qt 5.6 alpha, by the way, compiled to exclude dbus and some other things.

OSX

On OSX, there were some weirdnesses: OpenColorIO seems hardcoded to want myptch as a patch command, not just on Windows, but everywhere… That needs patching, of course, or symlinking patch to mypatch.

Eigen3 doesn’t want to build because it needs a dart file for some test setup which we don’t want to build. Patch in the cmake project.

Qt’s macdeployqt needs patching as well, the patch is in the cmake project. After building Qt with -rpath, it became necessary to manually set the rpath on desktop2json: as built by kcoreaddons, it won’t run because it cannot find Qt.

Finally, I managed to build everything including Krita. In order to run Krita, it’s necessary to use macdeployqt to deploy all plugins, libraries and frameworks to the app bundle, and then manually use install_name_tool to add @executable_path/../Frameworks to the rpaths of the executable.

But… Somehow, macdeployqt refuses to deploy the QtNetwork framework out of all Qt frameworks it deploys to the krita.app bundle. No idea why, yet, I had to stop debugging that because it was bedtime… More next weekend, but it is progress.

Windows

On Windows, I use the same kritadeposx repo: the name is wrong. When everything works, I want to add the externals definition to krita’s repo. In any case, with some coaxing, I got most things to build. Almost.

Qt was a bit of a problem: QtDeclarative just doesn’t build with Visual Studio 2015. Not sure why, for now I didn’t need that module.

Then it turned out that ki18n cannot find the gettext executable. I could bull past that by commenting out the line where it looks for it, but then the same happens when trying to configure Krita. It needs more investigation why this happens.

At that point the laptop overheated and shut down and I wasn’t motivated to start it up again, so again more next weekend… With hopefully more progress.

Done Porting!

Done Porting!

Technically, we’re done porting Krita to Qt5 and KDE Frameworks 5. That is to say, everything builds, links and Krita runs, and there are no dependencies on deprecated libraries or classes anymore. In the process, the majority of Calligra’s libraries and plugins were also ported. It was not an easy process, and if there hadn’t been sponsorship available for the porting work, it would not have happened. Not yet, in any case. It’s something I’ve heard from other KDE project maintainers, too: without sponsorship to work on the port full-time, projects might have died.

Krita wouldn’t have died, but looking back at the previous month’s work, I wonder I didn’t go crazy, in a loud way. I spent four, five days a week on porting, and fixing the porting documentation, and then one or two days on trying to keep the bug count down for the 2.9 branch. As Kalle noted, porting isn’t hard, it’s very mechanical work that despite all the scripts, still needs to be done by a human, one who can make judgement calls — and one who isn’t afraid of making mistakes. Lots of mistakes: it’s unavoidable. Most of them seem to be fixed now, though. It’s like running a racecourse in blinkers.

So, what were the hardest problems?

The winners, ex-equo are KStandardDirs to QStandardPaths and KUrl to QUrl.

The latter is weird, because, actually, we shouldn’t be using QUrl at all. The reason KUrl was used in KOffice, now Calligra, is for handling network transparent file access. That’s something I do use in Kate or KWrite, when writing blogs (my blog system is a bunch of nineties perl scripts) but which I am sure not a single Krita user is actually using. It’s too slow and dangerous, with big files, to depend on, it’s superseded by dropbox, one-drive, google-drive, owncloud and the rise of the cheap NAS. Not to mention that only Plasma Desktop users have access to it, because on all other platforms we use native file dialogs which don’t give access to remote locations. All the QUrl’s we use get created from local files and end up being translated to local filenames.

KStandardDirs is more interesting. KStandardDirs actually was two things in one: a way to figure out the paths where the system and the application can store stuff like configuration files, and a way to build a kind of resources database. You’d define a resource type, say “brush”, and add a bunch of locations where brushes can be found. For instance, Krita looks for brushes in its own brushes folder, but also in the shared ‘create project’ brushes folder and could even look in gimp’s brushes folder.

The resources part isn’t part of QStandardPaths, but is used really heavily in Calligra. The central place where we load resources, KoResourceServer just couldn’t be ported to QStandardPaths: we’d have to duplicate the code for every resource type. But there’s no problem that cannot be solved with another layer of indirection and a lump of putty, and I created a KoResourcePaths class that can handle the resource aliases. I’m not totally convinced I ironed out all the bugs, but Krita starts and all resources are being loaded.

There were a few more classes that were deprecated, the foremost being KDialog. There’s only a hundred or so places in Calligra where that class was used, and here the best solutions seemed to me to fork KDialog into KoDialog. Problem solved — and honestly, I don’t see why the class had to be deprecated in the first place.

Now all the basic porting has been done, it’s time to figure out what is broken, and why. Here’s a short list:

  • Loading icons. Right now, I need to patch out the use of the icon cache to load icons. But in any case I am still considering putting the icons in the executable as resources, because that makes packaging on Windows much easier.
  • Qt5’s SVG loader had trouble with our svg icons; that was fixed by cleaning up the icons.
  • OpenGL was a huge task, needing a nearly complete rewrite — it works now on my development system, but I’m not sure about others.
  • Qt5’s tablet support is much better, but now that we use that instead of our own tablet support, we’ve lost some performance (work is ongoing) and some things have changed meaning, which means that the scratchpad and the popup palette are broken for tablet users.
  • In general, the user interface feels sluggish: even things like the preferences dialog’s widgets are slow to react.

And when all that is fixed, there is more to do: make new build environments for Windows (hopefully we can start using MSVC 2015 now) and OSX, see about dropping superfluous dependencies on things like DBus and, then…

Testing, testing and testing!

But I am getting confident that Krita 3.0 could be something we can let people try and test this year. And here is, for your delectation, a delectable screenshot:

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.

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!

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.

Krita in history…

Krita in history…

“Azes is now being associated with the creation of the era of 58 BC that was to be known through the centures as the Krita, Malava or Vikramaditya, samvat, era. Possibly the era was also calculated for use in astronomy as the term krita, created, would suggest, but was given status by association with royalty.” Romila Thapar, The Penguin History of Early India, p. 220