diff options
author | quou <quou@disroot.org> | 2025-01-01 18:43:31 +1100 |
---|---|---|
committer | quou <quou@disroot.org> | 2025-01-01 18:43:31 +1100 |
commit | d26100734623f37063206b9b144c2a29fd71d414 (patch) | |
tree | 11aefe54b4110109a841cb656b2f309ee69a1893 | |
parent | 568ba73c71b650f905bd1b3f60f10871316eefdc (diff) |
material system
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 28 | ||||
-rw-r--r-- | asset.cpp | 14 | ||||
-rw-r--r-- | asset.hpp | 2 | ||||
-rw-r--r-- | c2.cpp | 36 | ||||
-rw-r--r-- | cfg/cfgparse.c | 54 | ||||
-rw-r--r-- | cfg/cfgparse.h | 17 | ||||
-rw-r--r-- | convmaterial.c | 83 | ||||
-rw-r--r-- | convmodel.c | 34 | ||||
-rw-r--r-- | intermediate/brick_albedo.bmp | bin | 0 -> 16777354 bytes | |||
-rw-r--r-- | intermediate/brick_ao.bmp | bin | 0 -> 16777354 bytes | |||
-rw-r--r-- | intermediate/brick_metal.bmp | bin | 0 -> 16777354 bytes | |||
-rw-r--r-- | intermediate/brick_normal.bmp | bin | 0 -> 16777354 bytes | |||
-rw-r--r-- | intermediate/bricks.mat | 11 | ||||
-rw-r--r-- | intermediate/monkey.glb | bin | 80692 -> 40636 bytes | |||
-rw-r--r-- | intermediate/plastic.mat | 11 | ||||
-rw-r--r-- | intermediate/surface.glsl | 83 | ||||
-rw-r--r-- | material.h | 16 | ||||
-rw-r--r-- | model.cpp | 124 | ||||
-rw-r--r-- | model.hpp | 39 | ||||
-rw-r--r-- | sc/sc.cpp | 2 | ||||
-rw-r--r-- | src/monkey.blend | bin | 539788 -> 544320 bytes | |||
-rwxr-xr-x | testbc1 | bin | 0 -> 20720 bytes | |||
-rw-r--r-- | video.cpp | 1 |
24 files changed, 520 insertions, 36 deletions
@@ -17,3 +17,4 @@ tags /packer /convtexture /convmodel +/convmaterial @@ -3,9 +3,15 @@ target = c2 data_dir = data shaders = $(data_dir)/triangle.csh $(data_dir)/ui.csh $(data_dir)/surface.csh -textures = $(data_dir)/22.tex $(data_dir)/kita.tex +textures = \ + $(data_dir)/22.tex \ + $(data_dir)/kita.tex \ + $(data_dir)/brick_albedo.tex \ + $(data_dir)/brick_ao.tex \ + $(data_dir)/brick_normal.tex models = $(data_dir)/monkey.mdl -packed_files = $(shaders) $(textures) $(models) +materials = $(data_dir)/bricks.mat $(data_dir)/plastic.mat +packed_files = $(shaders) $(textures) $(models) $(materials) tools = qstd cfg sc objects = app.o c2.o video.o pipeline.o asset.o ui.o maths.o model.o includes = -Iqstd @@ -35,6 +41,9 @@ convtexture: convtexture.c | qstd convmodel: convmodel.c | qstd $(CC) $(cflags) convmodel.c $(lflags) -Lqstd -lqstd -o convmodel +convmaterial: convmaterial.c | qstd cfg + $(CC) $(cflags) convmaterial.c $(lflags) -Lqstd -lqstd -Lcfg -lcfg -o convmaterial + pack: $(packed_files) packer ./packer pack $(data_dir) $(notdir $(packed_files)) @@ -53,9 +62,24 @@ data/22.tex: intermediate/22.bmp | $(data_dir) convtexture data/kita.tex: intermediate/kita.bmp | $(data_dir) convtexture ./convtexture intermediate/kita.bmp $(data_dir)/kita.tex bc1 +data/brick_albedo.tex: intermediate/brick_albedo.bmp | $(data_dir) convtexture + ./convtexture intermediate/brick_albedo.bmp $(data_dir)/brick_albedo.tex bc1 + +data/brick_ao.tex: intermediate/brick_ao.bmp | $(data_dir) convtexture + ./convtexture intermediate/brick_ao.bmp $(data_dir)/brick_ao.tex bc4 + +data/brick_normal.tex: intermediate/brick_normal.bmp | $(data_dir) convtexture + ./convtexture intermediate/brick_normal.bmp $(data_dir)/brick_normal.tex bc5 + data/monkey.mdl: intermediate/monkey.glb $(shaders) | $(data_dir) convmodel ./convmodel $(data_dir) intermediate/monkey.glb $(data_dir)/monkey.mdl +data/bricks.mat: intermediate/bricks.mat | $(data_dir) convmaterial + ./convmaterial intermediate/bricks.mat $(data_dir)/bricks.mat + +data/plastic.mat: intermediate/plastic.mat | $(data_dir) convmaterial + ./convmaterial intermediate/plastic.mat $(data_dir)/plastic.mat + app.o: $(CXX) -c $(cflags) app.cpp -o app.o @@ -8,7 +8,7 @@ extern "C" { } #define max_asset_types 32 -#define asset_scratch_size (1024 * 1024) +#define asset_scratch_size (1024) struct RLoader { char magic[4]; @@ -75,12 +75,6 @@ void Asset_Arena::init( p = pack_open(pack_name, arena); assert(p != 0); a = arena; - s = (Arena*)arena_alloc(a, sizeof *s); - init_arena( - s, - arena_alloc(a, asset_scratch_size), - asset_scratch_size - ); max_assets = max; assets = (Bucket*)arena_alloc(arena, max * sizeof(Bucket)); for (i = 0; i < max; i++) @@ -112,6 +106,8 @@ int Asset_Arena::bucket(const char* name) { Asset* Asset_Arena::load(const char* name) { char magic[4]; + char scratch[asset_scratch_size]; + Arena sa; Pack_File* f; int b = bucket(name); assert(b >= 0); @@ -122,8 +118,8 @@ Asset* Asset_Arena::load(const char* name) { pack_read(f, magic, 4); pack_seek(f, 0, seek_rel_start); Asset_Loader& loader = manager.get_loader(magic); - clear_arena(s); - Asset* asset = loader.load(a, s, name, f); + init_arena(&sa, scratch, sizeof scratch); + Asset* asset = loader.load(a, &sa, name, f); if (asset) { asset->loader = &loader; assets[b].name = dup_string(a, name); @@ -22,7 +22,7 @@ struct Asset_Loader { struct Asset_Arena { Pack* p; - Arena* a, * s; + Arena* a; struct Bucket { char* name; Asset* asset; @@ -58,6 +58,30 @@ static Buffer_Id upload_verts(Device* dev) { return vbo; } +Texture_Id make_default_texture(Device* dev) { + unsigned* mem; + Texture_Id tex; + Buffer_Id buf = dev->create_buffer( + "default texture stage", + 4, + Buffer_Flags::copy_src | + Buffer_Flags::cpu_readwrite + ); + mem = (unsigned*)dev->map_buffer(buf, 0, 4); + mem[0] = 0xffffffff; + dev->unmap_buffer(buf); + tex = dev->create_texture( + "default PBR texture", + texture_format_rgba8i, + Texture_Flags::sampleable | Texture_Flags::copy_dst, + 1, + 1, + buf + ); + dev->destroy_bufferi(buf); + return tex; +} + static Sampler_Id create_clamped_linear(Device* dev) { Sampler_State s{}; s.min = Filter_Mode::linear; @@ -79,11 +103,13 @@ struct Config_Buffer2 { extern "C" int entrypoint() { Arena video_arena, asset_arena, ui_arena; Model_Loader model_loader; + Material_Loader mat_loader; Asset_Arena assets; Device* dev; Shader* shader, * ui_shader; Texture* texture; Texture* texture2; + Texture_Id default_texture; Model* monkey; Buffer_Id vbo, cbuf; Sampler_Id clamped_linear; @@ -109,8 +135,11 @@ extern "C" int entrypoint() { ); assets.init(&asset_arena, "pack", 128); dev = Device::create(&video_arena, app); + default_texture = make_default_texture(dev); model_loader.init(dev, &assets); + mat_loader.init(&assets, default_texture); register_asset_loader("MODL", &model_loader); + register_asset_loader("MTRL", &mat_loader); monkey = (Model*)assets.load("monkey.mdl"); app->dev = dev; shader = (Shader*)assets.load("triangle.csh"); @@ -234,14 +263,16 @@ extern "C" int entrypoint() { monkey->render( dev, &frame_arena, - depth_prepass + depth_prepass, + clamped_linear ); ctx.debug_pop(); ctx.debug_push("forward"); monkey->render( dev, &frame_arena, - pass2 + pass2, + clamped_linear ); ctx.debug_pop(); @@ -257,6 +288,7 @@ extern "C" int entrypoint() { } ui->destroy(); assets.destroy(); + dev->destroy_texture(default_texture); dev->destroy_sampler(clamped_linear); dev->destroy_buffer(vbo); dev->destroy_buffer(cbuf); diff --git a/cfg/cfgparse.c b/cfg/cfgparse.c index 4dc6dbb..9ac8ec7 100644 --- a/cfg/cfgparse.c +++ b/cfg/cfgparse.c @@ -74,9 +74,18 @@ static void fill_prop_number( const char* start, int len ) { - (void)len; - p->type = cfg_type_int; - p->as.num = (int)strtol(start, 0, 10); + int is_f = 0; + int i; + for (i = 0; i < len; i++) + if (start[i] == '.') + is_f = 1; + if (is_f) { + p->type = cfg_type_float; + p->as.num = (float)strtod(start, 0); + } else { + p->type = cfg_type_int; + p->as.num = (int)strtol(start, 0, 10); + } } static void fill_prop_data( @@ -222,6 +231,36 @@ int find_int_default( return def; } +float find_float_default( + const cfg_Object* obj, + const char* name, + float def +) { + const cfg_Prop* prop; + prop = find_prop_of(obj, name, cfg_type_float); + if (prop) { + return prop->as.flt; + } + return def; +} + +float find_num_default( + const cfg_Object* obj, + const char* name, + float def +) { + const cfg_Prop* prop; + prop = find_prop_of(obj, name, cfg_type_float); + if (prop) { + return prop->as.flt; + } + prop = find_prop_of(obj, name, cfg_type_int); + if (prop) { + return prop->as.num; + } + return def; +} + const char* find_string_default( const cfg_Object* obj, const char* name, @@ -234,3 +273,12 @@ const char* find_string_default( } return def; } + +unsigned find_colour_default( + const cfg_Object* obj, + const char* name, + const char* def +) { + const char* s = find_string_default(obj, name, def); + return (unsigned)strtol(s, 0, 16); +} diff --git a/cfg/cfgparse.h b/cfg/cfgparse.h index 4865b48..a585de6 100644 --- a/cfg/cfgparse.h +++ b/cfg/cfgparse.h @@ -5,6 +5,7 @@ typedef enum { cfg_type_int, + cfg_type_float, cfg_type_string, cfg_type_data, cfg_type_none @@ -19,6 +20,7 @@ typedef struct cfg_Prop { char name[28]; cfg_Type type; union { + float flt; int num; cfg_Data data; char* str; @@ -53,10 +55,25 @@ int find_int_default( const char* name, int def ); +float find_float_default( + const cfg_Object* obj, + const char* name, + float def +); +float find_num_default( + const cfg_Object* obj, + const char* name, + float def +); const char* find_string_default( const cfg_Object* obj, const char* name, const char* def ); +unsigned find_colour_default( + const cfg_Object* obj, + const char* name, + const char* def +); #endif diff --git a/convmaterial.c b/convmaterial.c new file mode 100644 index 0000000..fde7223 --- /dev/null +++ b/convmaterial.c @@ -0,0 +1,83 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "cfg/cfgparse.h" +#include "material.h" +#include "memory.h" +#include "plat.h" +#include "str.h" + +void parse(cfg_Object* cfg, FILE* f) { + Material_File r; + zero(&r, sizeof r); + fwrite(&r, sizeof r, 1, f); + r.magic[0] = 'M'; + r.magic[1] = 'T'; + r.magic[2] = 'R'; + r.magic[3] = 'L'; + const char* albedo_tex = ""; + const char* ao_tex = ""; + const char* metal_tex = ""; + const char* rough_tex = ""; + const char* normal_tex = ""; + for (; cfg; cfg = cfg->next) { + if (string_equal(cfg->name, "params")) { + r.metalness = find_float_default(cfg, "metalness", 0.0f); + r.roughness = find_float_default(cfg, "roughness", 0.0f); + r.ao = find_float_default(cfg, "ao", 1.0f); + r.albedo = find_colour_default(cfg, "albedo", "ffffff"); + } else if (string_equal(cfg->name, "textures")) { + albedo_tex = find_string_default(cfg, "albedo", ""); + ao_tex = find_string_default(cfg, "ao", ""); + metal_tex = find_string_default(cfg, "metal", ""); + rough_tex = find_string_default(cfg, "rough", ""); + normal_tex = find_string_default(cfg, "normal", ""); + } + } + r.albedo_tex_len = string_len(albedo_tex); + r.ao_tex_len = string_len(ao_tex); + r.metal_tex_len = string_len(metal_tex); + r.rough_tex_len = string_len(rough_tex); + r.normal_tex_len = string_len(normal_tex); + fseek(f, 0, SEEK_SET); + fwrite(&r, sizeof r, 1, f); + fwrite(albedo_tex, 1, r.albedo_tex_len, f); + fwrite(ao_tex, 1, r.ao_tex_len, f); + fwrite(metal_tex, 1, r.metal_tex_len, f); + fwrite(rough_tex, 1, r.rough_tex_len, f); + fwrite(normal_tex, 1, r.albedo_tex_len, f); +} + +int main(int argc, const char** argv) { + int mem_size = 1024 * 1024; + void* mem = malloc(mem_size); + Arena arena; + cfg_Object* cfg; + FILE* infile, * outfile; + char* src; + int size; + init_arena(&arena, mem, mem_size); + if (argc < 3) { + print_err("Usage: %s infile outfile format.\n", argv[0]); + return 1; + } + infile = fopen(argv[1], "r"); + if (!infile) { + print_err("Failed to open %s.\n", argv[1]); + return 2; + } + fseek(infile, 0, SEEK_END); + size = ftell(infile); + rewind(infile); + src = malloc(size + 1); + src[fread(src, 1, size, infile)] = 0; + cfg = cfg_parse(src, &arena); + outfile = fopen(argv[2], "wb"); + if (!outfile) { + print_err("Failed to open %s.\n", argv[1]); + return 3; + } + parse(cfg, outfile); + fclose(outfile); + return 0; +} diff --git a/convmodel.c b/convmodel.c index 1a09f99..4e7184b 100644 --- a/convmodel.c +++ b/convmodel.c @@ -12,6 +12,7 @@ typedef struct { const char* shader; + const char* material; } Node_Config; typedef struct Shader_Attrib { @@ -84,6 +85,17 @@ void parse_node_cfg(const cgltf_node* n, Node_Config* cfg) { } i++; } + if (tcmp(json, "material", t)) { + cfg->material = read_str(json, &t[1]); + if (string_len(cfg->material) > 27) { + print_err( + "Material name %s too long (max 27 chars).\n", + cfg->material + ); + pbreak(3479); + } + i++; + } } } @@ -120,11 +132,11 @@ void read_vertex( Shader_Attrib* t = target_attribs[i]; if (!t) continue; int ec = t->size / 4; - if (a->component_type != cgltf_component_type_r_32f) { - print_err("Only float attributes are supported.\n"); - pbreak(33); - } if (a) { + if (a->component_type != cgltf_component_type_r_32f) { + print_err("Only float attributes are supported.\n"); + pbreak(33); + } const cgltf_buffer_view* v = a->buffer_view; int j, off = t->offset / 4; int sec = (a->stride / 4); @@ -233,14 +245,17 @@ void parse_node_mesh( int i, c = m->primitives_count; char buf[28]; float matrix[16]; - zero(buf, sizeof buf); - string_copy(buf, cfg->shader); vertex_count = 0; index_count = 0; for (i = 0; i < c; i++) parse_prim(&m->primitives[i], desired); cgltf_node_transform_local(n, matrix); fwrite("MESH", 4, 1, outfile); + zero(buf, sizeof buf); + string_copy(buf, cfg->shader); + fwrite(buf, 1, sizeof buf, outfile); + zero(buf, sizeof buf); + string_copy(buf, cfg->material); fwrite(buf, 1, sizeof buf, outfile); fwrite(&vertex_size, 4, 1, outfile); fwrite(&index_count, 4, 1, outfile); @@ -370,6 +385,13 @@ void parse_node( ); pbreak(48); } + if (!cfg.material) { + print_err( + "Node %s has a mesh, but doesn't specify a material.\n", + n->name + ); + pbreak(49); + } desired = parse_shader_attribs(cfg.shader); vertex_size = calc_vertex_size(desired); current_vertex = arena_alloc(&arena, vertex_size); diff --git a/intermediate/brick_albedo.bmp b/intermediate/brick_albedo.bmp Binary files differnew file mode 100644 index 0000000..54a8a71 --- /dev/null +++ b/intermediate/brick_albedo.bmp diff --git a/intermediate/brick_ao.bmp b/intermediate/brick_ao.bmp Binary files differnew file mode 100644 index 0000000..59ed011 --- /dev/null +++ b/intermediate/brick_ao.bmp diff --git a/intermediate/brick_metal.bmp b/intermediate/brick_metal.bmp Binary files differnew file mode 100644 index 0000000..bafe5f3 --- /dev/null +++ b/intermediate/brick_metal.bmp diff --git a/intermediate/brick_normal.bmp b/intermediate/brick_normal.bmp Binary files differnew file mode 100644 index 0000000..6add824 --- /dev/null +++ b/intermediate/brick_normal.bmp diff --git a/intermediate/bricks.mat b/intermediate/bricks.mat new file mode 100644 index 0000000..28bea24 --- /dev/null +++ b/intermediate/bricks.mat @@ -0,0 +1,11 @@ +[params] +metalness: 1.0 +roughness: 1.0 +ao: 1.0 +albedo: ffffff + +[textures] +albedo: brick_albedo.tex +ao: brick_ao.tex +metal: brick_metal.tex +normal: brick_normal.tex diff --git a/intermediate/monkey.glb b/intermediate/monkey.glb Binary files differindex d199545..3e8fd29 100644 --- a/intermediate/monkey.glb +++ b/intermediate/monkey.glb diff --git a/intermediate/plastic.mat b/intermediate/plastic.mat new file mode 100644 index 0000000..ff71d8b --- /dev/null +++ b/intermediate/plastic.mat @@ -0,0 +1,11 @@ +[params] +metalness: 0.0 +roughness: 0.0 +ao: 1.0 +albedo: ff0000 + +[textures] +#albedo: brick_albedo.tex +#ao: brick_ao.tex +#metal: brick_metal.tex +#normal: brick_normal.tex diff --git a/intermediate/surface.glsl b/intermediate/surface.glsl index 18c13a3..7988502 100644 --- a/intermediate/surface.glsl +++ b/intermediate/surface.glsl @@ -14,6 +14,9 @@ type: vec3 name: normal type: vec3 [attribute] +name: tangent +type: vec3 +[attribute] name: uv type: vec2 @@ -21,8 +24,14 @@ type: vec2 name: uv type: vec2 [interpolator] +name: position +type: vec4 +[interpolator] name: normal type: vec3 +[interpolator] +name: tbn +type: mat3 [struct] name: MVP @@ -33,11 +42,52 @@ type: mat4 name: view_projection type: mat4 +[struct] +name: Material +[variable] +name: albedo +type: vec3 +[variable] +name: metalness +type: float +[variable] +name: roughness +type: float +[variable] +name: ao +type: float + [cbuffer] name: c_mvp type: MVP stage: vertex +[cbuffer] +name: material +type: Material +stage: fragment + +[texture] +name: albedo +stage: fragment +dimension: 2 +[texture] +name: ao +stage: fragment +dimension: 2 +[texture] +name: metal +stage: fragment +dimension: 2 +[texture] +name: rough +stage: fragment +dimension: 2 +[texture] +name: normal +stage: fragment +dimension: 2 + [target] name: colour type: vec4 @@ -47,12 +97,16 @@ type: vec4 #ifdef VERTEX_SHADER void main() { + vec4 pos = c_mvp.model * vec4(position, 1.0); + vec3 t = normalize((c_mvp.model * vec4(tangent, 0.0)).xyz); + vec3 b = normalize((c_mvp.model * vec4(normal, 0.0)).xyz); + vec3 n = normalize((c_mvp.model * vec4(cross(normal, tangent), 0.0)).xyz); + interpolator.normal = n; + interpolator.tbn = mat3(t, b, n); interpolator.uv = uv; - interpolator.normal = mat3(c_mvp.model) * normal; - gl_Position = - c_mvp.view_projection * - c_mvp.model * - vec4(position, 1.0); + interpolator.position = pos; + interpolator.tbn = mat3(t, b, n); + gl_Position = c_mvp.view_projection * pos; } #endif @@ -60,9 +114,22 @@ void main() { #ifdef FRAGMENT_SHADER void main() { - vec3 normal = normalize(interpolator.normal); - float light = max(dot(normal, vec3(0, 0, 1)), 0.0); - colour = vec4(light.xxx, 1.0); + vec2 uv = interpolator.uv; + + vec3 nrmsample = texture(normal, uv).rgb; + + vec2 nrmxy = nrmsample.xy * 2.0 - 1.0; + vec3 nrm = normalize(vec3(nrmxy, 1.0)); + if (nrmsample.b == 1.0) /* default texture */ + nrm = vec3(0, 0, 1); + nrm = normalize(interpolator.tbn * nrm); + + float light = max(dot(nrm, vec3(0, 0, 1)), 0.0); + + vec3 ambient = 0.05.xxx * texture(ao, uv).r; + vec3 col = light * material.albedo; + col *= texture(albedo, uv).rgb; + colour = vec4(col, 1.0); } #endif diff --git a/material.h b/material.h new file mode 100644 index 0000000..7e58468 --- /dev/null +++ b/material.h @@ -0,0 +1,16 @@ +#ifndef material_h +#define material_h + +typedef struct { + char magic[4]; + float metalness, roughness; + float ao; + unsigned albedo; + int albedo_tex_len; + int ao_tex_len; + int metal_tex_len; + int rough_tex_len; + int normal_tex_len; +} Material_File; + +#endif @@ -2,6 +2,7 @@ #include "model.hpp" extern "C" { +#include "material.h" #include "memory.h" #include "pack.h" #include "plat.h" @@ -14,6 +15,35 @@ struct MVP_Cbuffer { m4f view_projection; }; +struct Mat_Cbuffer { + float albedo[3]; + float metalness; + float roughness; + float ao; + char pad[40]; +}; + +void Material::use( + Pipeline_Builder& pb, + Sampler_Id sampler, + Shader& shader +) { + auto bind = [&shader, &pb, sampler]( + const char* name, + Texture_Id t + ) { + int loc = shader.descriptor_binding(name); + if (loc >= 0) { + pb.texture(loc, t, sampler); + } + }; + bind("albedo", tex.albedo); + bind("ao", tex.ao); + bind("metal", tex.metal); + bind("rough", tex.rough); + bind("normal", tex.normal); +} + void Model_Loader::init(Device* device, Asset_Arena* shader_arena) { dev = device; shaders = shader_arena; @@ -68,6 +98,7 @@ Asset* Model_Loader::load( Mesh& mesh = meshes[i]; int vertex_size, vertex_count; char shader_name[28]; + char material_name[28]; Shader* shader; pack_read(f, magic, 4); if ( @@ -80,13 +111,18 @@ Asset* Model_Loader::load( return 0; } pack_read(f, shader_name, sizeof shader_name); + pack_read(f, material_name, sizeof material_name); mesh.offset = icoff; shader = (Shader*)shaders->load(shader_name); + mesh.material = (Material*)shaders->load(material_name); assert(shader != 0); + assert(mesh.material != 0); mesh.shader = shader->id; mesh.mvp_binding = shader->descriptor_binding("c_mvp"); + mesh.mat_binding = shader->descriptor_binding("material"); mesh.mesh_binding = shader->binding_index("mesh"); assert(mesh.mvp_binding >= 0); + assert(mesh.mat_binding >= 0); assert(mesh.mesh_binding >= 0); pack_read(f, &vertex_size, 4); pack_read(f, &mesh.count, 4); @@ -120,6 +156,12 @@ Asset* Model_Loader::load( Buffer_Flags::constant_buffer | Buffer_Flags::cpu_readwrite ); + r->mat = dev->create_buffer( + filename, + sizeof(Mat_Cbuffer) * node_count, + Buffer_Flags::constant_buffer | + Buffer_Flags::cpu_readwrite + ); ctx = &dev->acquire(); ctx->copy(r->vbo, stage_verts); ctx->copy(r->ibo, stage_indices); @@ -134,6 +176,7 @@ void Model_Loader::unload(Asset* a) { dev->destroy_buffer(m->vbo); dev->destroy_buffer(m->ibo); dev->destroy_buffer(m->mvp); + dev->destroy_buffer(m->mat); } const m4f& Mesh::get_world(Model& m) { @@ -168,17 +211,32 @@ void Model::update_cbuffers( 0, c * sizeof *cbuffers ); + Mat_Cbuffer* mats = (Mat_Cbuffer*)dev->map_buffer( + mat, + 0, + c * sizeof *cbuffers + ); for (i = 0; i < c; i++) { + Mat_Cbuffer& mat = mats[i]; + Material& sm = *meshes[i].material; cbuffers[i].view_projection = view_projection; cbuffers[i].model = transform * meshes[i].world; + mat.albedo[0] = sm.albedo.x; + mat.albedo[1] = sm.albedo.y; + mat.albedo[2] = sm.albedo.z; + mat.metalness = sm.metalness; + mat.roughness = sm.roughness; + mat.ao = sm.ao; } dev->unmap_buffer(mvp); + dev->unmap_buffer(mat); } void Model::render( Device* dev, Arena* a, - Render_Pass& pass + Render_Pass& pass, + Sampler_Id sampler ) { int i, c = mesh_count; Mesh* meshes = get_meshes(); @@ -211,14 +269,78 @@ void Model::render( pb.depth(true, false, Depth_Mode::equal); pb.cull(Cull_Mode::back); pb.shader(mesh.shader); + mesh.material->use(pb, sampler, dev->get_shader(mesh.shader)); pb.cbuffer( mesh.mvp_binding, mvp, i * sizeof(MVP_Cbuffer), sizeof(MVP_Cbuffer) ); + pb.cbuffer( + mesh.mat_binding, + mat, + i * sizeof(Mat_Cbuffer), + sizeof(Mat_Cbuffer) + ); pb.vertex_format(shader.vf); Pipeline& pip = pb.build(); ctx.submit(draw, pip, pass); } } + +void Material_Loader::init( + Asset_Arena* texture_arena, + Texture_Id dt +) { + default_tex = dt; + textures = texture_arena; +} + +Asset* Material_Loader::load( + Arena* a, + Arena* s, + const char* filename, + Pack_File* f +) { + Material_File mf; + Material* m = (Material*)arena_alloc(a, sizeof *m); + auto read_name = [&](int len) { + char* r = (char*)arena_alloc(s, len + 1); + r[pack_read(f, r, len)] = 0; + return r; + }; + auto read_tex = [&](int len) { + if (!len) return default_tex; + const char* name = read_name(len); + auto t = (Texture*)textures->load(name); + if (!t) + return default_tex; + return t->id; + }; + (void)filename; + pack_read(f, &mf, sizeof mf); + if ( + mf.magic[0] != 'M' || + mf.magic[1] != 'T' || + mf.magic[2] != 'R' || + mf.magic[3] != 'L' + ) return 0; + m->metalness = mf.metalness; + m->roughness = mf.roughness; + m->ao = mf.ao; + m->albedo = v3f( + (float)((mf.albedo >> 16) & 0xff) / 255.0f, + (float)((mf.albedo >> 8) & 0xff) / 255.0f, + (float)((mf.albedo) & 0xff) / 255.0f + ); + m->tex.albedo = read_tex(mf.albedo_tex_len); + m->tex.ao = read_tex(mf.ao_tex_len); + m->tex.metal = read_tex(mf.metal_tex_len); + m->tex.rough = read_tex(mf.rough_tex_len); + m->tex.normal = read_tex(mf.normal_tex_len); + return m; +} + +void Material_Loader::unload(Asset* a) { + (void)a; +} @@ -5,13 +5,31 @@ #include "maths.hpp" #include "video.hpp" +struct Material : public Asset { + float metalness, roughness, ao; + v3f albedo; + struct { + Texture_Id albedo; + Texture_Id ao; + Texture_Id metal; + Texture_Id rough; + Texture_Id normal; + } tex; + void use( + Pipeline_Builder& pb, + Sampler_Id sampler, + Shader& shader + ); +}; + struct Model; struct Mesh { int offset, vbo_offset, count; - int parent, mesh_binding, mvp_binding; + int parent, mesh_binding, mvp_binding, mat_binding; bool world_dirty; m4f local, world; Shader_Id shader; + Material* material; const m4f& get_world(Model& m); }; @@ -19,6 +37,7 @@ struct Model : public Asset { Buffer_Id vbo; Buffer_Id ibo; Buffer_Id mvp; + Buffer_Id mat; int mesh_count; Mesh* get_meshes() { @@ -35,7 +54,8 @@ struct Model : public Asset { void render( Device* dev, Arena* a, - Render_Pass& pass + Render_Pass& pass, + Sampler_Id sampler ); }; @@ -49,7 +69,20 @@ struct Model_Loader : public Asset_Loader { const char* filename, Pack_File* f ) override; - void unload(Asset* a); + void unload(Asset* a) override; +}; + +struct Material_Loader : public Asset_Loader { + Asset_Arena* textures; + Texture_Id default_tex; + void init(Asset_Arena* texture_arena, Texture_Id dt); + Asset* load( + Arena* a, + Arena* s, + const char* filename, + Pack_File* f + ) override; + void unload(Asset* a) override; }; #endif @@ -22,7 +22,7 @@ const int glsl_version = 440; const char* builtin_src = ""; static const auto client_version = glslang::EShTargetVulkan_1_0; static const auto target_version = glslang::EShTargetSpv_1_0; -const int desc_parse_memory = 4096; +const int desc_parse_memory = 4096 * 1024; std::string get_desc(const char* src) { const char* srcs[] = { diff --git a/src/monkey.blend b/src/monkey.blend Binary files differBinary files differindex 3f26c50..cd6fbbc 100644 --- a/src/monkey.blend +++ b/src/monkey.blend @@ -2049,6 +2049,7 @@ Texture_Id Device::get_depth_target() { } Texture& Device::get_texture(Texture_Id id) { + assert(id.index); return ((Device_Vk*)this)->textures[id]; } |