diff --git a/Examples/BasicExamples/RotatingTexturedCubeExample.cs b/Examples/BasicExamples/RotatingTexturedCubeExample.cs new file mode 100644 index 0000000..739f4d3 --- /dev/null +++ b/Examples/BasicExamples/RotatingTexturedCubeExample.cs @@ -0,0 +1,134 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using Examples.Shaders; +using ObjectTK.Buffers; +using ObjectTK.Shaders; +using ObjectTK.Textures; +using ObjectTK.Tools.Shapes; +using OpenTK; +using OpenTK.Graphics.OpenGL; +using OpenTK.Input; + +namespace Examples.BasicExamples +{ + [ExampleProject("Rotating textured cube rendering")] + public class RotatingTexturedCubeExample + : ExampleWindow + { + private Texture2D _texture; + + private SimpleTextureProgram _textureProgram; + + private TexturedCube _cube; + private VertexArray _cubeVao; + + private Matrix4 _baseView; + private Matrix4 _objectView; + + private Vector3[] _rotateVectors = new[] { Vector3.Zero, Vector3.UnitX, Vector3.UnitY, Vector3.UnitZ, Vector3.One }; + private const int _defaultRotateIndex = 4; + + private int _rotateIndex = _defaultRotateIndex; + private readonly Stopwatch _stopwatch = new Stopwatch(); + + public RotatingTexturedCubeExample() + { + Load += OnLoad; + RenderFrame += OnRenderFrame; + KeyDown += OnKeyDown; + } + + private void OnKeyDown(object sender, KeyboardKeyEventArgs e) + { + switch (e.Key) + { + case Key.R: + _objectView = _baseView = Matrix4.Identity; + _rotateIndex = _defaultRotateIndex; + _stopwatch.Restart(); + break; + + case Key.Space: + _baseView = _objectView; + _rotateIndex = (_rotateIndex + 1) % _rotateVectors.Length; + _stopwatch.Restart(); + break; + + case Key.Number0: + case Key.Number1: + case Key.Number2: + case Key.Number3: + case Key.Number4: + _baseView = _objectView; + _rotateIndex = (e.Key - Key.Number0) % _rotateVectors.Length; + _stopwatch.Restart(); + break; + } + } + + private void OnLoad(object sender, EventArgs e) + { + // load texture from file + using (var bitmap = new Bitmap("Data/Textures/crate.png")) + { + BitmapTexture.CreateCompatible(bitmap, out _texture); + _texture.LoadBitmap(bitmap); + } + + // initialize shaders + _textureProgram = ProgramFactory.Create(); + + // initialize cube object and base view matrix + _objectView = _baseView = Matrix4.Identity; + + // initialize demonstration geometry + _cube = new TexturedCube(); + _cube.UpdateBuffers(); + + // set up vertex attributes for the quad + _cubeVao = new VertexArray(); + _cubeVao.Bind(); + _cubeVao.BindAttribute(_textureProgram.InPosition, _cube.VertexBuffer); + _cubeVao.BindAttribute(_textureProgram.InTexCoord, _cube.TexCoordBuffer); + + // Enable culling, our cube vertices are defined inside out, so we flip them + GL.Enable(EnableCap.CullFace); + GL.CullFace(CullFaceMode.Back); + + // initialize camera position + Camera.DefaultState.Position = new Vector3(0, 0, 4); + Camera.ResetToDefault(); + + // set nice clear color + GL.ClearColor(Color.MidnightBlue); + + _stopwatch.Restart(); + } + + private void OnRenderFrame(object sender, OpenTK.FrameEventArgs e) + { + // set up viewport + GL.Viewport(0, 0, Width, Height); + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + SetupPerspective(); + + // determinate object view rotation vectors and apply them + _objectView = _baseView; + var rotation = _rotateVectors[_rotateIndex]; + if (rotation != Vector3.Zero) + _objectView *= Matrix4.CreateFromAxisAngle(_rotateVectors[_rotateIndex], (float)(_stopwatch.Elapsed.TotalSeconds * 1.0)); + + // set transformation matrix + _textureProgram.Use(); + _textureProgram.ModelViewProjectionMatrix.Set(_objectView * ModelView * Projection); + + // render cube with texture + _cubeVao.Bind(); + _cubeVao.DrawArrays(_cube.DefaultMode, 0, _cube.VertexBuffer.ElementCount); + + // swap buffers + SwapBuffers(); + } + } +} diff --git a/Examples/Data/Textures/crate.png b/Examples/Data/Textures/crate.png new file mode 100644 index 0000000..819d8d4 Binary files /dev/null and b/Examples/Data/Textures/crate.png differ diff --git a/Examples/Examples.csproj b/Examples/Examples.csproj index 5c40aca..2490c61 100644 --- a/Examples/Examples.csproj +++ b/Examples/Examples.csproj @@ -50,6 +50,7 @@ + @@ -106,6 +107,7 @@ + diff --git a/ObjectTK.Tools/ObjectTK.Tools.csproj b/ObjectTK.Tools/ObjectTK.Tools.csproj index 1cfb197..6b8226a 100644 --- a/ObjectTK.Tools/ObjectTK.Tools.csproj +++ b/ObjectTK.Tools/ObjectTK.Tools.csproj @@ -61,6 +61,7 @@ + diff --git a/ObjectTK.Tools/Shapes/TexturedCube.cs b/ObjectTK.Tools/Shapes/TexturedCube.cs new file mode 100644 index 0000000..cec25d5 --- /dev/null +++ b/ObjectTK.Tools/Shapes/TexturedCube.cs @@ -0,0 +1,45 @@ +// +// TexturedCube.cs +// +// Copyright (C) 2018 OpenTK +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. +// + +using OpenTK; +using OpenTK.Graphics.OpenGL; +using System.Linq; + +namespace ObjectTK.Tools.Shapes +{ + public class TexturedCube + : TexturedShape + { + public TexturedCube() + { + DefaultMode = PrimitiveType.Triangles; + + var quad_uv_map = new[] + { + new Vector2(0, 0), + new Vector2(0, 1), + new Vector2(1, 1), + new Vector2(1, 1), + new Vector2(1, 0), + new Vector2(0, 0), + }; + + // use default cube + using (var cube = new Cube()) + { + // Cube uses indexed vertices, TexturedShape assumes a flat vertices array + // So we need to assemble the missing vertices ourself + Vertices = cube.Indices.Select(idx => cube.Vertices[idx]).ToArray(); + + // Use predefined uv texture mapping for vertices + TexCoords = Enumerable.Range(0, Vertices.Length).Select(i => quad_uv_map[i % quad_uv_map.Length]).ToArray(); + } + } + } +}