/// <summary> /// Retrieves the value of a builtin shader variable using the index retrieved by <see cref="GetIndex"/>. /// </summary> /// <param name="currentDevice"></param> /// <param name="index"></param> /// <param name="value"></param> /// <returns></returns> public static bool TryGetValue(IDrawDevice currentDevice, int index, ref float[] value) { int size = 1; switch (index) { case InvalidIndex: return false; default: size = 1; break; case 4: size = 3; break; } value = (value != null && value.Length == size) ? value : new float[size]; switch (index) { case 0: value[0] = (float)Time.MainTimer.TotalSeconds; return true; case 1: value[0] = (float)Time.GameTimer.TotalSeconds; return true; case 2: value[0] = (float)Time.FrameCount; return true; case 3: value[0] = currentDevice.FocusDist; return true; case 4: value[0] = currentDevice.RefCoord.X; value[1] = currentDevice.RefCoord.Y; value[2] = currentDevice.RefCoord.Z; return true; case 5: value[0] = currentDevice.Perspective == PerspectiveMode.Parallax ? 1.0f : 0.0f; return true; } return false; }
public IEnumerable<ICmpRenderer> QueryVisibleRenderers(IDrawDevice device) { if (this.renderers == null) return Enumerable.Empty<ICmpRenderer>(); else return this.renderers.Where(r => (r as Component).Active && r.IsVisible(device)); }
bool ICmpRenderer.IsVisible(IDrawDevice device) { // Only render when in screen overlay mode and the visibility mask is non-empty. return (device.VisibilityMask & VisibilityFlag.AllGroups) != VisibilityFlag.None && (device.VisibilityMask & VisibilityFlag.ScreenOverlay) != VisibilityFlag.None; }
public override void Draw(IDrawDevice device) { // Perform Camera space transformation Vector3 posBefore = this.GameObj.Transform.Pos; Vector3 posTemp = posBefore; float scaleTemp = 1.0f; device.PreprocessCoords(this, ref posTemp, ref scaleTemp); // Draw debug text VertexC1P3T2[] textVertices; textVertices = null; Font.GenericMonospace10.Res.EmitTextVertices( string.Format("Position (world): {0:0}, {1:0}, {2:0}", posBefore.X, posBefore.Y, posBefore.Z), ref textVertices, posTemp.X, posTemp.Y, posTemp.Z); device.AddVertices(Font.GenericMonospace10.Res.Material, BeginMode.Quads, textVertices); textVertices = null; Font.GenericMonospace10.Res.EmitTextVertices( string.Format("Position (cam): {0:0}, {1:0}, {2:0}", posTemp.X, posTemp.Y, posTemp.Z), ref textVertices, posTemp.X, posTemp.Y + 10, posTemp.Z); device.AddVertices(Font.GenericMonospace10.Res.Material, BeginMode.Quads, textVertices); textVertices = null; Font.GenericMonospace10.Res.EmitTextVertices( string.Format("Scale: {0:F}", scaleTemp), ref textVertices, posTemp.X, posTemp.Y + 20, posTemp.Z); device.AddVertices(Font.GenericMonospace10.Res.Material, BeginMode.Quads, textVertices); // Draw position indicator device.AddVertices(new BatchInfo(DrawTechnique.Alpha, ColorRgba.Red.WithAlpha(0.25f)), BeginMode.Quads, new VertexP3[] { new VertexP3(posTemp.X - 50.0f * scaleTemp, posTemp.Y - 50.0f * scaleTemp, posTemp.Z), new VertexP3(posTemp.X + 50.0f * scaleTemp, posTemp.Y - 50.0f * scaleTemp, posTemp.Z), new VertexP3(posTemp.X + 50.0f * scaleTemp, posTemp.Y + 50.0f * scaleTemp, posTemp.Z), new VertexP3(posTemp.X - 50.0f * scaleTemp, posTemp.Y + 50.0f * scaleTemp, posTemp.Z) }); }
public override void Draw(IDrawDevice device) { Texture mainTex = this.RetrieveMainTex(); ColorRgba mainClr = this.RetrieveMainColor(); DrawTechnique tech = this.RetrieveDrawTechnique(); Rect uvRect; if (mainTex != null) { if (this.rectMode == UVMode.WrapBoth) uvRect = new Rect(mainTex.UVRatio.X * this.rect.W / mainTex.PixelWidth, mainTex.UVRatio.Y * this.rect.H / mainTex.PixelHeight); else if (this.rectMode == UVMode.WrapHorizontal) uvRect = new Rect(mainTex.UVRatio.X * this.rect.W / mainTex.PixelWidth, mainTex.UVRatio.Y); else if (this.rectMode == UVMode.WrapVertical) uvRect = new Rect(mainTex.UVRatio.X, mainTex.UVRatio.Y * this.rect.H / mainTex.PixelHeight); else uvRect = new Rect(mainTex.UVRatio.X, mainTex.UVRatio.Y); } else uvRect = new Rect(1.0f, 1.0f); this.PrepareVerticesLight(ref this.verticesLight, device, mainClr, uvRect, tech); if (this.customMat != null) device.AddVertices(this.customMat, VertexMode.Quads, this.verticesLight); else device.AddVertices(this.sharedMat, VertexMode.Quads, this.verticesLight); }
public void QueryVisibleRenderers(IDrawDevice device, RawList<ICmpRenderer> targetList) { // Empty the cached list of visible renderers targetList.Count = 0; targetList.Reserve(this.totalRendererCount); // Copy references to all renderers that are visible to the target device int visibleCount = 0; ICmpRenderer[] targetData = targetList.Data; foreach (var pair in this.renderersByType) { ICmpRenderer[] data = pair.Value.Data; for (int i = 0; i < data.Length; i++) { if (i >= pair.Value.Count) break; if ((data[i] as Component).Active && data[i].IsVisible(device)) { targetData[visibleCount] = data[i]; visibleCount++; } } } targetList.Count = visibleCount; }
public override void Draw(IDrawDevice device) { var mainClr = RetrieveMainColor(); PrepareVertices(device, mainClr); device.AddVertices(sharedMat, VertexMode.Quads, _vertices); }
public bool IsVisible(IDrawDevice device) { return // Make sure the ScreenOverlay flag is set (device.VisibilityMask & VisibilityFlag.ScreenOverlay) != VisibilityFlag.None && // Make sure some other flag is also set. (device.VisibilityMask & ~VisibilityFlag.ScreenOverlay) != VisibilityFlag.None; }
protected override void PrepareRendering(IDrawDevice device, BatchInfo material) { base.PrepareRendering(device, material); material.SetTexture("mainTex", TextureOne); material.SetTexture("samp1", TextureTwo); material.SetTexture("samp2", TextureThree); }
void ICmpRenderer.Draw(IDrawDevice device) { if (device.VisibilityMask.HasFlag(VisibilityFlag.ScreenOverlay)) { Canvas target = new Canvas(device, this.vertexBufferScreen); target.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White)); foreach (VisualLog log in VisualLog.All) { if (!log.Visible) continue; if (log.BaseColor.A == 0) continue; if ((log.VisibilityGroup & device.VisibilityMask & VisibilityFlag.AllGroups) == VisibilityFlag.None) continue; target.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, log.BaseColor)); foreach (VisualLogEntry logEntry in log.Entries) { if (logEntry.Anchor != VisualLogAnchor.Screen) continue; target.PushState(); if (logEntry.LifetimeAsAlpha) target.State.ColorTint = new ColorRgba(1.0f, logEntry.LifetimeRatio); else target.State.ColorTint = ColorRgba.White; logEntry.Draw(target); target.PopState(); } } } else { Canvas target = new Canvas(device, this.vertexBufferWorld); target.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White)); target.State.ZOffset = -1; foreach (VisualLog log in VisualLog.All) { if (!log.Visible) continue; if (log.BaseColor.A == 0) continue; if ((log.VisibilityGroup & device.VisibilityMask & VisibilityFlag.AllGroups) == VisibilityFlag.None) continue; target.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, log.BaseColor)); foreach (VisualLogEntry logEntry in log.Entries) { if (logEntry.Anchor == VisualLogAnchor.Screen) continue; target.PushState(); target.State.ZOffset += logEntry.DepthOffset; target.State.ColorTint = new ColorRgba(1.0f, logEntry.LifetimeRatio); if (logEntry.Anchor == VisualLogAnchor.Object && logEntry.AnchorObj != null && logEntry.AnchorObj.Transform != null) { Transform anchorTransform = logEntry.AnchorObj.Transform; logEntry.Draw(target, anchorTransform.Pos, anchorTransform.Angle, anchorTransform.Scale); } else { logEntry.Draw(target); } target.PopState(); } } } }
public void Draw(IDrawDevice device) { Canvas canvas = new Canvas(device); if(baseControl.NeedsLayout) { baseControl.Layout(); } baseControl.Draw(canvas); }
public static Bitmap GrabScreenshot(IDrawDevice device) { if (GraphicsContext.CurrentContext == null) throw new GraphicsContextMissingException(); var bmp = new Bitmap((int) device.TargetSize.X, (int)device.TargetSize.Y); var data = bmp.LockBits(new Rectangle(0, 0, (int) device.TargetSize.X, (int) device.TargetSize.Y), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); GL.ReadPixels(0, 0, (int) device.TargetSize.X, (int) device.TargetSize.Y, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0); bmp.UnlockBits(data); // bmp.RotateFlip(RotateFlipType.RotateNoneFlipY); return bmp; }
public override void PrepareRendering(IDrawDevice device, BatchInfo material) { base.PrepareRendering(device, material); Vector3 camPos = device.RefCoord; float camRefDist = MathF.Abs(device.FocusDist); // Don't pass RefDist, see note in Light.cs material.SetUniform("_camRefDist", camRefDist); material.SetUniform("_camWorldPos", camPos.X, camPos.Y, camPos.Z); DynamicLighting.Light.SetupLighting(device, material); }
void ICmpRenderer.Draw(IDrawDevice device) { Canvas canvas = new Canvas(device); // Draw the mouse cursor when available if (DualityApp.Mouse.IsAvailable) { canvas.State.ColorTint = ColorRgba.White; canvas.FillCircle( DualityApp.Mouse.X, DualityApp.Mouse.Y, 2); } }
public void Draw(IDrawDevice device) { var triangles = env.Triangles; var triangleSideLength = env.TriangleSideLength; Canvas canvas = new Canvas(device); Vector2[][] vectors = new Vector2[4][]; vectors[0] = new Vector2[3]; vectors[0][0] = new Vector2(-(triangleSideLength / 2), -(triangleSideLength / 2)); vectors[0][1] = new Vector2((triangleSideLength / 2), -(triangleSideLength / 2)); vectors[0][2] = new Vector2(0, 0); vectors[1] = new Vector2[3]; vectors[1][0] = new Vector2((triangleSideLength / 2), -(triangleSideLength / 2)); vectors[1][1] = new Vector2((triangleSideLength / 2), (triangleSideLength / 2)); vectors[1][2] = new Vector2(0, 0); vectors[2] = new Vector2[3]; vectors[2][0] = new Vector2((triangleSideLength / 2), (triangleSideLength / 2)); vectors[2][1] = new Vector2(-(triangleSideLength / 2), (triangleSideLength / 2)); vectors[2][2] = new Vector2(0, 0); vectors[3] = new Vector2[3]; vectors[3][0] = new Vector2(-(triangleSideLength / 2), (triangleSideLength / 2)); vectors[3][1] = new Vector2(-(triangleSideLength / 2), -(triangleSideLength / 2)); vectors[3][2] = new Vector2(0, 0); BatchInfo[] infos = new BatchInfo[4]; infos[0] = new BatchInfo(DrawTechnique.Alpha, ColorRgba.Red, null); infos[1] = new BatchInfo(DrawTechnique.Alpha, ColorRgba.Blue, null); infos[2] = new BatchInfo(DrawTechnique.Alpha, ColorRgba.White, null); infos[3] = new BatchInfo(DrawTechnique.Alpha, ColorRgba.Green, null); for (int x = 0; x < triangles.GetLength(0); x++) { for (int y = 0; y < triangles.GetLength(1); y++) { for (int i = 0; i < triangles.GetLength(2); i++) { canvas.State.SetMaterial(infos[i]); if(true/*triangles[x,y,i] != null*/) { canvas.FillPolygon(vectors[i], triangleSideLength / 2 + triangleSideLength * x, triangleSideLength / 2 + triangleSideLength * y); } } } } }
public bool IsVisible(IDrawDevice device) { // Differing ScreenOverlay flag? Don't render! if ((device.VisibilityMask & VisibilityFlag.ScreenOverlay) != (this.visibilityGroup & VisibilityFlag.ScreenOverlay)) { return false; } // No match in any VisibilityGroup? Don't render! if ((this.visibilityGroup & device.VisibilityMask & VisibilityFlag.AllGroups) == VisibilityFlag.None) { return false; } // (Culling:) Not located near the screen? Don't render! return true; }
void ICmpRenderer.Draw(IDrawDevice device) { Canvas canvas = new Canvas(device); // Update input stats texts for drawing this.WriteInputStats(ref this.mouseStatsText, DualityApp.Mouse); this.WriteInputStats(ref this.keyboardStatsText, DualityApp.Keyboard); this.WriteInputStats(ref this.joystickStatsText, DualityApp.Joysticks); this.WriteInputStats(ref this.gamepadStatsText, DualityApp.Gamepads); // Draw input stats texts { int y = 10; canvas.DrawText(this.mouseStatsText, 10, y, 0, null, Alignment.TopLeft, true); y += 20 + (int)this.mouseStatsText.TextMetrics.Size.Y; canvas.DrawText(this.keyboardStatsText, 10, y, 0, null, Alignment.TopLeft, true); y += 20 + (int)this.keyboardStatsText.TextMetrics.Size.Y; canvas.DrawText(this.joystickStatsText, 10, y, 0, null, Alignment.TopLeft, true); y += 20 + (int)this.joystickStatsText.TextMetrics.Size.Y; canvas.DrawText(this.gamepadStatsText, 10, y, 0, null, Alignment.TopLeft, true); y += 20 + (int)this.gamepadStatsText.TextMetrics.Size.Y; } // Draw the mouse cursor's movement trail if (DualityApp.Mouse.IsAvailable) { canvas.State.ColorTint = new ColorRgba(128, 192, 255, 128); canvas.FillThickLine( DualityApp.Mouse.X - DualityApp.Mouse.XSpeed, DualityApp.Mouse.Y - DualityApp.Mouse.YSpeed, DualityApp.Mouse.X, DualityApp.Mouse.Y, 2); // Draw the mouse cursor at its local window coordiates canvas.State.ColorTint = ColorRgba.White; canvas.FillCircle( DualityApp.Mouse.X, DualityApp.Mouse.Y, 2); } }
void ICmpRenderer.Draw(IDrawDevice device) { Canvas canvas = new Canvas(device); if (device.IsScreenOverlay) { // Testbed text Vector2 nameSize = this.name.Measure().Size; Vector2 descSize = this.desc.Measure().Size; Vector2 ctrlSize = this.controls.Measure().Size; Vector2 statsSize = this.stats.Measure().Size; canvas.PushState(); // Text background canvas.CurrentState.SetMaterial(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White)); canvas.CurrentState.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(10, 10, MathF.Max(nameSize.X, descSize.X, ctrlSize.X) + 20, nameSize.Y + descSize.Y + 10 + ctrlSize.Y + 10); canvas.FillRect(10, DualityApp.TargetResolution.Y - 20 - statsSize.Y, statsSize.X + 20, statsSize.Y + 10); // Caption / Name canvas.CurrentState.ColorTint = ColorRgba.White.WithAlpha(0.85f); canvas.DrawText(this.name, 20, 15); // Description, Controls, Stats canvas.CurrentState.ColorTint = ColorRgba.White.WithAlpha(0.65f); canvas.DrawText(this.desc, 20, 15 + nameSize.Y); canvas.DrawText(this.controls, 20, 15 + nameSize.Y + descSize.Y + 10); canvas.DrawText(this.stats, 20, DualityApp.TargetResolution.Y - 15 - statsSize.Y); canvas.PopState(); // Mouse cursor canvas.DrawCross(DualityApp.Mouse.X, DualityApp.Mouse.Y, 5.0f); } else { // Mouse joint, if existing if (this.mouseJoint != null) { Vector3 jointBegin = this.mouseJoint.BodyA.GameObj.Transform.GetWorldPoint(new Vector3(this.mouseJoint.LocalAnchor, -0.01f)); Vector3 jointEnd = new Vector3(this.mouseJoint.WorldAnchor, -0.01f); canvas.CurrentState.ColorTint = ColorRgba.Red.WithAlpha(0.5f); canvas.DrawLine(jointBegin.X, jointBegin.Y, jointBegin.Z, jointEnd.X, jointEnd.Y, jointEnd.Z); } } }
public override void Draw(IDrawDevice device) { Texture mainTex = this.RetrieveMainTex(); ColorRgba mainClr = this.RetrieveMainColor(); DrawTechnique tech = this.RetrieveDrawTechnique(); Rect uvRect; Rect uvRectNext; bool smoothShaderInput = tech != null && tech.PreferredVertexFormat == VertexC1P3T4A4A1.Declaration; this.GetAnimData(mainTex, tech, smoothShaderInput, out uvRect, out uvRectNext); if (!smoothShaderInput) { this.PrepareVerticesLight(ref this.verticesLight, device, mainClr, uvRect, tech); if (this.customMat != null) device.AddVertices(this.customMat, VertexMode.Quads, this.verticesLight); else device.AddVertices(this.sharedMat, VertexMode.Quads, this.verticesLight); } else { this.PrepareVerticesLightSmooth(ref this.verticesLightSmooth, device, this.CurrentFrameProgress, mainClr, uvRect, uvRectNext, tech); if (this.customMat != null) device.AddVertices(this.customMat, VertexMode.Quads, this.verticesLightSmooth); else device.AddVertices(this.sharedMat, VertexMode.Quads, this.verticesLightSmooth); } }
private void PrepareVertices(ref VertexC1P3T2[] vertices, IDrawDevice device, ColorRgba mainClr, Rect uvRect) { Transform transform = this.GameObj.Transform; Vector3 posTemp = transform.Pos; float scaleTemp = transform.Scale; Vector2 xDot, yDot; MathF.GetTransformDotVec(transform.Angle, scaleTemp, out xDot, out yDot); Vector2 edge1 = this.rect.TopLeft; Vector2 edge2 = this.rect.BottomLeft; Vector2 edge3 = this.rect.BottomRight; Vector2 edge4 = this.rect.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); float uvLeft = uvRect.X; float uvRight = uvRect.RightX; float uvTop = uvRect.Y; float uvBottom = uvRect.BottomY; if (vertices == null || vertices.Length != 4) { vertices = new VertexC1P3T2[4]; } vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y - this.height; vertices[0].Pos.Z = posTemp.Z; vertices[0].TexCoord.X = uvLeft; vertices[0].TexCoord.Y = uvTop; vertices[0].Color = mainClr; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y - this.height; vertices[1].Pos.Z = posTemp.Z; vertices[1].TexCoord.X = uvLeft; vertices[1].TexCoord.Y = uvBottom; vertices[1].Color = mainClr; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y - this.height; vertices[2].Pos.Z = posTemp.Z; vertices[2].TexCoord.X = uvRight; vertices[2].TexCoord.Y = uvBottom; vertices[2].Color = mainClr; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y - this.height; vertices[3].Pos.Z = posTemp.Z; vertices[3].TexCoord.X = uvRight; vertices[3].TexCoord.Y = uvTop; vertices[3].Color = mainClr; // Apply depth offsets float depthPerUnit = -this.depthScale; if (this.isVertical) { // Vertical actors share the same depth offset on all four vertices float baseDepthOffset = this.offset + transform.Pos.Y * depthPerUnit; vertices[0].DepthOffset = baseDepthOffset; vertices[1].DepthOffset = baseDepthOffset; vertices[2].DepthOffset = baseDepthOffset; vertices[3].DepthOffset = baseDepthOffset; } else { // Flat actors need to apply depth individually per vertex float worldBaseY = transform.Pos.Y; vertices[0].DepthOffset = this.offset + (worldBaseY + edge1.Y * transform.Scale / scaleTemp + this.height) * depthPerUnit; vertices[1].DepthOffset = this.offset + (worldBaseY + edge2.Y * transform.Scale / scaleTemp + this.height) * depthPerUnit; vertices[2].DepthOffset = this.offset + (worldBaseY + edge3.Y * transform.Scale / scaleTemp + this.height) * depthPerUnit; vertices[3].DepthOffset = this.offset + (worldBaseY + edge4.Y * transform.Scale / scaleTemp + this.height) * depthPerUnit; } }
protected void PrepareVerticesLight(ref VertexC1P3T2A4[] vertices, IDrawDevice device, ColorRgba mainClr, Rect uvRect, DrawTechnique tech) { bool perPixel = tech is LightingTechnique; Vector3 pos = this.GameObj.Transform.Pos; Vector3 posTemp = pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; float rotation = this.GameObj.Transform.Angle; MathF.GetTransformDotVec(rotation, out xDot, out yDot); Rect rectTemp = this.rect.Transform(this.GameObj.Transform.Scale, this.GameObj.Transform.Scale); 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); // Using Per-Vertex Lighting? Calculate vertex light values Vector4[] vertexLight = null; if (!perPixel) { vertexLight = new Vector4[4]; Light.GetLightAtWorldPos(pos + new Vector3(edge1), out vertexLight[0], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge2), out vertexLight[1], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge3), out vertexLight[2], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge4), out vertexLight[3], this.vertexTranslucency); } Vector2.Multiply(ref edge1, scaleTemp, out edge1); Vector2.Multiply(ref edge2, scaleTemp, out edge2); Vector2.Multiply(ref edge3, scaleTemp, out edge3); Vector2.Multiply(ref edge4, scaleTemp, out edge4); // Using Per-Pixel Lighting? Pass objRotation Matrix via vertex attribute. Vector4 objRotMat = Vector4.Zero; if (perPixel) objRotMat = new Vector4((float)Math.Cos(-rotation), -(float)Math.Sin(-rotation), (float)Math.Sin(-rotation), (float)Math.Cos(-rotation)); if (vertices == null || vertices.Length != 4) vertices = new VertexC1P3T2A4[4]; vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = uvRect.X; vertices[0].TexCoord.Y = uvRect.Y; vertices[0].Color = mainClr; vertices[0].Attrib = perPixel ? objRotMat : vertexLight[0]; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = uvRect.X; vertices[1].TexCoord.Y = uvRect.MaximumY; vertices[1].Color = mainClr; vertices[1].Attrib = perPixel ? objRotMat : vertexLight[1]; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = uvRect.MaximumX; vertices[2].TexCoord.Y = uvRect.MaximumY; vertices[2].Color = mainClr; vertices[2].Attrib = perPixel ? objRotMat : vertexLight[2]; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = uvRect.MaximumX; vertices[3].TexCoord.Y = uvRect.Y; vertices[3].Color = mainClr; vertices[3].Attrib = perPixel ? objRotMat : vertexLight[3]; }
protected void PrepareVerticesLightSmooth(ref VertexC1P3T4A4A1[] vertices, IDrawDevice device, float curAnimFrameFade, ColorRgba mainClr, Rect uvRect, Rect uvRectNext, DrawTechnique tech) { bool perPixel = tech is LightingTechnique; Vector3 pos = this.GameObj.Transform.Pos; Vector3 posTemp = pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; float rotation = this.GameObj.Transform.Angle; MathF.GetTransformDotVec(rotation, out xDot, out yDot); Rect rectTemp = this.rect.Transformed(this.GameObj.Transform.Scale, this.GameObj.Transform.Scale); 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); // Using Per-Vertex Lighting? Calculate vertex light values Vector4[] vertexLight = null; if (!perPixel) { vertexLight = new Vector4[4]; Light.GetLightAtWorldPos(pos + new Vector3(edge1), out vertexLight[0], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge2), out vertexLight[1], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge3), out vertexLight[2], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge4), out vertexLight[3], this.vertexTranslucency); } Vector2.Multiply(ref edge1, scaleTemp, out edge1); Vector2.Multiply(ref edge2, scaleTemp, out edge2); Vector2.Multiply(ref edge3, scaleTemp, out edge3); Vector2.Multiply(ref edge4, scaleTemp, out edge4); // Using Per-Pixel Lighting? Pass objRotation Matrix via vertex attribute. Vector4 objRotMat = Vector4.Zero; if (perPixel) { objRotMat = new Vector4((float)Math.Cos(-rotation), -(float)Math.Sin(-rotation), (float)Math.Sin(-rotation), (float)Math.Cos(-rotation)); } if (vertices == null || vertices.Length != 4) { vertices = new VertexC1P3T4A4A1[4]; } // Calculate UV coordinates float left = uvRect.X; float right = uvRect.RightX; float top = uvRect.Y; float bottom = uvRect.BottomY; float nextLeft = uvRectNext.X; float nextRight = uvRectNext.RightX; float nextTop = uvRectNext.Y; float nextBottom = uvRectNext.BottomY; if ((this.flipMode & FlipMode.Horizontal) != FlipMode.None) { MathF.Swap(ref left, ref right); MathF.Swap(ref nextLeft, ref nextRight); } if ((this.flipMode & FlipMode.Vertical) != FlipMode.None) { MathF.Swap(ref top, ref bottom); MathF.Swap(ref nextTop, ref nextBottom); } // Directly pass World Position with each vertex, see note in Light.cs vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = left; vertices[0].TexCoord.Y = top; vertices[0].TexCoord.Z = nextLeft; vertices[0].TexCoord.W = nextTop; vertices[0].Color = mainClr; vertices[0].Attrib = perPixel ? objRotMat : vertexLight[0]; vertices[0].Attrib2 = curAnimFrameFade; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = left; vertices[1].TexCoord.Y = bottom; vertices[1].TexCoord.Z = nextLeft; vertices[1].TexCoord.W = nextBottom; vertices[1].Color = mainClr; vertices[1].Attrib = perPixel ? objRotMat : vertexLight[1]; vertices[1].Attrib2 = curAnimFrameFade; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = right; vertices[2].TexCoord.Y = bottom; vertices[2].TexCoord.Z = nextRight; vertices[2].TexCoord.W = nextBottom; vertices[2].Color = mainClr; vertices[2].Attrib = perPixel ? objRotMat : vertexLight[2]; vertices[2].Attrib2 = curAnimFrameFade; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = right; vertices[3].TexCoord.Y = top; vertices[3].TexCoord.Z = nextRight; vertices[3].TexCoord.W = nextTop; vertices[3].Color = mainClr; vertices[3].Attrib = perPixel ? objRotMat : vertexLight[3]; vertices[3].Attrib2 = curAnimFrameFade; if (this.pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
void ICmpRenderer.Draw(IDrawDevice device) { // Create a buffer to cache and re-use vertices. Not required, but will boost performance. if (this.buffer == null) { this.buffer = new CanvasBuffer(); } // Create a Canvas to auto-generate vertices from high-level drawing commands. Canvas canvas = new Canvas(device, this.buffer); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White)); canvas.State.TextFont = this.font; // Retrieve players if (this.playerOne == null) { this.playerOne = Scene.Current.FindComponents <Player>().Where(p => p.Id == PlayerId.PlayerOne).FirstOrDefault(); } if (this.playerTwo == null) { this.playerTwo = Scene.Current.FindComponents <Player>().Where(p => p.Id == PlayerId.PlayerTwo).FirstOrDefault(); } // Is someone playing using mouse / keyboard? Display a mouse cursor then if (Player.AlivePlayers.Any(p => p.InputMethod == InputMethod.MouseAndKeyboard)) { canvas.FillCircle(DualityApp.Mouse.X, DualityApp.Mouse.Y, 2.0f); } // Is any player alive? Keep that value in mind, won't change here anyway. bool isAnyPlayerAlive = Player.IsAnyPlayerAlive; // Draw health and info of player one if (this.IsPlayerActive(this.playerOne)) { Ship playerShip = this.playerOne.ControlObject; if (playerShip.Active) { // Draw a health bar when alive float health = playerShip.Hitpoints; canvas.State.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(12 - 1, device.TargetSize.Y - 10 - 198 - 1, 16 + 2, 196 + 2); canvas.State.ColorTint = this.playerOne.Color; canvas.DrawRect(10, device.TargetSize.Y - 10 - 200, 20, 200); canvas.FillRect(12, device.TargetSize.Y - 10 - health * 198.0f, 16, health * 196.0f); } else if (isAnyPlayerAlive && !this.playerOne.HasReachedGoal) { // Draw a respawn timer when dead float respawnPercentage = this.playerOne.RespawnTime / Player.RespawnDelay; string respawnText = string.Format("Respawn in {0:F1}", (Player.RespawnDelay - this.playerOne.RespawnTime) / 1000.0f); Vector2 textSize = canvas.MeasureText(string.Format("Respawn in {0:F1}", 0.0f)); canvas.State.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(10 - 1, device.TargetSize.Y - 10 - textSize.Y - 2, textSize.X + 5, textSize.Y + 8); canvas.State.ColorTint = this.playerOne.Color; canvas.DrawText(respawnText, 10, device.TargetSize.Y - 10, 0.0f, Alignment.BottomLeft); canvas.FillRect(10, device.TargetSize.Y - 10 - textSize.Y, textSize.X * respawnPercentage, 3); canvas.FillRect(10, device.TargetSize.Y - 10, textSize.X * respawnPercentage, 3); } } // Draw health and info of player two if (this.IsPlayerActive(this.playerTwo)) { Ship playerShip = this.playerTwo.ControlObject; if (playerShip.Active) { // Draw a health bar when alive float health = playerShip.Hitpoints; canvas.State.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(device.TargetSize.X - 12 - 16 - 1, device.TargetSize.Y - 10 - 198 - 1, 16 + 2, 196 + 2); canvas.State.ColorTint = this.playerTwo.Color; canvas.DrawRect(device.TargetSize.X - 10 - 20, device.TargetSize.Y - 10 - 200, 20, 200); canvas.FillRect(device.TargetSize.X - 12 - 16, device.TargetSize.Y - 10 - health * 198.0f, 16, health * 196.0f); } else if (isAnyPlayerAlive && !this.playerTwo.HasReachedGoal) { // Draw a respawn timer when dead float respawnPercentage = this.playerTwo.RespawnTime / Player.RespawnDelay; string respawnText = string.Format("{0:F1} to Respawn", (Player.RespawnDelay - this.playerTwo.RespawnTime) / 1000.0f); Vector2 textSize = canvas.MeasureText(string.Format("{0:F1} to Respawn", 0.0f)); canvas.State.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(device.TargetSize.X - 10 - textSize.X - 3, device.TargetSize.Y - 10 - textSize.Y - 2, textSize.X + 2, textSize.Y + 10); canvas.State.ColorTint = this.playerTwo.Color; canvas.DrawText(respawnText, device.TargetSize.X - 10, device.TargetSize.Y - 10, 0.0f, Alignment.BottomRight); canvas.FillRect(device.TargetSize.X - 10 - textSize.X * respawnPercentage, device.TargetSize.Y - 10 - textSize.Y, textSize.X * respawnPercentage, 3); canvas.FillRect(device.TargetSize.X - 10 - textSize.X * respawnPercentage, device.TargetSize.Y - 10, textSize.X * respawnPercentage, 3); } } }
/// <summary> /// Performs a preprocessing operation for an incoming batch. Does nothing by default but may be overloaded, if needed. /// </summary> /// <typeparam name="T">The incoming vertex type</typeparam> /// <param name="device"></param> /// <param name="material"><see cref="Duality.Resources.Material"/> information for the current batch.</param> public virtual void PreprocessBatch(IDrawDevice device, IDrawBatch drawBatch) { }
void ICmpRenderer.Draw(IDrawDevice device) { RenderSpriteGlow(device, GameObj.GetComponent <SpriteRenderer>(), GlowType, ScaleAmount, OffsetAmount, Color, DrawTechnique.Res); }
public override void Draw(IDrawDevice device) { Vector3 posTemp = this.gameobj.Transform.Pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; MathF.GetTransformDotVec(this.GameObj.Transform.Angle, this.gameobj.Transform.Scale * scaleTemp, out xDot, out yDot); // Apply block alignment Vector2 textOffset = Vector2.Zero; Vector2 textSize = this.text.Size; if (this.text.MaxWidth > 0) { textSize.X = this.text.MaxWidth; } this.blockAlign.ApplyTo(ref textOffset, textSize); MathF.TransformDotVec(ref textOffset, ref xDot, ref yDot); posTemp.X += textOffset.X; posTemp.Y += textOffset.Y; if (this.text.Fonts != null && this.text.Fonts.Any(r => r.IsAvailable && r.Res.IsPixelGridAligned)) { posTemp.X = MathF.Round(posTemp.X); posTemp.Y = MathF.Round(posTemp.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { posTemp.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { posTemp.Y += 0.5f; } } // Draw design time metrics data if (DualityApp.ExecContext == DualityApp.ExecutionContext.Editor) { bool showLimits = true; bool showLines = false; bool showElements = false; Vector3 metricsOffset = new Vector3(0.0f, 0.0f, 0.01f); Vector3 lineOffset = new Vector3(0.5f, 0.5f, 0.0f); Vector3 tUnitX = Vector3.UnitX; Vector3 tUnitY = Vector3.UnitY; MathF.TransformDotVec(ref tUnitX, ref xDot, ref yDot); MathF.TransformDotVec(ref tUnitY, ref xDot, ref yDot); // Actual text size and maximum text size if (showLimits) { Vector3 textWidth = tUnitX * this.text.Size.X; Vector3 textHeight = tUnitY * this.text.Size.Y; Vector3 textMaxWidth = tUnitX * this.text.MaxWidth; Vector3 textMaxHeight = tUnitY * MathF.Max(this.text.MaxHeight, this.text.Size.Y); ColorRgba clrSize = ColorRgba.Green.WithAlpha(128); ColorRgba clrMaxSize = ColorRgba.Red.WithAlpha(128); device.AddVertices(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White), VertexMode.LineLoop, new VertexC1P3(metricsOffset + lineOffset + posTemp, clrSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textWidth, clrSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textWidth + textHeight, clrSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textHeight, clrSize)); device.AddVertices(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White), VertexMode.LineLoop, new VertexC1P3(metricsOffset + lineOffset + posTemp, clrMaxSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textMaxWidth, clrMaxSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textMaxWidth + textMaxHeight, clrMaxSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textMaxHeight, clrMaxSize)); } // Individual line sizes if (showLines) { ColorRgba clrLineBg = (ColorRgba.Blue + ColorRgba.Red).WithAlpha(64); for (int i = 0; i < this.text.TextMetrics.LineBounds.Count; i++) { Rect lineRect = this.text.TextMetrics.LineBounds[i]; device.AddVertices(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White), VertexMode.Quads, new VertexC1P3(metricsOffset + posTemp + lineRect.TopLeft.X * tUnitX + lineRect.TopLeft.Y * tUnitY, clrLineBg), new VertexC1P3(metricsOffset + posTemp + lineRect.BottomLeft.X * tUnitX + lineRect.BottomLeft.Y * tUnitY, clrLineBg), new VertexC1P3(metricsOffset + posTemp + lineRect.BottomRight.X * tUnitX + lineRect.BottomRight.Y * tUnitY, clrLineBg), new VertexC1P3(metricsOffset + posTemp + lineRect.TopRight.X * tUnitX + lineRect.TopRight.Y * tUnitY, clrLineBg)); } } // Individual line sizes if (showElements) { ColorRgba clrElementBg = (ColorRgba.Blue + ColorRgba.Green).WithAlpha(128); for (int i = 0; i < this.text.TextMetrics.ElementBounds.Count; i++) { Rect elemRect = this.text.TextMetrics.ElementBounds[i]; device.AddVertices(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White), VertexMode.LineLoop, new VertexC1P3(metricsOffset + lineOffset + posTemp + elemRect.TopLeft.X * tUnitX + elemRect.TopLeft.Y * tUnitY, clrElementBg), new VertexC1P3(metricsOffset + lineOffset + posTemp + elemRect.BottomLeft.X * tUnitX + elemRect.BottomLeft.Y * tUnitY, clrElementBg), new VertexC1P3(metricsOffset + lineOffset + posTemp + elemRect.BottomRight.X * tUnitX + elemRect.BottomRight.Y * tUnitY, clrElementBg), new VertexC1P3(metricsOffset + lineOffset + posTemp + elemRect.TopRight.X * tUnitX + elemRect.TopRight.Y * tUnitY, clrElementBg)); } } } ColorRgba matColor = this.customMat != null ? this.customMat.MainColor : ColorRgba.White; int[] vertLen = this.text.EmitVertices(ref this.vertFont, ref this.vertIcon, posTemp.X, posTemp.Y, posTemp.Z + this.VertexZOffset, this.colorTint * matColor, xDot, yDot); if (this.text.Fonts != null) { for (int i = 0; i < this.text.Fonts.Length; i++) { if (this.text.Fonts[i] != null && this.text.Fonts[i].IsAvailable) { if (this.customMat == null) { device.AddVertices(this.text.Fonts[i].Res.Material, VertexMode.Quads, this.vertFont[i], vertLen[i + 1]); } else { BatchInfo cm = new BatchInfo(this.customMat); cm.Textures = this.text.Fonts[i].Res.Material.Textures; device.AddVertices(cm, VertexMode.Quads, this.vertFont[i], vertLen[i + 1]); } } } } if (this.text.Icons != null && this.iconMat.IsAvailable) { device.AddVertices(this.iconMat, VertexMode.Quads, this.vertIcon, vertLen[0]); } }
void IGraphicsBackend.BeginRendering(IDrawDevice device, RenderOptions options, RenderStats stats) { DebugCheckOpenGLErrors(); this.CheckRenderingCapabilities(); this.currentDevice = device; this.renderOptions = options; this.renderStats = stats; // Prepare a shared index buffer object, in case we don't have one yet if (this.sharedBatchIBO == null) { this.sharedBatchIBO = new NativeGraphicsBuffer(GraphicsBufferType.Index); } // Prepare the target surface for rendering NativeRenderTarget.Bind(options.Target as NativeRenderTarget); // Determine whether masked blending should use alpha-to-coverage mode if (this.msaaIsDriverDisabled) { this.useAlphaToCoverageBlend = false; } else if (NativeRenderTarget.BoundRT != null) { this.useAlphaToCoverageBlend = NativeRenderTarget.BoundRT.Samples > 0; } else if (this.activeWindow != null) { this.useAlphaToCoverageBlend = this.activeWindow.IsMultisampled; } else { this.useAlphaToCoverageBlend = this.defaultGraphicsMode.Samples > 0; } // Determine the available size on the active rendering surface Point2 availableSize; if (NativeRenderTarget.BoundRT != null) { availableSize = new Point2(NativeRenderTarget.BoundRT.Width, NativeRenderTarget.BoundRT.Height); } else if (this.activeWindow != null) { availableSize = new Point2(this.activeWindow.Width, this.activeWindow.Height); } else { availableSize = this.externalBackbufferSize; } // Translate viewport coordinates to OpenGL screen coordinates (borrom-left, rising), unless rendering // to a texture, which is laid out Duality-like (top-left, descending) Rect openGLViewport = options.Viewport; if (NativeRenderTarget.BoundRT == null) { openGLViewport.Y = (availableSize.Y - openGLViewport.H) - openGLViewport.Y; } // Setup viewport and scissor rects GL.Viewport((int)openGLViewport.X, (int)openGLViewport.Y, (int)MathF.Ceiling(openGLViewport.W), (int)MathF.Ceiling(openGLViewport.H)); GL.Scissor((int)openGLViewport.X, (int)openGLViewport.Y, (int)MathF.Ceiling(openGLViewport.W), (int)MathF.Ceiling(openGLViewport.H)); // Clear buffers ClearBufferMask glClearMask = 0; ColorRgba clearColor = options.ClearColor; if ((options.ClearFlags & ClearFlag.Color) != ClearFlag.None) { glClearMask |= ClearBufferMask.ColorBufferBit; } if ((options.ClearFlags & ClearFlag.Depth) != ClearFlag.None) { glClearMask |= ClearBufferMask.DepthBufferBit; } GL.ClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f); GL.ClearDepth((double)options.ClearDepth); // The "float version" is from OpenGL 4.1.. GL.Clear(glClearMask); // Configure Rendering params GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); if (options.DepthTest) { GL.DepthFunc(DepthFunction.Lequal); } else { GL.DepthFunc(DepthFunction.Always); } // Prepare shared matrix stack for rendering Matrix4 viewMatrix = options.ViewMatrix; Matrix4 projectionMatrix = options.ProjectionMatrix; if (NativeRenderTarget.BoundRT != null) { Matrix4 flipOutput = Matrix4.CreateScale(1.0f, -1.0f, 1.0f); projectionMatrix = projectionMatrix * flipOutput; } this.renderOptions.ShaderParameters.Set( BuiltinShaderFields.ViewMatrix, viewMatrix); this.renderOptions.ShaderParameters.Set( BuiltinShaderFields.ProjectionMatrix, projectionMatrix); this.renderOptions.ShaderParameters.Set( BuiltinShaderFields.ViewProjectionMatrix, viewMatrix * projectionMatrix); }
/// <summary> /// Prepares rendering using this DrawTechnique. /// </summary> /// <param name="device"></param> /// <param name="material"></param> protected virtual void PrepareRendering(IDrawDevice device, BatchInfo material) { }
/// <summary> /// Sets up the appropriate OpenGL rendering state for this DrawTechnique. /// </summary> /// <param name="lastTechnique">The last DrawTechnique that has been set up. This parameter is optional, but /// specifying it will increase performance by reducing redundant state changes.</param> /// <param name="textures">A set of <see cref="Duality.Resources.Texture">Textures</see> to use.</param> /// <param name="uniforms">A set of <see cref="Duality.Resources.ShaderVarInfo">uniform values</see> to apply.</param> public void SetupForRendering(IDrawDevice device, BatchInfo material, DrawTechnique lastTechnique) { // Prepare Rendering if (this.NeedsPreparation) { // Clone the material, if not done yet due to vertex preprocessing if (!this.NeedsPreprocess) { material = new BatchInfo(material); } this.PrepareRendering(device, material); } // Setup BlendType if (lastTechnique == null || this.blendType != lastTechnique.blendType) { this.SetupBlendType(this.blendType, device.DepthWrite); } // Bind Shader ContentRef <ShaderProgram> selShader = this.SelectShader(); if (lastTechnique == null || selShader.Res != lastTechnique.shader.Res) { ShaderProgram.Bind(selShader); } // Setup shader data if (selShader.IsAvailable) { ShaderVarInfo[] varInfo = selShader.Res.VarInfo; // Setup sampler bindings automatically int curSamplerIndex = 0; if (material.Textures != null) { for (int i = 0; i < varInfo.Length; i++) { if (varInfo[i].glVarLoc == -1) { continue; } if (varInfo[i].type != ShaderVarType.Sampler2D) { continue; } // Bind Texture ContentRef <Texture> texRef = material.GetTexture(varInfo[i].name); Texture.Bind(texRef, curSamplerIndex); GL.Uniform1(varInfo[i].glVarLoc, curSamplerIndex); curSamplerIndex++; } } Texture.ResetBinding(curSamplerIndex); // Transfer uniform data from material to actual shader if (material.Uniforms != null) { for (int i = 0; i < varInfo.Length; i++) { if (varInfo[i].glVarLoc == -1) { continue; } float[] data = material.GetUniform(varInfo[i].name); if (data == null) { continue; } varInfo[i].SetupUniform(data); } } } // Setup fixed function data else { // Fixed function texture binding if (material.Textures != null) { int samplerIndex = 0; foreach (var pair in material.Textures) { Texture.Bind(pair.Value, samplerIndex); samplerIndex++; } Texture.ResetBinding(samplerIndex); } else { Texture.ResetBinding(); } } }
/// <summary> /// Performs a preprocessing operation for incoming vertices. Does nothing by default but may be overloaded, if needed. /// </summary> /// <typeparam name="T">The incoming vertex type</typeparam> /// <param name="device"></param> /// <param name="material"><see cref="Duality.Resources.Material"/> information for the current batch.</param> /// <param name="vertexMode">The mode of incoming vertex data.</param> /// <param name="vertexBuffer">A buffer storing incoming vertex data.</param> /// <param name="vertexCount">The number of vertices to preprocess, beginning at the start of the specified buffer.</param> public virtual void PreprocessBatch <T>(IDrawDevice device, BatchInfo material, ref VertexMode vertexMode, ref T[] vertexBuffer, ref int vertexCount) { }
public override void OnPaint(Canvas canvas, Rect view) { IDrawDevice device = canvas.DrawDevice; Vector2 center = device.TargetSize * 0.5f; center.Y *= 0.8f; string selectedDifficultyImage = GetDifficultyImage(selectedPlayerType); api.DrawMaterial("MenuDim", center.X * 0.36f, center.Y * 1.4f, Alignment.Center, ColorRgba.White, 24f, 36f); api.DrawMaterial(selectedDifficultyImage, selectedDifficulty, center.X * 0.36f, center.Y * 1.4f + 3f, Alignment.Center, new ColorRgba(0f, 0.2f * imageTransition), 0.88f, 0.88f); if (imageTransition < 1f) { string lastDifficultyImage = GetDifficultyImage(lastPlayerType); api.DrawMaterial(lastDifficultyImage, lastDifficulty, center.X * 0.36f, center.Y * 1.4f, Alignment.Center, new ColorRgba(1f, 1f - imageTransition), 0.88f, 0.88f); } api.DrawMaterial(selectedDifficultyImage, selectedDifficulty, center.X * 0.36f, center.Y * 1.4f, Alignment.Center, new ColorRgba(1f, imageTransition), 0.88f, 0.88f); int charOffset = 0; for (int i = 0; i < items.Length; i++) { if (selectedIndex == i) { float size = 0.5f + Ease.OutElastic(animation) * 0.6f; api.DrawMaterial("MenuGlow", center.X, center.Y, Alignment.Center, ColorRgba.White.WithAlpha(0.4f * size), (items[i].Length + 3) * 0.5f * size, 4f * size); api.DrawStringShadow(ref charOffset, items[i], center.X, center.Y, Alignment.Center, null, size, 0.7f, 1.1f, 1.1f, charSpacing: 0.9f); } else { api.DrawString(ref charOffset, items[i], center.X, center.Y, Alignment.Center, ColorRgba.TransparentBlack, 0.9f); } if (i == 0) { string[] playerTypes = { "Jazz", "Spaz", "Lori" }; ColorRgba[] playerColors = { new ColorRgba(0.2f, 0.45f, 0.2f, 0.5f), new ColorRgba(0.45f, 0.27f, 0.22f, 0.5f), new ColorRgba(0.5f, 0.45f, 0.22f, 0.5f) }; float offset, spacing; if (availableCharacters == 1) { offset = 0f; spacing = 0f; } else if (availableCharacters == 2) { offset = 50f; spacing = 100f; } else { offset = 100f; spacing = 300f / availableCharacters; } for (int j = 0; j < availableCharacters; j++) { float x = center.X - offset + j * spacing; if (selectedPlayerType == j) { api.DrawMaterial("MenuGlow", x, center.Y + 28f, Alignment.Center, ColorRgba.White.WithAlpha(0.2f), (playerTypes[j].Length + 3) * 0.4f, 2.2f); api.DrawStringShadow(ref charOffset, playerTypes[j], x, center.Y + 28f, Alignment.Center, playerColors[j], 0.9f, 0.4f, 0.55f, 0.55f, 8f, 0.9f); } else { api.DrawString(ref charOffset, playerTypes[j], x, center.Y + 28f, Alignment.Center, ColorRgba.TransparentBlack, 0.8f, charSpacing: 0.9f); } } api.DrawStringShadow(ref charOffset, "<", center.X - (100f + 40f), center.Y + 28f, Alignment.Center, ColorRgba.TransparentBlack, 0.7f); api.DrawStringShadow(ref charOffset, ">", center.X + (100f + 40f), center.Y + 28f, Alignment.Center, ColorRgba.TransparentBlack, 0.7f); } else if (i == 1) { for (int j = 0; j < difficultyTypes.Length; j++) { if (selectedDifficulty == j) { api.DrawMaterial("MenuGlow", center.X + (j - 1) * 100f, center.Y + 28f, Alignment.Center, ColorRgba.White.WithAlpha(0.2f), (difficultyTypes[j].Length + 3) * 0.4f, 2.2f); api.DrawStringShadow(ref charOffset, difficultyTypes[j], center.X + (j - 1) * 100f, center.Y + 28f, Alignment.Center, null, 0.9f, 0.4f, 0.55f, 0.55f, 8f, 0.9f); } else { api.DrawString(ref charOffset, difficultyTypes[j], center.X + (j - 1) * 100f, center.Y + 28f, Alignment.Center, ColorRgba.TransparentBlack, 0.8f, charSpacing: 0.9f); } } api.DrawStringShadow(ref charOffset, "<", center.X - (100f + 40f), center.Y + 28f, Alignment.Center, ColorRgba.TransparentBlack, 0.7f); api.DrawStringShadow(ref charOffset, ">", center.X + (100f + 40f), center.Y + 28f, Alignment.Center, ColorRgba.TransparentBlack, 0.7f); } center.Y += 70f; } if (imageTransition < 1f) { imageTransition += Time.TimeMult * 0.1f; if (imageTransition > 1f) { imageTransition = 1f; } } }
public override void Draw(IDrawDevice device) { // Determine basic working data Tilemap tilemap = this.ActiveTilemap; Tileset tileset = tilemap != null ? tilemap.Tileset.Res : null; Point2 tileCount = tilemap != null ? tilemap.Size : new Point2(1, 1); Vector2 tileSize = tileset != null ? tileset.TileSize : Tileset.DefaultTileSize; // Early-out, if insufficient if (tilemap == null) { return; } if (tileset == null) { return; } // Determine the total size and origin of the rendered Tilemap Vector2 renderTotalSize = tileCount * tileSize; Vector2 renderOrigin = Vector2.Zero; this.origin.ApplyTo(ref renderOrigin, ref renderTotalSize); MathF.TransformCoord(ref renderOrigin.X, ref renderOrigin.Y, this.GameObj.Transform.Angle, this.GameObj.Transform.Scale); // Determine Tile visibility TilemapCulling.TileInput cullingIn = new TilemapCulling.TileInput { // Remember: All these transform values are in world space TilemapPos = this.GameObj.Transform.Pos + new Vector3(renderOrigin), TilemapScale = this.GameObj.Transform.Scale, TilemapAngle = this.GameObj.Transform.Angle, TileCount = tileCount, TileSize = tileSize }; TilemapCulling.TileOutput cullingOut = TilemapCulling.GetVisibleTileRect(device, cullingIn); int renderedTileCount = cullingOut.VisibleTileCount.X * cullingOut.VisibleTileCount.Y; // Determine rendering parameters Material material = (tileset != null ? tileset.RenderMaterial : null) ?? Material.Checkerboard.Res; ColorRgba mainColor = material.MainColor * this.colorTint; // Reserve the required space for vertex data in our locally cached buffer if (this.vertices == null) { this.vertices = new RawList <VertexC1P3T2>(); } this.vertices.Count = renderedTileCount * 4; VertexC1P3T2[] vertexData = this.vertices.Data; // Determine and adjust data for Z offset generation float depthPerTile = -cullingIn.TileSize.Y * cullingIn.TilemapScale * this.tileDepthScale; if (this.tileDepthMode == TileDepthOffsetMode.Flat) { depthPerTile = 0.0f; } float originDepthOffset = Rect.Align(this.origin, 0, 0, 0, tileCount.Y * depthPerTile).Y; if (this.tileDepthMode == TileDepthOffsetMode.World) { originDepthOffset += (this.GameObj.Transform.Pos.Y / (float)tileSize.Y) * depthPerTile; } cullingOut.RenderOriginView.Z += this.offset + this.tileDepthOffset * depthPerTile + originDepthOffset; // Prepare vertex generation data Vector2 tileXStep = cullingOut.XAxisView * cullingIn.TileSize.X; Vector2 tileYStep = cullingOut.YAxisView * cullingIn.TileSize.Y; Vector3 renderPos = cullingOut.RenderOriginView; Point2 tileGridPos = cullingOut.VisibleTileStart; // Prepare vertex data array for batch-submitting IReadOnlyGrid <Tile> tiles = tilemap.Tiles; TileInfo[] tileData = tileset.TileData.Data; int submittedTileCount = 0; int vertexBaseIndex = 0; for (int tileIndex = 0; tileIndex < renderedTileCount; tileIndex++) { Tile tile = tiles[tileGridPos.X, tileGridPos.Y]; if (tile.Index < tileData.Length) { Rect uvRect = tileData[tile.Index].TexCoord0; bool visualEmpty = tileData[tile.Index].IsVisuallyEmpty; int tileBaseOffset = tileData[tile.Index].DepthOffset; float localDepthOffset = (tile.DepthOffset + tileBaseOffset) * depthPerTile; if (!visualEmpty) { vertexData[vertexBaseIndex + 0].Pos.X = renderPos.X; vertexData[vertexBaseIndex + 0].Pos.Y = renderPos.Y; vertexData[vertexBaseIndex + 0].Pos.Z = renderPos.Z + localDepthOffset; 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 + tileYStep.X; vertexData[vertexBaseIndex + 1].Pos.Y = renderPos.Y + tileYStep.Y; vertexData[vertexBaseIndex + 1].Pos.Z = renderPos.Z + localDepthOffset + depthPerTile; 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 + tileXStep.X + tileYStep.X; vertexData[vertexBaseIndex + 2].Pos.Y = renderPos.Y + tileXStep.Y + tileYStep.Y; vertexData[vertexBaseIndex + 2].Pos.Z = renderPos.Z + localDepthOffset + depthPerTile; 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 + tileXStep.X; vertexData[vertexBaseIndex + 3].Pos.Y = renderPos.Y + tileXStep.Y; vertexData[vertexBaseIndex + 3].Pos.Z = renderPos.Z + localDepthOffset; vertexData[vertexBaseIndex + 3].TexCoord.X = uvRect.X + uvRect.W; vertexData[vertexBaseIndex + 3].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 3].Color = mainColor; bool vertical = tileData[tile.Index].IsVertical; if (vertical) { vertexData[vertexBaseIndex + 0].Pos.Z += depthPerTile; vertexData[vertexBaseIndex + 3].Pos.Z += depthPerTile; } submittedTileCount++; vertexBaseIndex += 4; } } tileGridPos.X++; renderPos.X += tileXStep.X; renderPos.Y += tileXStep.Y; if ((tileGridPos.X - cullingOut.VisibleTileStart.X) >= cullingOut.VisibleTileCount.X) { tileGridPos.X = cullingOut.VisibleTileStart.X; tileGridPos.Y++; renderPos = cullingOut.RenderOriginView; renderPos.X += tileYStep.X * (tileGridPos.Y - cullingOut.VisibleTileStart.Y); renderPos.Y += tileYStep.Y * (tileGridPos.Y - cullingOut.VisibleTileStart.Y); renderPos.Z += tileGridPos.Y * depthPerTile; } } // Submit all the vertices as one draw batch device.AddVertices( material, VertexMode.Quads, vertexData, submittedTileCount * 4); Profile.AddToStat(@"Duality\Stats\Render\Tilemaps\NumTiles", renderedTileCount); Profile.AddToStat(@"Duality\Stats\Render\Tilemaps\NumVertices", submittedTileCount * 4); }
protected void PrepareVerticesSmooth(ref VertexC1P3T4A1[] vertices, IDrawDevice device, float curAnimFrameFade, ColorRgba mainClr, Rect uvRect, Rect uvRectNext) { Vector3 posTemp = this.gameobj.Transform.Pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; MathF.GetTransformDotVec(this.GameObj.Transform.Angle, scaleTemp, out xDot, out yDot); Rect rectTemp = this.rect.Transform(this.gameobj.Transform.Scale, this.gameobj.Transform.Scale); 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); if (vertices == null || vertices.Length != 4) { vertices = new VertexC1P3T4A1[4]; } vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = uvRect.X; vertices[0].TexCoord.Y = uvRect.Y; vertices[0].TexCoord.Z = uvRectNext.X; vertices[0].TexCoord.W = uvRectNext.Y; vertices[0].Color = mainClr; vertices[0].Attrib = curAnimFrameFade; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = uvRect.X; vertices[1].TexCoord.Y = uvRect.MaximumY; vertices[1].TexCoord.Z = uvRectNext.X; vertices[1].TexCoord.W = uvRectNext.MaximumY; vertices[1].Color = mainClr; vertices[1].Attrib = curAnimFrameFade; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = uvRect.MaximumX; vertices[2].TexCoord.Y = uvRect.MaximumY; vertices[2].TexCoord.Z = uvRectNext.MaximumX; vertices[2].TexCoord.W = uvRectNext.MaximumY; vertices[2].Color = mainClr; vertices[2].Attrib = curAnimFrameFade; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = uvRect.MaximumX; vertices[3].TexCoord.Y = uvRect.Y; vertices[3].TexCoord.Z = uvRectNext.MaximumX; vertices[3].TexCoord.W = uvRectNext.Y; vertices[3].Color = mainClr; vertices[3].Attrib = curAnimFrameFade; if (this.pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
public override void Draw(IDrawDevice device) { // Determine basic working data Tilemap tilemap = this.ActiveTilemap; Tileset tileset = tilemap != null ? tilemap.Tileset.Res : null; Point2 tileCount = tilemap != null ? tilemap.Size : new Point2(1, 1); Vector2 tileSize = tileset != null ? tileset.TileSize : Tileset.DefaultTileSize; // Early-out, if insufficient if (tilemap == null) return; if (tileset == null) return; // Determine the total size and origin of the rendered Tilemap Vector2 renderTotalSize = tileCount * tileSize; Vector2 renderOrigin = Vector2.Zero; this.origin.ApplyTo(ref renderOrigin, ref renderTotalSize); MathF.TransformCoord(ref renderOrigin.X, ref renderOrigin.Y, this.GameObj.Transform.Angle, this.GameObj.Transform.Scale); // Determine Tile visibility TilemapCulling.TileInput cullingIn = new TilemapCulling.TileInput { // Remember: All these transform values are in world space TilemapPos = this.GameObj.Transform.Pos + new Vector3(renderOrigin), TilemapScale = this.GameObj.Transform.Scale, TilemapAngle = this.GameObj.Transform.Angle, TileCount = tileCount, TileSize = tileSize }; TilemapCulling.TileOutput cullingOut = TilemapCulling.GetVisibleTileRect(device, cullingIn); int renderedTileCount = cullingOut.VisibleTileCount.X * cullingOut.VisibleTileCount.Y; // Determine rendering parameters Material material = (tileset != null ? tileset.RenderMaterial : null) ?? Material.Checkerboard.Res; ColorRgba mainColor = material.MainColor * this.colorTint; // Reserve the required space for vertex data in our locally cached buffer if (this.vertices == null) this.vertices = new RawList<VertexC1P3T2>(); this.vertices.Count = renderedTileCount * 4; VertexC1P3T2[] vertexData = this.vertices.Data; // Determine and adjust data for Z offset generation float depthPerTile = -cullingIn.TileSize.Y * cullingIn.TilemapScale * this.tileDepthScale; if (this.tileDepthMode == TileDepthOffsetMode.Flat) depthPerTile = 0.0f; float originDepthOffset = Rect.Align(this.origin, 0, 0, 0, tileCount.Y * depthPerTile).Y; if (this.tileDepthMode == TileDepthOffsetMode.World) originDepthOffset += (this.GameObj.Transform.Pos.Y / (float)tileSize.Y) * depthPerTile; cullingOut.RenderOriginView.Z += this.offset + this.tileDepthOffset * depthPerTile + originDepthOffset; // Prepare vertex generation data Vector2 tileXStep = cullingOut.XAxisView * cullingIn.TileSize.X; Vector2 tileYStep = cullingOut.YAxisView * cullingIn.TileSize.Y; Vector3 renderPos = cullingOut.RenderOriginView; Point2 tileGridPos = cullingOut.VisibleTileStart; // Prepare vertex data array for batch-submitting IReadOnlyGrid<Tile> tiles = tilemap.Tiles; TileInfo[] tileData = tileset.TileData.Data; int submittedTileCount = 0; int vertexBaseIndex = 0; for (int tileIndex = 0; tileIndex < renderedTileCount; tileIndex++) { Tile tile = tiles[tileGridPos.X, tileGridPos.Y]; if (tile.Index < tileData.Length) { Rect uvRect = tileData[tile.Index].TexCoord0; bool visualEmpty = tileData[tile.Index].IsVisuallyEmpty; int tileBaseOffset = tileData[tile.Index].DepthOffset; float localDepthOffset = (tile.DepthOffset + tileBaseOffset) * depthPerTile; if (!visualEmpty) { vertexData[vertexBaseIndex + 0].Pos.X = renderPos.X; vertexData[vertexBaseIndex + 0].Pos.Y = renderPos.Y; vertexData[vertexBaseIndex + 0].Pos.Z = renderPos.Z + localDepthOffset; 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 + tileYStep.X; vertexData[vertexBaseIndex + 1].Pos.Y = renderPos.Y + tileYStep.Y; vertexData[vertexBaseIndex + 1].Pos.Z = renderPos.Z + localDepthOffset + depthPerTile; 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 + tileXStep.X + tileYStep.X; vertexData[vertexBaseIndex + 2].Pos.Y = renderPos.Y + tileXStep.Y + tileYStep.Y; vertexData[vertexBaseIndex + 2].Pos.Z = renderPos.Z + localDepthOffset + depthPerTile; 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 + tileXStep.X; vertexData[vertexBaseIndex + 3].Pos.Y = renderPos.Y + tileXStep.Y; vertexData[vertexBaseIndex + 3].Pos.Z = renderPos.Z + localDepthOffset; vertexData[vertexBaseIndex + 3].TexCoord.X = uvRect.X + uvRect.W; vertexData[vertexBaseIndex + 3].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 3].Color = mainColor; bool vertical = tileData[tile.Index].IsVertical; if (vertical) { vertexData[vertexBaseIndex + 0].Pos.Z += depthPerTile; vertexData[vertexBaseIndex + 3].Pos.Z += depthPerTile; } submittedTileCount++; vertexBaseIndex += 4; } } tileGridPos.X++; renderPos.X += tileXStep.X; renderPos.Y += tileXStep.Y; if ((tileGridPos.X - cullingOut.VisibleTileStart.X) >= cullingOut.VisibleTileCount.X) { tileGridPos.X = cullingOut.VisibleTileStart.X; tileGridPos.Y++; renderPos = cullingOut.RenderOriginView; renderPos.X += tileYStep.X * (tileGridPos.Y - cullingOut.VisibleTileStart.Y); renderPos.Y += tileYStep.Y * (tileGridPos.Y - cullingOut.VisibleTileStart.Y); renderPos.Z += tileGridPos.Y * depthPerTile; } } // Submit all the vertices as one draw batch device.AddVertices( material, VertexMode.Quads, vertexData, submittedTileCount * 4); Profile.AddToStat(@"Duality\Stats\Render\Tilemaps\NumTiles", renderedTileCount); Profile.AddToStat(@"Duality\Stats\Render\Tilemaps\NumVertices", submittedTileCount * 4); }
void ICmpRenderer.Draw(IDrawDevice device) { Profile.BeginMeasure(@"ProfileRenderer"); Canvas canvas = new Canvas(device); canvas.CurrentState.SetMaterial(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White, null)); bool anyTextReport = this.textReportPerf || this.textReportStat; bool anyGraph = this.drawGraphs && this.counterGraphs.Count > 0; // Determine geometry int areaWidth = (int)device.TargetSize.X - 20; if (anyGraph && anyTextReport) areaWidth = (areaWidth - 10) / 2; Rect textReportRect = new Rect( 10, 10, anyTextReport ? areaWidth : 0, (int)device.TargetSize.Y - 20); Rect graphRect = new Rect( anyTextReport ? (textReportRect.MaximumX + 10) : 10, 10, anyGraph ? areaWidth : 0, (int)device.TargetSize.Y - 20); // Text Reports if (anyTextReport) { // Update Report IEnumerable<ProfileCounter> counters = Profile.GetUsedCounters(); if (!this.textReportPerf) counters = counters.Where(c => !(c is TimeCounter)); if (!this.textReportStat) counters = counters.Where(c => !(c is StatCounter)); if (this.textReport == null || (Time.MainTimer - this.textReportLast).TotalMilliseconds > this.updateInterval) { string report = Profile.GetTextReport(counters, this.textReportOptions | ReportOptions.FormattedText); if (this.textReport == null) { this.textReport = new FormattedText(); this.textReport.Fonts = new[] { Font.GenericMonospace8 }; } this.textReport.MaxWidth = (int)textReportRect.W; this.textReport.SourceText = report; this.textReportLast = Time.MainTimer; } // Draw Report canvas.DrawTextBackground(textReport, textReportRect.X, textReportRect.Y); canvas.DrawText(textReport, ref textReportTextVert, ref textReportIconVert, textReportRect.X, textReportRect.Y); } // Counter Graphs if (anyGraph) { // Mark graph cache as unused foreach (GraphCacheEntry entry in this.graphCache.Values) { entry.WasUsed = false; } int space = 5; int graphY = (int)graphRect.Y; int graphH = MathF.Min((int)(graphRect.H / this.counterGraphs.Count) - space, (int)graphRect.W / 2); foreach (string counterName in this.counterGraphs) { ProfileCounter counter = Profile.GetCounter<ProfileCounter>(counterName); if (counter == null) return; // Create or retrieve graph cache entry GraphCacheEntry cache = null; if (!this.graphCache.TryGetValue(counterName, out cache)) { cache = new GraphCacheEntry(); cache.GraphValues = new float[ProfileCounter.ValueHistoryLen]; cache.GraphColors = new ColorRgba[ProfileCounter.ValueHistoryLen]; this.graphCache[counterName] = cache; } cache.WasUsed = true; float cursorRatio = 0.0f; if (counter is TimeCounter) { TimeCounter timeCounter = counter as TimeCounter; for (int i = 0; i < ProfileCounter.ValueHistoryLen; i++) { float factor = timeCounter.ValueGraph[i] / Time.MsPFMult; cache.GraphValues[i] = factor * 0.75f; cache.GraphColors[i] = ColorRgba.Lerp(ColorRgba.White, ColorRgba.Red, factor); } canvas.CurrentState.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(graphRect.X, graphY, graphRect.W, graphH); canvas.CurrentState.ColorTint = ColorRgba.White; canvas.DrawHorizontalGraph(cache.GraphValues, cache.GraphColors, ref cache.VertGraph, graphRect.X, graphY, graphRect.W, graphH); cursorRatio = (float)timeCounter.ValueGraphCursor / (float)ProfileCounter.ValueHistoryLen; } else if (counter is StatCounter) { StatCounter statCounter = counter as StatCounter; for (int i = 0; i < ProfileCounter.ValueHistoryLen; i++) { cache.GraphValues[i] = (float)(statCounter.ValueGraph[i] - statCounter.MinValue) / statCounter.MaxValue; cache.GraphColors[i] = ColorRgba.White; } canvas.CurrentState.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(graphRect.X, graphY, graphRect.W, graphH); canvas.CurrentState.ColorTint = ColorRgba.White; canvas.DrawHorizontalGraph(cache.GraphValues, cache.GraphColors, ref cache.VertGraph, graphRect.X, graphY, graphRect.W, graphH); cursorRatio = (float)statCounter.ValueGraphCursor / (float)ProfileCounter.ValueHistoryLen; } canvas.DrawText(new string[] { counter.FullName }, ref cache.VertText, graphRect.X, graphY); canvas.DrawLine(graphRect.X + graphRect.W * cursorRatio, graphY, graphRect.X + graphRect.W * cursorRatio, graphY + graphH); graphY += graphH + space; } // Remove unused graph cache entries foreach (var pair in this.graphCache.ToArray()) { if (!pair.Value.WasUsed) { pair.Value.GraphColors = null; pair.Value.GraphValues = null; pair.Value.VertGraph = null; pair.Value.VertText = null; this.graphCache.Remove(pair.Key); } } } Profile.EndMeasure(@"ProfileRenderer"); }
void IGraphicsBackend.BeginRendering(IDrawDevice device, RenderOptions options, RenderStats stats) { this.currentDevice = device; this.renderStats = stats; // Prepare the target surface for rendering NativeRenderTarget.Bind(options.Target as NativeRenderTarget); if (this.primaryVBO == 0) { GL.GenBuffers(1, out this.primaryVBO); } GL.BindBuffer(BufferTarget.ArrayBuffer, this.primaryVBO); // Setup viewport Rect viewportRect = options.Viewport; GL.Viewport((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H); GL.Scissor((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H); // Clear buffers ClearBufferMask glClearMask = 0; ColorRgba clearColor = options.ClearColor; if ((options.ClearFlags & ClearFlag.Color) != ClearFlag.None) { glClearMask |= ClearBufferMask.ColorBufferBit; } if ((options.ClearFlags & ClearFlag.Depth) != ClearFlag.None) { glClearMask |= ClearBufferMask.DepthBufferBit; } GL.ClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f); GL.ClearDepth((double)options.ClearDepth); // The "float version" is from OpenGL 4.1.. GL.Clear(glClearMask); // Configure Rendering params if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Always); } else { GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Lequal); } OpenTK.Matrix4 openTkModelView; Matrix4 modelView = options.ModelViewMatrix; GetOpenTKMatrix(ref modelView, out openTkModelView); GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref openTkModelView); OpenTK.Matrix4 openTkProjection; Matrix4 projection = options.ProjectionMatrix; GetOpenTKMatrix(ref projection, out openTkProjection); GL.MatrixMode(MatrixMode.Projection); GL.LoadMatrix(ref openTkProjection); if (NativeRenderTarget.BoundRT != null) { if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Translate(0.0f, NativeRenderTarget.BoundRT.Height * 0.5f, 0.0f); } GL.Scale(1.0f, -1.0f, 1.0f); if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Translate(0.0f, -NativeRenderTarget.BoundRT.Height * 0.5f, 0.0f); } } }
/// <summary> /// Transforms world space coordinates to screen space coordinates. /// </summary> /// <param name="spacePos"></param> /// <param name="device"></param> /// <returns></returns> public static Vector3 GetScreenCoord(this IDrawDevice device, Vector2 spacePos) { return(device.GetScreenCoord(new Vector3(spacePos))); }
void IGraphicsBackend.EndRendering() { GL.BindBuffer(BufferTarget.ArrayBuffer, 0); this.currentDevice = null; }
void ICmpRenderer.Draw(IDrawDevice device) { Player player = this.GameObj.ParentScene.FindComponent <Player>(); Ship playerShip = player.ControlTarget; Canvas canvas = new Canvas(device); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White)); ColorRgba baseColor = ColorRgba.White.WithAlpha(this.displayedTeamColor.W); ColorRgba defaultColor = this.displayedTeamColor.ToColor().WithAlpha(1.0f) * baseColor; if (this.gameOverFade > 0.0f) { canvas.State.ColorTint = ColorRgba.Black.WithAlpha(this.gameOverFade); canvas.FillRect(0.0f, 0.0f, canvas.Width, canvas.Height); } if (baseColor.A == 0) { return; } canvas.State.ColorTint = defaultColor; // Health bar float healthBarHeight = 150; canvas.State.ColorTint = defaultColor * ColorRgba.Black.WithAlpha(0.25f); canvas.FillRect( 10, canvas.Height - 10 - healthBarHeight, 30, healthBarHeight); canvas.State.ColorTint = defaultColor; canvas.DrawRect( 10, canvas.Height - 10 - healthBarHeight, 30, healthBarHeight); canvas.FillRect( 12, canvas.Height - 12 - (healthBarHeight - 4) * playerShip.Health, 26, (healthBarHeight - 4) * playerShip.Health); // Energy bar float energyBarHeight = 150; canvas.FillRect( 10 + 30 + 2, canvas.Height - 10 - energyBarHeight * playerShip.WeaponEnergy, 5, energyBarHeight * playerShip.WeaponEnergy); // Radar float radarDisplayRadius = 100.0f; Rect radarArea = Rect.Align( Alignment.BottomRight, canvas.Width - 10, canvas.Height - 10, radarDisplayRadius * 2.0f, radarDisplayRadius * 2.0f); float radarRange = 2500.0f; canvas.State.ColorTint = defaultColor * ColorRgba.Black.WithAlpha(0.25f); canvas.FillOval( radarArea.X, radarArea.Y, radarArea.W, radarArea.H); foreach (SpawnPoint spawnpoint in player.GameObj.ParentScene.FindComponents <SpawnPoint>()) { Vector3 relativePos = spawnpoint.GameObj.Transform.Pos - playerShip.GameObj.Transform.Pos; Vector3 normalizedPos = relativePos / radarRange; if ((normalizedPos * radarDisplayRadius).Xy.Length > radarDisplayRadius - 6.0f) { continue; } Vector2 posOnRadar = radarArea.Center + (normalizedPos * radarDisplayRadius).Xy; canvas.State.ColorTint = baseColor * spawnpoint.TeamColor * ColorRgba.Grey; canvas.FillCircle(posOnRadar.X, posOnRadar.Y, 6.0f); } foreach (Ship ship in player.GameObj.ParentScene.FindComponents <Ship>()) { Vector3 relativePos = ship.GameObj.Transform.Pos - playerShip.GameObj.Transform.Pos; Vector3 normalizedPos = relativePos / radarRange; if ((normalizedPos * radarDisplayRadius).Xy.Length > radarDisplayRadius - 3.0f) { continue; } Vector2 posOnRadar = radarArea.Center + (normalizedPos * radarDisplayRadius).Xy; canvas.State.ColorTint = baseColor * ship.TeamColor; canvas.FillCircle(posOnRadar.X, posOnRadar.Y, 3.0f); } foreach (Laser laser in player.GameObj.ParentScene.FindComponents <Laser>()) { Vector3 relativePos = laser.GameObj.Transform.Pos - playerShip.GameObj.Transform.Pos; Vector3 normalizedPos = relativePos / radarRange; if (normalizedPos.Length > 1.0f) { continue; } Vector2 posOnRadar = radarArea.Center + (normalizedPos * radarDisplayRadius).Xy; canvas.State.ColorTint = baseColor * laser.TeamColor; canvas.FillRect(posOnRadar.X, posOnRadar.Y, 1.0f, 1.0f); } canvas.State.ColorTint = defaultColor; canvas.DrawOval( radarArea.X, radarArea.Y, radarArea.W, radarArea.H); Vector2 diffToCenter = -playerShip.GameObj.Transform.Pos.Xy; Vector2 dirToCenter = diffToCenter.Normalized; float centerIndicatorLength = MathF.Min(10.0f, 10.0f * diffToCenter.Length / 2000.0f); canvas.State.ColorTint = defaultColor * ColorRgba.White.WithAlpha(0.5f); canvas.DrawLine( radarArea.CenterX, radarArea.CenterY, radarArea.CenterX + dirToCenter.X * centerIndicatorLength, radarArea.CenterY + dirToCenter.Y * centerIndicatorLength); canvas.State.ColorTint = defaultColor; canvas.FillCircle(radarArea.CenterX, radarArea.CenterY, 3.0f); }
public override void OnPaint(Canvas canvas, Rect view) { IDrawDevice device = canvas.DrawDevice; Vector2 center = device.TargetSize * 0.5f; const float topLine = 131f; float bottomLine = device.TargetSize.Y - 42; api.DrawMaterial("MenuDim", center.X, (topLine + bottomLine) * 0.5f, Alignment.Center, ColorRgba.White, 55f, (bottomLine - topLine) * 0.063f, new Rect(0f, 0.3f, 1f, 0.4f)); api.DrawMaterial("MenuLine", 0, center.X, topLine, Alignment.Center, ColorRgba.White, 1.6f); api.DrawMaterial("MenuLine", 1, center.X, bottomLine, Alignment.Center, ColorRgba.White, 1.6f); int charOffset = 0; api.DrawStringShadow(ref charOffset, "menu/play story/title".T(), center.X, 110f, Alignment.Center, new ColorRgba(0.5f, 0.5f), 0.9f, 0.4f, 0.6f, 0.6f, 8f, charSpacing: 0.88f); if (episodes.Count > 0) { float topItem = topLine - 5f; float bottomItem = bottomLine + 5f; float contentHeight = bottomItem - topItem; float itemSpacing = contentHeight / (episodes.Count + 1); topItem += itemSpacing; float topItemSelected = 0f; for (int i = 0; i < episodes.Count; i++) { if (selectedIndex == i) { topItemSelected = topItem; } else { if (episodes[i].IsAvailable) { api.DrawString(ref charOffset, episodes[i].Episode.Name, center.X, topItem, Alignment.Center, ColorRgba.TransparentBlack, 0.9f); } else { api.DrawString(ref charOffset, episodes[i].Episode.Name, center.X, topItem, Alignment.Center, new ColorRgba(0.4f, 0.4f), 0.9f); } } topItem += itemSpacing; } // Selected item last float expandedAnimation2 = Math.Min(expandedAnimation * 6f, 1f); float expandedAnimation3 = (expandedAnimation2 * expandedAnimation2 * (3.0f - 2.0f * expandedAnimation2)); float size = 0.5f + Ease.OutElastic(selectAnimation) * 0.5f + (1f - expandedAnimation3) * 0.2f; if (episodes[selectedIndex].IsAvailable) { if (episodes[selectedIndex].Logo.IsAvailable) { api.DrawString(ref charOffset, episodes[selectedIndex].Episode.Name, center.X, topItemSelected, Alignment.Center, new ColorRgba(0.44f, 0.5f * MathF.Max(0f, 1f - selectAnimation * 2f)), 0.9f - selectAnimation * 0.5f); ContentRef <Material> logo = episodes[selectedIndex].Logo; Texture texture = logo.Res.MainTexture.Res; Vector2 originPos = new Vector2(center.X, topItemSelected); Vector2 logoSize = new Vector2(texture.InternalWidth * size, texture.InternalHeight * size); Alignment.Center.ApplyTo(ref originPos, logoSize); ColorRgba logoColor = ColorRgba.White.WithAlpha(1f - expandedAnimation3 * 0.5f); canvas.State.SetMaterial(logo); canvas.State.ColorTint = logoColor; canvas.FillRect(originPos.X, originPos.Y, texture.InternalWidth * size, texture.InternalHeight * size); if (episodes[selectedIndex].IsComplete) { api.DrawMaterial("EpisodeComplete", originPos.X + logoSize.X * 0.7f, originPos.Y + logoSize.Y * 0.4f, Alignment.TopLeft, logoColor, size, size); } if (episodes[selectedIndex].CanContinue) { float moveX = expandedAnimation3 * -24f; api.DrawString(ref charOffset, ">", center.X + 80f + moveX, topItemSelected, Alignment.Right, new ColorRgba(0.5f, 0.5f * MathF.Min(1f, 0.4f + selectAnimation)), 0.8f, charSpacing: 0.9f); if (expanded) { float expandedAnimation4 = Ease.OutElastic(expandedAnimation) * 0.8f; api.DrawStringShadow(ref charOffset, "menu/play story/restart".T(), center.X + 110f, topItemSelected, Alignment.Center, new ColorRgba(0.62f, 0.44f, 0.34f, 0.5f * MathF.Min(1f, 0.4f + expandedAnimation3)), expandedAnimation4, 0.4f, 0.6f, 0.6f, 8f, charSpacing: 0.8f); } } } else { api.DrawStringShadow(ref charOffset, episodes[selectedIndex].Episode.Name, center.X, topItemSelected, Alignment.Center, null, size, charSpacing: 0.9f); } } else { api.DrawString(ref charOffset, episodes[selectedIndex].Episode.Name, center.X, topItemSelected, Alignment.Center, new ColorRgba(0.4f, MathF.Max(0.3f, 0.4f - selectAnimation * 0.4f)), MathF.Max(0.7f, 0.9f - selectAnimation * 0.6f)); int index = episodes.IndexOfFirst(entry => entry.Episode.Token == episodes[selectedIndex].Episode.PreviousEpisode); Episode previousEpisode; if (index == -1) { previousEpisode = null; } else { previousEpisode = episodes[index].Episode; } string info; if (previousEpisode == null) { info = "menu/play story/locked".T(); } else { info = "menu/play story/locked prev".T(previousEpisode.Name); } api.DrawStringShadow(ref charOffset, info, center.X, topItemSelected, Alignment.Center, new ColorRgba(0.66f, 0.42f, 0.32f, MathF.Min(0.5f, 0.2f + 2f * selectAnimation)), 0.7f * size, charSpacing: 0.9f); } } else { api.DrawStringShadow(ref charOffset, "menu/play story/empty".T(), center.X, center.Y, Alignment.Center, new ColorRgba(0.62f, 0.44f, 0.34f, 0.5f), 0.9f, 0.4f, 0.6f, 0.6f, 8f, charSpacing: 0.88f); } }
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); } }
void ICmpRenderer.Draw(IDrawDevice device) { // Create a buffer to cache and re-use vertices. Not required, but will boost performance. if (this.buffer == null) this.buffer = new CanvasBuffer(); // Create a Canvas to auto-generate vertices from high-level drawing commands. Canvas canvas = new Canvas(device, this.buffer); canvas.State.TextFont = this.font; // If the game is over or won, display "game over" screen if (this.gameOver || this.gameWin) { // Various animation timing variables. float animOffset = this.gameWin ? 0.0f : 2500.0f; float animTime = this.gameWin ? 10000.0f : 4500.0f; float blendDurationRatio = this.gameWin ? 0.6f : 0.5f; float textOffsetRatio = this.gameWin ? 0.2f : 0.0f; float timeSinceGameOver = (float)Time.MainTimer.TotalMilliseconds - this.lastTimeAnyAlive; float gameOverAnimProgress = MathF.Clamp((timeSinceGameOver - animOffset) / animTime, 0.0f, 1.0f); float controlInfoAnimProgress = MathF.Clamp(((timeSinceGameOver - animOffset) - animTime - 2000.0f) / 2000.0f, 0.0f, 1.0f); float blendAnimProgress = MathF.Clamp(gameOverAnimProgress / blendDurationRatio, 0.0f, 1.0f); float textAnimProgress = MathF.Clamp((gameOverAnimProgress - blendDurationRatio - textOffsetRatio) / (1.0f - blendDurationRatio - textOffsetRatio), 0.0f, 1.0f); if (this.blendMaterial != null && blendAnimProgress > 0.0f) { canvas.PushState(); if (this.gameOver) { // Set up our special blending Material and specify the threshold to blend to this.blendMaterial.SetUniform("threshold", 1.0f - blendAnimProgress); canvas.State.SetMaterial(this.blendMaterial); canvas.State.ColorTint = ColorRgba.Black; // Specify a texture coordinate rect so it spans the entire screen repeating itself, instead of being stretched if (this.blendMaterial.MainTexture != null) { Random rnd = new Random((int)this.lastTimeAnyAlive); Vector2 randomTranslate = rnd.NextVector2(0.0f, 0.0f, canvas.State.TextureBaseSize.X, canvas.State.TextureBaseSize.Y); canvas.State.TextureCoordinateRect = new Rect( randomTranslate.X, randomTranslate.Y, device.TargetSize.X / canvas.State.TextureBaseSize.X, device.TargetSize.Y / canvas.State.TextureBaseSize.Y); } } else { // If we won, simply fade to white canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Add, ColorRgba.White)); canvas.State.ColorTint = ColorRgba.White.WithAlpha(blendAnimProgress); } // Fill the screen with a rect of our Material canvas.FillRect(0, 0, device.TargetSize.X, device.TargetSize.Y); canvas.PopState(); } if (this.font != null && textAnimProgress > 0.0f) { canvas.PushState(); // Determine which text to draw to screen and where to draw it string gameOverText = this.gameWin ? "is it over..?" : "darkness..."; Vector2 fullTextSize = canvas.MeasureText(gameOverText); Vector2 textPos = device.TargetSize * 0.5f - fullTextSize * 0.5f; gameOverText = gameOverText.Substring(0, MathF.RoundToInt(gameOverText.Length * textAnimProgress)); // Make sure not to draw inbetween pixels, so the text is perfectly sharp. textPos.X = MathF.Round(textPos.X); textPos.Y = MathF.Round(textPos.Y); // Draw the text to screen canvas.State.ColorTint = this.gameWin ? ColorRgba.Black : ColorRgba.White; canvas.DrawText(gameOverText, textPos.X, textPos.Y); canvas.PopState(); } if (controlInfoAnimProgress > 0.0f) { Vector2 infoBasePos = device.TargetSize * 0.5f + new Vector2(0.0f, device.TargetSize.Y * 0.25f); if (this.controlInfoMouseKeyboard != null) { canvas.PushState(); Vector2 texSize = this.controlInfoMouseKeyboard.Res.MainTexture.Res.Size * 0.5f; canvas.State.SetMaterial(this.controlInfoMouseKeyboard); canvas.State.ColorTint = ColorRgba.White.WithAlpha(controlInfoAnimProgress); canvas.FillRect( infoBasePos.X - texSize.X * 0.5f, infoBasePos.Y - texSize.Y - 10, texSize.X, texSize.Y); canvas.PopState(); } if (this.controlInfoGamepad != null) { canvas.PushState(); Vector2 texSize = this.controlInfoGamepad.Res.MainTexture.Res.Size * 0.5f; canvas.State.SetMaterial(this.controlInfoGamepad); canvas.State.ColorTint = ColorRgba.White.WithAlpha(controlInfoAnimProgress); canvas.FillRect( infoBasePos.X - texSize.X * 0.5f, infoBasePos.Y + 10, texSize.X, texSize.Y); canvas.PopState(); } } } }
public override void OnPaint(Canvas canvas) { IDrawDevice device = canvas.DrawDevice; Vector2 center = device.TargetSize * 0.5f; const float topLine = 131f; float bottomLine = device.TargetSize.Y - 42; api.DrawMaterial("MenuDim", center.X, (topLine + bottomLine) * 0.5f, Alignment.Center, ColorRgba.White, 55f, (bottomLine - topLine) * 0.063f, new Rect(0f, 0.3f, 1f, 0.4f)); int charOffset = 0; api.DrawStringShadow(ref charOffset, "Controls for Player #1", center.X * 0.3f, 110f, Alignment.Left, new ColorRgba(0.5f, 0.5f), 0.9f, 0.4f, 0.6f, 0.6f, 8f, charSpacing: 0.88f); api.DrawStringShadow(ref charOffset, "Key 1", center.X * (0.9f + 0 * 0.34f), 110f, Alignment.Center, new ColorRgba(0.46f, 0.5f), 0.8f, charSpacing: 0.88f); api.DrawStringShadow(ref charOffset, "Key 2", center.X * (0.9f + 1 * 0.34f), 110f, Alignment.Center, new ColorRgba(0.46f, 0.5f), 0.8f, charSpacing: 0.88f); api.DrawStringShadow(ref charOffset, "Gamepad", center.X * (0.9f + 2 * 0.34f), 110f, Alignment.Center, new ColorRgba(0.46f, 0.5f), 0.8f, charSpacing: 0.88f); int n = (int)PlayerActions.Count; float topItem = topLine - 5f; float bottomItem = bottomLine + 5f; float contentHeight = bottomItem - topItem; float itemSpacing = contentHeight / (n + 1); topItem += itemSpacing; for (int i = 0; i < n; i++) { string name; switch ((PlayerActions)i) { case PlayerActions.Left: name = "Left"; break; case PlayerActions.Right: name = "Right"; break; case PlayerActions.Up: name = "Up / Look Up"; break; case PlayerActions.Down: name = "Down / Crouch"; break; case PlayerActions.Fire: name = "Fire"; break; case PlayerActions.Jump: name = "Jump"; break; case PlayerActions.Run: name = "Run"; break; case PlayerActions.SwitchWeapon: name = "Switch Weapon"; break; default: name = ((PlayerActions)i).ToString(); break; } ref Mapping mapping = ref ControlScheme.GetCurrentMapping(0, (PlayerActions)i); api.DrawString(ref charOffset, name, center.X * 0.3f, topItem, Alignment.Left, ColorRgba.TransparentBlack, 0.8f); for (int j = 0; j < possibleButtons; j++) { string value; switch (j) { case 0: if (mapping.Key1 != Key.Unknown) { value = mapping.Key1.ToString(); } else { value = "-"; } break; case 1: if (mapping.Key2 != Key.Unknown) { value = mapping.Key2.ToString(); } else { value = "-"; } break; case 2: if (mapping.GamepadIndex != -1) { value = mapping.GamepadIndex + " : " + mapping.GamepadButton; } else { value = "-"; } break; default: value = null; break; } if (selectedIndex == i && selectedColumn == j) { float size = 0.5f + Ease.OutElastic(animation) * 0.5f; api.DrawStringShadow(ref charOffset, value, center.X * (0.9f + j * 0.34f), topItem, Alignment.Center, waitForInput ? new ColorRgba(0.62f, 0.44f, 0.34f, 0.5f) : new ColorRgba(0.48f, 0.5f), size, 0.7f, 1.1f, 1.1f, charSpacing: 0.9f); } else { api.DrawString(ref charOffset, value, center.X * (0.9f + j * 0.34f), topItem, Alignment.Center, ColorRgba.TransparentBlack, 0.8f); } } topItem += itemSpacing; }
/// <summary> /// Determines if the Renderer is visible to the specified <see cref="IDrawDevice"/>. /// This is usually the case if they share at least one mutual <see cref="VisibilityGroup">visibility group</see>. /// </summary> /// <param name="device"></param> /// <returns></returns> public virtual bool IsVisible(IDrawDevice device) { if ((device.VisibilityMask & VisibilityFlag.ScreenOverlay) != (this.visibilityGroup & VisibilityFlag.ScreenOverlay)) return false; if ((this.visibilityGroup & device.VisibilityMask & VisibilityFlag.AllGroups) == VisibilityFlag.None) return false; return device.IsCoordInView(this.gameobj.Transform.Pos, this.BoundRadius); }
bool ICmpRenderer.IsVisible(IDrawDevice device) { return((device.VisibilityMask & VisibilityFlag.ScreenOverlay) != VisibilityFlag.None); }
public override void Draw(IDrawDevice device) { Vector3 posTemp = this.gameobj.Transform.Pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; MathF.GetTransformDotVec(this.GameObj.Transform.Angle, this.gameobj.Transform.Scale * scaleTemp, out xDot, out yDot); // Apply block alignment Vector2 textOffset = Vector2.Zero; Vector2 textSize = this.text.Size; if (this.text.MaxWidth > 0) textSize.X = this.text.MaxWidth; this.blockAlign.ApplyTo(ref textOffset, textSize); MathF.TransformDotVec(ref textOffset, ref xDot, ref yDot); posTemp.X += textOffset.X; posTemp.Y += textOffset.Y; if (this.text.Fonts != null && this.text.Fonts.Any(r => r.IsAvailable && r.Res.IsPixelGridAligned)) { posTemp.X = MathF.Round(posTemp.X); posTemp.Y = MathF.Round(posTemp.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) posTemp.X += 0.5f; if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) posTemp.Y += 0.5f; } // Draw design time metrics data if (DualityApp.ExecContext == DualityApp.ExecutionContext.Editor) { bool showLimits = true; bool showLines = false; bool showElements = false; Vector3 metricsOffset = new Vector3(0.0f, 0.0f, 0.01f); Vector3 lineOffset = new Vector3(0.5f, 0.5f, 0.0f); Vector3 tUnitX = Vector3.UnitX; Vector3 tUnitY = Vector3.UnitY; MathF.TransformDotVec(ref tUnitX, ref xDot, ref yDot); MathF.TransformDotVec(ref tUnitY, ref xDot, ref yDot); // Actual text size and maximum text size if (showLimits) { Vector3 textWidth = tUnitX * this.text.Size.X; Vector3 textHeight = tUnitY * this.text.Size.Y; Vector3 textMaxWidth = tUnitX * this.text.MaxWidth; Vector3 textMaxHeight = tUnitY * MathF.Max(this.text.MaxHeight, this.text.Size.Y); ColorRgba clrSize = ColorRgba.Green.WithAlpha(128); ColorRgba clrMaxSize = ColorRgba.Red.WithAlpha(128); device.AddVertices(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White), VertexMode.LineLoop, new VertexC1P3(metricsOffset + lineOffset + posTemp, clrSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textWidth, clrSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textWidth + textHeight, clrSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textHeight, clrSize)); device.AddVertices(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White), VertexMode.LineLoop, new VertexC1P3(metricsOffset + lineOffset + posTemp, clrMaxSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textMaxWidth, clrMaxSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textMaxWidth + textMaxHeight, clrMaxSize), new VertexC1P3(metricsOffset + lineOffset + posTemp + textMaxHeight, clrMaxSize)); } // Individual line sizes if (showLines) { ColorRgba clrLineBg = (ColorRgba.Blue + ColorRgba.Red).WithAlpha(64); for (int i = 0; i < this.text.TextMetrics.LineBounds.Count; i++) { Rect lineRect = this.text.TextMetrics.LineBounds[i]; device.AddVertices(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White), VertexMode.Quads, new VertexC1P3(metricsOffset + posTemp + lineRect.TopLeft.X * tUnitX + lineRect.TopLeft.Y * tUnitY, clrLineBg), new VertexC1P3(metricsOffset + posTemp + lineRect.BottomLeft.X * tUnitX + lineRect.BottomLeft.Y * tUnitY, clrLineBg), new VertexC1P3(metricsOffset + posTemp + lineRect.BottomRight.X * tUnitX + lineRect.BottomRight.Y * tUnitY, clrLineBg), new VertexC1P3(metricsOffset + posTemp + lineRect.TopRight.X * tUnitX + lineRect.TopRight.Y * tUnitY, clrLineBg)); } } // Individual line sizes if (showElements) { ColorRgba clrElementBg = (ColorRgba.Blue + ColorRgba.Green).WithAlpha(128); for (int i = 0; i < this.text.TextMetrics.ElementBounds.Count; i++) { Rect elemRect = this.text.TextMetrics.ElementBounds[i]; device.AddVertices(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White), VertexMode.LineLoop, new VertexC1P3(metricsOffset + lineOffset + posTemp + elemRect.TopLeft.X * tUnitX + elemRect.TopLeft.Y * tUnitY, clrElementBg), new VertexC1P3(metricsOffset + lineOffset + posTemp + elemRect.BottomLeft.X * tUnitX + elemRect.BottomLeft.Y * tUnitY, clrElementBg), new VertexC1P3(metricsOffset + lineOffset + posTemp + elemRect.BottomRight.X * tUnitX + elemRect.BottomRight.Y * tUnitY, clrElementBg), new VertexC1P3(metricsOffset + lineOffset + posTemp + elemRect.TopRight.X * tUnitX + elemRect.TopRight.Y * tUnitY, clrElementBg)); } } } ColorRgba matColor = this.customMat != null ? this.customMat.MainColor : ColorRgba.White; int[] vertLen = this.text.EmitVertices(ref this.vertFont, ref this.vertIcon, posTemp.X, posTemp.Y, posTemp.Z, this.colorTint * matColor, xDot, yDot); if (this.text.Fonts != null) { for (int i = 0; i < this.text.Fonts.Length; i++) { if (this.text.Fonts[i] != null && this.text.Fonts[i].IsAvailable) { if (this.customMat == null) { device.AddVertices(this.text.Fonts[i].Res.Material, VertexMode.Quads, this.vertFont[i], vertLen[i + 1]); } else { BatchInfo cm = new BatchInfo(this.customMat); cm.Textures = this.text.Fonts[i].Res.Material.Textures; device.AddVertices(cm, VertexMode.Quads, this.vertFont[i], vertLen[i + 1]); } } } } if (this.text.Icons != null && this.iconMat.IsAvailable) { device.AddVertices(this.iconMat, VertexMode.Quads, this.vertIcon, vertLen[0]); } }
protected void PrepareVerticesLightSmooth(ref VertexC1P3T4A4A1[] vertices, IDrawDevice device, float curAnimFrameFade, ColorRgba mainClr, Rect uvRect, Rect uvRectNext, DrawTechnique tech) { bool perPixel = tech is LightingTechnique; Vector3 pos = this.GameObj.Transform.Pos; Vector3 posTemp = pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; float rotation = this.GameObj.Transform.Angle; MathF.GetTransformDotVec(rotation, out xDot, out yDot); Rect rectTemp = this.rect.Transformed(this.GameObj.Transform.Scale, this.GameObj.Transform.Scale); 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); // Using Per-Vertex Lighting? Calculate vertex light values Vector4[] vertexLight = null; if (!perPixel) { vertexLight = new Vector4[4]; Light.GetLightAtWorldPos(pos + new Vector3(edge1), out vertexLight[0], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge2), out vertexLight[1], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge3), out vertexLight[2], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge4), out vertexLight[3], this.vertexTranslucency); } Vector2.Multiply(ref edge1, scaleTemp, out edge1); Vector2.Multiply(ref edge2, scaleTemp, out edge2); Vector2.Multiply(ref edge3, scaleTemp, out edge3); Vector2.Multiply(ref edge4, scaleTemp, out edge4); // Using Per-Pixel Lighting? Pass objRotation Matrix via vertex attribute. Vector4 objRotMat = Vector4.Zero; if (perPixel) objRotMat = new Vector4((float)Math.Cos(-rotation), -(float)Math.Sin(-rotation), (float)Math.Sin(-rotation), (float)Math.Cos(-rotation)); if (vertices == null || vertices.Length != 4) vertices = new VertexC1P3T4A4A1[4]; // Calculate UV coordinates float left = uvRect.X; float right = uvRect.RightX; float top = uvRect.Y; float bottom = uvRect.BottomY; float nextLeft = uvRectNext.X; float nextRight = uvRectNext.RightX; float nextTop = uvRectNext.Y; float nextBottom = uvRectNext.BottomY; if ((this.flipMode & FlipMode.Horizontal) != FlipMode.None) { MathF.Swap(ref left, ref right); MathF.Swap(ref nextLeft, ref nextRight); } if ((this.flipMode & FlipMode.Vertical) != FlipMode.None) { MathF.Swap(ref top, ref bottom); MathF.Swap(ref nextTop, ref nextBottom); } // Directly pass World Position with each vertex, see note in Light.cs vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = left; vertices[0].TexCoord.Y = top; vertices[0].TexCoord.Z = nextLeft; vertices[0].TexCoord.W = nextTop; vertices[0].Color = mainClr; vertices[0].Attrib = perPixel ? objRotMat : vertexLight[0]; vertices[0].Attrib2 = curAnimFrameFade; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = left; vertices[1].TexCoord.Y = bottom; vertices[1].TexCoord.Z = nextLeft; vertices[1].TexCoord.W = nextBottom; vertices[1].Color = mainClr; vertices[1].Attrib = perPixel ? objRotMat : vertexLight[1]; vertices[1].Attrib2 = curAnimFrameFade; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = right; vertices[2].TexCoord.Y = bottom; vertices[2].TexCoord.Z = nextRight; vertices[2].TexCoord.W = nextBottom; vertices[2].Color = mainClr; vertices[2].Attrib = perPixel ? objRotMat : vertexLight[2]; vertices[2].Attrib2 = curAnimFrameFade; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = right; vertices[3].TexCoord.Y = top; vertices[3].TexCoord.Z = nextRight; vertices[3].TexCoord.W = nextTop; vertices[3].Color = mainClr; vertices[3].Attrib = perPixel ? objRotMat : vertexLight[3]; vertices[3].Attrib2 = curAnimFrameFade; if (this.pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
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++; } } }
/// <summary> /// Performs the Renderers drawing operation. /// </summary> /// <param name="device"></param> public abstract void Draw(IDrawDevice device);
private void OnRender(IDrawDevice device) { Vector2 center = device.TargetSize * 0.5f; canvas.Begin(device); int charOffset = 0; int charOffsetShadow = 0; RenderTexturedBackground(device); // Title DrawMaterial("MenuCarrot", -1, center.X - 76f, 64f + 2f, Alignment.Center, new ColorRgba(0f, 0.3f), 0.8f, 0.8f); DrawMaterial("MenuCarrot", -1, center.X - 76f, 64f, Alignment.Center, ColorRgba.White, 0.8f, 0.8f); fontMedium.DrawString(ref charOffsetShadow, "Jazz", center.X - 63f, 70f + 2f, Alignment.Left, new ColorRgba(0f, 0.32f), 0.75f, 1.63f, 3f, 3f, 0f, 0.92f); fontMedium.DrawString(ref charOffsetShadow, "2", center.X - 19f, 70f - 8f + 2f, Alignment.Left, new ColorRgba(0f, 0.32f), 0.5f, 0f, 0f, 0f, 0f); fontMedium.DrawString(ref charOffsetShadow, "Resurrection", center.X - 10f, 70f + 4f + 2.5f, Alignment.Left, new ColorRgba(0f, 0.3f), 0.5f, 0.4f, 1.2f, 1.2f, 7f, 0.8f); fontMedium.DrawString(ref charOffset, "Jazz", center.X - 63f, 70f, Alignment.Left, new ColorRgba(0.54f, 0.44f, 0.34f, 0.5f), 0.75f, 1.63f, 3f, 3f, 0f, 0.92f); fontMedium.DrawString(ref charOffset, "2", center.X - 19f, 70f - 8f, Alignment.Left, new ColorRgba(0.54f, 0.44f, 0.34f, 0.5f), 0.5f, 0f, 0f, 0f, 0f); fontMedium.DrawString(ref charOffset, "Resurrection", center.X - 10f, 70f + 4f, Alignment.Left, new ColorRgba(0.6f, 0.42f, 0.42f, 0.5f), 0.5f, 0.4f, 1.2f, 1.2f, 7f, 0.8f); // Version Vector2 bottomRight = device.TargetSize; bottomRight.X -= 24f; bottomRight.Y -= 10f; DrawStringShadow(ref charOffset, "v" + App.AssemblyVersion, bottomRight.X, bottomRight.Y, Alignment.BottomRight, ColorRgba.TransparentBlack, 0.7f, 0.4f, 1.2f, 1.2f, 7f, 0.8f); // Copyright Vector2 bottomLeft = bottomRight; bottomLeft.X = 24f; DrawStringShadow(ref charOffset, "(c) 2016-" + DateTime.Now.Year + " Dan R.", bottomLeft.X, bottomLeft.Y, Alignment.BottomLeft, ColorRgba.TransparentBlack, 0.7f, 0.4f, 1.2f, 1.2f, 7f, 0.8f); // New Version if (!string.IsNullOrEmpty(newVersion)) { DrawStringShadow(ref charOffset, "New version available: " + newVersion, (bottomLeft.X + bottomRight.X) * 0.5f, bottomLeft.Y, Alignment.Bottom, new ColorRgba(0.62f, 0.44f, 0.34f, 0.5f), 0.7f, 0.4f, 1.2f, 1.2f, 7f, 0.9f); } // Current section if (sectionStack.Count > 0) { sectionStack.Peek().OnPaint(canvas); } DrawTouch(device.TargetSize); canvas.End(); }
void ICmpRenderer.Draw(IDrawDevice device) { mainMenu.OnRender(device); }
public abstract void Draw(IDrawDevice device);
protected void PrepareVertices(ref VertexC1P3T2[] vertices, IDrawDevice device, ColorRgba mainClr, Rect uvRect) { Vector3 posTemp = this.gameobj.Transform.Pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; MathF.GetTransformDotVec(this.GameObj.Transform.Angle, scaleTemp, out xDot, out yDot); Rect rectTemp = this.rect.Transformed(this.gameobj.Transform.Scale, this.gameobj.Transform.Scale); 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); float left = uvRect.X; float right = uvRect.RightX; float top = uvRect.Y; float bottom = uvRect.BottomY; if ((this.flipMode & FlipMode.Horizontal) != FlipMode.None) MathF.Swap(ref left, ref right); if ((this.flipMode & FlipMode.Vertical) != FlipMode.None) MathF.Swap(ref top, ref bottom); if (vertices == null || vertices.Length != 4) vertices = new VertexC1P3T2[4]; vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = left; vertices[0].TexCoord.Y = top; vertices[0].Color = mainClr; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = left; vertices[1].TexCoord.Y = bottom; vertices[1].Color = mainClr; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = right; vertices[2].TexCoord.Y = bottom; vertices[2].Color = mainClr; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = right; vertices[3].TexCoord.Y = top; vertices[3].Color = mainClr; if (this.pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
public override void Draw(IDrawDevice device) { if (particles == null) { return; } Texture tex = RetrieveTexture(); if (tex == null) { return; } Vector2 particleHalfSize = particleSize * 0.5f; float objAngle = GameObj.Transform.Angle; float objScale = GameObj.Transform.Scale; Vector3 objPos = GameObj.Transform.Pos; Vector2 objXDot, objYDot; MathF.GetTransformDotVec(objAngle, objScale, out objXDot, out objYDot); if (vertexBuffer == null) { vertexBuffer = new RawList <VertexC1P3T2>(particles.Count * 4); } vertexBuffer.Count = vertexBuffer.Count = particles.Count * 4; VertexC1P3T2[] vertexData = vertexBuffer.Data; Particle[] particleData = particles.Data; int particleCount = particles.Count; for (int i = 0; i < particleCount; i++) { ColorRgba color = particleData[i].Color; float alpha = (float)color.A / 255.0f; if (fadeOutAt < 1.0f) { alpha *= MathF.Clamp((1.0f - particleData[i].AgeFactor) / fadeOutAt, 0.0f, 1.0f); } if (fadeInAt > 0.0f) { alpha *= MathF.Clamp(particleData[i].AgeFactor / fadeInAt, 0.0f, 1.0f); } color.A = (byte)(alpha * 255.0f); Rect uvRect; tex.LookupAtlas(particleData[i].SpriteIndex, out uvRect); Vector3 particlePos = particleData[i].Position; MathF.TransformDotVec(ref particlePos, ref objXDot, ref objYDot); particlePos += objPos; float particleAngle = objAngle + particleData[i].Angle; float particleScale = objScale; device.PreprocessCoords(ref particlePos, ref particleScale); Vector2 xDot, yDot; MathF.GetTransformDotVec(particleAngle, particleScale, out xDot, out yDot); Vector2 edgeTopLeft = new Vector2(-particleHalfSize.X, -particleHalfSize.Y); Vector2 edgeBottomLeft = new Vector2(-particleHalfSize.X, particleHalfSize.Y); Vector2 edgeBottomRight = new Vector2(particleHalfSize.X, particleHalfSize.Y); Vector2 edgeTopRight = new Vector2(particleHalfSize.X, -particleHalfSize.Y); MathF.TransformDotVec(ref edgeTopLeft, ref xDot, ref yDot); MathF.TransformDotVec(ref edgeBottomLeft, ref xDot, ref yDot); MathF.TransformDotVec(ref edgeBottomRight, ref xDot, ref yDot); MathF.TransformDotVec(ref edgeTopRight, ref xDot, ref yDot); int vertexBaseIndex = i * 4; vertexData[vertexBaseIndex + 0].Pos.X = particlePos.X + edgeTopLeft.X; vertexData[vertexBaseIndex + 0].Pos.Y = particlePos.Y + edgeTopLeft.Y; vertexData[vertexBaseIndex + 0].Pos.Z = particlePos.Z; vertexData[vertexBaseIndex + 0].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 0].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 0].Color = color; vertexData[vertexBaseIndex + 1].Pos.X = particlePos.X + edgeBottomLeft.X; vertexData[vertexBaseIndex + 1].Pos.Y = particlePos.Y + edgeBottomLeft.Y; vertexData[vertexBaseIndex + 1].Pos.Z = particlePos.Z; vertexData[vertexBaseIndex + 1].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 1].TexCoord.Y = uvRect.BottomY; vertexData[vertexBaseIndex + 1].Color = color; vertexData[vertexBaseIndex + 2].Pos.X = particlePos.X + edgeBottomRight.X; vertexData[vertexBaseIndex + 2].Pos.Y = particlePos.Y + edgeBottomRight.Y; vertexData[vertexBaseIndex + 2].Pos.Z = particlePos.Z; vertexData[vertexBaseIndex + 2].TexCoord.X = uvRect.RightX; vertexData[vertexBaseIndex + 2].TexCoord.Y = uvRect.BottomY; vertexData[vertexBaseIndex + 2].Color = color; vertexData[vertexBaseIndex + 3].Pos.X = particlePos.X + edgeTopRight.X; vertexData[vertexBaseIndex + 3].Pos.Y = particlePos.Y + edgeTopRight.Y; vertexData[vertexBaseIndex + 3].Pos.Z = particlePos.Z; vertexData[vertexBaseIndex + 3].TexCoord.X = uvRect.RightX; vertexData[vertexBaseIndex + 3].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 3].Color = color; } device.AddVertices(material, VertexMode.Quads, vertexData, vertexBuffer.Count); }
internal void NotifyCollectDrawcalls(IDrawDevice device) { Profile.TimeCollectDrawcalls.BeginMeasure(); if (this.CollectDrawcalls != null) this.CollectDrawcalls(this, new CollectDrawcallEventArgs(device)); Profile.TimeCollectDrawcalls.EndMeasure(); }
void IGraphicsBackend.BeginRendering(IDrawDevice device, RenderOptions options, RenderStats stats) { DebugCheckOpenGLErrors(); this.currentDevice = device; this.renderOptions = options; this.renderStats = stats; // Prepare the target surface for rendering NativeRenderTarget.Bind(options.Target as NativeRenderTarget); // Determine the available size on the active rendering surface //Point2 availableSize; //if (NativeRenderTarget.BoundRT != null) { // availableSize = new Point2(NativeRenderTarget.BoundRT.Width, NativeRenderTarget.BoundRT.Height); //} else { // availableSize = this.externalBackbufferSize; //} Rect openGLViewport = options.Viewport; // Setup viewport and scissor rects GL.Viewport((int)openGLViewport.X, (int)openGLViewport.Y, (int)MathF.Ceiling(openGLViewport.W), (int)MathF.Ceiling(openGLViewport.H)); GL.Scissor((int)openGLViewport.X, (int)openGLViewport.Y, (int)MathF.Ceiling(openGLViewport.W), (int)MathF.Ceiling(openGLViewport.H)); // Clear buffers ClearBufferMask glClearMask = 0; ColorRgba clearColor = options.ClearColor; if ((options.ClearFlags & ClearFlag.Color) != ClearFlag.None) { glClearMask |= ClearBufferMask.ColorBufferBit; } if ((options.ClearFlags & ClearFlag.Depth) != ClearFlag.None) { glClearMask |= ClearBufferMask.DepthBufferBit; } GL.ClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f); GL.ClearDepth(options.ClearDepth); GL.Clear(glClearMask); // Configure Rendering params GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); if (options.DepthTest) { GL.DepthFunc(DepthFunction.Lequal); } else { GL.DepthFunc(DepthFunction.Always); } Matrix4 view = options.ViewMatrix; Matrix4 projection = options.ProjectionMatrix; if (NativeRenderTarget.BoundRT != null) { Matrix4 flipOutput = Matrix4.CreateScale(1.0f, -1.0f, 1.0f); projection = projection * flipOutput; } // Convert matrices to float arrays GetArrayMatrix(ref view, viewData); GetArrayMatrix(ref projection, projectionData); // All EBOs can be used again lastUsedEBO = 0; }
bool ICmpRenderer.IsVisible(IDrawDevice device) { return DualityApp.ExecContext == DualityApp.ExecutionContext.Game && (device.VisibilityMask & VisibilityFlag.ScreenOverlay) != VisibilityFlag.None && (device.VisibilityMask & VisibilityFlag.AllGroups) != VisibilityFlag.None; }
public static void SetupLighting(IDrawDevice device, BatchInfo material) { DeviceLightInfo info = UpdateLighting(device); // Prepare shader dara float[] _lightPos = new float[4 * MaxVisible]; float[] _lightDir = new float[4 * MaxVisible]; float[] _lightColor = new float[3 * MaxVisible]; int _lightCount = MathF.Min(MaxVisible, info.PriorizedLights.Count); int i = 0; foreach (Light light in info.PriorizedLights) { if (light.Disposed) { continue; } Vector3 dir; Vector3 pos; float uniformScale; bool directional = light.IsDirectional; if (directional) { dir = light.dir; pos = Vector3.Zero; uniformScale = 1.0f; } else { dir = light.dir; pos = light.GameObj.Transform.Pos; uniformScale = light.GameObj.Transform.Scale; MathF.TransformCoord(ref dir.X, ref dir.Y, light.GameObj.Transform.Angle); } if (directional) { _lightPos[i * 4 + 0] = (float)light.ambientColor.R * light.ambientIntensity / 255.0f; _lightPos[i * 4 + 1] = (float)light.ambientColor.G * light.ambientIntensity / 255.0f; _lightPos[i * 4 + 2] = (float)light.ambientColor.B * light.ambientIntensity / 255.0f; _lightPos[i * 4 + 3] = 0.0f; } else { _lightPos[i * 4 + 0] = pos.X; _lightPos[i * 4 + 1] = pos.Y; _lightPos[i * 4 + 2] = pos.Z; _lightPos[i * 4 + 3] = light.range * uniformScale; } _lightDir[i * 4 + 0] = dir.X; _lightDir[i * 4 + 1] = dir.Y; _lightDir[i * 4 + 2] = dir.Z; _lightDir[i * 4 + 3] = dir == Vector3.Zero ? 0.0f : MathF.Max(light.spotFocus, 1.0f); _lightColor[i * 3 + 0] = (float)light.color.R * light.intensity / 255.0f; _lightColor[i * 3 + 1] = (float)light.color.G * light.intensity / 255.0f; _lightColor[i * 3 + 2] = (float)light.color.B * light.intensity / 255.0f; i++; if (i >= _lightCount) { break; } } if (i + 1 < _lightCount) { _lightCount = i + 1; } material.SetUniform("_lightCount", _lightCount); material.SetUniform("_lightPos", _lightPos); material.SetUniform("_lightDir", _lightDir); material.SetUniform("_lightColor", _lightColor); }
/// <summary> /// Enumerates all <see cref="Duality.Components.Renderer">Renderers</see> that are visible to /// the specified <see cref="IDrawDevice"/>. /// </summary> /// <param name="device"></param> /// <returns></returns> public IEnumerable <ICmpRenderer> QueryVisibleRenderers(IDrawDevice device) { return(this.renderers.Where(r => r.Active && (r as ICmpRenderer).IsVisible(device)).OfType <ICmpRenderer>()); }
public override void PrepareRendering(IDrawDevice device, BatchInfo material) { base.PrepareRendering(device, material); DynamicLighting.Light.SetupLighting(device, material); }