corrade-vassal – Rev 1

Subversion Repositories:
Rev:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;

using Tao.OpenGl;
using Tao.Platform.Windows;

using OpenMetaverse;
using OpenMetaverse.Imaging;
using OpenMetaverse.Rendering;
using OpenMetaverse.Assets;

namespace AvatarPreview
{
    public partial class frmAvatar : Form
    {
        GridClient _client = new GridClient();
        Dictionary<string, GLMesh> _meshes = new Dictionary<string, GLMesh>();
        bool _wireframe = true;
        bool _showSkirt = false;

        public frmAvatar()
        {
            InitializeComponent();

            glControl.InitializeContexts();

            Gl.glShadeModel(Gl.GL_SMOOTH);
            Gl.glClearColor(0f, 0f, 0f, 0f);

            Gl.glClearDepth(1.0f);
            Gl.glEnable(Gl.GL_DEPTH_TEST);
            Gl.glDepthMask(Gl.GL_TRUE);
            Gl.glDepthFunc(Gl.GL_LEQUAL);
            Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);

            glControl_Resize(null, null);
        }

        private void lindenLabMeshToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "avatar_lad.xml|avatar_lad.xml";

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                _meshes.Clear();

                try
                {
                    // Parse through avatar_lad.xml to find all of the mesh references
                    XmlDocument lad = new XmlDocument();
                    lad.Load(dialog.FileName);

                    XmlNodeList meshes = lad.GetElementsByTagName("mesh");

                    foreach (XmlNode meshNode in meshes)
                    {
                        string type = meshNode.Attributes.GetNamedItem("type").Value;
                        int lod = Int32.Parse(meshNode.Attributes.GetNamedItem("lod").Value);
                        string fileName = meshNode.Attributes.GetNamedItem("file_name").Value;
                        //string minPixelWidth = meshNode.Attributes.GetNamedItem("min_pixel_width").Value;

                        // Mash up the filename with the current path
                        fileName = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(dialog.FileName), fileName);

                        GLMesh mesh = (_meshes.ContainsKey(type) ? _meshes[type] : new GLMesh(type));

                        if (lod == 0)
                        {
                            mesh.LoadMesh(fileName);
                        }
                        else
                        {
                            mesh.LoadLODMesh(lod, fileName);
                        }

                        _meshes[type] = mesh;
                        glControl_Resize(null, null);
                        glControl.Invalidate();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Failed to load avatar mesh: " + ex.Message);
                }
            }
        }

        private void textureToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void wireframeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            wireframeToolStripMenuItem.Checked = !wireframeToolStripMenuItem.Checked;
            _wireframe = wireframeToolStripMenuItem.Checked;

            glControl.Invalidate();
        }

        private void skirtToolStripMenuItem_Click(object sender, EventArgs e)
        {
            skirtToolStripMenuItem.Checked = !skirtToolStripMenuItem.Checked;
            _showSkirt = skirtToolStripMenuItem.Checked;

            glControl.Invalidate();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show(
                "Written by John Hurliman <jhurliman@jhurliman.org> (http://www.jhurliman.org/)");
        }

        private void glControl_Paint(object sender, PaintEventArgs e)
        {
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
            Gl.glLoadIdentity();

            // Setup wireframe or solid fill drawing mode
            if (_wireframe)
                Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_LINE);
            else
                Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_FILL);

            // Push the world matrix
            Gl.glPushMatrix();

            Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
            Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);

            // World rotations
            Gl.glRotatef((float)scrollRoll.Value, 1f, 0f, 0f);
            Gl.glRotatef((float)scrollPitch.Value, 0f, 1f, 0f);
            Gl.glRotatef((float)scrollYaw.Value, 0f, 0f, 1f);

            if (_meshes.Count > 0)
            {
                foreach (GLMesh mesh in _meshes.Values)
                {
                    if (!_showSkirt && mesh.Name == "skirtMesh")
                        continue;

                    Gl.glColor3f(1f, 1f, 1f);

                    // Individual prim matrix
                    Gl.glPushMatrix();

                    //Gl.glTranslatef(mesh.Position.X, mesh.Position.Y, mesh.Position.Z);

                    Gl.glRotatef(mesh.RotationAngles.X, 1f, 0f, 0f);
                    Gl.glRotatef(mesh.RotationAngles.Y, 0f, 1f, 0f);
                    Gl.glRotatef(mesh.RotationAngles.Z, 0f, 0f, 1f);

                    Gl.glScalef(mesh.Scale.X, mesh.Scale.Y, mesh.Scale.Z);

                    // TODO: Texturing

                    Gl.glTexCoordPointer(2, Gl.GL_FLOAT, 0, mesh.RenderData.TexCoords);
                    Gl.glVertexPointer(3, Gl.GL_FLOAT, 0, mesh.RenderData.Vertices);
                    Gl.glDrawElements(Gl.GL_TRIANGLES, mesh.RenderData.Indices.Length, Gl.GL_UNSIGNED_SHORT, mesh.RenderData.Indices);
                }
            }

            // Pop the world matrix
            Gl.glPopMatrix();

            Gl.glDisableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
            Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);

            Gl.glFlush();
        }

        private void glControl_Resize(object sender, EventArgs e)
        {
            //Gl.glClearColor(0.39f, 0.58f, 0.93f, 1.0f); // Cornflower blue anyone?
            Gl.glClearColor(0f, 0f, 0f, 1f);

            Gl.glPushMatrix();
            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();

            Gl.glViewport(0, 0, glControl.Width, glControl.Height);

            Glu.gluPerspective(50.0d, 1.0d, 0.001d, 50d);

            Vector3 center = Vector3.Zero;
            GLMesh head, lowerBody;
            if (_meshes.TryGetValue("headMesh", out head) && _meshes.TryGetValue("lowerBodyMesh", out lowerBody))
                center = (head.RenderData.Center + lowerBody.RenderData.Center) / 2f;

            Glu.gluLookAt(
                    center.X, (double)scrollZoom.Value * 0.1d + center.Y, center.Z,
                    center.X, (double)scrollZoom.Value * 0.1d + center.Y + 1d, center.Z,
                    0d, 0d, 1d);

            Gl.glMatrixMode(Gl.GL_MODELVIEW);
        }

        private void scroll_ValueChanged(object sender, EventArgs e)
        {
            glControl_Resize(null, null);
            glControl.Invalidate();
        }

        private void pic_MouseClick(object sender, MouseEventArgs e)
        {
            PictureBox control = (PictureBox)sender;

            OpenFileDialog dialog = new OpenFileDialog();
            // TODO: Setup a dialog.Filter for supported image types

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    System.Drawing.Image image = System.Drawing.Image.FromFile(dialog.FileName);

                    #region Dimensions Check

                    if (control == picEyesBake)
                    {
                        // Eyes texture is 128x128
                        if (Width != 128 || Height != 128)
                        {
                            Bitmap resized = new Bitmap(128, 128, image.PixelFormat);
                            Graphics graphics = Graphics.FromImage(resized);

                            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                            graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                            graphics.DrawImage(image, 0, 0, 128, 128);

                            image.Dispose();
                            image = resized;
                        }
                    }
                    else
                    {
                        // Other textures are 512x512
                        if (Width != 128 || Height != 128)
                        {
                            Bitmap resized = new Bitmap(512, 512, image.PixelFormat);
                            Graphics graphics = Graphics.FromImage(resized);

                            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                            graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                            graphics.DrawImage(image, 0, 0, 512, 512);

                            image.Dispose();
                            image = resized;
                        }
                    }

                    #endregion Dimensions Check

                    // Set the control image
                    control.Image = image;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Failed to load image: " + ex.Message);
                }
            }
            else
            {
                control.Image = null;
            }

            #region Baking

            Dictionary<int, float> paramValues = GetParamValues();
            Dictionary<AvatarTextureIndex, AssetTexture> layers =
                    new Dictionary<AvatarTextureIndex, AssetTexture>();
            int textureCount = 0;

            if ((string)control.Tag == "Head")
            {
                if (picHair.Image != null)
                {
                    layers.Add(AvatarTextureIndex.Hair,
                        new AssetTexture(new ManagedImage((Bitmap)picHair.Image)));
                    ++textureCount;
                }
                if (picHeadBodypaint.Image != null)
                {
                    layers.Add(AvatarTextureIndex.HeadBodypaint,
                        new AssetTexture(new ManagedImage((Bitmap)picHeadBodypaint.Image)));
                    ++textureCount;
                }

                // Compute the head bake
                Baker baker = new Baker(BakeType.Head);

                foreach (KeyValuePair<AvatarTextureIndex, AssetTexture> kvp in layers)
                {
                    AppearanceManager.TextureData tdata = new AppearanceManager.TextureData();
                    tdata.Texture = kvp.Value;
                    baker.AddTexture(tdata);
                }

                baker.Bake();

                if (baker.BakedTexture != null)
                {
                    AssetTexture bakeAsset = baker.BakedTexture;
                    // Baked textures use the alpha layer for other purposes, so we need to not use it
                    bakeAsset.Image.Channels = ManagedImage.ImageChannels.Color;
                    picHeadBake.Image = LoadTGAClass.LoadTGA(new MemoryStream(bakeAsset.Image.ExportTGA()));
                }
                else
                {
                    MessageBox.Show("Failed to create the bake layer, unknown error");
                }
            }
            else if ((string)control.Tag == "Upper")
            {
                if (picUpperBodypaint.Image != null)
                {
                    layers.Add(AvatarTextureIndex.UpperBodypaint,
                        new AssetTexture(new ManagedImage((Bitmap)picUpperBodypaint.Image)));
                    ++textureCount;
                }
                if (picUpperGloves.Image != null)
                {
                    layers.Add(AvatarTextureIndex.UpperGloves,
                        new AssetTexture(new ManagedImage((Bitmap)picUpperGloves.Image)));
                    ++textureCount;
                }
                if (picUpperUndershirt.Image != null)
                {
                    layers.Add(AvatarTextureIndex.UpperUndershirt,
                        new AssetTexture(new ManagedImage((Bitmap)picUpperUndershirt.Image)));
                    ++textureCount;
                }
                if (picUpperShirt.Image != null)
                {
                    layers.Add(AvatarTextureIndex.UpperShirt,
                        new AssetTexture(new ManagedImage((Bitmap)picUpperShirt.Image)));
                    ++textureCount;
                }
                if (picUpperJacket.Image != null)
                {
                    layers.Add(AvatarTextureIndex.UpperJacket,
                        new AssetTexture(new ManagedImage((Bitmap)picUpperJacket.Image)));
                    ++textureCount;
                }

                // Compute the upper body bake
                Baker baker = new Baker(BakeType.UpperBody);

                foreach (KeyValuePair<AvatarTextureIndex, AssetTexture> kvp in layers)
                {
                    AppearanceManager.TextureData tdata = new AppearanceManager.TextureData();
                    tdata.Texture = kvp.Value;
                    baker.AddTexture(tdata);
                }

                baker.Bake();

                if (baker.BakedTexture != null)
                {
                    AssetTexture bakeAsset = baker.BakedTexture;
                    // Baked textures use the alpha layer for other purposes, so we need to not use it
                    bakeAsset.Image.Channels = ManagedImage.ImageChannels.Color;
                    picUpperBodyBake.Image = LoadTGAClass.LoadTGA(new MemoryStream(bakeAsset.Image.ExportTGA()));
                }
                else
                {
                    MessageBox.Show("Failed to create the bake layer, unknown error");
                }
            }
            else if ((string)control.Tag == "Lower")
            {
                if (picLowerBodypaint.Image != null)
                {
                    layers.Add(AvatarTextureIndex.LowerBodypaint,
                        new AssetTexture(new ManagedImage((Bitmap)picLowerBodypaint.Image)));
                    ++textureCount;
                }
                if (picLowerUnderpants.Image != null)
                {
                    layers.Add(AvatarTextureIndex.LowerUnderpants,
                        new AssetTexture(new ManagedImage((Bitmap)picLowerUnderpants.Image)));
                    ++textureCount;
                }
                if (picLowerSocks.Image != null)
                {
                    layers.Add(AvatarTextureIndex.LowerSocks,
                        new AssetTexture(new ManagedImage((Bitmap)picLowerSocks.Image)));
                    ++textureCount;
                }
                if (picLowerShoes.Image != null)
                {
                    layers.Add(AvatarTextureIndex.LowerShoes,
                        new AssetTexture(new ManagedImage((Bitmap)picLowerShoes.Image)));
                    ++textureCount;
                }
                if (picLowerPants.Image != null)
                {
                    layers.Add(AvatarTextureIndex.LowerPants,
                        new AssetTexture(new ManagedImage((Bitmap)picLowerPants.Image)));
                    ++textureCount;
                }

                // Compute the lower body bake
                Baker baker = new Baker(BakeType.LowerBody);

                foreach (KeyValuePair<AvatarTextureIndex, AssetTexture> kvp in layers)
                {
                    AppearanceManager.TextureData tdata = new AppearanceManager.TextureData();
                    tdata.Texture = kvp.Value;
                    baker.AddTexture(tdata);
                }

                baker.Bake();

                if (baker.BakedTexture != null)
                {
                    AssetTexture bakeAsset = baker.BakedTexture;
                    // Baked textures use the alpha layer for other purposes, so we need to not use it
                    bakeAsset.Image.Channels = ManagedImage.ImageChannels.Color;
                    picLowerBodyBake.Image = LoadTGAClass.LoadTGA(new MemoryStream(bakeAsset.Image.ExportTGA()));
                }
                else
                {
                    MessageBox.Show("Failed to create the bake layer, unknown error");
                }
            }
            else if ((string)control.Tag == "Bake")
            {
                // Bake image has been set manually, no need to manually calculate a bake
                // FIXME:
            }

            #endregion Baking
        }

        private Dictionary<int, float> GetParamValues()
        {
            Dictionary<int, float> paramValues = new Dictionary<int, float>(VisualParams.Params.Count);

            foreach (KeyValuePair<int, VisualParam> kvp in VisualParams.Params)
            {
                VisualParam vp = kvp.Value;
                paramValues.Add(vp.ParamID, vp.DefaultValue);
            }

            return paramValues;
        }
    }
}