Category Archives: February 2006

(De-)Forming Models with SharpConstruct

Creating 3D models usually requires abstract imagination; one needs to construct and merge geometric figures together. Claus Schwarm looks at SharpConstruct which uses a different, more visual approach to 3D modelling.

Introduction

The motion picture industry uses quite a lot of it: 3D modelling skills. Due to current trends in the industry – many fantasy, science fiction, and animation related movies have been released in the last 10 or 15 years – studios in Hollywood and elsewhere continue to rely on complex 3D models.

It’s not just the movie industry. Visualization is a hot topic in many industries with the need to sell ideas, plans, and projects. After all, a picture is worth a thousand words.

Creating 3D models is a complex art; even simple 3D models may require rather detailed knowledge and hours of study, training and an in-depth knowledge of the particular tool that you’re using. SharpConstruct, however, is different.

Just like a child may use clay to model simple figures, SharpConstruct lets you use simple tools to form complex figures out of basic geometric figures. It’s as simple as a paint program for children.

You may now think that the results will probably look like a child made it. This may be true, to some extent. As with any other tool, the quality of the results depend on practice. No software will ever be able to make you create a Mona Lisa just after a few hours of using it.

However, you can expect to have fun while learning to do so.

SharpConstruct is maintained and developed by Nicholas Bishop, a seventeen year old developer from South Carolina who’s just finishing up his last year of high school. He’s supported by Timon Christl who wants SharpConstruct to be ported to the Microsoft Windows platform.

Bishop started to think about SharpConstruct in May 2004, just a year after switching to GNU/Linux. “I had been using the 3D modeler ZBrush for several years, and it was the one program that I really missed in switching away from Windows. I needed an alternative to ZBrush, one that would be free and could run on a wider set of operating systems. When I didn’t find any, I decided to give it a try myself.”

The project registered at Sourceforge in June 2004.

In the beginning, SharpConstruct used FLTK for its interface, but dropped it to use a own custom-coded, OpenGL-based solution. During last year, it was decided to switch, again. According to Bishop, the reason was the maintaince burden: “The custom OpenGL toolkit worked well, but maintaining it was taking too much of my coding time, so I decided to switch back to an external library. I looked at both GTK and QT, but neither API really struck me as being better suited to SharpConstruct’s needs than the other.”

In the end, the choice was made to use GTKmm, the C++ binding from GNOME’s binding package. Several other projects such as InkscapeK-3D or Synfig are also using GTKmm. However, the main reason was basically GNOME’s look according to Bishop: “What convinced me was installing the GNOME 2.12 desktop. I was very impressed with how the GTK look and feel had progressed since I’d last upgraded.”

He started porting SharpConstruct to GTKmm in November 2005. Just a month later, the new code hit SharpConstruct’s CVS at the beginning of December, resulting in the first release using GTKmm five weeks later. “Overall, I found the porting process to be relatively easy, largely thanks to the good documentation available for the GTK+ and GTKmm libraries,” says Bishop.

So far, reactions from SharpConstruct’s user base have been positive, according to comments in SharpConstruct’s forum. Many hope for a faster Windows port due to the switch. However, GNOME users will probably favor the additional ease of use that SharpConstruct gained by using a familiar looking interface.

First Impressions

You’ll need to start SharpConstruct from the command line as there is no menu entry created if you install from the source code. On the other hand, you’ll find its icon in your workspace switcher when running SharpConstruct, which is a nice detail. Another nice detail can be found when the application is restarted for the first time: It remembers its window size (althought it forgets its position).

SharpConstruct presents a clean, and easy looking user interface. This is an interesting innovation for a 3D modeling application. Besides the usual menu- and toolbar on the top and the status bar on the bottom, its main area is split into a left-side control panel and the main view on the right.

The menubar presents no major surprise; it’s a good mix of known and unknown entries. An application without new functionality is usually rather boring to use and unknown entries everywhere usually creates an unnecessary impresssion of complexity. Also, all uncommon entries on the toolbar have tooltips showing the care of development that SharpConstruct recieves. Beginners should activate the “Wireframe” option at the start. That will make it easier to detect some of the finer details of SharpConstruct.

SharpConstruct’s main view presents a sphere whenever you start it. To change the basic model you’ll need to start a new file as there seems to be no other way. The “New file” dialog will let you pick from a sphere, a plane, or a cube. Additionally, you can determine the amount of polygons for the model by editing the initial numbers.

Getting Started

It’s easy to understand the way SharpConstruct works: Just position your “cursor” – the red circle – on the sphere, keep your left mouse button clicked, and then move your mouse. You’ll note the sphere changes. Congratulations! You just made you first abstract art! It will probably look like a sphere with a bump.

If you’re not quite sure what happened, right-click with your mouse and move it to rotate the sphere until you have a better angle. You should see a deformation. If you’d like to get a closer look at the change, you can zoom into the view with the scroll wheel of your mouse (assuming you have a scroll wheel). Mouse movements with the middle buttom held will finally move the center of the model. If you have ever worked with an application like K-3D, navigating is a snap!

SharpConstruct is much more powerful; it is capable of much more than just turning bumps into spheres. The main tool, of course, is the red circle which is called a brush. You have four types of brushes at your disposal: a Draw Brush, a Grab Brush, a Pinch Brush, and a Smooth Brush. You have already used the first brush. For each type of brush, you can determine the kind of stroke, symmetry, and shape of the brush. This is all done on the first tab of the left-hand panel.

The two other tabs on the panel present Deformations and Settings. It’s advisable to change the Undo Steps in the Settings tab to a higher value when you first start. It defaults to a setting of three.

