Blame |
Last modification |
View Log
| RSS feed
using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
namespace Examples
.Tutorial
{
[Example
("VBO Dynamic", ExampleCategory
.OpenGL,
"1.x",
4, Documentation
= "VBODynamic")]
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);
}
}
}
}