|
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using System.Reactive.Linq; |
|
|
|
using OpenTK; |
|
using OpenTK.Graphics; |
|
using OpenTK.Input; |
|
using OpenTK.Graphics.OpenGL; |
|
|
|
using OpenTK_RxUI; |
|
|
|
namespace OpenTK_RxUI_Test |
|
{ |
|
static public class OpenTKRxUIStarter |
|
{ |
|
static public void Do() |
|
{ |
|
using (MyWindow window = new MyWindow(800, 600)) |
|
{ |
|
window.Run(10.0); |
|
} |
|
} |
|
} |
|
|
|
partial class MyWindow : UIWindow |
|
{ |
|
readonly Vector4 lightPosition = new Vector4(200.0f, 150f, 500.0f, 0.0f); |
|
readonly Color4 lightAmbient = new Color4(0.2f, 0.2f, 0.2f, 1.0f); |
|
readonly Color4 lightDiffuse = new Color4(0.7f, 0.7f, 0.7f, 1.0f); |
|
readonly Color4 lightSpecular = new Color4(1.0f, 1.0f, 1.0f, 1.0f); |
|
|
|
readonly Color4 materialAmbient = new Color4(0.24725f, 0.1995f, 0.0225f, 1.0f); |
|
readonly Color4 materialDiffuse = new Color4(0.75164f, 0.60648f, 0.22648f, 1.0f); |
|
readonly Color4 materialSpecular = new Color4(0.628281f, 0.555802f, 0.366065f, 1.0f); |
|
readonly float materialShininess = 51.4f; |
|
|
|
Matrix4 rotate = Matrix4.Identity; |
|
float zoom = 1.0f; |
|
|
|
bool isCube = false; |
|
|
|
public MyWindow(int width, int height) |
|
: base(width, height) |
|
{ |
|
InitializeComponent(); |
|
|
|
WhiteButton.OnClick += (sender, e) => |
|
{ |
|
isCube = !isCube; |
|
Console.WriteLine("White"); |
|
}; |
|
RedButton.OnClick += (sender, e) => |
|
{ |
|
Console.WriteLine("Red"); |
|
}; |
|
GreenButton.OnClick += (sender, e) => |
|
{ |
|
Console.WriteLine("Green"); |
|
}; |
|
|
|
//Tracking |
|
MouseMoveSource.SkipUntil(MouseDownSource.Where(e => e.Button == MouseButton.Right)) |
|
.TakeUntil(MouseUpSource.Where(e => e.Button == MouseButton.Right)) |
|
.Repeat() |
|
.Subscribe(e => |
|
{ |
|
Vector2 delta = new Vector2(e.XDelta, e.YDelta); |
|
delta /= (float)Math.Sqrt(this.Width * this.Width + this.Height * this.Height); |
|
float length = delta.Length; |
|
if (length > 0.0) |
|
{ |
|
float rad = length * MathHelper.Pi; |
|
float theta = (float)Math.Sin(rad) / length; |
|
Quaternion after = new Quaternion(delta.Y * theta, delta.X * theta, 0.0f, (float)Math.Cos(rad)); |
|
rotate = rotate * Matrix4.Rotate(after); |
|
} |
|
}); |
|
|
|
//Zoom |
|
MouseWheelChangedSource.Subscribe(e => |
|
{ |
|
zoom *= (float)Math.Pow(1.2, e.DeltaPrecise); |
|
|
|
if (zoom > 2.0f) |
|
{ |
|
zoom = 2.0f; |
|
} |
|
if (zoom < 0.5f) |
|
{ |
|
zoom = 0.5f; |
|
} |
|
}); |
|
} |
|
|
|
protected override void OnLoad(EventArgs e) |
|
{ |
|
base.OnLoad(e); |
|
|
|
GL.ClearColor(Color4.Black); |
|
GL.Enable(EnableCap.DepthTest); |
|
|
|
//裏面削除、反時計回りが表でカリング |
|
GL.Enable(EnableCap.CullFace); |
|
GL.CullFace(CullFaceMode.Back); |
|
GL.FrontFace(FrontFaceDirection.Ccw); |
|
|
|
//ライティングON Light0を有効化 |
|
GL.Enable(EnableCap.Lighting); |
|
GL.Enable(EnableCap.Light0); |
|
|
|
//法線の正規化 |
|
GL.Enable(EnableCap.Normalize); |
|
|
|
|
|
GL.Light(LightName.Light0, LightParameter.Position, lightPosition); |
|
GL.Light(LightName.Light0, LightParameter.Ambient, lightAmbient); |
|
GL.Light(LightName.Light0, LightParameter.Diffuse, lightDiffuse); |
|
GL.Light(LightName.Light0, LightParameter.Specular, lightSpecular); |
|
|
|
GL.Material(MaterialFace.Front, MaterialParameter.Ambient, materialAmbient); |
|
GL.Material(MaterialFace.Front, MaterialParameter.Diffuse, materialDiffuse); |
|
GL.Material(MaterialFace.Front, MaterialParameter.Specular, materialSpecular); |
|
GL.Material(MaterialFace.Front, MaterialParameter.Shininess, materialShininess); |
|
} |
|
|
|
protected override void OnResize(EventArgs e) |
|
{ |
|
base.OnResize(e); |
|
|
|
GL.Viewport(ClientRectangle); |
|
} |
|
|
|
protected override void OnRenderFrame(FrameEventArgs e) |
|
{ |
|
base.OnRenderFrame(e); |
|
|
|
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); |
|
|
|
#region TransFormationMatrix |
|
|
|
Matrix4 modelView = Matrix4.LookAt(Vector3.UnitZ * 10 / zoom, Vector3.Zero, Vector3.UnitY); |
|
GL.MatrixMode(MatrixMode.Modelview); |
|
GL.LoadMatrix(ref modelView); |
|
GL.MultMatrix(ref rotate); |
|
|
|
Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4 / zoom, (float)this.Width / (float)this.Height, 1.0f, 64.0f); |
|
GL.MatrixMode(MatrixMode.Projection); |
|
GL.LoadMatrix(ref projection); |
|
|
|
#endregion |
|
|
|
GL.MatrixMode(MatrixMode.Modelview); |
|
|
|
GL.PushMatrix(); |
|
GL.Translate(2 * Vector3.UnitX); |
|
if (isCube) |
|
DrawCube(); |
|
GL.PopMatrix(); |
|
|
|
GL.PushMatrix(); |
|
GL.Translate(-2 * Vector3.UnitX); |
|
|
|
if (!isCube) |
|
DrawSphere(); |
|
|
|
GL.PopMatrix(); |
|
|
|
SwapBuffers(); |
|
} |
|
|
|
//立方体を描画する |
|
private void DrawCube() |
|
{ |
|
GL.Begin(BeginMode.Quads); |
|
|
|
GL.Normal3(1.0f, 0.0f, 0.0f); |
|
GL.Vertex3(1.0f, 1.0f, 1.0f); |
|
GL.Vertex3(1.0f, -1.0f, 1.0f); |
|
GL.Vertex3(1.0f, -1.0f, -1.0f); |
|
GL.Vertex3(1.0f, 1.0f, -1.0f); |
|
|
|
GL.Normal3(-1.0f, 0.0f, 0.0f); |
|
GL.Vertex3(-1.0f, 1.0f, 1.0f); |
|
GL.Vertex3(-1.0f, 1.0f, -1.0f); |
|
GL.Vertex3(-1.0f, -1.0f, -1.0f); |
|
GL.Vertex3(-1.0f, -1.0f, 1.0f); |
|
|
|
GL.Normal3(0.0f, 1.0f, 0.0f); |
|
GL.Vertex3(1.0f, 1.0f, 1.0f); |
|
GL.Vertex3(1.0f, 1.0f, -1.0f); |
|
GL.Vertex3(-1.0f, 1.0f, -1.0f); |
|
GL.Vertex3(-1.0f, 1.0f, 1.0f); |
|
|
|
GL.Normal3(0.0f, -1.0f, 0.0f); |
|
GL.Vertex3(1.0f, -1.0f, 1.0f); |
|
GL.Vertex3(-1.0f, -1.0f, 1.0f); |
|
GL.Vertex3(-1.0f, -1.0f, -1.0f); |
|
GL.Vertex3(1.0f, -1.0f, -1.0f); |
|
|
|
GL.Normal3(0.0f, 0.0f, 1.0f); |
|
GL.Vertex3(1.0f, 1.0f, 1.0f); |
|
GL.Vertex3(-1.0f, 1.0f, 1.0f); |
|
GL.Vertex3(-1.0f, -1.0f, 1.0f); |
|
GL.Vertex3(1.0f, -1.0f, 1.0f); |
|
|
|
GL.Normal3(0.0f, 0.0f, -1.0f); |
|
GL.Vertex3(1.0f, 1.0f, -1.0f); |
|
GL.Vertex3(1.0f, -1.0f, -1.0f); |
|
GL.Vertex3(-1.0f, -1.0f, -1.0f); |
|
GL.Vertex3(-1.0f, 1.0f, -1.0f); |
|
|
|
GL.End(); |
|
} |
|
|
|
//球を描画する |
|
private void DrawSphere() |
|
{ |
|
int slices = 16, stacks = 16; //横と縦の分割数 |
|
double r = 1.24; //半径 |
|
for (int i = 0; i < stacks; i++) |
|
{ |
|
//輪切り上部 |
|
double upper = Math.PI / stacks * i; |
|
double upperHeight = Math.Cos(upper); |
|
double upperWidth = Math.Sin(upper); |
|
//輪切り下部 |
|
double lower = Math.PI / stacks * (i + 1); |
|
double lowerHeight = Math.Cos(lower); |
|
double lowerWidth = Math.Sin(lower); |
|
|
|
GL.Begin(BeginMode.QuadStrip); |
|
for (int j = 0; j <= slices; j++) |
|
{ |
|
//輪切りの面を単位円としたときの座標 |
|
double rotor = 2 * Math.PI / slices * j; |
|
double x = Math.Cos(rotor); |
|
double y = Math.Sin(rotor); |
|
|
|
GL.Normal3(x * lowerWidth, lowerHeight, y * lowerWidth); |
|
GL.Vertex3(r * x * lowerWidth, r * lowerHeight, r * y * lowerWidth); |
|
GL.Normal3(x * upperWidth, upperHeight, y * upperWidth); |
|
GL.Vertex3(r * x * upperWidth, r * upperHeight, r * y * upperWidth); |
|
} |
|
GL.End(); |
|
} |
|
} |
|
} |
|
} |