public void Calculate (Vector2 p, Vector2 edgeAB, PenWorkspace ws, PenAlignment alignment, bool start) { edgeAB.Normalize(); // [ eAB.X -eAB.Y ] // [ eAB.Y eAB.X ] float tC = edgeAB.X * _width; float tS = edgeAB.Y * _width; float tX = p.X; float tY = p.Y; switch (alignment) { case PenAlignment.Center: break; case PenAlignment.Inset: if (start) { tX = p.X + (-.5f * tS); tY = p.Y - (-.5f * tC); } else { tX = p.X - (-.5f * tS); tY = p.Y + (-.5f * tC); } break; case PenAlignment.Outset: if (start) { tX = p.X + (.5f * tS); tY = p.Y - (.5f * tC); } else { tX = p.X - (.5f * tS); tY = p.Y + (.5f * tC); } break; } for (int i = 0; i < _xyBuffer.Length; i++) ws.XYBuffer[i] = new Vector2(_xyBuffer[i].X * tC - _xyBuffer[i].Y * tS + tX, _xyBuffer[i].X * tS + _xyBuffer[i].Y * tC + tY); for (int i = 0; i < _uvBuffer.Length; i++) ws.UVBuffer[i] = _uvBuffer[i]; for (int i = 0; i < _indexBuffer.Length; i++) ws.IndexBuffer[i] = _indexBuffer[i]; for (int i = 0; i < _outlineBuffer.Length; i++) ws.OutlineIndexBuffer[i] = _outlineBuffer[i]; ws.XYBuffer.Index = _xyBuffer.Length; ws.UVBuffer.Index = _uvBuffer.Length; ws.IndexBuffer.Index = _indexBuffer.Length; ws.OutlineIndexBuffer.Index = _outlineBuffer.Length; }
internal void ComputeEndPoint (Vector2 a, Vector2 b, PenWorkspace ws) { EndCapInfo.Calculate(b, a - b, ws, Alignment, false); for (int i = 0; i < ws.UVBuffer.Index; i++) ws.UVBuffer[i] = new Vector2(1 - ws.UVBuffer[i].X, ws.PathLength); }
internal void ComputeStartPoint (Vector2 a, Vector2 b, PenWorkspace ws) { StartCapInfo.Calculate(a, b - a, ws, Alignment, true); }
//internal InsetOutsetCount ComputeBevel (Vector2 a, Vector2 b, Vector2 c, PenWorkspace ws) internal InsetOutsetCount ComputeBevel (ref JoinSample js, PenWorkspace ws) { Vector2 a = js.PointA; Vector2 b = js.PointB; Vector2 c = js.PointC; Vector2 edgeBA = new Vector2(a.X - b.X, a.Y - b.Y); Vector2 edgeBC = new Vector2(c.X - b.X, c.Y - b.Y); double dot = Vector2.Dot(edgeBA, edgeBC); if (dot < 0) { double den = edgeBA.LengthSquared() * edgeBC.LengthSquared(); double cos2 = (dot * dot) / den; if (cos2 > _joinLimitCos2) return ComputeMiter(ref js, ws); } Vector2 edgeAB = new Vector2(b.X - a.X, b.Y - a.Y); edgeAB.Normalize(); Vector2 edgeABt = new Vector2(-edgeAB.Y, edgeAB.X); edgeBC.Normalize(); Vector2 edgeBCt = new Vector2(-edgeBC.Y, edgeBC.X); Vector2 pointA = a; Vector2 pointC = c; short vertexCount = 0; if (Cross2D(edgeAB, edgeBC) > 0) { switch (Alignment) { case PenAlignment.Center: float w2 = Width / 2; pointA = new Vector2(a.X - w2 * edgeABt.X, a.Y - w2 * edgeABt.Y); pointC = new Vector2(c.X - w2 * edgeBCt.X, c.Y - w2 * edgeBCt.Y); ws.XYInsetBuffer[0] = new Vector2(b.X + w2 * edgeABt.X, b.Y + w2 * edgeABt.Y); ws.XYInsetBuffer[1] = new Vector2(b.X + w2 * edgeBCt.X, b.Y + w2 * edgeBCt.Y); vertexCount = 2; break; case PenAlignment.Inset: ws.XYInsetBuffer[0] = new Vector2(b.X + Width * edgeABt.X, b.Y + Width * edgeABt.Y); ws.XYInsetBuffer[1] = new Vector2(b.X + Width * edgeBCt.X, b.Y + Width * edgeBCt.Y); vertexCount = 2; break; case PenAlignment.Outset: pointA = new Vector2(a.X - Width * edgeABt.X, a.Y - Width * edgeABt.Y); pointC = new Vector2(c.X - Width * edgeBCt.X, c.Y - Width * edgeBCt.Y); ws.XYInsetBuffer[0] = b; vertexCount = 1; break; } Vector2 point5; float tdiv = Vector2.Dot(edgeBCt, edgeAB); if (Math.Abs(tdiv) < 0.0005f) { point5 = new Vector2((pointA.X + pointC.X) / 2, (pointA.Y + pointC.Y) / 2); } else { float offset35 = Vector2.Dot(edgeBCt, pointC); float t5 = (offset35 - Vector2.Dot(edgeBCt, pointA)) / tdiv; point5 = new Vector2(pointA.X + t5 * edgeAB.X, pointA.Y + t5 * edgeAB.Y); } ws.XYOutsetBuffer[0] = point5; ws.UVOutsetBuffer[0] = new Vector2(1, js.LengthB); for (int i = 0; i < vertexCount; i++) ws.UVInsetBuffer[i] = new Vector2(0, js.LengthB); return new InsetOutsetCount(vertexCount, 1, false); } else { switch (Alignment) { case PenAlignment.Center: float w2 = Width / 2; pointA = new Vector2(a.X + w2 * edgeABt.X, a.Y + w2 * edgeABt.Y); pointC = new Vector2(c.X + w2 * edgeBCt.X, c.Y + w2 * edgeBCt.Y); ws.XYOutsetBuffer[0] = new Vector2(b.X - w2 * edgeABt.X, b.Y - w2 * edgeABt.Y); ws.XYOutsetBuffer[1] = new Vector2(b.X - w2 * edgeBCt.X, b.Y - w2 * edgeBCt.Y); vertexCount = 2; break; case PenAlignment.Inset: pointA = new Vector2(a.X + Width * edgeABt.X, a.Y + Width * edgeABt.Y); pointC = new Vector2(c.X + Width * edgeBCt.X, c.Y + Width * edgeBCt.Y); ws.XYOutsetBuffer[0] = b; vertexCount = 1; break; case PenAlignment.Outset: ws.XYOutsetBuffer[0] = new Vector2(b.X - Width * edgeABt.X, b.Y - Width * edgeABt.Y); ws.XYOutsetBuffer[1] = new Vector2(b.X - Width * edgeBCt.X, b.Y - Width * edgeBCt.Y); vertexCount = 2; break; } Vector2 point0; float tdiv = Vector2.Dot(edgeBCt, edgeAB); if (Math.Abs(tdiv) < 0.0005f) { point0 = new Vector2((pointA.X + pointC.X) / 2, (pointA.Y + pointC.Y) / 2); } else { float offset01 = Vector2.Dot(edgeBCt, pointC); float t0 = (offset01 - Vector2.Dot(edgeBCt, pointA)) / tdiv; point0 = new Vector2(pointA.X + t0 * edgeAB.X, pointA.Y + t0 * edgeAB.Y); } ws.XYInsetBuffer[0] = point0; ws.UVInsetBuffer[0] = new Vector2(0, js.LengthB); for (int i = 0; i < vertexCount; i++) ws.UVOutsetBuffer[i] = new Vector2(1, js.LengthB); return new InsetOutsetCount(1, vertexCount, true); } }
//internal InsetOutsetCount ComputeMiter (Vector2 a, Vector2 b, Vector2 c, PenWorkspace ws) internal InsetOutsetCount ComputeMiter (ref JoinSample js, PenWorkspace ws) { Vector2 a = js.PointA; Vector2 b = js.PointB; Vector2 c = js.PointC; Vector2 edgeAB = new Vector2(b.X - a.X, b.Y - a.Y); edgeAB.Normalize(); Vector2 edgeABt = new Vector2(-edgeAB.Y, edgeAB.X); Vector2 edgeBC = new Vector2(c.X - b.X, c.Y - b.Y); edgeBC.Normalize(); Vector2 edgeBCt = new Vector2(-edgeBC.Y, edgeBC.X); Vector2 point1, point2, point3, point4; switch (Alignment) { case PenAlignment.Center: float w2 = Width / 2; point2 = new Vector2(a.X + w2 * edgeABt.X, a.Y + w2 * edgeABt.Y); point4 = new Vector2(a.X - w2 * edgeABt.X, a.Y - w2 * edgeABt.Y); point1 = new Vector2(c.X + w2 * edgeBCt.X, c.Y + w2 * edgeBCt.Y); point3 = new Vector2(c.X - w2 * edgeBCt.X, c.Y - w2 * edgeBCt.Y); break; case PenAlignment.Inset: point2 = new Vector2(a.X + Width * edgeABt.X, a.Y + Width * edgeABt.Y); point4 = a; point1 = new Vector2(c.X + Width * edgeBCt.X, c.Y + Width * edgeBCt.Y); point3 = c; break; case PenAlignment.Outset: point2 = a; point4 = new Vector2(a.X - Width * edgeABt.X, a.Y - Width * edgeABt.Y); point1 = c; point3 = new Vector2(c.X - Width * edgeBCt.X, c.Y - Width * edgeBCt.Y); break; default: point2 = Vector2.Zero; point4 = Vector2.Zero; point1 = Vector2.Zero; point3 = Vector2.Zero; break; } Vector2 point0, point5; float tdiv = Vector2.Dot(edgeBCt, edgeAB); if (Math.Abs(tdiv) < .0005f) { point0 = new Vector2((point2.X + point1.X) / 2, (point2.Y + point1.Y) / 2); point5 = new Vector2((point4.X + point3.X) / 2, (point4.Y + point3.Y) / 2); } else { float offset01 = Vector2.Dot(edgeBCt, point1); float t0 = (offset01 - Vector2.Dot(edgeBCt, point2)) / tdiv; float offset35 = Vector2.Dot(edgeBCt, point3); float t5 = (offset35 - Vector2.Dot(edgeBCt, point4)) / tdiv; point0 = new Vector2(point2.X + t0 * edgeAB.X, point2.Y + t0 * edgeAB.Y); point5 = new Vector2(point4.X + t5 * edgeAB.X, point4.Y + t5 * edgeAB.Y); } double miterLimit = MiterLimit * Width; if ((point0 - point5).LengthSquared() > miterLimit * miterLimit) return ComputeBevel(ref js, ws); ws.XYInsetBuffer[0] = point0; ws.XYOutsetBuffer[0] = point5; ws.UVInsetBuffer[0] = new Vector2(0, js.LengthB); ws.UVOutsetBuffer[0] = new Vector2(1, js.LengthB); return new InsetOutsetCount(1, 1); }
private void AddPath (CCVector2[] points, int offset, int count, Pen pen, PenWorkspace ws) { RequestBufferSpace(count * 2, (count - 1) * 6); _ws.ResetWorkspace(pen); AddInfo(PrimitiveType.TriangleList, count * 2, (count - 1) * 6, pen.Brush); int baseVertexIndex = _vertexBufferIndex; AddStartPoint(points[offset + 0], points[offset + 1], pen, _ws); JoinSample js = new JoinSample(CCVector2.Zero, points[offset + 0], points[offset + 1]); for (int i = 0; i < count - 2; i++) { js.Advance(points[offset + i + 2]); AddMiteredJoint(ref js, pen, ws); } AddEndPoint(points[offset + count - 2], points[offset + count - 1], pen, _ws); for (int i = 0; i < count - 1; i++) AddSegment(baseVertexIndex + i * 2, baseVertexIndex + (i + 1) * 2); }
/// <summary> /// Enables a group of figures to be drawn using the same settings. /// </summary> /// <param name="device"></param> //public DrawBatch (GraphicsDevice device) //{ public DrawBatch () : base() { //if (device == null) // throw new ArgumentNullException("device"); //_device = device; //_device.DeviceReset += GraphicsDeviceReset; _infoBuffer = new DrawingInfo[2048]; _indexBuffer = new short[32768]; //_vertexBuffer = new VertexPositionColorTexture[8192]; _computeBuffer = new CCVector2[64]; _colorBuffer = new Color[64]; _geometryBuffer = new CCVector2[256]; _pathBuilder = new PathBuilder(); //_standardEffect = new BasicEffect(device); //_standardEffect.TextureEnabled = true; //_standardEffect.VertexColorEnabled = true; //_defaultTexture = new Texture2D(device, 1, 1); //_defaultTexture.SetData<Color>(new Color[] { Microsoft.Xna.Framework.Color.White }); _ws = new PenWorkspace(); }
/// <summary> /// Immediatley renders a <see cref="DrawCache"/> object. /// </summary> /// <param name="cache">A <see cref="DrawCache"/> object.</param> /// <remarks>Any previous unflushed geometry will be rendered first.</remarks> //public void DrawCache (DrawCache cache) //{ // if (_sortMode != DrawSortMode.Immediate) // SetRenderState(); // FlushBuffer(); // cache.Render(_device, _defaultTexture); //} //private void SetRenderState () //{ // _device.BlendState = (_blendState != null) // ? _blendState : BlendState.AlphaBlend; // _device.DepthStencilState = (_depthStencilState != null) // ? _depthStencilState : DepthStencilState.None; // _device.RasterizerState = (_rasterizerState != null) // ? _rasterizerState : RasterizerState.CullCounterClockwise; // _device.SamplerStates[0] = (_samplerState != null) // ? _samplerState : SamplerState.PointWrap; // _standardEffect.Projection = Matrix.CreateOrthographicOffCenter(0, _device.Viewport.Width, _device.Viewport.Height, 0, -1, 1); // _standardEffect.World = _transform; // _standardEffect.CurrentTechnique.Passes[0].Apply(); // if (_effect != null) // _effect.CurrentTechnique.Passes[0].Apply(); //} private void AddMiteredJoint (ref JoinSample js, Pen pen, PenWorkspace ws) { InsetOutsetCount vioCount = pen.ComputeMiter(ref js, ws); AddVertex(ws.XYInsetBuffer[0], pen.ColorAt(ws.UVInsetBuffer[0], ws.PathLengthScale), pen); AddVertex(ws.XYOutsetBuffer[0], pen.ColorAt(ws.UVOutsetBuffer[0], ws.PathLengthScale), pen); }
private void AddEndPoint (CCVector2 a, CCVector2 b, Pen pen, PenWorkspace ws) { pen.ComputeEndPoint(a, b, ws); AddVertex(ws.XYBuffer[0], pen.ColorAt(ws.UVBuffer[0], ws.PathLengthScale), pen); AddVertex(ws.XYBuffer[1], pen.ColorAt(ws.UVBuffer[1], ws.PathLengthScale), pen); }
private int AddJoint (int pointIndex, InsetOutsetCount vioCount, PenWorkspace ws) { int vIndex = _vertexBufferIndex; _vertexBufferIndex += vioCount.InsetCount + vioCount.OutsetCount; if (!vioCount.CCW) { _jointCCW[pointIndex] = false; _positionData[vIndex + 0] = ws.XYOutsetBuffer[0]; for (int i = 0; i < vioCount.InsetCount; i++) _positionData[vIndex + 1 + i] = ws.XYInsetBuffer[i]; for (int i = 0; i < vioCount.InsetCount - 1; i++) { _indexData[_indexBufferIndex++] = (short)(vIndex); _indexData[_indexBufferIndex++] = (short)(vIndex + i + 2); _indexData[_indexBufferIndex++] = (short)(vIndex + i + 1); } } else { _jointCCW[pointIndex] = true; _positionData[vIndex + 0] = ws.XYInsetBuffer[0]; for (int i = 0; i < vioCount.OutsetCount; i++) _positionData[vIndex + 1 + i] = ws.XYOutsetBuffer[i]; for (int i = 0; i < vioCount.OutsetCount - 1; i++) { _indexData[_indexBufferIndex++] = (short)(vIndex); _indexData[_indexBufferIndex++] = (short)(vIndex + i + 1); _indexData[_indexBufferIndex++] = (short)(vIndex + i + 2); } } if (_colorData != null) { if (!vioCount.CCW) { _colorData[vIndex] = _pen.ColorAt(ws.UVOutsetBuffer[0], ws.PathLengthScale); for (int i = 0; i < vioCount.InsetCount; i++) _colorData[vIndex + 1 + i] = _pen.ColorAt(ws.UVInsetBuffer[i], ws.PathLengthScale); } else { _colorData[vIndex] = _pen.ColorAt(ws.UVInsetBuffer[0], ws.PathLengthScale); for (int i = 0; i < vioCount.OutsetCount; i++) _colorData[vIndex + 1 + i] = _pen.ColorAt(ws.UVOutsetBuffer[i], ws.PathLengthScale); } } if (_textureData != null) { int texWidth = _pen.Brush.Texture.Width; int texHeight = _pen.Brush.Texture.Height; for (int i = vIndex; i < _vertexBufferIndex; i++) { Vector2 pos = _positionData[i]; _textureData[i] = new Vector2(pos.X / texWidth, pos.Y / texHeight); } } return _vertexBufferIndex - vIndex; }
private int AddJoint (int pointIndex, ref JoinSample joinSample, PenWorkspace ws, Buffer<Vector2> insetBuffer, Buffer<Vector2> outsetBuffer) { InsetOutsetCount vioCount = new InsetOutsetCount(); switch (_pen.LineJoin) { case LineJoin.Miter: vioCount = _pen.ComputeMiter(ref joinSample, ws); break; case LineJoin.Bevel: vioCount = _pen.ComputeBevel(ref joinSample, ws); break; } if (insetBuffer != null) { for (int i = 0; i < vioCount.InsetCount; i++) insetBuffer.SetNext(ws.XYInsetBuffer[i]); } if (outsetBuffer != null) { for (int i = 0; i < vioCount.OutsetCount; i++) outsetBuffer.SetNext(ws.XYOutsetBuffer[i]); } return (_strokeType != StrokeType.Outline) ? AddJoint(pointIndex, vioCount, ws) : 0; }
private int AddStartOrEndPoint (int pointIndex, PenWorkspace ws, Buffer<Vector2> positionBuffer, bool ccw) { int xyCount = ws.XYBuffer.Index; if (positionBuffer != null) { for (int i = 0; i < ws.OutlineIndexBuffer.Index; i++) positionBuffer.SetNext(ws.XYBuffer[ws.OutlineIndexBuffer[i]]); } if (_strokeType == StrokeType.Outline) return 0; int baseIndex = _vertexBufferIndex; _vertexBufferIndex += xyCount; for (int i = 0; i < xyCount; i++) _positionData[baseIndex + i] = ws.XYBuffer[i]; for (int i = 0; i < ws.IndexBuffer.Index; i++) _indexData[_indexBufferIndex++] = (short)(baseIndex + ws.IndexBuffer[i]); if (_colorData != null) { for (int i = 0; i < xyCount; i++) _colorData[baseIndex + i] = _pen.ColorAt(ws.UVBuffer[i], ws.PathLengthScale); } if (_textureData != null) { int texWidth = _pen.Brush.Texture.Width; int texHeight = _pen.Brush.Texture.Height; for (int i = baseIndex; i < _vertexBufferIndex; i++) { Vector2 pos = _positionData[i]; _textureData[i] = new Vector2(pos.X / texWidth, pos.Y / texHeight); } } _jointCCW[pointIndex] = ccw; return xyCount; }
private int AddEndPoint (int pointIndex, Vector2 a, Vector2 b, PenWorkspace ws, Buffer<Vector2> positionBuffer) { _pen.ComputeEndPoint(a, b, ws); int xyCount = AddStartOrEndPoint(pointIndex, ws, positionBuffer, true); return xyCount; }
private int AddStartPoint (int pointIndex, Vector2 a, Vector2 b, PenWorkspace ws, Buffer<Vector2> positionBuffer) { _pen.ComputeStartPoint(a, b, ws); int xyCount = AddStartOrEndPoint(pointIndex, ws, positionBuffer, false); if (positionBuffer != null) Array.Reverse(positionBuffer.Data, positionBuffer.Index - ws.OutlineIndexBuffer.Index, ws.OutlineIndexBuffer.Index); return xyCount; }