From 78266ace3fdb9701f4096889c8b31a8f6637e199 Mon Sep 17 00:00:00 2001 From: Andrei Alexeyev Date: Sat, 10 Jul 2021 05:09:08 +0300 Subject: [PATCH] pbr: refactor material management and shader Introduced a new PBRMaterial resource type. Materials are now fully described with .material files instead of being hardcoded. Added some functions to abstract away and simplify set up of PBR shaders. --- .../gfx/credits/tower.material | 5 + .../gfx/stage2/branch.material | 6 + .../gfx/stage2/grass.material | 6 + .../gfx/stage2/ground.material | 6 + .../gfx/stage2/leaves.material | 6 + .../gfx/stage2/rocks.material | 6 + .../gfx/stage3/ground.material | 5 + .../gfx/stage3/leaves.material | 5 + .../gfx/stage3/rocks.material | 5 + .../gfx/stage3/trees.material | 5 + .../gfx/stage4/corridor.material | 5 + .../gfx/stage4/ground.material | 5 + .../gfx/stage4/mansion.material | 5 + .../shader/interface/pbr.glslh | 31 +++-- .../00-taisei.pkgdir/shader/pbr.frag.glsl | 58 +++++++-- resources/meson.build | 1 + scripts/automaterials.py | 67 ++++++++++ src/resource/material.c | 119 +++++++++++++++++ src/resource/material.h | 33 +++++ src/resource/meson.build | 1 + src/resource/resource.c | 32 ++--- src/resource/resource.h | 1 + src/stages/stage2/draw.c | 78 +++++------ src/stages/stage2/draw.h | 9 ++ src/stages/stage2/stage2.c | 35 ++--- src/stages/stage3/draw.c | 72 +++++----- src/stages/stage3/draw.h | 13 ++ src/stages/stage3/stage3.c | 26 ++-- src/stages/stage4/draw.c | 123 ++++++++++-------- src/stages/stage4/draw.h | 7 + src/stages/stage4/stage4.c | 25 ++-- src/stages/stage5/draw.h | 6 + src/stages/stage6/draw.h | 14 +- src/stageutils.c | 67 ++++++++++ src/stageutils.h | 25 ++++ src/util/kvparser.c | 22 ++++ src/util/kvparser.h | 4 + 37 files changed, 707 insertions(+), 232 deletions(-) create mode 100644 resources/00-taisei.pkgdir/gfx/credits/tower.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage2/branch.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage2/grass.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage2/ground.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage2/leaves.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage2/rocks.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage3/ground.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage3/leaves.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage3/rocks.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage3/trees.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage4/corridor.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage4/ground.material create mode 100644 resources/00-taisei.pkgdir/gfx/stage4/mansion.material create mode 100755 scripts/automaterials.py create mode 100644 src/resource/material.c create mode 100644 src/resource/material.h diff --git a/resources/00-taisei.pkgdir/gfx/credits/tower.material b/resources/00-taisei.pkgdir/gfx/credits/tower.material new file mode 100644 index 00000000..480cc5f6 --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/credits/tower.material @@ -0,0 +1,5 @@ + +ambient_map = credits/tower_ambient +diffuse_map = credits/tower_diffuse +normal_map = credits/tower_normal +roughness_map = credits/tower_roughness diff --git a/resources/00-taisei.pkgdir/gfx/stage2/branch.material b/resources/00-taisei.pkgdir/gfx/stage2/branch.material new file mode 100644 index 00000000..c1ba4a6e --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage2/branch.material @@ -0,0 +1,6 @@ + +diffuse_map = stage2/branch_diffuse +normal_map = stage2/branch_normal +ambient_map = stage2/branch_ambient +roughness_map = stage2/branch_roughness + diff --git a/resources/00-taisei.pkgdir/gfx/stage2/grass.material b/resources/00-taisei.pkgdir/gfx/stage2/grass.material new file mode 100644 index 00000000..8f9cac93 --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage2/grass.material @@ -0,0 +1,6 @@ + +diffuse_map = stage2/grass_diffuse +normal_map = stage2/grass_normal +ambient_map = stage2/grass_ambient +roughness_map = stage2/grass_roughness + diff --git a/resources/00-taisei.pkgdir/gfx/stage2/ground.material b/resources/00-taisei.pkgdir/gfx/stage2/ground.material new file mode 100644 index 00000000..6a0bf5ed --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage2/ground.material @@ -0,0 +1,6 @@ + +diffuse_map = stage2/ground_diffuse +normal_map = stage2/ground_normal +ambient_map = stage2/ground_ambient +roughness_map = stage2/ground_roughness + diff --git a/resources/00-taisei.pkgdir/gfx/stage2/leaves.material b/resources/00-taisei.pkgdir/gfx/stage2/leaves.material new file mode 100644 index 00000000..988365fa --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage2/leaves.material @@ -0,0 +1,6 @@ + +diffuse_map = stage2/leaves_diffuse +normal_map = stage2/leaves_normal +ambient_map = stage2/leaves_ambient +roughness_map = stage2/leaves_roughness + diff --git a/resources/00-taisei.pkgdir/gfx/stage2/rocks.material b/resources/00-taisei.pkgdir/gfx/stage2/rocks.material new file mode 100644 index 00000000..d7fa1d91 --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage2/rocks.material @@ -0,0 +1,6 @@ + +diffuse_map = stage2/rocks_diffuse +normal_map = stage2/rocks_normal +ambient_map = stage2/rocks_ambient +roughness_map = stage2/rocks_roughness + diff --git a/resources/00-taisei.pkgdir/gfx/stage3/ground.material b/resources/00-taisei.pkgdir/gfx/stage3/ground.material new file mode 100644 index 00000000..66bf48c5 --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage3/ground.material @@ -0,0 +1,5 @@ + +ambient_map = stage3/ground_ambient +diffuse_map = stage3/ground_diffuse +normal_map = stage3/ground_normal +roughness_map = stage3/ground_roughness diff --git a/resources/00-taisei.pkgdir/gfx/stage3/leaves.material b/resources/00-taisei.pkgdir/gfx/stage3/leaves.material new file mode 100644 index 00000000..f1350a1e --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage3/leaves.material @@ -0,0 +1,5 @@ + +ambient_map = stage3/leaves_ambient +diffuse_map = stage3/leaves_diffuse +normal_map = stage3/leaves_normal +roughness_map = stage3/leaves_roughness diff --git a/resources/00-taisei.pkgdir/gfx/stage3/rocks.material b/resources/00-taisei.pkgdir/gfx/stage3/rocks.material new file mode 100644 index 00000000..cc94a098 --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage3/rocks.material @@ -0,0 +1,5 @@ + +ambient_map = stage3/rocks_ambient +diffuse_map = stage3/rocks_diffuse +normal_map = stage3/rocks_normal +roughness_map = stage3/rocks_roughness diff --git a/resources/00-taisei.pkgdir/gfx/stage3/trees.material b/resources/00-taisei.pkgdir/gfx/stage3/trees.material new file mode 100644 index 00000000..e1f0da07 --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage3/trees.material @@ -0,0 +1,5 @@ + +ambient_map = stage3/trees_ambient +diffuse_map = stage3/trees_diffuse +normal_map = stage3/trees_normal +roughness_map = stage3/trees_roughness diff --git a/resources/00-taisei.pkgdir/gfx/stage4/corridor.material b/resources/00-taisei.pkgdir/gfx/stage4/corridor.material new file mode 100644 index 00000000..b68c1ece --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage4/corridor.material @@ -0,0 +1,5 @@ + +ambient_map = stage4/corridor_ambient +diffuse_map = stage4/corridor_diffuse +normal_map = stage4/corridor_normal +roughness_map = stage4/corridor_roughness diff --git a/resources/00-taisei.pkgdir/gfx/stage4/ground.material b/resources/00-taisei.pkgdir/gfx/stage4/ground.material new file mode 100644 index 00000000..3ee9e5a2 --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage4/ground.material @@ -0,0 +1,5 @@ + +ambient_map = stage4/ground_ambient +diffuse_map = stage4/ground_diffuse +normal_map = stage4/ground_normal +roughness_map = stage4/ground_roughness diff --git a/resources/00-taisei.pkgdir/gfx/stage4/mansion.material b/resources/00-taisei.pkgdir/gfx/stage4/mansion.material new file mode 100644 index 00000000..600ef352 --- /dev/null +++ b/resources/00-taisei.pkgdir/gfx/stage4/mansion.material @@ -0,0 +1,5 @@ + +ambient_map = stage4/mansion_ambient +diffuse_map = stage4/mansion_diffuse +normal_map = stage4/mansion_normal +roughness_map = stage4/mansion_roughness diff --git a/resources/00-taisei.pkgdir/shader/interface/pbr.glslh b/resources/00-taisei.pkgdir/shader/interface/pbr.glslh index 5adfe9c1..c225488f 100644 --- a/resources/00-taisei.pkgdir/shader/interface/pbr.glslh +++ b/resources/00-taisei.pkgdir/shader/interface/pbr.glslh @@ -4,14 +4,29 @@ #include "standard.glslh" #include "../lib/pbr.glslh" -UNIFORM(1) sampler2D roughness_map; -UNIFORM(2) sampler2D normal_map; -UNIFORM(3) sampler2D ambient_map; -UNIFORM(4) float metallic; -UNIFORM(5) vec3 ambient_color; // modulates ambient map -UNIFORM(6) int light_count; -UNIFORM(7) vec3 light_positions[PBR_MAX_LIGHTS]; -UNIFORM(13) vec3 light_colors[PBR_MAX_LIGHTS]; // layout-id also depends on PBR_MAX_LIGHTS +#define PBR_FEATURE_DIFFUSE_MAP 1 +#define PBR_FEATURE_NORMAL_MAP 2 +#define PBR_FEATURE_AMBIENT_MAP 4 +#define PBR_FEATURE_ROUGHNESS_MAP 8 +#define PBR_FEATURE_ENVIRONMENT_MAP 16 + +UNIFORM(1) int features_mask; + +UNIFORM(2) sampler2D diffuse_map; +UNIFORM(3) sampler2D normal_map; +UNIFORM(4) sampler2D ambient_map; +UNIFORM(5) sampler2D roughness_map; +UNIFORM(6) samplerCube environment_map; + +// These either modulate their respective maps, or are used instead of them +UNIFORM(7) vec4 diffuseRGB_metallicA; +UNIFORM(8) vec4 ambientRGB_roughnessA; + +UNIFORM(11) mat4 inv_camera_transform; // only used if PBR_FEATURE_ENVIRONMENT_MAP is set + +UNIFORM(12) int light_count; +UNIFORM(13) vec3 light_positions[PBR_MAX_LIGHTS]; +UNIFORM(19) vec3 light_colors[PBR_MAX_LIGHTS]; // layout-id also depends on PBR_MAX_LIGHTS VARYING(3) vec3 pos; VARYING(4) vec3 tangent; diff --git a/resources/00-taisei.pkgdir/shader/pbr.frag.glsl b/resources/00-taisei.pkgdir/shader/pbr.frag.glsl index 33a49550..ed5ffa3a 100644 --- a/resources/00-taisei.pkgdir/shader/pbr.frag.glsl +++ b/resources/00-taisei.pkgdir/shader/pbr.frag.glsl @@ -4,23 +4,51 @@ #include "interface/pbr.glslh" void main(void) { - vec4 roughness_sample = texture(roughness_map, texCoord); - float alpha = roughness_sample.a; + float roughness = ambientRGB_roughnessA.a; + float alpha; - if(alpha < 0.3) { - discard; + if(bool(features_mask & PBR_FEATURE_ROUGHNESS_MAP)) { + vec4 roughness_sample = texture(roughness_map, texCoord); + roughness *= roughness_sample.r; + alpha = roughness_sample.a; + + // TODO: a way to opt out of this, since it hurts performance. + if(alpha < 0.3) { + discard; + } + } else { + alpha = 1.0; + } + + float metallic = diffuseRGB_metallicA.a; + vec3 diffuse = diffuseRGB_metallicA.rgb; + + if(bool(features_mask & PBR_FEATURE_DIFFUSE_MAP)) { + diffuse *= texture(diffuse_map, texCoord).rgb; + } + + vec3 ambient = ambientRGB_roughnessA.rgb; + + if(bool(features_mask & PBR_FEATURE_AMBIENT_MAP)) { + ambient *= texture(ambient_map, texCoord).rgb; + } + + vec3 tbn_normal; + + if(bool(features_mask & PBR_FEATURE_NORMAL_MAP)) { + tbn_normal = sample_normalmap(normal_map, texCoord); + } else { + tbn_normal = vec3(0, 0, 1); } - vec3 ambient = texture(ambient_map, texCoord).rgb; - vec3 tbn_normal = sample_normalmap(normal_map, texCoord); mat3 tbn = mat3(normalize(tangent), normalize(bitangent), normalize(normal)); PBRParams p; p.fragPos = pos; - p.albedo = r_color.rgb * texture(tex, texCoord).rgb; - p.roughness = roughness_sample.r; + p.albedo = diffuse; + p.roughness = roughness; p.metallic = metallic; - p.normal = normalize(tbn * tbn_normal); + p.normal = tbn * tbn_normal; PBRState pbr = PBR(p); @@ -29,9 +57,17 @@ void main(void) { Lo += PBR_PointLight(pbr, PointLight(light_positions[i], light_colors[i])); } - vec3 color = ambient * ambient_color + Lo; + vec3 color = ambient + Lo; + + if(bool(features_mask & PBR_FEATURE_ENVIRONMENT_MAP)) { + vec3 reflected_ray = mat3(inv_camera_transform) * reflect(pos, p.normal); + vec3 reflection = texture(environment_map, fixCubeCoord(reflected_ray)).rgb; + float r = (1 - p.roughness); + color += (r * r) * reflection * mix(vec3(0.5), p.albedo, p.metallic); + } + color = PBR_TonemapReinhard(color); color = PBR_GammaCorrect(color); - fragColor = vec4(color, 1) * alpha; + fragColor = vec4(color * alpha, alpha); } diff --git a/resources/meson.build b/resources/meson.build index bdc3579c..338ed168 100644 --- a/resources/meson.build +++ b/resources/meson.build @@ -26,6 +26,7 @@ if host_machine.system() == 'emscripten' 'gfx/*.ani', 'gfx/*.spr', 'gfx/*.tex', + 'gfx/*.material', 'fonts/*.font', 'models/*.iqm', diff --git a/scripts/automaterials.py b/scripts/automaterials.py new file mode 100755 index 00000000..c970f33a --- /dev/null +++ b/scripts/automaterials.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +import re +from pathlib import Path +from collections import defaultdict + +from taiseilib.common import ( + run_main, +) + + +mat_re = re.compile(r'(.*)_(diffuse|normal|ambient|roughness)\.(?:tex|basis|png|webp)$') + + +def main(args): + resdir = Path(__file__).parent.parent / 'resources' + + materials = defaultdict(set) + gfxdirs = [] + + for pkgdir in resdir.glob('*.pkgdir'): + gfx = pkgdir / 'gfx' + + if not gfx.is_dir(): + continue + + gfxdirs.append(gfx) + print(gfx) + + for p in gfx.glob('**/*'): + rel = p.relative_to(gfx) + m = mat_re.match(str(rel)) + + if m is None: + continue + + matname, mapname = m.groups() + materials[matname].add(mapname) + + gfxmain = gfxdirs[0] + + for mat, maps in materials.items(): + mat_filename = f'{mat}.material' + + skip = False + for gfx in gfxdirs: + if (gfx / mat_filename).exists(): + print(' - Skip', mat_filename) + skip = True + break + if skip: + continue + + outpath = (gfxmain / mat_filename).resolve() + + lines = [''] + + for mapname in sorted(maps): + lines.append(f'{mapname}_map = {mat}_{mapname}') + + lines.append('') + print(' * Write', outpath) + outpath.write_text('\n'.join(lines)) + + +if __name__ == '__main__': + run_main(main) diff --git a/src/resource/material.c b/src/resource/material.c new file mode 100644 index 00000000..94d5873c --- /dev/null +++ b/src/resource/material.c @@ -0,0 +1,119 @@ +/* + * This software is licensed under the terms of the MIT License. + * See COPYING for further information. + * --- + * Copyright (c) 2011-2019, Lukas Weber . + * Copyright (c) 2012-2019, Andrei Alexeyev . +*/ + +#include "taisei.h" + +#include "material.h" + +static char *material_path(const char *basename); +static bool material_check_path(const char *path); +static void material_load_stage1(ResourceLoadState *st); + +ResourceHandler material_res_handler = { + .type = RES_MATERIAL, + .typename = "material", + .subdir = MATERIAL_PATH_PREFIX, + + .procs = { + .find = material_path, + .check = material_check_path, + .load = material_load_stage1, + .unload = free, + }, +}; + +static char *material_path(const char *basename) { + return try_path(MATERIAL_PATH_PREFIX, basename, MATERIAL_EXTENSION); +} + +static bool material_check_path(const char *path) { + return strendswith(path, MATERIAL_EXTENSION); +} + +struct mat_load_data { + PBRMaterial *mat; + + union { + struct { + char *diffuse_map; + char *normal_map; + char *ambient_map; + char *roughness_map; + }; + + char *maps[4]; + }; +}; + +static void free_mat_load_data(struct mat_load_data *ld) { + for(int i = 0; i < ARRAY_SIZE(ld->maps); ++i) { + free(ld->maps[i]); + } + + free(ld); +} + +static void material_load_stage2(ResourceLoadState *st); + +static void material_load_stage1(ResourceLoadState *st) { + struct mat_load_data *ld = calloc(1, sizeof(*ld)); + ld->mat = calloc(1, sizeof(*ld->mat)); + *ld->mat = (PBRMaterial) { + .diffuse_color = { 1, 1, 1 }, + .ambient_color = { 1, 1, 1 }, + .roughness_value = 1, + .metallic_value = 0, + }; + + if(!parse_keyvalue_file_with_spec(st->path, (KVSpec[]) { + { "diffuse_map", .out_str = &ld->diffuse_map }, + { "normal_map", .out_str = &ld->normal_map }, + { "ambient_map", .out_str = &ld->ambient_map }, + { "roughness_map", .out_str = &ld->roughness_map }, + { "diffuse_color", .callback = kvparser_vec3, .callback_data = ld->mat->diffuse_color }, + { "ambient_color", .callback = kvparser_vec3, .callback_data = ld->mat->ambient_color }, + { "roughness", .out_float = &ld->mat->roughness_value }, + { "metallic", .out_float = &ld->mat->metallic_value }, + })) { + free_mat_load_data(ld); + log_error("Failed to parse material file '%s'", st->path); + res_load_failed(st); + return; + } + + for(int i = 0; i < ARRAY_SIZE(ld->maps); ++i) { + if(ld->maps[i]) { + res_load_dependency(st, RES_TEXTURE, ld->maps[i]); + } + } + + res_load_continue_after_dependencies(st, material_load_stage2, ld); +} + +#define LOADMAP(_map_) do { \ + if(ld->_map_##_map) { \ + ld->mat->_map_##_map = get_resource_data(RES_TEXTURE, ld->_map_##_map, st->flags); \ + if(UNLIKELY(ld->mat->_map_##_map == NULL)) { \ + log_fatal("%s: failed to load " #_map_ " map '%s'", st->name, ld->_map_##_map); \ + free_mat_load_data(ld); \ + res_load_failed(st); \ + } \ + } \ +} while(0) + +static void material_load_stage2(ResourceLoadState *st) { + struct mat_load_data *ld = st->opaque; + + LOADMAP(diffuse); + LOADMAP(normal); + LOADMAP(ambient); + LOADMAP(roughness); + + res_load_finished(st, ld->mat); + free_mat_load_data(ld); +} diff --git a/src/resource/material.h b/src/resource/material.h new file mode 100644 index 00000000..912bd238 --- /dev/null +++ b/src/resource/material.h @@ -0,0 +1,33 @@ +/* + * This software is licensed under the terms of the MIT License. + * See COPYING for further information. + * --- + * Copyright (c) 2011-2019, Lukas Weber . + * Copyright (c) 2012-2019, Andrei Alexeyev . +*/ + +#pragma once +#include "taisei.h" + +#include "resource.h" +#include "texture.h" + +typedef struct PBRMaterial { + Texture *diffuse_map; + Texture *normal_map; + Texture *ambient_map; + Texture *roughness_map; + + vec3 diffuse_color; + vec3 ambient_color; + float roughness_value; + float metallic_value; +} PBRMaterial; + +extern ResourceHandler material_res_handler; + +#define MATERIAL_PATH_PREFIX "res/gfx/" +#define MATERIAL_EXTENSION ".material" + +DEFINE_RESOURCE_GETTER(PBRMaterial, res_material, RES_MATERIAL) +DEFINE_OPTIONAL_RESOURCE_GETTER(PBRMaterial, res_material_optional, RES_MATERIAL) diff --git a/src/resource/meson.build b/src/resource/meson.build index 73081d1a..9d426ff3 100644 --- a/src/resource/meson.build +++ b/src/resource/meson.build @@ -3,6 +3,7 @@ resource_src = files( 'animation.c', 'bgm.c', 'font.c', + 'material.c', 'model.c', 'postprocess.c', 'resource.c', diff --git a/src/resource/resource.c b/src/resource/resource.c index fadc72e6..d022256d 100644 --- a/src/resource/resource.c +++ b/src/resource/resource.c @@ -15,30 +15,32 @@ #include "events.h" #include "taskmanager.h" -#include "texture.h" #include "animation.h" -#include "sfx.h" #include "bgm.h" -#include "shader_object.h" -#include "shader_program.h" +#include "font.h" +#include "material.h" #include "model.h" #include "postprocess.h" +#include "sfx.h" +#include "shader_object.h" +#include "shader_program.h" #include "sprite.h" -#include "font.h" +#include "texture.h" #include "renderer/common/backend.h" ResourceHandler *_handlers[] = { - [RES_TEXTURE] = &texture_res_handler, - [RES_ANIM] = &animation_res_handler, - [RES_SFX] = &sfx_res_handler, - [RES_BGM] = &bgm_res_handler, - [RES_MODEL] = &model_res_handler, - [RES_POSTPROCESS] = &postprocess_res_handler, - [RES_SPRITE] = &sprite_res_handler, - [RES_FONT] = &font_res_handler, - [RES_SHADER_OBJECT] = &shader_object_res_handler, - [RES_SHADER_PROGRAM] = &shader_program_res_handler, + [RES_ANIM] = &animation_res_handler, + [RES_BGM] = &bgm_res_handler, + [RES_FONT] = &font_res_handler, + [RES_MATERIAL] = &material_res_handler, + [RES_MODEL] = &model_res_handler, + [RES_POSTPROCESS] = &postprocess_res_handler, + [RES_SFX] = &sfx_res_handler, + [RES_SHADER_OBJECT] = &shader_object_res_handler, + [RES_SHADER_PROGRAM] = &shader_program_res_handler, + [RES_SPRITE] = &sprite_res_handler, + [RES_TEXTURE] = &texture_res_handler, }; typedef enum ResourceStatus { diff --git a/src/resource/resource.h b/src/resource/resource.h index 72291a58..66ea6561 100644 --- a/src/resource/resource.h +++ b/src/resource/resource.h @@ -22,6 +22,7 @@ typedef enum ResourceType { RES_POSTPROCESS, RES_SPRITE, RES_FONT, + RES_MATERIAL, RES_NUMTYPES, } ResourceType; diff --git a/src/stages/stage2/draw.c b/src/stages/stage2/draw.c index 28b7b890..b111250e 100644 --- a/src/stages/stage2/draw.c +++ b/src/stages/stage2/draw.c @@ -22,11 +22,9 @@ Stage2DrawData *stage2_get_draw_data(void) { } #define STAGE2_MAX_LIGHTS 4 -static void stage2_bg_setup_pbr_lighting(int max_lights) { + +static void stage2_bg_setup_pbr_lighting(Camera3D *cam, int max_lights) { // FIXME: Instead of calling this for each segment, maybe set up the lighting once for the whole scene? - - Camera3D *cam = &stage_3d_context.cam; - PointLight3D lights[STAGE2_MAX_LIGHTS] = { { { 100, cam->pos[1] - 100, 100 }, { 50000, 50000, 50000 } }, { { 0, 0, 0 }, { 1, 0, 30 } }, @@ -59,7 +57,11 @@ static void stage2_bg_setup_pbr_lighting(int max_lights) { } camera3d_set_point_light_uniforms(cam, imin(max_lights, ARRAY_SIZE(lights)), lights); - r_uniform_vec3("ambient_color", 0.5, 0.5, 0.5); +} + +static void stage2_bg_setup_pbr_env(Camera3D *cam, int max_lights, PBREnvironment *env) { + stage2_bg_setup_pbr_lighting(cam, max_lights); + glm_vec3_broadcast(0.5f, env->ambient_color); } static void stage2_branch_mv_transform(vec3 pos) { @@ -78,16 +80,13 @@ static void stage2_bg_branch_draw(vec3 pos) { stage2_branch_mv_transform(pos); r_shader("pbr"); - stage2_bg_setup_pbr_lighting(1); - r_uniform_float("metallic", 0); - r_uniform_sampler("tex", "stage2/branch_diffuse"); - r_uniform_sampler("roughness_map", "stage2/branch_roughness"); - r_uniform_sampler("normal_map", "stage2/branch_normal"); - r_uniform_sampler("ambient_map", "stage2/branch_ambient"); - r_draw_model("stage2/branch"); + PBREnvironment env = { 0 }; + stage2_bg_setup_pbr_env(&stage_3d_context.cam, 1, &env); + + pbr_draw_model(&stage2_draw_data->models.branch, &env); + r_mat_mv_pop(); - r_state_pop(); } @@ -100,16 +99,13 @@ static void stage2_bg_leaves_draw(vec3 pos) { stage2_branch_mv_transform(pos); r_shader("pbr"); - stage2_bg_setup_pbr_lighting(1); - r_uniform_float("metallic", 0); - r_uniform_sampler("tex", "stage2/leaves_diffuse"); - r_uniform_sampler("roughness_map", "stage2/leaves_roughness"); - r_uniform_sampler("normal_map", "stage2/leaves_normal"); - r_uniform_sampler("ambient_map", "stage2/leaves_ambient"); - r_draw_model("stage2/leaves"); + PBREnvironment env = { 0 }; + stage2_bg_setup_pbr_env(&stage_3d_context.cam, 1, &env); + + pbr_draw_model(&stage2_draw_data->models.leaves, &env); + r_mat_mv_pop(); - r_state_pop(); } @@ -126,9 +122,10 @@ static void stage2_bg_grass_draw(vec3 pos) { r_mat_mv_scale(2, 2, 2); ShaderProgram *sprite_shader = res_shader("sprite_pbr"); - r_shader_ptr(sprite_shader); - stage2_bg_setup_pbr_lighting(STAGE2_MAX_LIGHTS); + + PBREnvironment env = { 0 }; + stage2_bg_setup_pbr_env(&stage_3d_context.cam, STAGE2_MAX_LIGHTS, &env); r_disable(RCAP_CULL_FACE); // r_disable(RCAP_DEPTH_WRITE); @@ -169,20 +166,11 @@ static void stage2_bg_ground_draw(vec3 pos) { r_mat_mv_translate(pos[0], pos[1], pos[2]); r_shader("pbr"); - stage2_bg_setup_pbr_lighting(STAGE2_MAX_LIGHTS); + PBREnvironment env = { 0 }; + stage2_bg_setup_pbr_env(&stage_3d_context.cam, STAGE2_MAX_LIGHTS, &env); - r_uniform_float("metallic", 0); - r_uniform_sampler("tex", "stage2/rocks_diffuse"); - r_uniform_sampler("roughness_map", "stage2/rocks_roughness"); - r_uniform_sampler("normal_map", "stage2/rocks_normal"); - r_uniform_sampler("ambient_map", "stage2/rocks_ambient"); - r_draw_model("stage2/rocks"); - - r_uniform_sampler("tex", "stage2/ground_diffuse"); - r_uniform_sampler("roughness_map", "stage2/ground_roughness"); - r_uniform_sampler("normal_map", "stage2/ground_normal"); - r_uniform_sampler("ambient_map", "stage2/ground_ambient"); - r_draw_model("stage2/ground"); + pbr_draw_model(&stage2_draw_data->models.rocks, &env); + pbr_draw_model(&stage2_draw_data->models.ground, &env); r_mat_mv_pop(); r_state_pop(); @@ -195,15 +183,11 @@ static void stage2_bg_ground_grass_draw(vec3 pos) { r_mat_mv_translate(pos[0], pos[1], pos[2]); r_shader("pbr"); - stage2_bg_setup_pbr_lighting(STAGE2_MAX_LIGHTS); + PBREnvironment env = { 0 }; + stage2_bg_setup_pbr_env(&stage_3d_context.cam, STAGE2_MAX_LIGHTS, &env); + glm_vec3_broadcast(0.4f, env.ambient_color); - r_uniform_float("metallic", 0); - r_uniform_sampler("tex", "stage2/grass_diffuse"); - r_uniform_sampler("roughness_map", "stage2/grass_roughness"); - r_uniform_sampler("normal_map", "stage2/grass_normal"); - r_uniform_sampler("ambient_map", "stage2/grass_ambient"); - r_uniform_vec3("ambient_color", 0.4, 0.4, 0.4); - r_draw_model("stage2/grass"); + pbr_draw_model(&stage2_draw_data->models.grass, &env); r_mat_mv_pop(); r_state_pop(); @@ -296,6 +280,12 @@ void stage2_drawsys_init(void) { stage_3d_context.cam.near = 1; stage_3d_context.cam.far = 60; stage2_draw_data = calloc(1, sizeof(*stage2_draw_data)); + + pbr_load_model(&stage2_draw_data->models.branch, "stage2/branch", "stage2/branch"); + pbr_load_model(&stage2_draw_data->models.grass, "stage2/grass", "stage2/grass"); + pbr_load_model(&stage2_draw_data->models.ground, "stage2/ground", "stage2/ground"); + pbr_load_model(&stage2_draw_data->models.leaves, "stage2/leaves", "stage2/leaves"); + pbr_load_model(&stage2_draw_data->models.rocks, "stage2/rocks", "stage2/rocks"); } void stage2_drawsys_shutdown(void) { diff --git a/src/stages/stage2/draw.h b/src/stages/stage2/draw.h index 8493a387..8939f064 100644 --- a/src/stages/stage2/draw.h +++ b/src/stages/stage2/draw.h @@ -10,12 +10,21 @@ #include "taisei.h" #include "stagedraw.h" +#include "stageutils.h" typedef struct Stage2DrawData { struct { Color color; } fog; + struct { + PBRModel branch; + PBRModel grass; + PBRModel ground; + PBRModel leaves; + PBRModel rocks; + } models; + real hina_lights; } Stage2DrawData; diff --git a/src/stages/stage2/stage2.c b/src/stages/stage2/stage2.c index 6f3590a8..3e802bcf 100644 --- a/src/stages/stage2/stage2.c +++ b/src/stages/stage2/stage2.c @@ -78,36 +78,23 @@ static void stage2_preload(void) { "part/blast_huge_rays", NULL); preload_resources(RES_TEXTURE, RESF_DEFAULT, - "stage2/ground_diffuse", - "stage2/ground_roughness", - "stage2/ground_normal", - "stage2/ground_ambient", - "stage2/branch_diffuse", - "stage2/branch_roughness", - "stage2/branch_normal", - "stage2/branch_ambient", - "stage2/leaves_diffuse", - "stage2/leaves_roughness", - "stage2/leaves_normal", - "stage2/leaves_ambient", - "stage2/rocks_diffuse", - "stage2/rocks_roughness", - "stage2/rocks_normal", - "stage2/rocks_ambient", - "stage2/grass_diffuse", - "stage2/grass_roughness", - "stage2/grass_normal", - "stage2/grass_ambient", "stage2/water_floor", "stage2/spellbg1", "stage2/spellbg2", NULL); - preload_resources(RES_MODEL, RESF_DEFAULT, - "stage2/ground", - "stage2/rocks", + preload_resources(RES_MATERIAL, RESF_DEFAULT, "stage2/branch", - "stage2/leaves", "stage2/grass", + "stage2/ground", + "stage2/leaves", + "stage2/rocks", + NULL); + preload_resources(RES_MODEL, RESF_DEFAULT, + "stage2/branch", + "stage2/grass", + "stage2/ground", + "stage2/leaves", + "stage2/rocks", NULL); preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT, "stage1_water", diff --git a/src/stages/stage3/draw.c b/src/stages/stage3/draw.c index ede30fee..60952c2d 100644 --- a/src/stages/stage3/draw.c +++ b/src/stages/stage3/draw.c @@ -17,6 +17,12 @@ MODERNIZE_THIS_FILE_AND_REMOVE_ME +static Stage3DrawData *stage3_draw_data; + +Stage3DrawData *stage3_get_draw_data(void) { + return NOT_NULL(stage3_draw_data); +} + static uint stage3_bg_pos(Stage3D *s3d, vec3 pos, float maxrange) { vec3 p = { 0, @@ -29,8 +35,7 @@ static uint stage3_bg_pos(Stage3D *s3d, vec3 pos, float maxrange) { return linear3dpos(s3d, pos, maxrange, p, r); } -static void stage3_bg_setup_pbr_lighting(void) { - Camera3D *cam = &stage_3d_context.cam; +static void stage3_bg_setup_pbr_lighting(Camera3D *cam) { PointLight3D lights[] = { // TODO animate colors { { 0, 0, 10000 }, { 10, 42, 30 } }, @@ -60,44 +65,29 @@ static void stage3_bg_setup_pbr_lighting(void) { } camera3d_set_point_light_uniforms(cam, ARRAY_SIZE(lights), lights); +} - real f = 1/(1+global.frames/1000.); - r_uniform_vec3("ambient_color",f,f,sqrt(f)); +static void stage3_bg_setup_pbr_env(Camera3D *cam, PBREnvironment *env) { + stage3_bg_setup_pbr_lighting(cam); + + float f = 1.0f / (1.0f + global.frames / 1000.0f); + glm_vec3_copy((vec3) { f, f, sqrtf(f) }, env->ambient_color); } static void stage3_bg_ground_draw(vec3 pos) { r_state_push(); r_mat_mv_push(); - r_mat_mv_translate(pos[0], pos[1], pos[2]); - + r_mat_mv_translate_v(pos); r_shader("pbr"); - //r_uniform_vec3_array("light_positions[0]", 0, 1, &stage_3d_context.cx); - stage3_bg_setup_pbr_lighting(); + PBREnvironment env = { 0 }; + stage3_bg_setup_pbr_env(&stage_3d_context.cam, &env); - r_uniform_float("metallic", 0); - r_uniform_sampler("tex", "stage3/ground_diffuse"); - r_uniform_sampler("roughness_map", "stage3/ground_roughness"); - r_uniform_sampler("normal_map", "stage3/ground_normal"); - r_uniform_sampler("ambient_map", "stage3/ground_ambient"); + pbr_draw_model(&stage3_draw_data->models.ground, &env); + pbr_draw_model(&stage3_draw_data->models.trees, &env); + pbr_draw_model(&stage3_draw_data->models.rocks, &env); - - r_draw_model("stage3/ground"); - - r_uniform_sampler("tex", "stage3/trees_diffuse"); - r_uniform_sampler("roughness_map", "stage3/trees_roughness"); - r_uniform_sampler("normal_map", "stage3/trees_normal"); - r_uniform_sampler("ambient_map", "stage3/trees_ambient"); - - r_draw_model("stage3/trees"); - - r_uniform_sampler("tex", "stage3/rocks_diffuse"); - r_uniform_sampler("roughness_map", "stage3/rocks_roughness"); - r_uniform_sampler("normal_map", "stage3/rocks_normal"); - r_uniform_sampler("ambient_map", "stage3/rocks_ambient"); - - r_draw_model("stage3/rocks"); r_mat_mv_pop(); r_state_pop(); } @@ -105,22 +95,15 @@ static void stage3_bg_ground_draw(vec3 pos) { static void stage3_bg_leaves_draw(vec3 pos) { r_state_push(); r_mat_mv_push(); - r_mat_mv_translate(pos[0], pos[1], pos[2]); - r_mat_mv_translate(0,0,-0.0002); - + r_mat_mv_translate_v(pos); + r_mat_mv_translate(0, 0, -0.0002); r_shader("pbr"); - stage3_bg_setup_pbr_lighting(); + PBREnvironment env = { 0 }; + stage3_bg_setup_pbr_env(&stage_3d_context.cam, &env); - r_uniform_float("metallic", 0); - r_uniform_sampler("tex", "stage3/leaves_diffuse"); - r_uniform_sampler("roughness_map", "stage3/leaves_roughness"); - r_uniform_sampler("normal_map", "stage3/leaves_normal"); - r_uniform_sampler("ambient_map", "stage3/leaves_ambient"); - - - r_draw_model("stage3/leaves"); + pbr_draw_model(&stage3_draw_data->models.leaves, &env); r_mat_mv_pop(); r_state_pop(); @@ -132,10 +115,17 @@ void stage3_drawsys_init(void) { stage_3d_context.cam.rot.v[0] = 80; stage_3d_context.cam.vel[1] = 0.1; stage_3d_context.cam.vel[2] = 0.05; + + stage3_draw_data = calloc(1, sizeof(*stage3_draw_data)); + + pbr_load_model(&stage3_draw_data->models.ground, "stage3/ground", "stage3/ground"); pbr_load_model(&stage3_draw_data->models.leaves, "stage3/leaves", "stage3/leaves"); + pbr_load_model(&stage3_draw_data->models.rocks, "stage3/rocks", "stage3/rocks"); + pbr_load_model(&stage3_draw_data->models.trees, "stage3/trees", "stage3/trees"); } void stage3_drawsys_shutdown(void) { stage3d_shutdown(&stage_3d_context); + free(stage3_draw_data); } static bool stage3_fog(Framebuffer *fb) { diff --git a/src/stages/stage3/draw.h b/src/stages/stage3/draw.h index 43467306..b7a59b28 100644 --- a/src/stages/stage3/draw.h +++ b/src/stages/stage3/draw.h @@ -11,6 +11,19 @@ #include "util/fbpair.h" #include "stagedraw.h" +#include "stageutils.h" + +typedef struct Stage3DrawData { + struct { + PBRModel ground; + PBRModel leaves; + PBRModel rocks; + PBRModel trees; + } models; +} Stage3DrawData; + +Stage3DrawData *stage3_get_draw_data(void) + attr_returns_nonnull attr_returns_max_aligned; void stage3_drawsys_init(void); void stage3_drawsys_shutdown(void); diff --git a/src/stages/stage3/stage3.c b/src/stages/stage3/stage3.c index 340d82a0..7474e807 100644 --- a/src/stages/stage3/stage3.c +++ b/src/stages/stage3/stage3.c @@ -86,34 +86,24 @@ static void stage3_preload(void) { portrait_preload_base_sprite("scuttle", NULL, RESF_DEFAULT); portrait_preload_face_sprite("scuttle", "normal", RESF_DEFAULT); preload_resources(RES_BGM, RESF_OPTIONAL, "stage3", "stage3boss", NULL); - preload_resources(RES_SPRITE, RESF_DEFAULT, - "stage3/ground_ambient", - "stage3/ground_normal", - "stage3/ground_roughness", - "stage3/ground_diffuse", - "stage3/trees_ambient", - "stage3/trees_normal", - "stage3/trees_roughness", - "stage3/trees_diffuse", - "stage3/rocks_ambient", - "stage3/rocks_normal", - "stage3/rocks_roughness", - "stage3/rocks_diffuse", - "stage3/leaves_ambient", - "stage3/leaves_normal", - "stage3/leaves_roughness", - "stage3/leaves_diffuse", + preload_resources(RES_TEXTURE, RESF_DEFAULT, "stage3/spellbg1", "stage3/spellbg2", "stage3/wspellbg", "stage3/wspellclouds", "stage3/wspellswarm", NULL); - preload_resources(RES_MODEL, RESF_DEFAULT, + preload_resources(RES_MATERIAL, RESF_DEFAULT, "stage3/ground", + "stage3/leaves", "stage3/rocks", "stage3/trees", + NULL); + preload_resources(RES_MODEL, RESF_DEFAULT, + "stage3/ground", "stage3/leaves", + "stage3/rocks", + "stage3/trees", NULL); preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT, "zbuf_fog", diff --git a/src/stages/stage4/draw.c b/src/stages/stage4/draw.c index 9407f7f6..4eb63e74 100644 --- a/src/stages/stage4/draw.c +++ b/src/stages/stage4/draw.c @@ -80,47 +80,81 @@ static bool stage4_water_composite(Framebuffer *reflections) { return true; } -static uint stage4_lake_pos(Stage3D *s3d, vec3 pos, float maxrange) { - vec3 p = {0, 0, 0}; - return single3dpos(s3d, pos, maxrange, p); -} - -static void stage4_lake_draw(vec3 pos) { +static void stage4_bg_setup_pbr_lighting_outdoors(Camera3D *cam) { PointLight3D lights[] = { { { 0, 0, 0 }, { 3, 4, 5 } }, { { 0, 25, 3 }, { 4, 20, 22 } }, }; vec3 r; - Camera3D *cam = &stage_3d_context.cam; camera3d_unprojected_ray(cam, global.plr.pos, r); glm_vec3_scale(r, 4, r); glm_vec3_add(cam->pos, r, lights[0].pos); - r_mat_mv_push(); - r_mat_mv_translate(pos[0], pos[1], pos[2]); - r_shader("pbr"); + camera3d_set_point_light_uniforms(cam, ARRAY_SIZE(lights), lights); +} + +static void stage4_bg_setup_pbr_env_outdoors(Camera3D *cam, PBREnvironment *env) { + stage4_bg_setup_pbr_lighting_outdoors(cam); + glm_vec3_broadcast(1.0f, env->ambient_color); +} + +static void stage4_bg_setup_pbr_lighting_indoors(Camera3D *cam, vec3 pos) { + float xoff = 3.0f; + float zoff = 1.3f; + + PointLight3D lights[] = { + { { -xoff, pos[1], pos[2]+zoff }, { 1, 20, 20 } }, + { { xoff, pos[1], pos[2]+zoff }, { 1, 20, 20 } }, + { { -xoff, pos[1]-10, pos[2]+zoff }, { 1, 20, 20 } }, + { { xoff, pos[1]-10, pos[2]+zoff }, { 1, 20, 20 } }, + { { -xoff, pos[1]+10, pos[2]+zoff }, { 1, 20, 20 } }, + { { xoff, pos[1]+10, pos[2]+zoff }, { 1, 20, 20 } }, + }; + + for(int i = 0; i < ARRAY_SIZE(lights); i++) { + float t = global.frames * 0.02f; + float mod1 = cosf(13095434.0f * lights[i].pos[1]); + float mod2 = sinf(1242435.0f * lights[i].pos[0] * lights[i].pos[1]); + + float f = ( + sinf((1.0f + mod1) * t) + + sinf((2.35f + mod2) * t + mod1) + + sinf((3.1257f + mod1 * mod2) * t + mod2) + ) / 3.0f; + + glm_vec3_scale(lights[i].radiance, 0.6f + 0.4f * f, lights[i].radiance); + } camera3d_set_point_light_uniforms(cam, ARRAY_SIZE(lights), lights); +} - r_uniform_float("metallic", 0); - r_uniform_sampler("tex", "stage4/ground_diffuse"); - r_uniform_sampler("roughness_map", "stage4/ground_roughness"); - r_uniform_sampler("normal_map", "stage4/ground_normal"); - r_uniform_sampler("ambient_map", "stage4/ground_ambient"); - r_uniform_vec3("ambient_color", 1, 1, 1); +static void stage4_bg_setup_pbr_env_indoors(Camera3D *cam, vec3 pos, PBREnvironment *env) { + stage4_bg_setup_pbr_lighting_indoors(cam, pos); + glm_vec3_copy(&stage4_draw_data->ambient_color.r, env->ambient_color); + log_debug("%0.2f %0.2f %0.2f", env->ambient_color[0], env->ambient_color[1], env->ambient_color[2]); +} - r_draw_model("stage4/ground"); +static uint stage4_lake_pos(Stage3D *s3d, vec3 pos, float maxrange) { + vec3 p = {0, 0, 0}; + return single3dpos(s3d, pos, maxrange, p); +} - r_uniform_float("metallic", 0); - r_uniform_sampler("tex", "stage4/mansion_diffuse"); - r_uniform_sampler("roughness_map", "stage4/mansion_roughness"); - r_uniform_sampler("normal_map", "stage4/mansion_normal"); - r_uniform_sampler("ambient_map", "stage4/mansion_ambient"); +static void stage4_lake_draw(vec3 pos) { + r_state_push(); + r_mat_mv_push(); + r_mat_mv_translate_v(pos); + + r_shader("pbr"); + + PBREnvironment env = { 0 }; + stage4_bg_setup_pbr_env_outdoors(&stage_3d_context.cam, &env); + + pbr_draw_model(&stage4_draw_data->models.ground, &env); + pbr_draw_model(&stage4_draw_data->models.mansion, &env); - r_draw_model("stage4/mansion"); r_mat_mv_pop(); - r_shader_standard(); + r_state_pop(); } static uint stage4_corridor_pos(Stage3D *s3d, vec3 pos, float maxrange) { @@ -139,42 +173,19 @@ static uint stage4_corridor_pos(Stage3D *s3d, vec3 pos, float maxrange) { } static void stage4_corridor_draw(vec3 pos) { - real xoff = 3; - real zoff = 1.3; - PointLight3D lights[] = { - { { -xoff, pos[1], pos[2]+zoff }, { 1, 20, 20 } }, - { { xoff, pos[1], pos[2]+zoff }, { 1, 20, 20 } }, - { { -xoff, pos[1]-10, pos[2]+zoff }, { 1, 20, 20 } }, - { { xoff, pos[1]-10, pos[2]+zoff }, { 1, 20, 20 } }, - { { -xoff, pos[1]+10, pos[2]+zoff }, { 1, 20, 20 } }, - { { xoff, pos[1]+10, pos[2]+zoff }, { 1, 20, 20 } }, - }; - - for(int i = 0; i < ARRAY_SIZE(lights); i++) { - real t = global.frames*0.02; - real mod1 = cos(13095434*lights[i].pos[1]); - real mod2 = sin(1242435*lights[i].pos[0]*lights[i].pos[1]); - - double f = (sin((1+mod1)*t) + sin((2.35+mod2)*t+mod1) + sin((3.1257+mod1*mod2)*t+mod2))/3; - glm_vec3_scale(lights[i].radiance,0.6+0.4*f, lights[i].radiance); - } - + r_state_push(); r_mat_mv_push(); - r_mat_mv_translate(pos[0], pos[1], pos[2]); - //r_mat_mv_rotate(pos[1]/2000, 0, 1, 0); + r_mat_mv_translate_v(pos); + r_shader("pbr"); - camera3d_set_point_light_uniforms(&stage_3d_context.cam, ARRAY_SIZE(lights), lights); + PBREnvironment env = { 0 }; + stage4_bg_setup_pbr_env_indoors(&stage_3d_context.cam, pos, &env); - r_uniform_float("metallic", 0); - r_uniform_sampler("tex", "stage4/corridor_diffuse"); - r_uniform_sampler("roughness_map", "stage4/corridor_roughness"); - r_uniform_sampler("normal_map", "stage4/corridor_normal"); - r_uniform_sampler("ambient_map", "stage4/corridor_ambient"); - r_uniform_vec3_rgb("ambient_color", &stage4_draw_data->ambient_color); + pbr_draw_model(&stage4_draw_data->models.corridor, &env); - r_draw_model("stage4/corridor"); r_mat_mv_pop(); + r_state_pop(); } void stage4_draw(void) { @@ -189,6 +200,10 @@ void stage4_draw(void) { void stage4_drawsys_init(void) { stage4_draw_data = calloc(1, sizeof(*stage4_draw_data)); stage3d_init(&stage_3d_context, 16); + + pbr_load_model(&stage4_draw_data->models.corridor, "stage4/corridor", "stage4/corridor"); + pbr_load_model(&stage4_draw_data->models.ground, "stage4/ground", "stage4/ground"); + pbr_load_model(&stage4_draw_data->models.mansion, "stage4/mansion", "stage4/mansion"); } void stage4_drawsys_shutdown(void) { diff --git a/src/stages/stage4/draw.h b/src/stages/stage4/draw.h index 604185db..e1fe15e1 100644 --- a/src/stages/stage4/draw.h +++ b/src/stages/stage4/draw.h @@ -11,10 +11,17 @@ #include "stagedraw.h" #include "color.h" +#include "stageutils.h" typedef struct Stage4DrawData { Color ambient_color; vec3 midboss_light_pos; + + struct { + PBRModel corridor; + PBRModel ground; + PBRModel mansion; + } models; } Stage4DrawData; void stage4_drawsys_init(void); diff --git a/src/stages/stage4/stage4.c b/src/stages/stage4/stage4.c index 25316a06..1ba6a9c0 100644 --- a/src/stages/stage4/stage4.c +++ b/src/stages/stage4/stage4.c @@ -86,21 +86,9 @@ static void stage4_preload(void) { portrait_preload_base_sprite("kurumi", NULL, RESF_DEFAULT); portrait_preload_face_sprite("kurumi", "normal", RESF_DEFAULT); preload_resources(RES_BGM, RESF_OPTIONAL, "stage4", "stage4boss", NULL); - preload_resources(RES_SPRITE, RESF_DEFAULT, + preload_resources(RES_TEXTURE, RESF_DEFAULT, "stage4/kurumibg1", "stage4/kurumibg2", - "stage4/ground_ambient", - "stage4/ground_diffuse", - "stage4/ground_roughness", - "stage4/ground_normal", - "stage4/mansion_ambient", - "stage4/mansion_diffuse", - "stage4/mansion_roughness", - "stage4/mansion_normal", - "stage4/corridor_ambient", - "stage4/corridor_diffuse", - "stage4/corridor_roughness", - "stage4/corridor_normal", NULL); preload_resources(RES_SPRITE, RESF_DEFAULT, "stage6/scythe", // Stage 6 is intentional @@ -115,10 +103,15 @@ static void stage4_preload(void) { preload_resources(RES_ANIM, RESF_DEFAULT, "boss/kurumi", NULL); - preload_resources(RES_MODEL, RESF_DEFAULT, - "stage4/mansion", - "stage4/ground", + preload_resources(RES_MATERIAL, RESF_DEFAULT, "stage4/corridor", + "stage4/ground", + "stage4/mansion", + NULL); + preload_resources(RES_MODEL, RESF_DEFAULT, + "stage4/corridor", + "stage4/ground", + "stage4/mansion", NULL); preload_resources(RES_TEXTURE, RESF_OPTIONAL, "part/sinewave", diff --git a/src/stages/stage5/draw.h b/src/stages/stage5/draw.h index 6216eab4..4987bf6b 100644 --- a/src/stages/stage5/draw.h +++ b/src/stages/stage5/draw.h @@ -10,6 +10,7 @@ #include "taisei.h" #include "stagedraw.h" +#include "stageutils.h" typedef struct Stage5DrawData { @@ -33,6 +34,11 @@ typedef struct Stage5DrawData { float rad; } stairs; + struct { + PBRModel metal; + PBRModel stairs; + PBRModel wall; + } models; } Stage5DrawData; void stage5_drawsys_init(void); diff --git a/src/stages/stage6/draw.h b/src/stages/stage6/draw.h index f6f4e4ff..e8186111 100644 --- a/src/stages/stage6/draw.h +++ b/src/stages/stage6/draw.h @@ -18,7 +18,6 @@ enum { }; typedef struct Stage6DrawData { - struct { float position[3*NUM_STARS]; } stars; @@ -32,6 +31,19 @@ typedef struct Stage6DrawData { FBPair fbpair; } baryon; + struct { + PBRModel rim; + PBRModel spires; + PBRModel stairs; + PBRModel tower; + PBRModel tower_bottom; + + // these don't use pbr materials + Model *calabi_yau_quintic; + Model *top_plate; + } models; + + Texture *envmap; } Stage6DrawData; Stage6DrawData* stage6_get_draw_data(void); diff --git a/src/stageutils.c b/src/stageutils.c index 1b114f5c..3f3e06bb 100644 --- a/src/stageutils.c +++ b/src/stageutils.c @@ -12,6 +12,8 @@ #include "global.h" #include "util/glm.h" #include "video.h" +#include "resource/model.h" +#include "resource/material.h" Stage3D stage_3d_context; @@ -52,6 +54,19 @@ void stage3d_apply_transforms(Stage3D *s, mat4 mat) { camera3d_apply_transforms(&s->cam, mat); } +void camera3d_apply_inverse_transforms(Camera3D *cam, mat4 mat) { + // TODO optimize this + mat4 temp; + glm_mat4_identity(temp); + camera3d_apply_transforms(cam, temp); + glm_mat4_inv_fast(temp, mat); +} + +void stage3d_apply_inverse_transforms(Stage3D *s, mat4 mat) { + camera3d_apply_inverse_transforms(&s->cam, mat); +} + + // The author that brought you linear3dpos and that one function // that calculates the closest point to a line segment proudly presents: // @@ -121,6 +136,58 @@ void camera3d_set_point_light_uniforms( r_uniform_int("light_count", num_lights); } +void pbr_set_material_uniforms(const PBRMaterial *m, const PBREnvironment *env) { + int flags = 0; + + if(m->diffuse_map) { + r_uniform_sampler("diffuse_map", m->diffuse_map); + flags |= PBR_FEATURE_DIFFUSE_MAP; + } + + if(m->normal_map) { + r_uniform_sampler("normal_map", m->normal_map); + flags |= PBR_FEATURE_NORMAL_MAP; + } + + if(m->roughness_map) { + r_uniform_sampler("roughness_map", m->roughness_map); + flags |= PBR_FEATURE_ROUGHNESS_MAP; + } + + if(m->ambient_map) { + r_uniform_sampler("ambient_map", m->ambient_map); + flags |= PBR_FEATURE_AMBIENT_MAP; + } + + if(env->environment_map) { + r_uniform_sampler("environment_map", env->environment_map); + r_uniform_mat4("inv_camera_transform", (vec4*)env->cam_inverse_transform); + flags |= PBR_FEATURE_ENVIRONMENT_MAP; + } + + vec4 diffuseRGB_metallicA; + glm_vec3_copy((float*)m->diffuse_color, diffuseRGB_metallicA); + diffuseRGB_metallicA[3] = m->metallic_value; + r_uniform_vec4_vec("diffuseRGB_metallicA", diffuseRGB_metallicA); + + vec4 ambientRGB_roughnessA; + glm_vec3_mul((float*)env->ambient_color, (float*)m->ambient_color, ambientRGB_roughnessA); + ambientRGB_roughnessA[3] = m->roughness_value; + r_uniform_vec4_vec("ambientRGB_roughnessA", ambientRGB_roughnessA); + + r_uniform_int("features_mask", flags); +} + +void pbr_draw_model(const PBRModel *pmdl, const PBREnvironment *env) { + pbr_set_material_uniforms(NOT_NULL(pmdl->mat), env); + r_draw_model_ptr(NOT_NULL(pmdl->mdl), 0, 0); +} + +void pbr_load_model(PBRModel *pmdl, const char *model_name, const char *mat_name) { + pmdl->mdl = res_model(model_name); + pmdl->mat = res_material(mat_name); +} + void stage3d_draw_segment(Stage3D *s, SegmentPositionRule pos_rule, SegmentDrawRule draw_rule, float maxrange) { uint num = pos_rule(s, s->cam.pos, maxrange); diff --git a/src/stageutils.h b/src/stageutils.h index 596faf53..becaeed0 100644 --- a/src/stageutils.h +++ b/src/stageutils.h @@ -10,6 +10,7 @@ #include "taisei.h" #include "util.h" +#include "resource/material.h" #include "global.h" // remove when STAGE3D_DEFAULT_ASPECT aspect is removed typedef struct Stage3D Stage3D; @@ -47,6 +48,24 @@ typedef struct PointLight3D { // NOTE: should match PBR_MAX_LIGHTS in lib/pbr.glslh #define STAGE3D_MAX_LIGHTS 6 +// NOTE: should match definitions in interface/pbr.glslh +#define PBR_FEATURE_DIFFUSE_MAP 1 +#define PBR_FEATURE_NORMAL_MAP 2 +#define PBR_FEATURE_AMBIENT_MAP 4 +#define PBR_FEATURE_ROUGHNESS_MAP 8 +#define PBR_FEATURE_ENVIRONMENT_MAP 16 + +typedef struct PBREnvironment { + mat4 cam_inverse_transform; + Texture *environment_map; + vec3 ambient_color; +} PBREnvironment; + +typedef struct PBRModel { + Model *mdl; + PBRMaterial *mat; +} PBRModel; + #define STAGE3D_DEPRECATED(...) attr_deprecated(__VA_ARGS__) struct Stage3D { @@ -75,12 +94,14 @@ void stage3d_init(Stage3D *s, uint pos_buffer_size); void stage3d_update(Stage3D *s); void stage3d_shutdown(Stage3D *s); void stage3d_apply_transforms(Stage3D *s, mat4 mat); +void stage3d_apply_inverse_transforms(Stage3D *s, mat4 mat); void stage3d_draw_segment(Stage3D *s, SegmentPositionRule pos_rule, SegmentDrawRule draw_rule, float maxrange); void stage3d_draw(Stage3D *s, float maxrange, uint nsegments, const Stage3DSegment segments[nsegments]); void camera3d_init(Camera3D *cam) attr_nonnull(1); void camera3d_update(Camera3D *cam) attr_nonnull(1); void camera3d_apply_transforms(Camera3D *cam, mat4 mat) attr_nonnull(1, 2); +void camera3d_apply_inverse_transforms(Camera3D *cam, mat4 mat) attr_nonnull(1, 2); void camera3d_unprojected_ray(Camera3D *cam, cmplx pos, vec3 dest) attr_nonnull(1, 3); void camera3d_set_point_light_uniforms( @@ -97,6 +118,10 @@ void camera3d_fill_point_light_uniform_vectors( vec3 out_lrad[num_lights] ) attr_nonnull(1, 3, 4); +void pbr_set_material_uniforms(const PBRMaterial *m, const PBREnvironment *env) attr_nonnull_all; +void pbr_draw_model(const PBRModel *pmdl, const PBREnvironment *env) attr_nonnull_all; +void pbr_load_model(PBRModel *pmdl, const char *model_name, const char *mat_name); + uint linear3dpos(Stage3D *s3d, vec3 q, float maxrange, vec3 p, vec3 r); uint single3dpos(Stage3D *s3d, vec3 q, float maxrange, vec3 p); diff --git a/src/util/kvparser.c b/src/util/kvparser.c index 602253be..4b2d7785 100644 --- a/src/util/kvparser.c +++ b/src/util/kvparser.c @@ -191,3 +191,25 @@ bool kvparser_deprecation(const char *key, const char *val, void *data) { log_warn("'%s' is deprecated, use '%s' instead", key, alt); return true; } + +bool kvparser_vec3(const char *key, const char *val, void *data) { + float *out = data; + char *p = (char*)val; + + out[0] = strtof(p, &p); + if(!isspace(*p)) goto fail; + out[1] = strtof(p, &p); + if(!isspace(*p)) goto fail; + out[2] = strtof(p, &p); + + while(isspace(*p)) + ++p; + + if(*p == 0) { + return true; + } + +fail: + log_error("Invalid vec3 value for '%s': %s", key, val); + return false; +} diff --git a/src/util/kvparser.h b/src/util/kvparser.h index 44cb65f3..df26ce31 100644 --- a/src/util/kvparser.h +++ b/src/util/kvparser.h @@ -28,6 +28,9 @@ typedef struct KVSpec { float *out_float; bool *out_bool; + uint min_values; + uint max_values; + KVCallback callback; void *callback_data; } KVSpec; @@ -42,5 +45,6 @@ bool parse_keyvalue_file_with_spec(const char *filename, KVSpec *spec); bool parse_bool(const char *str, bool fallback) attr_nonnull(1); bool kvparser_deprecation(const char *key, const char *val, void *data); +bool kvparser_vec3(const char *key, const char *val, void *data); #define KVSPEC_DEPRECATED(new) .callback = kvparser_deprecation, .callback_data = (new)