Compare commits
No commits in common. "3484dce8c5644536a44f4d3c0e54a9d79eafba1f" and "d831c9b72dc05102a6cdd918dfec56beef108b25" have entirely different histories.
3484dce8c5
...
d831c9b72d
@ -1,158 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Quik.Media.Font
|
|
||||||
{
|
|
||||||
public struct FontAtlasGlyphInfo
|
|
||||||
{
|
|
||||||
public int Codepoint;
|
|
||||||
public QImage Image;
|
|
||||||
public QRectangle UVs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FontAtlas
|
|
||||||
{
|
|
||||||
private readonly int width, height;
|
|
||||||
private readonly List<AtlasPage> atlases = new List<AtlasPage>();
|
|
||||||
private readonly Dictionary<int, FontAtlasGlyphInfo> glyphs = new Dictionary<int, FontAtlasGlyphInfo>();
|
|
||||||
private int index = 0;
|
|
||||||
private AtlasPage last = null;
|
|
||||||
|
|
||||||
public FontAtlas(int width, int height)
|
|
||||||
{
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool GetGlyph(int codepoint, out FontAtlasGlyphInfo info)
|
|
||||||
{
|
|
||||||
return glyphs.TryGetValue(codepoint, out info);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PutGlyph(int codepoint, QImageLock source, out FontAtlasGlyphInfo info)
|
|
||||||
{
|
|
||||||
info = new FontAtlasGlyphInfo() { Codepoint = codepoint };
|
|
||||||
|
|
||||||
if (last == null || last.IsFull)
|
|
||||||
{
|
|
||||||
AddPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
last.PutGlyph(source, ref info);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddPage()
|
|
||||||
{
|
|
||||||
index++;
|
|
||||||
|
|
||||||
if (index < atlases.Count)
|
|
||||||
{
|
|
||||||
last = atlases[index];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
last = new AtlasPage(width, height);
|
|
||||||
atlases.Add(last);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
// Trim any pages that were not used yet.
|
|
||||||
for (int i = atlases.Count -1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (atlases[i].PointerX != 0 && atlases[i].PointerY != 0)
|
|
||||||
{
|
|
||||||
for (int j = i + 1; j < atlases.Count; j++)
|
|
||||||
{
|
|
||||||
atlases[j].Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i != atlases.Count - 1)
|
|
||||||
atlases.RemoveRange(i+1, atlases.Count - i - 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atlases.Count > 0)
|
|
||||||
{
|
|
||||||
last = atlases[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
last = null;
|
|
||||||
}
|
|
||||||
index = -1;
|
|
||||||
|
|
||||||
glyphs.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AtlasPage : IDisposable
|
|
||||||
{
|
|
||||||
public QImage Image;
|
|
||||||
public int PointerX, PointerY;
|
|
||||||
public int RowHeight;
|
|
||||||
|
|
||||||
public bool IsFull => PointerX > Image.Width || PointerY > Image.Height;
|
|
||||||
|
|
||||||
public AtlasPage(int width, int height)
|
|
||||||
{
|
|
||||||
Image = new QImageBuffer(QImageFormat.RedU8, width, height);
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PutGlyph(QImageLock src, ref FontAtlasGlyphInfo prototype)
|
|
||||||
{
|
|
||||||
if (IsFull)
|
|
||||||
throw new Exception("Page is full!");
|
|
||||||
|
|
||||||
Image.LockBits2d(out QImageLock dst, QImageLockOptions.Default);
|
|
||||||
src.CopyTo(dst, PointerX, PointerY);
|
|
||||||
Image.UnlockBits();
|
|
||||||
|
|
||||||
QVec2 min = new QVec2(PointerX/Image.Width, PointerY/Image.Width);
|
|
||||||
QVec2 size = new QVec2(src.Width/Image.Width, src.Height/Image.Height);
|
|
||||||
|
|
||||||
prototype.Image = Image;
|
|
||||||
prototype.UVs = new QRectangle(min + size, min);
|
|
||||||
|
|
||||||
AdvanceColumn(src.Width, src.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
RowHeight = PointerX = PointerY = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AdvanceRow()
|
|
||||||
{
|
|
||||||
PointerX = 0;
|
|
||||||
PointerY += RowHeight;
|
|
||||||
|
|
||||||
RowHeight = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AdvanceColumn(int width, int height)
|
|
||||||
{
|
|
||||||
RowHeight = Math.Max(RowHeight, height);
|
|
||||||
PointerX += width;
|
|
||||||
|
|
||||||
if (PointerX > Image.Width)
|
|
||||||
{
|
|
||||||
AdvanceRow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool isDisposed = false;
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (isDisposed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Image?.Dispose();
|
|
||||||
|
|
||||||
isDisposed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Quik.Media
|
namespace Quik.Media
|
||||||
{
|
{
|
||||||
public abstract class QImage : IDisposable
|
public abstract class QImage : IDisposable
|
||||||
@ -61,60 +62,5 @@ namespace Quik.Media
|
|||||||
Depth = depth;
|
Depth = depth;
|
||||||
ImagePtr = ptr;
|
ImagePtr = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void CopyTo(QImageLock destination, int x, int y)
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
Width + x > destination.Width ||
|
|
||||||
Height + y > destination.Height)
|
|
||||||
{
|
|
||||||
throw new Exception("Image falls outside the bounds of the destination.");
|
|
||||||
}
|
|
||||||
else if (Format != destination.Format)
|
|
||||||
{
|
|
||||||
throw new Exception("Image formats must be the same.");
|
|
||||||
}
|
|
||||||
|
|
||||||
int bpp = Format.BytesPerPixel();
|
|
||||||
for (int i = 0; i < Height; i++)
|
|
||||||
{
|
|
||||||
IntPtr srcPtr = (IntPtr)((long)ImagePtr + i * bpp);
|
|
||||||
|
|
||||||
long dstPos = x + i * destination.Width;
|
|
||||||
IntPtr dstPtr = (IntPtr)((long)destination.ImagePtr + dstPos * bpp);
|
|
||||||
|
|
||||||
Buffer.MemoryCopy((void*)srcPtr, (void*)dstPtr, Width * bpp, Width * bpp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe void ExtractFrom(QImageLock destination, int x, int y, int width, int height)
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
width != destination.Width ||
|
|
||||||
height != destination.Height)
|
|
||||||
{
|
|
||||||
throw new Exception("Destination is not the same size as the subregion.");
|
|
||||||
}
|
|
||||||
else if (x + width > Width || y + height > Height)
|
|
||||||
{
|
|
||||||
throw new Exception("The subregion is larger than this image.");
|
|
||||||
}
|
|
||||||
else if (Format != destination.Format)
|
|
||||||
{
|
|
||||||
throw new Exception("Image formats must be the same.");
|
|
||||||
}
|
|
||||||
|
|
||||||
int bpp = Format.BytesPerPixel();
|
|
||||||
for (int i = 0; i < height; i++)
|
|
||||||
{
|
|
||||||
long srcPos = x + y * i;
|
|
||||||
IntPtr srcPtr = (IntPtr)((long)ImagePtr + srcPos * bpp);
|
|
||||||
|
|
||||||
long dstPos = i * destination.Width;
|
|
||||||
IntPtr dstPtr = (IntPtr)((long)destination.ImagePtr + dstPos * bpp);
|
|
||||||
|
|
||||||
Buffer.MemoryCopy((void*)srcPtr, (void*)dstPtr, width * bpp, width * bpp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user