346 lines
11 KiB
C++
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;
|
|
}
|