/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "SrRasterizers.h" #include "SrFrameContext.h" // GsSrLineRasterizer implementation void GsSrLineRasterizer::draw(OdSrFrameContext&, GsSrRenderState& state, int x1, int y1, int x2, int y2, ODCOLORREF col) { y1 = (state.m_height - 1) - y1; y2 = (state.m_height - 1) - y2; // clipping if (!clipMin(x1, y1, x2, y2, state.m_clipRegion.m_min.x)) return; if (!clipMax(x1, y1, x2, y2, state.m_clipRegion.m_max.x)) return; if (!clipMin(x2, y2, x1, y1, state.m_clipRegion.m_min.x)) return; if (!clipMax(x2, y2, x1, y1, state.m_clipRegion.m_max.x)) return; if (!clipMin(y1, x1, y2, x2, state.m_clipRegion.m_min.y)) return; if (!clipMax(y1, x1, y2, x2, state.m_clipRegion.m_max.y)) return; if (!clipMin(y2, x2, y1, x1, state.m_clipRegion.m_min.y)) return; if (!clipMax(y2, x2, y1, x1, state.m_clipRegion.m_max.y)) return; OdUInt8 red(ODGETRED(col)), green(ODGETGREEN(col)), blue(ODGETBLUE(col)), alpha(ODGETALPHA(col)); int dx = Od_abs(x2 - x1); int dy = Od_abs(y2 - y1); int sx = x2 >= x1 ? 3 : -3; int sy = y2 >= y1 ? state.m_scanLineLength : -(int)state.m_scanLineLength; int d, d1, d2, i; OdUInt8* pCurPtr = state.m_pScanLines + state.m_scanLineLength * y1 + x1 * 3; if (!state.m_pStencilScanlinesPtr) { if (dy <= dx) { d = (dy << 1) - dx; d1 = dy << 1; d2 = (dy - dx) << 1; if (alpha == 255) { ::putPixel(pCurPtr, red, green, blue); for (pCurPtr += sx, i = 1; i <= dx; i++, pCurPtr += sx) { if (d > 0) { d += d2; pCurPtr += sy; } else d += d1; ::putPixel(pCurPtr, red, green, blue); } } else if (alpha > 0) { ::putPixel(pCurPtr, red, green, blue, alpha); for (pCurPtr += sx, i = 1; i <= dx; i++, pCurPtr += sx) { if (d > 0) { d += d2; pCurPtr += sy; } else d += d1; ::putPixel(pCurPtr, red, green, blue, alpha); } } } else { d = (dx << 1) - dy; d1 = dx << 1; d2 = (dx - dy) << 1; if (alpha == 255) { ::putPixel(pCurPtr, red, green, blue); for (pCurPtr += sy, i = 1; i <= dy; i++, pCurPtr += sy) { if (d > 0) { d += d2; pCurPtr += sx; } else d += d1; ::putPixel(pCurPtr, red, green, blue); } } else if (alpha > 0) { ::putPixel(pCurPtr, red, green, blue, alpha); for (pCurPtr += sy, i = 1; i <= dy; i++, pCurPtr += sy) { if (d > 0) { d += d2; pCurPtr += sx; } else d += d1; ::putPixel(pCurPtr, red, green, blue, alpha); } } } } else { int ssx = x2 >= x1 ? 1 : -1; int ssy = y2 >= y1 ? state.m_stencilWidth : -(int)state.m_stencilWidth; int stencilIdxInit = (y1 - state.m_stencilOffsetY) * state.m_stencilWidth + (x1 - state.m_stencilOffsetX); int maxIdx = state.m_pStencilScanlines.size() - 1; (void)maxIdx; OdUInt32 pStencilIdx = stencilIdxInit; if (dy <= dx) { d = (dy << 1) - dx; d1 = dy << 1; d2 = (dy - dx) << 1; if (alpha == 255) { if (state.m_pStencilScanlines[pStencilIdx]) ::putPixel(pCurPtr, red, green, blue); for (pCurPtr += sx, pStencilIdx += ssx, i = 1; i <= dx; i++, pCurPtr += sx, pStencilIdx += ssx) { if (d > 0) { d += d2; pCurPtr += sy; pStencilIdx += ssy; } else d += d1; if (state.m_pStencilScanlines[pStencilIdx]) ::putPixel(pCurPtr, red, green, blue); } } else if (alpha > 0) { if (state.m_pStencilScanlines[pStencilIdx]) ::putPixel(pCurPtr, red, green, blue, alpha); for (pCurPtr += sx, pStencilIdx += ssx, i = 1; i <= dx; i++, pCurPtr += sx, pStencilIdx += ssx) { if (d > 0) { d += d2; pCurPtr += sy; pStencilIdx += ssy; } else d += d1; if (state.m_pStencilScanlines[pStencilIdx]) ::putPixel(pCurPtr, red, green, blue, alpha); } } } else { d = (dx << 1) - dy; d1 = dx << 1; d2 = (dx - dy) << 1; if (alpha == 255) { if (state.m_pStencilScanlines[pStencilIdx]) ::putPixel(pCurPtr, red, green, blue); for (pCurPtr += sy, pStencilIdx += ssy, i = 1; i <= dy; i++, pCurPtr += sy, pStencilIdx += ssy) { if (d > 0) { d += d2; pCurPtr += sx; pStencilIdx += ssx; } else d += d1; if (state.m_pStencilScanlines[pStencilIdx]) ::putPixel(pCurPtr, red, green, blue); } } else if (alpha > 0) { if (state.m_pStencilScanlines[pStencilIdx]) ::putPixel(pCurPtr, red, green, blue, alpha); for (pCurPtr += sy, pStencilIdx += ssy, i = 1; i <= dy; i++, pCurPtr += sy, pStencilIdx += ssy) { if (d > 0) { d += d2; pCurPtr += sx; pStencilIdx += ssx; } else d += d1; if (state.m_pStencilScanlines[pStencilIdx]) ::putPixel(pCurPtr, red, green, blue, alpha); } } } } } // GsSrTriangleRasterizer implementation void GsSrTriangleRasterizer::draw(OdSrFrameContext& context, GsSrRenderState& state, int x1, int y1, int x2, int y2, int x3, int y3, ODCOLORREF col) { y1 = (state.m_height - 1) - y1; y2 = (state.m_height - 1) - y2; y3 = (state.m_height - 1) - y3; // must be y1 = min(y), y3 = max(y) if (y2 < y1) { std::swap(x1, x2); std::swap(y1, y2); } if (y3 < y1) { std::swap(x3, x1); std::swap(y3, y1); } if (y3 < y2) { std::swap(x3, x2); std::swap(y3, y2); } if (y1 == y3) { int minX(x1), maxX(x2); if (minX > x2) minX = x2; if (minX > x3) minX = x3; if (maxX < x2) maxX = x2; if (maxX < x3) maxX = x3; context.draw_horizontalLine(y1, minX, maxX, col); } else { for (int sy = y1; sy <= y3; sy++) { int xx1, xx2; xx1 = x1 + (sy - y1) * (x3 - x1) / (y3 - y1); if (sy < y2) xx2 = x1 + (sy - y1) * (x2 - x1) / (y2 - y1); else { if (y3 == y2) xx2 = x2; else xx2 = x2 + (sy - y2) * (x3 - x2) / (y3 - y2); } context.draw_horizontalLine(sy, xx1, xx2, col); } } } void GsSrTriangleRasterizer::drawMultiColor(OdSrFrameContext& context, GsSrRenderState&, float x1, float y1, float x2, float y2, float x3, float y3, const ODCOLORREF* threeColors) { OdSrVec2F v0{ x1, y1 }; OdSrVec2F v1{ x2, y2 }; OdSrVec2F v2{ x3, y3 }; // Find AABB int xMin = (int)::floor(odmin(odmin(v0.x, v1.x), v2.x)); int yMin = (int)::floor(odmin(odmin(v0.y, v1.y), v2.y)); int xMax = (int)::ceil(odmax(odmax(v0.x, v1.x), v2.x)); int yMax = (int)::ceil(odmax(odmax(v0.y, v1.y), v2.y)); float area = edge_cross(v0, v1, v2); float stepHorizontalW0 = (v1.y - v2.y); float stepHorizontalW1 = (v2.y - v0.y); float stepHorizontalW2 = (v0.y - v1.y); float stepVerticalW0 = (v2.x - v1.x); float stepVerticalW1 = (v0.x - v2.x); float stepVerticalW2 = (v1.x - v0.x); // Rasterization fill rule, to avoid problems with shared borders float offset0 = is_top_left(v1, v2) ? 0.0f : -0.0001f; float offset1 = is_top_left(v2, v0) ? 0.0f : -0.0001f; float offset2 = is_top_left(v0, v1) ? 0.0f : -0.0001f; OdSrVec2F p0 = { xMin + 0.5f, yMin + 0.5f }; float w0_row = edge_cross(v1, v2, p0) + offset0; float w1_row = edge_cross(v2, v0, p0) + offset1; float w2_row = edge_cross(v0, v1, p0) + offset2; for (int y = yMin; y <= yMax; y++) { float w0 = w0_row; float w1 = w1_row; float w2 = w2_row; for (int x = xMin; x <= xMax; x++) { bool is_inside = w0 >= 0.0f && w1 >= 0.0f && w2 >= 0.0f; if (is_inside) { float alpha = w0 / area; float beta = w1 / area; float gamma = w2 / area; int r = (int)((alpha)*ODGETRED(threeColors[0]) + (beta)*ODGETRED(threeColors[1]) + (gamma)*ODGETRED(threeColors[2])); int g = (int)((alpha)*ODGETGREEN(threeColors[0]) + (beta)*ODGETGREEN(threeColors[1]) + (gamma)*ODGETGREEN(threeColors[2])); int b = (int)((alpha)*ODGETBLUE(threeColors[0]) + (beta)*ODGETBLUE(threeColors[1]) + (gamma)*ODGETBLUE(threeColors[2])); context.draw_point(x, y, ODRGBA(r, g, b, 0xFF)); } w0 += stepHorizontalW0; w1 += stepHorizontalW1; w2 += stepHorizontalW2; } w0_row += stepVerticalW0; w1_row += stepVerticalW1; w2_row += stepVerticalW2; } } void GsSrTriangleRasterizer::drawClipping(OdSrFrameContext& context, GsSrRenderState& state, int x1, int y1, int x2, int y2, int x3, int y3) { y1 = (state.m_height - 1) - y1; y2 = (state.m_height - 1) - y2; y3 = (state.m_height - 1) - y3; // must be y1 = min(y), y3 = max(y) if (y2 < y1) { std::swap(x1, x2); std::swap(y1, y2); } if (y3 < y1) { std::swap(x3, x1); std::swap(y3, y1); } if (y3 < y2) { std::swap(x3, x2); std::swap(y3, y2); } if (y1 == y3) { int minX(x1), maxX(x2); if (minX > x2) minX = x2; if (minX > x3) minX = x3; if (maxX < x2) maxX = x2; if (maxX < x3) maxX = x3; context.draw_horizontalLineStencil(y1, minX, maxX, GsSrRenderState::kClippingContourArea); } else { for (int sy = y1; sy <= y3; sy++) { int xx1, xx2; xx1 = x1 + (sy - y1) * (x3 - x1) / (y3 - y1); if (sy < y2) xx2 = x1 + (sy - y1) * (x2 - x1) / (y2 - y1); else { if (y3 == y2) xx2 = x2; else xx2 = x2 + (sy - y2) * (x3 - x2) / (y3 - y2); } context.draw_horizontalLineStencil(sy, xx1, xx2, GsSrRenderState::kClippingContourArea); } } } // GsSrCircleRasterizer implementation void GsSrCircleRasterizer::drawOutline(OdSrFrameContext& context, GsSrRenderState& state, int centerX, int centerY, int radius) { int x; int y; int decisionParameter; x = 0; y = radius; decisionParameter = 3 - 2 * radius; while (y >= x) { context.draw_point(centerX + x, centerY + y, state.m_color); context.draw_point(centerX - x, centerY + y, state.m_color); context.draw_point(centerX + x, centerY - y, state.m_color); context.draw_point(centerX - x, centerY - y, state.m_color); context.draw_point(centerX + y, centerY + x, state.m_color); context.draw_point(centerX - y, centerY + x, state.m_color); context.draw_point(centerX + y, centerY - x, state.m_color); context.draw_point(centerX - y, centerY - x, state.m_color); x++; if (decisionParameter > 0) { y--; decisionParameter = decisionParameter + 4 * (x - y) + 10; } else decisionParameter = decisionParameter + 4 * x + 6; } } void GsSrCircleRasterizer::drawFilled(OdSrFrameContext& context, GsSrRenderState& state, int x, int y, double radius, ODCOLORREF color) { y = (state.m_height - 1) - y; OdInt32 iDmtr = (OdInt32)OdRound(radius * 2); OdInt32 dmtrLow = iDmtr / 2; OdInt32 dmtrHigh = dmtrLow; if (iDmtr < 2) { context.draw_point(x, y, color); } else { int xFrom = x - dmtrLow; int xTo = x + dmtrHigh; int yFrom = y - dmtrLow; int yTo = y + dmtrHigh; int i; if (xFrom > state.m_clipRegion.m_max.x || xTo < state.m_clipRegion.m_min.x || yFrom > state.m_clipRegion.m_max.y || yTo < state.m_clipRegion.m_min.y) return; // Low part for (i = yFrom; i <= y; i++) { OdInt32 inRad = (OdInt32)OdRound(sqrt(double(dmtrLow * dmtrLow) - double((i - y) * (i - y))) * 2); OdInt32 inRadLow = inRad / 2; OdInt32 inRadHigh = inRad - inRadLow; if (inRad > 0) context.draw_horizontalLine(i - 1, x - inRadLow, x + inRadHigh, color); } // High part for (i = y + 1; i <= yTo; i++) { OdInt32 inRad = (OdInt32)OdRound(sqrt(double(dmtrHigh * dmtrHigh) - double((i - y) * (i - y))) * 2); OdInt32 inRadLow = inRad / 2; OdInt32 inRadHigh = inRad - inRadLow; if (inRad > 0) context.draw_horizontalLine(i - 1, x - inRadLow, x + inRadHigh, color); } } } void GsSrCircleRasterizer::drawFilledPrecise(OdSrFrameContext& context, GsSrRenderState& state, double cx, double cy, double radius, ODCOLORREF color) { cy = (state.m_height - 1) - cy; { int xFrom = (int)ceil(cx - radius); int xTo = (int)floor(cx + radius); int yFrom = (int)ceil(cy - radius); int yTo = (int)floor(cy + radius); if (xFrom > state.m_clipRegion.m_max.x || xTo < state.m_clipRegion.m_min.x || yFrom > state.m_clipRegion.m_max.y || yTo < state.m_clipRegion.m_min.y) return; double ry_sq = radius * radius; for (int y = yFrom; y <= yTo; y++) { double dy = y - cy; double dy_sq = dy * dy; // Check if this scanline intersects the circle if (dy_sq <= ry_sq) { // Calculate x extent for this y using circle equation double x_extent = radius * sqrt(1.0 - dy_sq / ry_sq); // Calculate pixel-perfect left and right bounds int x_left = (int)ceil(cx - x_extent); int x_right = (int)floor(cx + x_extent); if (x_left <= x_right) context.draw_horizontalLine(y, x_left, x_right, color); } } } } // GsSrEllipseRasterizer implementation void GsSrEllipseRasterizer::drawOutline(OdSrFrameContext& context, GsSrRenderState& state, int centerX, int centerY, int radiusMajor, int radiusMinor) { int x = 0; int y = radiusMinor; double p1 = radiusMinor * radiusMinor - (radiusMajor * radiusMajor) * radiusMinor + (radiusMajor * radiusMajor) * (0.25); //slope double dx = 2 * (radiusMinor * radiusMinor) * x; double dy = 2 * (radiusMajor * radiusMajor) * y; while (dx < dy) { context.draw_point(centerX + x, centerY + y, state.m_color); context.draw_point(centerX - x, centerY + y, state.m_color); context.draw_point(centerX + x, centerY - y, state.m_color); context.draw_point(centerX - x, centerY - y, state.m_color); if (p1 < 0) { x = x + 1; dx = 2 * (radiusMinor * radiusMinor) * x; p1 = p1 + dx + (radiusMinor * radiusMinor); } else { x = x + 1; y = y - 1; dx = 2 * (radiusMinor * radiusMinor) * x; dy = 2 * (radiusMajor * radiusMajor) * y; p1 = p1 + dx - dy + (radiusMinor * radiusMinor); } } double p2 = (radiusMinor * radiusMinor) * (x + 0.5) * (x + 0.5) + (radiusMajor * radiusMajor) * (y - 1) * (y - 1) - (radiusMajor * radiusMajor) * (radiusMinor * radiusMinor); while (y > 0) { context.draw_point(centerX + x, centerY + y, state.m_color); context.draw_point(centerX - x, centerY + y, state.m_color); context.draw_point(centerX + x, centerY - y, state.m_color); context.draw_point(centerX - x, centerY - y, state.m_color); if (p2 > 0) { y = y - 1; dy = 2 * (radiusMajor * radiusMajor) * y; p2 = p2 - dy + (radiusMajor * radiusMajor); } else { x = x + 1; y = y - 1; dy = dy - 2 * (radiusMajor * radiusMajor); dx = dx + 2 * (radiusMinor * radiusMinor); p2 = p2 + dx - dy + (radiusMajor * radiusMajor); } } } void GsSrEllipseRasterizer::drawFilled(OdSrFrameContext& context, GsSrRenderState& state, int centerX, int centerY, int radiusMajor, int radiusMinor) { int x = 0; int y = radiusMinor; double p1 = radiusMinor * radiusMinor - (radiusMajor * radiusMajor) * radiusMinor + (radiusMajor * radiusMajor) * (0.25); //slope double dx = 2 * (radiusMinor * radiusMinor) * x; double dy = 2 * (radiusMajor * radiusMajor) * y; while (dx < dy) { context.draw_line(centerX + x, centerY + y, centerX - x, centerY + y, state.m_color); context.draw_line(centerX + x, centerY - y, centerX - x, centerY - y, state.m_color); if (p1 < 0) { x = x + 1; dx = 2 * (radiusMinor * radiusMinor) * x; p1 = p1 + dx + (radiusMinor * radiusMinor); } else { x = x + 1; y = y - 1; dx = 2 * (radiusMinor * radiusMinor) * x; dy = 2 * (radiusMajor * radiusMajor) * y; p1 = p1 + dx - dy + (radiusMinor * radiusMinor); } } double p2 = (radiusMinor * radiusMinor) * (x + 0.5) * (x + 0.5) + (radiusMajor * radiusMajor) * (y - 1) * (y - 1) - (radiusMajor * radiusMajor) * (radiusMinor * radiusMinor); while (y > 0) { context.draw_line(centerX + x, centerY + y, centerX - x, centerY + y, state.m_color); context.draw_line(centerX + x, centerY - y, centerX - x, centerY - y, state.m_color); if (p2 > 0) { y = y - 1; dy = 2 * (radiusMajor * radiusMajor) * y; p2 = p2 - dy + (radiusMajor * radiusMajor); } else { x = x + 1; y = y - 1; dy = dy - 2 * (radiusMajor * radiusMajor); dx = dx + 2 * (radiusMinor * radiusMinor); p2 = p2 + dx - dy + (radiusMajor * radiusMajor); } } }