clean up
This commit is contained in:
parent
8201316817
commit
34b4e7a4c5
4
dub.json
4
dub.json
@ -9,8 +9,8 @@
|
||||
"targetPath": "build",
|
||||
"sourceFiles-linux": ["build/libvma.a", "build/libstb_image.a", "build/libm3d.a", "build/libcglm.a"],
|
||||
"sourceFiles-windows": [],
|
||||
"importPaths": ["src/gears", "src/shared", "external/xxhash", "external/inteli", "src/VulkanRenderer"],
|
||||
"sourcePaths": ["src/gears", "src/shared", "external/xxhash", "external/inteli", "src/VulkanRenderer"],
|
||||
"importPaths": ["src/gears", "src/DLibs", "src/DLibs/external/xxhash", "src/VulkanRenderer"],
|
||||
"sourcePaths": ["src/gears", "src/DLibs", "src/DLibs/external/xxhash", "src/VulkanRenderer"],
|
||||
"libs-linux": ["xcb", "X11", "X11-xcb", "vulkan", "stdc++", "xcb-xfixes", "freetype"],
|
||||
"libs-windows": [],
|
||||
"preGenerateCommands-linux": ["./build.sh"],
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit fb45fd78ebb8e2c59de3ff89f932a50dba628638
|
||||
Subproject commit a91b50cb90397e4455bd505017541c72d1a959e0
|
||||
@ -1,42 +0,0 @@
|
||||
import core.memory;
|
||||
import std.stdint;
|
||||
import math;
|
||||
|
||||
debug
|
||||
{
|
||||
const BUILD_DEBUG = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const BUILD_DEBUG = false;
|
||||
}
|
||||
|
||||
alias i8 = byte;
|
||||
alias i16 = short;
|
||||
alias i32 = int;
|
||||
alias i64 = long;
|
||||
|
||||
alias u8 = ubyte;
|
||||
alias u16 = ushort;
|
||||
alias u32 = uint;
|
||||
alias u64 = ulong;
|
||||
|
||||
alias f32 = float;
|
||||
alias f64 = double;
|
||||
|
||||
alias b32 = uint;
|
||||
|
||||
alias intptr = i64;
|
||||
alias uintptr = u64;
|
||||
|
||||
alias usize = size_t;
|
||||
|
||||
alias Vec2 = Vector!(f32, 2);
|
||||
alias Vec3 = Vector!(f32, 3);
|
||||
alias Vec4 = Vector!(f32, 4);
|
||||
|
||||
alias UVec2 = Vector!(u32, 2);
|
||||
|
||||
alias Mat2 = Matrix!(f32, 2);
|
||||
alias Mat3 = Matrix!(f32, 3);
|
||||
alias Mat4 = Matrix!(f32, 4);
|
||||
@ -1,133 +0,0 @@
|
||||
import aliases;
|
||||
import math;
|
||||
import std.stdio;
|
||||
import core.stdc.string : memset;
|
||||
import core.memory;
|
||||
import platform;
|
||||
|
||||
const DEFAULT_ALIGNMENT = (void *).sizeof * 2;
|
||||
|
||||
struct Arena
|
||||
{
|
||||
u8* mem;
|
||||
u64 length;
|
||||
u64 pos;
|
||||
};
|
||||
|
||||
T*
|
||||
MAlloc(T)()
|
||||
{
|
||||
void* mem = MemAlloc(T.sizeof);
|
||||
return cast(T*)mem;
|
||||
}
|
||||
|
||||
T[]
|
||||
MAllocArray(T)(u64 count)
|
||||
{
|
||||
void* mem = MemAlloc(T.sizeof * count);
|
||||
return cast(T*)(mem)[0 .. count];
|
||||
}
|
||||
|
||||
void
|
||||
MFree(T)(T* ptr)
|
||||
{
|
||||
MemFree(cast(void*)ptr, T.sizeof);
|
||||
}
|
||||
|
||||
void
|
||||
MFreeArray(T)(T[] slice)
|
||||
{
|
||||
MemFree(cast(void*)slice.ptr, cast(u64)slice.length);
|
||||
}
|
||||
|
||||
T*
|
||||
Alloc(T)()
|
||||
{
|
||||
void* mem = pureMalloc(T.sizeof);
|
||||
memset(mem, 0, T.sizeof);
|
||||
return (cast(T*)mem);
|
||||
}
|
||||
|
||||
T[]
|
||||
AllocArray(T)(u64 count)
|
||||
{
|
||||
void* mem = pureMalloc(T.sizeof * count);
|
||||
memset(mem, 0, T.sizeof * count);
|
||||
return (cast(T*)mem)[0 .. count];
|
||||
}
|
||||
|
||||
Arena
|
||||
CreateArena(u64 size)
|
||||
{
|
||||
Arena arena = {
|
||||
mem: cast(u8 *)pureMalloc(size),
|
||||
length: size,
|
||||
pos: 0,
|
||||
};
|
||||
|
||||
assert(arena.mem != null, "Unable to allocate memory for arena");
|
||||
|
||||
return arena;
|
||||
};
|
||||
|
||||
T[]
|
||||
AllocArray(T)(Arena* arena, u64 count)
|
||||
{
|
||||
void* mem = AllocAlign(arena, T.sizeof * count, DEFAULT_ALIGNMENT);
|
||||
memset(mem, 0, T.sizeof * count);
|
||||
return (cast(T*)mem)[0 .. count];
|
||||
}
|
||||
|
||||
T*
|
||||
Alloc(T)(Arena* arena)
|
||||
{
|
||||
void* mem = AllocAlign(arena, T.sizeof, DEFAULT_ALIGNMENT);
|
||||
memset(mem, 0, T.sizeof);
|
||||
return cast(T*)mem;
|
||||
};
|
||||
|
||||
void*
|
||||
AllocAlign(Arena* arena, u64 size, u64 alignment)
|
||||
{
|
||||
void* ptr = null;
|
||||
|
||||
uintptr mem_pos = cast(uintptr)arena.mem;
|
||||
uintptr current = mem_pos + arena.pos;
|
||||
uintptr offset = AlignPow2(current, alignment) - mem_pos;
|
||||
|
||||
if (offset+size <= arena.length)
|
||||
{
|
||||
ptr = &arena.mem[offset];
|
||||
arena.pos = offset+size;
|
||||
}
|
||||
else
|
||||
{
|
||||
writefln("AllocAlign failure: out of memory, size requested: %llu", size);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
};
|
||||
|
||||
void
|
||||
Reset(Arena* arena)
|
||||
{
|
||||
arena.pos = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Free(Arena* arena)
|
||||
{
|
||||
pureFree(arena.mem);
|
||||
}
|
||||
|
||||
void
|
||||
FreeArray(T)(T[] arr)
|
||||
{
|
||||
pureFree(arr.ptr);
|
||||
}
|
||||
|
||||
void Free(T)(T* ptr)
|
||||
{
|
||||
pureFree(ptr);
|
||||
}
|
||||
@ -1,317 +0,0 @@
|
||||
import aliases;
|
||||
import std.file;
|
||||
import std.stdio;
|
||||
import util;
|
||||
import std.exception;
|
||||
import alloc;
|
||||
|
||||
File Asset_File;
|
||||
|
||||
FileHeader Asset_Header;
|
||||
|
||||
AssetInfo[] Asset_Info;
|
||||
|
||||
u8[][] Asset_Data;
|
||||
|
||||
const u32 FILE_VERSION = 2;
|
||||
const u32 MODEL_VERSION = 1;
|
||||
|
||||
enum AssetType : u32
|
||||
{
|
||||
None,
|
||||
ModelM3D,
|
||||
Shader,
|
||||
Texture,
|
||||
}
|
||||
|
||||
alias AT = AssetType;
|
||||
|
||||
struct FileHeader
|
||||
{
|
||||
u32 magic;
|
||||
u32 file_version;
|
||||
u64 asset_count;
|
||||
u64 asset_info_offset;
|
||||
}
|
||||
|
||||
struct ModelHeader
|
||||
{
|
||||
u32 magic;
|
||||
u32 model_version;
|
||||
u64 vertex_count;
|
||||
u64 vertex_offset;
|
||||
u64 index_count;
|
||||
u64 index_offset;
|
||||
u64 material_count;
|
||||
u64 material_offset;
|
||||
u64 texture_count;
|
||||
u64 texture_offset;
|
||||
}
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
Vec4 color;
|
||||
Vec4 tangent;
|
||||
Vec3 pos;
|
||||
Vec3 normal;
|
||||
Vec2 uv;
|
||||
}
|
||||
|
||||
struct ModelData
|
||||
{
|
||||
Vertex[] vertices;
|
||||
u32[] indices;
|
||||
Material[] materials;
|
||||
TextureInfo[] textures;
|
||||
}
|
||||
|
||||
struct Material
|
||||
{
|
||||
Vec4 ambient;
|
||||
Vec4 albedo;
|
||||
Vec4 specular;
|
||||
u32 albedo_texture;
|
||||
u32 ambient_texture;
|
||||
u32 specular_texture;
|
||||
u32 alpha_texture;
|
||||
b32 albedo_has_texture;
|
||||
b32 ambient_has_texture;
|
||||
b32 specular_has_texture;
|
||||
b32 alpha_has_texture;
|
||||
f32 shininess = 0.0;
|
||||
f32 alpha = 0.0;
|
||||
}
|
||||
|
||||
struct TextureInfo
|
||||
{
|
||||
string name;
|
||||
u32 id;
|
||||
}
|
||||
|
||||
struct TextureHeader
|
||||
{
|
||||
u64 str_length;
|
||||
u64 str_offset;
|
||||
u32 texture_id;
|
||||
}
|
||||
|
||||
struct ModelMeta
|
||||
{
|
||||
u64 index_count;
|
||||
}
|
||||
|
||||
struct TexData
|
||||
{
|
||||
void* data;
|
||||
TexMeta meta;
|
||||
}
|
||||
|
||||
struct TexMeta
|
||||
{
|
||||
u32 w;
|
||||
u32 h;
|
||||
u32 ch;
|
||||
}
|
||||
|
||||
struct AssetInfo
|
||||
{
|
||||
u64 hash;
|
||||
u64 offset;
|
||||
u64 length;
|
||||
AssetType type;
|
||||
}
|
||||
|
||||
bool Asset_Pack_Opened = false;
|
||||
|
||||
debug
|
||||
{
|
||||
|
||||
bool g_DIR_SET = false;
|
||||
|
||||
void
|
||||
SetDir()
|
||||
{
|
||||
if (exists("assets"))
|
||||
{
|
||||
chdir("./assets");
|
||||
}
|
||||
else if (exists("Gears") || exists("Gears.exe"))
|
||||
{
|
||||
chdir("../assets");
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "Unable to set directory");
|
||||
}
|
||||
|
||||
g_DIR_SET = true;
|
||||
}
|
||||
|
||||
u8[]
|
||||
LoadAssetData(Arena* arena, string name)
|
||||
{
|
||||
if (!g_DIR_SET)
|
||||
{
|
||||
SetDir();
|
||||
}
|
||||
|
||||
File f;
|
||||
try
|
||||
{
|
||||
f = File(name, "rb");
|
||||
}
|
||||
catch (ErrnoException e)
|
||||
{
|
||||
assert(false, "Unable to open file");
|
||||
}
|
||||
|
||||
u8[] mem = AllocArray!(u8)(arena, f.size());
|
||||
return f.rawRead(mem);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
void
|
||||
OpenAssetPack()
|
||||
{
|
||||
if (!Asset_Pack_Opened)
|
||||
{
|
||||
bool success = true;
|
||||
string file_path = exists("build/assets.sgp") ? "build/assets.sgp" : "assets.sgp";
|
||||
|
||||
// TODO: replace this with something that doesn't throw an exception and figure out if this is the best way to handle thing (probably isnt)
|
||||
try
|
||||
{
|
||||
Asset_File = File(file_path, "rb");
|
||||
}
|
||||
catch (ErrnoException e)
|
||||
{
|
||||
Logf("OpenAssetPack failure: Unable to open file %s", file_path);
|
||||
assert(false, "Unable to open asset pack file");
|
||||
}
|
||||
|
||||
FileHeader[1] header_arr;
|
||||
|
||||
Asset_File.rawRead(header_arr);
|
||||
|
||||
Asset_Header = header_arr[0];
|
||||
|
||||
Asset_Info = AllocArray!(AssetInfo)(Asset_Header.asset_count);
|
||||
Asset_Data = AllocArray!(u8[])(Asset_Header.asset_count);
|
||||
|
||||
assert(Asset_Header.file_version == FILE_VERSION, "OpenAssetPack failure: file version incorrect");
|
||||
|
||||
Asset_File.seek(Asset_Header.asset_info_offset);
|
||||
|
||||
Asset_File.rawRead(Asset_Info);
|
||||
}
|
||||
}
|
||||
|
||||
pragma(inline): void
|
||||
CheckAssetPack()
|
||||
{
|
||||
if (!Asset_Pack_Opened)
|
||||
{
|
||||
OpenAssetPack();
|
||||
}
|
||||
}
|
||||
|
||||
AssetInfo
|
||||
GetAssetInfo(string name)
|
||||
{
|
||||
CheckAssetPack();
|
||||
|
||||
u64 hash = Hash(name);
|
||||
|
||||
AssetInfo asset_info;
|
||||
foreach(i, info; Asset_Info)
|
||||
{
|
||||
if (info.hash == hash)
|
||||
{
|
||||
asset_info = info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(asset_info.hash != 0, "GetAssetInfo failure: unable to find matching asset");
|
||||
|
||||
return asset_info;
|
||||
}
|
||||
|
||||
u8[]
|
||||
LoadAssetData(Arena* arena, string name)
|
||||
{
|
||||
CheckAssetPack();
|
||||
|
||||
u64 hash = Hash(name);
|
||||
u8[] data = null;
|
||||
|
||||
foreach(i, info; Asset_Info)
|
||||
{
|
||||
if (info.hash == hash)
|
||||
{
|
||||
data = AllocArray!(u8)(arena, info.length);
|
||||
Asset_File.seek(info.offset);
|
||||
Asset_File.rawRead(data);
|
||||
assert(data != null && data.length == info.length, "LoadAssetData failure: Asset data loaded incorrectly");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
u8[]
|
||||
LoadAssetData(string name)
|
||||
{
|
||||
CheckAssetPack();
|
||||
|
||||
u64 hash = Hash(name);
|
||||
u8[] data = null;
|
||||
|
||||
foreach(i, info; Asset_Info)
|
||||
{
|
||||
if (info.hash == hash)
|
||||
{
|
||||
if (Asset_Data[i].ptr == null)
|
||||
{
|
||||
Asset_Data[i] = AllocArray!(u8)(info.length);
|
||||
Asset_File.seek(info.offset);
|
||||
Asset_File.rawRead(Asset_Data[i]);
|
||||
assert(Asset_Data[i] != null && Asset_Data[i].length == info.length, "LoadAssetData failure: Asset data loaded incorrectly.");
|
||||
}
|
||||
|
||||
data = Asset_Data[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
UnloadAssetData(string name)
|
||||
{
|
||||
u64 hash = Hash(name);
|
||||
|
||||
foreach(i, info; Asset_Info)
|
||||
{
|
||||
if (info.hash == hash)
|
||||
{
|
||||
if (Asset_Data[i] != null)
|
||||
{
|
||||
FreeArray(Asset_Data[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,210 +0,0 @@
|
||||
import aliases;
|
||||
import includes;
|
||||
import util;
|
||||
import alloc;
|
||||
|
||||
enum AtlasType
|
||||
{
|
||||
None = 0,
|
||||
SoftMask,
|
||||
}
|
||||
|
||||
enum YOrigin
|
||||
{
|
||||
None = 0,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
struct FontAtlas
|
||||
{
|
||||
AtlasType type;
|
||||
f32 size;
|
||||
u32 width;
|
||||
u32 height;
|
||||
YOrigin y_origin;
|
||||
f32 em_size;
|
||||
f32 line_height;
|
||||
f32 ascender;
|
||||
f32 descender;
|
||||
f32 underline_y;
|
||||
f32 underline_thickness;
|
||||
Glyph[] glyphs;
|
||||
}
|
||||
|
||||
struct Glyph
|
||||
{
|
||||
dchar ch;
|
||||
f32 advance;
|
||||
f32 plane_left;
|
||||
f32 plane_bottom;
|
||||
f32 plane_right;
|
||||
f32 plane_top;
|
||||
f32 atlas_left;
|
||||
f32 atlas_bottom;
|
||||
f32 atlas_right;
|
||||
f32 atlas_top;
|
||||
}
|
||||
|
||||
FT_Library FT_LIB;
|
||||
alias FontFace = FT_Face;
|
||||
|
||||
struct FontAtlasBuf
|
||||
{
|
||||
u8[] data;
|
||||
FontAtlas atlas;
|
||||
}
|
||||
|
||||
void
|
||||
InitFreeType()
|
||||
{
|
||||
FT_Init_FreeType(&FT_LIB);
|
||||
}
|
||||
|
||||
void
|
||||
CloseFreeType()
|
||||
{
|
||||
if (FT_LIB)
|
||||
{
|
||||
FT_Done_FreeType(FT_LIB);
|
||||
}
|
||||
}
|
||||
|
||||
FontFace
|
||||
OpenFont(u8[] data)
|
||||
{
|
||||
FontFace font;
|
||||
FT_New_Memory_Face(FT_LIB, data.ptr, cast(FT_Long)data.length, 0, &font);
|
||||
return font;
|
||||
}
|
||||
|
||||
void
|
||||
CloseFont(FontFace font)
|
||||
{
|
||||
if (font != null)
|
||||
{
|
||||
FT_Done_Face(font);
|
||||
}
|
||||
}
|
||||
|
||||
FontAtlasBuf
|
||||
CreateAtlas(Arena* arena, FontFace font, f32 size, u32 dimension)
|
||||
{
|
||||
assert(dimension >= 128, "Dimension must be at least 128");
|
||||
|
||||
FontAtlasBuf atlas = {
|
||||
data: AllocArray!(u8)(arena, dimension * dimension * 4),
|
||||
atlas: {
|
||||
size: size,
|
||||
width: dimension,
|
||||
height: dimension,
|
||||
},
|
||||
};
|
||||
|
||||
// TODO: proper packing algorithm
|
||||
if (font != null)
|
||||
{
|
||||
FT_Set_Pixel_Sizes(font, 0, cast(FT_UInt)((96.0/72.0) * size));
|
||||
|
||||
i64 f_ascent = cast(i64)(font.size.metrics.ascender >> 6);
|
||||
i64 f_descent = cast(i64)(font.size.metrics.descender >> 6);
|
||||
i64 f_height = cast(i64)(font.size.metrics.height >> 6);
|
||||
|
||||
u32 max_w = 0;
|
||||
u32 max_h = 0;
|
||||
u32 current_h = 0;
|
||||
u32 count = 0;
|
||||
|
||||
FT_UInt index;
|
||||
FT_ULong char_code = FT_Get_First_Char(font, &index);
|
||||
while (index != 0)
|
||||
{
|
||||
FT_Load_Char(font, char_code, cast(FT_Int32)FT_LOAD_RENDER);
|
||||
|
||||
u32 bmp_w = font.glyph.bitmap.width;
|
||||
u32 bmp_h = font.glyph.bitmap.rows;
|
||||
if (max_w + bmp_w > dimension)
|
||||
{
|
||||
max_h += current_h;
|
||||
max_w = 0;
|
||||
}
|
||||
|
||||
assert(max_h < dimension, "Unable to pack atlas within dimensions");
|
||||
|
||||
max_w += bmp_w;
|
||||
current_h = bmp_h > current_h ? bmp_h : current_h;
|
||||
count += 1;
|
||||
|
||||
char_code = FT_Get_Next_Char(font, char_code, &index);
|
||||
}
|
||||
|
||||
atlas.atlas.glyphs = AllocArray!(Glyph)(arena, count);
|
||||
|
||||
max_w = 0;
|
||||
max_h = 0;
|
||||
current_h = 0;
|
||||
count = 0;
|
||||
|
||||
u32 font_w = font.size.metrics.x_ppem;
|
||||
u32 font_h = font.size.metrics.y_ppem;
|
||||
|
||||
char_code = FT_Get_First_Char(font, &index);
|
||||
while (index != 0)
|
||||
{
|
||||
FT_Load_Char(font, char_code, cast(FT_Int32)FT_LOAD_RENDER);
|
||||
|
||||
FT_GlyphSlot glyph = font.glyph;
|
||||
FT_Bitmap* bmp = &font.glyph.bitmap;
|
||||
i32 top = font.glyph.bitmap_top;
|
||||
i32 left = font.glyph.bitmap_left;
|
||||
|
||||
if (max_w + bmp.rows > dimension)
|
||||
{
|
||||
max_h += current_h;
|
||||
max_w = 0;
|
||||
}
|
||||
|
||||
i32 x, y;
|
||||
foreach(r; 0 .. bmp.rows)
|
||||
{
|
||||
y = cast(i32)(max_h + r);
|
||||
foreach(c; 0 .. bmp.width)
|
||||
{
|
||||
x = max_w + c;
|
||||
u64 offset = (y*dimension + x) * 4;
|
||||
|
||||
atlas.data[offset+0] = bmp.buffer[r*bmp.pitch + c];
|
||||
atlas.data[offset+1] = bmp.buffer[r*bmp.pitch + c];
|
||||
atlas.data[offset+2] = bmp.buffer[r*bmp.pitch + c];
|
||||
atlas.data[offset+3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
Glyph* g = atlas.atlas.glyphs.ptr + count;
|
||||
|
||||
g.ch = cast(dchar)char_code;
|
||||
g.advance = cast(f32)(glyph.advance.x >> 6);
|
||||
g.plane_left = cast(f32)left;
|
||||
g.plane_right = g.plane_left + bmp.width;
|
||||
g.plane_top = cast(f32)top;
|
||||
g.plane_bottom = g.plane_top + bmp.rows;
|
||||
|
||||
g.atlas_top = max_h;
|
||||
g.atlas_left = max_w;
|
||||
g.atlas_bottom = max_h + bmp.rows;
|
||||
g.atlas_right = max_w + bmp.width;
|
||||
|
||||
max_w += bmp.width;
|
||||
current_h = bmp.rows > current_h ? bmp.rows : current_h;
|
||||
|
||||
char_code = FT_Get_Next_Char(font, char_code, &index);
|
||||
|
||||
count += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return atlas;
|
||||
}
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
#pragma attribute(push, nogc, nothrow)
|
||||
|
||||
#ifdef __linux__
|
||||
# include <xcb/xcb.h>
|
||||
# include <xcb/xfixes.h>
|
||||
# include <X11/XKBlib.h>
|
||||
# include <X11/Xlib-xcb.h>
|
||||
# include <X11/Xlib.h>
|
||||
# include <X11/keysym.h>
|
||||
# include <X11/extensions/Xfixes.h>
|
||||
# include <ft2build.h>
|
||||
# include FT_FREETYPE_H
|
||||
# include FT_GLYPH_H
|
||||
#endif
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
|
||||
#include "../../external/stb/stb_image.h"
|
||||
|
||||
#define M3D_IMPLEMENTATION
|
||||
|
||||
#include "../../external/m3d/m3d.h"
|
||||
|
||||
#define CGLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
|
||||
#include "../../external/cglm/cglm.h"
|
||||
1086
src/shared/math.d
1086
src/shared/math.d
File diff suppressed because it is too large
Load Diff
@ -1,661 +0,0 @@
|
||||
import aliases;
|
||||
import xxhash3;
|
||||
import includes;
|
||||
import std.stdio;
|
||||
import core.stdc.string : memset;
|
||||
import alloc;
|
||||
import core.simd;
|
||||
import std.conv;
|
||||
import std.string;
|
||||
|
||||
struct DynSlice(T)
|
||||
{
|
||||
T[][] slices;
|
||||
u32 length;
|
||||
u32 capacity;
|
||||
u32 grow_size;
|
||||
}
|
||||
|
||||
DynSlice!(T)
|
||||
CreateDynSlice(T)(u32 size)
|
||||
{
|
||||
DynSlice!(T) dslice = {
|
||||
slices: MAllocArray!(T[])(size),
|
||||
length: 0,
|
||||
capacity: size,
|
||||
grow_size: size,
|
||||
};
|
||||
|
||||
dslice.slices[0] = MAllocArray!(T)(size);
|
||||
|
||||
return dslice;
|
||||
}
|
||||
|
||||
u32
|
||||
Next(T)(DynSlice!(T)* slice)
|
||||
{
|
||||
if (slice.length < slice.capacity)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Logf(Args...)(string fmt, Args args)
|
||||
{
|
||||
try
|
||||
{
|
||||
writefln(fmt, args);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
assert(false, "Incompatible format type");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Log(string str)
|
||||
{
|
||||
writeln(str);
|
||||
}
|
||||
|
||||
void
|
||||
Log(char* str)
|
||||
{
|
||||
writeln(str);
|
||||
}
|
||||
|
||||
u64
|
||||
KB(u64 v)
|
||||
{
|
||||
return v * 1024;
|
||||
};
|
||||
|
||||
u64
|
||||
MB(u64 v)
|
||||
{
|
||||
return KB(v) * 1024;
|
||||
};
|
||||
|
||||
u64
|
||||
GB(u64 v)
|
||||
{
|
||||
return MB(v) * 1024;
|
||||
};
|
||||
|
||||
pragma(inline): void
|
||||
ConvertColor(Vec4 *dst, u32 src)
|
||||
{
|
||||
if (src == 0)
|
||||
{
|
||||
dst.rgb = 0.0;
|
||||
dst.a = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Convert(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
pragma(inline): void
|
||||
Convert(Vec4* dst, u32 src)
|
||||
{
|
||||
dst.r = cast(f32)((src >> 0) & 0xFF) / 255.0;
|
||||
dst.g = cast(f32)((src >> 8) & 0xFF) / 255.0;
|
||||
dst.b = cast(f32)((src >> 16) & 0xFF) / 255.0;
|
||||
dst.a = cast(f32)((src >> 24) & 0xFF) / 255.0;
|
||||
}
|
||||
|
||||
bool
|
||||
BitEq(u64 l, u64 r)
|
||||
{
|
||||
return (l & r) == r;
|
||||
}
|
||||
|
||||
struct Node(T)
|
||||
{
|
||||
Node!(T)* next;
|
||||
T value;
|
||||
}
|
||||
|
||||
struct SLList(T)
|
||||
{
|
||||
Node!(T)* first;
|
||||
Node!(T)* last;
|
||||
}
|
||||
|
||||
pragma(inline): bool
|
||||
CheckNil(T)(Node!(T)* nil, Node!(T)* node)
|
||||
{
|
||||
return node == null || node == nil;
|
||||
}
|
||||
|
||||
pragma(inline): void
|
||||
ConcatInPlace(T)(SLList!(T)* list, SLList!(T)* to_concat)
|
||||
{
|
||||
if (to_concat.first)
|
||||
{
|
||||
if (list.first)
|
||||
{
|
||||
list.last.next = to_concat.first;
|
||||
list.last = to_concat.last;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.first = to_concat.first;
|
||||
list.last = to_concat.last;
|
||||
}
|
||||
|
||||
memset(to_concat, 0, SLList!(T).sizeof);
|
||||
}
|
||||
}
|
||||
|
||||
pragma(inline): Node!(T)*
|
||||
Pop(T)(SLList!(T)*list, Node!(T)* nil)
|
||||
{
|
||||
Node!(T)* node = list.first;
|
||||
|
||||
if (list.first == list.last)
|
||||
{
|
||||
list.first = list.last = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.first = list.first.next;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
pragma(inline): void
|
||||
Remove(T)(SLList!(T)*list, Node!(T)* node, Node!(T)* prev, Node!(T)* nil)
|
||||
{
|
||||
node.next = nil;
|
||||
|
||||
if (list.first == list.last)
|
||||
{
|
||||
list.first = list.last = nil;
|
||||
}
|
||||
else if (list.first == node)
|
||||
{
|
||||
list.first = node.next;
|
||||
}
|
||||
else if (list.last == node)
|
||||
{
|
||||
list.last = prev;
|
||||
prev.next = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev.next = node.next;
|
||||
}
|
||||
}
|
||||
|
||||
pragma(inline): void
|
||||
PushFront(T)(SLList!(T)*list, Node!(T)* node, Node!(T)* nil)
|
||||
{
|
||||
if (CheckNil(nil, list.first))
|
||||
{
|
||||
list.first = list.last = node;
|
||||
node.next = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.next = list.first;
|
||||
list.first = node;
|
||||
}
|
||||
}
|
||||
|
||||
pragma(inline): void
|
||||
Push(T)(SLList!(T)*list, Node!(T)* node, Node!(T)* nil)
|
||||
{
|
||||
if (CheckNil(nil, list.first))
|
||||
{
|
||||
list.first = list.last = node;
|
||||
node.next = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.last.next = node;
|
||||
list.last = node;
|
||||
node.next = nil;
|
||||
}
|
||||
}
|
||||
|
||||
struct KVPair(K, V)
|
||||
{
|
||||
K key;
|
||||
V value;
|
||||
}
|
||||
|
||||
struct Result(V)
|
||||
{
|
||||
V value;
|
||||
bool ok;
|
||||
}
|
||||
|
||||
struct HashTable(K, V)
|
||||
{
|
||||
alias P = KVPair!(K, V);
|
||||
|
||||
SLList!(P) free_lists;
|
||||
SLList!(P)[] lists;
|
||||
Node!(P)* nil;
|
||||
u64 node_count;
|
||||
u64 list_count;
|
||||
|
||||
void opIndexAssign(V value, K key)
|
||||
{
|
||||
Push(&this, key, value);
|
||||
}
|
||||
|
||||
Result!(V) opIndex(K key)
|
||||
{
|
||||
P* pair = Search(&this, key);
|
||||
assert(pair != null, "HashTable key index failure: Result must be present");
|
||||
|
||||
Result!(V) result = { ok: false };
|
||||
if (pair != null)
|
||||
{
|
||||
result.value = pair.value;
|
||||
result.ok = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result!(V) opIndexUnary(string s: "~")(K key)
|
||||
{
|
||||
return Delete(&this, key);
|
||||
}
|
||||
}
|
||||
|
||||
HashTable!(K, V)
|
||||
CreateHashTable(K, V)(u64 size)
|
||||
{
|
||||
auto nil = Alloc!(Node!(KVPair!(K, V)));
|
||||
auto lists = AllocArray!(SLList!(KVPair!(K, V)))(size);
|
||||
|
||||
HashTable!(K, V) table = {
|
||||
lists: lists,
|
||||
list_count: size,
|
||||
nil: nil,
|
||||
free_lists: {
|
||||
first: nil,
|
||||
last: nil,
|
||||
},
|
||||
};
|
||||
|
||||
foreach(list; table.lists)
|
||||
{
|
||||
list.first = nil;
|
||||
list.last = nil;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
pragma(inline): void
|
||||
Clear(K, V)(HashTable!(K, V)* ht)
|
||||
{
|
||||
table.count = 0;
|
||||
foreach(i, list; ht.lists)
|
||||
{
|
||||
ConcatInPlace(&ht.free_lists, ht.lists.ptr + i);
|
||||
}
|
||||
}
|
||||
|
||||
pragma(inline): Node!(KVPair!(K, V))*
|
||||
Push(K, V)(HashTable!(K, V)* ht, K key, V value)
|
||||
{
|
||||
alias P = KVPair!(K, V);
|
||||
alias N = Node!(P);
|
||||
|
||||
N* node = ht.nil;
|
||||
|
||||
if (ht.free_lists.first != ht.nil)
|
||||
{
|
||||
node = Pop(&ht.free_lists, ht.nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = Alloc!(N);
|
||||
}
|
||||
|
||||
node.next = ht.nil;
|
||||
node.value.key = key;
|
||||
node.value.value = value;
|
||||
|
||||
Push(GetList(ht, key), node, ht.nil);
|
||||
|
||||
ht.node_count += 1;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
pragma(inline): KVPair!(K, V)*
|
||||
Search(K, V)(HashTable!(K, V)* ht, K key)
|
||||
{
|
||||
KVPair!(K, V)* result = null;
|
||||
|
||||
auto list = GetList(ht, key);
|
||||
for(auto node = list.first; node != ht.nil; node = node.next)
|
||||
{
|
||||
if (node.value.key == key)
|
||||
{
|
||||
result = &node.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pragma(inline): SLList!(KVPair!(K, V))*
|
||||
GetList(K, V)(HashTable!(K, V)* ht, K key)
|
||||
{
|
||||
u64 hash = Hash(&key);
|
||||
u64 index = hash % ht.list_count;
|
||||
return ht.lists.ptr + index;
|
||||
}
|
||||
|
||||
pragma(inline): Result!(V)
|
||||
Delete(K, V)(HashTable!(K, V)* ht, K key)
|
||||
{
|
||||
Result!(V) result = { ok: false };
|
||||
|
||||
auto list = GetList(ht, key);
|
||||
auto prev = ht.nil;
|
||||
for(auto node = list.first; node != ht.nil; node = node.next)
|
||||
{
|
||||
if (node.value.key == key)
|
||||
{
|
||||
Remove(list, node, prev, ht.nil);
|
||||
|
||||
result.ok = true;
|
||||
result.value = node.value.value;
|
||||
|
||||
memset(&node.value, 0, node.value.sizeof);
|
||||
|
||||
Push(&ht.free_lists, node, ht.nil);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const u64 HASH_SEED = 5995;
|
||||
|
||||
pragma(inline): u64
|
||||
Hash(T)(T* value)
|
||||
{
|
||||
return xxh3_64bits_withSeed(value, T.sizeof / u8.sizeof, HASH_SEED);
|
||||
}
|
||||
|
||||
pragma(inline): u64
|
||||
Hash(string str)
|
||||
{
|
||||
return xxh3_64bits_withSeed(str.ptr, str.length, HASH_SEED);
|
||||
}
|
||||
|
||||
pragma(inline): u64
|
||||
RDTSC()
|
||||
{
|
||||
union u64_split
|
||||
{
|
||||
u64 full;
|
||||
struct
|
||||
{
|
||||
u32 lower;
|
||||
u32 upper;
|
||||
};
|
||||
};
|
||||
|
||||
u64_split val;
|
||||
u64_split* valp = &val;
|
||||
asm
|
||||
{
|
||||
cpuid;
|
||||
rdtsc;
|
||||
mov R8, valp;
|
||||
mov valp.upper.offsetof[R8], EDX;
|
||||
mov valp.lower.offsetof[R8], EAX;
|
||||
}
|
||||
|
||||
return val.full;
|
||||
}
|
||||
|
||||
pragma(inline): u64
|
||||
OSTimeFreq()
|
||||
{
|
||||
version (linux)
|
||||
{
|
||||
u64 freq = 1000000;
|
||||
}
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
pragma(inline): u64
|
||||
OSTime()
|
||||
{
|
||||
version(linux)
|
||||
{
|
||||
import core.sys.linux.sys.time;
|
||||
timeval value;
|
||||
gettimeofday(&value, null);
|
||||
|
||||
u64 time = OSTimeFreq() * cast(u64)(value.tv_sec) + cast(u64)(value.tv_usec);
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
// TODO: probably needs improvement/testing
|
||||
struct IntervalTimer
|
||||
{
|
||||
u64 cpu_freq;
|
||||
u64 interval;
|
||||
u64 prev;
|
||||
}
|
||||
|
||||
IntervalTimer
|
||||
CreateTimer(u64 fps)
|
||||
{
|
||||
IntervalTimer timer;
|
||||
|
||||
u64 ms_to_wait = 50;
|
||||
|
||||
u64 os_freq = OSTimeFreq();
|
||||
u64 cpu_start = RDTSC();
|
||||
u64 os_start = OSTime();
|
||||
u64 os_end = 0;
|
||||
u64 os_elapsed = 0;
|
||||
|
||||
u64 os_wait_time = os_freq * ms_to_wait / 1000;
|
||||
|
||||
while (os_elapsed < os_wait_time)
|
||||
{
|
||||
os_end = OSTime();
|
||||
os_elapsed = os_end - os_start;
|
||||
}
|
||||
|
||||
u64 cpu_end = RDTSC();
|
||||
u64 cpu_elapsed = cpu_end - cpu_start;
|
||||
u64 cpu_freq = 0;
|
||||
if (os_elapsed)
|
||||
{
|
||||
cpu_freq = os_freq * cpu_elapsed / os_elapsed;
|
||||
}
|
||||
|
||||
timer.cpu_freq = cpu_freq;
|
||||
timer.interval = cpu_freq/(fps+1);
|
||||
timer.prev = RDTSC();
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
pragma(inline): bool
|
||||
CheckTimer(IntervalTimer* t)
|
||||
{
|
||||
bool result = false;
|
||||
u64 time = RDTSC();
|
||||
if (time - t.prev > t.interval)
|
||||
{
|
||||
result = true;
|
||||
t.prev = time;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Timer
|
||||
{
|
||||
u64 cpu_freq;
|
||||
u64 prev;
|
||||
}
|
||||
|
||||
Timer
|
||||
CreateTimer()
|
||||
{
|
||||
u64 ms_to_wait = 50;
|
||||
|
||||
u64 os_freq = OSTimeFreq();
|
||||
u64 cpu_start = RDTSC();
|
||||
u64 os_start = OSTime();
|
||||
u64 os_end = 0;
|
||||
u64 os_elapsed = 0;
|
||||
|
||||
u64 os_wait_time = os_freq * ms_to_wait / 1000;
|
||||
|
||||
while (os_elapsed < os_wait_time)
|
||||
{
|
||||
os_end = OSTime();
|
||||
os_elapsed = os_end - os_start;
|
||||
}
|
||||
|
||||
u64 cpu_end = RDTSC();
|
||||
u64 cpu_elapsed = cpu_end - cpu_start;
|
||||
u64 cpu_freq = 0;
|
||||
if (os_elapsed)
|
||||
{
|
||||
cpu_freq = os_freq * cpu_elapsed / os_elapsed;
|
||||
}
|
||||
|
||||
Timer timer = {
|
||||
cpu_freq: cpu_freq,
|
||||
prev: RDTSC(),
|
||||
};
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
pragma(inline): f32
|
||||
DeltaTime(Timer* t)
|
||||
{
|
||||
u64 time = RDTSC();
|
||||
u64 step = time - t.prev;
|
||||
t.prev = time;
|
||||
return cast(f32)(step) / cast(f32)(t.cpu_freq);
|
||||
}
|
||||
|
||||
static string
|
||||
IntToStr(int n) nothrow pure @safe
|
||||
{
|
||||
string result;
|
||||
|
||||
static immutable string[] table = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
|
||||
if (n < table.length)
|
||||
{
|
||||
result = table[n];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = to!string(n);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static string
|
||||
GenerateLoop(string format_string, int N)() nothrow pure @safe
|
||||
{
|
||||
string result;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
result ~= format_string.replace("@", IntToStr(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
MemCpy(void* dst_p, void* src_p, u64 length)
|
||||
{
|
||||
u8* dst = cast(u8*)dst_p;
|
||||
u8* src = cast(u8*)src_p;
|
||||
|
||||
u64 remaining = length;
|
||||
if (remaining >= 64)
|
||||
{
|
||||
for(u64 i = 0; i < length; i += 64)
|
||||
{
|
||||
asm
|
||||
{
|
||||
mov R8, src;
|
||||
mov R9, dst;
|
||||
|
||||
add R8, i;
|
||||
movdqu XMM0, [R8+00];
|
||||
movdqu XMM1, [R8+16];
|
||||
movdqu XMM2, [R8+32];
|
||||
movdqu XMM3, [R8+48];
|
||||
|
||||
add R9, i;
|
||||
movdqu [R9+00], XMM0;
|
||||
movups [R9+16], XMM1;
|
||||
movups [R9+32], XMM2;
|
||||
movups [R9+48], XMM3;
|
||||
|
||||
sub remaining, 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (remaining >= 32)
|
||||
{
|
||||
for(u64 i = remaining; i < length; i += 32)
|
||||
{
|
||||
asm
|
||||
{
|
||||
mov R8, src;
|
||||
mov R9, dst;
|
||||
|
||||
add R8, i;
|
||||
movdqu XMM0, [R8+00];
|
||||
movdqu XMM1, [R8+16];
|
||||
|
||||
add R9, i;
|
||||
movdqu [R9+00], XMM0;
|
||||
movdqu [R9+16], XMM1;
|
||||
|
||||
sub remaining, 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(u64 i = remaining; i < length; i += 1)
|
||||
{
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
u8[]
|
||||
Embed(string file_name)
|
||||
{
|
||||
import std.file;
|
||||
return cast(u8[])read(file_name);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user