refractor

This commit is contained in:
zyb3rwolfi 2025-11-11 15:35:10 +00:00
parent 3cada23149
commit 8d46d85df0
5 changed files with 384 additions and 30 deletions

132
TheRepo/TheLabs/Mesh.cs Normal file
View File

@ -0,0 +1,132 @@
namespace TheLabs;
using LearnOpenTK.Common;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using OpenTK.Windowing.Desktop;
using StbImageSharp;
public class Mesh : IDisposable
{
private readonly int _vao;
private readonly int _vbo;
private readonly int _ebo;
private readonly int _vertexCount;
private readonly bool _useIndices;
// A flexible way to define vertex layout
// (Could be an enum or a struct)
public enum VertexLayout { PosColor, PosTex }
public Mesh(float[] vertices, uint[] indices, VertexLayout layout)
{
_vertexCount = indices.Length;
_useIndices = true;
_vao = GL.GenVertexArray();
GL.BindVertexArray(_vao);
_vbo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo);
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);
_ebo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _ebo);
GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(uint), indices, BufferUsageHint.StaticDraw);
// --- Set up Vertex Attributes based on layout ---
if (layout == VertexLayout.PosColor)
{
// layout(location = 0) in shader: vec3 position
var stride = 7 * sizeof(float);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
GL.EnableVertexAttribArray(0);
// layout(location = 1) in shader: vec4 color
GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
GL.EnableVertexAttribArray(1);
}
else if (layout == VertexLayout.PosTex)
{
// layout(location = 0) in shader: vec3 position
var stride = 5 * sizeof(float);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
GL.EnableVertexAttribArray(0);
// layout(location = 1) in shader: vec2 texCoord
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
GL.EnableVertexAttribArray(1);
}
// ... (you could add more layouts)
GL.BindVertexArray(0);
}
// Constructor for non-indexed drawing (like your Circle)
public Mesh(float[] vertices, VertexLayout layout)
{
// Calculate vertex count based on stride
if (layout == VertexLayout.PosColor)
_vertexCount = vertices.Length / 7;
else // PosTex
_vertexCount = vertices.Length / 5;
_useIndices = false;
_ebo = 0; // No EBO
_vao = GL.GenVertexArray();
GL.BindVertexArray(_vao);
_vbo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo);
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);
// --- Set up Vertex Attributes based on layout ---
if (layout == VertexLayout.PosColor)
{
// layout(location = 0) in shader: vec3 position
var stride = 7 * sizeof(float);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
GL.EnableVertexAttribArray(0);
// layout(location = 1) in shader: vec4 color
GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
GL.EnableVertexAttribArray(1);
}
else if (layout == VertexLayout.PosTex)
{
// layout(location = 0) in shader: vec3 position
var stride = 5 * sizeof(float);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
GL.EnableVertexAttribArray(0);
// layout(location = 1) in shader: vec2 texCoord
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
GL.EnableVertexAttribArray(1);
}
GL.BindVertexArray(0);
}
// Draw the mesh. Notice it doesn't know about shaders or matrices!
public void Draw()
{
GL.BindVertexArray(_vao);
if (_useIndices)
{
GL.DrawElements(PrimitiveType.Triangles, _vertexCount, DrawElementsType.UnsignedInt, 0);
}
else
{
// For your Circle (which used TriangleFan)
GL.DrawArrays(PrimitiveType.TriangleFan, 0, _vertexCount);
}
}
public void Dispose()
{
GL.DeleteBuffer(_vbo);
GL.DeleteBuffer(_ebo);
GL.DeleteVertexArray(_vao);
}
}

View File