Beginners, however, will probably start with just two brushes: the one for drawing and the other one for smoothing.

You can also configure the characteristics of your stroke. The first two buttons determine the interaction between the model and the brush; activating Layer, for instance, makes a rather flat deformation. Changing the size and strenght of a stroke does just what is says. Your brush will additionally indicate the size of the brush by the size of the red circle.

The intensity of a stroke is not that obvious. It determines the intensity of the drawing color. To use color, you’ll need to active the RGB button, and pick a proper color in the color chooser just beside the RGB button. Let’s say you pick red and then adjust the intensity of the color to 100.

To test the basics, make a new file and this time maybe not the ususal shere but a cube. Center it by clicking View > Center (or just type the key combinationCtrl+C), zoom a little bit into the view, and then roll it down by dragging the sphere with your right mouse botton. Now just make a brush stroke with your left mouse button. You should get a glowing red bumb. Nothing new here.

Now center again and zoom into the model. Activate the X_ button for symmetry, adjust your brush size to something smaller, and then pick a nice blue color. Activate the _Sub button. Click a few times on the left side of the sphere, just where you’d expect an eye to be. Those are the first steps for an absolutely ugly “Robo Punk Model”.

You should have noted that you didn’t just make an eye, but two. The reason is of course, the activated X_ which makes every action have an symmetric action on the activated axis. Additionally, you didn’t create an ‘outer bump’ but an inner one. Again, the reason is obviously your previous switch from _Add to Sub.

Let’s attempt to add a mouth, and a nose. There!

OK, it’s not the Mona Lisa. But you were told that a little bit of practice is needed!

To smooth all the hard edges, just switch to the Smooth brush type, adjust the size and strength appropriately and try to make it less robot-like. Use the symmetry buttons to reduce the necessary work.

Of course, this is neither good-looking, nor an impressive piece of art. However, to create the same effects with a standard 3D modeling software might have required a lot more time and effort to get to this point.

Installation

Installing SharpConstruct is a two-step process on Ubuntu Linux 5.10, althought similar remarks probably hold for other distributions as well.

SharpConstruct uses a C++ binding for the GTK+ binding to the OpenGL library for its 3D magic. Confused? There’s no need to be. Just think in terms of layers. The needed library, called libgtkglextmm (“GTK+ OpenGL Extension -mm”), had released its last stable version several months ago, and thus is available in most distributions. Unfortunatly, SharpConstruct needs the 1.1.0 development version.

Step 1 is thus compiling libgtkglextmm 1.1.0 from the source.

This is rather easy with a special trick for Ubuntu users: Install the version Ubuntu provides as if you are going to to use it, and then remove it, again. This way you will satify all build dependencies for compiling the library:

 sudo apt-get install libgtkglextmm1c2 libgtkglextmm1-dev sudo apt-get remove libgtkglextmm1c2 libgtkglextmm1-dev 

Of course, regular Debian and Ubuntu users will complain that this is not the proper way to do it! Indeed, one should use “apt-get build-dep $package” to do this properly. But you need the source code repository adresses in your list for it to work.

You’re probably now wondering what the difference between these version are if it’s sufficient to use the dependecies of the old version. We need a more recent version of a library, namely the GTKmm libraries. That’s not a major problem; we would have needed them in the next step anyway.

 sudo apt-get install libgtkmm-2.4-dev 

With the build dependencies installed, download the 1.1.0 development version from Sourceforge and do the usual three steps of _./configure_, make, and sudomake install. You should get a few new libraries under /usr/local/. In the end, you will just need to add two symbolic links otherwise SharpConstruct won’t be able to find the libraries. The commands look a little bit strange but there’s nothing to worry about:

 sudo ln -s /usr/local/lib/libgdkglextmm-x11-1.1.so.0.0.0 /usr/lib/libgdkglextmm-x11-1.1.so.0 sudo ln -s /usr/local/lib/libgtkglextmm-x11-1.1.so.0.0.0 /usr/lib/libgtkglextmm-x11-1.1.so.0 

Now you can start step 2 by installing SharpConstruct. It’s a GTKmm application using Glade so you will need a few more libraries. SharpConstruct’s homepage provides no list of its required dependencies but since we built one from source, installed another one to do so, there’s just one open, libglademm. The following command should install all necessary pieces for you:

 sudo apt-get install libglademm-2.4-dev 

When you now do the usual three steps, again: _./configure_, makesudo make install, SharpConstruct will be built and installed under /usr/local.

You can spare the last compilation step by using a pre-compiled binary available on the SharpConstruct’s homepage. However, without the proper version of libgtkglextmm, this is not very useful. Compiling the required library was the most complicated step; building SharpConstruct is then just a small step to do.

The need for a development library of the GTK OpenGL Extensions is currently SharpConstruct’s major flaw. In fact, it’s a shame that it’s possible for such a library to become unmaintained, and remain so for over two years. Fortunatly, a new maintainer volunteered recently: Timothy M. Shead. Regular GNOME Journal readers will remember him as the creator and developer of K-3D.

Hopefully, someone will find the time to provide a proper autopackage of SharpConstruct soon – one that uses static linking for the problematic libraries. That’ll make installation of future versions much easier.

Conclusion

SharpConstruct is easy and fun to use. This makes it absolutely great. And did I forget to mention that it’s stable. Given the low version number, 0.11, and its history of interface switches, that’s amazing.

Bishop, who’s currently waiting on answers from colleges where he applied to study computer science, is, of course, not yet satiesfied with SharpConstruct: ”[It] is still not even close to a complete replacement for ZBrush, but it’s definitely useful for easy creation of organic models.”

