diff options
author | M Joonas Pihlaja <jpihlaja@cc.helsinki.fi> | 2009-02-15 15:10:30 +0200 |
---|---|---|
committer | M Joonas Pihlaja <jpihlaja@cc.helsinki.fi> | 2009-02-15 15:10:30 +0200 |
commit | 11ea8fbcc8634b130a22237dadf338c0d735adb1 (patch) | |
tree | 1e5a14ec69759702dc68bbda6f215af6c803db62 /README |
Import cairosdl.
Diffstat (limited to 'README')
-rw-r--r-- | README | 173 |
1 files changed, 173 insertions, 0 deletions
@@ -0,0 +1,173 @@ +Cairosdl: convenience functions for setting up drawing to SDL surfaces +using cairo. + +Using cairo to draw on SDL functions is very easy. The only gotcha is +that it's only possible for surfaces whose pixel format is supported +by cairo. + + +* Quick start to cairosdl.c +--------------------------- + +For one-off rendering using cairo only: + + sdlsurf = SDL_CreateRBGSurface(flags, width, height, 32, + CAIROSDL_RMASK, CAIROSDL_GMASK, CAIROSDL_BMASK, + 0 /* or CAIROSDL_AMASK*/); + + cairo_t *cairosdl_create(sdlsurf); + + /* ... normal cairo calls ... */ + + cairosdl_destroy(sdlsurf); + +For mixed cairo/non-cairo rendering: + + sdlsurf = ... as before ...; + + cairo_surface_t *cairosurf = cairosdl_surface_create(sdlsurf); + + /* ... normal cairo calls ... and then before switching to + * non-cairo rendering: */ + + cairosdl_surface_flush_rects (cairosurf, rects, num_rects); + + /* ... non-cairo rendering to the sdlsurf ... and then before + * resuming cairo rendering mark the changed areas: */ + + cairosdl_surface_mark_dirty_rects (cairosurf, rects, num_rects); + +So the short of it is: Use cairosdl_surface_create() or +cairosdl_create() to bind your SDL_Surface to a cairo_surface_t or +cairo_t context, and do normal cairo calls to render to it. Replace +calls to cairo_surface_flush() and cairo_surface_mark_dirty() with the +corresponding cairosdl.c calls. All the cairo functions expect the +SDL_Surface to be locked or not need locking. + + +* Amask = 0 surfaces +-------------------- + +Technically there is only one common pixel format in common between +cairo and SDL: 32 bit pixels which do NOT use per pixel alpha. Cairo +calls that format CAIRO_FORMAT_RGB24. In SDL terms such surfaces are +created by: + + SDL_CreateRGBSurface (flags, width, height, 32, + CAIROSDL_RMASK, // 0x00FF0000 + CAIROSDL_GMASK, // 0x0000FF00 + CAIROSDL_BMASK, // 0x000000FF + 0); + +Using the cairosdl_surface_create(SDL_Surface*) function one can get a +cairo_surface_t* that can be used to get a cairo_t drawing context, +just as normal. As a convenience, cairosdl_create(SDL_Surface*) will +make the cairo_surface_t and then bind it to a cairo_t drawing context. + +If your SDL_Surface has this pixel format and does not need locking, +that's all you need to do. + + +* Amask = 0xFF000000 surfaces +----------------------------- + +Unfortunately SDL and cairo have an inconsolable difference of opinion +on the interpretation of 32 bit pixels with per pixel alpha. SDL uses +unpremultiplied colour components, while cairo uses premultiplied +colours: an SDL pixel with components (r,g,b,a) would be represented +in a cairo as (a*r/255, a*g/255, a*b/255, a). (Here a=255 means fully +opaque and a=0 means fully transparent.) + +The first option to consider is whether you really need such surfaces +to be SDL_Surfaces or whether cairo's image surfaces would do just as +well. After all, the screen surface almost never has per-pixel alpha, +so you could create an Amask=0 surface for it and use cairo to blit to +it from a normal cairo image surface. This is likely a little faster +than SDL's per-pixel-alpha blits even when SDL can't accelerate them. + +Regardless, sometimes you really want to draw to an Amask=0xFF000000 +surface. The good news is that cairosdl.c supports such surfaces +anyway via a backing buffer and will format shift between them on +demand. In the simple one-off rendering case you just need to +remember to call cairosdl_destroy() rather than cairo_destroy(). That +will flush the backing buffer at the end to the SDL_Surface. + +If you plan to do mixed cairo/non-cairo rendering to the surface, +cairosdl needs some coordination from you so that it can format shift +between it's backing buffer and the SDL_Surface at the right times. + +The functions to call to make the cairo-drawn stuff appear in the +SDL_Surface are: + + cairosdl_surface_flush() ; writes to the entire SDL_Surface + + cairosdl_surface_flush_rect(); writes to just a region. + + cairosdl_surface_flush_rects(); writes via a list of SDL_Rects. + +These functions do not call SDL_UpdateRect or anything like that to +make the output visible on screen. + +The functions to call to import non-cairo drawn changes from the +SDL_Surface to the backing surface are: + + cairosdl_surface_mark_dirty () ; reads the entire SDL_Surface. + + cairosdl_surface_mark_dirty_rect () ; reads just a region. + + cairosdl_surface_mark_dirty_rects () ; reads via a list of SDL_Rects. + +If you're doing mixed rendering and are already using the +flush/mark_dirty functions, then you don't want to call +cairosdl_destroy() at the end since that does an implicit final flush. + + +* Palette indexed surfaces +-------------------------- + +You could create a cairo image surface using the CAIRO_FORMAT_A8 pixel +format. Cairo will ignore your palette though. cairosdl.c doesn't +support this at the moment. + + +* SDL_Surface flags, locking and other caveats +---------------------------------------------- + +Cairo really needs direct access to the pixel data of an SDL surface, +but it doesn't know anything about locking them. Since the SDL +locking rules can be a little inconvenient, the cairosdl_* functions +assume that you're passing in an SDL_Surface which does not need +locking or is already locked. In particular, the surface->pixels +member must be valid and not change for the lifetime of a +cairo_surface_t created by cairosdl_surface_create() or +cairosdl_create(). It must also be safe to call malloc and whatever +platform specific mutex operations inside cairo while the surface is +locked. + +For most platforms I believe this means that SDL_SWSURFACEs are always +safe to use with cairo. If they don't use RLEACCEL, they don't even +need any locking at all. + +One can also use SDL_HWSURFACEs if it's okay to call malloc and other +OS facilities while they're locked. In this case the the lifetime of +the cairo_surface_t created for the SDL_Surface must be contained +within a single SDL_LockSurface/UnlockSurface pair. Again, for many +platforms this isn't a problem. + +I haven't tested GL enabled SDL surfaces, but expect there shouldn't +be a problem if GL can be configured to accept cairo's pixel formats. + +Cairo ignores SDL_Surface colorkey and treats every 32 bit surface +with alpha as if it had SDL_SRCALPHA. + + +* Tips and tricks +----------------- + +Cairo's software blits seem to be slightly faster than SDL's software +blits. The fastest combination seems to be using a 32 bit SDL_Surface +with Amask = 0, wrap that up in a cairo_surface_t, and use normal +cairo image surfaces for the per-pixel-alpha surfaces. + +The cairosdl_surface_get_target() and cairosdl_get_target() functions +return the SDL_Surface bound to the given cairo_surface_t or cairo_t. |