private ClipMask GetClipMask(RasterizerVertex v) { ClipMask mask = 0; if (v.w - v.x < 0) { mask |= ClipMask.PosX; } if (v.x + v.w < 0) { mask |= ClipMask.NegX; } if (v.w - v.y < 0) { mask |= ClipMask.PosY; } if (v.y + v.w < 0) { mask |= ClipMask.NegY; } if (v.w - v.z < 0) { mask |= ClipMask.PosZ; } if (v.z + v.w < 0) { mask |= ClipMask.NegZ; } return(mask); }
public void init(ref RasterizerVertex v0, ref RasterizerVertex v1) { a = v0.y - v1.y; b = v1.x - v0.x; c = -(a * (v0.x + v1.x) + b * (v0.y + v1.y)) / 2; tie = a != 0 ? a > 0 : b > 0; }
public LineClipper(RasterizerVertex v0, RasterizerVertex v1) { m_v0 = v0; m_v1 = v1; t0 = 0.0f; t1 = 1.0f; fullyClipped = false; }
public unsafe void DrawTriangleSpanTemplate(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; } ref RasterizerVertex t = ref v0;
public void DrawPointList(List <RasterizerVertex> vertices, List <int> indices, int indexCount) { for (int i = 0; i < indexCount; ++i) { if (indices[i] == -1) { continue; } RasterizerVertex v = vertices[indices[i]]; DrawPoint(ref v); } }
public void DrawPointTemplate(ref RasterizerVertex v) { // Check scissor rect if (!rasterizer.ScissorTest(v.x, v.y)) { return; } PixelData p = PixelDataFromVertex(ref v); shader.DrawPixel(ref p); }
public void DrawLineList(List <RasterizerVertex> vertices, List <int> indices, int indexCount) { for (int i = 0; i + 2 <= indexCount; i += 2) { if (indices[i] == -1) { continue; } RasterizerVertex v0 = vertices[indices[i]]; RasterizerVertex v1 = vertices[indices[i + 1]]; DrawLine(ref v0, ref v1); } }
public void DrawTriangleList(List <RasterizerVertex> vertices, List <int> indices, int indexCount) { for (int i = 0; i + 3 <= indexCount; i += 3) { if (indices[i] == -1) { continue; } RasterizerVertex v0 = vertices[indices[i]]; RasterizerVertex v1 = vertices[indices[i + 1]]; RasterizerVertex v2 = vertices[indices[i + 2]]; DrawTriangle(ref v0, ref v1, ref v2); } }
// Clip the poly to the plane given by the formula a * x + b * y + c * z + d * w. public void ClipToPlane(float a, float b, float c, float d) { if (IsFullyClipped()) { return; } m_indicesOut.Clear(); int idxPrev = m_indicesIn[0]; m_indicesIn.Add(idxPrev); RasterizerVertex vPrev = m_vertices[idxPrev]; float dpPrev = a * vPrev.x + b * vPrev.y + c * vPrev.z + d * vPrev.w; for (int i = 1; i < m_indicesIn.Count; ++i) { int idx = m_indicesIn[i]; RasterizerVertex v = m_vertices[idx]; float dp = a * v.x + b * v.y + c * v.z + d * v.w; if (dpPrev >= 0) { m_indicesOut.Add(idxPrev); } if (Math.Sign(dp) != Math.Sign(dpPrev)) { float t = dp < 0 ? dpPrev / (dpPrev - dp) : -dpPrev / (dp - dpPrev); RasterizerVertex vOut = Helper.InterpolateVertex(m_vertices[idxPrev], m_vertices[idx], t, m_avarCount, m_pvarCount); m_vertices.Add(vOut); m_indicesOut.Add(m_vertices.Count - 1); } idxPrev = idx; dpPrev = dp; } var temp = m_indicesIn; m_indicesIn = m_indicesOut; m_indicesOut = temp; }
public unsafe void StepVertex(ref RasterizerVertex v, ref RasterizerVertex step) { v.x += step.x; v.y += step.y; if (shader.InterpolateZ) { v.z += step.z; } if (shader.InterpolateW) { v.w += step.w; } for (int i = 0; i < shader.AVarCount; ++i) { v.avar[i] += step.avar[i]; } for (int i = 0; i < shader.PVarCount; ++i) { v.pvar[i] += step.pvar[i]; } }
/// Draw a number of points, lines or triangles. public void DrawElements(DrawMode mode, int count, List <int> indices) { m_verticesOut.Clear(); m_indicesOut.Clear(); // TODO: Max 1024 primitives per batch. m_vCache.clear(); for (int i = 0; i < count; i++) { int index = indices[i]; int outputIndex = m_vCache.lookup(index); if (outputIndex != -1) { m_indicesOut.Add(outputIndex); } else { RasterizerVertex vOut = new RasterizerVertex(); ProcessVertex(index, ref vOut); outputIndex = m_verticesOut.Count; m_indicesOut.Add(outputIndex); m_verticesOut.Add(vOut); m_vCache.set(index, outputIndex); } if (PrimitiveCount(mode) >= 1024) { ProcessPrimitives(mode); m_verticesOut.Clear(); m_indicesOut.Clear(); m_vCache.clear(); } } ProcessPrimitives(mode); }
public void DrawLineTemplate(ref RasterizerVertex v0, ref RasterizerVertex v1) { int adx = Math.Abs((int)v1.x - (int)v0.x); int ady = Math.Abs((int)v1.y - (int)v0.y); int steps = Math.Max(adx, ady); RasterizerVertex step = ComputeVertexStep(ref v0, ref v1, steps); RasterizerVertex v = v0; while (steps-- > 0) { PixelData p = PixelDataFromVertex(ref v); if (rasterizer.ScissorTest(v.x, v.y)) { shader.DrawPixel(ref p); } StepVertex(ref v, ref step); } }
private void TransformVertices() { m_alreadyProcessed.Clear(); for (int i = 0; i < m_verticesOut.Count; i++) { m_alreadyProcessed.Add(false); } for (int i = 0; i < m_indicesOut.Count; i++) { int index = m_indicesOut[i]; if (index == -1) { continue; } if (m_alreadyProcessed[index]) { continue; } RasterizerVertex vOut = m_verticesOut[index]; // Perspective divide float invW = 1.0f / vOut.w; vOut.x *= invW; vOut.y *= invW; vOut.z *= invW; // Viewport transform vOut.x = (m_viewport.px * vOut.x + m_viewport.ox); vOut.y = (m_viewport.py * -vOut.y + m_viewport.oy); vOut.z = 0.5f * (m_depthRange.f - m_depthRange.n) * vOut.z + 0.5f * (m_depthRange.n + m_depthRange.f); m_verticesOut[index] = vOut; m_alreadyProcessed[index] = true; } }
private void CullTriangles() { for (int i = 0; i + 3 <= m_indicesOut.Count; i += 3) { if (m_indicesOut[i] == -1) { continue; } RasterizerVertex v0 = m_verticesOut[m_indicesOut[i]]; RasterizerVertex v1 = m_verticesOut[m_indicesOut[i + 1]]; RasterizerVertex v2 = m_verticesOut[m_indicesOut[i + 2]]; float facing = (v0.x - v1.x) * (v2.y - v1.y) - (v2.x - v1.x) * (v0.y - v1.y); if (facing < 0) { if (m_cullMode == CullMode.CW) { m_indicesOut[i] = m_indicesOut[i + 1] = m_indicesOut[i + 2] = -1; } } else { if (m_cullMode == CullMode.CCW) { m_indicesOut[i] = m_indicesOut[i + 1] = m_indicesOut[i + 2] = -1; } else { int temp = m_indicesOut[i]; m_indicesOut[i] = m_indicesOut[i + 2]; m_indicesOut[i + 2] = temp; } } } }
public unsafe PixelData PixelDataFromVertex(ref RasterizerVertex v) { PixelData p = new PixelData(); p.x = (int)v.x; p.y = (int)v.y; if (shader.InterpolateZ) { p.z = v.z; } if (shader.InterpolateW) { p.w = v.w; p.invw = 1.0f / v.w; } for (int i = 0; i < shader.AVarCount; ++i) { p.avar[i] = v.avar[i]; } for (int i = 0; i < shader.PVarCount; ++i) { p.pvar[i] = v.pvar[i]; } return(p); }
public unsafe RasterizerVertex ComputeVertexStep(ref RasterizerVertex v0, ref RasterizerVertex v1, int adx) { RasterizerVertex step = new RasterizerVertex(); step.x = (v1.x - v0.x) / adx; step.y = (v1.y - v0.y) / adx; if (shader.InterpolateZ) { step.z = (v1.z - v0.z) / adx; } if (shader.InterpolateW) { step.w = (v1.w - v0.w) / adx; } for (int i = 0; i < shader.AVarCount; ++i) { step.avar[i] = (v1.avar[i] - v0.avar[i]) / adx; } for (int i = 0; i < shader.PVarCount; ++i) { step.pvar[i] = (v1.pvar[i] - v0.pvar[i]) / adx; } return(step); }
/// Draw a single line. public void DrawLine(ref RasterizerVertex v0, ref RasterizerVertex v1) { m_lineFunc(ref v0, ref v1); }
private void ClipLines() { m_clipMask.Clear(); for (int i = 0; i < m_verticesOut.Count; i++) { m_clipMask.Add(0); } for (int i = 0; i < m_verticesOut.Count; i++) { m_clipMask[i] = GetClipMask(m_verticesOut[i]); } for (int i = 0; i < m_indicesOut.Count; i += 2) { int index0 = m_indicesOut[i]; int index1 = m_indicesOut[i + 1]; RasterizerVertex v0 = m_verticesOut[index0]; RasterizerVertex v1 = m_verticesOut[index1]; ClipMask clipMask = m_clipMask[index0] | m_clipMask[index1]; LineClipper lineClipper = new LineClipper(v0, v1); if ((clipMask & ClipMask.PosX) == ClipMask.PosX) { lineClipper.clipToPlane(-1, 0, 0, 1); } if ((clipMask & ClipMask.NegX) == ClipMask.NegX) { lineClipper.clipToPlane(1, 0, 0, 1); } if ((clipMask & ClipMask.PosY) == ClipMask.PosY) { lineClipper.clipToPlane(0, -1, 0, 1); } if ((clipMask & ClipMask.NegY) == ClipMask.NegY) { lineClipper.clipToPlane(0, 1, 0, 1); } if ((clipMask & ClipMask.PosZ) == ClipMask.PosZ) { lineClipper.clipToPlane(0, 0, -1, 1); } if ((clipMask & ClipMask.NegZ) == ClipMask.NegZ) { lineClipper.clipToPlane(0, 0, 1, 1); } if (lineClipper.fullyClipped) { m_indicesOut[i] = -1; m_indicesOut[i + 1] = -1; continue; } if (m_clipMask[index0] > 0) { RasterizerVertex newV = Helper.InterpolateVertex(v0, v1, lineClipper.t0, m_shader.AVarCount, m_shader.PVarCount); m_verticesOut.Add(newV); m_indicesOut[i] = m_verticesOut.Count - 1; } if (m_clipMask[index1] > 0) { RasterizerVertex newV = Helper.InterpolateVertex(v0, v1, lineClipper.t1, m_shader.AVarCount, m_shader.PVarCount); m_verticesOut.Add(newV); m_indicesOut[i + 1] = m_verticesOut.Count - 1; } } }
private void ProcessVertex(int index, ref RasterizerVertex output) { m_shader.ProcessVertex(index, ref output); }
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); } } }
/// Draw a single point. public void DrawPoint(ref RasterizerVertex v) { m_pointFunc(ref v); }
/// Draw a single triangle. public void DrawTriangle(ref RasterizerVertex v0, ref RasterizerVertex v1, ref RasterizerVertex v2) { m_triangleFunc(ref v0, ref v1, ref v2); }
public void ProcessVertex(int index, ref RasterizerVertex output) { }