All pastes #906104 Raw Edit

Unnamed

public text v1 · immutable
·published 2008-02-16 09:46 UTC
rendered paste body
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Fds.Xna.Enigma.Graphics;
using Microsoft.Xna.Framework.Graphics;
using Fds.Xna.Enigma.Graphics.Lighting;

namespace Fds.Xna.Enigma.Sandbox
{
    public enum EditType
    {
        Terrain,
        Texture
    }

    public class TerrainManipulationScene : Scene
    {
        const int width = 256;
        const int depth = 256;

        Vector4[] weights = new Vector4[] {
            new Vector4(1, 0, 0, 0),
            new Vector4(0, 1, 0, 0),
            new Vector4(0, 0, 1, 0),
            new Vector4(0, 0, 0, 1),
        };

        SpriteBatch spriteBatch;
        Effect effect;
        Texture2D[] textures;
        KeyboardState previousKeyboardState;
        MouseState previousMouseState;
        VertexDeclaration vertexDeclaration;
        Matrix world = Matrix.CreateTranslation(Vector3.Zero);
        VertexTerrain[] vertices = new VertexTerrain[width * depth];
        Vector3 pickTarget;
        EditType editType = EditType.Terrain;
        int[] indices = new int[(width * depth * 6)];
        int triangleCount;
        int? selctedIndex;
        float morphRadius = 1;
        float morphPower = 1;
        int currentTextureIndex = 0;

        public TerrainManipulationScene(Game game)
            : base(game)
        {

        }

        protected override void LoadContent()
        {
            base.LoadContent();

            Game.IsMouseVisible = true;

            spriteBatch = new SpriteBatch(GraphicsDevice);
            vertexDeclaration = new VertexDeclaration(GraphicsDevice, VertexTerrain.VertexElements);
            effect = Game.Content.Load<Effect>("Effects\\DeferredRendering\\DeferredTerrain");

            DirectionalLight dlight = new DirectionalLight();
            dlight.Direction = new Vector3(0f, -1f, 0);
            dlight.Color = Color.White;

            Lights.Add(dlight);

            textures = new Texture2D[5];

            textures[0] = Game.Content.Load<Texture2D>("Textures\\Sand01");
            textures[1] = Game.Content.Load<Texture2D>("Textures\\Grass01");
            textures[2] = Game.Content.Load<Texture2D>("Textures\\Rock01");
            textures[3] = Game.Content.Load<Texture2D>("Textures\\Snow01");
            textures[4] = Game.Content.Load<Texture2D>("Textures\\TerrainCursor");

            Camera = new Camera();
            Camera.Move(0f, 75f, -50f);
            Camera.Perspective(45f, 4f / 3f, 1f, 1000f);
            Camera.Rotate(0f, -90f, 0f);

            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    int index = x + (z * width);

                    vertices[index].Position = new Vector3(x + width / -2, 0, z + depth / -2);
                    vertices[index].Normal = new Vector3(0, 1, 0);
                    vertices[index].TextureWeight = new Vector4(1, 0, 0, 0);
                }
            }

            for (int z = 0; z < depth - 1; z++)
            {
                for (int x = 0; x < width - 1; x++)
                {
                    indices[(x + (z * width)) * 6] = (x + z * width);
                    indices[(x + (z * width)) * 6 + 1] = (x + z * width) + 1;
                    indices[(x + (z * width)) * 6 + 2] = (x + (z + 1) * width);

                    indices[(x + (z * width)) * 6 + 3] = (x + (z + 1) * width);
                    indices[(x + (z * width)) * 6 + 4] = (x + z * width) + 1;
                    indices[(x + (z * width)) * 6 + 5] = (x + (z + 1) * width) + 1;

                }
            }

