8dcb8601a2
Hopefully this is the first and last time we have to do this.
208 lines
No EOL
6.9 KiB
C#
208 lines
No EOL
6.9 KiB
C#
// This code was written for the OpenTK library and has been released
|
|
// to the Public Domain.
|
|
// It is provided "as is" without express or implied warranty of any kind.
|
|
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
|
|
using OpenTK;
|
|
using OpenTK.Graphics;
|
|
using OpenTK.Graphics.OpenGL;
|
|
using OpenTK.Input;
|
|
|
|
namespace Examples.Tutorial
|
|
{
|
|
[Example( "Anaglyph Stereo", ExampleCategory.OpenGL, "1.x", Documentation = "Anaglyph" )]
|
|
|
|
class Anaglyph : GameWindow
|
|
{
|
|
|
|
Examples.Shapes.DrawableShape Object;
|
|
|
|
/// <summary>Creates a 800x600 window with the specified title.</summary>
|
|
public Anaglyph()
|
|
: base(800, 600, GraphicsMode.Default, "OpenTK Quick Start Sample", GameWindowFlags.Default, DisplayDevice.Default, 3, 1, GraphicsContextFlags.Default)
|
|
{
|
|
VSync = VSyncMode.On;
|
|
}
|
|
|
|
/// <summary>Load resources here.</summary>
|
|
/// <param name="e">Not used.</param>
|
|
protected override void OnLoad(EventArgs e)
|
|
{
|
|
base.OnLoad(e);
|
|
|
|
GL.ClearColor(System.Drawing.Color.Black);
|
|
GL.Enable(EnableCap.DepthTest);
|
|
|
|
GL.Enable( EnableCap.Lighting );
|
|
GL.Enable( EnableCap.Light0 );
|
|
|
|
Object = new Examples.Shapes.MengerSponge(1.0, Shapes.MengerSponge.eSubdivisions.Two, true );
|
|
// Object = new Examples.Shapes.TorusKnot( 256, 32, 0.1, 3, 4, 1, true );
|
|
}
|
|
|
|
protected override void OnUnload( EventArgs e )
|
|
{
|
|
base.OnUnload( e );
|
|
|
|
Object.Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when your window is resized. Set your viewport here. It is also
|
|
/// a good place to set up your projection matrix (which probably changes
|
|
/// along when the aspect ratio of your window).
|
|
/// </summary>
|
|
/// <param name="e">Not used.</param>
|
|
protected override void OnResize(EventArgs e)
|
|
{
|
|
base.OnResize(e);
|
|
|
|
GL.Viewport(ClientRectangle);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when it is time to setup the next frame. Add you game logic here.
|
|
/// </summary>
|
|
/// <param name="e">Contains timing information for framerate independent logic.</param>
|
|
protected override void OnUpdateFrame(FrameEventArgs e)
|
|
{
|
|
base.OnUpdateFrame(e);
|
|
|
|
if (Keyboard[Key.Escape])
|
|
Exit();
|
|
}
|
|
|
|
struct Camera
|
|
{
|
|
public Vector3 Position, Direction, Up;
|
|
public double NearPlane, FarPlane;
|
|
public double EyeSeparation;
|
|
public double Aperture; // FOV in degrees
|
|
public double FocalLength;
|
|
}
|
|
|
|
enum Eye
|
|
{
|
|
left,
|
|
right,
|
|
}
|
|
|
|
void SetupCamera( Eye eye )
|
|
{
|
|
Camera camera;
|
|
|
|
camera.Position = Vector3.UnitZ;
|
|
camera.Up = Vector3.UnitY;
|
|
camera.Direction = -Vector3.UnitZ;
|
|
camera.NearPlane = 1.0;
|
|
camera.FarPlane = 5.0;
|
|
camera.FocalLength = 2.0;
|
|
camera.EyeSeparation = camera.FocalLength / 30.0;
|
|
camera.Aperture = 75.0;
|
|
|
|
double left, right,
|
|
bottom, top;
|
|
|
|
double widthdiv2 = camera.NearPlane * Math.Tan( MathHelper.DegreesToRadians( (float)( camera.Aperture / 2.0 ) ) ); // aperture in radians
|
|
double precalc1 = ClientRectangle.Width / (double)ClientRectangle.Height * widthdiv2;
|
|
double precalc2 = 0.5 * camera.EyeSeparation * camera.NearPlane / camera.FocalLength;
|
|
|
|
Vector3 Right = Vector3.Cross( camera.Direction, camera.Up ); // Each unit vectors
|
|
Right.Normalize();
|
|
|
|
Right.X *= (float)( camera.EyeSeparation / 2.0 );
|
|
Right.Y *= (float)( camera.EyeSeparation / 2.0 );
|
|
Right.Z *= (float)( camera.EyeSeparation / 2.0 );
|
|
|
|
// Projection Matrix
|
|
top = widthdiv2;
|
|
bottom = -widthdiv2;
|
|
if ( eye == Eye.right )
|
|
{
|
|
left = -precalc1 - precalc2;
|
|
right = precalc1 - precalc2;
|
|
}
|
|
else
|
|
{
|
|
left = -precalc1 + precalc2;
|
|
right = precalc1 + precalc2;
|
|
}
|
|
|
|
GL.MatrixMode( MatrixMode.Projection );
|
|
GL.LoadIdentity();
|
|
GL.Frustum( left, right, bottom, top, camera.NearPlane, camera.FarPlane );
|
|
|
|
// Modelview Matrix
|
|
Matrix4 modelview;
|
|
if ( eye == Eye.right )
|
|
{
|
|
modelview = Matrix4.LookAt(
|
|
new Vector3( camera.Position.X + Right.X, camera.Position.Y + Right.Y, camera.Position.Z + Right.Z ),
|
|
new Vector3( camera.Position.X + Right.X + camera.Direction.X, camera.Position.Y + Right.Y + camera.Direction.Y, camera.Position.Z + Right.Z + camera.Direction.Z ),
|
|
camera.Up );
|
|
}
|
|
else
|
|
{
|
|
modelview = Matrix4.LookAt(
|
|
new Vector3( camera.Position.X - Right.X, camera.Position.Y - Right.Y, camera.Position.Z - Right.Z ),
|
|
new Vector3( camera.Position.X - Right.X + camera.Direction.X, camera.Position.Y - Right.Y + camera.Direction.Y, camera.Position.Z - Right.Z + camera.Direction.Z ),
|
|
camera.Up );
|
|
}
|
|
GL.MatrixMode( MatrixMode.Modelview );
|
|
GL.LoadIdentity();
|
|
GL.MultMatrix( ref modelview );
|
|
|
|
}
|
|
|
|
float Angle;
|
|
|
|
void Draw()
|
|
{
|
|
GL.Translate( 0f, 0f, -2f );
|
|
GL.Rotate( Angle, Vector3.UnitY );
|
|
Object.Draw();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when it is time to render the next frame. Add your rendering code here.
|
|
/// </summary>
|
|
/// <param name="e">Contains timing information.</param>
|
|
protected override void OnRenderFrame( FrameEventArgs e )
|
|
{
|
|
Angle += (float)(e.Time *20.0);
|
|
|
|
|
|
GL.Clear( ClearBufferMask.DepthBufferBit | ClearBufferMask.ColorBufferBit );
|
|
SetupCamera( Eye.right );
|
|
GL.ColorMask( true, false, false, true );
|
|
Draw();
|
|
|
|
GL.Clear( ClearBufferMask.DepthBufferBit ); //
|
|
SetupCamera( Eye.left );
|
|
GL.ColorMask( false, true, true, true );
|
|
Draw();
|
|
|
|
GL.ColorMask( true, true, true, true );
|
|
SwapBuffers();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The main entry point for the application.
|
|
/// </summary>
|
|
[STAThread]
|
|
static void Main()
|
|
{
|
|
// The 'using' idiom guarantees proper resource cleanup.
|
|
// We request 30 UpdateFrame events per second, and unlimited
|
|
// RenderFrame events (as fast as the computer can handle).
|
|
using (Anaglyph game = new Anaglyph())
|
|
{
|
|
game.Run(10.0);
|
|
}
|
|
}
|
|
}
|
|
} |