mirror of
https://github.com/darlinghq/darling-cocotron.git
synced 2024-12-04 02:00:51 +00:00
- SWRender, more fill optimizations, added blending test, several blend formulas fixed and tested.
This commit is contained in:
parent
5d821940fd
commit
44511579a1
Binary file not shown.
@ -494,6 +494,82 @@ VGColor KGPixelPipeColorRamp(KGPixelPipe *self,RIfloat gradient, RIfloat rho)
|
||||
r = rsrc + rdst
|
||||
*//*-------------------------------------------------------------------*/
|
||||
|
||||
static inline float colorFromTemp(float c,float q,float p){
|
||||
if(6.0*c<1)
|
||||
c=p+(q-p)*6.0*c;
|
||||
else if(2.0*c<1)
|
||||
c=q;
|
||||
else if(3.0*c<2)
|
||||
c=p+(q-p)*((2.0/3.0)-c)*6.0;
|
||||
else
|
||||
c=p;
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline void HSLToRGB(float hue,float saturation,float luminance,float *redp,float *greenp,float *bluep) {
|
||||
float red=luminance,green=luminance,blue=luminance;
|
||||
|
||||
if(saturation!=0){
|
||||
float p,q;
|
||||
|
||||
if(luminance<0.5)
|
||||
q=luminance*(1+saturation);
|
||||
else
|
||||
q=luminance+saturation-(luminance*saturation);
|
||||
p=2*luminance-q;
|
||||
|
||||
red=hue+1.0/3.0;
|
||||
if(red<0)
|
||||
red+=1.0;
|
||||
green=hue;
|
||||
if(green<0)
|
||||
green+=1.0;
|
||||
blue=hue-1.0/3.0;
|
||||
if(blue<0)
|
||||
blue+=1.0;
|
||||
|
||||
red=colorFromTemp(red,q,p);
|
||||
green=colorFromTemp(green,q,p);
|
||||
blue=colorFromTemp(blue,q,p);
|
||||
}
|
||||
|
||||
*redp=red;
|
||||
*greenp=green;
|
||||
*bluep=blue;
|
||||
}
|
||||
|
||||
static inline void RGBToHSL(float r,float g,float b,float *huep,float *saturationp,float *luminancep) {
|
||||
float hue=0,saturation=0,luminance,min,max;
|
||||
|
||||
max=MAX(r,MAX(g,b));
|
||||
min=MIN(r,MIN(g,b));
|
||||
if(max==min)
|
||||
hue=0;
|
||||
else if(max==r && g>=b)
|
||||
hue=60*((g-b)/(max-min));
|
||||
else if(max==r && g<b)
|
||||
hue=60*((g-b)/(max-min))+360;
|
||||
else if(max==g)
|
||||
hue=60*((b-r)/(max-min))+120;
|
||||
else if(max==b)
|
||||
hue=60*((r-g)/(max-min))+240;
|
||||
|
||||
luminance=(max+min)/2.0;
|
||||
if(max==min)
|
||||
saturation=0;
|
||||
else if(luminance<=0.5)
|
||||
saturation=(max-min)/(max+min);
|
||||
else
|
||||
saturation=(max-min)/(2-(max+min));
|
||||
|
||||
if(huep!=NULL)
|
||||
*huep=fmod(hue,360)/360.0;
|
||||
if(saturationp!=NULL)
|
||||
*saturationp=saturation;
|
||||
if(luminancep!=NULL)
|
||||
*luminancep=luminance;
|
||||
}
|
||||
|
||||
static void KGPixelPipeWriteCoverage(KGPixelPipe *self,int x, int y, RIfloat coverage) {
|
||||
RI_ASSERT(self->m_renderingSurface);
|
||||
|
||||
@ -634,42 +710,58 @@ static void KGPixelPipeWriteCoverage(KGPixelPipe *self,int x, int y, RIfloat cov
|
||||
RI_ASSERT(d.b >= 0.0f && d.b <= d.a);
|
||||
switch(self->m_blendMode)
|
||||
{
|
||||
case kCGBlendModeNormal:
|
||||
r.r = s.r + d.r * (1.0f - ar);
|
||||
r.g = s.g + d.g * (1.0f - ag);
|
||||
r.b = s.b + d.b * (1.0f - ab);
|
||||
case kCGBlendModeNormal: // Passes Visual Test
|
||||
r.r = s.r + d.r * (1.0f - s.a);
|
||||
r.g = s.g + d.g * (1.0f - s.a);
|
||||
r.b = s.b + d.b * (1.0f - s.a);
|
||||
r.a = s.a + d.a * (1.0f - s.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModeMultiply:
|
||||
r.r = s.r * (1.0f - d.a + d.r) + d.r * (1.0f - ar);
|
||||
r.g = s.g * (1.0f - d.a + d.g) + d.g * (1.0f - ag);
|
||||
r.b = s.b * (1.0f - d.a + d.b) + d.b * (1.0f - ab);
|
||||
case kCGBlendModeMultiply: // Passes Visual Test
|
||||
r.r = s.r * (1.0f - d.a + d.r) + d.r * (1.0f - s.a);
|
||||
r.g = s.g * (1.0f - d.a + d.g) + d.g * (1.0f - s.a);
|
||||
r.b = s.b * (1.0f - d.a + d.b) + d.b * (1.0f - s.a);
|
||||
r.a = s.a + d.a * (1.0f - s.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModeScreen:
|
||||
r.r = s.r + d.r * (1.0f - s.r);
|
||||
r.g = s.g + d.g * (1.0f - s.g);
|
||||
r.b = s.b + d.b * (1.0f - s.b);
|
||||
case kCGBlendModeScreen: // Passes Visual Test
|
||||
r.r = s.r + d.r - s.r*d.r;
|
||||
r.g = s.g + d.g - s.g*d.g;
|
||||
r.b = s.b + d.b - s.b*d.b;
|
||||
r.a = s.a + d.a * (1.0f - s.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModeOverlay:
|
||||
r.r=(2*d.r<d.a)?(2*s.r*d.r+s.r*(1-d.a)+d.r*(1-s.a)):(s.r*d.r-2*(d.a-d.r)*(s.a-s.r)+s.r*(1-d.a)+d.r*(1-s.a));
|
||||
r.g=(2*d.g<d.a)?(2*s.g*d.g+s.g*(1-d.a)+d.g*(1-s.a)):(s.g*d.g-2*(d.a-d.g)*(s.a-s.g)+s.g*(1-d.a)+d.g*(1-s.a));
|
||||
r.b=(2*d.b<d.a)?(2*s.b*d.b+s.b*(1-d.a)+d.b*(1-s.a)):(s.b*d.b-2*(d.a-d.b)*(s.a-s.b)+s.b*(1-d.a)+d.b*(1-s.a));
|
||||
r.a=(2*d.a<d.a)?(2*s.a*d.a+s.a*(1-d.a)+d.a*(1-s.a)):(s.a*d.a-2*(d.a-d.a)*(s.a-s.a)+s.a*(1-d.a)+d.a*(1-s.a));
|
||||
break;
|
||||
case kCGBlendModeOverlay:// broken
|
||||
{
|
||||
RIfloat max=RI_MAX(s.r,RI_MAX(s.g,s.b));
|
||||
RIfloat min=RI_MIN(s.r,RI_MIN(s.g,s.b));
|
||||
RIfloat lum=(max+min)/2*(1.0-d.a);
|
||||
if(lum<=0.5)
|
||||
r.r = s.r * (1.0f - d.a + d.r) + d.r * (1.0f - s.a);
|
||||
else
|
||||
r.r = s.r + d.r - s.r*d.r;
|
||||
|
||||
if(lum<=0.5)
|
||||
r.g = s.g * (1.0f - d.a + d.g) + d.g * (1.0f - s.a);
|
||||
else
|
||||
r.g = s.g + d.g - s.g*d.g;
|
||||
|
||||
case kCGBlendModeDarken:
|
||||
if(lum<=0.5)
|
||||
r.b = s.b * (1.0f - d.a + d.b) + d.b * (1.0f - s.a);
|
||||
else
|
||||
r.b = s.b + d.b - s.b*d.b;
|
||||
|
||||
r.a = s.a + d.a * (1.0f - s.a);
|
||||
}break;
|
||||
|
||||
case kCGBlendModeDarken: // Passes Visual Test
|
||||
r.r = RI_MIN(s.r + d.r * (1.0f - ar), d.r + s.r * (1.0f - d.a));
|
||||
r.g = RI_MIN(s.g + d.g * (1.0f - ag), d.g + s.g * (1.0f - d.a));
|
||||
r.b = RI_MIN(s.b + d.b * (1.0f - ab), d.b + s.b * (1.0f - d.a));
|
||||
r.a = s.a + d.a * (1.0f - s.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModeLighten:
|
||||
case kCGBlendModeLighten: // Passes Visual Test
|
||||
r.r = RI_MAX(s.r + d.r * (1.0f - ar), d.r + s.r * (1.0f - d.a));
|
||||
r.g = RI_MAX(s.g + d.g * (1.0f - ag), d.g + s.g * (1.0f - d.a));
|
||||
r.b = RI_MAX(s.b + d.b * (1.0f - ab), d.b + s.b * (1.0f - d.a));
|
||||
@ -684,7 +776,7 @@ static void KGPixelPipeWriteCoverage(KGPixelPipe *self,int x, int y, RIfloat cov
|
||||
r.r=(s.r==1)?1:RI_MIN(1,d.r/(1.0-s.r));
|
||||
r.g=(s.g==1)?1:RI_MIN(1,d.g/(1.0-s.g));
|
||||
r.b=(s.b==1)?1:RI_MIN(1,d.b/(1.0-s.b));
|
||||
r.a=(s.a==1)?1:RI_MIN(1,d.a/(1.0-s.a));
|
||||
r.a = s.a + d.a * (1.0f - s.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModeColorBurn:
|
||||
@ -700,24 +792,40 @@ static void KGPixelPipeWriteCoverage(KGPixelPipe *self,int x, int y, RIfloat cov
|
||||
case kCGBlendModeSoftLight:
|
||||
break;
|
||||
|
||||
case kCGBlendModeDifference:
|
||||
r.r=RI_ABS(d.r-s.r);
|
||||
r.g=RI_ABS(d.g-s.g);
|
||||
r.b=RI_ABS(d.b-s.b);
|
||||
r.a=RI_ABS(d.a-s.a);
|
||||
case kCGBlendModeDifference: // Passes Visual Test
|
||||
r.r=s.r+d.r-2*(RI_MIN(s.r*d.a,d.r*s.a));
|
||||
r.g=s.g+d.g-2*(RI_MIN(s.g*d.a,d.g*s.a));
|
||||
r.b=s.b+d.b-2*(RI_MIN(s.b*d.a,d.b*s.a));
|
||||
r.a = s.a + d.a * (1.0f - s.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModeExclusion:
|
||||
r.r=d.r+s.r-2.0*d.r*s.r;
|
||||
r.g=d.g+s.g-2.0*d.g*s.g;
|
||||
r.b=d.b+s.b-2.0*d.b*s.b;
|
||||
r.a=d.a+s.a-2.0*d.a*s.a;
|
||||
r.r = (s.r * d.a + d.r * s.a - 2 * s.r * d.r) + s.r * (1 - d.a) + d.r * (1 - s.a);
|
||||
r.g = (s.g * d.a + d.g * s.a - 2 * s.g * d.r) + s.g * (1 - d.a) + d.g * (1 - s.a);
|
||||
r.b = (s.b * d.a + d.b * s.a - 2 * s.b * d.r) + s.b * (1 - d.a) + d.b * (1 - s.a);
|
||||
r.a = s.a + d.a * (1.0f - s.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModeHue:
|
||||
break;
|
||||
case kCGBlendModeHue:{
|
||||
RIfloat sh,ss,sl;
|
||||
RIfloat dh,ds,dl;
|
||||
|
||||
case kCGBlendModeSaturation:
|
||||
RGBToHSL(s.r,s.g,s.b,&sh,&ss,&sl);
|
||||
RGBToHSL(d.r,d.g,d.b,&dh,&ds,&dl);
|
||||
HSLToRGB(sh,ds,dl,&r.r,&r.g,&r.b);
|
||||
r.a = s.a + d.a * (1.0f - s.a);
|
||||
}
|
||||
break;
|
||||
|
||||
case kCGBlendModeSaturation:{
|
||||
RIfloat sh,ss,sl;
|
||||
RIfloat dh,ds,dl;
|
||||
|
||||
RGBToHSL(s.r,s.g,s.b,&sh,&ss,&sl);
|
||||
RGBToHSL(d.r,d.g,d.b,&dh,&ds,&dl);
|
||||
HSLToRGB(dh,ss,dl,&r.r,&r.g,&r.b);
|
||||
r.a = s.a + d.a * (1.0f - s.a);
|
||||
}
|
||||
break;
|
||||
|
||||
case kCGBlendModeColor:
|
||||
@ -726,86 +834,92 @@ static void KGPixelPipeWriteCoverage(KGPixelPipe *self,int x, int y, RIfloat cov
|
||||
case kCGBlendModeLuminosity:
|
||||
break;
|
||||
|
||||
case kCGBlendModeClear:
|
||||
case kCGBlendModeClear: // Passes Visual Test, duh
|
||||
r.r=0;
|
||||
r.g=0;
|
||||
r.b=0;
|
||||
r.a=0;
|
||||
break;
|
||||
|
||||
case kCGBlendModeCopy:
|
||||
case kCGBlendModeCopy: // Passes Visual Test
|
||||
r = s;
|
||||
break;
|
||||
|
||||
case kCGBlendModeSourceIn:
|
||||
case kCGBlendModeSourceIn: // Passes Visual Test
|
||||
r.r = s.r * d.a;
|
||||
r.g = s.g * d.a;
|
||||
r.b = s.b * d.a;
|
||||
r.a = s.a * d.a;
|
||||
break;
|
||||
|
||||
case kCGBlendModeSourceOut:
|
||||
case kCGBlendModeSourceOut: // Passes Visual Test
|
||||
r.r = s.r *(1.0- d.a);
|
||||
r.g = s.g * (1.0- d.a);
|
||||
r.b = s.b * (1.0- d.a);
|
||||
r.a = s.a * (1.0- d.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModeSourceAtop:
|
||||
r.r = s.r*d.a+d.r*(1.0-ar);
|
||||
r.g = s.g*d.a+d.g*(1.0-ag);
|
||||
r.b = s.b*d.a+d.b*(1.0-ab);
|
||||
case kCGBlendModeSourceAtop: // Passes Visual Test
|
||||
r.r = s.r*d.a+d.r*(1.0-s.a);
|
||||
r.g = s.g*d.a+d.g*(1.0-s.a);
|
||||
r.b = s.b*d.a+d.b*(1.0-s.a);
|
||||
r.a = s.a*d.a+d.a*(1.0-s.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModeDestinationOver:
|
||||
case kCGBlendModeDestinationOver: // Passes Visual Test
|
||||
r.r = s.r * (1.0f - d.a) + d.r;
|
||||
r.g = s.g * (1.0f - d.a) + d.g;
|
||||
r.b = s.b * (1.0f - d.a) + d.b;
|
||||
r.a = s.a * (1.0f - d.a) + d.a;
|
||||
break;
|
||||
|
||||
case kCGBlendModeDestinationIn:
|
||||
r.r = d.r * ar;
|
||||
r.g = d.g * ag;
|
||||
r.b = d.b * ab;
|
||||
case kCGBlendModeDestinationIn: // Passes Visual Test
|
||||
r.r = d.r * s.a;
|
||||
r.g = d.g * s.a;
|
||||
r.b = d.b * s.a;
|
||||
r.a = d.a * s.a;
|
||||
break;
|
||||
|
||||
|
||||
case kCGBlendModeDestinationOut:
|
||||
r.r = d.r *(1.0- ar);
|
||||
r.g = d.g * (1.0- ag);
|
||||
r.b = d.b * (1.0- ab);
|
||||
case kCGBlendModeDestinationOut: // Passes Visual Test
|
||||
r.r = d.r *(1.0- s.a);
|
||||
r.g = d.g * (1.0- s.a);
|
||||
r.b = d.b * (1.0- s.a);
|
||||
r.a = d.a * (1.0- s.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModeDestinationAtop:
|
||||
r.r=ar*(1.0-d.a)+d.r*s.a;
|
||||
r.g=ag*(1.0-d.a)+d.g*s.a;
|
||||
r.b=ab*(1.0-d.a)+d.b*s.a;
|
||||
case kCGBlendModeDestinationAtop: // Passes Visual Test
|
||||
r.r=s.r*(1.0-d.a)+d.r*s.a;
|
||||
r.g=s.g*(1.0-d.a)+d.g*s.a;
|
||||
r.b=s.b*(1.0-d.a)+d.b*s.a;
|
||||
r.a=s.a*(1.0-d.a)+d.a*s.a;
|
||||
break;
|
||||
|
||||
case kCGBlendModeXOR:
|
||||
r.r=ar*(1.0-d.a)+d.r*(1.0-s.a);
|
||||
r.g=ag*(1.0-d.a)+d.g*(1.0-s.a);
|
||||
r.b=ab*(1.0-d.a)+d.b*(1.0-s.a);
|
||||
case kCGBlendModeXOR: // Passes Visual Test
|
||||
r.r=s.r*(1.0-d.a)+d.r*(1.0-s.a);
|
||||
r.g=s.g*(1.0-d.a)+d.g*(1.0-s.a);
|
||||
r.b=s.b*(1.0-d.a)+d.b*(1.0-s.a);
|
||||
r.a=s.a*(1.0-d.a)+d.a*(1.0-s.a);
|
||||
break;
|
||||
|
||||
case kCGBlendModePlusDarker:
|
||||
r.r=RI_MAX(0,(1.0-d.r)+(1-s.r));
|
||||
r.g=RI_MAX(0,(1.0-d.g)+(1-s.g));
|
||||
r.b=RI_MAX(0,(1.0-d.b)+(1-s.b));
|
||||
r.a=RI_MAX(0,(1.0-d.a)+(1-s.a));
|
||||
r.r=RI_MIN(1,r.r);
|
||||
r.g=RI_MIN(1,r.g);
|
||||
r.b=RI_MIN(1,r.b);
|
||||
r.a=RI_MIN(1,r.a);
|
||||
#if 0
|
||||
// Doc.s say: R = MAX(0, (1 - D) + (1 - S)). No workie, no make sense.
|
||||
r.r=RI_MAX(0,(1-d.r)+(1-s.r));
|
||||
r.g=RI_MAX(0,(1-d.g)+(1-s.g));
|
||||
r.b=RI_MAX(0,(1-d.b)+(1-s.b));
|
||||
r.a=RI_MAX(0,(1-d.a)+(1-s.a));
|
||||
#else
|
||||
r.r=RI_MIN(1.0,(1-d.r)+(1-s.r));
|
||||
r.g=RI_MIN(1.0,(1-d.g)+(1-s.g));
|
||||
r.b=RI_MIN(1.0,(1-d.b)+(1-s.b));
|
||||
r.a = s.a ;
|
||||
// r.a=RI_MIN(1.0,(1-d.a)+(1-s.a));
|
||||
#endif
|
||||
break;
|
||||
|
||||
case kCGBlendModePlusLighter:
|
||||
// Doc.s say: R = MIN(1, S + D). That works
|
||||
case kCGBlendModePlusLighter: // Passes Visual Test
|
||||
r.r = RI_MIN(s.r + d.r, 1.0f);
|
||||
r.g = RI_MIN(s.g + d.g, 1.0f);
|
||||
r.b = RI_MIN(s.b + d.b, 1.0f);
|
||||
|
@ -50,12 +50,12 @@ typedef struct {
|
||||
RIfloat cnst;
|
||||
int minscany;
|
||||
int maxscany;
|
||||
Vector2 vd;
|
||||
RIfloat wl;
|
||||
RIfloat bminx;
|
||||
RIfloat bmaxx;
|
||||
RIfloat vdxwl;
|
||||
RIfloat sxPre;
|
||||
RIfloat exPre;
|
||||
// These are modified per scanline
|
||||
RIfloat minx; //for the current scanline
|
||||
int minx; //for the current scanline
|
||||
int ceilMinX;
|
||||
int maxx; //for the current scanline
|
||||
} Edge;
|
||||
|
||||
@ -65,18 +65,14 @@ typedef struct {
|
||||
RIfloat weight;
|
||||
} Sample;
|
||||
|
||||
typedef struct {
|
||||
int edgeCount;
|
||||
int edgeCapacity;
|
||||
Edge **edges;
|
||||
} Scanline;
|
||||
|
||||
typedef struct {
|
||||
int _vpx,_vpy,_vpwidth,_vpheight;
|
||||
|
||||
int _edgeCount;
|
||||
int _edgeCapacity;
|
||||
Edge *_edges;
|
||||
int _edgeCount;
|
||||
int _edgeCapacity;
|
||||
Edge *_edgePool;
|
||||
Edge **_edges;
|
||||
|
||||
Sample samples[32];
|
||||
int numSamples;
|
||||
|
@ -43,12 +43,12 @@ KGRasterizer *KGRasterizerInit(KGRasterizer *self) {
|
||||
|
||||
self->_edgeCount=0;
|
||||
self->_edgeCapacity=256;
|
||||
self->_edges=(Edge *)NSZoneMalloc(NULL,self->_edgeCapacity*sizeof(Edge));
|
||||
self->_edgePool=NSZoneMalloc(NULL,self->_edgeCapacity*sizeof(Edge));
|
||||
return self;
|
||||
}
|
||||
|
||||
void KGRasterizerDealloc(KGRasterizer *self) {
|
||||
NSZoneFree(NULL,self->_edges);
|
||||
NSZoneFree(NULL,self->_edgePool);
|
||||
NSZoneFree(NULL,self);
|
||||
}
|
||||
|
||||
@ -90,21 +90,16 @@ void KGRasterizerAddEdge(KGRasterizer *self,const Vector2 v0, const Vector2 v1)
|
||||
|
||||
if(v0.y>=MaxY && v1.y>=MaxY)
|
||||
return;
|
||||
|
||||
int MaxX=self->_vpx+self->_vpwidth;
|
||||
|
||||
if(v0.x>=MaxX && v1.x>=MaxX)
|
||||
return;
|
||||
|
||||
|
||||
if( self->_edgeCount >= RI_MAX_EDGES )
|
||||
NSLog(@"too many edges");
|
||||
|
||||
Edge *edge;
|
||||
if(self->_edgeCount+1>=self->_edgeCapacity){
|
||||
self->_edgeCapacity*=2;
|
||||
self->_edges=(Edge *)NSZoneRealloc(NULL,self->_edges,self->_edgeCapacity*sizeof(Edge));
|
||||
self->_edgePool=NSZoneRealloc(NULL,self->_edgePool,self->_edgeCapacity*sizeof(Edge));
|
||||
}
|
||||
edge=self->_edges+self->_edgeCount;
|
||||
edge=self->_edgePool+self->_edgeCount;
|
||||
self->_edgeCount++;
|
||||
|
||||
if(v0.y < v1.y)
|
||||
@ -123,10 +118,11 @@ void KGRasterizerAddEdge(KGRasterizer *self,const Vector2 v0, const Vector2 v1)
|
||||
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->vd = Vector2Subtract(edge->v1,edge->v0);
|
||||
edge->wl = 1.0f /edge->vd.y;
|
||||
edge->bminx = RI_MIN(edge->v0.x, edge->v1.x);
|
||||
edge->bmaxx = RI_MAX(edge->v0.x, edge->v1.x);
|
||||
Vector2 vd = Vector2Subtract(edge->v1,edge->v0);
|
||||
RIfloat wl = 1.0f /vd.y;
|
||||
edge->vdxwl=vd.x*wl;
|
||||
edge->sxPre = edge->v0.x - vd.x *edge->v0.y* wl;
|
||||
edge->exPre = edge->v0.x - vd.x *edge->v0.y* wl;
|
||||
edge->minx=edge->maxx=0;
|
||||
|
||||
}
|
||||
@ -170,10 +166,30 @@ void KGRasterizerSetShouldAntialias(KGRasterizer *self,BOOL antialias) {
|
||||
self->fradius = 0.0f;
|
||||
self->sumWeights = 1.0f;
|
||||
}
|
||||
else {
|
||||
// The Quartz AA filter is different than this
|
||||
// There doesn't seem to be much noticeable difference between 8 and 16 samples using this
|
||||
|
||||
else {
|
||||
#if 1
|
||||
//box filter of diameter 1.0f, 8-queen sampling pattern
|
||||
self->numSamples = 8;
|
||||
self->samples[0].x = 3;
|
||||
self->samples[1].x = 7;
|
||||
self->samples[2].x = 0;
|
||||
self->samples[3].x = 2;
|
||||
self->samples[4].x = 5;
|
||||
self->samples[5].x = 1;
|
||||
self->samples[6].x = 6;
|
||||
self->samples[7].x = 4;
|
||||
int i;
|
||||
for(i=0;i<self->numSamples;i++)
|
||||
{
|
||||
self->samples[i].x = (self->samples[i].x + 0.5f) / (RIfloat)self->numSamples - 0.5f;
|
||||
self->samples[i].y = ((RIfloat)i + 0.5f) / (RIfloat)self->numSamples - 0.5f;
|
||||
self->samples[i].weight = 1.0f / (RIfloat)self->numSamples;
|
||||
self->sumWeights += self->samples[i].weight;
|
||||
}
|
||||
self->fradius = 0.5f;
|
||||
#else
|
||||
// The Quartz AA filter is different than this, 16 is better than 8 but more expensive
|
||||
// FIX, 8 actually generates some bad rendering
|
||||
self->numSamples = 8;
|
||||
self->fradius = .75;
|
||||
int i;
|
||||
@ -198,6 +214,7 @@ void KGRasterizerSetShouldAntialias(KGRasterizer *self,BOOL antialias) {
|
||||
|
||||
self->sumWeights += self->samples[i].weight;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@ -210,46 +227,93 @@ void KGRasterizerSetShouldAntialias(KGRasterizer *self,BOOL antialias) {
|
||||
* \note
|
||||
*//*-------------------------------------------------------------------*/
|
||||
|
||||
static inline void scanlineSort(Edge **edges,int start,int end){
|
||||
if (start < end) {
|
||||
Edge *pivot=edges[end];
|
||||
int i = start;
|
||||
int j = end;
|
||||
while (i != j) {
|
||||
if (edges[i]->minx < pivot->minx) {
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
edges[j] = edges[i];
|
||||
edges[i] = edges[j-1];
|
||||
j--;
|
||||
}
|
||||
}
|
||||
edges[j] = pivot;
|
||||
scanlineSort(edges, start, j-1);
|
||||
scanlineSort(edges, j+1, end);
|
||||
}
|
||||
static void scanlineSort(Edge **edges,int count,Edge **B){
|
||||
int h, i, j, k, l, m, n = count;
|
||||
Edge *A;
|
||||
|
||||
for (h = 1; h < n; h += h)
|
||||
{
|
||||
for (m = n - 1 - h; m >= 0; m -= h + h)
|
||||
{
|
||||
l = m - h + 1;
|
||||
if (l < 0)
|
||||
l = 0;
|
||||
|
||||
for (i = 0, j = l; j <= m; i++, j++)
|
||||
B[i] = edges[j];
|
||||
|
||||
for (i = 0, k = l; k < j && j <= m + h; k++)
|
||||
{
|
||||
A = edges[j];
|
||||
if (A->minx>B[i]->minx)
|
||||
edges[k] = B[i++];
|
||||
else
|
||||
{
|
||||
edges[k] = A;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
while (k < j)
|
||||
edges[k++] = B[i++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sortEdgesByMinY(Edge *edges,int start,int end){
|
||||
if (start < end) {
|
||||
Edge pivot=edges[end];
|
||||
int i = start;
|
||||
int j = end;
|
||||
while (i != j) {
|
||||
if (edges[i].minscany < pivot.minscany) {
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
edges[j] = edges[i];
|
||||
edges[i] = edges[j-1];
|
||||
j--;
|
||||
}
|
||||
}
|
||||
edges[j] = pivot;
|
||||
sortEdgesByMinY(edges, start, j-1);
|
||||
sortEdgesByMinY(edges, j+1, end);
|
||||
}
|
||||
static void sortEdgesByMinY(Edge **edges,int count,Edge **B){
|
||||
int h, i, j, k, l, m, n = count;
|
||||
Edge *A;
|
||||
|
||||
for (h = 1; h < n; h += h)
|
||||
{
|
||||
for (m = n - 1 - h; m >= 0; m -= h + h)
|
||||
{
|
||||
l = m - h + 1;
|
||||
if (l < 0)
|
||||
l = 0;
|
||||
|
||||
for (i = 0, j = l; j <= m; i++, j++)
|
||||
B[i] = edges[j];
|
||||
|
||||
for (i = 0, k = l; k < j && j <= m + h; k++)
|
||||
{
|
||||
A = edges[j];
|
||||
if (A->minscany>B[i]->minscany)
|
||||
edges[k] = B[i++];
|
||||
else
|
||||
{
|
||||
edges[k] = A;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
while (k < j)
|
||||
edges[k++] = B[i++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void initEdgeForAET(Edge *edge,RIfloat cminy,RIfloat cmaxy,RIfloat fradius,int xlimit){
|
||||
//compute edge min and max x-coordinates for this scanline
|
||||
RIfloat bminx = RI_MIN(edge->v0.x, edge->v1.x);
|
||||
RIfloat bmaxx = RI_MAX(edge->v0.x, edge->v1.x);
|
||||
RIfloat sx = edge->sxPre+ edge->vdxwl*cminy;
|
||||
RIfloat ex = edge->exPre+ edge->vdxwl*cmaxy;
|
||||
sx = RI_CLAMP(sx, bminx, bmaxx);
|
||||
ex = RI_CLAMP(ex, bminx, bmaxx);
|
||||
RIfloat minx= RI_MIN(sx,ex)-fradius-0.5f;
|
||||
|
||||
edge->minx = minx;
|
||||
// FIX, we may not need this field
|
||||
edge->ceilMinX=RI_INT_MIN(xlimit,ceil(minx));
|
||||
//0.01 is a safety region to prevent too aggressive optimization due to numerical inaccuracy
|
||||
edge->maxx = RI_MAX(sx,ex)+fradius+0.5f+0.01f;
|
||||
}
|
||||
|
||||
static void incrementEdgeForAET(Edge *edge,RIfloat cminy,RIfloat cmaxy,RIfloat fradius,int xlimit){
|
||||
initEdgeForAET(edge,cminy,cmaxy,fradius,xlimit);
|
||||
// edge->minx += edge->vdxwl;
|
||||
// edge->maxx += edge->vdxwl;
|
||||
}
|
||||
|
||||
void KGRasterizerFill(KGRasterizer *self,VGFillRule fillRule, KGPixelPipe *pixelPipe)
|
||||
@ -269,42 +333,54 @@ void KGRasterizerFill(KGRasterizer *self,VGFillRule fillRule, KGPixelPipe *pixel
|
||||
int fillRuleMask = (fillRule == VG_NON_ZERO)?-1:1;
|
||||
|
||||
int miny=self->_vpy;
|
||||
int maxy=self->_vpy+self->_vpheight;
|
||||
|
||||
int ylimit=self->_vpy+self->_vpheight;
|
||||
int xlimit=self->_vpx+self->_vpwidth;
|
||||
|
||||
int edgeCount=self->_edgeCount;
|
||||
Edge **edges=NSZoneMalloc(NULL,edgeCount*sizeof(Edge *));
|
||||
Edge **sortTmp=NSZoneMalloc(NULL,(edgeCount/2 + 1) * sizeof(Edge *));
|
||||
|
||||
int i;
|
||||
int nextAvailableEdge=0;
|
||||
|
||||
sortEdgesByMinY(self->_edges,0,self->_edgeCount-1);
|
||||
for(i=0;i<edgeCount;i++)
|
||||
edges[i]=self->_edgePool+i;
|
||||
|
||||
sortEdgesByMinY(edges,edgeCount,sortTmp);
|
||||
|
||||
for(nextAvailableEdge=0;nextAvailableEdge<self->_edgeCount;nextAvailableEdge++){
|
||||
Edge *check=self->_edges+nextAvailableEdge;
|
||||
for(nextAvailableEdge=0;nextAvailableEdge<edgeCount;nextAvailableEdge++){
|
||||
Edge *check=edges[nextAvailableEdge];
|
||||
|
||||
if(check->maxscany>=self->_vpy)
|
||||
break;
|
||||
}
|
||||
|
||||
int scany;
|
||||
int activeCount=0;
|
||||
int activeCapacity=1024;
|
||||
Edge **activeEdges=NSZoneMalloc(NULL,activeCapacity*sizeof(Edge *));
|
||||
int scany;
|
||||
int activeCount=0;
|
||||
int activeCapacity=1024;
|
||||
Edge **activeEdges=NSZoneMalloc(NULL,activeCapacity*sizeof(Edge *));
|
||||
RIfloat cminy = (RIfloat)miny - self->fradius + 0.5f;
|
||||
RIfloat cmaxy = (RIfloat)miny + self->fradius + 0.5f;
|
||||
|
||||
for(scany=miny;scany<maxy;scany++){
|
||||
for(scany=miny;scany<ylimit;scany++,cminy+=1.0,cmaxy+=1.0){
|
||||
|
||||
int i;
|
||||
int removeNulls=0;
|
||||
|
||||
// remove edges out of range, load empty slot with an available edge
|
||||
for(i=0;i<activeCount;i++){
|
||||
Edge *check=activeEdges[i];
|
||||
|
||||
if(check->maxscany<scany){
|
||||
if(check->maxscany>=scany)
|
||||
incrementEdgeForAET(check,cminy,cmaxy,self->fradius,xlimit);
|
||||
else {
|
||||
activeEdges[i]=NULL;
|
||||
removeNulls++;
|
||||
|
||||
if(nextAvailableEdge<self->_edgeCount){
|
||||
Edge *check=self->_edges+nextAvailableEdge;
|
||||
if(nextAvailableEdge<edgeCount){
|
||||
Edge *check=edges[nextAvailableEdge];
|
||||
|
||||
if(check->minscany<=scany){
|
||||
initEdgeForAET(check,cminy,cmaxy,self->fradius,xlimit);
|
||||
activeEdges[i]=check;
|
||||
nextAvailableEdge++;
|
||||
removeNulls--;
|
||||
@ -329,8 +405,8 @@ void KGRasterizerFill(KGRasterizer *self,VGFillRule fillRule, KGPixelPipe *pixel
|
||||
}
|
||||
else {
|
||||
// load more available edges
|
||||
for(;nextAvailableEdge<self->_edgeCount;nextAvailableEdge++){
|
||||
Edge *check=self->_edges+nextAvailableEdge;
|
||||
for(;nextAvailableEdge<edgeCount;nextAvailableEdge++){
|
||||
Edge *check=edges[nextAvailableEdge];
|
||||
|
||||
if(check->minscany>scany)
|
||||
break;
|
||||
@ -339,6 +415,7 @@ void KGRasterizerFill(KGRasterizer *self,VGFillRule fillRule, KGPixelPipe *pixel
|
||||
activeCapacity*=2;
|
||||
activeEdges=NSZoneRealloc(NULL,activeEdges,activeCapacity*sizeof(Edge *));
|
||||
}
|
||||
initEdgeForAET(check,cminy,cmaxy,self->fradius,xlimit);
|
||||
activeEdges[activeCount++]=check;
|
||||
}
|
||||
}
|
||||
@ -346,39 +423,21 @@ void KGRasterizerFill(KGRasterizer *self,VGFillRule fillRule, KGPixelPipe *pixel
|
||||
if(activeCount==0)
|
||||
continue;
|
||||
|
||||
RIfloat cminy = (RIfloat)scany - self->fradius + 0.5f;
|
||||
RIfloat cmaxy = (RIfloat)scany + self->fradius + 0.5f;
|
||||
|
||||
int e;
|
||||
|
||||
for(e=0;e<activeCount;e++) {
|
||||
Edge *edge = activeEdges[e];
|
||||
|
||||
//compute edge min and max x-coordinates for this scanline
|
||||
RIfloat sx = edge->v0.x - edge->vd.x *edge->v0.y* edge->wl+ edge->vd.x *cminy* edge->wl;
|
||||
RIfloat ex = edge->v0.x - edge->vd.x *edge->v0.y* edge->wl+ edge->vd.x *cmaxy* edge->wl;
|
||||
sx = RI_CLAMP(sx, edge->bminx, edge->bmaxx);
|
||||
ex = RI_CLAMP(ex, edge->bminx, edge->bmaxx);
|
||||
edge->minx = RI_MIN(sx,ex)-self->fradius-0.5f;
|
||||
|
||||
//0.01 is a safety region to prevent too aggressive optimization due to numerical inaccuracy
|
||||
edge->maxx = RI_MAX(sx,ex)+0.01f+self->fradius-0.5f;
|
||||
}
|
||||
scanlineSort(activeEdges,0,activeCount-1);
|
||||
scanlineSort(activeEdges,activeCount,sortTmp);
|
||||
|
||||
int s;
|
||||
|
||||
float sidePre[activeCount][self->numSamples];
|
||||
RIfloat pcy=scany+0.5f; // pixel center
|
||||
for(e=0;e<activeCount;e++){
|
||||
Edge *edge = activeEdges[e];
|
||||
for(i=0;i<activeCount;i++){
|
||||
Edge *edge = activeEdges[i];
|
||||
|
||||
for(s=0;s<self->numSamples;s++){
|
||||
RIfloat spy = pcy+self->samples[s].y;
|
||||
if(spy >= edge->v0.y && spy < edge->v1.y)
|
||||
sidePre[e][s] = (spy*edge->normal.y - edge->cnst + self->samples[s].x*edge->normal.x);
|
||||
sidePre[i][s] = -(spy*edge->normal.y - edge->cnst + self->samples[s].x*edge->normal.x)-0.5f*edge->normal.x;
|
||||
else
|
||||
sidePre[e][s]=LONG_MAX; // arbitrary large number
|
||||
sidePre[i][s]=-LONG_MAX; // arbitrary large number
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,55 +445,60 @@ void KGRasterizerFill(KGRasterizer *self,VGFillRule fillRule, KGPixelPipe *pixel
|
||||
int scanx;
|
||||
int winding[self->numSamples];
|
||||
int nextEdge=0;
|
||||
int lastWinding=0;
|
||||
int lastBestWinding=0;
|
||||
int rightOfLastEdge=NO;
|
||||
|
||||
for(scanx=RI_INT_MAX(self->_vpx,activeEdges[0]->minx);scanx<xlimit;){
|
||||
|
||||
for(s=self->numSamples;--s>=0;)
|
||||
winding[s]=lastWinding;
|
||||
|
||||
int endSpan = xlimit;
|
||||
for(scanx=RI_INT_MAX(self->_vpx,activeEdges[0]->minx);nextEdge<activeCount && scanx<xlimit;){
|
||||
|
||||
for(e=nextEdge;e<activeCount;e++){
|
||||
Edge *edge=activeEdges[e];
|
||||
|
||||
if(scanx<=edge->maxx){
|
||||
endSpan = RI_INT_MAX(scanx+1,RI_INT_MIN(xlimit,(int)ceil(edge->minx)));
|
||||
break;
|
||||
}
|
||||
if(!rightOfLastEdge){
|
||||
for(s=self->numSamples;--s>=0;)
|
||||
winding[s]=lastBestWinding;
|
||||
|
||||
rightOfLastEdge=YES;
|
||||
}
|
||||
|
||||
BOOL rightOf=YES;
|
||||
|
||||
for(e=nextEdge;e<activeCount;e++){
|
||||
Edge *edge=activeEdges[e];
|
||||
for(i=nextEdge;i<activeCount;i++){
|
||||
Edge *edge=activeEdges[i];
|
||||
RIfloat minx=edge->minx;
|
||||
|
||||
if(scanx<minx)
|
||||
break;
|
||||
else{
|
||||
else {
|
||||
int direction=edge->direction;
|
||||
RIfloat pcxnormal=-((scanx+0.5f)*edge->normal.x);
|
||||
RIfloat *pre=sidePre[e];
|
||||
|
||||
RIfloat *pre=sidePre[i];
|
||||
RIfloat pcxnormal=scanx*edge->normal.x;
|
||||
|
||||
s=self->numSamples;
|
||||
while(--s>=0){
|
||||
BOOL check= (pcxnormal > pre[s]);
|
||||
|
||||
if(check)
|
||||
if(pcxnormal > pre[s])
|
||||
rightOfLastEdge=NO;
|
||||
else {
|
||||
winding[s] += direction;
|
||||
rightOf=rightOf&✓
|
||||
rightOfLastEdge&=YES;
|
||||
}
|
||||
}
|
||||
|
||||
if(rightOf){
|
||||
nextEdge=e+1;
|
||||
lastWinding=winding[0];
|
||||
if(rightOfLastEdge){
|
||||
rightOfLastEdge=YES;
|
||||
nextEdge=i+1;
|
||||
lastBestWinding=winding[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int nextx = xlimit;
|
||||
|
||||
for(i=nextEdge;i<activeCount;i++){
|
||||
Edge *edge=activeEdges[i];
|
||||
|
||||
if(scanx<=edge->maxx){
|
||||
nextx=RI_INT_MAX(scanx+1,edge->ceilMinX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RIfloat coverage = 0.0f;
|
||||
s=self->numSamples;
|
||||
@ -445,14 +509,15 @@ void KGRasterizerFill(KGRasterizer *self,VGFillRule fillRule, KGPixelPipe *pixel
|
||||
if(coverage > 0.0f){
|
||||
coverage /= self->sumWeights;
|
||||
|
||||
KGPixelPipeWriteCoverageSpan(pixelPipe,scanx,scany,(endSpan-scanx),coverage);
|
||||
KGPixelPipeWriteCoverageSpan(pixelPipe,scanx,scany,(nextx-scanx),coverage);
|
||||
}
|
||||
|
||||
scanx = endSpan;
|
||||
|
||||
scanx = nextx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NSZoneFree(NULL,activeEdges);
|
||||
NSZoneFree(NULL,edges);
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
|
||||
|
||||
-init {
|
||||
_pixelsWide=386;
|
||||
_pixelsHigh=386;
|
||||
_pixelsWide=400;
|
||||
_pixelsHigh=400;
|
||||
_bitsPerComponent=8;
|
||||
_bitsPerPixel=32;
|
||||
_bytesPerRow=(_pixelsWide*_bitsPerPixel)/8;
|
||||
@ -32,17 +32,18 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
}
|
||||
|
||||
-(CGImageRef)imageRefOfDifferences:(KGRender *)other {
|
||||
unsigned char *diff=NSZoneMalloc([self zone],_bytesPerRow*_pixelsHigh);
|
||||
char *diff=NSZoneMalloc([self zone],_bytesPerRow*_pixelsHigh);
|
||||
int i;
|
||||
for(i=0;i<_bytesPerRow*_pixelsHigh;i++){
|
||||
int d1=((unsigned char *)_data)[i];
|
||||
int d2=((unsigned char *)other->_data)[i];
|
||||
diff[i]=ABS(d2-d1);
|
||||
unsigned char d1=((unsigned char *)_data)[i];
|
||||
unsigned char d2=((unsigned char *)other->_data)[i];
|
||||
|
||||
diff[i]=d1^d2;
|
||||
}
|
||||
|
||||
CGDataProviderRef provider=CGDataProviderCreateWithData(NULL,diff,_pixelsWide*_pixelsHigh*4,NULL);
|
||||
return CGImageCreate(_pixelsWide,_pixelsHigh,_bitsPerComponent,_bitsPerPixel,_bytesPerRow,_colorSpace,
|
||||
kCGImageAlphaPremultipliedLast|kCGBitmapByteOrder32Little,provider,NULL,NO,kCGRenderingIntentDefault);
|
||||
kCGBitmapByteOrder32Little,provider,NULL,NO,kCGRenderingIntentDefault);
|
||||
}
|
||||
|
||||
-(void)setSize:(NSSize)size {
|
||||
|
@ -46,7 +46,7 @@ static CGColorRef cgColorFromColor(NSColor *color){
|
||||
|
||||
|
||||
-(CGAffineTransform)ctm {
|
||||
CGAffineTransform ctm=CGAffineTransformMakeTranslation(386/2,386/2);
|
||||
CGAffineTransform ctm=CGAffineTransformMakeTranslation(400/2,400/2);
|
||||
|
||||
ctm=CGAffineTransformScale(ctm, gState->_scalex,gState->_scaley);
|
||||
|
||||
@ -119,18 +119,18 @@ static void addSliceToPath(CGMutablePathRef path,float innerRadius,float outerRa
|
||||
CGColorRef blackColor=CGColorCreate(CGColorSpaceCreateDeviceRGB(),blackComponents);
|
||||
CGColorRef redColor=cgColorFromColor(_destinationColor);
|
||||
CGAffineTransform ctm=[self ctm];
|
||||
int i,width=386,height=386;
|
||||
int i,width=400,height=400;
|
||||
[render clear];
|
||||
|
||||
CGMutablePathRef path=CGPathCreateMutable();
|
||||
|
||||
for(i=0;i<386;i+=10){
|
||||
for(i=0;i<400;i+=10){
|
||||
|
||||
CGPathMoveToPoint(path,NULL,i,0);
|
||||
CGPathAddLineToPoint(path,NULL,i,height);
|
||||
}
|
||||
|
||||
for(i=0;i<386;i+=10){
|
||||
for(i=0;i<400;i+=10){
|
||||
CGPathMoveToPoint(path,NULL,0,i);
|
||||
CGPathAddLineToPoint(path,NULL,width,i);
|
||||
}
|
||||
@ -141,6 +141,44 @@ static void addSliceToPath(CGMutablePathRef path,float innerRadius,float outerRa
|
||||
CGPathRelease(path);
|
||||
}
|
||||
|
||||
-(void)drawBlendingInRender:(KGRender *)render {
|
||||
int width=400;
|
||||
int height=400;
|
||||
int i,limit=10;
|
||||
CGAffineTransform ctm=[self ctm];
|
||||
|
||||
ctm=CGAffineTransformTranslate(ctm,-200,-200);
|
||||
[render clear];
|
||||
|
||||
for(i=0;i<limit;i++){
|
||||
CGMutablePathRef path=CGPathCreateMutable();
|
||||
float g=(i+1)/(float)limit;
|
||||
float components[4]={g,g,g,g};
|
||||
CGColorRef fillColor=CGColorCreate(CGColorSpaceCreateDeviceRGB(),components);
|
||||
|
||||
CGPathAddRect(path,NULL,CGRectMake(i*width/limit,0,width/limit,height));
|
||||
|
||||
[render drawPath:path drawingMode:_pathDrawingMode blendMode:kCGBlendModeCopy
|
||||
interpolationQuality:kCGInterpolationDefault fillColor:fillColor strokeColor:NULL lineWidth:gState->_lineWidth lineCap:gState->_lineCap lineJoin:gState->_lineJoin miterLimit:gState->_miterLimit dashPhase:gState->_dashPhase dashLengthsCount:gState->_dashLengthsCount dashLengths:gState->_dashLengths transform:ctm antialias:gState->_shouldAntialias];
|
||||
CGColorRelease(fillColor);
|
||||
CGPathRelease(path);
|
||||
}
|
||||
|
||||
for(i=0;i<limit;i++){
|
||||
CGMutablePathRef path=CGPathCreateMutable();
|
||||
float g=(i+1)/(float)limit;
|
||||
float components[4]={g/2,(1.0-g),g,g};
|
||||
CGColorRef fillColor=CGColorCreate(CGColorSpaceCreateDeviceRGB(),components);
|
||||
|
||||
CGPathAddRect(path,NULL,CGRectMake(0,0,width,height-i*height/limit));
|
||||
|
||||
[render drawPath:path drawingMode:_pathDrawingMode blendMode:gState->_blendMode
|
||||
interpolationQuality:kCGInterpolationDefault fillColor:fillColor strokeColor:NULL lineWidth:gState->_lineWidth lineCap:gState->_lineCap lineJoin:gState->_lineJoin miterLimit:gState->_miterLimit dashPhase:gState->_dashPhase dashLengthsCount:gState->_dashLengthsCount dashLengths:gState->_dashLengths transform:ctm antialias:gState->_shouldAntialias];
|
||||
CGColorRelease(fillColor);
|
||||
CGPathRelease(path);
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setNeedsDisplay {
|
||||
switch([_testPopUp selectedTag]){
|
||||
case 0:
|
||||
@ -152,6 +190,11 @@ static void addSliceToPath(CGMutablePathRef path,float innerRadius,float outerRa
|
||||
[self drawStraightLinesInRender:_cgRender];
|
||||
[self drawStraightLinesInRender:_kgRender];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
[self drawBlendingInRender:_cgRender];
|
||||
[self drawBlendingInRender:_kgRender];
|
||||
break;
|
||||
}
|
||||
|
||||
[_cgView setImageRef:[_cgRender imageRef]];
|
||||
|
@ -272,6 +272,8 @@
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO;
|
||||
GCC_MODEL_TUNING = "";
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
GCC_UNROLL_LOOPS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
||||
GCC_WARN_SHADOW = NO;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
|
Loading…
Reference in New Issue
Block a user