196 lines
No EOL
7.8 KiB
C#
196 lines
No EOL
7.8 KiB
C#
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
|
|
static int MaxParticleCount = 2000;
|
|
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.25f...+0.25f]
|
|
// that's slow enough so you can see particles 'disappear' when they are respawned
|
|
temp.X = (float) ( ( rnd.NextDouble( ) - 0.5 ) * 0.5f );
|
|
temp.Y = (float) ( ( rnd.NextDouble( ) - 0.5 ) * 0.5f );
|
|
temp.Z = (float) ( ( rnd.NextDouble( ) - 0.5 ) * 0.5f );
|
|
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.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 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 += (uint)Math.Max(ParticleAttributes[i].Direction.LengthFast * 10, 1);
|
|
Vector3.Multiply( 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())
|
|
{
|
|
Utilities.SetWindowTitle(example);
|
|
example.Run(60.0, 0.0);
|
|
}
|
|
}
|
|
}
|
|
} |