mirror of
https://github.com/darlinghq/darling-cocotron.git
synced 2025-01-19 10:02:31 +00:00
- SWRender, image resampling test added, removal of scissoring code, some active edge optimizations for Rasterize::fill
This commit is contained in:
parent
d204ace317
commit
512a6f1756
@ -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;
|
||||
|
@ -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>
|
||||
|
Binary file not shown.
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
BIN
testing/SWRender/overlay.png
Normal file
BIN
testing/SWRender/overlay.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 ;
|
||||
};
|
||||
|
||||
//=======================================================================
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
|
Loading…
x
Reference in New Issue
Block a user