#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; int refcnt; void refcnt_inc () { refcnt++; } void refcnt_dec () { if (!--refcnt) delete this; }; public: refcounted () : refcnt(0) { } virtual ~refcounted (); }; template class ref { data *p; public: ref (const data &d) { d.refcnt_inc (); p = &v; } ref (const ref &r) { r.refcnt_inc (); p = r.p; } ref &operator =(const data &d) { d.refcnt_inc (); p->refcnt_dec (); p = &r; return *this; } ref &operator =(const ref r) { return *this = *r->p; } ref operator &() { return *this; } const ref operator &() const { return *this; } ref *operator ->() { return p; } const ref *operator ->() const { return p; } bool operator ==(const ref b) { return p == b->p; } }; typedef ref var; typedef ref updateable; struct shader_builder { struct shader_program *prog; vector refs; // uniform parameters vector inputs; // varying inputs vector outputs; // varying outputs vector samplers; // textures ostringstream fragment; template shader_builder &operator <<(const type &t) { fragment << t; return *this; } }; struct fragment { virtual void build (shader_builder &b) = 0; }; struct var_i : fragment { static int next_name; CGparameter param; int name; void build (shader_builder &b); void build_decl (shader_builder &b); var_i (CGtype cgtype); ~var_i (); }; inline ostringstream &operator <<(ostringstream &os, const var_i &v) { os << ' ' << v.name << ' '; return os; } struct updateable_i : var_i { virtual void update () = 0; updateable_i (CGtype cgtype) : var_i (cgtype) { } }; template struct uniform_i : updateable_i { gltype data[dimension]; bool dirty; void update () { if (dirty) { update (param, data); dirty = false; } } uniform_i () : var_i (cgtype) { } }; template struct uniform_f_i : uniform_i { }; struct uniform_1f_i : uniform_f_i<1, cgGLSetParameter1fv> { void operator =(GLfloat v) { data[0] = v; dirty = true; } }; struct uniform_2f_i : uniform_f_i<2, cgGLSetParameter2fv> { }; struct uniform_3f_i : uniform_f_i<3, 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, 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, cgGLSetMatrixParameterfc> { }; typedef ref uniform_1f; typedef ref uniform_2f; typedef ref uniform_3f; typedef ref uniform_4f; typedef ref uniform_matrix_f; template struct varying_i : var_i { char binding[16]; varying_i (const char *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> { varying_1f_i (const char *binding) : varying_f_i<1> (binding) { } }; struct varying_2f_i : varying_f_i<2> { varying_2f_i (const char *binding) : varying_f_i<2> (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> { varying_3f_i (const char *binding) : varying_f_i<3> (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> { varying_4f_i (const char *binding) : varying_f_i<4> (binding) { } }; typedef ref varying_1f; typedef ref varying_2f; typedef ref varying_3f; typedef ref varying_4f; extern varying_3f_i position_3f; extern varying_3f_i normal_3f; extern varying_3f_i color0_3f; extern varying_3f_i color1_3f; extern varying_2f_i texcoord0_2f; extern varying_2f_i texcoord1_2f; extern varying_2f_i texcoord2_2f; extern varying_2f_i texcoord3_2f; extern varying_2f_i texcoord4_2f; extern varying_2f_i texcoord5_2f; extern varying_2f_i texcoord6_2f; extern varying_2f_i texcoord7_2f; extern varying_1f_i attr6_1f, attr7_1f; extern varying_2f_i attr6_2f, attr7_2f; extern varying_3f_i attr6_3f, attr7_3f; template struct sampler_i : var_i { sampler_i () : var_i (cgtype) { } }; struct shader_program { }; } 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 shader { 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); } } shader (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, shader { osama_material () : shader ("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