00001 /*************************************************************************** 00002 CellProjector.cpp - description 00003 ------------------- 00004 begin : Thu May 1 2003 00005 copyright : (C) 2003 by tmeng 00006 email : tmeng@sfu.ca 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include <string.h> //for strcmp 00019 00020 #include "CellProjector.h" 00021 00022 //---------------------------------------------------------------------------- 00023 //------------------------- Class Variables Declaration ---------------------- 00024 //---------------------------------------------------------------------------- 00025 00026 const int vu111211a::TETS_DEF_5_FOLD[10][4] = //checked by inspection 00027 {{4,0,1,2}, {7,1,3,2}, {4,2,1,7}, {4,7,6,2}, {4,5,7,1}, //first scheme 00028 {6,0,3,2}, {5,0,1,3}, {5,6,0,3}, {4,5,6,0}, {5,7,6,3}}; //second scheme 00029 00030 const int vu111211a::TETS_DEF_6_FOLD[6][4] = //checked by inspection 00031 {{5,1,7,6}, {5,1,6,4}, {4,1,6,0}, {0,1,6,2}, {6,1,3,2}, {6,1,7,3}}; 00032 00033 //The voxel at origin has 8 vertices, each with x,y,z component 00034 const int vu111211a::VOXEL_VERTEX_LOCATIONS[8][3] = 00035 {{0,0,0}, {1,0,0}, {0,1,0}, {1,1,0}, 00036 {0,0,1}, {1,0,1}, {0,1,1}, {1,1,1}}; 00037 00038 const int vu111211a::TRIANGLE_DEF[4][3] = //checked by inspecting code 00039 {{0,1,2}, {1,3,2}, {0,2,3}, {0,3,1}}; 00040 00041 //---------------------------------------------------------------------------- 00042 //------------------------- The default constructor -------------------------- 00043 //---------------------------------------------------------------------------- 00044 00045 vu111211a::vu111211a() 00046 : m_state(NORMAL), m_subdivScheme(SIX_FOLD), m_isSort(false), 00047 m_isRender(false), m_tetIndex(0), m_grid() 00048 //m_View is set elsewhere, m_ImgBuffer set later. 00049 { 00050 } 00051 00052 //---------------------------------------------------------------------------- 00053 //------------------------- The copy constructor ----------------------------- 00054 //---------------------------------------------------------------------------- 00055 00056 vu111211a::vu111211a(const vu111211a& inst) 00057 { 00058 *this = inst; //invokes operator=, avoids redundent code 00059 } 00060 00061 //---------------------------------------------------------------------------- 00062 //------------------------- The destructor ----------------------------------- 00063 //---------------------------------------------------------------------------- 00064 00065 vu111211a::~vu111211a() 00066 { 00067 } 00068 00069 //---------------------------------------------------------------------------- 00070 //------------------------- The assignment operator -------------------------- 00071 //---------------------------------------------------------------------------- 00072 00073 vu111211a& vu111211a::operator=(const vu111211a& rhs) 00074 { 00075 if (this != &rhs) 00076 { 00077 vu111211::operator=(rhs); //chain to parent. 00078 m_View = rhs.m_View; 00079 m_ImgBuffer = rhs.m_ImgBuffer; 00080 m_state = rhs.m_state; 00081 m_subdivScheme = rhs.m_subdivScheme; 00082 m_isSort = rhs.m_isSort; 00083 m_isRender = rhs.m_isRender; 00084 m_tetIndex = rhs.m_tetIndex; 00085 m_grid = rhs.m_grid; 00086 } 00087 return *this; 00088 } 00089 00090 //---------------------------------------------------------------------------- 00091 //------------------------- public setViewVectors() -------------------------- 00092 //---------------------------------------------------------------------------- 00093 00094 void vu111211a::setViewVectors(const vuVector& view,const vuVector& up,const vuVector& right) 00095 { 00096 m_View = view; 00097 //m_View is the offset between the camera and the origin 00098 //so it is the opposite of the viewRay. 00099 } 00100 00101 //---------------------------------------------------------------------------- 00102 //------------------------- public initOpenGL() ------------------------------ 00103 //---------------------------------------------------------------------------- 00104 00105 void vu111211a::initOpenGL() const 00106 //I've looked in CellProjector's initGlut function, everything that's 00107 //there seems to be here, plus some more. Will need to clean up later. 00108 { 00109 GLfloat shininess = 50.0f; //very shiny material. 00110 GLfloat specular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; 00111 00112 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); 00113 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular); 00114 glEnable(GL_COLOR_MATERIAL); 00115 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); 00116 //after this line, OpenGL pays attention to glColor 00117 //and not glMaterial. Without this line, it would 00118 //be the other way around. 00119 00120 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 00121 //GL_FRONT only should NOT work, coz lots of tets will need to have their backfaces 00122 //toward the viewer and they are needed for compositing. 00123 00124 glShadeModel(GL_SMOOTH); 00125 glDisable(GL_DEPTH_TEST); 00126 glDisable(GL_ALPHA_TEST); 00127 glDisable(GL_CULL_FACE); 00128 00129 //For blending and compositing calculations. 00130 glEnable(GL_BLEND); 00131 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 00132 00133 //scaling scales normals, this normalizes them. KEEP. 00134 glEnable(GL_NORMALIZE); //does not have to normalize gradients later on. 00135 //the gradients are just like normals and are passed into glNormal() 00136 //should compare to see how slow this is. If software normalization is 00137 //faster, then should use that. 00138 00139 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //background color; 00140 glClearDepth(1.0f); //default depth 00141 //value clamps to between 0 and 1. If an incoming pixel has a depth value 00142 //less than 1, that pixel will replace the current one. Else, it will be 00143 //discarded. 00144 } 00145 00146 //---------------------------------------------------------------------------- 00147 //------------------------- public render() ---------------------------------- 00148 //---------------------------------------------------------------------------- 00149 00150 void vu111211a::render() 00151 { 00152 if(IsReRendering()) //only if redraw is desired do we render. 00153 { 00154 glClear(GL_COLOR_BUFFER_BIT); //erase color buffer 00155 00156 //Be careful about the following values. Off by 1 -> very distorted images. 00157 //So if image looks correct, couldn't have made a mistake here. 00158 00159 //quick hack to center data set, should be removed later 00160 //don't understand why the offset is needed, but it has 00161 //been working for every data set that I've been reading in. 00162 glMatrixMode(GL_MODELVIEW); 00163 glPushMatrix(); 00164 glTranslatef(0.5f, 0.5f, 0.0f); 00165 00166 //Set the OpenGL light info. Replaces the 0th light that 00167 //may already be shining from somewhere. Let the light be 00168 //fixed to the camera so the data set is always visible. 00169 glLightfv(GL_LIGHT0, GL_POSITION, m_View.getData()); 00170 00171 //Drawing the grid without lighting so it shows up properly. 00172 glDisable(GL_LIGHTING); 00173 m_grid.drawInOpenGL(); 00174 glEnable(GL_LIGHTING); 00175 00176 if ((m_DataSize <= 4096) || (m_isRender)) //16 cubed 00177 { //draw in real time only if data set is small. 00178 m_isRender = false; //only draw once for large data sets. 00179 if (m_isSort) 00180 drawVoxelsSorted(); 00181 else 00182 drawVoxelsUnsorted(); 00183 } 00184 glPopMatrix(); 00185 } 00186 00187 this->writeImgBuffer(); //writes current frame into m_ImgBuffer. 00188 //this line hardly takes up any time (about 6 ms) to execute. 00189 //So leave it in, even if there is no need to access the image 00190 //buffer from the outside. 00191 } 00192 00193 //---------------------------------------------------------------------------- 00194 //------------------------- public drawPic() --------------------------------- 00195 //---------------------------------------------------------------------------- 00196 00197 void vu111211a::drawPic() const 00200 //called by vuCellProjector::DrawFromImage(). 00201 { 00202 glDrawBuffer (GL_FRONT); 00203 glFinish (); 00204 00205 glDisable (GL_BLEND); 00206 00207 glDrawPixels (m_ImgBuffer.getWidth () - 1, m_ImgBuffer.getHeight () - 1, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *) (m_ImgBuffer.get_rgb ())); 00208 glDrawBuffer (GL_BACK); 00209 glDrawPixels (m_ImgBuffer.getWidth () - 1, m_ImgBuffer.getHeight () - 1, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *) (m_ImgBuffer.get_rgb ())); 00210 00211 glFinish (); 00212 00213 glDrawBuffer (GL_BACK); 00214 00215 glEnable (GL_BLEND); 00216 } 00217 00218 //---------------------------------------------------------------------------- 00219 //------------------------- public getBuffer() ------------------------------- 00220 //---------------------------------------------------------------------------- 00221 00222 vuImage* vu111211a::getBuffer () 00223 { 00224 return &m_ImgBuffer; 00225 } 00226 00227 //---------------------------------------------------------------------------- 00228 //------------------------- public read() ------------------------------------ 00229 //---------------------------------------------------------------------------- 00230 00231 bool vu111211a::read() 00232 { 00233 bool success = vu111211::read(); 00234 if (!success) return false; 00235 00236 //don't preprocess the gradients, cause quantized normals 00237 //are not entirely accurate, and float* normals take 12 times 00238 //as much space as the data set and will slow computations 00239 //down or even halt the program. 00240 00241 this->initGrid(); 00242 00243 return true; 00244 } 00245 00246 //---------------------------------------------------------------------------- 00247 //------------------------- public readRaw() --------------------------------- 00248 //---------------------------------------------------------------------------- 00249 00250 bool vu111211a::readRaw(void) 00251 { 00252 dword len; 00253 ifstream in; 00254 00255 #ifdef IS_NOCREATE_NEEDED 00256 in.open(m_FileName, ios::in|ios::binary|ios::nocreate); 00257 #else 00258 // The nocreate is not available on the IRIX boxes that we were compiling 00259 // this code on, so we had to remove this part from 00260 in.open(m_FileName, ios::in|ios::binary); 00261 #endif 00262 if (!in.is_open()) return false; 00263 00264 in.seekg(0, ios::end); 00265 len = in.tellg(); 00266 in.seekg(0, ios::beg); 00267 00268 in >> m_Dim1Size >> m_Dim2Size >> m_Dim3Size; 00269 if (in.fail()) return false; 00270 m_DataSize = m_Dim1Size*m_Dim2Size*m_Dim3Size; //volume::m_DataSize 00271 00272 m_Data = new byte[m_DataSize]; //volume::m_Data 00273 in.read((char *) (m_Data), int (m_DataSize)); 00274 if (in.fail()) return false; 00275 00276 in.close(); 00277 00278 //see read() above as to why not preprocess the gradients. 00279 00280 return true; 00281 } 00282 00283 //---------------------------------------------------------------------------- 00284 //------------------------- private drawVoxelsSorted() ----------------------- 00285 //---------------------------------------------------------------------------- 00286 00287 void vu111211a::drawVoxelsSorted() const 00288 { 00289 } 00290 00291 //---------------------------------------------------------------------------- 00292 //------------------------- private drawVoxelsUnSorted() --------------------- 00293 //---------------------------------------------------------------------------- 00294 00295 void vu111211a::drawVoxelsUnsorted() const 00296 { 00297 //CanNOT use the static keyword, else when opening a data set with 00298 //different dimentions, incorrect dimensions will be used. 00299 const int NUM_X_VOXELS = m_Dim1Size - 1; //one less than num of intensities. 00300 const int NUM_Y_VOXELS = m_Dim2Size - 1; 00301 const int NUM_Z_VOXELS = m_Dim3Size - 1; 00302 00303 int x, y, z; //indices for the three respective axes. 00304 for (x = 0; x < NUM_X_VOXELS; x++) 00305 for (y = 0; y < NUM_Y_VOXELS; y++) 00306 for(z = 0; z < NUM_Z_VOXELS; z++) 00307 drawVoxel(x, y, z); 00308 } 00309 00310 //---------------------------------------------------------------------------- 00311 //------------------------- private drawVoxel() ------------------------------ 00312 //---------------------------------------------------------------------------- 00313 00314 void vu111211a::drawVoxel(int x, int y, int z) const 00315 { 00316 int i; 00317 const int VOXEL_ORIGIN[3] = {x,y,z}; 00318 if (m_state == MANUAL_TET) 00319 { 00320 //Need to clear canvas for redrawing. 00321 glClear(GL_DEPTH_BUFFER_BIT); 00322 //can only draw one tet at once with above clearing call. 00323 00324 glDisable(GL_LIGHTING); 00325 glDisable(GL_BLEND); 00326 glEnable(GL_DEPTH_TEST); 00327 00328 switch (m_subdivScheme) 00329 { 00330 case FIVE_FOLD: 00331 drawTet(TETS_DEF_5_FOLD[m_tetIndex], VOXEL_ORIGIN); 00332 break; 00333 case SIX_FOLD: 00334 drawTet(TETS_DEF_6_FOLD[m_tetIndex], VOXEL_ORIGIN); 00335 break; 00336 } 00337 00338 glEnable(GL_LIGHTING); 00339 glEnable(GL_BLEND); 00340 glDisable(GL_DEPTH_TEST); 00341 } 00342 else if (m_state == NORMAL) 00343 { 00344 switch (m_subdivScheme) 00345 { 00346 case FIVE_FOLD: 00347 if((x+y+z)%2) //scheme 1 00348 { //could merge this with else by being smart with for statement. 00349 //int* tetOrder = getTetOrder(); 00350 for (i = 0; i < 5; i++) 00351 drawTet(TETS_DEF_5_FOLD[i], VOXEL_ORIGIN); 00352 } 00353 else //scheme 2, alternate with scheme 1 in all 3 axes 00354 { 00355 //int* tetOrder = getTetOrder(); 00356 for (i = 5; i < 10; i++) 00357 drawTet(TETS_DEF_5_FOLD[i], VOXEL_ORIGIN); 00358 } 00359 break; 00360 case SIX_FOLD: 00361 for (i = 0; i < 6; i++) 00362 drawTet(TETS_DEF_6_FOLD[i], VOXEL_ORIGIN); 00363 }; 00364 } 00365 } 00366 00367 //---------------------------------------------------------------------------- 00368 //------------------------- private drawTet() -------------------------------- 00369 //---------------------------------------------------------------------------- 00370 00371 void vu111211a::drawTet(const int TET_RELATIVE_INDICES[4], const int VOXEL_ORIGIN[3]) const 00372 { 00373 int tet[4][3]; //each tet has 4 vertices of 3 components each. 00374 int i, j; 00375 int vertexIndex; 00376 for (i = 0; i < 4; i++) //for each vertex of tet 00377 //compute the ith vertex of tet. 00378 { 00379 //find the vertex index on the voxel. 00380 vertexIndex = TET_RELATIVE_INDICES[i]; 00381 for (j = 0; j < 3; j++) //for each of x,y,z component 00382 { 00383 //add the xyz offset to the voxel at the origin. 00384 tet[i][j] = VOXEL_VERTEX_LOCATIONS[vertexIndex][j] + VOXEL_ORIGIN[j]; 00385 } 00386 } 00387 //seems right so far by inspecting cout statements 00388 drawTet(tet); 00389 } 00390 00391 //---------------------------------------------------------------------------- 00392 //------------------------- private drawTet() -------------------------------- 00393 //---------------------------------------------------------------------------- 00394 00395 void vu111211a::drawTet(int tetVertexLocations[4][3]) const 00396 { 00397 00398 int i, j; //loop indices 00399 int vertexIndex; 00400 byte intensity; 00401 00402 if (m_state == MANUAL_TET) 00403 { 00404 drawTetNormals(tetVertexLocations); //draw normals for debugging 00405 char orientation[5]; 00406 orientation[4] = '\0'; //nul terminated 00407 getTetOrientation(tetVertexLocations, orientation); 00408 } 00409 00410 glBegin(GL_TRIANGLES); //each triple is a triangle. 00411 00412 for (i = 0; i < 4; i++) //for each triangle 00413 { 00414 for (j = 0; j < 3; j++) //for each of its vertices 00415 { 00416 vertexIndex = TRIANGLE_DEF[i][j]; //draw this vertex in this iteration. 00417 if (m_state == NORMAL) 00418 { 00419 //compute the intensity at the vertex 00420 intensity = this->getIntensity(tetVertexLocations[vertexIndex]); 00421 00422 glColor4f(m_TFunc[intensity][0], 00423 //first [] returns RGBA color array, second [] returns float 00424 //in the range of 0 to 1. 00425 m_TFunc[intensity][1], 00426 m_TFunc[intensity][2], 00427 m_TFunc[intensity][3]); 00428 } 00429 else if (m_state == MANUAL_TET) 00430 { 00431 glColor4f(((i+j)/7.0f+0.5f)/1.5f, 00432 (i/7.0f+0.5f)/1.5f, 00433 (j/7.0f+0.5f)/1.5f, 00434 1.0f); 00435 } 00436 glVertex3iv(tetVertexLocations[vertexIndex]); 00437 } 00438 } 00439 glEnd(); 00440 } 00441 00442 //---------------------------------------------------------------------------- 00443 //------------------------- private drawTetNormals() ------------------------- 00444 //---------------------------------------------------------------------------- 00445 00446 void vu111211a::drawTetNormals(int tetVertexLocations[4][3]) const 00447 { 00448 int i, j; //loop indices. 00449 vuVector v[4]; //vertex locations in float instead of int 00450 00451 //compute the four triangle faces of the tet. 00452 for (i = 0; i < 4; i++) //for each triangle. 00453 { 00454 for (j = 0; j < 3; j++) //for each vertex of the triangle. 00455 { 00456 v[i][j] = (float)(tetVertexLocations[i][j]); 00457 } 00458 } 00459 00460 //Calculating a point inside the tetrahedron 00461 float m = 0.5f; 00462 vuVector p = v[0] + m*(v[1] - v[0]); 00463 p = p + m*(v[2] - p); 00464 p = p + m*(v[3] - p); 00465 00466 //drawing the normals centered at p. 00467 glBegin(GL_LINES); //each new pair is a new line. 00468 vuVector normals[4]; //one for each triangle 00469 this->getTetNormals(tetVertexLocations, normals); 00470 for (i = 0; i < 4; i++) 00471 { 00472 glColor4f(i/6.0f, (i+4)/ 7.0f, i/ 4.0f, 1.0f); 00473 glVertex3fv(p.getData()); 00474 glColor4f(i/4.0f, (i+3)/ 6.0f, i/ 7.0f, 1.0f); 00475 glVertex3fv((p+normals[i]).getData()); 00476 } 00477 glEnd(); //make sure the glBegin and glEnd are not nested 00478 } 00479 00480 //---------------------------------------------------------------------------- 00481 //------------------------- private getTetOrientation() ---------------------- 00482 //---------------------------------------------------------------------------- 00483 00484 void vu111211a::getTetOrientation(int tetVertexLocations[4][3], 00485 char orientation[4] /* out */) const 00486 { 00487 vuVector normals[4]; 00488 this->getTetNormals(tetVertexLocations, normals); 00489 00490 int i; 00491 for (i = 0; i < 4; i++) //for each triangle 00492 { 00493 if (normals[i].dot(m_View) > 0.0f) 00494 //m_View is the offset between the camera and the origin 00495 //so it is the opposite of the viewRay. 00496 { //triangle is pointing TOWARD the viewer (opp dir as view ray) 00497 orientation[i] = '+'; 00498 } 00499 else orientation[i] = '-'; //pointing AWAY from viewer 00500 //note the if else is different from old code, since m_View 00501 //is the view ray negated. 00502 } 00503 } 00504 00505 //---------------------------------------------------------------------------- 00506 //------------------------- private getTetNormals() -------------------------- 00507 //---------------------------------------------------------------------------- 00508 00509 void vu111211a::getTetNormals(int tetVertexLocations[4][3], 00510 vuVector normals[4] /* out */) const 00511 { 00512 /*static*/ const int TRIANGLE_DEF[4][3] = //checked by inspecting code 00513 {{0,1,2}, {1,3,2}, {0,2,3}, {0,3,1}}; 00514 00515 int i, j, k; //loop indices. 00516 int vertexIndex; 00517 vuVector v[4]; //vertex locations in float instead of int 00518 vuVector* triangles[4][3]; //4 triangles, 3 vertices each 00519 00520 //compute the four triangle faces of the tet. 00521 for (i = 0; i < 4; i++) //for each triangle. 00522 { 00523 for (j = 0; j < 3; j++) //for each vertex of the triangle. 00524 { 00525 v[i][j] = (float)(tetVertexLocations[i][j]); //update ith vertex 00526 for (k = 0; k < 3; k++) //for each xyz component of vertex. 00527 { 00528 vertexIndex = TRIANGLE_DEF[i][j]; 00529 triangles[i][j] = &(v[vertexIndex]); //update ith triangle 00530 } 00531 } //ith vertex and ith triangle computed, ok since triangle 00532 //is composed of pointers and other vertices will be changed 00533 //in subsequence iteration of loop. 00534 } 00535 for (i = 0; i < 4; i++) //calculate normal for each triangle. 00536 normals[i] = getNormal(triangles[i]); 00537 } 00538 00539 //---------------------------------------------------------------------------- 00540 //------------------------- private getNormal() ------------------------------ 00541 //---------------------------------------------------------------------------- 00542 00543 vuVector vu111211a::getNormal(vuVector* v[3]) const 00544 { 00545 vuVector normal; 00546 normal = (*v[2] - *v[1]).cross(*v[0] - *v[1]); 00547 return normal; 00548 } 00549 00550 //---------------------------------------------------------------------------- 00551 //------------------------- private getTetIntensity() ------------------------- 00552 //---------------------------------------------------------------------------- 00553 00554 byte vu111211a::getIntensity(int vertex[3]) const 00555 { 00556 //Cannot use "static" because data sets may be of different sizes 00557 //as the user opens and closes data set files. 00558 const int NUM_X_SAMPLES = m_Dim1Size; 00559 const int NUM_Y_SAMPLES = m_Dim2Size; 00560 00561 int x = vertex[0]; 00562 int y = vertex[1]; 00563 int z = vertex[2]; 00564 int intensityIndex = z * (NUM_X_SAMPLES * NUM_Y_SAMPLES) + y * NUM_X_SAMPLES + x; 00565 00566 byte intensity = this->m_Data[intensityIndex]; 00567 00568 return intensity; 00569 } 00570 00571 //---------------------------------------------------------------------------- 00572 //------------------------- private initGrid() ------------------------------- 00573 //---------------------------------------------------------------------------- 00574 00575 void vu111211a::initGrid() 00576 { 00577 float scale = 1.25f; 00578 float width = scale * (m_Dim1Size-1); //x 00579 float height = scale * (m_Dim2Size-1); //y 00580 float depth = scale * (m_Dim3Size-1); //z 00581 00582 m_grid = vuGrid(width, height, depth); 00583 } 00584 00585 //---------------------------------------------------------------------------- 00586 //------------------------- private writeImgBuffer() ------------------------- 00587 //---------------------------------------------------------------------------- 00588 00589 void vu111211a::writeImgBuffer() 00593 //To be used by i.e. a parallel coordinates interface that displays 00594 //renderings from different renderers side by side. 00595 00596 //This function needs to be re-examined to make sure it works. 00597 { 00598 int retval [4]; 00599 glGetIntegerv (GL_VIEWPORT, retval); 00600 m_ImgBuffer.init (retval [2] + 1, retval [3] + 1); 00601 glReadBuffer (GL_FRONT); 00602 glReadPixels (0, 0, m_ImgBuffer.getWidth () - 1, m_ImgBuffer.getHeight () - 1, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *) (m_ImgBuffer.get_rgb ())); 00603 00604 //testing to see if the dimensions are updating with window resizing. 00605 //cout << "dim1:" << retval [2] << "dim2:" << retval [3] << endl; 00606 }