From aee0c904ca16264eb9aa06bdfd80ae27b5d62645 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Fri, 25 Jan 2008 03:30:56 +0000 Subject: [PATCH] Added several new shader-parameter keywords, esp for lights and materials --- panda/src/display/graphicsStateGuardian.cxx | 132 +++++++ panda/src/gobj/shader.cxx | 370 +++++++++++++++----- panda/src/gobj/shader.h | 36 +- 3 files changed, 445 insertions(+), 93 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 094e863c82..ea54c2f3b0 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -40,6 +40,10 @@ #include "graphicsOutput.h" #include "texturePool.h" #include "geomMunger.h" +#include "ambientLight.h" +#include "directionalLight.h" +#include "pointLight.h" +#include "spotLight.h" #include #include @@ -825,6 +829,7 @@ fetch_specified_value(Shader::ShaderMatSpec &spec, bool altered) { const LMatrix4f *val2; static LMatrix4f t1; static LMatrix4f t2; + LVecBase3f v; switch(spec._func) { case Shader::SMF_compose: @@ -846,6 +851,38 @@ fetch_specified_value(Shader::ShaderMatSpec &spec, bool altered) { val1 = fetch_specified_part(spec._part[0], spec._arg[0], t1); acc.multiply(*val1, spec._cache); return &acc; + case Shader::SMF_transform_dlight: + if (altered) { + spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1); + } + val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2); + acc = spec._cache; + v = val2->xform_vec(spec._cache.get_row3(2)); + v.normalize(); + acc.set_row(2, v); + v = val2->xform_vec(spec._cache.get_row3(3)); + v.normalize(); + acc.set_row(3, v); + return &acc; + case Shader::SMF_transform_plight: + if (altered) { + spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1); + } + val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2); + acc = spec._cache; + acc.set_row(2, val2->xform_point(spec._cache.get_row3(2))); + return &acc; + case Shader::SMF_transform_slight: + if (altered) { + spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1); + } + val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2); + acc = spec._cache; + acc.set_row(2, val2->xform_point(spec._cache.get_row3(2))); + v = val2->xform_vec(spec._cache.get_row3(3)); + v.normalize(); + acc.set_row(3, v); + return &acc; case Shader::SMF_first: return fetch_specified_part(spec._part[0], spec._arg[0], t1); default: @@ -885,6 +922,101 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4f 0.0); return &t; } + case Shader::SMO_attr_material: { + // Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS + if (_target._material->is_off()) { + t = LMatrix4f(1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0); + return &t; + } + Material *m = _target._material->get_material(); + LVecBase4f const &amb = m->get_ambient(); + LVecBase4f const &dif = m->get_diffuse(); + LVecBase4f const &emm = m->get_emission(); + LVecBase4f spc = m->get_specular(); + spc[3] = m->get_shininess(); + t = LMatrix4f(amb[0],amb[1],amb[2],amb[3], + dif[0],dif[1],dif[2],dif[3], + emm[0],emm[1],emm[2],emm[3], + spc[0],spc[1],spc[2],spc[3]); + return &t; + } + case Shader::SMO_attr_color: { + if (_target._color->get_color_type() != ColorAttrib::T_flat) { + return &LMatrix4f::ones_mat(); + } + LVecBase4f c = _target._color->get_color(); + t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]); + return &t; + } + case Shader::SMO_alight_x: { + const NodePath &np = _target._shader->get_shader_input_nodepath(name); + nassertr(!np.is_empty(), &LMatrix4f::zeros_mat()); + AmbientLight *lt; + DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat()); + Colorf const &c = lt->get_color(); + t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]); + return &t; + } + case Shader::SMO_satten_x: { + const NodePath &np = _target._shader->get_shader_input_nodepath(name); + nassertr(!np.is_empty(), &LMatrix4f::ones_mat()); + Spotlight *lt; + DCAST_INTO_R(lt, np.node(), &LMatrix4f::ones_mat()); + LVecBase3f const &a = lt->get_attenuation(); + float x = lt->get_exponent(); + t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,a[0],a[1],a[2],x); + return &t; + } + case Shader::SMO_dlight_x: { + // The dlight matrix contains COLOR, SPECULAR, DIRECTION, PSEUDOHALFANGLE + const NodePath &np = _target._shader->get_shader_input_nodepath(name); + nassertr(!np.is_empty(), &LMatrix4f::zeros_mat()); + DirectionalLight *lt; + DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat()); + Colorf const &c = lt->get_color(); + Colorf const &s = lt->get_specular_color(); + t = np.get_net_transform()->get_mat() * + get_scene()->get_world_transform()->get_mat(); + LVecBase3f d = -(t.xform_vec(lt->get_direction())); + d.normalize(); + LVecBase3f h = d + LVecBase3f(0,-1,0); + h.normalize(); + t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],c[3],d[0],d[1],d[2],0,h[0],h[1],h[2],0); + return &t; + } + case Shader::SMO_plight_x: { + // The plight matrix contains COLOR, SPECULAR, POINT, ATTENUATION + const NodePath &np = _target._shader->get_shader_input_nodepath(name); + nassertr(!np.is_empty(), &LMatrix4f::ones_mat()); + PointLight *lt; + DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat()); + Colorf const &c = lt->get_color(); + Colorf const &s = lt->get_specular_color(); + t = np.get_net_transform()->get_mat() * + get_scene()->get_world_transform()->get_mat(); + LVecBase3f p = (t.xform_point(lt->get_point())); + LVecBase3f a = lt->get_attenuation(); + t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,a[0],a[1],a[2],0); + return &t; + } + case Shader::SMO_slight_x: { + // The slight matrix contains COLOR, SPECULAR, POINT, DIRECTION + const NodePath &np = _target._shader->get_shader_input_nodepath(name); + nassertr(!np.is_empty(), &LMatrix4f::zeros_mat()); + Spotlight *lt; + DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat()); + Lens *lens = lt->get_lens(); + nassertr(lens != (Lens *)NULL, &LMatrix4f::zeros_mat()); + Colorf const &c = lt->get_color(); + Colorf const &s = lt->get_specular_color(); + float cutoff = cos(deg_2_rad(lens->get_hfov() * 0.5f)); + t = np.get_net_transform()->get_mat() * + get_scene()->get_world_transform()->get_mat(); + LVecBase3f p = t.xform_point(lens->get_nodal_point()); + LVecBase3f d = -(t.xform_vec(lens->get_view_vector())); + t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff); + return &t; + } case Shader::SMO_mat_constant_x: { const NodePath &np = _target._shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4f::ident_mat()); diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index 60110e1714..52a000472d 100755 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -20,6 +20,8 @@ #include "shader.h" #include "preparedGraphicsObjects.h" #include "virtualFileSystem.h" +#include +#include #ifdef HAVE_CG #include "Cg/cg.h" @@ -31,6 +33,7 @@ TypeHandle Shader::_type_handle; Shader::LoadTable Shader::_load_table; Shader::MakeTable Shader::_make_table; Shader::ShaderCaps Shader::_default_caps; +int Shader::_shaders_generated; ShaderUtilization Shader::_shader_utilization = SUT_UNSPECIFIED; //////////////////////////////////////////////////////////////////// @@ -188,29 +191,136 @@ cp_errchk_parameter_sampler(ShaderArgInfo &p) } //////////////////////////////////////////////////////////////////// -// Function: Shader::cp_parse_trans_clause +// Function: Shader::cp_parse_eol // Access: Public -// Description: Parses a single clause of a "trans" parameter. +// Description: Make sure the next thing on the word list is EOL //////////////////////////////////////////////////////////////////// bool Shader:: -cp_parse_trans_clause(ShaderArgInfo &p, ShaderMatSpec &spec, - int part, const vector_string &pieces, - int &next, ShaderMatInput ofop, ShaderMatInput op) { - if (pieces[next+1]=="of") { - if (pieces[next+2]=="") { - cp_report_error(p, "'of' should be followed by a name"); - return false; - } - spec._part[part] = ofop; - spec._arg[part] = InternalName::make(pieces[next+2]); - next += 3; - return true; - } else { - spec._part[part] = op; - spec._arg[part] = NULL; - next += 1; - return true; +cp_parse_eol(ShaderArgInfo &p, vector_string &words, int &next) { + if (words[next] != "") { + cp_report_error(p, "Too many words in parameter"); + return false; } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::cp_parse_delimiter +// Access: Public +// Description: Pop a delimiter ('to' or 'rel') from the word list. +//////////////////////////////////////////////////////////////////// +bool Shader:: +cp_parse_delimiter(ShaderArgInfo &p, vector_string &words, int &next) { + if ((words[next] != "to")&&(words[next] != "rel")) { + cp_report_error(p, "Keyword 'to' or 'rel' expected"); + return false; + } + next += 1; + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::cp_parse_non_delimiter +// Access: Public +// Description: Pop a non-delimiter word from the word list. +// Delimiters are 'to' and 'rel.' +//////////////////////////////////////////////////////////////////// +string Shader:: +cp_parse_non_delimiter(vector_string &words, int &next) { + const string &nword = words[next]; + if ((nword == "")||(nword == "to")||(nword == "rel")) { + return ""; + } + next += 1; + return nword; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::cp_parse_coord_sys +// Access: Public +// Description: Convert a single-word coordinate system name into +// a PART/ARG of a ShaderMatSpec. +//////////////////////////////////////////////////////////////////// +bool Shader:: +cp_parse_coord_sys(ShaderArgInfo &p, + vector_string &pieces, int &next, + ShaderMatSpec &bind, bool fromflag) { + + string word1 = cp_parse_non_delimiter(pieces, next); + string word2 = cp_parse_non_delimiter(pieces, next); + + ShaderMatInput from_single; + ShaderMatInput from_double; + ShaderMatInput to_single; + ShaderMatInput to_double; + + if (word1 == "") { + cp_report_error(p, "Could not parse coordinate system name"); + return false; + } else if (word1 == "world") { + from_single = SMO_world_to_view; + from_double = SMO_INVALID; + to_single = SMO_view_to_world; + to_double = SMO_INVALID; + } else if (word1 == "model") { + from_single = SMO_model_to_view; + from_double = SMO_view_x_to_view; + to_single = SMO_view_to_model; + to_double = SMO_view_to_view_x; + } else if (word1 == "clip") { + from_single = SMO_clip_to_view; + from_double = SMO_clip_x_to_view; + to_single = SMO_view_to_clip; + to_double = SMO_view_to_clip_x; + } else if (word1 == "view") { + from_single = SMO_identity; + from_double = SMO_view_x_to_view; + to_single = SMO_identity; + to_double = SMO_view_to_view_x; + } else if (word1 == "apiview") { + from_single = SMO_apiview_to_view; + from_double = SMO_apiview_x_to_view; + to_single = SMO_view_to_apiview; + to_double = SMO_view_to_apiview_x; + } else if (word1 == "apiclip") { + from_single = SMO_apiclip_to_view; + from_double = SMO_apiclip_x_to_view; + to_single = SMO_view_to_apiclip; + to_double = SMO_view_to_apiclip_x; + } else { + from_single = SMO_view_x_to_view; + from_double = SMO_view_x_to_view; + to_single = SMO_view_to_view_x; + to_double = SMO_view_to_view_x; + word2 = word1; + } + + if (fromflag) { + if (word2 == "") { + bind._part[0] = from_single; + bind._arg[0] = NULL; + } else { + if (from_double == SMO_INVALID) { + cp_report_error(p, "Could not parse coordinate system name"); + return false; + } + bind._part[0] = from_double; + bind._arg[0] = InternalName::make(word2); + } + } else { + if (word2 == "") { + bind._part[1] = to_single; + bind._arg[1] = NULL; + } else { + if (to_double == SMO_INVALID) { + cp_report_error(p, "Could not parse coordinate system name"); + return false; + } + bind._part[1] = to_double; + bind._arg[1] = InternalName::make(word2); + } + } + return true; } //////////////////////////////////////////////////////////////////// @@ -468,76 +578,16 @@ compile_parameter(const ShaderArgId &arg_id, if (!cp_errchk_parameter_float(p, 4, 4)) return false; } - // Parse the first half of the clause. - bool ok = true; - if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){ - cp_report_error(p, "argument missing"); - return false; - } else if (pieces[next] == "world") { - bind._part[0] = SMO_world_to_view; - bind._arg[0] = NULL; - next += 1; - } else if (pieces[next] == "model") { - ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_model_to_view); - } else if (pieces[next] == "clip") { - ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_clip_x_to_view, SMO_clip_to_view); - } else if (pieces[next] == "view") { - ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_identity); - } else if (pieces[next] == "apiview") { - ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiview_x_to_view, SMO_apiview_to_view); - } else if (pieces[next] == "apiclip") { - ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiclip_x_to_view, SMO_apiclip_to_view); - } else { - bind._part[0] = SMO_view_x_to_view; - bind._arg[0] = InternalName::make(pieces[next]); - next += 1; - } - - // Check for errors in the first clause. - if (!ok) { + if (!cp_parse_coord_sys(p, pieces, next, bind, true)) { return false; } - - // Check for syntactic well-formed-ness. - if (pieces[next] != "to") { - cp_report_error(p, "keyword 'to' expected"); - return false; - } else { - next += 1; - } - - // Parse the second half of the clause. - if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){ - cp_report_error(p, "argument missing"); - return false; - } else if (pieces[next] == "world") { - bind._part[1] = SMO_view_to_world; - bind._arg[1] = NULL; - next += 1; - } else if (pieces[next] == "model") { - ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_view_to_model); - } else if (pieces[next] == "clip") { - ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_clip_x, SMO_view_to_clip); - } else if (pieces[next] == "view") { - ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_identity); - } else if (pieces[next] == "apiview") { - ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiview_x, SMO_view_to_apiview); - } else if (pieces[next] == "apiclip") { - ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiclip_x, SMO_view_to_apiclip); - } else { - bind._part[1] = SMO_view_to_view_x; - bind._arg[1] = InternalName::make(pieces[next]); - next += 1; - } - - // Check for errors in the second clause. - if (!ok) { + if (!cp_parse_delimiter(p, pieces, next)) { return false; } - - // Check for syntactic well-formed-ness. - if (pieces[next] != "") { - cp_report_error(p, "end of line expected"); + if (!cp_parse_coord_sys(p, pieces, next, bind, false)) { + return false; + } + if (!cp_parse_eol(p, pieces, next)) { return false; } @@ -546,6 +596,145 @@ compile_parameter(const ShaderArgId &arg_id, return true; } + // Special parameter: attr_material or attr_color + + if (pieces[0] == "attr") { + if ((!cp_errchk_parameter_words(p,2)) || + (!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))) { + return false; + } + ShaderMatSpec bind; + if (pieces[1] == "material") { + if (!cp_errchk_parameter_float(p,16,16)) { + return false; + } + bind._id = arg_id; + bind._piece = SMP_transpose; + bind._func = SMF_first; + bind._part[0] = SMO_attr_material; + bind._arg[0] = NULL; + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + } else if (pieces[1] == "color") { + if (!cp_errchk_parameter_float(p,3,4)) { + return false; + } + bind._id = arg_id; + bind._piece = SMP_row3; + bind._func = SMF_first; + bind._part[0] = SMO_attr_color; + bind._arg[0] = NULL; + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + } else { + cp_report_error(p,"Unknown attr parameter."); + return false; + } + + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + return true; + } + + if (pieces[0] == "color") { + if ((!cp_errchk_parameter_words(p,1)) || + (!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))) { + return false; + } + ShaderMatSpec bind; + + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + return true; + } + + // Keywords to access light properties. + + if (pieces[0] == "alight") { + if ((!cp_errchk_parameter_words(p,2))|| + (!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))|| + (!cp_errchk_parameter_float(p,3,4))) { + return false; + } + ShaderMatSpec bind; + bind._id = arg_id; + bind._piece = SMP_row3; + bind._func = SMF_first; + bind._part[0] = SMO_alight_x; + bind._arg[0] = InternalName::make(pieces[1]); + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + return true; + } + + if (pieces[0] == "satten") { + if ((!cp_errchk_parameter_words(p,2))|| + (!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))|| + (!cp_errchk_parameter_float(p,4,4))) { + return false; + } + ShaderMatSpec bind; + bind._id = arg_id; + bind._piece = SMP_row3; + bind._func = SMF_first; + bind._part[0] = SMO_satten_x; + bind._arg[0] = InternalName::make(pieces[1]); + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + return true; + } + + if ((pieces[0]=="dlight")||(pieces[0]=="plight")||(pieces[0]=="slight")) { + if ((!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))|| + (!cp_errchk_parameter_float(p,16,16))) { + return false; + } + ShaderMatSpec bind; + bind._id = arg_id; + bind._piece = SMP_transpose; + int next = 1; + pieces.push_back(""); + if (pieces[next] == "") { + cp_report_error(p, "Light name expected"); + return false; + } + if (pieces[0] == "dlight") { + bind._func = SMF_transform_dlight; + bind._part[0] = SMO_dlight_x; + } else if (pieces[0] == "plight") { + bind._func = SMF_transform_plight; + bind._part[0] = SMO_plight_x; + } else if (pieces[0] == "slight") { + bind._func = SMF_transform_slight; + bind._part[0] = SMO_slight_x; + } + bind._arg[0] = InternalName::make(pieces[next]); + next += 1; + if (!cp_parse_delimiter(p, pieces, next)) { + return false; + } + if (!cp_parse_coord_sys(p, pieces, next, bind, false)) { + return false; + } + if (!cp_parse_eol(p, pieces, next)) { + return false; + } + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + return true; + } + // Keywords to access unusual parameters. if (pieces[0] == "sys") { @@ -1253,6 +1442,17 @@ make(const string &body) { } PT(Shader) result = new Shader("created-shader", body); _make_table[body] = result; + if (dump_generated_shaders) { + ostringstream fns; + int index = _shaders_generated ++; + fns << "genshader" << index; + string fn = fns.str(); + gobj_cat.warning() << "Dumping shader: " << fn << "\n"; + ofstream s; + s.open(fn.c_str()); + s << body; + s.close(); + } return result; } diff --git a/panda/src/gobj/shader.h b/panda/src/gobj/shader.h index 107090bfcb..dd797b3436 100755 --- a/panda/src/gobj/shader.h +++ b/panda/src/gobj/shader.h @@ -72,6 +72,15 @@ public: SMO_pixel_size, SMO_card_center, + SMO_attr_material, + SMO_attr_color, + + SMO_alight_x, + SMO_dlight_x, + SMO_plight_x, + SMO_slight_x, + SMO_satten_x, + SMO_mat_constant_x, SMO_vec_constant_x, @@ -101,6 +110,12 @@ public: SMO_apiclip_x_to_view, SMO_view_to_apiclip_x, + + SMO_light_vector, + SMO_light_color, + SMO_light_spec, + + SMO_INVALID }; enum ShaderArgType { @@ -139,11 +154,14 @@ public: enum ShaderBug { SBUG_ati_draw_buffers, }; - + enum ShaderMatFunc { SMF_compose, SMF_compose_cache_first, SMF_compose_cache_second, + SMF_transform_dlight, + SMF_transform_plight, + SMF_transform_slight, SMF_first, }; @@ -215,13 +233,14 @@ public: bool cp_errchk_parameter_uniform(ShaderArgInfo &arg); bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi); bool cp_errchk_parameter_sampler(ShaderArgInfo &arg); - bool cp_parse_trans_clause(ShaderArgInfo &arg, - ShaderMatSpec &spec, - int part, - const vector_string &pieces, - int &next, - ShaderMatInput ofop, - ShaderMatInput op); + bool cp_parse_eol(ShaderArgInfo &arg, + vector_string &pieces, int &next); + bool cp_parse_delimiter(ShaderArgInfo &arg, + vector_string &pieces, int &next); + string cp_parse_non_delimiter(vector_string &pieces, int &next); + bool cp_parse_coord_sys(ShaderArgInfo &arg, + vector_string &pieces, int &next, + ShaderMatSpec &spec, bool fromflag); void cp_optimize_mat_spec(ShaderMatSpec &spec); bool compile_parameter(const ShaderArgId &arg_id, @@ -273,6 +292,7 @@ public: static ShaderCaps _default_caps; static ShaderUtilization _shader_utilization; + static int _shaders_generated; typedef pmap < Filename , Shader * > LoadTable; typedef pmap < string , Shader * > MakeTable;