Support for images, shading, layers, shadows, global alpha... for the AntiGrain context (not 100% complete yet)

This commit is contained in:
Airy ANDRE 2011-06-22 18:17:01 +02:00
parent 364fc85990
commit 0df24ed140
13 changed files with 1689 additions and 267 deletions

View File

@ -755,20 +755,24 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
CGContextSaveGState(context);
if(fraction!=1.0){
// fraction is accomplished with a 1x1 alpha mask
// FIXME: could use a float format image to completely preserve fraction
uint8_t bytes[1]={ MIN(MAX(0,fraction*255),255) };
CGDataProviderRef provider=CGDataProviderCreateWithData(NULL,bytes,1,NULL);
CGImageRef mask=CGImageMaskCreate(1,1,8,8,1,provider,NULL,NO);
CGContextClipToMask(context,rect,mask);
CGImageRelease(mask);
CGDataProviderRelease(provider);
}
[[NSGraphicsContext currentContext] setCompositingOperation:operation];
if ([context supportsGlobalAlpha] == NO) {
// That should really be done by setting the context alpha - and the compositing done in the context implementation
if(fraction!=1.0){
// fraction is accomplished with a 1x1 alpha mask
// FIXME: could use a float format image to completely preserve fraction
uint8_t bytes[1]={ MIN(MAX(0,fraction*255),255) };
CGDataProviderRef provider=CGDataProviderCreateWithData(NULL,bytes,1,NULL);
CGImageRef mask=CGImageMaskCreate(1,1,8,8,1,provider,NULL,NO);
CGContextClipToMask(context,rect,mask);
CGImageRelease(mask);
CGDataProviderRelease(provider);
}
} else {
CGContextSetAlpha(context, fraction);
}
[[NSGraphicsContext currentContext] setCompositingOperation:operation];
[self drawRepresentation:drawRep inRect:rect];
CGContextRestoreGState(context);

View File

@ -4,6 +4,11 @@
#ifdef ANTIGRAIN_PRESENT
#include <agg_basics.h>
#include <agg_pixfmt_rgba.h>
#include <agg_pixfmt_gray.h>
#include <agg_alpha_mask_u8.h>
#include <agg_scanline_p.h>
#include <agg_scanline_u.h>
#include <agg_alpha_mask_u8.h>
#include <agg_path_storage.h>
#include <agg_renderer_base.h>
#include <agg_renderer_mclip.h>
@ -14,22 +19,46 @@
#include <agg_conv_stroke.h>
#include <agg_conv_adaptor_vcgen.h>
typedef agg::comp_op_adaptor_rgba<agg::rgba8, agg::order_bgra> blender_type;
typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_type;
@class O2Context_AntiGrain;
typedef agg::renderer_base<pixfmt_type> renderer_base;
class context_renderer;
typedef agg::pixfmt_gray8 pixfmt_alphaMaskType;
typedef agg::renderer_base<pixfmt_alphaMaskType> BaseRendererWithAlphaMaskType;
typedef agg::rasterizer_scanline_aa<> RasterizerType; // We use an anti-aliased scanline rasterizer for AGG rendering.
@interface O2Context_AntiGrain : O2Context_builtin_gdi {
agg::rendering_buffer *renderingBuffer;
pixfmt_type *pixelFormat;
agg::rasterizer_scanline_aa<> *rasterizer;
renderer_base *ren_base;
agg::path_storage *path;
agg::rendering_buffer *renderingBuffer;
// Rendering buffer to use for shadow rendering
uint8_t *pixelShadowBytes;
agg::rendering_buffer *renderingBufferShadow;
agg::path_storage *path;
RasterizerType *rasterizer;
context_renderer *renderer;
// Rendering buffer to use for alpha masking (bezier path clipping)
agg::rendering_buffer* rBufAlphaMask[2];
agg::alpha_mask_gray8* alphaMask[2];
pixfmt_alphaMaskType* pixelFormatAlphaMask[2];
BaseRendererWithAlphaMaskType* baseRendererAlphaMask[2];
agg::renderer_scanline_aa_solid<BaseRendererWithAlphaMaskType>* solidScanlineRendererAlphaMask[2];
int currentMask;
NSArray *savedClipPhases;
BOOL maskValid;
BOOL useMask;
}
- (BOOL)useMask;
- (agg::alpha_mask_gray8*)currentMask;
- (RasterizerType *)rasterizer;
- (context_renderer *)renderer;
@end
#else
#import <Onyx2D/O2Context_builtin_gdi.h>
@interface O2Context_AntiGrain : O2Context_builtin_gdi
@end

