My blog has been moved to ariya.ofilabs.com.

Wednesday, July 30, 2008

Be my mirror, my sword and shield

The real blog title should be: experimental live tab (thumbnail) preview in Arora.

The nice thing about hacking on WebKit is, whenever you feel you want to experiment with some whacky web browser features, you can just go ahead and implement it. The code base is clean and easy to understand. For example, I always wonder how difficult it is to have a tab thumbnail preview like in Opera, where you hover the cursor on a tab and it displays the preview of the web page in that tab. This makes it easy for you to work with dozens of tabs (I know someone in Trolltech who opens at least 30 tabs in a browser :-), because often you can have a glance of the tab before really switch to that tab.

Today [1] I decided to give it a try, of course with QtWebKit. The victim is Arora, the famous lightweight QtWebKit-based web browser. Giving it a thought, there are surely million ways to do it, from QPainter redirection, grabWidget() abuse, Widgets-on-Canvas with GraphicsView, scaled painting even to a GLWidget, you name it. As a starting point, I picked the simplest one [2]: ask the web view to render to a pixmap and scale the pixmap. After an hour or so, I got to put Arora on par with Opera, in terms of tab thumbnail preview [3].

However, the fun just starts now. Remember video with CSS reflection and HTML 5 video support? If you open a tab and plays a video there, then you switch to another tab, then hover the cursor on the previous tab, you can see that the preview is live! [4] The video even plays in that tiny little window.

Since it is impossible to show this live preview feature in a completely static screenshot, I made a 133-second screencast and put it on YouTube. See the video or watch it here:

As you can see, basically I opened three tabs: Google (0:04), a web page that plays Transformer trailer video (0:09), and another page that plays the same trailer but with added reflection effect (0:24). Then I switched back to the Google page (0:34) and placed the mouse cursor on the trailer tab (0:38). There you can see the minified trailer running nicely. Whacky? You bet :-)

There is a big room for improvement, though. For starter, I just did a hack and repainted the preview at 10 fps even though nothing has been changed in the web page (e.g. the page contains no video or animation). This needs to be optimized, say by finding out a way to update only when it is absolutely necessary. Also, the preview scaling could be better, maybe using a QGLWidget for the preview viewport so the graphics card does the scaling for use. Once real full-page zoom is landed for QtWebKit, it is also interesting to explore it for painting the preview. I'm open for more ideas, especially tricks that can push the performance.

[1] After few days only focusing on bug fixing and other usual stuff. Yes, even QtWebKit in Qt 4.4.2 will receive some love and a bunch of bug fixes.
[2] The method of course can be improved later on.
[3] The code can be found in my cloned Arora repository, under the live-preview branch.
[4] Quite a coincidence, but the radio just plays I used to roll the dice, ..... But I reckon you assume that already.

Wednesday, July 16, 2008

vim: lightning fast navigation in a large software project

Love vim but need to work with a large software project that spans a dozen subdirectories and a bazillion source files? There are plenty of solutions, vim scripts or external tools, for this particular problem. Here is one that I've used for years: using the marvelous project script.

It comprises one .vim file (the script) and .txt file (the documentation), thus dead easy to install. After that, just launch vim using: vim +Project (replace vim with gvim if you favor the GUI version), the side pane will be visible. There is where the project tree will be displayed.

For a quick start, type \C and you will be prompted to answer 4 questions, as the example below (my answers are in bold)

Enter the Name of the Entry: KOffice
Enter the Absolute Directory to Load:/home/ariya/koffice/source
Enter the CD parameter:
Enter the File Filter: *.cpp *.h *.c

which, as you might guess, create an entry with the given name from all C/C++ headers and sources from the specified directory. Wait a few seconds (or minutes, depending on the project size) for the script to scan files in your disk, at last it will show the tree (as in the screenshot above) in the project window.

You can, of course, add as many entries as you want.

Note: for optimal usage, do not forget to put this on your .vimrc file:

:let g:proj_flags="imstvcg"

For details on the meaning, see the script documentation.

Navigating the project tree is easy, if you are familiar with the vim folding. In principle, use zo and zc to open and close the fold right where the cursor is located, or zO and zC to apply it recursively, i.e. for the whole entry.

How to open a file? Just place a cursor in a file name and press Enter. Since the project window is just a normal window, switching back and forth between the project window and main editing window is as easy as Ctrl+W w. Or you can use F12 to quickly show and hide the project pane. In addition, pressing Space toggle the wide and small version of project pane.

