- SWRender, image resampling test added, removal of scissoring code, some active edge optimizations for Rasterize::fill

This commit is contained in:
Christopher Lloyd 2008-03-13 15:09:26 +00:00
parent d204ace317
commit 512a6f1756
21 changed files with 544 additions and 528 deletions

View File

@ -3,15 +3,21 @@
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
ACTIONS = {
selectAntialias = id;
selectBlendMode = id;
selectDashLength = id;
selectDashPhase = id;
selectDestinationColor = id;
selectInterpolationQuality = id;
selectLineWidth = id;
selectPathDrawingMode = id;
selectRotation = id;
selectScaleX = id;
selectScaleY = id;
selectShadowBlur = id;
selectShadowColor = id;
selectShadowOffsetX = id;
selectShadowOffsetY = id;
setectSourceColor = id;
};
CLASS = KGRenderController;

View File

@ -23,8 +23,8 @@
<string>1</string>
<key>IBOpenObjects</key>
<array>
<integer>29</integer>
<integer>21</integer>
<integer>29</integer>
</array>
<key>IBSystem Version</key>
<string>8S2167</string>

View File

@ -18,6 +18,10 @@
CGColorSpaceRef _colorSpace;
CGBitmapInfo _bitmapInfo;
void *_data;
CGColorRef _shadowColor;
CGSize _shadowOffset;
float _shadowBlur;
}
-(void)setSize:(NSSize)size;
@ -26,7 +30,12 @@
-(void)clear;
-(void)drawPath:(CGPathRef)path drawingMode:(CGPathDrawingMode)drawingMode blendMode:(CGBlendMode)blendMode interpolationQuality:(CGInterpolationQuality)interpolationQuality fillColor:(CGColorRef)fillColor strokeColor:(CGColorRef)strokeColor lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJoin miterLimit:(float)miterLimit dashPhase:(float)dashPhase dashLengthsCount:(unsigned)dashLengthsCount dashLengths:(float *)dashLengths transform:(CGAffineTransform)xform;
-(void)setShadowColor:(CGColorRef)value;
-(void)setShadowOffset:(CGSize)value;
-(void)setShadowBlur:(float)value;
-(void)drawPath:(CGPathRef)path drawingMode:(CGPathDrawingMode)drawingMode blendMode:(CGBlendMode)blendMode interpolationQuality:(CGInterpolationQuality)interpolationQuality fillColor:(CGColorRef)fillColor strokeColor:(CGColorRef)strokeColor lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJoin miterLimit:(float)miterLimit dashPhase:(float)dashPhase dashLengthsCount:(unsigned)dashLengthsCount dashLengths:(float *)dashLengths transform:(CGAffineTransform)xform antialias:(BOOL)antialias;
-(void)drawBitmapImageRep:(NSBitmapImageRep *)imageRep antialias:(BOOL)antialias interpolationQuality:(CGInterpolationQuality)interpolationQuality blendMode:(CGBlendMode)blendMode fillColor:(CGColorRef)fillColor transform:(CGAffineTransform)xform;
@end

View File

@ -50,8 +50,27 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
((char *)_data)[i]=0;
}
-(void)drawPath:(CGPathRef)path drawingMode:(CGPathDrawingMode)drawingMode blendMode:(CGBlendMode)blendMode interpolationQuality:(CGInterpolationQuality)interpolationQuality fillColor:(CGColorRef)fillColor strokeColor:(CGColorRef)strokeColor lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJoin miterLimit:(float)miterLimit dashPhase:(float)dashPhase dashLengthsCount:(unsigned)dashLengthsCount dashLengths:(float *)dashLengths transform:(CGAffineTransform)xform{
-(void)setShadowColor:(CGColorRef)value {
value=CGColorRetain(value);
CGColorRelease(_shadowColor);
_shadowColor=value;
}
-(void)setShadowOffset:(CGSize)value {
_shadowOffset=value;
}
-(void)setShadowBlur:(float)value {
_shadowBlur=value;
}
-(void)drawPath:(CGPathRef)path drawingMode:(CGPathDrawingMode)drawingMode blendMode:(CGBlendMode)blendMode interpolationQuality:(CGInterpolationQuality)interpolationQuality fillColor:(CGColorRef)fillColor strokeColor:(CGColorRef)strokeColor lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJoin miterLimit:(float)miterLimit dashPhase:(float)dashPhase dashLengthsCount:(unsigned)dashLengthsCount dashLengths:(float *)dashLengths transform:(CGAffineTransform)xform antialias:(BOOL)antialias {
[self doesNotRecognizeSelector:_cmd];
}
-(void)drawBitmapImageRep:(NSBitmapImageRep *)imageRep antialias:(BOOL)antialias interpolationQuality:(CGInterpolationQuality)interpolationQuality blendMode:(CGBlendMode)blendMode fillColor:(CGColorRef)fillColor transform:(CGAffineTransform)xform {
[self doesNotRecognizeSelector:_cmd];
}
@end

View File

@ -7,17 +7,25 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#import <Cocoa/Cocoa.h>
#import <ApplicationServices/ApplicationServices.h>
@class KGRenderView;
@interface KGRenderController : NSObject {
IBOutlet KGRenderView *_cgView;
IBOutlet KGRenderView *_kgView;
NSBitmapImageRep *_imageRep;
}
-(void)selectDestinationColor:sender;
-(void)setectSourceColor:sender;
-(void)selectBlendMode:sender;
-(void)selectShadowColor:sender;
-(void)selectShadowBlur:sender;
-(void)selectShadowOffsetX:sender;
-(void)selectShadowOffsetY:sender;
-(void)selectPathDrawingMode:sender;
-(void)selectLineWidth:sender;
-(void)selectDashPhase:sender;
@ -26,5 +34,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
-(void)selectScaleX:sender;
-(void)selectScaleY:sender;
-(void)selectRotation:sender;
-(void)selectAntialias:sender;
-(void)selectInterpolationQuality:sender;
@end

View File

@ -17,6 +17,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
[_cgView setRender:[[[KGRender_cg alloc] init] autorelease]];
[_kgView setRender:[[[KGRender_baseline alloc] init] autorelease]];
[[NSColorPanel sharedColorPanel] setShowsAlpha:YES];
NSString *path=[[NSBundle bundleForClass:[self class]] pathForResource:@"overlay" ofType:@"png"];
_imageRep=[NSBitmapImageRep imageRepWithContentsOfFile:path];
[_cgView setOverlayImageRep:_imageRep];
[_kgView setOverlayImageRep:_imageRep];
}
-(void)selectDestinationColor:sender {
@ -34,6 +41,26 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
[_kgView setBlendMode:(CGBlendMode)[sender selectedTag]];
}
-(void)selectShadowColor:sender {
[_cgView setShadowColor:[sender color]];
[_kgView setShadowColor:[sender color]];
}
-(void)selectShadowBlur:sender {
[_cgView setShadowBlur:[sender floatValue]];
[_kgView setShadowBlur:[sender floatValue]];
}
-(void)selectShadowOffsetX:sender {
[_cgView setShadowOffsetX:[sender floatValue]];
[_kgView setShadowOffsetX:[sender floatValue]];
}
-(void)selectShadowOffsetY:sender {
[_cgView setShadowOffsetY:[sender floatValue]];
[_kgView setShadowOffsetY:[sender floatValue]];
}
-(void)selectPathDrawingMode:sender {
[_cgView setPathDrawingMode:(CGPathDrawingMode)[sender selectedTag]];
[_kgView setPathDrawingMode:(CGPathDrawingMode)[sender selectedTag]];
@ -69,4 +96,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
[_kgView setRotation:[sender floatValue]];
}
-(void)selectAntialias:sender {
[_cgView setShouldAntialias:[sender intValue]];
[_kgView setShouldAntialias:[sender intValue]];
}
-(void)selectInterpolationQuality:sender {
[_cgView setInterpolationQuality:(CGInterpolationQuality)[sender selectedTag]];
[_kgView setInterpolationQuality:(CGInterpolationQuality)[sender selectedTag]];
}
@end

