int main( int argc, char **argv ) { if ( argc > 1 ) { char * mode = argv[1]; if ( strcmp( mode, "server" ) == 0 ) { // printf( "STUB server mode.\n" ); } else if ( strcmp( mode, "client" ) == 0 ) { printf( "STUB client mode.\n" ); } else if ( strcmp( mode, "local" ) == 0 ) { if ( argc >= 4 ) { int w = atoi( argv[2] ); int h = atoi( argv[3] ); // parameter setup params.bmp = new BMP( w, h ); params.w = w; params.h = h; params.rt.camera.focalLength = 1.0; params.rt.camera.depthOfFocus = 40.0; params.rt.camera.aperture = 1.0; params.rt.camera.pos.y = -2; // raise the camera up slightly params.rt.camera.aspectRatio = static_cast<float>( w ) / static_cast<float>( h ); rt::Sphere s1( Vec3( -9, -13, -44 ), 7, new Dielectric( 1.3 ) ); rt::Sphere s2( Vec3( -2, -13, -88 ), 7, new Metallic( Vec4( 0.7, 0.7, 0.7, 1 ), 0.5 ) ); rt::Sphere s3( Vec3( 10, -13, -66 ), 7, new Lambertian( Vec4( 0.7, 0.7, 0.7, 1 ) ) ); // cornell box faces // top face rt::Plane ptop( Vec3( 0, 20, 0 ), Vec3( 0, -1, 0 ), new Lambertian( Vec4( 0.9, 0.9, 0.9, 1 ) ) ); // bottom face rt::Plane pbot( Vec3( 0, -20, 0 ), Vec3( 0, 1, 0 ), new Lambertian( Vec4( 0.8, 0.8, 0.8, 1 ) ) ); // back face rt::Plane pbak( Vec3( 0, 0, -65 ), Vec3( 0, 0, 1 ), new Lambertian( Vec4( 0.9, 0.9, 0.9, 1 ) ) ); // side faces rt::Plane pr( Vec3( 20, 0, 0 ), Vec3( -1, 0, 0 ), new Lambertian( Vec4( 0.8, 0.3, 0.3, 1 ) ) ); rt::Plane pl( Vec3( -20, 0, 0 ), Vec3( 1, 0, 0 ), new Lambertian( Vec4( 0.3, 0.8, 0.3, 1 ) ) ); params.rt.scene.objects.push_back( &s1 ); params.rt.scene.objects.push_back( &s2 ); params.rt.scene.objects.push_back( &s3 ); // params.rt.scene.objects.push_back( &ptop ); params.rt.scene.objects.push_back( &pbot ); // params.rt.scene.objects.push_back( &pbak ); // params.rt.scene.objects.push_back( &pl ); // params.rt.scene.objects.push_back( &pr ); Worker * worker; struct WorkParams work_params; work_params.bounces = 4; work_params.w = w; work_params.h = h; if ( params.singleThreaded ) { worker = new Worker( work_params ); worker->StartWork(); worker->WaitUntilFinished(); params.bmp = worker->GetOutput(); } else { // multithreaded pthread_t threads[ NUM_THREADS ]; pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); if ( params.useJobs ) { pthread_mutex_init( ¶ms.jobQueue_mutex, NULL ); pthread_cond_init( ¶ms.jobQueueAvailable, NULL ); for ( int i = 0; i < NUM_THREADS; i++ ) { uint64_t t = i; int rc = pthread_create( &threads[i], &attr, startWorker, (void *) t ); } // add jobs to the queue for ( int y = 0; y < h; y++ ) { pthread_mutex_lock( ¶ms.jobQueue_mutex ); params.jobQueue.push( y ); pthread_cond_signal( ¶ms.jobQueueAvailable ); pthread_mutex_unlock( ¶ms.jobQueue_mutex ); } // we're done, wake up all waiting threads pthread_mutex_lock( ¶ms.jobQueue_mutex ); params.allJobsQueued = true; pthread_cond_broadcast( ¶ms.jobQueueAvailable ); pthread_mutex_unlock( ¶ms.jobQueue_mutex ); } else { // simple thread-index based work division for ( int i = 0; i < NUM_THREADS; i++ ) { uint64_t t = i; int rc = pthread_create( &threads[i], &attr, renderTile, (void *) t ); } } void * status; for ( int i = 0; i < NUM_THREADS; i++ ) { pthread_join( threads[i], &status ); } } params.bmp->Write( "hello.bmp" ); // worker will be automatically reclaimed by the OS when we exit, so no need to manually call delete // params.bmp will be automatically reclaimed by the OS when we exit, so no need to delete } else { printf( "usage: ray local width height\n" ); } } else { printf( "usage: ray [server|client|local] args\n" ); } } else { printf( "usage: ray [server|client|local] args\n" ); } return 0; }