Thus, he continues to improve SharpConstruct whenever possible: “Right now I’m implementing surface reconstruction algorithms, which will take a 3D model as input and output a clean, evenly subdivided model. Better polygon tools will help obviate the need to create low-poly base mesh in an external program.”

He’s also looking to improve the interface to be more user-friendly: “The response to the new interface has been generally good, but there’s a lot of room for improvement by making better use of GTK’s widgets. For example, a model-preview widget could be added to the Open dialog, and time-consuming operations, such as subdivision or model loading, should display a progress bar.”

Let’s hope his studies will allow him to continue to work on Sharp Construct. A larger community of supporters could help him; the manual, for instance, is still showing the old interface. However, given the fun of using SharpConstruct, there’s a good chance it will find many fans. I know that I’m a fan for sure.

Discuss this story with other readers on the GNOME forums.

Advertisements

Writing a Widget Using Cairo and GTK+2.8, Part 2

In this article Davyd Madeley continues his tutorial on writing a clock widget using GTK and Cairo.

Thinking back to last issue, we used Cairo to build the face of a clock as part of a GtkWidget we called EggClockFace. We covered the basics of writing a GObject and drawing in the expose hander with Cairo, but what about making the clock run?

Step 3. Making it Tick

Making the clock run is as simple as starting a timer that calls a callback. However, we might also want to be able to set a different time on our clock, so we’ll store the time for the clock inside the widget. We don’t want to let people change the time directly, as then we won’t know that the time has been changed. Instead, we want them to have to use the public API we provide to change the time on the clock. In object-orientation speak, we want to make the time variable private.

We can add a structure of private data to the top of our C file. We add it to the C file rather than a header since it is private to this class (which is contained within this C file) and we don’t want to clutter our namespace with it (or let it be accessed from outside our class).

Add this to the top of your clock.c:

 typedef struct _EggClockFacePrivate EggClockFacePrivate; struct _EggClockFacePrivate { struct tm time; /* the time on the clock face */ }; 

We’ll also want to add a macro for easy access:

 #define EGG_CLOCK_FACE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EGG_TYPE_CLOCK_FACE, EggClockFacePrivate)) 

Finally, register this private struct with the class at the end of egg_clock_face_class_init():

 g_type_class_add_private (obj_class, sizeof (EggClockFacePrivate)); 

Doing this means that we can access our private variables from any function in this C file, as long as we’re passed our EggClockFace object. We get our private struct like this:

 static void egg_clock_face_example_function (EggClockFace *clock) { EggClockFacePrivate *priv; priv = EGG_CLOCK_FACE_GET_PRIVATE (clock); } 

You can then access the member variables as you might expect, for example:

 localtime_r (&timet, &priv->time); 

We can put this all together into a function we’ve called egg_clock_face_update() which will update the clock with the new time:

 static gboolean egg_clock_face_update (gpointer data) { EggClockFace *clock; EggClockFacePrivate *priv; time_t timet; clock = EGG_CLOCK_FACE (data); priv = EGG_CLOCK_FACE_GET_PRIVATE (clock); /* update the time */ time (&timet); localtime_r (&timet, &priv->time); egg_clock_face_redraw_canvas (clock); return TRUE; /* keep running this event */ } 

Notice that this function returns a boolean value (true). Functions passed as timeout events return a boolean value. If the value is true, the event will be run again; if the value is false it will not. There is also a function that we haven’t defined yet, egg_clock_face_redraw_canvas(). This function will redraw the canvas for us. From the manual page for GtkDrawingArea (our parent class), we are told to use gdk_window_invalidate_rect(), to reexpose the canvas (and cause it to redraw). Again from the manual, we can see that this is a wrapper around gdk_window_invalidate_region() and that in order to make our event happen now, we should also call gdk_window_process_all_updates(). Our redraw function looks like this:

 static void egg_clock_face_redraw_canvas (EggClockFace *clock) { GtkWidget *widget; GdkRegion *region; widget = GTK_WIDGET (clock); if (!widget->window) return; region = gdk_drawable_get_clip_region (widget->window); /* redraw the cairo canvas completely by exposing it */ gdk_window_invalidate_region (widget->window, region, TRUE); gdk_window_process_updates (widget->window, TRUE); gdk_region_destroy (region); } 

Drawing the hands requires us to think about a little geometry. For the hour hand, the hand is rotated around 30� for each hour and then a �� more per minute.

So to draw the hour hand, we might do something like:

 cairo_save (cr); cairo_set_line_width (cr, 2.5 * cairo_get_line_width (cr)); cairo_move_to (cr, x, y); cairo_line_to (cr, x + radius / 2 * sin (M_PI / 6 * hours + M_PI / 360 * minutes), y + radius / 2 * -cos (M_PI / 6 * hours + M_PI / 360 * minutes)); cairo_stroke (cr); cairo_restore (cr); 

The minute hand and the seconds hand each rotate 6� per minute/second. The minute hand is easily implemented as:

 cairo_move_to (cr, x, y); cairo_line_to (cr, x + radius * 0.75 * sin (M_PI / 30 * minutes), y + radius * 0.75 * -cos (M_PI / 30 * minutes)); cairo_stroke (cr); 

Finally, we need to set it running, in egg_clock_face_init() we will add our timeout function:

 static void egg_clock_face_init (EggClockFace *clock) { egg_clock_face_update (clock); /* update the clock once a second */ g_timeout_add (1000, egg_clock_face_update, clock); } 

We’re left with clock-ex4.c (get clock.h and main.c if you need them), which you can compile with:

 gcc -o clock `pkg-config --cflags --libs gtk+-2.0` clock-ex4.c main.c 

