private void RenderSinglePass(Rect viewportRect, Pass p) { this.drawDevice.VisibilityMask = this.visibilityMask & p.VisibilityMask; this.drawDevice.RenderMode = p.MatrixMode; this.drawDevice.Target = p.Output; this.drawDevice.ViewportRect = p.Output.IsAvailable ? new Rect(p.Output.Res.Width, p.Output.Res.Height) : viewportRect; if (p.Input == null) { // Render Scene this.drawDevice.PrepareForDrawcalls(); try { this.CollectDrawcalls(); p.NotifyCollectDrawcalls(this.drawDevice); } catch (Exception e) { Log.Core.WriteError("There was an error while {0} was collecting drawcalls: {1}", this.ToString(), Log.Exception(e)); } this.drawDevice.Render(p.ClearFlags, p.ClearColor, p.ClearDepth); } else { Profile.TimePostProcessing.BeginMeasure(); this.drawDevice.PrepareForDrawcalls(); Texture mainTex = p.Input.MainTexture.Res; Vector2 uvRatio = mainTex != null ? mainTex.UVRatio : Vector2.One; Vector2 inputSize = mainTex != null ? new Vector2(mainTex.PixelWidth, mainTex.PixelHeight) : Vector2.One; Rect targetRect; if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor && !this.drawDevice.Target.IsAvailable) { targetRect = Rect.Align(Alignment.Center, this.drawDevice.TargetSize.X * 0.5f, this.drawDevice.TargetSize.Y * 0.5f, inputSize.X, inputSize.Y); } else { targetRect = new Rect(this.drawDevice.TargetSize); } IDrawDevice device = this.drawDevice; { VertexC1P3T2[] vertices = new VertexC1P3T2[4]; vertices[0].Pos = new Vector3(targetRect.LeftX, targetRect.TopY, 0.0f); vertices[1].Pos = new Vector3(targetRect.RightX, targetRect.TopY, 0.0f); vertices[2].Pos = new Vector3(targetRect.RightX, targetRect.BottomY, 0.0f); vertices[3].Pos = new Vector3(targetRect.LeftX, targetRect.BottomY, 0.0f); vertices[0].TexCoord = new Vector2(0.0f, 0.0f); vertices[1].TexCoord = new Vector2(uvRatio.X, 0.0f); vertices[2].TexCoord = new Vector2(uvRatio.X, uvRatio.Y); vertices[3].TexCoord = new Vector2(0.0f, uvRatio.Y); device.AddVertices(p.Input, VertexMode.Quads, vertices); } this.drawDevice.Render(p.ClearFlags, p.ClearColor, p.ClearDepth); Profile.TimePostProcessing.EndMeasure(); } }
/// <summary> /// Emits a set of vertices based on a text. To render this text, simply use that set of vertices combined with /// the Fonts <see cref="Material"/>. /// </summary> /// <param name="text">The text to render.</param> /// <param name="vertices">The set of vertices that is emitted. You can re-use the same array each frame.</param> /// <returns>The number of emitted vertices. This values isn't necessarily equal to the emitted arrays length.</returns> public int EmitTextVertices(string text, ref VertexC1P3T2[] vertices) { int len = text.Length * 4; if (vertices == null || vertices.Length < len) { vertices = new VertexC1P3T2[len]; } if (this.texture == null) { return(len); } float curOffset = 0.0f; GlyphData glyphData; Rect uvRect; float glyphXOff; float glyphYOff; float glyphXAdv; for (int i = 0; i < text.Length; i++) { this.ProcessTextAdv(text, i, out glyphData, out uvRect, out glyphXAdv, out glyphXOff, out glyphYOff); Vector2 glyphPos; glyphPos.X = MathF.Round(curOffset + glyphXOff); glyphPos.Y = MathF.Round(0 + glyphYOff); vertices[i * 4 + 0].Pos.X = glyphPos.X; vertices[i * 4 + 0].Pos.Y = glyphPos.Y; vertices[i * 4 + 0].Pos.Z = 0.0f; vertices[i * 4 + 0].TexCoord = uvRect.TopLeft; vertices[i * 4 + 0].Color = ColorRgba.White; vertices[i * 4 + 1].Pos.X = glyphPos.X + glyphData.Width; vertices[i * 4 + 1].Pos.Y = glyphPos.Y; vertices[i * 4 + 1].Pos.Z = 0.0f; vertices[i * 4 + 1].TexCoord = uvRect.TopRight; vertices[i * 4 + 1].Color = ColorRgba.White; vertices[i * 4 + 2].Pos.X = glyphPos.X + glyphData.Width; vertices[i * 4 + 2].Pos.Y = glyphPos.Y + glyphData.Height; vertices[i * 4 + 2].Pos.Z = 0.0f; vertices[i * 4 + 2].TexCoord = uvRect.BottomRight; vertices[i * 4 + 2].Color = ColorRgba.White; vertices[i * 4 + 3].Pos.X = glyphPos.X; vertices[i * 4 + 3].Pos.Y = glyphPos.Y + glyphData.Height; vertices[i * 4 + 3].Pos.Z = 0.0f; vertices[i * 4 + 3].TexCoord = uvRect.BottomLeft; vertices[i * 4 + 3].Color = ColorRgba.White; curOffset += glyphXAdv; } return(len); }
public void RenderTexturedBackground(IDrawDevice device, ref TileMapLayer layer, int cacheIndex, float x, float y) { if (!cachedTexturedBackground.IsAvailable || cachedTexturedBackgroundAnimated) { RecreateTexturedBackground(ref layer); } // Fit the input material rect to the output size according to rendering step config Vector3 renderPos = new Vector3(device.ViewerPos.X - device.TargetSize.X / 2, device.ViewerPos.Y - device.TargetSize.Y / 2, layer.Depth); // Fit the target rect to actual pixel coordinates to avoid unnecessary filtering offsets renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { // AMD Bugfix? renderPos.Y -= 0.004f; } // Reserve the required space for vertex data in our locally cached buffer int neededVertices = 4; if (cachedVertices == null || cachedVertices.Length < neededVertices) { cachedVertices = new VertexC1P3T2[neededVertices]; } // Render it as world-space fullscreen quad cachedVertices[0].Pos = new Vector3(renderPos.X, renderPos.Y, renderPos.Z); cachedVertices[1].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y, renderPos.Z); cachedVertices[2].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); cachedVertices[3].Pos = new Vector3(renderPos.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); cachedVertices[0].TexCoord = new Vector2(0f, 0f); cachedVertices[1].TexCoord = new Vector2(1f, 0f); cachedVertices[2].TexCoord = new Vector2(1f, 1f); cachedVertices[3].TexCoord = new Vector2(0f, 1f); cachedVertices[0].Color = cachedVertices[1].Color = cachedVertices[2].Color = cachedVertices[3].Color = ColorRgba.White; // Setup custom pixel shader BatchInfo material = device.RentMaterial(); material.Technique = texturedBackgroundShader; material.MainTexture = cachedTexturedBackground; material.SetValue("horizonColor", layer.BackgroundColor); material.SetValue("shift", new Vector2(x, y)); material.SetValue("parallaxStarsEnabled", layer.ParallaxStarsEnabled ? 1f : 0f); device.AddVertices(material, VertexMode.Quads, cachedVertices, 0, 4); }
public StaticVertex(VertexC1P3T2 vtx) { x = vtx.Pos.X; y = vtx.Pos.Y; z = vtx.Pos.Z; w = vtx.DepthOffset; u = vtx.TexCoord.X; v = vtx.TexCoord.Y; r = vtx.Color.R; g = vtx.Color.G; b = vtx.Color.B; a = vtx.Color.A; }
private void PrepareVineVertices(ref VertexC1P3T2[] vertices, IDrawDevice device, ColorRgba mainClr, Rect uvRect) { if (vertices == null /*|| vertices.Length != 4*/) { vertices = new VertexC1P3T2[(ChunkPositions.Length - 1) * 4]; } Vector3 posTemp = this.gameobj.Transform.Pos; float uvStep = (uvRect.H / ChunkPositions.Length); int vertexOffset = 0; for (int i = 1; i < ChunkPositions.Length; i++) { ref Vector2 source = ref ChunkPositions[i - 1]; ref Vector2 target = ref ChunkPositions[i];
public Widget() { VisibilityGroup = VisibilityFlag.Group0; _areaOnScreen = new Polygon(4); _activeAreaOnScreen = new Polygon(4); _tempActiveAreaOnScreen = new Vector3[4]; _rect = new Duality.Rect(0, 0, 50, 50); _visibleRect = Rect.Empty; _vertices = new VertexC1P3T2[36]; _points = new MultiSpacePoint[16]; for (int i = 0; i < _vertices.Length; i++) { _vertices[i] = new VertexC1P3T2(); } }
public void RenderTexturedBackground(IDrawDevice device, ref TileMapLayer layer, int cacheIndex, float x, float y) { if (cachedTexturedBackground == null || cachedTexturedBackgroundAnimated) { RecreateTexturedBackground(ref layer); } // Fit the input material rect to the output size according to rendering step config Vector3 renderPos = new Vector3(device.RefCoord.X - device.TargetSize.X / 2, device.RefCoord.Y - device.TargetSize.Y / 2, layer.Depth); float scale = 1.0f; device.PreprocessCoords(ref renderPos, ref scale); // Fit the target rect to actual pixel coordinates to avoid unnecessary filtering offsets renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { //renderPos.Y += 0.5f; // AMD Bugfix? renderPos.Y -= 0.001f; } // Reserve the required space for vertex data in our locally cached buffer VertexC1P3T2[] vertexData; int neededVertices = 4; if (cachedVertices[cacheIndex] == null || cachedVertices[cacheIndex].Length < neededVertices) { cachedVertices[cacheIndex] = vertexData = new VertexC1P3T2[neededVertices]; } else { vertexData = cachedVertices[cacheIndex]; } // Render it as world-space fullscreen quad vertexData[0].Pos = new Vector3(renderPos.X, renderPos.Y, renderPos.Z); vertexData[1].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y, renderPos.Z); vertexData[2].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); vertexData[3].Pos = new Vector3(renderPos.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); vertexData[0].TexCoord = new Vector2(0.0f, 0.0f); vertexData[1].TexCoord = new Vector2(1f, 0.0f); vertexData[2].TexCoord = new Vector2(1f, 1f); vertexData[3].TexCoord = new Vector2(0.0f, 1f); vertexData[0].Color = vertexData[1].Color = vertexData[2].Color = vertexData[3].Color = ColorRgba.White; // Setup custom pixel shader BatchInfo material = new BatchInfo(texturedBackgroundShader, cachedTexturedBackground); material.SetValue("horizonColor", layer.BackgroundColor); material.SetValue("shift", new Vector2(x, y)); device.AddVertices(material, VertexMode.Quads, vertexData); }
protected void PrepareVertices(ref VertexC1P3T2[] vertices, IDrawDevice device) { Texture mainTex = this.RetrieveMainTexture(); ColorRgba mainClr = this.RetrieveMainColor(); // Determine texture sprite rect Rect blockSpriteRect; if (mainTex != null) blockSpriteRect = Rect.AlignTopLeft(0, 0, mainTex.PxWidth, mainTex.PxHeight); else blockSpriteRect = Rect.AlignTopLeft(0, 0, 1, 1); // Determine block rects to draw Collider col = this.GameObj.GetComponent<Collider>(); var blockShapes = col.Shapes.OfType<Collider.PolyShapeInfo>(); var blockRects = blockShapes.Select(p => p.AABB).ToArray(); Vector3 posTemp = this.GameObj.Transform.Pos; float scaleTemp = 1.0f; device.PreprocessCoords(this, ref posTemp, ref scaleTemp); Vector2 xDot, yDot; MathF.GetTransformDotVec(this.GameObj.Transform.Angle, scaleTemp, out xDot, out yDot); if (vertices == null || vertices.Length != blockRects.Length * 4) vertices = new VertexC1P3T2[blockRects.Length * 4]; for (int i = 0; i < blockRects.Length; i++) { Rect blockRect = blockRects[i]; Rect uvRect = new Rect( (blockRect.x - blockSpriteRect.x) / blockSpriteRect.w, (blockRect.y - blockSpriteRect.y) / blockSpriteRect.h, blockRect.w / blockSpriteRect.w, blockRect.h / blockSpriteRect.h); Rect rectTemp = blockRect.Transform(this.GameObj.Transform.Scale.Xy); Vector2 edge1 = rectTemp.TopLeft; Vector2 edge2 = rectTemp.BottomLeft; Vector2 edge3 = rectTemp.BottomRight; Vector2 edge4 = rectTemp.TopRight; MathF.TransformDotVec(ref edge1, ref xDot, ref yDot); MathF.TransformDotVec(ref edge2, ref xDot, ref yDot); MathF.TransformDotVec(ref edge3, ref xDot, ref yDot); MathF.TransformDotVec(ref edge4, ref xDot, ref yDot); vertices[i * 4 + 0].pos.X = posTemp.X + edge1.X; vertices[i * 4 + 0].pos.Y = posTemp.Y + edge1.Y; vertices[i * 4 + 0].pos.Z = posTemp.Z; vertices[i * 4 + 0].texCoord.X = uvRect.x; vertices[i * 4 + 0].texCoord.Y = uvRect.y; vertices[i * 4 + 0].clr = mainClr; vertices[i * 4 + 1].pos.X = posTemp.X + edge2.X; vertices[i * 4 + 1].pos.Y = posTemp.Y + edge2.Y; vertices[i * 4 + 1].pos.Z = posTemp.Z; vertices[i * 4 + 1].texCoord.X = uvRect.x; vertices[i * 4 + 1].texCoord.Y = uvRect.MaxY; vertices[i * 4 + 1].clr = mainClr; vertices[i * 4 + 2].pos.X = posTemp.X + edge3.X; vertices[i * 4 + 2].pos.Y = posTemp.Y + edge3.Y; vertices[i * 4 + 2].pos.Z = posTemp.Z; vertices[i * 4 + 2].texCoord.X = uvRect.MaxX; vertices[i * 4 + 2].texCoord.Y = uvRect.MaxY; vertices[i * 4 + 2].clr = mainClr; vertices[i * 4 + 3].pos.X = posTemp.X + edge4.X; vertices[i * 4 + 3].pos.Y = posTemp.Y + edge4.Y; vertices[i * 4 + 3].pos.Z = posTemp.Z; vertices[i * 4 + 3].texCoord.X = uvRect.MaxX; vertices[i * 4 + 3].texCoord.Y = uvRect.y; vertices[i * 4 + 3].clr = mainClr; } }
private void RecreateTexturedBackground(ref TileMapLayer layer) { int w = layer.LayoutWidth; int h = layer.Layout.Length / w; cachedTexturedBackgroundAnimated = false; Texture renderTarget; if (cachedTexturedBackground != null) { renderTarget = cachedTexturedBackground.Res; } else { renderTarget = new Texture(w * 32, h * 32, TextureSizeMode.NonPowerOfTwo, TextureMagFilter.Linear, TextureMinFilter.Linear, TextureWrapMode.Repeat, TextureWrapMode.Repeat); switch (layer.BackgroundStyle) { case BackgroundStyle.Sky: default: texturedBackgroundShader = ContentResolver.Current.RequestShader("TexturedBackground"); break; case BackgroundStyle.Circle: texturedBackgroundShader = ContentResolver.Current.RequestShader("TexturedBackgroundCircle"); break; } } using (DrawDevice device = new DrawDevice()) { device.VisibilityMask = VisibilityFlag.AllFlags; device.RenderMode = RenderMatrix.ScreenSpace; device.Target = new RenderTarget(AAQuality.Off, false, renderTarget); device.TargetSize = new Vector2(w * 32, h * 32); device.ViewportRect = new Rect(device.TargetSize); device.PrepareForDrawcalls(); Material material = null; Texture texture = null; // Reserve the required space for vertex data in our locally cached buffer int neededVertices = 4 * w * h; VertexC1P3T2[] vertexData = new VertexC1P3T2[neededVertices]; int vertexBaseIndex = 0; for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { LayerTile tile = layer.Layout[x + y * layer.LayoutWidth]; Point2 offset; bool isFlippedX, isFlippedY; if (tile.IsAnimated) { if (tile.TileID < animatedTiles.Count) { offset = animatedTiles[tile.TileID].CurrentTile.MaterialOffset; isFlippedX = (animatedTiles[tile.TileID].CurrentTile.IsFlippedX != tile.IsFlippedX); isFlippedY = (animatedTiles[tile.TileID].CurrentTile.IsFlippedY != tile.IsFlippedY); cachedTexturedBackgroundAnimated = true; } else { continue; } } else { offset = tile.MaterialOffset; isFlippedX = tile.IsFlippedX; isFlippedY = tile.IsFlippedY; } if (material != tile.Material) { // Submit all the vertices as one draw batch device.AddVertices( material, VertexMode.Quads, vertexData, 0, vertexBaseIndex); vertexBaseIndex = 0; material = tile.Material.Res; texture = material.MainTexture.Res; } Rect uvRect = new Rect( offset.X * texture.UVRatio.X / texture.ContentWidth, offset.Y * texture.UVRatio.Y / texture.ContentHeight, tileset.TileSize * texture.UVRatio.X / texture.ContentWidth, tileset.TileSize * texture.UVRatio.Y / texture.ContentHeight ); if (isFlippedX) { uvRect.X += uvRect.W; uvRect.W *= -1; } if (isFlippedY) { uvRect.Y += uvRect.H; uvRect.H *= -1; } Vector3 renderPos = new Vector3(x * 32, y * 32, 0); float scale = 1.0f; device.PreprocessCoords(ref renderPos, ref scale); renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { renderPos.Y += 0.5f; } Vector2 tileXStep = new Vector2(32, 0); Vector2 tileYStep = new Vector2(0, 32); vertexData[vertexBaseIndex + 0].Pos.X = renderPos.X; vertexData[vertexBaseIndex + 0].Pos.Y = renderPos.Y; vertexData[vertexBaseIndex + 0].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 0].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 0].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 0].Color = ColorRgba.White; vertexData[vertexBaseIndex + 1].Pos.X = renderPos.X + tileYStep.X; vertexData[vertexBaseIndex + 1].Pos.Y = renderPos.Y + tileYStep.Y; vertexData[vertexBaseIndex + 1].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 1].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 1].TexCoord.Y = uvRect.Y + uvRect.H; vertexData[vertexBaseIndex + 1].Color = ColorRgba.White; vertexData[vertexBaseIndex + 2].Pos.X = renderPos.X + tileXStep.X + tileYStep.X; vertexData[vertexBaseIndex + 2].Pos.Y = renderPos.Y + tileXStep.Y + tileYStep.Y; vertexData[vertexBaseIndex + 2].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 2].TexCoord.X = uvRect.X + uvRect.W; vertexData[vertexBaseIndex + 2].TexCoord.Y = uvRect.Y + uvRect.H; vertexData[vertexBaseIndex + 2].Color = ColorRgba.White; vertexData[vertexBaseIndex + 3].Pos.X = renderPos.X + tileXStep.X; vertexData[vertexBaseIndex + 3].Pos.Y = renderPos.Y + tileXStep.Y; vertexData[vertexBaseIndex + 3].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 3].TexCoord.X = uvRect.X + uvRect.W; vertexData[vertexBaseIndex + 3].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 3].Color = ColorRgba.White; vertexBaseIndex += 4; } } device.AddVertices( material, VertexMode.Quads, vertexData, 0, vertexBaseIndex); device.Render(); } cachedTexturedBackground = renderTarget; }
/// <summary> /// Emits a set of vertices based on a text. To render this text, simply use that set of vertices combined with /// the Fonts <see cref="Material"/>. /// </summary> /// <param name="text">The text to render.</param> /// <param name="vertices">The set of vertices that is emitted. You can re-use the same array each frame.</param> /// <returns>The number of emitted vertices. This values isn't necessarily equal to the emitted arrays length.</returns> public int EmitTextVertices(string text, ref VertexC1P3T2[] vertices) { int len = text.Length * 4; if (vertices == null || vertices.Length < len) vertices = new VertexC1P3T2[len]; float curOffset = 0.0f; GlyphData glyphData; Rect uvRect; float glyphXOff; float glyphXAdv; for (int i = 0; i < text.Length; i++) { this.ProcessTextAdv(text, i, out glyphData, out uvRect, out glyphXAdv, out glyphXOff); Vector2 glyphPos; glyphPos.X = MathF.Round(curOffset + glyphXOff); glyphPos.Y = MathF.Round(0.0f); vertices[i * 4 + 0].Pos.X = glyphPos.X; vertices[i * 4 + 0].Pos.Y = glyphPos.Y; vertices[i * 4 + 0].Pos.Z = 0.0f; vertices[i * 4 + 0].TexCoord = uvRect.TopLeft; vertices[i * 4 + 0].Color = ColorRgba.White; vertices[i * 4 + 1].Pos.X = glyphPos.X + glyphData.width; vertices[i * 4 + 1].Pos.Y = glyphPos.Y; vertices[i * 4 + 1].Pos.Z = 0.0f; vertices[i * 4 + 1].TexCoord = uvRect.TopRight; vertices[i * 4 + 1].Color = ColorRgba.White; vertices[i * 4 + 2].Pos.X = glyphPos.X + glyphData.width; vertices[i * 4 + 2].Pos.Y = glyphPos.Y + glyphData.height; vertices[i * 4 + 2].Pos.Z = 0.0f; vertices[i * 4 + 2].TexCoord = uvRect.BottomRight; vertices[i * 4 + 2].Color = ColorRgba.White; vertices[i * 4 + 3].Pos.X = glyphPos.X; vertices[i * 4 + 3].Pos.Y = glyphPos.Y + glyphData.height; vertices[i * 4 + 3].Pos.Z = 0.0f; vertices[i * 4 + 3].TexCoord = uvRect.BottomLeft; vertices[i * 4 + 3].Color = ColorRgba.White; curOffset += glyphXAdv; } return len; }
/// <summary> /// Emits a set of vertices based on a text. To render this text, simply use that set of vertices combined with /// the Fonts <see cref="Material"/>. /// </summary> /// <param name="text">The text to render.</param> /// <param name="vertices">The set of vertices that is emitted. You can re-use the same array each frame.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="z">An Z-Offset applied to the position of each emitted vertex.</param> /// <param name="clr">The color value that is applied to each emitted vertex.</param> /// <param name="angle">An angle by which the text is rotated (before applying the offset).</param> /// <param name="scale">A factor by which the text is scaled (before applying the offset).</param> public void EmitTextVertices(string text, ref VertexC1P3T2[] vertices, float x, float y, float z, ColorRgba clr, float angle = 0.0f, float scale = 1.0f) { this.EmitTextVertices(text, ref vertices); Vector3 offset = new Vector3(x, y, z); Vector2 xDot, yDot; MathF.GetTransformDotVec(angle, scale, out xDot, out yDot); for (int i = 0; i < vertices.Length; i++) { Vector3 vertex = vertices[i].Pos; MathF.TransformDotVec(ref vertex, ref xDot, ref yDot); vertex += offset; vertices[i].Pos = vertex; vertices[i].Color = clr; } }
private void DrawLayer(IDrawDevice device, ref TileMapLayer layer, int cacheIndex) { if (!layer.Visible) { return; } Vector2 viewSize = device.TargetSize; Vector3 viewCenter = device.RefCoord; Point2 tileCount = new Point2(layer.LayoutWidth, layer.Layout.Length / layer.LayoutWidth); Vector2 tileSize = new Vector2(tileset.TileSize, tileset.TileSize); // Update offsets for moving layers if (MathF.Abs(layer.AutoSpeedX) > 0) { layer.OffsetX += layer.AutoSpeedX * Time.TimeMult; if (layer.RepeatX) { if (layer.AutoSpeedX > 0) { while (layer.OffsetX > (tileCount.X * 32)) { layer.OffsetX -= (tileCount.X * 32); } } else { while (layer.OffsetX < 0) { layer.OffsetX += (tileCount.X * 32); } } } } if (MathF.Abs(layer.AutoSpeedY) > 0) { layer.OffsetY += layer.AutoSpeedY * Time.TimeMult; if (layer.RepeatY) { if (layer.AutoSpeedY > 0) { while (layer.OffsetY > (tileCount.Y * 32)) { layer.OffsetY -= (tileCount.Y * 32); } } else { while (layer.OffsetY < 0) { layer.OffsetY += (tileCount.Y * 32); } } } } // Get current layer offsets and speeds float loX = layer.OffsetX; float loY = layer.OffsetY - (layer.UseInherentOffset ? (viewSize.Y - 200) / 2 : 0); // Find out coordinates for a tile from outside the boundaries from topleft corner of the screen float x1 = viewCenter.X - 70 - (viewSize.X * 0.5f); float y1 = viewCenter.Y - 70 - (viewSize.Y * 0.5f); if (layer.BackgroundStyle != BackgroundStyle.Plain && tileCount.Y == 8 && tileCount.X == 8) { const float PerspectiveSpeedX = 0.4f; const float PerspectiveSpeedY = 0.16f; RenderTexturedBackground(device, ref layer, cacheIndex, (x1 * PerspectiveSpeedX + loX), (y1 * PerspectiveSpeedY + loY)); } else { // Figure out the floating point offset from the calculated coordinates and the actual tile // corner coordinates float xt = TranslateCoordinate(x1, layer.SpeedX, loX, false, viewSize.Y, viewSize.X); float yt = TranslateCoordinate(y1, layer.SpeedY, loY, true, viewSize.Y, viewSize.X); float remX = xt % 32f; float remY = yt % 32f; // Calculate the index (on the layer map) of the first tile that needs to be drawn to the // position determined earlier int tileX, tileY, tileAbsX, tileAbsY; // Get the actual tile coords on the layer layout if (xt > 0) { tileAbsX = (int)Math.Floor(xt / 32f); tileX = tileAbsX % tileCount.X; } else { tileAbsX = (int)Math.Ceiling(xt / 32f); tileX = tileAbsX % tileCount.X; while (tileX < 0) { tileX += tileCount.X; } } if (yt > 0) { tileAbsY = (int)Math.Floor(yt / 32f); tileY = tileAbsY % tileCount.Y; } else { tileAbsY = (int)Math.Ceiling(yt / 32f); tileY = tileAbsY % tileCount.Y; while (tileY < 0) { tileY += tileCount.Y; } } // update x1 and y1 with the remainder so that we start at the tile boundary // minus 1 because indices are updated in the beginning of the loops x1 -= remX - 32f; y1 -= remY - 32f; // Save the tile Y at the left border so that we can roll back to it at the start of // every row iteration int tileYs = tileY; // Calculate the last coordinates we want to draw to float x3 = x1 + 100 + viewSize.X; float y3 = y1 + 100 + viewSize.Y; Material material = null; Texture texture = null; ColorRgba mainColor = ColorRgba.White; // Reserve the required space for vertex data in our locally cached buffer VertexC1P3T2[] vertexData; int neededVertices = (int)((((x3 - x1) / 32) + 1) * (((y3 - y1) / 32) + 1) * 4); if (cachedVertices[cacheIndex] == null || cachedVertices[cacheIndex].Length < neededVertices) { cachedVertices[cacheIndex] = vertexData = new VertexC1P3T2[neededVertices]; } else { vertexData = cachedVertices[cacheIndex]; } int vertexBaseIndex = 0; int tile_xo = -1; for (float x2 = x1; x2 < x3; x2 += 32) { tileX = (tileX + 1) % tileCount.X; tile_xo++; if (!layer.RepeatX) { // If the current tile isn't in the first iteration of the layer horizontally, don't draw this column if (tileAbsX + tile_xo + 1 < 0 || tileAbsX + tile_xo + 1 >= tileCount.X) { continue; } } tileY = tileYs; int tile_yo = -1; for (float y2 = y1; y2 < y3; y2 += 32) { tileY = (tileY + 1) % tileCount.Y; tile_yo++; LayerTile tile = layer.Layout[tileX + tileY * layer.LayoutWidth]; if (!layer.RepeatY) { // If the current tile isn't in the first iteration of the layer vertically, don't draw it if (tileAbsY + tile_yo + 1 < 0 || tileAbsY + tile_yo + 1 >= tileCount.Y) { continue; } } Point2 offset; bool isFlippedX, isFlippedY; if (tile.IsAnimated) { if (tile.TileID < animatedTiles.Count) { offset = animatedTiles[tile.TileID].CurrentTile.MaterialOffset; isFlippedX = (animatedTiles[tile.TileID].CurrentTile.IsFlippedX != tile.IsFlippedX); isFlippedY = (animatedTiles[tile.TileID].CurrentTile.IsFlippedY != tile.IsFlippedY); //mainColor.A = tile.MaterialAlpha; mainColor.A = animatedTiles[tile.TileID].CurrentTile.MaterialAlpha; } else { continue; } } else { offset = tile.MaterialOffset; isFlippedX = tile.IsFlippedX; isFlippedY = tile.IsFlippedY; mainColor.A = tile.MaterialAlpha; } if (material != tile.Material) { // Submit all the vertices as one draw batch device.AddVertices( material, VertexMode.Quads, vertexData, 0, vertexBaseIndex); vertexBaseIndex = 0; material = tile.Material.Res; texture = material.MainTexture.Res; } Rect uvRect = new Rect( offset.X * texture.UVRatio.X / texture.ContentWidth, offset.Y * texture.UVRatio.Y / texture.ContentHeight, tileset.TileSize * texture.UVRatio.X / texture.ContentWidth, tileset.TileSize * texture.UVRatio.Y / texture.ContentHeight ); // ToDo: Flip normal map somehow if (isFlippedX) { uvRect.X += uvRect.W; uvRect.W *= -1; } if (isFlippedY) { uvRect.Y += uvRect.H; uvRect.H *= -1; } Vector3 renderPos = new Vector3(x2, y2, layer.Depth); float scale = 1.0f; device.PreprocessCoords(ref renderPos, ref scale); renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { renderPos.Y += 0.5f; } vertexData[vertexBaseIndex + 0].Pos.X = renderPos.X; vertexData[vertexBaseIndex + 0].Pos.Y = renderPos.Y; vertexData[vertexBaseIndex + 0].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 0].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 0].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 0].Color = mainColor; vertexData[vertexBaseIndex + 1].Pos.X = renderPos.X; vertexData[vertexBaseIndex + 1].Pos.Y = renderPos.Y + tileSize.Y; vertexData[vertexBaseIndex + 1].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 1].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 1].TexCoord.Y = uvRect.Y + uvRect.H; vertexData[vertexBaseIndex + 1].Color = mainColor; vertexData[vertexBaseIndex + 2].Pos.X = renderPos.X + tileSize.X; vertexData[vertexBaseIndex + 2].Pos.Y = renderPos.Y + tileSize.Y; vertexData[vertexBaseIndex + 2].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 2].TexCoord.X = uvRect.X + uvRect.W; vertexData[vertexBaseIndex + 2].TexCoord.Y = uvRect.Y + uvRect.H; vertexData[vertexBaseIndex + 2].Color = mainColor; vertexData[vertexBaseIndex + 3].Pos.X = renderPos.X + tileSize.X; vertexData[vertexBaseIndex + 3].Pos.Y = renderPos.Y; vertexData[vertexBaseIndex + 3].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 3].TexCoord.X = uvRect.X + uvRect.W; vertexData[vertexBaseIndex + 3].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 3].Color = mainColor; vertexBaseIndex += 4; } } // Submit all the vertices as one draw batch device.AddVertices( material, VertexMode.Quads, vertexData, 0, vertexBaseIndex); } }
/// <summary> /// Emits a set of vertices based on a text. To render this text, simply use that set of vertices combined with /// the Fonts <see cref="Material"/>. /// </summary> /// <param name="text">The text to render.</param> /// <param name="vertices">The set of vertices that is emitted. You can re-use the same array each frame.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="clr">The color value that is applied to each emitted vertex.</param> /// <returns>The number of emitted vertices. This values isn't necessarily equal to the emitted arrays length.</returns> public int EmitTextVertices(string text, ref VertexC1P3T2[] vertices, float x, float y, ColorRgba clr) { int len = this.EmitTextVertices(text, ref vertices); Vector3 offset = new Vector3(x, y, 0); for (int i = 0; i < len; i++) { Vector3.Add(ref vertices[i].Pos, ref offset, out vertices[i].Pos); vertices[i].Color = clr; } return len; }
/// <summary> /// Emits a set of vertices based on a text. To render this text, simply use that set of vertices combined with /// the Fonts <see cref="Material"/>. /// </summary> /// <param name="text">The text to render.</param> /// <param name="vertices">The set of vertices that is emitted. You can re-use the same array each frame.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="clr">The color value that is applied to each emitted vertex.</param> public void EmitTextVertices(string text, ref VertexC1P3T2[] vertices, float x, float y, ColorRgba clr) { this.EmitTextVertices(text, ref vertices); Vector3 offset = new Vector3(x, y, 0); for (int i = 0; i < vertices.Length; i++) { Vector3 vertex = vertices[i].Pos; vertex += offset; vertices[i].Pos = vertex; vertices[i].Color = clr; } }
/// <summary> /// Emits sets of vertices for glyphs and icons based on this formatted text. To render it, use each set of vertices combined with /// the corresponding Fonts <see cref="Material"/>. /// </summary> /// <param name="vertText">One set of vertices for each Font that is available to this ForattedText.</param> /// <param name="vertIcons">A set of icon vertices.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="clr">The color value that is applied to each emitted vertex.</param> /// <returns> /// Returns an array of vertex counts for each emitted vertex array. /// Index 0 represents the number of emitted icon vertices, Index n represents the number of vertices emitted using Font n - 1. /// </returns> public int[] EmitVertices(ref VertexC1P3T2[][] vertText, ref VertexC1P3T2[] vertIcons, float x, float y, ColorRgba clr) { int[] vertLen = this.EmitVertices(ref vertText, ref vertIcons); Vector3 offset = new Vector3(x, y, 0); if (clr == ColorRgba.White) { for (int i = 0; i < vertText.Length; i++) { for (int j = 0; j < vertLen[i + 1]; j++) { Vector3.Add(ref vertText[i][j].Pos, ref offset, out vertText[i][j].Pos); } } for (int i = 0; i < vertLen[0]; i++) { Vector3.Add(ref vertIcons[i].Pos, ref offset, out vertIcons[i].Pos); } } else { for (int i = 0; i < vertText.Length; i++) { for (int j = 0; j < vertLen[i + 1]; j++) { Vector3.Add(ref vertText[i][j].Pos, ref offset, out vertText[i][j].Pos); ColorRgba.Multiply(ref vertText[i][j].Color, ref clr, out vertText[i][j].Color); } } for (int i = 0; i < vertLen[0]; i++) { Vector3.Add(ref vertIcons[i].Pos, ref offset, out vertIcons[i].Pos); ColorRgba.Multiply(ref vertIcons[i].Color, ref clr, out vertIcons[i].Color); } } return vertLen; }
/// <summary> /// Emits sets of vertices for glyphs and icons based on this formatted text. To render it, use each set of vertices combined with /// the corresponding Fonts <see cref="Material"/>. /// </summary> /// <param name="vertText">One set of vertices for each Font that is available to this ForattedText.</param> /// <param name="vertIcons">A set of icon vertices.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="z">An Z-Offset applied to the position of each emitted vertex.</param> public void EmitVertices(ref VertexC1P3T2[][] vertText, ref VertexC1P3T2[] vertIcons, float x, float y, float z = 0.0f) { this.EmitVertices(ref vertText, ref vertIcons, x, y, z, ColorRgba.White); }
void ICmpRenderer.Draw(IDrawDevice device) { if (_inEditor) { if (FXSource != null && FXTarget != null) { Canvas c = new Canvas(device); FXSource.DrawInEditor(c); FXTarget.DrawInEditor(c); Vector3 src = FXSource.GameObj.Transform.Pos; Vector3 tar = FXTarget.GameObj.Transform.Pos; c.PushState(); Vector3 line = tar - src; Vector2 normal = line.Xy.PerpendicularLeft; Vector3 p1 = line * 0.33f; Vector3 p2 = line * 0.33f; Vector3 p3 = line * 0.67f; Vector3 p4 = line * 0.67f; p1 += src + new Vector3(normal * .04f, p1.Z); p2 += src + new Vector3(normal * -.02f, p2.Z); p3 += src + new Vector3(normal * .02f, p3.Z); p4 += src + new Vector3(normal * -.04f, p4.Z); c.State.ColorTint = Colors.Pink; c.DrawLine(src.X, src.Y, src.Z, p1.X, p1.Y, p1.Z); c.DrawLine(p1.X, p1.Y, p1.Z, p2.X, p2.Y, p2.Z); c.DrawLine(p2.X, p2.Y, p2.Z, p3.X, p3.Y, p3.Z); c.DrawLine(p3.X, p3.Y, p3.Z, p4.X, p4.Y, p4.Z); c.DrawLine(p4.X, p4.Y, p4.Z, tar.X, tar.Y, tar.Z); c.PopState(); } } else { foreach (LightningBolt bolt in _bolts) { if (bolt.IsAlive) { if (!bolt.BatchInfos.ContainsKey(device) || !bolt.BatchInfos[device].IsReady) { bolt.PrepareTextureForDrawDevice(device); } LightningBolt.BoltData bd = bolt.BatchInfos[device]; float scaleAtStart = device.GetScaleAtZ(FXSource.GameObj.Transform.Pos.Z); float scaleAtEnd = device.GetScaleAtZ(FXTarget.GameObj.Transform.Pos.Z); Vector2 axis = (bd.End - bd.Start).Xy; Vector2 normal = axis.PerpendicularLeft.Normalized; VertexC1P3T2[] v = new VertexC1P3T2[4]; v[0] = new VertexC1P3T2(); v[0].Pos = bd.Start - new Vector3(normal * Sway * scaleAtStart, 0); v[0].TexCoord = new Vector2(0, 0); v[0].Color = bolt.CurrentColor; v[1] = new VertexC1P3T2(); v[1].Pos = bd.Start + new Vector3(normal * Sway * scaleAtStart, 0); v[1].TexCoord = new Vector2(0, 1); v[1].Color = bolt.CurrentColor; v[2] = new VertexC1P3T2(); v[2].Pos = bd.End + new Vector3(normal * Sway * scaleAtEnd, 0); v[2].TexCoord = new Vector2(1, 1); v[2].Color = bolt.CurrentColor; v[3] = new VertexC1P3T2(); v[3].Pos = bd.End - new Vector3(normal * Sway * scaleAtEnd, 0); v[3].TexCoord = new Vector2(1, 0); v[3].Color = bolt.CurrentColor; device.AddVertices(bd.BatchInfo, VertexMode.Quads, v); } } } }
/// <summary> /// Emits sets of vertices for glyphs and icons based on this formatted text. To render it, use each set of vertices combined with /// the corresponding Fonts <see cref="Material"/>. /// </summary> /// <param name="vertText">One set of vertices for each Font that is available to this ForattedText.</param> /// <param name="vertIcons">A set of icon vertices.</param> public void EmitVertices(ref VertexC1P3T2[][] vertText, ref VertexC1P3T2[] vertIcons) { this.ValidateVertexCache(); // Allocate memory if (vertIcons == null || vertIcons.Length != this.vertIconsCache.Length) vertIcons = new VertexC1P3T2[this.vertIconsCache.Length]; if (vertText == null || vertText.Length != this.vertTextCache.Length) vertText = new VertexC1P3T2[this.vertTextCache.Length][]; for (int i = 0; i < this.vertTextCache.Length; i++) { if (vertText[i] == null || vertText[i].Length != this.vertTextCache[i].Length) vertText[i] = new VertexC1P3T2[this.vertTextCache[i].Length]; } // Copy actual data Array.Copy(this.vertIconsCache, vertIcons, this.vertIconsCache.Length); for (int i = 0; i < this.vertTextCache.Length; i++) Array.Copy(this.vertTextCache[i], vertText[i], this.vertTextCache[i].Length); }
/// <summary> /// Emits sets of vertices for glyphs and icons based on this formatted text. To render it, use each set of vertices combined with /// the corresponding Fonts <see cref="Material"/>. /// </summary> /// <param name="vertText">One set of vertices for each Font that is available to this ForattedText.</param> /// <param name="vertIcons">A set of icon vertices.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="z">An Z-Offset applied to the position of each emitted vertex.</param> /// <param name="clr">The color value that is applied to each emitted vertex.</param> /// <param name="xDot">Dot product base for the transformed vertices.</param> /// <param name="yDot">Dot product base for the transformed vertices.</param> public void EmitVertices(ref VertexC1P3T2[][] vertText, ref VertexC1P3T2[] vertIcons, float x, float y, float z, ColorRgba clr, Vector2 xDot, Vector2 yDot) { this.EmitVertices(ref vertText, ref vertIcons); Vector3 offset = new Vector3(x, y, z); for (int i = 0; i < vertText.Length; i++) { for (int j = 0; j < vertText[i].Length; j++) { Vector3 vertex = vertText[i][j].Pos; MathF.TransformDotVec(ref vertex, ref xDot, ref yDot); vertex += offset; vertText[i][j].Pos = vertex; vertText[i][j].Color *= clr; } } for (int i = 0; i < vertIcons.Length; i++) { Vector3 vertex = vertIcons[i].Pos; MathF.TransformDotVec(ref vertex, ref xDot, ref yDot); vertex += offset; vertIcons[i].Pos = vertex; vertIcons[i].Color *= clr; } }
protected override void OnRender(Canvas canvas) { Size size = ClientSize; size.Width -= scrollBar.ClientSize.Width; canvas.State.ColorTint = ColorRgba.White; canvas.FillRect(0, 0, size.Width, size.Height); if (tilemap == null) { return; } IDrawDevice device = canvas.DrawDevice; TileSet tileset = tilemap.Tileset; Material material = tilemap.Tileset.GetDefaultTile(0).Material.Res; Texture texture = material.MainTexture.Res; int scrollBarOffset = scrollBar.Value; ColorRgba mainColor = ColorRgba.White; Point2 tileSize = new Point2(tilemap.Tileset.TileSize, tilemap.Tileset.TileSize); VertexC1P3T2[] vertexData = new VertexC1P3T2[4]; int tileIndex = 0; for (int y = 0; tileIndex < tileset.TileCount; y += tileSize.Y) { for (int x = 0; x < 10 * tileSize.X; x += tileSize.X) { int tx = (tileIndex % tileset.TilesPerRow) * tileSize.X; int ty = (tileIndex / tileset.TilesPerRow) * tileSize.Y; Vector3 renderPos = new Vector3(x, y - scrollBarOffset, 0); Rect uvRect = new Rect( tx * texture.UVRatio.X / texture.ContentWidth, ty * texture.UVRatio.Y / texture.ContentHeight, tileset.TileSize * texture.UVRatio.X / texture.ContentWidth, tileset.TileSize * texture.UVRatio.Y / texture.ContentHeight ); vertexData[0].Pos.X = renderPos.X; vertexData[0].Pos.Y = renderPos.Y; vertexData[0].Pos.Z = renderPos.Z; vertexData[0].TexCoord.X = uvRect.X; vertexData[0].TexCoord.Y = uvRect.Y; vertexData[0].Color = mainColor; vertexData[1].Pos.X = renderPos.X; vertexData[1].Pos.Y = renderPos.Y + tileSize.Y; vertexData[1].Pos.Z = renderPos.Z; vertexData[1].TexCoord.X = uvRect.X; vertexData[1].TexCoord.Y = uvRect.Y + uvRect.H; vertexData[1].Color = mainColor; vertexData[2].Pos.X = renderPos.X + tileSize.X; vertexData[2].Pos.Y = renderPos.Y + tileSize.Y; vertexData[2].Pos.Z = renderPos.Z; vertexData[2].TexCoord.X = uvRect.X + uvRect.W; vertexData[2].TexCoord.Y = uvRect.Y + uvRect.H; vertexData[2].Color = mainColor; vertexData[3].Pos.X = renderPos.X + tileSize.X; vertexData[3].Pos.Y = renderPos.Y; vertexData[3].Pos.Z = renderPos.Z; vertexData[3].TexCoord.X = uvRect.X + uvRect.W; vertexData[3].TexCoord.Y = uvRect.Y; vertexData[3].Color = mainColor; device.AddVertices(material, VertexMode.Quads, vertexData); tileIndex++; } } }
private void RenderTexturedBackground(IDrawDevice device) { if (cachedTexturedBackground == null) { return; } float timeMult = Time.TimeMult; backgroundX += timeMult * 1.2f; backgroundY += timeMult * -0.2f + timeMult * MathF.Sin(backgroundPhase) * 0.6f; backgroundPhase += timeMult * 0.001f; Vector3 renderPos = new Vector3(0, 0, (device.NearZ + device.FarZ) * 0.5f); // Fit the target rect to actual pixel coordinates to avoid unnecessary filtering offsets renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { //renderPos.Y += 0.5f; // AMD Bugfix? renderPos.Y -= 0.001f; } // Reserve the required space for vertex data in our locally cached buffer VertexC1P3T2[] vertexData; int neededVertices = 4; if (cachedVertices == null || cachedVertices.Length < neededVertices) { cachedVertices = vertexData = new VertexC1P3T2[neededVertices]; } else { vertexData = cachedVertices; } // Render it as world-space fullscreen quad vertexData[0].Pos = new Vector3(renderPos.X, renderPos.Y, renderPos.Z); vertexData[1].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y, renderPos.Z); vertexData[2].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); vertexData[3].Pos = new Vector3(renderPos.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); vertexData[0].TexCoord = new Vector2(0.0f, 0.0f); vertexData[1].TexCoord = new Vector2(1f, 0.0f); vertexData[2].TexCoord = new Vector2(1f, 1f); vertexData[3].TexCoord = new Vector2(0.0f, 1f); vertexData[0].Color = vertexData[1].Color = vertexData[2].Color = vertexData[3].Color = ColorRgba.White; // Setup custom pixel shader BatchInfo material = new BatchInfo(texturedBackgroundShader, cachedTexturedBackground); material.SetValue("horizonColor", horizonColor); material.SetValue("shift", new Vector2(backgroundX, backgroundY)); device.AddVertices(material, VertexMode.Quads, vertexData); }
/// <summary> /// Emits a set of vertices based on a text. To render this text, simply use that set of vertices combined with /// the Fonts <see cref="Material"/>. /// </summary> /// <param name="text">The text to render.</param> /// <param name="vertices">The set of vertices that is emitted. You can re-use the same array each frame.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="z">An Z-Offset applied to the position of each emitted vertex.</param> /// <param name="clr">The color value that is applied to each emitted vertex.</param> /// <param name="angle">An angle by which the text is rotated (before applying the offset).</param> /// <param name="scale">A factor by which the text is scaled (before applying the offset).</param> /// <returns>The number of emitted vertices. This values isn't necessarily equal to the emitted arrays length.</returns> public int EmitTextVertices(string text, ref VertexC1P3T2[] vertices, float x, float y, float z, ColorRgba clr, float angle = 0.0f, float scale = 1.0f) { int len = this.EmitTextVertices(text, ref vertices); Vector3 offset = new Vector3(x, y, z); Vector2 xDot, yDot; MathF.GetTransformDotVec(angle, scale, out xDot, out yDot); for (int i = 0; i < len; i++) { MathF.TransformDotVec(ref vertices[i].Pos, ref xDot, ref yDot); Vector3.Add(ref vertices[i].Pos, ref offset, out vertices[i].Pos); vertices[i].Color = clr; } return len; }
/// <summary> /// Emits sets of vertices for glyphs and icons based on this formatted text. To render it, use each set of vertices combined with /// the corresponding Fonts <see cref="Material"/>. /// </summary> /// <param name="vertText">One set of vertices for each Font that is available to this ForattedText.</param> /// <param name="vertIcons">A set of icon vertices.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="clr">The color value that is applied to each emitted vertex.</param> public void EmitVertices(ref VertexC1P3T2[][] vertText, ref VertexC1P3T2[] vertIcons, float x, float y, ColorRgba clr) { this.EmitVertices(ref vertText, ref vertIcons); Vector3 offset = new Vector3(x, y, 0); for (int i = 0; i < vertText.Length; i++) { for (int j = 0; j < vertText[i].Length; j++) { Vector3 vertex = vertText[i][j].Pos; vertex += offset; vertText[i][j].Pos = vertex; vertText[i][j].Color *= clr; } } for (int i = 0; i < vertIcons.Length; i++) { Vector3 vertex = vertIcons[i].Pos; vertex += offset; vertIcons[i].Pos = vertex; vertIcons[i].Color *= clr; } }
[Test] public void RentAndClear() { VertexBatchStore memory = new VertexBatchStore(); // Repeatedly rent slices of varying types from memory { VertexSlice <VertexC1P3> slice = memory.Rent <VertexC1P3>(4); slice[0] = new VertexC1P3 { Color = new ColorRgba(0) }; slice[1] = new VertexC1P3 { Color = new ColorRgba(1) }; slice[2] = new VertexC1P3 { Color = new ColorRgba(2) }; slice[3] = new VertexC1P3 { Color = new ColorRgba(3) }; } { VertexSlice <VertexC1P3T2> slice = memory.Rent <VertexC1P3T2>(3); slice[0] = new VertexC1P3T2 { Color = new ColorRgba(4) }; slice[1] = new VertexC1P3T2 { Color = new ColorRgba(5) }; slice[2] = new VertexC1P3T2 { Color = new ColorRgba(6) }; } { VertexSlice <VertexC1P3> slice = memory.Rent <VertexC1P3>(2); slice[0] = new VertexC1P3 { Color = new ColorRgba(7) }; slice[1] = new VertexC1P3 { Color = new ColorRgba(8) }; } { VertexSlice <VertexC1P3> slice = memory.Rent <VertexC1P3>(1); slice[0] = new VertexC1P3 { Color = new ColorRgba(9) }; } // Assert correct storage property values Assert.AreEqual( 1 + Math.Max( VertexDeclaration.Get <VertexC1P3>().TypeIndex, VertexDeclaration.Get <VertexC1P3T2>().TypeIndex), memory.TypeIndexCount); Assert.AreEqual(1, memory.GetBatchCount <VertexC1P3>()); Assert.AreEqual(1, memory.GetBatchCount <VertexC1P3T2>()); // Retrieve specific internal vertex arrays VertexBatch <VertexC1P3> batchA = memory.GetBatch <VertexC1P3>(0); VertexBatch <VertexC1P3T2> batchB = memory.GetBatch <VertexC1P3T2>(0); RawList <VertexC1P3> verticesA = batchA.Vertices; RawList <VertexC1P3T2> verticesB = batchB.Vertices; // Assert that they contain all the data we submitted in the correct order Assert.AreEqual(7, batchA.Count); Assert.AreEqual(3, batchB.Count); Assert.AreEqual(7, verticesA.Count); Assert.AreEqual(3, verticesB.Count); Assert.AreEqual(new ColorRgba(0), verticesA[0].Color); Assert.AreEqual(new ColorRgba(1), verticesA[1].Color); Assert.AreEqual(new ColorRgba(2), verticesA[2].Color); Assert.AreEqual(new ColorRgba(3), verticesA[3].Color); Assert.AreEqual(new ColorRgba(4), verticesB[0].Color); Assert.AreEqual(new ColorRgba(5), verticesB[1].Color); Assert.AreEqual(new ColorRgba(6), verticesB[2].Color); Assert.AreEqual(new ColorRgba(7), verticesA[4].Color); Assert.AreEqual(new ColorRgba(8), verticesA[5].Color); Assert.AreEqual(new ColorRgba(9), verticesA[6].Color); // Clear all vertices memory.Clear(); // Assert correct storage property values Assert.AreEqual(0, memory.TypeIndexCount); Assert.AreEqual(0, memory.GetBatchCount <VertexC1P3>()); Assert.AreEqual(0, memory.GetBatchCount <VertexC1P3T2>()); // Assert that the vertices are gone, but capacity isn't Assert.AreEqual(0, batchA.Count); Assert.AreEqual(0, batchB.Count); Assert.AreEqual(0, verticesA.Count); Assert.AreEqual(0, verticesB.Count); Assert.GreaterOrEqual(verticesA.Capacity, 7); Assert.GreaterOrEqual(verticesB.Capacity, 3); }
protected internal override void OnCollectWorldOverlayDrawcalls(Canvas canvas) { base.OnCollectWorldOverlayDrawcalls(canvas); List <RigidBody> visibleColliders = this.QueryVisibleColliders().ToList(); RigidBody selectedBody = this.QuerySelectedCollider(); canvas.State.TextFont = Font.GenericMonospace10; canvas.State.TextInvariantScale = true; canvas.State.ZOffset = -0.5f; Font textFont = canvas.State.TextFont.Res; // Draw Shape layer foreach (RigidBody body in visibleColliders) { if (!body.Shapes.Any()) { continue; } float colliderAlpha = body == selectedBody ? 1.0f : (selectedBody != null ? 0.25f : 0.5f); float maxDensity = body.Shapes.Max(s => s.Density); float minDensity = body.Shapes.Min(s => s.Density); float avgDensity = (maxDensity + minDensity) * 0.5f; Vector3 objPos = body.GameObj.Transform.Pos; float objAngle = body.GameObj.Transform.Angle; float objScale = body.GameObj.Transform.Scale; int index = 0; foreach (ShapeInfo shape in body.Shapes) { CircleShapeInfo circle = shape as CircleShapeInfo; PolyShapeInfo poly = shape as PolyShapeInfo; ChainShapeInfo chain = shape as ChainShapeInfo; LoopShapeInfo loop = shape as LoopShapeInfo; ObjectEditorCamViewState editorState = this.View.ActiveState as ObjectEditorCamViewState; float shapeAlpha = colliderAlpha * (selectedBody == null || editorState == null || editorState.SelectedObjects.Any(sel => sel.ActualObject == shape) ? 1.0f : 0.5f); float densityRelative = MathF.Abs(maxDensity - minDensity) < 0.01f ? 1.0f : shape.Density / avgDensity; ColorRgba clr = shape.IsSensor ? this.ShapeSensorColor : this.ShapeColor; ColorRgba fontClr = this.FgColor; Vector2 center = Vector2.Zero; if (!body.IsAwake) { clr = clr.ToHsva().WithSaturation(0.0f).ToRgba(); } if (!shape.IsValid) { clr = this.ShapeErrorColor; } bool fillShape = (poly != null || circle != null); Vector2[] shapeVertices = null; if (poly != null) { shapeVertices = poly.Vertices; } else if (loop != null) { shapeVertices = loop.Vertices; } else if (chain != null) { shapeVertices = chain.Vertices; } if (circle != null) { Vector2 circlePos = circle.Position * objScale; MathF.TransformCoord(ref circlePos.X, ref circlePos.Y, objAngle); if (fillShape) { canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha((0.25f + densityRelative * 0.25f) * shapeAlpha))); canvas.FillCircle( objPos.X + circlePos.X, objPos.Y + circlePos.Y, objPos.Z, circle.Radius * objScale); } canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha(shapeAlpha))); canvas.DrawCircle( objPos.X + circlePos.X, objPos.Y + circlePos.Y, objPos.Z, circle.Radius * objScale); center = circlePos; } else if (shapeVertices != null) { ColorRgba vertexFillColor = canvas.State.ColorTint * clr.WithAlpha((0.25f + densityRelative * 0.25f) * shapeAlpha); ColorRgba vertexOutlineColor = canvas.State.ColorTint * clr; // Prepare vertices to submit. We can't use higher-level canvas functionality // here, because we want direct control over the vertex mode. float viewSpaceScale = objScale; Vector3 viewSpacePos = objPos; canvas.DrawDevice.PreprocessCoords(ref viewSpacePos, ref viewSpaceScale); VertexC1P3T2[] drawVertices = new VertexC1P3T2[shapeVertices.Length]; for (int i = 0; i < drawVertices.Length; i++) { drawVertices[i].Pos.X = shapeVertices[i].X; drawVertices[i].Pos.Y = shapeVertices[i].Y; drawVertices[i].Pos.Z = 0.0f; MathF.TransformCoord(ref drawVertices[i].Pos.X, ref drawVertices[i].Pos.Y, objAngle, viewSpaceScale); drawVertices[i].Pos.X += viewSpacePos.X; drawVertices[i].Pos.Y += viewSpacePos.Y; drawVertices[i].Pos.Z += viewSpacePos.Z; drawVertices[i].Color = vertexOutlineColor; } // Calculate the center coordinate for (int i = 0; i < drawVertices.Length; i++) { center += shapeVertices[i]; } center /= shapeVertices.Length; MathF.TransformCoord(ref center.X, ref center.Y, objAngle, objScale); // Make sure to render using an alpha material canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White)); // Fill the shape if (fillShape) { VertexC1P3T2[] fillVertices = drawVertices.Clone() as VertexC1P3T2[]; for (int i = 0; i < fillVertices.Length; i++) { fillVertices[i].Color = vertexFillColor; } canvas.DrawVertices(fillVertices, VertexMode.TriangleFan); } // Draw the outline canvas.DrawVertices(drawVertices, shape is ChainShapeInfo ? VertexMode.LineStrip : VertexMode.LineLoop); } // Draw shape index if (body == selectedBody) { string indexText = index.ToString(); Vector2 textSize = textFont.MeasureText(indexText); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, fontClr.WithAlpha((shapeAlpha + 1.0f) * 0.5f))); canvas.DrawText(indexText, objPos.X + center.X, objPos.Y + center.Y, objPos.Z); } index++; } // Draw center of mass if (body.BodyType == BodyType.Dynamic) { Vector2 localMassCenter = body.LocalMassCenter; MathF.TransformCoord(ref localMassCenter.X, ref localMassCenter.Y, objAngle, objScale); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, this.MassCenterColor.WithAlpha(colliderAlpha))); canvas.DrawLine( objPos.X + localMassCenter.X - 5.0f, objPos.Y + localMassCenter.Y, objPos.Z, objPos.X + localMassCenter.X + 5.0f, objPos.Y + localMassCenter.Y, objPos.Z); canvas.DrawLine( objPos.X + localMassCenter.X, objPos.Y + localMassCenter.Y - 5.0f, objPos.Z, objPos.X + localMassCenter.X, objPos.Y + localMassCenter.Y + 5.0f, objPos.Z); } } }
/// <summary> /// Emits sets of vertices for glyphs and icons based on this formatted text. To render it, use each set of vertices combined with /// the corresponding Fonts <see cref="Material"/>. /// </summary> /// <param name="vertText">One set of vertices for each Font that is available to this ForattedText.</param> /// <param name="vertIcons">A set of icon vertices.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="z">An Z-Offset applied to the position of each emitted vertex.</param> /// <param name="clr">The color value that is applied to each emitted vertex.</param> /// <param name="angle">An angle by which the text is rotated (before applying the offset).</param> /// <param name="scale">A factor by which the text is scaled (before applying the offset).</param> public void EmitVertices(ref VertexC1P3T2[][] vertText, ref VertexC1P3T2[] vertIcons, float x, float y, float z, ColorRgba clr, float angle = 0.0f, float scale = 1.0f) { Vector2 xDot, yDot; MathF.GetTransformDotVec(angle, scale, out xDot, out yDot); this.EmitVertices(ref vertText, ref vertIcons, x, y, z, clr, xDot, yDot); }
/// <summary> /// Emits a set of vertices based on a text. To render this text, simply use that set of vertices combined with /// the Fonts <see cref="Material"/>. /// </summary> /// <param name="text">The text to render.</param> /// <param name="vertices">The set of vertices that is emitted. You can re-use the same array each frame.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="z">An Z-Offset applied to the position of each emitted vertex.</param> /// <returns>The number of emitted vertices. This values isn't necessarily equal to the emitted arrays length.</returns> public int EmitTextVertices(string text, ref VertexC1P3T2[] vertices, float x, float y, float z = 0.0f) { return this.EmitTextVertices(text, ref vertices, x, y, z, ColorRgba.White); }
/// <summary> /// Emits sets of vertices for glyphs and icons based on this formatted text. To render it, use each set of vertices combined with /// the corresponding Fonts <see cref="Material"/>. /// </summary> /// <param name="vertText">One set of vertices for each Font that is available to this FormattedText.</param> /// <param name="vertIcons">A set of icon vertices.</param> /// <returns> /// Returns an array of vertex counts for each emitted vertex array. /// Index 0 represents the number of emitted icon vertices, Index n represents the number of vertices emitted using Font n - 1. /// </returns> public int[] EmitVertices(ref VertexC1P3T2[][] vertText, ref VertexC1P3T2[] vertIcons) { this.ValidateVertexCache(); // Allocate memory if (vertIcons == null || vertIcons.Length < this.vertCountCache[0]) vertIcons = new VertexC1P3T2[this.vertCountCache[0]]; if (vertText == null || vertText.Length != this.vertTextCache.Length) vertText = new VertexC1P3T2[this.vertTextCache.Length][]; for (int i = 0; i < this.vertTextCache.Length; i++) { if (vertText[i] == null || vertText[i].Length < this.vertCountCache[i + 1]) vertText[i] = new VertexC1P3T2[this.vertCountCache[i + 1]]; } // Copy actual data int[] vertLen = new int[this.vertCountCache.Length]; Array.Copy(this.vertCountCache, vertLen, this.vertCountCache.Length); Array.Copy(this.vertIconsCache, vertIcons, vertLen[0]); for (int i = 0; i < this.vertTextCache.Length; i++) Array.Copy(this.vertTextCache[i], vertText[i], vertLen[i + 1]); return vertLen; }