00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
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
00063
00064
00065
00066
00067
00068
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
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
00118
00119
00120
00121
00122
00123
00124
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
00143
00144 void ProgramChunk::onCreate(const ProgramChunk *)
00145 {
00146 if(GlobalSystemState == Startup)
00147 return;
00148 }
00149
00150
00151
00152
00153 const StateChunkClass *ProgramChunk::getClass(void) const
00154 {
00155 return &_class;
00156 }
00157
00158
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
00178
00179 void ProgramChunk::dump( UInt32 ,
00180 const BitVector ) const
00181 {
00182 SLOG << "Dump ProgramChunk NI" << std::endl;
00183 }
00184
00185
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
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
00360
00361
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
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
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
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
00472
00473
00474
00475 if(!win->hasExtension(extension))
00476 return;
00477
00478 id = win->getGLObjectId(osgid);
00479
00480 if(mode == Window::destroy)
00481 {
00482
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
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
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
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
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
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
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
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
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
00681
00682 return false;
00683 }
00684
00685 bool ProgramChunk::operator != (const StateChunk &other) const
00686 {
00687 return ! (*this == other);
00688 }
00689