Difference between revisions of "SVG support in CEGUI"
(→Decisions that have to be made) |
|||
Line 6: | Line 6: | ||
'''Module-integration:''' | '''Module-integration:''' | ||
* SVGImage and related files will be a part of CEGUI Core-library (<span style="color:#27a41a">'''yes'''</span>) | * SVGImage and related files will be a part of CEGUI Core-library (<span style="color:#27a41a">'''yes'''</span>) | ||
− | * Vector graphics rendering related files will be part of CEGUI Core-library (<span style="color:#27a41a">'''yes'''</span>) | + | * Vector graphics rendering related files will be part of CEGUI Core-library (<span style="color:#27a41a">'''yes, they are in the subfolder "svg"'''</span>) |
− | * The SVG File loading and parsing will be part of CEGUI Core-library (<span style="color:#27a41a">'''yes'''</span>) | + | * The SVG File loading and parsing will be part of CEGUI Core-library (<span style="color:#27a41a">'''yes, it is implemented in SVGData'''</span>) |
'''Classes and structures:''' | '''Classes and structures:''' | ||
* SVGImage will be a subclass of CEGUI::Image (<span style="color:#27a41a">'''yes'''</span>) | * SVGImage will be a subclass of CEGUI::Image (<span style="color:#27a41a">'''yes'''</span>) |
Revision as of 01:20, 2 October 2013
The purpose of this document is to determine how the SVG loading/handling and storage of related datastructures should be done.
Contents
Decisions that have to be made
Specific questions that need to be decided upon by the CEGUI team are: (in the brackets the current state of decision is noted)
Module-integration:
- SVGImage and related files will be a part of CEGUI Core-library (yes)
- Vector graphics rendering related files will be part of CEGUI Core-library (yes, they are in the subfolder "svg")
- The SVG File loading and parsing will be part of CEGUI Core-library (yes, it is implemented in SVGData)
Classes and structures:
- SVGImage will be a subclass of CEGUI::Image (yes)
- SVGImage contains the cached information required for rendering (yes, it is cached inside GeometryBuffers)
- A class called VGShapeData, VectorShapeData, VectorData or similar, will contain the abstract information on the shapes which is used in SVGImage to be cached and drawn (undecided)
- SVGImage will contain a reference to a shape-data class. This means that multiple SVGImages can share the same shape data. The question is if this is necessary (use-case?). If this data was shared and the user modified this data, all VGImages would have to be updated. An alternative would be that the shape-data class can only be referenced once, but can be copied and then altered if required. (undecided)
- CEGUI::VectorShape (or similar) will be a superclass for all draw shapes. These can be constructed manually but will also be used directly by the SVG parser. The mentioned ShapeData class will store the various shapes which can then be used for creating actual geometry in SVGImage. (undecided)
SVG loading and parsing:
- An SVG file can be referenced from within an Imageset file and used just in the same way as texture atlases are used (Pos+Size define an Image in it) (undecided)
- An Image defined in an SVG-Imageset can also address a group/layer using an optional "Group" or "Layer" attribute. This means that only data from the specified group will be used for the Image.
- When defining an Image in the imageset, as an alternative to a relative definition in respect to the Imageset's SVG file, each Image should also be able to reference a specific SVG file directly which would be then used for this image as a whole in the process of parsing the Imageset. A pos/size definition should in that case not be possible because that a seperate imageset should be created for. (undecided)
Notes: Probably SVGImage should rather be called VGImage or VectorImage or VectorGraphicsImage. This is because it should be easily possible to make that the class would not require actual SVG data but instead only require shape information for drawing. The SVG data can be converted into such abstract shape information. That way users can create their own shape information and which can be used in a VGImage. None of the names should refer to "SVG" as a name in my opinion, except for the SVG parser itself. Everything after the parser should be "general" although the whole data structures and drawing process will be designed in the first line to go well along with the SVG file standard and its definition of vector graphics.
We should probably think of a general naming concept, maybe using a common prefix for all files such as "VG-", and also maybe seperate all Vector Graphics related files into its own src/includes folder such as done with "widgets", unless this is not desired.
Parsing
- Should a warning be thrown if the svg file's version does not match SVG Tiny 1.2 (or lower) version? As we won't fully support all features of any profile either way, this might be redundant and it should just be documented in the CEGUI docs and SVG class docs what is supported and what isn't. (undecided)
Possible use-cases for SVG Images
As justification for the above suggestions following use-cases are to be considered:
- A user wants to load an SVG-file and then use the resulting SVGImage like a regular raster graphics image (BasicImage)
For this purpose, in the optimal case, the user could use an SVGImage equally to a BasicImage. Which means, it can be referred to via a String, defining the name of the Image. The VGImage would therefore have to be registered and maintained by the ImageManager in the same way as raster graphics. Autoscale and scaling in general, as well as any clipping have to be handled appropriately for that case. Stretching and alignment also have to be considered.
- A user wants to load an SVG-file with a progressbar. The progressbar image consists of overlapping parts as it would look in the final version. The image parts are seperated into different layers and the user wants most of the Image definitions to be using the data of only one specified layer
Images will contain an [optional] extra attribute "Group" or "Layer" which allow specifying a layer or group. The SVG group's contents will then exclusively be taken as shape information for the SVGImage.
- A user wants to create a drawable Vector graphics image, e.g. a mouse cursor, by defining it manually using CEGUI classes
The class maintaining the shape information has to store the draw-information the user wants to generate. An instance of this class has to be created using a CEGUI Manager. When it is constructed it should be possible to call functions that write the draw commands to this file. Such a command could be for example: addDrawLine(Point start, Point end, thickness, Colour col, ...) The question is if this function should remain inside the class storing the data, or if a Helper or super-class should deal with the interpretation of the draw command. Probably it is better to seperate it in some way from the data storage class (VectoData) to prevent it from containing too many function that are not of direct relevance. Alternatively, each draw shape could be a seperate class. This might be the best solution as the data structure would only need an add(const Shape& shape) function and therefore the rest would be duty of the specific implementation of the Shape. The Shapes would be passed as copy to the the data storage class so that the user doesnt have to take care of its memory management later-on. The data storage class would be managed by a Manager, similar to CEGUI::Texture and therefore could be addressed via a String and would be deleted and created analogously.
- (Optional/for post-GsoC) Usage of Animated Vector Graphics
Subclass of SVGImage, containing a time variable as addition. Needs to be updated on each update call that includes a time-change. This also requires recaching. Currently I do not see further issues with that, the main problem with these is the recaching process itself.
Currently I cannot think of further use-cases.
SVG parsing / Imagesets
Summary of my research: According to my research it would be best to specify images via an imageset file analogous to how it is done with raster graphics. They can then reference positions and dimensions in an SVG file to seperate the images. In case the user wants to use different layers as different images, the Image specification in the Imageset will also provide an attribute for Group(=Layer in Illustrator/Inkscape), to identify the specific group from which the vector shapes should exclusively be taken from. The default Image dimensions will be equal to the imageset dimensions and the position will be (0,0) in case these were not specified in the Image attributes.
The long version:
I have not yet checked how it is in Inkscape but Adobe Illustrator at least does not support a way to easily create multiple vector graphic images in a single file, that could then be loaded with a clear distinction from each other. But the SVG file standard itself also does not really offer a solution for this as I will mention in the following text. When i talk about SVG i always refer to the SVG 1.1 standard:
What could in general be done to create multiple SVG Images in Adobe Illustrator, is to make multiple layers, which then would each get converted to groups when saving to an SVG file, where each group can then be interpreted as one image. However, these groups would all be using the same workspace area, which is clearly defined in Illustrator and also specified by the SVG format. So this workspace area is a clear definition of boundaries which would be logical to use as boundaries of the image itself. There is no real other way to know the dimensions of a desired image, except maybe check the minimum and maximum dimensions, but this could lead to undesired results, such as too closely cropped images without margin. For a more intuitive approach, which is probably also more logical to users, the area defined in the SVG header ( http://www.w3.org/TR/SVG/struct.html#SVGElement ) should be used to define the dimensions of the image. This are is specified in Illustrator via the Artboard, whereas only the Artboard 1 seems to be exported when there are multiple ones. One other way this could have theoretically be done is by using groups, but they simply do not provide such attributes as defined in SVG 1.1: http://www.w3.org/TR/SVG/struct.html#Groups . So the only thing the user can do is to have all images scaled to suit the same workspace area, whereas each layer is one image. Obviously the problem here is that such odd scaling is not a way to work with. A perfect solutin would be to simply export the desired collection of vector graphics images and use an imageset which is saved seperately, this would work in the same way as it is working with the raster graphic texture atlases and their imagesets right now. But this would require some, hopefully only small, changes to the Imageset Editor of CEED, to make CEED compatible with this. Unfortunately i am pretty sure that I do not have enough knowledge of python and CEED to apply such changes myself, as I would then most definitely exceed the timeframe for this gsoc project. Still, the Imageset creation can be done manually in XML. As addition it has to be considered that the dimensions and positions in an SVG file are not necessarily specified in pixels.
Although not considerably different, I will in any case refer to the SVG Tiny 1.2 standard instead of SVG 1.1, as it is newer and "smaller" : http://www.w3.org/TR/SVGTiny12
SVG format support
In this section I will record what elements, attributes and features of SVG will be supported by my parsing and rendering classes and how special cases will be handled.
The first line of SVG files will usually contain the xml tag such as: ?<?xml version="1.0" encoding="UTF-8"?> For the xml meta-data probably no action has to be taken in any case. After this line, some programs (such as Adobe Illustrator) might add a comment line containing info about the used program and used exporter. This, we can also ignore.
The following element is the <svg> element, which encompasses all the data contained in the SVG file. "An SVG document fragment can only contain one single 'svg' element, this means that 'svg' elements cannot appear in the middle of SVG content. " We will only parse this first svg element and ignore all further elements if there are any. For this element there are several attributes. Version and Baseprofile could be relevant, as they would allow us to throw a warning in case they do not match SVG Tiny 1.2 or lower. The question is if this is helpful - see questions on top. Other attributes of the svg element that could be relevant are: width, height and viewBox. The viewBox offers a scalable solution, which describes the region of world coordinate space (the initial user coordinate system) used by the graphic. It requires a list of 4 numbers (no units) seperated with a space. Width and height provide a fixed size for the SVG image, so that it will not scale for different display resolutions. "These two attributes define the intrinsic aspect ratio and (unless both width and height are percentages) the intrinsic size of the svg element. " As viewBox would be ambiguous for usage in CEGUI (we already have attributes for stretching and orientation in CEGUI), as well as the usage of any real-world units (inches, cm, etc.) and % for width and height would be ambiguous (what pixel-size to apply to a left-oriented percentual image? should it be based on the host window size, or ImageryComponent area, etc? - or how many pixels is an "inch" on a users screen?) we will, for now, ONLY accept width and height attributes with pixel units for this and throw a warning if they are not present, taking the width and height values as pixel values instead. Further issues would arise when defining SVG sub-images inside the an Imageset (such as was suggested before). The question that would arise ther eis how the sub-images would be defined in relation to percentual SVGImage sizes or if using a viewbox definition. Because of the mentioned reasons I decided it is best to force the user to offer an SVG file that is defined using absolute pixel dimensions and is as such ready to be rendered without ambiguosness regarding Imagesets or effective rendering dimensions in screen space. For the case of users who create the SVGData object on their own, the size will by default be the maximum values of width and height (therefore the unsigned value will be set to -1).
All SVG Basic Shapes will be supported fully: 'rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon'.
Animation will not be supported so far.
Fonts in SVG images are not planned to be supported in CEGUI at any point of time. If users want to use a Font in their SVG graphics they can simply vectorize the Font and export it as such, which of course leads to a loss of scalability. Real support for this feature is impossible considering the way CEGUI renders fonts at the moment.
'transform' will only support a matrix value as of now, because that is the only thing illustrator seems to actually export. The definition of transforms can be found here: http://www.w3.org/TR/SVGTiny12/coords.html#TransformList
Custom drawing helper functions
To make it easier to draw custom geometry, we could extend the SVGData class with wrapper functions that contain necessary calls to draw basic elements. This would work in similar ways as with HTML5 canvas: http://www.w3schools.com/html/html5_canvas.asp or not.
References
A couple of websites i used as inspiration, reference or as a loose basis for my own code:
SVG Tiny 1.2 Standard: http://www.w3.org/TR/SVGTiny12/
Stroke drawing: http://www.codeproject.com/Articles/226569/Drawing-polylines-by-tessellation
Fast circle and arc drawing: http://slabode.exofire.net/circle_draw.shtml
Tesselated AA: http://www.codeproject.com/Articles/199525/Drawing-nearly-perfect-2D-line-segments-in-OpenGL