OSGProgramChunk.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *               Copyright (C) 2000-2002 by the OpenSG Forum                 *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038
00039 //---------------------------------------------------------------------------
00040 //  Includes
00041 //---------------------------------------------------------------------------
00042
00043 #include <cstdlib>
00044 #include <cstdio>
00045 #include <boost/bind.hpp>
00046
00047 #include "OSGConfig.h"
00048
00049 #include "OSGGL.h"
00050 #include "OSGGLU.h"
00051 #include "OSGGLEXT.h"
00052
00053 #include "OSGBaseFunctions.h"
00054
00055 #include "OSGDrawEnv.h"
00056 #include "OSGWindow.h"
00057
00058 #include "OSGProgramChunk.h"
00059
00060 OSG_USING_NAMESPACE
00061
00062 // Documentation for this class is emited in the
00063 // OSGProgramChunkBase.cpp file.
00064 // To modify it, please change the .fcd file (OSGProgramChunk.fcd) and
00065 // regenerate the base file.
00066
00067 /***************************************************************************\
00068  *                           Class variables                               *
00069 \***************************************************************************/
00070
00071 StateChunkClass ProgramChunk::_class("Program");
00072
00073 UInt32 ProgramChunk::_funcGenPrograms              = Window::invalidFunctionID;
00074 UInt32 ProgramChunk::_funcProgramString            = Window::invalidFunctionID;
00075 UInt32 ProgramChunk::_funcBindProgram              = Window::invalidFunctionID;
00076 UInt32 ProgramChunk::_funcDeletePrograms           = Window::invalidFunctionID;
00077 UInt32 ProgramChunk::_funcProgramLocalParameter4fv = Window::invalidFunctionID;
00078 UInt32 ProgramChunk::_funcGetProgramiv             = Window::invalidFunctionID;
00079
00080 /***************************************************************************\
00081  *                           Class methods                                 *
00082 \***************************************************************************/
00083
00084 void ProgramChunk::initMethod(InitPhase ePhase)
00085 {
00086     Inherited::initMethod(ePhase);
00087
00088     if(ePhase == TypeObject::SystemPost)
00089     {
00090         UInt32 extension = Window::registerExtension("GL_ARB_vertex_program");
00091
00092         _funcGenPrograms                    =
00093             Window::registerFunction (OSG_DLSYM_UNDERSCORE"glGenProgramsARB",
00094                                       extension);
00095
00096         _funcProgramString                  =
00097             Window::registerFunction(OSG_DLSYM_UNDERSCORE"glProgramStringARB",
00098                                      extension);
00099         _funcBindProgram                    =
00100             Window::registerFunction(OSG_DLSYM_UNDERSCORE"glBindProgramARB",
00101                                      extension);
00102         _funcDeletePrograms                 =
00103             Window::registerFunction(OSG_DLSYM_UNDERSCORE"glDeleteProgramsARB",
00104                                      extension);
00105         _funcProgramLocalParameter4fv       =
00106             Window::registerFunction(OSG_DLSYM_UNDERSCORE
00107                                      "glProgramLocalParameter4fvARB",
00108                                      extension);
00109         _funcGetProgramiv       =
00110             Window::registerFunction(OSG_DLSYM_UNDERSCORE"glGetProgramivARB",
00111                                      extension);
00112     }
00113 }
00114
00115
00116 /***************************************************************************\
00117  *                           Instance methods                              *
00118 \***************************************************************************/
00119
00120 /*-------------------------------------------------------------------------*\
00121  -  private                                                                 -
00122 \*-------------------------------------------------------------------------*/
00123
00124 /*----------------------- constructors & destructors ----------------------*/
00125
00126 ProgramChunk::ProgramChunk(void) :
00127     Inherited()
00128 {
00129 }
00130
00131 ProgramChunk::ProgramChunk(const ProgramChunk &source) :
00132     Inherited(source)
00133 {
00134 }
00135
00136 ProgramChunk::~ProgramChunk(void)
00137 {
00138     if(getGLId() > 0)
00139         Window::destroyGLObject(getGLId());
00140 }
00141
00142 /*----------------------------- onCreate --------------------------------*/
00143
00144 void ProgramChunk::onCreate(const ProgramChunk *)
00145 {
00146     if(GlobalSystemState == Startup)
00147         return;
00148 }
00149
00150
00151 /*------------------------- Chunk Class Access ---------------------------*/
00152
00153 const StateChunkClass *ProgramChunk::getClass(void) const
00154 {
00155     return &_class;
00156 }
00157
00158 /*----------------------------- class specific ----------------------------*/
00159
00160 void ProgramChunk::changed(ConstFieldMaskArg whichField,
00161                            UInt32            origin,
00162                            BitVector         details)
00163 {
00164     Inherited::changed(whichField, origin, details);
00165
00166     if(whichField & ProgramFieldMask)
00167     {
00168         Window::reinitializeGLObject(getGLId());
00169     }
00170
00171     if(whichField & ParamValuesFieldMask)
00172     {
00173         Window::refreshGLObject(getGLId());
00174     }
00175 }
00176
00177 /*------------------------------ Output ----------------------------------*/
00178
00179 void ProgramChunk::dump(      UInt32    ,
00180                         const BitVector ) const
00181 {
00182     SLOG << "Dump ProgramChunk NI" << std::endl;
00183 }
00184
00185 /*---------------------------- Access ------------------------------------*/
00186
00189 bool ProgramChunk::read(const char *file)
00190 {
00191     std::ifstream s(file);
00192
00193     if(s.good())
00194     {
00195         return read(s);
00196     }
00197     else
00198     {
00199         FWARNING(("ProgramChunk::read: couldn't open '%s' for reading!\n",
00200                     file));
00201         return false;
00202     }
00203 }
00204
00208 bool ProgramChunk::read(std::istream &stream)
00209 {
00210 #define BUFSIZE 200
00211 
00212     editProgram().erase();
00213     char buf[BUFSIZE];
00214
00215     if(!stream.good())
00216     {
00217         FWARNING(("ProgramChunk::read: stream is not good!\n"));
00218         return false;
00219
00220     }
00221
00222     do
00223     {
00224         stream.read(buf, BUFSIZE);
00225         editProgram().append(buf, stream.gcount());
00226     }
00227     while(!stream.eof());
00228
00229     return true;
00230 }
00231
00234 bool ProgramChunk::addParameter(const char   *name,
00235                                       Int16  index)
00236 {
00237     if(index < 0)
00238         return true;
00239
00240     if(getMFParamNames()->size() <= UInt16(index))
00241     {
00242         editMFParamNames()->resize(index + 1);
00243     }
00244
00245     editParamNames(index) = name;
00246
00247     return false;
00248 }
00249
00250 const Vec4f ProgramChunk::getParameter(Int16 index)
00251 {
00252     static const Vec4f bad(-1e10,-1e10,-1e10);
00253
00254     if(index < 0)
00255         return bad;
00256
00257     if(getMFParamValues()->size() <= UInt16(index))
00258     {
00259         return getParamValues(index);
00260     }
00261
00262     return bad;
00263 }
00264
00267 bool ProgramChunk::setParameter(Int16 index, const Vec4f& value)
00268 {
00269     if(index < 0)
00270         return true;
00271
00272     if(getMFParamValues()->size() <= UInt16(index))
00273     {
00274         editMFParamValues()->resize(index + 1);
00275     }
00276
00277     editParamValues(index) = value;
00278
00279     return false;
00280 }
00281
00284 Int16 ProgramChunk::findParameter(const std::string &name)
00285 {
00286     MField<std::string>::const_iterator it;
00287
00288     it = std::find(getMFParamNames()->begin(),
00289                    getMFParamNames()->end(), name);
00290
00291     if(it == getMFParamNames()->end())
00292         return -1;
00293
00294     return it - getMFParamNames()->begin();
00295 }
00296
00297
00298 /*------------------------------ State ------------------------------------*/
00299
00302 void ProgramChunk::printCompileError(Window *win, UInt32 id)
00303 {
00304     GLint pos;
00305     glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
00306
00307     FWARNING(("ProgramChunk(%p:%d): error compiling program "
00308               "at position %d: %s\n",
00309               win, id, pos, glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
00310
00311     UInt32 start = 0, end, line = 0;
00312
00313     for(end = 0; end < getProgram().size(); ++end)
00314     {
00315         if(getProgram()[end] == '\n')
00316         {
00317             ++line;
00318
00319             if(UInt32(pos) < end)
00320                 break;
00321
00322             start = end + 1;
00323         }
00324     }
00325
00326     std::string mesg;
00327
00328     for(UInt32 i = start; i < end; ++i)
00329     {
00330         if(i == UInt32(pos))
00331         {
00332             mesg += '>';
00333             mesg += '>';
00334         }
00335
00336         mesg += getProgram()[i];
00337
00338         if(i == UInt32(pos))
00339         {
00340             mesg += '<';
00341             mesg += '<';
00342         }
00343     }
00344
00345     SWARNING << "Location (line " << line << "): " << mesg << endLog;
00346 }
00347
00351 void ProgramChunk::handleGL(DrawEnv *pEnv, UInt32 osgid,
00352                     Window::GLObjectStatusE mode,
00353                     GLenum target,
00354                     UInt32 extension)
00355 {
00356     GLuint id;
00357     Window *win = pEnv->getWindow();
00358
00359     // get the program-specific specifics from the derived chunks
00360     //GLenum target = getTarget();
00361     //UInt32 extension = getExtension();
00362
00363     if(!win->hasExtension(extension))
00364         return;
00365
00366     id = win->getGLObjectId(osgid);
00367
00368     if(mode == Window::initialize || mode == Window::reinitialize ||
00369        mode == Window::needrefresh)
00370     {
00371         if(mode == Window::initialize)
00372         {
00373             // get "glGenProgramsARB" function pointer
00374             void (OSG_APIENTRY* genPrograms)(GLsizei n, GLuint *prog) =
00375                 reinterpret_cast<void (OSG_APIENTRY*)(GLsizei n, GLuint *prog)>(
00376                     win->getFunction(_funcGenPrograms));
00377
00378             genPrograms(1, &id);
00379             win->setGLObjectId(osgid, id);
00380         }
00381
00382         // get "glBindProgramARB" function pointer
00383         void (OSG_APIENTRY* bindProgram)(GLenum target, GLuint prog) =
00384             reinterpret_cast<void (OSG_APIENTRY*)(GLenum target, GLuint prog)>(
00385                 win->getFunction(_funcBindProgram));
00386
00387         glErr("ProgramChunk::handleGL: bindProgram precheck");
00388
00389         bindProgram(target, id);
00390
00391         glErr("ProgramChunk::handleGL: bindProgram postcheck");
00392
00393         if(mode != Window::needrefresh)
00394         {
00395             // get "glProgramStringARB" function pointer
00396             void (OSG_APIENTRY* programString)(GLenum target,
00397                                                GLenum format,
00398                                                GLsizei lesn,
00399                                                const void *string) =
00400                 reinterpret_cast<void (OSG_APIENTRY*)(GLenum target,
00401                                                       GLenum format,
00402                                                       GLsizei len,
00403                                                       const void *string)>(
00404                     win->getFunction(_funcProgramString));
00405
00406             glErr("ProgramChunk::handleGL: programString precheck");
00407
00408             glEnable(target);
00409
00410             glErr("ProgramChunk::handleGL: enable postcheck");
00411
00412             programString(target, GL_PROGRAM_FORMAT_ASCII_ARB,
00413                             getProgram().size(), getProgram().c_str());
00414
00415             GLenum err = glGetError();
00416
00417             if(err == GL_INVALID_OPERATION)
00418             {
00419                 printCompileError(win, osgid);
00420             }
00421             else if (err != GL_NO_ERROR)
00422             {
00423                 SWARNING << "ProgramChunk::programString postcheck failed:"
00424                          << gluErrorString(err) << endLog;
00425             }
00426
00427             glDisable(target);
00428
00429             glErr("ProgramChunk::handleGL: disable postcheck");
00430         }
00431
00432         void (OSG_APIENTRY* programLocalParameter4fv)(GLenum target,
00433                         GLuint index, const GLfloat *params) =
00434             reinterpret_cast<void (OSG_APIENTRY*)(GLenum target,
00435                                                   GLuint index,
00436                                                   const GLfloat *params)>(
00437                 win->getFunction(_funcProgramLocalParameter4fv));
00438
00439         glErr("ProgramChunk::handleGL: programLocalParameter precheck");
00440
00441         for(UInt16 i = 0; i < getMFParamValues()->size(); ++i)
00442         {
00443             const Vec4f &val = _mfParamValues[i];
00444
00445             programLocalParameter4fv(target, i, val.getValues());
00446
00447             glErr("ProgramChunk::handleGL: programLocalParameter");
00448         }
00449
00450         glErr("ProgramChunk::handleGL: programLocalParameter postcheck");
00451     }
00452     else
00453     {
00454         SWARNING << "ProgramChunk(" << this << "::handleGL: Illegal mode: "
00455              << mode << " for id " << id << std::endl;
00456     }
00457
00458 }
00459
00463 void ProgramChunk::handleDestroyGL(DrawEnv *pEnv, UInt32 osgid,
00464                     Window::GLObjectStatusE mode,
00465                     GLenum Target,
00466                     UInt32 extension)
00467 {
00468     GLuint id;
00469     Window *win = pEnv->getWindow();
00470
00471     // get the program-specific specifics from the derived chunks
00472     //GLenum target = getTarget();
00473     //UInt32 extension = getExtension();
00474
00475     if(!win->hasExtension(extension))
00476         return;
00477
00478     id = win->getGLObjectId(osgid);
00479
00480     if(mode == Window::destroy)
00481     {
00482         // get "glDeleteProgramsARB" function pointer
00483         void (OSG_APIENTRY* deletePrograms)(GLsizei num, const GLuint *progs) =
00484             reinterpret_cast<void (OSG_APIENTRY*)(GLsizei num,
00485                                                   const GLuint *progs)>(
00486                 win->getFunction(_funcDeletePrograms));
00487
00488         deletePrograms(1, &id);
00489
00490         win->setGLObjectId(osgid, 0);
00491     }
00492     else if(mode == Window::finaldestroy)
00493     {
00494         //SWARNING << "Last program user destroyed" << std::endl;
00495     }
00496     else
00497     {
00498         SWARNING << "ProgramChunk" << "::handleDestroyGL: Illegal mode: "
00499              << mode << " for id " << id << std::endl;
00500     }
00501
00502 }
00503
00504 void ProgramChunk::activate(DrawEnv *pEnv, UInt32)
00505 {
00506     // get the program-type specifics from the derived chunks
00507     GLenum target = getTarget();
00508     UInt32 extension = getExtension();
00509
00510     if(!pEnv->getWindow()->hasExtension(extension))
00511     {
00512         return;
00513     }
00514
00515     if(getProgram().empty())
00516         return;
00517
00518     pEnv->getWindow()->validateGLObject(getGLId(), pEnv);
00519
00520     // get "glBindProgramARB" function pointer
00521     void (OSG_APIENTRY* bindProgram)(GLenum target, GLuint prog) =
00522         reinterpret_cast<void (OSG_APIENTRY*)(GLenum target, GLuint prog)>(
00523             pEnv->getWindow()->getFunction(_funcBindProgram));
00524
00525     glErr("ProgramChunk::activate: bindProgram precheck");
00526
00527     glEnable(target);
00528
00529     glErr("ProgramChunk::activate: enable postcheck");
00530
00531     bindProgram(target, pEnv->getWindow()->getGLObjectId(getGLId()));
00532
00533     glErr("ProgramChunk::activate: bindProgram postcheck");
00534 }
00535
00536 void ProgramChunk::changeFrom(DrawEnv    *pEnv,
00537                               StateChunk  *old_chunk,
00538                               UInt32                )
00539 {
00540     ProgramChunk *old = dynamic_cast<ProgramChunk *>(old_chunk);
00541
00542     if(old == NULL)
00543     {
00544         FWARNING(( "ProgramChunk::changeFrom: caught non-ProgramChunk!\n"));
00545         return;
00546     }
00547
00548     // get the program-type specifics from the derived chunks
00549     GLenum target = getTarget();
00550     UInt32 extension = getExtension();
00551
00552     if(!pEnv->getWindow()->hasExtension(extension))
00553         return;
00554
00555     if(getProgram().empty())
00556     {
00557         if(old->getProgram().empty())
00558             return;
00559
00560         glDisable(target);
00561     }
00562
00563     pEnv->getWindow()->validateGLObject(getGLId(), pEnv);
00564
00565     // get "glBindProgramARB" function pointer
00566     void (OSG_APIENTRY* bindProgram)(GLenum target, GLuint prog) =
00567         reinterpret_cast<void (OSG_APIENTRY*)(GLenum target, GLuint prog)>(
00568             pEnv->getWindow()->getFunction(_funcBindProgram));
00569
00570     glErr("ProgramChunk::changeFrom: bindProgram precheck");
00571
00572     if(old->getProgram().empty())
00573         glEnable(target);
00574
00575     glErr("ProgramChunk::changeFrom: enable postcheck");
00576
00577     bindProgram(target, pEnv->getWindow()->getGLObjectId(getGLId()));
00578
00579     glErr("ProgramChunk::changeFrom: bindProgram postcheck");
00580 }
00581
00582 void ProgramChunk::deactivate(DrawEnv *pEnv, UInt32)
00583 {
00584     // get the program-type specifics from the derived chunks
00585     GLenum target = getTarget();
00586     UInt32 extension = getExtension();
00587
00588     if(!pEnv->getWindow()->hasExtension(extension))
00589     {
00590         return;
00591     }
00592
00593     if(getProgram().empty())
00594     {
00595         return;
00596     }
00597
00598     // get "glBindProgramARB" function pointer
00599     void (OSG_APIENTRY* bindProgram)(GLenum target, GLuint prog) =
00600         reinterpret_cast<void (OSG_APIENTRY*)(GLenum target, GLuint prog)>(
00601             pEnv->getWindow()->getFunction(_funcBindProgram));
00602
00603
00604     glErr("ProgramChunk::deactivate: bindProgram precheck");
00605
00606     bindProgram(target, pEnv->getWindow()->getGLObjectId(getGLId()));
00607
00608     glErr("ProgramChunk::deactivate: bindProgram postcheck");
00609
00610     glDisable(target);
00611
00612     glErr("ProgramChunk::deactivate: disable postcheck");
00613 }
00614
00615
00621 UInt32 ProgramChunk::getExtension(void) const
00622 {
00623     FWARNING(( "ProgramChunk::getExtension called!\n" ));
00624     return 0;
00625 }
00626
00631 GLenum ProgramChunk::getTarget(void) const
00632 {
00633     FWARNING(( "ProgramChunk::getTarget called!\n" ));
00634     return 0;
00635 }
00636
00637
00642 const char *ProgramChunk::getTargetName(void) const
00643 {
00644     FWARNING(( "ProgramChunk::getTargetName called!\n" ));
00645     return "ERROR";
00646 }
00647
00648 /*-------------------------- Comparison -----------------------------------*/
00649
00650 bool ProgramChunk::isTransparent(void) const
00651 {
00652     return false;
00653 }
00654
00655 Real32 ProgramChunk::switchCost(StateChunk *)
00656 {
00657     return 0;
00658 }
00659
00660 bool ProgramChunk::operator < (const StateChunk &other) const
00661 {
00662     return this < &other;
00663 }
00664
00665 bool ProgramChunk::operator == (const StateChunk &other) const
00666 {
00667     ProgramChunk const *tother = dynamic_cast<ProgramChunk const*>(&other);
00668
00669     if(!tother)
00670         return false;
00671
00672     if(tother == this)
00673         return true;
00674
00675     if(getProgram()               != tother->getProgram      ()         ||
00676        getMFParamValues()->size() != tother->getMFParamValues()->size() ||
00677        getMFParamNames()->size()  != tother->getMFParamNames ()->size()  )
00678         return false;
00679
00680     // !!! FIXME: implement    
00681
00682     return false;
00683 }
00684
00685 bool ProgramChunk::operator != (const StateChunk &other) const
00686 {
00687     return ! (*this == other);
00688 }
00689