#ifndef MATERIAL_H #define MATERIAL_H #include #include #include #include "opengl.h" #include "util.h" namespace shader { using namespace std; const int NAMELEN = 16; 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 ->() { return p; } const type *operator ->() const { return p; } operator type &() { return *p; } operator const type &() const { return *p; } template bool operator ==(const ref b) const { return (void *)p == (void *)b.p; } }; extern const char str_float []; extern const char str_float2 []; extern const char str_float3 []; extern const char str_float4 []; extern const char str_float4x4 []; extern const char str_sampler1d []; extern const char str_sampler2d []; extern const char str_sampler3d []; extern const char str_samplerCUBE []; extern const char str_samplerRECT []; typedef ref var; typedef ref uniform; struct shader_builder { struct shader_program *prog; 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 var_i : fragment_i { static int next_name; CGparameter param; int name; 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) : var_i (cgtype, strtype), dirty (true) { } }; 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_float2, cgGLSetParameter2fv> { }; struct uniform_3f_i : uniform_f_i<3, str_float3, 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_float4, cgGLSetParameter4fv> { void operator =(const gl::matrix &m) { memcpy (data, m.data, 16 * sizeof (GLfloat)); dirty = true; } }; struct uniform_matrix_f_i : uniform_f_i<16, str_float4x4, cgGLSetMatrixParameterfc> { }; typedef ref uniform_1f; typedef ref uniform_2f; typedef ref uniform_3f; typedef ref uniform_4f; typedef ref uniform_matrix_f; struct stream_i : var_i { char binding[16]; 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 *binding) : stream_i (cgtype, strtype) { strcpy (this->binding, binding); } void set (GLsizei stride, GLvoid *ptr) { cgGLSetParameterPointer (param, dimension, gltype, stride, ptr); } }; template struct varying_f_i : varying_i { varying_f_i (const char *binding) : varying_i (binding) { } 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 *binding) : varying_f_i<1, str_float> (binding) { } }; struct varying_2f_i : varying_f_i<2, str_float2> { varying_2f_i (const char *binding) : varying_f_i<2, str_float2> (binding) { } 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_float3> { varying_3f_i (const char *binding) : varying_f_i<3, str_float3> (binding) { } 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_float4> { varying_4f_i (const char *binding) : varying_f_i<4, str_float4> (binding) { } }; template struct ref_varying : ref { ref_varying (const char *binding) : ref (*new class_i (binding)) { } }; typedef ref_varying varying_1f; typedef ref_varying varying_2f; typedef ref_varying varying_3f; typedef ref_varying varying_4f; extern struct vin { static varying_3f position_3f; static varying_4f position_4f; static varying_3f normal_3f; static varying_4f normal_4f; static varying_3f color0_3f; static varying_4f color0_4f; static varying_3f color1_3f; static varying_4f color1_4f; static varying_1f psize_1f; static varying_1f attr6_1f, attr7_1f; static varying_2f attr6_2f, attr7_2f; static varying_3f attr6_3f, attr7_3f; static varying_4f attr6_4f, attr7_4f; static varying_1f texcoord_1f[8]; static varying_2f texcoord_2f[8]; static varying_3f texcoord_3f[8]; static varying_4f texcoord_4f[8]; bool is (const var &r); } vin; extern struct fin { static varying_4f position_4f; static varying_4f color0_4f; static varying_4f color1_4f; static varying_4f texcoord_4f[8]; bool is (const var &r); } fin; extern struct fin &vout; extern struct fout { static varying_4f color0_4f; static varying_3f color0_3f; static varying_4f color1_4f; static varying_3f color1_3f; static varying_1f depth_1f; bool is (const var &r); } fout; // predefined globals extern uniform_matrix_f mvp, mv, proj; struct temporary_i : var_i { void build (shader_builder &b); temporary_i (CGtype cgtype, const char *strtype) : var_i (cgtype, 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_f; 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 sampler1d_i : sampler_i { sampler1d_i (GLuint texturename) : sampler_i (texturename) { } }; struct sampler2d_i : sampler_i { sampler2d_i (GLuint texturename) : sampler_i (texturename) { } }; struct sampler3d_i : sampler_i { sampler3d_i (GLuint texturename) : sampler_i (texturename) { } }; struct samplerCUBE_i : sampler_i { samplerCUBE_i (GLuint texturename) : sampler_i (texturename) { } }; struct samplerRECT_i : sampler_i { samplerRECT_i (GLuint texturename) : sampler_i (texturename) { } }; template struct sampler_ref : ref { sampler_ref (GLuint texturename) : ref (*new sampler_i (texturename)) { } }; typedef sampler_ref sampler1d; typedef sampler_ref sampler2d; typedef sampler_ref sampler3d; typedef sampler_ref samplerCUBE; typedef sampler_ref samplerRECT; 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); template fragment_vector_i &operator <<(ref &f) { push_back (f); return *this; } template fragment_vector_i &operator <<(fragment_i &f) { push_back (f); return *this; } fragment_vector_i &operator <<(const char *s) { push_back (*new fragment_const_string_i (s)); return *this; } }; typedef ref fragment_vector; struct shader_program : fragment_vector_i { bool is_vertex; void print (); shader_program (bool is_vertex) : is_vertex(is_vertex) { } }; struct vertex_program : shader_program { vertex_program () : shader_program (true) { } }; struct fragment_program : shader_program { fragment_program () : shader_program (false) { } }; 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