コード例 #1
0
ファイル: GContext.cpp プロジェクト: Mokosha/COMP590
  void drawXFormPixelWithAlpha(const uint32_t i, const uint32_t j,
                               const GRect &srcRect, const GIRect &dstRect,
                               const GBitmap &src, const GBitmap &dst,
                               const uint8_t alpha,
                               const BlendFunc blend = blend_srcover) {

    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(srcRect, ctxPt[0], ctxPt[1])) {
      uint32_t x = static_cast<uint32_t>(ctxPt[0] - srcRect.fLeft);
      uint32_t y = static_cast<uint32_t>(ctxPt[1] - srcRect.fTop);

      GPixel *srcRow = GetRow(src, y);
      GPixel *dstRow = GetRow(dst, j+dstRect.fTop) + dstRect.fLeft;

      uint32_t srcA = fixed_multiply(GPixel_GetA(srcRow[x]), alpha);
      uint32_t srcR = fixed_multiply(GPixel_GetR(srcRow[x]), alpha);
      uint32_t srcG = fixed_multiply(GPixel_GetG(srcRow[x]), alpha);
      uint32_t srcB = fixed_multiply(GPixel_GetB(srcRow[x]), alpha);
      GPixel src = GPixel_PackARGB(srcA, srcR, srcG, srcB);
      dstRow[i] = blend(dstRow[i], src);
    }
  }
コード例 #2
0
ファイル: GContext.cpp プロジェクト: Mokosha/COMP590
  static GPixel blend_srcover(GPixel dst, GPixel src) {
    uint32_t srcA = GPixel_GetA(src);
    if(srcA == 255) {
      return src;
    }

    uint32_t srcR = GPixel_GetR(src);
    uint32_t srcG = GPixel_GetG(src);
    uint32_t srcB = GPixel_GetB(src);

    uint32_t dstA = GPixel_GetA(dst);
    uint32_t dstR = GPixel_GetR(dst);
    uint32_t dstG = GPixel_GetG(dst);
    uint32_t dstB = GPixel_GetB(dst);

    return GPixel_PackARGB(srcA + fixed_multiply(dstA, 255 - srcA),
                           srcR + fixed_multiply(dstR, 255 - srcA),
                           srcG + fixed_multiply(dstG, 255 - srcA),
                           srcB + fixed_multiply(dstB, 255 - srcA));
  }