and should look like this:

Extra: Making the Picture Tick

The animated GIF of the clock ticking was done with a tool called byzanz. I simply recorded 60 seconds of the clock. In order to find out the window location for byzanz-record, I added this to my main.c after gtk_widget_show_all():

 { GdkRectangle rect; gdk_window_get_frame_extents (window->window, &rect); g_print ("-x %i -y %i -w %i -h %i\n", rect.x, rect.y, rect.width, rect.height); } 

This printed settings that I could paste onto my other command line:

 $ ./byzanz-record -d 60 $GEOMETRY -l clock.gif 

Step 4: Emitting Signals

So far we’ve written a GObject with opaque property storage and we’ve used Cairo to draw our clock face. However the GTK+ widgets we commonly interact with also offer public APIs and emit signals to notify us when certain events take place. We will add a signal to say when someone is dragging the minute hand around.

Firstly we need to decide on what our signal is going to send and add this to our clock.h. We will implement a “time-changed” signal that along with the object also gives the time in hours and minutes that the clock has now been set to. If we were connecting this signal, our callback would look something like this:

 static void time_changed_cb (EggClockFace *clock, int hours, int minutes, gpointer user_data) { ... } 

In clock.h we would add this to _EggClockFaceClass:

 void (* time_changed) (EggClockFace *clock, int hours, int minutes); 

We need to do several things in clock.c, firstly we need to define enumerated values for all of our signals:

 enum { TIME_CHANGED, LAST_SIGNAL }; 

And we then need to define an array of unsigned ints to store their signal IDs in:

 static guint egg_clock_face_signals[LAST_SIGNAL] = { 0 }; 

Finally we need to register our signal in egg_clock_face_class_init():

 egg_clock_face_class_signals[TIME_CHANGED] = g_signal_new ( "time-changed", G_OBJECT_CLASS_TYPE (obj_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (EggClockFaceClass, time_changed), NULL, NULL, <em>clock_marshal_VOID</em>_INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); 

More information on g_signal_new can be found in the documentation. Notice the rather strange symbol there: `clock_marshal_VOIDINT_INT`. This is our marshaller. By default, GTK+ provides us with a useful set of common marshallers, all of which start with g_cclosure_marshal and are of the format `prefix_RETURNTYPE_PARAMETER_PARAMETER_etc`. A marshaller is unfortunately not provided for `VOID_INT_INT` so we will have to generate our own.

This is actually very easy to do, we simply define it in a file clock-marshallers.list, which contains a list of the marshallers we wish to generate. For example:

 # these marshallers are generated with glib-genmarshal(1) VOID:INT,INT 

To generate source files and headers for these marshallers, it is easiest to write a simple Makefile, for example:

 all: clock clock: clock.c clock.h main.c clock-marshallers.c clock-marshallers.h gcc -g -o clock clock.c main.c clock-marshallers.c \ `pkg-config --libs --cflags gtk+-2.0` clock-marshallers.c: clock-marshallers.list glib-genmarshal --prefix _clock_marshal --body $< > $@ clock-marshallers.h: clock-marshallers.list glib-genmarshal --prefix _clock_marshal --header $< > $@ 

You can see the ‘clock’ target depends on clock.c, clock.h and main.c which we have, but it also depends on clock-marshallers.c and clock-marshallers.h which we don’t, so we define additional targets to generate them from our marhallers list. You will need to make sure that you #include clock-marshallers.h into clock.c in order to get the symbols we generated.

This kind of code autogeneration is designed to make things easier for programmers without requiring them to write repetitive marshaller code over and over again. This is especialy useful if you have lots of signals. Of course, there is nothing wrong with either writing the marshallers yourself, or simply using a generated marshallers list, but why would you? Doing so only makes it harder to add or edit signals later on.

Next we have to implement a button-press-event handler so that we can determine when someone has actually clicked on a hand. We can override the signals for button-press-event, button-release-event and motion-notify-handler at the same time as replacing the expose-event. In egg_clock_face_class_init():

 widget_class->button_press_event = egg_clock_face_button_press; widget_class->button_release_event = egg_clock_face_button_release; widget_class->motion_notify_event = egg_clock_face_motion_notify; 

From reading the documentation for GtkDrawingArea, our parent class, you will see that button events and motion events are masked out, so we will need to set them so that we receive events for processing. We need to do this for each EggClockFace, so in egg_clock_face_init() we’ll add:

 gtk_widget_add_events (GTK_WIDGET (clock), GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); 

The line formed by the bearing of the hand is infinitely thin, so we can’t expect a user to be able to click on it. It would be nice to detect if the user clicked within 5 pixels of the line. To do this we require some more geometry.

We know that (sin ?, cos ?) is a point on the unit circle, that is it has magnitude 1. Thus a vector from the origin to (sin ?, cos ?) will be a unit vector, we will name it l. We will also take a vector p which is the vector from the origin to the point where the user clicked.

This would give vector components equal to:

 px = event->x - clock->allocation.width / 2; py = clock->allocation.height / 2 - event->y; lx = sin (M_PI / 30 * minutes); ly = cos (M_PI / 30 * minutes); 

Simple reasoning will tell us that there exists a point ul where l is perpendicular to (ul – p) (which is the shortest distance between the point and the line and is what we want to measure).

We can project p onto l using the dot product such that u = p.l. The dot product can be done mathematically like so:

 u = lx * px + ly * py; 

If u comes out to be a negative number we’ll ignore it, this means that the user clicked on the opposite side of the clock to where the hand is. Finally, the magnitude of the distance can be found. If the magnitude of the distance (squared) is less then 5 pixels (squared) we can set a private property dragging to be true (we used squared values here because we have no need to do a slow sqrt()).

 if (u < 0) return FALSE; d2 = pow (px - u * lx, 2) + pow (py - u * ly, 2); if (d2 < 25) /* 5 pixels away from the line */ { priv->dragging = TRUE; } 

We now need to implement handlers for the motion_notify_event and button_release_event. Both of these signal handlers share a lot of their code, so we can move it out into another function, emit_time_changed_signal(). The geometry for this function is simply the reverse of the geometry that we used to draw the hands on the clock face.

 static emit_time_changed_signal (EggClockFace *clock, int x, int y) { EggClockFacePrivate *priv; double phi; int hour, minute; priv = EGG_CLOCK_FACE_GET_PRIVATE (clock); /* decode the minute hand */ /* normalise the coordinates around the origin */ x -= GTK_WIDGET (clock)->allocation.width / 2; y -= GTK_WIDGET (clock)->allocation.height / 2; /* phi is a bearing from north clockwise, use the same geometry as we * did to position the minute hand originally */ phi = atan2 (x, -y); if (phi < 0) phi += M_PI * 2; hour = priv->time.tm_hour; minute = phi * 30 / M_PI; /* update the offset */ priv->minute_offset = minute - priv->time.tm_min; egg_clock_face_redraw_canvas (clock); g_signal_emit (clock, egg_clock_face_signals[TIME_CHANGED], 0, hour, minute); } 

The time-changed signal is actually sent to all listeners by g_signal_emit. You may also notice the variable minute_offset, we use this to know how far out of phase the minute hand is with the current time. This offset has to be added to any other requests for the current time. I will leave it as an exercise to the reader to implement a similar offset for the hour hand.

After all of this our two signals handlers from above are simply:

 static gboolean egg_clock_face_motion_notify (GtkWidget *clock, GdkEventMotion *event) { EggClockFacePrivate *priv; int x, y; priv = EGG_CLOCK_FACE_GET_PRIVATE (clock); if (priv->dragging) { emit_time_changed_signal (EGG_CLOCK_FACE (clock), event->x, event->y); } } static gboolean egg_clock_face_button_release (GtkWidget *clock, GdkEventButton *event) { EggClockFacePrivate *priv; priv = EGG_CLOCK_FACE_GET_PRIVATE (clock); if (priv->dragging) { priv = EGG_CLOCK_FACE_GET_PRIVATE (clock); priv->dragging = FALSE; emit_time_changed_signal (EGG_CLOCK_FACE (clock), event->x, event->y); } return FALSE; } 

Of course, in order to find out when our signal is emitted, we only need to connect a signal handler to the clock in main.c:

 g_signal_connect (clock, "time-changed<a href=":time-changed">, G_CALLBACK (time_changed_cb), NULL); static void time_changed_cb (EggClockFace *clock, int hours, int minutes, gpointer data) { g_print (</a> - %02i:%02i\n", hours, minutes); } 

