Tuesday, August 15, 2006

Glucose and graphics

Today I pushed a new acceleration architecture for Xorg. Called Glucose, it uses OpenGL to accelerate X. What happens there is that Glucose hooks into the initialisation code during the graphics card setup and dispatches the X rendering calls through the same codepaths that XGL uses. The email describing it and the some reasons for it is here: http://lists.freedesktop.org/archives/xorg/2006-August/017527.html. One step closer to the Open Source graphical utopia.

Besides that I've spent the last few days working on optimising various parts of Qt's rendering architecture. From OpenGL painter, through X11 to the raster code. Just beating down graphics into submission at this point really. At first a few code paths held me in a headlock that required some repetitive "banging head on the keyboard" action on my part but now it's ok. Now, Qt just rocks at rendering vector graphics. No screenshots today though :) I started writing a real-time vector graphics cartoon fully in Qt but it's not yet finished. By the way one thing I find missing in all Open Source vector editors is that you can't just scan your sketches and put them as background to trace over, Flash does it pretty ok. Instead of complaining I probably should just go ahead and implement it in Inkscape.

Finally Paul and I sat down today to figure out semantics of OpenGL support in Qtopia Core and we got it down. I'd like to have a fair dosage of 3D support on the Greenphone.

Oh, and US Airways stole my luggage. If you ever met me you know I have (had) a great collection of shirts. Now they belong to US Airways. Oh, and my US cell was in it, so if you've been wondering why I haven't been picking up your calls lately, it's because US Airways stole my phone.

Tuesday, August 08, 2006

Magic

So lets say you're writing an application. It's a pretty good looking application too. Lets say your gui is completely vector based. It's so nice because an artist designed it! But there's a problem, a large portion of your users doesn't really like the artist's style. Furthermore accessibility wise your application is a nightmare. To add insult to injury your application doesn't match at all the color scheme of any desktop environment. What do you do?

Crying is certainly an option. One used extensively by a lot of ISV as well (with limited success). What would be really cool is if you could have an external stylesheets that the desktop environment can affect, that your users can style with accessibility features, color schemes and basically whatever people want. So one would need a highly extensive support for external CSS stylesheets in SVG. One that goes a little beyond what SVG standard offers because SVG doesn't allow styling of things like "transform" element which would be very useful for number of things.

At this point it's probably very clear that is exactly what I did today.

QtSvg in 4.2 will have full support for external CSS stylesheets. That support includes all svg properties and attributes that we use.

So lets create a very simple application that loads its UI from a SVG file and lets one style it by editing an external CSS file. The SVG file that we come up is here. We add a style, that looks like this and we're well on our way. Now we add logic to our application. In this case we'll render gears as in the ever famous GLX example, but we'll do it 2D vector style. So our application looks like this: . Neat.

K, but it's pretty gray, so lets change it. First of all we'll add
#viewport {
fill:white;
}
to make sure our background is white. Then we'll change gradient on our controls by adjusting stop-color and stop-opacity properties. Then we'll change the font on our "Gears" sign. Add a wider stroke to the control container and change the stroke on our view. Final stylesheet is here. Suddenly our application looks completely different and we haven't changed one line of code. In fact we haven't really touched the application at all but it looks like this:

Magic. Let me create a bullet points with exact description of how this works:
  1. Artist creates a gui in SVG
  2. Developer does logic in his/hers favorite language
  3. Application loads the SVG and does selective rendering (as described in the last blog)
  4. ----- magic -----
  5. Flexible, good looking, accessible, scalable application.
I take full responsibility for point #4.

But lets continue. Now lets say this application has rather small controls and some of our friends have problems clicking on some elements and reading the text. So changing colors is not what we want, we would like to make it easier to read and click on elements. It's all vector graphics, so could be zoom the whole interface? Yes! We'll add
#wholeapp {
transform: scale(2,2);
}
to our stylesheet to zoom whole application and make it look like this:


Notice that because it's vector graphics you don't get artifacts you'd normally get when zooming. One can (as in the example before) extend the borders, zoom only certain elements... Well, basically rearrange everything.

The things we can do with this are pretty amazing and I've been playing with it for the last two hours and it's a little scarry how much fun it is to change the complete look and feel of an application this way. Especially the amount of things that can be changed while keeping the application still behaving more-less like the initial version, is amazing. I hope people will have a lot of fun with this.

Friday, August 04, 2006

Shadows

