added model loading
This commit is contained in:
parent
ad08d31f6a
commit
d737e1feb1
2
dub.json
2
dub.json
@ -7,7 +7,7 @@
|
||||
"targetType": "executable",
|
||||
"targetName": "Gears",
|
||||
"targetPath": "build",
|
||||
"sourceFiles-linux": ["build/libvma.a", "build/libstb_image.a"],
|
||||
"sourceFiles-linux": ["build/libvma.a", "build/libstb_image.a", "build/libm3d.a"],
|
||||
"sourceFiles-windows": [],
|
||||
"importPaths": ["src/gears", "src/shared", "src/generated", "external/xxhash"],
|
||||
"sourcePaths": ["src/gears", "src/shared", "src/generated", "external/xxhash"],
|
||||
|
||||
@ -12,7 +12,6 @@ import p = platform;
|
||||
alias Shader = VkShaderModule;
|
||||
alias Pipeline = PipelineHandle;
|
||||
alias Attribute = VkVertexInputAttributeDescription;
|
||||
alias Buffer = VkBuffer;
|
||||
|
||||
enum InputRate : int
|
||||
{
|
||||
@ -78,6 +77,8 @@ struct Renderer
|
||||
Pipeline triangle_pipeline;
|
||||
Pipeline compute_pipeline;
|
||||
Pipeline ui_pipeline;
|
||||
|
||||
Model yoder;
|
||||
}
|
||||
|
||||
struct GlobalUniforms
|
||||
@ -90,6 +91,20 @@ struct ShaderUniforms
|
||||
f32 placeholder;
|
||||
}
|
||||
|
||||
struct Material
|
||||
{
|
||||
u32 albedo_texture;
|
||||
u32 ambient_texture;
|
||||
u32 specular_texture;
|
||||
b32 albedo_has_texture;
|
||||
b32 ambient_has_texture;
|
||||
b32 specular_has_texture;
|
||||
Vec4 ambient;
|
||||
Vec4 diffuse;
|
||||
Vec4 specular;
|
||||
f32 shininess = 0.0;
|
||||
}
|
||||
|
||||
struct UIVertex
|
||||
{
|
||||
Vec2 p0;
|
||||
@ -100,8 +115,8 @@ struct UIVertex
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
Vec3 pos;
|
||||
Vec3 n;
|
||||
Vec4 pos;
|
||||
Vec4 n;
|
||||
Vec2 uv;
|
||||
u32 col;
|
||||
}
|
||||
@ -122,10 +137,7 @@ struct Model
|
||||
string name;
|
||||
|
||||
Buffer[] materials;
|
||||
u32[] m_indices;
|
||||
|
||||
ImageView[] textures;
|
||||
u32[] t_indices;
|
||||
}
|
||||
|
||||
Renderer
|
||||
@ -165,6 +177,8 @@ Init(p.Window* window)
|
||||
rd.ui_pipeline = BuildGfxPipeline(&rd, &ui_info);
|
||||
rd.compute_pipeline = BuildCompPipeline(&rd, "shaders/gradient.comp");
|
||||
|
||||
rd.yoder = LoadModel(&rd, "models/yoda");
|
||||
|
||||
return rd;
|
||||
}
|
||||
|
||||
@ -215,64 +229,216 @@ LoadModel(Renderer* rd, string name)
|
||||
u8[] data = LoadAssetData(&rd.temp_arena, name);
|
||||
m3d_t* m3d = m3d_load(data.ptr, null, null, null);
|
||||
|
||||
u32[] tex_lookup = AllocArray!(u32)(&rd.temp_arena, m3d.numtexture);
|
||||
model.textures = AllocArray!(ImageView)(&rd.arena, m3d.numtexture);
|
||||
foreach(i; 0 .. m3d.numtexture)
|
||||
{
|
||||
u32 w = m3d.texture[i].w; u32 h = m3d.texture[i].h; u32 ch = m3d.texture[i].f;
|
||||
|
||||
model.textures[i] = CreateImageView(&rd.vk, w, h, ch);
|
||||
u8[] texture_data = m3d.texture[i].d[0 .. w * h * ch];
|
||||
assert(Transfer(&rd.vk, &model.textures[i], texture_data, w, h), "LoadModel failure: Texture transfer error");
|
||||
|
||||
tex_lookup[i] = Pop(&rd.vk, DT.SampledImage);
|
||||
}
|
||||
|
||||
u32[] mat_lookup = AllocArray!(u32)(&rd.temp_arena, m3d.nummaterial);
|
||||
model.materials = AllocArray!(Buffer)(&rd.arena, m3d.nummaterial);
|
||||
foreach(i; 0 .. m3d.nummaterial)
|
||||
{
|
||||
Material mat;
|
||||
|
||||
foreach(j; 0 .. m3d.material[i].numprop)
|
||||
{
|
||||
switch (m3d.material[i].prop[j].type)
|
||||
{
|
||||
case m3dp_Ka: ConvertColor(&mat.ambient, m3d.material[i].prop[j].value.color); break;
|
||||
case m3dp_Ks: ConvertColor(&mat.specular, m3d.material[i].prop[j].value.color); break;
|
||||
case m3dp_Ns: mat.shininess = m3d.material[i].prop[j].value.fnum; break;
|
||||
case m3dp_map_Kd:
|
||||
{
|
||||
mat.albedo_texture = tex_lookup[m3d.material[i].prop[j].value.textureid];
|
||||
mat.albedo_has_texture = true;
|
||||
} break;
|
||||
case m3dp_map_Ka:
|
||||
{
|
||||
mat.ambient_texture = tex_lookup[m3d.material[i].prop[j].value.textureid];
|
||||
mat.ambient_has_texture = true;
|
||||
} break;
|
||||
case m3dp_map_Ks:
|
||||
{
|
||||
mat.specular_texture = tex_lookup[m3d.material[i].prop[j].value.textureid];
|
||||
mat.specular_has_texture = true;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
model.materials[i] = CreateBuffer(&rd.vk, BT.Uniform, Material.sizeof, false);
|
||||
assert(Transfer(&rd.vk, &model.materials[i], &mat), "LoadModel failure: Transfer error when transferring material");
|
||||
|
||||
mat_lookup[i] = Pop(&rd.vk, DT.Material);
|
||||
}
|
||||
|
||||
u32 mesh_count = 0;
|
||||
u64 last = u64.max;
|
||||
foreach(i; 0 .. m3d.numface)
|
||||
{
|
||||
if (m3d.face[i].materialid != last)
|
||||
{
|
||||
last = m3d.face[i].materialid;
|
||||
mesh_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
model.parts = AllocArray!(MeshPart)(&rd.arena, mesh_count);
|
||||
last = u64.max;
|
||||
u32 index = 0;
|
||||
foreach(i; 0 .. m3d.numface)
|
||||
{
|
||||
if (last == u64.max)
|
||||
{
|
||||
model.parts[index].mat = mat_lookup[m3d.face[i].materialid];
|
||||
model.parts[index].offset = 0;
|
||||
last = m3d.face[i].materialid;
|
||||
}
|
||||
else if (m3d.face[i].materialid != last)
|
||||
{
|
||||
u32 vertex_index = i * 3;
|
||||
|
||||
model.parts[index].length = vertex_index - model.parts[index].offset;
|
||||
index += 1;
|
||||
|
||||
model.parts[index].mat = mat_lookup[m3d.face[i].materialid];
|
||||
model.parts[index].offset = vertex_index;
|
||||
last = m3d.face[i].materialid;
|
||||
}
|
||||
else if (i == m3d.numface-1)
|
||||
{
|
||||
u32 vertex_index = i * 3;
|
||||
model.parts[index].length = vertex_index+3 - model.parts[index].offset;
|
||||
}
|
||||
}
|
||||
|
||||
m3dv_t* vertex;
|
||||
|
||||
u32[] indices = AllocArray!(u32)(&rd.temp_arena, m3d.numface * 3);
|
||||
Vertex[] vertices = AllocArray!(Vertex)(&rd.temp_arena, m3d.numface * 3);
|
||||
|
||||
foreach(i; 0 .. m3d.numface)
|
||||
{
|
||||
u32 vi = (i * 3);
|
||||
|
||||
CopyVertex(&vertices[vi+0].pos, &m3d.vertex[m3d.face[i].vertex[0]]);
|
||||
CopyVertex(&vertices[vi+1].pos, &m3d.vertex[m3d.face[i].vertex[1]]);
|
||||
CopyVertex(&vertices[vi+2].pos, &m3d.vertex[m3d.face[i].vertex[2]]);
|
||||
|
||||
CopyVertex(&vertices[vi+0].n, &m3d.vertex[m3d.face[i].vertex[0]]);
|
||||
CopyVertex(&vertices[vi+1].n, &m3d.vertex[m3d.face[i].vertex[1]]);
|
||||
CopyVertex(&vertices[vi+2].n, &m3d.vertex[m3d.face[i].vertex[2]]);
|
||||
|
||||
vertices[vi+0].col = m3d.vertex[m3d.face[i].vertex[0]].color;
|
||||
vertices[vi+1].col = m3d.vertex[m3d.face[i].vertex[1]].color;
|
||||
vertices[vi+2].col = m3d.vertex[m3d.face[i].vertex[2]].color;
|
||||
|
||||
if (m3d.numtmap)
|
||||
{
|
||||
vertices[vi+0].uv.x = m3d.tmap[m3d.face[i].texcoord[0]].u;
|
||||
vertices[vi+0].uv.y = m3d.tmap[m3d.face[i].texcoord[0]].v;
|
||||
|
||||
vertices[vi+1].uv.x = m3d.tmap[m3d.face[i].texcoord[1]].u;
|
||||
vertices[vi+1].uv.y = m3d.tmap[m3d.face[i].texcoord[1]].v;
|
||||
|
||||
vertices[vi+2].uv.x = m3d.tmap[m3d.face[i].texcoord[2]].u;
|
||||
vertices[vi+2].uv.y = m3d.tmap[m3d.face[i].texcoord[2]].v;
|
||||
}
|
||||
|
||||
indices[vi+0] = vi+0;
|
||||
indices[vi+1] = vi+1;
|
||||
indices[vi+2] = vi+2;
|
||||
}
|
||||
|
||||
model.vertex_buffer = CreateBuffer(&rd.vk, BT.Vertex, vertices.length * Vertex.sizeof, false);
|
||||
model.index_buffer = CreateBuffer(&rd.vk, BT.Index, indices.length * u32.sizeof, false);
|
||||
|
||||
assert(Transfer(&rd.vk, &model.vertex_buffer, vertices), "LoadModel failure: Unable to transfer vertex buffer");
|
||||
assert(Transfer(&rd.vk, &model.index_buffer, indices), "LoadModel failure: Unable to transfer index buffer");
|
||||
|
||||
Reset(&rd.temp_arena);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
bool
|
||||
pragma(inline): void
|
||||
CopyVertex(Vec4* dst, m3dv_t* src)
|
||||
{
|
||||
asm
|
||||
{
|
||||
mov R8, src;
|
||||
mov R9, dst;
|
||||
movups XMM0, src.x.offsetof[R8];
|
||||
movups dst.x.offsetof[R9], XMM0;
|
||||
}
|
||||
|
||||
assert(dst.x == src.x && dst.y == src.y && dst.z == src.z && dst.w == src.w, "CopyVertex failure");
|
||||
}
|
||||
|
||||
pragma(inline): bool
|
||||
BeginFrame(Renderer* rd)
|
||||
{
|
||||
return BeginFrame(&rd.vk);
|
||||
}
|
||||
|
||||
bool
|
||||
pragma(inline): bool
|
||||
FinishFrame(Renderer* rd)
|
||||
{
|
||||
return FinishFrame(&rd.vk);
|
||||
}
|
||||
|
||||
void
|
||||
pragma(inline): void
|
||||
Dispatch(Renderer* rd)
|
||||
{
|
||||
Dispatch(&rd.vk);
|
||||
}
|
||||
|
||||
void
|
||||
pragma(inline): void
|
||||
PrepCompute(Renderer* rd)
|
||||
{
|
||||
PrepCompute(&rd.vk);
|
||||
}
|
||||
|
||||
void
|
||||
pragma(inline): void
|
||||
SetUniform(Renderer* rd, GlobalUniforms* uniforms)
|
||||
{
|
||||
SetUniform(&rd.vk, uniforms);
|
||||
}
|
||||
|
||||
void
|
||||
pragma(inline): void
|
||||
BeginRender(Renderer* rd)
|
||||
{
|
||||
BeginRender(&rd.vk);
|
||||
}
|
||||
|
||||
void
|
||||
pragma(inline): void
|
||||
BindUIBuffers(Renderer* rd)
|
||||
{
|
||||
BindUIBuffers(&rd.vk);
|
||||
}
|
||||
|
||||
void
|
||||
pragma(inline): void
|
||||
DrawIndexed(Renderer* rd, u32 index_count, u32 instance_count)
|
||||
{
|
||||
DrawIndexed(&rd.vk, index_count, instance_count);
|
||||
}
|
||||
|
||||
void
|
||||
pragma(inline): void
|
||||
Draw(Renderer* rd, u32 index_count, u32 instance_count)
|
||||
{
|
||||
Draw(&rd.vk, index_count, instance_count);
|
||||
}
|
||||
|
||||
void Bind(Renderer* rd, Pipeline* pipeline)
|
||||
pragma(inline): void
|
||||
Bind(Renderer* rd, Pipeline* pipeline)
|
||||
{
|
||||
Bind(&rd.vk, pipeline);
|
||||
}
|
||||
@ -298,13 +464,13 @@ DrawRect(Renderer* rd, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col)
|
||||
rd.ui_count += 1;
|
||||
}
|
||||
|
||||
Pipeline
|
||||
pragma(inline): Pipeline
|
||||
BuildGfxPipeline(Renderer* rd, GfxPipelineInfo* info)
|
||||
{
|
||||
return CreateGraphicsPipeline(&rd.vk, info);
|
||||
}
|
||||
|
||||
Pipeline
|
||||
pragma(inline): Pipeline
|
||||
BuildCompPipeline(Renderer* rd, string compute)
|
||||
{
|
||||
return CreateComputePipeline(&rd.vk, compute);
|
||||
|
||||
@ -3,9 +3,9 @@ import vulkan_logging;
|
||||
import aliases;
|
||||
import std.stdio;
|
||||
import std.algorithm.comparison;
|
||||
import core.stdc.string : strcmp;
|
||||
import core.stdc.string : strcmp, memcpy;
|
||||
import std.format : sformat;
|
||||
import u = util : HashTable, Result, Logf, Log, MB;
|
||||
import u = util : HashTable, Result, Logf, Log, MB, Delete;
|
||||
import alloc;
|
||||
import p = platform;
|
||||
import ap = assets;
|
||||
@ -643,10 +643,12 @@ CreateImageView(Vulkan* vk, u32 w, u32 h, u32 ch)
|
||||
}
|
||||
|
||||
ImageView view = {
|
||||
format: VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
base: {
|
||||
layout: VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
},
|
||||
};
|
||||
|
||||
VkResult result = vmaCreateImage(vk.vma, &image_info, &alloc_info, &view.image, *view.alloc, null);
|
||||
VkResult result = vmaCreateImage(vk.vma, &image_info, &alloc_info, &view.image, &view.alloc, null);
|
||||
// TODO: handle errors and realloc
|
||||
assert(VkCheck("CreateImageView failure: vmaCreateImage error", result), "CreateImageView failure");
|
||||
|
||||
@ -670,9 +672,66 @@ CreateImageView(Vulkan* vk, u32 w, u32 h, u32 ch)
|
||||
}
|
||||
|
||||
u32
|
||||
Push(Vulkan* vk, ImageView* view)
|
||||
Pop(Vulkan* vk, DescType type)
|
||||
{
|
||||
DescBindings* bindings = vk.desc_bindings.ptr + type;
|
||||
|
||||
assert(bindings.count > 0, "Pop failure: no free bindings remaining");
|
||||
bindings.count -= 1;
|
||||
|
||||
return bindings.free[bindings.count];
|
||||
}
|
||||
|
||||
void
|
||||
Push(Vulkan* vk, u32 index, DescType type)
|
||||
{
|
||||
DescBindings* bindings = vk.desc_bindings.ptr + type;
|
||||
|
||||
bindings.free[bindings.count] = index;
|
||||
bindings.count += 1;
|
||||
}
|
||||
|
||||
u32
|
||||
Pop(Vulkan* vk, string name, DescType type)
|
||||
{
|
||||
DescBindings* bindings = vk.desc_bindings.ptr + type;
|
||||
|
||||
u32 index;
|
||||
auto result = bindings.lookup_table[name];
|
||||
if (!result.ok)
|
||||
{
|
||||
// TODO: handle unbinding assets (maybe)
|
||||
assert(bindings.count > 0, "Pop failure: no free bindings remaining");
|
||||
bindings.count -= 1;
|
||||
index = bindings.free[bindings.count];
|
||||
}
|
||||
else
|
||||
{
|
||||
index = result.value;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void
|
||||
Push(Vulkan* vk, string name, DescType type)
|
||||
{
|
||||
DescBindings* bindings = vk.desc_bindings.ptr + type;
|
||||
auto result = Delete(&bindings.lookup_table, name);
|
||||
if (result.ok)
|
||||
{
|
||||
assert(bindings.count < bindings.free.length, "Push failure: attempt to push a binding into a full stack");
|
||||
|
||||
bindings.free[bindings.count] = result.value;
|
||||
bindings.count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Transfer(T)(Vulkan* vk, Buffer* buf, T[] data)
|
||||
{
|
||||
u8[] u8_data = (cast(u8*)(data.ptr))[0 .. T.sizeof * data.length];
|
||||
return Transfer(vk, buf, u8_data);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -708,6 +767,33 @@ Transfer(Vulkan* vk, Buffer* buf, u8[] data)
|
||||
return success;
|
||||
}
|
||||
|
||||
bool
|
||||
Transfer(T)(Vulkan* vk, Buffer* buf, T* ptr)
|
||||
{
|
||||
assert(T.sizeof < vk.transfer_buf.data.length, "Transfer failure: structure size is too large");
|
||||
|
||||
memcpy(vk.transfer_buf.data.ptr, ptr, T.sizeof);
|
||||
|
||||
auto fn = delegate()
|
||||
{
|
||||
VkBufferCopy copy = {
|
||||
srcOffset: 0,
|
||||
dstOffset: 0,
|
||||
size: T.sizeof,
|
||||
};
|
||||
|
||||
vkCmdCopyBuffer(vk.imm_cmd, vk.transfer_buf.buffer, buf.buffer, 1, ©);
|
||||
};
|
||||
|
||||
return ImmSubmit(vk, fn);
|
||||
}
|
||||
|
||||
pragma(inline): bool
|
||||
Transfer(Vulkan* vk, ImageView* view, u8[] data, u32 w, u32 h)
|
||||
{
|
||||
return Transfer(vk, &view.base, data, w, h);
|
||||
}
|
||||
|
||||
bool
|
||||
Transfer(Vulkan* vk, Image* image, u8[] data, u32 w, u32 h)
|
||||
{
|
||||
|
||||
@ -42,6 +42,29 @@ GB(u64 v)
|
||||
return MB(v) * 1024;
|
||||
};
|
||||
|
||||
pragma(inline): void
|
||||
ConvertColor(Vec4 *dst, u32 src)
|
||||
{
|
||||
if (src == 0)
|
||||
{
|
||||
dst.v[] = 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)
|
||||
{
|
||||
@ -103,6 +126,30 @@ Pop(T)(SLList!(T)*list, Node!(T)* nil)
|
||||
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)
|
||||
{
|
||||
@ -282,10 +329,7 @@ Delete(K, V)(HashTable!(K, V)* ht, K key)
|
||||
{
|
||||
if (node.value.key == key)
|
||||
{
|
||||
if (prev != ht.nil)
|
||||
{
|
||||
prev.next = node.next;
|
||||
}
|
||||
Remove(list, node, prev, ht.nil);
|
||||
|
||||
result.ok = true;
|
||||
result.value = node.value.value;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user