Putting it all together, you should have clock.cclock.hmain.cclock-marshallers.list and the Makefile.

That’s it! You now know how to implement a GObject, draw things inside that GObject, add private data, add signals and animate the object. This forms pretty much everything you need to write your own GtkWidget.

Discuss this story with other readers on the GNOME forums.

Behind the Scenes: Jeff Waugh

Lucas Rocha launches the Behind the Scenes series which aims to bring informative and entertaining profiles of people who contribute to GNOME. This is based on “The People Behind KDE” initiative. In this issue, he interviews Jeff Waugh, the perky pants guy. Enjoy!

A Short Intro

  • Age: Dum-de-dum… 🙂
  • Located in:: Sydney, Australia
  • Profession:: Ubuntu Business & Community Development for Canonical Ltd
  • Nickname on IRC: jdub (freenode and gimpnet)
  • Homepage and blog: http://perkypants.org/blog/

Interview

In what ways do you contribute to GNOME?

I’m the Release Manager Emeritus, which means that I can safely worry myself to sleep, but not have to do anything about it. The ‘emeritus’ bit is a meme that Luis and I are attempting to propagate… He’s Bugmaster Emeritus. It’s catching on. Sort of. 😉 Having done release management, GARNOME, all kinds of odd jobs around the place and maintaining Planet GNOME, I’m mostly taking a breather and looking for my next big project within GNOME. I’m back on the Foundation Board this year, too.

How and when did you get involved in GNOME?

I had been hanging about on the periphery and using GNOME since around 1999, slowly coming to the realisation that my meagre coding skills were not going to be the most useful way for me to contribute back – I was no match for the hackers already working on GNOME – so I’d have to find something else to do. In late 2001, the Foundation Board asked for volunteers to help with the 2.0 release process, so I signed up to help in any way I could. By December, the 2.0 release manager, Maciej Stachowiak, was way too busy at his new job, and I had essentially taken on his role… Though I didn’t quite see it that way until he emailed me to suggest I take it on officially. That was a surprise. Since then my involvement in GNOME, and my involvement in Free Software, has snowballed. 🙂

What motivates/keeps you motivated to work on GNOME?

The unbeatable combination of moral philosophy and design philosophy, and of course, the awesome people and community.

How much time do you usually spend on GNOME?

What my employer and Pia do not demand of me, often to the detriment of my sleeping patterns. 😉

Which distribution do you use? Why?

Ubuntu, always on the developer branch, because it keeps me at the cutting edge of GNOME… and the rest of the Free Software world! I’ve always felt that Debian got so many things right – I’m really enjoying the opportunity to take GNOME, Debian and FREEDOM to the masses through Ubuntu.

What is the GNOME’s killer app? Why?

