Merged latest changes from trunk.
|
@ -150,7 +150,7 @@
|
|||
<Match path="." pattern="*.cs" recurse="true"/>
|
||||
<Match path="." pattern="*.rtf" recurse="true" buildAction="EmbeddedResource" />
|
||||
<Match path="." pattern="*.resx" recurse="true" buildAction="EmbeddedResource"/>
|
||||
<Match path="../Examples/Data" pattern="^.*\.(bmp|png|jpg|txt|glsl|wav|ogg)$" useRegex="true" recurse="true" buildAction="None" copyToOutput="Always"/>
|
||||
<Match path="../Examples/Data" pattern="^.*\.(bmp|png|jpg|txt|glsl|wav|ogg|dds)$" useRegex="true" recurse="true" buildAction="None" copyToOutput="Always"/>
|
||||
<Match path="../OpenTK" pattern="OpenTK.dll.config" buildAction="None" copyToOutput="Always"/>
|
||||
<Match path="../OpenTK" pattern="OpenTK.Compatibility.dll.config" buildAction="None" copyToOutput="Always"/>
|
||||
</Files>
|
||||
|
|
|
@ -6,4 +6,6 @@
|
|||
<dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
|
||||
<dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
|
||||
<dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
|
||||
<dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
|
||||
<dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
|
||||
</configuration>
|
||||
|
|
9
Source/Examples/Data/Shaders/CubeMap_FS.glsl
Normal 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 );
|
||||
}
|
10
Source/Examples/Data/Shaders/CubeMap_VS.glsl
Normal 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 ;
|
||||
}
|
57
Source/Examples/Data/Shaders/Parallax_FS.glsl
Normal 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 );
|
||||
}
|
||||
}
|
35
Source/Examples/Data/Shaders/Parallax_VS.glsl
Normal 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);
|
||||
}
|
8
Source/Examples/Data/Shaders/Picking_FS.glsl
Normal file
|
@ -0,0 +1,8 @@
|
|||
#version 120
|
||||
|
||||
flat varying vec4 vColor;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_FragColor = vColor;
|
||||
}
|
9
Source/Examples/Data/Shaders/Picking_VS.glsl
Normal 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();
|
||||
}
|
Before Width: | Height: | Size: 104 B After Width: | Height: | Size: 104 B |
18
Source/Examples/Data/Textures/Swizzled Textures License.txt
Normal 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.
|
BIN
Source/Examples/Data/Textures/earth-cubemap.dds
Normal file
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
BIN
Source/Examples/Data/Textures/swizzled-rock-diffuse-height.dds
Normal file
BIN
Source/Examples/Data/Textures/swizzled-rock-normal-gloss.dds
Normal 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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
/*
|
||||
|
|
311
Source/Examples/OpenGL/1.1/Picking.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
311
Source/Examples/OpenGL/1.1/StencilCSG.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
155
Source/Examples/OpenGL/1.1/TextureMatrix.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) { }
|
||||
|
|
198
Source/Examples/OpenGL/1.5/DynamicVBO.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ---
|
||||
|
|
278
Source/Examples/OpenGL/GLSL/DDSCubeMap.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
374
Source/Examples/OpenGL/GLSL/SwizzledParallax.cs
Normal file
|
@ -0,0 +1,374 @@
|
|||
#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-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-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:
|
||||
string extensions = GL.GetString(StringName.Extensions);
|
||||
if ( !GL.GetString(StringName.Extensions).Contains("GL_ARB_shading_language"))
|
||||
{
|
||||
throw new NotSupportedException(String.Format("This example requires OpenGL 2.0. Found {0}. Aborting.",
|
||||
GL.GetString(StringName.Version).Substring(0, 3)));
|
||||
}
|
||||
|
||||
if (!extensions.Contains("GL_ARB_texture_compression") ||
|
||||
!extensions.Contains("GL_EXT_texture_compression_s3tc"))
|
||||
{
|
||||
throw new NotSupportedException("This example requires support for texture compression. Aborting.");
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ namespace Examples.Tests
|
|||
readonly Font TextFont = new Font(FontFamily.GenericSansSerif, 16);
|
||||
readonly Bitmap TextBitmap = new Bitmap(1024, 256);
|
||||
int texture;
|
||||
bool mouse_in_window = false;
|
||||
|
||||
public GameWindowStates()
|
||||
: base(800, 600)
|
||||
|
@ -33,6 +34,8 @@ namespace Examples.Tests
|
|||
WindowBorderChanged += delegate(object sender, EventArgs e) { UpdateText(); };
|
||||
WindowStateChanged += delegate(object sender, EventArgs e) { UpdateText(); };
|
||||
FocusedChanged += delegate(object sender, EventArgs e) { UpdateText(); };
|
||||
MouseEnter += delegate(object sender, EventArgs e) { mouse_in_window = true; UpdateText(); };
|
||||
MouseLeave += delegate(object sender, EventArgs e) { mouse_in_window = false; UpdateText(); };
|
||||
}
|
||||
|
||||
void KeyUpHandler(object sender, KeyboardKeyEventArgs e)
|
||||
|
@ -62,6 +65,7 @@ namespace Examples.Tests
|
|||
gfx.DrawString(String.Format("[1 - 4]: change WindowState (current: {0}).", this.WindowState), TextFont, Brushes.White, new PointF(0, 0));
|
||||
gfx.DrawString(String.Format("[5 - 7]: change WindowBorder (current: {0}).", this.WindowBorder), TextFont, Brushes.White, new PointF(0, TextFont.Height));
|
||||
gfx.DrawString(String.Format("Focused: {0}.", this.Focused), TextFont, Brushes.White, new PointF(0, 2 * TextFont.Height));
|
||||
gfx.DrawString(String.Format("Mouse {0} window.", mouse_in_window ? "inside" : "outside of"), TextFont, Brushes.White, new PointF(0, 3 * TextFont.Height));
|
||||
}
|
||||
|
||||
System.Drawing.Imaging.BitmapData data = TextBitmap.LockBits(new Rectangle(0, 0, TextBitmap.Width, TextBitmap.Height),
|
||||
|
|
181
Source/Examples/Shapes/Base/DrawableShape.cs
Normal 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
|
||||
}
|
||||
|
||||
}
|
36
Source/Examples/Shapes/Base/VertexStructs.cs
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
110
Source/Examples/Shapes/Capsule.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
280
Source/Examples/Shapes/ChamferCube.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
82
Source/Examples/Shapes/Helpers/Chunk.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
422
Source/Examples/Shapes/Helpers/MengerCube.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
230
Source/Examples/Shapes/Helpers/TetrahedronFace.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
27
Source/Examples/Shapes/Helpers/VboShape.cs
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
71
Source/Examples/Shapes/KochTetrahedron.cs
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
116
Source/Examples/Shapes/MengerSponge.cs
Normal 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] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,54 +1,54 @@
|
|||
#region --- License ---
|
||||
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
|
||||
* See license.txt for license info
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using OpenTK;
|
||||
|
||||
namespace Examples.Shapes
|
||||
{
|
||||
public class Plane : Shape
|
||||
{
|
||||
public Plane(int x_res, int y_res, float x_scale, float y_scale)
|
||||
{
|
||||
Vertices = new Vector3[x_res * y_res];
|
||||
Normals = new Vector3[x_res * y_res];
|
||||
Indices = new int[6 * x_res * y_res];
|
||||
Texcoords = new Vector2[x_res * y_res];
|
||||
|
||||
int i = 0;
|
||||
for (int y = -y_res / 2; y < y_res / 2; y++)
|
||||
{
|
||||
for (int x = -x_res / 2; x < x_res / 2; x++)
|
||||
{
|
||||
Vertices[i].X = x_scale * (float)x / (float)x_res;
|
||||
Vertices[i].Y = y_scale * (float)y / (float)y_res;
|
||||
Vertices[i].Z = 0;
|
||||
Normals[i].X = Normals[i].Y = 0;
|
||||
Normals[i].Z = 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (int y = 0; y < y_res - 1; y++)
|
||||
{
|
||||
for (int x = 0; x < x_res - 1; x++)
|
||||
{
|
||||
Indices[i++] = (y + 0) * x_res + x;
|
||||
Indices[i++] = (y + 1) * x_res + x;
|
||||
Indices[i++] = (y + 0) * x_res + x + 1;
|
||||
|
||||
Indices[i++] = (y + 0) * x_res + x + 1;
|
||||
Indices[i++] = (y + 1) * x_res + x;
|
||||
Indices[i++] = (y + 1) * x_res + x + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#region --- License ---
|
||||
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
|
||||
* See license.txt for license info
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using OpenTK;
|
||||
|
||||
namespace Examples.Shapes
|
||||
{
|
||||
public class Plane : Shape
|
||||
{
|
||||
public Plane(int x_res, int y_res, float x_scale, float y_scale)
|
||||
{
|
||||
Vertices = new Vector3[x_res * y_res];
|
||||
Normals = new Vector3[x_res * y_res];
|
||||
Indices = new int[6 * x_res * y_res];
|
||||
Texcoords = new Vector2[x_res * y_res];
|
||||
|
||||
int i = 0;
|
||||
for (int y = -y_res / 2; y < y_res / 2; y++)
|
||||
{
|
||||
for (int x = -x_res / 2; x < x_res / 2; x++)
|
||||
{
|
||||
Vertices[i].X = x_scale * (float)x / (float)x_res;
|
||||
Vertices[i].Y = y_scale * (float)y / (float)y_res;
|
||||
Vertices[i].Z = 0;
|
||||
Normals[i].X = Normals[i].Y = 0;
|
||||
Normals[i].Z = 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (int y = 0; y < y_res - 1; y++)
|
||||
{
|
||||
for (int x = 0; x < x_res - 1; x++)
|
||||
{
|
||||
Indices[i++] = (y + 0) * x_res + x;
|
||||
Indices[i++] = (y + 1) * x_res + x;
|
||||
Indices[i++] = (y + 0) * x_res + x + 1;
|
||||
|
||||
Indices[i++] = (y + 0) * x_res + x + 1;
|
||||
Indices[i++] = (y + 1) * x_res + x;
|
||||
Indices[i++] = (y + 1) * x_res + x + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
173
Source/Examples/Shapes/Old/SierpinskiTetrahedron.cs
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
194
Source/Examples/Shapes/SlicedHose.cs
Normal 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 );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
196
Source/Examples/Shapes/SlicedSphere.cs
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
128
Source/Examples/Shapes/TorusKnot.cs
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
711
Source/Examples/Utilities/LoaderDDS.cs
Normal 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
|
||||
}
|
||||
}
|
152
Source/Examples/Utilities/LoaderGDI.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
50
Source/Examples/Utilities/LoaderStatics.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1221,7 +1221,7 @@ namespace OpenTK.Audio.OpenAL
|
|||
|
||||
if (!AudioContext.CurrentContext.SupportsExtension("ALC_EXT_EFX"))
|
||||
{
|
||||
Debug.WriteLine("EFX Extension (ALC_EXT_EFX) is not supported(AudioContext: {0}).", AudioContext.CurrentContext.ToString());
|
||||
Debug.Print("EFX Extension (ALC_EXT_EFX) is not supported(AudioContext: {0}).", AudioContext.CurrentContext.ToString());
|
||||
return;
|
||||
}
|
||||
// Console.WriteLine("ALC_EXT_EFX found. Efx can be used.");
|
||||
|
|
|
@ -88,8 +88,14 @@ namespace OpenTK.Audio.OpenAL
|
|||
/// <param name="attrlist">a pointer to a set of attributes: ALC_FREQUENCY, ALC_MONO_SOURCES, ALC_REFRESH, ALC_STEREO_SOURCES, ALC_SYNC</param>
|
||||
/// <returns>Returns a pointer to the new context (NULL on failure). The attribute list can be NULL, or a zero terminated list of integer pairs composed of valid ALC attribute tokens and requested values.</returns>
|
||||
[DllImport(Alc.Lib, EntryPoint = "alcCreateContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity]
|
||||
unsafe static extern IntPtr sys_CreateContext([In] IntPtr device, [In] int* attrlist);
|
||||
|
||||
[CLSCompliant(false)]
|
||||
unsafe public static extern ContextHandle CreateContext([In] IntPtr device, [In] int* attrlist);
|
||||
unsafe public static ContextHandle CreateContext([In] IntPtr device, [In] int* attrlist)
|
||||
{
|
||||
return new ContextHandle(sys_CreateContext(device, attrlist));
|
||||
}
|
||||
|
||||
// ALC_API ALCcontext * ALC_APIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist );
|
||||
|
||||
/// <summary>This function creates a context using a specified device.</summary>
|
||||
|
@ -114,38 +120,63 @@ namespace OpenTK.Audio.OpenAL
|
|||
/// <param name="context">A pointer to the new context.</param>
|
||||
/// <returns>Returns True on success, or False on failure.</returns>
|
||||
[DllImport(Alc.Lib, EntryPoint = "alcMakeContextCurrent", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
|
||||
public static extern bool MakeContextCurrent([In] ContextHandle context);
|
||||
static extern bool MakeContextCurrent(IntPtr context);
|
||||
public static bool MakeContextCurrent(ContextHandle context)
|
||||
{
|
||||
return MakeContextCurrent(context.Handle);
|
||||
}
|
||||
// ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent( ALCcontext *context );
|
||||
|
||||
/// <summary>This function tells a context to begin processing. When a context is suspended, changes in OpenAL state will be accepted but will not be processed. alcSuspendContext can be used to suspend a context, and then all the OpenAL state changes can be applied at once, followed by a call to alcProcessContext to apply all the state changes immediately. In some cases, this procedure may be more efficient than application of properties in a non-suspended state. In some implementations, process and suspend calls are each a NOP.</summary>
|
||||
/// <param name="context">a pointer to the new context</param>
|
||||
[DllImport(Alc.Lib, EntryPoint = "alcProcessContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
|
||||
public static extern void ProcessContext([In] ContextHandle context);
|
||||
static extern void ProcessContext(IntPtr context);
|
||||
public static void ProcessContext(ContextHandle context)
|
||||
{
|
||||
ProcessContext(context.Handle);
|
||||
}
|
||||
// ALC_API void ALC_APIENTRY alcProcessContext( ALCcontext *context );
|
||||
|
||||
/// <summary>This function suspends processing on a specified context. When a context is suspended, changes in OpenAL state will be accepted but will not be processed. A typical use of alcSuspendContext would be to suspend a context, apply all the OpenAL state changes at once, and then call alcProcessContext to apply all the state changes at once. In some cases, this procedure may be more efficient than application of properties in a non-suspended state. In some implementations, process and suspend calls are each a NOP.</summary>
|
||||
/// <param name="context">a pointer to the context to be suspended.</param>
|
||||
[DllImport(Alc.Lib, EntryPoint = "alcSuspendContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
|
||||
public static extern void SuspendContext([In] ContextHandle context);
|
||||
static extern void SuspendContext(IntPtr context);
|
||||
public static void SuspendContext(ContextHandle context)
|
||||
{
|
||||
SuspendContext(context.Handle);
|
||||
}
|
||||
// ALC_API void ALC_APIENTRY alcSuspendContext( ALCcontext *context );
|
||||
|
||||
/// <summary>This function destroys a context.</summary>
|
||||
/// <param name="context">a pointer to the new context.</param>
|
||||
[DllImport(Alc.Lib, EntryPoint = "alcDestroyContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
|
||||
public static extern void DestroyContext([In] ContextHandle context);
|
||||
static extern void DestroyContext(IntPtr context);
|
||||
public static void DestroyContext(ContextHandle context)
|
||||
{
|
||||
DestroyContext(context.Handle);
|
||||
}
|
||||
// ALC_API void ALC_APIENTRY alcDestroyContext( ALCcontext *context );
|
||||
|
||||
/// <summary>This function retrieves the current context.</summary>
|
||||
/// <returns>Returns a pointer to the current context.</returns>
|
||||
[DllImport(Alc.Lib, EntryPoint = "alcGetCurrentContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
|
||||
public static extern ContextHandle GetCurrentContext();
|
||||
private static extern IntPtr sys_GetCurrentContext();
|
||||
|
||||
public static ContextHandle GetCurrentContext()
|
||||
{
|
||||
return new ContextHandle(sys_GetCurrentContext());
|
||||
}
|
||||
// ALC_API ALCcontext * ALC_APIENTRY alcGetCurrentContext( void );
|
||||
|
||||
/// <summary>This function retrieves a context's device pointer.</summary>
|
||||
/// <param name="context">a pointer to a context.</param>
|
||||
/// <returns>Returns a pointer to the specified context's device.</returns>
|
||||
[DllImport(Alc.Lib, EntryPoint = "alcGetContextsDevice", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
|
||||
public static extern IntPtr GetContextsDevice([In] ContextHandle context);
|
||||
static extern IntPtr GetContextsDevice(IntPtr context);
|
||||
public static IntPtr GetContextsDevice(ContextHandle context)
|
||||
{
|
||||
return GetContextsDevice(context.Handle);
|
||||
}
|
||||
// ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice( ALCcontext *context );
|
||||
|
||||
#endregion Context Management
|
||||
|
@ -393,7 +424,7 @@ namespace OpenTK.Audio.OpenAL
|
|||
/// <param name="device">a pointer to a capture device.</param>
|
||||
/// <param name="buffer">a buffer, which must be large enough to accommodate the number of samples.</param>
|
||||
/// <param name="samples">the number of samples to be retrieved.</param>
|
||||
public static void CaptureSamples<T>(IntPtr device, T[,,] buffer, int samples)
|
||||
public static void CaptureSamples<T>(IntPtr device, T[, ,] buffer, int samples)
|
||||
where T : struct
|
||||
{
|
||||
CaptureSamples(device, ref buffer[0, 0, 0], samples);
|
||||
|
|
|
@ -129,9 +129,9 @@ namespace OpenTK
|
|||
if (delegates == null)
|
||||
throw new InvalidOperationException("The specified type does not have any loadable extensions.");
|
||||
|
||||
Debug.Write("Load extensions for " + this.GetType().FullName + "... ");
|
||||
Debug.Write("Loading extensions for " + this.GetType().FullName + "... ");
|
||||
|
||||
System.Diagnostics.Stopwatch time = new System.Diagnostics.Stopwatch();
|
||||
Stopwatch time = new Stopwatch();
|
||||
time.Reset();
|
||||
time.Start();
|
||||
|
||||
|
@ -147,7 +147,7 @@ namespace OpenTK
|
|||
rebuildExtensionList = true;
|
||||
|
||||
time.Stop();
|
||||
Debug.Print("{0} extensions loaded in {1} ms.", supported, time.ElapsedMilliseconds);
|
||||
Debug.Print("{0} extensions loaded in {1} ms.", supported, time.Elapsed.TotalMilliseconds);
|
||||
time.Reset();
|
||||
}
|
||||
|
||||
|
|
|
@ -30,13 +30,14 @@ namespace OpenTK
|
|||
#region --- Fields ---
|
||||
|
||||
DisplayResolution current_resolution, original_resolution;
|
||||
List<DisplayResolution> available_resolutions = new List<DisplayResolution>();
|
||||
readonly List<DisplayResolution> available_resolutions = new List<DisplayResolution>();
|
||||
readonly IList<DisplayResolution> available_resolutions_readonly;
|
||||
bool primary;
|
||||
|
||||
static List<DisplayDevice> available_displays = new List<DisplayDevice>();
|
||||
static object display_lock = new object();
|
||||
static readonly List<DisplayDevice> available_displays = new List<DisplayDevice>();
|
||||
static readonly IList<DisplayDevice> available_displays_readonly;
|
||||
static readonly object display_lock = new object();
|
||||
static DisplayDevice primary_display;
|
||||
//static FadeEffect effect = new FadeEffect();
|
||||
|
||||
static Platform.IDisplayDeviceDriver implementation;
|
||||
|
||||
|
@ -47,6 +48,7 @@ namespace OpenTK
|
|||
static DisplayDevice()
|
||||
{
|
||||
implementation = Platform.Factory.Default.CreateDisplayDeviceDriver();
|
||||
available_displays_readonly = available_displays.AsReadOnly();
|
||||
}
|
||||
|
||||
internal DisplayDevice(DisplayResolution currentResolution, bool primary,
|
||||
|
@ -65,6 +67,8 @@ namespace OpenTK
|
|||
if (primary)
|
||||
primary_display = this;
|
||||
}
|
||||
|
||||
available_resolutions_readonly = available_resolutions.AsReadOnly();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -155,21 +159,14 @@ namespace OpenTK
|
|||
|
||||
#endregion
|
||||
|
||||
#region public DisplayResolution[] AvailableResolutions
|
||||
#region public IList<DisplayResolution> AvailableResolutions
|
||||
|
||||
/// <summary>
|
||||
/// Gets an array of OpenTK.DisplayResolution objects, which describe all available resolutions
|
||||
/// for this device.
|
||||
/// Gets the list of <see cref="DisplayResolution"/> objects available on this device.
|
||||
/// </summary>
|
||||
public DisplayResolution[] AvailableResolutions
|
||||
public IList<DisplayResolution> AvailableResolutions
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (display_lock)
|
||||
{
|
||||
return available_resolutions.ToArray();
|
||||
}
|
||||
}
|
||||
get { return available_resolutions_readonly; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -242,20 +239,14 @@ namespace OpenTK
|
|||
|
||||
#endregion
|
||||
|
||||
#region public static DisplayDevice[] AvailableDisplays
|
||||
#region public static IList<DisplayDevice> AvailableDisplays
|
||||
|
||||
/// <summary>
|
||||
/// Gets an array of OpenTK.DisplayDevice objects, which describe all available display devices.
|
||||
/// Gets the list of available <see cref="DisplayDevice"/> objects.
|
||||
/// </summary>
|
||||
public static DisplayDevice[] AvailableDisplays
|
||||
public static IList<DisplayDevice> AvailableDisplays
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (display_lock)
|
||||
{
|
||||
return available_displays.ToArray();
|
||||
}
|
||||
}
|
||||
get { return available_displays_readonly; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -448,17 +448,19 @@ namespace OpenTK
|
|||
OnUpdateFrameInternal(update_args);
|
||||
update_time = update_watch.Elapsed.TotalSeconds;
|
||||
}
|
||||
if (TargetUpdateFrequency == 0.0)
|
||||
break;
|
||||
|
||||
time = update_watch.Elapsed.TotalSeconds;
|
||||
next_update -= time;
|
||||
|
||||
// Stopwatches are not accurate over long time periods.
|
||||
// We accumlate the total elapsed time into the time variable
|
||||
// while reseting the Stopwatch frequently.
|
||||
update_watch.Reset();
|
||||
update_watch.Start();
|
||||
|
||||
if (TargetUpdateFrequency == 0.0)
|
||||
break;
|
||||
|
||||
next_update -= time;
|
||||
}
|
||||
|
||||
// Calculate statistics
|
||||
|
|
|
@ -223,8 +223,17 @@ namespace OpenTK
|
|||
/// Occurs whenever a character is typed.
|
||||
/// </summary>
|
||||
event EventHandler<KeyPressEventArgs> KeyPress;
|
||||
|
||||
//event EventHandler<EventArgs> MouseEnter;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs whenever the mouse cursor leaves the window <see cref="Bounds"/>.
|
||||
/// </summary>
|
||||
event EventHandler<EventArgs> MouseLeave;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs whenever the mouse cursor enters the window <see cref="Bounds"/>.
|
||||
/// </summary>
|
||||
event EventHandler<EventArgs> MouseEnter;
|
||||
|
||||
//event EventHandler<MouseEventArgs> MouseMove;
|
||||
//event EventHandler<MouseEventArgs> MouseWheel;
|
||||
//event EventHandler<MouseEventArgs> MouseDown;
|
||||
|
|
93
Source/OpenTK/Minimal.cs
Normal file
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenTK
|
||||
{
|
||||
// Override a number of System.* classes when compiling for
|
||||
// minimal targets (e.g. MonoTouch).
|
||||
// Note: the "overriden" classes must not be fully qualified for this to work!
|
||||
|
||||
#if IPHONE
|
||||
// System.Diagnostics.Debug
|
||||
static class Debug
|
||||
{
|
||||
public static void Write(string message) { }
|
||||
public static void Write(object obj) { }
|
||||
public static void WriteLine(string message) { }
|
||||
public static void WriteLine(object obj) { }
|
||||
public static void Print(string message) { }
|
||||
public static void Print(string format, params object[] args) { }
|
||||
public static void Indent() { }
|
||||
public static void Unindent() { }
|
||||
public static void Flush() { }
|
||||
}
|
||||
|
||||
// System.Diagnostics.Trace
|
||||
static class Trace
|
||||
{
|
||||
public static void Write(string message) { }
|
||||
public static void Write(object obj) { }
|
||||
public static void WriteLine(string message) { }
|
||||
public static void WriteLine(object obj) { }
|
||||
public static void Indent() { }
|
||||
public static void Unindent() { }
|
||||
public static void Flush() { }
|
||||
}
|
||||
|
||||
// System.Diagnostics.Stopwatch
|
||||
sealed class Stopwatch
|
||||
{
|
||||
DateTime start, stop;
|
||||
bool running;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
start = stop = DateTime.MinValue;
|
||||
running = false;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
start = DateTime.Now;
|
||||
running = true;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
stop = DateTime.Now;
|
||||
running = false;
|
||||
}
|
||||
|
||||
public TimeSpan Elapsed
|
||||
{
|
||||
get
|
||||
{
|
||||
if (running)
|
||||
return TimeSpan.FromTicks(DateTime.Now.Ticks - start.Ticks);
|
||||
else
|
||||
return TimeSpan.FromTicks(stop.Ticks - start.Ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// System.Xml.XmlIgnoreAttribute
|
||||
class XmlIgnoreAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
// System.ComponentModel.EditorBrowrableAttribute
|
||||
class EditorBrowsableAttribute : Attribute
|
||||
{
|
||||
public EditorBrowsableAttribute(EditorBrowsableState state) { }
|
||||
}
|
||||
|
||||
// System.ComponentModel.EditorBrowsableState
|
||||
enum EditorBrowsableState
|
||||
{
|
||||
Always = 0,
|
||||
Never = 1,
|
||||
Advanced = 2,
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -565,6 +565,16 @@ namespace OpenTK
|
|||
/// </summary>
|
||||
public event EventHandler<EventArgs> Move;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs whenever the mouse cursor enters the window <see cref="Bounds"/>.
|
||||
/// </summary>
|
||||
public event EventHandler<EventArgs> MouseEnter;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs whenever the mouse cursor leaves the window <see cref="Bounds"/>.
|
||||
/// </summary>
|
||||
public event EventHandler<EventArgs> MouseLeave;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs whenever the window is resized.
|
||||
/// </summary>
|
||||
|
@ -747,6 +757,32 @@ namespace OpenTK
|
|||
|
||||
#endregion
|
||||
|
||||
#region OnMouseEnter
|
||||
|
||||
/// <summary>
|
||||
/// Called whenever the mouse cursor reenters the window <see cref="Bounds"/>.
|
||||
/// </summary>
|
||||
/// <param name="e">Not used.</param>
|
||||
protected virtual void OnMouseEnter(EventArgs e)
|
||||
{
|
||||
if (MouseEnter != null) MouseEnter(this, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region OnMouseLeave
|
||||
|
||||
/// <summary>
|
||||
/// Called whenever the mouse cursor leaves the window <see cref="Bounds"/>.
|
||||
/// </summary>
|
||||
/// <param name="e">Not used.</param>
|
||||
protected virtual void OnMouseLeave(EventArgs e)
|
||||
{
|
||||
if (MouseLeave != null) MouseLeave(this, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region OnResize
|
||||
|
||||
/// <summary>
|
||||
|
@ -875,6 +911,18 @@ namespace OpenTK
|
|||
|
||||
#endregion
|
||||
|
||||
#region OnMouseEnterInternal
|
||||
|
||||
private void OnMouseEnterInternal(object sender, EventArgs e) { OnMouseEnter(e); }
|
||||
|
||||
#endregion
|
||||
|
||||
#region OnMouseLeaveInternal
|
||||
|
||||
private void OnMouseLeaveInternal(object sender, EventArgs e) { OnMouseLeave(e); }
|
||||
|
||||
#endregion
|
||||
|
||||
#region OnMoveInternal
|
||||
|
||||
private void OnMoveInternal(object sender, EventArgs e) { OnMove(e); }
|
||||
|
@ -933,6 +981,8 @@ namespace OpenTK
|
|||
implementation.FocusedChanged += OnFocusedChangedInternal;
|
||||
implementation.IconChanged += OnIconChangedInternal;
|
||||
implementation.KeyPress += OnKeyPressInternal;
|
||||
implementation.MouseEnter += OnMouseEnterInternal;
|
||||
implementation.MouseLeave += OnMouseLeaveInternal;
|
||||
implementation.Move += OnMoveInternal;
|
||||
implementation.Resize += OnResizeInternal;
|
||||
implementation.TitleChanged += OnTitleChangedInternal;
|
||||
|
@ -949,6 +999,8 @@ namespace OpenTK
|
|||
implementation.FocusedChanged -= OnFocusedChangedInternal;
|
||||
implementation.IconChanged -= OnIconChangedInternal;
|
||||
implementation.KeyPress -= OnKeyPressInternal;
|
||||
implementation.MouseEnter -= OnMouseEnterInternal;
|
||||
implementation.MouseLeave -= OnMouseLeaveInternal;
|
||||
implementation.Move -= OnMoveInternal;
|
||||
implementation.Resize -= OnResizeInternal;
|
||||
implementation.TitleChanged -= OnTitleChangedInternal;
|
||||
|
|
|
@ -6,4 +6,6 @@
|
|||
<dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
|
||||
<dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
|
||||
<dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
|
||||
<dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
|
||||
<dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
|
||||
</configuration>
|
||||
|
|
|
@ -954,6 +954,10 @@ namespace OpenTK.Platform.MacOS
|
|||
|
||||
public event EventHandler<KeyPressEventArgs> KeyPress;
|
||||
|
||||
public event EventHandler<EventArgs> MouseEnter;
|
||||
|
||||
public event EventHandler<EventArgs> MouseLeave;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -928,6 +928,18 @@ namespace OpenTK.Platform.Windows
|
|||
|
||||
#region Input functions
|
||||
|
||||
[DllImport("user32.dll", SetLastError=true)]
|
||||
public static extern BOOL TrackMouseEvent(ref TrackMouseEventStructure lpEventTrack);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
|
||||
public static extern bool ReleaseCapture();
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
|
||||
public static extern IntPtr SetCapture(IntPtr hwnd);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
|
||||
public static extern IntPtr GetCapture();
|
||||
|
||||
#region Async input
|
||||
|
||||
#region GetCursorPos
|
||||
|
@ -2755,6 +2767,20 @@ namespace OpenTK.Platform.Windows
|
|||
|
||||
#endregion
|
||||
|
||||
#region TrackMouseEventStructure
|
||||
|
||||
struct TrackMouseEventStructure
|
||||
{
|
||||
public DWORD Size;
|
||||
public TrackMouseEventFlags Flags;
|
||||
public HWND TrackWindowHandle;
|
||||
public DWORD HoverTime;
|
||||
|
||||
public static readonly int SizeInBytes = Marshal.SizeOf(typeof(TrackMouseEventStructure));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- Enums ---
|
||||
|
@ -4063,6 +4089,20 @@ namespace OpenTK.Platform.Windows
|
|||
|
||||
#endregion
|
||||
|
||||
#region TrackMouseEventFlags
|
||||
|
||||
[Flags]
|
||||
enum TrackMouseEventFlags : uint
|
||||
{
|
||||
HOVER = 0x00000001,
|
||||
LEAVE = 0x00000002,
|
||||
NONCLIENT = 0x00000010,
|
||||
QUERY = 0x40000000,
|
||||
CANCEL = 0x80000000,
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- Callbacks ---
|
||||
|
|
|
@ -131,6 +131,8 @@ namespace OpenTK.Platform.Windows
|
|||
|
||||
keyboards.Add(keyboard);
|
||||
mice.Add(mouse);
|
||||
|
||||
EnableMouseLeaveNotifications();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -141,7 +143,7 @@ namespace OpenTK.Platform.Windows
|
|||
|
||||
IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
bool mouse_about_to_enter = false;
|
||||
bool mouse_left = false;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
|
@ -289,27 +291,26 @@ namespace OpenTK.Platform.Windows
|
|||
KeyPress(this, key_press);
|
||||
break;
|
||||
|
||||
//case WindowMessage.MOUSELEAVE:
|
||||
// Cursor.Current = Cursors.Default;
|
||||
// break;
|
||||
|
||||
//case WindowMessage.MOUSE_ENTER:
|
||||
// Cursor.Current = Cursors.Default;
|
||||
// break;
|
||||
|
||||
// Mouse events:
|
||||
case WindowMessage.NCMOUSEMOVE:
|
||||
mouse_about_to_enter = true; // Used to simulate a mouse enter event.
|
||||
break;
|
||||
|
||||
case WindowMessage.MOUSEMOVE:
|
||||
mouse.Position = new System.Drawing.Point(
|
||||
System.Drawing.Point point = new System.Drawing.Point(
|
||||
(int)(lParam.ToInt32() & 0x0000FFFF),
|
||||
(int)(lParam.ToInt32() & 0xFFFF0000) >> 16);
|
||||
if (mouse_about_to_enter)
|
||||
mouse.Position = point;
|
||||
{
|
||||
//Cursor.Current = Cursors.Default;
|
||||
mouse_about_to_enter = false;
|
||||
Rectangle rect;
|
||||
Functions.GetClientRect(window.WindowHandle, out rect);
|
||||
if (!rect.ToRectangle().Contains(point))
|
||||
{
|
||||
Functions.ReleaseCapture();
|
||||
if (MouseLeave != null)
|
||||
MouseLeave(this, EventArgs.Empty);
|
||||
}
|
||||
else if (Functions.GetCapture() != window.WindowHandle)
|
||||
{
|
||||
Functions.SetCapture(window.WindowHandle);
|
||||
if (MouseEnter != null)
|
||||
MouseEnter(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -619,6 +620,18 @@ namespace OpenTK.Platform.Windows
|
|||
|
||||
#endregion
|
||||
|
||||
void EnableMouseLeaveNotifications()
|
||||
{
|
||||
TrackMouseEventStructure tme = new TrackMouseEventStructure();
|
||||
tme.Size = TrackMouseEventStructure.SizeInBytes;
|
||||
tme.Flags |= TrackMouseEventFlags.LEAVE;
|
||||
tme.TrackWindowHandle = child_window.WindowHandle;
|
||||
tme.HoverTime = -1; // HOVER_DEFAULT
|
||||
if (!Functions.TrackMouseEvent(ref tme))
|
||||
Debug.Print("[Error] Failed to enable mouse event tracking. Error: {0}",
|
||||
Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region INativeWindow Members
|
||||
|
@ -1052,6 +1065,10 @@ namespace OpenTK.Platform.Windows
|
|||
public event EventHandler<EventArgs> WindowStateChanged;
|
||||
|
||||
public event EventHandler<KeyPressEventArgs> KeyPress;
|
||||
|
||||
public event EventHandler<EventArgs> MouseEnter;
|
||||
|
||||
public event EventHandler<EventArgs> MouseLeave;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -142,7 +142,8 @@ namespace OpenTK.Platform.X11
|
|||
window.EventMask = EventMask.StructureNotifyMask | EventMask.SubstructureNotifyMask | EventMask.ExposureMask |
|
||||
EventMask.KeyReleaseMask | EventMask.KeyPressMask |
|
||||
EventMask.PointerMotionMask | EventMask.FocusChangeMask |
|
||||
EventMask.ButtonPressMask | EventMask.ButtonReleaseMask;
|
||||
EventMask.ButtonPressMask | EventMask.ButtonReleaseMask |
|
||||
EventMask.EnterWindowMask | EventMask.LeaveWindowMask;
|
||||
attributes.event_mask = (IntPtr)window.EventMask;
|
||||
|
||||
uint mask = (uint)SetWindowValuemask.ColorMap | (uint)SetWindowValuemask.EventMask |
|
||||
|
@ -678,6 +679,16 @@ namespace OpenTK.Platform.X11
|
|||
FocusedChanged(this, EventArgs.Empty);
|
||||
}
|
||||
break;
|
||||
|
||||
case XEventName.LeaveNotify:
|
||||
if (MouseLeave != null)
|
||||
MouseLeave(this, EventArgs.Empty);
|
||||
break;
|
||||
|
||||
case XEventName.EnterNotify:
|
||||
if (MouseEnter != null)
|
||||
MouseEnter(this, EventArgs.Empty);
|
||||
break;
|
||||
|
||||
default:
|
||||
//Debug.WriteLine(String.Format("{0} event was not handled", e.type));
|
||||
|
@ -1092,6 +1103,10 @@ namespace OpenTK.Platform.X11
|
|||
public event EventHandler<EventArgs> WindowStateChanged;
|
||||
|
||||
public event EventHandler<KeyPressEventArgs> KeyPress;
|
||||
|
||||
public event EventHandler<EventArgs> MouseEnter;
|
||||
|
||||
public event EventHandler<EventArgs> MouseLeave;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|