fart/main/fart.cc
Josh Holtrop b7e2aa1bae added freeimage library (de)initialization
git-svn-id: svn://anubis/fart/trunk@381 7f9b0f55-74a9-4bce-be96-3c2cd072584d
2010-10-13 20:30:09 +00:00

346 lines
11 KiB
C++

#include <string.h>
#include <unistd.h> /* sysconf() */
#include <stdlib.h> /* rand(), srand() */
#include <time.h> /* time() */
#include <getopt.h>
#include <sys/time.h> /* gettimeofday() */
#include <iostream>
#include <string>
#include <map>
#include <FreeImage.h>
#include "Scene.h"
#include "distrib/distrib.h"
#include "BMP.h"
using namespace std;
void usage(const char * progname)
{
cout << "Usage: " << progname << " [options] <scene-file>" << endl;
cout << " Options:" << endl;
cout << " -o|--output-file <output-file-name>" << endl;
cout << " -w|--width <image-width>" << endl;
cout << " -h|--height <image-height>" << endl;
cout << " -m|--multisample <level>" << endl;
cout << " -f|--field-of-view <vertical-fov>" << endl;
cout << " -d|--max-depth <max-recursion-depth>" << endl;
cout << " -a|--ambient-occlusion <ambient-occlusion-level>" << endl;
cout << " -p|--preview (means -w400 -h300 -m1 -d8 -a0)" << endl;
cout << " --hosts <hosts-file>" << endl;
exit(42);
}
void startChildren(const string & servername,
int serverport,
const vector<string> options)
{
char server_port_str[15];
sprintf(server_port_str, "%d", serverport);
vector<string> args;
args.push_back("fart");
args.push_back("--child");
args.push_back("--host");
args.push_back(servername);
args.push_back("--port");
args.push_back(server_port_str);
for (int i = 0, sz = options.size(); i < sz; i++)
args.push_back(options[i]);
const char * char_star_args[args.size() + 1];
for (int i = 0, sz = args.size(); i < sz; i++)
char_star_args[i] = args[i].c_str();
char_star_args[args.size()] = (char *) NULL;
int num_children = sysconf(_SC_NPROCESSORS_CONF);
num_children--;
#if 0
/* debug */
cout << "executing: 'fart', ";
for (int i = 0, sz = args.size(); i < sz; i++)
cout << "'" << char_star_args[i] << "', ";
cout << endl;
#endif
for (int i = 0; i < num_children; i++)
{
int id = fork();
if (id == 0)
{
/* child process */
execvp("fart", (char * const *) char_star_args);
}
}
}
int main(int argc, char * argv[])
{
int opt;
int option_index;
map<string, const char *> scene_options;
vector<string> client_options;
bool server = true;
bool distributed = false;
const char * hosts_file = NULL;
const char * server_name = NULL;
int server_port = 0;
unsigned char * data = NULL;
const char * output_file_name = "fart.bmp";
bool child = false;
static const struct option long_options[] = {
{ "ambient-occlusion", required_argument, NULL, 'a' },
{ "output-file", required_argument, NULL, 'o' },
{ "width", required_argument, NULL, 'w' },
{ "height", required_argument, NULL, 'h' },
{ "multisample", required_argument, NULL, 'm' },
{ "field-of-view", required_argument, NULL, 'f' },
{ "max-depth", required_argument, NULL, 'd' },
{ "preview", no_argument, NULL, 'p' },
{ "help", no_argument, NULL, 256 },
{ "host", required_argument, NULL, 257 },
{ "port", required_argument, NULL, 258 },
{ "hosts", required_argument, NULL, 259 },
{ "child", no_argument, NULL, 260 },
{ NULL, 0, NULL, 0 }
};
while ((opt = getopt_long(argc, argv, "a:o:w:h:m:f:d:p",
long_options, &option_index)) != -1)
{
switch (opt)
{
case 'a':
scene_options["ambient-occlusion"] = optarg;
client_options.push_back("--ambient-occlusion");
client_options.push_back(optarg);
break;
case 'o':
output_file_name = optarg;
break;
case 'w':
scene_options["width"] = optarg;
client_options.push_back("--width");
client_options.push_back(optarg);
break;
case 'h':
scene_options["height"] = optarg;
client_options.push_back("--height");
client_options.push_back(optarg);
break;
case 'm':
scene_options["multisample"] = optarg;
client_options.push_back("--multisample");
client_options.push_back(optarg);
break;
case 'f':
scene_options["field-of-view"] = optarg;
client_options.push_back("--field-of-view");
client_options.push_back(optarg);
break;
case 'd':
scene_options["max-depth"] = optarg;
client_options.push_back("--max-depth");
client_options.push_back(optarg);
break;
case 'p':
scene_options["ambient-occlusion"] = "0";
scene_options["width"] = "400";
scene_options["height"] = "300";
scene_options["multisample"] = "1";
scene_options["max-depth"] = "8";
client_options.push_back("--preview");
break;
case 256:
usage(argv[0]);
break;
case 257:
server_name = optarg;
server = false;
distributed = true;
break;
case 258:
server_port = atoi(optarg);
distributed = true;
break;
case 259:
hosts_file = optarg;
distributed = true;
break;
case 260:
child = true;
break;
default:
usage(argv[0]);
break;
}
}
if (optind >= argc)
{
usage(argv[0]);
}
srand(time(NULL));
FreeImage_Initialise(FALSE);
const char * filename = argv[optind];
client_options.push_back(filename);
Scene scene(scene_options, filename);
const int width = scene.getWidth();
const int height = scene.getHeight();
if (server)
{
/* allocate data for the image */
data = new unsigned char[3 * width * height];
cout << " *** Beginning scene render ***" << endl;
cout << "Parameters:" << endl;
cout << "----------------------------------------" << endl;
cout << " Width: " << width << endl;
cout << " Height: " << height << endl;
cout << " Multisample Level: " << scene.getMultisampleLevel() << endl;
cout << " Ambient Occlusion Level: " << scene.getAmbientOcclusionLevel() << endl;
cout << " Vertical Field of View: " << scene.getVFOV() << endl;
cout << " Max Depth: " << scene.getMaxDepth() << endl;
cout << "----------------------------------------" << endl;
}
distrib the_distrib;
struct timeval before, after;
gettimeofday(&before, NULL); /* start timing */
if (distributed)
{
/* start the distribution infrastructure */
if (server)
{
if (strcmp(hosts_file, ""))
the_distrib.readHostFile(hosts_file);
int num_tasks = (width * height + (UNIT_TASK_SIZE - 1))
/ UNIT_TASK_SIZE;
the_distrib.set_num_tasks(num_tasks);
the_distrib.set_data(data, 3 * width * height);
the_distrib.startServer();
the_distrib.startClients(client_options);
/* wait until all tasks are complete */
the_distrib.waitAllTasks();
}
else
{
if (!child)
{
startChildren(server_name, server_port, client_options);
}
the_distrib.startClient(server_name, server_port);
unsigned char data[3 * UNIT_TASK_SIZE];
for (;;)
{
int task_id = the_distrib.getTask();
if (task_id < 0)
break;
int pixel = task_id * UNIT_TASK_SIZE;
int i = pixel / width;
int j = pixel % width;
for (int t = 0; t < UNIT_TASK_SIZE; t++)
{
scene.renderPixel(j, i, &data[3 * t]);
j++;
if (j >= width)
{
j = 0;
i++;
if (i >= height)
break;
}
}
int ret = the_distrib.send_data(task_id,
&data[0],
3 * UNIT_TASK_SIZE);
if (ret != 0)
break;
}
}
}
else
{
int total_pixels = height * width;
int total_pixels_1000 = total_pixels / 1000;
if (total_pixels_1000 < 1)
total_pixels_1000 = 1;
int pixel_num = 0;
/* "sequential" version */
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int pixel = i * width + j;
scene.renderPixel(j, i, &data[3 * pixel]);
pixel_num++;
if (pixel_num % total_pixels_1000 == 0)
{
double pct = 100.0 * pixel_num / (double) total_pixels;
printf("\e[8D%2.1f%%", pct);
fflush(stdout);
}
}
}
printf("\e[8D");
}
gettimeofday(&after, NULL); /* stop timing */
if (server)
{
cout << " *** Ending scene render ***" << endl;
cout << "Writing output file '" << output_file_name << '\'' << endl;
/* write the image */
BMP outputImage(output_file_name, width, height, data);
/* print how much time has elapsed */
double time_before = before.tv_sec + before.tv_usec / 1000000.0;
double time_after = after.tv_sec + after.tv_usec / 1000000.0;
double total_seconds = time_after - time_before;
cout << "Render time: " << total_seconds << " seconds";
double seconds = total_seconds;
int days = (int) (seconds / (60.0 * 60.0 * 24.0));
seconds -= days * 60.0 * 60.0 * 24.0;
int hours = (int) (seconds / (60.0 * 60.0));
seconds -= hours * 60.0 * 60.0;
int minutes = (int) (seconds / 60.0);
seconds -= minutes * 60.0;
if (days || hours || minutes)
{
cout << " (";
if (days)
cout << days << (days == 1 ? " day, " : " days, ");
if (days || hours)
cout << hours << (hours == 1 ? " hour, " : " hours, ");
cout << minutes << (minutes == 1 ? " minute, " : " minutes, ");
cout << seconds << (seconds == 1 ? " second)" : " seconds)");
}
cout << endl;
}
FreeImage_DeInitialise();
exit(0);
return 0;
}