00001
00002
00003
00004
00005
00006 #include "Volume.h"
00007
00008 #include "glew.h"
00009 #include "gl/glu.h"
00010 #pragma comment(lib,"OpenGL32.lib")
00011 #pragma comment(lib,"glu32.lib")
00012 #pragma comment(lib,"glew32.lib")
00013
00014 #include "Math/TVector3.h"
00015 #include "Math/TVector2.h"
00016 #include "modules/Math/perlin.h"
00017
00018
00019 #include "CConsole.h"
00020 extern CConsole * ptrConsole;
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 int CVolume::sverts[] = {-1,1,1 , -1,-1,1 , 1,-1,1 , 1,1,1 , -1,1,-1 , -1,-1,-1 , 1,-1,-1 , 1,1,-1 };
00038 float CVolume::scolors[] = { 0,1,0 , 0,0,0 , 1,0,0 , 1,1,0 , 0,1,1 , 0,0,1 , 1,0,1 , 1,1,1 };
00039 unsigned char CVolume::sindices[] = { 0,1,2,3 , 3,2,6,7 , 7,6,5,4 , 4,5,1,0 , 0,3,7,4 , 1,5,6,2 };
00040 int CVolume::snormals[] = {-1,1,1 , -1,-1,1 , 1,-1,1 , 1,1,1 , -1,1,-1 , -1,-1,-1 , 1,-1,-1 , 1,1,-1 };
00041 int CVolume::stexCoords[] = { 0,1,1 , 0,0,1 , 1,0,1 , 1,1,1 , 0,1,0 , 0,0,0 , 1,0,0 , 1,1,0 };
00042
00043
00044
00045
00046
00047
00048 CVolume::CVolume(std::string & fN)
00049 {
00050 fileName = fN;
00051 created = false;
00052 renderMode = MODE_NOTSET;
00053
00054 pFormat = NULL;
00055 pProgram = NULL;
00056 pLight = NULL;
00057 txVol = 0;
00058 txColorFront = 0;
00059 txColorBack = 0;
00060 txDepthFront = 0;
00061 txDepthBack = 0;
00062 frameBuffer = 0;
00063
00064 cullFaceEnabled = false;
00065 needUpdateUniform = true;
00066 needUpdateFBO = false;
00067
00068 noiseTexSize = 512;
00069 noiseTex = new uchar[noiseTexSize*noiseTexSize*4];
00070
00071 bSliceInViewSpace = true;
00072 nmbActiveSlices = 0;
00073 viewAspect = 1.0;
00074
00075 rotX = 0.0;
00076 rotY = 0.0;
00077 }
00078
00079
00080 CVolume::~CVolume()
00081 {
00082 Destroy();
00083 }
00084
00085
00086 void CVolume::Destroy()
00087 {
00088 pProgram = NULL;
00089 pLight = NULL;
00090 delete pFormat;
00091 delete [] noiseTex;
00092 }
00093
00094
00095 bool CVolume::Create(TSmartPointer<CGLProgram> program, int mode, int fboSize,
00096 float stepSize, int maxSamples, bool applyNoise,float minClip,
00097 bool shadowEnabled, float shadowQuality, float shadowTreshold)
00098 {
00099
00100 pProgram = program;
00101
00102
00103 this->renderMode = mode;
00104 this->fboSize = fboSize;
00105 this->stepSize = stepSize;
00106 this->maxSamples = maxSamples;
00107 this->applyNoise = applyNoise;
00108 this->minClip = minClip;
00109 this->shadowEnabled = shadowEnabled;
00110 this->shadowQuality = shadowQuality;
00111 this->shadowTreshold = shadowTreshold;
00112
00113
00114 for(int i = 0;i < noiseTexSize;i++){
00115 for(int j = 0;j < noiseTexSize;j++){
00116 int val = (double)rand() / (double)RAND_MAX * 255;
00117 noiseTex[(i*noiseTexSize*4) + (j*4)] = val;
00118 noiseTex[(i*noiseTexSize*4) + (j*4+1)] = val;
00119 noiseTex[(i*noiseTexSize*4) + (j*4+2)] = val;
00120 noiseTex[(i*noiseTexSize*4) + (j*4+3)] = 0xff;
00121 }
00122 }
00123
00124
00125 QFile volumeFile(QString().fromStdString(fileName));
00126 QFileInfo volumeFileInfo(volumeFile);
00127
00128
00129 if(volumeFileInfo.suffix().compare("vol8") == 0)
00130 pFormat = new CVolumeFormatVOL8();
00131 if(volumeFileInfo.suffix().compare("vol12") == 0)
00132 pFormat = new CVolumeFormatVOL12();
00133 if(volumeFileInfo.suffix().compare("vol16") == 0)
00134 pFormat = new CVolumeFormatVOL16();
00135 if(volumeFileInfo.suffix().compare("dat") == 0)
00136 pFormat = new CVolumeFormatLU_DAT();
00137
00138
00139
00140 bool volumeImportSuccess = false;
00141
00142 if(pFormat){
00143 if(volumeFile.open(QIODevice::ReadOnly)){
00144 if(volumeFile.read(pFormat->getVolumeHeader(),pFormat->getVolumeHeaderSize())){
00145
00146 int dataSize = pFormat->getVolumeDataSize();
00147 char *data = new char[dataSize];
00148
00149 if(dataSize == volumeFile.read(data,dataSize))
00150 {
00151
00152 if(pFormat->getBitDepth() == 16 || pFormat->getBitDepth() == 12)
00153 {
00154 int minVal = USHRT_MAX;
00155 int maxVal = 0;
00156
00157 ushort * dat = (ushort *)data;
00158
00159 for(int i = 0; i < (int)(dataSize/2) ; i++)
00160 {
00161 if(*(dat+i) > maxVal)
00162 {
00163 maxVal = *(dat+i);
00164 }
00165 if(*(dat+i) < minVal)
00166 {
00167 minVal = *(dat+i);
00168 }
00169 }
00170
00171 ptrConsole->Log(QString("Volume Data Original Min Value: ").append(QString("%1").arg(minVal)),0);
00172 ptrConsole->Log(QString("Volume Data Original Max Value: ").append(QString("%1").arg(maxVal)),0);
00173
00174 int range = maxVal - minVal;
00175
00176 for(int i = 0; i < (int)(dataSize/2) ; i++)
00177 {
00178 *(dat+i) = (ushort) (((*(dat+i)) - minVal) * (USHRT_MAX/(double)range));
00179 }
00180
00181 minVal = USHRT_MAX;
00182 maxVal = 0;
00183
00184 dat = (ushort *)data;
00185
00186 for(int i = 0; i < (int)(dataSize/2) ; i++)
00187 {
00188 if(*(dat+i) > maxVal)
00189 {
00190 maxVal = *(dat+i);
00191 }
00192 if(*(dat+i) < minVal)
00193 {
00194 minVal = *(dat+i);
00195 }
00196 }
00197
00198 ptrConsole->Log(QString("Volume Data New Min Value: ").append(QString("%1").arg(minVal)),0);
00199 ptrConsole->Log(QString("Volume Data New Max Value: ").append(QString("%1").arg(maxVal)),0);
00200 }
00201
00202 pFormat->setVolumeData(data);
00203 volumeImportSuccess = true;
00204 }
00205 }
00206 }
00207 }
00208 created = volumeImportSuccess;
00209
00210
00211 return created;
00212 }
00213
00214
00215 bool CVolume::CreateOpenGL()
00216 {
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 GLenum err = glewInit();
00231 if (GLEW_OK != err)
00232 {
00233 return false;
00234 }
00235
00236
00237
00238 pCubeVertices = sverts;
00239 pCubeNormals = snormals;
00240 pCubeTexCoords = stexCoords;
00241 pCubeColors = scolors;
00242 pCubeIndices = sindices;
00243
00244 glVertexPointer(3,GL_INT,0,pCubeVertices);
00245 glIndexPointer(GL_UNSIGNED_BYTE,0,pCubeIndices);
00246 glColorPointer(3,GL_FLOAT,0,pCubeColors);
00247
00248 glEnableClientState(GL_VERTEX_ARRAY);
00249 glEnableClientState(GL_INDEX_ARRAY);
00250 glEnableClientState(GL_COLOR_ARRAY);
00251
00252 cubeDispList = glGenLists(1);
00253
00254 glNewList(cubeDispList,GL_COMPILE);
00255 glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE,pCubeIndices);
00256 glEndList();
00257
00258 glDisableClientState(GL_VERTEX_ARRAY);
00259 glDisableClientState(GL_INDEX_ARRAY);
00260 glDisableClientState(GL_COLOR_ARRAY);
00261
00262
00263
00264 glPixelStorei(GL_UNPACK_ALIGNMENT,4);
00265
00266 glGenTextures(1,&txVol);
00267 glBindTexture(GL_TEXTURE_3D_EXT,txVol);
00268 glTexParameteri(GL_TEXTURE_3D_EXT,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
00269 glTexParameteri(GL_TEXTURE_3D_EXT,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
00270 glTexParameteri(GL_TEXTURE_3D_EXT,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
00271 glTexParameterf(GL_TEXTURE_3D_EXT, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
00272 glTexParameterf(GL_TEXTURE_3D_EXT, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
00273
00274 switch(pFormat->getBitDepth()){
00275 case 8:
00276 glTexImage3D(GL_TEXTURE_3D,0,GL_ALPHA,pFormat->getSizeX(),pFormat->getSizeY(),pFormat->getSizeZ(),0, GL_ALPHA, GL_UNSIGNED_BYTE, pFormat->getVolumeData());
00277 break;
00278
00279 case 12:
00280 glTexImage3D(GL_TEXTURE_3D,0,GL_ALPHA12,pFormat->getSizeX(),pFormat->getSizeY(),pFormat->getSizeZ(),0, GL_ALPHA, GL_UNSIGNED_SHORT, pFormat->getVolumeData());
00281 break;
00282
00283 case 16:
00284 glTexImage3D(GL_TEXTURE_3D,0,GL_ALPHA16,pFormat->getSizeX(),pFormat->getSizeY(),pFormat->getSizeZ(),0, GL_ALPHA, GL_UNSIGNED_SHORT, pFormat->getVolumeData());
00285 break;
00286 }
00287
00288
00289
00290 if(txNoise){
00291 glDeleteTextures(1,&txNoise);
00292 }
00293 glGenTextures(1, &txNoise);
00294 glBindTexture(GL_TEXTURE_2D,txNoise);
00295 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00296 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00297 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00298 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00299 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, noiseTexSize, noiseTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, noiseTex);
00300
00301
00302
00303 if( glIsTexture(txNoise) && (glIsTexture(txVol) && glIsList(cubeDispList)) ){
00304 glGenFramebuffersEXT(1,&frameBuffer);
00305 if(CreateFboTextures()){
00306 QString msg("Creating Volume (OpenGL): ");
00307 ptrConsole->Log(msg.append(QString(fileName.c_str())).append(QString(" Success!")),OPENGL_THREAD);
00308 return true;
00309 }
00310 }
00311
00312
00313 QString msg("Creating Volume (OpenGL): ");
00314 ptrConsole->Log(msg.append(QString(fileName.c_str())).append(QString(" Failed!")),OPENGL_THREAD);
00315 DestroyOpenGL();
00316 return false;
00317 }
00318
00319
00320 bool CVolume::DestroyOpenGL()
00321 {
00322 QString msg("Destroying Volume (OpenGL): ");
00323 ptrConsole->Log(msg.append(QString(fileName.c_str())),OPENGL_THREAD);
00324
00325 if(glIsList(cubeDispList)){
00326 glDeleteLists(cubeDispList,1);
00327 }
00328 if(frameBuffer){
00329 glDeleteFramebuffersEXT(1,&frameBuffer);
00330 }
00331 if(glIsTexture(txColorFront)){
00332 glDeleteTextures(1,&txColorFront);
00333 }
00334 if(glIsTexture(txColorBack)){
00335 glDeleteTextures(1,&txColorBack);
00336 }
00337 if(glIsTexture(txDepthFront)){
00338 glDeleteTextures(1,&txDepthFront);
00339 }
00340 if(glIsTexture(txDepthBack)){
00341 glDeleteTextures(1,&txDepthBack);
00342 }
00343 if(glIsTexture(txVol)){
00344 glDeleteTextures(1,&txVol);
00345 }
00346 return true;
00347 }
00348
00349
00350 void CVolume::SetRenderMode(int newMode)
00351 {
00352 renderMode = newMode;
00353 needUpdateUniform = true;
00354 }
00355
00356
00357 void CVolume::SetFboSize( int newFboSize )
00358 {
00359 fboSize = newFboSize;
00360 needUpdateFBO = true;
00361 }
00362
00363
00364 void CVolume::SetStepSize( float newStepSize )
00365 {
00366 stepSize = newStepSize;
00367 needUpdateUniform = true;
00368 }
00369
00370
00371 void CVolume::SetMaxSamples( int newMaxSamples )
00372 {
00373 maxSamples = newMaxSamples;
00374 needUpdateUniform = true;
00375 }
00376
00377
00378 void CVolume::SetMinClip( float newMinClip )
00379 {
00380 minClip = newMinClip;
00381 needUpdateUniform = true;
00382 }
00383
00384
00385 void CVolume::SetApplyNoise( bool newApplyNoise )
00386 {
00387 applyNoise = newApplyNoise;
00388 needUpdateUniform = true;
00389 }
00390
00391
00392 void CVolume::SetShadowEnabled( bool tf )
00393 {
00394 shadowEnabled = tf;
00395 needUpdateUniform = true;
00396 }
00397
00398
00399 void CVolume::SetShadowTreshold( float t )
00400 {
00401 shadowTreshold = t;
00402 needUpdateUniform = true;
00403 }
00404
00405
00406 void CVolume::SetShadowQuality( float q )
00407 {
00408 shadowQuality = q;
00409 needUpdateUniform = true;
00410 }
00411
00412
00413 void CVolume::SetHighQuality( bool tf )
00414 {
00415 static bool highQualitySet = false;
00416
00417 static float sstepSize;
00418 static bool sapplyNoise;
00419 static int smaxSamples;
00420 static float sshadowQuality;
00421
00422 if(tf && !highQualitySet)
00423 {
00424 sstepSize = stepSize;
00425 sapplyNoise = applyNoise;
00426 smaxSamples = maxSamples;
00427 sshadowQuality = shadowQuality;
00428 highQualitySet = true;
00429
00430 stepSize = 0.005;
00431 applyNoise = true;
00432 maxSamples = 3000;
00433 shadowQuality = 2.0;
00434
00435 needUpdateUniform = true;
00436 }
00437 else
00438 {
00439 if(highQualitySet)
00440 {
00441 stepSize = sstepSize;
00442 applyNoise = sapplyNoise;
00443 maxSamples = smaxSamples;
00444 shadowQuality = sshadowQuality;
00445 highQualitySet = false;
00446
00447 needUpdateUniform = true;
00448 }
00449 }
00450 }
00451
00452
00453 void CVolume::SwitchProgram( TSmartPointer<CGLProgram> newProgram)
00454 {
00455 pProgram = newProgram;
00456 }
00457
00458
00459 void CVolume::SetSliceInViewSpace( bool tf)
00460 {
00461 bSliceInViewSpace = tf;
00462 }
00463
00464
00465 void CVolume::SetRenderSlice(bool bxSlice,bool bySlice, bool bzSlice)
00466 {
00467 xSlice.bEnabled = bxSlice;
00468 ySlice.bEnabled = bySlice;
00469 zSlice.bEnabled = bzSlice;
00470
00471 int nmbSlices = bxSlice + bySlice + bzSlice;
00472
00473 nmbActiveSlices = nmbSlices;
00474
00475 if(bzSlice)
00476 {
00477 zSlice.pos = CVector3f( ( (2*(--nmbSlices)) +1 ) / float(nmbActiveSlices * 2) , 0.0, zSlice.depth);
00478 }
00479 if(bySlice)
00480 {
00481 ySlice.pos = CVector3f( ( (2*(--nmbSlices)) +1 ) / float(nmbActiveSlices * 2) , 0.0, ySlice.depth);
00482 }
00483 if(bxSlice)
00484 {
00485 xSlice.pos = CVector3f( ( (2*(--nmbSlices)) +1 ) / float(nmbActiveSlices * 2) , 0.0, xSlice.depth);
00486 }
00487
00488 float offset = nmbActiveSlices / float(nmbActiveSlices*2);
00489 zSlice.pos.m_X = zSlice.pos.m_X - offset;
00490 ySlice.pos.m_X = ySlice.pos.m_X - offset;
00491 xSlice.pos.m_X = xSlice.pos.m_X - offset;
00492 }
00493
00494
00495 void CVolume::SetSliceDepth(int slizePlaneID,float depth)
00496 {
00497 switch(slizePlaneID)
00498 {
00499 case 0: xSlice.depth = depth; break;
00500 case 1: ySlice.depth = depth; break;
00501 case 2: zSlice.depth = depth; break;
00502 }
00503 }
00504
00505
00506 void CVolume::Render(){
00507
00508
00509 assert((CLight *)pLight != NULL || "No Light Attached to Volume");
00510 assert(renderMode == MODE_BACK_FRONT_TEX || "Currently this RenderMode is not supported");
00511
00512
00513 if(needUpdateFBO){
00514 CreateFboTextures();
00515 needUpdateFBO = false;
00516 }
00517
00518 glRotatef(rotY,0,1,0);
00519 glRotatef(rotX,1,0,0);
00520
00521 switch(renderMode){
00522
00523
00524
00525
00526 case MODE_BACK_TEX:{
00527
00528
00529 if(pProgram->LinkSuccess()){
00530
00531
00532 glPushAttrib(GL_VIEWPORT_BIT);
00533 glViewport(0,0,fboSize,fboSize);
00534 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,frameBuffer);
00535
00536
00537 glCullFace(GL_FRONT);
00538
00539
00540 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,txColorBack, 0);
00541 assert(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT || "FrameBuffer not Complete");
00542
00543
00544 glClear(GL_COLOR_BUFFER_BIT);
00545 glCallList(cubeDispList);
00546
00547
00548 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
00549 glPopAttrib();
00550
00551
00552 pProgram->Use(true);
00553
00554
00555 glActiveTexture(GL_TEXTURE0);
00556 glBindTexture(GL_TEXTURE_3D_EXT,txVol);
00557 loc = glGetUniformLocation(pProgram->GetProgramID(),"txVolume");
00558 glUniform1i(loc,0);
00559
00560 glActiveTexture(GL_TEXTURE1);
00561 glBindTexture(GL_TEXTURE_2D,txColorBack);
00562 loc = glGetUniformLocation(pProgram->GetProgramID(),"txColorBack");
00563 glUniform1i(loc,1);
00564
00565 glActiveTexture(GL_TEXTURE2);
00566 glBindTexture(GL_TEXTURE_1D,txTransfer);
00567 loc = glGetUniformLocation(pProgram->GetProgramID(),"txTransfer");
00568 glUniform1i(loc,2);
00569
00570
00571 int texUnitConsumed = GL_TEXTURE2;
00572 int texNum = 2;
00573
00574 for(int i = 0 ; i < propertyList.size() ; i++)
00575 {
00576 if(propertyList[i]->NeedTextureUnit()) {
00577 propertyList[i]->UpdateShader(pProgram->GetProgramID(),++texUnitConsumed,++texNum);
00578 }else{
00579 propertyList[i]->UpdateShader(pProgram->GetProgramID());
00580 }
00581 }
00582
00583
00584 if(needUpdateUniform || pLight->HasChanged()){
00585 UpdateUniform();
00586 }
00587
00588
00589 glCullFace(GL_BACK);
00590 glCallList(cubeDispList);
00591
00592
00593 pProgram->Use(false);
00594
00595
00596 glActiveTexture(GL_TEXTURE0);
00597
00598 }else{
00599 glCullFace(GL_BACK);
00600 glCallList(cubeDispList);
00601 needUpdateUniform = true;
00602 }
00603 break;
00604 }
00605
00606
00607
00608
00609 case MODE_BACK_FRONT_TEX:{
00610
00611
00612 glPushMatrix();
00613 glScalef(pFormat->scX,pFormat->scY,pFormat->scZ);
00614
00615
00616 glPushAttrib(GL_VIEWPORT_BIT);
00617 glViewport(0,0,fboSize,fboSize);
00618 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,frameBuffer);
00619
00620
00621 glCullFace(GL_FRONT);
00622
00623
00624 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,txColorBack, 0);
00625 assert(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT || "FrameBuffer not Complete");
00626
00627
00628 glClear(GL_COLOR_BUFFER_BIT);
00629 glCallList(cubeDispList);
00630
00631
00632 glCullFace(GL_BACK);
00633
00634
00635 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,txColorFront, 0);
00636 assert(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT || "FrameBuffer not Complete");
00637
00638
00639 glClear(GL_COLOR_BUFFER_BIT);
00640 glCallList(cubeDispList);
00641
00642
00643 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
00644 glPopAttrib();
00645
00646
00647 if(pProgram->LinkSuccess()){
00648
00649
00650 pProgram->Use(true);
00651
00652
00653 glActiveTexture(GL_TEXTURE0);
00654 glBindTexture(GL_TEXTURE_3D_EXT,txVol);
00655 loc = glGetUniformLocation(pProgram->GetProgramID(),"txVolume");
00656 glUniform1i(loc,0);
00657
00658 glActiveTexture(GL_TEXTURE1);
00659 glBindTexture(GL_TEXTURE_2D,txColorFront);
00660 loc = glGetUniformLocation(pProgram->GetProgramID(),"txColorFront");
00661 glUniform1i(loc,1);
00662
00663 glActiveTexture(GL_TEXTURE2);
00664 glBindTexture(GL_TEXTURE_2D,txColorBack);
00665 loc = glGetUniformLocation(pProgram->GetProgramID(),"txColorBack");
00666 glUniform1i(loc,2);
00667
00668 glActiveTexture(GL_TEXTURE3);
00669 glBindTexture(GL_TEXTURE_2D,txNoise);
00670 loc = glGetUniformLocation(pProgram->GetProgramID(),"txNoise");
00671 glUniform1i(loc,3);
00672
00673
00674 int texUnitConsumed = GL_TEXTURE3;
00675 int texNum = 3;
00676
00677 for(int i = 0 ; i < propertyList.size() ; i++)
00678 {
00679 if(propertyList[i]->NeedTextureUnit()) {
00680 propertyList[i]->UpdateShader(pProgram->GetProgramID(),++texUnitConsumed,++texNum);
00681 }else{
00682 propertyList[i]->UpdateShader(pProgram->GetProgramID());
00683 }
00684 }
00685
00686
00687
00688 UpdateUniform();
00689
00690
00691
00692 glCallList(cubeDispList);
00693
00694
00695 pProgram->Use(false);
00696
00697
00698 glActiveTexture(GL_TEXTURE0);
00699
00700 }else{
00701 glCullFace(GL_BACK);
00702 glCallList(cubeDispList);
00703 needUpdateUniform = true;
00704 }
00705 break;
00706 }
00707
00708
00709
00710
00711 case MODE_SLICE:
00712 {
00713 float slicePosX;
00714 float slicePosY;
00715 float slicePosZ;
00716
00717 if(bSliceInViewSpace)
00718 {
00719 glMatrixMode(GL_PROJECTION);
00720 glPushMatrix();
00721 glLoadIdentity();
00722 glOrtho(-1*viewAspect,1*viewAspect,-1,1,-1,1);
00723
00724 float scale;
00725
00726 if(viewAspect < 1.0)
00727 {
00728 scale = viewAspect/nmbActiveSlices;
00729 slicePosX = xSlice.pos.m_X*2*viewAspect;
00730 slicePosY = ySlice.pos.m_X*2*viewAspect;
00731 slicePosZ = zSlice.pos.m_X*2*viewAspect;
00732 }
00733 else
00734 {
00735 scale = 1.0/nmbActiveSlices;
00736 slicePosX = xSlice.pos.m_X*2;
00737 slicePosY = ySlice.pos.m_X*2;
00738 slicePosZ = zSlice.pos.m_X*2;
00739 }
00740
00741
00742 glMatrixMode(GL_MODELVIEW);
00743 glPushMatrix();
00744 glLoadIdentity();
00745 glTranslatef(0,0,-0.1);
00746
00747 glActiveTexture(GL_TEXTURE0);
00748 glBindTexture(GL_TEXTURE_3D,txVol);
00749 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
00750 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_MODULATE);
00751 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS);
00752 glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR);
00753 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_TEXTURE);
00754 glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_ALPHA);
00755
00756 glLineWidth(2.0);
00757
00758
00759 if(zSlice.bEnabled)
00760 {
00761 glEnable(GL_TEXTURE_3D);
00762
00763 glPushMatrix();
00764 glTranslatef(slicePosZ,0,0);
00765 glScalef(scale,scale,scale);
00766
00767 glColor4f(1.0,1.0,1.0,1.0);
00768 glBegin(GL_QUADS);
00769 glTexCoord3f(0.0,0.0,zSlice.depth);
00770 glVertex3f(-1,-1,0);
00771
00772 glTexCoord3f(1.0,0.0,zSlice.depth);
00773 glVertex3f(1,-1,0);
00774
00775 glTexCoord3f(1.0,1.0,zSlice.depth);
00776 glVertex3f(1,1,0);
00777
00778 glTexCoord3f(0.0,1.0,zSlice.depth);
00779 glVertex3f(-1,1,0);
00780 glEnd();
00781
00782 glDisable(GL_TEXTURE_3D);
00783
00784 glColor4f(0.0,0.0,1.0,1.0);
00785 glBegin(GL_LINE_LOOP);
00786 glVertex3f(-1,-1,0.0);
00787 glVertex3f(1,-1,0.0);
00788 glVertex3f(1,1,0.0);
00789 glVertex3f(-1,1,0.0);
00790 glEnd();
00791
00792 glPopMatrix();
00793 }
00794
00795
00796 if(ySlice.bEnabled)
00797 {
00798 glEnable(GL_TEXTURE_3D);
00799
00800 glPushMatrix();
00801 glTranslatef(slicePosY,0,0);
00802 glScalef(scale,scale,scale);
00803
00804 glColor4f(1.0,1.0,1.0,1.0);
00805 glBegin(GL_QUADS);
00806 glTexCoord3f(0.0,ySlice.depth,0.0);
00807 glVertex3f(-1,-1,0);
00808
00809 glTexCoord3f(1.0,ySlice.depth,0.0);
00810 glVertex3f(1,-1,0);
00811
00812 glTexCoord3f(1.0,ySlice.depth,1.0);
00813 glVertex3f(1,1,0);
00814
00815 glTexCoord3f(0.0,ySlice.depth,1.0);
00816 glVertex3f(-1,1,0);
00817 glEnd();
00818
00819 glDisable(GL_TEXTURE_3D);
00820
00821 glColor4f(0.0,1.0,0.0,1.0);
00822 glBegin(GL_LINE_LOOP);
00823 glVertex3f(-1,-1,0.0);
00824 glVertex3f(1,-1,0.0);
00825 glVertex3f(1,1,0.0);
00826 glVertex3f(-1,1,0.0);
00827 glEnd();
00828
00829 glPopMatrix();
00830 }
00831
00832
00833 if(xSlice.bEnabled)
00834 {
00835 glEnable(GL_TEXTURE_3D);
00836
00837 glPushMatrix();
00838 glTranslatef(slicePosX,0,0);
00839 glScalef(scale,scale,scale);
00840
00841 glColor4f(1.0,1.0,1.0,1.0);
00842 glBegin(GL_QUADS);
00843 glTexCoord3f(xSlice.depth,1.0,0.0);
00844 glVertex3f(-1,-1,0);
00845
00846 glTexCoord3f(xSlice.depth,0.0,0.0);
00847 glVertex3f(1,-1,0);
00848
00849 glTexCoord3f(xSlice.depth,0.0,1.0);
00850 glVertex3f(1,1,0);
00851
00852 glTexCoord3f(xSlice.depth,1.0,1.0);
00853 glVertex3f(-1,1,0);
00854 glEnd();
00855
00856 glDisable(GL_TEXTURE_3D);
00857
00858 glColor4f(1.0,0.0,0.0,1.0);
00859 glBegin(GL_LINE_LOOP);
00860 glVertex3f(-1,-1,0.0);
00861 glVertex3f(1,-1,0.0);
00862 glVertex3f(1,1,0.0);
00863 glVertex3f(-1,1,0.0);
00864 glEnd();
00865
00866 glPopMatrix();
00867 }
00868
00869 glPopMatrix();
00870
00871 glMatrixMode(GL_PROJECTION);
00872 glPopMatrix();
00873 }
00874 else
00875 {
00876 glActiveTexture(GL_TEXTURE0);
00877 glBindTexture(GL_TEXTURE_3D,txVol);
00878 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
00879 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_MODULATE);
00880 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS);
00881 glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR);
00882 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_TEXTURE);
00883 glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_ALPHA);
00884
00885 glLineWidth(2.0);
00886 glDepthFunc(GL_LEQUAL);
00887 glDisable(GL_CULL_FACE);
00888 glScalef(pFormat->scX,pFormat->scY,pFormat->scZ);
00889
00890
00891
00892 if(zSlice.bEnabled)
00893 {
00894 glEnable(GL_TEXTURE_3D);
00895
00896 glPushMatrix();
00897 glTranslatef(0,0,1.0 - (2.0*zSlice.depth));
00898
00899 glColor4f(1.0,1.0,1.0,1.0);
00900 glBegin(GL_QUADS);
00901 glTexCoord3f(0.0,0.0,zSlice.depth);
00902 glVertex3f(-1,-1,0);
00903
00904 glTexCoord3f(1.0,0.0,zSlice.depth);
00905 glVertex3f(1,-1,0);
00906
00907 glTexCoord3f(1.0,1.0,zSlice.depth);
00908 glVertex3f(1,1,0);
00909
00910 glTexCoord3f(0.0,1.0,zSlice.depth);
00911 glVertex3f(-1,1,0);
00912 glEnd();
00913
00914 glDisable(GL_TEXTURE_3D);
00915
00916 glColor4f(0.0,0.0,1.0,1.0);
00917 glBegin(GL_LINE_LOOP);
00918 glVertex3f(-1,-1,0.0);
00919 glVertex3f(1,-1,0.0);
00920 glVertex3f(1,1,0.0);
00921 glVertex3f(-1,1,0.0);
00922 glEnd();
00923
00924 glPopMatrix();
00925 }
00926
00927
00928 if(ySlice.bEnabled)
00929 {
00930 glEnable(GL_TEXTURE_3D);
00931
00932 glPushMatrix();
00933 glTranslatef(0,(-1.0) + (2.0*ySlice.depth),0);
00934 glRotatef(-90,1.0,0.0,0.0);
00935
00936 glColor4f(1.0,1.0,1.0,1.0);
00937 glBegin(GL_QUADS);
00938 glTexCoord3f(0.0,ySlice.depth,0.0);
00939 glVertex3f(-1,-1,0);
00940
00941 glTexCoord3f(1.0,ySlice.depth,0.0);
00942 glVertex3f(1,-1,0);
00943
00944 glTexCoord3f(1.0,ySlice.depth,1.0);
00945 glVertex3f(1,1,0);
00946
00947 glTexCoord3f(0.0,ySlice.depth,1.0);
00948 glVertex3f(-1,1,0);
00949 glEnd();
00950
00951 glDisable(GL_TEXTURE_3D);
00952
00953 glColor4f(0.0,1.0,0.0,1.0);
00954 glBegin(GL_LINE_LOOP);
00955 glVertex3f(-1,-1,0.0);
00956 glVertex3f(1,-1,0.0);
00957 glVertex3f(1,1,0.0);
00958 glVertex3f(-1,1,0.0);
00959 glEnd();
00960
00961 glPopMatrix();
00962 }
00963
00964
00965 if(xSlice.bEnabled)
00966 {
00967 glEnable(GL_TEXTURE_3D);
00968
00969 glPushMatrix();
00970 glTranslatef((-1.0) + (2.0*xSlice.depth),0,0);
00971 glRotatef(90,0.0,1.0,0.0);
00972
00973 glColor4f(1.0,1.0,1.0,1.0);
00974 glBegin(GL_QUADS);
00975 glTexCoord3f(xSlice.depth,0.0,0.0);
00976 glVertex3f(-1,-1,0);
00977
00978 glTexCoord3f(xSlice.depth,0.0,1.0);
00979 glVertex3f(1,-1,0);
00980
00981 glTexCoord3f(xSlice.depth,1.0,1.0);
00982 glVertex3f(1,1,0);
00983
00984 glTexCoord3f(xSlice.depth,1.0,0.0);
00985 glVertex3f(-1,1,0);
00986 glEnd();
00987
00988 glDisable(GL_TEXTURE_3D);
00989
00990 glColor4f(1.0,0.0,0.0,1.0);
00991 glBegin(GL_LINE_LOOP);
00992 glVertex3f(-1,-1,0.0);
00993 glVertex3f(1,-1,0.0);
00994 glVertex3f(1,1,0.0);
00995 glVertex3f(-1,1,0.0);
00996 glEnd();
00997
00998 glPopMatrix();
00999 }
01000
01001 glDepthFunc(GL_LESS);
01002 glEnable(GL_CULL_FACE);
01003 }
01004 break;
01005 }
01006
01007
01008
01009
01010 case MODE_DEPTH_TEX:{
01011
01012
01013 glPushAttrib(GL_VIEWPORT_BIT);
01014 glViewport(0,0,fboSize,fboSize);
01015 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,frameBuffer);
01016
01017
01018 glCullFace(GL_FRONT);
01019
01020
01021 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,txColorFront, 0);
01022 assert(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT || "FrameBuffer not Complete");
01023
01024
01025 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D,txDepthBack, 0);
01026 assert(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT || "FrameBuffer not Complete");
01027
01028
01029 glClear(GL_DEPTH_BUFFER_BIT);
01030 glCallList(cubeDispList);
01031
01032
01033 glCullFace(GL_BACK);
01034
01035
01036 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D,txDepthFront, 0);
01037 assert(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT || "FrameBuffer not Complete");
01038
01039
01040 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01041 glCallList(cubeDispList);
01042
01043
01044 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
01045 glPopAttrib();
01046
01047
01048 if(pProgram->LinkSuccess()){
01049
01050
01051 pProgram->Use(true);
01052
01053
01054 glActiveTexture(GL_TEXTURE0);
01055 glBindTexture(GL_TEXTURE_2D,txDepthBack);
01056 loc = glGetUniformLocation(pProgram->GetProgramID(),"txProxyBack");
01057 glUniform1i(loc,0);
01058
01059 glActiveTexture(GL_TEXTURE1);
01060 glBindTexture(GL_TEXTURE_2D,txDepthFront);
01061 loc = glGetUniformLocation(pProgram->GetProgramID(),"txProxyFront");
01062 glUniform1i(loc,1);
01063
01064 glActiveTexture(GL_TEXTURE2);
01065 glBindTexture(GL_TEXTURE_3D_EXT,txVol);
01066 loc = glGetUniformLocation(pProgram->GetProgramID(),"txVolume");
01067 glUniform1i(loc,2);
01068
01069 glActiveTexture(GL_TEXTURE3);
01070 glBindTexture(GL_TEXTURE_2D,txColorFront);
01071 loc = glGetUniformLocation(pProgram->GetProgramID(),"txColor");
01072 glUniform1i(loc,3);
01073
01074
01075 int texUnitConsumed = GL_TEXTURE3;
01076 int texNum = 3;
01077
01078 for(int i = 0 ; i < propertyList.size() ; i++)
01079 {
01080 if(propertyList[i]->NeedTextureUnit()) {
01081 propertyList[i]->UpdateShader(pProgram->GetProgramID(),++texUnitConsumed,++texNum);
01082 }else{
01083 propertyList[i]->UpdateShader(pProgram->GetProgramID());
01084 }
01085 }
01086
01087
01088 if(needUpdateUniform || pLight->HasChanged()){
01089 UpdateUniform();
01090 }
01091
01092
01093 glPushMatrix();
01094 glLoadIdentity();
01095
01096 glBegin(GL_QUADS);
01097 glVertex3f(-1,-1,0);
01098 glVertex3f(1,-1,0);
01099 glVertex3f(1,1,0);
01100 glVertex3f(-1,1,0);
01101 glEnd();
01102
01103 glPopMatrix();
01104
01105
01106 pProgram->Use(false);
01107
01108
01109 glActiveTexture(GL_TEXTURE0);
01110
01111 }else{
01112 glCullFace(GL_BACK);
01113 glCallList(cubeDispList);
01114 needUpdateUniform = true;
01115 }
01116 break;
01117 }
01118
01119
01120
01121
01122
01123
01124 default:{
01125 glPushMatrix();
01126 glLoadIdentity();
01127 glTranslatef(0,0,-10);
01128 glRotatef(45,1,1,1);
01129 glCallList(cubeDispList);
01130 glPopMatrix();
01131 needUpdateUniform = true;
01132 }
01133 }
01134
01135
01136 glPopMatrix();
01137 }
01138
01139
01140
01141
01142
01143
01144 void CVolume::UpdateUniform()
01145 {
01146 loc = glGetUniformLocation(pProgram->GetProgramID(),"stepSize");
01147 glUniform1f(loc,stepSize*0.1/2.0);
01148 loc = glGetUniformLocation(pProgram->GetProgramID(),"maxSamples");
01149 glUniform1i(loc,maxSamples*10);
01150 loc = glGetUniformLocation(pProgram->GetProgramID(),"minClip");
01151 glUniform1f(loc,minClip);
01152 loc = glGetUniformLocation(pProgram->GetProgramID(),"applyNoise");
01153 glUniform1i(loc,applyNoise);
01154
01155 gradDelta.m_X = pLight->gradDelta.m_X * pFormat->scNX;
01156 gradDelta.m_Y = pLight->gradDelta.m_Y * pFormat->scNY;
01157 gradDelta.m_Z = pLight->gradDelta.m_Z * pFormat->scNZ;
01158
01159 loc = glGetUniformLocation(pProgram->GetProgramID(),"gradDelta");
01160 glUniform3fv(loc,1,(GLfloat*)&(gradDelta));
01161 loc = glGetUniformLocation(pProgram->GetProgramID(),"lightColor");
01162 glUniform3fv(loc,1,(GLfloat*)&(pLight->color));
01163 loc = glGetUniformLocation(pProgram->GetProgramID(),"lightPos");
01164 glUniform3fv(loc,1,(GLfloat*)&(pLight->m_pos));
01165 loc = glGetUniformLocation(pProgram->GetProgramID(),"bEnableLight");
01166 glUniform1i(loc,pLight->bEnabled);
01167 loc = glGetUniformLocation(pProgram->GetProgramID(),"bLocalViewer");
01168 glUniform1i(loc,pLight->bLocalViewer);
01169 loc = glGetUniformLocation(pProgram->GetProgramID(),"bHeadLight");
01170 glUniform1i(loc,pLight->bHeadLight);
01171 loc = glGetUniformLocation(pProgram->GetProgramID(),"ambience");
01172 glUniform1f(loc,pLight->ambience);
01173 loc = glGetUniformLocation(pProgram->GetProgramID(),"specularity");
01174 glUniform1f(loc,pLight->specularity);
01175 loc = glGetUniformLocation(pProgram->GetProgramID(),"shadowEnabled");
01176 glUniform1i(loc,shadowEnabled);
01177 loc = glGetUniformLocation(pProgram->GetProgramID(),"shadowSamples");
01178 glUniform1i(loc,int(shadowQuality*100.0));
01179 loc = glGetUniformLocation(pProgram->GetProgramID(),"shadowTreshold");
01180 glUniform1f(loc,shadowTreshold);
01181
01182 pLight->hasChanged = false;
01183 needUpdateUniform = false;
01184 }
01185
01186
01187 bool CVolume::CreateFboTextures(){
01188
01189
01190
01191 if(txColorFront){
01192 glDeleteTextures(1,&txColorFront);
01193 }
01194 glGenTextures(1,&txColorFront);
01195 glBindTexture(GL_TEXTURE_2D,txColorFront);
01196 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01197 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01198 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01199 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01200 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, fboSize, fboSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
01201
01202
01203
01204 if(txColorBack){
01205 glDeleteTextures(1,&txColorBack);
01206 }
01207 glGenTextures(1,&txColorBack);
01208 glBindTexture(GL_TEXTURE_2D,txColorBack);
01209 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01210 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01211 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01212 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01213 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, fboSize, fboSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
01214
01215
01216
01217 if(txDepthFront){
01218 glDeleteTextures(1,&txDepthFront);
01219 }
01220 glGenTextures(1, &txDepthFront);
01221 glBindTexture(GL_TEXTURE_2D,txDepthFront);
01222 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01223 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01224 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_COMPARE_MODE,GL_NONE);
01225 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, fboSize, fboSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
01226
01227
01228
01229 if(txDepthBack){
01230 glDeleteTextures(1,&txDepthBack);
01231 }
01232 glGenTextures(1, &txDepthBack);
01233 glBindTexture(GL_TEXTURE_2D,txDepthBack);
01234 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01235 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01236 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_COMPARE_MODE,GL_NONE);
01237 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, fboSize, fboSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
01238
01239
01240 if( glIsTexture(txColorFront) && glIsTexture(txColorBack) && glIsTexture(txDepthFront) && glIsTexture(txDepthBack)){
01241 return true;
01242 }else{
01243 return false;
01244 }
01245 }
01246
01247 void CVolume::AddTransferProperty(TSmartPointer<CTransferProperty> ptr)
01248 {
01249 propertyList.append((CShaderProperty*)(CTransferProperty*)ptr);
01250 }
01251
01252
01253
01254
01255
01256 static bool leftKeyDown;
01257 static bool middleKeyDown;
01258 static float dx;
01259 static float dy;
01260 static sdword oldX = 0;
01261 static sdword oldY = 0;
01262
01263 bool CVolume::OnMouseMove( sdword sdwX, sdword sdwY, sdword sdwZ )
01264 {
01265 if(leftKeyDown)
01266 {
01267 rotY += sdwX;
01268 rotX += sdwY;
01269 }
01270 if(middleKeyDown)
01271 {
01272
01273 }
01274 return true;
01275 }
01276
01277 bool CVolume::OnMouseKeyDown( byte bKey )
01278 {
01279 switch(bKey)
01280 {
01281 case 1: leftKeyDown = true; break;
01282
01283 case 4: middleKeyDown = true; break;
01284 }
01285 return true;
01286 }
01287
01288 bool CVolume::OnMouseKeyUp( byte bKey )
01289 {
01290 switch(bKey)
01291 {
01292 case 1: leftKeyDown = false; break;
01293
01294 case 4: middleKeyDown = false; break;
01295 }
01296 return true;
01297 }