|
- /*
- ---------------------------------------------------------------------------
- Open Asset Import Library (ASSIMP)
- ---------------------------------------------------------------------------
-
- Copyright (c) 2006-2010, ASSIMP Development Team
-
- All rights reserved.
-
- Redistribution and use of this software in source and binary forms,
- with or without modification, are permitted provided that the following
- conditions are met:
-
- * Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
- * Neither the name of the ASSIMP team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the ASSIMP Development Team.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- ---------------------------------------------------------------------------
- */
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Diagnostics;
- using System.Drawing;
- using System.IO;
- using System.Text;
- using System.Windows.Forms;
- using Microsoft.DirectX;
- using Microsoft.DirectX.Direct3D;
-
- namespace Assimp.Viewer
- {
- public partial class AssimpView : Form
- {
- public AssimpView()
- {
- InitializeComponent();
-
- // Window title
- this.Text = "Assimp .NET Viewer";
-
- // Ignore WM_ERASEBKGND messages to prevent flicker
- this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
-
- // Listen to mouse
- this.MouseDown += new MouseEventHandler(AssimpView_MouseDown);
- this.MouseMove += new MouseEventHandler(AssimpView_MouseMove);
- this.MouseUp += new MouseEventHandler(AssimpView_MouseUp);
- this.MouseWheel += new MouseEventHandler(AssimpView_MouseWheel);
- }
-
- void AssimpView_MouseWheel(object sender, MouseEventArgs e) {
- g_sCamera.vPos.Z *= 1.0f - (e.Delta / 1000.0f);
- Refresh();
- }
-
- private void AssimpView_MouseDown(object sender, MouseEventArgs e) {
- UpdateMouseState(e);
- }
-
- private void AssimpView_MouseMove(object sender, MouseEventArgs e) {
- UpdateMouseState(e);
- }
-
- private void AssimpView_MouseUp(object sender, MouseEventArgs e) {
- UpdateMouseState(e);
- }
-
- private void UpdateMouseState(MouseEventArgs e) {
- g_bMousePressed = (e.Button == MouseButtons.Left);
- g_bMousePressedR = (e.Button == MouseButtons.Right);
- g_bMousePressedM = (e.Button == MouseButtons.Middle);
- g_bMousePressedBoth = (e.Button == (MouseButtons.Left | MouseButtons.Right));
- Refresh();
- }
-
- protected override void OnPaintBackground(PaintEventArgs pevent) {
- /* Do nothing to prevent flicker during resize */
- }
-
- private void Form1_Load(object sender, EventArgs e)
- {
- InitializeDevice();
- InitializeAssimp();
- }
-
- private void Form1_SizeChanged(object sender, EventArgs e) {
- presentParams.BackBufferWidth = Width;
- presentParams.BackBufferHeight = Height;
- device.Reset(presentParams);
- Invalidate();
- }
-
- public void InitializeDevice()
- {
- // Improve Performance
- // http://blogs.msdn.com/b/tmiller/archive/2003/11/14/57531.aspx
- Device.IsUsingEventHandlers = false;
-
- // For Windowed mode leave Width and Height at 0
- var adapter = Manager.Adapters.Default;
- presentParams = new PresentParameters();
- presentParams.AutoDepthStencilFormat = DepthFormat.D16;
- presentParams.EnableAutoDepthStencil = true;
- presentParams.Windowed = true;
- presentParams.SwapEffect = SwapEffect.Discard;
-
- // Keep precision in floating point calculations
- // http://blogs.msdn.com/b/tmiller/archive/2004/06/01/145596.aspx
- var createFlags = CreateFlags.FpuPreserve;
-
- // Pure device for performance - all device render states are now write only
- var deviceType = DeviceType.Hardware;
- var caps = Manager.GetDeviceCaps(adapter.Adapter, deviceType);
- if (caps.DeviceCaps.SupportsPureDevice) {
- createFlags |= CreateFlags.PureDevice;
- }
-
- // Warning: some drivers lie about supporting HT&L. Use Software if you see problems.
- if (caps.DeviceCaps.SupportsHardwareTransformAndLight) {
- createFlags |= CreateFlags.HardwareVertexProcessing;
- }
- else {
- createFlags |= CreateFlags.SoftwareVertexProcessing;
- }
-
- // Create Device
- device = new Device(adapter.Adapter, deviceType, this, createFlags, presentParams);
-
- // Add event handlers
- device.DeviceResizing += new CancelEventHandler(device_DeviceResizing);
- }
-
- private void device_DeviceResizing(object sender, CancelEventArgs e) {
- device.Reset();
- }
-
- // default pp steps
- private static aiPostProcessSteps ppsteps =
- aiPostProcessSteps.aiProcess_CalcTangentSpace | // calculate tangents and bitangents if possible
- aiPostProcessSteps.aiProcess_JoinIdenticalVertices | // join identical vertices/ optimize indexing
- aiPostProcessSteps.aiProcess_ValidateDataStructure | // perform a full validation of the loader's output
- aiPostProcessSteps.aiProcess_ImproveCacheLocality | // improve the cache locality of the output vertices
- aiPostProcessSteps.aiProcess_RemoveRedundantMaterials | // remove redundant materials
- aiPostProcessSteps.aiProcess_FindDegenerates | // remove degenerated polygons from the import
- aiPostProcessSteps.aiProcess_FindInvalidData | // detect invalid model data, such as invalid normal vectors
- aiPostProcessSteps.aiProcess_GenUVCoords | // convert spherical, cylindrical, box and planar mapping to proper UVs
- aiPostProcessSteps.aiProcess_TransformUVCoords | // preprocess UV transformations (scaling, translation ...)
- aiPostProcessSteps.aiProcess_FindInstances | // search for instanced meshes and remove them by references to one master
- aiPostProcessSteps.aiProcess_LimitBoneWeights | // limit bone weights to 4 per vertex
- aiPostProcessSteps.aiProcess_OptimizeMeshes | // join small meshes, if possible;
- (aiPostProcessSteps)0;
-
-
- public void InitializeAssimp() {
- var flags = ( ppsteps |
- aiPostProcessSteps.aiProcess_GenSmoothNormals | // generate smooth normal vectors if not existing
- aiPostProcessSteps.aiProcess_SplitLargeMeshes | // split large, unrenderable meshes into submeshes
- aiPostProcessSteps.aiProcess_Triangulate | // triangulate polygons with more than 3 edges
- aiPostProcessSteps.aiProcess_ConvertToLeftHanded | // convert everything to D3D left handed space
- aiPostProcessSteps.aiProcess_SortByPType | // make 'clean' meshes which consist of a single typ of primitives
- (aiPostProcessSteps)0);
-
- // default model
- var path = "../../../../../test/models/3DS/test1.3ds";
-
- importer = new Importer();
- string[] args = Environment.GetCommandLineArgs();
- if (args.Length > 1) {
- path = args[1];
- }
-
-
- //var path = "man.3ds";
- scene = importer.ReadFile(path, flags);
- if (scene != null)
- {
- directory = Path.GetDirectoryName(path);
- CacheMaterials(scene.mMaterials);
- CacheMeshes(scene.mMeshes);
- SetupCamera(scene.mCameras);
- }
- else {
- MessageBox.Show("Failed to open file: " + path + ". Either Assimp screwed up or the path is not valid.");
- Application.Exit();
- }
- }
-
- private void CacheMeshes(aiMeshVector meshes) {
- var numMeshes = meshes.Count;
- meshCache = new Mesh[numMeshes];
- meshBoundsMin = new Vector3[numMeshes];
- meshBoundsMax = new Vector3[numMeshes];
-
- for (int i = 0; i < numMeshes; ++i) {
- var mesh = meshes[i];
-
- switch (mesh.mPrimitiveTypes) {
- case aiPrimitiveType.aiPrimitiveType_TRIANGLE:
- Vector3 min, max;
- meshCache[i] = CreateMesh(mesh, out min, out max);
- meshBoundsMin[i] = min;
- meshBoundsMax[i] = max;
- break;
- }
- }
- }
-
- private void CacheMaterials(aiMaterialVector materials) {
- var numMaterials = materials.Count;
- materialCache = new ExtendedMaterial[numMaterials];
- textureCache = new Dictionary<string, Texture>();
-
- for (int i = 0; i < numMaterials; ++i) {
- var material = materials[i];
- var dxExtendedMaterial = new ExtendedMaterial();
- var dxMaterial = new Material();
- dxMaterial.AmbientColor = material.Ambient.ToColorValue();
- dxMaterial.DiffuseColor = material.Diffuse.ToColorValue();
- dxMaterial.EmissiveColor = material.Emissive.ToColorValue();
- dxMaterial.SpecularColor = material.Specular.ToColorValue();
- dxMaterial.SpecularSharpness = material.ShininessStrength;
- dxExtendedMaterial.Material3D = dxMaterial;
- dxExtendedMaterial.TextureFilename = material.TextureDiffuse0;
-
- materialCache[i] = dxExtendedMaterial;
-
- var textureFilename = dxExtendedMaterial.TextureFilename;
- if (!string.IsNullOrEmpty(textureFilename) && !textureCache.ContainsKey(textureFilename)) {
- textureCache.Add(textureFilename, CreateTexture(textureFilename));
- }
- }
- }
-
- private Texture CreateTexture(string fileName) {
- var path = Path.Combine(directory, fileName);
- try {
- using (var data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) {
- var dxTexture = Texture.FromStream(device, data, Usage.None, Pool.Managed);
- textureCache[path] = dxTexture;
- return dxTexture;
- }
- }
- catch (Exception) {
- return null;
- }
- }
-
- private Mesh CreateMesh(aiMesh aiMesh, out Vector3 min, out Vector3 max) {
- var numFaces = (int) aiMesh.mNumFaces;
- var numVertices = (int) aiMesh.mNumVertices;
-
- var dxMesh = new Mesh(numFaces, numVertices, MeshFlags.Managed | MeshFlags.Use32Bit,
- CustomVertex.PositionNormalTextured.Format, device);
-
- var aiPositions = aiMesh.mVertices;
- var aiNormals = aiMesh.mNormals;
- var aiTextureCoordsAll = aiMesh.mTextureCoords;
- var aiTextureCoords = (aiTextureCoordsAll!=null) ? aiTextureCoordsAll[0] : null;
- var dxVertices = new CustomVertex.PositionNormalTextured[numVertices];
- for (int i = 0; i < numVertices; ++i) {
- dxVertices[i].Position = aiPositions[i].ToVector3();
- if (aiNormals != null) {
- dxVertices[i].Normal = aiNormals[i].ToVector3();
- }
- if (aiTextureCoords != null) {
- var uv = aiTextureCoords[i];
- dxVertices[i].Tu = uv.x;
- dxVertices[i].Tv = uv.y;
- }
- }
- dxMesh.VertexBuffer.SetData(dxVertices, 0, LockFlags.None);
-
- var aiFaces = aiMesh.mFaces;
- var dxIndices = new uint[numFaces * 3];
- for (int i = 0; i < numFaces; ++i) {
- var aiFace = aiFaces[i];
- var aiIndices = aiFace.mIndices;
- for (int j = 0; j < 3; ++j) {
- dxIndices[i * 3 + j] = aiIndices[j];
- }
- }
- dxMesh.IndexBuffer.SetData(dxIndices, 0, LockFlags.None);
-
- var dxAttributes = dxMesh.LockAttributeBufferArray(LockFlags.None);
- // TODO: Set face material index for attributes
- dxMesh.UnlockAttributeBuffer(dxAttributes);
-
- var adjacency = new int[numFaces * 3];
- dxMesh.GenerateAdjacency(0.0f, adjacency);
- dxMesh.OptimizeInPlace(MeshFlags.OptimizeAttributeSort, adjacency);
-
- Geometry.ComputeBoundingBox(dxVertices, CustomVertex.PositionNormalTextured.StrideSize, out min, out max);
-
- return dxMesh;
- }
-
- //-------------------------------------------------------------------------------
- // Calculate the boundaries of a given node and all of its children
- // The boundaries are in Worldspace (AABB)
- // piNode Input node
- // min/max Receives the min/max boundaries
- // piMatrix Transformation matrix of the graph at this position
- //-------------------------------------------------------------------------------
- private void CalculateBounds(aiNode piNode, ref Vector3 min, ref Vector3 max, Matrix piMatrix) {
- Debug.Assert(null != piNode);
-
- var mTemp = piNode.mTransformation.ToMatrix();
- var aiMe = mTemp * piMatrix;
-
- var meshes = piNode.mMeshes;
- var numMeshes = meshes.Count;
- for (int i = 0; i < numMeshes; ++i) {
- var mesh = meshes[i];
- var meshMin = Vector3.TransformCoordinate(meshBoundsMin[mesh], aiMe);
- var meshMax = Vector3.TransformCoordinate(meshBoundsMax[mesh], aiMe);
- min.X = Math.Min(min.X, meshMin.X);
- min.Y = Math.Min(min.Y, meshMin.Y);
- min.Z = Math.Min(min.Z, meshMin.Z);
- max.X = Math.Max(max.X, meshMax.X);
- max.Y = Math.Max(max.Y, meshMax.Y);
- max.Z = Math.Max(max.Z, meshMax.Z);
- }
- var children = piNode.mChildren;
- var numChildren = children.Count;
- for (int i = 0; i < numChildren; ++i) {
- CalculateBounds(children[i], ref min, ref max, aiMe);
- }
- }
-
- protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {
- HandleMouseInputLocal();
- Render();
- }
-
- private void Render() {
- device.Clear(ClearFlags.Target|ClearFlags.ZBuffer, Color.DarkSlateBlue, 1.0f, 0);
- device.BeginScene();
-
- SetupMatrices();
-
- if (scene != null && scene.mRootNode != null) {
- SetupLights(scene.mLights);
- RenderNode(scene.mRootNode, g_mWorldRotate);
- }
-
- device.EndScene();
- device.Present();
- }
-
- private void SetupMatrices() {
- var fovy = Geometry.DegreeToRadian(45.0f);
- var aspect = ((float)this.Width / (float)this.Height);
- device.Transform.Projection = Matrix.PerspectiveFovLH(fovy, aspect, g_zNear, g_zFar);
- device.Transform.View = g_sCamera.GetMatrix();
- }
-
- private void SetupCamera(aiCameraVector cameras) {
- // Get scene bounds
- var min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
- var max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
- CalculateBounds(scene.mRootNode, ref min, ref max, Matrix.Identity);
-
- // Projection Depth
- var size = (max-min);
- g_zFar = Math.Max(Math.Max(size.X, size.Y), size.Z) * 100;
-
- // Starting View Position
- var center = min + size * 0.5f;
- var lookAt = new Vector3(0,0,1); // Unit vector not coordinate
- var position = new Vector3(center.X, center.Y, center.Z-(size.Z*10));
- var up = new Vector3(0, 1, 0);
- if (cameras.Count > 0) {
- var camera = cameras[0];
- lookAt = camera.mLookAt.ToVector3();
- position = camera.mPosition.ToVector3();
- up = camera.mUp.ToVector3();
- }
- g_sCamera.vLookAt = lookAt;
- g_sCamera.vPos = position;
- g_sCamera.vUp = up;
- }
-
- private void SetupLights(aiLightVector lights) {
- var numLights = lights.Count;
-
- if (numLights == 0) {
- var light = device.Lights[0];
- light.Type = LightType.Directional;
- light.Diffuse = Color.LightGray;
- light.Direction = new Vector3(-1, -1, 1);
- light.Enabled = true;
- }
- else {
- // TODO: setup lights
- }
-
- // Enables lighting
- device.RenderState.Lighting = true;
- device.RenderState.Ambient = Color.DarkGray;
- device.RenderState.SpecularEnable = true;
- }
-
- private void RenderNode(aiNode node, Matrix parentMatrix) {
- var nodeMatrix = node.mTransformation.ToMatrix() * parentMatrix;
-
- var children = node.mChildren;
- var numChildren = node.mNumChildren;
- for (int i = 0; i < numChildren; ++i) {
- var child = children[i];
- RenderNode(child, nodeMatrix);
- }
-
- device.Transform.World = nodeMatrix;
- var meshes = node.mMeshes;
- var numMeshes = meshes.Count;
- for (int i = 0; i < numMeshes; ++i) {
- var meshId = (int)meshes[i];
- var mesh = scene.mMeshes[meshId];
- var materialId = (int)mesh.mMaterialIndex;
-
- var dxMaterial = materialCache[materialId];
- device.Material = dxMaterial.Material3D;
-
- Texture dxTexture = null;
- if (!string.IsNullOrEmpty(dxMaterial.TextureFilename)) {
- textureCache.TryGetValue(dxMaterial.TextureFilename, out dxTexture);
- }
- device.SetTexture(0, dxTexture);
-
- var dxMesh = meshCache[meshId];
- RenderMesh(dxMesh);
- }
- }
-
- private void RenderMesh(Mesh mesh) {
- for (int i = 0; i < mesh.NumberAttributes; ++i) {
- mesh.DrawSubset(i);
- }
- }
-
- private Device device;
- private PresentParameters presentParams;
-
- private Importer importer;
- private string directory;
- private aiScene scene;
- private Mesh[] meshCache;
- private ExtendedMaterial[] materialCache;
- private Dictionary<string, Texture> textureCache;
- private Vector3[] meshBoundsMin;
- private Vector3[] meshBoundsMax;
-
- private Camera g_sCamera = new Camera();
- private float g_zNear = 0.2f;
- private float g_zFar = 1000.0f;
- private Matrix g_mProjection = Matrix.Identity;
- private Matrix g_mWorldRotate = Matrix.Identity;
- }
-
- //-------------------------------------------------------------------------------
- // Position of the cursor relative to the 3ds max' like control circle
- //-------------------------------------------------------------------------------
- public enum EClickPos {
- // The click was inside the inner circle (x,y axis)
- Circle,
- // The click was inside one of tghe vertical snap-ins
- CircleVert,
- // The click was inside onf of the horizontal snap-ins
- CircleHor,
- // the cklick was outside the circle (z-axis)
- Outside
- };
- }
|