- SWRender, more cleanup, implemented bicubic resampling, fill rate optimizations

This commit is contained in:
Christopher Lloyd 2008-04-11 01:37:26 +00:00
parent 081518cf21
commit a287c303f1
15 changed files with 1178 additions and 530 deletions

View File

@ -22,7 +22,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
-(void)drawRect:(NSRect)rect {
CGContextRef context=(CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
[[NSColor whiteColor] set];
[[NSColor blackColor] set];
NSRectFill([self bounds]);
if(_imageRef!=NULL){
CGContextSaveGState(context);

View File

@ -32,7 +32,7 @@
#import <Foundation/Foundation.h>
#import <ApplicationServices/ApplicationServices.h>
#import "riMath.h"
#import "VGmath.h"
#import "VGImage.h"
typedef enum {
@ -108,4 +108,5 @@ void KGPixelPipeLinearGradient(KGPixelPipe *self,RIfloat *g, RIfloat *rho, RIflo
void KGPixelPipeRadialGradient(KGPixelPipe *self,RIfloat *g, RIfloat *rho, RIfloat x, RIfloat y);
VGColor KGPixelPipeIntegrateColorRamp(KGPixelPipe *self,RIfloat gmin, RIfloat gmax);
VGColor KGPixelPipeColorRamp(KGPixelPipe *self,RIfloat gradient, RIfloat rho);
void KGPixelPipeWriteCoverageSpan(KGPixelPipe *self,int x, int y, int length, RIfloat coverage);
void KGPixelPipeWriteCoverage(KGPixelPipe *self,int x, int y,RIfloat *coverage,int length);
void KGPixelPipeWriteConstantCoverageSpan(KGPixelPipe *self,int x, int y, int length, RIfloat coverage);

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@
*
*-------------------------------------------------------------------*/
#import "riMath.h"
#import "VGmath.h"
#import "KGPixelPipe.h"
/*-------------------------------------------------------------------*//*!
@ -65,7 +65,6 @@ typedef struct {
RIfloat weight;
} Sample;
typedef struct {
int _vpx,_vpy,_vpwidth,_vpheight;
@ -74,11 +73,10 @@ typedef struct {
Edge *_edgePool;
Edge **_edges;
Sample samples[32];
int numSamples;
RIfloat sumWeights ;
RIfloat fradius ; //max offset of the sampling points from a pixel center
bool reflect ;
int numSamples;
RIfloat sumWeights;
RIfloat fradius; //max offset of the sampling points from a pixel center
Sample samples[32];
} KGRasterizer;
KGRasterizer *KGRasterizerAlloc();

View File

@ -116,8 +116,8 @@ void KGRasterizerAddEdge(KGRasterizer *self,const Vector2 v0, const Vector2 v1)
}
edge->normal=Vector2Make(edge->v0.y - edge->v1.y, edge->v1.x - edge->v0.x); //edge normal
edge->cnst = Vector2Dot(edge->v0, edge->normal); //distance of v0 from the origin along the edge normal
edge->minscany=floorf(edge->v0.y-self->fradius);
edge->maxscany=ceilf(edge->v1.y+self->fradius);
edge->minscany=RI_FLOOR_TO_INT(edge->v0.y-self->fradius);
edge->maxscany=ceil(edge->v1.y+self->fradius);
Vector2 vd = Vector2Subtract(edge->v1,edge->v0);
RIfloat wl = 1.0f /vd.y;
edge->vdxwl=vd.x*wl;
@ -447,6 +447,9 @@ void KGRasterizerFill(KGRasterizer *self,VGFillRule fillRule, KGPixelPipe *pixel
int nextEdge=0;
int lastBestWinding=0;
int rightOfLastEdge=NO;
int spanCapacity=256;
int spanCount=0,spanX=-1;
RIfloat span[spanCapacity];
for(scanx=RI_INT_MAX(self->_vpx,activeEdges[0]->minx);nextEdge<activeCount && scanx<xlimit;){
@ -469,15 +472,14 @@ void KGRasterizerFill(KGRasterizer *self,VGFillRule fillRule, KGPixelPipe *pixel
RIfloat pcxnormal=scanx*edge->normal.x;
s=self->numSamples;
while(--s>=0){
if(pcxnormal > pre[s])
while(--s>=0){
if(pcxnormal>pre[s])
rightOfLastEdge=NO;
else {
winding[s] += direction;
winding[s]+=direction;
rightOfLastEdge&=YES;
}
}
}
if(rightOfLastEdge){
rightOfLastEdge=YES;
@ -509,12 +511,32 @@ void KGRasterizerFill(KGRasterizer *self,VGFillRule fillRule, KGPixelPipe *pixel
if(coverage > 0.0f){
coverage /= self->sumWeights;
KGPixelPipeWriteCoverageSpan(pixelPipe,scanx,scany,(nextx-scanx),coverage);
if(spanCount==0)
spanX=scanx;
else if(scanx!=(spanX+spanCount)){
KGPixelPipeWriteCoverage(pixelPipe,spanX,scany,span,spanCount);
spanCount=0;
spanX=scanx;
}
for(i=0;i<(nextx-scanx);i++){
if(spanCount>=spanCapacity){
KGPixelPipeWriteCoverage(pixelPipe,spanX,scany,span,spanCount);
spanCount=0;
spanX=scanx+i;
}
span[spanCount++]=coverage;
}
}
scanx = nextx;
}
if(spanCount>0){
KGPixelPipeWriteCoverage(pixelPipe,spanX,scany,span,spanCount);
spanCount=0;
}
}
NSZoneFree(NULL,activeEdges);

View File

@ -111,7 +111,7 @@ static void addSliceToPath(CGMutablePathRef path,float innerRadius,float outerRa
CGAffineTransform t=CGAffineTransformMakeTranslation(-[_imageRep pixelsWide],-[_imageRep pixelsHigh]);
ctm=CGAffineTransformConcat(t,ctm);
ctm=CGAffineTransformScale(ctm,2,2);
// [render drawBitmapImageRep:_imageRep antialias:YES interpolationQuality:gState->_interpolationQuality blendMode:gState->_blendMode fillColor:blackColor transform:ctm];
[render drawBitmapImageRep:_imageRep antialias:YES interpolationQuality:gState->_interpolationQuality blendMode:gState->_blendMode fillColor:blackColor transform:ctm];
}
-(void)drawStraightLinesInRender:(KGRender *)render {
@ -179,21 +179,29 @@ static void addSliceToPath(CGMutablePathRef path,float innerRadius,float outerRa
}
}
-(void)performTest:(SEL)selector {
double start=[NSDate timeIntervalSinceReferenceDate];
[self performSelector:selector withObject:_cgRender];
[_cgTime setDoubleValue:[NSDate timeIntervalSinceReferenceDate]-start];
start=[NSDate timeIntervalSinceReferenceDate];
[self performSelector:selector withObject:_kgRender];
[_kgTime setDoubleValue:[NSDate timeIntervalSinceReferenceDate]-start];
}
-(void)setNeedsDisplay {
switch([_testPopUp selectedTag]){
case 0:
[self drawSampleInRender:_cgRender];
[self drawSampleInRender:_kgRender];
[self performTest:@selector(drawSampleInRender:)];
break;
case 1:
[self drawStraightLinesInRender:_cgRender];
[self drawStraightLinesInRender:_kgRender];
[self performTest:@selector(drawStraightLinesInRender:)];
break;
case 2:
[self drawBlendingInRender:_cgRender];
[self drawBlendingInRender:_kgRender];
[self performTest:@selector(drawBlendingInRender:)];
break;
}

View File

@ -23,7 +23,7 @@
#import "KGRender_baseline.h"
#import "VGPath.h"
#import "riMath.h"
#import "VGmath.h"
typedef float CGFloat;
@ -55,7 +55,7 @@ static void applyPath(void *info,const CGPathElement *element) {
switch(element->type){
case kCGPathElementMoveToPoint:{
RIuint8 segment[1]={VG_MOVE_TO};
RIuint8 segment[1]={kCGPathElementMoveToPoint};
RIfloat coords[2];
coords[0]=points[pointIndex].x;
@ -66,7 +66,7 @@ static void applyPath(void *info,const CGPathElement *element) {
break;
case kCGPathElementAddLineToPoint:{
RIuint8 segment[1]={VG_LINE_TO};
RIuint8 segment[1]={kCGPathElementAddLineToPoint};
RIfloat coords[2];
coords[0]=points[pointIndex].x;
@ -77,7 +77,7 @@ static void applyPath(void *info,const CGPathElement *element) {
break;
case kCGPathElementAddCurveToPoint:{
RIuint8 segment[1]={VG_CUBIC_TO};
RIuint8 segment[1]={kCGPathElementAddCurveToPoint};
RIfloat coords[6];
coords[0]=points[pointIndex].x;
@ -92,7 +92,7 @@ static void applyPath(void *info,const CGPathElement *element) {
break;
case kCGPathElementAddQuadCurveToPoint:{
RIuint8 segment[1]={VG_QUAD_TO};
RIuint8 segment[1]={kCGPathElementAddQuadCurveToPoint};
RIfloat coords[4];
coords[0]=points[pointIndex].x;
@ -105,7 +105,7 @@ static void applyPath(void *info,const CGPathElement *element) {
break;
case kCGPathElementCloseSubpath:{
RIuint8 segment[1]={VG_CLOSE_PATH};
RIuint8 segment[1]={kCGPathElementCloseSubpath};
RIfloat coords[1];
VGPathAppendData(vgPath,segment,1,coords);

View File

@ -18,7 +18,7 @@
FE1F93630D7EF19900969491 /* KGImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = FE1F93620D7EF19900969491 /* KGImageView.m */; };
FE1F937A0D7EF1F800969491 /* KGRenderController.m in Sources */ = {isa = PBXBuildFile; fileRef = FE1F93790D7EF1F800969491 /* KGRenderController.m */; };
FE9552810D77CA67009B765B /* VGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = FE9552780D77CA67009B765B /* VGImage.m */; };
FE9552820D77CA67009B765B /* riMath.m in Sources */ = {isa = PBXBuildFile; fileRef = FE95527A0D77CA67009B765B /* riMath.m */; };
FE9552820D77CA67009B765B /* VGmath.m in Sources */ = {isa = PBXBuildFile; fileRef = FE95527A0D77CA67009B765B /* VGmath.m */; };
FE9552830D77CA67009B765B /* VGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = FE95527C0D77CA67009B765B /* VGPath.m */; };
FE9552840D77CA67009B765B /* KGPixelPipe.m in Sources */ = {isa = PBXBuildFile; fileRef = FE95527E0D77CA67009B765B /* KGPixelPipe.m */; };
FE9552850D77CA67009B765B /* KGRasterizer.m in Sources */ = {isa = PBXBuildFile; fileRef = FE9552800D77CA67009B765B /* KGRasterizer.m */; };
@ -58,8 +58,8 @@
FE1F93790D7EF1F800969491 /* KGRenderController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGRenderController.m; sourceTree = "<group>"; };
FE9552770D77CA67009B765B /* VGImage.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VGImage.h; sourceTree = "<group>"; };
FE9552780D77CA67009B765B /* VGImage.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = VGImage.m; sourceTree = "<group>"; };
FE9552790D77CA67009B765B /* riMath.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = riMath.h; sourceTree = "<group>"; };
FE95527A0D77CA67009B765B /* riMath.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = riMath.m; sourceTree = "<group>"; };
FE9552790D77CA67009B765B /* VGmath.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VGmath.h; sourceTree = "<group>"; };
FE95527A0D77CA67009B765B /* VGmath.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = VGmath.m; sourceTree = "<group>"; };
FE95527B0D77CA67009B765B /* VGPath.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VGPath.h; sourceTree = "<group>"; };
FE95527C0D77CA67009B765B /* VGPath.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = VGPath.m; sourceTree = "<group>"; };
FE95527D0D77CA67009B765B /* KGPixelPipe.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = KGPixelPipe.h; sourceTree = "<group>"; };
@ -120,8 +120,8 @@
FE1F93620D7EF19900969491 /* KGImageView.m */,
FE9552770D77CA67009B765B /* VGImage.h */,
FE9552780D77CA67009B765B /* VGImage.m */,
FE9552790D77CA67009B765B /* riMath.h */,
FE95527A0D77CA67009B765B /* riMath.m */,
FE9552790D77CA67009B765B /* VGmath.h */,
FE95527A0D77CA67009B765B /* VGmath.m */,
FE95527B0D77CA67009B765B /* VGPath.h */,
FE95527C0D77CA67009B765B /* VGPath.m */,
FE95527D0D77CA67009B765B /* KGPixelPipe.h */,
@ -224,7 +224,7 @@
files = (
8D11072D0486CEB800E47090 /* main.m in Sources */,
FE9552810D77CA67009B765B /* VGImage.m in Sources */,
FE9552820D77CA67009B765B /* riMath.m in Sources */,
FE9552820D77CA67009B765B /* VGmath.m in Sources */,
FE9552830D77CA67009B765B /* VGPath.m in Sources */,
FE9552840D77CA67009B765B /* KGPixelPipe.m in Sources */,
FE9552850D77CA67009B765B /* KGRasterizer.m in Sources */,

View File

@ -26,7 +26,9 @@
*
*-------------------------------------------------------------------*/
#import "riMath.h"
#import <Foundation/NSObject.h>
#import "VGmath.h"
typedef unsigned int RIuint32;
typedef short RIint16;
@ -218,9 +220,6 @@ static inline VGColor VGColorRGBA(RIfloat cr, RIfloat cg, RIfloat cb, RIfloat ca
return result;
}
VGColor VGColorUnpack(unsigned int inputData,VGColorDescriptor inputDesc);
unsigned int VGColorPack(VGColor color,VGColorDescriptor outputDesc);
static inline VGColor VGColorMultiplyByFloat(VGColor c,RIfloat f){
return VGColorRGBA(c.r*f, c.g*f, c.b*f, c.a*f, c.m_format);
}
@ -272,14 +271,7 @@ VGColor VGColorConvert(VGColor result,VGColorInternalFormat outputFormat);
//==============================================================================================
/*-------------------------------------------------------------------*//*!
* \brief Storage and operations for VGImage.
* \param
* \return
* \note
*//*-------------------------------------------------------------------*/
typedef struct VGImage {
@interface VGImage : NSObject {
VGColorDescriptor m_desc;
int m_width;
int m_height;
@ -292,7 +284,7 @@ typedef struct VGImage {
int _mipmapsCount;
int _mipmapsCapacity;
struct VGImage **_mipmaps;
} VGImage;
}
VGImage *VGImageAlloc();
VGImage *VGImageInit(VGImage *self,VGColorDescriptor desc, int width, int height); //throws bad_alloc
@ -304,29 +296,28 @@ void VGImageDealloc(VGImage *self);
bool VGImageIsValidFormat(int format);
static inline VGColorDescriptor VGImageColorDescriptor(VGImage *image){
return image->m_desc;
}
VGColorDescriptor VGImageColorDescriptor(VGImage *image);
static inline int VGImageGetWidth(VGImage *image){
return image->m_width;
}
int VGImageGetWidth(VGImage *image);
static inline int VGImageGetHeight(VGImage *image){
return image->m_height;
}
int VGImageGetHeight(VGImage *image);
void VGImageResize(VGImage *self,int newWidth, int newHeight, VGColor newPixelColor);
void VGImageClear(VGImage *self,VGColor clearColor, int x, int y, int w, int h);
void VGImageBlit(VGImage *self,VGImage * src, int sx, int sy, int dx, int dy, int w, int h, bool dither);
void VGImageMask(VGImage *self,VGImage* src, VGMaskOperation operation, int x, int y, int w, int h);
VGColor VGImageReadPixel(VGImage *self,int x, int y);
VGColor inline VGImageReadPixel(VGImage *self,int x, int y);
VGColorInternalFormat VGImageReadPremultipliedPixelSpan(VGImage *self,int x,int y,VGColor *span,int length);
void inline VGImageWritePixel(VGImage *self,int x, int y, VGColor c);
void VGImageWritePixelSpan(VGImage *self,int x,int y,VGColor *span,int length);
void VGImageWritePixel(VGImage *self,int x, int y, VGColor c);
void VGImageWriteFilteredPixel(VGImage *self,int x, int y, VGColor c, VGbitfield channelMask);
RIfloat VGImageReadMaskPixel(VGImage *self,int x, int y); //can read any image format
void VGImageReadMaskPixelSpanIntoCoverage(VGImage *self,int x,int y,RIfloat *coverage,int length);
void VGImageWriteMaskPixel(VGImage *self,int x, int y, RIfloat m); //can write only to VG_A_8
VGColor VGImageResample(VGImage *self,RIfloat x, RIfloat y, Matrix3x3 surfaceToImage, CGInterpolationQuality quality, VGTilingMode tilingMode, VGColor tileFillColor);
@ -339,3 +330,5 @@ void VGImageSeparableConvolve(VGImage *self,VGImage * src, int kernelWidth, int
void VGImageGaussianBlur(VGImage *self,VGImage * src, RIfloat stdDeviationX, RIfloat stdDeviationY, VGTilingMode tilingMode, VGColor edgeFillColor, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask);
void VGImageLookup(VGImage *self,VGImage * src, const RIuint8 * redLUT, const RIuint8 * greenLUT, const RIuint8 * blueLUT, const RIuint8 * alphaLUT, bool outputLinear, bool outputPremultiplied, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask);
void VGImageLookupSingle(VGImage *self,VGImage * src, const RIuint32 * lookupTable, VGImageChannel sourceChannel, bool outputLinear, bool outputPremultiplied, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask);
@end

View File

@ -33,6 +33,8 @@
#import "VGImage.h"
#import "KGRasterizer.h"
@implementation VGImage
#define RI_MAX_GAUSSIAN_STD_DEVIATION 128.0f
bool VGImageIsValidFormat(int f)
@ -64,7 +66,7 @@ static unsigned int bitsToMask(unsigned int bits, unsigned int shift)
static unsigned int colorToInt(RIfloat c, int maxc)
{
return RI_INT_MIN(RI_INT_MAX((int)floor(c * (RIfloat)maxc + 0.5f), 0), maxc);
return RI_INT_MIN(RI_INT_MAX(RI_FLOOR_TO_INT(c * (RIfloat)maxc + 0.5f), 0), maxc);
}
/*-------------------------------------------------------------------*//*!
@ -87,21 +89,21 @@ static inline RIfloat intToColor(unsigned int i, unsigned int maxi)
* \note
*//*-------------------------------------------------------------------*/
VGColor VGColorUnpack(unsigned int inputData,VGColorDescriptor inputDesc) {
VGColor VGColorUnpack(unsigned int inputData,VGImage *img){
VGColor result;
int rb = inputDesc.redBits;
int gb = inputDesc.greenBits;
int bb = inputDesc.blueBits;
int ab = inputDesc.alphaBits;
int lb = inputDesc.luminanceBits;
int rs = inputDesc.redShift;
int gs = inputDesc.greenShift;
int bs = inputDesc.blueShift;
int as = inputDesc.alphaShift;
int ls = inputDesc.luminanceShift;
int rb = img->m_desc.redBits;
int gb = img->m_desc.greenBits;
int bb = img->m_desc.blueBits;
int ab = img->m_desc.alphaBits;
int lb = img->m_desc.luminanceBits;
int rs = img->m_desc.redShift;
int gs = img->m_desc.greenShift;
int bs = img->m_desc.blueShift;
int as = img->m_desc.alphaShift;
int ls = img->m_desc.luminanceShift;
result.m_format = inputDesc.internalFormat;
result.m_format = img->m_desc.internalFormat;
if(lb)
{ //luminance
result.r = result.g = result.b = intToColor(inputData >> ls, (1<<lb)-1);
@ -131,7 +133,7 @@ VGColor VGColorUnpack(unsigned int inputData,VGColorDescriptor inputDesc) {
* \note
*//*-------------------------------------------------------------------*/
unsigned int VGColorPack(VGColor color,VGColorDescriptor outputDesc) {
unsigned int VGColorPack(VGColor color,VGImage *img) {
RI_ASSERT(color.r >= 0.0f && color.r <= 1.0f);
RI_ASSERT(color.g >= 0.0f && color.g <= 1.0f);
RI_ASSERT(color.b >= 0.0f && color.b <= 1.0f);
@ -140,16 +142,16 @@ unsigned int VGColorPack(VGColor color,VGColorDescriptor outputDesc) {
RI_ASSERT(!(color.m_format & VGColorPREMULTIPLIED) || (color.r <= color.a && color.g <= color.a && color.b <= color.a)); //premultiplied colors must have color channels less than or equal to alpha
RI_ASSERT((color.m_format & VGColorLUMINANCE && color.r == color.g && color.r == color.b) || !(color.m_format & VGColorLUMINANCE)); //if luminance, r=g=b
int rb = outputDesc.redBits;
int gb = outputDesc.greenBits;
int bb = outputDesc.blueBits;
int ab = outputDesc.alphaBits;
int lb = outputDesc.luminanceBits;
int rs = outputDesc.redShift;
int gs = outputDesc.greenShift;
int bs = outputDesc.blueShift;
int as = outputDesc.alphaShift;
int ls = outputDesc.luminanceShift;
int rb = img->m_desc.redBits;
int gb = img->m_desc.greenBits;
int bb = img->m_desc.blueBits;
int ab = img->m_desc.alphaBits;
int lb = img->m_desc.luminanceBits;
int rs = img->m_desc.redShift;
int gs = img->m_desc.greenShift;
int bs = img->m_desc.blueShift;
int as = img->m_desc.alphaShift;
int ls = img->m_desc.luminanceShift;
if(lb)
{ //luminance
@ -535,6 +537,18 @@ void VGImageDealloc(VGImage *self) {
}
}
VGColorDescriptor VGImageColorDescriptor(VGImage *image){
return image->m_desc;
}
int VGImageGetWidth(VGImage *image){
return image->m_width;
}
int VGImageGetHeight(VGImage *image){
return image->m_height;
}
/*-------------------------------------------------------------------*//*!
* \brief Resizes an image. New pixels are set to the given color.
* \param
@ -572,7 +586,7 @@ void VGImageResize(VGImage *self,int newWidth, int newHeight, VGColor newPixelCo
VGColor col = newPixelColor;
col=VGColorClamp(col);
col=VGColorConvert(col,self->m_desc.internalFormat);
unsigned int c = VGColorPack(col,self->m_desc);
unsigned int c = VGColorPack(col,self);
int w = RI_INT_MIN(self->m_width, newWidth);
int j;
@ -942,7 +956,7 @@ void VGImageMask(VGImage *self,VGImage* src, VGMaskOperation operation, int x, i
* \note
*//*-------------------------------------------------------------------*/
VGColor VGImageReadPixel(VGImage *self,int x, int y) {
VGColor inline VGImageReadPixel(VGImage *self,int x, int y) {
RI_ASSERT(self->m_data);
RI_ASSERT(x >= 0 && x < self->m_width);
RI_ASSERT(y >= 0 && y < self->m_height);
@ -981,9 +995,137 @@ VGColor VGImageReadPixel(VGImage *self,int x, int y) {
break;
}
}
return VGColorUnpack(p, self->m_desc);
return VGColorUnpack(p, self);
}
static RIfloat byteToColor(unsigned int i){
return (RIfloat)(i & 0xFF) / (RIfloat)0xFF;
}
static void VGImageReadPixelSpan_RGBA_8888(VGImage *self,RIuint8 *scanline,int x,int y,VGColor *span,int length){
int format=self->m_desc.internalFormat;
int i;
for(i=0;i<length;i++,x++){
RIuint32 p = *(((RIuint32*)scanline) + x);
VGColor result;
result.r = byteToColor(p >> 24);
result.g = byteToColor(p >> 16);
result.b = byteToColor(p >> 8);
result.a = byteToColor(p >> 0);
result.m_format=format;
span[i]=result;
}
}
static void VGImageReadPixelSpan_32(VGImage *self,RIuint8 *scanline,int x,int y,VGColor *span,int length){
int i;
unsigned int p;
for(i=0;i<length;i++,x++){
RIuint32* s = (((RIuint32*)scanline) + x);
p = (unsigned int)*s;
span[i]=VGColorUnpack(p, self);
}
}
static void VGImageReadPixelSpan_16(VGImage *self,RIuint8 *scanline,int x,int y,VGColor *span,int length){
int i;
unsigned int p;
for(i=0;i<length;i++,x++){
RIuint16* s = ((RIuint16*)scanline) + x;
p = (unsigned int)*s;
span[i]=VGColorUnpack(p, self);
}
}
static void VGImageReadPixelSpan_08(VGImage *self,RIuint8 *scanline,int x,int y,VGColor *span,int length){
int i;
unsigned int p;
for(i=0;i<length;i++,x++){
RIuint8* s = ((RIuint8*)scanline) + x;
p = (unsigned int)*s;
span[i]=VGColorUnpack(p, self);
}
}
static void VGImageReadPixelSpan_01(VGImage *self,RIuint8 *scanline,int x,int y,VGColor *span,int length){
int i;
unsigned int p;
for(i=0;i<length;i++,x++){
x += self->m_bitOffset;
RIuint8* s = scanline + (x>>3);
p = (((unsigned int)*s) >> (x&7)) & 1u;
span[i]=VGColorUnpack(p, self);
}
}
static void premultiplySpan(VGColor *span,int length){
int i;
for(i=0;i<length;i++)
span[i]=VGColorPremultiply(span[i]);
}
//clamp premultiplied color to alpha to enforce consistency
static void clampPremultipliedSpan(VGColor *span,int length){
int i;
for(i=0;i<length;i++){
span[i].r = RI_MIN(span[i].r, span[i].a);
span[i].g = RI_MIN(span[i].g, span[i].a);
span[i].b = RI_MIN(span[i].b, span[i].a);
}
}
VGColorInternalFormat VGImageReadPremultipliedPixelSpan(VGImage *self,int x,int y,VGColor *span,int length) {
RIuint8 *scanline = self->m_data + y * self->m_stride;
switch(self->m_desc.format){
case VG_sRGBA_8888:
case VG_lRGBA_8888:
VGImageReadPixelSpan_RGBA_8888(self,scanline,x,y,span,length);
premultiplySpan(span,length);
break;
case VG_sRGBA_8888_PRE:
case VG_lRGBA_8888_PRE:
VGImageReadPixelSpan_RGBA_8888(self,scanline,x,y,span,length);
clampPremultipliedSpan(span,length); // We don't need to do this for internally generated images (context)
break;
default:
switch(self->m_desc.bitsPerPixel){
case 32:
VGImageReadPixelSpan_32(self,scanline,x,y,span,length);
break;
case 16:
VGImageReadPixelSpan_16(self,scanline,x,y,span,length);
break;
case 8:
VGImageReadPixelSpan_08(self,scanline,x,y,span,length);
break;
default:
RI_ASSERT(self->m_desc.bitsPerPixel == 1);
VGImageReadPixelSpan_01(self,scanline,x,y,span,length);
break;
}
if(!(self->m_desc.internalFormat&VGColorPREMULTIPLIED))
premultiplySpan(span,length);
break;
}
return span[0].m_format; // not internal format
}
/*-------------------------------------------------------------------*//*!
* \brief Writes the color to pixel (x,y). Internal color formats must
* match.
@ -992,13 +1134,13 @@ VGColor VGImageReadPixel(VGImage *self,int x, int y) {
* \note
*//*-------------------------------------------------------------------*/
void VGImageWritePixel(VGImage *self,int x, int y, VGColor c) {
void inline VGImageWritePixel(VGImage *self,int x, int y, VGColor c) {
RI_ASSERT(self->m_data);
RI_ASSERT(x >= 0 && x < self->m_width);
RI_ASSERT(y >= 0 && y < self->m_height);
RI_ASSERT(c.m_format == self->m_desc.internalFormat);
unsigned int p = VGColorPack(c,self->m_desc);
unsigned int p = VGColorPack(c,self);
RIuint8* scanline = self->m_data + y * self->m_stride;
switch(self->m_desc.bitsPerPixel)
{
@ -1038,6 +1180,122 @@ void VGImageWritePixel(VGImage *self,int x, int y, VGColor c) {
self->m_mipmapsValid = false;
}
static void VGImageWritePixelSpan_RGBA_8888(VGImage *self,RIuint8 *scanline,int x,int y,VGColor *span,int length){
int i;
for(i=0;i<length;i++,x++){
unsigned int cr = colorToInt(span[i].r, 0xFF);
unsigned int cg = colorToInt(span[i].g, 0xFF);
unsigned int cb = colorToInt(span[i].b, 0xFF);
unsigned int ca = colorToInt(span[i].a, 0xFF);
unsigned int p= (cr << 24) | (cg << 16) | (cb << 8) | (ca << 0);
RIuint32* s = ((RIuint32*)scanline) + x;
*s = (RIuint32)p;
}
}
static void VGImageWritePixelSpan_32(VGImage *self,RIuint8 *scanline,int x,int y,VGColor *span,int length){
int i;
for(i=0;i<length;i++,x++){
unsigned int p=VGColorPack(span[i],self);
RIuint32* s = ((RIuint32*)scanline) + x;
*s = (RIuint32)p;
}
}
static void VGImageWritePixelSpan_16(VGImage *self,RIuint8 *scanline,int x,int y,VGColor *span,int length){
int i;
for(i=0;i<length;i++,x++){
unsigned int p=VGColorPack(span[i],self);
RIuint16* s = ((RIuint16*)scanline) + x;
*s = (RIuint16)p;
}
}
static void VGImageWritePixelSpan_08(VGImage *self,RIuint8 *scanline,int x,int y,VGColor *span,int length){
int i;
for(i=0;i<length;i++,x++){
unsigned int p=VGColorPack(span[i],self);
RIuint8* s = ((RIuint8*)scanline) + x;
*s = (RIuint8)p;
}
}
static void VGImageWritePixelSpan_01(VGImage *self,RIuint8 *scanline,int x,int y,VGColor *span,int length){
int i;
for(i=0;i<length;i++,x++){
unsigned int p=VGColorPack(span[i],self);
x += self->m_bitOffset;
RIuint8* s = scanline + (x>>3);
RIuint8 d = *s;
d &= ~(1<<(x&7));
d |= (RIuint8)(p<<(x&7));
*s = d;
}
}
static void convertSpan(VGColor *span,int length,int format){
int i;
for(i=0;i<length;i++)
span[i]=VGColorConvert(span[i],format);
}
void VGImageWritePixelSpan(VGImage *self,int x,int y,VGColor *span,int length) {
RIuint8* scanline = self->m_data + y * self->m_stride;
if(length==0)
return;
if(span[0].m_format!=self->m_desc.internalFormat)
convertSpan(span,length,self->m_desc.internalFormat);
switch(self->m_desc.format){
case VG_sRGBA_8888:
case VG_lRGBA_8888:
VGImageWritePixelSpan_RGBA_8888(self,scanline,x,y,span,length);
break;
case VG_sRGBA_8888_PRE:
case VG_lRGBA_8888_PRE:
VGImageWritePixelSpan_RGBA_8888(self,scanline,x,y,span,length);
break;
default:
switch(self->m_desc.bitsPerPixel){
case 32:
VGImageWritePixelSpan_32(self,scanline,x,y,span,length);
break;
case 16:
VGImageWritePixelSpan_16(self,scanline,x,y,span,length);
break;
case 8:
VGImageWritePixelSpan_08(self,scanline,x,y,span,length);
break;
default:
RI_ASSERT(self->m_desc.bitsPerPixel == 1);
VGImageWritePixelSpan_01(self,scanline,x,y,span,length);
break;
}
break;
}
}
/*-------------------------------------------------------------------*//*!
* \brief Writes a filtered color to destination surface
* \param
@ -1104,6 +1362,14 @@ RIfloat VGImageReadMaskPixel(VGImage *self,int x, int y){
}
}
void VGImageReadMaskPixelSpanIntoCoverage(VGImage *self,int x,int y,RIfloat *coverage,int length) {
int i;
for(i=0;i<length;i++,x++){
coverage[i] *= VGImageReadMaskPixel(self,x, y);
}
}
/*-------------------------------------------------------------------*//*!
* \brief Writes the alpha mask to pixel (x,y) of a VG_A_8 image.
* \param
@ -1185,6 +1451,23 @@ VGColor VGImageReadTexel(VGImage *self,int u, int v, int level, VGTilingMode til
* \note
*//*-------------------------------------------------------------------*/
static inline float cubic(float v0,float v1,float v2,float v3,float fraction){
float p = (v3 - v2) - (v0 - v1);
float q = (v0 - v1) - p;
return RI_CLAMP((p * (fraction*fraction*fraction)) + (q * fraction*fraction) + ((v2 - v0) * fraction) + v1,0,1);
}
VGColor bicubicInterpolate(VGColor a,VGColor b,VGColor c,VGColor d,float fraction)
{
return VGColorRGBA(
cubic(a.r, b.r, c.r, d.r, fraction),
cubic(a.g, b.g, c.g, d.g, fraction),
cubic(a.b, b.b, c.b, d.b, fraction),
cubic(a.a, b.a, c.a, d.a, fraction),a.m_format);
}
VGColor VGImageResample(VGImage *self,RIfloat x, RIfloat y, Matrix3x3 surfaceToImage, CGInterpolationQuality quality, VGTilingMode tilingMode, VGColor tileFillColor) //throws bad_alloc
{
Vector3 uvw=Vector3Make(x,y,1);
@ -1193,7 +1476,10 @@ VGColor VGImageResample(VGImage *self,RIfloat x, RIfloat y, Matrix3x3 surfaceToI
uvw=Vector3MultiplyByFloat(uvw,oow);
if(quality== kCGInterpolationHigh)
#if 1
// Visual test indicates this is close to what Apple is using
{ //EWA on mipmaps
VGImageMakeMipMaps(self); //throws bad_alloc
VGColorInternalFormat procFormat = (VGColorInternalFormat)(self->m_desc.internalFormat | VGColorPREMULTIPLIED);
@ -1263,10 +1549,10 @@ VGColor VGImageResample(VGImage *self,RIfloat x, RIfloat y, Matrix3x3 surfaceToI
//calculate bounding box in texture space
RIfloat usize = (RIfloat)sqrt(C);
RIfloat vsize = (RIfloat)sqrt(A);
int u1 = (int)floor(U0 - usize + 0.5f);
int u2 = (int)floor(U0 + usize + 0.5f);
int v1 = (int)floor(V0 - vsize + 0.5f);
int v2 = (int)floor(V0 + vsize + 0.5f);
int u1 = RI_FLOOR_TO_INT(U0 - usize + 0.5f);
int u2 = RI_FLOOR_TO_INT(U0 + usize + 0.5f);
int v1 = RI_FLOOR_TO_INT(V0 - vsize + 0.5f);
int v2 = RI_FLOOR_TO_INT(V0 + vsize + 0.5f);
if( u1 == u2 || v1 == v2 )
return VGColorRGBA(0,0,0,0,procFormat);
@ -1309,12 +1595,44 @@ VGColor VGImageResample(VGImage *self,RIfloat x, RIfloat y, Matrix3x3 surfaceToI
sumweight = 1.0f / sumweight;
return VGColorMultiplyByFloat(color,sumweight);
}
#else
// bicubic
{
uvw.x -= 0.5f;
uvw.y -= 0.5f;
int u = RI_FLOOR_TO_INT(uvw.x);
float ufrac=uvw.x-u;
int v = RI_FLOOR_TO_INT(uvw.y);
float vfrac=uvw.y-v;
VGColor t0,t1,t2,t3;
t0 = bicubicInterpolate(
VGImageReadTexel(self,u - 1,v - 1, 0, tilingMode, tileFillColor),
VGImageReadTexel(self,u,v - 1, 0, tilingMode, tileFillColor),
VGImageReadTexel(self,u + 1,v - 1, 0, tilingMode, tileFillColor),
VGImageReadTexel(self,u + 2,v - 1, 0, tilingMode, tileFillColor), ufrac);
t1 = bicubicInterpolate(
VGImageReadTexel(self,u - 1,v, 0, tilingMode, tileFillColor),
VGImageReadTexel(self,u,v, 0, tilingMode, tileFillColor),
VGImageReadTexel(self,u + 1,v, 0, tilingMode, tileFillColor), VGImageReadTexel(self,u + 2,v, 0, tilingMode, tileFillColor), ufrac);
t2 = bicubicInterpolate(
VGImageReadTexel(self,u - 1,v + 1, 0, tilingMode, tileFillColor),
VGImageReadTexel(self,u,v + 1, 0, tilingMode, tileFillColor),
VGImageReadTexel(self,u + 1,v + 1, 0, tilingMode, tileFillColor),
VGImageReadTexel(self,u + 2,v + 1, 0, tilingMode, tileFillColor), ufrac);
t3 = bicubicInterpolate(VGImageReadTexel(self,u - 1,v + 2, 0, tilingMode, tileFillColor), VGImageReadTexel(self,u,v + 2, 0, tilingMode, tileFillColor), VGImageReadTexel(self,u + 1,v + 2, 0, tilingMode, tileFillColor), VGImageReadTexel(self,u + 2,v + 2, 0, tilingMode, tileFillColor), ufrac);
return bicubicInterpolate(t0,t1,t2,t3, vfrac);
}
#endif
else if(quality== kCGInterpolationLow)
{ //bilinear
uvw.x -= 0.5f;
uvw.y -= 0.5f;
int u = (int)floor(uvw.x);
int v = (int)floor(uvw.y);
int u = RI_FLOOR_TO_INT(uvw.x);
int v = RI_FLOOR_TO_INT(uvw.y);
VGColor c00 = VGImageReadTexel(self,u,v, 0, tilingMode, tileFillColor);
VGColor c10 = VGImageReadTexel(self,u+1,v, 0, tilingMode, tileFillColor);
VGColor c01 = VGImageReadTexel(self,u,v+1, 0, tilingMode, tileFillColor);
@ -1327,7 +1645,7 @@ VGColor VGImageResample(VGImage *self,RIfloat x, RIfloat y, Matrix3x3 surfaceToI
}
else
{ //point sampling
return VGImageReadTexel(self,(int)floor(uvw.x), (int)floor(uvw.y), 0, tilingMode, tileFillColor);
return VGImageReadTexel(self,RI_FLOOR_TO_INT(uvw.x), RI_FLOOR_TO_INT(uvw.y), 0, tilingMode, tileFillColor);
}
}
@ -1390,9 +1708,9 @@ void VGImageMakeMipMaps(VGImage *self) {
v0 *= prev->m_height;
v1 *= prev->m_height;
int su = (int)floor(u0);
int su = RI_FLOOR_TO_INT(u0);
int eu = (int)ceil(u1);
int sv = (int)floor(v0);
int sv = RI_FLOOR_TO_INT(v0);
int ev = (int)ceil(v1);
VGColor c=VGColorRGBA(0,0,0,0,procFormat);
@ -1993,3 +2311,5 @@ void VGImageLookupSingle(VGImage *self,VGImage * src, const RIuint32 * lookupTab
}
}
}
@end

View File

@ -26,19 +26,9 @@
*
*-------------------------------------------------------------------*/
#import "riMath.h"
#import "VGmath.h"
#import "KGRasterizer.h"
typedef enum {
VG_CLOSE_PATH,
VG_MOVE_TO,
VG_LINE_TO,
VG_QUAD_TO,
VG_CUBIC_TO,
VG_SQUAD_TO,
VG_SCUBIC_TO,
} VGPathSegment;
typedef struct {
Vector2 userPosition;
Vector2 userTangent;
@ -76,7 +66,7 @@ typedef struct {
int end;
} VertexIndex;
typedef struct {
@interface VGPath : NSObject {
int _segmentCount;
int _segmentCapacity;
RIuint8 *_segments;
@ -97,16 +87,12 @@ typedef struct {
RIfloat m_userMiny;
RIfloat m_userMaxx;
RIfloat m_userMaxy;
} VGPath;
}
VGPath *VGPathAlloc();
VGPath *VGPathInit(VGPath *self,int segmentCapacityHint, int coordCapacityHint);
void VGPathDealloc(VGPath *self);
static inline int VGPathGetNumCoordinates(VGPath *self){
return self->_coordinateCount;
}
void VGPathAppendData(VGPath *self,const RIuint8* segments, int numSegments, const RIfloat* data);
void VGPathAppend(VGPath *self,VGPath* srcPath);
void VGPathTransform(VGPath *self,VGPath* srcPath, Matrix3x3 matrix);
@ -119,7 +105,7 @@ RIfloat getPathLength(VGPath *self,int startIndex, int numSegments);
void VGPathGetPathBounds(VGPath *self,RIfloat *minx, RIfloat *miny, RIfloat *maxx, RIfloat *maxy);
void VGPathGetPathTransformedBounds(VGPath *self,Matrix3x3 pathToSurface, RIfloat *minx, RIfloat *miny, RIfloat *maxx, RIfloat *maxy);
int VGPathSegmentToNumCoordinates(VGPathSegment segment);
int CGPathElementTypeToNumCoordinates(CGPathElementType segment);
int VGPathCountNumCoordinates(const RIuint8* segments, int numSegments);
RIfloat VGPathGetCoordinate(VGPath *self,int i);
@ -138,3 +124,5 @@ void VGPathTessellate(VGPath *self);
void VGPathInterpolateStroke(Matrix3x3 pathToSurface, KGRasterizer *rasterizer,StrokeVertex v0,StrokeVertex v1, RIfloat strokeWidth);
void VGPathDoCap(Matrix3x3 pathToSurface, KGRasterizer *rasterizer,StrokeVertex v, RIfloat strokeWidth, CGLineCap capStyle);
void VGPathDoJoin(Matrix3x3 pathToSurface, KGRasterizer *rasterizer,StrokeVertex v0,StrokeVertex v1, RIfloat strokeWidth, CGLineJoin joinStyle, RIfloat miterLimit);
@end

View File

@ -34,7 +34,7 @@
#warning verify pointers arent assigned false or 0
#import "VGPath.h"
#import "riMath.h"
#import "VGmath.h"
enum VertexFlags
{
@ -46,26 +46,7 @@
IMPLICIT_CLOSE_SUBPATH = (1<<5)
};
/* maximum mantissa is 23 */
#define RI_MANTISSA_BITS 23
/* maximum exponent is 8 */
#define RI_EXPONENT_BITS 8
typedef union
{
float f;
unsigned i;
} RIfloatInt;
inline float getFloatMax()
{
RIfloatInt v;
v.i = (((1<<(RI_EXPONENT_BITS-1))-1+127) << 23) | (((1<<RI_MANTISSA_BITS)-1) << (23-RI_MANTISSA_BITS));
return v.f;
}
#define RI_FLOAT_MAX getFloatMax()
#define RI_FLOAT_MAX FLT_MAX
static inline RIfloat inputFloat(RIfloat f) {
//this function is used for all floating point input values
@ -192,12 +173,11 @@ static Vector2 circularLerp(Vector2 t0, Vector2 t1, RIfloat ratio)
return u0;
}
/*-------------------------------------------------------------------*//*!
* \brief VGPath constructor.
* \param
* \return
* \note
*//*-------------------------------------------------------------------*/
@implementation VGPath
static inline int VGPathGetNumCoordinates(VGPath *self){
return self->_coordinateCount;
}
VGPath *VGPathAlloc(){
return (VGPath *)NSZoneCalloc(NULL,1,sizeof(VGPath));
@ -273,9 +253,9 @@ void VGPathSetCoordinate(VGPath *self,int i, RIfloat c){
* \note
*//*-------------------------------------------------------------------*/
int VGPathSegmentToNumCoordinates(VGPathSegment segment){
int CGPathElementTypeToNumCoordinates(CGPathElementType segment){
RI_ASSERT(((int)segment) >= 0 && ((int)segment) <= 6);
static const int coords[13] = {0,2,2,4,6,2,4};
static const int coords[13] = {2,2,4,6,0};
return coords[(int)segment];
}
@ -294,7 +274,7 @@ int VGPathCountNumCoordinates(const RIuint8* segments, int numSegments)
int coordinates = 0;
int i;
for(i=0;i<numSegments;i++)
coordinates += VGPathSegmentToNumCoordinates((VGPathSegment)segments[i]);
coordinates += CGPathElementTypeToNumCoordinates((CGPathElementType)segments[i]);
return coordinates;
}
@ -457,8 +437,8 @@ void VGPathTransform(VGPath *self,VGPath* srcPath, Matrix3x3 matrix){
int i;
for(i=0;i<srcPath->_segmentCount;i++)
{
VGPathSegment segment = (VGPathSegment)srcPath->_segments[i];
int coords = VGPathSegmentToNumCoordinates(segment);
CGPathElementType segment = (CGPathElementType)srcPath->_segments[i];
int coords = CGPathElementTypeToNumCoordinates(segment);
numSrcCoords += coords;
numDstCoords += coords;
}
@ -509,19 +489,19 @@ void VGPathTransform(VGPath *self,VGPath* srcPath, Matrix3x3 matrix){
Vector2 o=Vector2Make(0,0); //the last point of the previous segment
for(i=0;i<srcPath->_segmentCount;i++)
{
VGPathSegment segment = (VGPathSegment)srcPath->_segments[i];
int coords = VGPathSegmentToNumCoordinates(segment);
CGPathElementType segment = (CGPathElementType)srcPath->_segments[i];
int coords = CGPathElementTypeToNumCoordinates(segment);
switch(segment)
{
case VG_CLOSE_PATH:
case kCGPathElementCloseSubpath:
{
RI_ASSERT(coords == 0);
o = s;
break;
}
case VG_MOVE_TO:
case kCGPathElementMoveToPoint:
{
RI_ASSERT(coords == 2);
Vector2 c=Vector2Make(VGPathGetCoordinate(srcPath,srcCoord+0), VGPathGetCoordinate(srcPath,srcCoord+1));
@ -533,7 +513,7 @@ void VGPathTransform(VGPath *self,VGPath* srcPath, Matrix3x3 matrix){
break;
}
case VG_LINE_TO:
case kCGPathElementAddLineToPoint:
{
RI_ASSERT(coords == 2);
Vector2 c=Vector2Make(VGPathGetCoordinate(srcPath,srcCoord+0), VGPathGetCoordinate(srcPath,srcCoord+1));
@ -544,7 +524,7 @@ void VGPathTransform(VGPath *self,VGPath* srcPath, Matrix3x3 matrix){
break;
}
case VG_QUAD_TO:
case kCGPathElementAddQuadCurveToPoint:
{
RI_ASSERT(coords == 4);
Vector2 c0=Vector2Make(VGPathGetCoordinate(srcPath,srcCoord+0), VGPathGetCoordinate(srcPath,srcCoord+1));
@ -559,7 +539,7 @@ void VGPathTransform(VGPath *self,VGPath* srcPath, Matrix3x3 matrix){
break;
}
case VG_CUBIC_TO:
case kCGPathElementAddCurveToPoint:
{
RI_ASSERT(coords == 6);
Vector2 c0=Vector2Make(VGPathGetCoordinate(srcPath,srcCoord+0), VGPathGetCoordinate(srcPath,srcCoord+1));
@ -578,32 +558,6 @@ void VGPathTransform(VGPath *self,VGPath* srcPath, Matrix3x3 matrix){
break;
}
case VG_SQUAD_TO:
{
RI_ASSERT(coords == 2);
Vector2 c1=Vector2Make(VGPathGetCoordinate(srcPath,srcCoord+0), VGPathGetCoordinate(srcPath,srcCoord+1));
Vector2 tc1 = Matrix3x3TransformVector2(matrix, c1);
VGPathSetCoordinate(self, self->_coordinateCount++, tc1.x);
VGPathSetCoordinate(self, self->_coordinateCount++, tc1.y);
o = c1;
break;
}
case VG_SCUBIC_TO:
{
RI_ASSERT(coords == 4);
Vector2 c1=Vector2Make(VGPathGetCoordinate(srcPath,srcCoord+0), VGPathGetCoordinate(srcPath,srcCoord+1));
Vector2 c2=Vector2Make(VGPathGetCoordinate(srcPath,srcCoord+2), VGPathGetCoordinate(srcPath,srcCoord+3));
Vector2 tc1 = Matrix3x3TransformVector2(matrix, c1);
VGPathSetCoordinate(self, self->_coordinateCount++, tc1.x);
VGPathSetCoordinate(self, self->_coordinateCount++, tc1.y);
Vector2 tc2 = Matrix3x3TransformVector2(matrix, c2);
VGPathSetCoordinate(self, self->_coordinateCount++, tc2.x);
VGPathSetCoordinate(self, self->_coordinateCount++, tc2.y);
o = c2;
break;
}
}
self->_segments[self->_segmentCount++] = (RIuint8)segment;
@ -1435,6 +1389,10 @@ bool VGPathAddLineTo(VGPath *self,Vector2 p0, Vector2 p1, bool subpathHasGeometr
* \note
*//*-------------------------------------------------------------------*/
/*
Given a quadratic BŽzier curve with control points (x0, y0), (x1, y1), and (x2, y2), an identical cubic BŽzier curve may be formed using the control points (x0, y0), (x0 + 2*x1, y0 + 2*y1)/3, (x2 + 2*x1, y2 + 2*y1)/3, (x2, y2)
*/
bool VGPathAddQuadTo(VGPath *self,Vector2 p0, Vector2 p1, Vector2 p2, bool subpathHasGeometry){
if(Vector2IsEqual(p0,p1) && Vector2IsEqual(p0,p2))
{
@ -1580,17 +1538,17 @@ void VGPathTessellate(VGPath *self){
o=Vector2Make(0,0);
p=Vector2Make(0,0);
bool subpathHasGeometry = false;
VGPathSegment prevSegment = VG_MOVE_TO;
CGPathElementType prevSegment = kCGPathElementMoveToPoint;
int i;
for(i=0;i<self->_segmentCount;i++)
{
VGPathSegment segment = (VGPathSegment)self->_segments[i];
int coords = VGPathSegmentToNumCoordinates(segment);
CGPathElementType segment = (CGPathElementType)self->_segments[i];
int coords = CGPathElementTypeToNumCoordinates(segment);
self->_segmentToVertex[i].start = self->_vertexCount;
switch(segment)
{
case VG_CLOSE_PATH:
case kCGPathElementCloseSubpath:
{
RI_ASSERT(coords == 0);
VGPathAddEndPath(self,o, s, subpathHasGeometry, CLOSE_SUBPATH);
@ -1600,11 +1558,11 @@ void VGPathTessellate(VGPath *self){
break;
}
case VG_MOVE_TO:
case kCGPathElementMoveToPoint:
{
RI_ASSERT(coords == 2);
Vector2 c=Vector2Make(VGPathGetCoordinate(self,coordIndex+0), VGPathGetCoordinate(self,coordIndex+1));
if(prevSegment != VG_MOVE_TO && prevSegment != VG_CLOSE_PATH)
if(prevSegment != kCGPathElementMoveToPoint && prevSegment != kCGPathElementCloseSubpath)
VGPathAddEndPath(self,o, s, subpathHasGeometry, IMPLICIT_CLOSE_SUBPATH);
s = c;
p = c;
@ -1613,7 +1571,7 @@ void VGPathTessellate(VGPath *self){
break;
}
case VG_LINE_TO:
case kCGPathElementAddLineToPoint:
{
RI_ASSERT(coords == 2);
Vector2 c=Vector2Make(VGPathGetCoordinate(self,coordIndex+0), VGPathGetCoordinate(self,coordIndex+1));
@ -1624,7 +1582,7 @@ void VGPathTessellate(VGPath *self){
break;
}
case VG_QUAD_TO:
case kCGPathElementAddQuadCurveToPoint:
{
RI_ASSERT(coords == 4);
Vector2 c0=Vector2Make(VGPathGetCoordinate(self,coordIndex+0), VGPathGetCoordinate(self,coordIndex+1));
@ -1636,19 +1594,7 @@ void VGPathTessellate(VGPath *self){
break;
}
case VG_SQUAD_TO:
{
RI_ASSERT(coords == 2);
Vector2 c0 = Vector2Subtract(Vector2MultiplyByFloat(o,2.0f) , p);
Vector2 c1=Vector2Make(VGPathGetCoordinate(self,coordIndex+0), VGPathGetCoordinate(self,coordIndex+1));
if(VGPathAddQuadTo(self,o, c0, c1, subpathHasGeometry))
subpathHasGeometry = true;
p = c0;
o = c1;
break;
}
case VG_CUBIC_TO:
case kCGPathElementAddCurveToPoint:
{
RI_ASSERT(coords == 6);
Vector2 c0=Vector2Make(VGPathGetCoordinate(self,coordIndex+0), VGPathGetCoordinate(self,coordIndex+1));
@ -1661,19 +1607,6 @@ void VGPathTessellate(VGPath *self){
break;
}
case VG_SCUBIC_TO:
{
RI_ASSERT(coords == 4);
Vector2 c0 = Vector2Subtract(Vector2MultiplyByFloat(o,2.0f) , p);
Vector2 c1=Vector2Make(VGPathGetCoordinate(self,coordIndex+0), VGPathGetCoordinate(self,coordIndex+1));
Vector2 c2=Vector2Make(VGPathGetCoordinate(self,coordIndex+2), VGPathGetCoordinate(self,coordIndex+3));
if(VGPathAddCubicTo(self,o, c0, c1, c2, subpathHasGeometry))
subpathHasGeometry = true;
p = c1;
o = c2;
break;
}
}
if(self->_vertexCount > self->_segmentToVertex[i].start)
@ -1691,7 +1624,7 @@ void VGPathTessellate(VGPath *self){
//add an implicit MOVE_TO to the end to close the last subpath.
//if the subpath contained only zero-length segments, this produces the necessary geometry to get it stroked
// and included in path bounds. The geometry won't be included in the pointAlongPath query.
if(prevSegment != VG_MOVE_TO && prevSegment != VG_CLOSE_PATH)
if(prevSegment != kCGPathElementMoveToPoint && prevSegment != kCGPathElementCloseSubpath)
VGPathAddEndPath(self,o, s, subpathHasGeometry, IMPLICIT_CLOSE_SUBPATH);
#if 0 // DEBUG
@ -1781,3 +1714,5 @@ void VGPathTessellate(VGPath *self){
}
#endif
}
@end

View File

@ -24,20 +24,17 @@
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
* THE USE OR OTHER DEALINGS IN THE MATERIALS.
*
*//**
* \file
* \brief Math functions, Vector and Matrix classes.
* \note
*//*-------------------------------------------------------------------*/
*-------------------------------------------------------------------*/
#import <math.h>
#import <assert.h>
#import <ApplicationServices/ApplicationServices.h>
#import <Foundation/Foundation.h>
typedef unsigned char RIuint8;
typedef float RIfloat;
#define RI_ASSERT(_) assert(_)
//#define RI_ASSERT(_) NSCParameterAssert(_)
#define RI_ASSERT(_)
#define RI_INT32_MAX (0x7fffffff)
#define RI_INT32_MIN (-0x7fffffff-1)
@ -76,6 +73,13 @@ static inline int RI_INT_MIN(int a, int b) { return (a < b) ? a : b; }
static inline int RI_INT_MOD(int a, int b) { RI_ASSERT(b >= 0); if(!b) return 0; int i = a % b; if(i < 0) i += b; RI_ASSERT(i >= 0 && i < b); return i; }
static inline int RI_INT_ADDSATURATE(int a, int b) { RI_ASSERT(b >= 0); int r = a + b; return (r >= a) ? r : RI_INT32_MAX; }
static inline int RI_FLOOR_TO_INT(RIfloat value){
if(value<0)
return floor(value);
return value;
}
typedef struct {
RIfloat x,y;
} Vector2;
@ -194,29 +198,8 @@ static inline Matrix3x3 Matrix3x3WithCGAffineTransform(CGAffineTransform transfo
return result;
}
static inline Matrix3x3 Matrix3x3Make( RIfloat m00, RIfloat m01, RIfloat m02, RIfloat m10, RIfloat m11, RIfloat m12, RIfloat m20, RIfloat m21, RIfloat m22 ) {
Matrix3x3 result;
result.matrix[0][0] = m00;
result.matrix[0][1] = m01;
result.matrix[0][2] = m02;
result.matrix[1][0] = m10;
result.matrix[1][1] = m11;
result.matrix[1][2] = m12;
result.matrix[2][0] = m20;
result.matrix[2][1] = m21;
result.matrix[2][2] = m22;
return result;
}
bool Matrix3x3InplaceInvert(Matrix3x3 *m);
static inline Matrix3x3 Matrix3x3Invert(Matrix3x3 result){
Matrix3x3InplaceInvert(&result);
return result;
}
static inline Matrix3x3 Matrix3x3Multiply(Matrix3x3 m1,Matrix3x3 m2){
Matrix3x3 t;
int i,j;
@ -244,12 +227,6 @@ static inline Vector2 Matrix3x3TransformVector2(Matrix3x3 m,Vector2 v){
return Vector2Make(v.x * m.matrix[0][0] + v.y * m.matrix[0][1] + m.matrix[0][2], v.x * m.matrix[1][0] + v.y * m.matrix[1][1] + m.matrix[1][2]);
}
//matrix * column vector. The input vector2 is implicitly expanded to (x,y,0)
static inline Vector2 Matrix3x3TangentTransformVector2(Matrix3x3 m, Vector2 v){
RI_ASSERT(Matrix3x3IsAffine(m));
return Vector2Make(v.x * m.matrix[0][0] + v.y * m.matrix[0][1], v.x * m.matrix[1][0] + v.y * m.matrix[1][1]);
}
//matrix * column vector
static inline Vector3 Matrix3x3MultiplyVector3( Matrix3x3 m,Vector3 v){
return Vector3Make(v.x*m.matrix[0][0]+v.y*m.matrix[0][1]+v.z*m.matrix[0][2],v.x*m.matrix[1][0]+v.y*m.matrix[1][1]+v.z*m.matrix[1][2], v.x*m.matrix[2][0]+v.y*m.matrix[2][1]+v.z*m.matrix[2][2] );

View File

@ -30,7 +30,7 @@
* \note
*//*-------------------------------------------------------------------*/
#import "riMath.h"
#import "VGmath.h"
/*-------------------------------------------------------------------*//*!
* \brief Inverts a 3x3 m->matrix. Returns false if the matrix is singular.