using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;
namespace MdxCreateMesh
{
class MdxCreateMesh : IDisposable
{
Form1 form;
PresentParameters pp;
Microsoft.DirectX.Direct3D.Device dev;
Microsoft.DirectX.Direct3D.Font font;
Microsoft.DirectX.DirectInput.Device keyboard;
List<CustomVertex.PositionNormal> vertexList =
new List<CustomVertex.PositionNormal>();
List<short> indexList = new List<short>();
Mesh mesh;
Mesh meshBox;
Mesh meshSphere;
GraphicsStream adjacencyBox; // 隣接性情報
int[] adjacency;
// fps
int fpsSec;
int fpsDraw = 0;
int fpsCount = 0;
// カメラ
float camDist = 10;
int camLat = 30;
int camLon = 210;
public bool DXInitialize(Form1 topLevelForm)
{
try
{
form = topLevelForm;
// キーボードデバイスの初期化
keyboard = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);
keyboard.SetCooperativeLevel(form,
CooperativeLevelFlags.NonExclusive | CooperativeLevelFlags.Background);
keyboard.Acquire();
// Direct3Dデバイス作成
pp = new PresentParameters();
pp.Windowed = true;
pp.SwapEffect = SwapEffect.Discard;
pp.AutoDepthStencilFormat = DepthFormat.D16;
pp.EnableAutoDepthStencil = true;
dev = new Microsoft.DirectX.Direct3D.Device(0,
Microsoft.DirectX.Direct3D.DeviceType.Hardware, form,
CreateFlags.HardwareVertexProcessing, pp);
// フォントの作成
FontDescription fd = new FontDescription();
fd.Height = 24;
fd.FaceName = "MS ゴシック";
font = new Microsoft.DirectX.Direct3D.Font(dev, fd);
dev.Transform.Projection = Matrix.PerspectiveFovLH(Geometry.DegreeToRadian(45),
(float)dev.Viewport.Width / (float)dev.Viewport.Height, 1, 100);
// ライト
//dev.RenderState.Lighting = false;
dev.RenderState.Ambient = Color.FromArgb(0x7f, 0x7f, 0x7f);
dev.Lights[0].Type = LightType.Directional;
dev.Lights[0].Direction = Vector3.Normalize(new Vector3(1, -2, 3));
dev.Lights[0].Diffuse = Color.FromArgb(0xff, 0xff, 0xff);
dev.Lights[0].Ambient = Color.FromArgb(0x7f, 0x7f, 0x7f);
dev.Lights[0].Enabled = true;
dev.Lights[0].Update();
CreateMesh();
return true;
}
catch (Exception e)
{
MessageBox.Show(e.Message, "MdxCreateMesh",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
void CreateMesh()
{
meshBox = Mesh.Box(dev, 1, 1, 1, out adjacencyBox);
meshSphere = Mesh.Sphere(dev, 0.5f, 16, 8);
CreateBox(-0.5f, 0.5f, -0.5f, 0.5f, -2.5f, 5); // 胴体
CreateBox(-5, 5, -0.4f, -0.2f, -1, 1); // 主翼
CreateBox(-2, 2, 0.2f, 0.3f, 3.5f, 4.5f); // 水平尾翼
CreateBox(-0.05f, 0.05f, 0.5f, 1.5f, 4, 5); // 垂直尾翼
CreateBox(-0.3f, 0.3f, 0.5f, 1, -0.5f, 1.5f); // 風防
int numVertices = vertexList.Count;
mesh = new Mesh(numVertices * 3 / 2, numVertices, MeshFlags.Managed,
CustomVertex.PositionNormal.Format, dev);
using (VertexBuffer vb = mesh.VertexBuffer)
{
GraphicsStream data = vb.Lock(0, 0, LockFlags.None);
data.Write(vertexList.ToArray());
vb.Unlock();
}
using (IndexBuffer ib = mesh.IndexBuffer)
{
ib.SetData(indexList.ToArray(), 0, LockFlags.None);
}
adjacency = new int[3 * mesh.NumberFaces];
mesh.GenerateAdjacency(0.01f, adjacency);
}
void CreateBox(float x1, float x2, float y1, float y2, float z1, float z2)
{
int numVertices = vertexList.Count;
// 頂点リスト
Vector3[] box =
{
new Vector3(x2, y2, z1), new Vector3(x2, y2, z2),
new Vector3(x2, y1, z1), new Vector3(x2, y1, z2),
new Vector3(x1, y1, z2), new Vector3(x1, y2, z2),
new Vector3(x1, y1, z1), new Vector3(x1, y2, z1),
};
Vector3 center = new Vector3((x1 + x2) / 2, (y1 + y2) / 2, (z1 + z2) / 2);
for (int i = 0; i < 8; i++)
{
vertexList.Add(new CustomVertex.PositionNormal(
box[i], Vector3.Normalize(box[i] - center)));
}
// 索引リスト
short[] indices =
{
0, 1, 2, 3, 2, 1, // +X面
4, 5, 6, 7, 6, 5, // -X面
0, 7, 1, 5, 1, 7, // +Y面
4, 6, 3, 2, 3, 6, // -Y面
0, 2, 7, 6, 7, 2, // +Z面
4, 3, 5, 1, 5, 3, // -Z面
};
for (int i = 0; i < 36; i++)
{
indexList.Add((short)(numVertices + indices[i]));
}
}
public void Render()
{
if (form.WindowState == FormWindowState.Minimized) return;
dev.RenderState.ZBufferEnable = true;
dev.RenderState.ZBufferWriteEnable = true;
// キー入力
const int delta = 2;
KeyboardState state;
state = keyboard.GetCurrentKeyboardState();
if (state[Key.Escape])
{
form.Close();
return;
}
if (state[Key.Up]) camLat = Math.Min(camLat + delta, 89);
if (state[Key.Down]) camLat = Math.Max(camLat - delta, -89);
if (state[Key.Left]) camLon = (camLon + delta) % 360;
if (state[Key.Right]) camLon = (camLon + (360 - delta)) % 360;
if (state[Key.PageUp]) camDist -= 0.1f;
if (state[Key.PageDown]) camDist += 0.1f;
if (state[Key.S] && state[Key.LeftControl])
{
if (SaveMesh())
{
MessageBox.Show("保存しました。", "MdxCreateMesh");
}
}
// fps
fpsDraw++;
int sec = DateTime.Now.Second;
if (fpsSec != sec)
{
fpsCount = fpsDraw;
fpsDraw = 0;
fpsSec = sec;
}
// カメラ位置
Vector3 pos;
float rad = Geometry.DegreeToRadian(camLat);
pos.Y = (float)Math.Sin(rad) * camDist;
float r = (float)Math.Cos(rad) * camDist;
rad = Geometry.DegreeToRadian(camLon);
pos.Z = (float)Math.Cos(rad) * r;
pos.X = (float)Math.Sin(rad) * r;
dev.Transform.View = Matrix.LookAtLH(pos, new Vector3(), new Vector3(0, 1, 0));
// バックバッファのクリア
dev.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.CornflowerBlue, 1.0f, 0);
dev.BeginScene();
// メッシュ描画
Material mat = new Material();
dev.Transform.World = Matrix.Translation(0, 0, 0);
mat.DiffuseColor = new ColorValue(0.0f, 0.8f, 0.0f);
mat.AmbientColor = new ColorValue(0.0f, 0.3f, 0.0f);
dev.Material = mat;
mesh.DrawSubset(0);
dev.Transform.World = Matrix.Translation(0, -2, 0);
mat.DiffuseColor = new ColorValue(0.0f, 0.0f, 0.8f);
mat.AmbientColor = new ColorValue(0.0f, 0.0f, 0.3f);
dev.Material = mat;
meshBox.DrawSubset(0);
dev.Transform.World = Matrix.Translation(0, 2, 0);
mat.DiffuseColor = new ColorValue(0.8f, 0.0f, 0.0f);
mat.AmbientColor = new ColorValue(0.3f, 0.0f, 0.0f);
dev.Material = mat;
meshSphere.DrawSubset(0);
string text = string.Format("fps={0} lat={1} lon={2} dist={3:f1}",
fpsCount, camLat, camLon, camDist);
font.DrawText(null, text, 0, 0, Color.White);
// バックバッファを表画面に反映
dev.EndScene();
try
{
dev.Present();
}
catch (DeviceLostException)
{
ResetDevice();
}
}
void ResetDevice()
{
int result;
if (!dev.CheckCooperativeLevel(out result))
{
switch ((ResultCode)result)
{
case ResultCode.DeviceLost:
Thread.Sleep(10);
break;
case ResultCode.DeviceNotReset:
dev.Reset(pp);
break;
default:
form.Close();
break;
}
}
}
bool SaveMesh()
{
try
{
ExtendedMaterial[] mtrl = new ExtendedMaterial[0];
mesh.Save(@"C:\tmp\mesh.x", adjacency, mtrl, XFileFormat.Text);
meshBox.Save(@"C:\tmp\box_2.x", adjacencyBox, mtrl, XFileFormat.Text);
return true;
}
catch (Exception e)
{
MessageBox.Show(e.Message, "エラー");
return false;
}
}
public void Dispose()
{
if (font != null)
{
font.Dispose();
}
}
}
}