@ -16,12 +16,15 @@ namespace TheLabs
// Negative Y coordinates move to the bottom, positive Y move to the top. // Negative Y coordinates move to the bottom, positive Y move to the top.
// OpenGL only supports rendering in 3D, so to create a flat triangle, the Z coordinate will be kept as 0. // OpenGL only supports rendering in 3D, so to create a flat triangle, the Z coordinate will be kept as 0.
private Cube _cube;
private TexturedCube _texturedCube;
private Circle _circle;
private Cylinder _cylinder;
private Shader _shader; private Shader _shader;
// - Resources that only need to be created once
private Mesh _cubeMesh;
private Texture _cubeTexture;
private float _rotation; private float _rotation;
// -- Scene Objects
private RenderObject _cubeObject;
public MyExampleWindow(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings) public MyExampleWindow(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings)
: base(gameWindowSettings, nativeWindowSettings) : base(gameWindowSettings, nativeWindowSettings)
@ -33,20 +36,29 @@ namespace TheLabs
{ {
// This is called when the window is created and is where we can set up OpenGL resources. // This is called when the window is created and is where we can set up OpenGL resources.
base.OnLoad(); base.OnLoad();
string shaderVertPath = "Shaders/shader.vert";
string texturePath = "Textures/placeholder.png";
if (!File.Exists(shaderVertPath))
{
throw new FileNotFoundException($"The shader file was not found at: {Path.GetFullPath(shaderVertPath)}");
}
if (!File.Exists(texturePath))
{
throw new FileNotFoundException($"The texture file was not found at: {Path.GetFullPath(texturePath)}");
}
//GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); //GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
// Set The background color to a nice blue. // Set The background color to a nice blue.
GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f);
// Enable depth buffering.
GL.Enable(EnableCap.DepthTest); GL.Enable(EnableCap.DepthTest);
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
// Create and compile our shader program from the shader source files
_shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag"); _shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");
// Create a cube
// Use the shader program. This is similar to "activating" the shader program.
_shader.Use();
GL.Uniform1(GL.GetUniformLocation(_shader.Handle, "uTexture"), 0);
_cubeMesh = ShapeFactory.CreateTexturedCube();
_cubeTexture = new Texture("Textures/placeholder.png");
_cubeObject = new RenderObject(_cubeMesh, _shader, _cubeTexture);
_cubeObject.Position = new Vector3(-0.75f, 0.0f, 0.0f);
} }
// Now that initialization is done, let's create our render loop. // Now that initialization is done, let's create our render loop.
@ -56,44 +68,33 @@ namespace TheLabs
base.OnRenderFrame(e); base.OnRenderFrame(e);
// Clear the color buffer and the depth buffer // Clear the color buffer and the depth buffer
GL.Clear(ClearBufferMask.DepthBufferBit | ClearBufferMask.ColorBufferBit); GL.Clear(ClearBufferMask.DepthBufferBit | ClearBufferMask.ColorBufferBit);
// Create the model, view, and projection matrices _cubeObject.Rotation = Quaternion.FromEulerAngles(_rotation * 0.5f, _rotation, 0); //
Matrix4 model = Matrix4.CreateRotationY(_rotation) * Matrix4.CreateRotationX(_rotation * 0.5f);
// --- Set up Camera ---
Matrix4 view = Matrix4.CreateTranslation(0.0f, 0.0f, -3.0f); Matrix4 view = Matrix4.CreateTranslation(0.0f, 0.0f, -3.0f);
Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView( Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView(
MathHelper.DegreesToRadians(45f), MathHelper.DegreesToRadians(45f),
Size.X / (float)Size.Y, Size.X / (float)Size.Y,
0.1f, 0.1f,
100.0f 100.0f
); );
_cubeObject.Draw(view, projection);
// Draw the cube
//_cube = new Cube();
//_cube.Draw(_shader, view, projection, _rotation);
//_circle.Draw(_shader, view, projection, model);
//_cylinder.Draw(_shader, model, view, projection);
_texturedCube = new TexturedCube();
_texturedCube.Draw(_shader, view, projection, _rotation);
SwapBuffers(); SwapBuffers();
GL.GetError();
} }
protected override void OnUpdateFrame(FrameEventArgs e) protected override void OnUpdateFrame(FrameEventArgs e)
{ {
base.OnUpdateFrame(e); base.OnUpdateFrame(e);
_rotation += (float)e.Time;
var input = KeyboardState; var input = KeyboardState;
if (input.IsKeyDown(Keys.Escape)) if (input.IsKeyDown(Keys.Escape))
{ {
Close(); Close();
} }
if (input.IsKeyDown(Keys.R))
{
_rotation += 0.8f * (float)e.Time; // Update rotation only when the condition is met
} else if (input.IsKeyDown(Keys.T))
{
_rotation -= 0.8f * (float)e.Time; // Update rotation only when the condition is met
}
} }
protected override void OnResize(ResizeEventArgs e) protected override void OnResize(ResizeEventArgs e)

View File

@ -0,0 +1,42 @@
using LearnOpenTK.Common;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
namespace TheLabs;
public class RenderObject
{
public Mesh Mesh;
public Shader Shader;
public Texture Texture;
public Vector3 Position = Vector3.Zero;
public Quaternion Rotation = Quaternion.Identity;
public Vector3 Scale = Vector3.One;
public RenderObject(Mesh mesh, Shader shader, Texture texture)
{
Mesh = mesh;
Shader = shader;
Texture = texture;
}
public void Draw(Matrix4 view, Matrix4 projection)
{
// 1. Activate Shader
Shader.Use();
Shader.SetInt("uTexture", 0);
// 2. Bind Texture
Texture.Use(); // Assumes you have a Texture class
// 3. Calculate Model Matrix
Matrix4 model = Matrix4.CreateScale(Scale) * Matrix4.CreateFromQuaternion(Rotation) * Matrix4.CreateTranslation(Position);
// 4. Set Uniforms
Shader.SetMatrix4("model", model);
Shader.SetMatrix4("view", view);
Shader.SetMatrix4("projection", projection);
// 5. Tell the Mesh to draw itself
Mesh.Draw();
}
}

View File

