529 lines
19 KiB
C#
529 lines
19 KiB
C#
// -----------------------------------------------------------------------------
|
|
// file="Partical"
|
|
// Project: StgSharp
|
|
// Copyright (c) Nitload.
|
|
// SPDX-License-Identifier: MIT
|
|
// -----------------------------------------------------------------------------
|
|
|
|
using StgSharp.Geometries;
|
|
using StgSharp.Graphics;
|
|
using StgSharp.Graphics.OpenGL;
|
|
using StgSharp.Mathematics;
|
|
using StgSharp.Mathematics.Numeric.Graphics;
|
|
using StgSharp.Mathematics.Numeric.Graphics;
|
|
using StgSharp.Timing;
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace StgSharp
|
|
{
|
|
public class ParticleRenderStream : glRender
|
|
{
|
|
|
|
private ElementBuffer ebo;
|
|
private ElementBuffer f_ebo;
|
|
private FrameBuffer fbo;
|
|
private Image<Rgba8> i;
|
|
|
|
private int temp = 0;
|
|
private PlainInstancingBuffer<ParticleOnPlain> buffer;
|
|
private RenderBuffer rbo;
|
|
private ShaderProgram frameMainShader;
|
|
private ShaderProgram s;
|
|
private TextureGL f_t;
|
|
private TextureGL t;
|
|
private Uniform<GraphicsMatrix> cameraUniform;
|
|
private Uniform<int> texUniform;
|
|
private Uniform<float> time;
|
|
private VertexArray f_vao;
|
|
private VertexArray vao;
|
|
|
|
private VertexBuffer f_vbo;
|
|
private VertexBuffer vbo;
|
|
|
|
public ParticleRenderStream() { }
|
|
|
|
public override bool IsContextSharable => true;
|
|
|
|
public Rectangle ButtonBounding { get; private set; }
|
|
|
|
public TextureProvider ButtonTextureProvider { get; private set; }
|
|
|
|
// render a controlling item
|
|
public void ButtonMain(
|
|
IEnumerable<PlainGeometryMesh> items
|
|
)
|
|
{
|
|
// Console.WriteLine("Render Button Itself");
|
|
|
|
GL.BindFrameBuffer(FrameBufferTarget.All, GlHandle.Zero); /*GL.Assert(true);/**/
|
|
GL.ClearColor(0.4f, TimePassed % 1.0f, 0f, 1.0f); /*GL.Assert(true);/**/
|
|
GL.Clear(MaskBufferBit.COLOR /**/ | MaskBufferBit.DEPTH/**/); /*GL.Assert(true);/**/
|
|
|
|
GL.BindVertexArray(f_vao[0]); //GL.Assert(true);
|
|
|
|
foreach (PlainGeometryMesh mesh in items)
|
|
{
|
|
GL.ActiveTextureUnit((uint)TextureUnit.Unit1);
|
|
GL.BindTexture(glConst.TEXTURE_2D, f_t[0]);
|
|
GL.TextureImage2d(Texture2DTarget.Texture2D, 0, glConst.RGBA8,
|
|
mesh.TextureImage.Width, mesh.TextureImage.Height,
|
|
FrameBufferChannel.RGBA, PixelChannelLayout.UByte,
|
|
mesh.TextureImage.ReadOnlyPixels);
|
|
GL.GenerateMipmap(glConst.TEXTURE_2D);
|
|
|
|
// GL.Assert(true);
|
|
|
|
GL.UseProgram(frameMainShader.Handle); //GL.Assert(true);
|
|
|
|
GL.DrawElements(GeometryType.TRIANGLES, 6, TypeCode.UInt32, IntPtr.Zero);
|
|
}
|
|
|
|
// GL.ClearError();
|
|
// GL.Assert(true);
|
|
}
|
|
|
|
public void Main()
|
|
{
|
|
temp++;
|
|
|
|
// GL.ClearError();
|
|
GL.Viewport(0, 0, Width, Height);
|
|
|
|
// Console.Clear();
|
|
buffer.UpdateAllParticles();
|
|
|
|
// Console.WriteLine(GL.CheckFrameBufferStatus(FrameBufferTarget.All));
|
|
|
|
GL.BindFrameBuffer(FrameBufferTarget.All, fbo[0]); //GL.Assert(true);
|
|
GL.BindVertexArray(vao[0]); //GL.Assert(true);
|
|
GL.ActiveTextureUnit((uint)TextureUnit.Unit0);
|
|
GL.BindTexture(glConst.TEXTURE_2D, t[0]); //GL.Assert(false);
|
|
|
|
GL.Viewport(0, 0, Width, Height);
|
|
|
|
/**/
|
|
|
|
GL.TextureImage2d(Texture2DTarget.Texture2D, 0, glConst.RGBA8, Width, Height,
|
|
FrameBufferChannel.RGBA, PixelChannelLayout.UByte);
|
|
/**/
|
|
|
|
// GL.Assert(false);
|
|
// Console.WriteLine(GL.CheckFrameBufferStatus(FrameBufferTarget.All));
|
|
|
|
GL.ClearColor((0.6f + TimePassed) % 1.0f, 0.1f, 0.3f, 1);
|
|
|
|
// GL.Assert( false );
|
|
|
|
// Console.WriteLine(GL.CheckFrameBufferStatus(FrameBufferTarget.All));
|
|
GL.Clear(MaskBufferBit.COLOR /**/ | MaskBufferBit.DEPTH/**/);
|
|
|
|
|
|
// GL.Assert(false);
|
|
|
|
GL.BindBuffer(BufferType.ArrayBuffer, vbo[1]);
|
|
GL.SetBufferData<Vec4>(BufferType.ArrayBuffer, buffer.CoordAndRotationSpan,
|
|
BufferUsage.StreamDraw);
|
|
|
|
|
|
GL.UseProgram(s.Handle);
|
|
GL.SetUniformValue(cameraUniform, NativeCamera.CameraMatrix());
|
|
GL.SetUniformValue(time, TimePassed);
|
|
|
|
GL.DrawElementsInstanced(GeometryType.TRIANGLES, 6, TypeCode.UInt32, IntPtr.Zero, 100);
|
|
|
|
// Console.WriteLine(TimePassed);
|
|
// GL.Assert(true);
|
|
|
|
GL.WaitAccomplishment();
|
|
GL.BindVertexArray(GlHandle.Zero);
|
|
/**/
|
|
|
|
// GL.Assert(true);
|
|
|
|
if (i.Size != (Width, Height))
|
|
{
|
|
i = new Image<Rgba8>(Width, Height);
|
|
ButtonTextureProvider.Image = i;
|
|
}
|
|
|
|
// GL.ClearError();
|
|
// Console.Write($"Size set to {Height},{Width}");
|
|
// Console.WriteLine($"Image resized to {i.Height} {i.Width}");
|
|
GL.GetTextureImage(Texture2DTarget.Texture2D, 0, FrameBufferChannel.RGBA,
|
|
PixelChannelLayout.UByte, i.Bytes);
|
|
/*
|
|
for (int num = 0; num < i.Bytes.Length; num+=10000)
|
|
{
|
|
Console.Write($"{i.Bytes[num]}\t");
|
|
}
|
|
/**/
|
|
|
|
// GL.Assert(true);
|
|
// i.Bytes.Fill(24);
|
|
|
|
GL.BindFrameBuffer(FrameBufferTarget.All, GlHandle.Zero);
|
|
|
|
// GL.Assert(true);
|
|
/**/
|
|
}
|
|
|
|
public void NothingMain()
|
|
{
|
|
GL.ClearError();
|
|
|
|
// GL.BindFrameBuffer(FrameBufferTarget.All, GlHandle.Zero);
|
|
GL.ClearColor(0.5f, 0.2f, 0.3f, 1.0f);
|
|
GL.Assert(false);
|
|
}
|
|
|
|
/*
|
|
public void RenderButton(
|
|
ButtonStatus status,
|
|
float statusBegin,
|
|
in TextureProvider provider
|
|
)
|
|
{
|
|
provider.UpdateFromImage(i);
|
|
}
|
|
/**/
|
|
internal static Vec3 DefaultRotation(
|
|
TimeSpanProvider provider,
|
|
out float rotation
|
|
)
|
|
{
|
|
rotation = 1.0f / 60;
|
|
float angle = (float)provider.CurrentSecond * 2;
|
|
return (new Vec3(MathF.Cos(angle), MathF.Sin(angle),
|
|
0)) * rotation;
|
|
}
|
|
|
|
protected override void CustomizeDeinit()
|
|
{
|
|
GL.DeleteProgram(s.Handle);
|
|
GL.DeleteProgram(frameMainShader.Handle);
|
|
|
|
GL.DeleteBuffers(vbo.Handles);
|
|
GL.DeleteBuffers(ebo.Handles);
|
|
GL.DeleteBuffers(f_vbo.Handles);
|
|
GL.DeleteBuffers(f_ebo.Handles);
|
|
GL.DeleteVertexArrays(vao.Handles);
|
|
GL.DeleteVertexArrays(f_vao.Handles);
|
|
GL.DeleteFramebuffers(fbo.Handles);
|
|
GL.DeleteRenderbuffers(rbo.Handles);
|
|
GL.DeleteTextures(t.Handles);
|
|
GL.DeleteTextures(f_t.Handles);
|
|
}
|
|
|
|
protected override void CustomizeInit()
|
|
{
|
|
// GL.ClearError();
|
|
// GL.Assert(true);
|
|
|
|
buffer = new PlainInstancingBuffer<ParticleOnPlain>();
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
float ai = MathF.Abs(i - 5.0f);
|
|
for (int t = 0; t < 10; t++)
|
|
{
|
|
float at = MathF.Abs(t - 5.0f);
|
|
|
|
ParticleOnPlain p = new ParticleOnPlain(buffer);
|
|
((IInstancing)p).Coord = new Vec3(
|
|
(((-5) + i) * 0.2f) + 0.1f, (((-5) + t) * 0.2f) + 0.1f, 0);
|
|
((IInstancing)p).Scale =
|
|
float.Min(i, t) * 0.15f;
|
|
((IInstancing)p).Motion = new GeometryMotion(
|
|
true, TimeProvider, DefaultRotation);
|
|
}
|
|
}
|
|
|
|
// GL.Assert(true);
|
|
|
|
// SetSizeLimit(800, 800, 800, 800);
|
|
|
|
s = new ShaderProgram(GL.CreateProgram());
|
|
frameMainShader = new ShaderProgram(GL.CreateProgram());
|
|
Shader pvs = CreateShaderSet(ShaderType.Vertex, 2);
|
|
Shader pfs = CreateShaderSet(ShaderType.Fragment, 2);
|
|
|
|
// GL.Assert(true);
|
|
CompileShaderFromFile(pvs[0], Path.Combine("Shader", "particle.vert"));
|
|
|
|
// GL.Assert(true);
|
|
GL.AttachShader(s.Handle, pvs[0]);
|
|
|
|
// GL.Assert(true);
|
|
CompileShaderFromFile(pfs[0], Path.Combine("Shader", "particle.frag"));
|
|
GL.AttachShader(s.Handle, pfs[0]);
|
|
LinkShaderProgram(s.Handle);
|
|
|
|
// GL.Assert(true);
|
|
|
|
CompileShaderFromFile(pvs[1], Path.Combine("Shader", "fbo.vert"));
|
|
GL.AttachShader(frameMainShader.Handle, pvs[1]);
|
|
CompileShaderFromFile(pfs[1], Path.Combine("Shader", "fbo.frag"));
|
|
GL.AttachShader(frameMainShader.Handle, pfs[1]);
|
|
LinkShaderProgram(frameMainShader.Handle);
|
|
|
|
DeleteShaderSet(pvs);
|
|
DeleteShaderSet(pfs);
|
|
|
|
// GL.Assert(true);
|
|
vbo = new VertexBuffer(GL.GenBuffers(3));
|
|
vao = new VertexArray(GL.GenVertexArrays(1));
|
|
ebo = new ElementBuffer(GL.GenBuffers(1));
|
|
GL.BindBuffer(BufferType.ArrayBuffer, vbo[0]);
|
|
|
|
Rectangle rec = new Rectangle(0.05f, 0.05f, 0.05f, -0.05f, -0.05f, -0.05f, -0.05f,
|
|
0.05f);
|
|
|
|
// GL.Assert(true);
|
|
GL.BindVertexArray(vao[0]);
|
|
GL.BindBuffer(BufferType.ArrayBuffer, vbo[0]);
|
|
GL.SetBufferData(BufferType.ArrayBuffer, rec.VertexStream, BufferUsage.StaticDraw);
|
|
GL.BindBuffer(BufferType.ElementArrayBuffer, ebo[0]);
|
|
GL.SetBufferData(BufferType.ElementArrayBuffer, rec.VertexIndices,
|
|
BufferUsage.StaticDraw);
|
|
GL.SetVertexAttribute(0, 3, TypeCode.Single, false, 4 * sizeof(float), 0);
|
|
|
|
GL.BindBuffer(BufferType.ArrayBuffer, vbo[1]);
|
|
GL.SetBufferData<Vec4>(BufferType.ArrayBuffer, buffer.CoordAndRotationSpan,
|
|
BufferUsage.StreamDraw);
|
|
GL.SetVertexAttribute(1, 3, TypeCode.Single, false, 4 * sizeof(float), 0);
|
|
GL.SetVertexAttribute(2, 1, TypeCode.Single, false, 4 * sizeof(float),
|
|
3 * sizeof(float));
|
|
|
|
GL.VertexAttributeDivisor(1, 1);
|
|
GL.VertexAttributeDivisor(2, 1);
|
|
|
|
GL.BindBuffer(BufferType.ArrayBuffer, vbo[2]);
|
|
GL.SetBufferData<float>(BufferType.ArrayBuffer, buffer.ScalingSpan,
|
|
BufferUsage.StaticDraw);
|
|
GL.SetVertexAttribute(3, 1, TypeCode.Single, false, sizeof(float), 0);
|
|
|
|
GL.VertexAttributeDivisor(3, 1);
|
|
|
|
GL.BindBuffer(BufferType.ArrayBuffer, GlHandle.Zero);
|
|
GL.BindVertexArray(GlHandle.Zero);
|
|
|
|
NativeCameraViewTarget([
|
|
0f,
|
|
0f,
|
|
-100f
|
|
], [
|
|
0f,
|
|
0f,
|
|
0f
|
|
], [
|
|
0f,
|
|
1f,
|
|
0f
|
|
]);
|
|
NativeCameraViewRange(new Degree(1.5f), Vec2.Zero, (50, 50));
|
|
cameraUniform = GL.GetUniform<GraphicsMatrix>(s.Handle, "Camera");
|
|
|
|
GL.UseProgram(s.Handle);
|
|
|
|
GlHandle[] frameBufferHandles = new GlHandle[1];
|
|
GL.GenFrameBuffers(frameBufferHandles);
|
|
fbo = new FrameBuffer(frameBufferHandles);
|
|
rbo = new RenderBuffer(GL.GenRenderBuffer(1));
|
|
GL.BindFrameBuffer(FrameBufferTarget.All, fbo[0]);
|
|
GL.BindRenderBuffer(rbo[0]);
|
|
|
|
// GL.Assert(true);
|
|
t = new TextureGL(GL.GenTextures(1));
|
|
GL.ActiveTextureUnit((uint)TextureUnit.Unit0);
|
|
GL.BindTexture(glConst.TEXTURE_2D, t[0]);
|
|
GL.TextureImage2d(Texture2DTarget.Texture2D, 0, glConst.RGBA8, Width, Height,
|
|
FrameBufferChannel.RGBA, PixelChannelLayout.UByte);
|
|
GL.TextureParameter(glConst.TEXTURE_2D, glConst.TEXTURE_WRAP_S,
|
|
(int)TextureWrap.Repeat);
|
|
GL.TextureParameter(glConst.TEXTURE_2D, glConst.TEXTURE_WRAP_T,
|
|
(int)TextureWrap.Repeat);
|
|
GL.TextureParameter(glConst.TEXTURE_2D, glConst.TEXTURE_MIN_FILTER,
|
|
(int)TextureFilter.Linear);
|
|
GL.TextureParameter(glConst.TEXTURE_2D, glConst.TEXTURE_MAG_FILTER,
|
|
(int)TextureFilter.Linear);
|
|
|
|
// GL.Assert(true);
|
|
GL.FrameBufferTexture2d(FrameBufferTarget.All, glAttachment.Color(0),
|
|
Texture2DTarget.Texture2D, t[0], 0);
|
|
|
|
GL.SetRenderBufferStorage(RenderBufferInternalFormat.Depth24_Stencil8, this.Size);
|
|
GL.CombineFrameBufferRenderBuffer(FrameBufferAttachment.DepthAndStencil, rbo[0]);
|
|
|
|
Console.WriteLine(GL.CheckFrameBufferStatus(FrameBufferTarget.All));
|
|
|
|
GL.BindFrameBuffer(FrameBufferTarget.All, GlHandle.Zero);
|
|
|
|
// GL.Assert(true);
|
|
i = new Image<Rgba8>(this.Size);
|
|
|
|
|
|
time = GL.GetUniform<float>(s.Handle, "time");
|
|
|
|
Vec2[] buttonTextureCoordArray = {
|
|
(0f, 1f),
|
|
(1f, 1f),
|
|
(1f, 0f),
|
|
(0f, 0f)
|
|
};
|
|
ButtonBounding = new Rectangle(-0.9f, 0.9f, 0.9f, 0.9f, 0.9f, -0.9f, -0.9f, -0.9f);
|
|
|
|
// GL.Assert(true);
|
|
ButtonTextureProvider = new TextureProvider(i, buttonTextureCoordArray);
|
|
|
|
f_vao = new VertexArray(GL.GenVertexArrays(1));
|
|
f_vbo = new VertexBuffer(GL.GenBuffers(2));
|
|
f_ebo = new ElementBuffer(GL.GenBuffers(1));
|
|
|
|
// GL.Assert(true);
|
|
GL.BindVertexArray(f_vao[0]);
|
|
|
|
GL.BindBuffer(BufferType.ElementArrayBuffer, f_ebo[0]);
|
|
GL.SetBufferData(BufferType.ElementArrayBuffer, ButtonBounding.VertexIndices,
|
|
BufferUsage.StaticDraw);
|
|
|
|
// GL.Assert(true);
|
|
GL.BindBuffer(BufferType.ArrayBuffer, f_vbo[0]);
|
|
GL.SetBufferData(BufferType.ArrayBuffer, ButtonBounding.VertexStream,
|
|
BufferUsage.StaticDraw);
|
|
GL.SetVertexAttribute(0, 3, TypeCode.Single, false, 4 * sizeof(float), 0);
|
|
|
|
// GL.Assert(true);
|
|
GL.BindBuffer(BufferType.ArrayBuffer, f_vbo[1]);
|
|
GL.SetBufferData(BufferType.ArrayBuffer, buttonTextureCoordArray,
|
|
BufferUsage.StaticDraw);
|
|
GL.SetVertexAttribute(1, 3, TypeCode.Single, false, 4 * sizeof(float), 0);
|
|
|
|
// GL.Assert(true);
|
|
|
|
f_t = new TextureGL(GL.GenTextures(1));
|
|
GL.ActiveTextureUnit((uint)TextureUnit.Unit1);
|
|
GL.BindTexture(glConst.TEXTURE_2D, f_t[0]);
|
|
GL.TextureParameter(glConst.TEXTURE_2D, glConst.TEXTURE_WRAP_S,
|
|
(int)TextureWrap.Repeat);
|
|
GL.TextureParameter(glConst.TEXTURE_2D, glConst.TEXTURE_WRAP_T,
|
|
(int)TextureWrap.Repeat);
|
|
GL.TextureParameter(glConst.TEXTURE_2D, glConst.TEXTURE_MIN_FILTER,
|
|
(int)TextureFilter.Nearest);
|
|
GL.TextureParameter(glConst.TEXTURE_2D, glConst.TEXTURE_MAG_FILTER,
|
|
(int)TextureFilter.Nearest);
|
|
|
|
// GL.Assert(true);
|
|
GL.UseProgram(frameMainShader.Handle);
|
|
texUniform = GL.GetUniform<int>(frameMainShader.Handle, "tex");
|
|
|
|
// GL.Assert(true);
|
|
GL.SetUniformValue(texUniform, 1);
|
|
|
|
// GL.Assert(true);
|
|
|
|
GL.ClearError();
|
|
GL.Assert(true);
|
|
}
|
|
|
|
private void CompileShaderFromFile(
|
|
GlHandle shader,
|
|
string path
|
|
)
|
|
{
|
|
byte[] source = File.ReadAllBytes(path);
|
|
if (source.Length == 0) {
|
|
throw new InvalidOperationException($"Shader source is empty: {path}");
|
|
}
|
|
|
|
GL.ShaderSource(shader, source);
|
|
GL.CompileShader(shader);
|
|
|
|
Span<int> status = stackalloc int[1];
|
|
GL.GetShaderiv(shader, glConst.COMPILE_STATUS, status);
|
|
if (status[0] != 0) {
|
|
return;
|
|
}
|
|
|
|
throw new InvalidOperationException(
|
|
$"Failed to compile shader '{path}'.{Environment.NewLine}{GetShaderInfoLog(shader)}");
|
|
}
|
|
|
|
private Shader CreateShaderSet(
|
|
ShaderType type,
|
|
int count
|
|
)
|
|
{
|
|
GlHandle[] handles = new GlHandle[count];
|
|
for (int index = 0; index < handles.Length; index++) {
|
|
handles[index] = GL.CreateShader((uint)type);
|
|
}
|
|
return new Shader(handles, type);
|
|
}
|
|
|
|
private void DeleteShaderSet(
|
|
Shader shaderSet
|
|
)
|
|
{
|
|
for (int index = 0; index < shaderSet.Count; index++) {
|
|
GL.DeleteShader(shaderSet[index]);
|
|
}
|
|
}
|
|
|
|
private string GetProgramInfoLog(
|
|
GlHandle program
|
|
)
|
|
{
|
|
Span<int> requiredLength = stackalloc int[1];
|
|
GL.GetProgramiv(program, glConst.INFO_LOG_LENGTH, requiredLength);
|
|
if (requiredLength[0] <= 1) {
|
|
return "OpenGL did not provide a program info log.";
|
|
}
|
|
|
|
byte[] bytes = new byte[requiredLength[0]];
|
|
GL.GetProgramInfoLog(program, out int written, bytes);
|
|
return Encoding.UTF8
|
|
.GetString(bytes, 0, Math.Clamp(written, 0, bytes.Length))
|
|
.TrimEnd('\0');
|
|
}
|
|
|
|
private string GetShaderInfoLog(
|
|
GlHandle shader
|
|
)
|
|
{
|
|
Span<int> requiredLength = stackalloc int[1];
|
|
GL.GetShaderiv(shader, glConst.INFO_LOG_LENGTH, requiredLength);
|
|
if (requiredLength[0] <= 1) {
|
|
return "OpenGL did not provide a shader info log.";
|
|
}
|
|
|
|
byte[] bytes = new byte[requiredLength[0]];
|
|
GL.GetShaderInfoLog(shader, out int written, bytes);
|
|
return Encoding.UTF8
|
|
.GetString(bytes, 0, Math.Clamp(written, 0, bytes.Length))
|
|
.TrimEnd('\0');
|
|
}
|
|
|
|
private void LinkShaderProgram(
|
|
GlHandle program
|
|
)
|
|
{
|
|
GL.LinkProgram(program);
|
|
|
|
Span<int> status = stackalloc int[1];
|
|
GL.GetProgramiv(program, glConst.LINK_STATUS, status);
|
|
if (status[0] != 0) {
|
|
return;
|
|
}
|
|
|
|
throw new InvalidOperationException(
|
|
$"Failed to link shader program.{Environment.NewLine}{GetProgramInfoLog(program)}");
|
|
}
|
|
|
|
}
|
|
}
|