- SWRender, more fill optimizations, added blending test, several blend formulas fixed and tested.

This commit is contained in:
Christopher Lloyd 2008-04-07 20:07:41 +00:00
parent 5d821940fd
commit 44511579a1
7 changed files with 439 additions and 218 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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&&check;
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);
}

View File

@ -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 {

View File

@ -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]];

View File

@ -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;