Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

glsl_shader.C

Go to the documentation of this file.
00001 /*****************************************************************
00002  * glsl_shader.C
00003  *
00004  *****************************************************************/
00005 #include "gtex/gl_extensions.H"
00006 #include "gtex/util.H"
00007 #include "geom/gl_util.H"
00008 #include "mesh/patch.H"
00009 #include "paper_effect.H"
00010 #include "glsl_shader.H"
00011 
00012 using namespace mlib;
00013 
00014 static bool debug = Config::get_var_bool("DEBUG_GLSL_SHADER", false);
00015 
00016 // the following tells whether GLSL is available via extensions
00017 // (e.g. in OpenGL 1.5). It will be initialized in init():
00018 static bool need_arb_ext = false;
00019 
00020 GLSLShader::GLSLShader(Patch* p, StripCB* cb) :
00021    BasicTexture(p, cb ? cb : new VertNormStripCB),
00022    _program(0),
00023    _did_init(false)
00024 {
00025 }
00026 
00027 GLSLShader::~GLSLShader()
00028 { 
00029    delete_program(_program);
00030 }
00031 
00032 void
00033 GLSLShader::delete_program(GLuint& prog)
00034 {
00035    if (prog == 0)
00036       return;
00037    if (need_arb_ext) {
00038       glDeleteObjectARB(prog);
00039    } else {
00040       glDeleteProgram(prog);
00041    }
00042    prog = 0;
00043 }
00044 
00045 void
00046 GLSLShader::print_shader_source(GLuint shader)
00047 {
00048    GLint src_len = 0;
00049    glGetObjectParameterivARB(shader, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB,
00050                              &src_len);
00051    if (src_len < 1) {
00052       cerr << "  source length is 0" << endl;
00053       return;
00054    }
00055    GLcharARB* buf = new GLcharARB [ src_len ];
00056    GLint chars_written = 0;
00057    glGetShaderSourceARB(shader, src_len, &chars_written, buf);
00058    cerr << buf << endl;
00059 }
00060 
00061 void
00062 GLSLShader::print_info(Cstr_ptr& gtex_name, GLuint obj)
00063 {
00064    cerr << gtex_name << ": print_info: checking object " << obj << endl;
00065    GLint log_len = 0;
00066    GL_VIEW::print_gl_errors(gtex_name + "::print_info:");
00067    glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_len);
00068    if (log_len < 1) {
00069       cerr << " print_info: log length is 0" << endl;
00070       return;
00071    }
00072    GLcharARB* buf = new GLcharARB [ log_len ];
00073    GLint chars_written = 0;
00074    glGetInfoLogARB(obj, log_len, &chars_written, buf);
00075    cerr << "info log: " << endl
00076         << buf << endl;
00077    delete buf;
00078 }
00079 
00080 bool
00081 GLSLShader::link_program(Cstr_ptr& gtex_name, GLuint prog)
00082 {
00083    GLint status = 0;
00084    if (need_arb_ext) {
00085       glLinkProgramARB(prog);
00086       glGetObjectParameterivARB(prog, GL_OBJECT_LINK_STATUS_ARB, &status);
00087    } else {
00088       glLinkProgram(prog);
00089       glGetProgramiv(prog, GL_LINK_STATUS, &status);
00090    }
00091    if (status != GL_TRUE)
00092       cerr << gtex_name << ": link_program: link failed" << endl;
00093 
00094    // print log messages about the error:
00095    const GLsizei BUF_SIZE = 4096;
00096    char info_log[BUF_SIZE] = {0};
00097    GLsizei len=0;
00098    if (need_arb_ext) {
00099       // todo...
00100    } else {
00101       glGetProgramInfoLog(prog, BUF_SIZE, &len, info_log);
00102    }
00103    cerr << gtex_name
00104         << ": ProgramInfoLog: "
00105         << endl
00106         << info_log
00107         << endl;
00108 
00109    if (debug && need_arb_ext) {
00110       glValidateProgramARB(prog);
00111       GLint ret = 0;
00112       glGetObjectParameterivARB(prog, GL_OBJECT_VALIDATE_STATUS_ARB, &ret);
00113       cerr << "program " << prog
00114            << " validation status: " << ret << endl;
00115       print_info(gtex_name, prog);
00116    }
00117    return (status == GL_TRUE);
00118 }
00119 
00120 bool
00121 GLSLShader::compile_shader(Cstr_ptr& gtex_name, GLuint shader)
00122 {
00123    GLint status = 0;
00124    if (need_arb_ext) {
00125       glCompileShaderARB(shader);
00126       glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
00127       if (debug)
00128          print_info(gtex_name, shader);
00129    } else {
00130       glCompileShader(shader);
00131       glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
00132    }
00133    return (status == GL_TRUE);
00134 }
00135 
00136 char*
00137 GLSLShader::read_file(
00138   Cstr_ptr& gtex_name,
00139   Cstr_ptr& filename,
00140   GLint& length
00141 )
00142 {
00143    // Read characters from file into buffer
00144    char* buf = 0;
00145    ifstream in(**filename, ifstream::in | ifstream::binary);
00146    if (in.is_open()) {
00147       in.seekg(0, ios::end);
00148       length = in.tellg();
00149       buf = new char[length + 1];
00150       memset(buf, 0, length + 1);
00151       in.seekg(0, ios::beg);
00152       in.read(buf, length);
00153       in.close();
00154    } else {
00155       cerr << gtex_name << "::read_file: could not read file: "
00156            << filename
00157            << endl;
00158    }
00159    return buf;
00160 }
00161 
00162 void
00163 GLSLShader::delete_shader(GLuint shader)
00164 {
00165    if (need_arb_ext) {
00166       glDeleteObjectARB(shader);
00167    } else {
00168       glDeleteShader(shader);
00169    }
00170 }
00171 
00172 void
00173 GLSLShader::delete_shaders(CARRAY<GLuint>& shaders)
00174 {
00175    for (int i=0; i<shaders.num(); i++)
00176       delete_shader(shaders[i]);
00177 }
00178 
00179 GLuint
00180 GLSLShader::load_shader(Cstr_ptr& gtex_name, Cstr_ptr& filename, GLenum type)
00181 {
00182    // Read characters from file into dynamically allocated buffer:
00183    GLint length = 0;
00184    char* buf = read_file(gtex_name, filename, length);
00185    if (!buf)
00186       return 0;
00187 
00188    // Allocate shader object, attach the source code, and compile:
00189    GLuint shader = 0;
00190    if (need_arb_ext) {
00191       shader = glCreateShaderObjectARB(type);
00192       glShaderSourceARB(shader, 1, (const GLcharARB**)&buf, &length);
00193    } else {
00194       shader = glCreateShader(type);
00195       glShaderSource(shader, 1, (const GLchar**)&buf, &length);
00196    }
00197    delete [] buf;
00198    if (compile_shader(gtex_name, shader)) {
00199       if (debug) {
00200          const GLsizei BUF_SIZE = 4096;
00201          char info_log[BUF_SIZE] = {0};
00202          GLsizei len;
00203          if (need_arb_ext) {
00204             glGetInfoLogARB(shader, BUF_SIZE, &len, info_log);
00205          } else {
00206             glGetShaderInfoLog(shader, BUF_SIZE, &len, info_log);
00207          }
00208          cerr << gtex_name
00209               << "ShaderInfoLog for shader: "
00210               << filename
00211               << endl
00212               << info_log
00213               << endl;
00214       }
00215       return shader;
00216    }
00217 
00218    // failed to compile
00219    cerr << gtex_name
00220         << "::load_shader: compile failed for file: "
00221         << filename
00222         << endl;
00223 
00224    // print log messages about the error:
00225    const GLsizei BUF_SIZE = 4096;
00226    char info_log[BUF_SIZE] = {0};
00227    GLsizei len=0;
00228    if (need_arb_ext) {
00229       glGetInfoLogARB(shader, BUF_SIZE, &len, info_log);
00230    } else {
00231       glGetShaderInfoLog(shader, BUF_SIZE, &len, info_log);
00232    }
00233    cerr << gtex_name << ": ShaderInfoLog: "
00234         << endl
00235         << info_log
00236         << endl;
00237 
00238    delete_shader(shader);
00239    return 0;
00240 }
00241 
00242 bool
00243 GLSLShader::load_shaders(
00244    Cstr_ptr& gtex_name,
00245    Cstr_list& filenames,
00246    ARRAY<GLuint>& shaders,
00247    GLenum type)
00248 {
00249    for (int i=0; i<filenames.num(); i++) {
00250       GLuint shader = load_shader(gtex_name, filenames[i], type);
00251       if (shader == 0) {
00252          cerr << gtex_name
00253               << "::load_shaders: failed to load file: "
00254               << filenames[i]
00255               << endl;
00256          // if one failed, delete them all:
00257          delete_shaders(shaders);
00258          return false;
00259       }
00260       if (debug && need_arb_ext) {
00261          cerr << gtex_name
00262               << ": print_shader_source: checking shader " << shader << endl;
00263 
00264          print_shader_source(shader);
00265       }
00266       shaders += shader;
00267    }
00268    // returns true even if the list of filenames is empty:
00269    return true; 
00270 }
00271 
00272 bool
00273 GLSLShader::attach_shaders(CARRAY<GLuint>& shaders, GLuint prog)
00274 {
00275    if (need_arb_ext) {
00276       for (int i=0; i<shaders.num(); i++)
00277          glAttachObjectARB(prog, shaders[i]);
00278    } else {
00279       for (int i=0; i<shaders.num(); i++)
00280          glAttachShader(prog, shaders[i]);
00281    }
00282    return true;
00283 }
00284 
00285 bool
00286 GLSLShader::init()
00287 {
00288    // Only do things once.
00289    if (did_init())
00290       return program() != 0;
00291    did_init() = true;
00292 
00293    if (GLEW_VERSION_2_0) {
00294       // In OpenGL 2.0, GLSL is available in the core spec
00295       if (debug) cerr << class_name() << "::init: OpenGL 2.0" << endl;
00296    } else if (GLEW_VERSION_1_5) {
00297       // In OpenGL 1.5, GLSL is available via extensions
00298       need_arb_ext = true;
00299       if (debug) cerr << class_name() << "::init: OpenGL 1.5" << endl;
00300    } else {
00301       // In earlier OpenGL GLSL is not available
00302       if (debug) cerr << class_name()
00303                       << "::init: pre-OpenGL 1.5: can't do GLSL" << endl;
00304       return false;
00305    }
00306 
00307    // Create the program object:
00308    if (need_arb_ext) {
00309       program() = glCreateProgramObjectARB();
00310    } else {
00311       GL_VIEW::print_gl_errors("GLSLShader::init");
00312       program() = glCreateProgram();
00313    }
00314 
00315    if (!program()) {
00316       // should never happen
00317       cerr << class_name() << "::init: error: glCreateProgram failed" << endl;
00318       return false;
00319    }
00320 
00321    // Read shaders from files, compile them, 
00322    // attach them to the program, and link...
00323    ARRAY<GLuint> shaders;
00324    GLenum vp, fp;
00325    if (need_arb_ext) {
00326       vp = GL_VERTEX_SHADER_ARB;
00327       fp = GL_FRAGMENT_SHADER_ARB;
00328    } else {
00329       vp = GL_VERTEX_SHADER;
00330       fp = GL_FRAGMENT_SHADER;
00331    }
00332 
00333    if (load_shaders(class_name(), vp_filenames(), shaders, vp) &&
00334        load_shaders(class_name(), fp_filenames(), shaders, fp) &&
00335        attach_shaders(shaders, program()) && bind_attributes(program()) &&
00336        link_program(class_name(), program())) {
00337 
00338       // query variable locations and store the results:
00339       activate_program();
00340       if (!get_variable_locs()) {
00341          // don't over-react to this; if the program is under development
00342          // and the variable is not yet used, we'll get that error,
00343          // but everything else should still work.
00344          cerr << class_name()
00345               << "::init: error: can't get variable locations." << endl
00346               << "This error might mean a variable is simply not used " << endl
00347               << "in your program, and otherwise nothing is actually wrong"
00348               << endl;
00349       }
00350       deactivate_program();
00351 
00352       // report success if debugging:
00353       if (debug)
00354          cerr << class_name() << "::init: loaded program" << endl;
00355       return true;
00356    }
00357 
00358    // Failure: delete program
00359    cerr << class_name() << "::init: could not load program" << endl;
00360    delete_program(program());
00361 
00362    return false;
00363 }
00364 
00365 void
00366 GLSLShader::use_program(GLuint prog)
00367 {
00368    if (need_arb_ext) {
00369       glUseProgramObjectARB(prog);
00370    } else {
00371       glUseProgram(prog);
00372    }
00373 }
00374 
00375 bool
00376 GLSLShader::get_uniform_loc(Cstr_ptr& var_name, GLint& loc) 
00377 {
00378    // wrapper for glGetUniformLocation, with error reporting
00379 
00380    loc = glGetUniformLocation(program(), **var_name);
00381    if (loc < 0) {
00382       cerr << class_name() << "::get_uniform_loc: error: variable "
00383            << "\"" << var_name << "\" not found"
00384            << endl;
00385       return false;
00386    }
00387    return true;
00388 }
00389 
00390 bool
00391 GLSLShader::load_texture(TEXTUREglptr& tex)
00392 {
00393    // Load the texture (should be already allocated TEXTUREgl
00394    // with filename set as member variable).
00395    //
00396    // Note: Does not activate the texture for use in the current frame.
00397    //
00398    // This is a no-op of the texture was previously loaded.
00399 
00400    if (!tex) {
00401       return false;
00402    } else if (tex->is_valid()) {
00403       return true;
00404    } else if (tex->load_attempt_failed()) {
00405       // we previously tried to load this texture and failed.
00406       // no sense trying again with the same filename.
00407       return false;
00408    }
00409 
00410    return tex->load_texture();
00411 }
00412 
00413 bool
00414 GLSLShader::activate_texture(TEXTUREglptr& tex)
00415 {
00416    // Load (if needed) and activate the texture.
00417 
00418    if (!load_texture(tex))
00419       return false;
00420    tex->apply_texture();
00421 
00422    return true;
00423 }
00424 
00425 void
00426 GLSLShader::set_gl_state(GLbitfield mask) const
00427 {
00428    // push GL state before changing things
00429    glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | mask);
00430 
00431    set_face_culling();                  // GL_ENABLE_BIT
00432 
00433    // set the color from the patch:
00434    if (_patch)
00435       GL_COL(_patch->color(), alpha());    // GL_CURRENT_BIT
00436 }
00437 
00438 void
00439 GLSLShader::restore_gl_state() const
00440 {
00441    glPopAttrib();
00442 }
00443 
00444 void 
00445 GLSLShader::set_ref_tex_shader()
00446 {
00447     _tex_ref_shader=0;
00448 }
00449 
00450 
00451 void 
00452 GLSLShader::use_ref_tex_shader()
00453 {
00454     //TODO: everything :P
00455 }
00456 
00457 int
00458 GLSLShader::draw(CVIEWptr& v)
00459 {
00460    GL_VIEW::print_gl_errors(class_name() + "::draw: start");
00461 
00462    // Ensure program is loaded:
00463    if (!init())
00464       return 0;
00465    assert(program());
00466 
00467    // Load textures (if any) and set their parameters.
00468    // This is a no-op after the first time.
00469    //
00470    // Q: Why not do it in the constructor?
00471    // A: Some textures get created but not drawn, so we
00472    //    prefer to wait until we're sure we need the textures
00473    //    before requesting resources from OpenGL.
00474    init_textures();
00475    if (debug)
00476       GL_VIEW::print_gl_errors(class_name() + "::draw: init textures");
00477 
00478    // call glPushAttrib() and set desired state 
00479    set_gl_state();
00480    if (debug)
00481       GL_VIEW::print_gl_errors(class_name() + "::draw: push attrib");
00482 
00483    // activate textures, if any:
00484    activate_textures(); // GL_ENABLE_BIT
00485    if (debug)
00486       GL_VIEW::print_gl_errors(class_name() + "::draw: activate textures");
00487 
00488    // activate program:
00489    activate_program();
00490    if (debug)
00491       GL_VIEW::print_gl_errors(class_name() + "::draw: activate program");
00492 
00493    // send values to uniform variables:
00494    set_uniform_variables();
00495    if (debug)
00496       GL_VIEW::print_gl_errors(class_name() + "::draw: set uniform variables");
00497 
00498 
00499    // use a display list:
00500    // execute display list if it's valid:
00501    if (BasicTexture::dl_valid(v)) {
00502       BasicTexture::draw(v);
00503    } else {
00504       // try to generate a display list
00505       int dl = _dl.get_dl(v, 1, _patch->stamp());
00506       if (dl)
00507          glNewList(dl, GL_COMPILE);
00508 
00509       // draw the triangle strips
00510       _patch->draw_tri_strips(_cb);
00511 
00512       // end the display list here
00513       if (_dl.dl(v)) {
00514          _dl.close_dl(v);
00515          BasicTexture::draw(v);
00516       }
00517    }
00518 
00519    if (debug)
00520       GL_VIEW::print_gl_errors(class_name() + "::draw: draw triangles");
00521 
00522    // restore gl state:
00523    restore_gl_state();
00524 
00525    if (debug)
00526       GL_VIEW::print_gl_errors(class_name() + "::draw: pop attrib");
00527 
00528    deactivate_program();
00529 
00530    GL_VIEW::print_gl_errors(class_name() + "::draw: end");
00531 
00532    return _patch->num_faces();
00533 }
00534 
00535 /**********************************************************************
00536  * GLSLLightingShader:
00537  *
00538  *   Does OpenGL lighting calculations in GLSL.
00539  **********************************************************************/
00540 GLuint GLSLLightingShader::_program = 0;
00541 bool   GLSLLightingShader::_did_init = false;
00542 
00543 GLSLLightingShader::GLSLLightingShader(Patch* p) :
00544    GLSLShader(p) 
00545 {
00546 }
00547 
00548 int
00549 GLSLLightingShader::draw(CVIEWptr& v)
00550 {
00551    // Set material parameters for OGL:
00552    GtexUtil::setup_material(_patch);
00553 
00554    // Execute the GLSL program:
00555    return GLSLShader::draw(v);
00556 }
00557 
00558 // end of file glsl_shader.C

Generated on Mon Sep 18 11:39:31 2006 for jot by  doxygen 1.4.4