Some of the questions that I get quite a lot lately are: how do I make good looking shadows with Qt4? How do I make them from SVG's? Can you show me the code?

So to answer those question in general I wrote a small application that shows how to do shadows. There's couple of ways of getting the shadows look decently. The first step is getting a black rendering of whatever it is that you want to shadow. In this example we open a QPainter on the svg rendering that we want to shadow and we fill the entire area with black color. The trick is to set the composition operation to SourceAtop, which basically makes rendered area from the SVG black - exactly what we wanted. Once we have our rendering in black we can blur it. The code for the application along a couple of SVG's is here: http://ktown.kde.org/~zrusin/examples/shadows.tar.bz2. Finally images showing the results of our demo application follow:




Fun with SVG

On top of the selective rendering of SVG's another feature that I promised to implement was the ability of rendering a SVG file/element into an arbitrary rectangle on the surface.
So one can have a SVG with some viewbox, that SVG can in turn have some element defined and one can have a surface with a whole different coordinate system and in that system have a rectangle on which the SVG element should be rendered. So in the picture it would look like this - SVG with an element mapped to another viewport with a custom bounding box.

Implementing it on top of selective rendering turned out to be rather simple. All we have to do is translate and scale (but we translate by the difference between the destination and mapped scaled coordinates of the source).

As always, I wrote a demo application to test it. In the application I have 4 SVG elements renderer at different locations within the same viewport and a circle with a radial gradient rendered on top of them. Here's how it looks:


What's pretty nice about all of this is that it makes styling applications using SVG's pretty simple. For example I wrote a simple application that renders a clock, clock is stylable via SVG. SVG contains five elements with four predefined id's "face", "minutes", "hours" and "seconds". The application loads those element into respective spots and renders them. I couldn't help myself so besides rendering them I'm dynamically generating correct shadows for SVG shapes defined in the style files. It really is pretty cool. Here are the screenshots (yeah, yeah, I didn't have any time to create really good looking SVG clocks so you'll have to live with one's I slapped together :) ).


Ideally I'd love to see applications that do custom rendering stylable in the same way. For example KOrganizer for the calendar view could easily load SVG file that defines the look of that view. This way before new KDE releases we wouldn't have to be manually changing the look of applications to match the style or make them seem more modern - we would just add a new SVG file and that's it.

Thursday, August 03, 2006

SVG on graphicsview

A lot of people has been asking for a simple way of rendering SVG files on top of qgraphicsview. The only catch was that most of them wanted it along a way of doing selective rendering of SVG files. For example people create huge SVG files and use them as collection of items. Individual elements are nested inside a group element that has a predefined xml:id. I've spent most of yesterday just fixing things in QtSvg to make it possible. The thing that makes it tricky is the following: lets say that we have a SVG fragment with the following structure:
<g transform="scale(0.5,0.5)">
  <g id="myElem" transform="scale(2,2)">
    <rect x="0" y="0" width="2" height="2"       transform="translate(20,20)" />
  </g>
</g>
So we have a group that defines a transformation matrix and inside that group we have our predefined element with id="myElem". The question is what is the bounding box of our rectangle and how do we make sure it fills out the complete area of the rendering viewport. To do that we need to find the rendered element and traverse starting from that element down through its children propagating the transformation matrix correctly. So when we're in rect out transformation matrix is defined by the rect transformation (one translating by 20 in each direction) matrix muliplied by the parent transformation matrix (scaling by 2 in each direction). So the actual bounding box of the rectangle is x=40, y=40, width=4, height=4. Having that all we need to do is set our window to those dimensions and render the element. The code to traverse the SVG tree and QGraphicsSvgItem are already in Qt so once we'll update the snapshots you'll have it.

One of the things that are possible with it is for example having an entire card deck in an SVG file and putting individual cards into predefined groups. I wrote a quick example that takes such constructed SVG files, fetches the cards from the SVG and renders them with some arbitrary transformations on QGraphicsView. A pretty nice feature of it is that I made sure the SVG file has to be loaded only once. QGraphicsSvgItem's can share the context and are capable of picking the right parts of the SVG that actually constitute their whole visual appearance. Thanks to that no unecessary parsing or processing of the SVG tree takes place. A screenshot follows :)

So now it's possible to use QGraphicsView along SVG elements. And since QGraphicsItem's handle all input events one can do pretty nice things by using SVG to define look of the items and handle the logic in the code.