blend modes,stroking support for AGG context

This commit is contained in:
Christopher Lloyd 2011-05-20 15:29:04 -04:00
parent 0d70882b6a
commit 3ec53ba388
7 changed files with 129 additions and 65 deletions

View File

@ -1,7 +1,10 @@
#import <stdlib.h>
#import "O2Defines_AntiGrain.h"
#import <Onyx2D/O2Context.h>
// There are some constructs in Onyx2D which cause compiler crashes with ObjC++
// So we're just wrapping the AGG calls with straight C until it is sorted out.
// This might not be needed anymore, marking the ObjC headers with extern "C" seems to work
#ifdef __cplusplus
extern "C" {
@ -22,6 +25,9 @@ void O2AGGContextClipReset(O2AGGContextRef self);
void O2AGGContextSetDeviceViewport(O2AGGContextRef self,int x,int y,int w,int h);
void O2AGGContextClipToPath(O2AGGContextRef self,int evenOdd);
void O2AGGContextSetBlendMode(O2AGGContextRef self,O2BlendMode blendMode);
void O2AGGContextSetLineWidth(O2AGGContextRef self,float value);
void O2AGGContextSetLineCap(O2AGGContextRef self,O2LineCap lineCap);
void O2AGGContextFillPath(O2AGGContextRef self,float r,float g,float b,float a,double xa,double xb,double xc,double xd,double xtx,double xty);
void O2AGGContextEOFillPath(O2AGGContextRef self,float r,float g,float b,float a,double xa,double xb,double xc,double xd,double xtx,double xty);
void O2AGGContextStrokePath(O2AGGContextRef self,float r,float g,float b,float a,double xa,double xb,double xc,double xd,double xtx,double xty);

View File

@ -1,8 +1,7 @@
#import "O2AGGContext.h"
#import "O2Defines_AntiGrain.h"
#import <stdio.h>
#ifdef ANTIGRAIN_PRESENT
#import <stdio.h>
#include <agg_basics.h>
#include <agg_pixfmt_rgba.h>
#include <agg_path_storage.h>
@ -13,63 +12,56 @@
#include <agg_renderer_scanline.h>
#include <agg_conv_curve.h>
#include <agg_conv_stroke.h>
typedef agg::blender_rgba_pre<agg::rgba8, agg::order_bgra> blender_type_pre;
typedef agg::pixfmt_alpha_blend_rgba<blender_type_pre, agg::rendering_buffer, agg::int32u> pixfmt_pre;
#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;
typedef agg::renderer_base<agg::pixfmt_bgra32> renderer_base;
typedef agg::renderer_base<pixfmt_type> renderer_base;
struct O2AGGContext {
agg::rendering_buffer *renderingBuffer;
agg::pixfmt_bgra32 pixelFormat;
pixfmt_type *pixelFormat;
agg::rasterizer_scanline_aa<> *rasterizer;
renderer_base *ren_base;
agg::path_storage path;
agg::path_storage *path;
float lineWidth;
int lineCap;
};
#else
struct O2AGGContext {
int notPresent;
};
#endif
O2AGGContextRef O2AGGContextCreateBGRA32(unsigned char *pixelBytes,size_t width,size_t height,size_t bytesPerRow) {
O2AGGContextRef self=(O2AGGContextRef)calloc(1,sizeof(struct O2AGGContext));
self->renderingBuffer=new agg::rendering_buffer(pixelBytes,width,height,bytesPerRow);
self->pixelFormat.attach(*(self->renderingBuffer));
self->pixelFormat=new pixfmt_type(*(self->renderingBuffer));
self->rasterizer=new agg::rasterizer_scanline_aa<>();
self->ren_base=new renderer_base(self->pixelFormat);
self->ren_base=new renderer_base(*(self->pixelFormat));
self->path=new agg::path_storage();
return self;
}
void O2AGGContextBeginPath(O2AGGContextRef self) {
self->path.remove_all();
self->path->remove_all();
}
void O2AGGContextMoveTo(O2AGGContextRef self,double x,double y) {
self->path.move_to(x,y);
self->path->move_to(x,y);
}
void O2AGGContextAddLineTo(O2AGGContextRef self,double x,double y) {
self->path.line_to(x,y);
self->path->line_to(x,y);
}
void O2AGGContextAddCurveToPoint(O2AGGContextRef self,double cp1x,double cp1y,double cp2x,double cp2y,double endx,double endy) {
self->path.curve4(cp1x,cp1y,cp2x,cp2y,endx,endy);
self->path->curve4(cp1x,cp1y,cp2x,cp2y,endx,endy);
}
void O2AGGContextAddQuadCurveToPoint(O2AGGContextRef self,double cp1x,double cp1y,double endx,double endy) {
self->path.curve3(cp1x,cp1y,endx,endy);
self->path->curve3(cp1x,cp1y,endx,endy);
}
void O2AGGContextCloseSubpath(O2AGGContextRef self) {
self->path.end_poly();
self->path->end_poly();
}
void O2AGGContextClipReset(O2AGGContextRef self) {
@ -83,12 +75,56 @@ void O2AGGContextSetDeviceViewport(O2AGGContextRef self,int x,int y,int w,int h)
void O2AGGContextClipToPath(O2AGGContextRef self,int evenOdd) {
}
void O2AGGContextSetBlendMode(O2AGGContextRef self,O2BlendMode blendMode){
enum agg::comp_op_e blendModeMap[28]={
agg::comp_op_src_over,
agg::comp_op_multiply,
agg::comp_op_screen,
agg::comp_op_overlay,
agg::comp_op_darken,
agg::comp_op_lighten,
agg::comp_op_color_dodge,
agg::comp_op_color_burn,
agg::comp_op_hard_light,
agg::comp_op_soft_light,
agg::comp_op_difference,
agg::comp_op_exclusion,
agg::comp_op_src_over, // Hue
agg::comp_op_src_over, // Saturation
agg::comp_op_src_over, // Color
agg::comp_op_src_over, // Luminosity
agg::comp_op_clear,
agg::comp_op_src,
agg::comp_op_src_in,
agg::comp_op_src_out,
agg::comp_op_src_atop,
agg::comp_op_dst_over,
agg::comp_op_dst_in,
agg::comp_op_dst_out,
agg::comp_op_dst_atop,
agg::comp_op_xor,
agg::comp_op_plus, // PlusDarker
agg::comp_op_minus, // PlusLighter
};
self->pixelFormat->comp_op(blendModeMap[blendMode]);
}
void O2AGGContextSetLineWidth(O2AGGContextRef self,float value){
self->lineWidth=value;
}
void O2AGGContextSetLineCap(O2AGGContextRef self,O2LineCap lineCap) {
self->lineCap=lineCap;
}
void O2AGGContextFillPathWithRule(O2AGGContextRef self,float r,float g,float b,float a,double xa,double xb,double xc,double xd,double xtx,double xty,agg::filling_rule_e fillingRule) {
agg::scanline_u8 sl;
agg::trans_affine mtx(xa,xb,xc,xd,xtx,xty);
agg::conv_curve<agg::path_storage> curve(self->path);
agg::conv_curve<agg::path_storage> curve(*(self->path));
agg::conv_transform<agg::conv_curve<agg::path_storage>, agg::trans_affine> trans(curve, mtx);
curve.approximation_scale(mtx.scale());
@ -96,8 +132,6 @@ void O2AGGContextFillPathWithRule(O2AGGContextRef self,float r,float g,float b,f
self->rasterizer->add_path(trans);
self->rasterizer->filling_rule(fillingRule);
//self->pixelFormat.comp_op(2);
agg::render_scanlines_aa_solid(*(self->rasterizer),sl,*(self->ren_base),agg::rgba(r,g,b,a));
}
@ -110,15 +144,27 @@ void O2AGGContextEOFillPath(O2AGGContextRef self,float r,float g,float b,float a
}
void O2AGGContextStrokePath(O2AGGContextRef self,float r,float g,float b,float a,double xa,double xb,double xc,double xd,double xtx,double xty) {
agg::scanline_u8 sl;
agg::trans_affine mtx(xa,xb,xc,xd,xtx,xty);
agg::conv_stroke<agg::path_storage> stroke(self->path);
// agg::conv_transform<agg::conv_stroke<agg::path_storage>, agg::trans_affine> trans(stroke, mtx);
self->rasterizer->add_path(stroke);
self->rasterizer->filling_rule(agg::fill_non_zero);
agg::render_scanlines_aa_solid(*(self->rasterizer),sl,*(self->ren_base),agg::rgba(r,g,b,a));
agg::conv_curve<agg::path_storage> curve(*(self->path));
agg::conv_stroke<agg::conv_curve<agg::path_storage> > stroke(curve);
agg::conv_transform<agg::conv_stroke<agg::conv_curve<agg::path_storage> >, agg::trans_affine> trans(stroke, mtx);
curve.approximation_scale(mtx.scale());
switch(self->lineCap){
}
stroke.width(self->lineWidth);
self->rasterizer->add_path(trans);
self->rasterizer->filling_rule(agg::fill_non_zero);
agg::render_scanlines_aa_solid(*(self->rasterizer),sl,*(self->ren_base),agg::rgba(r,g,b,a));
}
#endif

View File

@ -1,7 +1,6 @@
#import <Onyx2D/O2Context_builtin_gdi.h>
#import "O2AGGContext.h"
@interface O2Context_AntiGrain : O2Context_builtin_gdi {
O2AGGContextRef _agg;
}

View File

@ -7,6 +7,7 @@
#import "O2AGGContext.h"
@implementation O2Context_AntiGrain
#ifdef ANTIGRAIN_PRESENT
-initWithSurface:(O2Surface *)surface flipped:(BOOL)flipped {
[super initWithSurface:surface flipped:flipped];
@ -72,7 +73,10 @@ static void transferPath(O2AGGContextRef agg,O2PathRef path,O2AffineTransform xf
[super clipToState:clipState];
O2AGGContextSetDeviceViewport(_agg,_vpx,_vpy,_vpwidth,_vpheight);
#if 0
// If we supported path clipping we'd need to do this
O2GState *gState=O2ContextCurrentGState(self);
NSArray *phases=[O2GStateClipState(gState) clipPhases];
int i,count=[phases count];
@ -102,20 +106,10 @@ static void transferPath(O2AGGContextRef agg,O2PathRef path,O2AffineTransform xf
}
}
#endif
}
-(void)drawPath:(O2PathDrawingMode)drawingMode {
O2GState *gState=O2ContextCurrentGState(self);
transferPath(_agg,(O2PathRef)_path,O2AffineTransformInvert(gState->_userSpaceTransform));
O2ColorRef fillColor=O2ColorConvertToDeviceRGB(gState->_fillColor);
const float *fill=O2ColorGetComponents(fillColor);
O2ColorRef strokeColor=O2ColorConvertToDeviceRGB(gState->_strokeColor);
const float *stroke=O2ColorGetComponents(strokeColor);
O2AffineTransform deviceTransform=gState->_deviceSpaceTransform;
-(void)drawPath:(O2PathDrawingMode)drawingMode {
BOOL doFill=NO;
BOOL doEOFill=NO;
BOOL doStroke=NO;
@ -143,25 +137,39 @@ static void transferPath(O2AGGContextRef agg,O2PathRef path,O2AffineTransform xf
doEOFill=YES;
doStroke=YES;
break;
}
O2GState *gState=O2ContextCurrentGState(self);
O2ColorRef fillColor=O2ColorConvertToDeviceRGB(gState->_fillColor);
const float *fillComps=O2ColorGetComponents(fillColor);
O2ColorRef strokeColor=O2ColorConvertToDeviceRGB(gState->_strokeColor);
const float *strokeComps=O2ColorGetComponents(strokeColor);
O2AGGContextSetBlendMode(_agg,O2GStateBlendMode(gState));
transferPath(_agg,(O2PathRef)_path,O2AffineTransformInvert(gState->_userSpaceTransform));
O2AffineTransform deviceTransform=gState->_deviceSpaceTransform;
if(doFill)
O2AGGContextFillPath(_agg,fill[0],fill[1],fill[2],fill[3],
O2AGGContextFillPath(_agg,fillComps[0],fillComps[1],fillComps[2],fillComps[3],
deviceTransform.a,deviceTransform.b,deviceTransform.c,deviceTransform.d,deviceTransform.tx,deviceTransform.ty);
if(doEOFill)
O2AGGContextEOFillPath(_agg,fill[0],fill[1],fill[2],fill[3],
O2AGGContextEOFillPath(_agg,fillComps[0],fillComps[1],fillComps[2],fillComps[3],
deviceTransform.a,deviceTransform.b,deviceTransform.c,deviceTransform.d,deviceTransform.tx,deviceTransform.ty);
if(doStroke)
O2AGGContextStrokePath(_agg,stroke[0],stroke[1],stroke[2],stroke[3],
if(doStroke){
O2AGGContextSetLineWidth(_agg,gState->_lineWidth);
O2AGGContextStrokePath(_agg,strokeComps[0],strokeComps[1],strokeComps[2],strokeComps[3],
deviceTransform.a,deviceTransform.b,deviceTransform.c,deviceTransform.d,deviceTransform.tx,deviceTransform.ty);
O2ColorRelease(fillColor);
O2ColorRelease(strokeColor);
}
O2ColorRelease(fillColor);
O2ColorRelease(strokeColor);
O2PathReset(_path);
}
#endif
@end

View File

@ -9,8 +9,8 @@
/* Begin PBXBuildFile section */
8D576314048677EA00EA77CD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AA1909FFE8422F4C02AAC07 /* Foundation.framework */; };
8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D5B49A704867FD3000E48DA /* InfoPlist.strings */; };
FE5C8314121D81470063E96F /* O2Context_AntiGrain.m in Sources */ = {isa = PBXBuildFile; fileRef = FE5C8313121D81470063E96F /* O2Context_AntiGrain.m */; };
FEB99C471382CDFE0072F784 /* O2AGGContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEB99C461382CDFE0072F784 /* O2AGGContext.cpp */; };
FE5C8314121D81470063E96F /* O2Context_AntiGrain.mm in Sources */ = {isa = PBXBuildFile; fileRef = FE5C8313121D81470063E96F /* O2Context_AntiGrain.mm */; };
FEB99C471382CDFE0072F784 /* O2AGGContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEB99C461382CDFE0072F784 /* O2AGGContext.mm */; };
FEE163EA137C6DAD00B2F340 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FEE163E9137C6DAD00B2F340 /* AppKit.framework */; };
/* End PBXBuildFile section */
@ -77,9 +77,9 @@
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>"; };
FE5C8313121D81470063E96F /* O2Context_AntiGrain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = O2Context_AntiGrain.m; sourceTree = "<group>"; };
FE5C8313121D81470063E96F /* O2Context_AntiGrain.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = O2Context_AntiGrain.mm; sourceTree = "<group>"; };
FEB99C451382CDFE0072F784 /* O2AGGContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = O2AGGContext.h; sourceTree = "<group>"; };
FEB99C461382CDFE0072F784 /* O2AGGContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = O2AGGContext.cpp; sourceTree = "<group>"; };
FEB99C461382CDFE0072F784 /* O2AGGContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = O2AGGContext.mm; sourceTree = "<group>"; };
FEE163E9137C6DAD00B2F340 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
FEE163EC137C6DC600B2F340 /* AppKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AppKit.xcodeproj; path = ../AppKit/AppKit.xcodeproj; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
@ -102,12 +102,12 @@
children = (
FEE163EC137C6DC600B2F340 /* AppKit.xcodeproj */,
FE5C8312121D81470063E96F /* O2Context_AntiGrain.h */,
FE5C8313121D81470063E96F /* O2Context_AntiGrain.m */,
FE5C8313121D81470063E96F /* O2Context_AntiGrain.mm */,
089C167CFE841241C02AAC07 /* Resources */,
089C1671FE841209C02AAC07 /* External Frameworks and Libraries */,
19C28FB6FE9D52B211CA2CBB /* Products */,
FEB99C451382CDFE0072F784 /* O2AGGContext.h */,
FEB99C461382CDFE0072F784 /* O2AGGContext.cpp */,
FEB99C461382CDFE0072F784 /* O2AGGContext.mm */,
);
name = O2Context_AntiGrain;
sourceTree = "<group>";
@ -276,8 +276,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FE5C8314121D81470063E96F /* O2Context_AntiGrain.m in Sources */,
FEB99C471382CDFE0072F784 /* O2AGGContext.cpp in Sources */,
FE5C8314121D81470063E96F /* O2Context_AntiGrain.mm in Sources */,
FEB99C471382CDFE0072F784 /* O2AGGContext.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -337,10 +337,10 @@
EXECUTABLE_SUFFIX = .1.0.dll;
FRAMEWORK_SEARCH_PATHS = /Developer/Cocotron/1.0/Windows/i386/Frameworks;
GCC_MODEL_TUNING = G5;
HEADER_SEARCH_PATHS = "/Developer/Cocotron/1.0/Windows/i386/agg-2.5/include/";
HEADER_SEARCH_PATHS = "/Developer/Cocotron/1.0/Windows/i386/agg-2.4/include/";
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = /Developer/Cocotron/1.0/Windows/i386/Frameworks/AppKit.framework/Resources;
LIBRARY_SEARCH_PATHS = "/Developer/Cocotron/1.0/Windows/i386/agg-2.5";
LIBRARY_SEARCH_PATHS = "/Developer/Cocotron/1.0/Windows/i386/agg-2.4";
OTHER_CFLAGS = "-D__LITTLE_ENDIAN__";
OTHER_LDFLAGS = (
"-static",

View File

@ -141,6 +141,7 @@ void O2GStateSetMiterLimit(O2GState *self,float limit);
void O2GStateSetLineDash(O2GState *self,float phase,const float *lengths,unsigned count);
-(void)setRenderingIntent:(O2ColorRenderingIntent)intent;
O2BlendMode O2GStateBlendMode(O2GState *self);
void O2GStateSetBlendMode(O2GState *self,O2BlendMode mode);
-(void)setFlatness:(float)flatness;

View File

@ -383,6 +383,10 @@ void O2GStateSetLineDash(O2GState *self,float phase,const float *lengths,unsigne
_renderingIntent=intent;
}
O2BlendMode O2GStateBlendMode(O2GState *self) {
return self->_blendMode;
}
void O2GStateSetBlendMode(O2GState *self,O2BlendMode mode){
self->_blendMode=mode;
}