| /*************************************************************************/ |
| /* */ |
| /* Copyright (c) 1994 Stanford University */ |
| /* */ |
| /* All rights reserved. */ |
| /* */ |
| /* Permission is given to use, copy, and modify this software for any */ |
| /* non-commercial purpose as long as this copyright notice is not */ |
| /* removed. All other uses, including redistribution in whole or in */ |
| /* part, are forbidden without prior written permission. */ |
| /* */ |
| /* This software is provided with absolutely no warranty and no */ |
| /* support. */ |
| /* */ |
| /*************************************************************************/ |
| |
| /****************************************************************************** |
| * * |
| * octree.c: Perform hiearchical enumeration of dataset. * |
| * * |
| ******************************************************************************/ |
| |
| #include "incl.h" |
| |
| #define WRITE_PYR(IBIT,ILEVEL,IZ,IY,IX)\ |
| (PYR_ADDRESS(ILEVEL,IZ,IY,IX),\ |
| *pyr_address2|=(IBIT)<<pyr_offset2) |
| |
| /* The following declarations show the layout of the .pyr file. */ |
| /* If changed, the version number must be incremented and code */ |
| /* written to handle loading of both old and current versions. */ |
| |
| /* Version for new .pyr files: */ |
| #define PYR_CUR_VERSION 1 /* Initial release */ |
| uint16_t pyr_version; /* Version of this .pyr file */ |
| |
| uint16_t pyr_levels; /* Number of levels in this pyramid */ |
| |
| uint16_t pyr_len[MAX_PYRLEVEL+1][NM]; /* Number of voxels on each level */ |
| uint16_t pyr_voxlen[MAX_PYRLEVEL+1][NM]; /* Size of voxels on each level */ |
| |
| uint32_t pyr_length[MAX_PYRLEVEL+1]; /* Total number of bytes on this level */ |
| /* (= (int)((product of lens+7)/8)) */ |
| BYTE *pyr_address[MAX_PYRLEVEL+1];/* Pointer to binary pyramid */ |
| /* (only pyr_levels sets of lens, lengths, */ |
| /* and 3-D arrays are written to file) */ |
| |
| /* End of layout of .pyr file. */ |
| |
| /* Subscripted access to binary pyramid */ |
| /* (PYR_ADDRESS only computes temporaries, */ |
| /* most others invoke PYR_ADDRESS, then: */ |
| /* PYR returns char with bit in low bit,*/ |
| /* CLEAR_PYR clears bit to 0, */ |
| /* SET_PYR sets bit to 1, */ |
| /* WRITE_PYR ORs BOOLEAN IBIT into bit, */ |
| /* OVERWRITE_PYR clears, then ORs IBIT, */ |
| /* CURRENT_PYR returns at current address)*/ |
| /* Warning: do not invoke any of these */ |
| /* macros more than once per statement, */ |
| /* or values of temporaries may conflict, */ |
| /* depending on optimization by compiler. */ |
| long pyr_offset1, /* Bit offset of desired bit within pyramid */ |
| pyr_offset2; /* Bit offset of bit within byte */ |
| BYTE *pyr_address2; /* Pointer to byte containing bit */ |
| |
| void Compute_Base(); |
| void Or_Neighbors_In_Base(); |
| |
| MAIN_ENV |
| |
| #include "anl.h" |
| |
| Compute_Octree() |
| { |
| int level,max_len; |
| int i; |
| max_len = 0; |
| for (i=0; i<NM; i++) { |
| max_len = MAX(max_len,opc_len[i]); |
| } |
| pyr_levels = 1; |
| while ((1<<(pyr_levels-1)) < max_len) |
| pyr_levels++; |
| printf(" Computing binary pyramid of %d levels...\n", |
| pyr_levels); |
| |
| for (i=0; i<NM; i++) { |
| pyr_len[0][i] = opc_len[i]; |
| pyr_voxlen[0][i] = 1; |
| } |
| pyr_length[0] = (pyr_len[0][X]*pyr_len[0][Y]*pyr_len[0][Z]+7)/8; |
| Allocate_Pyramid_Level(&pyr_address[0], pyr_length[0]); |
| |
| printf(" Computing octree base...\n"); |
| |
| Global->Index = NODE0; |
| |
| /* POSSIBLE ENHANCEMENT: If you did want to replicate the octree |
| on all processors, don't do this create. |
| */ |
| |
| #ifndef SERIAL_PREPROC |
| for (i=1; i<num_nodes; i++) CREATE(Compute_Base) |
| #endif |
| |
| Compute_Base(); |
| |
| printf(" Performing OR of eight neighbors in binary mask...\n"); |
| |
| Global->Index = 0; |
| |
| |
| /* POSSIBLE ENHANCEMENT: If you did want to replicate the octree |
| on all processors, don't do this create. |
| */ |
| |
| #ifndef SERIAL_PREPROC |
| for (i=1; i<num_nodes; i++) CREATE(Or_Neighbors_In_Base) |
| #endif |
| |
| Or_Neighbors_In_Base(); |
| |
| for (level=1; level<pyr_levels; level++) { |
| for (i=0; i<NM; i++) { |
| if (pyr_len[level-1][i] > 1) { |
| pyr_len[level][i] = |
| (pyr_len[level-1][i]+1)>>1; |
| pyr_voxlen[level][i] = |
| pyr_voxlen[level-1][i]<<1; |
| } |
| else { |
| pyr_len[level][i] = |
| pyr_len[level-1][i]; |
| pyr_voxlen[level][i] = |
| pyr_voxlen[level-1][i]; |
| } |
| } |
| pyr_length[level] = (pyr_len[level][X]* |
| pyr_len[level][Y]*pyr_len[level][Z]+7)/8; |
| Allocate_Pyramid_Level(&pyr_address[level], pyr_length[level]); |
| Compute_Pyramid_Level(level); |
| } |
| } |
| |
| |
| void Compute_Base() |
| { |
| int outx, outy, outz, i; |
| int pmap_partition,zstart,zstop; |
| int num_xqueue,num_yqueue,num_zqueue,num_queue; |
| int xstart,xstop,ystart,ystop; |
| int my_node; |
| |
| LOCK(Global->IndexLock); |
| my_node = Global->Index++; |
| UNLOCK(Global->IndexLock); |
| my_node = my_node%num_nodes; |
| |
| /* POSSIBLE ENHANCEMENT: Here's where one might bind the process to a |
| processor, if one wanted to. |
| */ |
| |
| num_xqueue = ROUNDUP((float)pyr_len[0][X]/(float)voxel_section[X]); |
| num_yqueue = ROUNDUP((float)pyr_len[0][Y]/(float)voxel_section[Y]); |
| num_zqueue = ROUNDUP((float)pyr_len[0][Z]/(float)voxel_section[Z]); |
| num_queue = num_xqueue * num_yqueue * num_zqueue; |
| xstart = (my_node % voxel_section[X]) * num_xqueue; |
| xstop = MIN(xstart+num_xqueue,pyr_len[0][X]); |
| ystart = ((my_node / voxel_section[X]) % voxel_section[Y]) * num_yqueue; |
| ystop = MIN(ystart+num_yqueue,pyr_len[0][Y]); |
| zstart = (my_node / (voxel_section[X] * voxel_section[Y])) * num_zqueue; |
| zstop = MIN(zstart+num_zqueue,pyr_len[0][Z]); |
| |
| /* POSSIBLE ENHANCEMENT: If you did want to replicate the octree |
| on all processors, then execute what's in the SERIAL_PREPROC ifdef below. |
| */ |
| |
| #ifdef SERIAL_PREPROC |
| zstart = 0; |
| zstop = pyr_len[0][Z]; |
| ystart = 0; |
| ystop = pyr_len[0][Y]; |
| xstart = 0; |
| xstop = pyr_len[0][X]; |
| #endif |
| |
| for (outz=zstart; outz<zstop; outz++) { |
| for (outy=ystart; outy<ystop; outy++) { |
| for (outx=xstart; outx<xstop; outx++) { |
| if (OPC(outz,outy,outx) == 0) /* mask bit is one unless opacity */ |
| WRITE_PYR(0,0,outz,outy,outx); /* value is zero. */ |
| else |
| WRITE_PYR(1,0,outz,outy,outx); |
| } |
| } |
| } |
| |
| /* POSSIBLE ENHANCEMENT: If you did want to replicate the octree |
| on all processors, then this computation is serial and you don't need |
| this barrier either. |
| */ |
| |
| #ifndef SERIAL_PREPROC |
| BARRIER(Global->SlaveBarrier,num_nodes); |
| #endif |
| } |
| |
| |
| void Or_Neighbors_In_Base() |
| { |
| int outx,outy,outz; /* Loop indices in image space */ |
| int outx_plus_one,outy_plus_one,outz_plus_one; |
| int i; |
| BOOLEAN bit; |
| int pmap_partition,zstart,zstop; |
| int my_node; |
| |
| LOCK(Global->IndexLock); |
| my_node = Global->Index++; |
| UNLOCK(Global->IndexLock); |
| my_node = my_node%num_nodes; |
| |
| /* POSSIBLE ENHANCEMENT: Here's where one might bind the process to a |
| processor, if one wanted to. |
| */ |
| |
| /* assumed for now that z direction has enough parallelism */ |
| pmap_partition = ROUNDUP((double)pyr_len[0][Z]/(double)num_nodes); |
| zstart = pmap_partition * my_node; |
| zstop = MIN(zstart+pmap_partition,pyr_len[0][Z]); |
| |
| /* POSSIBLE ENHANCEMENT: If you did want to replicate the octree |
| on all processors, then you should execute what's in the SERIAL_PREPROC |
| ifdef below. |
| */ |
| |
| #ifdef SERIAL_PREPROC |
| zstart = 0; |
| zstop = pyr_len[0][Z]; |
| #endif |
| |
| for (outz=zstart; outz<zstop; outz++) { |
| outz_plus_one = MIN(outz+1,pyr_len[0][Z]-1); |
| for (outy=0; outy<pyr_len[0][Y]; outy++) { |
| outy_plus_one = MIN(outy+1,pyr_len[0][Y]-1); |
| for (outx=0; outx<pyr_len[0][X]; outx++) { |
| outx_plus_one = MIN(outx+1,pyr_len[0][X]-1); |
| |
| bit = PYR(0,outz,outy,outx); |
| bit |= PYR(0,outz,outy,outx_plus_one); |
| bit |= PYR(0,outz,outy_plus_one,outx); |
| bit |= PYR(0,outz,outy_plus_one,outx_plus_one); |
| bit |= PYR(0,outz_plus_one,outy,outx); |
| bit |= PYR(0,outz_plus_one,outy,outx_plus_one); |
| bit |= PYR(0,outz_plus_one,outy_plus_one,outx); |
| bit |= PYR(0,outz_plus_one,outy_plus_one,outx_plus_one); |
| |
| WRITE_PYR(bit,0,outz,outy,outx); |
| } |
| } |
| } |
| |
| /* POSSIBLE ENHANCEMENT: If you did want to replicate the octree |
| on all processors, then this computation is serial and you don't |
| need this barrier either. |
| */ |
| |
| #ifndef SERIAL_PREPROC |
| BARRIER(Global->SlaveBarrier,num_nodes); |
| #endif |
| } |
| |
| |
| Allocate_Pyramid_Level(address, length) |
| BYTE **address; |
| long length; |
| { |
| unsigned int i,j,size,type_per_page,count,block; |
| unsigned int p,numbytes; |
| |
| printf(" Allocating pyramid level of %ld bytes...\n", |
| length*sizeof(BYTE)); |
| |
| /* POSSIBLE ENHANCEMENT: If you want to replicate the octree |
| on all processors, then replace the macro below with a regular malloc. |
| */ |
| |
| *address = (BYTE *)NU_MALLOC(length*sizeof(BYTE),0); |
| |
| if (*address == NULL) |
| Error(" No space available for pyramid level.\n"); |
| |
| /* POSSIBLE ENHANCEMENT: Here's where one might distribute the |
| octree among physical memories if one wanted to. |
| */ |
| |
| for (i=0; i<length; i++) *(*address+i) = 0; |
| |
| } |
| |
| |
| Compute_Pyramid_Level(level) |
| int level; |
| { |
| int outx,outy,outz; /* Loop indices in image space */ |
| int i; |
| int inx,iny,inz; |
| int inx_plus_one,iny_plus_one,inz_plus_one; |
| BOOLEAN bit; |
| |
| printf(" Computing pyramid level %d from level %d...\n", |
| level,level-1); |
| for (outz=0; outz<pyr_len[level][Z]; outz++) { |
| inz = outz<<1; |
| inz_plus_one = MIN(inz+1,pyr_len[level-1][Z]-1); |
| for (outy=0; outy<pyr_len[level][Y]; outy++) { |
| iny = outy<<1; |
| iny_plus_one = MIN(iny+1,pyr_len[level-1][Y]-1); |
| for (outx=0; outx<pyr_len[level][X]; outx++) { |
| inx = outx<<1; |
| inx_plus_one = MIN(inx+1,pyr_len[level-1][X]-1); |
| |
| bit = PYR(level-1,inz,iny,inx); |
| bit |= PYR(level-1,inz,iny,inx_plus_one); |
| bit |= PYR(level-1,inz,iny_plus_one,inx); |
| bit |= PYR(level-1,inz,iny_plus_one,inx_plus_one); |
| bit |= PYR(level-1,inz_plus_one,iny,inx); |
| bit |= PYR(level-1,inz_plus_one,iny,inx_plus_one); |
| bit |= PYR(level-1,inz_plus_one,iny_plus_one,inx); |
| bit |= PYR(level-1,inz_plus_one,iny_plus_one,inx_plus_one); |
| |
| WRITE_PYR(bit,level,outz,outy,outx); |
| } |
| } |
| } |
| } |
| |
| |
| Load_Octree(filename) |
| char filename[]; |
| { |
| char local_filename[FILENAME_STRING_SIZE]; |
| int fd,level; |
| |
| strcpy(local_filename,filename); |
| strcat(local_filename,".pyr"); |
| fd = Open_File(local_filename); |
| |
| Read_Shorts(fd,&pyr_version, (long)sizeof(pyr_version)); |
| if (pyr_version != PYR_CUR_VERSION) |
| Error(" Can't load version %d file\n",pyr_version); |
| |
| Read_Shorts(fd,&pyr_levels,(long)sizeof(pyr_levels)); |
| Read_Shorts(fd,pyr_len,(long)(pyr_levels*NM*sizeof(uint16_t))); |
| Read_Shorts(fd,pyr_voxlen,(long)(pyr_levels*NM*sizeof(uint16_t))); |
| Read_Longs(fd,pyr_length,(long)(pyr_levels*sizeof(uint32_t))); |
| |
| printf(" Loading binary pyramid of %d levels...\n",pyr_levels); |
| for (level=0; level<pyr_levels; level++) { |
| Allocate_Pyramid_Level(&pyr_address[level],pyr_length[level]); |
| printf(" Loading pyramid level %d from .pyr file...\n",level); |
| Read_Bytes(fd,pyr_address[level],(long)(pyr_length[level]*sizeof(BYTE))); |
| } |
| Close_File(fd); |
| } |
| |
| |
| Store_Octree(filename) |
| char filename[]; |
| { |
| char local_filename[FILENAME_STRING_SIZE]; |
| int fd,level; |
| |
| strcpy(local_filename,filename); |
| strcat(local_filename,".pyr"); |
| fd = Create_File(local_filename); |
| |
| pyr_version = PYR_CUR_VERSION; |
| Write_Shorts(fd,&pyr_version,(long)sizeof(pyr_version)); |
| |
| Write_Shorts(fd,&pyr_levels,(long)sizeof(pyr_levels)); |
| Write_Shorts(fd,pyr_len,(long)(pyr_levels*NM*sizeof(uint16_t))); |
| Write_Shorts(fd,pyr_voxlen,(long)(pyr_levels*NM*sizeof(uint16_t))); |
| Write_Longs(fd,pyr_length,(long)(pyr_levels*sizeof(uint32_t))); |
| |
| printf(" Storing binary pyramid of %d levels...\n",pyr_levels); |
| for (level=0; level<pyr_levels; level++) { |
| printf(" Storing pyramid level %d into .pyr file...\n",level); |
| |
| Write_Bytes(fd,pyr_address[level],(long)(pyr_length[level]*sizeof(BYTE))); |
| } |
| Close_File(fd); |
| } |
| |
| |
| |
| |
| |