There are no killer apps. 🙂 I am quite serious about that. If we look at the kinds of things we describe as ‘killer apps’, they’re almost always killer network effects. Look at the success of LAMP – which is the killer app? Is it Linux, Apache, one of the Free databases, or one of the Free languages that rocks for web stuff? None of them. It was a network effect, from cheap commodity hardware through a capable and flexible software stack, and the massive expansion of commerce on the web. Same with the iPod. It’s not a killer device – it’s just good quality hardware, matched with a strong network effect between it, iTunes and ITMS. I’d love readers to think about the kinds of network effects we can employ to drive GNOME adoption!

What does your desktop look like?

Rather like the default Ubuntu layout, though on my laptop I’ve removed the bottom panel. I disable the minimise button in metacity, because I never do it, and I don’t have the silly window switcher applet taking up space. 🙂

Which book is on your bedside table?

  • No Logo by Naomi Klein
  • Will in the World (a biography of William Shakespeare)
  • In the Beginning (a History of the King James Bible)
  • The Road to Airstrip One (a biography of George Orwell)

Who or what in your life would you say influenced you most?

I think I missed out on the wise, inspirational sensei/role model/mentor figure! That would’ve been a convenient answer to this question. In reality, I don’t think the things that sharpened and rounded my personality are going to be pleasing stories, but the hunger and drive had to come from somewhere.

How would you describe yourself?

Perky. Pants. Perkypants.

What do you get passionate about?

  • User experience
  • Community
  • Performance, song and writing
  • Defending the ‘Big Freedoms’ through Free Software
  • Connecting good dots
  • A growing interest in proper installation of airconditioning systems
  • Pia – she’s the turbocharger under my hood and nitro in my fuel tank

What sites do you visit daily?

Lots of Planets. 🙂

Free Software or Open Source?

I see them as two sides of the same coin, but ultimately, what excites me is Freedom and community, not Process and methodology. 🙂

Married, partner or single?

Married to Pia.

If you have a partner or children, how do they cope with a GNOME addict?

Given that Pia is also deeply involved in the Free Software community, most people who see us in action are concerned about how the rest of the world is going to cope with us. 🙂

If someone visits your country, which spot is a must-see?

linux.conf.au 2007, which will be held in Sydney in January! 🙂

Quickies

A personality?

Do you mean like… “anal retentive”… “Reese Witherspoon”… or both?

A phrase?

“A problem worthy of attack, proves its worth by fighting back.” – Paul Erdos (with the funny O, which I can’t type)

A movie?

UHF, “Weird” Al Yankovic’s insane movie from the early nineties. Go see it.

A food?

Sashimi, wasabi, soy. Can’t go wrong.

A place?

The energy centre of the Earth, according to the Dalai Lama, is where a set of limestone boulders sits in a glacial plain somewhere between Christchurch and the west coast of New Zealand. Glynn Foster (Gman, and the Face of Sun Microsystems) took Pia and I there on our recent trip to New Zealand (where linux.conf.au was held this year).

A text editor?

vim.

A band?

Radiohead.

A song?

Candy by Iggy Pop (with Kate Pierson from the B-52s). I’ve been listening to it quite a bit lately. No idea why.

Discuss this story with other readers on the GNOME forums.

Marketing GNOME Part Two: Segmentation, Targeting and Positioning

John Williams takes you through some of his own thoughts on marketing in general and how that applies to GNOME as a product that will compete effectively in a very cut-throat market. This is the second installment of a series on marketing.

Introduction

This is the second article in a series about marketing GNOME. The first article focussed on issues of branding and the need for market research. In this article I will examine some ideas about market segmentation. Almost none of these ideas are original to me. They evolved from conversations held on IRC, on mailing lists, and captured on live.gnome.org website. I hope to suggest some ideas for discussion and debate, and suggest a way to proceed on these issues. I do not claim to have any answers, only a framework for working toward them.

First, a bit of marketing theory:

In the marketing world there exists a triple STP: “Segmentation, Targeting, Positioning”. The reason why they are a triple is that they should almost never be analysed or discussed in isolation.

Market segmentation is about the recognition of diversity within a market, i.e. that not all customers in a given market have the same needs. Furthermore, these differing needs may be so different that separate marketing strategies or tactics are necessary for particular sub-markets or “segments”. If that is so, the segments need to be explicitly defined, and separate marketing actions need to be planned with respect to each segment.

This is, of course, predicated on the understanding that we know who “the market” is. This is often a very tricky question. One way to approach a solution is to ask “Who or what else is the customer choosing between?” when we want them to choose us. In other words, what are the substitutes for GNOME? If not GNOME, then what?

Target marketing is about selecting those segments that the organisation is willing and able to service. Any given segment may be attractive in some way, but not able to be serviced due to the particular mix of capabilities within the organisation.

Positioning is about differentiating the organisation’s offering(s) from that of the competition in the minds of the customers in the chosen segment.

One of the biggest and most often repeated mistakes that people make when segmenting a market is to split the market on the basis of easily observable characteristics of customers (for example age, sex, education, income). This is silly. The correct way is to segment the market on the basis of the differing desires (needs, wants) of the market.

Now, the application in our context to GNOME:

