mirror of
https://github.com/darlinghq/darling-cocotron.git
synced 2025-03-02 08:45:54 +00:00
- SWRender, more cleanup, implemented bicubic resampling, fill rate optimizations
This commit is contained in:
parent
081518cf21
commit
a287c303f1
Binary file not shown.
@ -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);
|
||||
|
@ -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
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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] );
|
@ -30,7 +30,7 @@
|
||||
* \note
|
||||
*//*-------------------------------------------------------------------*/
|
||||
|
||||
#import "riMath.h"
|
||||
#import "VGmath.h"
|
||||
|
||||
/*-------------------------------------------------------------------*//*!
|
||||
* \brief Inverts a 3x3 m->matrix. Returns false if the matrix is singular.
|
Loading…
x
Reference in New Issue
Block a user