public SceneGenerator SelectGenerator(int floor, int seed) { // for testing //return new SceneGeneratorIce(this, floor); List <Func <SceneGenerator> > gens = new List <Func <SceneGenerator> > { () => new SceneGeneratorJungle(this, floor), () => new SceneGeneratorLava(this, floor), () => new SceneGeneratorIce(this, floor) }; Mathg.Shuffle(new Random(seed), gens); gens.Insert(0, () => new SceneGeneratorDefault(this, floor)); return(gens[((floor - 1) / 4) % gens.Count].Invoke()); }
public void Raster(Scene scene) { Camera camera = scene.Camera; // Reset console for (int i = 0; i < console.Width; i++) { for (int j = 0; j < console.Height; j++) { console.Data[i, j] = ' '; console.Color[i, j] = 255; zBuffer[i, j] = 1; bBuffer[i, j] = Vector3.Zero; tBuffer[i, j] = null; } } List <Triangle> triangles = new List <Triangle>(); ASCII_FPS.triangleCount = 0; ASCII_FPS.triangleCountClipped = 0; ASCII_FPS.zonesRendered = 0; // Extract dynamic meshes Matrix cameraSpaceMatrix = camera.CameraSpaceMatrix; foreach (GameObject gameObject in scene.gameObjects) { MeshObject mesh = gameObject.MeshObject; ASCII_FPS.triangleCount += mesh.triangles.Count; Matrix meshToCameraMatrix = mesh.WorldSpaceMatrix * cameraSpaceMatrix; foreach (Triangle triangle in mesh.triangles) { Vector3 v0 = Vector3.Transform(triangle.V0, meshToCameraMatrix); Vector3 v1 = Vector3.Transform(triangle.V1, meshToCameraMatrix); Vector3 v2 = Vector3.Transform(triangle.V2, meshToCameraMatrix); triangles.Add(new Triangle(v0, v1, v2, triangle.Texture, triangle.UV0, triangle.UV1, triangle.UV2)); } } // Clipping triangles = ClipTriangles(triangles, camera); ASCII_FPS.triangleCountClipped += triangles.Count; // Rendering RenderTriangles(triangles, camera, 0, console.Width); // Find first zone Zone firstZone = null; foreach (Zone zone in scene.zones) { if (zone.Bounds.TestPoint(new Vector2(camera.CameraPos.X, camera.CameraPos.Z))) { firstZone = zone; break; } } if (firstZone != null) { ProcessZone(camera, firstZone, 0, console.Width); } // Shading for (int i = 0; i < console.Width; i++) { for (int j = 0; j < console.Height; j++) { Triangle triangle = tBuffer[i, j]; if (triangle != null) { float z = zBuffer[i, j]; Vector3 bar = bBuffer[i, j]; // Sample from texture Vector2 uv = bar.X * triangle.UV0 + bar.Y * triangle.UV1 + bar.Z * triangle.UV2; if (EyeEasy) { float d = Math.Clamp(1f - (float)Math.Pow(z, 25), 0f, 1f); console.Data[i, j] = '@'; console.Color[i, j] = Mathg.ColorTo8Bit(triangle.Texture.Sample(uv) * d); } else { int fogId = (z < 0) ? 0 : Math.Min((int)(Math.Pow(z, 10) * fogString.Length + offset[i, j]), fogString.Length - 1); console.Data[i, j] = fogString[fogId]; console.Color[i, j] = Mathg.ColorTo8Bit(triangle.Texture.Sample(uv)); } } } } }
// Render triangles, only for pixels with x in [boundsLeft, boundsRight) private void RenderTriangles(List <Triangle> triangles, Camera camera, int boundsLeft, int boundsRight) { Matrix projectionMatrix = camera.ProjectionMatrix; foreach (Triangle triangle in triangles) { Vector4 v0 = Vector4.Transform(new Vector4(triangle.V0, 1), projectionMatrix); Vector4 v1 = Vector4.Transform(new Vector4(triangle.V1, 1), projectionMatrix); Vector4 v2 = Vector4.Transform(new Vector4(triangle.V2, 1), projectionMatrix); Vector2 p0 = new Vector2(v0.X, -v0.Y) / v0.W; Vector2 p1 = new Vector2(v1.X, -v1.Y) / v1.W; Vector2 p2 = new Vector2(v2.X, -v2.Y) / v2.W; float z0 = v0.Z / v0.W; float z1 = v1.Z / v1.W; float z2 = v2.Z / v2.W; float minX = Math.Min(p0.X, Math.Min(p1.X, p2.X)); float maxX = Math.Max(p0.X, Math.Max(p1.X, p2.X)); float minY = Math.Min(p0.Y, Math.Min(p1.Y, p2.Y)); float maxY = Math.Max(p0.Y, Math.Max(p1.Y, p2.Y)); int minI = Math.Max(boundsLeft, (int)((minX + 1f) * 0.5f * console.Width)); int maxI = Math.Min(boundsRight, (int)((maxX + 1f) * 0.5f * console.Width) + 1); int minJ = Math.Max(0, (int)((minY + 1f) * 0.5f * console.Height)); int maxJ = Math.Min(console.Height, (int)((maxY + 1f) * 0.5f * console.Height) + 1); // Four corners of rectangle Vector2 topLeft = new Vector2(2f * minI / console.Width - 1f, 2f * minJ / console.Height - 1f); Vector2 bottomLeft = new Vector2(2f * minI / console.Width - 1f, 2f * maxJ / console.Height - 1f); Vector2 topRight = new Vector2(2f * maxI / console.Width - 1f, 2f * minJ / console.Height - 1f); Vector2 bottomRight = new Vector2(2f * maxI / console.Width - 1f, 2f * maxJ / console.Height - 1f); // Barycentric coordinates of corners Vector3 barTopLeft = Mathg.Barycentric(topLeft, p0, p1, p2); Vector3 barBottomLeft = Mathg.Barycentric(bottomLeft, p0, p1, p2); Vector3 barTopRight = Mathg.Barycentric(topRight, p0, p1, p2); Vector3 barBottomRight = Mathg.Barycentric(bottomRight, p0, p1, p2); for (int i = minI; i < maxI; i++) { // Barycentric coordinates of points on top and bottom edge, interpolated from corners float t = (float)(i - minI) / (maxI - minI); Vector3 barTop = barTopLeft * (1 - t) + barTopRight * t; Vector3 barBottom = barBottomLeft * (1 - t) + barBottomRight * t; for (int j = minJ; j < maxJ; j++) { // Barycentric coordinates of point (i, j), interpolated from top and bottom float t2 = (float)(j - minJ) / (maxJ - minJ); Vector3 bar = barTop * (1 - t2) + barBottom * t2; if (bar.X >= -0.01f && bar.Y >= -0.01f && bar.Z >= -0.01f) { float z = z0 * bar.X + z1 * bar.Y + z2 * bar.Z; if (z > -1 && z < 1 && z < zBuffer[i, j]) { zBuffer[i, j] = z; tBuffer[i, j] = triangle; bBuffer[i, j] = new Vector3(bar.X / v0.W, bar.Y / v1.W, bar.Z / v2.W) / (bar.X / v0.W + bar.Y / v1.W + bar.Z / v2.W); } } } } } }