Who are the “customers” of GNOME, and what do they want from GNOME and its substitutes? I do not have the answers to these questions, but I can make some guesses. At the very least GNOME and KDE define a market, in some sense. (Are there any Linux distributions that don’t use one of these DEs?) We are reduced to the question: “What do people want from a Linux/Unix Desktop Environment?”. From there we can ask “In what major ways will the wants of customers differ from one another?”. Again, I have no definitive answers to this, but I can make some guesses.

  • Distributions want a desktop environment that is easly branded, i.e. adaptable for their uses, with easy ways to change strings in messages, artwork, and default URIs etc. Also desirable are fast change cycles (ideally synched to the release cycles of the distribution) are also desirable.
  • System administrators want a desktop environment that is easily configured for thousands or tens of thousands of users. They also want stability and long change-cycles. Fast bug-fixes (especially security fixes) that are easily deployable are also needed. The ability to lock down configurable aspects of the environment is also necessary. Help and support is vital, and paying for it is no problem.
  • Corporate users want simplicity, usability, stability and long change-cycles.
  • Home users and hobbyists want the latest, greatest and coolest features, simplicity (note: simplicity and power/flexibility) and security. Note that these needs are similar even though the technical knowledge of these people ranges from almost zero to as much as it is possible to have. What they use the computer foris similar (with the exception of development, almost by definition) but the way they use it is different. Tellingly, they are often—- but not always, of course—- willing to sacrifice performance and stability for “bling”.

People who have followed similar discussions may be surprised that I have not included ISVs (Independent Software Vendors) in the above analysis. It is frequently mentioned that GNOME lacks good developer documentation and that this hinders ISVs from contributing to GNOME. This is arguably true, but in this article I want to concentrate on the desktop environment aspect of GNOME as opposed to the developement platform aspect.

Note how the desires of groups (1) and (4) are in direct contrast to those of groups (2) and (3). These are obviously broad generalisations, but I believe that they are sufficiently close to the “truth” that we can learn something: GNOME needs separate marketing strategies for distributions and home users, as opposed to system administrators and corporate users. Furthermore, perhaps we need to decide whether we are willing and able to serve all four markets. Can we? And if so, should we?

The “should we?” question is about target marketing. We want to choose the market segments that are attractive to us, and that we can compete effectively in (if we are in fact in a competitive situation). I am, of course, thinking about KDE here. It seems fairly obvious to me that KDE has a particular “feel” about it that contrasts with GNOME. It is also obvious to me that each desktop environment can play to its strengths and acheive its goals without encroaching on the other’s space. This freedom can be enhanced by interoperability. This seems paradoxical (I seem to be saying make it easy to switch, or—- horrors—- “defect”) until one considers how customers react to the perception that they are being “locked in” to a product choice. Freedesktop.org is our friend here. We must never forget that GNOME and KDE share the common goal of liberating our fellows from the opression of proprietary software. It’s all about that most boring and repetitive of questions: “Is Linux ready for the desktop?”. When do we want to be able to answer, confidently and truthfully, “yes”? I am fairly certain we can’t do that yet, for the unsupported home user. But how long are we willing to wait before we can say “yes”? A year? Two? Five? Ten?

It is often remarked these days that “in the battle for the desktop, free is not good enough.” Many, many people use software that they haven’t paid for, in the sense that their parent, school, employer or government paid for it. (And many people don’t realise that they are paying for Windows when they buy a new PC). Additionally, and sadly, many people don’t care about software freedom. To woo these people away from their invisible chains, we must be at least as good as, and probably much better than, their current option, along dimensions that matter to them. In this article I have made some guesses about the things that matter, but empirical research is needed to assess how good these guesses are.

Progress

So, have we made any progress here? Is there anything here that we don’t know already? For some people who are involved with distributions, or the governance of GNOME and KDE, all of this may be old hat (or wrong!), but it is for the people who don’t hang out on the mailing lists, IRC channels and wikis that I am writing this article. So, where do we go from here?

Firstly, the GNOME community must decide where to concentrate its efforts when considering the improvements that can and should be make to GNOME. My money is on system administrators and distributions, simply because they are capable of big victories. One system administrator can make descisions that affects thousands or tens of thousands of users. They are the “low hanging fruit”. Similarly with distributions, although, as noted, these two groups need a separate strategy. But they share a similar technological thread: the behind-the-scenes managability and configurability of GNOME, as opposed to user-visible features and aesthetics. (At this point I should note that I would much rather help develop a desktop environment that was for the home user that emphasised personal power and freedom. So I am not advocating a course that I have an emotional committment to. But that’s another story).

Secondly, distributions and system administrators like documentation, plans and schedules. The current roadmap for GNOME, such as it is, is more like a community scratchpad than a plan (Maybe the “real” planning is behind closed doors? I doubt it, but these sentiments have been raised and probably need to be addressed)? I think that we can serve our customers better by creating a more detailed plan. This brings me to my third and final point.

We need to get distributions and sysadmins more involved with the GNOME planning and the entire development process. In short we should “market with” rather than “market to” them (This is my academic hobby horse coming to the fore). Rather than GNOME “creating value” which we can then “deliver to the market,” we need to co-create value for GNOME and its consumers with those consumers. I could go on about this, but I am trying to restrain myself 🙂

Conclusion

What can we do right now? Form separate (but integrated!) groups to manage the aspects of GNOME that are relevant for distributions on the one hand, and system administrators on the other.

That is all, until next time.

Discuss this story with other readers on the GNOME forums.

GStreamer 0.10 – What’s in it for the Users

Christian Schaller shows what the GStreamer team has been working on for the new 0.10 release. With new additions like an automatic plugin registry, support for the RTP protocol and greatly improved playback support, you’ll want to keep on reading!

Introduction

The newest version of GStreamer, the Gnome multimedia framework, was released just before Christmas. Its release announcement described the new features available to developers but neglected to talk about its improved user experience. This article will introduce the improvements users will notice as they upgrade from 0.8 to 0.10 and offer some background into what makes them possible. Of course, because GStreamer is a library, many applications will need to be updated to benefit from these features.

