From f8ad31b8b1856784aefdd3457b6b8f5cb5576892 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 12 Dec 2016 08:32:58 +0200 Subject: [PATCH] ubershaders and path stripping in metascene --- sdr/shadow-notex.p.glsl | 60 --------------- sdr/shadow.v.glsl | 27 ------- sdr/uber.p.glsl | 100 +++++++++++++++++++++++++ sdr/uber.v.glsl | 33 +++++++++ src/app.cc | 38 +++++++++- src/datamap.cc | 17 +++++ src/datamap.h | 4 + src/material.cc | 28 +++++-- src/metascene.cc | 7 +- src/ubersdr.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++ src/ubersdr.h | 36 +++++++++ 11 files changed, 437 insertions(+), 98 deletions(-) delete mode 100644 sdr/shadow-notex.p.glsl delete mode 100644 sdr/shadow.v.glsl create mode 100644 sdr/uber.p.glsl create mode 100644 sdr/uber.v.glsl create mode 100644 src/ubersdr.c create mode 100644 src/ubersdr.h diff --git a/sdr/shadow-notex.p.glsl b/sdr/shadow-notex.p.glsl deleted file mode 100644 index 4946ca0..0000000 --- a/sdr/shadow-notex.p.glsl +++ /dev/null @@ -1,60 +0,0 @@ -/* vi: set ft=glsl */ -#ifdef USE_CUBEMAP -uniform samplerCube envmap; -#endif -uniform sampler2DShadow shadowmap; - -varying vec3 vdir, ldir[3], normal; -varying vec4 shadow_tc; -varying vec3 wdir; - -#define KD gl_FrontMaterial.diffuse.rgb -#define KS gl_FrontMaterial.specular.rgb -#define SPOW gl_FrontMaterial.shininess - -#define LD(i) gl_LightSource[i].diffuse.rgb -#define LS(i) gl_LightSource[i].specular.rgb - -vec3 calc_diffuse(in vec3 n, in vec3 l, in vec3 lcol) -{ - float ndotl = max(dot(n, l), 0.0); - return KD * lcol * ndotl; -} - -vec3 calc_specular(in vec3 n, in vec3 l, in vec3 v, in vec3 lcol) -{ - vec3 h = normalize(l + v); - float ndoth = max(dot(n, h), 0.0); - return KS * lcol * pow(ndoth, SPOW); -} - -void main() -{ - float shadow = shadow2DProj(shadowmap, shadow_tc).x; - - vec3 n = normalize(normal); - vec3 v = normalize(vdir); - - vec3 l = normalize(ldir[0]); - vec3 diffuse = calc_diffuse(n, l, LD(0)) * shadow; - vec3 specular = calc_specular(n, l, v, LS(0)) * shadow; - - l = normalize(ldir[1]); - diffuse += calc_diffuse(n, l, LD(1)); - specular += calc_specular(n, l, v, LS(1)); - - l = normalize(ldir[2]); - diffuse += calc_diffuse(n, l, LD(2)); - specular += calc_specular(n, l, v, LS(2)); - -#ifdef USE_CUBEMAP - // envmap - vec3 rdir = -reflect(wdir, n); - vec3 env_texel = textureCube(envmap, rdir).xyz; - specular += KS * env_texel; -#endif // USE_CUBEMAP - - vec3 ambient = gl_LightModel.ambient.rgb * KD; - gl_FragColor.rgb = ambient + diffuse + specular; - gl_FragColor.a = gl_FrontMaterial.diffuse.a; -} diff --git a/sdr/shadow.v.glsl b/sdr/shadow.v.glsl deleted file mode 100644 index 8f9f045..0000000 --- a/sdr/shadow.v.glsl +++ /dev/null @@ -1,27 +0,0 @@ -uniform mat4 envmap_matrix; - -varying vec3 vdir, ldir[3], normal; -varying vec4 shadow_tc; -varying vec3 wdir; - -void main() -{ - gl_Position = ftransform(); - - vec3 vpos = (gl_ModelViewMatrix * gl_Vertex).xyz; - normal = gl_NormalMatrix * gl_Normal; - vdir = -vpos; - wdir = (envmap_matrix * vec4(vdir, 1.0)).xyz; // bring back to world space - ldir[0] = gl_LightSource[0].position.xyz - vpos; - ldir[1] = gl_LightSource[1].position.xyz - vpos; - ldir[2] = gl_LightSource[2].position.xyz - vpos; - gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; - - mat4 offmat = mat4(0.5, 0.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.5, 0.5, 0.5, 1.0); - mat4 tex_matrix = offmat * gl_TextureMatrix[1]; - - shadow_tc = tex_matrix * vec4(vpos, 1.0); -} diff --git a/sdr/uber.p.glsl b/sdr/uber.p.glsl new file mode 100644 index 0000000..ee5c0f1 --- /dev/null +++ b/sdr/uber.p.glsl @@ -0,0 +1,100 @@ +/* vi:set ft=glsl: */ +#ifdef USE_TEXMAP +uniform sampler2D texmap; +#endif +#ifdef USE_CUBEMAP +uniform samplerCube envmap; +#endif +#ifdef USE_SHADOWMAP +uniform sampler2DShadow shadowmap; +#endif + +varying vec3 vpos, vdir, normal; +#ifdef USE_SHADOWMAP +varying vec4 shadow_tc; +#endif +#ifdef USE_CUBEMAP +varying vec3 wdir; +#endif + +#ifdef USE_TEXMAP +#define KD texel.rgb +#else +#define KD gl_FrontMaterial.diffuse.rgb +#endif + +#define KS gl_FrontMaterial.specular.rgb +#define SPOW gl_FrontMaterial.shininess + +#define LD(i) gl_LightSource[i].diffuse.rgb +#define LS(i) gl_LightSource[i].specular.rgb +#define LPOS(i) gl_LightSource[i].position.xyz + +vec3 calc_diffuse(in vec3 n, in vec3 l, in vec3 color, in vec3 lcol) +{ + float ndotl = max(dot(n, l), 0.0); + return color * lcol * ndotl; +} + +vec3 calc_specular(in vec3 n, in vec3 l, in vec3 v, in vec3 color, in vec3 lcol) +{ + vec3 h = normalize(l + v); + float ndoth = max(dot(n, h), 0.0); + return color * lcol * pow(ndoth, SPOW); +} + + +void main() +{ +#ifdef USE_TEXMAP + vec4 texel = texture2D(texmap, gl_TexCoord[0].st); +#endif +#ifdef USE_SHADOWMAP + float shadow = shadow2DProj(shadowmap, shadow_tc).x; +#else + const float shadow = 1.0; +#endif + + vec3 n = normalize(normal); + vec3 v = normalize(vdir); + + vec3 diffuse = vec3(0.0, 0.0, 0.0); + vec3 specular = vec3(0.0, 0.0, 0.0); + +#ifdef USE_LIGHT0 + { + vec3 l = normalize(LPOS(0) - vpos); + diffuse += calc_diffuse(n, l, KD, LD(0)) * shadow; + specular += calc_specular(n, l, v, KS, LS(0)) * shadow; + } +#endif +#ifdef USE_LIGHT1 + { + vec3 l = normalize(LPOS(1) - vpos); + diffuse += calc_diffuse(n, l, KD, LD(1)) * shadow; + specular += calc_specular(n, l, v, KS, LS(1)) * shadow; + } +#endif +#ifdef USE_LIGHT2 + { + vec3 l = normalize(LPOS(2) - vpos); + diffuse += calc_diffuse(n, l, KD, LD(2)) * shadow; + specular += calc_specular(n, l, v, KS, LS(2)) * shadow; + } +#endif + +#ifdef USE_CUBEMAP + // envmap + vec3 rdir = -reflect(wdir, n); + vec3 env_texel = textureCube(envmap, rdir).xyz; + specular += KS * env_texel; +#endif // USE_CUBEMAP + + vec3 ambient = gl_LightModel.ambient.rgb * KD; + gl_FragColor.rgb = ambient + diffuse + specular; +#ifdef USE_TEXMAP + gl_FragColor.a = gl_FrontMaterial.diffuse.a * texel.a; +#else + gl_FragColor.a = gl_FrontMaterial.diffuse.a; +#endif +} diff --git a/sdr/uber.v.glsl b/sdr/uber.v.glsl new file mode 100644 index 0000000..a6c82d0 --- /dev/null +++ b/sdr/uber.v.glsl @@ -0,0 +1,33 @@ +varying vec3 vpos, vdir, normal; +#ifdef USE_SHADOWMAP +varying vec4 shadow_tc; +#endif +#ifdef USE_CUBEMAP +varying vec3 wdir; +uniform mat4 envmap_matrix; +#endif + +void main() +{ + gl_Position = ftransform(); + + vpos = (gl_ModelViewMatrix * gl_Vertex).xyz; + normal = gl_NormalMatrix * gl_Normal; + vdir = -vpos; +#ifdef USE_CUBEMAP + wdir = (envmap_matrix * vec4(vdir, 1.0)).xyz; // bring back to world space +#endif +#ifdef USE_TEXMAP + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; +#endif + +#ifdef USE_SHADOWMAP + mat4 offmat = mat4(0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0); + mat4 tex_matrix = offmat * gl_TextureMatrix[1]; + + shadow_tc = tex_matrix * vec4(vpos, 1.0); +#endif +} diff --git a/src/app.cc b/src/app.cc index db3031f..fbd8609 100644 --- a/src/app.cc +++ b/src/app.cc @@ -4,6 +4,7 @@ #include "app.h" #include "opengl.h" #include "sdr.h" +#include "ubersdr.h" #include "texture.h" #include "mesh.h" #include "meshgen.h" @@ -21,6 +22,7 @@ static void draw_scene(); static void toggle_flight(); static void calc_framerate(); +static void prebake_shaders(); long time_msec; int win_width, win_height; @@ -97,10 +99,11 @@ bool app_init(int argc, char **argv) glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_NORMALIZE); + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); Mesh::use_custom_sdr_attr = false; - float ambient[] = {0.0, 0.0, 0.0, 0.0}; + float ambient[] = {0.02, 0.02, 0.02, 0.0}; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); glClearColor(0.1, 0.1, 0.1, 1.0); @@ -123,11 +126,17 @@ bool app_init(int argc, char **argv) blobs->node->set_scaling(Vec3(0.1, 0.1, 0.1)); blobs->node->update(0); + if(uber_init("sdr/uber.v.glsl", "sdr/uber.p.glsl") == -1) { + return false; + } + prebake_shaders(); + /* if(!(sdr_shadow_notex = create_program_load("sdr/shadow.v.glsl", "sdr/shadow-notex.p.glsl"))) { return false; } set_uniform_int(sdr_shadow_notex, "shadowmap", 1); set_uniform_int(sdr_shadow_notex, "envmap", 2); + */ if(!fb_srgb) { sdr_post_gamma = create_program_load("sdr/post_gamma.v.glsl", "sdr/post_gamma.p.glsl"); @@ -282,6 +291,8 @@ static void set_light(int idx, const Vec3 &pos, const Vec3 &color) glLightfv(lt, GL_POSITION, posv); glLightfv(lt, GL_DIFFUSE, colv); glLightfv(lt, GL_SPECULAR, colv); + + uber_enable_light(idx); } void app_display() @@ -345,8 +356,8 @@ static void draw_scene() { static const Vec3 lpos[] = { Vec3(-50, 75, 100), Vec3(100, 0, 30), Vec3(-10, -10, 60) }; set_light(0, lpos[0], Vec3(1.0, 0.8, 0.7) * 0.8); - set_light(1, lpos[1], Vec3(0.6, 0.7, 1.0) * 0.6); - set_light(2, lpos[2], Vec3(0.8, 1.0, 0.8) * 0.3); + //set_light(1, lpos[1], Vec3(0.6, 0.7, 1.0) * 0.6); + //set_light(2, lpos[2], Vec3(0.8, 1.0, 0.8) * 0.3); mscn->draw(); if(show_blobs) { @@ -588,3 +599,24 @@ static void calc_framerate() ++nframes; } } + +static void prebake_shaders() +{ + /* + unsigned int prog; + + uber_clear(); + uber_enable_light(0); + uber_enable_light(1); + uber_enable_light(2); + if((prog = uber_program())) { + } + + uber_enable_texmap(); + if((prog = uber_program())) { + set_uniform_int(prog, "texmap", MTL_TEX_DIFFUSE); + } + + uber_clear(); + */ +} diff --git a/src/datamap.cc b/src/datamap.cc index e466082..e448923 100644 --- a/src/datamap.cc +++ b/src/datamap.cc @@ -11,6 +11,11 @@ static char *clean_line(char *s); +DataMap::DataMap() +{ + strip_paths = false; +} + void DataMap::clear() { dmap.clear(); @@ -22,6 +27,11 @@ void DataMap::set_path(const char *path) root = std::string(path); } +void DataMap::set_strip(bool s) +{ + strip_paths = s; +} + bool DataMap::load_map(const char *fname) { std::string path = root.empty() ? fname : root + std::string("/") + fname; @@ -91,6 +101,13 @@ int DataMap::lookup(const char *in, char *buf, int bsz) const { std::string res; + if(strip_paths) { + const char *ptr = strrchr(in, '/'); + if(ptr) { + in = ptr + 1; + } + } + char *inbuf = (char*)alloca(strlen(in) + 1); strcpy(inbuf, in); in = clean_line(inbuf); diff --git a/src/datamap.h b/src/datamap.h index 137fdca..674ab7c 100644 --- a/src/datamap.h +++ b/src/datamap.h @@ -9,11 +9,15 @@ class DataMap { std::vector> dmap; mutable std::map cache; std::string root; + bool strip_paths; public: + DataMap(); + void clear(); void set_path(const char *path); + void set_strip(bool s); bool load_map(const char *fname); void map(const char *match, const char *path); diff --git a/src/material.cc b/src/material.cc index 189b6ad..f345204 100644 --- a/src/material.cc +++ b/src/material.cc @@ -4,6 +4,7 @@ #include "material.h" #include "sdr.h" #include "app.h" +#include "ubersdr.h" Material::Material() : diffuse(1.0f, 1.0f, 1.0f) @@ -22,16 +23,29 @@ void Material::setup() const glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, ks); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); - int ntex = std::min((int)textures.size(), 8); // TODO: use max texture units - for(int i=0; iget_type() == TEX_CUBE) { + uber_enable_cubemap(); + } else { + uber_disable_cubemap(); } - */ + if(stdtex[MTL_TEX_ENVMAP] && stdtex[MTL_TEX_ENVMAP]->get_type() == TEX_2D) { + uber_enable_sphmap(); + } else { + uber_disable_sphmap(); + } + /* TODO shadows */ + + unsigned int sdrprog = uber_program(); + bind_program(sdrprog); } void Material::add_texture(Texture *tex, int type) diff --git a/src/metascene.cc b/src/metascene.cc index 53474f7..6059664 100644 --- a/src/metascene.cc +++ b/src/metascene.cc @@ -118,10 +118,15 @@ static bool proc_scenefile(MetaScene *mscn, struct ts_node *node) // datapath struct ts_attr *adpath = attr_inscope(node, "datapath"); if(adpath && adpath->val.type == TS_STRING) { - info_log("adding data path: %s\n", adpath->val.str); mscn->datamap.set_path(adpath->val.str); } + // strip path + struct ts_attr *aspath = attr_inscope(node, "strip_path"); + if(aspath && aspath->val.type == TS_NUMBER) { + mscn->datamap.set_strip(aspath->val.inum); + } + // walkmesh struct ts_attr *awmesh = attr_inscope(node, "walkmesh"); if(awmesh && awmesh->val.type == TS_STRING) { diff --git a/src/ubersdr.c b/src/ubersdr.c new file mode 100644 index 0000000..60a39b2 --- /dev/null +++ b/src/ubersdr.c @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include "ubersdr.h" +#include "sdr.h" + +enum { + UBER_LIGHT0, + UBER_LIGHT1, + UBER_LIGHT2, + UBER_LIGHT3, + UBER_TEXMAP, + UBER_CUBEMAP, + UBER_SPHMAP, + UBER_SHADOWS, + + MAX_STATE_BITS +}; +#define MAX_LIGHTS 4 + +static const char *macros[] = { + "#define USE_LIGHT0\n", + "#define USE_LIGHT1\n", + "#define USE_LIGHT2\n", + "#define USE_LIGHT3\n", + "#define USE_TEXMAP\n", + "#define USE_CUBEMAP\n", + "#define USE_SPHMAP\n", + "#define USE_SHADOWMAP\n", + 0 +}; + +struct sdrcache { + unsigned int vs, ps; + unsigned int prog; +}; + +static unsigned int mkshader(unsigned int type); + +static char *vs_fname, *ps_fname; +static unsigned int state; + +#define CACHE_SIZE (1 << MAX_STATE_BITS) +static struct sdrcache cache[CACHE_SIZE]; + +int uber_init(const char *vsname, const char *psname) +{ + state = 0; + memset(cache, 0, sizeof cache); + + vs_fname = strdup(vsname); + ps_fname = strdup(psname); + if(!vs_fname || !ps_fname) { + free(vs_fname); + return -1; + } + return 0; +} + +void uber_destroy(void) +{ + int i; + + for(i=0; i= 0 && idx < MAX_LIGHTS) { + state |= (1 << (UBER_LIGHT0 + idx)); + } +} + +void uber_disable_light(int idx) +{ + if(idx >= 0 && idx < MAX_LIGHTS) { + state &= ~(1 << (UBER_LIGHT0 + idx)); + } +} + +void uber_enable_texmap(void) +{ + state |= (1 << UBER_TEXMAP); +} + +void uber_disable_texmap(void) +{ + state &= ~(1 << UBER_TEXMAP); +} + +void uber_enable_cubemap(void) +{ + state |= (1 << UBER_CUBEMAP); +} + +void uber_disable_cubemap(void) +{ + state &= ~(1 << UBER_CUBEMAP); +} + +void uber_enable_sphmap(void) +{ + state |= (1 << UBER_SPHMAP); +} + +void uber_disable_sphmap(void) +{ + state &= ~(1 << UBER_SPHMAP); +} + +void uber_enable_shadows(void) +{ + state |= (1 << UBER_SHADOWS); +} + +void uber_disable_shadows(void) +{ + state &= ~(1 << UBER_SHADOWS); +} + +unsigned int uber_vertex_shader(void) +{ + if(!cache[state].vs) { + cache[state].vs = mkshader(GL_VERTEX_SHADER); + } + return cache[state].vs; +} + +unsigned int uber_pixel_shader(void) +{ + if(!cache[state].ps) { + cache[state].ps = mkshader(GL_FRAGMENT_SHADER); + } + return cache[state].ps; +} + +static unsigned int mkshader(unsigned int type) +{ + int i; + unsigned int res; + clear_shader_header(type); + + debug_log("mkshader(%s): %x\n", type == GL_VERTEX_SHADER ? "vertex" : "pixel"); + + for(i=0; i