Skip to content

Commit

Permalink
Sync back some important changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
LoneWandererProductions committed Jan 26, 2025
1 parent d7cfcb5 commit 442c446
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 118 deletions.
2 changes: 1 addition & 1 deletion CommonLibraryGuiTests/CommonCtrl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public void Basic()
_ = new ScrollingRichTextBox();
_ = new Thumbnails();
_ = new NativeBitmapDisplay();
_ = new TkRender();
_ = new OpenTkControl();

Assert.Pass();
}
Expand Down
11 changes: 10 additions & 1 deletion RenderEngine/TKHelper.cs → RenderEngine/OpenTKHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
*/

using System;
using System.Diagnostics;
using System.IO;
using Imaging; // For Marshal.Copy and memory management
using OpenTK.Graphics.OpenGL4; // For GL methods, ShaderType, TextureTarget, etc.
using PixelFormat = OpenTK.Graphics.OpenGL4.PixelFormat;

namespace RenderEngine
{
internal static class TkHelper
internal static class OpenTKHelper
{
internal static int CompileShader(ShaderType type, string source)
{
Expand Down Expand Up @@ -100,6 +102,13 @@ public static byte[] LoadTexture(string filePath, out int width, out int height)

public static int LoadTexture(string filePath)
{
// Check if the file exists
if (!File.Exists(filePath))
{
Trace.WriteLine($"File not found: {filePath}");
return -1;
}

var textureId = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, textureId);

Expand Down
203 changes: 108 additions & 95 deletions RenderEngine/TKRender.xaml.cs → RenderEngine/OpenTkControl.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: RenderEngine
* FILE: RenderEngine/TkRender.cs
* PURPOSE: Main Render Control
* PROGRAMER: Peter Geinitz (Wayfarer)
* COPYRIGHT: See COPYING in the top-level directory
* PROJECT: Imaging
* FILE: Imaging/OpenTkControl.cs
* PURPOSE: OpenGL Viewer for WPF applications.
* PROGRAMMER: Peter Geinitz (Wayfarer)
*/

#nullable enable
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using OpenTK.GLControl;
Expand All @@ -19,41 +19,40 @@

namespace RenderEngine
{
public partial class TkRender
/// <summary>
/// Display Control for OpenGL
/// </summary>
/// <seealso cref="System.Windows.Forms.Integration.WindowsFormsHost" />
public sealed class OpenTkControl : WindowsFormsHost
{
private GLControl _glControl;
private GLControl? _glControl;
private int _shaderProgram;
private int _vao;
private int _vbo;

// New texture variable for the background image
private int _vao, _vbo;
private int _backgroundTexture;

public TkRender()
public OpenTkControl()
{
InitializeComponent();
Loaded += OnLoaded;
Unloaded += OnUnloaded;
InitializeGlControl();
InitializeShaders();
InitializeBuffers();
Child = _glControl; // Set GLControl as the hosted child
}

private void OnLoaded(object sender, RoutedEventArgs e)
private void InitializeGlControl()
{
var windowsFormsHost = new WindowsFormsHost();
_glControl = new GLControl { Dock = DockStyle.Fill };
windowsFormsHost.Child = _glControl;
MainGrid.Children.Add(windowsFormsHost);
_glControl = new GLControl
{
Dock = DockStyle.Fill
};

_glControl.Load += GlControl_Load;
_glControl.Paint += GlControl_Paint;
_glControl.Resize += GlControl_Resize;

// Load background texture
_backgroundTexture = TkHelper.LoadTexture("path_to_your_background_image.jpg");

_glControl.Invalidate();
_glControl.MakeCurrent();
GL.ClearColor(0.1f, 0.2f, 0.3f, 1.0f);
}

public void Initialize()
private void InitializeShaders()
{
const string vertexShaderSource = @"
#version 450 core
Expand All @@ -77,17 +76,42 @@ void main()
}
";

var vertexShader = TkHelper.CompileShader(ShaderType.VertexShader, vertexShaderSource);
var fragmentShader = TkHelper.CompileShader(ShaderType.FragmentShader, fragmentShaderSource);

_shaderProgram = GL.CreateProgram();

int vertexShader = CompileShader(ShaderType.VertexShader, vertexShaderSource);
int fragmentShader = CompileShader(ShaderType.FragmentShader, fragmentShaderSource);

GL.AttachShader(_shaderProgram, vertexShader);
GL.AttachShader(_shaderProgram, fragmentShader);
GL.LinkProgram(_shaderProgram);

GL.DetachShader(_shaderProgram, vertexShader);
GL.DetachShader(_shaderProgram, fragmentShader);
GL.DeleteShader(vertexShader);
GL.DeleteShader(fragmentShader);

// Load background texture
_backgroundTexture = OpenTKHelper.LoadTexture("path_to_your_background_image.jpg");
}

private int CompileShader(ShaderType type, string source)
{
int shader = GL.CreateShader(type);
GL.ShaderSource(shader, source);
GL.CompileShader(shader);

GL.GetShader(shader, ShaderParameter.CompileStatus, out int status);
if (status == 0)
{
string log = GL.GetShaderInfoLog(shader);
throw new Exception($"Error compiling {type}: {log}");
}

return shader;
}

private void InitializeBuffers()
{
_vao = GL.GenVertexArray();
_vbo = GL.GenBuffer();

Expand All @@ -101,6 +125,34 @@ void main()
GL.EnableVertexAttribArray(1);
}

private void GlControl_Paint(object? sender, PaintEventArgs e)
{
if (_glControl == null) return;

if (!_glControl.Context.IsCurrent)
{
_glControl.MakeCurrent();
}

GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

if(_backgroundTexture != -1) RenderBackground(_backgroundTexture); // Render the background

_glControl.SwapBuffers();
}

private void GlControl_Resize(object? sender, System.EventArgs e)
{
if (_glControl == null) return;

if (!_glControl.Context.IsCurrent)
{
_glControl.MakeCurrent();
}

GL.Viewport(0, 0, _glControl.Width, _glControl.Height);
}

private void RenderBackground(int textureId)
{
GL.UseProgram(_shaderProgram);
Expand All @@ -117,18 +169,14 @@ private void RenderBackground(int textureId)
public void RenderColumns(ColumnData[] columns, int screenWidth, int screenHeight)
{
GL.Clear(ClearBufferMask.ColorBufferBit);

// Render the background first
RenderBackground(_backgroundTexture);

// Generate vertex data for columns
var vertexData = TkHelper.GenerateVertexData(columns, screenWidth, screenHeight, column => new[] { column.Height / screenHeight, column.Color.X, column.Color.Y, column.Color.Z });
var vertexData = OpenTKHelper.GenerateVertexData(columns, screenWidth, screenHeight, column =>
new[] { column.Height / screenHeight, column.Color.X, column.Color.Y, column.Color.Z });

// Upload column vertex data to GPU
GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo);
GL.BufferData(BufferTarget.ArrayBuffer, vertexData.Length * sizeof(float), vertexData, BufferUsageHint.DynamicDraw);

// Render columns on top of background
GL.UseProgram(_shaderProgram);
GL.BindVertexArray(_vao);
GL.DrawArrays(PrimitiveType.Triangles, 0, columns.Length * 6);
Expand All @@ -137,96 +185,61 @@ public void RenderColumns(ColumnData[] columns, int screenWidth, int screenHeigh
public void RenderPixels(PixelData[] pixels, int screenWidth, int screenHeight)
{
GL.Clear(ClearBufferMask.ColorBufferBit);

// Render the background first
RenderBackground(_backgroundTexture);

// Generate vertex data for pixels
var vertexData = TkHelper.GenerateVertexData(pixels, screenWidth, screenHeight, pixel =>
var vertexData = OpenTKHelper.GenerateVertexData(pixels, screenWidth, screenHeight, pixel =>
{
var pixelWidth = 2.0f / screenWidth;
var pixelHeight = 2.0f / screenHeight;

// Assuming you want to use both pixelWidth and pixelHeight for vertex position,
// you can define the coordinates for each vertex of the pixel quad
return new[]
{
-1 + pixel.X * pixelWidth, -1 + pixel.Y * pixelHeight, 0.0f, // Bottom-left vertex
-1 + (pixel.X + 1) * pixelWidth, -1 + pixel.Y * pixelHeight, 0.0f, // Bottom-right vertex
-1 + pixel.X * pixelWidth, -1 + (pixel.Y + 1) * pixelHeight, 0.0f, // Top-left vertex

-1 + (pixel.X + 1) * pixelWidth, -1 + pixel.Y * pixelHeight, 0.0f, // Bottom-right vertex
-1 + (pixel.X + 1) * pixelWidth, -1 + (pixel.Y + 1) * pixelHeight, 0.0f, // Top-right vertex
-1 + pixel.X * pixelWidth, -1 + (pixel.Y + 1) * pixelHeight, 0.0f, // Top-left vertex

pixel.Color.X, pixel.Color.Y, pixel.Color.Z // Color for each pixel
-1 + pixel.X * pixelWidth, -1 + pixel.Y * pixelHeight, 0.0f,
-1 + (pixel.X + 1) * pixelWidth, -1 + pixel.Y * pixelHeight, 0.0f,
-1 + pixel.X * pixelWidth, -1 + (pixel.Y + 1) * pixelHeight, 0.0f,
pixel.Color.X, pixel.Color.Y, pixel.Color.Z
};
});

// Upload pixel vertex data to GPU
GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo);
GL.BufferData(BufferTarget.ArrayBuffer, vertexData.Length * sizeof(float), vertexData, BufferUsageHint.DynamicDraw);

// Render pixels on top of the background
GL.UseProgram(_shaderProgram);
GL.BindVertexArray(_vao);
GL.DrawArrays(PrimitiveType.Triangles, 0, pixels.Length * 6);
}

// Screenshot method
public void CaptureScreenshot(string filePath)
{
// Step 1: Determine the dimensions of the OpenGL viewport or control
int width = _glControl.Width; // Replace _glControl with your actual OpenGL control or window
int height = _glControl.Height;
if (_glControl == null) return;

// Step 2: Allocate a byte array to store the pixel data (RGBA format)
byte[] pixels = new byte[width * height * 4]; // 4 bytes per pixel (RGBA)
int width = _glControl.Width;
int height = _glControl.Height;

// Step 3: Read the pixels from the OpenGL framebuffer
byte[] pixels = new byte[width * height * 4];
GL.ReadPixels(0, 0, width, height, PixelFormat.Rgba, PixelType.UnsignedByte, pixels);

// Step 4: Create a Bitmap and copy the pixel data into it
using (var bitmap = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
{
var rect = new Rectangle(0, 0, width, height);
var bitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

// Copy pixel data from the byte array to the Bitmap
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
using var bitmap = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
var rect = new Rectangle(0, 0, width, height);
var bitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

bitmap.UnlockBits(bitmapData);
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);

// Step 5: Save the Bitmap as a file
bitmap.Save(filePath, ImageFormat.Png);
}
}

private void OnUnloaded(object sender, RoutedEventArgs e)
{
if (_shaderProgram != 0) GL.DeleteProgram(_shaderProgram);
if (_vao != 0) GL.DeleteVertexArray(_vao);
if (_vbo != 0) GL.DeleteBuffer(_vbo);
GL.DeleteTexture(_backgroundTexture); // Delete the background texture
_glControl?.Dispose();
}

private void GlControl_Load(object sender, EventArgs e)
{
GL.ClearColor(0.1f, 0.2f, 0.3f, 1.0f);
bitmap.UnlockBits(bitmapData);
bitmap.Save(filePath, ImageFormat.Png);
}

private void GlControl_Paint(object sender, PaintEventArgs e)
protected override void Dispose(bool disposing)
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
_glControl.SwapBuffers();
}
if (disposing)
{
GL.DeleteProgram(_shaderProgram);
GL.DeleteVertexArray(_vao);
GL.DeleteBuffer(_vbo);
_glControl?.Dispose();
}

private void GlControl_Resize(object sender, EventArgs e)
{
GL.Viewport(0, 0, _glControl.Width, _glControl.Height);
// Initialize shaders and other OpenGL resources here
Initialize();
base.Dispose(disposing);
}
}
}
10 changes: 0 additions & 10 deletions RenderEngine/RenderEngine.csproj.user
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<ItemGroup>
<Compile Update="TKRender.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Update="TKRender.xaml">
<SubType>Designer</SubType>
</Page>
</ItemGroup>
</Project>
11 changes: 0 additions & 11 deletions RenderEngine/TKRender.xaml

This file was deleted.

0 comments on commit 442c446

Please sign in to comment.