void CGameMap::calcCellHeights() { CRandomFast rnd; const int NEIGHBOUR_X[8] = { -1, 0, 1, -1, 1, -1, 0, 1 }; const int NEIGHBOUR_Y[8] = { -1, -1, -1, 0, 0, 1, 1, 1 }; int idx = 0; for( int y = 0; y < mCellsY; ++y ) { for( int x = 0; x < mCellsX; ++x, ++idx ) { if( !isBlood( mCells[idx].type ) ) continue; // see if any of 8-neighbors is a bone bool nearBone = false; if( x < 1 || x >= mCellsX-1 || y < 1 || y >= mCellsY-1 ) nearBone = true; else { for( int i = 0; i < 8; ++i ) { int nidx = idx + NEIGHBOUR_Y[i]*mCellsX + NEIGHBOUR_X[i]; if( !isCellBlood(nidx) ) { nearBone = true; break; } } } mCells[idx].nearBone = nearBone; const int SAMPLING_R = 20; int emptyR = 0; for( int r = 1; r < SAMPLING_R; ++r ) { const int samples = round( 2*D3DX_PI*r * 0.25f ); float dphi = 2*D3DX_PI / samples; float phi = gRandom.getFloat( dphi ); bool empty = true; for( int i = 0; i < samples; ++i, phi += dphi ) { int px = round( x + cosf(phi) * r ); int py = round( y + sinf(phi) * r ); if( px < 0 || py < 0 || px >= mCellsX || py >= mCellsY ) { empty = false; break; } if( !isCellBlood(py*mCellsX+px) ) { empty = false; break; } } if( !empty ) break; ++emptyR; } mCells[idx].height += (1-powf(1-(float)emptyR/SAMPLING_R, 2)) * SAMPLING_R * 0.2f; } } }
bool CGameMap::checkMapValidity() const { // invalid map topology is: // XO or OX // OX XO // i.e. when two blood cells meet only diagonally for( int y = 0; y < mCellsY-1; ++y ) { for( int x = 0; x < mCellsX-1; ++x ) { eCellType t00 = getCell( x, y ).type; eCellType t01 = getCell( x, y+1 ).type; eCellType t10 = getCell( x+1, y ).type; eCellType t11 = getCell( x+1, y+1 ).type; if( isBlood(t00) && isBlood(t11) && !isBlood(t01) && !isBlood(t10) ) return false; if( !isBlood(t00) && !isBlood(t11) && isBlood(t01) && isBlood(t10) ) return false; } } return true; }
std::string CGameMap::initialize() { assert( !mCells ); /* Format of map data: string Tissue Name int32 Tissue Bitmap Length byte[] Tissue Bitmap (200*200) string Entites text file string Streams text file string Walls text files */ const BYTE* data; // // parse name mName = bu::receiveStr(); // TBD: workaround around Richard's funky stuff int lastSlash = mName.find_last_of( "\\//" ); if( lastSlash >= 0 ) mName = mName.substr( lastSlash+1, mName.length()-lastSlash ); CONS << "Game map name: " << mName << endl; // // read map bitmap int bmpSize = bu::receiveInt(); net::receiveChunk( data, bmpSize, true ); // compute CRC of the bitmap const char* bmpFile = (const char*)data; mCRC = boost::crc<32,0xFFFFFFFF,0,0,false,false>( bmpFile, bmpSize ); HRESULT hr; D3DXIMAGE_INFO bitmapInfo; hr = D3DXGetImageInfoFromFileInMemory( bmpFile, bmpSize, &bitmapInfo ); if( FAILED(hr) ) { return "Error in game map - incorrect tissue bitmap format"; } assert( bitmapInfo.Width > 10 && bitmapInfo.Height > 10 ); assert( bitmapInfo.Width * bitmapInfo.Height <= 256*256 ); if( bitmapInfo.Width < 10 || bitmapInfo.Height < 10 ) { return "Error in game map - map is too small"; } if( bitmapInfo.Width * bitmapInfo.Height > 256*256 ) { return "Error in game map - map is too large"; } mCellsX = bitmapInfo.Width; mCellsY = bitmapInfo.Height; mCells = new SCell[ mCellsX * mCellsY ]; CD3DDevice& dx = CD3DDevice::getInstance(); IDirect3DSurface9* surface = 0; hr = dx.getDevice().CreateOffscreenPlainSurface( bitmapInfo.Width, bitmapInfo.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surface, NULL ); assert( SUCCEEDED(hr) ); hr = D3DXLoadSurfaceFromFileInMemory( surface, NULL, NULL, bmpFile, bmpSize, NULL, D3DX_DEFAULT, 0, NULL ); if( FAILED(hr) ) { return "Error in game map - incorrect cells map format"; } D3DLOCKED_RECT lr; surface->LockRect( &lr, NULL, D3DLOCK_READONLY ); const char* linePtr = (const char*)lr.pBits; for( int y = 0; y < mCellsY; ++y ) { const D3DCOLOR* p = (const D3DCOLOR*)linePtr; for( int x = 0; x < mCellsX; ++x ) { SCell& cell = mCells[y*mCellsX+x]; switch( *p ) { case 0xFFff0000: cell.type = CELL_BLOOD1; cell.color = CCOLOR_BLOOD; break; case 0xFF00ff00: cell.type = CELL_BLOOD2; cell.color = CCOLOR_BLOOD; break; case 0xFF0000ff: cell.type = CELL_BLOOD3; cell.color = CCOLOR_BLOOD; break; case 0xFF800000: cell.type = CELL_BLOOD1; cell.color = CCOLOR_BONE; break; case 0xFF008000: cell.type = CELL_BLOOD2; cell.color = CCOLOR_BONE; break; case 0xFF000080: cell.type = CELL_BLOOD3; cell.color = CCOLOR_BONE; break; case 0xFFC80000: cell.type = CELL_BLOOD1; cell.color = CCOLOR_NEURON; break; case 0xFF00C800: cell.type = CELL_BLOOD2; cell.color = CCOLOR_NEURON; break; case 0xFF0000C8: cell.type = CELL_BLOOD3; cell.color = CCOLOR_NEURON; break; default: cell.type = CELL_BONE; cell.color = CCOLOR_BLOOD; } cell.height = MIN_CELL_HEIGHT; cell.nearBone = true; ++p; } linePtr += lr.Pitch; } surface->UnlockRect(); surface->Release(); // check map validity if( !checkMapValidity() ) return "Tissue contains invalid topology (cells adjacent only diagonally)"; // // read entities std::string pts = bu::receiveStr(); char* ptsFile = (char*)pts.c_str(); // HACK const char* tokens = "\n\r"; const char* pline = strtok( ptsFile, tokens ); do { if( !pline ) break; int etype, eposx, eposy; int fread = sscanf( pline, "%i:%i:%i", &eposx, &eposy, &etype ); if( fread != 3 ) break; mPoints.push_back( SPoint(ePointType(etype), eposx, eposy ) ); } while( pline = strtok( NULL, tokens ) ); // // read streams std::string strms = bu::receiveStr(); // streams char* strmsFile = (char*)strms.c_str(); // HACK pline = strtok( strmsFile, tokens ); do { if( !pline ) break; int sx, sy, sw, sh, sdir; int fread = sscanf( pline, "%i:%i:%i:%i:%i", &sx, &sy, &sw, &sh, &sdir ); assert( sx >= 0 && sx < mCellsX ); assert( sy >= 0 && sy < mCellsY ); assert( sx+sw <= mCellsX ); assert( sy+sh <= mCellsY ); assert( sdir >= 0 && sdir <= 3 ); assert( fread == 5 ); if( fread != 5 ) break; SStream strm; strm.x = sx; strm.y = sy; strm.width = sw; strm.height = sh; switch( sdir ) { case 0: strm.deltaX = 0; strm.deltaY = 1; break; case 1: strm.deltaX = 0; strm.deltaY = -1; break; case 2: strm.deltaX = 1; strm.deltaY = 0; break; case 3: strm.deltaX = -1; strm.deltaY = 0; break; } mStreams.push_back( strm ); } while( pline = strtok( NULL, tokens ) ); // TBD: walls bu::receiveStr(); // walls // // all is loaded now // calculate cell heights calcCellHeights(); // add some decorative elements static int DECOR_TYPES_IN_TISSUE[DECOR_POINT_TYPE_COUNT] = { (1<<CCOLOR_BLOOD), (1<<CCOLOR_BLOOD), (1<<CCOLOR_BLOOD), (1<<CCOLOR_BONE), (1<<CCOLOR_BONE), (1<<CCOLOR_BONE) | (1<<CCOLOR_BLOOD), (1<<CCOLOR_NEURON), (1<<CCOLOR_NEURON), (1<<CCOLOR_NEURON), (1<<CCOLOR_NEURON), (1<<CCOLOR_NEURON), (1<<CCOLOR_NEURON)|(1<<CCOLOR_BLOOD)|(1<<CCOLOR_BONE), }; const int DECOR_PTS_COUNT = 125; const int MAX_TRY_COUNT = DECOR_PTS_COUNT * 10; int decPtsCounter = 0; int tryCounter = 0; while( decPtsCounter < DECOR_PTS_COUNT && tryCounter < MAX_TRY_COUNT ) { ++tryCounter; int x = gRandom.getUInt() % mCellsX; int y = gRandom.getUInt() % mCellsY; const SCell& cell = mCells[pos2index(x,y)]; if( !isBlood(cell.type) || cell.nearBone ) continue; if( cell.height < 2.0f ) continue; int ptType = gRandom.getUInt() % DECOR_POINT_TYPE_COUNT; if( !(DECOR_TYPES_IN_TISSUE[ptType] & (1<<cell.color)) ) continue; mPoints.push_back( SPoint(PT_DECORATIVE,x,y, ptType) ); decPtsCounter++; } // register level texture CSharedTextureBundle::getInstance().registerTexture( RID_TEX_LEVEL, *new CGameMapTextureCreator( *this ) ); return ""; // all ok! }
//------------------------------------------------------------------------------ void vtkMEDRayCastCleaner::Execute() //------------------------------------------------------------------------------ { vtkStructuredPoints *outputImage = this->GetOutput(); this->GetInput()->Update(); double range[2]; double newValue, boneValue; //generating a copy of the input outputImage->DeepCopy(this->GetInput()); outputImage->UpdateData(); outputImage->Update(); //getting image dimension for neighbors calculation outputImage->GetDimensions(VolumeDimension); //Creating a copy of data array //(proximity checks need to be done with unmodified original values) vtkDataArray* imgScalars = (vtkDataArray*)outputImage->GetPointData()->GetScalars(); vtkUnsignedShortArray * newScalars; vtkNEW(newScalars); int nPoints=outputImage->GetNumberOfPoints(); imgScalars->GetRange(range); newScalars->SetNumberOfTuples(nPoints); newScalars->SetNumberOfComponents(1); for (int i=0;i<nPoints;i++) { newValue=scalarShift(imgScalars->GetTuple1(i)); newScalars->SetTuple1(i,newValue); } //In MR_MODALITY The cleaner just make scalarshift to avoid vtkVolumeRayCastMapper errors //In CT_MODALITY the cleaner remove the blood from bone boundary if (Modality==CT_MODALITY) { for (int i=0;i<nPoints;i++) { //this filter removes border interpolation values from bone boundary //if i get a blood voxel and a neighbor is a bone I set it's value //to bone lower threshold if (isBlood(imgScalars->GetTuple1(i))) { int maxSidesInNeighboors=BoneInNeighborsAffinity(i,imgScalars); if (maxSidesInNeighboors) { //If there is a bone neighbors we set a bone value in output depending on //level of affinity, in this manner if there is a high affinity the output //voxel has an high level of opacity in raycast pipe boneValue= scalarShift(BoneLowerThreshold*(1.0+(maxSidesInNeighboors*0.02))); newScalars->SetTuple1(i, boneValue); } } } } //settings new scalar values to output volume outputImage->GetPointData()->SetScalars(newScalars); outputImage->GetPointData()->Modified(); outputImage->GetPointData()->Update(); outputImage->UpdateData(); outputImage->Update(); this->SetOutput(outputImage); vtkDEL(newScalars); }