ubershaders and path stripping in metascene
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 12 Dec 2016 06:32:58 +0000 (08:32 +0200)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 12 Dec 2016 06:32:58 +0000 (08:32 +0200)
sdr/shadow-notex.p.glsl [deleted file]
sdr/shadow.v.glsl [deleted file]
sdr/uber.p.glsl [new file with mode: 0644]
sdr/uber.v.glsl [new file with mode: 0644]
src/app.cc
src/datamap.cc
src/datamap.h
src/material.cc
src/metascene.cc
src/ubersdr.c [new file with mode: 0644]
src/ubersdr.h [new file with mode: 0644]

diff --git a/sdr/shadow-notex.p.glsl b/sdr/shadow-notex.p.glsl
deleted file mode 100644 (file)
index 4946ca0..0000000
+++ /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 (file)
index 8f9f045..0000000
+++ /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 (file)
index 0000000..ee5c0f1
--- /dev/null
@@ -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 (file)
index 0000000..a6c82d0
--- /dev/null
@@ -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
+}
index db3031f..fbd8609 100644 (file)
@@ -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();
+       */
+}
index e466082..e448923 100644 (file)
 
 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);
index 137fdca..674ab7c 100644 (file)
@@ -9,11 +9,15 @@ class DataMap {
        std::vector<std::pair<std::string, std::string>> dmap;
        mutable std::map<std::string, std::string> 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);
index 189b6ad..f345204 100644 (file)
@@ -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; i<ntex; i++) {
-               bind_texture(textures[i], i);
+       for(int i=0; i<NUM_MTL_TEXTURES; i++) {
+               bind_texture(stdtex[i], i);
        }
 
-       /*
-       if(stdtex[MTL_TEX_LIGHTMAP]) {
-               bind_program(stdtex[MTL_TEX_DIFFUSE] ? sdr_ltmap : sdr_ltmap_notex);
+       if(stdtex[MTL_TEX_DIFFUSE]) {
+               uber_enable_texmap();
+       } else {
+               uber_disable_texmap();
+       }
+       if(stdtex[MTL_TEX_ENVMAP] && stdtex[MTL_TEX_ENVMAP]->get_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)
index 53474f7..6059664 100644 (file)
@@ -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 (file)
index 0000000..60a39b2
--- /dev/null
@@ -0,0 +1,185 @@
+#include <stdlib.h>
+#include <string.h>
+#include <opengl.h>
+#include <logger.h>
+#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<CACHE_SIZE; i++) {
+               if(cache[i].vs)
+                       free_shader(cache[i].vs);
+               if(cache[i].ps)
+                       free_shader(cache[i].ps);
+               if(cache[i].prog)
+                       free_program(cache[i].prog);
+       }
+       free(vs_fname);
+       free(ps_fname);
+}
+
+void uber_clear(void)
+{
+       state = 0;
+}
+
+void uber_enable_light(int idx)
+{
+       if(idx >= 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<MAX_STATE_BITS; i++) {
+               if(state & (1 << i)) {
+                       add_shader_header(type, macros[i]);
+                       debug_log("  - header: %s\n", macros[i]);
+               }
+       }
+       res = load_shader(type == GL_VERTEX_SHADER ? vs_fname : ps_fname, type);
+       clear_shader_header(type);
+       return res;
+}
+
+unsigned int uber_program(void)
+{
+       if(!cache[state].prog) {
+               unsigned int vs, ps;
+               if(!(vs = uber_vertex_shader()) || !(ps = uber_pixel_shader())) {
+                       error_log("uber_program failed to make shaders for state: %x\n", state);
+                       return 0;
+               }
+               if(!(cache[state].prog = create_program_link(vs, ps, 0))) {
+                       error_log("uber_program failed to link program for state: %x\n", state);
+                       return 0;
+               }
+       }
+       return cache[state].prog;
+}
diff --git a/src/ubersdr.h b/src/ubersdr.h
new file mode 100644 (file)
index 0000000..8b2ada4
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef UBERSDR_H_
+#define UBERSDR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int uber_init(const char *vsname, const char *psname);
+void uber_destroy(void);
+
+void uber_clear(void);
+
+void uber_enable_light(int idx);
+void uber_disable_light(int idx);
+
+void uber_enable_texmap(void);
+void uber_disable_texmap(void);
+
+void uber_enable_cubemap(void);
+void uber_disable_cubemap(void);
+
+void uber_enable_sphmap(void);
+void uber_disable_sphmap(void);
+
+void uber_enable_shadows(void);
+void uber_disable_shadows(void);
+
+unsigned int uber_vertex_shader(void);
+unsigned int uber_pixel_shader(void);
+unsigned int uber_program(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UBERSDR_H_ */