File diff suppressed because it is too large Load Diff

View File

@ -80,6 +80,7 @@
/* Begin PBXFileReference section */
089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
0AA1909FFE8422F4C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
4931E7B913B1042600CEF331 /* partial_stack_blur.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = partial_stack_blur.h; sourceTree = "<group>"; };
8D576316048677EA00EA77CD /* O2Context_AntiGrain.cgContext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = O2Context_AntiGrain.cgContext; sourceTree = BUILT_PRODUCTS_DIR; };
8D576317048677EA00EA77CD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
FE5C8312121D81470063E96F /* O2Context_AntiGrain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = O2Context_AntiGrain.h; sourceTree = "<group>"; };
@ -105,6 +106,7 @@
isa = PBXGroup;
children = (
FEE163EC137C6DC600B2F340 /* AppKit.xcodeproj */,
4931E7B913B1042600CEF331 /* partial_stack_blur.h */,
FE5C8312121D81470063E96F /* O2Context_AntiGrain.h */,
FE5C8313121D81470063E96F /* O2Context_AntiGrain.mm */,
089C167CFE841241C02AAC07 /* Resources */,

View File

@ -0,0 +1,310 @@
/*
* partial_stack_blur.h
* O2Context_AntiGrain
*
* Created by Airy ANDRE on 21/06/11.
* Copyright 2011 plasq. All rights reserved.
*
*/
#ifndef PARTIAL_BLUR_INCLUDED
#define PARTIAL_BLUR_INCLUDED
#include <agg_blur.h>
// Adapted from stack_blur_rgba32 to allow partial blurring - blame the original for the lack of comments
namespace agg
{
//======================================================= partial_stack_blur_rgba32
template<class Img>
void partial_stack_blur_rgba32(Img& img, unsigned rx, unsigned ry, unsigned startX, unsigned endX, unsigned startY, unsigned endY)
{
typedef typename Img::color_type color_type;
typedef typename Img::order_type order_type;
enum order_e
{
R = order_type::R,
G = order_type::G,
B = order_type::B,
A = order_type::A
};
unsigned x, y, xp, yp, i;
unsigned stack_ptr;
unsigned stack_start;
const int8u* src_pix_ptr;
int8u* dst_pix_ptr;
color_type* stack_pix_ptr;
unsigned sum_r;
unsigned sum_g;
unsigned sum_b;
unsigned sum_a;
unsigned sum_in_r;
unsigned sum_in_g;
unsigned sum_in_b;
unsigned sum_in_a;
unsigned sum_out_r;
unsigned sum_out_g;
unsigned sum_out_b;
unsigned sum_out_a;
unsigned w = endX;
unsigned h = endY;
unsigned wm = w - 1;
unsigned hm = h - 1;
unsigned div;
unsigned mul_sum;
unsigned shr_sum;
pod_vector<color_type> stack;
if(rx > 0)
{
if(rx > 254) rx = 254;
div = rx * 2 + 1;
mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[rx];
shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[rx];
stack.allocate(div);
for(y = startY; y < endY; y++)
{
sum_r =
sum_g =
sum_b =
sum_a =
sum_in_r =
sum_in_g =
sum_in_b =
sum_in_a =
sum_out_r =
sum_out_g =
sum_out_b =
sum_out_a = 0;
src_pix_ptr = img.pix_ptr(startX, y);
for(i = 0; i <= rx; i++)
{
stack_pix_ptr = &stack[i];
stack_pix_ptr->r = src_pix_ptr[R];
stack_pix_ptr->g = src_pix_ptr[G];
stack_pix_ptr->b = src_pix_ptr[B];
stack_pix_ptr->a = src_pix_ptr[A];
sum_r += src_pix_ptr[R] * (i + 1);
sum_g += src_pix_ptr[G] * (i + 1);
sum_b += src_pix_ptr[B] * (i + 1);
sum_a += src_pix_ptr[A] * (i + 1);
sum_out_r += src_pix_ptr[R];
sum_out_g += src_pix_ptr[G];
sum_out_b += src_pix_ptr[B];
sum_out_a += src_pix_ptr[A];
}
for(i = 1; i <= rx; i++)
{
if(i <= wm) src_pix_ptr += Img::pix_width;
stack_pix_ptr = &stack[i + rx];
stack_pix_ptr->r = src_pix_ptr[R];
stack_pix_ptr->g = src_pix_ptr[G];
stack_pix_ptr->b = src_pix_ptr[B];
stack_pix_ptr->a = src_pix_ptr[A];
sum_r += src_pix_ptr[R] * (rx + 1 - i);
sum_g += src_pix_ptr[G] * (rx + 1 - i);
sum_b += src_pix_ptr[B] * (rx + 1 - i);
sum_a += src_pix_ptr[A] * (rx + 1 - i);
sum_in_r += src_pix_ptr[R];
sum_in_g += src_pix_ptr[G];
sum_in_b += src_pix_ptr[B];
sum_in_a += src_pix_ptr[A];
}
stack_ptr = rx;
xp = rx + startX;
if(xp > wm) xp = wm;
src_pix_ptr = img.pix_ptr(xp, y);
dst_pix_ptr = img.pix_ptr(startX, y);
for(x = startX; x < endX; x++)
{
dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum;
dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum;
dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum;
dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum;
dst_pix_ptr += Img::pix_width;
sum_r -= sum_out_r;
sum_g -= sum_out_g;
sum_b -= sum_out_b;
sum_a -= sum_out_a;
stack_start = stack_ptr + div - rx;
if(stack_start >= div) stack_start -= div;
stack_pix_ptr = &stack[stack_start];
sum_out_r -= stack_pix_ptr->r;
sum_out_g -= stack_pix_ptr->g;
sum_out_b -= stack_pix_ptr->b;
sum_out_a -= stack_pix_ptr->a;
if(xp < wm)
{
src_pix_ptr += Img::pix_width;
++xp;
}
stack_pix_ptr->r = src_pix_ptr[R];
stack_pix_ptr->g = src_pix_ptr[G];
stack_pix_ptr->b = src_pix_ptr[B];
stack_pix_ptr->a = src_pix_ptr[A];
sum_in_r += src_pix_ptr[R];
sum_in_g += src_pix_ptr[G];
sum_in_b += src_pix_ptr[B];
sum_in_a += src_pix_ptr[A];
sum_r += sum_in_r;
sum_g += sum_in_g;
sum_b += sum_in_b;
sum_a += sum_in_a;
++stack_ptr;
if(stack_ptr >= div) stack_ptr = 0;
stack_pix_ptr = &stack[stack_ptr];
sum_out_r += stack_pix_ptr->r;
sum_out_g += stack_pix_ptr->g;
sum_out_b += stack_pix_ptr->b;
sum_out_a += stack_pix_ptr->a;
sum_in_r -= stack_pix_ptr->r;
sum_in_g -= stack_pix_ptr->g;
sum_in_b -= stack_pix_ptr->b;
sum_in_a -= stack_pix_ptr->a;
}
}
}
if(ry > 0)
{
if(ry > 254) ry = 254;
div = ry * 2 + 1;
mul_sum = stack_blur_tables<int>::g_stack_blur8_mul[ry];
shr_sum = stack_blur_tables<int>::g_stack_blur8_shr[ry];
stack.allocate(div);
int stride = img.stride();
for(x = startX; x < w; x++)
{
sum_r =
sum_g =
sum_b =
sum_a =
sum_in_r =
sum_in_g =
sum_in_b =
sum_in_a =
sum_out_r =
sum_out_g =
sum_out_b =
sum_out_a = 0;
src_pix_ptr = img.pix_ptr(x, startY);
for(i = 0; i <= ry; i++)
{
stack_pix_ptr = &stack[i];
stack_pix_ptr->r = src_pix_ptr[R];
stack_pix_ptr->g = src_pix_ptr[G];
stack_pix_ptr->b = src_pix_ptr[B];
stack_pix_ptr->a = src_pix_ptr[A];
sum_r += src_pix_ptr[R] * (i + 1);
sum_g += src_pix_ptr[G] * (i + 1);
sum_b += src_pix_ptr[B] * (i + 1);
sum_a += src_pix_ptr[A] * (i + 1);
sum_out_r += src_pix_ptr[R];
sum_out_g += src_pix_ptr[G];
sum_out_b += src_pix_ptr[B];
sum_out_a += src_pix_ptr[A];
}
for(i = 1; i <= ry; i++)
{
if(i <= hm) src_pix_ptr += stride;
stack_pix_ptr = &stack[i + ry];
stack_pix_ptr->r = src_pix_ptr[R];
stack_pix_ptr->g = src_pix_ptr[G];
stack_pix_ptr->b = src_pix_ptr[B];
stack_pix_ptr->a = src_pix_ptr[A];
sum_r += src_pix_ptr[R] * (ry + 1 - i);
sum_g += src_pix_ptr[G] * (ry + 1 - i);
sum_b += src_pix_ptr[B] * (ry + 1 - i);
sum_a += src_pix_ptr[A] * (ry + 1 - i);
sum_in_r += src_pix_ptr[R];
sum_in_g += src_pix_ptr[G];
sum_in_b += src_pix_ptr[B];
sum_in_a += src_pix_ptr[A];
}
stack_ptr = ry;
yp = startY + ry;
if(yp > hm) yp = hm;
src_pix_ptr = img.pix_ptr(x, yp);
dst_pix_ptr = img.pix_ptr(x, startY);
for(y = startY; y < h; y++)
{
dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum;
dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum;
dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum;
dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum;
dst_pix_ptr += stride;
sum_r -= sum_out_r;
sum_g -= sum_out_g;
sum_b -= sum_out_b;
sum_a -= sum_out_a;
stack_start = stack_ptr + div - ry;
if(stack_start >= div) stack_start -= div;
stack_pix_ptr = &stack[stack_start];
sum_out_r -= stack_pix_ptr->r;
sum_out_g -= stack_pix_ptr->g;
sum_out_b -= stack_pix_ptr->b;
sum_out_a -= stack_pix_ptr->a;
if(yp < hm)
{
src_pix_ptr += stride;
++yp;
}
stack_pix_ptr->r = src_pix_ptr[R];
stack_pix_ptr->g = src_pix_ptr[G];
stack_pix_ptr->b = src_pix_ptr[B];
stack_pix_ptr->a = src_pix_ptr[A];
sum_in_r += src_pix_ptr[R];
sum_in_g += src_pix_ptr[G];
sum_in_b += src_pix_ptr[B];
sum_in_a += src_pix_ptr[A];
sum_r += sum_in_r;
sum_g += sum_in_g;
sum_b += sum_in_b;
sum_a += sum_in_a;
++stack_ptr;
if(stack_ptr >= div) stack_ptr = 0;
stack_pix_ptr = &stack[stack_ptr];
sum_out_r += stack_pix_ptr->r;
sum_out_g += stack_pix_ptr->g;
sum_out_b += stack_pix_ptr->b;
sum_out_a += stack_pix_ptr->a;
sum_in_r -= stack_pix_ptr->r;
sum_in_g -= stack_pix_ptr->g;
sum_in_b -= stack_pix_ptr->b;
sum_in_a -= stack_pix_ptr->a;
}
}
}
}
}
#endif