@ -0,0 +1,118 @@
namespace TheLabs;
public static class ShapeFactory
{
public static Mesh CreateTexturedCube()
{
float[] vertices = {
// Front face (z = +0.5)
-0.5f, -0.5f, 0.5f, 0f, 0f, // Bottom-left
0.5f, -0.5f, 0.5f, 1f, 0f, // Bottom-right
0.5f, 0.5f, 0.5f, 1f, 1f, // Top-right
-0.5f, 0.5f, 0.5f, 0f, 1f, // Top-left
// Back face (z = -0.5)
-0.5f, -0.5f, -0.5f, 1f, 0f, // Bottom-left
0.5f, -0.5f, -0.5f, 0f, 0f, // Bottom-right
0.5f, 0.5f, -0.5f, 0f, 1f, // Top-right
-0.5f, 0.5f, -0.5f, 1f, 1f, // Top-left
// Left face (x = -0.5)
-0.5f, -0.5f, -0.5f, 0f, 0f, // Bottom-left
-0.5f, -0.5f, 0.5f, 1f, 0f, // Bottom-right
-0.5f, 0.5f, 0.5f, 1f, 1f, // Top-right
-0.5f, 0.5f, -0.5f, 0f, 1f, // Top-left
// Right face (x = +0.5)
0.5f, -0.5f, -0.5f, 1f, 0f, // Bottom-left
0.5f, -0.5f, 0.5f, 0f, 0f, // Bottom-right
0.5f, 0.5f, 0.5f, 0f, 1f, // Top-right
0.5f, 0.5f, -0.5f, 1f, 1f, // Top-left
// Top face (y = +0.5)
-0.5f, 0.5f, -0.5f, 0f, 1f, // Bottom-left
0.5f, 0.5f, -0.5f, 1f, 1f, // Bottom-right
0.5f, 0.5f, 0.5f, 1f, 0f, // Top-right
-0.5f, 0.5f, 0.5f, 0f, 0f, // Top-left
// Bottom face (y = -0.5)
-0.5f, -0.5f, -0.5f, 1f, 1f, // Bottom-left
0.5f, -0.5f, -0.5f, 0f, 1f, // Bottom-right
0.5f, -0.5f, 0.5f, 0f, 0f, // Top-right
-0.5f, -0.5f, 0.5f, 1f, 0f, // Top-left
};
uint[] indices = {
// Front face
0, 1, 2,
0, 2, 3,
// Back face
4, 5, 6,
4, 6, 7,
// Left face
8, 9, 10,
8, 10, 11,
// Right face
12, 13, 14,
12, 14, 15,
// Top face
16, 17, 18,
16, 18, 19,
// Bottom face
20, 21, 22,
20, 22, 23
};
return new Mesh(vertices, indices, Mesh.VertexLayout.PosTex);
}
public static Mesh CreateColorCube()
{
float[] vertices = {
// Front face (z = +0.5)
-0.5f, -0.5f, 0.5f, 1f, 0f, 0f, 1f, // Bottom-left
0.5f, -0.5f, 0.5f, 1f, 0f, 0f, 1f, // Bottom-right
0.5f, 0.5f, 0.5f, 0f, 0f, 0f, 1f, // Top-right
-0.5f, 0.5f, 0.5f, 1f, 0f, 0f, 1f, // Top-left
// Back face (z = -0.5)
-0.5f, -0.5f, -0.5f, 1f, 0f, 1f, 1f, // Bottom-left
0.5f, -0.5f, -0.5f, 0f, 1f, 1f, 1f, // Bottom-right
0.5f, 0.5f, -0.5f, 1f, 1f, 1f, 1f, // Top-right
-0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 1f // Top-left
};
uint[] indices = {
// Front face
0, 1, 2,
2, 3, 0,
// Back face
4, 5, 6,
6, 7, 4,
// Left face
4, 0, 3,
3, 7, 4,
// Right face
1, 5, 6,
6, 2, 1,
// Top face
3, 2, 6,
6, 7, 3,
// Bottom face
4, 5, 1,
1, 0, 4
};
return new Mesh(vertices, indices, Mesh.VertexLayout.PosColor);
}
// You'd also add CreateCircle, CreateCylinder, etc.
// Your Cylinder should be ONE mesh, not 3 draw calls.
// Generate the top, bottom, and side vertices into one
// big array and use one EBO for all of it.
}

View File

@ -0,0 +1,61 @@
namespace TheLabs;
using OpenTK.Graphics.OpenGL4;
using StbImageSharp;
using System.IO;
public class Texture : IDisposable
{
public readonly int Handle;
public Texture(string path)
{
// Generate the handle
Handle = GL.GenTexture();
// Bind the texture so we can configure it
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, Handle);
// --- Set texture parameters ---
// Repeat the texture if UVs go outside [0, 1]
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
// Set filter for shrinking (mipmap) and stretching (linear)
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
// --- Load and upload the image data ---
StbImage.stbi_set_flip_vertically_on_load(1);
// Load the image from disk
using (var stream = File.OpenRead(path))
{
ImageResult image = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha);
// Upload data to the GPU
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
image.Width, image.Height, 0,
PixelFormat.Rgba, PixelType.UnsignedByte, image.Data);
}
// Generate mipmaps for better quality shrinking
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
// Unbind the texture
GL.BindTexture(TextureTarget.Texture2D, 0);
}
// A simple method to bind the texture to a specific unit
public void Use(TextureUnit unit = TextureUnit.Texture0)
{
GL.ActiveTexture(unit);
GL.BindTexture(TextureTarget.Texture2D, Handle);
}
public void Dispose()
{
GL.DeleteTexture(Handle);
}
}