#include #include #include #include #include #include #include #include #include #include #include #include static const double ROT_HORZ_RADIANS = M_PI / 16.0; static const double ROT_VERT_RADIANS = M_PI / 16.0; static const double MOVE_AMOUNT = 10; void help( void ) { printf( "Help:\n" " - F1: show this text.\n" " - F2: toggle edges display.\n" " - F3: Top tour.\n" " - F4: Bottom tour.\n" " - Q/W: increase/decrease maximum voxel intensity.\n" " - q/w: increase/decrease minimum voxel intensity.\n" "\n" " Camera operations:\n" " - UP/DOWN: move camera vertically.\n" " - LEFT/RIGHT: move camera horizontally.\n" " Extra plan operations:\n" " - 1/2: move extra plane to front/back.\n" " - 3/4: move extra plane to left/right.\n" " - 5/6: move extra plane to up/down.\n" " - 7/8: rotate extra plane around y.\n" " - 9/0: rotate extra plane around x.\n" " Plans Operation (model faces):\n" " - F/f: move front plane more to front or to back.\n" " - B/b: move back plane more to back or to front.\n" " - L/l: move left plane more to left or to right.\n" " - R/r: move right plane more to right or to left.\n" " - T/t: move top plane more to top or to bottom.\n" " - O/o: move bottom plane more to bottom or to top.\n" "\n" ); } void do_render( surface_t *surface, const model3d_t *model, const plane_t *planes, const unsigned n_planes, const double rot_y, const double rot_x, const color_t *edge_color, const color_t *bg_color, const uint16_t vmin, const uint16_t vmax ) { render( surface, 0, 0, model, planes, n_planes, rot_y, rot_x, edge_color, bg_color, vmin, vmax ); } void do_tour_top( SDL_Surface *screen, surface_t *surface, const model3d_t *model, const plane_t *planes, const unsigned n_planes, const color_t *edge_color, const color_t *bg_color, const uint16_t vmin, const uint16_t vmax ) { double rot_y, rot_x=M_PI_4; for ( rot_y=0; rot_y < 2 * M_PI; rot_y += ROT_HORZ_RADIANS ) { do_render( surface, model, planes, n_planes, rot_y, rot_x, edge_color, bg_color, vmin, vmax ); SDL_Flip( screen ); } } void do_tour_bottom( SDL_Surface *screen, surface_t *surface, const model3d_t *model, const plane_t *planes, const unsigned n_planes, const color_t *edge_color, const color_t *bg_color, const uint16_t vmin, const uint16_t vmax ) { double rot_y, rot_x=-M_PI_4; for ( rot_y=0; rot_y < 2 * M_PI; rot_y += ROT_HORZ_RADIANS ) { do_render( surface, model, planes, n_planes, rot_y, rot_x, edge_color, bg_color, vmin, vmax ); SDL_Flip( screen ); } } int main( int argc, char *argv[] ) { debug_level = DEBUG_ERR; if ( argc < 2 ) { fprintf( stderr, "Missing SCN file.\n" ); return -1; } model3d_t *model = scn_load( argv[ 1 ] ); uint16_t vmin, vmax; find_intensities( model, &vmin, &vmax ); uint16_t d = sqrt( pow2( model->size.x ) + pow2( model->size.y ) + pow2( model->size.z ) ); if ( SDL_Init( SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE ) != 0) { err( "Could not initialize SDL: %s\n", SDL_GetError() ); return -1; } SDL_Surface *screen = SDL_SetVideoMode( d, d, 32, SDL_SWSURFACE | SDL_DOUBLEBUF ); if ( screen == NULL ) { err( "Could not create screen %dx%d @ %dbpp.\n", d, d, 32 ); return -1; } /* DIRTY OPTIMIZATION HACK * use SDL buffer as our surface buffer */ surface_t surface; surface.size.x = screen->w; surface.size.y = screen->h; surface.buffer = screen->pixels; color_t edge_color, *pedge_color; color_t bg_color, *pbg_color; COLOR_FROM_ARGB( edge_color, COLOR_RED ); COLOR_FROM_ARGB( bg_color, COLOR_YELLOW ); pedge_color = &edge_color; pbg_color = &bg_color; int x = model->size.x / 2 - 1; int y = model->size.y / 2 - 1; int z = model->size.z / 2 - 1; double rot_y=-M_PI_4, rot_x=M_PI_4; unsigned n_planes = 7; plane_t *planes = calloc( n_planes, sizeof( plane_t ) ); planes[ 0 ].point = vector3_init( x, 0, 0 ); planes[ 0 ].normal = vector3_init( 1, 0, 0 ); planes[ 1 ].point = vector3_init( 0, y, 0 ); planes[ 1 ].normal = vector3_init( 0, 1, 0 ); planes[ 2 ].point = vector3_init( 0, 0, z ); planes[ 2 ].normal = vector3_init( 0, 0, 1 ); planes[ 3 ].point = vector3_init( -x-1, 0, 0 ); planes[ 3 ].normal = vector3_init( -1, 0, 0 ); planes[ 4 ].point = vector3_init( 0, -y-1, 0 ); planes[ 4 ].normal = vector3_init( 0, -1, 0 ); planes[ 5 ].point = vector3_init( 0, 0, -z-1 ); planes[ 5 ].normal = vector3_init( 0, 0, -1 ); planes[ 6 ].point = vector3_init( 0, 0, 0 ); planes[ 6 ].normal = vector3_init( 0, 1, 1 ); do_render( &surface, model, planes, n_planes, rot_y, rot_x, pedge_color, pbg_color, vmin, vmax ); SDL_Flip( screen ); matrix4x4_t *rot_y_pos = rotate_y( ROT_HORZ_RADIANS ); matrix4x4_t *rot_y_neg = rotate_y( - ROT_HORZ_RADIANS ); matrix4x4_t *rot_x_pos = rotate_x( ROT_VERT_RADIANS ); matrix4x4_t *rot_x_neg = rotate_x( - ROT_VERT_RADIANS ); help(); int run = 1; int need_render = 0; while ( run ) { SDL_Event e; SDL_WaitEvent( &e ); switch ( e.type ) { case SDL_KEYDOWN: /* ignore keydown */ break; case SDL_KEYUP: switch ( e.key.keysym.sym ) { case SDLK_ESCAPE: run = 0; break; case SDLK_F1: help(); break; case SDLK_F2: if ( pedge_color == NULL ) pedge_color = &edge_color; else pedge_color = NULL; need_render = 1; break; case SDLK_q: if ( e.key.keysym.mod & KMOD_SHIFT ) { if ( vmax + 1 < INT16_MAX ) { vmax += 1; need_render = 1; } } else { if ( ( vmin + 1 < INT16_MAX ) && ( vmin + 1 < vmax ) ) { vmin += 1; need_render = 1; } } break; case SDLK_w: if ( e.key.keysym.mod & KMOD_SHIFT ) { if ( ( vmax > 0 ) && ( vmax > vmin + 1 ) ) { vmax -= 1; need_render = 1; } } else { if ( vmin > 0 ) { vmin -= 1; need_render = 1; } } break; case SDLK_LEFT: rot_y += ROT_HORZ_RADIANS; need_render = 1; break; case SDLK_RIGHT: rot_y -= ROT_HORZ_RADIANS; need_render = 1; break; case SDLK_UP: rot_x += ROT_VERT_RADIANS; need_render = 1; break; case SDLK_DOWN: rot_x -= ROT_VERT_RADIANS; need_render = 1; break; case SDLK_1: if ( VECTOR3_Z( planes[ n_planes - 1 ].point ) < z ) { VECTOR3_Z( planes[ n_planes - 1 ].point ) += MOVE_AMOUNT; need_render = 1; } break; case SDLK_2: if ( VECTOR3_Z( planes[ n_planes - 1 ].point ) > -z ) { VECTOR3_Z( planes[ n_planes - 1 ].point ) -= MOVE_AMOUNT; need_render = 1; } break; case SDLK_3: if ( VECTOR3_X( planes[ n_planes - 1 ].point ) < x ) { VECTOR3_X( planes[ n_planes - 1 ].point ) += MOVE_AMOUNT; need_render = 1; } break; case SDLK_4: if ( VECTOR3_X( planes[ n_planes - 1 ].point ) > -x ) { VECTOR3_X( planes[ n_planes - 1 ].point ) -= MOVE_AMOUNT; need_render = 1; } break; case SDLK_5: if ( VECTOR3_Y( planes[ n_planes - 1 ].point ) < y ) { VECTOR3_Y( planes[ n_planes - 1 ].point ) += MOVE_AMOUNT; need_render = 1; } break; case SDLK_6: if ( VECTOR3_Y( planes[ n_planes - 1 ].point ) > -y ) { VECTOR3_Y( planes[ n_planes - 1 ].point ) -= MOVE_AMOUNT; need_render = 1; } break; case SDLK_7: { vector3_t r; multiply_matrix4x4_vector3( *rot_y_neg, planes[ n_planes - 1 ].normal, &r ); planes[ n_planes - 1 ].normal = r; need_render = 1; } break; case SDLK_8: { vector3_t r; multiply_matrix4x4_vector3( *rot_y_pos, planes[ n_planes - 1 ].normal, &r ); planes[ n_planes - 1 ].normal = r; need_render = 1; } break; case SDLK_9: { vector3_t r; multiply_matrix4x4_vector3( *rot_x_neg, planes[ n_planes - 1 ].normal, &r ); planes[ n_planes - 1 ].normal = r; need_render = 1; } break; case SDLK_0: { vector3_t r; multiply_matrix4x4_vector3( *rot_x_pos, planes[ n_planes - 1 ].normal, &r ); planes[ n_planes - 1 ].normal = r; need_render = 1; } break; case SDLK_f: { if ( e.key.keysym.mod & KMOD_SHIFT ) { if ( VECTOR3_Z( planes[ 2 ].point ) < z ) { VECTOR3_Z( planes[ 2 ].point ) += MOVE_AMOUNT; need_render = 1; } } else { if ( VECTOR3_Z( planes[ 2 ].point ) > -z ) { VECTOR3_Z( planes[ 2 ].point ) -= MOVE_AMOUNT; need_render = 1; } } } break; case SDLK_b: { if ( e.key.keysym.mod & KMOD_SHIFT ) { if ( VECTOR3_Z( planes[ 5 ].point ) > -z ) { VECTOR3_Z( planes[ 5 ].point ) -= MOVE_AMOUNT; need_render = 1; } } else { if ( VECTOR3_Z( planes[ 5 ].point ) < z ) { VECTOR3_Z( planes[ 5 ].point ) += MOVE_AMOUNT; need_render = 1; } } } break; case SDLK_r: { if ( e.key.keysym.mod & KMOD_SHIFT ) { if ( VECTOR3_X( planes[ 0 ].point ) < x ) { VECTOR3_X( planes[ 0 ].point ) += MOVE_AMOUNT; need_render = 1; } } else { if ( VECTOR3_X( planes[ 0 ].point ) > -x ) { VECTOR3_X( planes[ 0 ].point ) -= MOVE_AMOUNT; need_render = 1; } } } break; case SDLK_l: { if ( e.key.keysym.mod & KMOD_SHIFT ) { if ( VECTOR3_X( planes[ 3 ].point ) > -x ) { VECTOR3_X( planes[ 3 ].point ) -= MOVE_AMOUNT; need_render = 1; } } else { if ( VECTOR3_X( planes[ 3 ].point ) < x ) { VECTOR3_X( planes[ 3 ].point ) += MOVE_AMOUNT; need_render = 1; } } } break; case SDLK_t: { if ( e.key.keysym.mod & KMOD_SHIFT ) { if ( VECTOR3_Y( planes[ 1 ].point ) < y ) { VECTOR3_Y( planes[ 1 ].point ) += MOVE_AMOUNT; need_render = 1; } } else { if ( VECTOR3_Y( planes[ 1 ].point ) > -y ) { VECTOR3_Y( planes[ 1 ].point ) -= MOVE_AMOUNT; need_render = 1; } } } break; case SDLK_o: { if ( e.key.keysym.mod & KMOD_SHIFT ) { if ( VECTOR3_Y( planes[ 4 ].point ) > -y ) { VECTOR3_Y( planes[ 4 ].point ) -= MOVE_AMOUNT; need_render = 1; } } else { if ( VECTOR3_Y( planes[ 4 ].point ) < y ) { VECTOR3_Y( planes[ 4 ].point ) += MOVE_AMOUNT; need_render = 1; } } } break; case SDLK_F3: do_tour_top( screen, &surface, model, planes, n_planes, pedge_color, pbg_color, vmin, vmax ); need_render = 1; break; case SDLK_F4: do_tour_bottom( screen, &surface, model, planes, n_planes, pedge_color, pbg_color, vmin, vmax ); need_render = 1; break; default: break; } break; case SDL_ACTIVEEVENT: SDL_Flip( screen ); break; case SDL_QUIT: run = 0; break; default: break; } if ( need_render ) { do_render( &surface, model, planes, n_planes, rot_y, rot_x, pedge_color, pbg_color, vmin, vmax ); SDL_Flip( screen ); need_render = 0; } } matrix4x4_free( rot_y_pos ); matrix4x4_free( rot_y_neg ); matrix4x4_free( rot_x_pos ); matrix4x4_free( rot_x_neg ); free( planes ); model3d_free( model ); SDL_Quit(); return 0; }