View File

@ -13,11 +13,18 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
@interface KGRenderView : NSView {
KGRender *_render;
NSBitmapImageRep *_overlayRep;
struct {
BOOL _shouldAntialias;
CGInterpolationQuality _interpolationQuality;
float _scalex;
float _scaley;
float _rotation;
CGBlendMode _blendMode;
NSColor *_shadowColor;
float _shadowBlur;
NSSize _shadowOffset;
float _lineWidth;
CGLineCap _lineCap;
CGLineJoin _lineJoin;
@ -33,10 +40,17 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
}
-(void)setRender:(KGRender *)render;
-(void)setOverlayImageRep:(NSBitmapImageRep *)imageRep;
-(void)setDestinationColor:(NSColor *)color;
-(void)setSourceColor:(NSColor *)color;
-(void)setBlendMode:(CGBlendMode)blendMode;
-(void)setShadowColor:(NSColor *)value;
-(void)setShadowBlur:(float)value;
-(void)setShadowOffsetX:(float)value;
-(void)setShadowOffsetY:(float)value;
-(void)setPathDrawingMode:(CGPathDrawingMode)pathDrawingMode;
-(void)setLineWidth:(float)width;
-(void)setDashPhase:(float)value;
@ -46,4 +60,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
-(void)setScaleY:(float)value;
-(void)setRotation:(float)value;
-(void)setShouldAntialias:(BOOL)value;
-(void)setInterpolationQuality:(CGInterpolationQuality)value;
@end

View File

@ -15,10 +15,15 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
-initWithFrame:(NSRect)frame {
[super initWithFrame:frame];
gState=&gStateX;
gState->_shouldAntialias=YES;
gState->_interpolationQuality=kCGInterpolationDefault;
gState->_scalex=1;
gState->_scaley=1;
gState->_rotation=0;
gState->_blendMode=kCGBlendModeNormal;
gState->_shadowColor=[[NSColor blackColor] copy];
gState->_shadowBlur=0;
gState->_shadowOffset=NSMakeSize(10,10);
gState->_lineWidth=1;
gState->_lineCap=kCGLineCapButt;
gState->_lineJoin=kCGLineJoinMiter;
@ -31,6 +36,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
return self;
}
-(void)setOverlayImageRep:(NSBitmapImageRep *)imageRep {
[_overlayRep release];
_overlayRep=[imageRep retain];
}
-(void)setRender:(KGRender *)render {
[_render autorelease];
_render=[render retain];
@ -54,6 +64,27 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
[self setNeedsDisplay:YES];
}
-(void)setShadowColor:(NSColor *)value {
[gState->_shadowColor release];
gState->_shadowColor=[value copy];
[self setNeedsDisplay:YES];
}
-(void)setShadowBlur:(float)value {
gState->_shadowBlur=value;
[self setNeedsDisplay:YES];
}
-(void)setShadowOffsetX:(float)value {
gState->_shadowOffset.width=value;
[self setNeedsDisplay:YES];
}
-(void)setShadowOffsetY:(float)value {
gState->_shadowOffset.height=value;
[self setNeedsDisplay:YES];
}
-(void)setPathDrawingMode:(CGPathDrawingMode)pathDrawingMode {
_pathDrawingMode=pathDrawingMode;
[self setNeedsDisplay:YES];
@ -97,6 +128,16 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
[self setNeedsDisplay:YES];
}
-(void)setShouldAntialias:(BOOL)value {
gState->_shouldAntialias=value;
[self setNeedsDisplay:YES];
}
-(void)setInterpolationQuality:(CGInterpolationQuality)value {
gState->_interpolationQuality=value;
[self setNeedsDisplay:YES];
}
-(void)resizeWithOldSuperviewSize:(NSSize)oldSize {
[super resizeWithOldSuperviewSize:oldSize];
[_render setSize:[self bounds].size];
@ -139,11 +180,20 @@ static CGColorRef cgColorFromColor(NSColor *color){
ctm=CGAffineTransformRotate(ctm,M_PI*gState->_rotation/180.0);
[_render setShadowColor:cgColorFromColor(gState->_shadowColor)];
[_render setShadowOffset:CGSizeMake(gState->_shadowOffset.width,gState->_shadowOffset.height)];
[_render setShadowBlur:gState->_shadowBlur];
[_render drawPath:path1 drawingMode:_pathDrawingMode blendMode:kCGBlendModeNormal
interpolationQuality:kCGInterpolationDefault fillColor:redColor strokeColor:blackColor lineWidth:gState->_lineWidth lineCap:gState->_lineCap lineJoin:gState->_lineJoin miterLimit:gState->_miterLimit dashPhase:gState->_dashPhase dashLengthsCount:gState->_dashLengthsCount dashLengths:gState->_dashLengths transform:ctm];
[_render drawPath:path2 drawingMode:_pathDrawingMode blendMode:gState->_blendMode
interpolationQuality:kCGInterpolationDefault fillColor:blueColor strokeColor:blackColor lineWidth:gState->_lineWidth lineCap:gState->_lineCap lineJoin:gState->_lineJoin miterLimit:gState->_miterLimit dashPhase:gState->_dashPhase dashLengthsCount:gState->_dashLengthsCount dashLengths:gState->_dashLengths transform:ctm];
interpolationQuality:kCGInterpolationDefault fillColor:redColor strokeColor:blackColor lineWidth:gState->_lineWidth lineCap:gState->_lineCap lineJoin:gState->_lineJoin miterLimit:gState->_miterLimit dashPhase:gState->_dashPhase dashLengthsCount:gState->_dashLengthsCount dashLengths:gState->_dashLengths transform:ctm antialias:gState->_shouldAntialias];
[_render setShadowColor:NULL];
[_render drawPath:path2 drawingMode:_pathDrawingMode blendMode:gState->_blendMode
interpolationQuality:kCGInterpolationDefault fillColor:blueColor strokeColor:blackColor lineWidth:gState->_lineWidth lineCap:gState->_lineCap lineJoin:gState->_lineJoin miterLimit:gState->_miterLimit dashPhase:gState->_dashPhase dashLengthsCount:gState->_dashLengthsCount dashLengths:gState->_dashLengths transform:ctm antialias:gState->_shouldAntialias];
[_render drawBitmapImageRep:_overlayRep antialias:YES interpolationQuality:gState->_interpolationQuality blendMode:gState->_blendMode fillColor:blackColor transform:ctm];
[_render drawImageInContext:context];
}

View File

@ -23,6 +23,9 @@
#import "KGRender_baseline.h"
#import "riPath.h"
#import "riMath.h"
typedef float CGFloat;
@implementation KGRender_baseline
@ -140,7 +143,7 @@ static OpenVGRI::Paint *paintFromColor(CGColorRef color){
}
-(void)drawPath:(CGPathRef)path drawingMode:(CGPathDrawingMode)drawingMode blendMode:(CGBlendMode)blendMode interpolationQuality:(CGInterpolationQuality)interpolationQuality fillColor:(CGColorRef)fillColor strokeColor:(CGColorRef)strokeColor
lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJoin miterLimit:(float)miterLimit dashPhase:(float)dashPhase dashLengthsCount:(unsigned)dashLengthsCount dashLengths:(float *)dashLengths transform:(CGAffineTransform)xform {
lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJoin miterLimit:(float)miterLimit dashPhase:(float)dashPhase dashLengthsCount:(unsigned)dashLengthsCount dashLengths:(float *)dashLengths transform:(CGAffineTransform)xform antialias:(BOOL)antialias {
OpenVGRI::Path *vgPath=[self buildDeviceSpacePath:path];
OpenVGRI::PixelPipe pixelPipe;
@ -150,9 +153,6 @@ lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJ
try
{
// if(context->m_scissoring)
// _rasterizer.setScissor(context->m_scissor); //throws bad_alloc
// pixelPipe.setMask(context->m_masking ? context->getMask() : NULL);
pixelPipe.setBlendMode(blendMode);
// pixelPipe.setTileFillColor(context->m_tileFillColor);
@ -161,6 +161,10 @@ lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJ
else
pixelPipe.setImageQuality(interpolationQuality);
rasterizer.setViewport(0,0,_image->getWidth(),_image->getHeight());
rasterizer.setShouldAntialias(antialias);
CGAffineTransform u2d=CGAffineTransformMakeTranslation(0,_pixelsHigh);
u2d=CGAffineTransformScale(u2d,1,-1);
xform=CGAffineTransformConcat(xform,u2d);
@ -182,7 +186,7 @@ xform=CGAffineTransformConcat(xform,u2d);
VGFillRule fillRule=(drawingMode==kCGPathFill || drawingMode==kCGPathFillStroke)?VG_NON_ZERO:VG_EVEN_ODD;
rasterizer.fill(0, 0, _image->getWidth(), _image->getHeight(), fillRule, VG_RENDERING_QUALITY_BETTER, pixelPipe); //throws bad_alloc
rasterizer.fill(fillRule, pixelPipe); //throws bad_alloc
}
}
@ -200,7 +204,7 @@ xform=CGAffineTransformConcat(xform,u2d);
vgPath->stroke(userToSurfaceMatrix, rasterizer, dashLengths,dashLengthsCount, dashPhase, true /* context->m_strokeDashPhaseReset ? true : false*/,
lineWidth, lineCap, lineJoin, OpenVGRI::RI_MAX(miterLimit, 1.0f)); //throws bad_alloc
rasterizer.fill(0, 0, _image->getWidth(), _image->getHeight(), VG_NON_ZERO, VG_RENDERING_QUALITY_BETTER,pixelPipe); //throws bad_alloc
rasterizer.fill(VG_NON_ZERO,pixelPipe); //throws bad_alloc
}
}
}
@ -212,4 +216,88 @@ xform=CGAffineTransformConcat(xform,u2d);
}
-(void)drawBitmapImageRep:(NSBitmapImageRep *)imageRep antialias:(BOOL)antialias interpolationQuality:(CGInterpolationQuality)interpolationQuality blendMode:(CGBlendMode)blendMode fillColor:(CGColorRef)fillColor transform:(CGAffineTransform)xform {
OpenVGRI::Image* img;
OpenVGRI::Color::Descriptor descriptor=OpenVGRI::Color::formatToDescriptor(VG_lRGBA_8888);
img=new OpenVGRI::Image(descriptor,[imageRep pixelsWide],[imageRep pixelsHigh],[imageRep bytesPerRow],(OpenVGRI::RIuint8 *)[imageRep bitmapData]);
img->addReference();
try
{
CGAffineTransform i2u=CGAffineTransformMakeTranslation(0,[imageRep pixelsHigh]);
i2u=CGAffineTransformScale(i2u,1,-1);
CGAffineTransform u2d=CGAffineTransformMakeTranslation(0,_pixelsHigh);
u2d=CGAffineTransformScale(u2d,1,-1);
xform=CGAffineTransformConcat(i2u,xform);
xform=CGAffineTransformConcat(xform,u2d);
OpenVGRI::Matrix3x3 imageUserToSurface=OpenVGRI::Matrix3x3(xform);
// FIX, adjustable
OpenVGRI::Matrix3x3 fillPaintToUser=OpenVGRI::Matrix3x3();
//transform image corners into the surface space
OpenVGRI::Vector3 p0(0, 0, 1);
OpenVGRI::Vector3 p1(0, (CGFloat)img->getHeight(), 1);
OpenVGRI::Vector3 p2((CGFloat)img->getWidth(), (CGFloat)img->getHeight(), 1);
OpenVGRI::Vector3 p3((CGFloat)img->getWidth(), 0, 1);
p0 = imageUserToSurface * p0;
p1 = imageUserToSurface * p1;
p2 = imageUserToSurface * p2;
p3 = imageUserToSurface * p3;
if(p0.z <= 0.0f || p1.z <= 0.0f || p2.z <= 0.0f || p3.z <= 0.0f)
{
return;
}
//projection
p0 *= 1.0f/p0.z;
p1 *= 1.0f/p1.z;
p2 *= 1.0f/p2.z;
p3 *= 1.0f/p3.z;
OpenVGRI::Rasterizer rasterizer;
rasterizer.setViewport(0, 0, _image->getWidth(), _image->getHeight());
rasterizer.setShouldAntialias(antialias);
OpenVGRI::PixelPipe pixelPipe;
// pixelPipe.setTileFillColor(context->m_tileFillColor);
pixelPipe.setPaint(paintFromColor(fillColor));
if(interpolationQuality==kCGInterpolationDefault)
pixelPipe.setImageQuality(kCGInterpolationHigh);
else
pixelPipe.setImageQuality(interpolationQuality);
pixelPipe.setBlendMode(blendMode);
//set up rendering surface and mask buffer
pixelPipe.setRenderingSurface(_image);
// pixelPipe.setMask(context->m_masking ? context->getMask() : NULL);
OpenVGRI::Matrix3x3 surfaceToImageMatrix = imageUserToSurface;
OpenVGRI::Matrix3x3 surfaceToPaintMatrix = imageUserToSurface * fillPaintToUser;
if(surfaceToImageMatrix.invert() && surfaceToPaintMatrix.invert())
{
VGImageMode imode = VG_DRAW_IMAGE_NORMAL;
if(!surfaceToPaintMatrix.isAffine())
imode = VG_DRAW_IMAGE_NORMAL; //if paint matrix is not affine, always use normal image mode
pixelPipe.setImage(img, imode);
pixelPipe.setSurfaceToPaintMatrix(surfaceToPaintMatrix);
pixelPipe.setSurfaceToImageMatrix(surfaceToImageMatrix);
rasterizer.addEdge(OpenVGRI::Vector2(p0.x,p0.y), OpenVGRI::Vector2(p1.x,p1.y)); //throws bad_alloc
rasterizer.addEdge(OpenVGRI::Vector2(p1.x,p1.y), OpenVGRI::Vector2(p2.x,p2.y)); //throws bad_alloc
rasterizer.addEdge(OpenVGRI::Vector2(p2.x,p2.y), OpenVGRI::Vector2(p3.x,p3.y)); //throws bad_alloc
rasterizer.addEdge(OpenVGRI::Vector2(p3.x,p3.y), OpenVGRI::Vector2(p0.x,p0.y)); //throws bad_alloc
rasterizer.fill(VG_EVEN_ODD, pixelPipe); //throws bad_alloc
}
}
catch(std::bad_alloc)
{
NSLog(@"out of memory %s %d",__FILE__,__LINE__);
}
}
@end

