--- libgender/shader.C 2004/10/24 01:40:31 1.10 +++ libgender/shader.C 2006/01/25 22:48:02 1.32 @@ -1,17 +1,22 @@ +#include + #include "shader.h" #include "shader_vars.h" +#include +#include + namespace shader { + using namespace std; + refcounted::~refcounted () { -#if 0 if (refcnt) abort (); -#endif } - void refcounted::refcnt_dec () const + void refcounted::refcnt_destroy () const { if (!--refcnt) delete this; // quite a bit of code... @@ -37,314 +42,269 @@ unsigned int var_i::next_id = 0; - var_i::var_i (const char *typestr) - : typestr (typestr) + var_i::var_i (const char *domainstr, const char *typestr) + : domainstr (domainstr), typestr (typestr) { - //param = cgCreateParameter (cg_context, cgtype); } var_i::~var_i () { - //cgDestroyParameter (param); } +#if 0 stream_i::stream_i (const char *strtype) : var_i (strtype) { - sprintf (name, "V%lx_%d", ((long)this >> 4) & 0xfff, ++next_id); + sprintf (name, "V%d", ++next_id); } +#endif temporary_i::temporary_i (const char *strtype) - : var_i (strtype) + : var_i (0, strtype) { - sprintf (name, "T%lx_%d", ((long)this >> 4) & 0xfff, ++next_id); + sprintf (name, "T%d", ++next_id); } - uniform_i::uniform_i (const char *strtype) - : var_i (strtype), dirty (true) + varying_i::varying_i (const char *strtype) + : var_i ("varying", strtype) { - sprintf (name, "U%lx_%d", ((long)this >> 4) & 0xfff, ++next_id); + sprintf (name, "V%d", ++next_id); } - fragment_string_i::~fragment_string_i () + uniform_i::uniform_i (const char *strtype) + : var_i ("uniform", strtype) { - free (str); + sprintf (name, "U%d", ++next_id); } //////////////////////////////////////////////////////////////////////////// - void var_i::build_decl (ostringstream &b) + void var_i::operator ()() const { - b << typestr << ' ' << name; - } - - void uniform_i::build_decl (ostringstream &b) - { - b << "uniform " << typestr << ' ' << name; - } + shader_builder::cur->code << name; - void stream_i::build_decl (ostringstream &b) - { - b << typestr << ' ' << name; + if (shader_builder::cur->first (this)) + { + if (domainstr) + shader_builder::cur->global << domainstr << ' ' << typestr << ' ' << name << ";\n"; + else + shader_builder::cur->local << " " << typestr << ' ' << name << ";\n"; + } } //////////////////////////////////////////////////////////////////////////// - void glvar_i::build (shader_builder &b) + int texture_units::unit_count = 8; + int texture_units::units[8] = { 7, 6, 5, 4, 3, 2, 1, 0 }; + + shader_object_i *cur = 0; + + shader_object_i::shader_object_i (GLenum type) + : type (type) { - b << name; + id = glCreateShaderObjectARB (type); + assert (id); } - void var_i::build (shader_builder &b) + shader_object_i::~shader_object_i () { - b << name; + glDeleteObjectARB (id); } - void uniform_i::build (shader_builder &b) + static string linify (const string &s) { - var_i::build (b); + ostringstream o; - if (find (b.refs.begin (), b.refs.end (), uniform (*this)) == b.refs.end ()) - b.refs.push_back (*this); + int b = 0, e; + int l = 1; + do { + o << setw (3) << l << ": "; + e = s.find ('\n', b); + if (e == string::npos) + e = s.size (); + + o << s.substr (b, e - b + 1); + b = e + 1; + l++; + } while (b < s.size ()); + + return o.str (); } - void stream_i::build (shader_builder &b) + //////////////////////////////////////////////////////////////////////////// + + GLint uniform_i::location () { - var_i::build (b); + assert (program_object_i::cur); - if (find (b.streams.begin (), b.streams.end (), var (*this)) == b.streams.end ()) - b.streams.push_back (*this); - } + GLint &rid = program_object_i::cur->uloc[this]; - void temporary_i::build (shader_builder &b) - { - var_i::build (b); + if (!rid) + rid = glGetUniformLocationARB (program_object_i::cur->id, name); - if (find (b.temps.begin (), b.temps.end (), var (*this)) == b.temps.end ()) - b.temps.push_back (*this); + return rid; } - void fragment_vector_i::build (shader_builder &b) - { - for (vector::iterator i = begin (); i != end (); i++) - (*i)->build (b); - } + program_object_i *program_object_i::cur; - void fragment_const_string_i::build (shader_builder &b) + program_object_i::program_object_i () { - b << str; + id = glCreateProgramObjectARB (); + assert (id); } - void fragment_string_i::build (shader_builder &b) + program_object_i::~program_object_i () { - b << str; + glDeleteProgramsARB (1, &id); } -#if 0 - void statement_i::build (shader_builder &b) + void program_object_i::link () { - b << " "; - fragment_vector_i::build (b); - b << ";\n"; - } -#endif - - //////////////////////////////////////////////////////////////////////////// - - shader_object_i *cur = 0; + glLinkProgramARB (id); + + GLint linked; + glGetObjectParameterivARB (id, GL_OBJECT_LINK_STATUS_ARB, &linked); - shader_object_i::shader_object_i (GLenum type) - : type (type) - { - id = glCreateShaderObjectARB (type); - } + if (!linked) + { + char infolog[8192]; + glGetInfoLogARB (id, 8192, NULL, infolog); + printf ("LINK-INFOLOG<%s>\n", infolog); + abort (); + } - shader_object_i::~shader_object_i () - { - glDeleteObjectARB (id); + uloc.clear (); } - void shader_object_i::start () + void program_object_i::enable () { - clear (); - cur = this; + if (this != cur) + { + glUseProgramObjectARB (id); + //TODO: set samplers here? + cur = this; + } } - void shader_object_i::stop () + void program_object_i::disable () { + //TODO: clear samplers here? + glUseProgramObjectARB (0); cur = 0; } - string shader_object_i::source () + static map progcache; + + program_object get_program (const string &vsh, const string &fsh) { - shader_builder b; - build (b); - ostringstream os; + string idx = vsh + "\0" + fsh; - for (vector::iterator i = b.refs.begin (); i != b.refs.end (); i++) - { - (*i)->build_decl (os); - os << ";\n"; - } + map::iterator i = progcache.find (idx); - // not neccessary right now, as GLSL is rich on predefinitions - for (vector::iterator i = b.streams.begin (); i != b.streams.end (); i++) - { - os << "attribute "; - (*i)->build_decl (os); - os << ";\n"; - } + if (i != progcache.end ()) + return i->second; - os << "\nvoid main (void)\n{\n"; + program_object p; - for (vector::iterator i = b.temps.begin (); i != b.temps.end (); i++) + if (vsh.size ()) { - os << " "; - (*i)->build_decl (os); - os << ";\n"; + vertex_shader sh; + p->attach (sh); + sh->compile (vsh); } - os << "\n"; - os << b.source.str (); - os << "}\n"; - - return os.str (); - } - - void shader_object_i::compile () - { - string src = source (); - const char *sptr = src.data (); - const int slen = src.size (); - - printf ("SOURCE<%s>\n", src.c_str ()); - glShaderSourceARB (id, 1, &sptr, &slen); - glCompileShaderARB (id); - - GLint compiled; - glGetObjectParameterivARB (id, GL_OBJECT_COMPILE_STATUS_ARB, &compiled); - - if (!compiled) + if (fsh.size ()) { - char infolog[8192]; - glGetInfoLogARB (id, 8192, NULL, infolog); - printf ("SOURCE<%s>\n", src.c_str ()); - printf ("INFOLOG<%s>\n", infolog); - abort (); + fragment_shader sh; + p->attach (sh); + sh->compile (fsh); } - } - void sl_func0::begin () const - { - cur->append_string (name_par); - } - - void sl_func0::comma () const - { - cur->append (str_comma); - } + p->link (); - void sl_func0::end () const - { - str_rpar (); - } + progcache.insert (pair (idx, p)); - void sl_float::operator ()() const - { - char s[20]; - sprintf (s, "%g", c); - cur->append_string (s); + return p; } - const sl_convert< ::vec2 >::T sl_convert< ::vec2 >::convert (const ::vec2 &v) + const sl_expr< sl_string<60> > sl_convert< ::vec2 >::convert (const ::vec2 &v) { sl_string<60> s; - sprintf (s.str, "vec2 (%g, %g)", v.x, v.y); + sprintf (s.str, "vec2 (%e, %e)", v.x, v.y); return s; } - const sl_convert< ::vec3 >::T sl_convert< ::vec3 >::convert (const ::vec3 &v) + const sl_expr< sl_string<80> > sl_convert< ::vec3 >::convert (const ::vec3 &v) { sl_string<80> s; - sprintf (s.str, "vec3 (%g, %g, %g)", v.x, v.y, v.z); + sprintf (s.str, "vec3 (%e, %e, %e)", v.x, v.y, v.z); return s; } - const sl_convert< ::vec4 >::T sl_convert< ::vec4 >::convert (const ::vec4 &v) + const sl_expr< sl_string<100> > sl_convert< ::vec4 >::convert (const ::vec4 &v) { sl_string<100> s; - sprintf (s.str, "vec4 (%g, %g, %g, %g)", v.x, v.y, v.z, v.w); + sprintf (s.str, "vec4 (%e, %e, %e, %e)", v.x, v.y, v.z, v.w); return s; } - const fragment_const_string str_2sp (" "); - const fragment_const_string str_equal (" = "); - const fragment_const_string str_comma (", "); - const fragment_const_string str_endl (";\n"); - - const sl_append_const_string str_plus (" + "); - const sl_append_const_string str_minus (" - "); - const sl_append_const_string str_mul (" * "); - const sl_append_const_string str_div (" / "); - const sl_append_const_string str_mod (" % "); - - const sl_append_const_string str_lpar ("("); - const sl_append_const_string str_rpar (")"); + shader_builder *shader_builder::cur = 0; - void swizzle_mask (sl_string<7> &s, int mask) + bool shader_builder::first (const void *p) { - static const char channel[4] = { 'x', 'y', 'z', 'w' }; - - char *str = s.str; - - *str++ = ')'; - *str++ = '.'; - - while (mask) + if (seen.find (p) == seen.end ()) { - int c = mask % 5; - mask /= 5; - - if (c) - *str++ = channel[c - 1]; + seen.insert (p); + return true; } - *str++ = 0; + return false; } - - void debdebdebdebug ()//D + void shader_builder::start () { - vertex_shader vsh; - - vsh->start (); + cur = new shader_builder; + cur->code << scientific; + } - temp_4f lightpos; - temp_3f wpos; + string shader_builder::stop () + { + ostringstream os; - lightpos = vec4 (10, -10, 0, 1); - wpos = xyz (gl.model_view_matrix * vin.vertex); - vout.position = gl.model_view_matrix_inverse_transpose * vin.vertex; - vout.tex_coord[0] = vin.tex_coord[0]; - vout.tex_coord[1] = normalize (lightpos - wpos); - vout.tex_coord[2] = normalize (wpos); - vout.tex_coord[3] = normalize (xyz (gl.model_view_matrix_inverse_transpose) * vin.normal); - vout.tex_coord[4] = normalize (xyz (gl.projection_matrix_inverse_transpose) - wpos); + os << cur->global.str () + << "\nvoid main (void)\n" + << "{\n" + << cur->local.str () + << "\n" + << cur->code.str () + << "}\n"; - vsh->end (); - vsh->compile (); + delete cur; + cur = 0; - fragment_shader fsh; + return os.str (); + } - fsh->start (); + void shader_object_i::compile (const string &source) + { + const char *sptr = source.data (); + const int slen = source.size (); - temp_1f spec_expon; - spec_expon = 200; + printf ("%s\n", linify (source).c_str ()); + glShaderSourceARB (id, 1, &sptr, &slen); + glCompileShaderARB (id); - fsh->end (); - fsh->compile (); + GLint compiled; + glGetObjectParameterivARB (id, GL_OBJECT_COMPILE_STATUS_ARB, &compiled); - abort (); + if (!compiled) + { + char infolog[8192]; + glGetInfoLogARB (id, 8192, NULL, infolog); + printf ("%s\n", linify (source).c_str ()); + printf ("%s\n", infolog); + abort (); + } } }