コード例 #3
0
ファイル: mike_canvas.cpp プロジェクト: msarett/575
static void srcover_row(GPixel row[], int count, GPixel src) {
    unsigned sa = GPixel_GetA(src);
    unsigned sr = GPixel_GetR(src);
    unsigned sg = GPixel_GetG(src);
    unsigned sb = GPixel_GetB(src);
    unsigned isa = 255 - sa;

    for (int i = 0; i < count; ++i) {
        GPixel dst = row[i];
        unsigned da = GPixel_GetA(dst);
        unsigned dr = GPixel_GetR(dst);
        unsigned dg = GPixel_GetG(dst);
        unsigned db = GPixel_GetB(dst);

        unsigned a = sa + GDiv255(isa * da);
        unsigned r = sr + GDiv255(isa * dr);
        unsigned g = sg + GDiv255(isa * dg);
        unsigned b = sb + GDiv255(isa * db);
        row[i] = GPixel_PackARGB(a, r, g, b);
    }
}
コード例 #4
0
ファイル: GBitmap.cpp プロジェクト: Mokosha/COMP590
static void convertToPNG(const GPixel src[], int width, char dst[]) {
    for (int i = 0; i < width; i++) {
        GPixel c = *src++;
        int a = GPixel_GetA(c);
        int r = GPixel_GetR(c);
        int g = GPixel_GetG(c);
        int b = GPixel_GetB(c);
        
        // PNG requires unpremultiplied, but GPixel is premultiplied
        if (0 != a && 255 != a) {
            r = r * 255 / a;
            g = g * 255 / a;
            b = b * 255 / a;
        }
        *dst++ = r;
        *dst++ = g;
        *dst++ = b;
        *dst++ = a;
    }
}
コード例 #5
0
ファイル: my_canvas.cpp プロジェクト: fangelod/Coursework
	/**
	 *	Fill the rectangle with color, using SRC_OVER porter-duff mode.
	 *
	 *	The affected pixels are those whose centers are "contained" inside the rectangle:
	 *		e.g. contained == center > min_edge && center <= max_edge
	 *
	 *	Any area in the rectangle that is outside of the bounds of the canvas is ignored.
	 */
	void fillRect(const GRect& rect, const GColor& color) {
		// Get dimensions of rectangle
		int le = GRoundToInt(rect.left());
		int to = GRoundToInt(rect.top());
		int ri = GRoundToInt(rect.right());
		int bo = GRoundToInt(rect.bottom());

		// Fix rectangle boundaries
		if (le < 0) {le = 0;}
		if (to < 0) {to = 0;}
		if (ri > draw.width()) {ri = draw.width();}
		if (bo > draw.height()) {bo = draw.height();}

		// Don't draw if rectangle is of zero size
		if ((le < 0 && ri < 0) || (le > draw.width() && ri > draw.width())) {
			return;
		}
		if ((to < 0 && bo < 0) || (to > draw.height() && bo > draw.height())) {
			return;
		}
		if ((to == bo) || (le == ri)) {
			return;
		}

		// If alpha value is 0, end method
        if (color.fA <= 0) {
        	return;
        }

        // Prepare color to place into bitmap
        GColor c = color.pinToUnit();
        unsigned a = (int)(c.fA * 255.99999);
        unsigned r = (int)(c.fR * c.fA * 255.99999);
        unsigned g = (int)(c.fG * c.fA * 255.99999);
        unsigned b = (int)(c.fB * c.fA * 255.99999);

        // Fill desired pixels
        GPixel* dst = draw.fPixels;
		dst = (GPixel*)((char*)dst + (int)to * draw.rowBytes());
        for (int y = to; y < bo; ++y)  {
    	    for (int x = le; x < ri; ++x) {
    	    	if (GPixel_GetA(*draw.getAddr(x, y)) > 0) {
    	    		// blend
					float sA = c.fA + ((GPixel_GetA(*draw.getAddr(x, y)) / 255.99999) * (1.0f - c.fA));
					float sR = (c.fR * c.fA) + ((GPixel_GetR(*draw.getAddr(x, y)) / 255.99999) * (1.0f - c.fA));
					float sG = (c.fG * c.fA) + ((GPixel_GetG(*draw.getAddr(x, y)) / 255.99999) * (1.0f - c.fA));
					float sB = (c.fB * c.fA) + ((GPixel_GetB(*draw.getAddr(x, y)) / 255.99999) * (1.0f - c.fA));
									
					unsigned nA = (int)(sA * 255.99999);
					unsigned nR = (int)(sR * 255.99999);
					unsigned nG = (int)(sG * 255.99999);
					unsigned nB = (int)(sB * 255.99999);

    	    		dst[x] = GPixel_PackARGB(nA, nR, nG, nB);
    	    	} else {
    	    		// Fill color unblended
    	    		dst[x] = GPixel_PackARGB(a, r, g, b);
    	    	}
		  	}
            dst = (GPixel*)((char*)dst + draw.rowBytes());
        }
	}
