Merged Inertia's example and geometry branch,

This commit is contained in:
the_fiddler 2009-10-24 10:07:43 +00:00
parent 0c25f266d3
commit fe5b0afe5b
49 changed files with 4986 additions and 46 deletions

View file

@ -0,0 +1,9 @@
// Copyright (c) 2008 the OpenTK Team. See license.txt for legal bla
uniform samplerCube Earth;
varying vec3 Normal;
void main()
{
gl_FragColor = textureCube( Earth, Normal.xyz );
}

View file

@ -0,0 +1,10 @@
// Copyright (c) 2008 the OpenTK Team. See license.txt for legal bla
// MUST be written to for FS
varying vec3 Normal;
void main()
{
gl_Position = ftransform();
Normal = /*gl_NormalMatrix * */ gl_Normal ;
}

View file

@ -0,0 +1,57 @@
// Copyright (c) 2008 the OpenTK Team. See license.txt for legal bla
// Material uniforms
uniform sampler2D Material_DiffuseAndHeight;
uniform sampler2D Material_NormalAndGloss;
uniform vec3 Material_ScaleBiasShininess; // x=Scale, y=Bias, z=Shininess
// Light uniforms
uniform vec3 Light_DiffuseColor;
uniform vec3 Light_SpecularColor;
// from VS
varying vec3 VaryingLightVector;
varying vec3 VaryingEyeVector;
vec3 normal;
void main()
{
vec3 lightVector = normalize( VaryingLightVector );
vec3 eyeVector = normalize( VaryingEyeVector );
// first, find the parallax displacement by reading only the height map
float parallaxOffset = texture2D( Material_DiffuseAndHeight, gl_TexCoord[0].st ).a *
Material_ScaleBiasShininess.x - Material_ScaleBiasShininess.y;
vec2 newTexCoords = gl_TexCoord[0].st + ( parallaxOffset * eyeVector.xy ); // displace texcoords according to viewer
// knowing the displacement, read RGB, Normal and Gloss
vec3 diffuseColor = texture2D( Material_DiffuseAndHeight, newTexCoords.st ).rgb;
vec4 temp = texture2D( Material_NormalAndGloss, newTexCoords.st );
// build a usable normal vector
normal.xy = temp.ag * 2.0 - 1.0; // swizzle alpha and green to x/y and scale to [-1..+1]
normal.z = sqrt( 1.0 - normal.x*normal.x - normal.y*normal.y ); // z = sqrt(1-x²-y²)
// move other properties to be better readable
float gloss = temp.r;
// float alpha = temp.b;
// if ( alpha < 0.2 ) // optimization: should move this test before reading RGB texture
// discard;
// tweaked phong lighting
float lambert = max( dot( lightVector, normal ), 0.0 );
gl_FragColor = vec4( Light_DiffuseColor * diffuseColor, 1.0 ) *
lambert;
if ( lambert > 0.0 )
{
float specular = pow(
clamp( dot( reflect( -lightVector, normal ), eyeVector ), 0.0, 1.0 ),
Material_ScaleBiasShininess.z );
gl_FragColor += vec4( Light_SpecularColor * diffuseColor, 1.0 ) * ( specular * gloss );
}
}

View file

@ -0,0 +1,35 @@
// Copyright (c) 2008 the OpenTK Team. See license.txt for legal bla
// custom vertex attribute
attribute vec3 AttributeTangent;
// world uniforms
uniform vec3 Light_Position;
uniform vec3 Camera_Position;
// MUST be written to for FS
varying vec3 VaryingLightVector;
varying vec3 VaryingEyeVector;
void main()
{
gl_Position = ftransform();
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
vec3 nor = normalize( gl_NormalMatrix * gl_Normal );
vec3 tan = normalize( gl_NormalMatrix * AttributeTangent );
vec3 bi = cross(nor, tan);
// need positions in tangent space
vec3 vertex = vec3( gl_ModelViewMatrix * gl_Vertex );
vec3 temp = Light_Position - vertex;
VaryingLightVector.x = dot(temp, tan); // optimization, calculate dot products rather than building TBN matrix
VaryingLightVector.y = dot(temp, bi);
VaryingLightVector.z = dot(temp, nor);
temp = Camera_Position - vertex;
VaryingEyeVector.x = dot(temp, tan);
VaryingEyeVector.y = dot(temp, bi);
VaryingEyeVector.z = dot(temp, nor);
}

View file

@ -0,0 +1,8 @@
#version 120
flat varying vec4 vColor;
void main(void)
{
gl_FragColor = vColor;
}

View file

@ -0,0 +1,9 @@
#version 120
flat varying vec4 vColor; // must be flat, cannot have this interpolated in any way
void main(void)
{
vColor = gl_Color;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; // ftransform();
}

Binary file not shown.

View file

Before

Width:  |  Height:  |  Size: 104 B

After

Width:  |  Height:  |  Size: 104 B

View file

@ -0,0 +1,18 @@
The files named "Swizzled *.dds" for the Parallax mapping demo originate from
http://www.TyphoonLabs.com ShaderDesigner application. Used with permission.
The Textures have been altered from the layout:
Diffuse R, Diffuse G, Diffuse B, Gloss
Normal X, Normal Y, Normal Z, Height
to
Diffuse R, Diffuse G, Diffuse B, Height
Gloss, Normal Y, Gloss, Normal X
Additionally, the Textures in this folder have been compressed with a lossy
algorithm (S3TC) and do not reflect the quality of the source Textures.
Please refer to the above website for unaltered versions of the textures,
or licensing information.

View file

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View file

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View file

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

View file

@ -43,7 +43,7 @@ namespace Examples
uint source;
int state;
Console.WriteLine("PlayStatic Test Application\n");
Trace.WriteLine("PlayStatic Test Application\n");
// Generate an AL Buffer
AL.GenBuffers(out buffer);
@ -59,17 +59,17 @@ namespace Examples
// Play Source
AL.SourcePlay(source);
Console.WriteLine("Playing Source ");
Trace.WriteLine("Playing Source ");
do
{
Thread.Sleep(100);
Console.Write(".");
Trace.Write(".");
// Get Source State
AL.GetSource(source, ALGetSourcei.SourceState, out state);
} while ((ALSourceState)state == ALSourceState.Playing);
Console.WriteLine();
Trace.WriteLine();
// Clean up by deleting Source(s) and Buffer(s)
AL.SourceStop(source);

View file

@ -7,6 +7,7 @@
#endregion
using System;
using System.Diagnostics;
using System.Threading;
using System.IO;
@ -80,7 +81,7 @@ namespace Examples
{
using (AudioContext context = new AudioContext())
{
Console.WriteLine("Testing WaveReader({0}).ReadToEnd()", filename);
Trace.WriteLine("Testing WaveReader({0}).ReadToEnd()", filename);
int buffer = AL.GenBuffer();
int source = AL.GenSource();
@ -93,18 +94,18 @@ namespace Examples
AL.Source(source, ALSourcei.Buffer, buffer);
AL.SourcePlay(source);
Console.Write("Playing");
Trace.Write("Playing");
// Query the source to find out when it stops playing.
do
{
Thread.Sleep(250);
Console.Write(".");
Trace.Write(".");
AL.GetSource(source, ALGetSourcei.SourceState, out state);
}
while ((ALSourceState)state == ALSourceState.Playing);
Console.WriteLine();
Trace.WriteLine("");
AL.SourceStop(source);
AL.DeleteSource(source);

View file

@ -7,6 +7,7 @@
#endregion
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Threading;
@ -36,9 +37,9 @@ namespace Examples.OpenAL
int[] buffers = AL.GenBuffers(buffer_count);
int state;
Console.WriteLine("Testing WaveReader({0}).ReadSamples()", filename);
Trace.WriteLine("Testing WaveReader({0}).ReadSamples()", filename);
Console.Write("Playing");
Trace.Write("Playing");
//foreach (int buffer in buffers)
// AL.BufferData(buffer, sound.ReadSamples(buffer_size));
@ -49,7 +50,7 @@ namespace Examples.OpenAL
do
{
//Console.Write(".");
//Trace.Write(".");
do
{
@ -58,13 +59,13 @@ namespace Examples.OpenAL
}
while (processed_count == 0);
Console.WriteLine(processed_count);
Trace.WriteLine(processed_count);
//while (processed_count > 0)
//{
// int buffer = AL.SourceUnqueueBuffer(source);
// if (buffer != 0 && !sound.EndOfFile)
// {
// Console.WriteLine(" " + buffer.ToString());
// Trace.WriteLine(" " + buffer.ToString());
// AL.BufferData(buffer, sound.ReadSamples(buffer_size));
// AL.SourceQueueBuffer(source, buffer);
// }
@ -78,7 +79,7 @@ namespace Examples.OpenAL
if ((ALSourceState)state != ALSourceState.Playing)
{
AL.SourcePlay(source);
Console.WriteLine("r");
Trace.WriteLine("r");
}
}
else
@ -91,7 +92,7 @@ namespace Examples.OpenAL
AL.DeleteBuffers(buffers);
}
Console.WriteLine();
Trace.WriteLine("");
}
}
}

View file

@ -26,6 +26,7 @@
#endregion
using System;
using System.Diagnostics;
using System.Threading;
using System.IO;
using OpenTK.Audio;
@ -42,7 +43,7 @@ namespace Examples
{
using (AudioContext context = new AudioContext())
{
Console.WriteLine("Testing WaveReader({0}).ReadToEnd()", filename);
Trace.WriteLine("Testing WaveReader({0}).ReadToEnd()", filename);
EffectsExtension efx = new EffectsExtension();
@ -73,18 +74,18 @@ namespace Examples
AL.Source(source, ALSourcei.Buffer, buffer);
AL.SourcePlay(source);
Console.Write("Playing");
Trace.Write("Playing");
// Query the source to find out when it stops playing.
do
{
Thread.Sleep(250);
Console.Write(".");
Trace.Write(".");
AL.GetSource(source, ALGetSourcei.SourceState, out state);
}
while ((ALSourceState)state == ALSourceState.Playing);
Console.WriteLine();
Trace.WriteLine("");
AL.SourceStop(source);
AL.DeleteSource(source);

View file

@ -99,8 +99,8 @@ namespace Examples
rec = null;
}
Trace.WriteLine("All done. Press Enter to exit.");
Console.ReadLine();
// Trace.WriteLine("All done. Press Enter to exit.");
// Console.ReadLine();
}
}

View file

@ -23,7 +23,7 @@ namespace Examples
public static void PrintOpenALErrors( IntPtr device )
{
ALError AlErr = AL.GetError();
Console.WriteLine("OpenAL error: {0}", AlErr);
Trace.WriteLine("OpenAL error: {0}"+ AlErr);
}
public static void Main()
@ -65,7 +65,7 @@ namespace Examples
//int AttribCount;
//Alc.GetInteger(context.Device, AlcGetInteger.AttributesSize, sizeof(int), out AttribCount);
//Console.WriteLine("AttributeSize: " + AttribCount);
//Trace.WriteLine("AttributeSize: " + AttribCount);
//if (AttribCount > 0)
//{
@ -73,10 +73,10 @@ namespace Examples
// Alc.GetInteger(context.Device, AlcGetInteger.AllAttributes, AttribCount, out Attribs[0]);
// for (int i = 0; i < Attribs.Length; i++)
// {
// Console.Write(Attribs[i]);
// Console.Write(" ");
// Trace.Write(Attribs[i]);
// Trace.Write(" ");
// }
// Console.WriteLine();
// Trace.WriteLine();
//}
#endregion Get Attribs
@ -89,36 +89,36 @@ namespace Examples
MyDevice = Alc.OpenDevice( null );// open default device
if ( MyDevice != Al.Null )
{
Console.WriteLine( "Device allocation succeeded." );
Trace.WriteLine( "Device allocation succeeded." );
MyContext = Alc.CreateContext( MyDevice, Al.Null ); // create context
if ( MyContext != Al.Null )
{
Console.WriteLine( "Context allocation succeeded." );
Trace.WriteLine( "Context allocation succeeded." );
GetOpenALErrors( MyDevice );
Alc.SuspendContext( MyContext ); // disable context
Alc.ProcessContext( MyContext ); // enable context. The default state of a context created by alcCreateContext is that it is processing.
Al.Bool result = Alc.MakeContextCurrent( MyContext ); // set active context
Console.WriteLine( "MakeContextCurrent succeeded? " + result );
Trace.WriteLine( "MakeContextCurrent succeeded? " + result );
GetOpenALErrors( MyDevice );
Console.WriteLine( "Default: " + Alc.GetString( MyDevice, Enums.AlcGetString.DefaultDeviceSpecifier ) );
Console.WriteLine( "Device: " + Alc.GetString( MyDevice, Enums.AlcGetString.DeviceSpecifier ) );
Console.WriteLine( "Extensions: " + Alc.GetString( MyDevice, Enums.AlcGetString.Extensions ) );
Trace.WriteLine( "Default: " + Alc.GetString( MyDevice, Enums.AlcGetString.DefaultDeviceSpecifier ) );
Trace.WriteLine( "Device: " + Alc.GetString( MyDevice, Enums.AlcGetString.DeviceSpecifier ) );
Trace.WriteLine( "Extensions: " + Alc.GetString( MyDevice, Enums.AlcGetString.Extensions ) );
GetOpenALErrors( MyDevice );
#region Get Attribs
int AttribCount;
Alc.GetInteger( MyDevice, Enums.AlcGetInteger.AttributesSize, sizeof( int ), out AttribCount );
Console.WriteLine( "AttributeSize: " + AttribCount );
Trace.WriteLine( "AttributeSize: " + AttribCount );
if ( AttribCount > 0 )
{
int[] Attribs = new int[AttribCount];
Alc.GetInteger( MyDevice, Enums.AlcGetInteger.AttributesSize, AttribCount, out Attribs[0] );
for ( int i = 0; i < Attribs.Length; i++ )
Console.Write( ", " + Attribs[i] );
Console.WriteLine( );
Trace.Write( ", " + Attribs[i] );
Trace.WriteLine( );
}
#endregion Get Attribs
GetOpenALErrors( MyDevice );
@ -127,30 +127,30 @@ namespace Examples
AlContext currcon = Alc.GetCurrentContext( );
if ( MyDevice == currdev )
Console.WriteLine( "Devices match." );
Trace.WriteLine( "Devices match." );
else
Console.WriteLine( "Error: Devices do not match." );
Trace.WriteLine( "Error: Devices do not match." );
if ( MyContext == currcon )
Console.WriteLine( "Context match." );
Trace.WriteLine( "Context match." );
else
Console.WriteLine( "Error: Contexts do not match." );
Trace.WriteLine( "Error: Contexts do not match." );
// exit
Alc.MakeContextCurrent( Al.Null ); // results in no context being current
Alc.DestroyContext( MyContext );
result = Alc.CloseDevice( MyDevice );
Console.WriteLine( "Result: " + result );
Console.ReadLine( );
Trace.WriteLine( "Result: " + result );
Trace.ReadLine( );
}
else
{
Console.WriteLine( "Context creation failed." );
Trace.WriteLine( "Context creation failed." );
}
}
else
{
Console.WriteLine( "Failed to find suitable Device." );
Trace.WriteLine( "Failed to find suitable Device." );
}
#endif
/*

View file

@ -0,0 +1,311 @@
using System;
using System.IO;
using System.Drawing;
using System.Diagnostics;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using Examples.Shapes;
namespace Examples.Tutorial
{
/// <summary>
/// This demo shows over which triangle the cursor is, it does so by assigning all 3 vertices of a triangle the same Ids.
/// Each Id is a uint, split into 4 bytes and used as triangle color. In an extra pass, the screen is cleared to uint.MaxValue,
/// and then the mesh is drawn using color. Using GL.ReadPixels() the value under the mouse cursor is read and can be converted.
/// </summary>
[Example("Picking", ExampleCategory.OpenGL, "1.1", Documentation = "Picking")]
class Picking : GameWindow
{
/// <summary>Creates a 800x600 window with the specified title.</summary>
public Picking()
: base(800, 600, GraphicsMode.Default, "Picking", GameWindowFlags.Default, DisplayDevice.Default, 1, 1, GraphicsContextFlags.Default)
{
VSync = VSyncMode.On;
}
struct Byte4
{
public byte R, G, B, A;
public Byte4(byte[] input)
{
R = input[0];
G = input[1];
B = input[2];
A = input[3];
}
public uint ToUInt32()
{
byte[] temp = new byte[] { this.R, this.G, this.B, this.A };
return BitConverter.ToUInt32(temp, 0);
}
public override string ToString()
{
return this.R + ", " + this.G + ", " + this.B + ", " + this.A;
}
}
struct Vertex
{
public Byte4 Color; // 4 bytes
public Vector3 Position; // 12 bytes
public const byte SizeInBytes = 16;
}
const TextureTarget Target = TextureTarget.TextureRectangleArb;
float angle;
BeginMode VBO_PrimMode;
Vertex[] VBO_Array;
uint VBO_Handle;
uint SelectedTriangle;
// int VertexShaderObject, FragmentShaderObject, ProgramObject;
/// <summary>Load resources here.</summary>
/// <param name="e">Not used.</param>
protected override void OnLoad(EventArgs e)
{
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.CullFace);
#region prepare data for VBO from procedural object
DrawableShape temp_obj = new SierpinskiTetrahedron(3f, SierpinskiTetrahedron.eSubdivisions.Five, false);
VertexT2fN3fV3f[] temp_VBO;
uint[] temp_IBO;
temp_obj.GetArraysforVBO(out VBO_PrimMode, out temp_VBO, out temp_IBO);
temp_obj.Dispose();
if (temp_IBO != null)
throw new Exception("Expected data for GL.DrawArrays, but Element Array is not null.");
// Convert from temp mesh to final object, copy position and add triangle Ids for the color attribute.
VBO_Array = new Vertex[temp_VBO.Length];
int TriangleCounter = -1;
for (int i = 0; i < temp_VBO.Length; i++)
{
// Position
VBO_Array[i].Position = temp_VBO[i].Position;
// Index
if (i % 3 == 0)
TriangleCounter++;
VBO_Array[i].Color = new Byte4(BitConverter.GetBytes(TriangleCounter));
}
#endregion prepare data for VBO from procedural object
#region Setup VBO for drawing
GL.GenBuffers(1, out VBO_Handle);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBO_Handle);
GL.BufferData<Vertex>(BufferTarget.ArrayBuffer, (IntPtr)(VBO_Array.Length * Vertex.SizeInBytes), VBO_Array, BufferUsageHint.StaticDraw);
GL.InterleavedArrays(InterleavedArrayFormat.C4ubV3f, 0, IntPtr.Zero);
ErrorCode err = GL.GetError();
if (err != ErrorCode.NoError)
Trace.WriteLine("VBO Setup failed (Error: " + err + "). Attempting to continue.");
#endregion Setup VBO for drawing
#region Shader
/*
// Load&Compile Vertex Shader
using (StreamReader sr = new StreamReader("Data/Shaders/Picking_VS.glsl"))
{
VertexShaderObject = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(VertexShaderObject, sr.ReadToEnd());
GL.CompileShader(VertexShaderObject);
}
err = GL.GetError();
if (err != ErrorCode.NoError)
Trace.WriteLine("Vertex Shader: " + err);
string LogInfo;
GL.GetShaderInfoLog(VertexShaderObject, out LogInfo);
if (LogInfo.Length > 0 && !LogInfo.Contains("hardware"))
Trace.WriteLine("Vertex Shader failed!\nLog:\n" + LogInfo);
else
Trace.WriteLine("Vertex Shader compiled without complaint.");
// Load&Compile Fragment Shader
using (StreamReader sr = new StreamReader("Data/Shaders/Picking_FS.glsl"))
{
FragmentShaderObject = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(FragmentShaderObject, sr.ReadToEnd());
GL.CompileShader(FragmentShaderObject);
}
GL.GetShaderInfoLog(FragmentShaderObject, out LogInfo);
err = GL.GetError();
if (err != ErrorCode.NoError)
Trace.WriteLine("Fragment Shader: " + err);
if (LogInfo.Length > 0 && !LogInfo.Contains("hardware"))
Trace.WriteLine("Fragment Shader failed!\nLog:\n" + LogInfo);
else
Trace.WriteLine("Fragment Shader compiled without complaint.");
// Link the Shaders to a usable Program
ProgramObject = GL.CreateProgram();
GL.AttachShader(ProgramObject, VertexShaderObject);
GL.AttachShader(ProgramObject, FragmentShaderObject);
// link it all together
GL.LinkProgram(ProgramObject);
err = GL.GetError();
if (err != ErrorCode.NoError)
Trace.WriteLine("LinkProgram: " + err);
GL.UseProgram(ProgramObject);
err = GL.GetError();
if (err != ErrorCode.NoError)
Trace.WriteLine("UseProgram: " + err);
// flag ShaderObjects for delete when not used anymore
GL.DeleteShader(VertexShaderObject);
GL.DeleteShader(FragmentShaderObject);
int temp;
GL.GetProgram(ProgramObject, ProgramParameter.LinkStatus, out temp);
Trace.WriteLine("Linking Program (" + ProgramObject + ") " + ((temp == 1) ? "succeeded." : "FAILED!"));
if (temp != 1)
{
GL.GetProgramInfoLog(ProgramObject, out LogInfo);
Trace.WriteLine("Program Log:\n" + LogInfo);
}
Trace.WriteLine("End of Shader build. GL Error: " + GL.GetError());
GL.UseProgram(0);
*/
#endregion Shader
}
protected override void OnUnload(EventArgs e)
{
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.DeleteBuffers(1, ref VBO_Handle);
base.OnUnload(e);
}
/// <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">Contains information on the new Width and Size of the GameWindow.</param>
protected override void OnResize(EventArgs e)
{
GL.Viewport(ClientRectangle);
Matrix4 projection = Matrix4.Perspective(45.0f, this.Width / (float)this.Height, 0.1f, 10.0f);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projection);
}
/// <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)
{
if (Keyboard[Key.Escape])
Exit();
}
/// <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)
{
GL.Color3(Color.White);
GL.Enable(EnableCap.ColorArray);
#region Pass 1: Draw Object and pick Triangle
GL.ClearColor(1f, 1f, 1f, 1f); // clears to uint.MaxValue
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
Matrix4 modelview = Matrix4.LookAt(Vector3.UnitZ, Vector3.Zero, Vector3.UnitY);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref modelview);
GL.Translate(0f, 0f, -3f);
GL.Rotate(angle, Vector3.UnitX);
GL.Rotate(angle, Vector3.UnitY);
angle += (float)e.Time * 3.0f;
// You may re-enable the shader, but it works perfectly without and will run on intel HW too
// GL.UseProgram(ProgramObject);
GL.DrawArrays(VBO_PrimMode, 0, VBO_Array.Length);
// GL.UseProgram(0);
// Read Pixel under mouse cursor
Byte4 Pixel = new Byte4();
GL.ReadPixels(Mouse.X, this.Height - Mouse.Y, 1, 1, PixelFormat.Rgba, PixelType.UnsignedByte, ref Pixel);
SelectedTriangle = Pixel.ToUInt32();
#endregion Pass 1: Draw Object and pick Triangle
GL.Color3(Color.White);
GL.Disable(EnableCap.ColorArray);
#region Pass 2: Draw Shape
if (SelectedTriangle == uint.MaxValue)
GL.ClearColor(.2f, .1f, .3f, 1f); // purple
else
GL.ClearColor(0f, .2f, .3f, 1f); // cyan
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Color3(1f, 1f, 1f);
GL.DrawArrays(VBO_PrimMode, 0, VBO_Array.Length);
GL.PolygonMode(MaterialFace.Front, PolygonMode.Line);
GL.Color3(Color.Red);
GL.DrawArrays(VBO_PrimMode, 0, VBO_Array.Length);
GL.PolygonMode(MaterialFace.Front, PolygonMode.Fill);
if (SelectedTriangle != uint.MaxValue)
{
GL.Disable(EnableCap.DepthTest);
GL.Color3(Color.Green);
GL.DrawArrays(VBO_PrimMode, (int)SelectedTriangle * 3, 3);
GL.Enable(EnableCap.DepthTest);
}
#endregion Pass 2: Draw Shape
this.SwapBuffers();
ErrorCode err = GL.GetError();
if (err != ErrorCode.NoError)
Trace.WriteLine("Error at Swapbuffers: " + err);
}
/// <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 (Picking example = new Picking())
{
// Get the title and category of this example using reflection.
ExampleAttribute info = ((ExampleAttribute)example.GetType().GetCustomAttributes(false)[0]);
example.Title = String.Format("OpenTK | {0} {1}: {2} (use the mouse to pick)", info.Category, info.Difficulty, info.Title);
example.Run(30.0);
}
}
}
}

