#ifndef SHADER_H #define SHADER_H #include #include "opengl.h" #include "util.h" namespace shader { using namespace std; const int NAMELEN = 32; template struct sl_expr { const T t; sl_expr (const T &t) : t(t) { } void operator ()() const { t (); } }; template struct sl_concat2 { const A a; const B b; sl_concat2 (const A &a, const B &b) : a(a), b(b) { } void operator ()() const { a (); b (); } }; template struct sl_concat3 { const A a; const B b; const C c; sl_concat3 (const A &a, const B &b, const C &c) : a(a), b(b), c(c) { } void operator ()() const { a (); b (); c (); } }; template struct sl_concat4 { const A a; const B b; const C c; const D d; sl_concat4 (const A &a, const B &b, const C &c, const D &d) : a(a), b(b), c(c), d(d) { } void operator ()() const { a (); b (); c (); d(); } }; class refcounted { template friend class ref; mutable int refcnt; void refcnt_inc () const { refcnt++; } void refcnt_dec () const { if (!--refcnt) delete this; }; public: refcounted () : refcnt(0) { } virtual ~refcounted (); }; template struct ref { type *p; ref () { p = new type; p->refcnt_inc (); } ref (type &d) { d.refcnt_inc (); p = &d; } ref (const ref &r) { r.p->refcnt_inc (); p = r.p; } template ref (const ref &r) { r.p->refcnt_inc (); p = r.p; } ~ref () { p->refcnt_dec (); } ref &operator =(type &d) { d.refcnt_inc (); p->refcnt_dec (); p = &d; return *this; } type *operator ->() const { return p; } operator type &() const { return *p; } template bool operator ==(const ref b) const { return (void *)p == (void *)b.p; } }; // ref with auto-construct template struct auto_ref0 : ref { auto_ref0 () : ref (*new type ()) { } }; template struct auto_ref1 : ref { auto_ref1 (arg1 a) : ref (*new type (a)) { } }; template struct auto_lvalue_ref0 : ref { auto_lvalue_ref0 () : ref (*new type ()) { } template const auto_lvalue_ref0 &operator =(const expr &e) const; }; template struct auto_lvalue_ref1 : ref { auto_lvalue_ref1 (arg1 a) : ref (*new type (a)) { } template const auto_lvalue_ref1 &operator =(const expr &e) const; }; extern const char str_float []; extern const char str_vec2 []; extern const char str_vec3 []; extern const char str_vec4 []; extern const char str_mat2 []; extern const char str_mat3 []; extern const char str_mat4 []; extern const char str_sampler_1d []; extern const char str_sampler_1d_shadow []; extern const char str_sampler_2d []; extern const char str_sampler_2d_shadow []; extern const char str_sampler_2d_rect []; extern const char str_sampler_2d_rect_shadow []; extern const char str_sampler_3d []; extern const char str_sampler_3d_rect []; extern const char str_sampler_cube []; typedef ref var; typedef ref uniform; struct shader_builder { vector refs; // uniform parameters vector temps; // temporary variables vector streams; // varying inputs & outputs ostringstream source; template shader_builder &operator <<(const type &t) { source << t; return *this; } }; struct fragment_i : refcounted { virtual void build (shader_builder &b) = 0; }; typedef ref fragment; struct lvalue_i : fragment_i { }; // a simple predeclared variable with unspecified type struct glvar_i : lvalue_i { const char *name; void build (shader_builder &b); glvar_i (const char *name) : name (name) { } }; typedef auto_lvalue_ref1 glvar; struct var_i : lvalue_i { static unsigned int next_id; char name[NAMELEN]; const char *typestr; void build (shader_builder &b); virtual void build_decl (ostringstream &b); var_i (const char *typestr); ~var_i (); }; struct uniform_i : var_i { bool dirty; virtual void update () = 0; void build (shader_builder &b); void build_decl (ostringstream &b); uniform_i (const char *strtype); }; template struct uniform2_i : uniform_i { gltype data[dimension]; void update () { if (dirty) { //upd (param, data); dirty = false; } } uniform2_i () : uniform_i (strtype) { } }; template struct uniform_f_i : uniform2_i { }; struct uniform_1f_i : uniform_f_i<1, str_float, cgGLSetParameter1fv> { void operator =(GLfloat v) { data[0] = v; dirty = true; } }; struct uniform_2f_i : uniform_f_i<2, str_vec2, cgGLSetParameter2fv> { }; struct uniform_3f_i : uniform_f_i<3, str_vec3, cgGLSetParameter3fv> { void operator =(const vec3 &v) { data[0] = v.x; data[1] = v.y; data[2] = v.z; dirty = true; } }; struct uniform_4f_i : uniform_f_i<4, str_vec4, cgGLSetParameter4fv> { #if 0 void operator =(const gl::matrix &m) { memcpy (data, m.data, 16 * sizeof (GLfloat)); dirty = true; } #endif }; struct uniform_matrix_2f_i : uniform_f_i< 4, str_mat2, cgGLSetMatrixParameterfc> { }; struct uniform_matrix_3f_i : uniform_f_i< 9, str_mat3, cgGLSetMatrixParameterfc> { }; struct uniform_matrix_4f_i : uniform_f_i<16, str_mat4, cgGLSetMatrixParameterfc> { }; template struct var_ref : ref { var_ref (const char *glname = 0) : ref (*new var_i) { if (glname) strcpy ((*this)->name, glname); } }; typedef var_ref uniform_1f; typedef var_ref uniform_2f; typedef var_ref uniform_3f; typedef var_ref uniform_4f; typedef var_ref uniform_matrix_2f; typedef var_ref uniform_matrix_3f; typedef var_ref uniform_matrix_4f; struct stream_i : var_i { void build (shader_builder &b); void build_decl (ostringstream &b); stream_i (const char *strtype) : var_i (strtype) { } }; template struct varying_i : stream_i { varying_i (const char *glname) : stream_i (strtype) { strcpy (name, glname); } void set (GLsizei stride, GLvoid *ptr) { //cgGLSetParameterPointer (param, dimension, gltype, stride, ptr); } }; template struct varying_f_i : varying_i { varying_f_i (const char *glname) : varying_i (glname) { } void set (const gl::vertex_buffer_object &vb, GLint offset) { varying_i::set (gl::format_stride (vb.format), (GLvoid *)(long)offset); } }; struct varying_1f_i : varying_f_i<1, str_float> { varying_1f_i (const char *glname) : varying_f_i<1, str_float> (glname) { } }; struct varying_2f_i : varying_f_i<2, str_vec2> { varying_2f_i (const char *glname) : varying_f_i<2, str_vec2> (glname) { } void set_t (const gl::vertex_buffer_object &vb) { set (vb, gl::format_offset_t (vb.format)); } }; struct varying_3f_i : varying_f_i<3, str_vec3> { varying_3f_i (const char *glname) : varying_f_i<3, str_vec3> (glname) { } void set_p (const gl::vertex_buffer_object &vb) { set (vb, gl::format_offset_p (vb.format)); } void set_n (const gl::vertex_buffer_object &vb) { set (vb, gl::format_offset_n (vb.format)); } }; struct varying_4f_i : varying_f_i<4, str_vec4> { varying_4f_i (const char *glname) : varying_f_i<4, str_vec4> (glname) { } }; typedef var_ref varying_1f; typedef var_ref varying_2f; typedef var_ref varying_3f; typedef var_ref varying_4f; struct temporary_i : var_i { void build (shader_builder &b); temporary_i (const char *strtype); }; template struct temp_ref : ref { temp_ref () : ref (*new temporary_i (strtype)) { } template const temp_ref &operator =(const expr &e) const; }; typedef temp_ref temp_1f; typedef temp_ref temp_2f; typedef temp_ref temp_3f; typedef temp_ref temp_4f; typedef temp_ref temp_matrix_2f; typedef temp_ref temp_matrix_3f; typedef temp_ref temp_matrix_4f; template struct sampler_i : uniform_i { GLuint texture; void update () { if (dirty) { //cgGLSetTextureParameter (param, texture); dirty = false; } } void begin () { cgGLEnableTextureParameter (texture); } sampler_i (GLuint texturename) : uniform_i (strtype), texture (texturename) { } }; struct sampler_1d_i : sampler_i { sampler_1d_i (GLuint texturename) : sampler_i (texturename) { } }; struct sampler_1d_shadow_i : sampler_i { sampler_1d_shadow_i (GLuint texturename) : sampler_i (texturename) { } }; struct sampler_2d_i : sampler_i { sampler_2d_i (GLuint texturename) : sampler_i (texturename) { } }; struct sampler_2d_shadow_i : sampler_i { sampler_2d_shadow_i (GLuint texturename) : sampler_i (texturename) { } }; struct sampler_2d_rect_i : sampler_i { sampler_2d_rect_i (GLuint texturename) : sampler_i (texturename) { } }; struct sampler_2d_rect_shadow_i : sampler_i { sampler_2d_rect_shadow_i (GLuint texturename) : sampler_i (texturename) { } }; struct sampler_3d_i : sampler_i { sampler_3d_i (GLuint texturename) : sampler_i (texturename) { } }; struct sampler_3d_rect_i : sampler_i { sampler_3d_rect_i (GLuint texturename) : sampler_i (texturename) { } }; struct sampler_cube_i : sampler_i { sampler_cube_i (GLuint texturename) : sampler_i (texturename) { } }; typedef auto_ref1 sampler_1d; typedef auto_ref1 sampler_1d_shadow; typedef auto_ref1 sampler_2d; typedef auto_ref1 sampler_2d_shadow; typedef auto_ref1 sampler_2d_rect; typedef auto_ref1 sampler_2d_rect_shadow; typedef auto_ref1 sampler_3d; typedef auto_ref1 sampler_3d_rect; typedef auto_ref1 sampler_cube; struct fragment_const_string_i : fragment_i { const char *str; void build (shader_builder &b); fragment_const_string_i (const char *str) : str(str) { } }; typedef auto_ref1 fragment_const_string; struct fragment_string_i : fragment_i { char *str; void build (shader_builder &b); fragment_string_i (const char *str) : str (strdup (str)) { } ~fragment_string_i (); }; struct fragment_vector_i : fragment_i, vector { void build (shader_builder &b); template void append (const ref &f) { push_back (f); } void append_const (const char *s) { push_back (*new fragment_const_string_i (s)); } void append_string (const char *s) { push_back (*new fragment_string_i (s)); } #if 0 fragment_vector_i &operator <<(statement_i &f) { push_back (*new fragment_const_string_i (" ")); for (vector::iterator i = f.begin (); i != f.end (); i++) push_back (*i); push_back (*new fragment_const_string_i (";\n")); return *this; } #endif }; typedef ref fragment_vector; struct shader_object_i : fragment_vector_i { GLenum type; GLuint id; // GLhandleARB, but 2.0 will use uint string source (); void compile (); void start (); void stop (); shader_object_i (GLenum type); ~shader_object_i (); }; extern shader_object_i *cur; // record actions to this shader template struct shader_object : ref { shader_object () : ref (*new shader_object_i (type)) { } }; typedef shader_object vertex_shader; typedef shader_object fragment_shader; void debdebdebdebug ();//D } #endif