Commit patch #157 by Elio which adds SVG support to betawidget, along with some modifications by myself.
git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@6437 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
a60dcc9b31
commit
3e9530696d
|
@ -21,6 +21,7 @@
|
|||
#include "init.h"
|
||||
|
||||
#include "../../widget.h"
|
||||
#include "../../svgManager.h"
|
||||
#include "../../window.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
@ -33,6 +34,9 @@ void widgetSDLInit()
|
|||
// Set the screen size
|
||||
windowSetScreenSize(surface->w, surface->h);
|
||||
|
||||
// Initialise the SVG manager
|
||||
svgManagerInit();
|
||||
|
||||
// Create an initial window vector to store windows
|
||||
windowSetWindowVector(vectorCreate());
|
||||
}
|
||||
|
@ -44,5 +48,8 @@ void widgetSDLQuit()
|
|||
|
||||
// Release all active windows
|
||||
vectorMapAndDestroy(windowVector, (mapCallback) widgetDestroy);
|
||||
|
||||
// Release any cached SVG images
|
||||
svgManagerQuit();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
This file is part of Warzone 2100.
|
||||
Copyright (C) 2008 Freddie Witherden
|
||||
Copyright (C) 2008 Elio Gubser
|
||||
Copyright (C) 2008 Warzone Resurrection Project
|
||||
|
||||
Warzone 2100 is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Warzone 2100 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Warzone 2100; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "svgManager.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <svg-cairo.h>
|
||||
|
||||
static vector *svgImages = NULL;
|
||||
|
||||
/*
|
||||
* Internal structures
|
||||
*/
|
||||
typedef struct _svgImage svgImage;
|
||||
|
||||
struct _svgImage
|
||||
{
|
||||
/// Path to the image
|
||||
const char *filename;
|
||||
|
||||
/// libsvg-cairo internal parse tree
|
||||
svg_cairo_t *svg;
|
||||
|
||||
/// Array of svgRenderedImages for the currently rendered sizes
|
||||
vector *renders;
|
||||
};
|
||||
|
||||
static void svgManagerFreeRender(void *renderedImage)
|
||||
{
|
||||
// Un-reference the pattern
|
||||
cairo_pattern_destroy(((svgRenderedImage *) renderedImage)->pattern);
|
||||
|
||||
// Free the memory allocated for the structure
|
||||
free(renderedImage);
|
||||
}
|
||||
|
||||
static void svgManagerFreeImage(void *image)
|
||||
{
|
||||
// Free the libcairo-svg parse tree
|
||||
svg_cairo_destroy(((svgImage *) image)->svg);
|
||||
|
||||
// Release all renders of the image
|
||||
vectorMapAndDestroy(((svgImage *) image)->renders, svgManagerFreeRender);
|
||||
|
||||
// Finally, free the memory allocated for our structure
|
||||
free(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the SVG image specified by filename and adds it to the global list
|
||||
* of SVG images. The newly loaded image is then returned for rendering.
|
||||
*
|
||||
* @param filename The path of the image to load.
|
||||
* @return A pointer to the newly loaded SVG image on success, NULL otherwise.
|
||||
*/
|
||||
static svgImage *svgManagerLoad(const char *filename)
|
||||
{
|
||||
svgImage *svg = malloc(sizeof(svgImage));
|
||||
svg_cairo_status_t status;
|
||||
|
||||
// Set the filename of the newly loaded image
|
||||
svg->filename = filename;
|
||||
|
||||
// Initialise the svg_cairo structure
|
||||
status = svg_cairo_create(&svg->svg);
|
||||
|
||||
// Ensure that we were able to create the structure
|
||||
assert(status == SVG_CAIRO_STATUS_SUCCESS);
|
||||
|
||||
// Parse the SVG
|
||||
status = svg_cairo_parse(svg->svg, filename);
|
||||
|
||||
// Ensure that the SVG was successfully parsed
|
||||
assert(status == SVG_CAIRO_STATUS_SUCCESS);
|
||||
|
||||
// Create a new vector to store size-specific renders of the image
|
||||
svg->renders = vectorCreate();
|
||||
|
||||
// Add the newly loaded image to the images array and return it
|
||||
return vectorAdd(svgImages, svg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the SVG image, svg, at (width,height) and adds it to the cache. The
|
||||
* rendered image is then returned.
|
||||
*
|
||||
* @param svg The SVG image to render.
|
||||
* @param width The width to render the image at.
|
||||
* @param height The height to render the image at.
|
||||
* @return A pointer to the newly rendered image on success, false othwewise.
|
||||
*/
|
||||
static svgRenderedImage *svgManagerRender(svgImage *svg, int width, int height)
|
||||
{
|
||||
svgRenderedImage *render = malloc(sizeof(svgRenderedImage));
|
||||
unsigned int sourceWidth, sourceHeight;
|
||||
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *surface;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
// Create the surface
|
||||
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||
|
||||
// Ensure the surface was created
|
||||
assert(cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS);
|
||||
|
||||
// Create a context to draw onto the surface with
|
||||
cr = cairo_create(surface);
|
||||
|
||||
// Ensure the context was created
|
||||
assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
|
||||
|
||||
// Get the native width/height of the SVG
|
||||
svg_cairo_get_size(svg->svg, &sourceWidth, &sourceHeight);
|
||||
|
||||
// Scale the cairo context such that the SVG is rendered at the desired size
|
||||
cairo_scale(cr, (double) width / (double) sourceWidth,
|
||||
(double) height / (double) sourceHeight);
|
||||
|
||||
// Render the SVG to the context
|
||||
svg_cairo_render(svg->svg, cr);
|
||||
|
||||
// Create a pattern out of the surface
|
||||
pattern = cairo_pattern_create_for_surface(surface);
|
||||
|
||||
// Release the cairo context and surface as they are no longer needed
|
||||
cairo_destroy(cr);
|
||||
cairo_surface_destroy(surface);
|
||||
|
||||
// Save the rendering information in the vector
|
||||
render->pattern = pattern;
|
||||
render->patternSize.x = width;
|
||||
render->patternSize.y = height;
|
||||
|
||||
// Add the newly rendered image to the renders array and return it
|
||||
return vectorAdd(svg->renders, render);
|
||||
}
|
||||
|
||||
void svgManagerInit()
|
||||
{
|
||||
// Make sure that we are not being called twice in a row
|
||||
assert(svgImages == NULL);
|
||||
|
||||
svgImages = vectorCreate();
|
||||
}
|
||||
|
||||
void svgManagerQuit()
|
||||
{
|
||||
// Ensure that we have not already been called
|
||||
assert(svgImages != NULL);
|
||||
|
||||
// Release all rendered SVG images
|
||||
vectorMapAndDestroy(svgImages, svgManagerFreeImage);
|
||||
|
||||
// Note that we have quit
|
||||
svgImages = NULL;
|
||||
}
|
||||
|
||||
void svgManagerBlit(cairo_t *cr, const svgRenderedImage *svg)
|
||||
{
|
||||
// Save the state of the current cairo context
|
||||
cairo_save(cr);
|
||||
|
||||
// Set the current painting source to be the rendered SVG image
|
||||
cairo_set_source(cr, svg->pattern);
|
||||
|
||||
// Draw a rectangle the size of the image
|
||||
cairo_rectangle(cr, 0.0, 0.0, svg->patternSize.x, svg->patternSize.y);
|
||||
|
||||
// Fill the rectangle with the pattern
|
||||
cairo_fill(cr);
|
||||
|
||||
// Finally, paint the rectangle to the surface
|
||||
cairo_paint(cr);
|
||||
|
||||
// Restore the cairo context
|
||||
cairo_restore(cr);
|
||||
}
|
||||
|
||||
svgRenderedImage *svgManagerGet(const char *filename, int width, int height)
|
||||
{
|
||||
svgImage *currSvg, *svg = NULL;
|
||||
svgRenderedImage *currRender, *render = NULL;
|
||||
|
||||
// See if the image exists in the cache at *any* size
|
||||
while ((currSvg = vectorNext(svgImages)))
|
||||
{
|
||||
// If the filenames match then we have found the image
|
||||
if (strcmp(filename, currSvg->filename) == 0)
|
||||
{
|
||||
svg = currSvg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no image was found then go ahead and load/parse it
|
||||
if (svg == NULL)
|
||||
{
|
||||
svg = svgManagerLoad(filename);
|
||||
}
|
||||
|
||||
// Fill out any missing size information
|
||||
if (width == 0 || height == 0)
|
||||
{
|
||||
unsigned int sourceWidth, sourceHeight;
|
||||
|
||||
svg_cairo_get_size(svg->svg, &sourceWidth, &sourceHeight);
|
||||
|
||||
// No size information provided, render at source
|
||||
if (width == 0 && height == 0)
|
||||
{
|
||||
width = sourceWidth;
|
||||
height = sourceHeight;
|
||||
}
|
||||
// No width given, compute from height
|
||||
else if (width == 0)
|
||||
{
|
||||
width = ((float) height / (float) sourceHeight) * (float) sourceWidth;
|
||||
}
|
||||
// No height given, compute from width
|
||||
else // (height == 0)
|
||||
{
|
||||
height = ((float) width / (float) sourceWidth) * (float) sourceHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// See if the image exists at the desired size
|
||||
while ((currRender = vectorNext(svg->renders)))
|
||||
{
|
||||
// If the sizes match then we have found the render
|
||||
if (currRender->patternSize.x == width
|
||||
&& currRender->patternSize.y == height)
|
||||
{
|
||||
render = currRender;
|
||||
}
|
||||
}
|
||||
|
||||
// If no render was found then render the SVG at the requested size
|
||||
if (render == NULL)
|
||||
{
|
||||
render = svgManagerRender(svg, width, height);
|
||||
}
|
||||
|
||||
// Return the final rendering
|
||||
return render;
|
||||
}
|
||||
|
||||
svgRenderedImage *svgManagerGetWithWidth(const char *filename, int width,
|
||||
int *height)
|
||||
{
|
||||
// Render the image
|
||||
svgRenderedImage *render = svgManagerGet(filename, width, 0);
|
||||
|
||||
// If height is non-NULL copy the height into it
|
||||
if (height)
|
||||
{
|
||||
*height = render->patternSize.y;
|
||||
}
|
||||
|
||||
// Return the render
|
||||
return render;
|
||||
}
|
||||
|
||||
svgRenderedImage *svgManagerGetWithHeight(const char *filename, int height,
|
||||
int *width)
|
||||
{
|
||||
// Render the image
|
||||
svgRenderedImage *render = svgManagerGet(filename, 0, height);
|
||||
|
||||
// If width is non-NULL copy the width into it
|
||||
if (width)
|
||||
{
|
||||
*width = render->patternSize.x;
|
||||
}
|
||||
|
||||
// Return the render
|
||||
return render;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
This file is part of Warzone 2100.
|
||||
Copyright (C) 2008 Freddie Witherden
|
||||
Copyright (C) 2008 Elio Gubser
|
||||
Copyright (C) 2008 Warzone Resurrection Project
|
||||
|
||||
Warzone 2100 is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Warzone 2100 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Warzone 2100; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SVG_MANAGER_H
|
||||
#define SVG_MANAGER_H
|
||||
|
||||
#include "internal-cairo.h"
|
||||
#include "vector.h"
|
||||
#include "geom.h"
|
||||
|
||||
/*
|
||||
* Forward declarations
|
||||
*/
|
||||
typedef struct _svgRenderedImage svgRenderedImage;
|
||||
|
||||
/**
|
||||
* Represents a rendered SVG image which is ready to be blitted/composited onto
|
||||
* a widget.
|
||||
*/
|
||||
struct _svgRenderedImage
|
||||
{
|
||||
/// Bitmap cairo_pattern_t containing the rendered image
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
/// Size of the rendered image
|
||||
size patternSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialises the SVG manager. This must be called before any SVG images are
|
||||
* loaded/used.
|
||||
*/
|
||||
void svgManagerInit(void);
|
||||
|
||||
/**
|
||||
* Uninitialises the SVG manager. Once this method has been called the result of
|
||||
* attempting to call any svgManager* methods (without a call to svgManagerInit
|
||||
* first) is undefined. Undefined behaviour is also encountered if one attempts
|
||||
* to call this method without having first called svgManagerInit.
|
||||
*/
|
||||
void svgManagerQuit(void);
|
||||
|
||||
/**
|
||||
* Composites the rendered SVG image, svg, onto the cairo context, cr, at the
|
||||
* current translation position. The state of the cairo context is unchanged by
|
||||
* this method.
|
||||
*
|
||||
* @param cr The cairo context to composite the image onto.
|
||||
* @param svg The rendered SVG image to composite.
|
||||
*/
|
||||
void svgManagerBlit(cairo_t *cr, const svgRenderedImage *svg);
|
||||
|
||||
/**
|
||||
* Loads and renders the SVG image, filename, at a size of (width,height). In
|
||||
* order to improve performance the SVG manager makes use of an image cache.
|
||||
* Hence, repeated calls to this method with the same parameters will not
|
||||
* result in any kind of performance penalty.
|
||||
*
|
||||
* If both width and height are 0 then the image will be rendered at its native
|
||||
* size. If just width is 0 then the rendered width is the native width
|
||||
* multiplied by the height scale factor. The same applies when the height is 0
|
||||
* except that the width scale factor is used instead.
|
||||
*
|
||||
* @param filename The path to the SVG image to render.
|
||||
* @param width The width to render the image at, 0 for auto-select.
|
||||
* @param height The height to render the image at, 0 for auto-select.
|
||||
* @return A pointer to the rendered SVG image on success or NULL on failure.
|
||||
*/
|
||||
svgRenderedImage *svgManagerGet(const char *filename, int width, int height);
|
||||
|
||||
/**
|
||||
* A convenience wrapper around svgManagerGet which automatically computes the
|
||||
* desired image-height based off the provided width.
|
||||
*
|
||||
* @param filename The path to the SVG image to render.
|
||||
* @param width The width to render the image.
|
||||
* @param height The resulting height of the image, may be NULL.
|
||||
* @return A pointer to the rendered SVG image on success or NULL on failure.
|
||||
* @see svgManagerGet
|
||||
*/
|
||||
svgRenderedImage *svgManagerGetWithWidth(const char *filename, int width,
|
||||
int *height);
|
||||
|
||||
/**
|
||||
* A convenience wrapper around svgManagerGet which automatically computes the
|
||||
* desired image-width based off the provided height.
|
||||
*
|
||||
* @param filename The path to the SVG image to render.
|
||||
* @param height The height to render the image.
|
||||
* @param width The resulting width of the image, may be NULL.
|
||||
* @return A pointer to the rendered SVG image on success or NULL on failure.
|
||||
* @see svgManagerGet
|
||||
*/
|
||||
svgRenderedImage *svgManagerGetWithHeight(const char *filename, int height,
|
||||
int *width);
|
||||
|
||||
#endif /*SVG_MANAGER_H*/
|
Loading…
Reference in New Issue