コード例 #6
0
ファイル: my_canvas.cpp プロジェクト: fangelod/Coursework
	/**
	 *	Fill the convex polygon with the color, following the same "containment" rule as
	 *	rectangles.
	 *
	 *	Any area in the polygon that is outside of the bounds of the canvas is ignored.
	 *
	 *	If the color's alpha is < 1, blend it using SRCOVER blend mode.
	 */
	void fillConvexPolygon(const GPoint* po, int count, const GColor& color) {
		// Consider points
			// int count = # of points

		// Do nothing if less than 3 points (i.e. not enough points to make a polygon)
		if (count < 3) {
			return;
		}

		// Adjust points according to CTM
			// Array to hold adjusted points
		GPoint* p = new GPoint[count];

			// Loop to change each point
		for (int i = 0; i < count; i++) {
			float px;
			float py;

			px = (CTM[0] * po[i].x()) + (CTM[1] * po[i].y()) + (CTM[2]);
			py = (CTM[3] * po[i].x()) + (CTM[4] * po[i].y()) + (CTM[5]);

			// Set new x and y
			p[i].set(px, py); 
		}

		// Create edges
		Edge tmpE;
		std::vector<Edge> eArr;
		for (int i = 0; i < count; i++) {
			if (i == (count - 1)) {
				if (GFloorToInt(p[i].x() + 0.5) == GFloorToInt(p[0].x() + 0.5)) {
					// vertical line
					tmpE.top = GFloorToInt(std::min(p[i].y(),p[0].y()) + 0.5);
					tmpE.bottom = GFloorToInt(std::max(p[i].y(),p[0].y()) + 0.5);
					tmpE.m = 0;
					tmpE.b = 0;
					tmpE.v = GFloorToInt(p[i].x()  + 0.5);
					tmpE.x = tmpE.v;
				} else if (GFloorToInt(p[i].y() + 0.5) == GFloorToInt(p[0].y() + 0.5)) {
					// horizontal line
					tmpE.top = 0;
					tmpE.bottom = 0;
					tmpE.m = 0;
					tmpE.b = 0;
					tmpE.v = 0;
					tmpE.x = 0;
				} else {
					tmpE.top = GFloorToInt(std::min(p[i].y(),p[0].y()) + 0.5);
					tmpE.bottom = GFloorToInt(std::max(p[i].y(),p[0].y()) + 0.5);
					tmpE.m = ((p[0].x()-p[i].x())/(p[0].y()-p[i].y()));
					tmpE.b = (p[i].x()-(tmpE.m * p[i].y()));
					tmpE.v = 0;
					tmpE.x = GFloorToInt(std::min(p[i].x(), p[0].x()) + 0.5);
				}
			} else {
				if (GFloorToInt(p[i].x() + 0.5) == GFloorToInt(p[i+1].x() + 0.5)) {
					// vertical line
					tmpE.top = GFloorToInt(std::min(p[i].y(),p[i+1].y()) + 0.5);
					tmpE.bottom = GFloorToInt(std::max(p[i].y(),p[i+1].y()) + 0.5);
					tmpE.m = 0;
					tmpE.b = 0;
					tmpE.v = GFloorToInt(p[i].x()  + 0.5);
					tmpE.x = tmpE.v;
				} else if (GFloorToInt(p[i].y() + 0.5) == GFloorToInt(p[i+1].y() + 0.5)) {
					// horizontal line
					tmpE.top = 0;
					tmpE.bottom = 0;
					tmpE.m = 0;
					tmpE.b = 0;
					tmpE.v = 0;
					tmpE.x = 0;
				} else {
					tmpE.top = GFloorToInt(std::min(p[i].y(),p[i+1].y()) + 0.5);
					tmpE.bottom = GFloorToInt(std::max(p[i].y(),p[i+1].y()) + 0.5);
					tmpE.m = ((p[i+1].x()-p[i].x())/(p[i+1].y()-p[i].y()));
					tmpE.b = (p[i].x()-(tmpE.m * p[i].y()));
					tmpE.v = 0;
					tmpE.x = GFloorToInt(std::min(p[i].x(), p[i+1].x()) + 0.5);
				}
			}

			if (tmpE.top != tmpE.bottom) {
				eArr.push_back(tmpE);
			}
		}

		// Sort edges
		std::sort(eArr.begin(), eArr.end(), sortEdges);
		
		// Prepare color to fill
		GColor c = color.pinToUnit();
        unsigned a = (int)(c.fA * 255.99999);
        unsigned r = (int)(c.fR * c.fA * 255.99999);
        unsigned g = (int)(c.fG * c.fA * 255.99999);
        unsigned b = (int)(c.fB * c.fA * 255.99999);

        // Find starting y pixel
        int startY = eArr[0].top;

        // Find ending y pixel
        int endY = eArr.back().bottom;

        // Fill desired pixels
        	// Set indexes for left and right edges at beginning
        int index;
        int currL;
        int currR;

        index = 0;
        currL = index;
        currR = index + 1;
        index += 2;

		GPixel* d = draw.fPixels;
		d = (GPixel*)((char*)d + (int)startY * draw.rowBytes());
		for (int y = startY; y < endY; ++y) {
			for (int x = lrBound(eArr, currL, y); x < lrBound(eArr, currR, y); ++x) {
				// blend if alpha isn't 255

				// if pixel is out of bounds, skip pixel
				if ((x >= 0) && (x < draw.width()) && (y >= 0) && (y < draw.height())) {
					if (GPixel_GetA(*draw.getAddr(x, y)) > 0) {
	    	    		// blend
						float sA = c.fA + ((GPixel_GetA(*draw.getAddr(x, y)) / 255.99999) * (1.0f - c.fA));
						float sR = (c.fR * c.fA) + ((GPixel_GetR(*draw.getAddr(x, y)) / 255.99999) * (1.0f - c.fA));
						float sG = (c.fG * c.fA) + ((GPixel_GetG(*draw.getAddr(x, y)) / 255.99999) * (1.0f - c.fA));
						float sB = (c.fB * c.fA) + ((GPixel_GetB(*draw.getAddr(x, y)) / 255.99999) * (1.0f - c.fA));
										
						unsigned nA = (int)(sA * 255.99999);
						unsigned nR = (int)(sR * 255.99999);
						unsigned nG = (int)(sG * 255.99999);
						unsigned nB = (int)(sB * 255.99999);

	    	    		d[x] = GPixel_PackARGB(nA, nR, nG, nB);
    	    		} else {
    	    			d[x] = GPixel_PackARGB(a, r, g, b);
    	    		}
				}

				if (eArr[currL].bottom == y) {
					currL = index;
					index++;
				}
				if (eArr[currR].bottom == y) {
					currR = index;
					index++;
				}
			}
			d = (GPixel*)((char*)d + draw.rowBytes());
		}
	}
