summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2025-01-01 18:43:31 +1100
committerquou <quou@disroot.org>2025-01-01 18:43:31 +1100
commitd26100734623f37063206b9b144c2a29fd71d414 (patch)
tree11aefe54b4110109a841cb656b2f309ee69a1893
parent568ba73c71b650f905bd1b3f60f10871316eefdc (diff)
material system
-rw-r--r--.gitignore1
-rw-r--r--Makefile28
-rw-r--r--asset.cpp14
-rw-r--r--asset.hpp2
-rw-r--r--c2.cpp36
-rw-r--r--cfg/cfgparse.c54
-rw-r--r--cfg/cfgparse.h17
-rw-r--r--convmaterial.c83
-rw-r--r--convmodel.c34
-rw-r--r--intermediate/brick_albedo.bmpbin0 -> 16777354 bytes
-rw-r--r--intermediate/brick_ao.bmpbin0 -> 16777354 bytes
-rw-r--r--intermediate/brick_metal.bmpbin0 -> 16777354 bytes
-rw-r--r--intermediate/brick_normal.bmpbin0 -> 16777354 bytes
-rw-r--r--intermediate/bricks.mat11
-rw-r--r--intermediate/monkey.glbbin80692 -> 40636 bytes
-rw-r--r--intermediate/plastic.mat11
-rw-r--r--intermediate/surface.glsl83
-rw-r--r--material.h16
-rw-r--r--model.cpp124
-rw-r--r--model.hpp39
-rw-r--r--sc/sc.cpp2
-rw-r--r--src/monkey.blendbin539788 -> 544320 bytes
-rwxr-xr-xtestbc1bin0 -> 20720 bytes
-rw-r--r--video.cpp1
24 files changed, 520 insertions, 36 deletions
diff --git a/.gitignore b/.gitignore
index b763440..92de1bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@ tags
/packer
/convtexture
/convmodel
+/convmaterial
diff --git a/Makefile b/Makefile
index 8f7bbce..600bdda 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/asset.cpp b/asset.cpp
index 8a5a1cc..1d0da2c 100644
--- a/asset.cpp
+++ b/asset.cpp
@@ -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);
diff --git a/asset.hpp b/asset.hpp
index 63ea047..5218268 100644
--- a/asset.hpp
+++ b/asset.hpp
@@ -22,7 +22,7 @@ struct Asset_Loader {
struct Asset_Arena {
Pack* p;
- Arena* a, * s;
+ Arena* a;
struct Bucket {
char* name;
Asset* asset;
diff --git a/c2.cpp b/c2.cpp
index fd02e50..73bbbb6 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -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
new file mode 100644
index 0000000..54a8a71
--- /dev/null
+++ b/intermediate/brick_albedo.bmp
Binary files differ
diff --git a/intermediate/brick_ao.bmp b/intermediate/brick_ao.bmp
new file mode 100644
index 0000000..59ed011
--- /dev/null
+++ b/intermediate/brick_ao.bmp
Binary files differ
diff --git a/intermediate/brick_metal.bmp b/intermediate/brick_metal.bmp
new file mode 100644
index 0000000..bafe5f3
--- /dev/null
+++ b/intermediate/brick_metal.bmp
Binary files differ
diff --git a/intermediate/brick_normal.bmp b/intermediate/brick_normal.bmp
new file mode 100644
index 0000000..6add824
--- /dev/null
+++ b/intermediate/brick_normal.bmp
Binary files differ
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
index d199545..3e8fd29 100644
--- a/intermediate/monkey.glb
+++ b/intermediate/monkey.glb
Binary files differ
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
diff --git a/model.cpp b/model.cpp
index 2b6f1f4..d911ac7 100644
--- a/model.cpp
+++ b/model.cpp
@@ -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;
+}
diff --git a/model.hpp b/model.hpp
index 03cdef4..0dd8c43 100644
--- a/model.hpp
+++ b/model.hpp
@@ -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
diff --git a/sc/sc.cpp b/sc/sc.cpp
index 3c39b0c..dfe4325 100644
--- a/sc/sc.cpp
+++ b/sc/sc.cpp
@@ -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
index 3f26c50..cd6fbbc 100644
--- a/src/monkey.blend
+++ b/src/monkey.blend
Binary files differ
diff --git a/testbc1 b/testbc1
new file mode 100755
index 0000000..9329c89
--- /dev/null
+++ b/testbc1
Binary files differ
diff --git a/video.cpp b/video.cpp
index abcf47d..b8b3f51 100644
--- a/video.cpp
+++ b/video.cpp
@@ -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];
}