View file

@ -0,0 +1,311 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using Examples.Shapes;
namespace Examples.Tutorial
{
[Example("Stencil CSG", ExampleCategory.OpenGL, "1.1", Documentation = "StencilCSG")]
partial class StencilCSG: GameWindow
{
#region Model Related
DrawableShape OperandB;
DrawableShape OperandA;
float MySphereZOffset = 0f;
float MySphereXOffset = 0f;
int Texture;
#endregion Model Related
string WindowTitle;
bool ShowDebugWireFrame = true;
float CameraZoom;
float CameraRotX;
float CameraRotY;
Vector3 EyePosition = new Vector3( 0f, 0f, 5f );
#region Window
public StencilCSG()
: base( 800, 600, new GraphicsMode( new ColorFormat( 8, 8, 8, 8 ), 24, 8 ) ) // request 8-bit stencil buffer
{
base.VSync = VSyncMode.Off;
}
protected override void OnResize(EventArgs e )
{
GL.Viewport( 0, 0, Width, Height );
GL.MatrixMode( MatrixMode.Projection );
Matrix4 p= Matrix4.Perspective( 45f, Width / (float)Height, 0.1f, 15.0f);
GL.LoadMatrix(ref p);
}
#endregion Window
protected override void OnLoad(EventArgs e)
{
#region Abort on platforms which will not be able to execute the ops properly
/*
if (!GL.SupportsExtension("VERSION_1_2"))
{
Trace.WriteLine("Aborting. OpenGL 1.2 or later required.");
this.Exit();
}
int[] t = new int[2];
GL.GetInteger(GetPName.MajorVersion, out t[0]);
GL.GetInteger(GetPName.MinorVersion, out t[1]);
Trace.WriteLine("OpenGL Context Version: " + t[0] + "." + t[1]);
GL.GetInteger(GetPName.DepthBits, out t[0]);
Trace.WriteLine("Depth Bits: " + t[0]);
GL.GetInteger(GetPName.StencilBits, out t[1]);
Trace.WriteLine("Stencil Bits: " + t[1]);
if (t[0] < 16)
{
Trace.WriteLine("Aborting. Need at least 16 depth bits, only " + t[0] + " available.");
this.Exit();
}
if (t[1] < 1)
{
Trace.WriteLine("Aborting. Need at least 1 stencil bit, only " + t[1] + " available.");
this.Exit();
}
*/
#endregion Abort on platforms which will not be able to execute the ops properly
WindowTitle = "Cube-Sphere Stencil CSG " + GL.GetString(StringName.Renderer) + " (GL " + GL.GetString(StringName.Version) + ")";
#region GL States
GL.ClearColor(.08f, .12f, .16f, 1f);
GL.Enable(EnableCap.DepthTest);
GL.DepthFunc(DepthFunction.Less);
GL.ClearDepth(1.0);
GL.Enable(EnableCap.StencilTest);
GL.ClearStencil(0);
GL.StencilMask(0xFFFFFFFF); // read&write
GL.Enable(EnableCap.CullFace);
GL.FrontFace(FrontFaceDirection.Ccw);
GL.CullFace(CullFaceMode.Back);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
GL.Color4(1f, 1f, 1f, 1f);
GL.Enable(EnableCap.Lighting);
GL.Enable(EnableCap.Light0);
GL.ShadeModel(ShadingModel.Smooth);
#endregion GL States
#region Load Texture
Bitmap bitmap = new Bitmap("Data/Textures/logo-dark.jpg");
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
GL.GenTextures(1, out Texture);
GL.BindTexture(TextureTarget.Texture2D, Texture);
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.Finish();
bitmap.UnlockBits(data);
#endregion Load Texture
OperandA = new ChamferCube(1.5, 2.0, 2.5, ChamferCube.SubDivs.Four, 0.42, true);
OperandB = new SlicedSphere(2.0f, Vector3d.Zero,
SlicedSphere.eSubdivisions.Three,
new SlicedSphere.eDir[] { SlicedSphere.eDir.All },
true);
#region Invert Operand B's Normals
// only the inside of the operand is ever drawn to color buffers and lighting requires this.
BeginMode tempPrimMode;
VertexT2dN3dV3d[] tempVertices;
uint[] tempIndices;
OperandB.GetArraysforVBO(out tempPrimMode, out tempVertices, out tempIndices);
OperandB.Dispose();
for (int i = 0; i < tempVertices.Length; i++)
{
tempVertices[i].Normal.Mult(-1.0);
tempVertices[i].Normal.Normalize();
}
OperandB = new VboShape(ref tempPrimMode, ref tempVertices, ref tempIndices, true);
#endregion Invert Operand B's Normals
}
protected override void OnUnload(EventArgs e)
{
GL.DeleteTextures( 1, ref Texture );
OperandA.Dispose();
OperandB.Dispose();
base.OnUnload( e );
}
protected override void OnUpdateFrame( FrameEventArgs e )
{
if (Keyboard[OpenTK.Input.Key.Escape])
{
this.Exit();
}
if (Keyboard[Key.Space])
{
ShowDebugWireFrame = !ShowDebugWireFrame;
}
#region Magic numbers for camera
CameraRotX = -Mouse.X * .5f;
CameraRotY = Mouse.Y * .5f;
CameraZoom = Mouse.Wheel * .2f;
#endregion Magic numbers for camera
}
public void DrawOperandB()
{
GL.PushMatrix();
GL.Translate( Math.Cos(MySphereXOffset), -1f, Math.Cos(MySphereZOffset) );
OperandB.Draw();
GL.PopMatrix();
}
public void DrawOperandA()
{
GL.Enable( EnableCap.Texture2D );
OperandA.Draw();
GL.Disable( EnableCap.Texture2D );
}
public void RenderCsg()
{
// first pass
GL.Disable( EnableCap.StencilTest );
GL.ColorMask( false, false, false, false );
GL.CullFace( CullFaceMode.Front );
DrawOperandB();// draw front-faces into depth buffer
// use stencil plane to find parts of b in a
GL.DepthMask( false );
GL.Enable( EnableCap.StencilTest );
GL.StencilFunc( StencilFunction.Always, 0, 0 );
GL.StencilOp( StencilOp.Keep, StencilOp.Keep, StencilOp.Incr );
GL.CullFace( CullFaceMode.Back );
DrawOperandA(); // increment the stencil where the front face of a is drawn
GL.StencilOp( StencilOp.Keep, StencilOp.Keep, StencilOp.Decr );
GL.CullFace( CullFaceMode.Front );
DrawOperandA(); // decrement the stencil buffer where the back face of a is drawn
GL.DepthMask( true );
GL.Disable( EnableCap.DepthTest );
GL.ColorMask( true, true, true, true );
GL.StencilFunc( StencilFunction.Notequal, 0, 1 );
DrawOperandB(); // draw the part of b that's in a
// fix depth
GL.ColorMask( false, false, false, false );
GL.Enable( EnableCap.DepthTest );
GL.Disable( EnableCap.StencilTest );
GL.DepthFunc( DepthFunction.Always );
DrawOperandA();
GL.DepthFunc( DepthFunction.Less );
// second pass
GL.CullFace( CullFaceMode.Back );
DrawOperandA();
GL.DepthMask( false );
GL.Enable( EnableCap.StencilTest );
GL.StencilFunc( StencilFunction.Always, 0, 0 );
GL.StencilOp( StencilOp.Keep, StencilOp.Keep, StencilOp.Incr );
DrawOperandB(); // increment the stencil where the front face of b is drawn
GL.StencilOp( StencilOp.Keep, StencilOp.Keep, StencilOp.Decr );
GL.CullFace( CullFaceMode.Front );
DrawOperandB(); // decrement the stencil buffer where the back face of b is drawn
GL.DepthMask( true );
GL.Disable( EnableCap.DepthTest );
GL.ColorMask( true, true, true, true );
GL.StencilFunc( StencilFunction.Equal, 0, 1 );
GL.CullFace( CullFaceMode.Back );
DrawOperandA(); // draw the part of a that's in b
GL.Enable( EnableCap.DepthTest );
}
protected override void OnRenderFrame( FrameEventArgs e )
{
this.Title = WindowTitle + " fps: " + ( 1f / e.Time );
MySphereZOffset += (float)( e.Time * 3.1 );
MySphereXOffset += (float)( e.Time * 4.2 );
#region Transform setup
GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit );
// Camera
GL.MatrixMode( MatrixMode.Modelview );
Matrix4 mv = Matrix4.LookAt( EyePosition, Vector3.Zero, Vector3.UnitY );
GL.LoadMatrix(ref mv);
GL.Translate( 0f, 0f, CameraZoom );
GL.Rotate( CameraRotX, Vector3.UnitY );
GL.Rotate( CameraRotY, Vector3.UnitX );
#endregion Transform setup
RenderCsg();
// ---------------------------------
if ( ShowDebugWireFrame )
{
GL.Disable( EnableCap.StencilTest );
GL.Disable( EnableCap.Lighting );
GL.Disable( EnableCap.DepthTest );
GL.PolygonMode( MaterialFace.Front, PolygonMode.Line );
DrawOperandB();
GL.PolygonMode( MaterialFace.Front, PolygonMode.Fill );
GL.Enable( EnableCap.DepthTest );
GL.Enable( EnableCap.Lighting );
GL.Enable( EnableCap.StencilTest );
}
this.SwapBuffers();
}
[STAThread]
static void Main()
{
using ( StencilCSG example = new StencilCSG() )
{
Utilities.SetWindowTitle(example);
example.Run( 30.0, 0.0 );
}
}
}
}

View file

