зеркало из https://github.com/mono/libgdiplus.git
104 строки
4.3 KiB
Plaintext
104 строки
4.3 KiB
Plaintext
|
Region implementations in libgdiplus
|
||
|
Last update: 2006-03-23
|
||
|
|
||
|
* Introduction
|
||
|
|
||
|
First you should notice "implementations" in the title. Yes there is more
|
||
|
than one implementation to handle region code.
|
||
|
|
||
|
|
||
|
* Rectangular based regions
|
||
|
|
||
|
The first implementation (i.e. the only one available before 1.1.14) is
|
||
|
based on rectangles. A region is simply a list of rectangles and all
|
||
|
binary operations (union, intersection, complement, exclude and xor) are
|
||
|
done mathematically (i.e. they results in a new list of rectangles).
|
||
|
|
||
|
This approach is simple, efficient and allow to implement some other GDI+
|
||
|
API very easily (e.g. GdipGetRegionData, GdipGetRegionDataSize,
|
||
|
GdipGetRegionScans).
|
||
|
|
||
|
However it is limited to rectangles (i.e. no polygons, beziers ...) and
|
||
|
makes it impossible to implement some other GDI+ API, like
|
||
|
GdipTransformRegion where the rectangles would be transformed into paths.
|
||
|
Software depending on these features simply can't work.
|
||
|
|
||
|
All the code for this implementation resides inside the file
|
||
|
/libgdiplus/src/region.c
|
||
|
|
||
|
|
||
|
* Bitmap based regions
|
||
|
|
||
|
This implementation use 1bbp (1 bit per pixel) bitmaps to represent the
|
||
|
regions. This allows us to implement the binary operators on memory
|
||
|
buffers, not on coordinates (see /libgdiplus/src/region-bitmap.c). At
|
||
|
display time (GdipFillRegion) the bitmap is used as the alpha channel and
|
||
|
we simply draw a rectangle using the selected brush.
|
||
|
|
||
|
This approach is simple, compared to a pure mathematical implementation,
|
||
|
but not as efficient and somewhat less precise (float to int
|
||
|
conversions). This is why the bitmap implementation co-exists with the
|
||
|
rectangular based region code. Simple regions get treated simply ;-)
|
||
|
|
||
|
To minimize the inconveniences the bitmaps are created only on demand
|
||
|
(e.g. when an API requires them) and we try, as much as possible, to
|
||
|
avoid this code path (e.g. using the rectangle code where possible, check
|
||
|
for special cases, like an union with infinity...).
|
||
|
|
||
|
Sadly having bitmaps isn't quite enough. We still have to be able to
|
||
|
apply transforms (i.e. GdipTransformRegion) and be able to [de]serialize
|
||
|
the region (GdipGetRegionData). While both operations _could_ be done
|
||
|
with bitmaps the results wouldn't be very precise (transform) nor small
|
||
|
(serialization). This is why the region keeps a tree of all the paths and
|
||
|
operations required to re-construct itself (see
|
||
|
/libgdiplus/src/region-path-tree.c).
|
||
|
|
||
|
The code for this implementation resides in the files:
|
||
|
|
||
|
/libgdiplus/src/region.c|h
|
||
|
The GDI+ API for regions. The API will switch to the rectangle or
|
||
|
bitmap code based on the regions type. If required a rectangle-
|
||
|
based region will be "promoted" to a bitmap region.
|
||
|
|
||
|
/libgdiplus/src/region-bitmap.c|h
|
||
|
Handle the bitmap allocation, creation (from path), the binary
|
||
|
operations, ...
|
||
|
|
||
|
/libgdiplus/src/region-path-tree.c|h
|
||
|
Handle the tree of path and (binary) operations required to
|
||
|
re-construct the region if required (e.g. transform and
|
||
|
serialization).
|
||
|
|
||
|
There are currently two main limitations to this approach:
|
||
|
|
||
|
1. Memory. It's simply impossible to allocate enough memory for an
|
||
|
"infinite" region. There is a maximum of 2 megabytes allocated for a
|
||
|
region bitmap (see region-bitmap.h). This is enough (1bbp) for
|
||
|
regions to cover a full screen resolution.
|
||
|
|
||
|
2. Clipping. Graphics.Clip can't use the bitmap (at least not without
|
||
|
major changes). This means that clipping _will_work_ for any region
|
||
|
(not just rectangles) until a binary operation is done on it. So far
|
||
|
I've not seen any code trying that...
|
||
|
|
||
|
|
||
|
* Future?
|
||
|
|
||
|
A pure, totally mathematical, implementation would be a nice addition to
|
||
|
libgdiplus. It could, once debugged, replace both the rectangular and
|
||
|
bitmap implementations.
|
||
|
|
||
|
The main advantages of this implementation would be:
|
||
|
- reduced memory requirements (well most of the time);
|
||
|
- (almost) unlimited size;
|
||
|
- more precision (no float to int conversion);
|
||
|
- no limits on clipping;
|
||
|
|
||
|
So if it's the best solution why don't we have it yet ?
|
||
|
|
||
|
Well it's really not an easy problem. Writing an effective intersector is
|
||
|
a complex problem. You must deal with curves (well they could be cheated
|
||
|
into linear paths) and a _lot_ of corner cases (google for them). Most
|
||
|
existing (open source) implementation aren't satisfied with their results
|
||
|
(e.g. libart, livarot). But don't let us discourage you from trying! ;-)
|