implement slug data packing
This commit is contained in:
parent
53dbb8bf34
commit
91d7c75ca4
17
alloc.d
17
alloc.d
@ -314,24 +314,25 @@ AllocAlign(Arena* arena, u64 size, u64 alignment)
|
||||
{
|
||||
void* ptr = null;
|
||||
|
||||
u64 pool_alloc_size = size;
|
||||
if(pool_alloc_size > arena.def_size)
|
||||
{
|
||||
pool_alloc_size += arena.def_size;
|
||||
}
|
||||
|
||||
uintptr mem_pos, current, offset;
|
||||
ArenaPool* node = arena.first;
|
||||
while (true)
|
||||
{
|
||||
if(node == null)
|
||||
{
|
||||
if(size > arena.def_size)
|
||||
{
|
||||
size += arena.def_size;
|
||||
}
|
||||
|
||||
AddArenaPool(arena, Max(size, arena.def_size));
|
||||
AddArenaPool(arena, Max(pool_alloc_size, arena.def_size));
|
||||
node = arena.first;
|
||||
}
|
||||
|
||||
mem_pos = cast(uintptr)node.mem;
|
||||
current = mem_pos + node.pos;
|
||||
offset = AlignPow2(current, alignment) - mem_pos;
|
||||
offset = AlignPow2(current, alignment) - mem_pos;
|
||||
|
||||
if(offset+size <= node.length)
|
||||
{
|
||||
@ -341,7 +342,7 @@ AllocAlign(Arena* arena, u64 size, u64 alignment)
|
||||
node = node.next;
|
||||
}
|
||||
|
||||
ptr = &node.mem[offset];
|
||||
ptr = &node.mem[offset];
|
||||
node.pos = offset+size;
|
||||
|
||||
return ptr;
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#ifndef NO_STBI
|
||||
# include "external/stb/stb_image.h"
|
||||
# include "external/stb/stb_image_write.h"
|
||||
# include "external/stb/stb_truetype.h"
|
||||
#endif
|
||||
|
||||
#define CGLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
|
||||
3
external/stb/stb.c
vendored
3
external/stb/stb.c
vendored
@ -1,2 +1,5 @@
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "stb_truetype.h"
|
||||
|
||||
5079
external/stb/stb_truetype.h
vendored
Normal file
5079
external/stb/stb_truetype.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
538
fonts.d
538
fonts.d
@ -6,6 +6,120 @@ import dlib.util;
|
||||
import dlib.alloc;
|
||||
import dlib.math;
|
||||
import std.math.traits : isNaN;
|
||||
import std.math : Floor = floor;
|
||||
import std.algorithm.comparison : clamp;
|
||||
import std.algorithm.sorting;
|
||||
|
||||
const u64 FONT_MAX_BANDS = 8;
|
||||
const u64 FONT_TEX_WIDTH = 4096;
|
||||
|
||||
struct SlugCurveRef
|
||||
{
|
||||
u32 index;
|
||||
f32 sort_key;
|
||||
}
|
||||
|
||||
struct SlugBandEntry
|
||||
{
|
||||
u32[] indices;
|
||||
u32 count;
|
||||
}
|
||||
|
||||
struct SlugGlyphBandData
|
||||
{
|
||||
SlugBandEntry[FONT_MAX_BANDS][2] bands;
|
||||
U8Vec2 band_counts;
|
||||
}
|
||||
|
||||
struct SlugCurve
|
||||
{
|
||||
Vec2 p1, p2, p3;
|
||||
}
|
||||
|
||||
struct SlugRect
|
||||
{
|
||||
Vec2 min, max;
|
||||
}
|
||||
|
||||
struct SlugGlyph
|
||||
{
|
||||
SlugRect rect;
|
||||
IVec2 bearing;
|
||||
IVec2 size;
|
||||
Vec2 band_scale;
|
||||
Vec2 band_offset;
|
||||
i32 glyph_index;
|
||||
i32 advance;
|
||||
i32 curve_start;
|
||||
i32 curve_count;
|
||||
U16Vec2 coords;
|
||||
U8Vec2 max_bands;
|
||||
}
|
||||
|
||||
struct SlugFontInfo
|
||||
{
|
||||
SlugCurve[] curves;
|
||||
f32[] curve_texel_data;
|
||||
u32[] band_texel_data;
|
||||
SlugGlyphBandData[] glyph_bands;
|
||||
SlugFont base;
|
||||
|
||||
alias base this;
|
||||
}
|
||||
|
||||
struct SlugFont
|
||||
{
|
||||
SlugGlyph[128] glyphs;
|
||||
f32 scale;
|
||||
f32 line_height;
|
||||
i32 ascent;
|
||||
i32 descent;
|
||||
i32 line_gap;
|
||||
}
|
||||
|
||||
struct SlugVertex
|
||||
{
|
||||
union
|
||||
{
|
||||
Vec4 pos;
|
||||
struct
|
||||
{
|
||||
Vec2 vertex_coords;
|
||||
Vec2 normal;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
Vec4 tex;
|
||||
struct
|
||||
{
|
||||
Vec2 em_space_pos;
|
||||
U16Vec2 glyph_data_coords;
|
||||
struct max_bands
|
||||
{
|
||||
u8 x, pad, y, e;
|
||||
};
|
||||
}
|
||||
};
|
||||
union
|
||||
{
|
||||
Vec4 jac;
|
||||
struct
|
||||
{
|
||||
f32 p00, p01, p10, p11;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
Vec4 band;
|
||||
struct
|
||||
{
|
||||
Vec4 scale;
|
||||
Vec4 offset;
|
||||
};
|
||||
};
|
||||
Vec4 color;
|
||||
}
|
||||
|
||||
struct FontAtlas
|
||||
{
|
||||
@ -260,5 +374,429 @@ CreateAtlas(Arena* arena, FontFace font, u32 size, UVec2 atlas_dim)
|
||||
return atlas;
|
||||
}
|
||||
|
||||
void
|
||||
BuildFontGlyph(Arena* arena, u32 index, u32 glyph_index, SlugFontInfo* font_info, u32* curve_index, stbtt_fontinfo* stb_font_info)
|
||||
{
|
||||
SlugGlyph* glyph = &font_info.glyphs[index];
|
||||
|
||||
glyph.glyph_index = glyph_index;
|
||||
glyph.curve_start = *curve_index;
|
||||
|
||||
stbtt_vertex* vertices;
|
||||
u32 vertex_count = stbtt_GetGlyphShape(stb_font_info, glyph_index, &vertices);
|
||||
|
||||
if(vertex_count > 0)
|
||||
{
|
||||
f32 cx = 0.0, cy = 0.0;
|
||||
|
||||
foreach(i; 0 .. vertex_count)
|
||||
{
|
||||
stbtt_vertex* vtx = &vertices[i];
|
||||
f32 x = cast(f32)(vtx.x);
|
||||
f32 y = cast(f32)(vtx.y);
|
||||
|
||||
switch(vtx.type)
|
||||
{
|
||||
case STBTT_vmove:
|
||||
{
|
||||
cx = x;
|
||||
cy = y;
|
||||
} break;
|
||||
case STBTT_vline:
|
||||
{
|
||||
f32 dx = x-cx;
|
||||
f32 dy = y-cy;
|
||||
|
||||
if(fabs(dx) < 0.1 && fabs(dy) < 0.1)
|
||||
{
|
||||
cx = x;
|
||||
cy = y;
|
||||
break;
|
||||
}
|
||||
|
||||
f32 length = sqrt(dx*dx + dy*dy);
|
||||
f32 nx = -dy/length*0.05;
|
||||
f32 ny = -dx/length*0.05;
|
||||
|
||||
SlugCurve* curve = &font_info.curves[*curve_index];
|
||||
|
||||
*curve = SlugCurve(
|
||||
Vec2(cx, cy),
|
||||
Vec2((cx+x) * 0.5 + nx, (cy+y) * 0.5 + ny),
|
||||
Vec2(x, y),
|
||||
);
|
||||
|
||||
cx = x;
|
||||
cy = y;
|
||||
|
||||
*curve_index += 1;
|
||||
} break;
|
||||
case STBTT_vcurve:
|
||||
{
|
||||
SlugCurve* curve = &font_info.curves[*curve_index];
|
||||
|
||||
*curve = SlugCurve(
|
||||
Vec2(cx, cy),
|
||||
Vec2(vtx.cx, vtx.cy),
|
||||
Vec2(x, y),
|
||||
);
|
||||
|
||||
*curve_index += 1;
|
||||
} break;
|
||||
case STBTT_vcubic:
|
||||
{
|
||||
f32 cx1 = cast(f32)(vtx.cx );
|
||||
f32 cy1 = cast(f32)(vtx.cy );
|
||||
f32 cx2 = cast(f32)(vtx.cx1);
|
||||
f32 cy2 = cast(f32)(vtx.cy1);
|
||||
|
||||
Vec2 m01 = Vec2(cx+cx1, cy+cy1 ) * 0.5;
|
||||
Vec2 m12 = Vec2(cx1+cx2, cy1+cy2) * 0.5;
|
||||
Vec2 m23 = Vec2(cx2+x, cy2+y ) * 0.5;
|
||||
Vec2 m012 = (m01+m12) * 0.5;
|
||||
Vec2 m123 = (m12+m23) * 0.5;
|
||||
Vec2 mid = (m012+m123) * 0.5;
|
||||
|
||||
font_info.curves[(*curve_index)+0] = SlugCurve( Vec2(cx, cy), m01, mid );
|
||||
font_info.curves[(*curve_index)+1] = SlugCurve( mid, m123, Vec2(x, y) );
|
||||
|
||||
cx = x;
|
||||
cy = y;
|
||||
|
||||
*curve_index += 2;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
stbtt_FreeShape(stb_font_info, vertices);
|
||||
}
|
||||
|
||||
glyph.curve_count = *curve_index - glyph.curve_start;
|
||||
|
||||
i32 advance_width, left_side_bearing;
|
||||
|
||||
stbtt_GetGlyphHMetrics(stb_font_info, glyph_index, &advance_width, &left_side_bearing);
|
||||
|
||||
glyph.advance = advance_width;
|
||||
|
||||
IVec2 p0, p1;
|
||||
if(!stbtt_GetGlyphBox(stb_font_info, glyph_index, &p0.x, &p0.y, &p1.x, &p1.y))
|
||||
{
|
||||
p0 = p1 = 0;
|
||||
}
|
||||
|
||||
glyph.bearing = p0;
|
||||
glyph.size = p1-p0;
|
||||
|
||||
glyph.rect.min = Vec2(p0.x, p0.y);
|
||||
glyph.rect.max = Vec2(p1.x, p1.y);
|
||||
|
||||
glyph.coords = 0;
|
||||
glyph.max_bands = 0;
|
||||
glyph.band_scale = 0;
|
||||
glyph.band_offset = 0;
|
||||
|
||||
SlugBuildBands(arena, glyph_index, font_info, FONT_MAX_BANDS);
|
||||
}
|
||||
|
||||
bool
|
||||
LoadFontCurves(Arena* arena, SlugFontInfo* font_info, u8[] font_file_data)
|
||||
{
|
||||
bool result = true;
|
||||
u32 curve_count;
|
||||
|
||||
stbtt_fontinfo stb_font_info;
|
||||
|
||||
if(!stbtt_InitFont(&stb_font_info, font_file_data.ptr, stbtt_GetFontOffsetForIndex(font_file_data.ptr, 0)))
|
||||
{
|
||||
Errf("Failed to load font data");
|
||||
result = false;
|
||||
}
|
||||
|
||||
if(result)
|
||||
{
|
||||
foreach(i; 0 .. font_info.glyphs.length)
|
||||
{
|
||||
curve_count += SlugCountCurvesForGlyph(stbtt_FindGlyphIndex(&stb_font_info, cast(i32)i), &stb_font_info);
|
||||
}
|
||||
|
||||
font_info.curves = Alloc!(SlugCurve)(arena, curve_count+1);
|
||||
font_info.glyph_bands = Alloc!(SlugGlyphBandData)(arena, font_info.glyphs.length);
|
||||
|
||||
f32 font_scale = stbtt_ScaleForPixelHeight(&stb_font_info, 200.0);
|
||||
|
||||
stbtt_GetFontVMetrics(&stb_font_info, &font_info.ascent, &font_info.descent, &font_info.line_gap);
|
||||
|
||||
font_info.scale = font_scale;
|
||||
font_info.line_height = cast(f32)(font_info.ascent-font_info.descent);
|
||||
|
||||
u32 curve_index = 1;
|
||||
u32 curve_texel_count;
|
||||
|
||||
foreach(i; 0 .. font_info.glyphs.length)
|
||||
{
|
||||
BuildFontGlyph(arena, cast(u32)i, stbtt_FindGlyphIndex(&stb_font_info, cast(int)i), font_info, &curve_index, &stb_font_info);
|
||||
curve_texel_count += font_info.glyphs[i].curve_count*2;
|
||||
}
|
||||
|
||||
u32 curve_texel_height = clamp(cast(u32)((curve_texel_count+FONT_TEX_WIDTH-1) / FONT_TEX_WIDTH), 1, -1);
|
||||
|
||||
f32[] curve_texel_data = Alloc!(f32)(arena, FONT_TEX_WIDTH*curve_texel_height*4);
|
||||
u32[] curve_start_indices = Alloc!(u32)(arena, font_info.glyphs.length);
|
||||
|
||||
curve_index = 1;
|
||||
foreach(i; 0 .. font_info.glyphs.length)
|
||||
{
|
||||
SlugGlyph* glyph = &font_info.glyphs[i];
|
||||
|
||||
curve_start_indices[i] = curve_index;
|
||||
|
||||
SlugCurve[] glyph_curves = font_info.curves[glyph.curve_start .. glyph.curve_start+glyph.curve_count];
|
||||
foreach(j; 0 .. glyph.curve_count)
|
||||
{
|
||||
SlugCurve* curve = &glyph_curves[j];
|
||||
|
||||
UVec2 t0 = UVec2(curve_index%FONT_TEX_WIDTH, curve_index/FONT_TEX_WIDTH);
|
||||
u32 offset = cast(u32)((t0.y*FONT_TEX_WIDTH + t0.x) * 4);
|
||||
|
||||
curve_texel_data[offset .. offset+4] = [curve.p1.x, curve.p1.y, curve.p2.x, curve.p2.y];
|
||||
|
||||
curve_index += 1;
|
||||
|
||||
UVec2 t1 = UVec2(curve_index%FONT_TEX_WIDTH, curve_index/FONT_TEX_WIDTH);
|
||||
offset = cast(u32)((t1.y*FONT_TEX_WIDTH + t1.x) * 4);
|
||||
|
||||
curve_texel_data[offset .. offset+4] = [curve.p3.x, curve.p3.y, 0.0, 0.0];
|
||||
|
||||
curve_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
u32 band_total_count;
|
||||
|
||||
foreach(i; 0 .. font_info.glyphs.length)
|
||||
{
|
||||
SlugGlyph* glyph = &font_info.glyphs[i];
|
||||
SlugGlyphBandData* band_data = &font_info.glyph_bands[i];
|
||||
|
||||
u32 band_total = band_data.band_counts[0] + band_data.band_counts[1];
|
||||
u32 padding = cast(u32)(FONT_TEX_WIDTH - (band_total_count%FONT_TEX_WIDTH));
|
||||
|
||||
if(padding < band_total && padding < FONT_TEX_WIDTH)
|
||||
{
|
||||
band_total_count += padding;
|
||||
}
|
||||
|
||||
band_total_count += band_total;
|
||||
|
||||
foreach(axis; 0 .. 2)
|
||||
{
|
||||
foreach(j; 0 .. band_data.band_counts[axis])
|
||||
{
|
||||
band_total_count += band_data.bands[axis][j].count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 band_texel_height = clamp(cast(u32)((band_total_count+FONT_TEX_WIDTH-1) / FONT_TEX_WIDTH), 1U, u32.max);
|
||||
u32[] band_texel_data = Alloc!(u32)(arena, FONT_TEX_WIDTH*band_texel_height*4);
|
||||
|
||||
u32 band_index;
|
||||
foreach(i; 0 .. font_info.glyphs.length)
|
||||
{
|
||||
SlugGlyph* glyph = &font_info.glyphs[i];
|
||||
SlugGlyphBandData* band_data = &font_info.glyph_bands[i];
|
||||
u32 glyph_curve_start = curve_start_indices[i];
|
||||
|
||||
u32 band_total = cast(u32)(band_data.band_counts.x + band_data.band_counts.y);
|
||||
|
||||
u32 next_band_index = band_index%FONT_TEX_WIDTH;
|
||||
if(next_band_index+band_total > FONT_TEX_WIDTH)
|
||||
{
|
||||
band_index = cast(u32)((band_index/FONT_TEX_WIDTH+1) * FONT_TEX_WIDTH);
|
||||
}
|
||||
|
||||
glyph.coords = U16Vec2(band_index%FONT_TEX_WIDTH, band_index/FONT_TEX_WIDTH);
|
||||
|
||||
u32 glyph_start = band_index;
|
||||
|
||||
SlugCurve[] curves = font_info.curves[glyph.curve_start .. glyph.curve_start+glyph.curve_count];
|
||||
foreach(axis; 0 .. 2)
|
||||
{
|
||||
foreach(j; 0 .. band_data.band_counts[axis])
|
||||
{
|
||||
SlugSortBand(arena, &band_data.bands[axis][j], curves, axis);
|
||||
}
|
||||
}
|
||||
|
||||
u32 band_offset = band_total;
|
||||
u32[] offsets = Alloc!(u32)(arena, band_total);
|
||||
foreach(j; 0 .. band_data.band_counts.x)
|
||||
{
|
||||
offsets[j] = band_offset;
|
||||
band_offset += band_data.bands[0][j].count;
|
||||
}
|
||||
|
||||
foreach(j; 0 .. band_data.band_counts.y)
|
||||
{
|
||||
offsets[band_data.band_counts.x+j] = band_offset;
|
||||
band_offset += band_data.bands[1][j].count;
|
||||
}
|
||||
|
||||
foreach(j; 0 .. band_total)
|
||||
{
|
||||
u32 tl = glyph_start+j;
|
||||
u32 di = cast(u32)((tl/FONT_TEX_WIDTH*FONT_TEX_WIDTH + tl%FONT_TEX_WIDTH) * 4);
|
||||
u32 index = j;
|
||||
u32 count = 0;
|
||||
|
||||
if(index < cast(u32)band_data.band_counts.x)
|
||||
{
|
||||
count = band_data.bands[0][index].count;
|
||||
}
|
||||
else
|
||||
{
|
||||
index -= band_data.band_counts.x;
|
||||
count = band_data.bands[1][index].count;
|
||||
}
|
||||
|
||||
band_texel_data[di .. di+2] = [count, offsets[j]];
|
||||
}
|
||||
|
||||
foreach(j; 0 .. band_total)
|
||||
{
|
||||
u32 axis = j < band_data.band_counts.x ? 0 : 1;
|
||||
u32 index = j < band_data.band_counts.x ? j : j - band_data.band_counts.x;
|
||||
|
||||
SlugBandEntry* band = &band_data.bands[axis][index];
|
||||
|
||||
u32 ls = glyph_start+offsets[j];
|
||||
foreach(k; 0 .. band.count)
|
||||
{
|
||||
u32 ct = curve_start_indices[i] + band.indices[k]*2;
|
||||
u32 tl = ls+k;
|
||||
u32 di = cast(u32)((tl/FONT_TEX_WIDTH*FONT_TEX_WIDTH + tl%FONT_TEX_WIDTH) * 4);
|
||||
|
||||
band_texel_data[di .. di+2] = [ct%FONT_TEX_WIDTH, ct/FONT_TEX_WIDTH];
|
||||
}
|
||||
}
|
||||
|
||||
band_index = glyph_start+band_offset;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
SlugSortBand(Arena* arena, SlugBandEntry* entry, SlugCurve[] curves, u32 axis)
|
||||
{
|
||||
if(entry.count <= 1) return;
|
||||
|
||||
SlugCurveRef[] refs = Alloc!(SlugCurveRef)(arena, entry.count);
|
||||
foreach(i; 0 .. entry.count)
|
||||
{
|
||||
SlugCurve* curve = &curves[entry.indices[i]];
|
||||
|
||||
f32 mx = Max(curve.p1[axis], curve.p2[axis], curve.p3[axis]);
|
||||
|
||||
refs[i] = SlugCurveRef(entry.indices[i], mx);
|
||||
}
|
||||
|
||||
sort!("a.sort_key < b.sort_key")(refs);
|
||||
|
||||
foreach(i; 0 .. entry.count)
|
||||
{
|
||||
entry.indices[i] = refs[i].index;
|
||||
}
|
||||
}
|
||||
|
||||
u32
|
||||
SlugCountCurvesForGlyph(u32 glyph_index, stbtt_fontinfo* stb_font_info)
|
||||
{
|
||||
u32 result;
|
||||
|
||||
stbtt_vertex* vertices;
|
||||
u32 vertex_count = stbtt_GetGlyphShape(stb_font_info, glyph_index, &vertices);
|
||||
|
||||
foreach(i; 0 .. vertex_count)
|
||||
{
|
||||
switch(vertices[i].type)
|
||||
{
|
||||
case STBTT_vline, STBTT_vcurve: result += 1; break;
|
||||
case STBTT_vcubic: result += 2; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if(vertex_count > 0)
|
||||
{
|
||||
stbtt_FreeShape(stb_font_info, vertices);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
SlugBuildBands(Arena* arena, u32 glyph_index, SlugFontInfo* font_info, u32 band_count)
|
||||
{
|
||||
SlugGlyphBandData* band_data = &font_info.glyph_bands[glyph_index];
|
||||
SlugGlyph* glyph = &font_info.glyphs[glyph_index];
|
||||
|
||||
Vec2 size = glyph.rect.max - glyph.rect.min;
|
||||
|
||||
band_data.band_counts = cast(u8)band_count;
|
||||
|
||||
for(u32 i = 0; i < band_count; i += 1)
|
||||
{
|
||||
band_data.bands[0][i].indices = Alloc!(u32)(arena, glyph.curve_count);
|
||||
band_data.bands[1][i].indices = Alloc!(u32)(arena, glyph.curve_count);
|
||||
}
|
||||
|
||||
glyph.max_bands = cast(u8)band_count;
|
||||
glyph.band_scale = Vec2(
|
||||
size.x > 0.0 ? cast(f32)(band_count)/size.x : 0.0,
|
||||
size.y > 0.0 ? cast(f32)(band_count)/size.y : 0.0,
|
||||
);
|
||||
glyph.band_offset = -glyph.rect.min * glyph.band_scale;
|
||||
|
||||
for(u32 i = 0; i < glyph.curve_count; i += 1)
|
||||
{
|
||||
SlugCurve* curve = &font_info.curves[glyph.curve_start+i];
|
||||
|
||||
Vec2 curve_min = Vec2(
|
||||
Min(curve.p1.x, curve.p2.x, curve.p3.x),
|
||||
Min(curve.p1.y, curve.p2.y, curve.p3.y),
|
||||
);
|
||||
|
||||
Vec2 curve_max = Vec2(
|
||||
Max(curve.p1.x, curve.p2.x, curve.p3.x),
|
||||
Min(curve.p1.y, curve.p2.y, curve.p3.y),
|
||||
);
|
||||
|
||||
if(size.y > 0.0)
|
||||
{
|
||||
u32 b0 = cast(u32)clamp(floor(curve_min.y * glyph.band_scale.y + glyph.band_offset.y), 0.0, cast(f32)(band_count-1));
|
||||
u32 b1 = cast(u32)clamp(floor(curve_max.y * glyph.band_scale.y + glyph.band_offset.y), 0.0, cast(f32)(band_count-1));
|
||||
|
||||
for(u32 j = b0; j <= b1; j += 1)
|
||||
{
|
||||
SlugBandEntry* entry = &band_data.bands[0][j];
|
||||
entry.indices[entry.count++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
if(size.x > 0.0)
|
||||
{
|
||||
u32 b0 = cast(u32)clamp(Floor(curve_min.x * glyph.band_scale.x + glyph.band_offset.x), 0.0, cast(f32)(band_count-1));
|
||||
u32 b1 = cast(u32)clamp(Floor(curve_max.x * glyph.band_scale.x + glyph.band_offset.x), 0.0, cast(f32)(band_count-1));
|
||||
|
||||
for(u32 j = b0; j <= b1; j += 1)
|
||||
{
|
||||
SlugBandEntry* entry = &band_data.bands[1][j];
|
||||
entry.indices[entry.count++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
65
math.d
65
math.d
@ -16,15 +16,28 @@ import std.format;
|
||||
import std.stdio;
|
||||
|
||||
T
|
||||
Max(T)(T a, T b)
|
||||
_MinOrMaxInner(T, bool max, Args...)(T first, Args args)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
T value = first;
|
||||
static foreach(i; 0 .. args.length)
|
||||
{
|
||||
static if(max) if(cast(T)(args[i]) > value) value = cast(T)(args[i]);
|
||||
static if(!max) if(cast(T)(args[i]) < value) value = cast(T)(args[i]);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
T
|
||||
Min(T)(T a, T b)
|
||||
Max(T, Args...)(T first, Args args)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
return _MinOrMaxInner!(T, true, Args)(first, args);
|
||||
}
|
||||
|
||||
T
|
||||
Min(T, Args...)(T first, Args args)
|
||||
{
|
||||
return _MinOrMaxInner!(T, false, Args)(first, args);
|
||||
}
|
||||
|
||||
T
|
||||
@ -94,11 +107,22 @@ struct Vector(T, int N)
|
||||
{
|
||||
static if(args.length == 1)
|
||||
{
|
||||
opAssign!(Args[0])(args[0]);
|
||||
enum bool is_array = isArray!(Args[0]);
|
||||
enum bool is_assignable = isAssignable!(T, Args[0]);
|
||||
enum bool types_are_numeric = TypesAreNumeric!(T, Args[0]);
|
||||
|
||||
static if(is_array || is_assignable || types_are_numeric)
|
||||
{
|
||||
opAssign!(Args[0])(args[0]);
|
||||
}
|
||||
else static assert(false, "Invalid Vector constructor");
|
||||
}
|
||||
else static if(args.length == N)
|
||||
{
|
||||
mixin(GenerateLoop!("v[@] = args[@];", N)());
|
||||
static foreach(i; 0 .. N)
|
||||
{
|
||||
v[i] = cast(T)args[i];
|
||||
}
|
||||
}
|
||||
else static if(args.length == 2 && N == 4)
|
||||
{
|
||||
@ -113,15 +137,18 @@ struct Vector(T, int N)
|
||||
}
|
||||
}
|
||||
|
||||
ref Vector opAssign(U)(U x) if(is(U: T) || isAssignable!(T, U))
|
||||
ref Vector opAssign(U)(U x) if(is(U: T) || isAssignable!(T, U) || TypesAreNumeric!(T, U))
|
||||
{
|
||||
mixin(GenerateLoop!("v[@] = x;", N)());
|
||||
v[] = cast(T)x;
|
||||
return this;
|
||||
}
|
||||
|
||||
ref Vector opAssign(U)(U u) if(isStaticArray!(U) && U.length == N && isAssignable!(T, typeof(*U.init.ptr)))
|
||||
{
|
||||
mixin(GenerateLoop!("v[@] = u[@];", N)());
|
||||
static foreach(i; 0 .. N)
|
||||
{
|
||||
v[i] = cast(T)u[i];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -309,6 +336,11 @@ struct Vector(T, int N)
|
||||
enum bool IsConvertible = (!is(T : Vector)) && is(typeof({ T x; Vector v = x; }()));
|
||||
}
|
||||
|
||||
template TypesAreNumeric(U, V)
|
||||
{
|
||||
enum bool TypesAreNumeric = isNumeric!(U) && isNumeric!(V);
|
||||
}
|
||||
|
||||
template SwizzleIndex(char c)
|
||||
{
|
||||
static if((c == 'x' || c == 'r') && N > 0)
|
||||
@ -1223,4 +1255,19 @@ version(DLIB_TEST) unittest
|
||||
v.r = 55;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
u32 max = Max(50, 33, 123.0);
|
||||
assert(max == 123);
|
||||
}
|
||||
|
||||
{
|
||||
Vec2 v0 = 50U;
|
||||
|
||||
assert(fabsf(v0.x-50.0) < 0.0009 && fabsf(v0.y-50.0) < 0.0009);
|
||||
|
||||
U8Vec2 v1 = U8Vec2(55U);
|
||||
|
||||
assert(v1.x == 55 && v1.y == 55);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user