public static void DrawBlock(ref T shader, ref TriangleEquations eqn, int x, int y, bool TestEdges) { float xf = x + 0.5f; float yf = y + 0.5f; PixelData po = new PixelData(); po.Init(ref eqn, xf, yf, shader.AVarCount, shader.PVarCount, shader.InterpolateZ, shader.InterpolateW); EdgeData eo = new EdgeData(); if (TestEdges) { eo.init(ref eqn, xf, yf); } for (int yy = y; yy < y + Constants.BlockSize; yy++) { PixelData pi = CopyPixelData(ref shader, ref po); EdgeData ei = new EdgeData(); if (TestEdges) { ei = eo; } for (int xx = x; xx < x + Constants.BlockSize; xx++) { if (!TestEdges || ei.test(ref eqn)) { pi.x = xx; pi.y = yy; shader.DrawPixel(ref pi); } pi.StepX(ref eqn, shader.AVarCount, shader.PVarCount, shader.InterpolateZ, shader.InterpolateW); if (TestEdges) { ei.stepX(ref eqn); } } po.StepY(ref eqn, shader.AVarCount, shader.PVarCount, shader.InterpolateZ, shader.InterpolateW); if (TestEdges) { eo.stepY(ref eqn); } } }
public void DrawTriangleBlockTemplate(ref RasterizerVertex v0, ref RasterizerVertex v1, ref RasterizerVertex v2) { // Compute triangle equations. TriangleEquations eqn = new TriangleEquations(ref v0, ref v1, ref v2, shader.AVarCount, shader.PVarCount); // Check if triangle is backfacing. if (eqn.area2 <= 0) { return; } // Compute triangle bounding box. int minX = (int)Math.Min(Math.Min(v0.x, v1.x), v2.x); int maxX = (int)Math.Max(Math.Max(v0.x, v1.x), v2.x); int minY = (int)Math.Min(Math.Min(v0.y, v1.y), v2.y); int maxY = (int)Math.Max(Math.Max(v0.y, v1.y), v2.y); // Clip to scissor rect. minX = Math.Max(minX, rasterizer.m_minX); maxX = Math.Min(maxX, rasterizer.m_maxX); minY = Math.Max(minY, rasterizer.m_minY); maxY = Math.Min(maxY, rasterizer.m_maxY); // Round to block grid. minX &= ~(Constants.BlockSize - 1); maxX &= ~(Constants.BlockSize - 1); minY &= ~(Constants.BlockSize - 1); maxY &= ~(Constants.BlockSize - 1); float s = Constants.BlockSize - 1; int stepsX = (maxX - minX) / Constants.BlockSize + 1; int stepsY = (maxY - minY) / Constants.BlockSize + 1; for (int i = 0; i < stepsX * stepsY; ++i) { int sx = i % stepsX; int sy = i / stepsX; // Add 0.5 to sample at pixel centers. int x = minX + sx * Constants.BlockSize; int y = minY + sy * Constants.BlockSize; float xf = x + 0.5f; float yf = y + 0.5f; // Test if block is inside or outside triangle or touches it. EdgeData e00 = new EdgeData(); e00.init(ref eqn, xf, yf); EdgeData e01 = e00; e01.stepY(ref eqn, s); EdgeData e10 = e00; e10.stepX(ref eqn, s); EdgeData e11 = e01; e11.stepX(ref eqn, s); bool e00_0 = eqn.e0.test(e00.ev0), e00_1 = eqn.e1.test(e00.ev1), e00_2 = eqn.e2.test(e00.ev2), e00_all = e00_0 && e00_1 && e00_2; bool e01_0 = eqn.e0.test(e01.ev0), e01_1 = eqn.e1.test(e01.ev1), e01_2 = eqn.e2.test(e01.ev2), e01_all = e01_0 && e01_1 && e01_2; bool e10_0 = eqn.e0.test(e10.ev0), e10_1 = eqn.e1.test(e10.ev1), e10_2 = eqn.e2.test(e10.ev2), e10_all = e10_0 && e10_1 && e10_2; bool e11_0 = eqn.e0.test(e11.ev0), e11_1 = eqn.e1.test(e11.ev1), e11_2 = eqn.e2.test(e11.ev2), e11_all = e11_0 && e11_1 && e11_2; int result = (e00_all ? 1 : 0) + (e01_all ? 1 : 0) + (e10_all ? 1 : 0) + (e11_all ? 1 : 0); // Potentially all out. if (result == 0) { // Test for special case. bool e00Same = e00_0 == e00_1 == e00_2; bool e01Same = e01_0 == e01_1 == e01_2; bool e10Same = e10_0 == e10_1 == e10_2; bool e11Same = e11_0 == e11_1 == e11_2; if (!e00Same || !e01Same || !e10Same || !e11Same) { shader.DrawBlock(ref eqn, x, y, true); } } else if (result == 4) { // Fully Covered. shader.DrawBlock(ref eqn, x, y, false); } else { // Partially Covered. shader.DrawBlock(ref eqn, x, y, true); } } }