@ -0,0 +1,155 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
namespace Examples.Tutorial
{
[Example("Texture Matrix Wormhole", ExampleCategory.OpenGL, "1.1", Documentation = "TextureMatrix")]
class TextureMatrix : GameWindow
{
public TextureMatrix()
: base(800, 600 )
{
VSync = VSyncMode.Off;
}
int Texture;
int list;
protected override void OnLoad(EventArgs e)
{
GL.ClearColor(0f, 0f, 0f, 0f);
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.CullFace);
Texture = LoadTexture("Data/Textures/logo-dark.jpg");
GL.Enable(EnableCap.Texture2D);
list = GL.GenLists(1);
GL.NewList(list, ListMode.Compile);
{
const int slices = 32;
const float distance = 0.25f;
GL.Begin(BeginMode.Quads);
for (float scale = 0.26f; scale < 5f; scale += distance)
for (int i = 0; i < slices; i++)
{
Vector3 MiddleCenter = new Vector3((float)(Math.Sin((double)i / slices * 2 * Math.PI) * scale),
(float)(Math.Cos((double)i / slices * 2 * Math.PI) * scale),
(float)(1f / scale));
Vector3 MiddleRight = new Vector3((float)(Math.Sin((double)(i + 1) / slices * 2 * Math.PI) * scale),
(float)(Math.Cos((double)(i + 1) / slices * 2 * Math.PI) * scale),
(float)(1f / scale));
Vector3 BottomRight = new Vector3((float)(Math.Sin((double)(i + 1) / slices * 2 * Math.PI) * (scale - distance)),
(float)(Math.Cos((double)(i + 1) / slices * 2 * Math.PI) * (scale - distance)),
(float)(1f / (scale - distance)));
Vector3 BottomCenter = new Vector3((float)(Math.Sin((double)i / slices * 2 * Math.PI) * (scale - distance)),
(float)(Math.Cos((double)i / slices * 2 * Math.PI) * (scale - distance)),
(float)(1f / (scale - distance)));
GL.TexCoord2(1f, 0f);
GL.Vertex3(MiddleCenter);
GL.TexCoord2(0f, 0f);
GL.Vertex3(MiddleRight);
GL.TexCoord2(0f, 1f);
GL.Vertex3(BottomRight);
GL.TexCoord2(1f, 1f);
GL.Vertex3(BottomCenter);
}
GL.End();
}
GL.EndList();
}
protected override void OnResize(EventArgs e)
{
GL.Viewport(this.ClientRectangle);
Matrix4 projection = Matrix4.Perspective(45.0f, Width / (float)Height, 1.0f, 50.0f);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projection);
}
protected override void OnUpdateFrame(FrameEventArgs e)
{
if (Keyboard[Key.Escape])
Exit();
}
protected override void OnRenderFrame(FrameEventArgs e)
{
GL.Clear(ClearBufferMask.ColorBufferBit |
ClearBufferMask.DepthBufferBit);
GL.MatrixMode(MatrixMode.Texture);
GL.Translate(e.Time/2, -e.Time, 0f);
Matrix4 modelview = Matrix4.LookAt(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref modelview);
GL.Translate(0f, 0f, 1.5f);
GL.Rotate(Mouse.X, Vector3.UnitY);
GL.Rotate(Mouse.Y, Vector3.UnitX);
GL.CallList(list);
SwapBuffers();
}
public static int LoadTexture(string filename)
{
TextureTarget Target = TextureTarget.Texture2D;
int texture;
GL.GenTextures(1, out texture);
GL.BindTexture(Target, texture);
Bitmap bitmap = new Bitmap(filename);
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(Target, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
GL.Finish();
bitmap.UnlockBits(data);
GL.TexParameter(Target, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(Target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(Target, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
GL.TexParameter(Target, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
if (GL.GetError() != ErrorCode.NoError)
throw new Exception("Error loading texture " + filename);
return texture;
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (TextureMatrix example = new TextureMatrix())
{
// Get the title and category of this example using reflection.
ExampleAttribute info = ((ExampleAttribute)example.GetType().GetCustomAttributes(false)[0]);
example.Title = String.Format("OpenTK | {0} {1}: {2}", info.Category, info.Difficulty, info.Title);
example.Run(30.0, 0.0);
}
}
}
}

View file

@ -25,7 +25,7 @@ namespace Examples.Tutorial
[Example("Texture mapping", ExampleCategory.OpenGL, "1.1", Documentation="Textures")]
public class Textures : GameWindow
{
Bitmap bitmap = new Bitmap("Data/logo.jpg");
Bitmap bitmap = new Bitmap("Data/Textures/logo.jpg");
int texture;
public Textures() : base(800, 600) { }

View file

@ -0,0 +1,198 @@
using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
namespace Examples.Tutorial
{
[Example("Dynamic Vertex Buffer Objects", ExampleCategory.OpenGL, "VBO", Documentation = "DynamicVBO")]
class T09_VBO_Dynamic: GameWindow
{
/// <summary>Creates a 800x600 window with the specified title.</summary>
public T09_VBO_Dynamic( )
: base( 800, 600 )
{
this.VSync = VSyncMode.Off;
}
#region Particles
const int MaxParticleCount = 1000;
int VisibleParticleCount;
VertexC4ubV3f[] VBO = new VertexC4ubV3f[MaxParticleCount];
ParticleAttribut[] ParticleAttributes = new ParticleAttribut[MaxParticleCount];
// this struct is used for drawing
struct VertexC4ubV3f
{
public byte R, G, B, A;
public Vector3 Position;
public static int SizeInBytes = 16;
}
// this struct is used for updates
struct ParticleAttribut
{
public Vector3 Direction;
public uint Age;
// more stuff could be here: Rotation, Radius, whatever
}
uint VBOHandle;
#endregion Particles
/// <summary>Load resources here.</summary>
/// <param name="e">Not used.</param>
protected override void OnLoad( EventArgs e )
{
GL.ClearColor( .1f, 0f, .1f, 0f );
GL.Enable( EnableCap.DepthTest );
// Setup parameters for Points
GL.PointSize( 5f );
GL.Enable( EnableCap.PointSmooth );
GL.Hint( HintTarget.PointSmoothHint, HintMode.Nicest );
// Setup VBO state
GL.EnableClientState( EnableCap.ColorArray );
GL.EnableClientState( EnableCap.VertexArray );
GL.GenBuffers( 1, out VBOHandle );
// Since there's only 1 VBO in the app, might aswell setup here.
GL.BindBuffer( BufferTarget.ArrayBuffer, VBOHandle );
GL.ColorPointer( 4, ColorPointerType.UnsignedByte, VertexC4ubV3f.SizeInBytes, (IntPtr) 0 );
GL.VertexPointer( 3, VertexPointerType.Float, VertexC4ubV3f.SizeInBytes, (IntPtr) (4*sizeof(byte)) );
Random rnd = new Random( );
Vector3 temp = Vector3.Zero;
// generate some random stuff for the particle system
for ( uint i = 0 ; i < MaxParticleCount ; i++ )
{
VBO[i].R = (byte) rnd.Next( 0, 256 );
VBO[i].G = (byte) rnd.Next( 0, 256 );
VBO[i].B = (byte) rnd.Next( 0, 256 );
VBO[i].A = (byte) rnd.Next( 0, 256 ); // isn't actually used
VBO[i].Position = Vector3.Zero; // all particles are born at the origin
// generate direction vector in the range [-0.1f...+0.1f]
// that's slow enough so you can see particles 'disappear' when they are respawned
temp.X = (float) ( ( rnd.NextDouble( ) - 0.5 ) * 0.2 );
temp.Y = (float) ( ( rnd.NextDouble( ) - 0.5 ) * 0.2 );
temp.Z = (float) ( ( rnd.NextDouble( ) - 0.5 ) * 0.2 );
ParticleAttributes[i].Direction = temp; // copy
ParticleAttributes[i].Age = 0;
}
VisibleParticleCount = 0;
}
protected override void OnUnload(EventArgs e)
{
GL.DeleteBuffers( 1, ref VBOHandle );
}
/// <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">Contains information on the new Width and Size of the GameWindow.</param>
protected override void OnResize(EventArgs e)
{
GL.Viewport(0, 0, Width, Height);
GL.MatrixMode(MatrixMode.Projection);
Matrix4 p = Matrix4.Perspective(45.0f, Width / (float)Height, 0.1f, 50.0f);
GL.LoadMatrix(ref p);
GL.MatrixMode(MatrixMode.Modelview);
Matrix4 mv = Matrix4.LookAt(Vector3.UnitZ, Vector3.Zero, Vector3.UnitY);
GL.LoadMatrix(ref mv);
}
/// <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 )
{
if ( Keyboard[Key.Escape] )
{
Exit( );
}
// will update particles here. When using a Physics SDK, it's update rate is much higher than
// the framerate and it would be a waste of cycles copying to the VBO more often than drawing it.
if ( VisibleParticleCount < MaxParticleCount )
VisibleParticleCount++;
Vector3 temp;
for ( int i = MaxParticleCount - VisibleParticleCount ; i < MaxParticleCount ; i++ )
{
if ( ParticleAttributes[i].Age >= MaxParticleCount )
{
// reset particle
ParticleAttributes[i].Age = 0;
VBO[i].Position = Vector3.Zero;
} else
{
ParticleAttributes[i].Age++;
Vector3.Mult( ref ParticleAttributes[i].Direction, (float) e.Time, out temp );
Vector3.Add( ref VBO[i].Position, ref temp, out VBO[i].Position );
}
}
}
/// <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 )
{
this.Title = VisibleParticleCount + " Points. FPS: " + string.Format( "{0:F}", 1.0 / e.Time );
GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
GL.PushMatrix( );
GL.Translate( 0f, 0f, -5f );
// Tell OpenGL to discard old VBO when done drawing it and reserve memory _now_ for a new buffer.
// without this, GL would wait until draw operations on old VBO are complete before writing to it
GL.BufferData( BufferTarget.ArrayBuffer, (IntPtr) ( VertexC4ubV3f.SizeInBytes * MaxParticleCount ), IntPtr.Zero, BufferUsageHint.StreamDraw );
// Fill newly allocated buffer
GL.BufferData( BufferTarget.ArrayBuffer, (IntPtr) ( VertexC4ubV3f.SizeInBytes * MaxParticleCount ), VBO, BufferUsageHint.StreamDraw );
// Only draw particles that are alive
GL.DrawArrays( BeginMode.Points, MaxParticleCount - VisibleParticleCount, VisibleParticleCount );
GL.PopMatrix( );
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 (T09_VBO_Dynamic example = new T09_VBO_Dynamic())
{
// Get the title and category of this example using reflection.
ExampleAttribute info = ((ExampleAttribute)example.GetType().GetCustomAttributes(false)[0]);
example.Title = String.Format("OpenTK | {0} {1}: {2}", info.Category, info.Difficulty, info.Title);
example.Run(60.0, 0.0);
}
}
}
}

View file

@ -21,7 +21,7 @@ using OpenTK.Platform;
namespace Examples.Tutorial
{
[Example("Vertex Buffer Objects", ExampleCategory.OpenGL, "1.5", false, Documentation="VertexBufferObject")]
[Example("Static Vertex Buffer Objects", ExampleCategory.OpenGL, "VBO", Documentation="VertexBufferObject")]
public class T08_VBO : GameWindow
{
#region --- Private Fields ---

View file

@ -0,0 +1,278 @@
#region --- License ---
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing details.
*/
#endregion
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using System.IO;
using System.Text;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using Examples.Shapes;
using Examples.TextureLoaders;
namespace Examples.Tutorial
{
[Example("DDS Cube Map", ExampleCategory.OpenGL, "GLSL", Documentation = "DDSCubeMap")]
public class T13_GLSL_Earth: GameWindow
{
public T13_GLSL_Earth( )
: base( 800, 800 )
{
}
#region internal Fields
// Shader
int VertexShaderObject, FragmentShaderObject, ProgramObject;
const string VertexShaderFilename = "Data/Shaders/CubeMap_VS.glsl";
const string FragmentShaderFilename = "Data/Shaders/CubeMap_FS.glsl";
// Textures
const TextureUnit TMU0_Unit = TextureUnit.Texture0;
const int TMU0_UnitInteger = 0;
const string TMU0_Filename = "Data/Textures/Earth CubeMap.dds";
uint TMU0_Handle;
TextureTarget TMU0_Target;
// DL
DrawableShape sphere;
// Camera
Vector3 EyePos = new Vector3( 0.0f, 0.0f, 3.0f );
Vector3 Trackball = Vector3.Zero;
#endregion internal Fields
/// <summary>Setup OpenGL and load resources here.</summary>
/// <param name="e">Not used.</param>
protected override void OnLoad(EventArgs e)
{
this.VSync = VSyncMode.Off;
/*
// Check for necessary capabilities:
if ( !GL.SupportsExtension( "VERSION_2_0" ) )
{
MessageBox.Show( "You need at least OpenGL 2.0 to run this example. Aborting.",
"GLSL not supported", MessageBoxButtons.OK, MessageBoxIcon.Exclamation );
this.Exit( );
}
if ( !GL.SupportsExtension( "GL_ARB_texture_compression" ) ||
!GL.SupportsExtension( "GL_EXT_texture_compression_s3tc" ) )
{
MessageBox.Show( "Texture compression extensions not found. Trying to run anyways.",
"Possible problem", MessageBoxButtons.OK, MessageBoxIcon.Warning );
}
*/
#region GL State
GL.ClearColor( 0f, 0f, 0f, 0f );
GL.Disable( EnableCap.Dither );
GL.Enable( EnableCap.CullFace );
GL.FrontFace( FrontFaceDirection.Ccw );
GL.PolygonMode( MaterialFace.Front, PolygonMode.Fill );
// GL.PolygonMode( MaterialFace.Back, PolygonMode.Line );
#endregion GL State
#region Shaders
string LogInfo;
// Load&Compile Vertex Shader
using ( StreamReader sr = new StreamReader( VertexShaderFilename ) )
{
VertexShaderObject = GL.CreateShader( ShaderType.VertexShader );
GL.ShaderSource( VertexShaderObject, sr.ReadToEnd( ) );
GL.CompileShader( VertexShaderObject );
}
GL.GetShaderInfoLog( VertexShaderObject, out LogInfo );
if ( LogInfo.Length > 0 && !LogInfo.Contains( "hardware" ) )
Trace.WriteLine( "Vertex Shader failed!\nLog:\n" + LogInfo );
else
Trace.WriteLine( "Vertex Shader compiled without complaint." );
// Load&Compile Fragment Shader
using ( StreamReader sr = new StreamReader( FragmentShaderFilename ) )
{
FragmentShaderObject = GL.CreateShader( ShaderType.FragmentShader );
GL.ShaderSource( FragmentShaderObject, sr.ReadToEnd( ) );
GL.CompileShader( FragmentShaderObject );
}
GL.GetShaderInfoLog( FragmentShaderObject, out LogInfo );
if ( LogInfo.Length > 0 && !LogInfo.Contains( "hardware" ) )
Trace.WriteLine( "Fragment Shader failed!\nLog:\n" + LogInfo );
else
Trace.WriteLine( "Fragment Shader compiled without complaint." );
// Link the Shaders to a usable Program
ProgramObject = GL.CreateProgram( );
GL.AttachShader( ProgramObject, VertexShaderObject );
GL.AttachShader( ProgramObject, FragmentShaderObject );
// link it all together
GL.LinkProgram( ProgramObject );
// flag ShaderObjects for delete when not used anymore
GL.DeleteShader( VertexShaderObject );
GL.DeleteShader( FragmentShaderObject );
int[] temp = new int[1];
GL.GetProgram( ProgramObject, ProgramParameter.LinkStatus, out temp[0] );
Trace.WriteLine( "Linking Program (" + ProgramObject + ") " + ( ( temp[0] == 1 ) ? "succeeded." : "FAILED!" ) );
if ( temp[0] != 1 )
{
GL.GetProgramInfoLog( ProgramObject, out LogInfo );
Trace.WriteLine( "Program Log:\n" + LogInfo );
}
GL.GetProgram( ProgramObject, ProgramParameter.ActiveAttributes, out temp[0] );
Trace.WriteLine( "Program registered " + temp[0] + " Attributes. (Should be 4: Pos, UV, Normal, Tangent)" );
Trace.WriteLine( "Tangent attribute bind location: " + GL.GetAttribLocation( ProgramObject, "AttributeTangent" ) );
Trace.WriteLine( "End of Shader build. GL Error: " + GL.GetError( ) );
#endregion Shaders
#region Textures
TextureLoaderParameters.FlipImages = false;
TextureLoaderParameters.MagnificationFilter = TextureMagFilter.Linear;
TextureLoaderParameters.MinificationFilter = TextureMinFilter.Linear;
TextureLoaderParameters.WrapModeS = TextureWrapMode.ClampToEdge;
TextureLoaderParameters.WrapModeT = TextureWrapMode.ClampToEdge;
TextureLoaderParameters.EnvMode = TextureEnvMode.Modulate;
ImageDDS.LoadFromDisk( TMU0_Filename, out TMU0_Handle, out TMU0_Target );
Trace.WriteLine( "Loaded " + TMU0_Filename + " with handle " + TMU0_Handle + " as " + TMU0_Target );
#endregion Textures
Trace.WriteLine( "End of Texture Loading. GL Error: " + GL.GetError( ) );
Trace.WriteLine( "");
sphere = new SlicedSphere(1.5f, Vector3d.Zero, SlicedSphere.eSubdivisions.Four, new SlicedSphere.eDir[] { SlicedSphere.eDir.All }, true);
}
protected override void OnUnload(EventArgs e)
{
sphere.Dispose();
GL.DeleteProgram( ProgramObject );
GL.DeleteTextures( 1, ref TMU0_Handle );
base.OnUnload( e );
}
/// <summary>Respond to resize events here.</summary>
/// <param name="e">Contains information on the new GameWindow size.</param>
/// <remarks>There is no need to call the base implementation.</remarks>
protected override void OnResize( EventArgs e )
{
GL.Viewport( 0, 0, Width, Height );
GL.MatrixMode( MatrixMode.Projection );
Matrix4 p = Matrix4.Perspective( 45.0f, Width / (float) Height, 0.1f, 10.0f );
GL.LoadMatrix(ref p);
GL.MatrixMode( MatrixMode.Modelview );
GL.LoadIdentity( );
base.OnResize( e );
}
/// <summary>Add your game logic here.</summary>
/// <param name="e">Contains timing information.</param>
/// <remarks>There is no need to call the base implementation.</remarks>
protected override void OnUpdateFrame( FrameEventArgs e )
{
base.OnUpdateFrame( e );
if ( Keyboard[OpenTK.Input.Key.Escape] )
this.Exit( );
if ( Keyboard[OpenTK.Input.Key.Space] )
Trace.WriteLine( "GL: " + GL.GetError( ) );
Trackball.X = Mouse.X;
Trackball.Y = Mouse.Y;
Trackball.Z = Mouse.Wheel * 0.5f;
}
/// <summary>Add your game rendering code here.</summary>
/// <param name="e">Contains timing information.</param>
/// <remarks>There is no need to call the base implementation.</remarks>
protected override void OnRenderFrame(FrameEventArgs e)
{
this.Title = "FPS: " + 1 / e.Time;
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.UseProgram(ProgramObject);
#region Textures
GL.ActiveTexture(TMU0_Unit);
GL.BindTexture(TMU0_Target, TMU0_Handle);
#endregion Textures
#region Uniforms
GL.Uniform1(GL.GetUniformLocation(ProgramObject, "Earth"), TMU0_UnitInteger);
#endregion Uniforms
GL.PushMatrix();
Matrix4 temp = Matrix4.LookAt(EyePos, Vector3.Zero, Vector3.UnitY);
GL.MultMatrix(ref temp);
GL.Rotate(Trackball.X, Vector3.UnitY);
GL.Rotate(Trackball.Y, Vector3.UnitX);
#region Draw
GL.Color3(1f, 1f, 1f);
sphere.Draw();
#endregion Draw
GL.PopMatrix();
this.SwapBuffers();
}
/// <summary>Entry point</summary>
[STAThread]
public static void Main( )
{
using ( T13_GLSL_Earth example = new T13_GLSL_Earth( ) )
{
Utilities.SetWindowTitle(example);
example.Run( 30.0, 0.0 );
}
}
}
}

View file

@ -157,7 +157,7 @@ namespace Examples.Tutorial
GL.TexParameter(TextureTarget.Texture1D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture1D, TextureParameterName.TextureWrapS, (int)(TextureWrapMode)All.ClampToEdge);
using (Bitmap bitmap = new Bitmap("Data/JuliaColorTable.bmp"))
using (Bitmap bitmap = new Bitmap("Data/Textures/JuliaColorTable.bmp"))
{
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);

View file

@ -0,0 +1,379 @@
#region --- License ---
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing details.
*/
#endregion
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using Examples.TextureLoaders;
namespace Examples.Tutorial
{
/// <summary>Demonstrates Swizzled DXT5 Parallax Mapping
/// The idea is described in more detail right here: http://www.opentk.com/node/394
/// </summary>
[Example("Swizzled Parallax Mapping", ExampleCategory.OpenGL, "GLSL", Documentation = "SwizzledParallax")]
public class T12_GLSL_Parallax: GameWindow
{
public T12_GLSL_Parallax( )
: base( 800, 600 )
{
}
#region internal Fields
// Shader
int VertexShaderObject, FragmentShaderObject, ProgramObject;
const string VertexShaderFilename = "Data/Shaders/Parallax_VS.glsl";
const string FragmentShaderFilename = "Data/Shaders/Parallax_FS.glsl";
const int AttribTangent = 5; // slot where to pass tangents to VS, not sure which are reserved besides 0
Vector3 Tangent = new Vector3( 1f, 0f, 0f );
Vector3 Normal = new Vector3( 0f, 0f, 1f );
// Material parameter
//Vector3 MaterialScaleAndBiasAndShininess = new Vector3( 0.07f, 0.0f, 38.0f ); // for Metal tex
Vector3 MaterialScaleAndBiasAndShininess = new Vector3( 0.04f, 0.0f, 92.0f ); // for Rock tex
// Textures
const TextureUnit TMU0_Unit = TextureUnit.Texture0;
const int TMU0_UnitInteger = 0;
//const string TMU0_Filename = "Data/Textures/Swizzled Metal Diffuse&Height.dds";
const string TMU0_Filename = "Data/Textures/Swizzled Rock Diffuse&Height.dds";
uint TMU0_Handle;
TextureTarget TMU0_Target;
const TextureUnit TMU1_Unit = TextureUnit.Texture1;
const int TMU1_UnitInteger = 1;
//const string TMU1_Filename = "Data/Textures/Swizzled Metal Normal&Gloss.dds";
const string TMU1_Filename = "Data/Textures/Swizzled Rock Normal&Gloss.dds";
uint TMU1_Handle;
TextureTarget TMU1_Target;
// Camera
Vector3 EyePos = new Vector3( 0.0f, 0.0f, 3.0f );
// Light
Vector3 LightPosition = new Vector3( 0.0f, 1.0f, 1.0f );
Vector3 LightDiffuse = new Vector3( 0.5f, 0.5f, 0.5f );
Vector3 LightSpecular = new Vector3( 1f, 1f, 1f );
#endregion internal Fields
/// <summary>Setup OpenGL and load resources here.</summary>
/// <param name="e">Not used.</param>
protected override void OnLoad(EventArgs e)
{
this.VSync = VSyncMode.Off;
/*
// Check for necessary capabilities:
if ( !GL.SupportsExtension( "VERSION_2_0" ) )
{
MessageBox.Show( "You need at least OpenGL 2.0 to run this example. Aborting.",
"GLSL not supported", MessageBoxButtons.OK, MessageBoxIcon.Exclamation );
this.Exit( );
}
if ( !GL.SupportsExtension( "GL_ARB_texture_compression" ) ||
!GL.SupportsExtension( "GL_EXT_texture_compression_s3tc" ) )
{
MessageBox.Show( "Texture compression extensions not found. Trying to run anyways.",
"Possible problem", MessageBoxButtons.OK, MessageBoxIcon.Warning );
}
*/
int[] temp = new int[1];
GL.GetInteger( GetPName.MaxTextureImageUnits, out temp[0] );
Trace.WriteLine( temp[0] + " TMU's for Fragment Shaders found. (2 required)" );
GL.GetInteger( GetPName.MaxVaryingFloats, out temp[0] );
Trace.WriteLine( temp[0] + " varying floats between VS and FS allowed. (6 required)" );
GL.GetInteger( GetPName.MaxVertexUniformComponents, out temp[0] );
Trace.WriteLine( temp[0] + " uniform components allowed in Vertex Shader. (6 required)" );
GL.GetInteger( GetPName.MaxFragmentUniformComponents, out temp[0] );
Trace.WriteLine( temp[0] + " uniform components allowed in Fragment Shader. (11 required)" );
Trace.WriteLine("" );
#region GL State
GL.ClearColor( 0.2f, 0f, 0.4f, 0f );
GL.PointSize( 10f );
GL.Disable( EnableCap.Dither );
GL.FrontFace( FrontFaceDirection.Ccw );
GL.PolygonMode( MaterialFace.Front, PolygonMode.Fill );
GL.PolygonMode( MaterialFace.Back, PolygonMode.Line );
#endregion GL State
#region Shaders
string LogInfo;
// Load&Compile Vertex Shader
using ( StreamReader sr = new StreamReader( VertexShaderFilename ) )
{
VertexShaderObject = GL.CreateShader( ShaderType.VertexShader );
GL.ShaderSource( VertexShaderObject, sr.ReadToEnd( ) );
GL.CompileShader( VertexShaderObject );
}
GL.GetShaderInfoLog( VertexShaderObject, out LogInfo );
if ( LogInfo.Length > 0 && !LogInfo.Contains( "hardware" ) )
Trace.WriteLine( "Vertex Shader failed!\nLog:\n" + LogInfo );
else
Trace.WriteLine( "Vertex Shader compiled without complaint." );
// Load&Compile Fragment Shader
using ( StreamReader sr = new StreamReader( FragmentShaderFilename ) )
{
FragmentShaderObject = GL.CreateShader( ShaderType.FragmentShader );
GL.ShaderSource( FragmentShaderObject, sr.ReadToEnd( ) );
GL.CompileShader( FragmentShaderObject );
}
GL.GetShaderInfoLog( FragmentShaderObject, out LogInfo );
if ( LogInfo.Length > 0 && !LogInfo.Contains( "hardware" ) )
Trace.WriteLine( "Fragment Shader failed!\nLog:\n" + LogInfo );
else
Trace.WriteLine( "Fragment Shader compiled without complaint." );
// Link the Shaders to a usable Program
ProgramObject = GL.CreateProgram( );
GL.AttachShader( ProgramObject, VertexShaderObject );
GL.AttachShader( ProgramObject, FragmentShaderObject );
// must bind the attribute before linking
GL.BindAttribLocation( ProgramObject, AttribTangent, "AttributeTangent" );
// link it all together
GL.LinkProgram( ProgramObject );
// flag ShaderObjects for delete when not used anymore
GL.DeleteShader( VertexShaderObject );
GL.DeleteShader( FragmentShaderObject );
GL.GetProgram( ProgramObject, ProgramParameter.LinkStatus, out temp[0] );
Trace.WriteLine( "Linking Program (" + ProgramObject + ") " + ( ( temp[0] == 1 ) ? "succeeded." : "FAILED!" ) );
if ( temp[0] != 1 )
{
GL.GetProgramInfoLog( ProgramObject, out LogInfo );
Trace.WriteLine( "Program Log:\n" + LogInfo );
}
GL.GetProgram( ProgramObject, ProgramParameter.ActiveAttributes, out temp[0] );
Trace.WriteLine( "Program registered " + temp[0] + " Attributes. (Should be 4: Pos, UV, Normal, Tangent)" );
Trace.WriteLine( "Tangent attribute bind location: " + GL.GetAttribLocation( ProgramObject, "AttributeTangent" ) );
Trace.WriteLine( "End of Shader build. GL Error: " + GL.GetError( ) );
#endregion Shaders
#region Textures
TextureLoaderParameters.MagnificationFilter = TextureMagFilter.Linear;
TextureLoaderParameters.MinificationFilter = TextureMinFilter.LinearMipmapLinear;
TextureLoaderParameters.WrapModeS = TextureWrapMode.ClampToBorder;
TextureLoaderParameters.WrapModeT = TextureWrapMode.ClampToBorder;
TextureLoaderParameters.EnvMode = TextureEnvMode.Modulate;
ImageDDS.LoadFromDisk( TMU0_Filename, out TMU0_Handle, out TMU0_Target );
Trace.WriteLine( "Loaded " + TMU0_Filename + " with handle " + TMU0_Handle + " as " + TMU0_Target );
ImageDDS.LoadFromDisk( TMU1_Filename, out TMU1_Handle, out TMU1_Target );
Trace.WriteLine( "Loaded " + TMU1_Filename + " with handle " + TMU1_Handle + " as " + TMU1_Target );
#endregion Textures
Trace.WriteLine( "End of Texture Loading. GL Error: " + GL.GetError( ) );
Trace.WriteLine( "");
}
protected override void OnUnload(EventArgs e)
{
GL.DeleteProgram( ProgramObject );
GL.DeleteTextures( 1, ref TMU0_Handle );
GL.DeleteTextures( 1, ref TMU1_Handle );
base.OnUnload( e );
}
/// <summary>Respond to resize events here.</summary>
/// <param name="e">Contains information on the new GameWindow size.</param>
/// <remarks>There is no need to call the base implementation.</remarks>
protected override void OnResize( EventArgs e )
{
GL.Viewport( 0, 0, Width, Height );
GL.MatrixMode( MatrixMode.Projection );
Matrix4 p = Matrix4.Perspective( 45.0f, Width / (float) Height, 0.1f, 100.0f );
GL.LoadMatrix(ref p);
GL.MatrixMode( MatrixMode.Modelview );
GL.LoadIdentity( );
base.OnResize( e );
}
/// <summary>Add your game logic here.</summary>
/// <param name="e">Contains timing information.</param>
/// <remarks>There is no need to call the base implementation.</remarks>
protected override void OnUpdateFrame( FrameEventArgs e )
{
base.OnUpdateFrame( e );
if ( Keyboard[OpenTK.Input.Key.Escape] )
this.Exit( );
if ( Keyboard[OpenTK.Input.Key.Space] )
Trace.WriteLine( "GL: " + GL.GetError( ) );
if ( Keyboard[OpenTK.Input.Key.Q] )
{
MaterialScaleAndBiasAndShininess.X += 0.01f;
Trace.WriteLine( "Scale: " + MaterialScaleAndBiasAndShininess.X + " Bias: " + MaterialScaleAndBiasAndShininess.Y );
}
if ( Keyboard[OpenTK.Input.Key.A] )
{
MaterialScaleAndBiasAndShininess.X -= 0.01f;
Trace.WriteLine( "Scale: " + MaterialScaleAndBiasAndShininess.X + " Bias: " + MaterialScaleAndBiasAndShininess.Y );
}
if ( Keyboard[OpenTK.Input.Key.W] )
{
MaterialScaleAndBiasAndShininess.Y += 0.01f;
Trace.WriteLine( "Scale: " + MaterialScaleAndBiasAndShininess.X + " Bias: " + MaterialScaleAndBiasAndShininess.Y );
}
if ( Keyboard[OpenTK.Input.Key.S] )
{
MaterialScaleAndBiasAndShininess.Y -= 0.01f;
Trace.WriteLine( "Scale: " + MaterialScaleAndBiasAndShininess.X + " Bias: " + MaterialScaleAndBiasAndShininess.Y );
}
if ( Keyboard[OpenTK.Input.Key.E] )
{
MaterialScaleAndBiasAndShininess.Z += 1f;
Trace.WriteLine( "Shininess: " + MaterialScaleAndBiasAndShininess.Z );
}
if ( Keyboard[OpenTK.Input.Key.D] )
{
MaterialScaleAndBiasAndShininess.Z -= 1f;
Trace.WriteLine( "Shininess: " + MaterialScaleAndBiasAndShininess.Z );
}
LightPosition.X = ( -( this.Width / 2 ) + Mouse.X ) / 100f;
LightPosition.Y = ( ( this.Height / 2 ) - Mouse.Y ) / 100f;
EyePos.Y = Mouse.Wheel * 0.5f;
}
/// <summary>Add your game rendering code here.</summary>
/// <param name="e">Contains timing information.</param>
/// <remarks>There is no need to call the base implementation.</remarks>
protected override void OnRenderFrame( FrameEventArgs e )
{
this.Title = "FPS: " + 1 / e.Time;
GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
GL.UseProgram( ProgramObject );
#region Textures
GL.ActiveTexture( TMU0_Unit );
GL.BindTexture( TMU0_Target, TMU0_Handle );
GL.ActiveTexture( TMU1_Unit );
GL.BindTexture( TMU1_Target, TMU1_Handle );
#endregion Textures
#region Uniforms
// first Material's uniforms
GL.Uniform1( GL.GetUniformLocation( ProgramObject, "Material_DiffuseAndHeight" ), TMU0_UnitInteger );
GL.Uniform1( GL.GetUniformLocation( ProgramObject, "Material_NormalAndGloss" ), TMU1_UnitInteger );
GL.Uniform3( GL.GetUniformLocation( ProgramObject, "Material_ScaleBiasShininess" ), MaterialScaleAndBiasAndShininess.X, MaterialScaleAndBiasAndShininess.Y, MaterialScaleAndBiasAndShininess.Z );
// the rest are vectors
GL.Uniform3( GL.GetUniformLocation( ProgramObject, "Camera_Position" ), EyePos.X, EyePos.Y, EyePos.Z );
GL.Uniform3( GL.GetUniformLocation( ProgramObject, "Light_Position" ), LightPosition.X, LightPosition.Y, LightPosition.Z );
GL.Uniform3( GL.GetUniformLocation( ProgramObject, "Light_DiffuseColor" ), LightDiffuse.X, LightDiffuse.Y, LightDiffuse.Z );
GL.Uniform3( GL.GetUniformLocation( ProgramObject, "Light_SpecularColor" ), LightSpecular.X, LightSpecular.Y, LightSpecular.Z );
#endregion Uniforms
GL.PushMatrix( );
Matrix4 t = Matrix4.LookAt( EyePos, Vector3.Zero, Vector3.UnitY );
GL.MultMatrix(ref t);
#region Draw Quad
GL.Color3( 1f, 1f, 1f );
GL.Begin( BeginMode.Quads );
{
GL.Normal3( Normal );
GL.VertexAttrib3( AttribTangent, ref Tangent );
GL.MultiTexCoord2( TextureUnit.Texture0, 0f, 1f );
GL.Vertex3( -1.0f, 1.0f, 0.0f );
GL.Normal3( Normal );
GL.VertexAttrib3( AttribTangent, ref Tangent );
GL.MultiTexCoord2( TextureUnit.Texture0, 0f, 0f );
GL.Vertex3( -1.0f, -1.0f, 0.0f );
GL.Normal3( Normal );
GL.VertexAttrib3( AttribTangent, ref Tangent );
GL.MultiTexCoord2( TextureUnit.Texture0, 1f, 0f );
GL.Vertex3( 1.0f, -1.0f, 0.0f );
GL.Normal3( Normal );
GL.VertexAttrib3( AttribTangent, ref Tangent );
GL.MultiTexCoord2( TextureUnit.Texture0, 1f, 1f );
GL.Vertex3( 1.0f, 1.0f, 0.0f );
}
GL.End( );
#endregion Draw Quad
GL.UseProgram( 0 );
// visualize the light position 'somehow'
GL.Begin( BeginMode.Points );
{
GL.Color3( LightSpecular );
GL.Vertex3( LightPosition );
}
GL.End( );
GL.PopMatrix( );
this.SwapBuffers( );
}
/// <summary>Entry point</summary>
[STAThread]
public static void Main( )
{
using ( T12_GLSL_Parallax example = new T12_GLSL_Parallax( ) )
{
Utilities.SetWindowTitle( example );
example.Run( 30.0, 0.0 );
}
}
}
}

View file

@ -0,0 +1,181 @@
#region --- License ---
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
* See license.txt for license info
*/
#endregion
using System;
using OpenTK;
using OpenTK.Graphics.OpenGL;
namespace Examples.Shapes
{
// Abstract base class for procedurally generated geometry
//
// All classes derived from it must produce Counter-Clockwise (CCW) primitives.
// Derived classes must create a single VBO and IBO, without primitive restarts for strips.
// Uses an double-precision all-possible-attributes VertexT2dN3dV3d Array internally.
// Cannot directly use VBO, but has Get-methods to retrieve VBO-friendly data.
// Can use a Display List to prevent repeated immediate mode draws.
//
public abstract class DrawableShape: IDisposable
{
protected BeginMode PrimitiveMode;
protected VertexT2dN3dV3d[] VertexArray;
protected uint[] IndexArray;
public int GetTriangleCount
{
get
{
switch ( PrimitiveMode )
{
case BeginMode.Triangles:
if ( IndexArray != null )
{
return IndexArray.Length / 3;
} else
{
return VertexArray.Length / 3;
}
// break;
default: throw new NotImplementedException("Unknown primitive type.");
}
}
}
#region Display List
private bool UseDisplayList;
private int DisplayListHandle = 0;
#endregion Display List
public DrawableShape( bool useDisplayList )
{
UseDisplayList = useDisplayList;
PrimitiveMode = BeginMode.Triangles;
VertexArray = null;
IndexArray = null;
}
#region Convert to VBO
public void GetArraysforVBO(out BeginMode primitives, out VertexT2dN3dV3d[] vertices, out uint[] indices)
{
primitives = PrimitiveMode;
vertices = new VertexT2dN3dV3d[VertexArray.Length];
for (uint i = 0; i < VertexArray.Length; i++)
{
vertices[i].TexCoord = VertexArray[i].TexCoord;
vertices[i].Normal = VertexArray[i].Normal;
vertices[i].Position = VertexArray[i].Position;
}
indices = IndexArray;
}
public void GetArraysforVBO(out BeginMode primitives, out VertexT2fN3fV3f[] vertices, out uint[] indices)
{
primitives = PrimitiveMode;
vertices = new VertexT2fN3fV3f[VertexArray.Length];
for (uint i = 0; i < VertexArray.Length; i++)
{
vertices[i].TexCoord = (Vector2)VertexArray[i].TexCoord;
vertices[i].Normal = (Vector3)VertexArray[i].Normal;
vertices[i].Position = (Vector3)VertexArray[i].Position;
}
indices = IndexArray;
}
public void GetArraysforVBO(out BeginMode primitives, out VertexT2hN3hV3h[] vertices, out uint[] indices)
{
primitives = PrimitiveMode;
vertices = new VertexT2hN3hV3h[VertexArray.Length];
for (uint i = 0; i < VertexArray.Length; i++)
{
vertices[i].TexCoord = (Vector2h)VertexArray[i].TexCoord;
vertices[i].Normal = (Vector3h)VertexArray[i].Normal;
vertices[i].Position = (Vector3h)VertexArray[i].Position;
}
indices = IndexArray;
}
#endregion Convert to VBO
private void DrawImmediateMode()
{
GL.Begin( PrimitiveMode );
{
if ( IndexArray == null )
foreach ( VertexT2dN3dV3d v in VertexArray )
{
GL.TexCoord2( v.TexCoord.X, v.TexCoord.Y );
GL.Normal3( v.Normal.X, v.Normal.Y, v.Normal.Z );
GL.Vertex3( v.Position.X, v.Position.Y, v.Position.Z );
} else
{
for ( uint i = 0; i < IndexArray.Length; i++ )
{
uint index = IndexArray[i];
GL.TexCoord2( VertexArray[index].TexCoord.X, VertexArray[index].TexCoord.Y );
GL.Normal3( VertexArray[index].Normal.X, VertexArray[index].Normal.Y, VertexArray[index].Normal.Z );
GL.Vertex3( VertexArray[index].Position.X, VertexArray[index].Position.Y, VertexArray[index].Position.Z );
}
}
}
GL.End();
}
/// <summary>
/// Does not touch any state/matrices. Does call Begin/End and Vertex&Co.
/// Creates and compiles a display list if not present yet. Requires an OpenGL context.
/// </summary>
public void Draw()
{
if ( !UseDisplayList )
DrawImmediateMode();
else
if ( DisplayListHandle == 0 )
{
if ( VertexArray == null )
throw new Exception("Cannot draw null Vertex Array.");
DisplayListHandle = GL.GenLists( 1 );
GL.NewList( DisplayListHandle, ListMode.CompileAndExecute );
DrawImmediateMode();
GL.EndList();
} else
GL.CallList( DisplayListHandle );
}
#region IDisposable Members
/// <summary>
/// Removes reference to VertexArray and IndexArray.
/// Deletes the Display List, so it requires an OpenGL context.
/// The instance is effectively destroyed.
/// </summary>
public void Dispose()
{
if ( VertexArray != null )
VertexArray = null;
if ( IndexArray != null )
IndexArray = null;
if ( DisplayListHandle != 0 )
{
GL.DeleteLists( DisplayListHandle, 1 );
DisplayListHandle = 0;
}
}
#endregion
}
}

View file

@ -0,0 +1,36 @@
using System;
using OpenTK;
namespace Examples.Shapes
{
public struct VertexT2dN3dV3d
{
public Vector2d TexCoord;
public Vector3d Normal;
public Vector3d Position;
public VertexT2dN3dV3d( Vector2d texcoord, Vector3d normal, Vector3d position )
{
TexCoord = texcoord;
Normal = normal;
Position = position;
}
}
public struct VertexT2fN3fV3f
{
public Vector2 TexCoord;
public Vector3 Normal;
public Vector3 Position;
}
public struct VertexT2hN3hV3h
{
public Vector2h TexCoord;
public Vector3h Normal;
public Vector3h Position;
}
}

View file

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using OpenTK;
namespace Examples.Shapes
{
public sealed class Capsule: DrawableShape
{
public enum eSubdivisions
{
None = 0,
One = 1,
Two = 2,
Three = 3,
Four = 4,
}
public Capsule( double radius, double height, eSubdivisions subdivs, bool useDL )
: base( useDL )
{
uint HoseSubDivs = 0;
SlicedSphere.eSubdivisions spheresubdivs = SlicedSphere.eSubdivisions.Zero;
switch ( subdivs )
{
case eSubdivisions.None:
spheresubdivs = SlicedSphere.eSubdivisions.Zero;
HoseSubDivs = 0;
break;
case eSubdivisions.One:
spheresubdivs = SlicedSphere.eSubdivisions.One;
HoseSubDivs = 1;
break;
case eSubdivisions.Two:
spheresubdivs = SlicedSphere.eSubdivisions.Two;
HoseSubDivs = 3;
break;
case eSubdivisions.Three:
spheresubdivs = SlicedSphere.eSubdivisions.Three;
HoseSubDivs = 7;
break;
case eSubdivisions.Four:
spheresubdivs = SlicedSphere.eSubdivisions.Four;
HoseSubDivs = 15;
break;
}
PrimitiveMode = OpenTK.Graphics.OpenGL.BeginMode.Triangles;
OpenTK.Graphics.OpenGL.BeginMode TemporaryMode;
VertexT2dN3dV3d[] TemporaryVBO;
uint[] TemporaryIBO;
List<Chunk> AllChunks = new List<Chunk>();
Vector3d offset1 = new Vector3d( 0.0, 0.0, height ),
offset2 = new Vector3d( 0.0, 0.0, -height );
for ( int i = 0; i < 4; i++ )
{
SlicedHose.eSide tempSide = SlicedHose.eSide.FrontTop;
switch ( i )
{
case 0:
tempSide = SlicedHose.eSide.FrontBottom;
break;
case 1:
tempSide = SlicedHose.eSide.BackBottom;
break;
case 2:
tempSide = SlicedHose.eSide.BackTop;
break;
case 3:
tempSide = SlicedHose.eSide.FrontTop;
break;
}
SlicedHose tempHose = new SlicedHose( tempSide, HoseSubDivs, radius, offset1, offset2, false );
tempHose.GetArraysforVBO( out TemporaryMode, out TemporaryVBO, out TemporaryIBO );
tempHose.Dispose();
AllChunks.Add( new Chunk( ref TemporaryVBO, ref TemporaryIBO ) );
}
SlicedSphere front = new SlicedSphere( radius, offset1, spheresubdivs,
new SlicedSphere.eDir[] {
SlicedSphere.eDir.BackBottomRight,
SlicedSphere.eDir.FrontTopRight,
SlicedSphere.eDir.BackTopRight,
SlicedSphere.eDir.FrontBottomRight,
},
false );
front.GetArraysforVBO( out TemporaryMode, out TemporaryVBO, out TemporaryIBO );
AllChunks.Add( new Chunk( ref TemporaryVBO, ref TemporaryIBO ) );
front.Dispose();
SlicedSphere back = new SlicedSphere( radius, offset2, spheresubdivs,
new SlicedSphere.eDir[] {
SlicedSphere.eDir.FrontBottomLeft,
SlicedSphere.eDir.FrontTopLeft,
SlicedSphere.eDir.BackTopLeft,
SlicedSphere.eDir.BackBottomLeft },
false );
back.GetArraysforVBO( out TemporaryMode, out TemporaryVBO, out TemporaryIBO );
AllChunks.Add( new Chunk( ref TemporaryVBO, ref TemporaryIBO ) );
back.Dispose();
Chunk.GetArray( ref AllChunks, out VertexArray, out IndexArray );
AllChunks.Clear();
}
}
}

View file

@ -0,0 +1,280 @@
using System;
using System.Collections.Generic;
using OpenTK;
namespace Examples.Shapes
{
public sealed class ChamferCube: DrawableShape
{
public enum SubDivs: byte
{
Zero,
One,
Two,
Three,
Four,
}
public ChamferCube( double Width, double Height, double Length, SubDivs subdivs, double radius, bool useDL )
: base( useDL )
{
SlicedSphere.eSubdivisions sphereSubDivs = SlicedSphere.eSubdivisions.Zero;
uint hoseSubDivs = 0;
switch ( subdivs )
{
case SubDivs.Zero:
sphereSubDivs = SlicedSphere.eSubdivisions.Zero;
hoseSubDivs = 0;
break;
case SubDivs.One:
sphereSubDivs = SlicedSphere.eSubdivisions.One;
hoseSubDivs = 1;
break;
case SubDivs.Two:
sphereSubDivs = SlicedSphere.eSubdivisions.Two;
hoseSubDivs = 3;
break;
case SubDivs.Three:
sphereSubDivs = SlicedSphere.eSubdivisions.Three;
hoseSubDivs = 7;
break;
case SubDivs.Four:
sphereSubDivs = SlicedSphere.eSubdivisions.Four;
hoseSubDivs = 15;
break;
}
#region Temporary Storage
List<Chunk> AllChunks = new List<Chunk>();
OpenTK.Graphics.OpenGL.BeginMode TemporaryMode;
VertexT2dN3dV3d[] TemporaryVBO;
uint[] TemporaryIBO;
#endregion Temporary Storage
Vector3d FrontTopRightEdge = new Vector3d( +Width - radius, +Height - radius, +Length - radius );
Vector3d FrontTopLeftEdge = new Vector3d( +Width - radius, +Height - radius, -Length + radius );
Vector3d FrontBottomRightEdge = new Vector3d( +Width - radius, -Height + radius, +Length - radius );
Vector3d FrontBottomLeftEdge = new Vector3d( +Width - radius, -Height + radius, -Length + radius );
Vector3d BackTopRightEdge = new Vector3d( -Width + radius, +Height - radius, +Length - radius );
Vector3d BackTopLeftEdge = new Vector3d( -Width + radius, +Height - radius, -Length + radius );
Vector3d BackBottomRightEdge = new Vector3d( -Width + radius, -Height + radius, +Length - radius );
Vector3d BackBottomLeftEdge = new Vector3d( -Width + radius, -Height + radius, -Length + radius );
#region 8 sliced Spheres
SlicedSphere tempSphere;
Vector3d tempVector = Vector3d.Zero;
SlicedSphere.eDir[] tempEdge = new SlicedSphere.eDir[1];
for ( int i = 0; i < 8; i++ )
{
switch ( i )
{
case 0:
tempVector = FrontTopRightEdge;
tempEdge = new SlicedSphere.eDir[] { SlicedSphere.eDir.FrontTopRight };
break;
case 1:
tempVector = FrontTopLeftEdge;
tempEdge = new SlicedSphere.eDir[] { SlicedSphere.eDir.FrontTopLeft };
break;
case 2:
tempVector = FrontBottomRightEdge;
tempEdge = new SlicedSphere.eDir[] { SlicedSphere.eDir.FrontBottomRight };
break;
case 3:
tempVector = FrontBottomLeftEdge;
tempEdge = new SlicedSphere.eDir[] { SlicedSphere.eDir.FrontBottomLeft };
break;
case 4:
tempVector = BackBottomRightEdge;
tempEdge = new SlicedSphere.eDir[] { SlicedSphere.eDir.BackBottomRight };
break;
case 5:
tempVector = BackBottomLeftEdge;
tempEdge = new SlicedSphere.eDir[] { SlicedSphere.eDir.BackBottomLeft };
break;
case 6:
tempVector = BackTopRightEdge;
tempEdge = new SlicedSphere.eDir[] { SlicedSphere.eDir.BackTopRight };
break;
case 7:
tempVector = BackTopLeftEdge;
tempEdge = new SlicedSphere.eDir[] { SlicedSphere.eDir.BackTopLeft };
break;
}
tempSphere = new SlicedSphere( radius,
tempVector,
sphereSubDivs,
tempEdge,
false );
tempSphere.GetArraysforVBO( out TemporaryMode, out TemporaryVBO, out TemporaryIBO );
tempSphere.Dispose();
AllChunks.Add( new Chunk( ref TemporaryVBO, ref TemporaryIBO ) );
}
#endregion 8 sliced Spheres
#region 12 sliced Hoses
SlicedHose tempHose;
SlicedHose.eSide tempSide = SlicedHose.eSide.BackBottom;
Vector3d tempHoseStart = Vector3d.Zero;
Vector3d tempHoseEnd = Vector3d.Zero;
for ( int i = 0; i < 12; i++ )
{
switch ( i )
{
#region Around X Axis
case 0:
tempSide = SlicedHose.eSide.BottomRight;
tempHoseStart = BackBottomRightEdge;
tempHoseEnd = FrontBottomRightEdge;
break;
case 1:
tempSide = SlicedHose.eSide.TopRight;
tempHoseStart = BackTopRightEdge;
tempHoseEnd = FrontTopRightEdge;
break;
case 2:
tempSide = SlicedHose.eSide.TopLeft;
tempHoseStart = BackTopLeftEdge;
tempHoseEnd = FrontTopLeftEdge;
break;
case 3:
tempSide = SlicedHose.eSide.BottomLeft;
tempHoseStart = BackBottomLeftEdge;
tempHoseEnd = FrontBottomLeftEdge;
break;
#endregion Around X Axis
#region Around Y Axis
case 4:
tempSide = SlicedHose.eSide.FrontRight;
tempHoseStart = FrontBottomRightEdge;
tempHoseEnd = FrontTopRightEdge;
break;
case 5:
tempSide = SlicedHose.eSide.BackRight;
tempHoseStart = BackBottomRightEdge;
tempHoseEnd = BackTopRightEdge;
break;
case 6:
tempSide = SlicedHose.eSide.BackLeft;
tempHoseStart = BackBottomLeftEdge;
tempHoseEnd = BackTopLeftEdge;
break;
case 7:
tempSide = SlicedHose.eSide.FrontLeft;
tempHoseStart = FrontBottomLeftEdge;
tempHoseEnd = FrontTopLeftEdge;
break;
#endregion Around Y Axis
#region Around Z Axis
case 8:
tempSide = SlicedHose.eSide.FrontTop;
tempHoseStart = FrontTopRightEdge;
tempHoseEnd = FrontTopLeftEdge;
break;
case 9:
tempSide = SlicedHose.eSide.BackTop;
tempHoseStart = BackTopRightEdge;
tempHoseEnd = BackTopLeftEdge;
break;
case 10:
tempSide = SlicedHose.eSide.BackBottom;
tempHoseStart = BackBottomRightEdge;
tempHoseEnd = BackBottomLeftEdge;
break;
case 11:
tempSide = SlicedHose.eSide.FrontBottom;
tempHoseStart = FrontBottomRightEdge;
tempHoseEnd = FrontBottomLeftEdge;
break;
#endregion Around Z Axis
}
tempHose = new SlicedHose( tempSide,
hoseSubDivs,
radius,
tempHoseStart,
tempHoseEnd,
false );
tempHose.GetArraysforVBO( out TemporaryMode, out TemporaryVBO, out TemporaryIBO );
tempHose.Dispose();
AllChunks.Add( new Chunk( ref TemporaryVBO, ref TemporaryIBO ) );
}
#endregion 12 sliced Hoses
#region 6 quads for the sides
VertexT2dN3dV3d[] tempVBO = new VertexT2dN3dV3d[4];
uint[] tempIBO = new uint[6] { 0, 1, 2, 0, 2, 3 }; // all quads share this IBO
// all quads use the same texcoords
tempVBO[0].TexCoord = new Vector2d( 0.0, 1.0 );
tempVBO[1].TexCoord = new Vector2d( 0.0, 0.0 );
tempVBO[2].TexCoord = new Vector2d( 1.0, 0.0 );
tempVBO[3].TexCoord = new Vector2d( 1.0, 1.0 );
// front face
tempVBO[0].Normal = tempVBO[1].Normal = tempVBO[2].Normal = tempVBO[3].Normal = Vector3d.UnitX;
tempVBO[0].Position = FrontTopRightEdge + new Vector3d( radius, 0.0, 0.0 );
tempVBO[1].Position = FrontBottomRightEdge + new Vector3d( radius, 0.0, 0.0 );
tempVBO[2].Position = FrontBottomLeftEdge + new Vector3d( radius, 0.0, 0.0 );
tempVBO[3].Position = FrontTopLeftEdge + new Vector3d( radius, 0.0, 0.0 );
AllChunks.Add( new Chunk( ref tempVBO, ref tempIBO ) );
// back face
tempVBO[0].Normal = tempVBO[1].Normal = tempVBO[2].Normal = tempVBO[3].Normal = -Vector3d.UnitX;
tempVBO[0].Position = BackTopLeftEdge - new Vector3d( radius, 0.0, 0.0 );
tempVBO[1].Position = BackBottomLeftEdge - new Vector3d( radius, 0.0, 0.0 );
tempVBO[2].Position = BackBottomRightEdge - new Vector3d( radius, 0.0, 0.0 );
tempVBO[3].Position = BackTopRightEdge - new Vector3d( radius, 0.0, 0.0 );
AllChunks.Add( new Chunk( ref tempVBO, ref tempIBO ) );
// top face
tempVBO[0].Normal = tempVBO[1].Normal = tempVBO[2].Normal = tempVBO[3].Normal = Vector3d.UnitY;
tempVBO[0].Position = BackTopRightEdge + new Vector3d( 0.0, radius, 0.0 );
tempVBO[1].Position = FrontTopRightEdge + new Vector3d( 0.0, radius, 0.0 );
tempVBO[2].Position = FrontTopLeftEdge + new Vector3d( 0.0, radius, 0.0 );
tempVBO[3].Position = BackTopLeftEdge + new Vector3d( 0.0, radius, 0.0 );
AllChunks.Add( new Chunk( ref tempVBO, ref tempIBO ) );
// bottom face
tempVBO[0].Normal = tempVBO[1].Normal = tempVBO[2].Normal = tempVBO[3].Normal = -Vector3d.UnitY;
tempVBO[0].Position = BackBottomLeftEdge - new Vector3d( 0.0, radius, 0.0 );
tempVBO[1].Position = FrontBottomLeftEdge - new Vector3d( 0.0, radius, 0.0 );
tempVBO[2].Position = FrontBottomRightEdge - new Vector3d( 0.0, radius, 0.0 );
tempVBO[3].Position = BackBottomRightEdge - new Vector3d( 0.0, radius, 0.0 );
AllChunks.Add( new Chunk( ref tempVBO, ref tempIBO ) );
// right face
tempVBO[0].Normal = tempVBO[1].Normal = tempVBO[2].Normal = tempVBO[3].Normal = Vector3d.UnitZ;
tempVBO[0].Position = BackTopRightEdge + new Vector3d( 0.0, 0.0, radius );
tempVBO[1].Position = BackBottomRightEdge + new Vector3d( 0.0, 0.0, radius );
tempVBO[2].Position = FrontBottomRightEdge + new Vector3d( 0.0, 0.0, radius );
tempVBO[3].Position = FrontTopRightEdge + new Vector3d( 0.0, 0.0, radius );
AllChunks.Add( new Chunk( ref tempVBO, ref tempIBO ) );
// left face
tempVBO[0].Normal = tempVBO[1].Normal = tempVBO[2].Normal = tempVBO[3].Normal = -Vector3d.UnitZ;
tempVBO[0].Position = FrontTopLeftEdge - new Vector3d( 0.0, 0.0, radius );
tempVBO[1].Position = FrontBottomLeftEdge - new Vector3d( 0.0, 0.0, radius );
tempVBO[2].Position = BackBottomLeftEdge - new Vector3d( 0.0, 0.0, radius );
tempVBO[3].Position = BackTopLeftEdge - new Vector3d( 0.0, 0.0, radius );
AllChunks.Add( new Chunk( ref tempVBO, ref tempIBO ) );
#endregion 6 quads for the sides
#region Final Assembly of Chunks
PrimitiveMode = OpenTK.Graphics.OpenGL.BeginMode.Triangles;
Chunk.GetArray( ref AllChunks, out VertexArray, out IndexArray );
AllChunks.Clear();
#endregion Final Assembly of Chunks
}
}
}

View file

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Examples.Shapes
{
public class Chunk
{
public VertexT2dN3dV3d[] Vertices;
public uint[] Indices;
public uint VertexCount
{
get
{
return (uint)Vertices.Length;
}
}
public uint IndexCount
{
get
{
return (uint)Indices.Length;
}
}
public Chunk( uint vertexcount, uint indexcount )
{
Vertices = new VertexT2dN3dV3d[vertexcount];
Indices = new uint[indexcount];
}
public Chunk( ref VertexT2dN3dV3d[] vbo, ref uint[] ibo )
{
Vertices = new VertexT2dN3dV3d[vbo.Length];
for ( int i = 0; i < Vertices.Length; i++ )
{
Vertices[i] = vbo[i];
}
Indices = new uint[ibo.Length];
for ( int i = 0; i < Indices.Length; i++ )
{
Indices[i] = ibo[i];
}
}
public static void GetArray( ref List<Chunk> c, out VertexT2dN3dV3d[] vbo, out uint[] ibo )
{
uint VertexCounter = 0;
uint IndexCounter = 0;
foreach ( Chunk ch in c )
{
VertexCounter += ch.VertexCount;
IndexCounter += ch.IndexCount;
}
vbo = new VertexT2dN3dV3d[VertexCounter];
ibo = new uint[IndexCounter];
VertexCounter = 0;
IndexCounter = 0;
foreach ( Chunk ch in c )
{
for ( int i = 0; i < ch.Vertices.Length; i++ )
{
vbo[VertexCounter + i] = ch.Vertices[i];
}
for ( int i = 0; i < ch.Indices.Length; i++ )
{
ibo[IndexCounter + i] = ch.Indices[i] + VertexCounter;
}
VertexCounter += (uint)ch.VertexCount;
IndexCounter += (uint)ch.IndexCount;
}
}
}
}

View file

@ -0,0 +1,422 @@
using System;
using System.Collections.Generic;
using OpenTK;
namespace Examples.Shapes
{
public sealed partial class MengerSponge
{
private struct MengerCube
{
private Vector3d Center;
private double SideLength;
private eSides[] VisibleSides;
private eSides[] VisibilityToInherit;
public void GetArraySizes( out uint vertexcount, out uint indexcount )
{
vertexcount = (uint)VisibleSides.Length * 8 + 6 * 12;
indexcount = (uint)VisibleSides.Length * 8 * 3 + 6 * 8 * 3;
}
public MengerCube( Vector3d center, double sidelength, eSides[] visibleSides, eSides[] parentsVisibility )
{
Center = center;
SideLength = sidelength;
/* List<eSides> Sides = new List<eSides>();
foreach ( eSides s in visibleSides )
{
bool isVisible = false;
foreach ( eSides p in parentsVisibility )
{
if ( (int)p == (int)s )
{
isVisible = true;
break;
}
}
if ( isVisible )
{
Sides.Add( s );
}
}
VisibleSides = Sides.ToArray();*/
VisibleSides = visibleSides;
VisibilityToInherit = visibleSides;
}
public void Subdivide( out MengerCube[] cubes )
{
cubes = new MengerCube[20]; // 8 + 4 + 8
double NewLength = this.SideLength / 3.0;
double six = this.SideLength * 2.0 / 3.0;
// we got 3x3x3 cubes. All center cubes who touch the XYZ-Axis are removed.
// front
cubes[0] = new MengerCube( new Vector3d( Center.X - six, Center.Y + six, Center.Z + six ), NewLength, new eSides[] { eSides.Front, eSides.Left, eSides.Top }, this.VisibilityToInherit );
cubes[1] = new MengerCube( new Vector3d( Center.X + 0.0, Center.Y + six, Center.Z + six ), NewLength, new eSides[] { eSides.Front, eSides.Bottom, eSides.Back, eSides.Top }, this.VisibilityToInherit );
cubes[2] = new MengerCube( new Vector3d( Center.X + six, Center.Y + six, Center.Z + six ), NewLength, new eSides[] { eSides.Front, eSides.Right, eSides.Top }, this.VisibilityToInherit );
cubes[3] = new MengerCube( new Vector3d( Center.X - six, Center.Y + 0.0, Center.Z + six ), NewLength, new eSides[] { eSides.Front, eSides.Right, eSides.Back, eSides.Left }, this.VisibilityToInherit );
cubes[4] = new MengerCube( new Vector3d( Center.X + six, Center.Y + 0.0, Center.Z + six ), NewLength, new eSides[] { eSides.Front, eSides.Right, eSides.Back, eSides.Left }, this.VisibilityToInherit );
cubes[5] = new MengerCube( new Vector3d( Center.X - six, Center.Y - six, Center.Z + six ), NewLength, new eSides[] { eSides.Front, eSides.Left, eSides.Bottom } , this.VisibilityToInherit );
cubes[6] = new MengerCube( new Vector3d( Center.X + 0.0, Center.Y - six, Center.Z + six ), NewLength, new eSides[] { eSides.Front, eSides.Top, eSides.Back, eSides.Bottom }, this.VisibilityToInherit );
cubes[7] = new MengerCube( new Vector3d( Center.X + six, Center.Y - six, Center.Z + six ), NewLength, new eSides[] { eSides.Front, eSides.Right, eSides.Bottom }, this.VisibilityToInherit );
// center
cubes[8] = new MengerCube( new Vector3d( Center.X - six, Center.Y + six, Center.Z + 0.0 ), NewLength, new eSides[] { eSides.Top, eSides.Right, eSides.Bottom, eSides.Left }, this.VisibilityToInherit );
cubes[9] = new MengerCube( new Vector3d( Center.X + six, Center.Y + six, Center.Z + 0.0 ), NewLength, new eSides[] { eSides.Top, eSides.Right, eSides.Bottom, eSides.Left }, this.VisibilityToInherit );
cubes[10] = new MengerCube( new Vector3d( Center.X - six, Center.Y - six, Center.Z + 0.0 ), NewLength, new eSides[] { eSides.Top, eSides.Right, eSides.Bottom, eSides.Left }, this.VisibilityToInherit );
cubes[11] = new MengerCube( new Vector3d( Center.X + six, Center.Y - six, Center.Z + 0.0 ), NewLength, new eSides[] { eSides.Top, eSides.Right, eSides.Bottom, eSides.Left }, this.VisibilityToInherit );
// back
cubes[12] = new MengerCube( new Vector3d( Center.X - six, Center.Y + six, Center.Z - six ), NewLength, new eSides[] { eSides.Top, eSides.Back, eSides.Left }, this.VisibilityToInherit );
cubes[13] = new MengerCube( new Vector3d( Center.X + 0.0, Center.Y + six, Center.Z - six ), NewLength, new eSides[] { eSides.Top, eSides.Back, eSides.Bottom, eSides.Front }, this.VisibilityToInherit );
cubes[14] = new MengerCube( new Vector3d( Center.X + six, Center.Y + six, Center.Z - six ), NewLength, new eSides[] { eSides.Top, eSides.Back, eSides.Right }, this.VisibilityToInherit );
cubes[15] = new MengerCube( new Vector3d( Center.X - six, Center.Y + 0.0, Center.Z - six ), NewLength, new eSides[] { eSides.Front, eSides.Right, eSides.Back, eSides.Left } , this.VisibilityToInherit );
cubes[16] = new MengerCube( new Vector3d( Center.X + six, Center.Y + 0.0, Center.Z - six ), NewLength, new eSides[] { eSides.Front, eSides.Right, eSides.Back, eSides.Left } , this.VisibilityToInherit );
cubes[17] = new MengerCube( new Vector3d( Center.X - six, Center.Y - six, Center.Z - six ), NewLength, new eSides[] { eSides.Back, eSides.Bottom, eSides.Left } , this.VisibilityToInherit );
cubes[18] = new MengerCube( new Vector3d( Center.X + 0.0, Center.Y - six, Center.Z - six ), NewLength, new eSides[] { eSides.Top, eSides.Back, eSides.Bottom, eSides.Front }, this.VisibilityToInherit );
cubes[19] = new MengerCube( new Vector3d( Center.X + six, Center.Y - six, Center.Z - six ), NewLength, new eSides[] { eSides.Back, eSides.Bottom, eSides.Right }, this.VisibilityToInherit );
}
public enum eSides: byte
{
Front,
Back,
Right,
Left,
Top,
Bottom
}
internal static readonly eSides[] AllSides = new eSides[] { eSides.Front, eSides.Back, eSides.Right, eSides.Left, eSides.Top, eSides.Bottom };
public void GetVboAndIbo( ref List<Chunk> chunks )
{
foreach ( eSides s in AllSides )
{
DrawSide( s, ref chunks );
}
}
private void DrawSide( eSides side, ref List<Chunk> chunks )
{
#region Setup constants for current direction
double _Zero = 0.0; // 0/3
double _Three = 0.3333333333333; // 1/3
double _Six = 0.66666666666666; // 2/3
double _One = 1.0; // 3/3
double ThirdLength = SideLength / 3f;
Vector3d C0 = Center + new Vector3d( -SideLength, -SideLength, +SideLength );
Vector3d C1 = Center + new Vector3d( +SideLength, -SideLength, +SideLength );
Vector3d C2 = Center + new Vector3d( +SideLength, +SideLength, +SideLength );
Vector3d C3 = Center + new Vector3d( -SideLength, +SideLength, +SideLength );
Vector3d C4 = Center + new Vector3d( -SideLength, -SideLength, -SideLength );
Vector3d C5 = Center + new Vector3d( +SideLength, -SideLength, -SideLength );
Vector3d C6 = Center + new Vector3d( +SideLength, +SideLength, -SideLength );
Vector3d C7 = Center + new Vector3d( -SideLength, +SideLength, -SideLength );
Vector3d P0, P1, P2, P3, P4, P5, P6, P7;
switch ( side )
{
case eSides.Front:
P0 = C0;
P1 = C1;
P2 = C2;
P3 = C3;
P4 = C4;
P5 = C5;
P6 = C6;
P7 = C7;
break;
case eSides.Back:
P0 = C5;
P1 = C4;
P2 = C7;
P3 = C6;
P4 = C1;
P5 = C0;
P6 = C3;
P7 = C2;
break;
case eSides.Right:
P0 = C1;
P1 = C5;
P2 = C6;
P3 = C2;
P4 = C0;
P5 = C4;
P6 = C7;
P7 = C3;
break;
case eSides.Left:
P0 = C4;
P1 = C0;
P2 = C3;
P3 = C7;
P4 = C5;
P5 = C1;
P6 = C2;
P7 = C6;
break;
case eSides.Top:
P0 = C3;
P1 = C2;
P2 = C6;
P3 = C7;
P4 = C0;
P5 = C1;
P6 = C5;
P7 = C4;
break;
case eSides.Bottom:
P0 = C1;
P1 = C0;
P2 = C4;
P3 = C5;
P4 = C2;
P5 = C3;
P6 = C7;
P7 = C6;
break;
default:
throw new NotImplementedException( "Unknown enum value: " + side );
}
#endregion Setup constants for current direction
#region Set Normal
Vector3d FaceNormal;
switch ( side )
{
case eSides.Front:
FaceNormal = Vector3d.UnitZ;
break;
case eSides.Back:
FaceNormal = -Vector3d.UnitZ;
break;
case eSides.Right:
FaceNormal = Vector3d.UnitX;
break;
case eSides.Left:
FaceNormal = -Vector3d.UnitX;
break;
case eSides.Top:
FaceNormal = Vector3d.UnitY;
break;
case eSides.Bottom:
FaceNormal = -Vector3d.UnitY;
break;
default:
throw new NotImplementedException( "Unknown enum value: " + side );
}
#endregion Set Normal
bool FaceIsVisible = false;
foreach ( eSides s in VisibleSides )
{
if ( s == side )
{
FaceIsVisible = true;
break;
}
}
if ( FaceIsVisible )
{
#region Define Layer1 Vertices
Chunk Layer1 = new Chunk( 8, 8 * 3 );
Layer1.Vertices[0].TexCoord = new Vector2d( _Zero, _Zero );
Layer1.Vertices[0].Normal = FaceNormal;
Layer1.Vertices[0].Position = P0;
Layer1.Vertices[1].TexCoord = new Vector2d( _One, _Zero );
Layer1.Vertices[1].Normal = FaceNormal;
Layer1.Vertices[1].Position = P1;
Layer1.Vertices[2].TexCoord = new Vector2d( _One, _One );
Layer1.Vertices[2].Normal = FaceNormal;
Layer1.Vertices[2].Position = P2;
Layer1.Vertices[3].TexCoord = new Vector2d( _Zero, _One );
Layer1.Vertices[3].Normal = FaceNormal;
Layer1.Vertices[3].Position = P3;
Layer1.Vertices[4].TexCoord = new Vector2d( _Three, _Three );
Layer1.Vertices[4].Normal = FaceNormal;
Vector3d.Lerp( ref P0, ref P2, _Three, out Layer1.Vertices[4].Position );
Layer1.Vertices[5].TexCoord = new Vector2d( _Six, _Three );
Layer1.Vertices[5].Normal = FaceNormal;
Vector3d.Lerp( ref P1, ref P3, _Three, out Layer1.Vertices[5].Position );
Layer1.Vertices[6].TexCoord = new Vector2d( _Six, _Six );
Layer1.Vertices[6].Normal = FaceNormal;
Vector3d.Lerp( ref P0, ref P2, _Six, out Layer1.Vertices[6].Position );
Layer1.Vertices[7].TexCoord = new Vector2d( _Three, _Six );
Layer1.Vertices[7].Normal = FaceNormal;
Vector3d.Lerp( ref P1, ref P3, _Six, out Layer1.Vertices[7].Position );
#endregion Define Layer1 Vertices
#region Define Layer1 Indices
Layer1.Indices[0] = 0;
Layer1.Indices[1] = 5;
Layer1.Indices[2] = 4;
Layer1.Indices[3] = 0;
Layer1.Indices[4] = 1;
Layer1.Indices[5] = 5;
Layer1.Indices[6] = 5;
Layer1.Indices[7] = 1;
Layer1.Indices[8] = 2;
Layer1.Indices[9] = 6;
Layer1.Indices[10] = 5;
Layer1.Indices[11] = 2;
Layer1.Indices[12] = 7;
Layer1.Indices[13] = 6;
Layer1.Indices[14] = 2;
Layer1.Indices[15] = 3;
Layer1.Indices[16] = 7;
Layer1.Indices[17] = 2;
Layer1.Indices[18] = 0;
Layer1.Indices[19] = 7;
Layer1.Indices[20] = 3;
Layer1.Indices[21] = 0;
Layer1.Indices[22] = 4;
Layer1.Indices[23] = 7;
chunks.Add( Layer1 );
#endregion Define Layer1 Indices
}
#region Define Layer2 Vertices
Chunk Layer2 = new Chunk( 12, 8 * 3 );
Vector3d T0, T1, T2, T3;
Vector3d.Lerp( ref P0, ref P4, _Six, out T0 );
Vector3d.Lerp( ref P1, ref P5, _Six, out T1 );
Vector3d.Lerp( ref P2, ref P6, _Six, out T2 );
Vector3d.Lerp( ref P3, ref P7, _Six, out T3 );
Layer2.Vertices[0].TexCoord = new Vector2d( _Three, _Zero );
Layer2.Vertices[0].Normal = FaceNormal;
Vector3d.Lerp( ref T0, ref T1, _Three, out Layer2.Vertices[0].Position );
Layer2.Vertices[1].TexCoord = new Vector2d( _Six, _Zero );
Layer2.Vertices[1].Normal = FaceNormal;
Vector3d.Lerp( ref T0, ref T1, _Six, out Layer2.Vertices[1].Position );
Layer2.Vertices[3].TexCoord = new Vector2d( _One, _Three );
Layer2.Vertices[3].Normal = FaceNormal;
Vector3d.Lerp( ref T1, ref T2, _Three, out Layer2.Vertices[3].Position );
Layer2.Vertices[4].TexCoord = new Vector2d( _One, _Six );
Layer2.Vertices[4].Normal = FaceNormal;
Vector3d.Lerp( ref T1, ref T2, _Six, out Layer2.Vertices[4].Position );
Layer2.Vertices[6].TexCoord = new Vector2d( _Six, _One );
Layer2.Vertices[6].Normal = FaceNormal;
Vector3d.Lerp( ref T2, ref T3, _Three, out Layer2.Vertices[6].Position );
Layer2.Vertices[7].TexCoord = new Vector2d( _Three, _One );
Layer2.Vertices[7].Normal = FaceNormal;
Vector3d.Lerp( ref T2, ref T3, _Six, out Layer2.Vertices[7].Position );
Layer2.Vertices[9].TexCoord = new Vector2d( _Zero, _Six );
Layer2.Vertices[9].Normal = FaceNormal;
Vector3d.Lerp( ref T3, ref T0, _Three, out Layer2.Vertices[9].Position );
Layer2.Vertices[10].TexCoord = new Vector2d( _Zero, _Three );
Layer2.Vertices[10].Normal = FaceNormal;
Vector3d.Lerp( ref T3, ref T0, _Six, out Layer2.Vertices[10].Position );
Layer2.Vertices[2].TexCoord = new Vector2d( _Six, _Three );
Layer2.Vertices[2].Normal = FaceNormal;
Vector3d.Lerp( ref Layer2.Vertices[1].Position, ref Layer2.Vertices[6].Position, _Three, out Layer2.Vertices[2].Position );
Layer2.Vertices[5].TexCoord = new Vector2d( _Six, _Six );
Layer2.Vertices[5].Normal = FaceNormal;
Vector3d.Lerp( ref Layer2.Vertices[1].Position, ref Layer2.Vertices[6].Position, _Six, out Layer2.Vertices[5].Position );
Layer2.Vertices[8].TexCoord = new Vector2d( _Three, _Six );
Layer2.Vertices[8].Normal = FaceNormal;
Vector3d.Lerp( ref Layer2.Vertices[7].Position, ref Layer2.Vertices[0].Position, _Three, out Layer2.Vertices[8].Position );
Layer2.Vertices[11].TexCoord = new Vector2d( _Three, _Three );
Layer2.Vertices[11].Normal = FaceNormal;
Vector3d.Lerp( ref Layer2.Vertices[7].Position, ref Layer2.Vertices[0].Position, _Six, out Layer2.Vertices[11].Position );
#endregion Define Layer2 Vertices
#region Define Layer2 Indices
Layer2.Indices[0] = 0;
Layer2.Indices[1] = 2;
Layer2.Indices[2] = 11;
Layer2.Indices[3] = 0;
Layer2.Indices[4] = 1;
Layer2.Indices[5] = 2;
Layer2.Indices[6] = 2;
Layer2.Indices[7] = 3;
Layer2.Indices[8] = 4;
Layer2.Indices[9] = 2;
Layer2.Indices[10] = 4;
Layer2.Indices[11] = 5;
Layer2.Indices[12] = 5;
Layer2.Indices[13] = 6;
Layer2.Indices[14] = 8;
Layer2.Indices[15] = 8;
Layer2.Indices[16] = 6;
Layer2.Indices[17] = 7;
Layer2.Indices[18] = 11;
Layer2.Indices[19] = 8;
Layer2.Indices[20] = 10;
Layer2.Indices[21] = 10;
Layer2.Indices[22] = 8;
Layer2.Indices[23] = 9;
chunks.Add( Layer2 );
#endregion Define Layer2 Indices
}
}
}
}

View file

@ -0,0 +1,230 @@
using System;
using OpenTK;
namespace Examples.Shapes
{
/// <summary>winding always assumed CCW (Counter-ClockWise)</summary>
internal struct TetrahedronFace
{
private Vector3d APosition, BPosition, CPosition;
private Vector3d DPosition, Normal;
private Vector2d ATexCoord, BTexCoord, CTexCoord;
public TetrahedronFace( ref Vector3d apos, ref Vector2d atc,
ref Vector3d bpos, ref Vector2d btc,
ref Vector3d cpos, ref Vector2d ctc,
ref Vector3d dpos,
ref Vector3d normal )
{
APosition = apos; ATexCoord = atc;
BPosition = bpos; BTexCoord = btc;
CPosition = cpos; CTexCoord = ctc;
DPosition = dpos;
Normal = normal;
}
/// <summary>Expects CCW triangle order as input, emits 4 new CCW triangles.</summary>
/// <param name="first">1st output Triangle</param>
/// <param name="second">2nd output Triangle</param>
/// <param name="third">3rd output Triangle</param>
/// <param name="fourth">4th output Triangle</param>
public void SubdivideSierpinski( out TetrahedronFace first, out TetrahedronFace second, out TetrahedronFace third, out TetrahedronFace fourth )
{
Vector3d temp;
// find the 3 points AB, BC, CA
Vector3d CenterAB;
Vector3d.Add( ref this.APosition, ref this.BPosition, out temp );
Vector3d.Mult( ref temp, 0.5f, out CenterAB );
Vector3d CenterBC;
Vector3d.Add( ref this.BPosition, ref this.CPosition, out temp );
Vector3d.Mult( ref temp, 0.5f, out CenterBC );
Vector3d CenterCA;
Vector3d.Add( ref this.CPosition, ref this.APosition, out temp );
Vector3d.Mult( ref temp, 0.5f, out CenterCA );
// find the 3 points AD, BD, CD
Vector3d CenterAD;
Vector3d.Lerp( ref this.APosition, ref this.DPosition, 0.5, out CenterAD );
Vector3d CenterBD;
Vector3d.Lerp( ref this.BPosition, ref this.DPosition, 0.5, out CenterBD );
Vector3d CenterCD;
Vector3d.Lerp( ref this.CPosition, ref this.DPosition, 0.5, out CenterCD );
// emit 4 new CCW triangles
first = new TetrahedronFace( ref this.APosition, ref this.ATexCoord,
ref CenterAB, ref this.BTexCoord,
ref CenterCA, ref this.CTexCoord,
ref CenterAD,
ref this.Normal );
second = new TetrahedronFace( ref CenterAB, ref this.ATexCoord,
ref this.BPosition, ref this.BTexCoord,
ref CenterBC, ref this.CTexCoord,
ref CenterBD,
ref this.Normal );
third = new TetrahedronFace( ref CenterCA, ref this.ATexCoord,
ref CenterBC, ref this.BTexCoord,
ref this.CPosition, ref this.CTexCoord,
ref CenterCD,
ref this.Normal );
fourth = new TetrahedronFace( ref CenterAD, ref this.ATexCoord,
ref CenterBD, ref this.BTexCoord,
ref CenterCD, ref this.CTexCoord,
ref this.DPosition,
ref this.Normal );
}
internal void SubdivideKoch( double height, out TetrahedronFace first, out TetrahedronFace second, out TetrahedronFace third, out TetrahedronFace fourth, out TetrahedronFace fifth, out TetrahedronFace sixth )
{
Vector3d CenterAB, CenterBC, CenterCA, CenterD;
Vector2d TexCoordAB, TexCoordBC, TexCoordCA, TexCoordD;
Vector3d.Lerp( ref this.APosition, ref this.BPosition, 0.5, out CenterAB );
Vector3d.Lerp( ref this.BPosition, ref this.CPosition, 0.5, out CenterBC );
Vector3d.Lerp( ref this.CPosition, ref this.APosition, 0.5, out CenterCA );
CenterD = CenterAB;
CenterD.Add( ref CenterBC );
CenterD.Add( ref CenterCA );
CenterD.Div( 3.0 );
Vector3d E = CenterD + ( this.Normal * 0.5 );
Vector3d temp = this.Normal;
temp.Mult( height );
CenterD.Add( temp );
Vector2d.Lerp( ref this.ATexCoord, ref this.BTexCoord, 0.5, out TexCoordAB );
Vector2d.Lerp( ref this.BTexCoord, ref this.CTexCoord, 0.5, out TexCoordBC );
Vector2d.Lerp( ref this.CTexCoord, ref this.ATexCoord, 0.5, out TexCoordCA );
TexCoordD = TexCoordAB;
TexCoordD.Add( ref TexCoordBC );
TexCoordD.Add( ref TexCoordCA );
TexCoordD.Div( 3.0 );
#region 1
first.APosition = this.APosition;
first.ATexCoord = this.ATexCoord;
first.BPosition = CenterAB;
first.BTexCoord = TexCoordAB;
first.CPosition = CenterCA;
first.CTexCoord = TexCoordCA;
first.Normal = this.Normal;
temp = ( this.APosition + CenterAB + CenterCA );
temp.Div( 3.0 );
temp.Add( this.Normal * -1.0 );
first.DPosition = temp;
#endregion 1
#region 2
second.APosition = CenterAB;
second.ATexCoord = TexCoordAB;
second.BPosition = this.BPosition;
second.BTexCoord = this.BTexCoord;
second.CPosition = CenterBC;
second.CTexCoord = TexCoordBC;
second.Normal = this.Normal;
temp = CenterAB + this.BPosition + CenterBC;
temp.Div( 3.0 );
temp.Add( this.Normal * -1.0 );
second.DPosition = temp;
#endregion 2
#region 3
third.APosition = CenterBC;
third.ATexCoord = TexCoordBC;
third.BPosition = this.CPosition;
third.BTexCoord = this.CTexCoord;
third.CPosition = CenterCA;
third.CTexCoord = TexCoordCA;
third.Normal = this.Normal;
temp = CenterBC + this.CPosition + CenterCA;
temp.Div( 3.0 );
temp.Add( this.Normal * -1.0 );
third.DPosition = temp;
#endregion 3
#region 4
fourth.APosition = CenterAB;
fourth.ATexCoord = TexCoordAB;
fourth.BPosition = CenterD;
fourth.BTexCoord = TexCoordD;
fourth.CPosition = CenterCA;
fourth.CTexCoord = TexCoordCA;
SierpinskiTetrahedron.FindNormal( ref CenterAB, ref CenterD, ref CenterCA, out fourth.Normal );
fourth.DPosition = E;
#endregion 4
#region 5
fifth.APosition = CenterAB;
fifth.ATexCoord = TexCoordAB;
fifth.BPosition = CenterBC;
fifth.BTexCoord = TexCoordBC;
fifth.CPosition = CenterD;
fifth.CTexCoord = TexCoordD;
SierpinskiTetrahedron.FindNormal( ref CenterAB, ref CenterBC, ref CenterD, out fifth.Normal );
fifth.DPosition = E;
#endregion 5
#region 6
sixth.APosition = CenterBC;
sixth.ATexCoord = TexCoordBC;
sixth.BPosition = CenterCA;
sixth.BTexCoord = TexCoordCA;
sixth.CPosition = CenterD;
sixth.CTexCoord = TexCoordD;
SierpinskiTetrahedron.FindNormal( ref CenterBC, ref CenterCA, ref CenterD, out sixth.Normal );
sixth.DPosition = E;
#endregion 6
}
/// <summary>Returns 3 Vertices which form a CCW triangle.</summary>
public void GetVertices( out VertexT2dN3dV3d first, out VertexT2dN3dV3d second, out VertexT2dN3dV3d third )
{
first.TexCoord = this.ATexCoord;
first.Normal = this.Normal;
first.Position = this.APosition;
second.TexCoord = this.BTexCoord;
second.Normal = this.Normal;
second.Position = this.BPosition;
third.TexCoord = this.CTexCoord;
third.Normal = this.Normal;
third.Position = this.CPosition;
}
/// <summary>Debugging Aid, no real purpose</summary>
public override string ToString()
{
return "A= " + this.APosition.ToString() + " TexCoord: " + this.ATexCoord.ToString() + "\n" +
"B= " + this.BPosition.ToString() + " TexCoord: " + this.ATexCoord.ToString() + "\n" +
"C= " + this.CPosition.ToString() + " TexCoord: " + this.ATexCoord.ToString() + "\n" +
"Normal= " + this.Normal.ToString();
}
}
}

View file

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Examples.Shapes
{
public sealed class VboShape: DrawableShape
{
public VboShape( ref OpenTK.Graphics.OpenGL.BeginMode primitives, ref VertexT2dN3dV3d[] vertices, ref uint[] indices, bool useDL )
: base( useDL )
{
PrimitiveMode = primitives;
VertexArray = new VertexT2dN3dV3d[vertices.Length];
for ( uint i = 0; i < vertices.Length; i++ )
{
VertexArray[i] = vertices[i];
}
IndexArray = new uint[indices.Length];
for ( uint i = 0; i < indices.Length; i++ )
{
IndexArray[i] = indices[i];
}
}
}
}

View file

@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
namespace Examples.Shapes
{
public sealed class KochTetrahedron: DrawableShape
{
public enum eSubdivisions
{
Zero = 0,
One = 1,
Two = 2,
Three = 3,
Four = 4,
Five=5,
Six=6,
Seven=7,
Eight=8,
}
public KochTetrahedron( double scale, double extrusionHeight, double extrusionMultiplier, eSubdivisions subdivs, bool useDL )
: base( useDL )
{
TetrahedronFace[] Triangles;
switch ( subdivs )
{
case eSubdivisions.Zero:
SierpinskiTetrahedron.CreateDefaultTetrahedron( scale, out Triangles );
break;
case eSubdivisions.One:
case eSubdivisions.Two:
case eSubdivisions.Three:
case eSubdivisions.Four:
case eSubdivisions.Five:
case eSubdivisions.Six:
case eSubdivisions.Seven:
case eSubdivisions.Eight:
SierpinskiTetrahedron.CreateDefaultTetrahedron( scale, out Triangles );
for ( int i = 0; i < (int)subdivs; i++ )
{
TetrahedronFace[] temp;
this.SubdivideKoch( extrusionHeight, ref Triangles, out temp );
Triangles = temp;
extrusionHeight *= extrusionMultiplier;
}
break;
default: throw new ArgumentOutOfRangeException( "Subdivisions other than contained in the enum cause overflows and are not allowed." );
}
PrimitiveMode = OpenTK.Graphics.OpenGL.BeginMode.Triangles;
SierpinskiTetrahedron.GetVertexArray( ref Triangles, out VertexArray );
IndexArray = null;
}
private void SubdivideKoch( double height, ref TetrahedronFace[] input, out TetrahedronFace[] output )
{
output = new TetrahedronFace[input.Length * 6];
int counter = 0;
for ( int i = 0; i < input.Length; i++ )
{
input[i].SubdivideKoch(height, out output[counter + 0], out output[counter + 1], out output[counter + 2], out output[counter + 3], out output[counter + 4], out output[counter + 5] );
counter += 6; // every source triangle emits 6 new triangles
}
}
}
}

View file

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using OpenTK;
namespace Examples.Shapes
{
public sealed partial class MengerSponge: DrawableShape
{
public enum eSubdivisions
{
None = 0,
One = 1,
Two = 2,
Three = 3,
}
public MengerSponge( double scale, eSubdivisions subdivs, bool useDL )
: base( useDL )
{
List<MengerCube> Cubes;
switch ( subdivs )
{
case eSubdivisions.None:
CreateDefaultMengerSponge( scale, out Cubes );
break;
case eSubdivisions.One:
case eSubdivisions.Two:
case eSubdivisions.Three:
CreateDefaultMengerSponge( scale, out Cubes );
for ( int i = 0; i < (int)subdivs; i++ )
{
List<MengerCube> temp;
SubdivideMengerSponge( ref Cubes, out temp );
Cubes = temp;
}
break;
default: throw new ArgumentOutOfRangeException( "Subdivisions other than contained in the enum cause overflows and are not allowed." );
}
PrimitiveMode = OpenTK.Graphics.OpenGL.BeginMode.Triangles;
#region Get Array Dimensions
uint
VertexCount = 0,
IndexCount = 0;
foreach ( MengerCube c in Cubes )
{
uint t1, t2;
c.GetArraySizes( out t1, out t2 );
VertexCount += t1;
IndexCount += t2;
}
VertexArray = new VertexT2dN3dV3d[VertexCount];
IndexArray = new uint[IndexCount];
#endregion Get Array Dimensions
List<Chunk> AllChunks = new List<Chunk>();
#region Build a temporary List of all loose pieces
foreach ( MengerCube c in Cubes )
{
c.GetVboAndIbo( ref AllChunks );
}
#endregion Build a temporary List of all loose pieces
#region Assemble pieces into a single VBO and IBO
VertexCount = 0;
IndexCount = 0;
foreach ( Chunk ch in AllChunks )
{
for ( int i = 0; i < ch.Vertices.Length; i++ )
{
VertexArray[VertexCount + i] = ch.Vertices[i];
}
for ( int i = 0; i < ch.Indices.Length; i++ )
{
IndexArray[IndexCount + i] = ch.Indices[i] + VertexCount;
}
VertexCount += (uint)ch.Vertices.Length;
IndexCount += (uint)ch.Indices.Length;
}
#endregion Assemble pieces into a single VBO and IBO
AllChunks.Clear();
}
private void CreateDefaultMengerSponge( double halfwidth, out List<MengerCube> output )
{
output = new List<MengerCube>( 1 );
output.Add( new MengerCube( Vector3d.Zero, halfwidth, MengerCube.AllSides, MengerCube.AllSides ) );
}
private void SubdivideMengerSponge( ref List<MengerCube> input, out List<MengerCube> output )
{
output = new List<MengerCube>( input.Count * 20 );
foreach ( MengerCube InputCube in input )
{
MengerCube[] SubdividedCubes;
InputCube.Subdivide( out SubdividedCubes );
for ( int i = 0; i < SubdividedCubes.Length; i++ )
{
output.Add( SubdividedCubes[i] );
}
}
}
}
}

View file

@ -0,0 +1,173 @@
using System;
using System.Diagnostics;
using OpenTK;
namespace Examples.Shapes
{
public sealed partial class SierpinskiTetrahedron: DrawableShape
{
public enum eSubdivisions
{
/// <summary>Creates a Sierpinski Tetrahedron using 4 triangles.</summary>
Zero = 0,
/// <summary>Creates a Sierpinski Tetrahedron using 16 triangles.</summary>
One = 1,
/// <summary>Creates a Sierpinski Tetrahedron using 64 triangles.</summary>
Two = 2,
/// <summary>Creates a Sierpinski Tetrahedron using 256 triangles.</summary>
Three = 3,
/// <summary>Creates a Sierpinski Tetrahedron using 1024 triangles.</summary>
Four = 4,
/// <summary>Creates a Sierpinski Tetrahedron using 4096 triangles.</summary>
Five = 5,
/// <summary>Creates a Sierpinski Tetrahedron using 16384 triangles.</summary>
Six = 6,
/// <summary>Creates a Sierpinski Tetrahedron using 65536 triangles.</summary>
Seven = 7,
/// <summary>Creates a Sierpinski Tetrahedron using 262144 triangles.</summary>
Eight = 8,
/// <summary>Creates a Sierpinski Tetrahedron using 1048576 triangles.</summary>
Nine = 9,
}
/// <summary>Creates a Sierpinski Tetrahedron which is centered at (0,0,0) and fits into a sphere of radius 1f, or a diameter of 2f</summary>
/// <param name="scale">Default: 1f.</param>
/// <param name="subdivs">The number of subdivisions of the Tetrahedron.</param>
/// <param name="useDL"></param>
public SierpinskiTetrahedron( double scale, eSubdivisions subdivs, bool useDL )
: base( useDL )
{
TetrahedronFace[] Triangles;
switch ( subdivs )
{
case eSubdivisions.Zero:
CreateDefaultTetrahedron( scale, out Triangles );
break;
case eSubdivisions.One:
case eSubdivisions.Two:
case eSubdivisions.Three:
case eSubdivisions.Four:
case eSubdivisions.Five:
case eSubdivisions.Six:
case eSubdivisions.Seven:
case eSubdivisions.Eight:
case eSubdivisions.Nine:
CreateDefaultTetrahedron( scale, out Triangles );
for ( int i = 0; i < (int)subdivs; i++ )
{
TetrahedronFace[] temp;
SubdivideTetrahedron( ref Triangles, out temp );
Triangles = temp;
}
break;
default: throw new ArgumentOutOfRangeException( "Subdivisions other than contained in the enum cause overflows and are not allowed." );
}
PrimitiveMode = OpenTK.Graphics.OpenGL.BeginMode.Triangles;
SierpinskiTetrahedron.GetVertexArray( ref Triangles, out VertexArray );
IndexArray = null;
}
internal static void GetVertexArray( ref TetrahedronFace[] input, out VertexT2dN3dV3d[] output )
{
output = new VertexT2dN3dV3d[input.Length * 3];
int counter = 0;
for ( int i = 0; i < input.Length; i++ )
{
input[i].GetVertices( out output[counter + 0], out output[counter + 1], out output[counter + 2] );
counter += 3;
}
}
/// <summary>Generates the lowest subdivision mesh, which consists of 4 Triangles.</summary>
internal static void CreateDefaultTetrahedron( double scale, out TetrahedronFace[] array )
{
Vector3d[] Points = new Vector3d[4];
Points[0] = new Vector3d( 0.0 * scale, 0.0 * scale, 1.0 * scale );
Points[1] = new Vector3d( -0.816 * scale, 0.471 * scale, -0.333 * scale );
Points[2] = new Vector3d( 0.816 * scale, 0.471 * scale, -0.333 * scale );
Points[3] = new Vector3d( 0.0 * scale, -0.943 * scale, -0.333 * scale );
Vector2d[] TexCoords = new Vector2d[4];
TexCoords[0] = new Vector2d( 0.0, 0.0 );
TexCoords[1] = new Vector2d( 1.0, 0.0 );
TexCoords[2] = new Vector2d( 0.0, 1.0 );
TexCoords[3] = new Vector2d( 1.0, 1.0 );
Vector3d Normal;
array = new TetrahedronFace[4];
FindNormal( ref Points[0], ref Points[2], ref Points[1], ref Points[3], out Normal );
array[0] = new TetrahedronFace( ref Points[0], ref TexCoords[2],
ref Points[2], ref TexCoords[0],
ref Points[1], ref TexCoords[1],
ref Points[3],
ref Normal );
FindNormal( ref Points[0], ref Points[3], ref Points[2], ref Points[1], out Normal );
array[1] = new TetrahedronFace( ref Points[0], ref TexCoords[0],
ref Points[3], ref TexCoords[1],
ref Points[2], ref TexCoords[2],
ref Points[1],
ref Normal );
FindNormal( ref Points[0], ref Points[1], ref Points[3], ref Points[2], out Normal );
array[2] = new TetrahedronFace( ref Points[0], ref TexCoords[2],
ref Points[1], ref TexCoords[1],
ref Points[3], ref TexCoords[3],
ref Points[2],
ref Normal );
FindNormal( ref Points[1], ref Points[2], ref Points[3], ref Points[0], out Normal );
array[3] = new TetrahedronFace( ref Points[1], ref TexCoords[3],
ref Points[2], ref TexCoords[2],
ref Points[3], ref TexCoords[1],
ref Points[0],
ref Normal );
}
/// <summary>Subdivides each triangle into 4 new ones.</summary>
private void SubdivideTetrahedron( ref TetrahedronFace[] source, out TetrahedronFace[] output )
{
output = new TetrahedronFace[source.Length * 4];
int counter = 0;
for ( int i = 0; i < source.Length; i++ )
{
source[i].SubdivideSierpinski( out output[counter + 0], out output[counter + 1], out output[counter + 2], out output[counter + 3] );
counter += 4; // every source triangle emits 4 new triangles
}
}
/// <summary>A, B and C are the triangle whos normal is to be determined. D is the 4th Point in the Tetraeder which does not belong to the triangle.</summary>
internal static void FindNormal( ref Vector3d A, ref Vector3d B, ref Vector3d C, ref Vector3d D, out Vector3d result )
{
Vector3d temp1, temp2, temp3;
Vector3d.Sub( ref A, ref D, out temp1 );
Vector3d.Sub( ref B, ref D, out temp2 );
Vector3d.Sub( ref C, ref D, out temp3 );
Vector3d.Add( ref temp1, ref temp2, out result );
result.Add( ref temp3 );
result.Normalize();
}
internal static void FindNormal( ref Vector3d A, ref Vector3d B, ref Vector3d C, out Vector3d result )
{
Vector3d temp1, temp2;
Vector3d.Sub( ref A, ref B, out temp1 );
temp1.Normalize();
Vector3d.Sub( ref C, ref B, out temp2 );
temp2.Normalize();
Vector3d.Cross( ref temp1, ref temp2, out result );
result.Mult( -1.0 );
result.Normalize();
}
}
}

View file

@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using OpenTK;
namespace Examples.Shapes
{
public sealed class SlicedHose : DrawableShape
{
public enum eSide:byte
{
// Around X Axis
BottomRight,
TopRight,
TopLeft,
BottomLeft,
// Around Y Axis
FrontRight,
BackRight,
BackLeft,
FrontLeft,
// Around Z Axis
FrontBottom,
BackBottom,
BackTop,
FrontTop,
}
public SlicedHose( eSide side, uint subdivs, double scale, Vector3d offset1, Vector3d offset2, bool useDL )
: base( useDL )
{
PrimitiveMode = OpenTK.Graphics.OpenGL.BeginMode.Triangles;
Vector3d start = Vector3d.Zero,
end = Vector3d.Zero;
double TexCoordStart=0f, TexCoordEnd=0f;
switch ( side )
{
#region Around X Axis
case eSide.BottomRight:
start = -Vector3d.UnitY;
end = Vector3d.UnitZ;
TexCoordStart = 0.0;
TexCoordEnd = 0.25;
break;
case eSide.TopRight:
start = Vector3d.UnitZ;
end = Vector3d.UnitY;
TexCoordStart = 0.25;
TexCoordEnd = 0.5;
break;
case eSide.TopLeft:
start = Vector3d.UnitY;
end = -Vector3d.UnitZ;
TexCoordStart = 0.5;
TexCoordEnd = 0.75;
break;
case eSide.BottomLeft:
start = -Vector3d.UnitZ;
end = -Vector3d.UnitY;
TexCoordStart = 0.75;
TexCoordEnd = 1.0;
break;
#endregion Around X Axis
#region Around Y Axis
case eSide.FrontRight:
start = Vector3d.UnitX;
end = Vector3d.UnitZ;
TexCoordStart = 0.0;
TexCoordEnd = 0.25;
break;
case eSide.BackRight:
start = Vector3d.UnitZ;
end = -Vector3d.UnitX;
TexCoordStart = 0.25;
TexCoordEnd = 0.5;
break;
case eSide.BackLeft:
start = -Vector3d.UnitX;
end = -Vector3d.UnitZ;
TexCoordStart = 0.5;
TexCoordEnd = 0.75;
break;
case eSide.FrontLeft:
start = -Vector3d.UnitZ;
end = Vector3d.UnitX;
TexCoordStart = 0.75;
TexCoordEnd = 1.0;
break;
#endregion Around Y Axis
#region Around Z Axis
case eSide.FrontBottom:
start = -Vector3d.UnitY;
end = Vector3d.UnitX;
TexCoordStart = 0.0;
TexCoordEnd = 0.25;
break;
case eSide.BackBottom:
start = -Vector3d.UnitX;
end = -Vector3d.UnitY;
TexCoordStart = 0.25;
TexCoordEnd = 0.5;
break;
case eSide.BackTop:
start = Vector3d.UnitY;
end = -Vector3d.UnitX;
TexCoordStart = 0.5;
TexCoordEnd = 0.75;
break;
case eSide.FrontTop:
start = Vector3d.UnitX;
end = Vector3d.UnitY;
TexCoordStart = 0.75;
TexCoordEnd = 1.0;
break;
#endregion Around Z Axis
}
VertexT2dN3dV3d[] temp = new VertexT2dN3dV3d[2 + subdivs];
double divisor = 1.0/ ((double)temp.Length-1.0);
for ( int i = 0; i < temp.Length; i++ )
{
float Multiplier = (float)( i * divisor );
temp[i].TexCoord.X = TexCoordStart * Multiplier + TexCoordEnd * ( 1.0f- Multiplier);
Slerp( ref start, ref end, Multiplier, out temp[i].Normal );
temp[i].Normal.Normalize();
temp[i].Position = temp[i].Normal;
temp[i].Position.Mult( scale );
}
VertexArray = new VertexT2dN3dV3d[temp.Length * 2];
IndexArray = new uint[( temp.Length - 1 ) * 2 * 3];
uint VertexCounter = 0,
IndexCounter = 0,
QuadCounter = 0;
for ( int i = 0; i < temp.Length; i++ )
{
VertexArray[VertexCounter + 0].TexCoord.X = temp[i].TexCoord.X;
VertexArray[VertexCounter + 0].TexCoord.Y = 0.0;
VertexArray[VertexCounter + 0].Normal = temp[i].Normal;
VertexArray[VertexCounter + 0].Position = temp[i].Position + offset1;
VertexArray[VertexCounter + 1].TexCoord.X = temp[i].TexCoord.X;
VertexArray[VertexCounter + 1].TexCoord.Y = 1.0;
VertexArray[VertexCounter + 1].Normal = temp[i].Normal;
VertexArray[VertexCounter + 1].Position = temp[i].Position + offset2;
VertexCounter += 2;
if ( i < temp.Length - 1 )
{
IndexArray[IndexCounter + 0] = QuadCounter + 0;
IndexArray[IndexCounter + 1] = QuadCounter + 1;
IndexArray[IndexCounter + 2] = QuadCounter + 2;
IndexArray[IndexCounter + 3] = QuadCounter + 2;
IndexArray[IndexCounter + 4] = QuadCounter + 1;
IndexArray[IndexCounter + 5] = QuadCounter + 3;
IndexCounter += 6;
QuadCounter += 2;
}
}
}
private void Slerp( ref Vector3d a, ref Vector3d b, double factor, out Vector3d result)
{
double t1;
Vector3d.Dot( ref a, ref b, out t1 );
double theta = System.Math.Acos( t1 );
double temp = 1.0 / System.Math.Sin( theta );
double t2 = System.Math.Sin( ( 1.0 - factor ) * theta ) * temp;
double t3 = System.Math.Sin( factor * theta ) * temp;
Vector3d v1 = Vector3d.Mult( a, t2);
Vector3d v2 = Vector3d.Mult( b, t3 );
result = Vector3d.Add( v1, v2 );
}
}
}

View file

@ -0,0 +1,196 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenTK;
namespace Examples.Shapes
{
public sealed class SlicedSphere: DrawableShape
{
public enum eSubdivisions
{
Zero = 0,
One = 1,
Two = 2,
Three = 3,
Four = 4,
Five=5,
Six=6,
Seven=7,
Eight=8,
}
public enum eDir
{
All,
FrontTopRight,
FrontBottomRight,
FrontBottomLeft,
FrontTopLeft,
BackTopRight,
BackBottomRight,
BackBottomLeft,
BackTopLeft,
}
public SlicedSphere( double radius, Vector3d offset, eSubdivisions subdivs, eDir[] sides, bool useDL )
: base( useDL )
{
double Diameter = radius;
PrimitiveMode = OpenTK.Graphics.OpenGL.BeginMode.Triangles;
if ( sides[0] == eDir.All )
{
sides = new eDir[] { eDir.FrontTopRight,
eDir.FrontBottomRight,
eDir.FrontBottomLeft,
eDir.FrontTopLeft,
eDir.BackTopRight,
eDir.BackBottomRight,
eDir.BackBottomLeft,
eDir.BackTopLeft,};
}
VertexArray = new VertexT2dN3dV3d[sides.Length * 3];
IndexArray = new uint[sides.Length * 3];
uint counter = 0;
foreach ( eDir s in sides )
{
GetDefaultVertices( s, Diameter, out VertexArray[counter + 0], out VertexArray[counter + 1], out VertexArray[counter + 2] );
IndexArray[counter + 0] = counter + 0;
IndexArray[counter + 1] = counter + 1;
IndexArray[counter + 2] = counter + 2;
counter += 3;
}
if ( subdivs != eSubdivisions.Zero )
{
for ( int s = 0; s < (int)subdivs; s++ )
{
#region Assemble Chunks and convert to Arrays
List<Chunk> AllChunks = new List<Chunk>();
for ( uint i = 0; i < IndexArray.Length; i += 3 )
{
Chunk chu;
Subdivide( Diameter,
ref VertexArray[IndexArray[i + 0]],
ref VertexArray[IndexArray[i + 1]],
ref VertexArray[IndexArray[i + 2]],
out chu );
AllChunks.Add( chu );
}
Chunk.GetArray( ref AllChunks, out VertexArray, out IndexArray );
AllChunks.Clear();
#endregion Assemble Chunks and convert to Arrays
}
}
for (int i=0; i<VertexArray.Length;i++)
{
VertexArray[i].Position.Add( ref offset );
}
}
private void GetDefaultVertices( eDir s, double scale, out VertexT2dN3dV3d first, out VertexT2dN3dV3d second, out VertexT2dN3dV3d third )
{
VertexT2dN3dV3d t1 = new VertexT2dN3dV3d(),
t2 = new VertexT2dN3dV3d(),
t3 = new VertexT2dN3dV3d();
switch ( s )
{
case eDir.FrontTopRight:
t1 = new VertexT2dN3dV3d( new Vector2d( 0.5, 1.0 ), Vector3d.UnitY, Vector3d.UnitY * scale );
t2 = new VertexT2dN3dV3d( new Vector2d( 0.0, 0.0 ), Vector3d.UnitZ, Vector3d.UnitZ * scale );
t3 = new VertexT2dN3dV3d( new Vector2d( 0.5, 0.0 ), Vector3d.UnitX, Vector3d.UnitX * scale );
break;
case eDir.FrontBottomRight:
t1 = new VertexT2dN3dV3d( new Vector2d( 0.5, 0.0 ), Vector3d.UnitX, Vector3d.UnitX * scale );
t2 = new VertexT2dN3dV3d( new Vector2d( 0.0, 0.0 ), Vector3d.UnitZ, Vector3d.UnitZ * scale );
t3 = new VertexT2dN3dV3d( new Vector2d( 0.5, 1.0 ), -Vector3d.UnitY, -Vector3d.UnitY * scale );
break;
case eDir.FrontBottomLeft:
t1 = new VertexT2dN3dV3d( new Vector2d( 0.5, 0.0 ), Vector3d.UnitX, Vector3d.UnitX * scale );
t2 = new VertexT2dN3dV3d( new Vector2d( 0.5, 1.0 ), -Vector3d.UnitY, -Vector3d.UnitY * scale );
t3 = new VertexT2dN3dV3d( new Vector2d( 1.0, 0.0 ), -Vector3d.UnitZ, -Vector3d.UnitZ * scale );
break;
case eDir.FrontTopLeft:
t1 = new VertexT2dN3dV3d( new Vector2d( 1.0, 0.0 ), -Vector3d.UnitZ, -Vector3d.UnitZ * scale );
t2 = new VertexT2dN3dV3d( new Vector2d( 0.5, 1.0 ), Vector3d.UnitY, Vector3d.UnitY * scale );
t3 = new VertexT2dN3dV3d( new Vector2d( 0.5, 0.0 ), Vector3d.UnitX, Vector3d.UnitX * scale );
break;
case eDir.BackTopRight:
t1 = new VertexT2dN3dV3d( new Vector2d( 0.5, 1.0 ), Vector3d.UnitY, Vector3d.UnitY * scale );
t2 = new VertexT2dN3dV3d( new Vector2d( 0.0, 1.0 ), -Vector3d.UnitX, -Vector3d.UnitX * scale );
t3 = new VertexT2dN3dV3d( new Vector2d( 0.0, 0.0 ), Vector3d.UnitZ, Vector3d.UnitZ * scale );
break;
case eDir.BackBottomRight:
t1 = new VertexT2dN3dV3d( new Vector2d( 0.5, 1.0 ), -Vector3d.UnitY, -Vector3d.UnitY * scale );
t2 = new VertexT2dN3dV3d( new Vector2d( 0.0, 0.0 ), Vector3d.UnitZ, Vector3d.UnitZ * scale );
t3 = new VertexT2dN3dV3d( new Vector2d( 0.0, 1.0 ), -Vector3d.UnitX, -Vector3d.UnitX * scale );
break;
case eDir.BackBottomLeft:
t1 = new VertexT2dN3dV3d( new Vector2d( 0.5, 1.0 ), -Vector3d.UnitY, -Vector3d.UnitY * scale );
t2 = new VertexT2dN3dV3d( new Vector2d( 1.0, 1.0 ), -Vector3d.UnitX, -Vector3d.UnitX * scale );
t3 = new VertexT2dN3dV3d( new Vector2d( 1.0, 0.0 ), -Vector3d.UnitZ, -Vector3d.UnitZ * scale );
break;
case eDir.BackTopLeft:
t1 = new VertexT2dN3dV3d( new Vector2d( 0.5, 1.0 ), Vector3d.UnitY, Vector3d.UnitY * scale );
t2 = new VertexT2dN3dV3d( new Vector2d( 1.0, 0.0 ), -Vector3d.UnitZ, -Vector3d.UnitZ * scale );
t3 = new VertexT2dN3dV3d( new Vector2d( 1.0, 1.0 ), -Vector3d.UnitX, -Vector3d.UnitX * scale );
break;
}
first = t1;
second = t2;
third = t3;
}
private void Subdivide( double Scale, ref VertexT2dN3dV3d first, ref VertexT2dN3dV3d second, ref VertexT2dN3dV3d third, out Chunk c )
{
c = new Chunk(6, 12);
c.Vertices[0] = first;
Vector3d.Lerp(ref first.Position, ref second.Position, 0.5,out c.Vertices[1].Normal );
c.Vertices[1].Normal.Normalize();
c.Vertices[1].Position = c.Vertices[1].Normal * Scale;
Vector2d.Lerp( ref first.TexCoord, ref second.TexCoord, 0.5, out c.Vertices[1].TexCoord );
Vector3d.Lerp( ref third.Position, ref first.Position, 0.5, out c.Vertices[2].Normal );
c.Vertices[2].Normal.Normalize();
c.Vertices[2].Position = c.Vertices[2].Normal * Scale;
Vector2d.Lerp( ref third.TexCoord, ref first.TexCoord, 0.5, out c.Vertices[2].TexCoord );
c.Vertices[3] = second;
Vector3d.Lerp( ref second.Position, ref third.Position, 0.5, out c.Vertices[4].Normal );
c.Vertices[4].Normal.Normalize();
c.Vertices[4].Position = c.Vertices[4].Normal * Scale;
Vector2d.Lerp( ref second.TexCoord, ref third.TexCoord, 0.5, out c.Vertices[4].TexCoord );
c.Vertices[5] = third;
#region Indices
c.Indices[0]=0;
c.Indices[1]=1;
c.Indices[2]=2;
c.Indices[3]=2;
c.Indices[4]=1;
c.Indices[5]=4;
c.Indices[6]=1;
c.Indices[7]=3;
c.Indices[8]=4;
c.Indices[9]=2;
c.Indices[10]=4;
c.Indices[11]=5;
#endregion Indices
}
}
}

View file

@ -0,0 +1,128 @@
using System;
using System.Diagnostics;
using OpenTK;
namespace Examples.Shapes
{
public sealed class TorusKnot: DrawableShape
{
#region Constants
// hard minimums to make sure the created Torusknot is 3D
private const int MINShapeVertices = 3;
private const int MINPathSteps = 32;
private const double TwoPi = ( 2.0 * System.Math.PI );
#endregion Constants
public TorusKnot( int pathsteps, int shapevertices, double radius, int p, int q, int TexCount, bool useDL )
: base( useDL )
{
Trace.Assert( pathsteps >= MINPathSteps, "A Path must have at least " + MINPathSteps + " Steps to form a volume." );
Trace.Assert( shapevertices >= MINShapeVertices, "A Shape must contain at least " + MINShapeVertices + " Vertices to be considered valid and create a volume." );
Trace.Assert( TexCount > 1, "at least 1 Texture set is required." );
PrimitiveMode = OpenTK.Graphics.OpenGL.BeginMode.TriangleStrip;
Vector3d[] PathPositions = new Vector3d[pathsteps];
#region Find the center Points for each step on the path
for ( int i = 0; i < pathsteps; i++ )
{
double Angle = ( i / (double)pathsteps ) * TwoPi;
double AngleTimesP = Angle * p;
double AngleTimesQ = Angle * q;
double r = ( 0.5 * ( 2.0 + System.Math.Sin( AngleTimesQ ) ) );
PathPositions[i] = new Vector3d( ( r * System.Math.Cos( AngleTimesP ) ),
( r * System.Math.Cos( AngleTimesQ ) ),
( r * System.Math.Sin( AngleTimesP ) ) );
}
#endregion Find the center Points for each step on the path
#region Find the Torus length
Vector3d result;
double[] Lengths = new double[pathsteps];
Vector3d.Sub( ref PathPositions[pathsteps - 1], ref PathPositions[0], out result );
Lengths[0] = result.Length;
double TotalLength = result.Length;
for ( int i = 1; i < pathsteps; i++ ) // skipping
{
Vector3d.Sub( ref PathPositions[i - 1], ref PathPositions[i], out result );
Lengths[i] = result.Length;
TotalLength += result.Length;
}
Trace.WriteLine( "the TorusKnot's length is: " + TotalLength + " " );
#endregion Find the Torus length
VertexArray = new VertexT2dN3dV3d[pathsteps * shapevertices];
#region Loft a circle Shape along the path
double TwoPiThroughVert = TwoPi / shapevertices; // precalc for reuse
for ( uint i = 0; i < pathsteps; i++ )
{
Vector3d last, next, normal, tangent;
if ( i == pathsteps - 1 )
next = PathPositions[0];
else
next = PathPositions[i + 1];
if ( i == 0 )
last = PathPositions[pathsteps - 1];
else
last = PathPositions[i - 1];
Vector3d.Sub( ref next, ref last, out tangent ); // Guesstimate tangent
tangent.Normalize();
Vector3d.Add( ref next, ref last, out normal ); // Approximate N
normal.Normalize();
Vector3d.Mult( ref normal, radius, out normal );// scale the shape to desired radius
for ( uint j = 0; j < shapevertices; j++ )
{
uint index = i * (uint)shapevertices + j;
// Create a point on the plane and rotate it
Matrix4d RotationMatrix = Matrix4d.Rotate( tangent, -( j * TwoPiThroughVert ) );
Vector3d point = Vector3d.TransformVector( normal, RotationMatrix );
Vector3d.Add( ref PathPositions[i], ref point, out VertexArray[index].Position );
// Since the used shape is a circle, the Vertex normal's heading is easy to find
Vector3d.Sub( ref VertexArray[index].Position, ref PathPositions[i], out VertexArray[index].Normal );
VertexArray[index].Normal.Normalize();
// just generate some semi-useful UVs to fill blanks
VertexArray[index].TexCoord = new Vector2d( (double)( i / TotalLength/ TexCount ), j / ( shapevertices - 1.0 ) );
}
}
#endregion Loft a circle Shape along the path
PathPositions = null; // not needed anymore
uint currentindex = 0;
#region Build a Triangle strip from the Vertices
IndexArray = new uint[pathsteps * ( shapevertices * 2 + 2 )]; // 2 triangles per vertex, +2 due to added degenerate triangles
for ( uint i = 0; i < pathsteps; i++ )
{
uint RowCurrent = i * (uint)shapevertices;
uint RowBelow;
if ( i == pathsteps - 1 )
RowBelow = 0; // for the last row, the first row is the following
else
RowBelow = ( i + 1 ) * (uint)shapevertices;
// new ring begins here
for ( uint j = 0; j < shapevertices; j++ )
{
IndexArray[currentindex++] = RowCurrent + j;
IndexArray[currentindex++] = RowBelow + j;
}
// ring ends here, repeat first 2 vertices to insert 2 degenerate triangles to reach following ring
IndexArray[currentindex++] = RowCurrent;
IndexArray[currentindex++] = RowBelow;
}
#endregion Build a Triangle strip from the Vertices
}
}
}

View file

@ -0,0 +1,711 @@
#region --- License ---
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing details.
*/
#endregion
// #define READALL
// uncomment so ALL fields read from file are interpreted and filled. Necessary to implement uncompressed DDS
// TODO: Find app that can build compressed dds cubemaps and verify that the import code works.
using System;
using System.IO;
using System.Diagnostics;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
namespace Examples.TextureLoaders
{
/// <summary>
/// Expects the presence of a valid OpenGL Context and Texture Compression Extensions (GL 1.5) and Cube Maps (GL 1.3).
/// You will get what you give. No automatic Mipmap generation or automatic compression is done. (both bad quality)
/// Textures are never rescaled or checked if Power of 2, but you should make the Width and Height a multiple of 4 because DXTn uses 4x4 blocks.
/// (Image displays correctly but runs extremely slow with non-power-of-two Textures on FX5600, Cache misses?)
/// CubeMap support is experimental and the file must specify all 6 faces to work at all.
/// </summary>
static class ImageDDS
{
#region Constants
private const byte HeaderSizeInBytes = 128; // all non-image data together is 128 Bytes
private const uint BitMask = 0x00000007; // bits = 00 00 01 11
private static NotImplementedException Unfinished = new NotImplementedException( "ERROR: Only 2 Dimensional DXT1/3/5 compressed images for now. 1D/3D Textures may not be compressed according to spec." );
#endregion Constants
#region Simplified In-Memory representation of the Image
private static bool _IsCompressed;
private static int _Width, _Height, _Depth, _MipMapCount;
private static int _BytesForMainSurface; // must be handled with care when implementing uncompressed formats!
private static byte _BytesPerBlock;
private static PixelInternalFormat _PixelInternalFormat;
#endregion Simplified In-Memory representation of the Image
#region Flag Enums
[Flags] // Surface Description
private enum eDDSD: uint
{
CAPS = 0x00000001, // is always present
HEIGHT = 0x00000002, // is always present
WIDTH = 0x00000004, // is always present
PITCH = 0x00000008, // is set if the image is uncompressed
PIXELFORMAT = 0x00001000, // is always present
MIPMAPCOUNT = 0x00020000, // is set if the image contains MipMaps
LINEARSIZE = 0x00080000, // is set if the image is compressed
DEPTH = 0x00800000 // is set for 3D Volume Textures
}
[Flags] // Pixelformat
private enum eDDPF: uint
{
NONE = 0x00000000, // not part of DX, added for convenience
ALPHAPIXELS = 0x00000001,
FOURCC = 0x00000004,
RGB = 0x00000040,
RGBA = 0x00000041
}
/// <summary>This list was derived from nVidia OpenGL SDK</summary>
[Flags] // Texture types
private enum eFOURCC: uint
{
UNKNOWN = 0,
#if READALL
R8G8B8 = 20,
A8R8G8B8 = 21,
X8R8G8B8 = 22,
R5G6B5 = 23,
X1R5G5B5 = 24,
A1R5G5B5 = 25,
A4R4G4B4 = 26,
R3G3B2 = 27,
A8 = 28,
A8R3G3B2 = 29,
X4R4G4B4 = 30,
A2B10G10R10 = 31,
A8B8G8R8 = 32,
X8B8G8R8 = 33,
G16R16 = 34,
A2R10G10B10 = 35,
A16B16G16R16 = 36,
L8 = 50,
A8L8 = 51,
A4L4 = 52,
D16_LOCKABLE = 70,
D32 = 71,
D24X8 = 77,
D16 = 80,
D32F_LOCKABLE = 82,
L16 = 81,
// s10e5 formats (16-bits per channel)
R16F = 111,
G16R16F = 112,
A16B16G16R16F = 113,
// IEEE s23e8 formats (32-bits per channel)
R32F = 114,
G32R32F = 115,
A32B32G32R32F = 116
#endif
DXT1 = 0x31545844,
DXT2 = 0x32545844,
DXT3 = 0x33545844,
DXT4 = 0x34545844,
DXT5 = 0x35545844,
}
[Flags] // dwCaps1
private enum eDDSCAPS: uint
{
NONE = 0x00000000, // not part of DX, added for convenience
COMPLEX = 0x00000008, // should be set for any DDS file with more than one main surface
TEXTURE = 0x00001000, // should always be set
MIPMAP = 0x00400000 // only for files with MipMaps
}
[Flags] // dwCaps2
private enum eDDSCAPS2: uint
{
NONE = 0x00000000, // not part of DX, added for convenience
CUBEMAP = 0x00000200,
CUBEMAP_POSITIVEX = 0x00000400,
CUBEMAP_NEGATIVEX = 0x00000800,
CUBEMAP_POSITIVEY = 0x00001000,
CUBEMAP_NEGATIVEY = 0x00002000,
CUBEMAP_POSITIVEZ = 0x00004000,
CUBEMAP_NEGATIVEZ = 0x00008000,
CUBEMAP_ALL_FACES = 0x0000FC00,
VOLUME = 0x00200000 // for 3D Textures
}
#endregion Flag Enums
#region Private Members
private static string idString; // 4 bytes, must be "DDS "
private static UInt32 dwSize; // Size of structure is 124 bytes, 128 including all sub-structs and the header
private static UInt32 dwFlags; // Flags to indicate valid fields.
private static UInt32 dwHeight; // Height of the main image in pixels
private static UInt32 dwWidth; // Width of the main image in pixels
private static UInt32 dwPitchOrLinearSize; // For compressed formats, this is the total number of bytes for the main image.
private static UInt32 dwDepth; // For volume textures, this is the depth of the volume.
private static UInt32 dwMipMapCount; // total number of levels in the mipmap chain of the main image.
#if READALL
private static UInt32[] dwReserved1; // 11 UInt32s
#endif
// Pixelformat sub-struct, 32 bytes
private static UInt32 pfSize; // Size of Pixelformat structure. This member must be set to 32.
private static UInt32 pfFlags; // Flags to indicate valid fields.
private static UInt32 pfFourCC; // This is the four-character code for compressed formats.
#if READALL
private static UInt32 pfRGBBitCount; // For RGB formats, this is the total number of bits in the format. dwFlags should include DDpf_RGB in this case. This value is usually 16, 24, or 32. For A8R8G8B8, this value would be 32.
private static UInt32 pfRBitMask; // For RGB formats, these three fields contain the masks for the red, green, and blue channels. For A8R8G8B8, these values would be 0x00ff0000, 0x0000ff00, and 0x000000ff respectively.
private static UInt32 pfGBitMask; // ..
private static UInt32 pfBBitMask; // ..
private static UInt32 pfABitMask; // For RGB formats, this contains the mask for the alpha channel, if any. dwFlags should include DDpf_ALPHAPIXELS in this case. For A8R8G8B8, this value would be 0xff000000.
#endif
// Capabilities sub-struct, 16 bytes
private static UInt32 dwCaps1; // always includes DDSCAPS_TEXTURE. with more than one main surface DDSCAPS_COMPLEX should also be set.
private static UInt32 dwCaps2; // For cubic environment maps, DDSCAPS2_CUBEMAP should be included as well as one or more faces of the map (DDSCAPS2_CUBEMAP_POSITIVEX, DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY, DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ). For volume textures, DDSCAPS2_VOLUME should be included.
#if READALL
private static UInt32[] dwReserved2; // 3 = 2 + 1 UInt32
#endif
#endregion Private Members
/// <summary>
/// This function will generate, bind and fill a Texture Object with a DXT1/3/5 compressed Texture in .dds Format.
/// MipMaps below 4x4 Pixel Size are discarded, because DXTn's smallest unit is a 4x4 block of Pixel data.
/// It will set correct MipMap parameters, Filtering, Wrapping and EnvMode for the Texture.
/// The only call inside this function affecting OpenGL State is GL.BindTexture();
/// </summary>
/// <param name="filename">The name of the file you wish to load, including path and file extension.</param>
/// <param name="texturehandle">0 if invalid, otherwise a Texture Object usable with GL.BindTexture().</param>
/// <param name="dimension">0 if invalid, will output what was loaded (typically Texture1D/2D/3D or Cubemap)</param>
public static void LoadFromDisk( string filename, out uint texturehandle, out TextureTarget dimension )
{
#region Prep data
// invalidate whatever it was before
dimension = (TextureTarget) 0;
texturehandle = TextureLoaderParameters.OpenGLDefaultTexture;
ErrorCode GLError = ErrorCode.NoError;
_IsCompressed = false;
_Width = 0;
_Height = 0;
_Depth = 0;
_MipMapCount = 0;
_BytesForMainSurface = 0;
_BytesPerBlock = 0;
_PixelInternalFormat = PixelInternalFormat.Rgba8;
byte[] _RawDataFromFile;
#endregion
#region Try
try // Exceptions will be thrown if any Problem occurs while working on the file.
{
_RawDataFromFile = File.ReadAllBytes( @filename );
#region Translate Header to less cryptic representation
ConvertDX9Header( ref _RawDataFromFile ); // The first 128 Bytes of the file is non-image data
// start by checking if all forced flags are present. Flags indicate valid fields, but aren't written by every tool .....
if ( idString != "DDS " || // magic key
dwSize != 124 || // constant size of struct, never reused
pfSize != 32 || // constant size of struct, never reused
!CheckFlag( dwFlags, (uint) eDDSD.CAPS ) || // must know it's caps
!CheckFlag( dwFlags, (uint) eDDSD.PIXELFORMAT ) || // must know it's format
!CheckFlag( dwCaps1, (uint) eDDSCAPS.TEXTURE ) // must be a Texture
)
throw new ArgumentException( "ERROR: File has invalid signature or missing Flags." );
#region Examine Flags
if ( CheckFlag( dwFlags, (uint) eDDSD.WIDTH ) )
_Width = (int) dwWidth;
else
throw new ArgumentException( "ERROR: Flag for Width not set." );
if ( CheckFlag( dwFlags, (uint) eDDSD.HEIGHT ) )
_Height = (int) dwHeight;
else
throw new ArgumentException( "ERROR: Flag for Height not set." );
if ( CheckFlag( dwFlags, (uint) eDDSD.DEPTH ) && CheckFlag( dwCaps2, (uint) eDDSCAPS2.VOLUME ) )
{
dimension = TextureTarget.Texture3D; // image is 3D Volume
_Depth = (int) dwDepth;
throw Unfinished;
} else
{// image is 2D or Cube
if ( CheckFlag( dwCaps2, (uint) eDDSCAPS2.CUBEMAP ) )
{
dimension = TextureTarget.TextureCubeMap;
_Depth = 6;
} else
{
dimension = TextureTarget.Texture2D;
_Depth = 1;
}
}
// these flags must be set for mipmaps to be included
if ( CheckFlag( dwCaps1, (uint) eDDSCAPS.MIPMAP ) && CheckFlag( dwFlags, (uint) eDDSD.MIPMAPCOUNT ) )
_MipMapCount = (int) dwMipMapCount; // image contains MipMaps
else
_MipMapCount = 1; // only 1 main image
// Should never happen
if ( CheckFlag( dwFlags, (uint) eDDSD.PITCH ) && CheckFlag( dwFlags, (uint) eDDSD.LINEARSIZE ) )
throw new ArgumentException( "INVALID: Pitch AND Linear Flags both set. Image cannot be uncompressed and DTXn compressed at the same time." );
// This flag is set if format is uncompressed RGB RGBA etc.
if ( CheckFlag( dwFlags, (uint) eDDSD.PITCH ) )
{
// _BytesForMainSurface = (int) dwPitchOrLinearSize; // holds bytes-per-scanline for uncompressed
_IsCompressed = false;
throw Unfinished;
}
// This flag is set if format is compressed DXTn.
if ( CheckFlag( dwFlags, (uint) eDDSD.LINEARSIZE ) )
{
_BytesForMainSurface = (int) dwPitchOrLinearSize;
_IsCompressed = true;
}
#endregion Examine Flags
#region Examine Pixel Format, anything but DXTn will fail atm.
if ( CheckFlag( pfFlags, (uint) eDDPF.FOURCC ) )
switch ( (eFOURCC) pfFourCC )
{
case eFOURCC.DXT1:
_PixelInternalFormat = (PixelInternalFormat) ExtTextureCompressionS3tc.CompressedRgbS3tcDxt1Ext;
_BytesPerBlock = 8;
_IsCompressed = true;
break;
//case eFOURCC.DXT2:
case eFOURCC.DXT3:
_PixelInternalFormat = (PixelInternalFormat) ExtTextureCompressionS3tc.CompressedRgbaS3tcDxt3Ext;
_BytesPerBlock = 16;
_IsCompressed = true;
break;
//case eFOURCC.DXT4:
case eFOURCC.DXT5:
_PixelInternalFormat = (PixelInternalFormat) ExtTextureCompressionS3tc.CompressedRgbaS3tcDxt5Ext;
_BytesPerBlock = 16;
_IsCompressed = true;
break;
default:
throw Unfinished; // handle uncompressed formats
} else
throw Unfinished;
// pf*Bitmasks should be examined here
#endregion
// Works, but commented out because some texture authoring tools don't set this flag.
/* Safety Check, if file is only 1x 2D surface without mipmaps, eDDSCAPS.COMPLEX should not be set
if ( CheckFlag( dwCaps1, (uint) eDDSCAPS.COMPLEX ) )
{
if ( result == eTextureDimension.Texture2D && _MipMapCount == 1 ) // catch potential problem
Trace.WriteLine( "Warning: Image is declared complex, but contains only 1 surface." );
}*/
if ( TextureLoaderParameters.Verbose )
Trace.WriteLine( "\n" + GetDescriptionFromMemory( filename, dimension ) );
#endregion Translate Header to less cryptic representation
#region send the Texture to GL
#region Generate and Bind Handle
GL.GenTextures( 1, out texturehandle );
GL.BindTexture( dimension, texturehandle );
#endregion Generate and Bind Handle
int Cursor = HeaderSizeInBytes;
// foreach face in the cubemap, get all it's mipmaps levels. Only one iteration for Texture2D
for ( int Slices = 0 ; Slices < _Depth ; Slices++ )
{
int trueMipMapCount = _MipMapCount - 1; // TODO: triplecheck correctness
int Width = _Width;
int Height = _Height;
for ( int Level = 0 ; Level < _MipMapCount ; Level++ ) // start at base image
{
#region determine Dimensions
int BlocksPerRow = ( Width + 3 ) >> 2;
int BlocksPerColumn = ( Height + 3 ) >> 2;
int SurfaceBlockCount = BlocksPerRow * BlocksPerColumn; // // DXTn stores Texels in 4x4 blocks, a Color block is 8 Bytes, an Alpha block is 8 Bytes for DXT3/5
int SurfaceSizeInBytes = SurfaceBlockCount * _BytesPerBlock;
// this check must evaluate to false for 2D and Cube maps, or it's impossible to determine MipMap sizes.
if ( TextureLoaderParameters.Verbose && Level == 0 && _IsCompressed && _BytesForMainSurface != SurfaceSizeInBytes )
Trace.WriteLine( "Warning: Calculated byte-count of main image differs from what was read from file." );
#endregion determine Dimensions
// skip mipmaps smaller than a 4x4 Pixels block, which is the smallest DXTn unit.
if ( Width > 2 && Height > 2 )
{ // Note: there could be a potential problem with non-power-of-two cube maps
#region Prepare Array for TexImage
byte[] RawDataOfSurface = new byte[SurfaceSizeInBytes];
if ( !TextureLoaderParameters.FlipImages )
{ // no changes to the image, copy as is
Array.Copy( _RawDataFromFile, Cursor, RawDataOfSurface, 0, SurfaceSizeInBytes );
} else
{ // Turn the blocks upside down and the rows aswell, done in a single pass through all blocks
for ( int sourceColumn = 0 ; sourceColumn < BlocksPerColumn ; sourceColumn++ )
{
int targetColumn = BlocksPerColumn - sourceColumn - 1;
for ( int row = 0 ; row < BlocksPerRow ; row++ )
{
int target = ( targetColumn * BlocksPerRow + row ) * _BytesPerBlock;
int source = ( sourceColumn * BlocksPerRow + row ) * _BytesPerBlock + Cursor;
#region Swap Bytes
switch ( _PixelInternalFormat )
{
case (PixelInternalFormat) ExtTextureCompressionS3tc.CompressedRgbS3tcDxt1Ext:
// Color only
RawDataOfSurface[target + 0] = _RawDataFromFile[source + 0];
RawDataOfSurface[target + 1] = _RawDataFromFile[source + 1];
RawDataOfSurface[target + 2] = _RawDataFromFile[source + 2];
RawDataOfSurface[target + 3] = _RawDataFromFile[source + 3];
RawDataOfSurface[target + 4] = _RawDataFromFile[source + 7];
RawDataOfSurface[target + 5] = _RawDataFromFile[source + 6];
RawDataOfSurface[target + 6] = _RawDataFromFile[source + 5];
RawDataOfSurface[target + 7] = _RawDataFromFile[source + 4];
break;
case (PixelInternalFormat) ExtTextureCompressionS3tc.CompressedRgbaS3tcDxt3Ext:
// Alpha
RawDataOfSurface[target + 0] = _RawDataFromFile[source + 6];
RawDataOfSurface[target + 1] = _RawDataFromFile[source + 7];
RawDataOfSurface[target + 2] = _RawDataFromFile[source + 4];
RawDataOfSurface[target + 3] = _RawDataFromFile[source + 5];
RawDataOfSurface[target + 4] = _RawDataFromFile[source + 2];
RawDataOfSurface[target + 5] = _RawDataFromFile[source + 3];
RawDataOfSurface[target + 6] = _RawDataFromFile[source + 0];
RawDataOfSurface[target + 7] = _RawDataFromFile[source + 1];
// Color
RawDataOfSurface[target + 8] = _RawDataFromFile[source + 8];
RawDataOfSurface[target + 9] = _RawDataFromFile[source + 9];
RawDataOfSurface[target + 10] = _RawDataFromFile[source + 10];
RawDataOfSurface[target + 11] = _RawDataFromFile[source + 11];
RawDataOfSurface[target + 12] = _RawDataFromFile[source + 15];
RawDataOfSurface[target + 13] = _RawDataFromFile[source + 14];
RawDataOfSurface[target + 14] = _RawDataFromFile[source + 13];
RawDataOfSurface[target + 15] = _RawDataFromFile[source + 12];
break;
case (PixelInternalFormat) ExtTextureCompressionS3tc.CompressedRgbaS3tcDxt5Ext:
// Alpha, the first 2 bytes remain
RawDataOfSurface[target + 0] = _RawDataFromFile[source + 0];
RawDataOfSurface[target + 1] = _RawDataFromFile[source + 1];
// extract 3 bits each and flip them
GetBytesFromUInt24( ref RawDataOfSurface, (uint) target + 5, FlipUInt24( GetUInt24( ref _RawDataFromFile, (uint) source + 2 ) ) );
GetBytesFromUInt24( ref RawDataOfSurface, (uint) target + 2, FlipUInt24( GetUInt24( ref _RawDataFromFile, (uint) source + 5 ) ) );
// Color
RawDataOfSurface[target + 8] = _RawDataFromFile[source + 8];
RawDataOfSurface[target + 9] = _RawDataFromFile[source + 9];
RawDataOfSurface[target + 10] = _RawDataFromFile[source + 10];
RawDataOfSurface[target + 11] = _RawDataFromFile[source + 11];
RawDataOfSurface[target + 12] = _RawDataFromFile[source + 15];
RawDataOfSurface[target + 13] = _RawDataFromFile[source + 14];
RawDataOfSurface[target + 14] = _RawDataFromFile[source + 13];
RawDataOfSurface[target + 15] = _RawDataFromFile[source + 12];
break;
default:
throw new ArgumentException( "ERROR: Should have never arrived here! Bad _PixelInternalFormat! Should have been dealt with much earlier." );
}
#endregion Swap Bytes
}
}
}
#endregion Prepare Array for TexImage
#region Create TexImage
switch ( dimension )
{
case TextureTarget.Texture2D:
GL.CompressedTexImage2D( TextureTarget.Texture2D,
Level,
_PixelInternalFormat,
Width,
Height,
TextureLoaderParameters.Border,
SurfaceSizeInBytes,
RawDataOfSurface );
break;
case TextureTarget.TextureCubeMap:
GL.CompressedTexImage2D( TextureTarget.TextureCubeMapPositiveX + Slices,
Level,
_PixelInternalFormat,
Width,
Height,
TextureLoaderParameters.Border,
SurfaceSizeInBytes,
RawDataOfSurface );
break;
case TextureTarget.Texture1D: // Untested
case TextureTarget.Texture3D: // Untested
default:
throw new ArgumentException( "ERROR: Use DXT for 2D Images only. Cannot evaluate " + dimension );
}
GL.Finish( );
#endregion Create TexImage
#region Query Success
int width, height, internalformat, compressed;
switch ( dimension )
{
case TextureTarget.Texture1D:
case TextureTarget.Texture2D:
case TextureTarget.Texture3D:
GL.GetTexLevelParameter( dimension, Level, GetTextureParameter.TextureWidth, out width );
GL.GetTexLevelParameter( dimension, Level, GetTextureParameter.TextureHeight, out height );
GL.GetTexLevelParameter( dimension, Level, GetTextureParameter.TextureInternalFormat, out internalformat );
GL.GetTexLevelParameter( dimension, Level, GetTextureParameter.TextureCompressed, out compressed );
break;
case TextureTarget.TextureCubeMap:
GL.GetTexLevelParameter( TextureTarget.TextureCubeMapPositiveX + Slices, Level, GetTextureParameter.TextureWidth, out width );
GL.GetTexLevelParameter( TextureTarget.TextureCubeMapPositiveX + Slices, Level, GetTextureParameter.TextureHeight, out height );
GL.GetTexLevelParameter( TextureTarget.TextureCubeMapPositiveX + Slices, Level, GetTextureParameter.TextureInternalFormat, out internalformat );
GL.GetTexLevelParameter( TextureTarget.TextureCubeMapPositiveX + Slices, Level, GetTextureParameter.TextureCompressed, out compressed );
break;
default:
throw Unfinished;
}
GLError = GL.GetError( );
if ( TextureLoaderParameters.Verbose )
Trace.WriteLine( "GL: " + GLError.ToString( ) + " Level: " + Level + " DXTn: " + ( ( compressed == 1 ) ? "Yes" : "No" ) + " Frmt:" + (ExtTextureCompressionS3tc) internalformat + " " + width + "*" + height );
if ( GLError != ErrorCode.NoError || compressed == 0 || width == 0 || height == 0 || internalformat == 0 )
{
GL.DeleteTextures( 1, ref texturehandle );
throw new ArgumentException( "ERROR: Something went wrong after GL.CompressedTexImage(); Last GL Error: " + GLError.ToString( ) );
}
#endregion Query Success
} else
{
if ( trueMipMapCount > Level )
trueMipMapCount = Level - 1; // The current Level is invalid
}
#region Prepare the next MipMap level
Width /= 2;
if ( Width < 1 )
Width = 1;
Height /= 2;
if ( Height < 1 )
Height = 1;
Cursor += SurfaceSizeInBytes;
#endregion Prepare the next MipMap level
}
#region Set States properly
GL.TexParameter( dimension, (TextureParameterName) All.TextureBaseLevel, 0 );
GL.TexParameter( dimension, (TextureParameterName) All.TextureMaxLevel, trueMipMapCount );
int TexMaxLevel;
GL.GetTexParameter( dimension, GetTextureParameter.TextureMaxLevel, out TexMaxLevel );
if ( TextureLoaderParameters.Verbose )
Trace.WriteLine( "Verification: GL: " + GL.GetError( ).ToString( ) + " TextureMaxLevel: " + TexMaxLevel + ( ( TexMaxLevel == trueMipMapCount ) ? " (Correct.)" : " (Wrong!)" ) );
#endregion Set States properly
}
#region Set Texture Parameters
GL.TexParameter( dimension, TextureParameterName.TextureMinFilter, (int) TextureLoaderParameters.MinificationFilter );
GL.TexParameter( dimension, TextureParameterName.TextureMagFilter, (int) TextureLoaderParameters.MagnificationFilter );
GL.TexParameter( dimension, TextureParameterName.TextureWrapS, (int) TextureLoaderParameters.WrapModeS );
GL.TexParameter( dimension, TextureParameterName.TextureWrapT, (int) TextureLoaderParameters.WrapModeT );
GL.TexEnv( TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int) TextureLoaderParameters.EnvMode );
GLError = GL.GetError( );
if ( GLError != ErrorCode.NoError )
{
throw new ArgumentException( "Error setting Texture Parameters. GL Error: " + GLError );
}
#endregion Set Texture Parameters
// If it made it here without throwing any Exception the result is a valid Texture.
return; // success
#endregion send the Texture to GL
} catch ( Exception e )
{
dimension = (TextureTarget) 0;
texturehandle = TextureLoaderParameters.OpenGLDefaultTexture;
throw new ArgumentException( "ERROR: Exception caught when attempting to load file " + filename + ".\n" + e + "\n" + GetDescriptionFromFile( filename ) );
// return; // failure
} finally
{
_RawDataFromFile = null; // clarity, not really needed
}
#endregion Try
}
#region Helpers
private static void ConvertDX9Header( ref byte[] input )
{
UInt32 offset = 0;
idString = GetString( ref input, offset );
offset += 4;
dwSize = GetUInt32( ref input, offset );
offset += 4;
dwFlags = GetUInt32( ref input, offset );
offset += 4;
dwHeight = GetUInt32( ref input, offset );
offset += 4;
dwWidth = GetUInt32( ref input, offset );
offset += 4;
dwPitchOrLinearSize = GetUInt32( ref input, offset );
offset += 4;
dwDepth = GetUInt32( ref input, offset );
offset += 4;
dwMipMapCount = GetUInt32( ref input, offset );
offset += 4;
#if READALL
dwReserved1 = new UInt32[11]; // reserved
#endif
offset += 4 * 11;
pfSize = GetUInt32( ref input, offset );
offset += 4;
pfFlags = GetUInt32( ref input, offset );
offset += 4;
pfFourCC = GetUInt32( ref input, offset );
offset += 4;
#if READALL
pfRGBBitCount = GetUInt32( ref input, offset );
offset += 4;
pfRBitMask = GetUInt32( ref input, offset );
offset += 4;
pfGBitMask = GetUInt32( ref input, offset );
offset += 4;
pfBBitMask = GetUInt32( ref input, offset );
offset += 4;
pfABitMask = GetUInt32( ref input, offset );
offset += 4;
#else
offset += 20;
#endif
dwCaps1 = GetUInt32( ref input, offset );
offset += 4;
dwCaps2 = GetUInt32( ref input, offset );
offset += 4;
#if READALL
dwReserved2 = new UInt32[3]; // offset is 4+112 here, + 12 = 4+124
#endif
offset += 4 * 3;
}
/// <summary> Returns true if the flag is set, false otherwise</summary>
private static bool CheckFlag( uint variable, uint flag )
{
return ( variable & flag ) > 0 ? true : false;
}
private static string GetString( ref byte[] input, uint offset )
{
return "" + (char) input[offset + 0] + (char) input[offset + 1] + (char) input[offset + 2] + (char) input[offset + 3];
}
private static uint GetUInt32( ref byte[] input, uint offset )
{
return (uint) ( ( ( input[offset + 3] * 256 + input[offset + 2] ) * 256 + input[offset + 1] ) * 256 + input[offset + 0] );
}
private static uint GetUInt24( ref byte[] input, uint offset )
{
return (uint) ( ( input[offset + 2] * 256 + input[offset + 1] ) * 256 + input[offset + 0] );
}
private static void GetBytesFromUInt24( ref byte[] input, uint offset, uint splitme )
{
input[offset + 0] = (byte) ( splitme & 0x000000ff );
input[offset + 1] = (byte) ( ( splitme & 0x0000ff00 ) >> 8 );
input[offset + 2] = (byte) ( ( splitme & 0x00ff0000 ) >> 16 );
return;
}
/// <summary>DXT5 Alpha block flipping, inspired by code from Evan Hart (nVidia SDK)</summary>
private static uint FlipUInt24( uint inputUInt24 )
{
byte[][] ThreeBits = new byte[2][];
for ( int i = 0 ; i < 2 ; i++ )
ThreeBits[i] = new byte[4];
// extract 3 bits each into the array
ThreeBits[0][0] = (byte) ( inputUInt24 & BitMask );
inputUInt24 >>= 3;
ThreeBits[0][1] = (byte) ( inputUInt24 & BitMask );
inputUInt24 >>= 3;
ThreeBits[0][2] = (byte) ( inputUInt24 & BitMask );
inputUInt24 >>= 3;
ThreeBits[0][3] = (byte) ( inputUInt24 & BitMask );
inputUInt24 >>= 3;
ThreeBits[1][0] = (byte) ( inputUInt24 & BitMask );
inputUInt24 >>= 3;
ThreeBits[1][1] = (byte) ( inputUInt24 & BitMask );
inputUInt24 >>= 3;
ThreeBits[1][2] = (byte) ( inputUInt24 & BitMask );
inputUInt24 >>= 3;
ThreeBits[1][3] = (byte) ( inputUInt24 & BitMask );
// stuff 8x 3bits into 3 bytes
uint Result = 0;
Result = Result | (uint) ( ThreeBits[1][0] << 0 );
Result = Result | (uint) ( ThreeBits[1][1] << 3 );
Result = Result | (uint) ( ThreeBits[1][2] << 6 );
Result = Result | (uint) ( ThreeBits[1][3] << 9 );
Result = Result | (uint) ( ThreeBits[0][0] << 12 );
Result = Result | (uint) ( ThreeBits[0][1] << 15 );
Result = Result | (uint) ( ThreeBits[0][2] << 18 );
Result = Result | (uint) ( ThreeBits[0][3] << 21 );
return Result;
}
#endregion Helpers
#region String Representations
private static string GetDescriptionFromFile( string filename )
{
return "\n--> Header of " + filename +
"\nID: " + idString +
"\nSize: " + dwSize +
"\nFlags: " + dwFlags + " (" + (eDDSD) dwFlags + ")" +
"\nHeight: " + dwHeight +
"\nWidth: " + dwWidth +
"\nPitch: " + dwPitchOrLinearSize +
"\nDepth: " + dwDepth +
"\nMipMaps: " + dwMipMapCount +
"\n\n---PixelFormat---" + filename +
"\nSize: " + pfSize +
"\nFlags: " + pfFlags + " (" + (eDDPF) pfFlags + ")" +
"\nFourCC: " + pfFourCC + " (" + (eFOURCC) pfFourCC + ")" +
#if READALL
"\nBitcount: " + pfRGBBitCount +
"\nBitMask Red: " + pfRBitMask +
"\nBitMask Green: " + pfGBitMask +
"\nBitMask Blue: " + pfBBitMask +
"\nBitMask Alpha: " + pfABitMask +
#endif
"\n\n---Capabilities---" + filename +
"\nCaps1: " + dwCaps1 + " (" + (eDDSCAPS) dwCaps1 + ")" +
"\nCaps2: " + dwCaps2 + " (" + (eDDSCAPS2) dwCaps2 + ")";
}
private static string GetDescriptionFromMemory( string filename, TextureTarget Dimension )
{
return "\nFile: " + filename +
"\nDimension: " + Dimension +
"\nSize: " + _Width + " * " + _Height + " * " + _Depth +
"\nCompressed: " + _IsCompressed +
"\nBytes for Main Image: " + _BytesForMainSurface +
"\nMipMaps: " + _MipMapCount;
}
#endregion String Representations
}
}

View file

@ -0,0 +1,152 @@
#region --- License ---
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing details.
*/
#endregion
// TODO: Find paint program that can properly export 8/16 Bit Textures and make sure they are loaded correctly.
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
namespace Examples.TextureLoaders
{
class ImageGDI
{
public static void LoadFromDisk( string filename, out uint texturehandle, out TextureTarget dimension )
{
dimension = (TextureTarget) 0;
texturehandle = TextureLoaderParameters.OpenGLDefaultTexture;
ErrorCode GLError = ErrorCode.NoError;
Bitmap CurrentBitmap = null;
try // Exceptions will be thrown if any Problem occurs while working on the file.
{
CurrentBitmap = new Bitmap( filename );
if ( TextureLoaderParameters.FlipImages )
CurrentBitmap.RotateFlip( RotateFlipType.RotateNoneFlipY );
if ( CurrentBitmap.Height > 1 )
dimension = TextureTarget.Texture2D;
else
dimension = TextureTarget.Texture1D;
GL.GenTextures( 1, out texturehandle );
GL.BindTexture( dimension, texturehandle );
#region Load Texture
OpenTK.Graphics.OpenGL.PixelInternalFormat pif;
OpenTK.Graphics.OpenGL.PixelFormat pf;
OpenTK.Graphics.OpenGL.PixelType pt;
if (TextureLoaderParameters.Verbose)
Trace.WriteLine( "File: " + filename + " Format: " + CurrentBitmap.PixelFormat );
switch ( CurrentBitmap.PixelFormat )
{
case System.Drawing.Imaging.PixelFormat.Format8bppIndexed: // misses glColorTable setup
pif = OpenTK.Graphics.OpenGL.PixelInternalFormat.Rgb8;
pf = OpenTK.Graphics.OpenGL.PixelFormat.ColorIndex;
pt = OpenTK.Graphics.OpenGL.PixelType.Bitmap;
break;
case System.Drawing.Imaging.PixelFormat.Format16bppArgb1555:
case System.Drawing.Imaging.PixelFormat.Format16bppRgb555: // does not work
pif = OpenTK.Graphics.OpenGL.PixelInternalFormat.Rgb5A1;
pf = OpenTK.Graphics.OpenGL.PixelFormat.Bgr;
pt = OpenTK.Graphics.OpenGL.PixelType.UnsignedShort5551Ext;
break;
/* case System.Drawing.Imaging.PixelFormat.Format16bppRgb565:
pif = OpenTK.Graphics.OpenGL.PixelInternalFormat.R5G6B5IccSgix;
pf = OpenTK.Graphics.OpenGL.PixelFormat.R5G6B5IccSgix;
pt = OpenTK.Graphics.OpenGL.PixelType.UnsignedByte;
break;
*/
case System.Drawing.Imaging.PixelFormat.Format24bppRgb: // works
pif = OpenTK.Graphics.OpenGL.PixelInternalFormat.Rgb8;
pf = OpenTK.Graphics.OpenGL.PixelFormat.Bgr;
pt = OpenTK.Graphics.OpenGL.PixelType.UnsignedByte;
break;
case System.Drawing.Imaging.PixelFormat.Format32bppRgb: // has alpha too? wtf?
case System.Drawing.Imaging.PixelFormat.Canonical:
case System.Drawing.Imaging.PixelFormat.Format32bppArgb: // works
pif = OpenTK.Graphics.OpenGL.PixelInternalFormat.Rgba;
pf = OpenTK.Graphics.OpenGL.PixelFormat.Bgra;
pt = OpenTK.Graphics.OpenGL.PixelType.UnsignedByte;
break;
default:
throw new ArgumentException( "ERROR: Unsupported Pixel Format " + CurrentBitmap.PixelFormat );
}
BitmapData Data = CurrentBitmap.LockBits( new Rectangle( 0, 0, CurrentBitmap.Width, CurrentBitmap.Height ), ImageLockMode.ReadOnly, CurrentBitmap.PixelFormat );
if ( Data.Height > 1 )
{ // image is 2D
if (TextureLoaderParameters.BuildMipmapsForUncompressed)
{
throw new Exception("Cannot build mipmaps, Glu is deprecated.");
// Glu.Build2DMipmap(dimension, (int)pif, Data.Width, Data.Height, pf, pt, Data.Scan0);
}
else
GL.TexImage2D(dimension, 0, pif, Data.Width, Data.Height, TextureLoaderParameters.Border, pf, pt, Data.Scan0);
} else
{ // image is 1D
if (TextureLoaderParameters.BuildMipmapsForUncompressed)
{
throw new Exception("Cannot build mipmaps, Glu is deprecated.");
// Glu.Build1DMipmap(dimension, (int)pif, Data.Width, pf, pt, Data.Scan0);
}
else
GL.TexImage1D(dimension, 0, pif, Data.Width, TextureLoaderParameters.Border, pf, pt, Data.Scan0);
}
GL.Finish( );
GLError = GL.GetError( );
if ( GLError != ErrorCode.NoError )
{
throw new ArgumentException( "Error building TexImage. GL Error: " + GLError );
}
CurrentBitmap.UnlockBits( Data );
#endregion Load Texture
#region Set Texture Parameters
GL.TexParameter( dimension, TextureParameterName.TextureMinFilter, (int) TextureLoaderParameters.MinificationFilter );
GL.TexParameter( dimension, TextureParameterName.TextureMagFilter, (int) TextureLoaderParameters.MagnificationFilter );
GL.TexParameter( dimension, TextureParameterName.TextureWrapS, (int) TextureLoaderParameters.WrapModeS );
GL.TexParameter( dimension, TextureParameterName.TextureWrapT, (int) TextureLoaderParameters.WrapModeT );
GL.TexEnv( TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int) TextureLoaderParameters.EnvMode );
GLError = GL.GetError( );
if ( GLError != ErrorCode.NoError )
{
throw new ArgumentException( "Error setting Texture Parameters. GL Error: " + GLError );
}
#endregion Set Texture Parameters
return; // success
} catch ( Exception e )
{
dimension = (TextureTarget) 0;
texturehandle = TextureLoaderParameters.OpenGLDefaultTexture;
throw new ArgumentException( "Texture Loading Error: Failed to read file " + filename + ".\n" + e );
// return; // failure
} finally
{
CurrentBitmap = null;
}
}
}
}

View file

@ -0,0 +1,50 @@
#region --- License ---
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing details.
*/
#endregion
using System;
using OpenTK.Graphics.OpenGL;
namespace Examples.TextureLoaders
{
/// <summary>The parameters in this class have only effect on the following Texture loads.</summary>
public static class TextureLoaderParameters
{
/// <summary>(Debug Aid, should be set to false) If set to false only Errors will be printed. If set to true, debug information (Warnings and Queries) will be printed in addition to Errors.</summary>
public static bool Verbose = false;
/// <summary>Always-valid fallback parameter for GL.BindTexture (Default: 0). This number will be returned if loading the Texture failed. You can set this to a checkerboard texture or similar, which you have already loaded.</summary>
public static uint OpenGLDefaultTexture = 0;
/// <summary>Compressed formats must have a border of 0, so this is constant.</summary>
public const int Border = 0;
/// <summary>false==DirectX TexCoords, true==OpenGL TexCoords (Default: true)</summary>
public static bool FlipImages = true;
/// <summary>When enabled, will use Glu to create MipMaps for images loaded with GDI+ (Default: false)</summary>
public static bool BuildMipmapsForUncompressed = false;
/// <summary>Selects the Magnification filter for following Textures to be loaded. (Default: Nearest)</summary>
public static TextureMagFilter MagnificationFilter = TextureMagFilter.Nearest;
/// <summary>Selects the Minification filter for following Textures to be loaded. (Default: Nearest)</summary>
public static TextureMinFilter MinificationFilter = TextureMinFilter.Nearest;
/// <summary>Selects the S Wrapping for following Textures to be loaded. (Default: Repeat)</summary>
public static TextureWrapMode WrapModeS = TextureWrapMode.Repeat;
/// <summary>Selects the T Wrapping for following Textures to be loaded. (Default: Repeat)</summary>
public static TextureWrapMode WrapModeT = TextureWrapMode.Repeat;
/// <summary>Selects the Texture Environment Mode for the following Textures to be loaded. Default: Modulate)</summary>
public static TextureEnvMode EnvMode = TextureEnvMode.Modulate;
}
}