Compare commits

...

4 Commits

9 changed files with 270 additions and 46 deletions

@ -11,12 +11,14 @@ namespace Quik.Media.Defaults
{ {
private readonly StbImage image; private readonly StbImage image;
private QImageBuffer buffer; private QImageBuffer buffer;
private bool isSdf = false;
public override int Width => image.Width; public override int Width => image.Width;
public override int Height => image.Height; public override int Height => image.Height;
public override int Depth => 1; public override int Depth => 1;
public override bool IsSdf => isSdf;
public override QImageFormat InternalFormat => Stb2QImageFormat(image.Format); public override QImageFormat InternalFormat => Stb2QImageFormat(image.Format);
public QImageStbi(Stream source) public QImageStbi(Stream source)
@ -79,6 +81,11 @@ namespace Quik.Media.Defaults
buffer.UnlockBits(); buffer.UnlockBits();
} }
public void SdfHint(bool value = true)
{
isSdf = value;
}
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
base.Dispose(disposing); base.Dispose(disposing);

@ -1,3 +1,4 @@
using Quik.Media;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -214,7 +215,7 @@ namespace Quik.CommandMachine
} }
} }
public void Image(QuikTexture texture, in QRectangle rectangle) public void Image(QImage texture, in QRectangle rectangle)
{ {
Enqueue(Command.Image); Enqueue(Command.Image);
Enqueue((Frame)(int)ImageCommandFlags.Single); Enqueue((Frame)(int)ImageCommandFlags.Single);
@ -222,7 +223,7 @@ namespace Quik.CommandMachine
Enqueue(rectangle); Enqueue(rectangle);
} }
public void Image(QuikTexture texture, in QRectangle rectangle, in QRectangle uv) public void Image(QImage texture, in QRectangle rectangle, in QRectangle uv)
{ {
Enqueue(Command.Image); Enqueue(Command.Image);
Enqueue((Frame)(int)(ImageCommandFlags.Single | ImageCommandFlags.UVs)); Enqueue((Frame)(int)(ImageCommandFlags.Single | ImageCommandFlags.UVs));
@ -231,7 +232,7 @@ namespace Quik.CommandMachine
Enqueue(uv); Enqueue(uv);
} }
public void Image(QuikTexture texture, ReadOnlySpan<QRectangle> rectangles, bool interleavedUV = false) public void Image(QImage texture, ReadOnlySpan<QRectangle> rectangles, bool interleavedUV = false)
{ {
int count = rectangles.Length; int count = rectangles.Length;
ImageCommandFlags flags = ImageCommandFlags.None; ImageCommandFlags flags = ImageCommandFlags.None;
@ -252,7 +253,7 @@ namespace Quik.CommandMachine
} }
} }
public void Image(QuikTexture texture, ReadOnlySpan<QRectangle> rectangles, ReadOnlySpan<QRectangle> uvs) public void Image(QImage texture, ReadOnlySpan<QRectangle> rectangles, ReadOnlySpan<QRectangle> uvs)
{ {
int count = Math.Min(rectangles.Length, uvs.Length); int count = Math.Min(rectangles.Length, uvs.Length);
Enqueue(Command.Image); Enqueue(Command.Image);
@ -266,7 +267,7 @@ namespace Quik.CommandMachine
} }
} }
public void Image3D(QuikTexture texture, in Image3DCall call) public void Image3D(QImage texture, in Image3DCall call)
{ {
Enqueue(Command.Image); Enqueue(Command.Image);
Enqueue(new Frame(ImageCommandFlags.Image3d | ImageCommandFlags.Single)); Enqueue(new Frame(ImageCommandFlags.Image3d | ImageCommandFlags.Single));
@ -276,7 +277,7 @@ namespace Quik.CommandMachine
Enqueue(new Frame(call.Layer)); Enqueue(new Frame(call.Layer));
} }
public void Image3D(QuikTexture texture, ReadOnlySpan<Image3DCall> calls) public void Image3D(QImage texture, ReadOnlySpan<Image3DCall> calls)
{ {
Enqueue(Command.Image); Enqueue(Command.Image);
Enqueue(new Frame((int)ImageCommandFlags.Image3d, calls.Length)); Enqueue(new Frame((int)ImageCommandFlags.Image3d, calls.Length));

@ -10,6 +10,7 @@ namespace Quik.Media
public abstract QImageFormat InternalFormat { get; } public abstract QImageFormat InternalFormat { get; }
public virtual int MipMapLevels => 0; public virtual int MipMapLevels => 0;
public virtual bool Premultiplied => false; public virtual bool Premultiplied => false;
public virtual bool IsSdf => false;
public abstract void LockBits2d(out QImageLock imageLock, QImageLockOptions options); public abstract void LockBits2d(out QImageLock imageLock, QImageLockOptions options);
public abstract void LockBits3d(out QImageLock imageLock, QImageLockOptions options); public abstract void LockBits3d(out QImageLock imageLock, QImageLockOptions options);

@ -9,7 +9,9 @@ namespace Quik.OpenGL
private delegate void PixelStoreiProc(GLEnum pname, int param); private delegate void PixelStoreiProc(GLEnum pname, int param);
private delegate void PixelStorefProc(GLEnum pname, float param); private delegate void PixelStorefProc(GLEnum pname, float param);
private delegate void TexImage2DProc(GLEnum target, int level, GLEnum internalFormat, int width, int height, int border, GLEnum format, GLEnum pixelType, void *data); private delegate void TexImage2DProc(GLEnum target, int level, GLEnum internalFormat, int width, int height, int border, GLEnum format, GLEnum pixelType, void *data);
private delegate void TexImage3DProc(GLEnum target, int level, GLEnum internalFormat, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, void* data);
private delegate void TexSubImage2DProc(GLEnum target, int level, int x, int y, int width, int height, GLEnum format, GLEnum pixelType, void *data); private delegate void TexSubImage2DProc(GLEnum target, int level, int x, int y, int width, int height, GLEnum format, GLEnum pixelType, void *data);
private delegate void TexSubImage3DProc(GLEnum target, int level, int x, int y, int z, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, void* data);
private delegate void TexParameteriProc(GLEnum target, GLEnum pname, int value); private delegate void TexParameteriProc(GLEnum target, GLEnum pname, int value);
private delegate void TexParameterfProc(GLEnum target, GLEnum pname, float value); private delegate void TexParameterfProc(GLEnum target, GLEnum pname, float value);
private delegate void TexParameterivProc(GLEnum target, GLEnum pname, int* value); private delegate void TexParameterivProc(GLEnum target, GLEnum pname, int* value);
@ -23,7 +25,9 @@ namespace Quik.OpenGL
private static PixelStoreiProc _pixelStorei; private static PixelStoreiProc _pixelStorei;
private static PixelStorefProc _pixelStoref; private static PixelStorefProc _pixelStoref;
private static TexImage2DProc _texImage2D; private static TexImage2DProc _texImage2D;
private static TexImage3DProc _texImage3D;
private static TexSubImage2DProc _texSubImage2D; private static TexSubImage2DProc _texSubImage2D;
private static TexSubImage3DProc _texSubImage3D;
private static TexParameteriProc _texParameteri; private static TexParameteriProc _texParameteri;
private static TexParameterfProc _texParameterf; private static TexParameterfProc _texParameterf;
private static TexParameterivProc _texParameteriv; private static TexParameterivProc _texParameteriv;
@ -39,7 +43,9 @@ namespace Quik.OpenGL
_pixelStorei = GetProcAddress<PixelStoreiProc>("glPixelStorei"); _pixelStorei = GetProcAddress<PixelStoreiProc>("glPixelStorei");
_pixelStoref = GetProcAddress<PixelStorefProc>("glPixelStoref"); _pixelStoref = GetProcAddress<PixelStorefProc>("glPixelStoref");
_texImage2D = GetProcAddress<TexImage2DProc>("glTexImage2D"); _texImage2D = GetProcAddress<TexImage2DProc>("glTexImage2D");
_texImage3D = GetProcAddress<TexImage3DProc>("glTexImage3D");
_texSubImage2D = GetProcAddress<TexSubImage2DProc>("glTexSubImage2D"); _texSubImage2D = GetProcAddress<TexSubImage2DProc>("glTexSubImage2D");
_texSubImage3D = GetProcAddress<TexSubImage3DProc>("glTexSubImage3D");
_texParameteri = GetProcAddress<TexParameteriProc>("glTexParameteri"); _texParameteri = GetProcAddress<TexParameteriProc>("glTexParameteri");
_texParameterf = GetProcAddress<TexParameterfProc>("glTexParameterf"); _texParameterf = GetProcAddress<TexParameterfProc>("glTexParameterf");
_texParameteriv = GetProcAddress<TexParameterivProc>("glTexParameteriv"); _texParameteriv = GetProcAddress<TexParameterivProc>("glTexParameteriv");
@ -92,7 +98,7 @@ namespace Quik.OpenGL
_texImage2D(target, level, internalFormat, width, height, border, format, pixelType, (void*)data); _texImage2D(target, level, internalFormat, width, height, border, format, pixelType, (void*)data);
[MethodImpl(AggressiveInlining)] [MethodImpl(AggressiveInlining)]
public static void TexImage2d<T>(GLEnum target, int level, GLEnum internalFormat, int width, int height, int border, GLEnum format, GLEnum pixelType, in T data) where T : unmanaged public static void TexImage2D<T>(GLEnum target, int level, GLEnum internalFormat, int width, int height, int border, GLEnum format, GLEnum pixelType, in T data) where T : unmanaged
{ {
fixed(T *ptr = &data) fixed(T *ptr = &data)
_texImage2D(target, level, internalFormat, width, height, border, format, pixelType, ptr); _texImage2D(target, level, internalFormat, width, height, border, format, pixelType, ptr);
@ -100,7 +106,24 @@ namespace Quik.OpenGL
[MethodImpl(AggressiveInlining)] [MethodImpl(AggressiveInlining)]
public static void TexImage2D<T>(GLEnum target, int level, GLEnum internalFormat, int width, int height, int border, GLEnum format, GLEnum pixelType, T[] data) where T : unmanaged => public static void TexImage2D<T>(GLEnum target, int level, GLEnum internalFormat, int width, int height, int border, GLEnum format, GLEnum pixelType, T[] data) where T : unmanaged =>
TexImage2d<T>(target, level, internalFormat, width, height, border, format, pixelType, in data[0]); TexImage2D(target, level, internalFormat, width, height, border, format, pixelType, in data[0]);
[MethodImpl(AggressiveInlining)]
public static void TexImage3D(GLEnum target, int level, GLEnum internalFormat, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, void* data) =>
_texImage3D(target, level, internalFormat, width, height, depth, border, format, pixelType, data);
[MethodImpl(AggressiveInlining)]
public static void TexImage3D<T>(GLEnum target, int level, GLEnum internalFormat, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, in T data)
where T : unmanaged
{
fixed (T* ptr = &data)
_texImage3D(target, level, internalFormat, width, height, depth, border, format, pixelType, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void TexImage3D<T>(GLEnum target, int level, GLEnum internalFormat, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, T[] data)
where T : unmanaged =>
TexImage3D(target, level, internalFormat, width, height, depth, border, format, pixelType, in data[0]);
[MethodImpl(AggressiveInlining)] [MethodImpl(AggressiveInlining)]
public static void TexSubImage2D(GLEnum target, int level, int x, int y, int width, int height, GLEnum format, GLEnum pixelType, IntPtr data) => public static void TexSubImage2D(GLEnum target, int level, int x, int y, int width, int height, GLEnum format, GLEnum pixelType, IntPtr data) =>
@ -117,6 +140,23 @@ namespace Quik.OpenGL
public static void TexSubImage2D<T>(GLEnum target, int level, int x, int y, int width, int height, GLEnum format, GLEnum pixelType, T[] data) where T : unmanaged => public static void TexSubImage2D<T>(GLEnum target, int level, int x, int y, int width, int height, GLEnum format, GLEnum pixelType, T[] data) where T : unmanaged =>
TexSubImage2d<T>(target, level, x, y, width, height, format, pixelType, in data[0]); TexSubImage2d<T>(target, level, x, y, width, height, format, pixelType, in data[0]);
[MethodImpl(AggressiveInlining)]
public static void TexSubImage3D(GLEnum target, int level, int x, int y, int z, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, void* data) =>
_texSubImage3D(target, level, x, y, z, width, height, depth, border, format, pixelType, data);
[MethodImpl(AggressiveInlining)]
public static void TexSubImage3D<T>(GLEnum target, int level, int x, int y, int z, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, in T data)
where T : unmanaged
{
fixed (T* ptr = &data)
_texSubImage3D(target, level, x, y, z, width, height, depth, border, format, pixelType, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void TexSubImage3D<T>(GLEnum target, int level, int x, int y, int z, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, T[] data)
where T : unmanaged =>
TexSubImage3D(target, level, x, y, z, width, height, depth, border, format, pixelType, in data[0]);
[MethodImpl(AggressiveInlining)] [MethodImpl(AggressiveInlining)]
public static void TexParameter(GLEnum target, GLEnum pname, int value) => _texParameteri(target, pname, value); public static void TexParameter(GLEnum target, GLEnum pname, int value) => _texParameteri(target, pname, value);
[MethodImpl(AggressiveInlining)] [MethodImpl(AggressiveInlining)]

@ -3,6 +3,8 @@ using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using Quik.VertexGenerator; using Quik.VertexGenerator;
using static Quik.OpenGL.GLEnum; using static Quik.OpenGL.GLEnum;
using Quik.Media;
using System.Linq;
namespace Quik.OpenGL namespace Quik.OpenGL
{ {
@ -10,18 +12,23 @@ namespace Quik.OpenGL
{ {
private int program; private int program;
private int v2Position; private int v2Position;
private int iZIndex; private int fZIndex;
private int v2TexPos; private int v2TexPos;
private int fTexLayer;
private int v4Color; private int v4Color;
private int m4Transforms; private int m4Transforms;
private int iMaxZ; private int fMaxZ;
private int iEnableSdf; private int iEnableSdf;
private int iEnableTexture; private int iEnableTexture;
private int iAlphaDiscard; private int iAlphaDiscard;
private int fSdfThreshold; private int fSdfThreshold;
private int txTexture; private int tx2d;
private int tx2darray;
private bool isDiposed; private bool isDiposed;
private readonly Dictionary<DrawQueue, DrawData> data = new Dictionary<DrawQueue, DrawData>(); private readonly Dictionary<DrawQueue, DrawData> data = new Dictionary<DrawQueue, DrawData>();
private readonly TextureManager textures = new TextureManager();
public bool IsInit { get; private set; } = false; public bool IsInit { get; private set; } = false;
public event Action<GL21Driver> OnGCDispose; public event Action<GL21Driver> OnGCDispose;
@ -57,16 +64,19 @@ namespace Quik.OpenGL
GL.DeleteShader(fs); GL.DeleteShader(fs);
v2Position = GL.GetAttribLocation(program, nameof(v2Position)); v2Position = GL.GetAttribLocation(program, nameof(v2Position));
iZIndex = GL.GetAttribLocation(program, nameof(iZIndex)); fZIndex = GL.GetAttribLocation(program, nameof(fZIndex));
v2TexPos = GL.GetAttribLocation(program, nameof(v2TexPos)); v2TexPos = GL.GetAttribLocation(program, nameof(v2TexPos));
fTexLayer = GL.GetAttribLocation(program, nameof(fTexLayer));
v4Color = GL.GetAttribLocation(program, nameof(v4Color)); v4Color = GL.GetAttribLocation(program, nameof(v4Color));
m4Transforms = GL.GetUniformLocation(program, nameof(m4Transforms)); m4Transforms = GL.GetUniformLocation(program, nameof(m4Transforms));
iMaxZ = GL.GetUniformLocation(program, nameof(iMaxZ)); fMaxZ = GL.GetUniformLocation(program, nameof(fMaxZ));
fSdfThreshold = GL.GetUniformLocation(program, nameof(fSdfThreshold));
iEnableSdf = GL.GetUniformLocation(program, nameof(iEnableSdf)); iEnableSdf = GL.GetUniformLocation(program, nameof(iEnableSdf));
iEnableTexture = GL.GetUniformLocation(program, nameof(iEnableSdf)); iEnableTexture = GL.GetUniformLocation(program, nameof(iEnableTexture));
iAlphaDiscard = GL.GetUniformLocation(program, nameof(iAlphaDiscard)); iAlphaDiscard = GL.GetUniformLocation(program, nameof(iAlphaDiscard));
txTexture = GL.GetUniformLocation(program, nameof(txTexture)); tx2d = GL.GetUniformLocation(program, nameof(tx2d));
tx2darray = GL.GetUniformLocation(program, nameof(tx2darray));
IsInit = true; IsInit = true;
} }
@ -93,23 +103,39 @@ namespace Quik.OpenGL
QMat4.Orthographic(out QMat4 matrix, view); QMat4.Orthographic(out QMat4 matrix, view);
GL.UseProgram(program); GL.UseProgram(program);
GL.Uniform1(iMaxZ, queue.ZDepth+1); GL.Uniform1(fMaxZ, (float)(queue.ZDepth+1));
GL.UniformMatrix4(m4Transforms, false, in matrix); GL.UniformMatrix4(m4Transforms, false, in matrix);
GL.Uniform1(fSdfThreshold, 0.0f); GL.Uniform1(fSdfThreshold, 0.0f);
GL.Uniform1(txTexture, 0); GL.Uniform1(tx2d, 0);
GL.Enable(GL_BLEND); GL.Enable(GL_BLEND);
GL.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
foreach (DrawCall call in queue) foreach (DrawCall call in queue)
{ {
GL.Viewport(
(int)call.Bounds.Left,
(int)(view.Bottom - call.Bounds.Bottom),
(int)call.Bounds.Right,
(int)(view.Bottom - call.Bounds.Top));
GL.ActiveTexture(GL_TEXTURE0); GL.ActiveTexture(GL_TEXTURE0);
GL.BindTexture(GL_TEXTURE_2D, 0); GL.BindTexture(GL_TEXTURE_2D, 0);
if (call.Texture != null) if (call.Texture != null)
{ {
// TODO: actually use textures? GL.Uniform1(iEnableSdf, call.Texture.IsSdf ? 1 : 0);
GL.Uniform1(iEnableTexture, 1);
GL.Uniform1(iEnableSdf, call.Texture.SignedDistanceField ? 1 : 0);
GL.Uniform1(iAlphaDiscard, 1); GL.Uniform1(iAlphaDiscard, 1);
if (call.Texture.Depth > 1)
{
GL.Uniform1(iEnableTexture, 3);
GL.ActiveTexture(GL_TEXTURE1);
GL.BindTexture(GL_TEXTURE_2D_ARRAY, textures.GetTexture(call.Texture));
}
else
{
GL.Uniform1(iEnableTexture, 2);
GL.ActiveTexture(GL_TEXTURE0);
GL.BindTexture(GL_TEXTURE_2D, textures.GetTexture(call.Texture));
}
} }
else else
{ {
@ -254,13 +280,15 @@ namespace Quik.OpenGL
GL.BufferData(GL_ARRAY_BUFFER, QuikVertex.Stride * Queue.VertexCount, Queue.VertexArray, GL_STREAM_DRAW); GL.BufferData(GL_ARRAY_BUFFER, QuikVertex.Stride * Queue.VertexCount, Queue.VertexArray, GL_STREAM_DRAW);
GL.VertexAttribPointer(driver.v2Position, 2, GL_FLOAT, false, QuikVertex.Stride, QuikVertex.PositionOffset); GL.VertexAttribPointer(driver.v2Position, 2, GL_FLOAT, false, QuikVertex.Stride, QuikVertex.PositionOffset);
GL.VertexAttribIPointer(driver.iZIndex, 1, GL_UNSIGNED_INT, QuikVertex.Stride, QuikVertex.ZIndexOffset); GL.VertexAttribPointer(driver.fZIndex, 1, GL_UNSIGNED_INT, false, QuikVertex.Stride, QuikVertex.ZIndexOffset);
GL.VertexAttribPointer(driver.v2TexPos, 2, GL_FLOAT, false, QuikVertex.Stride, QuikVertex.TextureCoordinatesOffset); GL.VertexAttribPointer(driver.v2TexPos, 2, GL_FLOAT, false, QuikVertex.Stride, QuikVertex.TextureCoordinatesOffset);
GL.VertexAttribPointer(driver.fTexLayer, 1, GL_FLOAT, false, QuikVertex.Stride, QuikVertex.TextureLayerOffset);
GL.VertexAttribPointer(driver.v4Color, 4, GL_UNSIGNED_BYTE, true, QuikVertex.Stride, QuikVertex.ColorOffset); GL.VertexAttribPointer(driver.v4Color, 4, GL_UNSIGNED_BYTE, true, QuikVertex.Stride, QuikVertex.ColorOffset);
GL.EnableVertexAttribArray(driver.v2Position); GL.EnableVertexAttribArray(driver.v2Position);
GL.EnableVertexAttribArray(driver.iZIndex); GL.EnableVertexAttribArray(driver.fZIndex);
GL.EnableVertexAttribArray(driver.v2TexPos); GL.EnableVertexAttribArray(driver.v2TexPos);
GL.EnableVertexAttribArray(driver.v4Color); GL.EnableVertexAttribArray(driver.v4Color);
GL.EnableVertexAttribArray(driver.fTexLayer);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, Queue.ElementCount * sizeof(int), Queue.ElementArray, GL_STREAM_DRAW); GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, Queue.ElementCount * sizeof(int), Queue.ElementArray, GL_STREAM_DRAW);
@ -287,4 +315,115 @@ namespace Quik.OpenGL
} }
} }
} }
internal class TextureManager : IDisposable
{
private readonly Dictionary<QImage, int> textures = new Dictionary<QImage, int>();
private readonly HashSet<QImage> imagesNotUsed = new HashSet<QImage>();
private bool isDisposed = false;
public void BeginFrame()
{
if (imagesNotUsed.Count > 0)
{
foreach (QImage image in imagesNotUsed)
{
GL.DeleteTexture(textures[image]);
}
imagesNotUsed.Clear();
}
foreach (QImage image in textures.Keys)
{
imagesNotUsed.Add(image);
}
}
public int GetTexture(QImage image)
{
if (textures.TryGetValue(image, out int texture))
{
return texture;
}
if (image.Depth > 1)
{
texture = UploadTexture3d(image);
}
else
{
texture = UploadTexture2d(image);
}
return textures[image] = texture;
}
public int UploadTexture3d(QImage image3d)
{
int texture = GL.GenTexture();
GL.BindTexture(GL_TEXTURE_2D_ARRAY, texture);
image3d.LockBits3d(out QImageLock lck, QImageLockOptions.Default);
GL.TexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, lck.Width, lck.Height, lck.Depth, 0, s_InternalFormat[lck.Format], s_PixelType[lck.Format], lck.ImagePtr);
image3d.UnlockBits();
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return texture;
}
public int UploadTexture2d(QImage image2d)
{
int texture = GL.GenTexture();
GL.BindTexture(GL_TEXTURE_2D, texture);
image2d.LockBits2d(out QImageLock lck, QImageLockOptions.Default);
GL.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lck.Width, lck.Height, 0, s_InternalFormat[lck.Format], s_PixelType[lck.Format], lck.ImagePtr);
image2d.UnlockBits();
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return texture;
}
public void Dispose()
{
if (isDisposed)
return;
isDisposed = true;
int[] ids = textures.Values.ToArray();
GL.DeleteTextures(ids);
}
private static readonly Dictionary<QImageFormat, GLEnum> s_InternalFormat = new Dictionary<QImageFormat, GLEnum>()
{
[QImageFormat.AlphaF] = GL_ALPHA,
[QImageFormat.AlphaU8] = GL_ALPHA,
[QImageFormat.RedF] = GL_RED,
[QImageFormat.RedU8] = GL_RED,
[QImageFormat.RgbF] = GL_RGB,
[QImageFormat.RgbU8] = GL_RGB,
[QImageFormat.RgbaU8] = GL_RGBA,
[QImageFormat.RgbaF] = GL_RGBA,
};
private static readonly Dictionary<QImageFormat, GLEnum> s_PixelType = new Dictionary<QImageFormat, GLEnum>()
{
[QImageFormat.AlphaF] = GL_FLOAT,
[QImageFormat.RedF] = GL_FLOAT,
[QImageFormat.RgbF] = GL_FLOAT,
[QImageFormat.RgbaF] = GL_FLOAT,
[QImageFormat.AlphaU8] = GL_UNSIGNED_BYTE,
[QImageFormat.RedU8] = GL_UNSIGNED_BYTE,
[QImageFormat.RgbU8] = GL_UNSIGNED_BYTE,
[QImageFormat.RgbaU8] = GL_UNSIGNED_BYTE,
};
}
} }

@ -50,6 +50,7 @@ namespace Quik.OpenGL
GL_TEXTURE6 = GL_TEXTURE0 + 6, GL_TEXTURE6 = GL_TEXTURE0 + 6,
GL_TEXTURE_2D = 0x0DE1, GL_TEXTURE_2D = 0x0DE1,
GL_TEXTURE_2D_ARRAY = 0x8C1A,
GL_UNPACK_ALIGNMENT = 0x0CF5, GL_UNPACK_ALIGNMENT = 0x0CF5,
GL_TEXTURE_MAG_FILTER = 0x2800, GL_TEXTURE_MAG_FILTER = 0x2800,

@ -12,7 +12,7 @@ namespace Quik
{ {
public float X; public float X;
public float Y; public float Y;
public float Magnitude => MathF.Sqrt(X * X + Y * Y); public float Magnitude => MathF.Sqrt(X * X + Y * Y);
public QVec2(float x, float y) public QVec2(float x, float y)
@ -92,6 +92,10 @@ namespace Quik
{ {
return $"({X}; {Y})"; return $"({X}; {Y})";
} }
public static readonly QVec2 Zero = new QVec2(0, 0);
public static readonly QVec2 UnitX = new QVec2(1, 0);
public static readonly QVec2 UnitY = new QVec2(0, 1);
} }
/// <summary> /// <summary>

@ -2,16 +2,34 @@
* QUIK: User Interface Kit * QUIK: User Interface Kit
* Copyright (C) 2023 Halit Utku Maden, et al. * Copyright (C) 2023 Halit Utku Maden, et al.
*/ */
#version 120 #version 130
varying vec2 fv2TexPos; in vec2 fv2TexPos;
varying vec4 fv4Color; in vec4 fv4Color;
in float ffTexLayer;
uniform int iEnableSdf; out vec4 fragColor;
uniform int iEnableTexture;
uniform int iAlphaDiscard; uniform int iEnableSdf;
uniform float fSdfThreshold; uniform int iEnableTexture;
uniform sampler2D txTexture; uniform int iAlphaDiscard;
uniform float fSdfThreshold;
uniform sampler2D tx2d;
uniform sampler2DArray tx2dArray;
const float fAlphaThreshold = 0.01;
vec4 getTexture()
{
if (iEnableTexture == 3)
{
return texture(tx2dArray, vec3(fv2TexPos, ffTexLayer));
}
else
{
return texture(tx2d, fv2TexPos);
}
}
void main(void) void main(void)
{ {
@ -19,16 +37,19 @@ void main(void)
if (iEnableTexture != 0) if (iEnableTexture != 0)
{ {
vec4 value = texture2D(txTexture, fv2TexPos); vec4 value = getTexture();
if (iEnableSdf != 0) if (iEnableSdf != 0)
{ {
float a = max(value.r, value.a); float a = max(value.r, value.a);
value = (a >= fSdfThreshold) ? vec4(1,1,1,1) : vec4(0,0,0,0); value =
(a >= fSdfThreshold) ?
vec4(1.0,1.0,1.0,1.0) :
vec4(0.0,0.0,0.0,0.0);
} }
if (iAlphaDiscard != 0 && value.a == 0.0) if (iAlphaDiscard != 0 && value.a <= fAlphaThreshold)
{ {
discard; discard;
} }
@ -36,5 +57,5 @@ void main(void)
albedo = albedo * value; albedo = albedo * value;
} }
gl_FragColor = albedo; fragColor = albedo;
} }

@ -2,24 +2,34 @@
* QUIK: User Interface Kit * QUIK: User Interface Kit
* Copyright (C) 2023 Halit Utku Maden, et al. * Copyright (C) 2023 Halit Utku Maden, et al.
*/ */
#version 120 #version 130
attribute vec2 v2Position; /**< The vertex position.*/ in vec2 v2Position; /**< The vertex position.*/
attribute int iZIndex; /**< The z index. */ in float fZIndex; /**< The z index. */
attribute vec2 v2TexPos; /**< The texture coorindates. */ in vec2 v2TexPos; /**< The texture coorindates. */
attribute vec4 v4Color; /**< The vertex color. */ in float fTexLayer; /**< The texture layer for 3D textures. */
in vec4 v4Color; /**< The vertex color. */
varying vec2 fv2TexPos; out vec2 fv2TexPos;
varying vec4 fv4Color; out float ffTexLayer;
out vec4 fv4Color;
uniform mat4 m4Transforms; /**< The view matrix. */ uniform mat4 m4Transforms; /**< The view matrix. */
uniform int iMaxZ; /**< Highest Z coordinate. */ uniform float fMaxZ; /**< Highest Z coordinate. */
const mat4 m4BaseTransforms = mat4(
vec4( 2.0, 0.0, 0.0, 0.0),
vec4( 0.0, -2.0, 0.0, 0.0),
vec4( 0.0, 0.0, 1.0, 0.0),
vec4(-1.0, 1.0, 0.0, 1.0)
);
void main(void) void main(void)
{ {
vec4 v = vec4(v2Position, float(iZIndex)/float(iMaxZ), 1); vec4 v = vec4(v2Position, fZIndex/fMaxZ, 1);
gl_Position = v * m4Transforms; gl_Position = m4Transforms * v;
fv2TexPos = v2TexPos; fv2TexPos = v2TexPos;
fv4Color = v4Color; fv4Color = v4Color;
} ffTexLayer = fTexLayer;
}