View File

@ -187,6 +187,8 @@ O2ColorRef O2ContextFillColor(O2ContextRef self);
-(void)clipToState:(O2ClipState *)clipState;
-(void)supportsGlobalAlpha;
O2ContextRef O2ContextRetain(O2ContextRef self);
void O2ContextRelease(O2ContextRef self);

View File

@ -235,6 +235,20 @@ O2ColorRef O2ContextFillColor(O2ContextRef self) {
O2ContextSetCMYKFillColor(self,c,m,y,k,alpha);
}
-(void)setAlpha:(float)alpha
{
O2GStateSetAlpha(O2ContextCurrentGState(self), alpha);
if ([self supportsGlobalAlpha] == NO) {
[self setStrokeAlpha:alpha];
[self setFillAlpha:alpha];
}
}
-(void)supportsGlobalAlpha
{
return NO;
}
-(void)drawPath:(O2PathDrawingMode)pathMode {
O2InvalidAbstractInvocation();
// reset path in subclass
@ -874,8 +888,7 @@ void O2ContextSetAlpha(O2ContextRef self,O2Float alpha) {
if(self==nil)
return;
[self setStrokeAlpha:alpha];
[self setFillAlpha:alpha];
[self setAlpha:alpha];
}
void O2ContextSetPatternPhase(O2ContextRef self,O2Size phase) {

View File

@ -165,6 +165,15 @@ void O2DContextClipAndFillEdges(O2Context_builtin *self,int fillRuleMask);
[self->_layerStack addObject:layer];
O2LayerRelease(layer);
O2ContextSaveGState(self);
/**
* From Cocoa doc :
* graphics state parameters remain unchanged except for alpha (which is set to 1), shadow (which is turned off), blend mode (which is set to normal),
* and other parameters that affect the final composite.
*/
O2GStateSetBlendMode(O2ContextCurrentGState(self), kO2BlendModeNormal);
[O2ContextCurrentGState(self) setShadowOffset:O2SizeZero blur:0. color:nil];
O2GStateSetAlpha(O2ContextCurrentGState(self), 1.);
}
-(void)endTransparencyLayer {

View File

@ -50,6 +50,7 @@ extern "C" {
float *_dashLengths;
O2ColorRenderingIntent _renderingIntent;
O2BlendMode _blendMode;
float _alpha;
float _flatness;
O2InterpolationQuality _interpolationQuality;
O2Size _shadowOffset;
@ -143,6 +144,8 @@ void O2GStateSetLineDash(O2GState *self,float phase,const float *lengths,unsigne
-(void)setRenderingIntent:(O2ColorRenderingIntent)intent;
O2BlendMode O2GStateBlendMode(O2GState *self);
void O2GStateSetBlendMode(O2GState *self,O2BlendMode mode);
float O2GStateAlpha(O2GState *self);
void O2GStateSetAlpha(O2GState *self,float alpha);
-(void)setFlatness:(float)flatness;
-(void)setInterpolationQuality:(O2InterpolationQuality)quality;

View File

@ -40,6 +40,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
_interpolationQuality=kO2InterpolationDefault;
_shouldAntialias=YES;
_antialiasingQuality=64;
_alpha = 1.;
return self;
}
@ -98,6 +99,8 @@ O2GState *O2GStateCopyWithZone(O2GState *self,NSZone *zone) {
copy->_shadowKernel=O2GaussianKernelRetain(self->_shadowKernel);
copy->_alpha = self->_alpha;
return copy;
}
@ -384,11 +387,19 @@ void O2GStateSetLineDash(O2GState *self,float phase,const float *lengths,unsigne
}
O2BlendMode O2GStateBlendMode(O2GState *self) {
return self->_blendMode;
return self->_blendMode;
}
void O2GStateSetBlendMode(O2GState *self,O2BlendMode mode){
self->_blendMode=mode;
self->_blendMode=mode;
}
float O2GStateAlpha(O2GState *self) {
return self->_alpha;
}
void O2GStateSetAlpha(O2GState *self,float alpha){
self->_alpha=alpha;
}
-(void)setFlatness:(float)flatness {

View File

@ -1545,7 +1545,7 @@ void O2ImageReadPatternSpan_largb32f_PRE(O2Image *self,O2Float x, O2Float y, O2a
}
-(NSString *)description {
return [NSString stringWithFormat:@"<%@:%p> width=%d,height=%d,bpc=%d,bpp=%d,bpr=%d, data length=%d",isa,self,_width,_height,_bitsPerComponent,_bitsPerPixel,_bytesPerRow,[_provider length]];
return [NSString stringWithFormat:@"<%@:%p> width=%d,height=%d,bpc=%d,bpp=%d,bpr=%d,bminfo=%x data length=%d",isa,self,_width,_height,_bitsPerComponent,_bitsPerPixel,_bytesPerRow,_bitmapInfo,[_provider length]];
}
@end

View File

@ -19,7 +19,6 @@ O2Surface *O2LayerGetSurface(O2LayerRef self) {
O2LayerRef O2LayerCreateWithContext(O2ContextRef context,O2Size size,NSDictionary *unused) {
O2LayerRef self=NSAllocateObject([O2Layer class],0,NULL);
self->_context=[context createCompatibleContextWithSize:size unused:unused];
self->_size=size;
self->_unused=[unused copy];
@ -44,4 +43,10 @@ O2ContextRef O2LayerGetContext(O2LayerRef self) {
return self->_context;
}
- (void)dealloc
{
[_context release];
[_unused release];
[super dealloc];
}
@end

View File

@ -422,13 +422,20 @@ static inline void purgeGlyphCache(O2Context_builtin_gdi *self){
}
#endif
#else
// Use the current layer context if any
O2Context_builtin_gdi *context = self;
O2LayerRef layer=[self->_layerStack lastObject];
if (layer) {
context = (O2Context_builtin_gdi *)O2LayerGetContext(layer);
}
if(gState->_fontIsDirty){
O2GStateClearFontIsDirty(gState);
[self->_gdiFont release];
self->_gdiFont=[(O2Font_gdi *)font createGDIFontSelectedInDC:self->_dc pointSize:ABS(fontSize.height)];
self->_gdiFont=[(O2Font_gdi *)font createGDIFontSelectedInDC:context->_dc pointSize:ABS(fontSize.height)];
}
SetTextColor(self->_dc,COLORREFFromColor(O2ContextFillColor(self)));
SelectObject(context->_dc,[self->_gdiFont fontHandle]);
SetTextColor(context->_dc,COLORREFFromColor(O2ContextFillColor(self)));
INT dx[count];
@ -437,7 +444,7 @@ static inline void purgeGlyphCache(O2Context_builtin_gdi *self){
dx[i]=lroundf(O2SizeApplyAffineTransform(advances[i],Trm).width);
}
ExtTextOutW(self->_dc,lroundf(point.x),lroundf(point.y),ETO_GLYPH_INDEX,NULL,(void *)glyphs,count,(advances!=NULL)?dx:NULL);
ExtTextOutW(context->_dc,lroundf(point.x),lroundf(point.y),ETO_GLYPH_INDEX,NULL,(void *)glyphs,count,(advances!=NULL)?dx:NULL);
#endif
}
else if(O2FontGetPlatformType(font)==O2FontPlatformTypeFreeType){