some C# cause why not. C# guy might like this? idk. some python too. mostly simulations. WindowsAPI C# is good i guess
This commit is contained in:
276
simulations/fluids/fluidsC#/FluidWindow.cs
Normal file
276
simulations/fluids/fluidsC#/FluidWindow.cs
Normal file
@@ -0,0 +1,276 @@
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
using OpenTK.Mathematics;
|
||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||
|
||||
namespace fluidsC_;
|
||||
|
||||
public class FluidWindow : GameWindow
|
||||
{
|
||||
private FluidSimulation _fluid;
|
||||
private int _vertexArrayObject;
|
||||
private int _vertexBufferObject;
|
||||
private int _elementBufferObject;
|
||||
private int _shaderProgram;
|
||||
private int _texture;
|
||||
|
||||
private readonly int _fluidSizeX = 128;
|
||||
private readonly int _fluidSizeY = 128;
|
||||
private float[] _pixels;
|
||||
|
||||
private bool _mouseDown = false;
|
||||
private Vector2 _lastMousePos;
|
||||
private MouseButton _activeButton;
|
||||
|
||||
public FluidWindow(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings)
|
||||
: base(gameWindowSettings, nativeWindowSettings)
|
||||
{
|
||||
_fluid = new FluidSimulation(_fluidSizeX, _fluidSizeY);
|
||||
_pixels = new float[_fluidSizeX * _fluidSizeY * 4];
|
||||
}
|
||||
|
||||
protected override void OnLoad()
|
||||
{
|
||||
base.OnLoad();
|
||||
|
||||
GL.ClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
|
||||
SetupShaders();
|
||||
SetupTexture();
|
||||
SetupQuad();
|
||||
|
||||
Console.WriteLine("Fluid Simulation Controls:");
|
||||
Console.WriteLine("<22> Click and drag to add fluid");
|
||||
Console.WriteLine("<22> Right click to add velocity");
|
||||
Console.WriteLine("<22> R key to reset simulation");
|
||||
Console.WriteLine("<22> ESC to exit");
|
||||
}
|
||||
|
||||
private void SetupShaders()
|
||||
{
|
||||
const string vertexShaderSource = @"
|
||||
#version 330 core
|
||||
layout (location = 0) in vec2 aPosition;
|
||||
layout (location = 1) in vec2 aTexCoord;
|
||||
|
||||
out vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(aPosition, 0.0, 1.0);
|
||||
texCoord = aTexCoord;
|
||||
}";
|
||||
|
||||
const string fragmentShaderSource = @"
|
||||
#version 330 core
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform sampler2D fluidTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture(fluidTexture, texCoord);
|
||||
// Create a nice blue-to-cyan color gradient based on density
|
||||
fragColor = vec4(color.r * 0.2, color.r * 0.5, color.r, 1.0);
|
||||
}";
|
||||
|
||||
var vertexShader = GL.CreateShader(ShaderType.VertexShader);
|
||||
GL.ShaderSource(vertexShader, vertexShaderSource);
|
||||
GL.CompileShader(vertexShader);
|
||||
|
||||
var fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
|
||||
GL.ShaderSource(fragmentShader, fragmentShaderSource);
|
||||
GL.CompileShader(fragmentShader);
|
||||
|
||||
_shaderProgram = GL.CreateProgram();
|
||||
GL.AttachShader(_shaderProgram, vertexShader);
|
||||
GL.AttachShader(_shaderProgram, fragmentShader);
|
||||
GL.LinkProgram(_shaderProgram);
|
||||
|
||||
GL.DeleteShader(vertexShader);
|
||||
GL.DeleteShader(fragmentShader);
|
||||
}
|
||||
|
||||
private void SetupTexture()
|
||||
{
|
||||
_texture = GL.GenTexture();
|
||||
GL.BindTexture(TextureTarget.Texture2D, _texture);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
|
||||
|
||||
// Initialize with empty data
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba32f,
|
||||
_fluidSizeX, _fluidSizeY, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero);
|
||||
}
|
||||
|
||||
private void SetupQuad()
|
||||
{
|
||||
float[] vertices = {
|
||||
// positions // texture coords
|
||||
-1.0f, 1.0f, 0.0f, 1.0f,
|
||||
-1.0f, -1.0f, 0.0f, 0.0f,
|
||||
1.0f, -1.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f
|
||||
};
|
||||
|
||||
uint[] indices = {
|
||||
0, 1, 2,
|
||||
2, 3, 0
|
||||
};
|
||||
|
||||
_vertexArrayObject = GL.GenVertexArray();
|
||||
_vertexBufferObject = GL.GenBuffer();
|
||||
_elementBufferObject = GL.GenBuffer();
|
||||
|
||||
GL.BindVertexArray(_vertexArrayObject);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferObject);
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _elementBufferObject);
|
||||
GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(uint), indices, BufferUsageHint.StaticDraw);
|
||||
|
||||
// Position attribute
|
||||
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0);
|
||||
GL.EnableVertexAttribArray(0);
|
||||
|
||||
// Texture coordinate attribute
|
||||
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2 * sizeof(float));
|
||||
GL.EnableVertexAttribArray(1);
|
||||
}
|
||||
|
||||
protected override void OnRenderFrame(FrameEventArgs e)
|
||||
{
|
||||
base.OnRenderFrame(e);
|
||||
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
|
||||
UpdateTextureFromFluid();
|
||||
|
||||
GL.UseProgram(_shaderProgram);
|
||||
GL.BindTexture(TextureTarget.Texture2D, _texture);
|
||||
GL.BindVertexArray(_vertexArrayObject);
|
||||
GL.DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, 0);
|
||||
|
||||
SwapBuffers();
|
||||
}
|
||||
|
||||
protected override void OnUpdateFrame(FrameEventArgs e)
|
||||
{
|
||||
base.OnUpdateFrame(e);
|
||||
|
||||
// Update fluid simulation
|
||||
_fluid.Step(0.1f, 0.0001f, 0.0001f);
|
||||
_fluid.FadeDensity(0.002f);
|
||||
|
||||
Title = $"Fluid Simulation :3 - FPS: {1.0 / e.Time:0}";
|
||||
}
|
||||
|
||||
private void UpdateTextureFromFluid()
|
||||
{
|
||||
// Convert fluid density to pixel data
|
||||
for (int y = 0; y < _fluidSizeY; y++)
|
||||
{
|
||||
for (int x = 0; x < _fluidSizeX; x++)
|
||||
{
|
||||
int index = (y * _fluidSizeX + x) * 4;
|
||||
float density = Math.Clamp(_fluid.GetDensity(x, y), 0, 1);
|
||||
|
||||
_pixels[index] = density; // R
|
||||
_pixels[index + 1] = density; // G
|
||||
_pixels[index + 2] = density; // B
|
||||
_pixels[index + 3] = 1.0f; // A
|
||||
}
|
||||
}
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, _texture);
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, _fluidSizeX, _fluidSizeY,
|
||||
PixelFormat.Rgba, PixelType.Float, _pixels);
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
_mouseDown = true;
|
||||
_activeButton = e.Button;
|
||||
_lastMousePos = new Vector2(MousePosition.X, MousePosition.Y);
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseUp(e);
|
||||
_mouseDown = false;
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseMoveEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
if (_mouseDown)
|
||||
{
|
||||
var mousePos = new Vector2(e.X, e.Y);
|
||||
var delta = mousePos - _lastMousePos;
|
||||
|
||||
int fluidX = (int)(e.X / Size.X * _fluidSizeX);
|
||||
int fluidY = (int)((Size.Y - e.Y) / Size.Y * _fluidSizeY);
|
||||
|
||||
// Ensure coordinates are within bounds
|
||||
fluidX = Math.Clamp(fluidX, 1, _fluidSizeX - 2);
|
||||
fluidY = Math.Clamp(fluidY, 1, _fluidSizeY - 2);
|
||||
|
||||
if (_activeButton == MouseButton.Left)
|
||||
{
|
||||
// Add density in a small area
|
||||
for (int i = -2; i <= 2; i++)
|
||||
{
|
||||
for (int j = -2; j <= 2; j++)
|
||||
{
|
||||
_fluid.AddDensity(fluidX + i, fluidY + j, 10.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_activeButton == MouseButton.Right)
|
||||
{
|
||||
// Add velocity
|
||||
_fluid.AddVelocity(fluidX, fluidY, delta.X * 0.5f, -delta.Y * 0.5f);
|
||||
}
|
||||
|
||||
_lastMousePos = mousePos;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyboardKeyEventArgs e)
|
||||
{
|
||||
base.OnKeyDown(e);
|
||||
|
||||
if (e.Key == Keys.Escape)
|
||||
Close();
|
||||
else if (e.Key == Keys.R)
|
||||
{
|
||||
_fluid = new FluidSimulation(_fluidSizeX, _fluidSizeY);
|
||||
Console.WriteLine("Simulation reset!");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnResize(ResizeEventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
GL.Viewport(0, 0, e.Width, e.Height);
|
||||
}
|
||||
|
||||
protected override void OnUnload()
|
||||
{
|
||||
GL.DeleteBuffer(_vertexBufferObject);
|
||||
GL.DeleteBuffer(_elementBufferObject);
|
||||
GL.DeleteVertexArray(_vertexArrayObject);
|
||||
GL.DeleteProgram(_shaderProgram);
|
||||
GL.DeleteTexture(_texture);
|
||||
|
||||
base.OnUnload();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user