            triangleCount = indices.Length / 3;
        }

        public void ProcessNormals()
        {
            for (int z = 1; z < depth - 1; z++)
            {
                for (int x = 1; x < width - 1; x++)
                {
                    int index = x + (z * width);

                    Vector3 normX =
                        new Vector3((vertices[index - 1].Position.Y -
                                     vertices[index + 1].Position.Y) / 2,
                                     1, 0);
                    Vector3 normZ =
                        new Vector3(0, 1,
                                   (vertices[x + ((z - 1) * width)].Position.Y -
                                    vertices[x + ((z + 1) * width)].Position.Y) / 2);

                    vertices[index].Normal = normX + normZ;
                    vertices[index].Normal.Normalize();
                }
            }
        }
        public void SmoothTerrain(int smoothingPasses)
        {
            if (smoothingPasses < 0)
            {
                smoothingPasses = 0;
            }

            int passes = (int)smoothingPasses;

            VertexTerrain[] newVertices;

            while (passes > 0)
            {
                passes--;

                newVertices = new VertexTerrain[width * depth];

                for (int x = 0; x < width; x++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        int adjacentSections = 0;
                        float sectionsTotal = 0.0f;

                        if (x == 0 || x == width - 1 || z == 0 || z == depth - 1)
                        {
                            continue;
                        }

                        // =================================================================
                        if ((x - 1) > 0)            // Check to left
                        {
                            sectionsTotal += vertices[z + ((x - 1) * depth)].Position.Y;
                            adjacentSections++;

                            if ((z - 1) > 0)        // Check up and to the left
                            {
                                sectionsTotal += vertices[(z - 1) + ((x - 1) * depth)].Position.Y;
                                adjacentSections++;
                            }

                            if ((z + 1) < depth)        // Check down and to the left
                            {
                                sectionsTotal += vertices[(z + 1) + ((x - 1) * depth)].Position.Y;
                                adjacentSections++;
                            }
                        }
                        // =================================================================

                        // =================================================================
                        if ((x + 1) < width)     // Check to right
                        {
                            sectionsTotal += vertices[z + ((x + 1) * depth)].Position.Y;
                            adjacentSections++;

                            if ((z - 1) > 0)        // Check up and to the right
                            {
                                sectionsTotal += vertices[(z - 1) + ((x + 1) * depth)].Position.Y;
                                adjacentSections++;
                            }

                            if ((z + 1) < depth)        // Check down and to the right
                            {
                                sectionsTotal += vertices[(z + 1) + ((x + 1) * depth)].Position.Y;
                                adjacentSections++;
                            }
                        }
                        // =================================================================

                        // =================================================================
                        if ((z - 1) > 0)            // Check above
                        {
                            sectionsTotal += vertices[(z - 1) + (x * depth)].Position.Y;
                            adjacentSections++;
                        }
                        // =================================================================

                        // =================================================================
                        if ((z + 1) < depth)    // Check below
                        {
                            sectionsTotal += vertices[(z + 1) + (x * depth)].Position.Y;
                            adjacentSections++;
                        }
                        // =================================================================

                        newVertices[z + (x * depth)].Position.Y = (vertices[z + (x * depth)].Position.Y + (sectionsTotal / adjacentSections)) * 0.5f;
                    }
                }

                // Overwrite the HeightData info with our new smoothed info
                for (int x = 0; x < width; x++)
                    for (int z = 0; z < depth; z++)
                    {
                        vertices[z + (x * depth)].Position.Y = newVertices[z + (x * depth)].Position.Y;
                    }
            }
        }
        public int? FindPickingTarget(MouseState mouseState)
        {
            Viewport viewport = GraphicsDevice.Viewport;

            Vector3 minSource = new Vector3(mouseState.X, mouseState.Y, viewport.MinDepth);
            Vector3 maxSource = new Vector3(mouseState.X, mouseState.Y, viewport.MaxDepth);

            Vector3 nearSource = viewport.Unproject(minSource, Camera.Projection, Camera.View, world);
            Vector3 farSource = viewport.Unproject(maxSource, Camera.Projection, Camera.View, world);

            Vector3 direction = farSource - nearSource;

            Ray ray = new Ray(nearSource, direction);

            for (int i = 0; i < vertices.Length - 3; i++)
            {
                Vector3 pos = Vector3.Transform(vertices[i].Position, world);

                BoundingBox bb = new BoundingBox(pos + Vector3.One * -1f, pos + Vector3.One * 1f);
                float? length;

                ray.Intersects(ref bb, out length);

                if (length.HasValue)
                {
                    pickTarget = ray.Position + ray.Direction * length.Value;
                    return i;
                }
            }

            return null;
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            KeyboardState currentKeyboardState = Keyboard.GetState();
            MouseState currentMouseState = Mouse.GetState();

            if (currentKeyboardState.IsKeyDown(Keys.Left)) Camera.Move(-50 * elapsed, 0, 0);
            if (currentKeyboardState.IsKeyDown(Keys.Right)) Camera.Move(50 * elapsed, 0, 0);
            if (currentKeyboardState.IsKeyDown(Keys.Up)) Camera.Move(0, 0, 50 * elapsed);
            if (currentKeyboardState.IsKeyDown(Keys.Down)) Camera.Move(0, 0, -50 * elapsed);
            if (currentKeyboardState.IsKeyDown(Keys.PageUp)) Camera.Move(0, 50 * elapsed, 0);
            if (currentKeyboardState.IsKeyDown(Keys.PageDown)) Camera.Move(0, -50 * elapsed, 0);
            if (currentKeyboardState.IsKeyDown(Keys.A)) Camera.Rotate(50 * elapsed, 0, 0);
            if (currentKeyboardState.IsKeyDown(Keys.D)) Camera.Rotate(-50 * elapsed, 0, 0);
            if (currentKeyboardState.IsKeyDown(Keys.W)) Camera.Rotate(0, 50 * elapsed, 0);
            if (currentKeyboardState.IsKeyDown(Keys.S)) Camera.Rotate(0, -50 * elapsed, 0);

            if (currentKeyboardState.IsKeyDown(Keys.OemMinus)) morphRadius = MathHelper.Clamp(morphRadius - (morphRadius * 0.5f) * elapsed, 1f, 6f);
            if (currentKeyboardState.IsKeyDown(Keys.OemPlus)) morphRadius = MathHelper.Clamp(morphRadius + (morphRadius * 0.5f) * elapsed, 1f, 6f);
            if (currentKeyboardState.IsKeyDown(Keys.Q)) morphPower = MathHelper.Clamp(morphPower - (morphPower * 0.5f) * elapsed, 1f, 30f);
            if (currentKeyboardState.IsKeyDown(Keys.E)) morphPower = MathHelper.Clamp(morphPower + (morphPower * 0.5f) * elapsed, 1f, 30f);

            if (previousKeyboardState != null)
            {
                if (currentKeyboardState.IsKeyDown(Keys.Tab) && !previousKeyboardState.IsKeyDown(Keys.Tab))
                {
                    editType = (editType == EditType.Terrain) ? EditType.Texture : EditType.Terrain;
                }

                if (currentKeyboardState.IsKeyDown(Keys.T) && !previousKeyboardState.IsKeyDown(Keys.T))
                {
                    currentTextureIndex++;

                    if (currentTextureIndex > 3)
                    {
                        currentTextureIndex = 0;
                    }
                }

                if (currentKeyboardState.IsKeyDown(Keys.F1) && !previousKeyboardState.IsKeyDown(Keys.F1))
                {
                    SmoothTerrain(1);
                    ProcessNormals();
                }

                if (currentKeyboardState.IsKeyDown(Keys.F2))
                {
                    SmoothTerrain(1);
                    ProcessNormals();
                }

                if (currentKeyboardState.IsKeyDown(Keys.F12) && !previousKeyboardState.IsKeyDown(Keys.F12))
                {
                    float min = float.MaxValue;
                    float max = float.MinValue;

                    for (int i = 0; i < vertices.Length; i++)
                    {
                        if (vertices[i].Position.Y > max) max = vertices[i].Position.Y;
                        if (vertices[i].Position.Y < min) min = vertices[i].Position.Y;
                    }

                    max -= min;
                    min = 0;

                    if (max < 256)
                    {
                        max = 256;
                    }

                    Texture2D heightmap = new Texture2D(GraphicsDevice, width, depth, 1, TextureUsage.None, SurfaceFormat.Vector4);
                    Vector4[] colors = new Vector4[width * depth];

                    for (int z = 0; z < depth; z++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            float posY = vertices[x + z * width].Position.Y;

                            float height = MathHelper.Clamp(posY / max, 0.0f, 1f);
                            float w = 1.0f;

                            colors[x + z * width] = new Vector4(height, height, height, w);
                        }
                    }

                    heightmap.SetData<Vector4>(colors);
                    heightmap.Save("heightmap.png", ImageFileFormat.Png);
                }

                if (currentKeyboardState.IsKeyDown(Keys.F11) && !previousKeyboardState.IsKeyDown(Keys.F11))
                {
                    Texture2D colormap = new Texture2D(GraphicsDevice, width, depth, 1, TextureUsage.None, SurfaceFormat.Vector4);
                    Vector4[] colors = new Vector4[width * depth];

                    for (int z = 0; z < depth; z++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            Vector4 color = vertices[x + z * width].TextureWeight;
                            color.W = 1 - color.W;
                            colors[x + z * width] = color;
                        }
                    }

                    colormap.SetData<Vector4>(colors);
                    colormap.Save("colormap.png", ImageFileFormat.Png);
                }
            }

            if (previousMouseState != null)
            {
                if (currentMouseState.LeftButton == ButtonState.Pressed && selctedIndex.HasValue)
                {
                    for (int i = 0; i < vertices.Length; i++)
                    {
                        Vector3 delta = pickTarget - vertices[i].Position;
                        float length = delta.Length();
                        float scalar = MathHelper.Clamp(morphRadius - (length / morphRadius), 0.0f, 1f);

                        if (editType == EditType.Terrain)
                        {
                            vertices[i].Position.Y += morphPower * scalar * elapsed;
                        }
                        else
                        {
                            vertices[i].TextureWeight -= vertices[i].TextureWeight * scalar * elapsed;
                            vertices[i].TextureWeight += weights[currentTextureIndex] * scalar * elapsed;
                        }
                    }

                    if (editType == EditType.Terrain)
                    {
                        ProcessNormals();
                    }
                }
                else if (currentMouseState.RightButton == ButtonState.Pressed && selctedIndex.HasValue)
                {
                    for (int i = 0; i < vertices.Length; i++)
                    {
                        Vector3 delta = pickTarget - vertices[i].Position;
                        float length = delta.Length();
                        float scalar = MathHelper.Clamp(morphRadius - (length / morphRadius), 0.0f, 1f);
                        vertices[i].Position.Y -= morphPower * scalar * elapsed;
                    }

                    if (editType == EditType.Terrain)
                    {
                        ProcessNormals();
                    }
                }

                selctedIndex = FindPickingTarget(currentMouseState);
            }


            Game.Window.Title = String.Format("Edit Type: {2} Morph Power: {0} Morph Radius: {1}",
                morphPower, morphRadius, Enum.GetName(typeof(EditType), editType));

            previousKeyboardState = currentKeyboardState;
            previousMouseState = currentMouseState;
        }
        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);

            Matrix world = Matrix.CreateTranslation(Vector3.Zero);

            GraphicsDevice.VertexDeclaration = vertexDeclaration;

            GraphicsDevice.RenderState.DepthBufferEnable = true;
            GraphicsDevice.RenderState.CullMode = CullMode.None;
            GraphicsDevice.RenderState.PointSpriteEnable = false;

            if (selctedIndex.HasValue)
            {
                effect.Parameters["EditTexture"].SetValue(textures[4]);
            }
            else
            {
                effect.Parameters["EditTexture"].SetValue((Texture)null);
            }

            effect.Parameters["WorldViewProj"].SetValue(world * Camera.View * Camera.Projection);
            effect.Parameters["World"].SetValue(world);
            effect.Parameters["DirtTexture"].SetValue(textures[0]);
            effect.Parameters["GrassTexture"].SetValue(textures[1]);
            effect.Parameters["RockTexture"].SetValue(textures[2]);
            effect.Parameters["SnowTexture"].SetValue(textures[3]);
            effect.Parameters["Scale"].SetValue(new Vector3(1, 1, 1));
            effect.Parameters["UVScale"].SetValue(new Vector2(0.05f, 0.05f));
            effect.Parameters["EditMode"].SetValue(true);
            effect.Parameters["EditRadius"].SetValue(morphRadius);
            effect.Parameters["EditPosition"].SetValue(pickTarget);
            effect.Parameters["HeightmapSize"].SetValue(new Vector2(width, depth));

            effect.Begin();
            effect.CurrentTechnique.Passes[0].Begin();

            GraphicsDevice.DrawUserIndexedPrimitives<VertexTerrain>(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, triangleCount);

            effect.CurrentTechnique.Passes[0].End();
            effect.End();
        }
        public void DrawDiagnosticInfo()
        {
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            spriteBatch.Draw(textures[currentTextureIndex], new Rectangle(0, 0, 50, 50), Color.White);
            spriteBatch.End();
        }
    }
}