Some more tricks. Because the project window is just a normal vim window, use the blazing fast incremental search (along with n or N) to spot the file that you want. It even does allow you to jump between different matches quickly. Again, if the project window is too narrow, hit Space to make it wider and another Space will return the width back to normal. If you press Enter on a filename to open it, a wide project window is toggled to the usual width automagically. Master this technique and you will open any file you need in an instant.

Because I love tabbed editing, I also have this in my .vimrc:

:map <C-T> <Esc>:tabnew<CR>

so that Ctrl+T opens a new empty tab. Wherever I am, I can open KSpread's Cell.cpp (to have a quick look, hence in a new tab) as fast as hitting Ctrl+T, F12, /Cell.cpp, Enter. Try to beat that.

But that is not all. You might ask: what's the use of a big file list if I don't know which file I need to open? Right, because everyone (and his dog) just needs grep. Use \G (which will use vimgrep) and type in your search string. After a while, all the matches are listed in another small window. Choose one that you want and hit Enter, all the magic ensures that the corresponding file will be opened and the cursor is right located in the matched line.

For more features, e.g. rescan the files from disk, adjust the pane width, execute a command on a file, non-global project tree, etc., refer to the script documentation.

Untap the potential of this wonderful vim script and a 3000-files project is not a burden anymore!

Sunday, July 13, 2008

from SDL to Qt: the underwater effect

Doing a real underwater after effect would involve creating a believable water caustics plus some vertex shader incantations, both are far away from my expertise and it would even have taken more than an hour I would like to spend on the rainy Sunday morning preparing an example for this week's Graphics Dojo corner. Instead, I just cheated and ported my previous SDL version of Quake-like underwater effect to use QImage, and that became the example. Since this is an animation effect, the still photo below could not really depict the idea. So, just grab the code, build it, drag-and-drop your favorite photo and stare at the result for few seconds.

Qt for doing underwater effect

Lucky to have been where I have been

Bakso (Indonesian meatballs)

This is Indonesian-style meatballs (but made from lamb instead of beef) served with noodles, soy sauce, chilli sauce and fried onions. It involved mixing mashed lamb with tapioca flour, egg white, garlic, salt, pepper, other herbs to taste and then boiling in hot water.

Saturday, July 05, 2008

dojo this week: HSV pie

Update: Fabian Jakobs has ported the Qt/C++ code to HTML Canvas and JavaScript, runnable inside a web browser.

I was having headache fiddling with some fragment programs when Helder (of SpeedCrunch fame) asked me an innocent question that eventually triggered me to write the Graphics Dojo example for this week: rendering the well-known HSV cylinder in 3-D. At first, I thought using a fragment program is the perfect solution, but considering that we are Trolls, let us write a pure Qt solution that works everywhere. So check out the code!

HSV Pie

Unfortunately, in its current state, the code is not really optimized for (near) real-time rendering. If it would have been fast enough (which I guess not really feasible with a non-OpenGL solution), we could have used it for a fancy color picker. Why use a 2-D color picker/dialog when you can have a 3-D one? I'm sure once the 3-D version is introduced, the 2-D version quickly becomes confusing for any creature on this planet.

The question now: shall I do the HSL sphere?

Wednesday, July 02, 2008

Converting between HSL and HSV

Amazingly, tons of code fragments on how to convert between RGB and HSV as well as between RGB and HSL do exist (in any imagineable programming languages). However, googling for HSL to HSV conversion did not reveal anything useful. Maybe I was blind, but there is really no point wasting minutes for something that (should be trivial). A quick glance at the wikipedia article on HSL and HSV gave me the following code:

 1 void hsv_to_hsl(double h, double s, double v,
 2 double* hh, double* ss, double *ll)
 3 {
 4     *hh = h;
 5     *ll = (2 - s) * v;
 6     *ss = s * v;
 7     *ss /= (*ll <= 1) ? (*ll) : 2 - (*ll);
 8     *ll /= 2;
 9 }
10
11 void hsl_to_hsv(double hh, double ss, double ll,
12 double* h, double* s, double *v)
13 {
14     *h = hh;
15     ll *= 2;
16     ss *= (ll <= 1) ? ll : 2 - ll;
17     *v = (ll + ss) / 2;
18     *s = (2 * ss) / (ll + ss);
19 }

Error checking is left as an exercise to the reader, corrections are welcomed. If the code seems to be cryptic, then there is a reason to take a napkin and jot some stuff there...