void testMadelbrot(float x0, float y0, GContext* ctx){ x0+=.003125; y0+=.003125; float length = (x0*x0 + y0*y0); float x = x0; float y = y0; if (length >= 4){ return; } else{ float red = 0.00048828125; GPaint paint; for(int i=1;i<2048;++i){ x = x*x - y*y + x0; y = 2*x*y + y0; length = (x*x + y*y); if(sqrt(length) >= 2){ paint.setARGB(red, red, 0, 0); ctx->drawRect(GRect::MakeLTRB(x0-.003125, y0-.003125, x0 + .003125, y0+.003125), paint); return; } red = math.sin(i); } paint.setARGB(1,1,1,1); ctx->drawRect(GRect::MakeLTRB(x0-.003125, y0-.003125, x0 + .003125, y0+.003125),paint); } }
void drawRect(const GRect &rect, const GPaint &p) { const GBitmap &ctxbm = GetInternalBitmap(); GRect ctxRect = GRect::MakeXYWH(0, 0, ctxbm.width(), ctxbm.height()); GRect pixelRect = GetTransformedBoundingBox(rect); if(pixelRect.isEmpty()) { return; } GRect trRect; if(!(trRect.setIntersection(ctxRect, pixelRect))) { return; } // Rein everything back into integer land GIRect dstRect = trRect.round(); if(dstRect.isEmpty()) { return; } if(!(CheckSkew(m_CTM))) { fillIRect(dstRect, p.getColor(), eBlendOp_SrcOver); return; } GPixel clearValue = ColorToPixel(p.getColor()); // If the alpha value is above this value, then it will round to // an opaque pixel during quantization. const float kOpaqueAlpha = (254.5f / 255.0f); float alpha = p.getAlpha(); // Blend func is currently just srcover BlendFunc blend = blend_srcover; for(uint32_t j = 0; j < dstRect.height(); j++) { for(uint32_t i = 0; i < dstRect.width(); i++) { GVec3f ctxPt(static_cast<float>(dstRect.fLeft + i) + 0.5f, static_cast<float>(dstRect.fTop + j) + 0.5f, 1.0f); ctxPt = m_CTMInv * ctxPt; if(ContainsPoint(rect, ctxPt[0], ctxPt[1])) { uint32_t x = static_cast<uint32_t>(ctxPt[0] - rect.fLeft); uint32_t y = static_cast<uint32_t>(ctxPt[1] - rect.fTop); GPixel *dstRow = GetRow(ctxbm, j+dstRect.fTop) + dstRect.fLeft; dstRow[i] = blend(dstRow[i], clearValue); } } } }
// This code draws a bitmap using the full m_CTM transform without any thought // to whether or not the transform has any special properties. void drawBitmapXForm(const GBitmap &bm, const GPaint &paint) { const GBitmap &ctxbm = GetInternalBitmap(); GRect ctxRect = GRect::MakeXYWH(0, 0, ctxbm.width(), ctxbm.height()); GIRect bmRect = GIRect::MakeXYWH(0, 0, bm.width(), bm.height()); GRect pixelRect = GetTransformedBoundingBox(bmRect); GRect rect; if(!(rect.setIntersection(ctxRect, pixelRect))) { return; } // Rein everything back into integer land GIRect dstRect = rect.round(); if(dstRect.isEmpty()) { return; } float alpha = paint.getAlpha(); if(alpha >= kOpaqueAlpha) { for(uint32_t j = 0; j < dstRect.height(); j++) { for(uint32_t i = 0; i < dstRect.width(); i++) { drawXFormPixel(i, j, dstRect, bmRect, bm, ctxbm); } } } else { const uint32_t alphaVal = static_cast<uint32_t>((alpha * 255.0f) + 0.5f); for(uint32_t j = 0; j < dstRect.height(); j++) { for(uint32_t i = 0; i < dstRect.width(); i++) { drawXFormPixelWithAlpha(i, j, dstRect, bmRect, bm, ctxbm, alphaVal); } } } }
void GContext4::drawRect(const GRect& rect, const GPaint& bucket){ if((int)(bucket.getAlpha()*255 + .5) > 0){ //only do something if the alpha is greater than zero const GColor& color = bucket.getColor(); if(helper.isLegalColor(color)){ if(!rect.isEmpty()){ float rTop=rect.fTop,rBottom=rect.fBottom,rLeft=rect.fLeft,rRight=rect.fRight; mapping.vectorMult(&rLeft, &rTop); mapping.vectorMult(&rRight, &rBottom); if(rLeft>rRight){ rLeft += rRight; rRight = rLeft - rRight; rLeft = rLeft - rRight; } if (rTop > rBottom){ rTop += rBottom; rBottom = rTop - rBottom; rTop = rTop - rBottom; } int left = helper.roundToInt(rLeft); int right = helper.roundToInt(rRight); int top = helper.roundToInt(rTop); int bottom = helper.roundToInt(rBottom); helper.findIntersection(&left, &right, &top, &bottom, Btmp.fHeight, Btmp.fWidth); uint32_t storedResult = 0x01; uint32_t storedDestination = 0x01; uint32_t DstColor; uint32_t rectColor = helper.packARGB(color); char* row = ((char*) Btmp.fPixels) + top*Btmp.fRowBytes; for(int j = top; j<bottom; j++){ for(int i=left ; i<right; i++){ DstColor = *((GPixel*) row + i); if(storedDestination == DstColor){ //if we have the value already, don't do the math *((GPixel*) row + i) = storedResult; } else{ storedDestination = DstColor; storedResult = helper.blendColor(DstColor, rectColor); *((GPixel*) row + i) = storedResult; //blends the two colors } } row += Btmp.fRowBytes; } } } } }
void Shape::bounce(int w, int h, GMSec now) { float dur = (now - fPrevTime) / 1000.0f; fPrevTime = now; ::bounce(fX, fDx, dur, w); ::bounce(fY, fDy, dur, h); ::bounce(fA, fDa, dur, 1); ::bounce(fScale, fDScale, dur, 2, 0.25f); fPaint.setAlpha(fA); fRad += fDRad; }
void GContext4::drawBitmap(const GBitmap& lclBmp, float x, float y, const GPaint& paint){ float alpha = paint.getAlpha(); alpha = (alpha>1)?1:((alpha<0)?0:alpha);//bound alpha by 0 and 1 uint8_t intAlpha = alpha*255 + .5; if(intAlpha != 0){ float gTop = y, gLeft = x, gBottom = y+lclBmp.fHeight, gRight = x+lclBmp.fWidth; mapMtx.vectorMult(&gLeft, &gTop); mapMtx.vectorMult(&gRight, &gBottom); ConversionMatrix invMtx; mapMtx.getInverse(invMtx); helper.findIntersection(&gLeft, &gRight, &gTop, &gBottom, Btmp.fHeight, Btmp.fWidth); if((gLeft != gRight) && (gTop != gBottom)){ //if intersection surface area is zero, do nothing float topPixValue = helper.roundToInt(gTop), bottomPixValue = helper.roundToInt(gBottom); float gLeftStartValue = helper.roundToInt(gLeft), gRightPixValue = helper.roundToInt(gRight); uint32_t DstColor; uint32_t lclColor; for (float j = topPixValue; j< bottomPixValue; j++) { float lclYVal = j + .5; size_t gRowsDown = j*Btmp.fRowBytes; for (float i = gLeftStartValue; i <gRightPixValue; i++) { float lclXVal = i + .5; char* gAddress = (char*) Btmp.fPixels + gRowsDown + (int) i; DstColor = *((GPixel*) gAddress); invMtx.vectorMult(&lclXVal, &lclYVal); lclColor = *(GPixel*) (char*) lclBmp.fPixels + floorf(lclYVal)*lclBmp.fRowBytes + floorf(lclXVal); if (lclColor != 0) { //if there is something to blend if(intAlpha == 1){ *((GPixel*) gAddress) = helper.blendColor(DstColor, lclColor); } else if( DstColor == 0 ) { //if destination alpha == 0 *((GPixel*) gAddress) = helper.packARGB(lclColor, intAlpha); } else{ *((GPixel*) gAddress) = helper.blendColorWithAlpha(DstColor, lclColor, intAlpha); } } } } } } }
void drawBitmap(const GBitmap &bm, float x, float y, const GPaint &paint) { float alpha = paint.getAlpha(); if(alpha < kTransparentAlpha) { return; } save(); translate(x, y); if(CheckSkew(m_CTM)) { drawBitmapXForm(bm, paint); } else { drawBitmapSimple(bm, paint); } restore(); }
void GContext4::drawBitmap(const GBitmap& lclBmp, float x, float y, const GPaint& paint){ float alpha = paint.getAlpha(); alpha = (alpha>1)?1:((alpha<0)?0:alpha);//bound alpha by 0 and 1 uint8_t intAlpha = alpha*255 + .5; if(intAlpha != 0){ // first find the intersection float gTop = y, gLeft = x, gBottom = y+lclBmp.fHeight, gRight = x+lclBmp.fWidth; float inverseScaleX = 1; float inverseScaleY = 1; mapping.vectorMult(&gLeft, &gTop); mapping.vectorMult(&gRight, &gBottom); if(mapping.a1 != 1){ inverseScaleX = abs(1/mapping.a1); //hide divides as much as possible } if(mapping.b2 != 1){ inverseScaleY = abs(1/mapping.b2); } float lclTop = (gTop<0)?-gTop*inverseScaleY:(gTop>Btmp.fHeight)?(gTop-Btmp.fHeight*inverseScaleY):0; float lclLeft = (gLeft<0)?-gLeft*inverseScaleX:(gLeft>Btmp.fWidth)?(gLeft-Btmp.fWidth*inverseScaleX):0; helper.findIntersection(&gLeft, &gRight, &gTop, &gBottom, Btmp.fHeight, Btmp.fWidth); //even if directions are switched we will still move from gLeft to gRight and gTop to gBottom if((gLeft != gRight) && (gTop != gBottom)){ //if not visible, do nothing int topPixValue = helper.roundToInt(gTop), bottomPixValue = helper.roundToInt(gBottom); int gLeftStartValue = helper.roundToInt(gLeft), gRightPixValue = helper.roundToInt(gRight); int gIntervalPixelWidth = gRightPixValue - gLeftStartValue; int gIntervalPixelHeight = bottomPixValue - topPixValue; int lclLeftStartValue = helper.roundToInt(lclLeft); uint32_t DstColor; uint32_t lclColor; char* gRow = ((char*) Btmp.fPixels + topPixValue*Btmp.fRowBytes); char* lclRow = ((char*) lclBmp.fPixels + helper.roundToInt(lclTop)*lclBmp.fRowBytes); char* lclStartRow = lclRow; float lclXIncrementer = 0; float lclYIncrementer = 0; if (mapping.b2 > 0) { //if scale up & positive for Y for (int j = 0; j<gIntervalPixelHeight; j++) { if (mapping.a1 > 0) { for (int i = 0; i < gIntervalPixelWidth; i++) { DstColor = *((GPixel*) gRow + gLeftStartValue + i); lclColor = *((GPixel*) lclRow + lclLeftStartValue + helper.roundToInt(lclXIncrementer)); lclXIncrementer += inverseScaleX; if (lclColor != 0) { //if source alpha is not zero if(intAlpha == 1){ *((GPixel*) gRow + gLeftStartValue + i) = helper.blendColor(DstColor, lclColor); } else if( DstColor == 0 ) { //if destination alpha == 0 *((GPixel*) gRow + gLeftStartValue + i) = helper.packARGB(lclColor, intAlpha); } else{ *((GPixel*) gRow + gLeftStartValue + i) = helper.blendColorWithAlpha(DstColor, lclColor, intAlpha); } } } lclXIncrementer = 0; } else{ for (int i = 0; i > gIntervalPixelWidth; i--) { DstColor = *((GPixel*) gRow + gLeftStartValue + i); lclColor = *((GPixel*) lclRow + lclLeftStartValue + helper.roundToInt(lclXIncrementer)); lclXIncrementer += inverseScaleX; if (lclColor != 0) { //if source alpha is not zero if(intAlpha == 1){ *((GPixel*) gRow + gLeftStartValue + i) = helper.blendColor(DstColor, lclColor); } else if( DstColor == 0 ) { //if destination alpha == 0 *((GPixel*) gRow + gLeftStartValue + i) = helper.packARGB(lclColor, intAlpha); } else{ *((GPixel*) gRow + gLeftStartValue + i) = helper.blendColorWithAlpha(DstColor, lclColor, intAlpha); } } } lclXIncrementer = 0; } lclYIncrementer += inverseScaleY; gRow += Btmp.fRowBytes; lclRow = lclStartRow + helper.roundToInt(lclYIncrementer)*lclBmp.fRowBytes; } } else{ for (int j = 0; j>gIntervalPixelHeight; j--) { if (mapping.a1 > 0) { for (int i = 0; i < gIntervalPixelWidth; i++) { DstColor = *((GPixel*) gRow + gLeftStartValue + i); lclColor = *((GPixel*) lclRow + lclLeftStartValue + helper.roundToInt(lclXIncrementer)); lclXIncrementer += inverseScaleX; if (lclColor != 0) { if(intAlpha == 1){ *((GPixel*) gRow + gLeftStartValue + i) = helper.blendColor(DstColor, lclColor); } else if( DstColor == 0 ) { *((GPixel*) gRow + gLeftStartValue + i) = helper.packARGB(lclColor, intAlpha); } else{ *((GPixel*) gRow + gLeftStartValue + i) = helper.blendColorWithAlpha(DstColor, lclColor, intAlpha); } } } lclXIncrementer = 0; } else{ for (int i = 0; i > gIntervalPixelWidth; i--) { DstColor = *((GPixel*) gRow + gLeftStartValue + i); lclColor = *((GPixel*) lclRow + lclLeftStartValue + helper.roundToInt(lclXIncrementer)); lclXIncrementer += inverseScaleX; if (lclColor != 0) { //if source alpha is not zero if(intAlpha == 1){ *((GPixel*) gRow + gLeftStartValue + i) = helper.blendColor(DstColor, lclColor); } else if( DstColor == 0 ) { //if destination alpha == 0 *((GPixel*) gRow + gLeftStartValue + i) = helper.packARGB(lclColor, intAlpha); } else{ *((GPixel*) gRow + gLeftStartValue + i) = helper.blendColorWithAlpha(DstColor, lclColor, intAlpha); } } } lclXIncrementer = 0; } lclYIncrementer += inverseScaleY; gRow += Btmp.fRowBytes; //steps a row of bytes in Btmp lclRow = lclStartRow + helper.roundToInt(lclYIncrementer)*lclBmp.fRowBytes; //steps a row of bytes in lclBmp } } } } }
void WalkEdges(const GEdge e1, const GEdge e2, const GPaint &paint) { const GBitmap &bm = GetInternalBitmap(); int h = bm.fHeight; int w = bm.fWidth; GASSERT(e1.p1.y() == e2.p1.y()); int startY = Clamp(static_cast<int>(e1.p1.y() + 0.5f), 0, h-1); GASSERT(e1.p2.y() == e2.p2.y()); int endY = Clamp(static_cast<int>(e1.p2.y() + 0.5f), 0, h-1); if(endY == startY) { return; } GASSERT(endY > startY); // Initialize to NAN float m1 = 0.0f/0.0f, b1; float m2 = 0.0f/0.0f, b2; bool vert1 = e1.ComputeLine(m1, b1); bool vert2 = e2.ComputeLine(m2, b2); if(m1 == 0 || m2 == 0) { return; } // Collinear? if(vert2 && vert1 && e1.p1.x() == e2.p1.x()) { return; } else if(m1 == m2 && b1 == b2) { return; } float stepX1 = vert1? 0 : 1/m1; float stepX2 = vert2? 0 : 1/m2; GPoint p1, p2; float sY = static_cast<float>(startY) + 0.5f; if(vert1) { p1.set(e1.p1.x(), sY); } else { p1.set((sY - b1) / m1, sY); } if(vert2) { p2.set(e2.p1.x(), sY); } else { p2.set((sY - b2) / m2, sY); } // Make sure that p1 is always less than p2 to avoid // doing a min/max in the inner loop if(p1.x() > p2.x()) { std::swap(p1, p2); std::swap(stepX1, stepX2); } GPixel color = ColorToPixel(paint.getColor()); BlendFunc blend = GetBlendFunc(eBlendOp_SrcOver); uint32_t nSteps = endY - startY; for(uint32_t i = 0; i < nSteps; i++) { // Since we haven't implemented clipping yet, take care // not to go beyond our bounds... const int x1 = Clamp<int>(p1.fX + 0.5f, 0, w-1); const int x2 = Clamp<int>(p2.fX + 0.5f, 0, w-1); GPixel *row = GetRow(bm, startY + i); for(int x = x1; x < x2; x++) { row[x] = blend(row[x], color); } p1.fX += stepX1; p2.fX += stepX2; } }
// This code draws a bitmap assuming that we only have translation and scale, // which allows us to perform certain optimizations... void drawBitmapSimple(const GBitmap &bm, const GPaint &paint) { const GBitmap &ctxbm = GetInternalBitmap(); GRect ctxRect = GRect::MakeXYWH(0, 0, ctxbm.width(), ctxbm.height()); GRect bmRect = GRect::MakeXYWH(0, 0, bm.width(), bm.height()); GRect pixelRect = GetTransformedBoundingBox(bmRect); GRect rect; if(!(rect.setIntersection(ctxRect, pixelRect))) { return; } // We know that since we're only doing scale and translation, that all of the pixel // centers contained in rect are going to be drawn, so we only need to know the // dimensions of the mapping... GVec3f origin(0, 0, 1); GVec3f offset(1, 1, 1); origin = m_CTM * origin; offset = m_CTM * offset; float xScale = 1.0f / (offset.X() - origin.X()); float yScale = 1.0f / (offset.Y() - origin.Y()); GVec2f start = GVec2f(0, 0); if(xScale < 0.0f) { start.X() = pixelRect.fRight - 1.0f; } if(yScale < 0.0f) { start.Y() = pixelRect.fBottom - 1.0f; } GIRect dstRect = rect.round(); // Construct new bitmap int32_t offsetX = ::std::max(0, -dstRect.fLeft); int32_t offsetY = ::std::max(0, -dstRect.fTop); GBitmap fbm; fbm.fWidth = bm.width(); fbm.fHeight = bm.height(); fbm.fPixels = GetRow(bm, offsetY) + offsetX; fbm.fRowBytes = bm.fRowBytes; BlendFunc blend = blend_srcover; float alpha = paint.getAlpha(); if(alpha >= kOpaqueAlpha) { for(uint32_t j = 0; j < dstRect.height(); j++) { uint32_t srcIdxY = static_cast<uint32_t>(start.Y() + static_cast<float>(j) * yScale); GPixel *srcPixels = GetRow(fbm, Clamp<int>(srcIdxY, 0, fbm.height())); GPixel *dstPixels = GetRow(ctxbm, dstRect.fTop + j) + dstRect.fLeft; for(uint32_t i = 0; i < dstRect.width(); i++) { uint32_t srcIdxX = static_cast<uint32_t>(start.X() + static_cast<float>(i) * xScale); dstPixels[i] = blend(dstPixels[i], srcPixels[Clamp<int>(srcIdxX, 0, fbm.width())]); } } } else { const uint32_t alphaVal = static_cast<uint32_t>((alpha * 255.0f) + 0.5f); for(uint32_t j = 0; j < dstRect.height(); j++) { uint32_t srcIdxY = static_cast<uint32_t>(start.Y() + static_cast<float>(j) * yScale); GPixel *srcPixels = GetRow(fbm, srcIdxY); GPixel *dstPixels = GetRow(ctxbm, dstRect.fTop + j) + dstRect.fLeft; for(uint32_t i = 0; i < dstRect.width(); i++) { uint32_t srcIdxX = static_cast<uint32_t>(start.X() + static_cast<float>(i) * xScale); uint32_t srcA = fixed_multiply(GPixel_GetA(srcPixels[srcIdxX]), alphaVal); uint32_t srcR = fixed_multiply(GPixel_GetR(srcPixels[srcIdxX]), alphaVal); uint32_t srcG = fixed_multiply(GPixel_GetG(srcPixels[srcIdxX]), alphaVal); uint32_t srcB = fixed_multiply(GPixel_GetB(srcPixels[srcIdxX]), alphaVal); GPixel src = GPixel_PackARGB(srcA, srcR, srcG, srcB); dstPixels[i] = blend(dstPixels[i], src); } } } }