arbeit
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

PShaderTxt.cpp

Go to the documentation of this file.
00001 //------------------------------------------------------------------------
00002 //
00003 //   Joe Kniss
00004 //     7-15-03
00005 //                   ________    ____   ___ 
00006 //                  |        \  /    | /  /
00007 //                  +---+     \/     |/  /
00008 //                  +--+|  |\    /|     < 
00009 //                  |  ||  | \  / |  |\  \ 
00010 //                  |      |  \/  |  | \  \ 
00011 //                   \_____|      |__|  \__\
00012 //                       Copyright  2003 
00013 //                      Joe Michael Kniss
00014 //                   <<< jmk@cs.utah.edu >>>
00015 //               "All Your Base are Belong to Us"
00016 //-------------------------------------------------------------------------
00017 
00018 
00019 // PShaderTxt.cpp
00020 
00021 #include "PShaderTxt.h"
00022 
00023 #include <qlayout.h>
00024 #include <qmessagebox.h>
00025 #include <iostream>
00026 #include <sstream>
00027 #include <fstream>
00028 #include <stateGlift.h>
00029 
00030 using namespace std;
00031 using namespace glift;
00032 
00033 PShaderTxt::PShaderTxt(const QGLContext *ctx, QWidget *parent, const char *name, WFlags wf)
00034 : QWidget(parent, name, wf), 
00035   _stype(NOT_LOADED), 
00036   _shader(0),
00037   _fpshader(0),
00038   _vpshader(0),
00039   _ctx(ctx),
00040   _errw(0)
00041 {
00042     QHBoxLayout *topLayout = new QHBoxLayout( this, 2 );
00043 
00044     _mle = new QMultiLineEdit( this, "shader text editor" );
00045     topLayout->addWidget(_mle);
00046     _mle->setWordWrap( QMultiLineEdit::WidgetWidth );
00047     _mle->setText("");
00048     _errw = new ErrTxtWin("",0,"a text error window");
00049     _errw->resize(512,768);
00050     _errw->setCaption("Programmable Shader Error");
00051 }
00052 
00053 PShaderTxt::~PShaderTxt()
00054 {
00055 
00056 }
00057 
00058 //////////////////////////////////////////////////////////////////////////
00059 /// load Shader
00060 //////////////////////////////////////////////////////////////////////////
00061 QString PShaderTxt::getFileName()
00062 {
00063    if(_shader.isNull())
00064       return QString("No Shader");
00065 
00066    switch(_stype) {
00067    case ARB_FP:
00068       if(_fpshader->getProgFile())
00069          return QString(_fpshader->getProgFile());
00070       else
00071       break;
00072    case ARB_VP:
00073       if(_fpshader->getProgFile())
00074          return QString(_fpshader->getProgFile());
00075       break;
00076    }
00077 
00078    return QString("Not Saved");
00079 }
00080 
00081 
00082 //////////////////////////////////////////////////////////////////////////
00083 //////////////////////////////////////////////////////////////////////////
00084 /// Public slots
00085 //////////////////////////////////////////////////////////////////////////
00086 //////////////////////////////////////////////////////////////////////////
00087 
00088 //////////////////////////////////////////////////////////////////////////
00089 /// load Shader
00090 //////////////////////////////////////////////////////////////////////////
00091 void PShaderTxt::loadShader()
00092 {
00093    /// for capturing errors
00094    int errpos = -1;
00095    string fperr;
00096    ostringstream oss;
00097    ostream *ossave;
00098    
00099    ///make the gl context current for loading
00100    /// might be dangerous
00101    const_cast<QGLContext*>(_ctx)->makeCurrent();
00102 
00103    ///do the right thing for each type
00104    switch(_stype)
00105    {
00106    case ARB_FP:
00107       /// save off old error stream
00108       ossave = _fpshader->getErrStream();
00109       /// capture init errors
00110       _fpshader->setErrStream(&oss);
00111       /// load the changed shader
00112       _fpshader->reload(_mle->text().ascii());
00113       /// return the default error stream
00114       _fpshader->setErrStream(ossave);
00115       /// handle any errors
00116       fperr = oss.str();
00117       /// launch error, if there is one
00118       _errw->maybeError(fperr.c_str());
00119       /// be nice and mark where it happened
00120       if( (errpos = getErrorPos(fperr)) > -1 )
00121       {
00122          _errw->markSelection(errpos);
00123       }
00124 
00125       break;
00126    case ARB_VP:
00127       /// save off old error stream
00128       ossave = _vpshader->getErrStream();
00129       /// capture init errors
00130       _vpshader->setErrStream(&oss);
00131       _vpshader->reload(_mle->text().ascii());
00132       _vpshader->setErrStream(ossave);
00133       fperr = oss.str();
00134       /// launch error, if there is one
00135       _errw->maybeError(fperr.c_str());
00136       if( (errpos = getErrorPos(fperr)) > -1 )
00137       {
00138          _errw->markSelection(errpos);
00139       }
00140 
00141       break;
00142 
00143    }
00144 }
00145 
00146 //////////////////////////////////////////////////////////////////////////
00147 /// load shader, from glift shader
00148 //////////////////////////////////////////////////////////////////////////
00149 void PShaderTxt::loadShader(glift::ProgShaderSP shader)
00150 {
00151    if((_stype != NOT_LOADED) || (!_shader.isNull()))
00152    {
00153       cerr << "PShaderTxt::loadShader(), Shader already loaded!!!" << endl;
00154       return;
00155    }
00156 
00157    if(shader.isNull())
00158    {
00159       cerr << "PShaderTxt::loadShader(), Shader is null!!!" << endl;
00160       return;   
00161    }
00162 
00163    _shader = shader;
00164    if(castShader())
00165    {      
00166       cerr << "PShaderTxt::loadShader(), Shader type not supported" << endl;
00167       return;
00168    }
00169 
00170    /// set the text for editing
00171    switch(_stype){
00172    case ARB_FP:
00173       _mle->setText(QString(_fpshader->getProgText()));
00174       break;
00175    case ARB_VP:
00176       _mle->setText(QString(_vpshader->getProgText()));
00177       break;
00178    }
00179 
00180    loadShader();
00181 }
00182 
00183 
00184 //////////////////////////////////////////////////////////////////////////
00185 /// load Shader from file
00186 //////////////////////////////////////////////////////////////////////////
00187 void PShaderTxt::loadShaderFromFile(const QString &fname)
00188 {
00189    if((_stype != NOT_LOADED) || (!_shader.isNull()))
00190    {
00191       cerr << "PShaderTxt::loadShaderFromFile(), Shader already loaded!!!" << endl;
00192       return;
00193    }
00194 
00195    if(fname.isEmpty())
00196    {
00197       cerr << "PShaderTxt::loadShaderFromFile(), No file name given" << endl;
00198       return;
00199    }
00200 
00201    /// check the context to see if we can do anything
00202    if((!_ctx) || (!_ctx->isValid()))
00203    {
00204       cerr << "PShaderTxt::loadShaderFromFile(), Invalid gl context" << endl;
00205       return;
00206    }
00207 
00208    ///make the gl context current for loading
00209    const_cast<QGLContext*>(_ctx)->makeCurrent();
00210 
00211    /// capture error stream...
00212    ostringstream oss;
00213    /// generate shader using glift shader factory function
00214    _shader = glift::getProgShaderFromFile(fname, (ostream*)&oss);
00215    /// launch error if there is one
00216    _errw->launchError(oss.str().c_str());
00217    /// mark where it happened
00218    int errpos = -1;
00219    if( (errpos = getErrorPos(oss.str())) > -1 )
00220    {
00221       _errw->markSelection(errpos);
00222    }
00223 
00224    /// figure out what kind of shader it was
00225    if(castShader())
00226    {
00227       cerr << "PShaderTxt::loadShaderFromFile(), shader type not supported" << endl;   
00228    }
00229 
00230    /// set the text for editing
00231    switch(_stype){
00232    case ARB_FP:
00233       _mle->setText(QString(_fpshader->getProgText()));
00234       break;
00235    case ARB_VP:
00236       _mle->setText(QString(_vpshader->getProgText()));
00237       break;
00238    }
00239 }
00240 
00241 //////////////////////////////////////////////////////////////////////////
00242 /// load Shader from text
00243 //////////////////////////////////////////////////////////////////////////
00244 void PShaderTxt::loadShaderFromText(const QString &text)
00245 {
00246    if((_stype != NOT_LOADED) || (!_shader.isNull()))
00247    {
00248       cerr << "PShaderTxt::loadShaderFromText(), Shader already loaded!!!" << endl;
00249       return;
00250    }
00251    
00252    if(text.isEmpty())
00253    {      
00254       cerr << "PShaderTxt::loadShaderFromText(), No Shader to load" << endl;
00255       return;
00256    }
00257 
00258    ///make the gl context current for loading
00259    const_cast<QGLContext*>(_ctx)->makeCurrent();
00260 
00261    /// capture error stream...
00262    ostringstream oss;
00263    /// generate shader using glift shader factory function
00264    _shader = glift::getProgShaderFromText(text, (ostream*)&oss);
00265    /// launch error if there is one
00266    _errw->launchError(oss.str().c_str());
00267    /// mark where it happened
00268    int errpos = -1;
00269    if( (errpos = getErrorPos(oss.str())) > -1 )
00270    {
00271       _errw->markSelection(errpos);
00272    }
00273 
00274    /// figure out what kind of shader it was
00275    if(castShader())
00276    {
00277       cerr << "PShaderTxt::loadShaderFromFile(), shader type not supported" << endl;   
00278    }
00279 
00280    /// setup the text editor
00281    _mle->setText(text);
00282 }
00283 
00284 
00285 //////////////////////////////////////////////////////////////////////////
00286 /// save shader
00287 //////////////////////////////////////////////////////////////////////////
00288 void PShaderTxt::saveShader(const QString &lastPath)
00289 {
00290    QString s;
00291    ofstream of;
00292    
00293    if(_mle->isModified())
00294       loadShader();
00295 
00296    switch(_stype)
00297    {
00298    case ARB_FP:
00299       if(_fpshader.isNull())
00300       {
00301          cerr << "PShaderTxt::saveShader(), null fpshader" << endl;
00302          return;
00303       }
00304  
00305       /// nothing to save?
00306       if(!_fpshader->getProgText()) return;
00307 
00308       /// do we have a name?
00309       if(!_fpshader->getProgFile())
00310       {
00311          s = QFileDialog::getSaveFileName( lastPath, "Shaders (*.fp *.txt)");
00312          if(QString::null == s)
00313             return;
00314          _fpshader->setProgFile(s.ascii());
00315       }
00316       else /// use it's given name
00317       {
00318          s = _fpshader->getProgFile();
00319       }
00320       of.open(s.ascii(), ios::binary);
00321       if(of.bad())
00322       {
00323          _errw->launchError( "failed to open " + s + " for writing \n" );
00324          of.close();
00325          return;
00326       }
00327 
00328       of.write(_fpshader->getProgText(), strlen(_fpshader->getProgText()));
00329       
00330       if(of.bad())
00331       {
00332          _errw->launchError( "error writing " + s + "\n" );
00333          of.close();
00334          return;
00335       }
00336 
00337       of.close();
00338       _mle->setModified(false);
00339       return;
00340 
00341       break;
00342    case ARB_VP:
00343       if(_vpshader.isNull())
00344       {
00345          cerr << "PShaderTxt::saveShader(), null vpshader" << endl;
00346          return;
00347       }
00348       /// nothing to save?
00349       if(!_vpshader->getProgText()) return;
00350 
00351       /// do we have a name?
00352       if(!_vpshader->getProgFile())
00353       {
00354          s = QFileDialog::getSaveFileName( lastPath, "Shaders (*.vp *.txt)");
00355          if(QString::null == s)
00356             return;
00357          _vpshader->setProgFile(s.ascii());
00358       }
00359       else
00360       {
00361          s = _vpshader->getProgFile();
00362       }
00363 
00364       of.open(s.ascii(), ios::binary);
00365       if(of.bad())
00366       {
00367          _errw->launchError( "failed to open " + s + " for writing \n" );
00368          of.close();
00369          return;
00370       }
00371 
00372       of.write(_vpshader->getProgText(), strlen(_vpshader->getProgText()));
00373       
00374       if(of.bad())
00375       {
00376          _errw->launchError( "error writing " + s + "\n" );
00377          of.close();
00378          return;
00379       }
00380 
00381       of.close();
00382       _mle->setModified(false);
00383       return;
00384       break;
00385    }
00386 }
00387 
00388 //////////////////////////////////////////////////////////////////////////
00389 /// save shader as
00390 //////////////////////////////////////////////////////////////////////////
00391 void PShaderTxt::saveShaderAs(const QString &lastPath)
00392 {
00393    QString s;
00394    ofstream of;
00395 
00396    s = QFileDialog::getSaveFileName( lastPath, "Shaders (*.fp *.vp *.txt)");
00397    if(QString::null == s)
00398       return;
00399 
00400    of.open(s.ascii(), ios::binary);
00401    if(of.bad())
00402    {
00403       _errw->launchError( "failed to open " + s + " for writing \n" );
00404       of.close();
00405       return;
00406    }
00407 
00408    if(_mle->isModified())
00409       loadShader();
00410 
00411    switch(_stype)
00412    {
00413    case ARB_FP:
00414       if(_fpshader.isNull()) return;
00415       _fpshader->setProgFile(s.ascii());
00416       of.write(_fpshader->getProgText(), strlen(_fpshader->getProgText()));
00417       break;
00418    case ARB_VP:
00419       if(_vpshader.isNull()) return;
00420       _vpshader->setProgFile(s.ascii());
00421       of.write(_vpshader->getProgText(), strlen(_vpshader->getProgText()));
00422       break;
00423    }
00424 
00425    if(of.bad())
00426    {
00427       _errw->launchError( "error writing " + s + "\n" );
00428    }
00429 
00430    of.close();
00431 
00432    _mle->setModified(false);
00433 }
00434 
00435 //////////////////////////////////////////////////////////////////////////
00436 /// close shader
00437 //////////////////////////////////////////////////////////////////////////
00438 void PShaderTxt::closeShader(const QString &lastPath)
00439 {
00440    if(_mle->isModified())
00441    {
00442       loadShader();
00443 
00444       if(!QMessageBox::information(this,"Save File?", 
00445          "This shader has not been saved, save now?",
00446          "Save","Cancel"))
00447       {
00448          saveShader(lastPath);
00449       }
00450    }
00451 }
00452 
00453 //////////////////////////////////////////////////////////////////////////
00454 /// cast Shader
00455 //////////////////////////////////////////////////////////////////////////
00456 bool PShaderTxt::castShader()
00457 {
00458    if(_shader.isNull())
00459    {
00460       cerr << "PShaderTxt::castShader(), Shader is null!!!" << endl;
00461       return true;   
00462    }
00463 
00464    /// fragment program ARB
00465    if(_fpshader = dynamic_cast<FragProgARB*>(_shader.getPtr()))
00466    {
00467       _stype = ARB_FP;
00468    }
00469    /// vertex program ARB
00470    else if(_vpshader = dynamic_cast<VertexProgARB*>(_shader.getPtr()))
00471    {
00472       _stype = ARB_VP;
00473    }
00474    /// catch all, don't know what to do??
00475    else
00476    {
00477       cerr << "PShaderTxt::castShader(), shader type unknown " << endl;
00478       return true;
00479    }
00480 
00481    return false;
00482 }
00483 
00484 //////////////////////////////////////////////////////////////////////////
00485 /// get error position
00486 //////////////////////////////////////////////////////////////////////////
00487 const string ARB_ERR_CHAR("at character");
00488 
00489 int PShaderTxt::getErrorPos(std::string s)
00490 {
00491    if(s.empty()) return -1;
00492 
00493    /// arb style error position at a specific character
00494    if(s.find(ARB_ERR_CHAR) != -1)
00495    {
00496       string epos = s.substr(s.find(ARB_ERR_CHAR) + ARB_ERR_CHAR.size(), 8);
00497       istringstream iss(epos);
00498       int p;
00499       iss >> p;
00500 
00501       return s.find("!!ARB") + p;
00502    }
00503 
00504    return -1;
00505 }
00506 

Send questions, comments, and bug reports to:
jmk