Background

It became clear to the GStreamer development community that, after two years of development, version 0.8 was suffering from a number of fundamental design flaws For instance, threading was added 0.8 almost as an afterthought so it was predictable that it would suffer from a number of threading issues. Stressing the framework would easily lead to crashes, especially on hyperthreaded or multi-CPU systems. Also, performance was bad when seeking or switching files, leading to a poor user experience. Fixing these flaws would require some rather large changes.

Now that hyperthreaded and multithreaded systems are becoming popular, it was clear that the project should create a strong threading model and then write GStreamer to fit that model. It was quite common for an old GStreamer application to become unresponsive. In fact, if you ever tried moving the seeker bar inTotem back and forth at rapid speed in GStreamer 0.8 you will probably see a segfault. The new GStreamer should not crash and will even show the images blurring by as you scan. Even though 0.10’s internals are very different from 0.8’s, care was taken to ensure that its API remains very compatible. Sound Juicer was ported in one day.

Fixed Registry

Most of the support requests in the #gstreamer IRC channel came from people whose GStreamer applications were refusing to use their installed plugins. This was usually because the registry of usable plugins, manually updated by the package installation system, was updated wrong. While things improved during the lifetime of 0.8 as distributions took more care to run gst-register, it still caused a lot of grief. GStreamer 0.10 registers plugins automatically so they automatically made available and gst-register no longer exists.

Improved Packaging

Most distributions, for legal reasons, only ship a small subset of GStreamer 0.8 plugins. Because GStreamer’s plugins are built from the same source module, each packager was forced to split it up to remove components that were illegal or unwise to use in their particular area of operation. The amount of custom code caused a number of problems for users. To solve this, 0.10 has five plugin modules called base, good, ugly, bad and ffmpeg. Base and good contain plugins that any distribution can ship without fear of potential legal issues. Ugly contains well-maintained plugins which may or may have legal issues of some form, generally patent or license issues. Bad is an incubation area where new plugins mature before moving to good or ugly. If a plugin never matures, it may remain in bad for the rest of its life. ffmpeg contains wrappers for all the codecs in the ffmpeg package. This new scheme will allow downstream packagers to have more consistent package naming and installation scripts, making it easier for users to discover and install the plugins that they need.

The base package is not intended to contain all the plugins required by a typical GStreamer setup. Instead, it contains one important example of each type of GStreamer plugin. The code and documentation for base plugins will remain current so developers will always be able to create new plugins from a known working code base.

Better Playback System

While playback in 0.8 did become quite good, it would never meet the high standards of the GStreamer team. 0.10 provides the infrastructure required for a much better playback experience. Switching tracks is very fast now, as close to instant as possible. Seeking should be much more responsive and the return to playback after seek is also very clean. A fun little feature of the new architecture is that if you seek in an audio file (in Totem for instance) and have a visualization active, you can watch the visualization change along with the seeking.

Audio and Video Syncronisation

GStreamer 0.10 has functions that should ensure 100% A/V syncronisation even for very long streams. For instance if you used Thoggen to RIP DVD’s with 0.8, you might have experienced that audio and video slowly drifted apart as the movie played. In 0.10, no matter how long the stream is or how often you seek around in the stream, the audio and video should stay locked together. GStreamer also features a system allowing synchronized recording from multiple sources, like a webcam and your soundcard microphone which will give a better result for applications like Flumotion and video conferencing systems like Farsight.

Improved Plugins

In 0.8, many plugins that should have worked together would somehow fail. This was especially true for less-used plugins that lacked the developer time required to shake out all the corner cases. For instance, sending audio to to alsa, oss, esound, and artsd should be a straightforward operation, yet each back-end had its own idiosyncrasies that needed to be worked around. An operation that would work perfectly for one person would fail horribly for another, and it would be entirely unclear just where the difference was. To solve this, 0.10 plugins now derive from a base class that handles the common operations. This allows all plugins to share a lot more code. It’s possible for work on the most important plugins to benefit those with a smaller audience too. Ultimately, this code sharing will ensure that plugins will now behave much more consistently.

GStreamer 0.10 also makes it much easier to integrate applications into the various desktop environments. Old applications would link against a tiny helper library to access the GStreamer gconf keys. In 0.10, GConf is supported by a set of plugins. Both a Gtk-only application like bmpx or a Qt/KDE application like Amarok can use the GConf plugins today. This allows Amarok to integrate more tightly with the Gnome desktop and, if the appropriate plugins are written, could allow bmpx and other Gnome applications to integrate more tightly with KDE.

Various plugins have also improved. GStreamer 0.10 comes with a fully functional Real Media demuxer which, when used in conjunction with ffmpeg or the Windows .dll loader plugin, can give support for Real Media formats. An MMS plugin adds support for the mmsh protocol, so Windows Media streaming audio (internet radio) should now work as well.

Support for RTP

A lot of work has been put into Real Time Protocol (RTP) support for GStreamer. This makes it a much more suitable foundation for Voice Over IP (VOIP) and videoconferencing applications. There is even an effort afoot to port Ekiga (formerly GNOME Meeting) to GStreamer this year. The Farsight project is also working in this area, aiming to support all instant messenger, VoIP and videoconferencing systems.

Conclusion

I hope this has been a useful introduction to the user experience improvements of GStreamer 0.10. There will of course be many more as application developer starts taking advantage of the possibilities the new framework. Anyway if you want to talk about GStreamer you can find me and the rest of the GStreamer community on #gstreamer on irc.freenode.com.

By Christian Schaller.

Discuss this story with other readers on the GNOME forums.