コード例 #7
0
ファイル: my_canvas.cpp プロジェクト: fangelod/Coursework
	/**
	 *	Scale and translate the bitmap such that is fills the specific rectangle.
	 *
	 *	Any area in the rectangle that is outside of the bounds of the canvas is ignored.
	 *
	 *	If a given pixel in the bitmap is not opaque (e.g. GPixel_GetA() < 255) then blend it
	 *	using SRCOVER blend mode.
	 */
	void fillBitmapRect(const GBitmap& src, const GRect& dst) {
		// Store dimensions of dst rectangle
		int left = dst.left();
		int top = dst.top();
		int right = dst.right();
		int bottom = dst.bottom();
		int rW = dst.width();
		int rH = dst.height();

		// Store dimensions of src bitmap
		int bW = src.width();
		int bH = src.height();

		// Find necessary scale factor for both width and height
		float sx = (float)bW/(float)rW;
		float sy = (float)bH/(float)rH;

		float tx = 0 - left;
		float ty = 0 - top;

		// Create matrix for scaling
		float scale[6] = 
			{sx, 0, 0, 
			 0, sy, 0};

		// Create matrix for translating
		float translate[6] =
			{1, 0, tx,
			 0, 1, ty};

		// Combine the matrices
		float both[6] = 
			{sx, 0, sx*tx,
			 0, sy, sy*ty};

		// For loop that takes each point in dst and find corresponding point in src
		GPixel* d = draw.fPixels;
		d = (GPixel*)((char*)d + (int)top * draw.rowBytes());
		for (int y = top; y < bottom; ++y) {
			for (int x = left; x < right; ++x) {
				// Only map pixels that are in the bitmap
				if ((x >= 0 && x < draw.width()) && (y >= 0 && y < draw.height())) {
					// Find corresponding point in src bitmap
					int xP;
					int yP;

					xP = both[0] * x + both[1] * y + both[2];
					yP = both[3] * x + both[4] * y + both[5];

					// Apply CTM to x and y
					int nX = (CTM[0] * x) + (CTM[1] * y) + (CTM[2]);
					int nY = (CTM[3] * x) + (CTM[4] * y) + (CTM[5]);

					// Prepare color to fill
					unsigned a = GPixel_GetA(*src.getAddr(xP, yP));
					unsigned r = GPixel_GetR(*src.getAddr(xP, yP));
					unsigned g = GPixel_GetG(*src.getAddr(xP, yP));
					unsigned b = GPixel_GetB(*src.getAddr(xP, yP));

					unsigned nA = a;
					unsigned nR = r;
					unsigned nG = g;
					unsigned nB = b;

					if (GPixel_GetA(*draw.getAddr(x, y)) > 0) {
	    	    		// blend
						float lA = GPixel_GetA(*src.getAddr(xP, yP)) / 255.99999;
						float lR = GPixel_GetR(*src.getAddr(xP, yP)) / 255.99999;
						float lG = GPixel_GetG(*src.getAddr(xP, yP)) / 255.99999;
						float lB = GPixel_GetB(*src.getAddr(xP, yP)) / 255.99999;

						
						float sA = lA + ((GPixel_GetA(*draw.getAddr(x, y)) / 255.99999) * (1.0f - lA));
						float sR = lR + ((GPixel_GetR(*draw.getAddr(x, y)) / 255.99999) * (1.0f - lA));
						float sG = lG + ((GPixel_GetG(*draw.getAddr(x, y)) / 255.99999) * (1.0f - lA));
						float sB = lB + ((GPixel_GetB(*draw.getAddr(x, y)) / 255.99999) * (1.0f - lA));
						

						/*
						float sA = lA + ((GPixel_GetA(*draw.getAddr(nX, nY)) / 255.99999) * (1.0f - lA));
						float sR = lR + ((GPixel_GetR(*draw.getAddr(nX, nY)) / 255.99999) * (1.0f - lA));
						float sG = lG + ((GPixel_GetG(*draw.getAddr(nX, nY)) / 255.99999) * (1.0f - lA));
						float sB = lB + ((GPixel_GetB(*draw.getAddr(nX, nY)) / 255.99999) * (1.0f - lA));
						*/
										
						nA = (int)(sA * 255.99999);
						nR = (int)(sR * 255.99999);
						nG = (int)(sG * 255.99999);
						nB = (int)(sB * 255.99999);

	    	    		d[x] = GPixel_PackARGB(nA, nR, nG, nB);
	    	    		//d = (GPixel*)((char*)d + (int)nY * draw.rowBytes());
	    	    		//d[nX] = GPixel_PackARGB(nA, nR, nG, nB);
	    	    		//d = (GPixel*)((char*)d - (int)nY * draw.rowBytes());
    	    		} else {
    	    			d[x] = GPixel_PackARGB(a, r, g, b);
    	    			//d = (GPixel*)((char*)d + (int)nY * draw.rowBytes());
	    	    		//d[nX] = GPixel_PackARGB(a, r, g, b);
	    	    		//d = (GPixel*)((char*)d - (int)nY * draw.rowBytes());
    	    		}	    		
				}
			}
			d = (GPixel*)((char*)d + draw.rowBytes());
		}
	}
コード例 #8
0
ファイル: GContext.cpp プロジェクト: Mokosha/COMP590
  // 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);
        }
      }
    }
  }