#ifndef MATERIAL_H #define MATERIAL_H #include #include #include #include "opengl.h" #include "util.h" namespace shader { using namespace std; const int NAMELEN = 24; 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)) { } }; 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; // a simple predeclared variable with unspecified type struct glvar_i : fragment_i { const char *name; void build (shader_builder &b); glvar_i (const char *name) : name (name) { } }; typedef auto_ref1 glvar; struct var_i : fragment_i { static unsigned int next_id; CGparameter param; char name[NAMELEN]; const char *typestr; void build (shader_builder &b); virtual void build_decl (ostringstream &b); var_i (CGtype cgtype, 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 (CGtype cgtype, 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 (cgtype, 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> { }; typedef ref uniform_1f; typedef ref uniform_2f; typedef ref uniform_3f; typedef ref uniform_4f; typedef ref uniform_matrix_2f; typedef ref uniform_matrix_3f; typedef ref uniform_matrix_4f; struct stream_i : var_i { void build (shader_builder &b); void build_decl (ostringstream &b); stream_i (CGtype type, const char *strtype) : var_i (type, strtype) { } }; template struct varying_i : stream_i { varying_i (const char *glname) : stream_i (cgtype, 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 auto_ref1 varying_1f; typedef auto_ref1 varying_2f; typedef auto_ref1 varying_3f; typedef auto_ref1 varying_4f; extern struct vin { static varying_3f position_3f; static varying_4f position_4f; static varying_3f normal_3f; static varying_3f color_3f; static varying_4f color_4f; static varying_3f color2_3f; static varying_4f color2_4f; static varying_1f psize_1f; static varying_1f texcoord_1f[8]; static varying_2f texcoord_2f[8]; static varying_3f texcoord_3f[8]; static varying_4f texcoord_4f[8]; } vin; extern struct vout { // glstate builtin static glvar position; static glvar point_size; static glvar clip_vertex; // standard varying static glvar front_color; static glvar back_color; static glvar front_secondary_color; static glvar back_secondary_color; static glvar texcoord[8]; static glvar fog_frag_coord; } vout; extern struct fin { // glstate builtin static glvar frag_coord; // standard varying static glvar color; static glvar secondary_color; static glvar texcoord[8]; static glvar fog_frag_coord; } fin; extern struct fout { // glstate builtin static glvar frag_color; static glvar frag_depth; static glvar frag_data[2]; } fout; // predefined globals extern struct gl { static uniform_matrix_4f model_view_matrix, projection_matrix, model_view_projection_matrix, texture_matrix[8]; static uniform_matrix_4f model_view_matrix_inverse, projection_matrix_inverse, model_view_projection_matrix_inverse, texture_matrix_inverse[8]; static uniform_matrix_4f model_view_matrix_transpose, projection_matrix_transpose, model_view_projection_matrix_transpose, texture_matrix_transpose[8]; static uniform_matrix_4f model_view_matrix_inverse_transpose, projection_matrix_inverse_transpose, model_view_projection_matrix_inverse_transpose, texture_matrix_inverse_transpose[8]; static uniform_matrix_3f normal_matrix; static uniform_1f normal_scale; static uniform_1f depth_range_near, depth_range_far, depth_range_diff; static uniform_4f clip_plane[2];//TODO // point parameters TODO static uniform_4f front_material_emission, front_material_ambient, front_material_diffuse, front_material_specular, front_material_shininess; static uniform_4f back_material_emission, back_material_ambient, back_material_diffuse, back_material_specular, back_material_shininess; // light source parameters TODO static uniform_4f light_model_ambient; static uniform_4f front_light_model_product_scene_color; static uniform_4f back_light_model_product_scene_color; // light products TODO // texture env and gen TODO // fogparameters TODO // shader output are in vout and fout } gl; struct temporary_i : var_i { void build (shader_builder &b); temporary_i (CGtype cgtype, const char *strtype); }; template struct temp_ref : ref { temp_ref () : ref (*new temporary_i (cgtype, strtype)) { } }; 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 (cgtype, 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) { } }; struct fragment_vector_i : fragment_i, vector { void build (shader_builder &b); #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 statement_i : fragment_vector_i { void build (shader_builder &b); }; struct statement : ref { template statement (ref &f) : ref (*new statement_i) { p->push_back (f); } template const statement &operator <<(ref &f) const { p->push_back (f); return *this; } const statement &operator <<(const char *s) const { p->push_back (*new fragment_const_string_i (s)); return *this; } }; struct shader_object_i : fragment_vector_i { GLenum type; GLuint id; // GLhandleARB, but 2.0 will use uint string source (); void compile (); shader_object_i (GLenum type); ~shader_object_i (); }; template struct shader_object : ref { shader_object () : ref (*new shader_object_i (type)) { } const statement &operator <<(const statement &f) { p->push_back (f); return f; } }; typedef shader_object vertex_shader; typedef shader_object fragment_shader; void debdebdebdebug ();//D } struct texture_execption { texture_execption (string s) : msg(s) { } string msg; }; inline int power_of_two (int input) { int value = 1; while (value < input) { value <<= 1; } return value; } struct material { virtual void begin () = 0; virtual void end () = 0; virtual ~material (); }; struct simple_material : material { colour diffuse, specular, emission; GLfloat shininess; void begin (); void end (); simple_material () : diffuse(1, 0, 1, 1) , specular(1, 0, 1, 1) , emission(1, 0, 1, 1) , shininess(1.) { } }; struct texture { SDL_Surface *image; GLuint texture_pxls; GLfloat texcoord[4]; GLuint load_texture (SDL_Surface *surface, GLfloat *texcoord); texture(const char *f) { image = IMG_Load (f); if (!image) throw (texture_execption ("Couldn't load " + (string) f + ": " + (string) IMG_GetError ())); texture_pxls = load_texture (image, (GLfloat*)&texcoord); if (texture_pxls == 0) throw (texture_execption ("Couldn't make GL Texture, failed to create new RGB SWSurface")); } }; extern CGcontext cgc; struct xshader { CGprogram vsh, fsh; CGparameter lightpos; // mv, mvp CGprofile vsh_profile, fsh_profile; CGparameter g_Texture; // the texture parameter void check_cg_error (void) { CGerror err = cgGetError (); if (err != CG_NO_ERROR) { printf("CG error: %s\n", cgGetErrorString (err)); exit(1); } } xshader (const char *vshp, const char *fshp) { vsh_profile = CG_PROFILE_ARBVP1; //if (cgGLIsProfileSupported (CG_PROFILE_VP30)) vsh_profile = CG_PROFILE_VP30; //if (cgGLIsProfileSupported (CG_PROFILE_VP40)) vsh_profile = CG_PROFILE_VP40; fsh_profile = CG_PROFILE_ARBFP1; //if (cgGLIsProfileSupported (CG_PROFILE_FP30)) fsh_profile = CG_PROFILE_FP30; //if (cgGLIsProfileSupported (CG_PROFILE_FP40)) fsh_profile = CG_PROFILE_FP40; vsh = cgCreateProgramFromFile (cgc, CG_SOURCE, vshp, vsh_profile, 0, 0); check_cg_error (); cgGLLoadProgram (vsh); check_cg_error (); fsh = cgCreateProgramFromFile (cgc, CG_SOURCE, fshp, fsh_profile, 0, 0); check_cg_error (); cgGLLoadProgram (fsh); check_cg_error (); cgGLBindProgram (vsh); cgGLBindProgram (fsh); // mv = cgGetNamedParameter (vsh, "WorldProj"); // mvp = cgGetNamedParameter (vsh, "WorldViewProj"); //lightpos = cgGetNamedParameter (vsh, "LightPos"); //cgGLSetParameter4f (lightpos, 10, 10, 0, 1); //camera.p.x, camera.p.y, camera.p.z, 1); check_cg_error (); } }; struct osama_material : material, texture, xshader { osama_material () : xshader ("vsh.cg", "fsh.cg"), texture ("textures/osama.jpg") { g_Texture = cgGetNamedParameter(fsh, "Texture"); // the texture cg-warper ;) cgGLSetTextureParameter(g_Texture, texture_pxls); // Bind the texture number 999 to g_Texture } void begin (); void end (); }; void init_shaders (); #endif