View File

@ -23,9 +23,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
}
-(void)drawPath:(CGPathRef)path drawingMode:(CGPathDrawingMode)drawingMode blendMode:(CGBlendMode)blendMode interpolationQuality:(CGInterpolationQuality)interpolationQuality fillColor:(CGColorRef)fillColor strokeColor:(CGColorRef)strokeColor
lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJoin miterLimit:(float)miterLimit dashPhase:(float)dashPhase dashLengthsCount:(unsigned)dashLengthsCount dashLengths:(float *)dashLengths transform:(CGAffineTransform)xform {
lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJoin miterLimit:(float)miterLimit dashPhase:(float)dashPhase dashLengthsCount:(unsigned)dashLengthsCount dashLengths:(float *)dashLengths transform:(CGAffineTransform)xform antialias:(BOOL)antialias {
CGContextSaveGState(_context);
CGContextConcatCTM(_context,xform);
CGContextSetShouldAntialias(_context,antialias);
CGContextSetBlendMode(_context,blendMode);
CGContextSetFillColorWithColor(_context,fillColor);
CGContextSetStrokeColorWithColor(_context,strokeColor);
@ -36,8 +37,28 @@ lineWidth:(float)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJ
CGContextSetLineDash(_context,dashPhase,dashLengths,dashLengthsCount);
CGContextBeginPath(_context);
CGContextAddPath(_context,path);
if(_shadowColor!=NULL){
CGContextSetShadowWithColor(_context,_shadowOffset,_shadowBlur,_shadowColor);
}
CGContextDrawPath(_context,drawingMode);
CGContextRestoreGState(_context);
}
-(void)drawBitmapImageRep:(NSBitmapImageRep *)imageRep antialias:(BOOL)antialias interpolationQuality:(CGInterpolationQuality)interpolationQuality blendMode:(CGBlendMode)blendMode fillColor:(CGColorRef)fillColor transform:(CGAffineTransform)xform {
CGDataProviderRef provider=CGDataProviderCreateWithData(NULL,[imageRep bitmapData],[imageRep pixelsHigh]*[imageRep bytesPerRow],NULL);
CGImageRef image=CGImageCreate([imageRep pixelsWide],[imageRep pixelsHigh],8,[imageRep bitsPerPixel],[imageRep bytesPerRow],CGColorSpaceCreateDeviceRGB(),kCGImageAlphaLast|kCGBitmapByteOrder32Little,provider,NULL,NO,kCGRenderingIntentDefault);
CGContextSaveGState(_context);
CGContextConcatCTM(_context,xform);
CGContextSetShouldAntialias(_context,antialias);
CGContextSetInterpolationQuality(_context,interpolationQuality);
CGContextSetBlendMode(_context,blendMode);
CGContextSetFillColorWithColor(_context,fillColor);
CGContextDrawImage(_context,CGRectMake(0,0,[imageRep pixelsWide],[imageRep pixelsHigh]),image);
CGContextRestoreGState(_context);
}
@end

View File

@ -11,6 +11,7 @@
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
FE0997430D87095000033630 /* overlay.png in Resources */ = {isa = PBXBuildFile; fileRef = FE0997420D87095000033630 /* overlay.png */; };
FE1F932E0D7EEDF900969491 /* KGRender.m in Sources */ = {isa = PBXBuildFile; fileRef = FE1F932D0D7EEDF900969491 /* KGRender.m */; };
FE1F93370D7EEE6900969491 /* KGRender_cg.m in Sources */ = {isa = PBXBuildFile; fileRef = FE1F93360D7EEE6900969491 /* KGRender_cg.m */; };
FE1F93430D7EEECA00969491 /* KGRender_baseline.mm in Sources */ = {isa = PBXBuildFile; fileRef = FE1F93420D7EEECA00969491 /* KGRender_baseline.mm */; };
@ -33,6 +34,7 @@
32CA4F630368D1EE00C91783 /* SWRender_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWRender_Prefix.pch; sourceTree = "<group>"; };
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
8D1107320486CEB800E47090 /* SWRender.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SWRender.app; sourceTree = BUILT_PRODUCTS_DIR; };
FE0997420D87095000033630 /* overlay.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = overlay.png; sourceTree = "<group>"; };
FE1F932C0D7EEDF900969491 /* KGRender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGRender.h; sourceTree = "<group>"; };
FE1F932D0D7EEDF900969491 /* KGRender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGRender.m; sourceTree = "<group>"; };
FE1F93350D7EEE6900969491 /* KGRender_cg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGRender_cg.h; sourceTree = "<group>"; };
@ -141,6 +143,7 @@
29B97317FDCFA39411CA2CEA /* Resources */ = {
isa = PBXGroup;
children = (
FE0997420D87095000033630 /* overlay.png */,
8D1107310486CEB800E47090 /* Info.plist */,
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
29B97318FDCFA39411CA2CEA /* MainMenu.nib */,
@ -200,6 +203,7 @@
files = (
8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */,
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
FE0997430D87095000033630 /* overlay.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -252,6 +256,7 @@
ARCHS = i386;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = "";
GENERATE_PROFILING_CODE = NO;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
PRODUCT_NAME = SWRender;

View File

@ -65,11 +65,6 @@ typedef int VGint;
typedef unsigned int VGuint;
typedef unsigned int VGbitfield;
typedef enum {
VG_FALSE = 0,
VG_TRUE = 1
} VGboolean;
#define VG_MAXSHORT ((VGshort)((~((unsigned)0)) >> 1))
#define VG_MAXINT ((VGint)((~((unsigned)0)) >> 1))
@ -145,12 +140,6 @@ typedef enum {
VG_MAX_GAUSSIAN_STD_DEVIATION = 0x116A
} VGParamType;
typedef enum {
VG_RENDERING_QUALITY_NONANTIALIASED = 0x1200,
VG_RENDERING_QUALITY_FASTER = 0x1201,
VG_RENDERING_QUALITY_BETTER = 0x1202 /* Default */
} VGRenderingQuality;
typedef enum {
VG_PIXEL_LAYOUT_UNKNOWN = 0x1300,
VG_PIXEL_LAYOUT_RGB_VERTICAL = 0x1301,

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -208,9 +208,7 @@ public:
void resize(int newWidth, int newHeight, const Color& newPixelColor); //throws bad_alloc
void clear(const Color& clearColor, int x, int y, int w, int h);
void clear(const Color& clearColor, int x, int y, int w, int h, const Array<Rectangle>& scissors);
void blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h, bool dither); //throws bad_alloc
void blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h, const Array<Rectangle>& scissors); //throws bad_alloc
void mask(const Image* src, VGMaskOperation operation, int x, int y, int w, int h);
Color readPixel(int x, int y) const;

View File

@ -852,94 +852,6 @@ void Image::clear(const Color& clearColor, int x, int y, int w, int h)
m_mipmapsValid = false;
}
/*-------------------------------------------------------------------*//*!
* \brief Clears a rectangular portion of an image with the given clear color.
* Takes scissoring into account.
* \param
* \return
* \note
*//*-------------------------------------------------------------------*/
void Image::clear(const Color& clearColor, int x, int y, int w, int h, const Array<Rectangle>& scissors)
{
RI_ASSERT(m_data);
RI_ASSERT(m_referenceCount > 0);
//intersect clear region with image bounds
Rectangle r(0,0,m_width,m_height);
r.intersect(Rectangle(x,y,w,h));
if(!r.width || !r.height)
return; //intersection is empty or one of the rectangles is invalid
Array<ScissorEdge> scissorEdges;
for(int i=0;i<scissors.size();i++)
{
if(scissors[i].width > 0 && scissors[i].height > 0)
{
ScissorEdge e;
e.miny = scissors[i].y;
e.maxy = RI_INT_ADDSATURATE(scissors[i].y, scissors[i].height);
e.x = scissors[i].x;
e.direction = 1;
scissorEdges.push_back(e); //throws bad_alloc
e.x = RI_INT_ADDSATURATE(scissors[i].x, scissors[i].width);
e.direction = -1;
scissorEdges.push_back(e); //throws bad_alloc
}
}
if(!scissorEdges.size())
return; //there are no scissor rectangles => nothing is visible
//sort scissor edges by edge x
for(int e=0;e<scissorEdges.size()-1;e++)
{
for(int f=e+1;f<scissorEdges.size();f++)
{
if(scissorEdges[e].x > scissorEdges[f].x)
{
ScissorEdge tmp = scissorEdges[e];
scissorEdges[e] = scissorEdges[f];
scissorEdges[f] = tmp;
}
}
}
//clear the image
Color col = clearColor;
col.convert(m_desc.internalFormat);
Array<ScissorEdge> scissorAet;
for(int j=r.y;j<r.y + r.height;j++)
{
//gather scissor edges intersecting this scanline
scissorAet.clear();
for(int e=0;e<scissorEdges.size();e++)
{
const ScissorEdge& se = scissorEdges[e];
if(j >= se.miny && j < se.maxy)
scissorAet.push_back(scissorEdges[e]); //throws bad_alloc
}
if(!scissorAet.size())
continue; //scissoring is on, but there are no scissor rectangles on this scanline
//clear a scanline
int scissorWinding = 0;
int scissorIndex = 0;
for(int i=r.x;i<r.x + r.width;i++)
{
while(scissorIndex < scissorAet.size() && scissorAet[scissorIndex].x <= i)
scissorWinding += scissorAet[scissorIndex++].direction;
RI_ASSERT(scissorWinding >= 0);
if(scissorWinding)
writePixel(i, j, col);
}
}
m_mipmapsValid = false;
}
/*-------------------------------------------------------------------*//*!
* \brief Blits a source region to destination. Source and destination
* can overlap.
@ -1074,160 +986,6 @@ void Image::blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h,
m_mipmapsValid = false;
}
/*-------------------------------------------------------------------*//*!
* \brief Blits a source region to destination. Source and destination
* can overlap. Takes scissoring into account.
* \param
* \return
* \note
*//*-------------------------------------------------------------------*/
void Image::blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h, const Array<Rectangle>& scissors)
{
RI_ASSERT(src.m_data); //source exists
RI_ASSERT(m_data); //destination exists
RI_ASSERT(w > 0 && h > 0);
RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
sx = RI_INT_MIN(RI_INT_MAX(sx, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
sy = RI_INT_MIN(RI_INT_MAX(sy, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
dx = RI_INT_MIN(RI_INT_MAX(dx, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
dy = RI_INT_MIN(RI_INT_MAX(dy, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
w = RI_INT_MIN(w, (int)(RI_INT32_MAX>>2));
h = RI_INT_MIN(h, (int)(RI_INT32_MAX>>2));
int srcsx = sx, srcex = sx + w, dstsx = dx, dstex = dx + w;
if(srcsx < 0)
{
dstsx -= srcsx;
srcsx = 0;
}
if(srcex > src.m_width)
{
dstex -= srcex - src.m_width;
srcex = src.m_width;
}
if(dstsx < 0)
{
srcsx -= dstsx;
dstsx = 0;
}
if(dstex > m_width)
{
srcex -= dstex - m_width;
dstex = m_width;
}
RI_ASSERT(srcsx >= 0 && dstsx >= 0 && srcex <= src.m_width && dstex <= m_width);
w = srcex - srcsx;
RI_ASSERT(w == dstex - dstsx);
if(w <= 0)
return; //zero area
int srcsy = sy, srcey = sy + h, dstsy = dy, dstey = dy + h;
if(srcsy < 0)
{
dstsy -= srcsy;
srcsy = 0;
}
if(srcey > src.m_height)
{
dstey -= srcey - src.m_height;
srcey = src.m_height;
}
if(dstsy < 0)
{
srcsy -= dstsy;
dstsy = 0;
}
if(dstey > m_height)
{
srcey -= dstey - m_height;
dstey = m_height;
}
RI_ASSERT(srcsy >= 0 && dstsy >= 0 && srcey <= src.m_height && dstey <= m_height);
h = srcey - srcsy;
RI_ASSERT(h == dstey - dstsy);
if(h <= 0)
return; //zero area
Array<ScissorEdge> scissorEdges;
for(int i=0;i<scissors.size();i++)
{
if(scissors[i].width > 0 && scissors[i].height > 0)
{
ScissorEdge e;
e.miny = scissors[i].y;
e.maxy = RI_INT_ADDSATURATE(scissors[i].y, scissors[i].height);
e.x = scissors[i].x;
e.direction = 1;
scissorEdges.push_back(e); //throws bad_alloc
e.x = RI_INT_ADDSATURATE(scissors[i].x, scissors[i].width);
e.direction = -1;
scissorEdges.push_back(e); //throws bad_alloc
}
}
if(!scissorEdges.size())
return; //there are no scissor rectangles => nothing is visible
//sort scissor edges by edge x
for(int e=0;e<scissorEdges.size()-1;e++)
{
for(int f=e+1;f<scissorEdges.size();f++)
{
if(scissorEdges[e].x > scissorEdges[f].x)
{
ScissorEdge tmp = scissorEdges[e];
scissorEdges[e] = scissorEdges[f];
scissorEdges[f] = tmp;
}
}
}
Array<Color> tmp;
tmp.resize(w*h); //throws bad_alloc
//copy source region to tmp
for(int j=0;j<h;j++)
{
for(int i=0;i<w;i++)
{
Color c = src.readPixel(srcsx + i, srcsy + j);
c.convert(m_desc.internalFormat);
tmp[j*w+i] = c;
}
}
Array<ScissorEdge> scissorAet;
for(int j=0;j<h;j++)
{
//gather scissor edges intersecting this scanline
scissorAet.clear();
for(int e=0;e<scissorEdges.size();e++)
{
const ScissorEdge& se = scissorEdges[e];
if(dstsy + j >= se.miny && dstsy + j < se.maxy)
scissorAet.push_back(scissorEdges[e]); //throws bad_alloc
}
if(!scissorAet.size())
continue; //scissoring is on, but there are no scissor rectangles on this scanline
//blit a scanline
int scissorWinding = 0;
int scissorIndex = 0;
for(int i=0;i<w;i++)
{
while(scissorIndex < scissorAet.size() && scissorAet[scissorIndex].x <= dstsx + i)
scissorWinding += scissorAet[scissorIndex++].direction;
RI_ASSERT(scissorWinding >= 0);
if(scissorWinding)
writePixel(dstsx + i, dstsy + j, tmp[j*w+i]);
}
}
m_mipmapsValid = false;
}
/*-------------------------------------------------------------------*//*!
* \brief Applies a mask operation to a rectangular portion of a mask image.
* \param
@ -1601,15 +1359,15 @@ Color Image::resample(RIfloat x, RIfloat y, const Matrix3x3& surfaceToImage, CGI
{
RI_ASSERT(m_referenceCount > 0);
VGbitfield aq = getAllowedQuality();
aq &= (VGbitfield)quality;
//VGbitfield aq = getAllowedQuality();
//aq &= (VGbitfield)quality;
Vector3 uvw(x,y,1.0f);
uvw = surfaceToImage * uvw;
RIfloat oow = 1.0f / uvw.z;
uvw *= oow;
if(aq & kCGInterpolationHigh)
if(quality== kCGInterpolationHigh)
{ //EWA on mipmaps
makeMipMaps(); //throws bad_alloc
@ -1724,7 +1482,7 @@ Color Image::resample(RIfloat x, RIfloat y, const Matrix3x3& surfaceToImage, CGI
sumweight = 1.0f / sumweight;
return color * sumweight;
}
else if(aq & kCGInterpolationLow)
else if(quality== kCGInterpolationLow)
{ //bilinear
uvw.x -= 0.5f;
uvw.y -= 0.5f;

View File

@ -140,14 +140,6 @@ public:
RI_INLINE void operator*= ( RIfloat f ) { x *= f; y *= f; }
RI_INLINE void operator-= ( const Vector2& v ) { x -= v.x; y -= v.y; }
/* unused
RI_INLINE Vector2& operator= ( const Vector2& v ) { x = v.x; y = v.y; return *this; }
RI_INLINE RIfloat& operator[] ( int i ) { RI_ASSERT(i>=0&&i<2); return (&x)[i]; }
RI_INLINE const RIfloat& operator[] ( int i ) const { RI_ASSERT(i>=0&&i<2); return (&x)[i]; }
//if the vector is zero, returns false and leaves it unmodified
RI_INLINE void scale ( const Vector2& v ) { x *= v.x; y *= v.y; } //component-wise scale
RI_INLINE void negate () { x = -x; y = -y; }
*/
RIfloat x,y;
};

View File

@ -33,6 +33,8 @@
* \note
*//*-------------------------------------------------------------------*/
#import <Foundation/Foundation.h>
#ifndef __RIMATH_H
#include "riMath.h"
#endif
@ -74,7 +76,7 @@ public:
VGColorRampSpreadMode m_colorRampSpreadMode;
Array<GradientStop> m_colorRampStops;
Array<GradientStop> m_inputColorRampStops;
VGboolean m_colorRampPremultiplied;
BOOL m_colorRampPremultiplied;
Vector2 m_linearGradientPoint0;
Vector2 m_linearGradientPoint1;
Vector2 m_radialGradientCenter;

View File

@ -51,7 +51,7 @@ Paint::Paint() :
m_colorRampSpreadMode(VG_COLOR_RAMP_SPREAD_PAD),
m_colorRampStops(),
m_inputColorRampStops(),
m_colorRampPremultiplied(VG_TRUE),
m_colorRampPremultiplied(YES),
m_linearGradientPoint0(0,0),
m_linearGradientPoint1(1,0),
m_radialGradientCenter(0,0),
@ -322,7 +322,7 @@ void PixelPipe::radialGradient(RIfloat &g, RIfloat &rho, RIfloat x, RIfloat y) c
* \note
*//*-------------------------------------------------------------------*/
static Color readStopColor(const Array<Paint::GradientStop>& colorRampStops, int i, VGboolean colorRampPremultiplied)
static Color readStopColor(const Array<Paint::GradientStop>& colorRampStops, int i, BOOL colorRampPremultiplied)
{
RI_ASSERT(i >= 0 && i < colorRampStops.size());
Color c = colorRampStops[i].color;

View File

@ -64,42 +64,27 @@ public:
Rasterizer(); //throws bad_alloc
~Rasterizer();
void setScissor(const Array<Rectangle>& scissors); //throws bad_alloc
void setViewport(int vpx,int vpy,int vpwidth,int vpheight);
void clear();
void addEdge(const Vector2& v0, const Vector2& v1); //throws bad_alloc
void fill(int vpx, int vpy, int vpwidth, int vpheight, VGFillRule fillRule, VGRenderingQuality renderingQuality, const PixelPipe& pixelPipe) const; //throws bad_alloc
void setShouldAntialias(BOOL antialias);
void fill(VGFillRule fillRule, const PixelPipe& pixelPipe) ; //throws bad_alloc
private:
Rasterizer(const Rasterizer&); //!< Not allowed.
const Rasterizer& operator=(const Rasterizer&); //!< Not allowed.
void Rasterizer::sortEdgeTable(int start,int end) const;
struct Edge
{
Edge() : v0(), v1() {}
Vector2 v0;
Vector2 v1;
};
struct ScissorEdge
{
ScissorEdge() : x(0), miny(0), maxy(0), direction(0) {}
int x;
int miny;
int maxy;
int direction; //1 start, -1 end
};
struct ActiveEdge
{
ActiveEdge() : v0(), v1(), direction(0), minx(0.0f), maxx(0.0f), n(), cnst(0.0f) {}
Vector2 v0;
Vector2 v1;
int direction; //-1 down, 1 up
RIfloat minx; //for the current scanline
RIfloat maxx; //for the current scanline
Vector2 n;
RIfloat cnst;
int direction;
Vector2 normal;
RIfloat cnst;
};
struct Sample
@ -109,10 +94,18 @@ private:
RIfloat y;
RIfloat weight;
};
int _vpx,_vpy,_vpwidth,_vpheight;
int _edgeCount;
int _edgeCapacity;
struct Edge *_edges;
Array<Edge> m_edges;
Array<ScissorEdge> m_scissorEdges;
bool m_scissor;
Sample samples[32];
int numSamples;
RIfloat sumWeights ;
RIfloat fradius ; //max offset of the sampling points from a pixel center
bool reflect ;
};
//=======================================================================

View File

@ -44,11 +44,14 @@ namespace OpenVGRI
* \note
*//*-------------------------------------------------------------------*/
Rasterizer::Rasterizer() :
m_edges(),
m_scissorEdges(),
m_scissor(false)
{}
Rasterizer::Rasterizer()
{
_vpx=_vpy=_vpwidth=_vpheight=0;
_edgeCount=0;
_edgeCapacity=256;
_edges=(Edge *)NSZoneMalloc(NULL,_edgeCapacity*sizeof(Edge));
}
/*-------------------------------------------------------------------*//*!
* \brief Rasterizer destructor.
@ -61,6 +64,16 @@ Rasterizer::~Rasterizer()
{
}
void Rasterizer::setViewport(int vpx,int vpy,int vpwidth,int vpheight) {
RI_ASSERT(vpwidth >= 0 && vpheight >= 0);
RI_ASSERT(vpx + vpwidth >= vpx && vpy + vpheight >= vpy);
_vpx=vpx;
_vpy=vpy;
_vpwidth=vpwidth;
_vpheight=vpheight;
}
/*-------------------------------------------------------------------*//*!
* \brief Removes all appended edges.
* \param
@ -70,7 +83,7 @@ Rasterizer::~Rasterizer()
void Rasterizer::clear()
{
m_edges.clear();
_edgeCount=0;
}
/*-------------------------------------------------------------------*//*!
@ -82,53 +95,34 @@ void Rasterizer::clear()
void Rasterizer::addEdge(const Vector2& v0, const Vector2& v1)
{
if( m_edges.size() >= RI_MAX_EDGES )
if( _edgeCount >= RI_MAX_EDGES )
throw std::bad_alloc(); //throw an out of memory error if there are too many edges
if(v0.y == v1.y)
return; //skip horizontal edges (they don't affect rasterization since we scan horizontally)
Edge e;
e.v0 = v0;
e.v1 = v1;
m_edges.push_back(e); //throws bad_alloc
}
/*-------------------------------------------------------------------*//*!
* \brief Sets scissor rectangles.
* \param
* \return
* \note
*//*-------------------------------------------------------------------*/
void Rasterizer::setScissor(const Array<Rectangle>& scissors)
{
m_scissor = true;
try
{
m_scissorEdges.clear();
for(int i=0;i<scissors.size();i++)
{
if(scissors[i].width > 0 && scissors[i].height > 0)
{
ScissorEdge e;
e.miny = scissors[i].y;
e.maxy = RI_INT_ADDSATURATE(scissors[i].y, scissors[i].height);
e.x = scissors[i].x;
e.direction = 1;
m_scissorEdges.push_back(e); //throws bad_alloc
e.x = RI_INT_ADDSATURATE(scissors[i].x, scissors[i].width);
e.direction = -1;
m_scissorEdges.push_back(e); //throws bad_alloc
}
}
}
catch(std::bad_alloc)
{
m_scissorEdges.clear();
throw;
}
if(v0.y < v1.y)
{ //edge is going upward
e.v0 = v0;
e.v1 = v1;
e.direction = 1;
}
else
{ //edge is going downward
e.v0 = v1;
e.v1 = v0;
e.direction = -1;
}
e.normal.set(e.v0.y - e.v1.y, e.v1.x - e.v0.x); //edge normal
e.cnst = dot(e.v0, e.normal); //distance of v0 from the origin along the edge normal
if(_edgeCount+1>=_edgeCapacity){
_edgeCapacity*=2;
_edges=(Edge *)NSZoneRealloc(NULL,_edges,_edgeCapacity*sizeof(Edge));
}
_edges[_edgeCount++]=e;
}
/*-------------------------------------------------------------------*//*!
@ -155,48 +149,13 @@ static double radicalInverseBase2(unsigned int i)
return p;
}
/*-------------------------------------------------------------------*//*!
* \brief Calls PixelPipe::pixelPipe for each pixel with coverage greater
* than zero.
* \param
* \return
* \note
*//*-------------------------------------------------------------------*/
void Rasterizer::fill(int vpx, int vpy, int vpwidth, int vpheight, VGFillRule fillRule, VGRenderingQuality renderingQuality, const PixelPipe& pixelPipe) const
{
RI_ASSERT(vpwidth >= 0 && vpheight >= 0);
RI_ASSERT(vpx + vpwidth >= vpx && vpy + vpheight >= vpy);
RI_ASSERT(fillRule == VG_EVEN_ODD || fillRule == VG_NON_ZERO);
RI_ASSERT(renderingQuality == VG_RENDERING_QUALITY_NONANTIALIASED ||
renderingQuality == VG_RENDERING_QUALITY_FASTER ||
renderingQuality == VG_RENDERING_QUALITY_BETTER);
if(m_scissor && !m_scissorEdges.size())
return; //scissoring is on, but there are no scissor rectangles => nothing is visible
//proceed scanline by scanline
//keep track of edges that can intersect the pixel filters of the current scanline (Active Edge Table)
//until all pixels of the scanline have been processed
// for all sampling points of the current pixel
// determine the winding number using edge functions
// add filter weight to coverage
// divide coverage by the number of samples
// determine a run of pixels with constant coverage
// call fill callback for each pixel of the run
int fillRuleMask = 1;
if(fillRule == VG_NON_ZERO)
fillRuleMask = -1;
void Rasterizer::setShouldAntialias(BOOL antialias) {
//make a sampling pattern
Sample samples[32];
int numSamples;
RIfloat sumWeights = 0.0f;
RIfloat fradius = 0.0f; //max offset of the sampling points from a pixel center
bool reflect = false;
if(renderingQuality == VG_RENDERING_QUALITY_NONANTIALIASED)
{
sumWeights = 0.0f;
fradius = 0.0f; //max offset of the sampling points from a pixel center
if(!antialias){
numSamples = 1;
samples[0].x = 0.0f;
samples[0].y = 0.0f;
@ -204,31 +163,12 @@ void Rasterizer::fill(int vpx, int vpy, int vpwidth, int vpheight, VGFillRule fi
fradius = 0.0f;
sumWeights = 1.0f;
}
else if(renderingQuality == VG_RENDERING_QUALITY_FASTER)
{ //box filter of diameter 1.0f, 8-queen sampling pattern
else {
/* This is close to the Quartz AA filter, Quartz appears to be more linear but more likely to cut off */
// There doesn't seem to be much noticeable difference between 8 and 16 samples using this
numSamples = 8;
samples[0].x = 3;
samples[1].x = 7;
samples[2].x = 0;
samples[3].x = 2;
samples[4].x = 5;
samples[5].x = 1;
samples[6].x = 6;
samples[7].x = 4;
for(int i=0;i<numSamples;i++)
{
samples[i].x = (samples[i].x + 0.5f) / (RIfloat)numSamples - 0.5f;
samples[i].y = ((RIfloat)i + 0.5f) / (RIfloat)numSamples - 0.5f;
samples[i].weight = 1.0f / (RIfloat)numSamples;
sumWeights += samples[i].weight;
}
fradius = 0.5f;
}
else
{
RI_ASSERT(renderingQuality == VG_RENDERING_QUALITY_BETTER);
numSamples = 32;
fradius = 0.75f;
fradius = .75;
for(int i=0;i<numSamples;i++)
{ //Gaussian filter, implemented using Hammersley point set for sample point locations
RIfloat x = (RIfloat)radicalInverseBase2(i);
@ -250,135 +190,221 @@ void Rasterizer::fill(int vpx, int vpy, int vpwidth, int vpheight, VGFillRule fi
}
}
}
/*-------------------------------------------------------------------*//*!
* \brief Calls PixelPipe::pixelPipe for each pixel with coverage greater
* than zero.
* \param
* \return
* \note
*//*-------------------------------------------------------------------*/
struct ActiveEdge {
Vector2 v0;
Vector2 v1;
int direction; //-1 down, 1 up
RIfloat minx; //for the current scanline
RIfloat maxx; //for the current scanline
Vector2 n;
RIfloat cnst;
};
typedef struct {
int _count;
int _capacity;
ActiveEdge *_activeEdges;
} ActiveEdgeTable;
static inline void activeEdgeTableInit(ActiveEdgeTable *aet){
aet->_count=0;
aet->_capacity=512;
aet->_activeEdges=(ActiveEdge *)NSZoneMalloc(NULL,aet->_capacity*sizeof(ActiveEdge));
}
static inline void activeEdgeTableFree(ActiveEdgeTable *aet){
NSZoneFree(NULL,aet->_activeEdges);
}
static inline int activeEdgeTableCount(ActiveEdgeTable *aet){
return aet->_count;
}
static inline void activeEdgeTableReset(ActiveEdgeTable *aet){
aet->_count=0;
}
static inline ActiveEdge *activeEdgeTableAt(ActiveEdgeTable *aet,int index){
RI_ASSERT(index<aet->_count);
return aet->_activeEdges+index;
}
static inline void activeEdgeTableAdd(ActiveEdgeTable *aet,ActiveEdge edge){
if(aet->_count+1>=aet->_capacity){
aet->_capacity*=2;
aet->_activeEdges=(ActiveEdge *)NSZoneRealloc(NULL,aet->_activeEdges,aet->_capacity*sizeof(ActiveEdge));
}
aet->_activeEdges[aet->_count++]=edge;
}
static inline void activeEdgeTableSort(ActiveEdgeTable *aet,int start,int end){
if (start < end) {
ActiveEdge pivot=aet->_activeEdges[end];
int i = start;
int j = end;
while (i != j) {
if (aet->_activeEdges[i].minx < pivot.minx) {
i++;
}
else {
aet->_activeEdges[j] = aet->_activeEdges[i];
aet->_activeEdges[i] = aet->_activeEdges[j-1];
j--;
}
}
aet->_activeEdges[j] = pivot;
activeEdgeTableSort(aet, start, j-1);
activeEdgeTableSort(aet, j+1, end);
}
}
void Rasterizer::sortEdgeTable(int start,int end) const{
if (start < end) {
Edge pivot=_edges[end];
int i = start;
int j = end;
while (i != j) {
if (_edges[i].v0.y < pivot.v0.y || (_edges[i].v0.y==pivot.v0.y && _edges[i].v1.y<pivot.v1.y)) {
i ++;
}
else {
_edges[j] = _edges[i];
_edges[i] = _edges[j-1];
j --;
}
}
_edges[j] = pivot;
sortEdgeTable( start, j-1);
sortEdgeTable( j+1, end);
}
}
void Rasterizer::fill(VGFillRule fillRule, const PixelPipe& pixelPipe)
{
RI_ASSERT(fillRule == VG_EVEN_ODD || fillRule == VG_NON_ZERO);
//proceed scanline by scanline
//keep track of edges that can intersect the pixel filters of the current scanline (Active Edge Table)
//until all pixels of the scanline have been processed
// for all sampling points of the current pixel
// determine the winding number using edge functions
// add filter weight to coverage
// divide coverage by the number of samples
// determine a run of pixels with constant coverage
// call fill callback for each pixel of the run
int fillRuleMask = 1;
if(fillRule == VG_NON_ZERO)
fillRuleMask = -1;
//fill the screen
Array<ActiveEdge> aet;
Array<ScissorEdge> scissorAet;
for(int j=vpy;j<vpy+vpheight;j++)
ActiveEdgeTable aet;
activeEdgeTableInit(&aet);
sortEdgeTable(0,_edgeCount-1);
int miny=_vpy;
int maxy=_vpy+_vpheight;
if(_edgeCount>0){
int lowesty=floorf(_edges[0].v0.y-fradius+0.5f);
if(lowesty>miny){
miny=lowesty;
}
}
int startAtEdge=0;
for(int j=miny;j<maxy;j++)
{
//gather scissor edges intersecting this scanline
scissorAet.clear();
if( m_scissor )
{
for(int e=0;e<m_scissorEdges.size();e++)
{
const ScissorEdge& se = m_scissorEdges[e];
if(j >= se.miny && j < se.maxy)
scissorAet.push_back(m_scissorEdges[e]); //throws bad_alloc
}
if(!scissorAet.size())
continue; //scissoring is on, but there are no scissor rectangles on this scanline
}
RIfloat cminy = (RIfloat)j - fradius + 0.5f;
RIfloat cmaxy = (RIfloat)j + fradius + 0.5f;
//simple AET: scan through all the edges and pick the ones intersecting this scanline
aet.clear();
for(int e=0;e<m_edges.size();e++)
{
RIfloat cminy = (RIfloat)j - fradius + 0.5f;
RIfloat cmaxy = (RIfloat)j + fradius + 0.5f;
const Edge& ed = m_edges[e];
RI_ASSERT(ed.v0.y != ed.v1.y); //horizontal edges should have been dropped already
activeEdgeTableReset(&aet);
BOOL gotActiveEdge=NO;
for(int e=startAtEdge;e<_edgeCount;e++) {
const Edge ed = _edges[e];
ActiveEdge ae;
if(ed.v0.y < ed.v1.y)
{ //edge is going upward
ae.v0 = ed.v0;
ae.v1 = ed.v1;
ae.direction = 1;
}
else
{ //edge is going downward
ae.v0 = ed.v1;
ae.v1 = ed.v0;
ae.direction = -1;
}
if(cmaxy >= ae.v0.y && cminy < ae.v1.y)
{
ae.n.set(ae.v0.y - ae.v1.y, ae.v1.x - ae.v0.x); //edge normal
ae.cnst = dot(ae.v0, ae.n); //distance of v0 from the origin along the edge normal
if(cmaxy >= ed.v0.y && cminy < ed.v1.y){
if(!gotActiveEdge){
gotActiveEdge=YES;
startAtEdge=e;
}
ActiveEdge ae;
ae.v0=ed.v0;
ae.v1=ed.v1;
ae.direction=ed.direction;
ae.n=ed.normal;
ae.cnst=ed.cnst;
//compute edge min and max x-coordinates for this scanline
Vector2 vd = ae.v1 - ae.v0;
RIfloat wl = 1.0f / vd.y;
RIfloat sx = ae.v0.x + vd.x * (cminy - ae.v0.y) * wl;
RIfloat ex = ae.v0.x + vd.x * (cmaxy - ae.v0.y) * wl;
RIfloat bminx = RI_MIN(ae.v0.x, ae.v1.x);
RIfloat bmaxx = RI_MAX(ae.v0.x, ae.v1.x);
RIfloat sx = ae.v0.x + vd.x * (cminy - ae.v0.y) * wl;
RIfloat ex = ae.v0.x + vd.x * (cmaxy - ae.v0.y) * wl;
sx = RI_CLAMP(sx, bminx, bmaxx);
ex = RI_CLAMP(ex, bminx, bmaxx);
ae.minx = RI_MIN(sx,ex);
ae.maxx = RI_MAX(sx,ex);
aet.push_back(ae); //throws bad_alloc
activeEdgeTableAdd(&aet,ae);
}
else if(ed.v0.y>cmaxy)
break;
}
if(!aet.size())
if(!activeEdgeTableCount(&aet))
continue; //no edges on the whole scanline, skip it
//sort AET by edge minx
for(int e=0;e<aet.size()-1;e++)
{
for(int f=e+1;f<aet.size();f++)
{
if(aet[e].minx > aet[f].minx)
{
ActiveEdge tmp = aet[e];
aet[e] = aet[f];
aet[f] = tmp;
}
}
}
//sort scissor AET by edge x
for(int e=0;e<scissorAet.size()-1;e++)
{
for(int f=e+1;f<scissorAet.size();f++)
{
if(scissorAet[e].x > scissorAet[f].x)
{
ScissorEdge tmp = scissorAet[e];
scissorAet[e] = scissorAet[f];
scissorAet[f] = tmp;
}
}
}
activeEdgeTableSort(&aet,0,activeEdgeTableCount(&aet)-1);
//fill the scanline
int scissorWinding = m_scissor ? 0 : 1; //if scissoring is off, winding is always 1
int scissorIndex = 0;
int aes = 0;
int aen = 0;
for(int i=vpx;i<vpx+vpwidth;)
for(int i=_vpx;i<_vpx+_vpwidth;)
{
Vector2 pc(i + 0.5f, j + 0.5f); //pixel center
//find edges that intersect or are to the left of the pixel antialiasing filter
while(aes < aet.size() && pc.x + fradius >= aet[aes].minx)
while(aes < activeEdgeTableCount(&aet) && pc.x + fradius >= activeEdgeTableAt(&aet,aes)->minx)
aes++;
//edges [0,aes[ may have an effect on winding, and need to be evaluated while sampling
//edges [0,aes] may have an effect on winding, and need to be evaluated while sampling
//compute coverage
RIfloat coverage = 0.0f;
for(int s=0;s<numSamples;s++)
{
for(int s=0;s<numSamples;s++){
Vector2 sp = pc; //sampling point
if(reflect && (i&1))
sp.x -= samples[s].x;
else
sp.x += samples[s].x;
if(reflect && (j&1))
sp.y -= samples[s].y;
else
sp.y += samples[s].y;
sp.x += samples[s].x;
sp.y += samples[s].y;
//compute winding number by evaluating the edge functions of edges to the left of the sampling point
int winding = 0;
for(int e=0;e<aes;e++)
{
if(sp.y >= aet[e].v0.y && sp.y < aet[e].v1.y)
{ //evaluate edge function to determine on which side of the edge the sampling point lies
RIfloat side = dot(sp, aet[e].n) - aet[e].cnst;
for(int e=0;e<aes;e++){
if(sp.y >= activeEdgeTableAt(&aet,e)->v0.y && sp.y < activeEdgeTableAt(&aet,e)->v1.y){
//evaluate edge function to determine on which side of the edge the sampling point lies
RIfloat side = dot(sp, activeEdgeTableAt(&aet,e)->n) - activeEdgeTableAt(&aet,e)->cnst;
if(side <= 0.0f) //implicit tie breaking: a sampling point on an opening edge is in, on a closing edge it's out
winding += aet[e].direction;
winding += activeEdgeTableAt(&aet,e)->direction;
}
}
if( winding & fillRuleMask )
@ -389,33 +415,29 @@ void Rasterizer::fill(int vpx, int vpy, int vpwidth, int vpheight, VGFillRule fi
//scan AET from left to right and skip all the edges that are completely to the left of the pixel filter.
//since AET is sorted by minx, the edge we stop at is the leftmost of the edges we haven't passed yet.
//if that edge is to the right of this pixel, coverage is constant between this pixel and the start of the edge.
while(aen < aet.size() && aet[aen].maxx < pc.x - fradius - 0.01f) //0.01 is a safety region to prevent too aggressive optimization due to numerical inaccuracy
while(aen < activeEdgeTableCount(&aet) && activeEdgeTableAt(&aet,aen)->maxx < pc.x - fradius - 0.01f) //0.01 is a safety region to prevent too aggressive optimization due to numerical inaccuracy
aen++;
int endSpan = vpx + vpwidth; //endSpan is the first pixel NOT part of the span
if(aen < aet.size())
endSpan = RI_INT_MAX(i+1, RI_INT_MIN(endSpan, (int)ceil(aet[aen].minx - fradius - 0.5f)));
int endSpan = _vpx + _vpwidth; //endSpan is the first pixel NOT part of the span
if(aen < activeEdgeTableCount(&aet))
endSpan = RI_INT_MAX(i+1, RI_INT_MIN(endSpan, (int)ceil(activeEdgeTableAt(&aet,aen)->minx - fradius - 0.5f)));
coverage /= sumWeights;
RI_ASSERT(coverage >= 0.0f && coverage <= 1.0f);
//fill a run of pixels with constant coverage
if(coverage > 0.0f)
{
for(;i<endSpan;i++)
{
//update scissor winding number
while(scissorIndex < scissorAet.size() && scissorAet[scissorIndex].x <= i)
scissorWinding += scissorAet[scissorIndex++].direction;
RI_ASSERT(scissorWinding >= 0);
if(scissorWinding)
pixelPipe.pixelPipe(i, j, coverage);
}
}
i = endSpan;
}
}
activeEdgeTableFree(&aet);
}
//=======================================================================