Compare commits

...

12 Commits
master ... d

68 changed files with 619 additions and 7168 deletions

3
.gitignore vendored
View File

@ -1,5 +1,6 @@
fart
/fart
*.bmp
*.png
/.propane*
/.rscons*
/build/

View File

@ -1,21 +1,29 @@
configure do
check_cxx_compiler
check_program "flex"
check_program "bison"
check_lib ":libfl.a"
check_lib "pthread"
check_lib "freeimage"
check_d_compiler
end
env do |env|
env["CCFLAGS"] += %w[-Wall -O2]
env["CPPPATH"] += glob("src/**")
fart_env = env "fart" do |env|
env["DFLAGS"] += %w[-Werror -O2]
env["D_IMPORT_PATH"] += %w[src]
env.CFile("^/parser/lexer.cc", "src/parser/parser.ll")
env.CFile("^/parser/parser.cc", "src/parser/parser.yy")
env["CPPPATH"] += ["#{env.build_root}/parser"]
sources = glob("src/**/*.cc")
sources += ["^/parser/lexer.cc", "^/parser/parser.cc"]
env.Program("fart", sources)
env.Command("^/src/sceneparser.d", "src/sceneparser.propane",
"CMD" => %w[./propane ${_SOURCES} ${_TARGET}],
"CMD_DESC" => "Generating scene parser")
env.add_build_hook do |builder|
if builder.sources.first =~ /sceneparser\.d/
builder.vars["DFLAGS"] -= %w[-Werror]
end
end
env["sources"] = glob("src/**/*.d") + ["^/src/sceneparser.d"]
env.Program("fart", "${sources}")
end
task "test" do
test_env = fart_env.clone "test" do |env|
env["DFLAGS"] += %w[-funittest]
env.Program("^/farttest", "${sources}")
end
test_env.process
sh test_env.expand("^/farttest")
end

45
propane Executable file

File diff suppressed because one or more lines are too long

View File

@ -1,438 +0,0 @@
#include "distrib.h"
#include <fstream>
#include <string>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h> /* gethostbyname() */
#include <string.h> /* memset() */
#include <fcntl.h> /* fcntl(), F_GETFD, F_SETFD, FD_CLOEXEC */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h> /* TCP_NODELAY */
using namespace std;
#define MSG_WANT_DATA 1
#define MSG_SEND_DATA 2
distrib::distrib()
{
pthread_cond_init(&m_listen_cond, NULL);
pthread_cond_init(&m_tasks_complete_cond, NULL);
pthread_mutex_init(&m_listen_mutex, NULL);
pthread_mutex_init(&m_task_mutex, NULL);
pthread_mutex_init(&m_tasks_in_progress_mutex, NULL);
pthread_mutex_init(&m_tasks_complete_mutex, NULL);
m_num_clients = 0;
m_data = NULL;
m_server = true;
m_next_task = 0;
m_client_socket = -1;
m_tasks_complete = 0;
}
distrib::~distrib()
{
if (m_client_socket != -1)
close(m_client_socket);
}
int distrib::readHostFile(const char * filename)
{
ifstream ifs(filename);
if ( ! ifs.is_open() )
return 1;
string host;
while ( ! ifs.eof() )
{
ifs >> host;
if ( ifs.eof() )
break;
m_hosts.push_back(host);
}
ifs.close();
return 0;
}
int distrib::startClients(const std::vector<std::string> & client_options)
{
int ret = 0;
for (int i = 0, sz = m_hosts.size(); i < sz; i++)
{
ret += clientConnect(m_hosts[i], client_options);
}
return ret;
}
int distrib::clientConnect(const string & host,
const std::vector<std::string> & client_options)
{
int id = fork();
if (id < 0) /* check for fork() error */
{
cerr << "Error forking: " << id << endl;
return 1;
}
else if (id > 0) /* in the parent */
{
m_children.push_back(id);
m_num_clients++;
}
else /* in the child */
{
char server_port_str[15];
sprintf(server_port_str, "%d", m_serverport);
vector<string> args;
args.push_back("ssh");
args.push_back(host);
args.push_back("fart");
args.push_back("--host");
args.push_back(m_servername);
args.push_back("--port");
args.push_back(server_port_str);
for (int i = 0, sz = client_options.size(); i < sz; i++)
args.push_back(client_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;
#if 0
/* debug */
cout << "executing: 'ssh', ";
for (int i = 0, sz = args.size(); i < sz; i++)
cout << "'" << char_star_args[i] << "', ";
cout << endl;
#endif
execvp("ssh", (char * const *) char_star_args);
/* we should not get here */
cerr << "Error " << errno << " with execlp()!" << endl;
exit(33);
}
return 0;
}
void connection_thread(distrib::connection_thread_arg_t * arg)
{
distrib * the_distrib = arg->the_distrib;
int client_socket = arg->client_socket;
delete arg;
int flag = 1;
if (setsockopt(client_socket,
IPPROTO_TCP,
TCP_NODELAY,
(char *) &flag,
sizeof(flag)) < 0)
{
cerr << "Failed to set TCP_NODELAY on client socket in connection thread!" << endl;
}
bool done = false;
/* loop listening for messages from the client */
while (!done)
{
int msg_type;
size_t nread = read(client_socket, &msg_type, sizeof(msg_type));
if (nread == sizeof(msg_type))
{
switch (msg_type)
{
case MSG_WANT_DATA:
{
int task = the_distrib->getTask();
if (write(client_socket, &task, sizeof(task)) < 0)
done = true;
}
break;
case MSG_SEND_DATA:
{
unsigned char data[3 * UNIT_TASK_SIZE];
int task;
if (read(client_socket, &task, sizeof(task)) < 0)
done = true;
else if (read(client_socket, &data[0], sizeof(data)) < 0)
done = true;
else
the_distrib->send_data(task, &data[0], sizeof(data));
}
break;
default:
break;
}
}
else if (nread > 0 && nread < sizeof(msg_type))
{
cerr << "Error: nread = " << nread << "!" << endl;
}
else if (nread < 0)
{
break;
}
}
close(client_socket);
cerr << "Closing connection thread!" << endl;
pthread_exit(NULL);
}
void distrib_server(distrib * the_distrib)
{
char hostname[1000];
gethostname(&hostname[0], 1000);
the_distrib->m_servername = hostname;
int listen_socket = socket(PF_INET, SOCK_STREAM, 0);
if ( listen_socket == -1 )
{
cerr << "Error " << errno << " creating listen socket!" << endl;
exit(39);
}
int flags = fcntl(listen_socket, F_GETFD);
flags |= FD_CLOEXEC;
fcntl(listen_socket, F_SETFD, flags);
if ( listen(listen_socket, 5) == -1 )
{
cerr << "Error " << errno << " when trying to listen!" << endl;
exit(40);
}
struct sockaddr_in addr;
int addr_len = sizeof(struct sockaddr_in);
getsockname(listen_socket,
(struct sockaddr *) &addr,
(socklen_t *) &addr_len);
int ip_addr = ntohl(addr.sin_addr.s_addr);
the_distrib->m_serverport = ntohs(addr.sin_port);
cout << "Listening on "
<< (unsigned int) ((ip_addr >> 24) & 0xFF)
<< '.'
<< (unsigned int) ((ip_addr >> 16) & 0xFF)
<< '.'
<< (unsigned int) ((ip_addr >> 8) & 0xFF)
<< '.'
<< (unsigned int) (ip_addr & 0xFF)
<< ':'
<< the_distrib->m_serverport
<< endl;
/* signal readiness of the listen thread */
pthread_mutex_lock(&the_distrib->m_listen_mutex);
pthread_cond_signal(&the_distrib->m_listen_cond);
pthread_mutex_unlock(&the_distrib->m_listen_mutex);
for (;;)
{
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_socket = accept(listen_socket,
(struct sockaddr *) &client_addr,
&client_addr_len);
if (client_socket < 0)
break;
#if 0
int cip = ntohl(client_addr.sin_addr.s_addr);
cout << "Connection from "
<< (unsigned int) ((cip >> 24) & 0xFF)
<< '.'
<< (unsigned int) ((cip >> 16) & 0xFF)
<< '.'
<< (unsigned int) ((cip >> 8) & 0xFF)
<< '.'
<< (unsigned int) (cip & 0xFF)
<< ':'
<< client_addr.sin_port
<< endl;
#endif
distrib::connection_thread_arg_t * arg =
new distrib::connection_thread_arg_t;
arg->the_distrib = the_distrib;
arg->client_socket = client_socket;
pthread_t client_thread;
pthread_create(&client_thread,
NULL,
(void * (*)(void *)) &connection_thread,
arg);
}
cout << "Listen thread exiting!" << endl;
}
int distrib::startServer()
{
m_server = true;
pthread_mutex_lock(&m_listen_mutex);
/* start the listen thread */
int ret = pthread_create(&m_server_thread,
NULL,
(void * (*)(void *)) distrib_server,
this);
if (ret)
return ret;
/* wait for the listen thread to be running */
pthread_cond_wait(&m_listen_cond, &m_listen_mutex);
pthread_mutex_unlock(&m_listen_mutex);
return ret;
}
int distrib::startClient(const char * server, int port)
{
m_server = false;
m_client_socket = socket(PF_INET, SOCK_STREAM, 0);
if (m_client_socket < 0)
{
cerr << "Error creating client socket: " << errno << endl;
return 1;
}
int flag = 1;
if (setsockopt(m_client_socket,
IPPROTO_TCP,
TCP_NODELAY,
(char *) &flag,
sizeof(flag)) < 0)
{
cerr << "Failed to set TCP_NODELAY on client socket!" << endl;
return 2;
}
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
struct addrinfo * res;
char portstr[15];
sprintf(portstr, "%d", port);
getaddrinfo(server, portstr, &hint, &res);
if (connect(m_client_socket, res->ai_addr, res->ai_addrlen) == -1)
{
cerr << "Error connecting from client socket: " << errno << endl;
return 2;
}
return 0;
}
int distrib::send_data(int task, unsigned char * data, int num_bytes)
{
if (m_server)
{
if (m_data != NULL)
{
int num_to_copy = num_bytes;
if (3 * task * UNIT_TASK_SIZE + num_to_copy > m_data_size)
num_to_copy = m_data_size - 3 * task * UNIT_TASK_SIZE;
if (num_to_copy > 0)
{
memcpy(m_data + 3 * task * UNIT_TASK_SIZE, data, num_to_copy);
}
taskDone(task);
}
}
else
{
int msg_header = MSG_SEND_DATA; /* send data */
if ( write(m_client_socket, &msg_header, sizeof(msg_header)) < 0
|| write(m_client_socket, &task, sizeof(task)) < 0
|| write(m_client_socket, data, num_bytes) < 0)
{
return -1;
}
}
return 0;
}
int distrib::getTask()
{
int task = -1;
if (m_server)
{
pthread_mutex_lock(&m_task_mutex);
if (m_next_task < m_num_tasks)
{
task = m_next_task;
m_next_task++;
}
pthread_mutex_unlock(&m_task_mutex);
if (task > -1)
startTask(task);
else
{
pthread_mutex_lock(&m_tasks_in_progress_mutex);
std::map<int, int>::const_iterator it = m_tasks_in_progress.begin();
if (it != m_tasks_in_progress.end())
{
task = it->first;
}
pthread_mutex_unlock(&m_tasks_in_progress_mutex);
}
}
else
{
int msg_header = MSG_WANT_DATA;
if (write(m_client_socket, &msg_header, sizeof(msg_header)) < 0)
return -1;
/* wait for a message back */
if (read(m_client_socket, &task, sizeof(task)) < 0)
return -1;
}
return task;
}
void distrib::startTask(int task)
{
pthread_mutex_lock(&m_tasks_in_progress_mutex);
m_tasks_in_progress[task] = 1;
pthread_mutex_unlock(&m_tasks_in_progress_mutex);
}
void distrib::taskDone(int task)
{
pthread_mutex_lock(&m_tasks_in_progress_mutex);
m_tasks_in_progress.erase(task);
m_tasks_complete++;
if (m_tasks_complete == m_num_tasks)
{
pthread_mutex_lock(&m_tasks_complete_mutex);
pthread_cond_signal(&m_tasks_complete_cond);
pthread_mutex_unlock(&m_tasks_complete_mutex);
}
pthread_mutex_unlock(&m_tasks_in_progress_mutex);
}
void distrib::waitAllTasks()
{
int done;
pthread_mutex_lock(&m_tasks_in_progress_mutex);
done = m_tasks_complete;
if (done < m_num_tasks)
pthread_mutex_lock(&m_tasks_complete_mutex);
pthread_mutex_unlock(&m_tasks_in_progress_mutex);
if (done < m_num_tasks)
{
pthread_cond_wait(&m_tasks_complete_cond, &m_tasks_complete_mutex);
pthread_mutex_unlock(&m_tasks_complete_mutex);
}
}

View File

@ -1,72 +0,0 @@
#ifndef DISTRIB_H
#define DISTRIB_H DISTRIB_H
#include <string>
#include <vector>
#include <map>
#include <pthread.h>
#define UNIT_TASK_SIZE 100
class distrib
{
public:
distrib();
~distrib();
int readHostFile(const char * filename);
int startServer();
int startClient(const char * server, int port);
int startClients(const std::vector<std::string> & client_options);
int getNumClients() { return m_num_clients; }
void set_data(unsigned char * data, int size)
{
m_data = data;
m_data_size = size;
}
void set_num_tasks(int num_tasks) { m_num_tasks = num_tasks; }
int getTask();
int send_data(int task, unsigned char * data, int num_bytes);
int getNumTasksInProgress() { return m_tasks_in_progress.size(); }
void waitAllTasks();
std::string & getServerName() { return m_servername; }
int getServerPort() { return m_serverport; }
typedef struct
{
distrib * the_distrib;
int client_socket;
} connection_thread_arg_t;
friend void distrib_server(distrib * the_distrib);
friend void connection_thread(connection_thread_arg_t * arg);
protected:
int clientConnect(const std::string & host,
const std::vector<std::string> & client_options);
void startTask(int task);
void taskDone(int task);
std::vector<std::string> m_hosts;
std::vector<int> m_children;
std::string m_servername;
int m_serverport;
int m_client_socket;
pthread_t m_server_thread;
pthread_cond_t m_listen_cond;
pthread_mutex_t m_listen_mutex;
int m_num_clients;
unsigned char * m_data;
int m_data_size;
int m_num_tasks;
int m_tasks_complete;
int m_next_task;
bool m_server;
pthread_mutex_t m_task_mutex;
std::map<int, int> m_tasks_in_progress;
pthread_mutex_t m_tasks_in_progress_mutex;
pthread_mutex_t m_tasks_complete_mutex;
pthread_cond_t m_tasks_complete_cond;
};
#endif

54
src/fart/bfile.d Normal file
View File

@ -0,0 +1,54 @@
module fart.bfile;
import std.stdio;
/**
* Struct to handle easily writing data to a binary file.
*/
public struct BFile
{
/**
* Underlying file handle.
*/
private File m_file;
/**
* Create a binary file.
*/
this(string filename)
{
m_file = File(filename, "wb");
}
/**
* Write arbitrary byte data to the file.
*/
public void write(const(void) * data, size_t length)
{
write((cast(const(ubyte) *)data)[0..length]);
}
/**
* Write an array to the file.
*/
public void write(T)(const(T)[] data)
{
m_file.rawWrite(data);
}
/**
* Write an arbitrary object to the file.
*/
public void writeObject(T)(ref const(T) obj)
{
write(&obj, obj.sizeof);
}
/**
* Close the file.
*/
public void close()
{
m_file.close();
}
}

45
src/fart/color.d Normal file
View File

@ -0,0 +1,45 @@
module fart.color;
/**
* Structure to represent a RGBA color value.
*/
struct Color
{
/** Red color component. */
double r;
/** Green color component. */
double g;
/** Blue color component. */
double b;
/** Alpha color component. */
double a;
/**
* Convert color to a 32-bit integer RGBA value.
*
* Each color component uses one byte.
*/
public ubyte[] rgba32() const
{
return [toubyte(r), toubyte(g), toubyte(b), toubyte(a)];
}
/**
* Scale a floating point color component value to an unsigned 8-bit byte
* value.
*
* @param v
* Floating point color component value.
*
* @return Unsigned 8-bit byte value for the color component.
*/
private static ubyte toubyte(double v)
{
return cast(ubyte)(0xFF * v);
}
public static immutable Color TRANSPARENT = Color(0, 0, 0, 0);
}

18
src/fart/crc32.d Normal file
View File

@ -0,0 +1,18 @@
module fart.crc32;
import std.digest.crc;
/**
* Calculate the CRC32 across the given chunk(s) of data.
*/
public uint crc32(Args...)(Args data)
{
CRC32 crc32;
crc32.start();
static foreach (arg; data)
{
crc32.put(cast(const(ubyte)[])arg);
}
auto crc = crc32.finish();
return crc[0] | (crc[1] << 8) | (crc[2] << 16) | (crc[3] << 24);
}

35
src/fart/hton.d Normal file
View File

@ -0,0 +1,35 @@
/**
* @file
*
* Host to network byte-swapping functions.
*/
module fart.hton;
version (BigEndian)
{
public uint htonl(uint v)
{
return v;
}
public uint ntohl(uint v)
{
return v;
}
}
version (LittleEndian)
{
import core.bitop;
public uint htonl(uint v)
{
return bswap(v);
}
public uint ntohl(uint v)
{
return bswap(v);
}
}

27
src/fart/main.d Normal file
View File

@ -0,0 +1,27 @@
module fart.main;
import fart.png;
import fart.color;
/**
* Main program entry point.
*
* @param args
* Program arguments.
*/
int main(string[] args)
{
size_t width = 800;
size_t height = 600;
string output_filename = "out.png";
Color[] pixels = [];
for (size_t y = 0; y < height; y++)
{
for (size_t x = 0; x < width; x++)
{
pixels ~= Color.TRANSPARENT;
}
}
write_png(output_filename, width, height, pixels);
return 0;
}

158
src/fart/png.d Normal file
View File

@ -0,0 +1,158 @@
module fart.png;
import std.zlib;
import std.digest;
import fart.bfile;
import fart.crc32;
import fart.hton;
import fart.color;
/**
* PNG file header.
*/
private immutable ubyte[] HEADER = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
/**
* PNG IHDR chunk.
*/
struct IHDR
{
uint width;
uint height;
ubyte bit_depth;
ubyte color_type;
ubyte compression;
ubyte filter;
ubyte interlace;
ubyte[0] end;
this(size_t width, size_t height)
{
this.width = htonl(cast(uint)width);
this.height = htonl(cast(uint)height);
this.bit_depth = 8;
this.color_type = 6;
this.compression = 0;
this.filter = 0;
this.interlace = 0;
}
public const(void) * data()
{
return &this;
}
public size_t data_length()
{
return end.offsetof;
}
}
/**
* PNG IDAT chunk.
*/
struct IDAT
{
private const(ubyte)[] m_data;
this(ubyte[] data)
{
m_data = compress(data);
}
public const(void) * data()
{
return m_data.ptr;
}
public size_t data_length()
{
return m_data.length;
}
}
/**
* PNG IEND chunk.
*/
struct IEND
{
public const(void) * data()
{
return &this;
}
public size_t data_length()
{
return 0;
}
}
/**
* Write a PNG chunk to the output file.
*
* @param file
* Output file
* @param chunk_type
* Chunk type.
* @param chunk
* Chunk to write.
*/
private void write_chunk(Chunk)(BFile file, string chunk_type, Chunk chunk)
{
size_t chunk_data_length = chunk.data_length();
uint chunk_length_be32 = htonl(cast(uint)chunk_data_length);
file.writeObject(chunk_length_be32);
file.write(chunk_type);
const(ubyte)[] chunk_data = (cast(const(ubyte) *)chunk.data())[0..chunk_data_length];
file.write(chunk_data);
uint crc_be32 = htonl(crc32(chunk_type, chunk_data));
file.writeObject(crc_be32);
}
/**
* Write a PNG image from the given metadata and pixel data.
*
* @param filename
* Name of file to write.
* @param width
* Width of image.
* @param height
* Height of image.
* @param data
* Pixel color data.
*/
public void write_png(string filename, size_t width, size_t height, const(Color)[] data)
{
if (data.length != width * height)
return;
/* Convert Color values to 32-bit RGBA values. */
ubyte[] pixel_data;
size_t data_index;
for (size_t y = 0; y < height; y++)
{
/* Filter method 0 (None) */
pixel_data ~= 0;
for (size_t x = 0; x < width; x++)
{
pixel_data ~= data[data_index++].rgba32();
}
}
/* Open output file. */
BFile file = BFile(filename);
/* Write PNG header. */
file.write(HEADER);
/* Write IHDR chunk. */
IHDR ihdr = IHDR(width, height);
write_chunk(file, "IHDR", ihdr);
/* Write IDAT chunk. */
IDAT idat = IDAT(pixel_data);
write_chunk(file, "IDAT", idat);
/* Write IEND chunk. */
IEND iend;
write_chunk(file, "IEND", iend);
/* Close output file. */
file.close();
}

190
src/fart/vector.d Normal file
View File

@ -0,0 +1,190 @@
module fart.vector;
import std.math;
/**
* Structure to represent a 3-dimensional vector.
*/
struct Vector
{
/** Vector X coordinate. */
double x;
/** Vector Y coordinate. */
double y;
/** Vector Z coordinate. */
double z;
/**
* Compute the cross product of two vectors.
*/
public Vector cross()(auto ref const Vector other) const
{
return Vector(y * other.z - z * other.y,
z * other.x - x * other.z,
x * other.y - y * other.x);
}
/**
* Compute the dot product of two vectors.
*/
public double dot()(auto ref const Vector other) const
{
return x * other.x + y * other.y + z * other.z;
}
/**
* Get the magnitude of the vector.
*/
public double mag() const
{
return sqrt(mag2());
}
/**
* Get the squared magnitude of the vector.
*/
public double mag2() const
{
return x * x + y * y + z * z;
}
/**
* Normalize the vector to have unit length.
*/
public ref Vector normalize()
{
double mag = mag();
x /= mag;
y /= mag;
z /= mag;
return this;
}
/**
* Get a normalized vector in the same direction as this.
*/
public Vector normalized() const
{
double mag = mag();
return Vector(x / mag, y / mag, z / mag);
}
/**
* Project the vector onto a target vector.
*/
public Vector proj()(auto ref const Vector other) const
{
Vector on = other.normalized();
return on * dot(on);
}
/**
* Add two vectors.
*/
public Vector opBinary(string op : "+")(auto ref const Vector other) const
{
return Vector(x + other.x, y + other.y, z + other.z);
}
/**
* Add two vectors and assign to self.
*/
public Vector opOpAssign(string op : "+")(auto ref const Vector other)
{
x += other.x;
y += other.y;
z += other.z;
return this;
}
/**
* Negate a vector.
*/
public Vector opUnary(string op : "-")() const
{
return Vector(-x, -y, -z);
}
/**
* Subtract two vectors.
*/
public Vector opBinary(string op : "-")(auto ref const Vector other) const
{
return Vector(x - other.x, y - other.y, z - other.z);
}
/**
* Subtract two vectors and assign to self.
*/
public Vector opOpAssign(string op : "-")(auto ref const Vector other)
{
x -= other.x;
y -= other.y;
z -= other.z;
return this;
}
/**
* Scale a vector.
*/
public Vector opBinary(string op : "*")(double m) const
{
return Vector(x * m, y * m, z * m);
}
/**
* Scale a vector.
*/
public Vector opBinaryRight(string op : "*")(double m) const
{
return Vector(x * m, y * m, z * m);
}
/**
* Compute the cross product of two vectors.
*/
public Vector opBinary(string op : "*")(auto ref const Vector other) const
{
return cross(other);
}
public static immutable Vector X = Vector(1.0, 0.0, 0.0);
public static immutable Vector Y = Vector(0.0, 1.0, 0.0);
public static immutable Vector Z = Vector(0.0, 0.0, 1.0);
}
unittest
{
Vector v = Vector(1, 2, 3);
const Vector w = Vector(0, 4, 5);
Vector v_times_2 = v * 2;
assert(v_times_2.x == 2);
assert(v_times_2.y == 4);
assert(v_times_2.z == 6);
Vector v_plus_w = v + w;
assert(v_plus_w == Vector(1, 6, 8));
Vector v_minus_w = v - w;
assert(v_minus_w == Vector(1, -2, -2));
assert(v_minus_w.mag2() == 9.0);
assert(v_minus_w.mag() == 3.0);
v += v_minus_w;
assert(v == 2 * Vector.X + 0 * Vector.Y + Vector.Z);
assert(Vector.X * Vector.Y == Vector.Z);
assert(Vector.Y * Vector.Z == Vector.X);
assert(Vector.Z * Vector.X == Vector.Y);
assert(Vector.Y * Vector.X == -Vector.Z);
assert(Vector.Z * Vector.Y == -Vector.X);
assert(Vector.X * Vector.Z == -Vector.Y);
assert(w.proj(Vector.X) == Vector(0, 0, 0));
assert(w.proj(Vector.Y) == Vector(0, 4, 0));
assert(w.proj(Vector.Z) == Vector(0, 0, 5));
}

View File

@ -1,130 +0,0 @@
// BMP.cc
// extracts/inserts data from/into .bmp file
// Adapted by Josh Holtrop from the original access_bmp.c by gw
// Supports reading and creating 24-bit color BMP images
#include "BMP.h"
#include <stdio.h>
#include <iostream>
using namespace std;
BMP::BMP(const char * fileName)
{
open(fileName);
}
BMP::BMP(const char * fileName, int width, int height, unsigned char * data)
{
create(fileName, width, height, data);
}
BMP::~BMP()
{
if (m_fp != NULL)
close();
}
bool BMP::open(const char * fileName)
{
size_t bytes_read;
m_fp = fopen(fileName, "r+");
if (m_fp != NULL)
{
// read file header
bytes_read = fread(&m_header, sizeof(m_header), 1, m_fp);
if (m_header.id[0] != 'B' || m_header.id[1] != 'M')
{
cerr << fileName << " does not appear to be a BMP file." << endl;
fclose(m_fp);
m_fp = NULL;
}
// read image information
bytes_read = fread(&m_info, sizeof(m_info), 1, m_fp);
}
(void)bytes_read;
return (m_fp != NULL);
}
bool BMP::create(const char * fileName, int width, int height,
unsigned char * data)
{
size_t bytes_written;
m_fp = fopen(fileName, "w+");
if (m_fp != NULL)
{
/* Initialize the header structure */
m_header.id[0] = 'B';
m_header.id[1] = 'M';
int row_padding = (3 * width) & 0x3;
if (row_padding)
row_padding = 4 - row_padding;
int row_bytes = (3 * width) + row_padding;
m_header.file_size = sizeof(m_header) +
sizeof(m_info) +
row_bytes * height;
m_header.reserved = 0;
m_header.offset = sizeof(m_header) + sizeof(m_info);
/* Initialize the information structure */
m_info.header_size = 40;
m_info.width = width;
m_info.height = height;
m_info.color_planes = 1;
m_info.color_depth = 24;
m_info.compression = 0;
m_info.image_size = 0;
m_info.xresolution = 2835;
m_info.yresolution = 2835;
m_info.num_colors = 0;
m_info.num_important_colors = 0;
/* write them to the file */
bytes_written = fwrite(&m_header, sizeof(m_header), 1, m_fp);
bytes_written = fwrite(&m_info, sizeof(m_info), 1, m_fp);
unsigned int zero = 0;
unsigned char * data_ptr = data + (3 * width) * (height - 1);
for (int i = 0; i < height; i++)
{
bytes_written = fwrite(data_ptr, 3 * width, 1, m_fp);
if (row_padding)
bytes_written = fwrite(&zero, row_padding, 1, m_fp);
data_ptr -= 3 * width;
}
}
(void)bytes_written;
return (m_fp != NULL);
}
void BMP::read(unsigned char * buf)
{
size_t bytes_read;
if (m_fp != NULL)
{
int row_data_bytes = 3 * m_info.width;
int row_padding = row_data_bytes & 0x3;
if (row_padding)
row_padding = 4 - row_padding;
fseek(m_fp,
(m_header.offset != 0
? m_header.offset
: sizeof(m_header) + sizeof(m_info)),
SEEK_SET);
unsigned char * data_ptr = buf + row_data_bytes * (m_info.height - 1);
for (int i = 0; i < m_info.height; i++)
{
bytes_read = fread(data_ptr, row_data_bytes, 1, m_fp);
if (row_padding)
fseek(m_fp, row_padding, SEEK_CUR);
data_ptr -= row_data_bytes;
}
}
(void)bytes_read;
}
void BMP::close()
{
if (m_fp != NULL)
fclose(m_fp);
m_fp = NULL;
}

View File

@ -1,54 +0,0 @@
// BMP.h
// extracts/inserts data from/into .bmp file
// Adapted by Josh Holtrop from the original access_bmp.c by gw
// Supports reading and creating 24-bit color BMP images
#include <stdio.h>
#define BMP_RED 2
#define BMP_GREEN 1
#define BMP_BLUE 0
class BMP
{
public:
typedef struct
{
char id[2];
int file_size;
int reserved;
int offset;
} __attribute__ ((packed)) header_t;
typedef struct
{
int header_size;
int width;
int height;
unsigned short int color_planes;
unsigned short int color_depth;
unsigned int compression;
int image_size;
int xresolution;
int yresolution;
int num_colors;
int num_important_colors;
} __attribute__ ((packed)) info_t;
BMP(const char * fileName);
BMP(const char * fileName, int width, int height, unsigned char * data);
~BMP();
void read(unsigned char * buf);
int getWidth() { return m_info.width; }
int getHeight() { return m_info.height; }
protected:
FILE * m_fp;
header_t m_header;
info_t m_info;
bool open(const char * fileName);
bool create(const char * fileName, int width, int height,
unsigned char * data);
void close();
};

View File

@ -1,20 +0,0 @@
#include "Light.h"
#include "util/Vector.h"
#include "util/Ray.h"
Light::Light()
{
m_position = Vector(0, 0, 0);
m_diffuse_color = Color::white;
m_specular_color = Color::white;
m_jitter = 1;
m_radius = 1.0;
}
Vector Light::getJitterPosition(int index) const
{
if (index == 0)
return m_position;
return m_position + Vector::randomVector() * m_radius;
}

View File

@ -1,48 +0,0 @@
#ifndef LIGHT_H
#define LIGHT_H LIGHT_H
#include "util/Vector.h"
#include "util/Color.h"
class Light
{
public:
Light();
void setPosition(const Vector & position) { m_position = position; }
void setPosition(refptr<Vector> vec) { setPosition(*vec); }
const Vector & getPosition() const { return m_position; }
Vector getJitterPosition(int index) const;
void setDiffuseColor(const Color & diffuse)
{
m_diffuse_color = diffuse;
}
const Color & getDiffuseColor() const { return m_diffuse_color; }
void setSpecularColor(const Color & specular)
{
m_specular_color = specular;
}
const Color & getSpecularColor() const { return m_specular_color; }
void setJitter(int j) { m_jitter = j >= 1 ? j : 1; }
int getJitter() const { return m_jitter; }
void setRadius(double r) { m_radius = r; }
double getRadius() const { return m_radius; }
protected:
Vector m_position;
Color m_diffuse_color;
Color m_specular_color;
double m_radius;
int m_jitter;
};
#include "PointLight.h"
#endif

View File

@ -1,7 +0,0 @@
#include "PointLight.h"
PointLight::PointLight()
: Light()
{
}

View File

@ -1,17 +0,0 @@
#ifndef POINTLIGHT_H
#define POINTLIGHT_H POINTLIGHT_H
#include "Light.h"
#include "util/Color.h"
class PointLight : public Light
{
public:
PointLight();
protected:
};
#endif

View File

@ -1,840 +0,0 @@
#include <math.h>
#include <typeinfo>
#include <iostream>
#include "Scene.h"
#include "Light.h"
#include "parser/parser.h"
#include "parser/nodes.h"
#include "util/Polygon.h"
#include "util/Scope.h"
using namespace std;
typedef vector< refptr<Node> >::const_iterator Node_Iterator;
#ifdef NODE_TREE_DEBUG
static void dumpNodeTree(refptr<Node> node)
{
static int depth = 0;
for (int i = 0; i < depth; i++)
cerr << ' ';
cerr << typeid(*node).name() << endl;
depth++;
for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++)
{
dumpNodeTree(*it);
}
depth--;
}
#endif
void Scene::load(const char * filename)
{
refptr<Scope> scope = new Scope();
refptr<Node> node = parse(filename, scope);
#ifdef NODE_TREE_DEBUG
dumpNodeTree(node);
#endif
if ( ! node.isNull() )
{
/* evaluate any scripting nodes in the node tree */
refptr<Node> processed_scene = node->evaluate();
node->evaluateChildren(processed_scene);
/* now we have a new node tree under 'dummy' with no scripting nodes */
processScene(processed_scene);
}
}
void Scene::processScene(refptr<Node> node)
{
/* first process any cameras present */
int cameras_found = 0;
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(CameraNode) )
{
cameras_found++;
if (cameras_found == 1)
processCamera(*it);
else
{
cerr << "Error: multiple camera definitions found!" << endl;
exit(5);
}
}
}
/* then any other scene-specific items */
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(LightNode) )
{
refptr<Light> light = processLight(*it);
if ( ! light.isNull() )
m_lights.push_back(light);
}
else if ( typeid(**it) == typeid(OptionsNode) )
{
processOptions(*it);
}
}
/* then any general items */
vector<ShapeRef> shapes = processGeneralItems(node);
for (vector<ShapeRef>::iterator it = shapes.begin();
it != shapes.end();
it++)
{
m_shapes.push_back(*it);
}
}
ShapeRef Scene::processShape(refptr<Node> node)
{
if ( typeid(*node) == typeid(BoxNode) )
{
return processBox(node);
}
else if ( typeid(*node) == typeid(PlaneNode) )
{
return processPlane(node);
}
else if ( typeid(*node) == typeid(SphereNode) )
{
return processSphere(node);
}
else if ( typeid(*node) == typeid(CylNode) )
{
return processCyl(node);
}
else if ( typeid(*node) == typeid(IntersectNode)
|| typeid(*node) == typeid(UnionNode)
|| typeid(*node) == typeid(SubtractNode) )
{
return processBool(node);
}
else if ( typeid(*node) == typeid(ExtrudeNode) )
{
return processExtrude(node);
}
else if ( typeid(*node) == typeid(ShapeRefNode) )
{
return processShapeRef(node);
}
else
{
cerr << "Error: Unknown shape!" << endl;
exit(3);
}
return ShapeRef(NULL);
}
void Scene::processCamera(refptr<Node> node)
{
Vector position(0, 0, 0);
Vector look_at(0, 1, 0);
Vector up(0, 0, 1);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(PositionNode) )
{
position = * (*it)->getVector();
}
else if ( typeid(**it) == typeid(LookAtNode) )
{
look_at = * (*it)->getVector();
}
else if ( typeid(**it) == typeid(UpNode) )
{
up = * (*it)->getVector();
}
else if ( typeid(**it) == typeid(VFOVNode) )
{
m_vfov = (*it)->getNumber();
}
}
m_transforms.top().lookAt(position, look_at, up);
}
void Scene::processOptions(refptr<Node> node)
{
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(WidthNode) )
{
m_width = (*it)->getInteger();
}
else if ( typeid(**it) == typeid(HeightNode) )
{
m_height = (*it)->getInteger();
}
else if ( typeid(**it) == typeid(ExposureNode) )
{
m_exposure = (*it)->getNumber();
if (m_exposure < 0.0)
m_exposure = 0.0;
}
else if ( typeid(**it) == typeid(MultisampleNode) )
{
m_multisample_level = (*it)->getInteger();
}
else if ( typeid(**it) == typeid(MaxDepthNode) )
{
m_max_depth = (*it)->getInteger();
}
else if ( typeid(**it) == typeid(AmbientNode) )
{
setAmbientLight(Color((*it)->getVector()));
}
else if ( typeid(**it) == typeid(AmbientOcclusionNode) )
{
m_ambient_occlusion_level = (*it)->getInteger();
}
}
}
vector<ShapeRef> Scene::processTransformBlock(refptr<Node> node)
{
if ( typeid(*node) == typeid(TranslateBlockNode) )
{
m_transforms.push(m_transforms.top());
m_transforms.top().translate(node->getVector());
}
else if ( typeid(*node) == typeid(RotateBlockNode) )
{
m_transforms.push(m_transforms.top());
m_transforms.top().rotate(node->getNumber(),
node->getVector());
}
else if ( typeid(*node) == typeid(ScaleBlockNode) )
{
m_transforms.push(m_transforms.top());
m_transforms.top().scale(node->getVector());
}
else
{
cerr << "Unknown transformation block node type!" << endl;
exit(4);
}
vector<ShapeRef> shapes = processGeneralItems(node);
m_transforms.pop();
return shapes;
}
vector<ShapeRef> Scene::processGeneralItems(refptr<Node> node)
{
vector<ShapeRef> shapes, incoming;
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ((*it)->isTransformBlock())
{
incoming = processTransformBlock(*it);
}
else if ( typeid(**it) == typeid(MaterialDefinitionNode) )
{
processMaterialDefinition(*it);
}
else if ( typeid(**it) == typeid(ShapeDefinitionNode) )
{
processShapeDefinition(*it);
}
else if ( (*it)->isShape() )
{
shapes.push_back(processShape(*it));
}
while (incoming.size() > 0)
{
shapes.push_back(incoming[0]);
incoming.erase(incoming.begin());
}
}
return shapes;
}
void Scene::processMaterialDefinition(refptr<Node> node)
{
map< string, refptr<Material> >::iterator it =
m_materials.find(node->getString());
if ( it == m_materials.end() )
{
m_materials[node->getString()] = processMaterial(node);
}
else
{
cerr << "Error: duplicate material definition for material '"
<< node->getString() << "'" << endl;
exit(4);
}
}
refptr<Material> Scene::processMaterial(refptr<Node> node)
{
if ( typeid(*node) == typeid(MaterialRefNode) )
{
map< string, refptr<Material> >::iterator it =
m_materials.find(node->getString());
if ( it == m_materials.end() )
{
cerr << "Undefined material '" << node->getString()
<< "' requested!" << endl;
exit(4);
}
return m_materials[node->getString()];
}
refptr<Material> material = new Material();
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(ColorNode) )
{
material->setDiffuseColor(Color((*it)->getVector()));
material->setAmbientColor(Color((*it)->getVector()));
}
else if ( typeid(**it) == typeid(AmbientNode) )
{
material->setAmbientColor(Color((*it)->getVector()));
}
else if ( typeid(**it) == typeid(DiffuseNode) )
{
material->setDiffuseColor(Color((*it)->getVector()));
}
else if ( typeid(**it) == typeid(SpecularNode) )
{
material->setSpecularColor(Color((*it)->getVector()));
}
else if ( typeid(**it) == typeid(ReflectanceNode) )
{
material->setReflectance((*it)->getNumber());
}
else if ( typeid(**it) == typeid(RefractionNode) )
{
material->setRefraction((*it)->getNumber());
}
else if ( typeid(**it) == typeid(ShininessNode) )
{
material->setShininess((*it)->getNumber());
}
else if ( typeid(**it) == typeid(TransparencyNode) )
{
material->setTransparency((*it)->getNumber());
}
else if ( typeid(**it) == typeid(TextureNode) )
{
string filename = (*it)->getString();
FIBITMAP * fib = NULL;
if (m_textures.find(filename) != m_textures.end())
{
/* texture already loaded */
fib = m_textures[filename];
}
else
{
fib = loadTexture((*it)->getString());
}
if (fib != NULL)
{
material->setTexture(fib);
}
}
}
return material;
}
ShapeRef Scene::processBox(refptr<Node> node)
{
refptr<Vector> size = new Vector(1, 1, 1);
refptr<Material> material;
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(SizeNode) )
{
size = (*it)->getVector();
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
ShapeRef box = new Box(size);
if ( ! material.isNull() )
box->setMaterial(material);
box->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return box;
}
ShapeRef Scene::processCyl(refptr<Node> node)
{
double radius1 = 1.0;
double radius2 = 1.0;
double height = 1.0;
refptr<Material> material;
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(SizeNode) )
{
refptr<Vector> v = (*it)->getVector();
radius1 = (*v)[0];
radius2 = (*v)[1];
height = (*v)[2];
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
ShapeRef cyl = new Cyl(radius1, radius2, height);
if ( ! material.isNull() )
cyl->setMaterial(material);
cyl->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return cyl;
}
refptr<Light> Scene::processLight(refptr<Node> node)
{
refptr<Light> light = new PointLight();
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(PositionNode) )
{
refptr<Vector> v = (*it)->getVector();
light->setPosition(m_transforms.top().transform_point(*v));
}
else if ( typeid(**it) == typeid(DiffuseNode) )
{
Color c((*it)->getVector());
light->setDiffuseColor(c);
}
else if ( typeid(**it) == typeid(SpecularNode) )
{
Color c((*it)->getVector());
light->setSpecularColor(c);
}
else if ( typeid(**it) == typeid(ColorNode) )
{
Color c((*it)->getVector());
light->setDiffuseColor(c);
light->setSpecularColor(c);
}
else if ( typeid(**it) == typeid(RadiusNode) )
{
light->setRadius((*it)->getNumber());
}
else if ( typeid(**it) == typeid(JitterNode) )
{
light->setJitter((*it)->getInteger());
}
}
return light;
}
ShapeRef Scene::processPlane(refptr<Node> node)
{
Vector normal(0, 0, 1);
double dist = 0;
refptr<Material> material;
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(PlanePositionNode) )
{
normal = *(*it)->getVector();
dist = (*it)->getNumber();
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
ShapeRef plane = new Plane(normal[0],
normal[1],
normal[2],
dist);
if ( ! material.isNull() )
plane->setMaterial(material);
plane->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return plane;
}
ShapeRef Scene::processSphere(refptr<Node> node)
{
double radius = 1.0;
refptr<Material> material;
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(RadiusNode) )
{
radius = (*it)->getNumber();
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
ShapeRef sphere = new Sphere(radius);
if ( ! material.isNull() )
sphere->setMaterial(material);
sphere->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return sphere;
}
ShapeRef Scene::processBool(refptr<Node> node)
{
vector<ShapeRef> shapes;
refptr<Material> material;
bool restore_transform = processTransforms(node);
m_transforms.push(Transform());
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( (*it)->isShape() )
{
ShapeRef shape = processShape(*it);
if ( ! shape.isNull() )
shapes.push_back(shape);
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
else if ( (*it)->isTransformBlock() )
{
vector<ShapeRef> in = processTransformBlock(*it);
for (int i = 0, sz = in.size(); i < sz; i++)
{
shapes.push_back(in[i]);
}
}
else if ( typeid(**it) == typeid(ShapeDefinitionNode) )
{
processShapeDefinition(*it);
}
}
if (shapes.size() < 2)
{
cerr << "Error: boolean objects must have 2 or more sub-objects!"
<< endl;
exit(3);
}
ShapeRef shape;
if ( typeid(*node) == typeid(IntersectNode) )
shape = new Intersect(shapes);
else if ( typeid(*node) == typeid(UnionNode) )
shape = new Union(shapes);
else if ( typeid(*node) == typeid(SubtractNode) )
shape = new Subtract(shapes);
else
{
cerr << __FILE__ << ": " << __LINE__
<< ": error: bool object unrecognized" << endl;
exit(3);
}
if ( ! material.isNull() )
shape->setMaterial(material);
m_transforms.pop();
shape->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return shape;
}
ShapeRef Scene::processExtrude(refptr<Node> node)
{
refptr<Material> material;
Extrude * extrude = new Extrude();
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(PolygonNode) )
{
extrude->addPolygon(processPolygon(*it));
}
else if ( typeid(**it) == typeid(NGonNode) )
{
extrude->addPolygon(processNGon(*it));
}
else if ( typeid(**it) == typeid(OffsetNode) )
{
double distance = (*it)->getNumber();
if (distance <= 0.0)
{
cerr << "Error: extrude distance must be positive" << endl;
exit(3);
}
Vector scale(1, 1, 1);
Vector position(0, 0, 0);
for (Node_Iterator it2 = (*it)->getChildren().begin();
it2 != (*it)->getChildren().end();
it2++)
{
if ( typeid(**it2) == typeid(ScaleNode) )
{
scale = * (*it2)->getVector();
}
else if ( typeid(**it2) == typeid(PositionNode) )
{
position = * (*it2)->getVector();
}
}
if (scale[0] < 0.0 || scale[1] < 0.0)
{
cerr << "Error: extrude scale cannot be negative" << endl;
exit(3);
}
extrude->addOffset(distance, scale, position);
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
if ( ! material.isNull() )
extrude->setMaterial(material);
extrude->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return extrude;
}
refptr<Polygon> Scene::processPolygon(refptr<Node> node)
{
refptr<Polygon> p = new Polygon();
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(VectorNode) )
{
p->push_back((*it)->getVector());
}
else
{
cerr << "Error: Unknown polygon sub-object" << endl;
exit(3);
}
}
if (p->size() < 3)
{
cerr << "Error: Polygon with fewer than three points!" << endl;
exit(3);
}
return p;
}
refptr<Polygon> Scene::processNGon(refptr<Node> node)
{
refptr<Polygon> p = new Polygon();
double radius = node->getChildren()[0]->getNumber();
int n = node->getInteger();
int step = n < 0 ? -1 : 1;
n = abs(n);
if (n < 3)
n = 3;
int pos = 0;
double astep = 2.0 * M_PI / n;
for (int i = 0; i < n; i++)
{
p->push_back(new Vector(
radius * cos(pos * astep),
radius * sin(pos * astep),
0.0));
pos += step;
}
return p;
}
ShapeRef Scene::processShapeRef(refptr<Node> node)
{
if (m_shape_definitions.find(node->getString())
== m_shape_definitions.end())
{
cerr << "Error: no shape definition for '" << node->getString()
<< "' found!" << endl;
exit(3);
}
refptr<Material> material;
ShapeRef shape = m_shape_definitions[node->getString()]->clone();
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
if ( ! material.isNull() )
shape->setMaterial(material);
shape->setTransform(m_transforms.top() * shape->getTransform());
if (restore_transform)
m_transforms.pop();
return shape;
}
bool Scene::processTransforms(refptr<Node> node)
{
bool did_any = false;
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(TranslateNode) )
{
if (did_any == false)
{
m_transforms.push(m_transforms.top());
did_any = true;
}
m_transforms.top().translate((*it)->getVector());
}
else if ( typeid(**it) == typeid(RotateNode) )
{
if (did_any == false)
{
m_transforms.push(m_transforms.top());
did_any = true;
}
m_transforms.top().rotate((*it)->getNumber(),
(*it)->getVector());
}
else if ( typeid(**it) == typeid(ScaleNode) )
{
if (did_any == false)
{
m_transforms.push(m_transforms.top());
did_any = true;
}
m_transforms.top().scale((*it)->getVector());
}
}
return did_any;
}
void Scene::processShapeDefinition(refptr<Node> node)
{
m_transforms.push(Transform());
m_shape_definitions[node->getString()]
= processShape(node->getChildren()[0]);
m_transforms.pop();
}
FIBITMAP * Scene::loadTexture(const std::string & filename)
{
FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(filename.c_str(), 0);
if (fif == FIF_UNKNOWN)
{
fif = FreeImage_GetFIFFromFilename(filename.c_str());
if (fif == FIF_UNKNOWN)
{
cerr << "Error: couldn't determine image format for \""
<< filename << "\"" << endl;
return NULL;
}
}
if (!FreeImage_FIFSupportsReading(fif))
{
cerr << "Error: image format of \"" << filename
<< "\" does not support reading" << endl;
return NULL;
}
FIBITMAP * fib = FreeImage_Load(fif, filename.c_str(), 0);
if (fib == NULL)
{
cerr << "Error: image \"" << filename << "\" could not be loaded"
<< endl;
}
return fib;
}

View File

@ -1,405 +0,0 @@
#include <math.h> /* exp(), pow(), M_PI */
#include <stdlib.h>
#include <string>
#include <vector>
#include <utility> /* pair */
#include <map>
#include <algorithm> /* sort() */
#include <functional> /* binary_function */
#include <typeinfo> /* typeid operator support */
#include "Scene.h"
#include "BMP.h"
#include "util/Color.h"
#include "shapes/Shape.h"
#include "Light.h"
using namespace std;
#define MAX_AMBIENT_OCCLUSION_DISTANCE 50.0
Scene::Scene(const map<string, const char *> & options,
const char * filename)
{
m_width = 800;
m_height = 600;
m_multisample_level = 1;
m_vfov = 60.0;
m_ambient_light = Color(0.2, 0.2, 0.2);
m_max_depth = 10;
m_exposure = 1.0f;
m_ambient_occlusion_level = 0;
m_transforms.push(Transform());
load(filename);
/* after loading the scene file, apply any command-line render options */
for (map<const string, const char *>::const_iterator it = options.begin();
it != options.end();
it++)
{
if (it->first == "width")
{
m_width = atoi(it->second);
}
else if (it->first == "height")
{
m_height = atoi(it->second);
}
else if (it->first == "multisample")
{
m_multisample_level = atoi(it->second);
}
else if (it->first == "field-of-view")
{
m_vfov = atof(it->second);
}
else if (it->first == "max-depth")
{
m_max_depth = atoi(it->second);
}
else if (it->first == "ambient-occlusion")
{
m_ambient_occlusion_level = atoi(it->second);
}
}
/* view plane distance is calculated based on the field of view */
m_view_plane_dist = (m_height / 2.0) / tan(M_PI * m_vfov / 360.0);
m_sample_span = 1.0 / m_multisample_level;
m_half_sample_span = m_sample_span / 2.0;
m_multisample_level_squared = m_multisample_level * m_multisample_level;
}
Scene::~Scene()
{
/* clean up any textures loaded with freeimage */
for (std::map< std::string, FIBITMAP * >::iterator it = m_textures.begin();
it != m_textures.end();
it++)
{
FreeImage_Unload(it->second);
}
}
void Scene::renderPixel(int x, int y, unsigned char * pixel)
{
/* calculate the ray going from the camera through this pixel */
Color finalColor;
for (int i = 0; i < m_multisample_level; i++)
{
for (int j = 0; j < m_multisample_level; j++)
{
double rx = (x + i * m_sample_span + m_half_sample_span)
- (m_width / 2.0);
double rz = (m_height / 2.0)
- (y + j * m_sample_span + m_half_sample_span);
Ray ray(Vector(0, 0, 0), Vector(rx, m_view_plane_dist, rz));
finalColor += traceRay(ray);
}
}
/* apply exposure formula so we aren't saturated */
finalColor.r = 1.0f -
exp(-m_exposure * finalColor.r / m_multisample_level_squared);
finalColor.g = 1.0f -
exp(-m_exposure * finalColor.g / m_multisample_level_squared);
finalColor.b = 1.0f -
exp(-m_exposure * finalColor.b / m_multisample_level_squared);
#if 0
/* gamma correct */
finalColor.r = pow(finalColor.r, 1 / 2.2);
finalColor.g = pow(finalColor.g, 1 / 2.2);
finalColor.b = pow(finalColor.b, 1 / 2.2);
#endif
/* take the average of all the samples as the final pixel value */
pixel[BMP_RED] = (unsigned char) (0xFF * finalColor.r);
pixel[BMP_GREEN] = (unsigned char) (0xFF * finalColor.g);
pixel[BMP_BLUE] = (unsigned char) (0xFF * finalColor.b);
}
Color Scene::traceRay(const Ray & ray)
{
return traceRayRecurse(ray, m_max_depth, 1.0, NULL);
}
/**
* factor: the proportion of the final color that this computation is worth
*/
Color Scene::traceRayRecurse(const Ray & ray, int depth, double factor,
refptr<Material> last_material)
{
static refptr<Material> air = new Material();
Color color(0, 0, 0);
if (last_material.isNull())
last_material = air;
Shape::Intersection hit = getRayClosestHit(ray);
if ( ! hit.shape.isNull() )
{
/* compute the Phong lighting for each hit */
refptr<Material> material = hit.shape->getMaterial();
/* check for backfaces */
bool frontface = ray.getDirection() % hit.normal < 0.0;
if (frontface)
{
color = computePhong(material,
ray,
hit.position,
hit.normal);
if (depth > 0 && factor > SCENE_FACTOR_THRESHOLD)
{
double reflectance = material->getReflectance();
if (factor * reflectance > SCENE_FACTOR_THRESHOLD)
{
color *= (1.0 - reflectance);
Vector reflected_direction =
ray.getDirection().reflect(hit.normal);
Ray newRay(hit.position, reflected_direction);
Vector jitter_surface_point = newRay[0.0001];
Ray jitterNewRay(jitter_surface_point, reflected_direction);
Color c = traceRayRecurse(jitterNewRay,
depth - 1,
factor * reflectance,
material);
color += c * reflectance;
}
double transparency = material->getTransparency();
if (factor * transparency > SCENE_FACTOR_THRESHOLD)
{
color *= (1.0 - transparency);
Vector jitter_surface_point = hit.position
+ ray.getDirection() * 0.0001;
Vector refracted_direction =
ray.getDirection().refract(hit.normal,
last_material->getRefraction(),
material->getRefraction());
Ray newRay(jitter_surface_point, refracted_direction);
Color c = traceRayRecurse(newRay,
depth - 1,
factor * transparency,
material);
color += c * transparency;
}
}
}
else
{
material = air;
Vector jitter_surface_point = hit.position
+ ray.getDirection() * 0.0001;
Vector refracted_direction =
ray.getDirection().refract(-hit.normal,
last_material->getRefraction(),
material->getRefraction());
Ray newRay(jitter_surface_point, refracted_direction);
color = traceRayRecurse(newRay, depth, factor, material);
}
}
return color;
}
Shape::Intersection Scene::getRayClosestHit(const Ray & ray)
{
Shape::Intersection hit;
double min_dist = 0.0;
bool foundOne = false;
/* loop through all shapes in the scene */
for (vector< refptr<Shape> >::iterator it = m_shapes.begin();
it != m_shapes.end();
it++)
{
Shape::IntersectionList intersections = (*it)->intersect(*it, ray);
for (int i = 0, num_results = intersections.size();
i < num_results;
i++)
{
refptr<Shape> shape = intersections[i].shape;
const Vector & isect_point = intersections[i].position;
double intersect_dist = ray.getOrigin().dist_to(isect_point);
if (foundOne == false || intersect_dist < min_dist)
{
hit = intersections[i];
min_dist = intersect_dist;
foundOne = true;
}
}
}
return hit;
}
Color Scene::computePhong(const refptr<Material> material,
const Ray & viewRay,
const Vector & surfacePoint,
const Vector & surfaceNormal)
{
Color result = m_ambient_light * material->getAmbientColor();
if (m_ambient_occlusion_level > 0)
{
result *= calculateAmbientOcclusion(
Ray(surfacePoint, surfaceNormal).shift(1e-7));
}
Vector viewDirection = -viewRay.getDirection();
double shininess = material->getShininess();
const Color & diffuseColor = material->getDiffuseColor();
const Color & specularColor = material->getSpecularColor();
for (std::vector< refptr<Light> >::const_iterator it = m_lights.begin();
it != m_lights.end();
it++)
{
Vector lightC = (*it)->getPosition();
double lightRadius = (*it)->getRadius();
Vector directionToLightC = lightC - surfacePoint;
Vector lightPlaneX = directionToLightC.getPerpendicular().normalize();
Vector lightPlaneY = (directionToLightC * lightPlaneX).normalize();
int jitter_samples = 0, jitter_level = (*it)->getJitter();;
Color jitterResult;
for (int jitter_index = 0; jitter_index < jitter_level; jitter_index++)
{
double jitterRadius = jitter_index * lightRadius
/ (jitter_level - 0.5);
for (int i = 0, num = (int) (M_PI * jitter_index) + 1; i < num; i++)
{
jitter_samples++;
double jitter_angle = i * 2.0 * M_PI / num;
Vector jitterPosition = lightC
+ lightPlaneX * jitterRadius * cos(jitter_angle)
+ lightPlaneY * jitterRadius * sin(jitter_angle);
Vector directionToLight = jitterPosition - surfacePoint;
directionToLight.normalize();
Vector reflectedLightDirection =
(-directionToLight).reflect(surfaceNormal);
Ray surfaceToLight(surfacePoint, directionToLight);
Color light_contribution =
calculateLightContribution(surfaceToLight.shift(0.0001),
jitterPosition);
if ( light_contribution.r > 0.0
|| light_contribution.g > 0.0
|| light_contribution.b > 0.0 )
{
/* calculate the diffuse term */
double diffuse_coef = directionToLight % surfaceNormal;
if (diffuse_coef > 0.0)
{
jitterResult += diffuseColor
* (*it)->getDiffuseColor()
* diffuse_coef
* light_contribution;
}
/* calculate the specular term */
double specular_coef = reflectedLightDirection % viewDirection;
if (specular_coef > 0.0)
{
jitterResult += specularColor
* (*it)->getSpecularColor()
* pow(specular_coef, shininess)
* light_contribution;
}
}
}
}
jitterResult /= jitter_samples;
result += jitterResult;
}
return result;
}
Color Scene::calculateLightContribution(const Ray & toLight,
const Vector & lightPosition)
{
Color contrib(1.0, 1.0, 1.0);
double dist_to_light = (lightPosition - toLight.getOrigin()).mag();
double dist_so_far = 0.0;
Ray currentRay = toLight;
for (;;)
{
Shape::Intersection hit = getRayClosestHit(currentRay);
if ( hit.shape.isNull() )
break;
double offset = currentRay.getOrigin().dist_to(hit.position) + 0.0001;
if ( dist_so_far + offset > dist_to_light )
break;
contrib *= hit.shape->getMaterial()->getTransparency();
contrib *= hit.shape->getMaterial()->getDiffuseColor();
if ( contrib.r < SCENE_FACTOR_THRESHOLD
&& contrib.g < SCENE_FACTOR_THRESHOLD
&& contrib.b < SCENE_FACTOR_THRESHOLD )
break;
dist_so_far += offset;
currentRay = currentRay.shift(offset);
}
return contrib;
}
Color Scene::calculateAmbientOcclusion(const Ray & surfaceNormal)
{
Color result(1, 1, 1);
const int nISteps = m_ambient_occlusion_level * 6;
const int nJSteps = nISteps / 2;
int nRays = 0;
Vector perpX = surfaceNormal.getDirection().getPerpendicular().normalize();
Vector perpY = (surfaceNormal.getDirection() * perpX).normalize();
double istep = 2.0 * M_PI / nISteps;
double jstep = M_PI_2 / nJSteps;
for (int i = 0; i < nISteps; i++)
{
int lim = i > 0 ? nJSteps : 1;
for (int j = 0; j < lim; j++)
{
Vector direction = cos(i * istep) * sin(j * jstep) * perpX
+ sin(i * istep) * sin(j * jstep) * perpY
+ cos(j * jstep) * surfaceNormal.getDirection();
Ray thisRay(surfaceNormal.getOrigin(), direction);
double dist = 0.0;
Color contrib(1, 1, 1);
while (contrib.r > 0.2 && contrib.g > 0.2 && contrib.b > 0.2)
{
Shape::Intersection hit = getRayClosestHit(thisRay);
if (hit.shape.isNull())
break;
double hitDist = (hit.position - thisRay.getOrigin()).mag();
dist += hitDist;
if (dist > MAX_AMBIENT_OCCLUSION_DISTANCE)
break;
contrib *= hit.shape->getMaterial()->getTransparency()
* hit.shape->getMaterial()->getDiffuseColor();
thisRay = thisRay.shift(hitDist + 1E-7);
}
result += contrib;
nRays++;
}
}
result /= nRays;
return result;
}

View File

@ -1,111 +0,0 @@
#ifndef SCENE_H
#define SCENE_H SCENE_H
#include <string>
#include <map>
#include <vector>
#include <utility>
#include <stack>
#include <FreeImage.h>
#include "util/refptr.h"
#include "util/Ray.h"
#include "util/Color.h"
#include "util/Material.h"
#include "util/Polygon.h"
#include "shapes/shapes.h"
#include "parser/parser.h"
#include "parser/nodes.h"
#include "Light.h"
#define SCENE_FACTOR_THRESHOLD 0.02
class Scene
{
public:
Scene(const std::map<std::string, const char *> & options,
const char * filename);
~Scene();
void setWidth(int width) { m_width = width; }
void setHeight(int height) { m_height = height; }
void setMultisampleLevel(int level) { m_multisample_level = level; }
void setVFOV(double vfov) { m_vfov = vfov; }
void setAmbientLight(const Color & al) { m_ambient_light = al; }
void renderPixel(int x, int y, unsigned char * pixel);
void setMaxDepth(int d) { m_max_depth = d; }
int getWidth() { return m_width; }
int getHeight() { return m_height; }
int getMultisampleLevel() { return m_multisample_level; }
int getAmbientOcclusionLevel() { return m_ambient_occlusion_level; }
double getVFOV() { return m_vfov; }
int getMaxDepth() { return m_max_depth; }
protected:
/* private methods */
Color traceRay(const Ray & ray);
Color traceRayRecurse(const Ray & ray, int depth, double factor,
refptr<Material> last_material);
Shape::Intersection getRayClosestHit(const Ray & ray);
Color computePhong(const refptr<Material> material,
const Ray & viewRay,
const Vector & surfacePoint,
const Vector & surfaceNormal);
Color calculateLightContribution(const Ray & toLight,
const Vector & lightPosition);
Color calculateAmbientOcclusion(const Ray & surfaceNormal);
/* In Scene-load.cc */
void load(const char * filename);
void processScene(refptr<Node> node);
refptr<Material> processMaterial(refptr<Node> node);
ShapeRef processBox(refptr<Node> node);
ShapeRef processCyl(refptr<Node> node);
refptr<Light> processLight(refptr<Node> node);
ShapeRef processPlane(refptr<Node> node);
ShapeRef processSphere(refptr<Node> node);
ShapeRef processShape(refptr<Node> node);
ShapeRef processBool(refptr<Node> node);
ShapeRef processExtrude(refptr<Node> node);
ShapeRef processShapeRef(refptr<Node> node);
refptr<Polygon> processPolygon(refptr<Node> node);
refptr<Polygon> processNGon(refptr<Node> node);
bool processTransforms(refptr<Node> node);
void processCamera(refptr<Node> node);
void processOptions(refptr<Node> node);
std::vector<ShapeRef> processTransformBlock(refptr<Node> node);
std::vector<ShapeRef> processGeneralItems(refptr<Node> node);
std::vector<ShapeRef> processForNode(refptr<Node> node);
void processMaterialDefinition(refptr<Node> node);
void processShapeDefinition(refptr<Node> node);
FIBITMAP * loadTexture(const std::string & filename);
/* rendering parameters */
int m_width;
int m_height;
int m_multisample_level;
double m_vfov;
Color m_ambient_light;
int m_max_depth;
double m_exposure;
int m_ambient_occlusion_level;
/* private data */
std::vector<ShapeRef> m_shapes;
std::map<std::string, ShapeRef> m_shape_definitions;
std::vector< refptr<Light> > m_lights;
std::stack<Transform> m_transforms;
double m_view_plane_dist;
int m_multisample_level_squared;
double m_sample_span;
double m_half_sample_span;
std::map< std::string, refptr<Material> > m_materials;
std::map< std::string, FIBITMAP * > m_textures;
};
#endif

View File

@ -1,345 +0,0 @@
#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;
}

View File

@ -1,283 +0,0 @@
#include <stdlib.h>
#include <math.h>
#include <vector>
#include <iostream>
#include <typeinfo>
#include <map>
#include "nodes.h"
using namespace std;
typedef NodeRef (*Function)(NodeRef args);
NodeRef CosFunction(NodeRef args);
NodeRef SinFunction(NodeRef args);
NodeRef SqrtFunction(NodeRef args);
NodeRef AbsFunction(NodeRef args);
static const struct {
const char * fn_name;
Function fn;
} functions[] = {
{"cos", CosFunction},
{"sin", SinFunction},
{"sqrt", SqrtFunction},
{"abs", AbsFunction}
};
class FunctionMap : public map<string, Function>
{
public:
FunctionMap()
{
for (unsigned int i = 0;
i < sizeof(functions)/sizeof(functions[0]);
i++)
{
(*this)[functions[i].fn_name] = functions[i].fn;
}
}
bool contains(const string & key)
{
return find(key) != end();
}
};
static FunctionMap function_map;
void Node::evaluateChildren(refptr<Node> parent)
{
/* recursively evaluate all children nodes */
for (std::vector< refptr<Node> >::iterator it = m_children.begin();
it != m_children.end();
it++)
{
refptr<Node> evaluated = (*it)->evaluate();
if ( ! evaluated.isNull() )
{
if (typeid(*evaluated) == typeid(EvaluatePropagateNode))
{
for (vector<NodeRef>::iterator it2
= evaluated->getChildren().begin();
it2 != evaluated->getChildren().end();
it2++)
{
parent->addChild(*it2);
}
}
else
{
(*it)->evaluateChildren(evaluated);
parent->addChild(evaluated);
}
}
}
}
void Node::addChildren(NodeRef other)
{
if (other.isNull())
return;
for (vector<NodeRef>::const_iterator it = other->m_children.begin();
it != other->m_children.end();
it++)
{
addChild(*it);
}
}
Node::~Node()
{
}
NodeRef BinOpNode::evaluate()
{
double o = one->evaluate()->getNumber();
double t = two->evaluate()->getNumber();
double r = 0.0;
switch (m_op)
{
case '*':
r = o * t;
break;
case '/':
r = o / t;
break;
case '+':
r = o + t;
break;
case '-':
r = o - t;
break;
case '%':
r = (int) o % (int) t;
break;
case '^':
r = pow(o, t);
break;
default:
cerr << "Error: BinOpNode created with op '" << m_op << "'" << endl;
exit(-3);
}
return new NumberNode(r);
}
NodeRef BoolExpressionNode::evaluate()
{
double o = 0, t = 0;
double r = 0;
if (m_op != '!' && m_op != '&' && m_op != '|')
{
o = one->evaluate()->getNumber();
t = two->evaluate()->getNumber();
}
switch (m_op)
{
case '<':
r = o < t ? 1 : 0;
break;
case 'l':
r = o <= t ? 1 : 0;
break;
case '>':
r = o > t ? 1 : 0;
break;
case 'g':
r = o >= t ? 1 : 0;
break;
case '=':
r = o == t ? 1 : 0;
break;
case 'n':
r = o != t ? 1 : 0;
break;
case '&':
r = one->evaluate()->getInteger();
if (r != 0)
{
r = two->evaluate()->getInteger();
}
break;
case '|':
r = one->evaluate()->getInteger();
if (r == 0)
{
r = two->evaluate()->getInteger();
}
break;
case '!':
r = ! one->evaluate()->getInteger();
break;
case 'T':
r = 1;
break;
}
return new NumberNode(r);
}
NodeRef ForNode::evaluate()
{
NodeRef eval = new EvaluatePropagateNode();
if (!m_nodes[0].isNull())
{
m_nodes[0]->evaluate();
}
while (m_nodes[1]->evaluate()->getInteger() != 0)
{
evaluateChildren(eval);
if (!m_nodes[2].isNull())
{
m_nodes[2]->evaluate();
}
}
return eval;
}
NodeRef IfNode::evaluate()
{
NodeRef eval = new EvaluatePropagateNode();
int if_val = m_test_expr->evaluate()->getInteger();
if (if_val != 0)
{
evaluateChildren(eval);
}
else if ( ! m_elses.isNull() )
{
return m_elses->evaluate();
}
return eval;
}
NodeRef ElseNode::evaluate()
{
NodeRef eval = new EvaluatePropagateNode();
evaluateChildren(eval);
return eval;
}
NodeRef FunctionCallNode::evaluate()
{
if (function_map.contains(m_name->getString()))
{
return function_map[m_name->getString()](m_parameters);
}
cerr << "Error: no function \"" << m_name->getString() << "\" defined!"
<< endl;
exit(4);
}
/**************************************************************************
* Scene file functions *
*************************************************************************/
NodeRef CosFunction(NodeRef args)
{
if (args->getChildren().size() != 1)
{
cerr << "Error: cos function requires 1 argument" << endl;
exit(4);
}
return new NumberNode(cos(args->getChildren()[0]->evaluate()->getNumber()));
}
NodeRef SinFunction(NodeRef args)
{
if (args->getChildren().size() != 1)
{
cerr << "Error: sin function requires 1 argument" << endl;
exit(4);
}
return new NumberNode(sin(args->getChildren()[0]->evaluate()->getNumber()));
}
NodeRef SqrtFunction(NodeRef args)
{
if (args->getChildren().size() != 1)
{
cerr << "Error: sqrt function requires 1 argument" << endl;
exit(4);
}
return new NumberNode(sqrt(args->getChildren()[0]->evaluate()->getNumber()));
}
NodeRef AbsFunction(NodeRef args)
{
if (args->getChildren().size() != 1)
{
cerr << "Error: abs function requires 1 argument" << endl;
exit(4);
}
return new NumberNode(fabs(args->getChildren()[0]->evaluate()->getNumber()));
}

View File

@ -1,791 +0,0 @@
#ifndef NODES_H
#define NODES_H NODES_H
#include <stdlib.h> /* exit() */
#include <vector>
#include <string>
#include <iostream>
#include "util/refptr.h"
#include "util/Vector.h"
#include "util/Scope.h"
extern refptr<Scope> parser_scope;
class Node
{
public:
virtual ~Node();
void addChild(refptr<Node> child) { m_children.push_back(child); }
void addChildren(refptr<Node> other);
std::vector< refptr<Node> > & getChildren() { return m_children; }
virtual int getInteger() { return getNumber(); }
virtual double getNumber()
{
std::cerr << "Warning: Node::getNumber() called!" << std::endl;
return 0.0;
}
virtual refptr<Vector> getVector()
{
std::cerr << "Warning: Node::getVector() called!" << std::endl;
return refptr<Vector>(NULL);
}
virtual std::string getString()
{
std::cerr << "Warning: Node::getString() called!" << std::endl;
return "";
}
virtual refptr<Node> evaluate()
{
std::cerr << "Warning: Node::evaluate() called!" << std::endl;
return NULL;
}
virtual void evaluateChildren(refptr<Node> parent);
virtual bool isShape() { return false; }
virtual bool isMaterial() { return false; }
virtual bool isTransformBlock() { return false; }
virtual bool isExpression() { return false; }
protected:
std::vector< refptr<Node> > m_children;
};
typedef refptr<Node> NodeRef;
class NumberNode : public Node
{
public:
NumberNode(double number)
: m_number(number), m_direct(true)
{
}
NumberNode(NodeRef expr)
: m_direct(false)
{
m_expr = expr;
}
virtual double getNumber()
{
return m_direct ? m_number : m_expr->getNumber();
}
virtual refptr<Node> evaluate()
{
return m_direct
? new NumberNode(m_number)
: new NumberNode(m_expr->evaluate());
}
protected:
double m_number;
bool m_direct;
NodeRef m_expr;
};
class VectorNode : public Node
{
public:
VectorNode(NodeRef a, NodeRef b, NodeRef c)
: m_a(a), m_b(b), m_c(c), m_direct(true)
{
}
VectorNode(NodeRef node)
: m_vector(node), m_direct(false)
{
}
refptr<Vector> getVector()
{
return m_direct
? new Vector(m_a->getNumber(),
m_b->getNumber(),
m_c->getNumber())
: m_vector->getVector();
}
virtual NodeRef evaluate()
{
return m_direct
? new VectorNode(m_a->evaluate(),
m_b->evaluate(),
m_c->evaluate())
: m_vector->evaluate();
}
protected:
NodeRef m_a, m_b, m_c, m_vector;
bool m_direct;
};
class AmbientNode : public VectorNode
{
public:
AmbientNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new AmbientNode(m_vector->evaluate());
}
};
class AmbientOcclusionNode : public NumberNode
{
public:
AmbientOcclusionNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new AmbientOcclusionNode(m_expr->evaluate());
}
};
class BoxNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate()
{
return new BoxNode();
}
};
class CameraNode : public Node
{
public:
virtual NodeRef evaluate()
{
return new CameraNode();
}
};
class ColorNode : public VectorNode
{
public:
ColorNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new ColorNode(m_vector->evaluate());
}
};
class CylNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate()
{
return new CylNode();
}
};
class DiffuseNode : public VectorNode
{
public:
DiffuseNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new DiffuseNode(m_vector->evaluate());
}
};
class ExposureNode : public NumberNode
{
public:
ExposureNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new ExposureNode(m_expr->evaluate());
}
};
class ExtrudeNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate()
{
return new ExtrudeNode();
}
};
class HeightNode : public NumberNode
{
public:
HeightNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new HeightNode(m_expr->evaluate());
}
};
class IdentifierNode : public Node
{
public:
IdentifierNode(const std::string & str) { m_string = str; }
std::string getString() { return m_string; }
virtual NodeRef evaluate()
{
return new IdentifierNode(m_string);
}
protected:
std::string m_string;
};
class IntersectNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate()
{
return new IntersectNode();
}
};
class ItemsNode : public Node
{
public:
virtual NodeRef evaluate()
{
return new ItemsNode();
}
};
class JitterNode : public NumberNode
{
public:
JitterNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new JitterNode(m_expr->evaluate());
}
};
class LightNode : public Node
{
public:
virtual NodeRef evaluate() { return new LightNode(); }
};
class LookAtNode : public VectorNode
{
public:
LookAtNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new LookAtNode(m_vector->evaluate());
}
};
class MaterialNode : public Node
{
public:
bool isMaterial() { return true; }
virtual NodeRef evaluate() { return new MaterialNode(); }
};
class MaterialDefinitionNode : public IdentifierNode
{
public:
MaterialDefinitionNode(const std::string & str) : IdentifierNode(str) {}
virtual NodeRef evaluate()
{
return new MaterialDefinitionNode(m_string);
}
};
class MaterialRefNode : public IdentifierNode
{
public:
MaterialRefNode(const std::string & str) : IdentifierNode(str) {}
bool isMaterial() { return true; }
virtual NodeRef evaluate() { return new MaterialRefNode(m_string); }
};
class MaxDepthNode : public NumberNode
{
public:
MaxDepthNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new MaxDepthNode(m_expr->evaluate());
}
};
class MultisampleNode : public NumberNode
{
public:
MultisampleNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new MultisampleNode(m_expr->evaluate());
}
};
class NGonNode : public NumberNode
{
public:
NGonNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new NGonNode(m_expr->evaluate());
}
};
class OffsetNode : public NumberNode
{
public:
OffsetNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new OffsetNode(m_expr->evaluate());
}
};
class OptionsNode : public Node
{
public:
virtual NodeRef evaluate() { return new OptionsNode(); }
};
class PlaneNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate() { return new PlaneNode(); }
};
class PlanePositionNode : public VectorNode
{
public:
PlanePositionNode(NodeRef vec_node, NodeRef dist)
: VectorNode(vec_node)
{
m_dist = dist;
}
double getNumber() { return m_dist->getNumber(); }
virtual NodeRef evaluate()
{
return new PlanePositionNode(m_vector->evaluate(),
m_dist->evaluate());
}
protected:
NodeRef m_dist;
};
class PolygonNode : public Node
{
public:
virtual NodeRef evaluate() { return new PolygonNode(); }
};
class PositionNode : public VectorNode
{
public:
PositionNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new PositionNode(m_vector->evaluate());
}
};
class RadiusNode : public NumberNode
{
public:
RadiusNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new RadiusNode(m_expr->evaluate());
}
};
class ReflectanceNode : public NumberNode
{
public:
ReflectanceNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new ReflectanceNode(m_expr->evaluate());
}
};
class RefractionNode : public NumberNode
{
public:
RefractionNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new RefractionNode(m_expr->evaluate());
}
};
class RotateNode : public VectorNode
{
public:
RotateNode(NodeRef angle, NodeRef vec_node)
: VectorNode(vec_node)
{
m_angle = angle;
}
double getNumber() { return m_angle->getNumber(); }
virtual NodeRef evaluate()
{
return new RotateNode(m_angle->evaluate(), m_vector->evaluate());
}
protected:
NodeRef m_angle;
};
class RotateBlockNode : public RotateNode
{
public:
RotateBlockNode(NodeRef angle, NodeRef vec_node)
: RotateNode(angle, vec_node) {}
bool isTransformBlock() { return true; }
virtual NodeRef evaluate()
{
return new RotateBlockNode(m_angle->evaluate(), m_vector->evaluate());
}
};
class ScaleNode : public VectorNode
{
public:
ScaleNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new ScaleNode(m_vector->evaluate());
}
};
class ScaleBlockNode : public ScaleNode
{
public:
ScaleBlockNode(NodeRef vector) : ScaleNode(vector) {}
bool isTransformBlock() { return true; }
virtual NodeRef evaluate()
{
return new ScaleBlockNode(m_vector->evaluate());
}
};
class ScaleScalarNode : public Node
{
public:
ScaleScalarNode(NodeRef expr)
: m_expr(expr)
{
}
virtual NodeRef evaluate()
{
NodeRef n = m_expr->evaluate();
return new VectorNode(n, n, n);
}
protected:
NodeRef m_expr;
};
class SceneNode : public Node
{
public:
virtual NodeRef evaluate() { return new SceneNode(); }
};
class ShapeDefinitionNode : public IdentifierNode
{
public:
ShapeDefinitionNode(const std::string & str) : IdentifierNode(str) {}
virtual NodeRef evaluate() { return new ShapeDefinitionNode(m_string); }
};
class ShapeRefNode : public IdentifierNode
{
public:
ShapeRefNode(const std::string & str) : IdentifierNode(str) {}
bool isShape() { return true; }
virtual NodeRef evaluate() { return new ShapeRefNode(m_string); }
};
class ShininessNode : public NumberNode
{
public:
ShininessNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new ShininessNode(m_expr->evaluate());
}
};
class SizeNode : public VectorNode
{
public:
SizeNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new SizeNode(m_vector->evaluate());
}
};
class SpecularNode : public VectorNode
{
public:
SpecularNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new SpecularNode(m_vector->evaluate());
}
};
class SphereNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate() { return new SphereNode(); }
};
class SubtractNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate() { return new SubtractNode(); }
};
class TextureNode : public IdentifierNode
{
public:
TextureNode(const std::string & str) : IdentifierNode(str) {}
virtual NodeRef evaluate() { return new TextureNode(m_string); }
};
class TranslateNode : public VectorNode
{
public:
TranslateNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new TranslateNode(m_vector->evaluate());
}
};
class TranslateBlockNode : public TranslateNode
{
public:
TranslateBlockNode(NodeRef vector) : TranslateNode(vector) {}
bool isTransformBlock() { return true; }
virtual NodeRef evaluate()
{
return new TranslateBlockNode(m_vector->evaluate());
}
};
class TransparencyNode : public NumberNode
{
public:
TransparencyNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new TransparencyNode(m_expr->evaluate());
}
};
class UnionNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate() { return new UnionNode(); }
};
class UpNode : public VectorNode
{
public:
UpNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new UpNode(m_vector->evaluate());
}
};
class VFOVNode : public NumberNode
{
public:
VFOVNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new VFOVNode(m_expr->evaluate());
}
};
class WidthNode : public NumberNode
{
public:
WidthNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new WidthNode(m_expr->evaluate());
}
};
/******** scripting nodes ********/
class ExpressionNode : public Node
{
public:
bool isExpression() { return true; }
virtual NodeRef evaluate() = 0;
};
class AssignmentNode : public ExpressionNode
{
public:
AssignmentNode(NodeRef varref, NodeRef expr)
: m_varref(varref), m_expr(expr)
{
}
std::string getString() { return m_varref->getString(); }
virtual NodeRef evaluate()
{
double n = m_expr->evaluate()->getNumber();
parser_scope->putGlobal(getString(), n);
return new NumberNode(n);
}
protected:
NodeRef m_varref;
NodeRef m_expr;
};
class LocalAssignmentNode : public ExpressionNode
{
public:
LocalAssignmentNode(NodeRef varref, NodeRef expr)
: m_varref(varref), m_expr(expr)
{
}
std::string getString() { return m_varref->getString(); }
virtual NodeRef evaluate()
{
double n = m_expr->evaluate()->getNumber();
parser_scope->putLocal(getString(), n);
return new NumberNode(n);
}
protected:
NodeRef m_varref;
NodeRef m_expr;
};
class LocalDeclNode : public ExpressionNode
{
public:
LocalDeclNode(NodeRef varref) : m_varref(varref) { }
virtual NodeRef evaluate()
{
parser_scope->putLocal(m_varref->getString(), 0.0);
return NULL;
}
protected:
NodeRef m_varref;
};
class BinOpNode : public ExpressionNode
{
public:
BinOpNode(char op, NodeRef one, NodeRef two)
: m_op(op), one(one), two(two)
{
}
virtual NodeRef evaluate();
protected:
char m_op;
NodeRef one;
NodeRef two;
};
class BoolExpressionNode : public Node
{
public:
BoolExpressionNode(char op, NodeRef one, NodeRef two)
: m_op(op), one(one), two(two)
{
}
virtual NodeRef evaluate();
protected:
char m_op;
NodeRef one;
NodeRef two;
};
class VarRefNode : public Node
{
public:
VarRefNode(const std::string & str) { m_string = str; }
std::string getString() { return m_string; }
virtual NodeRef evaluate()
{
if (parser_scope->contains(m_string))
{
return new NumberNode(parser_scope->get(m_string));
}
std::cerr << "Error: No identifier '" << m_string << "' in scope"
<< std::endl;
exit(4);
}
protected:
std::string m_string;
};
class ForNode : public Node
{
public:
ForNode(NodeRef e1, NodeRef e2, NodeRef e3)
{
m_nodes[0] = e1;
m_nodes[1] = e2;
m_nodes[2] = e3;
}
virtual NodeRef evaluate();
protected:
NodeRef m_nodes[3];
};
class IfNode : public Node
{
public:
IfNode(NodeRef test_expr, NodeRef elses)
{
m_test_expr = test_expr;
m_elses = elses;
}
virtual NodeRef evaluate();
protected:
NodeRef m_test_expr, m_elses;
};
class ElseNode : public Node
{
public:
virtual NodeRef evaluate();
};
class FunctionCallNode : public Node
{
public:
FunctionCallNode(NodeRef name, NodeRef parameters)
{
m_name = name;
m_parameters = parameters;
}
virtual NodeRef evaluate();
protected:
NodeRef m_name, m_parameters;
};
/* this class is only used to hold a set of items coming out of a class's
* evaluate() from above. the evaluateChildren() top-level method will
* propagate children of this class up to the level of their parent */
class EvaluatePropagateNode : public Node
{
};
#endif

View File

@ -1,13 +0,0 @@
#ifndef PARSER_H
#define PARSER_H PARSER_H
#include "nodes.h"
#include "util/refptr.h"
#include "util/Scope.h"
#define YYSTYPE refptr<Node>
refptr<Node> parse(const char * fileName, refptr<Scope> scope);
#endif

View File

@ -1,156 +0,0 @@
%option nounput
%option bison-locations
%{
#include <string>
#include "nodes.h"
#include "parser.h"
#include "parser.hh"
#define YY_USER_ACTION yylloc->first_column += yyleng;
static std::string build_string;
%}
%x str
%%
\+ return PLUS;
- return MINUS;
\* return TIMES;
\/ return DIVIDE;
% return MOD;
\^ return POW;
= return ASSIGN;
== return EQUALS;
!= return NOTEQUALS;
\< return LESS;
\<= return LESSEQ;
\> return GREATER;
\>= return GREATEREQ;
&& return AND;
\|\| return OR;
! return NOT;
; return SEMICOLON;
: return COLON;
\? return QUESTION;
\$ return DOLLAR;
\. return DOT;
, return COMMA;
\{ return LCURLY;
\} return RCURLY;
\[ return LBRACKET;
\] return RBRACKET;
\( return LPAREN;
\) return RPAREN;
[0-9]+ *yylval = new NumberNode(atof(yytext)); return REAL_NUMBER;
[0-9]*\.[0-9]+ *yylval = new NumberNode(atof(yytext)); return REAL_NUMBER;
ambient return AMBIENT;
ambient_occlusion return AMBIENT_OCCLUSION;
box return BOX;
camera return CAMERA;
color return COLOR;
cyl return CYL;
define return DEFINE;
diffuse return DIFFUSE;
exposure return EXPOSURE;
extrude return EXTRUDE;
height return HEIGHT;
intersect return INTERSECT;
jitter return JITTER;
light return LIGHT;
look_at return LOOKAT;
material return MATERIAL;
max_depth return MAXDEPTH;
multisample return MULTISAMPLE;
ngon return NGON;
offset return OFFSET;
options return OPTIONS;
plane return PLANE;
polygon return POLYGON;
position return POSITION;
radius return RADIUS;
reflectance return REFLECTANCE;
refraction return REFRACTION;
rotate return ROTATE;
scale return SCALE;
scene return SCENE;
shape return SHAPE;
shininess return SHININESS;
size return SIZE;
specular return SPECULAR;
sphere return SPHERE;
subtract return SUBTRACT;
texture return TEXTURE;
translate return TRANSLATE;
transparency return TRANSPARENCY;
union return UNION;
up return UP;
vfov return VFOV;
width return WIDTH;
else return ELSE;
elsif return ELSIF;
for return FOR;
if return IF;
while return WHILE;
local return LOCAL;
[a-zA-Z_][a-zA-Z_0-9]* {
*yylval = new IdentifierNode(yytext);
return IDENTIFIER;
}
\$[a-zA-Z_][a-zA-Z_0-9]* {
*yylval = new VarRefNode(yytext+1);
return VARREF;
}
#.*\n {
yylloc->first_line++; yylloc->last_line++;
yylloc->first_column = yylloc->last_column = 0;
}
\n {
yylloc->first_line++; yylloc->last_line++;
yylloc->first_column = yylloc->last_column = 0;
}
[ \t\v] /* ignore whitespace */
/* strings */
\" build_string = ""; BEGIN(str);
<str>{
\" {
/* end of the string literal */
BEGIN(INITIAL);
*yylval = new IdentifierNode(build_string);
return STRING;
}
\\x[0-9A-Fa-f]{2} {
/* hexadecimal escape code */
unsigned int val;
(void) sscanf(yytext + 2, "%x", &val);
build_string += (char) val;
}
\\n build_string += '\n';
\\t build_string += '\t';
\\r build_string += '\r';
\\b build_string += '\b';
\\f build_string += '\f';
\\(.|\n) build_string += yytext[1];
[^\\\"]+ build_string += yytext;
}
. return yytext[0];
%%

View File

@ -1,510 +0,0 @@
%{
#include <stdio.h>
#include <iostream>
#include "util/Vector.h"
#include "util/refptr.h"
#include "util/Scope.h"
#include "nodes.h"
#include "parser.h"
#include "parser.hh" /* bison-generated header with YY[SL]TYPE */
using namespace std;
#define yyerror(msg) errFunc(msg, &yylloc)
int yylex(YYSTYPE *, YYLTYPE *);
extern FILE * yyin;
void errFunc(const char * str, YYLTYPE * yyllocp);
int yywrap()
{
return 1;
}
static refptr<Node> parsed_scene_node;
refptr<Scope> parser_scope;
%}
%define api.pure
%locations
%define parse.error verbose
%token PLUS;
%token MINUS;
%token TIMES;
%token DIVIDE;
%token MOD;
%token POW;
%token ASSIGN;
%token EQUALS;
%token NOTEQUALS;
%token LESS;
%token LESSEQ;
%token GREATER;
%token GREATEREQ;
%token AND
%token OR
%token NOT;
%token SEMICOLON;
%token COLON;
%token QUESTION;
%token DOLLAR;
%token DOT;
%token COMMA;
%token LCURLY;
%token RCURLY;
%token LBRACKET;
%token RBRACKET;
%token LPAREN;
%token RPAREN;
%token REAL_NUMBER;
%token STRING;
%token AMBIENT;
%token AMBIENT_OCCLUSION;
%token BOX;
%token CAMERA;
%token COLOR;
%token CYL;
%token DEFINE;
%token DIFFUSE;
%token EXPOSURE;
%token EXTRUDE;
%token HEIGHT;
%token INTERSECT;
%token JITTER;
%token LIGHT;
%token LOOKAT;
%token MATERIAL;
%token MAXDEPTH;
%token MULTISAMPLE;
%token NGON;
%token OFFSET;
%token OPTIONS;
%token PLANE;
%token POLYGON;
%token POSITION;
%token RADIUS;
%token REFLECTANCE;
%token REFRACTION;
%token ROTATE;
%token SCALE;
%token SCENE;
%token SHAPE;
%token SHININESS;
%token SIZE;
%token SPECULAR;
%token SPHERE;
%token SUBTRACT;
%token TEXTURE;
%token TRANSLATE;
%token TRANSPARENCY;
%token UNION;
%token UP;
%token VFOV;
%token WIDTH;
%token IDENTIFIER;
%token VARREF;
%token ELSE;
%token ELSIF;
%token FOR;
%token IF;
%token WHILE;
%token LOCAL;
%right ASSIGN
%left AND OR NOT
%left PLUS MINUS
%left TIMES DIVIDE MOD
%right POW
%left UMINUS
%%
scene: SCENE LCURLY general_items RCURLY {
$$ = new SceneNode();
$$->addChildren($3);
parsed_scene_node = $$;
}
;
box: BOX LCURLY general_items RCURLY {
$$ = new BoxNode();
$$->addChildren($3);
}
;
camera: CAMERA LCURLY general_items RCURLY {
$$ = new CameraNode();
$$->addChildren($3);
}
;
cyl: CYL LCURLY general_items RCURLY {
$$ = new CylNode();
$$->addChildren($3);
}
;
extrude: EXTRUDE LCURLY general_items RCURLY {
$$ = new ExtrudeNode();
$$->addChildren($3);
}
;
general_items: /* empty */ { $$ = NULL; }
| general_item general_items {
$$ = new ItemsNode();
$$->addChild($1);
$$->addChildren($2);
}
;
general_item: AMBIENT vector3 { $$ = new AmbientNode($2); }
| AMBIENT_OCCLUSION expression {
$$ = new AmbientOcclusionNode($2);
}
| camera { $$ = $1; }
| COLOR vector3 { $$ = new ColorNode($2); }
| DIFFUSE vector3 { $$ = new DiffuseNode($2); }
| EXPOSURE expression { $$ = new ExposureNode($2); }
| for { $$ = $1; }
| HEIGHT expression { $$ = new HeightNode($2); }
| if { $$ = $1; }
| JITTER expression { $$ = new JitterNode($2); }
| light { $$ = $1; }
| LOOKAT vector3 { $$ = new LookAtNode($2); }
| material { $$ = $1; }
| material_definition { $$ = $1; }
| material_ref { $$ = $1; }
| MAXDEPTH expression { $$ = new MaxDepthNode($2); }
| MULTISAMPLE expression { $$ = new MultisampleNode($2); }
| ngon { $$ = $1; }
| offset { $$ = $1; }
| options { $$ = $1; }
| polygon { $$ = $1; }
| POSITION vector3 { $$ = new PositionNode($2); }
| POSITION vector3 COMMA expression {
$$ = new PlanePositionNode($2, $4);
}
| RADIUS expression { $$ = new RadiusNode($2); }
| REFLECTANCE expression { $$ = new ReflectanceNode($2); }
| REFRACTION expression { $$ = new RefractionNode($2); }
| ROTATE expression COMMA vector3 { $$ = new RotateNode($2, $4); }
| SCALE expression { $$ = new ScaleNode(new ScaleScalarNode($2)); }
| SCALE vector2 { $$ = new ScaleNode($2); }
| SCALE vector3 { $$ = new ScaleNode($2); }
| shape { $$ = $1; }
| shape_definition { $$ = $1; }
| SHININESS expression { $$ = new ShininessNode($2); }
| SIZE vector3 { $$ = new SizeNode($2); }
| SPECULAR vector3 { $$ = new SpecularNode($2); }
| stmt_expression { $$ = $1; }
| TEXTURE STRING { $$ = new TextureNode($2->getString()); }
| transform_block { $$ = $1; }
| TRANSLATE vector3 { $$ = new TranslateNode($2); }
| TRANSPARENCY expression { $$ = new TransparencyNode($2); }
| UP vector3 { $$ = new UpNode($2); }
| vector2 { $$ = $1; }
| VFOV expression { $$ = new VFOVNode($2); }
| while { $$ = $1; }
| WIDTH expression { $$ = new WidthNode($2); }
;
intersect: INTERSECT LCURLY general_items RCURLY {
$$ = new IntersectNode();
$$->addChildren($3);
}
;
light: LIGHT LCURLY general_items RCURLY {
$$ = new LightNode();
$$->addChildren($3);
}
;
material: MATERIAL LCURLY general_items RCURLY {
$$ = new MaterialNode();
$$->addChildren($3);
}
;
material_definition: DEFINE MATERIAL IDENTIFIER LCURLY general_items RCURLY {
$$ = new MaterialDefinitionNode($3->getString());
$$->addChildren($5);
}
;
material_ref: MATERIAL IDENTIFIER {
$$ = new MaterialRefNode($2->getString());
}
;
number: REAL_NUMBER { $$ = $1; }
;
ngon: NGON expression COMMA expression {
$$ = new NGonNode($2);
$$->addChild(new RadiusNode($4));
}
;
offset: OFFSET expression {
$$ = new OffsetNode($2);
}
| OFFSET expression LCURLY general_items RCURLY {
$$ = new OffsetNode($2);
$$->addChildren($4);
}
;
options: OPTIONS LCURLY general_items RCURLY {
$$ = new OptionsNode();
$$->addChildren($3);
}
;
plane: PLANE LCURLY general_items RCURLY {
$$ = new PlaneNode();
$$->addChildren($3);
}
;
polygon: POLYGON LCURLY general_items RCURLY {
$$ = new PolygonNode();
$$->addChildren($3);
}
;
shape: plane { $$ = $1; }
| sphere { $$ = $1; }
| box { $$ = $1; }
| cyl { $$ = $1; }
| union { $$ = $1; }
| intersect { $$ = $1; }
| subtract { $$ = $1; }
| extrude { $$ = $1; }
| shape_ref { $$ = $1; }
;
shape_definition: DEFINE SHAPE IDENTIFIER shape {
$$ = new ShapeDefinitionNode($3->getString());
$$->addChild($4);
}
;
shape_ref: SHAPE IDENTIFIER shape_ref_more {
$$ = new ShapeRefNode($2->getString());
$$->addChildren($3);
}
;
shape_ref_more: /* empty */ { $$ = NULL; }
| LCURLY general_items RCURLY { $$ = $2; }
;
sphere: SPHERE LCURLY general_items RCURLY {
$$ = new SphereNode();
$$->addChildren($3);
}
;
subtract: SUBTRACT LCURLY general_items RCURLY {
$$ = new SubtractNode();
$$->addChildren($3);
}
;
transform_block: TRANSLATE vector3 LCURLY general_items RCURLY {
$$ = new TranslateBlockNode($2);
$$->addChildren($4);
}
| ROTATE expression COMMA vector3 LCURLY general_items RCURLY {
$$ = new RotateBlockNode($2, $4);
$$->addChildren($6);
}
| SCALE vector3 LCURLY general_items RCURLY {
$$ = new ScaleBlockNode($2);
$$->addChildren($4);
}
| SCALE expression LCURLY general_items RCURLY {
$$ = new ScaleBlockNode(new ScaleScalarNode($2));
$$->addChildren($4);
}
;
union: UNION LCURLY general_items RCURLY {
$$ = new UnionNode();
$$->addChildren($3);
}
;
vector2: LESS expression COMMA expression GREATER {
$$ = new VectorNode($2, $4, new NumberNode(0.0));
}
;
vector3: LESS expression COMMA expression COMMA expression GREATER {
$$ = new VectorNode($2, $4, $6);
}
;
expression: expression TIMES expression { $$ = new BinOpNode('*', $1, $3); }
| expression DIVIDE expression { $$ = new BinOpNode('/', $1, $3); }
| expression PLUS expression { $$ = new BinOpNode('+', $1, $3); }
| expression MINUS expression { $$ = new BinOpNode('-', $1, $3); }
| expression MOD expression { $$ = new BinOpNode('%', $1, $3); }
| expression POW expression { $$ = new BinOpNode('^', $1, $3); }
| MINUS expression %prec UMINUS {
$$ = new BinOpNode('-', new NumberNode(0.0), $2);
}
| stmt_expression { $$ = $1; }
| function_call { $$ = $1; }
| number { $$ = $1; }
| VARREF { $$ = $1; }
| LPAREN expression RPAREN { $$ = $2; }
;
maybe_expression: /* empty */ { $$ = NULL; }
| expression { $$ = $1; }
;
stmt_expression: assignment { $$ = $1; }
| local_assignment { $$ = $1; }
| local_decl { $$ = $1; }
;
bool_expression: expression LESS expression {
$$ = new BoolExpressionNode('<', $1, $3);
}
| expression LESSEQ expression {
$$ = new BoolExpressionNode('l', $1, $3);
}
| expression GREATER expression {
$$ = new BoolExpressionNode('>', $1, $3);
}
| expression GREATEREQ expression {
$$ = new BoolExpressionNode('g', $1, $3);
}
| expression EQUALS expression {
$$ = new BoolExpressionNode('=', $1, $3);
}
| expression NOTEQUALS expression {
$$ = new BoolExpressionNode('n', $1, $3);
}
| bool_expression AND bool_expression {
$$ = new BoolExpressionNode('&', $1, $3);
}
| bool_expression OR bool_expression {
$$ = new BoolExpressionNode('|', $1, $3);
}
| NOT bool_expression {
$$ = new BoolExpressionNode('!', $2, NULL);
}
| LPAREN bool_expression RPAREN {
$$ = $2;
}
;
assignment: VARREF ASSIGN expression {
$$ = new AssignmentNode($1, $3);
}
;
local_assignment: LOCAL VARREF ASSIGN expression {
$$ = new LocalAssignmentNode($2, $4);
}
;
local_decl: LOCAL VARREF {
$$ = new LocalDeclNode($2);
}
;
for: FOR LPAREN maybe_expression SEMICOLON bool_expression SEMICOLON maybe_expression RPAREN LCURLY general_items RCURLY {
$$ = new ForNode($3, $5, $7);
$$->addChildren($10);
}
;
while: WHILE LPAREN bool_expression RPAREN LCURLY general_items RCURLY {
$$ = new ForNode(NULL, $3, NULL);
$$->addChildren($6);
}
;
if: IF LPAREN bool_expression RPAREN LCURLY general_items RCURLY if_more {
$$ = new IfNode($3, $8);
$$->addChildren($6);
}
;
if_more: /* empty */ { $$ = NULL; }
| ELSIF LPAREN bool_expression RPAREN LCURLY general_items RCURLY if_more {
$$ = new IfNode($3, $8);
$$->addChildren($6);
}
| ELSE LCURLY general_items RCURLY {
$$ = new ElseNode();
$$->addChildren($3);
}
;
function_call: IDENTIFIER LPAREN function_call_parameters RPAREN {
$$ = new FunctionCallNode($1, $3);
}
;
function_call_parameters: /* empty */ { $$ = NULL; }
| expression function_call_more_parameters {
$$ = new ItemsNode();
$$->addChild($1);
$$->addChildren($2);
}
;
function_call_more_parameters: /* empty */ { $$ = NULL; }
| COMMA expression function_call_more_parameters {
$$ = new ItemsNode();
$$->addChild($2);
$$->addChildren($3);
}
;
%%
refptr<Node> parse(const char * fileName, refptr<Scope> scope)
{
parser_scope = scope;
yyin = fopen(fileName, "r");
if (yyin == NULL)
{
cerr << "Failed to open file '" << fileName << "'" << endl;
return refptr<Node>(NULL);
}
if (yyparse())
{
cerr << "Aborting." << endl;
exit(1);
}
return parsed_scene_node;
}
void errFunc(const char * str, YYLTYPE * yyllocp)
{
fprintf(stderr, "error: %s: line %d, column %d\n",
str,
yyllocp->first_line,
yyllocp->first_column);
}

View File

@ -1,34 +0,0 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
using namespace std;
int preprocess(const char * fileName)
{
struct stat st;
if (stat(fileName, &st))
{
cerr << "Error accessing " << fileName << endl;
return -1;
}
ifstream ifs(fileName);
if ( ! ifs.is_open() )
{
cerr << "Error opening " << fileName << endl;
return -2;
}
char * buff = new char[st.st_size];
while ( ! ifs.eof() )
{
ifs.getline(buff, st.st_size);
}
delete[] buff;
return 0;
}

22
src/sceneparser.propane Normal file
View File

@ -0,0 +1,22 @@
<<
import std.conv;
>>
token background;
token comma /,/;
token number /\d+(\.\d+)?/;
token lt /</;
token gt />/;
token semicolon /;/;
Start -> Statements;
Statements -> ;
Statements -> Statement Statements;
Statement -> BackgroundStatement;
BackgroundStatement -> background Vec3 semicolon;
Vec3 -> lt number comma number comma number gt;

View File

@ -1,9 +0,0 @@
#include "BoolShape.h"
void BoolShape::setMaterial(refptr<Material> material)
{
m_material = material;
m_shape1->setMaterial(material);
m_shape2->setMaterial(material);
}

View File

@ -1,19 +0,0 @@
#ifndef BOOLSHAPE_H
#define BOOLSHAPE_H BOOLSHAPE_H
#include "Shape.h"
class BoolShape : public Shape
{
public:
virtual IntersectionList intersect(refptr<Shape> _this, const Ray & ray) = 0;
virtual void setMaterial(refptr<Material> material);
virtual refptr<Shape> clone() = 0;
protected:
refptr<Shape> m_shape1;
refptr<Shape> m_shape2;
};
#endif

View File

@ -1,111 +0,0 @@
#include "Box.h"
#include "util/Solver.h"
#include <math.h>
#include <iostream>
using namespace std;
#define FP_EQUAL(x,y) (fabs((x)-(y)) < 0.000001)
Box::Box(refptr<Vector> size)
{
m_size = *size;
m_size[0] = fabs(m_size[0]) / 2.0;
m_size[1] = fabs(m_size[1]) / 2.0;
m_size[2] = fabs(m_size[2]) / 2.0;
}
Shape::IntersectionList Box::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res;
/*** optimization ***/
if (ray_inv.getOrigin()[0] > m_size[0])
{
if (ray_inv.getDirection() % Vector::X > 0)
return res;
}
else if (ray_inv.getOrigin()[0] < -m_size[0])
{
if (ray_inv.getDirection() % Vector::X < 0)
return res;
}
if (ray_inv.getOrigin()[1] > m_size[1])
{
if (ray_inv.getDirection() % Vector::Y > 0)
return res;
}
else if (ray_inv.getOrigin()[1] < -m_size[1])
{
if (ray_inv.getDirection() % Vector::Y < 0)
return res;
}
if (ray_inv.getOrigin()[2] > m_size[2])
{
if (ray_inv.getDirection() % Vector::Z > 0)
return res;
}
else if (ray_inv.getOrigin()[2] < -m_size[2])
{
if (ray_inv.getDirection() % Vector::Z < 0)
return res;
}
/*** end optimization ***/
/*
* Ray equation: R = R0 + tRd
* x = R0x + tRdx
* y = R0y + tRdy
* z = R0z + tRdz
* Side equation: x - size_x = 0
* Combined: R0x + (t)Rdx - size_x = 0
*/
for (int dim = 0; dim < 3; dim++)
{
for (int side = -1; side <= 1; side += 2)
{
LinearSolver solver(ray_inv.getDirection()[dim],
ray_inv.getOrigin()[dim]
+ side * m_size[dim]);
Solver::Result solutions = solver.solve();
for (int i = 0; i < solutions.numResults; i++)
{
if (solutions.results[i] >= 0.0)
{
Vector isect_point = ray_inv[solutions.results[i]];
if ( (dim == 0 || fabs(isect_point[0]) <= m_size[0])
&& (dim == 1 || fabs(isect_point[1]) <= m_size[1])
&& (dim == 2 || fabs(isect_point[2]) <= m_size[2]) )
{
Vector normal(0, 0, -1);
if ( FP_EQUAL(isect_point[0], m_size[0]) )
normal = Vector(1, 0, 0);
else if ( FP_EQUAL(isect_point[0], -m_size[0]) )
normal = Vector(-1, 0, 0);
else if ( FP_EQUAL(isect_point[1], m_size[1]) )
normal = Vector(0, 1, 0);
else if ( FP_EQUAL(isect_point[1], -m_size[1]) )
normal = Vector(0, -1, 0);
else if ( FP_EQUAL(isect_point[2], m_size[2]) )
normal = Vector(0, 0, 1);
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(normal))
);
}
}
}
}
}
return res;
}
refptr<Shape> Box::clone()
{
return new Box(*this);
}

View File

@ -1,19 +0,0 @@
#ifndef BOX_H
#define BOX_H BOX_H
#include "Shape.h"
class Box : public Shape
{
public:
Box(refptr<Vector> size);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
virtual refptr<Shape> clone();
protected:
Vector m_size;
};
#endif

View File

@ -1,141 +0,0 @@
#include "Cyl.h"
#include "util/Solver.h"
#include <math.h>
#include <iostream>
using namespace std;
#define FP_EQUAL(x,y) (fabs((x)-(y)) < 0.000001)
Cyl::Cyl(double bottom_radius, double top_radius, double height)
{
m_bottom_radius = fabs(bottom_radius);
m_bottom_radius_2 = bottom_radius * bottom_radius;
m_top_radius = fabs(top_radius);
m_top_radius_2 = top_radius * top_radius;
m_height = fabs(height);
if (m_height == 0.0)
m_height = 1.0;
m_slope = (m_top_radius - m_bottom_radius) / m_height; /* rise over run */
if ( ! FP_EQUAL(m_slope, 0.0) )
m_inv_slope = -1.0 / m_slope;
}
Shape::IntersectionList Cyl::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res;
/* First intersect with the bottom plane, if it has positive area */
if (m_bottom_radius > 0.0)
{
LinearSolver solver(-ray_inv.getDirection()[2],
-ray_inv.getOrigin()[2]);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0 && solutions.results[0] > 0.0)
{
Vector isect_point = ray_inv[solutions.results[0]];
if (isect_point[0]*isect_point[0] + isect_point[1]*isect_point[1]
<= m_bottom_radius_2)
{
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(Vector(0, 0, -1))));
}
}
}
/* Same for the top plane */
if (m_top_radius > 0.0)
{
LinearSolver solver(ray_inv.getDirection()[2],
ray_inv.getOrigin()[2] - m_height);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0 && solutions.results[0] > 0.0)
{
Vector isect_point = ray_inv[solutions.results[0]];
if (isect_point[0]*isect_point[0] + isect_point[1]*isect_point[1]
<= m_top_radius_2)
{
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(Vector(0, 0, 1))));
}
}
}
/*
* Now see if the ray hit the side of the cylinder/cone thingy
* Ray equation: R = R0 + tRd
* x = R0x + tRdx
* y = R0y + tRdy
* z = R0z + tRdz
* Side equation: x^2 + y^2 = (m*z + b)^2
* Combined: (R0x+t*Rdx)^2 + (R0y+t*Rdy)^2 = (m*(R0z+t*Rdz) + b)^2
* Expanded: (R0x*R0x + (t*t)*Rdx*Rdx + 2*R0x*t*Rdx)
* + (R0y*R0y + (t*t)*Rdy*Rdy + 2*R0y*t*Rdy)
* = ((m*R0z+m*t*Rdz)^2 + b*b + 2*m*(R0z+t*Rdz)*b)
* = ((m*R0z*m*R0z + m*m*t*t*Rdz*Rdz + 2*m*R0z*m*t*Rdz)
* + b*b + 2*m*R0z*b + 2*m*t*Rdz*b)
* Quadratic form: (t*t)(Rdx*Rdx + Rdy*Rdy - m*m*Rdz*Rdz)
* + (t)(2*R0x*Rdx + 2*R0y*Rdy - 2*m*R0z*m*Rdz - 2*m*Rdz*b)
* + (R0x*R0x + R0y*R0y - m*m*R0z*R0z - b*b - 2*m*R0z*b)
* = 0
*/
double Rdx = ray_inv.getDirection()[0];
double Rdy = ray_inv.getDirection()[1];
double Rdz = ray_inv.getDirection()[2];
double R0x = ray_inv.getOrigin()[0];
double R0y = ray_inv.getOrigin()[1];
double R0z = ray_inv.getOrigin()[2];
double m = m_slope;
double m2 = m*m;
double b = m_bottom_radius;
QuadraticSolver solver(Rdx * Rdx + Rdy * Rdy - m2 * Rdz * Rdz,
2.0 * (R0x*Rdx + R0y*Rdy - m2*R0z*Rdz - m*Rdz*b),
R0x*R0x + R0y*R0y - m2*R0z*R0z - b*b - 2*m*R0z*b);
Solver::Result solutions = solver.solve();
for (int i = 0; i < solutions.numResults; i++)
{
if (solutions.results[i] >= 0.0)
{
Vector isect_point = ray_inv[solutions.results[i]];
if (isect_point[2] > 0.0 && isect_point[2] < m_height)
{
Vector normal;
if ( FP_EQUAL(m_slope, 0.0) )
{
normal = Vector(isect_point[0], isect_point[1], 0.0);
}
else
{
double x = isect_point[0];
double y = isect_point[1];
double dist = sqrt( isect_point[0] * isect_point[0]
+ isect_point[1] * isect_point[1] );
if (dist > 0.0)
{
double scale = 1.0 / dist;
x *= scale;
y *= scale;
}
normal = Vector(x, y, m_inv_slope);
}
normal.normalize();
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(normal)));
}
}
}
return res;
}
refptr<Shape> Cyl::clone()
{
return new Cyl(*this);
}

View File

@ -1,25 +0,0 @@
#ifndef CYL_H
#define CYL_H CYL_H
#include "Shape.h"
class Cyl : public Shape
{
public:
Cyl(double bottom_radius, double top_radius, double height);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
virtual refptr<Shape> clone();
protected:
double m_bottom_radius;
double m_bottom_radius_2;
double m_top_radius;
double m_top_radius_2;
double m_height;
double m_slope;
double m_inv_slope;
};
#endif

View File

@ -1,267 +0,0 @@
#include <math.h>
#include <iostream>
#include <algorithm> /* sort() */
#include "Extrude.h"
#include "util/Polygon.h"
#include "util/Solver.h"
using namespace std;
#define FP_EQUAL(x,y) (fabs((x)-(y)) < 0.000001)
Extrude::Extrude()
{
}
class IntersectListComparator
{
public:
IntersectListComparator(Vector start) : m_start(start) {}
bool operator()(const Shape::Intersection & i1,
const Shape::Intersection & i2) const
{
double d1 = (i1.position - m_start).mag2();
double d2 = (i2.position - m_start).mag2();
return d1 < d2;
}
protected:
Vector m_start;
};
Shape::IntersectionList Extrude::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res;
/*** optimization ***/
if (ray_inv.getOrigin()[0] > m_aabb.max[0])
{
if (ray_inv.getDirection() % Vector::X > 0)
return res;
}
else if (ray_inv.getOrigin()[0] < m_aabb.min[0])
{
if (ray_inv.getDirection() % Vector::X < 0)
return res;
}
if (ray_inv.getOrigin()[1] > m_aabb.max[1])
{
if (ray_inv.getDirection() % Vector::Y > 0)
return res;
}
else if (ray_inv.getOrigin()[1] < m_aabb.min[1])
{
if (ray_inv.getDirection() % Vector::Y < 0)
return res;
}
if (ray_inv.getOrigin()[2] > m_aabb.max[2])
{
if (ray_inv.getDirection() % Vector::Z > 0)
return res;
}
else if (ray_inv.getOrigin()[2] < m_aabb.min[2])
{
if (ray_inv.getDirection() % Vector::Z < 0)
return res;
}
/*** end optimization ***/
int n_polygons = m_polygons.size();
int n_offsets = m_offsets.size();
double distance = 0.0;
Vector scale(1.0, 1.0, 1.0);
Vector shift(0.0, 0.0, 0.0);
for (int p = 0; p < n_polygons; p++)
{
refptr<Polygon> polygon = m_polygons[p];
for (int o = 0; o < n_offsets; o++)
{
Offset & offset = m_offsets[o];
for (int pt = 0, n_pts = polygon->size(); pt < n_pts; pt++)
{
Vector p1 = scale.mult(*(*polygon)[pt]) + shift;
Vector p2 = scale.mult(*(*polygon)[(pt+1) % n_pts]) + shift;
Vector p3 = scale.mult(offset.scale)
.mult(*(*polygon)[(pt+1) % n_pts])
+ shift + offset.shift;
Vector p4 = scale.mult(offset.scale).mult(*(*polygon)[pt])
+ shift + offset.shift;
p1[2] += distance;
p2[2] += distance;
p3[2] += distance + offset.distance;
p4[2] += distance + offset.distance;
Vector e1 = p2 - p1;
Vector e2 = p3 - p2;
Vector normal = (e1 * e2).normalize();
double a = normal[0], b = normal[1], c = normal[2];
double d = -(a * p1[0] + b * p1[1] + c * p1[2]);
LinearSolver solver( a * ray_inv.getDirection()[0]
+ b * ray_inv.getDirection()[1]
+ c * ray_inv.getDirection()[2],
a * ray_inv.getOrigin()[0]
+ b * ray_inv.getOrigin()[1]
+ c * ray_inv.getOrigin()[2]
+ d);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0 && solutions.results[0] > 0.0)
{
Vector ipoint = ray_inv[solutions.results[0]];
Polygon quad;
quad.add(p1).add(p2).add(p3).add(p4);
if (quad.containsPointConvex(ipoint))
{
res.add(Intersection(_this,
m_transform.transform_point(ipoint),
m_transform.transform_normal(normal)));
}
}
}
distance += offset.distance;
scale = scale.mult(offset.scale);
shift += offset.shift;
}
}
double a = 0, b = 0, c = -1.0, d = 0.0;
LinearSolver solver( a * ray_inv.getDirection()[0]
+ b * ray_inv.getDirection()[1]
+ c * ray_inv.getDirection()[2],
a * ray_inv.getOrigin()[0]
+ b * ray_inv.getOrigin()[1]
+ c * ray_inv.getOrigin()[2]
+ d);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0 && solutions.results[0] > 0.0)
{
Vector ipoint = ray_inv[solutions.results[0]];
for (int p = 0; p < n_polygons; p++)
{
refptr<Polygon> polygon = m_polygons[p];
if (polygon->containsPoint2D(ipoint))
{
res.add(Intersection(_this,
m_transform.transform_point(ipoint),
m_transform.transform_normal(Vector(a, b, c))));
}
}
}
if (scale[0] > 0.0 && scale[1] > 0.0)
{
a = 0, b = 0, c = 1.0, d = -distance;
LinearSolver solver( a * ray_inv.getDirection()[0]
+ b * ray_inv.getDirection()[1]
+ c * ray_inv.getDirection()[2],
a * ray_inv.getOrigin()[0]
+ b * ray_inv.getOrigin()[1]
+ c * ray_inv.getOrigin()[2]
+ d);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0 && solutions.results[0] > 0.0)
{
Vector ipoint = ray_inv[solutions.results[0]];
for (int p = 0; p < n_polygons; p++)
{
Polygon tp = *m_polygons[p];
for (int i = 0, sz = tp.size(); i < sz; i++)
{
tp[i] = new Vector(tp[i]->mult(scale) + shift);
(*tp[i])[2] += distance;
}
if (tp.containsPoint2D(ipoint))
{
res.add(Intersection(_this,
m_transform.transform_point(ipoint),
m_transform.transform_normal(Vector(a, b, c))));
break;
}
}
}
}
sort(res.begin(), res.end(), IntersectListComparator(ray.getOrigin()));
return res;
}
void Extrude::addPolygon(refptr<Polygon> polygon)
{
m_polygons.push_back(polygon);
updateAABB();
}
void Extrude::addOffset(double distance,
const Vector & scale, const Vector & shift)
{
m_offsets.push_back(Offset(distance, scale, shift));
updateAABB();
}
void Extrude::updateAABB()
{
int n_polygons = m_polygons.size();
int n_offsets = m_offsets.size();
bool first = true;
double distance = 0.0;
Vector scale(1.0, 1.0, 1.0);
Vector shift(0.0, 0.0, 0.0);
for (int p = 0; p < n_polygons; p++)
{
refptr<Polygon> polygon = m_polygons[p];
for (int o = 0; o < n_offsets; o++)
{
Offset & offset = m_offsets[o];
for (int pt = 0, n_pts = polygon->size(); pt < n_pts; pt++)
{
Vector p1 = scale.mult(*(*polygon)[pt]) + shift;
Vector p2 = scale.mult(*(*polygon)[(pt+1) % n_pts]) + shift;
Vector p3 = scale.mult(offset.scale)
.mult(*(*polygon)[(pt+1) % n_pts])
+ shift + offset.shift;
Vector p4 = scale.mult(offset.scale).mult(*(*polygon)[pt])
+ shift + offset.shift;
p1[2] += distance;
p2[2] += distance;
p3[2] += distance + offset.distance;
p4[2] += distance + offset.distance;
if (first)
{
m_aabb.min = p1;
m_aabb.max = p1;
first = false;
}
expandAABB(p1);
expandAABB(p2);
expandAABB(p3);
expandAABB(p4);
}
distance += offset.distance;
scale = scale.mult(offset.scale);
shift += offset.shift;
}
}
}
void Extrude::expandAABB(const Vector & v)
{
if (v[0] < m_aabb.min[0])
m_aabb.min[0] = v[0];
if (v[0] > m_aabb.max[0])
m_aabb.max[0] = v[0];
if (v[1] < m_aabb.min[1])
m_aabb.min[1] = v[1];
if (v[1] > m_aabb.max[1])
m_aabb.max[1] = v[1];
if (v[2] < m_aabb.min[2])
m_aabb.min[2] = v[2];
if (v[2] > m_aabb.max[2])
m_aabb.max[2] = v[2];
}
refptr<Shape> Extrude::clone()
{
return new Extrude(*this);
}

View File

@ -1,43 +0,0 @@
#ifndef EXTRUDE_H
#define EXTRUDE_H EXTRUDE_H
#include <vector>
#include "util/Polygon.h"
#include "util/AABB.h"
#include "Shape.h"
class Extrude : public Shape
{
public:
Extrude();
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
void addPolygon(refptr<Polygon> polygon);
void addOffset(double distance,
const Vector & scale, const Vector & shift);
class Offset
{
public:
Offset(double d, const Vector & s, const Vector & p)
: distance(d), scale(s), shift(p)
{
}
double distance;
Vector scale;
Vector shift;
};
virtual refptr<Shape> clone();
protected:
std::vector< refptr<Polygon> > m_polygons;
std::vector<Offset> m_offsets;
AABB m_aabb;
void updateAABB();
void expandAABB(const Vector & v);
};
#endif

View File

@ -1,115 +0,0 @@
#include "Intersect.h"
#include <iostream>
using namespace std;
Intersect::Intersect(const vector< refptr<Shape> > & shapes)
{
int num_shapes = shapes.size();
if (num_shapes > 2)
{
m_shape2 = shapes[num_shapes - 1];
vector< refptr<Shape> > rest = shapes;
rest.pop_back();
m_shape1 = new Intersect(rest);
}
else if (num_shapes == 2)
{
m_shape1 = shapes[0];
m_shape2 = shapes[1];
}
else
{
cerr << __FILE__ << ": " << __LINE__
<< ": error: Intersect::Intersect() called with only "
<< num_shapes
<< " sub-shapes!"
<< endl;
exit(4);
}
}
Shape::IntersectionList Intersect::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res1 = m_shape1->intersect(m_shape1, ray_inv);
/*** optimization ***/
if (res1.size() == 0)
return res1;
/*** end optimization ***/
IntersectionList res2 = m_shape2->intersect(m_shape2, ray_inv);
BoolIntersectionList merged(res1, res2, ray_inv.getOrigin());
IntersectionList res;
bool in1 = false, in2 = false;
/* initially go through the merged intersections to see whether
* the ray started inside one of the sub-objects */
for (int i = 0, sz = merged.size(), saw1 = 0, saw2 = 0;
i < sz && (!saw1 || !saw2);
i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool back = dot < 0.0;
bool left = merged[i].left;
if (back)
{
if (left && !saw1)
in1 = true;
else if (!left && !saw2)
in2 = true;
}
if (left)
saw1 = 1;
else
saw2 = 1;
}
bool in_bool = in1 && in2;
for (int i = 0, sz = merged.size(); i < sz; i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool front = dot > 0.0;
bool left = merged[i].left;
if (front)
{
if (left)
in1 = true;
else
in2 = true;
if (!in_bool && in1 && in2)
{
/* we found an intersection point with the boolean object */
in_bool = true;
res.add( merged[i].intersection.transform(m_transform) );
}
}
else
{
if (in_bool && in1 && in2)
{
/* we found an intersection point with the boolean object */
res.add( merged[i].intersection.transform(m_transform) );
}
if (left)
in1 = false;
else
in2 = false;
in_bool = false;
}
}
return res;
}
refptr<Shape> Intersect::clone()
{
Intersect * s = new Intersect(*this);
s->m_shape1 = m_shape1->clone();
s->m_shape2 = m_shape2->clone();
return refptr<Shape>(s);
}

View File

@ -1,17 +0,0 @@
#ifndef INTERSECT_H
#define INTERSECT_H INTERSECT_H
#include "BoolShape.h"
#include <vector>
class Intersect : public BoolShape
{
public:
Intersect(const std::vector< refptr<Shape> > & shapes);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
refptr<Shape> clone();
};
#endif

View File

@ -1,57 +0,0 @@
#include "Plane.h"
#include "util/Solver.h"
#include <math.h>
#include <iostream>
using namespace std;
Plane::Plane(double a, double b, double c, double d)
{
m_a = a;
m_b = b;
m_c = c;
m_d = d;
m_normal = Vector(m_a, m_b, m_c);
m_normal.normalize();
}
Shape::IntersectionList Plane::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res;
/*
* Plane equation: ax + by + cz + d = 0
* Ray equation: R = R0 + tRd
* x = R0x + tRdx
* y = R0y + tRdy
* z = R0z + tRdz
* Combined: a(R0x + tRdx) + b(R0y + tRdy) + c(R0z + tRdz) + d = 0
* aR0x + (t)aRdx + bR0y + (t)bRdy + cR0z + (t)cRdz + d = 0
* (t)(aRdx + bRdy + cRdz) + aR0x + bR0y + cR0z + d = 0
*/
LinearSolver solver( m_a * ray_inv.getDirection()[0]
+ m_b * ray_inv.getDirection()[1]
+ m_c * ray_inv.getDirection()[2],
m_a * ray_inv.getOrigin()[0]
+ m_b * ray_inv.getOrigin()[1]
+ m_c * ray_inv.getOrigin()[2]
+ m_d);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0)
{
if (solutions.results[0] > 0.0)
{
Vector isect_point = ray_inv[solutions.results[0]];
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(m_normal)));
}
}
return res;
}
refptr<Shape> Plane::clone()
{
return new Plane(*this);
}

View File

@ -1,20 +0,0 @@
#ifndef PLANE_H
#define PLANE_H PLANE_H
#include "Shape.h"
class Plane : public Shape
{
public:
Plane(double a, double b, double c, double d);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
virtual refptr<Shape> clone();
protected:
double m_a, m_b, m_c, m_d;
Vector m_normal;
};
#endif

View File

@ -1,70 +0,0 @@
#include "Shape.h"
#include <algorithm> /* sort() */
#include <functional> /* binary_function */
#include <utility>
using namespace std;
static refptr<Material> default_material;
static bool default_material_initialized = false;
Shape::Shape()
{
if (default_material_initialized == false)
{
default_material = new Material();
default_material_initialized = true;
}
m_material = default_material;
}
Shape::~Shape()
{
}
void Shape::setMaterial(refptr<Material> material)
{
m_material = material;
}
class BoolIntersectionComparator
: public std::binary_function<Shape::BoolIntersection,
Shape::BoolIntersection,
bool>
{
public:
BoolIntersectionComparator(const Vector & refPoint)
{
m_refPoint = refPoint;
}
bool operator()(const Shape::BoolIntersection & i1,
const Shape::BoolIntersection & i2) const
{
return ( m_refPoint.dist_to(i1.intersection.position)
< m_refPoint.dist_to(i2.intersection.position) );
}
protected:
Vector m_refPoint;
};
Shape::BoolIntersectionList::BoolIntersectionList(const IntersectionList & l1,
const IntersectionList & l2,
const Vector & startPoint)
{
for (size_t i = 0, sz = l1.size();
i < sz;
i++)
{
m_intersections.push_back( BoolIntersection(l1[i], true) );
}
for (size_t i = 0, sz = l2.size();
i < sz;
i++)
{
m_intersections.push_back( BoolIntersection(l2[i], false) );
}
sort(m_intersections.begin(),
m_intersections.end(),
BoolIntersectionComparator(startPoint));
}

View File

@ -1,131 +0,0 @@
#ifndef SHAPE_H
#define SHAPE_H SHAPE_H
#include "util/Solver.h"
#include "util/Ray.h"
#include "util/Vector.h"
#include "util/Transform.h"
#include "util/Material.h"
#include "util/refptr.h"
#include <vector>
#include <utility>
class Shape
{
public:
class Intersection
{
public:
Intersection() {};
Intersection(refptr<Shape> shape,
const Vector & position,
const Vector & normal)
{
this->shape = shape;
this->position = position;
this->normal = normal;
}
refptr<Shape> shape;
Vector position;
Vector normal;
Intersection transform(Transform & t)
{
return Intersection(shape,
t.transform_point(position),
t.transform_normal(normal));
}
};
class BoolIntersection
{
public:
BoolIntersection() {};
BoolIntersection(const Intersection & intersection, bool left)
{
this->intersection = intersection;
this->left = left;
}
Intersection intersection;
bool left;
};
class IntersectionList
{
public:
void add(const Intersection & i)
{
m_intersections.push_back(i);
}
Intersection & operator[](int i)
{
return m_intersections[i];
}
const Intersection & operator[](int i) const
{
return m_intersections[i];
}
size_t size() const { return m_intersections.size(); }
std::vector<Intersection>::iterator begin()
{
return m_intersections.begin();
}
std::vector<Intersection>::iterator end()
{
return m_intersections.end();
}
protected:
std::vector< Intersection > m_intersections;
};
class BoolIntersectionList
{
public:
BoolIntersectionList(const IntersectionList & l1,
const IntersectionList & l2,
const Vector & startPoint);
BoolIntersection & operator[](int i)
{
return m_intersections[i];
}
const BoolIntersection & operator[](int i) const
{
return m_intersections[i];
}
size_t size() const { return m_intersections.size(); }
std::vector<BoolIntersection>::iterator begin()
{
return m_intersections.begin();
}
std::vector<BoolIntersection>::iterator end()
{
return m_intersections.end();
}
protected:
std::vector< BoolIntersection > m_intersections;
};
Shape();
virtual ~Shape();
virtual IntersectionList intersect(refptr<Shape> _this,
const Ray & ray) = 0;
virtual refptr<Shape> clone() = 0;
void setTransform(const Transform & t)
{
m_transform = t;
m_inverse = m_transform.getInverse();
}
Transform & getTransform() { return m_transform; }
virtual void setMaterial(refptr<Material> material);
refptr<Material> getMaterial() const { return m_material; }
protected:
Transform m_transform;
Transform m_inverse;
refptr<Material> m_material;
};
typedef refptr<Shape> ShapeRef;
#endif

View File

@ -1,49 +0,0 @@
#include "Sphere.h"
#include "util/Solver.h"
#include <math.h>
#include <iostream>
using namespace std;
Sphere::Sphere(double radius)
{
m_radius = radius;
m_radius2 = radius * radius;
}
Shape::IntersectionList Sphere::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res;
QuadraticSolver solver(1.0,
2 * ( ray_inv.getOrigin()[0] * ray_inv.getDirection()[0]
+ ray_inv.getOrigin()[1] * ray_inv.getDirection()[1]
+ ray_inv.getOrigin()[2] * ray_inv.getDirection()[2] ),
ray_inv.getOrigin()[0] * ray_inv.getOrigin()[0]
+ ray_inv.getOrigin()[1] * ray_inv.getOrigin()[1]
+ ray_inv.getOrigin()[2] * ray_inv.getOrigin()[2]
- m_radius2);
Solver::Result quadSolutions = solver.solve();
for (int i = 0; i < quadSolutions.numResults; i++)
{
if (quadSolutions.results[i] >= 0.0)
{
Vector isect_point = ray_inv[quadSolutions.results[i]];
Vector normal = isect_point;
normal.normalize();
res.add(
Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(normal))
);
}
}
return res;
}
refptr<Shape> Sphere::clone()
{
return new Sphere(*this);
}

View File

@ -1,20 +0,0 @@
#ifndef SPHERE_H
#define SPHERE_H SPHERE_H
#include "Shape.h"
class Sphere : public Shape
{
public:
Sphere(double radius);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
virtual refptr<Shape> clone();
protected:
double m_radius;
double m_radius2;
};
#endif

View File

@ -1,115 +0,0 @@
#include "Subtract.h"
#include <iostream>
using namespace std;
Subtract::Subtract(const vector< refptr<Shape> > & shapes)
{
int num_shapes = shapes.size();
if (num_shapes > 2)
{
m_shape2 = shapes[num_shapes - 1];
vector< refptr<Shape> > rest = shapes;
rest.pop_back();
m_shape1 = new Subtract(rest);
}
else if (num_shapes == 2)
{
m_shape1 = shapes[0];
m_shape2 = shapes[1];
}
else
{
cerr << __FILE__ << ": " << __LINE__
<< ": error: Subtract::Subtract() called with only "
<< num_shapes
<< " sub-shapes!"
<< endl;
exit(4);
}
}
Shape::IntersectionList Subtract::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res1 = m_shape1->intersect(m_shape1, ray_inv);
/*** optimization ***/
if (res1.size() == 0)
return res1;
/*** end optimization ***/
IntersectionList res2 = m_shape2->intersect(m_shape2, ray_inv);
BoolIntersectionList merged(res1, res2, ray_inv.getOrigin());
IntersectionList res;
bool in1 = false, in2 = false;
/* initially go through the merged intersections to see whether
* the ray started inside one of the sub-objects */
for (int i = 0, sz = merged.size(), saw1 = 0, saw2 = 0;
i < sz && (!saw1 || !saw2);
i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool back = dot < 0.0;
bool left = merged[i].left;
if (back)
{
if (left && !saw1)
in1 = true;
else if (!left && !saw2)
in2 = true;
}
if (left)
saw1 = 1;
else
saw2 = 1;
}
bool in_bool = in1 && !in2;
for (int i = 0, sz = merged.size(); i < sz; i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool front = dot > 0.0;
bool left = merged[i].left;
if (left)
in1 = front;
else
in2 = front;
if (!in_bool && in1 && !in2)
{
/* we found an intersection point
* to get into the boolean object */
in_bool = true;
BoolIntersection bi = merged[i];
Intersection i = bi.intersection;
if ( ! left ) /* if this point came from object B (A - B) */
i.normal = - i.normal;
res.add(i.transform(m_transform));
}
else if (in_bool && !(in1 && !in2))
{
/* we found an intersection point
* to get out of the boolean object */
BoolIntersection bi = merged[i];
Intersection i = bi.intersection;
if ( ! left ) /* if this point came from object B (A - B) */
i.normal = - i.normal;
res.add(i.transform(m_transform));
in_bool = false;
}
}
return res;
}
refptr<Shape> Subtract::clone()
{
Subtract * s = new Subtract(*this);
s->m_shape1 = m_shape1->clone();
s->m_shape2 = m_shape2->clone();
return refptr<Shape>(s);
}

View File

@ -1,17 +0,0 @@
#ifndef SUBTRACT_H
#define SUBTRACT_H SUBTRACT_H
#include "BoolShape.h"
#include <vector>
class Subtract : public BoolShape
{
public:
Subtract(const std::vector< refptr<Shape> > & shapes);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
refptr<Shape> clone();
};
#endif

View File

@ -1,110 +0,0 @@
#include "Union.h"
#include <iostream>
#include <vector>
using namespace std;
Union::Union(const vector< refptr<Shape> > & shapes)
{
int num_shapes = shapes.size();
if (num_shapes > 2)
{
m_shape2 = shapes[num_shapes - 1];
vector< refptr<Shape> > rest = shapes;
rest.pop_back();
m_shape1 = new Union(rest);
}
else if (num_shapes == 2)
{
m_shape1 = shapes[0];
m_shape2 = shapes[1];
}
else
{
cerr << __FILE__ << ": " << __LINE__
<< ": error: Union::Union() called with only "
<< num_shapes
<< " sub-shapes!"
<< endl;
exit(4);
}
}
Shape::IntersectionList Union::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res1 = m_shape1->intersect(m_shape1, ray_inv);
IntersectionList res2 = m_shape2->intersect(m_shape2, ray_inv);
BoolIntersectionList merged(res1, res2, ray_inv.getOrigin());
IntersectionList res;
bool in1 = false, in2 = false;
/* initially go through the merged intersections to see whether
* the ray started inside one of the sub-objects */
for (int i = 0, sz = merged.size(), saw1 = 0, saw2 = 0;
i < sz && (!saw1 || !saw2);
i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool back = dot < 0.0;
bool left = merged[i].left;
if (back)
{
if (left && !saw1)
in1 = true;
else if (!left && !saw2)
in2 = true;
}
if (left)
saw1 = 1;
else
saw2 = 1;
}
bool in_bool = in1 || in2;
for (int i = 0, sz = merged.size(); i < sz; i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool front = dot > 0.0;
bool left = merged[i].left;
if (front)
{
if (left)
in1 = true;
else
in2 = true;
if (!in_bool && (in1 || in2))
{
/* we found an intersection point with the boolean object */
in_bool = true;
res.add( merged[i].intersection.transform(m_transform) );
}
}
else
{
if (left)
in1 = false;
else
in2 = false;
if (in_bool && !(in1 || in2))
{
/* we found an intersection point with the boolean object */
res.add( merged[i].intersection.transform(m_transform) );
in_bool = false;
}
}
}
return res;
}
refptr<Shape> Union::clone()
{
Union * s = new Union(*this);
s->m_shape1 = m_shape1->clone();
s->m_shape2 = m_shape2->clone();
return refptr<Shape>(s);
}

View File

@ -1,17 +0,0 @@
#ifndef UNION_H
#define UNION_H UNION_H
#include "BoolShape.h"
#include <vector>
class Union : public BoolShape
{
public:
Union(const std::vector< refptr<Shape> > & shapes);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
refptr<Shape> clone();
};
#endif

View File

@ -1,10 +0,0 @@
#include "BoolShape.h"
#include "Box.h"
#include "Cyl.h"
#include "Extrude.h"
#include "Intersect.h"
#include "Plane.h"
#include "Sphere.h"
#include "Subtract.h"
#include "Union.h"

View File

@ -1,21 +0,0 @@
#ifndef AABB_H
#define AABB_H
class AABB
{
public:
Vector min;
Vector max;
AABB()
{
}
AABB(const Vector & min, const Vector & max)
: min(min), max(max)
{
}
};
#endif /* AABB_H */

View File

@ -1,17 +0,0 @@
#include "Color.h"
const Color Color::black = Color(0, 0, 0);
const Color Color::white = Color(1, 1, 1);
const Color Color::red = Color(1, 0, 0);
const Color Color::green = Color(0, 1, 0);
const Color Color::blue = Color(0, 0, 1);
const Color Color::yellow = Color(1, 1, 0);
const Color Color::cyan = Color(0, 1, 1);
const Color Color::magenta = Color(1, 0, 1);
std::ostream & operator<<(std::ostream & out, const Color & color)
{
out << "[" << color.r << ", " << color.g << ", " << color.b << "]";
return out;
}

View File

@ -1,132 +0,0 @@
#ifndef COLOR_H
#define COLOR_H COLOR_H
#include "refptr.h"
#include <iostream>
#include "util/Vector.h"
class Color
{
public:
double r, g, b;
Color()
{
r = g = b = 0.0;
}
Color(double r, double g, double b)
{
this->r = r;
this->g = g;
this->b = b;
}
Color(const Vector & v)
{
r = v[0];
g = v[1];
b = v[2];
}
Color(refptr<Vector> v)
{
r = (*v)[0];
g = (*v)[1];
b = (*v)[2];
}
Color operator*(const Color & other) const
{
Color result;
result.r = r * other.r;
result.g = g * other.g;
result.b = b * other.b;
return result;
}
Color operator*(double scale) const
{
return Color(r * scale, g * scale, b * scale);
}
Color operator/(double scale) const
{
return Color(r / scale, g / scale, b / scale);
}
Color & operator+=(const Color & other)
{
r += other.r;
g += other.g;
b += other.b;
return *this;
}
Color & operator-=(const Color & other)
{
r += other.r;
g += other.g;
b += other.b;
return *this;
}
Color & operator*=(double scale)
{
r *= scale;
g *= scale;
b *= scale;
return *this;
}
Color & operator*=(const Color & other)
{
r *= other.r;
g *= other.g;
b *= other.b;
return *this;
}
Color & operator/=(double scale)
{
r /= scale;
g /= scale;
b /= scale;
return *this;
}
Color & operator/=(const Color & other)
{
r /= other.r;
g /= other.g;
b /= other.b;
return *this;
}
Color operator+(const Color & c2)
{
return Color(r + c2.r, g + c2.g, b + c2.b);
}
Color operator-(const Color & c2)
{
return Color(r - c2.r, g - c2.g, b - c2.b);
}
static const Color black;
static const Color white;
static const Color red;
static const Color green;
static const Color blue;
static const Color yellow;
static const Color cyan;
static const Color magenta;
};
static inline Color operator*(double d, const Color & c) { return c * d; }
static inline Color operator/(double d, const Color & c) { return c / d; }
std::ostream & operator<<(std::ostream & out, const Color & color);
#endif

View File

@ -1,73 +0,0 @@
#ifndef MATERIAL_H
#define MATERIAL_H MATERIAL_H
#include <FreeImage.h>
#include "Color.h"
class Material
{
public:
Material()
{
m_ambient_color = Color::white;
m_diffuse_color = Color::white;
m_specular_color = Color::white;
m_shininess = 50.0;
m_reflectance = 0.0;
m_transparency = 0.0;
m_refraction = 1.0;
m_texture = NULL;
}
void setAmbientColor(const Color & ambient)
{
m_ambient_color = ambient;
}
const Color & getAmbientColor() const { return m_ambient_color; }
void setDiffuseColor(const Color & diffuse)
{
m_diffuse_color = diffuse;
}
const Color & getDiffuseColor() const { return m_diffuse_color; }
void setSpecularColor(const Color & specular)
{
m_specular_color = specular;
}
const Color & getSpecularColor() const { return m_specular_color; }
void setShininess(double shininess) { m_shininess = shininess; }
double getShininess() const { return m_shininess; }
void setReflectance(double reflectance) { m_reflectance = reflectance; }
double getReflectance() const { return m_reflectance; }
void setRefraction(double refraction)
{
if (refraction > 0.0)
m_refraction = refraction;
}
double getRefraction() const { return m_refraction; }
void setTransparency(double t) { m_transparency = t; }
double getTransparency() const { return m_transparency; }
void setTexture(FIBITMAP * fib) { m_texture = fib; }
FIBITMAP * getTexture() const { return m_texture; }
protected:
Color m_ambient_color;
Color m_diffuse_color;
Color m_specular_color;
double m_shininess;
double m_reflectance;
double m_refraction;
double m_transparency;
FIBITMAP * m_texture;
};
#endif

View File

@ -1,241 +0,0 @@
#include "Matrix.h"
#include <math.h> /* fabs() */
#include <iostream>
#include <iomanip> /* setprecision() */
#define FP_EQ(x,y) (fabs((x)-(y)) < 0.00001)
Matrix::Matrix()
{
/* set matrix to the identity matrix */
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
m_matrix[i][j] = i == j ? 1.0 : 0.0;
}
}
m_inverse_calculated = false;
}
Matrix Matrix::identity()
{
Matrix res;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
res[i][j] = i == j ? 1.0 : 0.0;
}
}
return res;
}
/* Formulas from http://www.cvl.iis.u-tokyo.ac.jp/~miyazaki/tech/teche23.html */
double Matrix::determinant()
{
return m_matrix[0][0] * m_matrix[1][1] * m_matrix[2][2] * m_matrix[3][3]
+ m_matrix[0][0] * m_matrix[1][2] * m_matrix[2][3] * m_matrix[3][1]
+ m_matrix[0][0] * m_matrix[1][3] * m_matrix[2][1] * m_matrix[3][2]
+ m_matrix[0][1] * m_matrix[1][0] * m_matrix[2][3] * m_matrix[3][2]
+ m_matrix[0][1] * m_matrix[1][2] * m_matrix[2][0] * m_matrix[3][3]
+ m_matrix[0][1] * m_matrix[1][3] * m_matrix[2][2] * m_matrix[3][0]
+ m_matrix[0][2] * m_matrix[1][0] * m_matrix[2][1] * m_matrix[3][3]
+ m_matrix[0][2] * m_matrix[1][1] * m_matrix[2][3] * m_matrix[3][0]
+ m_matrix[0][2] * m_matrix[1][3] * m_matrix[2][0] * m_matrix[3][1]
+ m_matrix[0][3] * m_matrix[1][0] * m_matrix[2][2] * m_matrix[3][1]
+ m_matrix[0][3] * m_matrix[1][1] * m_matrix[2][0] * m_matrix[3][2]
+ m_matrix[0][3] * m_matrix[1][2] * m_matrix[2][1] * m_matrix[3][0]
- m_matrix[0][0] * m_matrix[1][1] * m_matrix[2][3] * m_matrix[3][2]
- m_matrix[0][0] * m_matrix[1][2] * m_matrix[2][1] * m_matrix[3][3]
- m_matrix[0][0] * m_matrix[1][3] * m_matrix[2][2] * m_matrix[3][1]
- m_matrix[0][1] * m_matrix[1][0] * m_matrix[2][2] * m_matrix[3][3]
- m_matrix[0][1] * m_matrix[1][2] * m_matrix[2][3] * m_matrix[3][0]
- m_matrix[0][1] * m_matrix[1][3] * m_matrix[2][0] * m_matrix[3][2]
- m_matrix[0][2] * m_matrix[1][0] * m_matrix[2][3] * m_matrix[3][1]
- m_matrix[0][2] * m_matrix[1][1] * m_matrix[2][0] * m_matrix[3][3]
- m_matrix[0][2] * m_matrix[1][3] * m_matrix[2][1] * m_matrix[3][0]
- m_matrix[0][3] * m_matrix[1][0] * m_matrix[2][1] * m_matrix[3][2]
- m_matrix[0][3] * m_matrix[1][1] * m_matrix[2][2] * m_matrix[3][0]
- m_matrix[0][3] * m_matrix[1][2] * m_matrix[2][0] * m_matrix[3][1];
}
/* Formulas from http://www.cvl.iis.u-tokyo.ac.jp/~miyazaki/tech/teche23.html */
void Matrix::calculateInverse()
{
if (m_inverse_calculated)
return;
m_inverse_calculated = true;
m_inverse_valid = false;
double det = determinant();
if (det == 0.0)
return;
m_inverse[0][0] = m_matrix[1][1] * m_matrix[2][2] * m_matrix[3][3]
+ m_matrix[1][2] * m_matrix[2][3] * m_matrix[3][1]
+ m_matrix[1][3] * m_matrix[2][1] * m_matrix[3][2]
- m_matrix[1][1] * m_matrix[2][3] * m_matrix[3][2]
- m_matrix[1][2] * m_matrix[2][1] * m_matrix[3][3]
- m_matrix[1][3] * m_matrix[2][2] * m_matrix[3][1];
m_inverse[0][1] = m_matrix[0][1] * m_matrix[2][3] * m_matrix[3][2]
+ m_matrix[0][2] * m_matrix[2][1] * m_matrix[3][3]
+ m_matrix[0][3] * m_matrix[2][2] * m_matrix[3][1]
- m_matrix[0][1] * m_matrix[2][2] * m_matrix[3][3]
- m_matrix[0][2] * m_matrix[2][3] * m_matrix[3][1]
- m_matrix[0][3] * m_matrix[2][1] * m_matrix[3][2];
m_inverse[0][2] = m_matrix[0][1] * m_matrix[1][2] * m_matrix[3][3]
+ m_matrix[0][2] * m_matrix[1][3] * m_matrix[3][1]
+ m_matrix[0][3] * m_matrix[1][1] * m_matrix[3][2]
- m_matrix[0][1] * m_matrix[1][3] * m_matrix[3][2]
- m_matrix[0][2] * m_matrix[1][1] * m_matrix[3][3]
- m_matrix[0][3] * m_matrix[1][2] * m_matrix[3][1];
m_inverse[0][3] = m_matrix[0][1] * m_matrix[1][3] * m_matrix[2][2]
+ m_matrix[0][2] * m_matrix[1][1] * m_matrix[2][3]
+ m_matrix[0][3] * m_matrix[1][2] * m_matrix[2][1]
- m_matrix[0][1] * m_matrix[1][2] * m_matrix[2][3]
- m_matrix[0][2] * m_matrix[1][3] * m_matrix[2][1]
- m_matrix[0][3] * m_matrix[1][1] * m_matrix[2][2];
m_inverse[1][0] = m_matrix[1][0] * m_matrix[2][3] * m_matrix[3][2]
+ m_matrix[1][2] * m_matrix[2][0] * m_matrix[3][3]
+ m_matrix[1][3] * m_matrix[2][2] * m_matrix[3][0]
- m_matrix[1][0] * m_matrix[2][2] * m_matrix[3][3]
- m_matrix[1][2] * m_matrix[2][3] * m_matrix[3][0]
- m_matrix[1][3] * m_matrix[2][0] * m_matrix[3][2];
m_inverse[1][1] = m_matrix[0][0] * m_matrix[2][2] * m_matrix[3][3]
+ m_matrix[0][2] * m_matrix[2][3] * m_matrix[3][0]
+ m_matrix[0][3] * m_matrix[2][0] * m_matrix[3][2]
- m_matrix[0][0] * m_matrix[2][3] * m_matrix[3][2]
- m_matrix[0][2] * m_matrix[2][0] * m_matrix[3][3]
- m_matrix[0][3] * m_matrix[2][2] * m_matrix[3][0];
m_inverse[1][2] = m_matrix[0][0] * m_matrix[1][3] * m_matrix[3][2]
+ m_matrix[0][2] * m_matrix[1][0] * m_matrix[3][3]
+ m_matrix[0][3] * m_matrix[1][2] * m_matrix[3][0]
- m_matrix[0][0] * m_matrix[1][2] * m_matrix[3][3]
- m_matrix[0][2] * m_matrix[1][3] * m_matrix[3][0]
- m_matrix[0][3] * m_matrix[1][0] * m_matrix[3][2];
m_inverse[1][3] = m_matrix[0][0] * m_matrix[1][2] * m_matrix[2][3]
+ m_matrix[0][2] * m_matrix[1][3] * m_matrix[2][0]
+ m_matrix[0][3] * m_matrix[1][0] * m_matrix[2][2]
- m_matrix[0][0] * m_matrix[1][3] * m_matrix[2][2]
- m_matrix[0][2] * m_matrix[1][0] * m_matrix[2][3]
- m_matrix[0][3] * m_matrix[1][2] * m_matrix[2][0];
m_inverse[2][0] = m_matrix[1][0] * m_matrix[2][1] * m_matrix[3][3]
+ m_matrix[1][1] * m_matrix[2][3] * m_matrix[3][0]
+ m_matrix[1][3] * m_matrix[2][0] * m_matrix[3][1]
- m_matrix[1][0] * m_matrix[2][3] * m_matrix[3][1]
- m_matrix[1][1] * m_matrix[2][0] * m_matrix[3][3]
- m_matrix[1][3] * m_matrix[2][1] * m_matrix[3][0];
m_inverse[2][1] = m_matrix[0][0] * m_matrix[2][3] * m_matrix[3][1]
+ m_matrix[0][1] * m_matrix[2][0] * m_matrix[3][3]
+ m_matrix[0][3] * m_matrix[2][1] * m_matrix[3][0]
- m_matrix[0][0] * m_matrix[2][1] * m_matrix[3][3]
- m_matrix[0][1] * m_matrix[2][3] * m_matrix[3][0]
- m_matrix[0][3] * m_matrix[2][0] * m_matrix[3][1];
m_inverse[2][2] = m_matrix[0][0] * m_matrix[1][1] * m_matrix[3][3]
+ m_matrix[0][1] * m_matrix[1][3] * m_matrix[3][0]
+ m_matrix[0][3] * m_matrix[1][0] * m_matrix[3][1]
- m_matrix[0][0] * m_matrix[1][3] * m_matrix[3][1]
- m_matrix[0][1] * m_matrix[1][0] * m_matrix[3][3]
- m_matrix[0][3] * m_matrix[1][1] * m_matrix[3][0];
m_inverse[2][3] = m_matrix[0][0] * m_matrix[1][3] * m_matrix[2][1]
+ m_matrix[0][1] * m_matrix[1][0] * m_matrix[2][3]
+ m_matrix[0][3] * m_matrix[1][1] * m_matrix[2][0]
- m_matrix[0][0] * m_matrix[1][1] * m_matrix[2][3]
- m_matrix[0][1] * m_matrix[1][3] * m_matrix[2][0]
- m_matrix[0][3] * m_matrix[1][0] * m_matrix[2][1];
m_inverse[3][0] = m_matrix[1][0] * m_matrix[2][2] * m_matrix[3][1]
+ m_matrix[1][1] * m_matrix[2][0] * m_matrix[3][2]
+ m_matrix[1][2] * m_matrix[2][1] * m_matrix[3][0]
- m_matrix[1][0] * m_matrix[2][1] * m_matrix[3][2]
- m_matrix[1][1] * m_matrix[2][2] * m_matrix[3][0]
- m_matrix[1][2] * m_matrix[2][0] * m_matrix[3][1];
m_inverse[3][1] = m_matrix[0][0] * m_matrix[2][1] * m_matrix[3][2]
+ m_matrix[0][1] * m_matrix[2][2] * m_matrix[3][0]
+ m_matrix[0][2] * m_matrix[2][0] * m_matrix[3][1]
- m_matrix[0][0] * m_matrix[2][2] * m_matrix[3][1]
- m_matrix[0][1] * m_matrix[2][0] * m_matrix[3][2]
- m_matrix[0][2] * m_matrix[2][1] * m_matrix[3][0];
m_inverse[3][2] = m_matrix[0][0] * m_matrix[1][2] * m_matrix[3][1]
+ m_matrix[0][1] * m_matrix[1][0] * m_matrix[3][2]
+ m_matrix[0][2] * m_matrix[1][1] * m_matrix[3][0]
- m_matrix[0][0] * m_matrix[1][1] * m_matrix[3][2]
- m_matrix[0][1] * m_matrix[1][2] * m_matrix[3][0]
- m_matrix[0][2] * m_matrix[1][0] * m_matrix[3][1];
m_inverse[3][3] = m_matrix[0][0] * m_matrix[1][1] * m_matrix[2][2]
+ m_matrix[0][1] * m_matrix[1][2] * m_matrix[2][0]
+ m_matrix[0][2] * m_matrix[1][0] * m_matrix[2][1]
- m_matrix[0][0] * m_matrix[1][2] * m_matrix[2][1]
- m_matrix[0][1] * m_matrix[1][0] * m_matrix[2][2]
- m_matrix[0][2] * m_matrix[1][1] * m_matrix[2][0];
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
m_inverse[i][j] /= det;
}
}
m_inverse_valid = true;
}
Matrix Matrix::getInverse()
{
calculateInverse();
Matrix m;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
m.m_matrix[i][j] = m_inverse[i][j];
m.m_inverse[i][j] = m_matrix[i][j];
}
}
m.m_inverse_calculated = true;
m.m_inverse_valid = m_inverse_valid;
return m;
}
Matrix & Matrix::operator*=(const Matrix & other)
{
Matrix temp = (*this) * other;
(*this) = temp;
return (*this);
}
bool operator==(const Matrix & m1, const Matrix & m2)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (! FP_EQ(m1[i][j], m2[i][j]))
return false;
}
}
return true;
}
std::ostream & operator<<(std::ostream & out, const Matrix & m)
{
out << std::setprecision(3);
for (int i = 0; i < 4; i++)
{
out << (i == 0 ? "[ " : " ");
out << "[ ";
for (int j = 0; j < 4; j++)
{
out << m[i][j];
if (j < 3)
out << ", ";
}
out << " ]";
if (i == 3)
out << " ]";
out << std::endl;
}
return out;
}

View File

@ -1,75 +0,0 @@
#ifndef MATRIX_H
#define MATRIX_H MATRIX_H
#include "Vector.h"
#include <iostream>
class Matrix
{
public:
Matrix();
typedef double Matrix_row_t[4];
Matrix_row_t & operator[](int idx) { return m_matrix[idx]; }
const Matrix_row_t & operator[](int idx) const { return m_matrix[idx]; }
static Matrix identity();
double determinant();
Matrix getInverse();
Matrix & operator*=(const Matrix & other);
Matrix operator*(const Matrix & m2) const
{
Matrix res;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
res[i][j] = m_matrix[i][0] * m2.m_matrix[0][j]
+ m_matrix[i][1] * m2.m_matrix[1][j]
+ m_matrix[i][2] * m2.m_matrix[2][j]
+ m_matrix[i][3] * m2.m_matrix[3][j];
}
}
return res;
}
/* transform a point */
Vector operator*(const Vector & v)
{
Vector res;
for (int i = 0; i < 3; i++)
{
res[i] = m_matrix[i][0] * v[0]
+ m_matrix[i][1] * v[1]
+ m_matrix[i][2] * v[2]
+ m_matrix[i][3]; /* v[3] is implicitly 1.0 */
}
return res;
}
/* transform a direction */
Vector operator%(const Vector & v)
{
Vector res;
for (int i = 0; i < 3; i++)
{
res[i] = m_matrix[i][0] * v[0]
+ m_matrix[i][1] * v[1]
+ m_matrix[i][2] * v[2];
}
return res;
}
protected:
double m_matrix[4][4];
double m_inverse[4][4];
bool m_inverse_calculated;
bool m_inverse_valid;
void calculateInverse();
};
bool operator==(const Matrix & m1, const Matrix & m2);
std::ostream & operator<<(std::ostream & out, const Matrix & m);
#endif

View File

@ -1,95 +0,0 @@
#include <math.h> /* acos(), M_PI */
#include "Polygon.h"
#define FP_EQUAL(x,y) (fabs((x)-(y)) < 1E-3)
/*
* from http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/
* Return the angle between two vectors on a plane
* The angle is from vector 1 to vector 2, positive anticlockwise
* The result is between -pi -> pi
*/
static double angle2D(double x1, double y1, double x2, double y2)
{
double dtheta, theta1, theta2;
theta1 = atan2(y1,x1);
theta2 = atan2(y2,x2);
dtheta = theta2 - theta1;
while (dtheta > M_PI)
dtheta -= 2.0 * M_PI;
while (dtheta < -M_PI)
dtheta += 2.0 * M_PI;
return dtheta;
}
static bool similarPoint(const Vector & v, const Vector & w)
{
return FP_EQUAL(v[0], w[0]) && FP_EQUAL(v[1], w[1]) && FP_EQUAL(v[2], w[2]);
}
Polygon & Polygon::add(const Vector & v)
{
int sz = size();
if (sz < 1 || !similarPoint(v, *(*this)[sz-1]))
{
push_back(new Vector(v));
}
return *this;
}
Polygon & Polygon::add(refptr<Vector> v)
{
int sz = size();
if (sz < 1 || !similarPoint(*v, *(*this)[sz-1]))
{
push_back(v);
}
return *this;
}
bool Polygon::containsPoint2D(const Vector & v)
{
if (size() < 3)
{
return false;
}
if (similarPoint(*(*this)[0], *(*this)[size()-1]))
{
pop_back();
}
double angle_sum = 0.0;
for (int i = 0, sz = size(); i < sz; i++)
{
Vector v1 = *(*this)[i] - v;
Vector v2 = *(*this)[(i+1) % sz] - v;
double angle = angle2D(v1[0], v1[1], v2[0], v2[1]);
angle_sum += angle;
}
return FP_EQUAL(angle_sum, 2.0 * M_PI);
}
bool Polygon::containsPointConvex(const Vector & v)
{
if (size() < 3)
{
return false;
}
if (similarPoint(*(*this)[0], *(*this)[size()-1]))
{
pop_back();
}
double angle_sum = 0.0;
for (int i = 0, sz = size(); i < sz; i++)
{
Vector v1 = *(*this)[i] - v;
Vector v2 = *(*this)[(i+1) % sz] - v;
double cosine = (v1 % v2) / (v1.mag() * v2.mag());
double angle = acos(cosine);
angle_sum += angle;
}
return FP_EQUAL(angle_sum, 2.0 * M_PI);
}

View File

@ -1,19 +0,0 @@
#ifndef POLYGON_H
#define POLYGON_H
#include <vector>
#include "refptr.h"
#include "Vector.h"
class Polygon : public std::vector< refptr<Vector> >
{
public:
Polygon & add(const Vector & v);
Polygon & add(refptr<Vector> v);
bool containsPoint2D(const Vector & v);
bool containsPointConvex(const Vector & v);
};
#endif

View File

@ -1,17 +0,0 @@
#include <stdlib.h> /* rand() */
#include <iostream>
#include "Ray.h"
Ray Ray::randomRay()
{
return Ray(Vector(0, 0, 0), Vector::randomVector());
}
std::ostream & operator<<(std::ostream & out, const Ray & r)
{
out << "(" << r.getOrigin() << " -> " << r.getDirection() << ")";
return out;
}

View File

@ -1,58 +0,0 @@
#ifndef RAY_H
#define RAY_H RAY_H
#include "Vector.h"
#include <iostream>
class Ray
{
public:
Ray()
{
}
Ray(const Vector & origin, const Vector & direction)
: m_origin(origin), m_direction(direction)
{
m_direction.normalize();
}
/*
* return a vector for the point at distance dist
* from the ray's origin point, along its direction.
*/
Vector getPositionAt(double dist) const
{
return Vector(
m_origin[0] + dist * m_direction[0],
m_origin[1] + dist * m_direction[1],
m_origin[2] + dist * m_direction[2]);
}
Ray shift(double amt)
{
return Ray(getPositionAt(amt), m_direction, false);
}
const Vector & getOrigin() const { return m_origin; }
const Vector & getDirection() const { return m_direction; }
static Ray randomRay();
Vector operator[](double dist) const { return getPositionAt(dist); }
protected:
Ray(const Vector & origin, const Vector & direction, bool no_norm)
: m_origin(origin), m_direction(direction)
{
/* no normalize version */
}
Vector m_origin;
Vector m_direction;
};
std::ostream & operator<<(std::ostream & out, const Ray & r);
#endif

View File

@ -1,73 +0,0 @@
#ifndef SCOPE_H
#define SCOPE_H
#include <list>
#include <map>
#include <string>
class Scope
{
public:
Scope() { push(); }
bool contains(const std::string & key)
{
for (m_list_type::const_reverse_iterator it = m_list.rbegin();
it != m_list.rend();
it++)
{
if (it->find(key) != it->end())
{
return true;
}
}
return false;
}
double get(const std::string & key)
{
for (m_list_type::reverse_iterator it = m_list.rbegin();
it != m_list.rend();
it++)
{
if (it->find(key) != it->end())
{
return (*it)[key];
}
}
return 0.0;
}
void putLocal(const std::string & key, double val)
{
(*m_list.rbegin())[key] = val;
}
void putGlobal(const std::string & key, double val)
{
for (m_list_type::reverse_iterator it = m_list.rbegin();
it != m_list.rend();
it++)
{
if (it->find(key) != it->end())
{
(*it)[key] = val;
return;
}
}
putLocal(key, val);
}
void push()
{
m_list.push_back(std::map< std::string, double >());
}
void pop()
{
if (m_list.size() > 1)
{
m_list.pop_back();
}
}
protected:
typedef std::list< std::map< std::string, double > > m_list_type;
m_list_type m_list;
};
#endif

View File

@ -1,127 +0,0 @@
#include "Solver.h"
#include <math.h>
/* Generic Solver constructor */
Solver::Solver(double a, double b, double c, double d, double e)
{
this->a = a;
this->b = b;
this->c = c;
this->d = d;
this->e = e;
}
Solver::~Solver()
{
}
Solver::Result::Result()
{
numResults = 0;
}
/**************************************************************************
* LinearSolver methods *
*************************************************************************/
LinearSolver::LinearSolver(double a, double b)
: Solver(a, b)
{
}
/* solve a linear equation */
Solver::Result LinearSolver::solve()
{
/* equation ax + b = 0 */
Result res;
if (a == 0.0)
{
if (b == 0.0)
{
res.numResults = 1;
res.results[0] = 0.0;
}
else
{
res.numResults = 0;
}
}
else
{
res.numResults = 1;
res.results[0] = -b / a;
}
return res;
}
/**************************************************************************
* QuadraticSolver methods *
*************************************************************************/
QuadraticSolver::QuadraticSolver(double a, double b, double c)
: Solver(a, b, c)
{
}
/* solve a quadratic equation */
Solver::Result QuadraticSolver::solve()
{
Result res;
double discriminant = b * b - 4 * a * c;
if (discriminant < 0.0)
{
res.numResults = 0;
}
else
{
double sqrt_discriminant = sqrt(discriminant);
double two_a = 2.0 * a;
if (sqrt_discriminant == 0.0)
{
res.numResults = 1;
res.results[0] = (-b) / two_a;
}
else
{
res.numResults = 2;
res.results[0] = (-b - sqrt_discriminant) / two_a;
res.results[1] = (-b + sqrt_discriminant) / two_a;
}
}
return res;
}
/**************************************************************************
* CubicSolver methods *
*************************************************************************/
CubicSolver::CubicSolver(double a, double b, double c, double d)
: Solver(a, b, c, d)
{
}
Solver::Result CubicSolver::solve()
{
Result res;
/* TODO: fill in */
return res;
}
/**************************************************************************
* QuarticSolver methods *
*************************************************************************/
QuarticSolver::QuarticSolver(double a, double b, double c, double d, double e)
: Solver(a, b, c, d, e)
{
}
Solver::Result QuarticSolver::solve()
{
Result res;
/* TODO: fill in */
return res;
}

View File

@ -1,57 +0,0 @@
#ifndef SOLVER_H
#define SOLVER_H SOLVER_H
class Solver
{
public:
class Result
{
public:
Result();
int numResults;
double results[4];
};
Solver(double a = 0.0,
double b = 0.0,
double c = 0.0,
double d = 0.0,
double e = 0.0);
virtual ~Solver();
virtual Result solve() = 0;
protected:
double a, b, c, d, e;
};
class LinearSolver : public Solver
{
public:
LinearSolver(double a, double b);
Result solve();
};
class QuadraticSolver : public Solver
{
public:
QuadraticSolver(double a, double b, double c);
Result solve();
};
class CubicSolver : public Solver
{
public:
CubicSolver(double a, double b, double c, double d);
Result solve();
};
class QuarticSolver : public Solver
{
public:
QuarticSolver(double a, double b, double c, double d, double e);
Result solve();
};
#endif

View File

@ -1,72 +0,0 @@
#include "Transform.h"
#include <math.h>
void Transform::lookAt(const Vector & eye,
const Vector & focus,
const Vector & up)
{
Vector forward = focus - eye;
forward.normalize();
Vector perpendicular_up = (up - up.proj(forward)).normalize();
Vector right = forward * perpendicular_up;
Matrix mult;
mult[0][0] = right[0];
mult[0][1] = right[1];
mult[0][2] = right[2];
mult[1][0] = forward[0];
mult[1][1] = forward[1];
mult[1][2] = forward[2];
mult[2][0] = perpendicular_up[0];
mult[2][1] = perpendicular_up[1];
mult[2][2] = perpendicular_up[2];
m_matrix *= mult;
translate(-eye[0], -eye[1], -eye[2]);
}
void Transform::translate(double x, double y, double z)
{
Matrix t = Matrix::identity();
t[0][3] = x;
t[1][3] = y;
t[2][3] = z;
m_matrix *= t;
}
void Transform::rotate(double angle, double xv, double yv, double zv)
{
/* formula from http://en.wikipedia.org/wiki/Rotation_matrix */
Vector l(xv, yv, zv);
l.normalize();
double c = cos(M_PI * angle / 180.0);
double s = sin(M_PI * angle / 180.0);
double lx2 = l[0] * l[0];
double ly2 = l[1] * l[1];
double lz2 = l[2] * l[2];
Matrix t = Matrix::identity();
t[0][0] = lx2 + (1 - lx2) * c;
t[0][1] = l[0] * l[1] * (1 - c) - l[2] * s;
t[0][2] = l[0] * l[2] * (1 - c) + l[1] * s;
t[1][0] = l[0] * l[1] * (1 - c) + l[2] * s;
t[1][1] = ly2 + (1 - ly2) * c;
t[1][2] = l[1] * l[2] * (1 - c) - l[0] * s;
t[2][0] = l[0] * l[2] * (1 - c) - l[1] * s;
t[2][1] = l[1] * l[2] * (1 - c) + l[0] * s;
t[2][2] = lz2 + (1 - lz2) * c;
m_matrix *= t;
}
void Transform::scale(double xs, double ys, double zs)
{
Matrix t = Matrix::identity();
t[0][0] = xs;
t[1][1] = ys;
t[2][2] = zs;
m_matrix *= t;
}

View File

@ -1,72 +0,0 @@
#ifndef TRANSFORM_H
#define TRANSFORM_H TRANSFORM_H
#include "refptr.h"
#include "Matrix.h"
#include "Ray.h"
#include "Vector.h"
#include <stack>
class Transform
{
public:
Transform getInverse()
{
Transform inv;
inv.m_matrix = m_matrix.getInverse();
return inv;
}
void lookAt(const Vector & eye,
const Vector & focus,
const Vector & up);
void translate(double x, double y, double z);
void translate(refptr<Vector> vec)
{
translate((*vec)[0], (*vec)[1], (*vec)[2]);
}
void rotate(double angle, double xv, double yv, double zv);
void rotate(double angle, refptr<Vector> vec)
{
rotate(angle, (*vec)[0], (*vec)[1], (*vec)[2]);
}
void scale(double xs, double ys, double zs);
void scale(refptr<Vector> vec)
{
scale((*vec)[0], (*vec)[1], (*vec)[2]);
}
Matrix & getMatrix() { return m_matrix; }
Vector transform_point(const Vector & v)
{
return m_matrix * v;
}
Vector transform_direction(const Vector & v)
{
return m_matrix % v;
}
Vector transform_normal(const Vector & v)
{
return (m_matrix % v).normalize();
}
Ray transform_ray(const Ray & r)
{
return Ray(m_matrix * r.getOrigin(), m_matrix % r.getDirection());
}
Transform operator*(const Transform & other) const
{
Transform t;
t.m_matrix = m_matrix * other.m_matrix;
return t;
}
protected:
Matrix m_matrix;
};
#endif

View File

@ -1,29 +0,0 @@
#include <stdlib.h> /* rand() */
#include <math.h>
#include <iostream>
#include "Vector.h"
const Vector Vector::X(1, 0, 0);
const Vector Vector::Y(0, 1, 0);
const Vector Vector::Z(0, 0, 1);
Vector Vector::randomVector()
{
double x, y, z;
do
{
x = 2.0 * rand() / RAND_MAX - 1.0;
y = 2.0 * rand() / RAND_MAX - 1.0;
z = 2.0 * rand() / RAND_MAX - 1.0;
} while (x*x + y*y + z*z > 1.0);
return Vector(x, y, z).normalize();
}
std::ostream & operator<<(std::ostream & out, const Vector & v)
{
out << "[" << v[0] << ", " << v[1] << ", " << v[2] << "]";
return out;
}

View File

@ -1,203 +0,0 @@
#ifndef VECTOR_H
#define VECTOR_H VECTOR_H
#include <math.h> /* sqrt() */
#include <iostream>
class Vector
{
public:
Vector()
{
m_array[0] = 0.0;
m_array[1] = 0.0;
m_array[2] = 0.0;
}
Vector(double x, double y, double z)
{
m_array[0] = x;
m_array[1] = y;
m_array[2] = z;
}
Vector & normalize()
{
double length = mag();
m_array[0] /= length;
m_array[1] /= length;
m_array[2] /= length;
return *this;
}
double mag() const
{
return sqrt(m_array[0] * m_array[0]
+ m_array[1] * m_array[1]
+ m_array[2] * m_array[2]);
}
double mag2() const
{
return m_array[0] * m_array[0]
+ m_array[1] * m_array[1]
+ m_array[2] * m_array[2];
}
double dist_to(const Vector & other) const
{
return (other - *this).mag();
}
Vector proj(const Vector & target) const
{
Vector target_normalized = target;
target_normalized.normalize();
return target_normalized * ((*this) % target_normalized);
}
Vector reflect(const Vector & target) const
{
return (*this) - target * (2 * dot(target));
}
/*
* from http://www.flipcode.com/archives/
* Reflections_and_Refraction_in_Raytracing.shtml
* target: normal vector of surface
* n1: refraction index of object we're coming from
* n2: refraction index of object we're going into
*/
Vector refract(const Vector & target, double n1, double n2) const
{
const double n = n1 / n2;
const double cosI = -dot(target);
const double sinT2 = n * n * (1.0 - cosI * cosI);
if (sinT2 > 1.0)
return Vector(0.0, 0.0, 0.0);
return (*this) * n + target * (n * cosI - sqrt(1.0 - sinT2));
}
Vector getPerpendicular() const
{
Vector t = *this;
t.normalize();
Vector p = t * Vector(0, 0, 1);
if (p.mag() <= 0.1)
{
p = t * Vector(1, 0, 0);
}
return p;
}
Vector mult(const Vector & v2) const
{
return Vector(
m_array[0] * v2.m_array[0],
m_array[1] * v2.m_array[1],
m_array[2] * v2.m_array[2]);
}
Vector div(const Vector & v2) const
{
return Vector(
m_array[0] / v2.m_array[0],
m_array[1] / v2.m_array[1],
m_array[2] / v2.m_array[2]);
}
Vector operator-() const
{
return Vector(
-m_array[0],
-m_array[1],
-m_array[2]);
}
/* Compute the dot-product of two vectors */
double dot(const Vector & v2) const
{
return m_array[0] * v2.m_array[0]
+ m_array[1] * v2.m_array[1]
+ m_array[2] * v2.m_array[2];
}
double operator%(const Vector & v2) const { return dot(v2); }
/* Compute the cross-product of two vectors */
Vector cross(const Vector & v2) const
{
return Vector(
m_array[1] * v2.m_array[2] - m_array[2] * v2.m_array[1],
m_array[2] * v2.m_array[0] - m_array[0] * v2.m_array[2],
m_array[0] * v2.m_array[1] - m_array[1] * v2.m_array[0]);
}
Vector operator*(const Vector & v2) const { return cross(v2); }
Vector operator+(const Vector & v2) const
{
return Vector(
m_array[0] + v2.m_array[0],
m_array[1] + v2.m_array[1],
m_array[2] + v2.m_array[2]);
}
Vector operator-(const Vector & v2) const
{
return Vector(
m_array[0] - v2.m_array[0],
m_array[1] - v2.m_array[1],
m_array[2] - v2.m_array[2]);
}
Vector operator*(double scale) const
{
return Vector(
m_array[0] * scale,
m_array[1] * scale,
m_array[2] * scale);
}
Vector operator/(double scale) const
{
return Vector(
m_array[0] / scale,
m_array[1] / scale,
m_array[2] / scale);
}
Vector & operator+=(const Vector & v2)
{
m_array[0] += v2.m_array[0];
m_array[1] += v2.m_array[1];
m_array[2] += v2.m_array[2];
return *this;
}
Vector & operator-=(const Vector & v2)
{
m_array[0] -= v2.m_array[0];
m_array[1] -= v2.m_array[1];
m_array[2] -= v2.m_array[2];
return *this;
}
double & operator[](int idx) { return m_array[idx]; }
double operator[](int idx) const { return m_array[idx]; }
static Vector randomVector();
static const Vector X;
static const Vector Y;
static const Vector Z;
protected:
double m_array[3];
};
std::ostream & operator<<(std::ostream & out, const Vector & v);
static inline Vector operator*(double d, const Vector & v) { return v * d; }
static inline Vector operator/(double d, const Vector & v) { return v / d; }
#endif

View File

@ -1,115 +0,0 @@
#ifndef REFPTR_H
#define REFPTR_H REFPTR_H
#include <stdlib.h> /* NULL */
template <typename T>
class refptr
{
public:
refptr<T>();
refptr<T>(T * ptr);
refptr<T>(const refptr<T> & orig);
refptr<T> & operator=(const refptr<T> & orig);
refptr<T> & operator=(T * ptr);
~refptr<T>();
T & operator*() const;
T * operator->() const;
bool isNull() const { return m_ptr == NULL; }
bool operator==(const refptr<T> & right) const;
bool operator!=(const refptr<T> & right) const;
private:
void cloneFrom(const refptr<T> & orig);
void destroy();
T * m_ptr;
int * m_refCount;
};
template <typename T> refptr<T>::refptr()
{
m_ptr = NULL;
m_refCount = NULL;
}
template <typename T> refptr<T>::refptr(T * ptr)
{
m_ptr = ptr;
m_refCount = new int;
*m_refCount = 1;
}
template <typename T> refptr<T>::refptr(const refptr<T> & orig)
{
cloneFrom(orig);
}
template <typename T> refptr<T> & refptr<T>::operator=(const refptr<T> & orig)
{
destroy();
cloneFrom(orig);
return *this;
}
template <typename T> refptr<T> & refptr<T>::operator=(T * ptr)
{
destroy();
m_ptr = ptr;
m_refCount = new int;
*m_refCount = 1;
return *this;
}
template <typename T> void refptr<T>::cloneFrom(const refptr<T> & orig)
{
this->m_ptr = orig.m_ptr;
this->m_refCount = orig.m_refCount;
if (m_refCount != NULL)
(*m_refCount)++;
}
template <typename T> refptr<T>::~refptr()
{
destroy();
}
template <typename T> void refptr<T>::destroy()
{
if (m_refCount != NULL)
{
if (*m_refCount <= 1)
{
delete m_ptr;
delete m_refCount;
}
else
{
(*m_refCount)--;
}
}
}
template <typename T> T & refptr<T>::operator*() const
{
return *m_ptr;
}
template <typename T> T * refptr<T>::operator->() const
{
return m_ptr;
}
template <typename T> bool refptr<T>::operator==(const refptr<T> & right) const
{
return m_ptr == right.m_ptr;
}
template <typename T> bool refptr<T>::operator!=(const refptr<T> & right) const
{
return m_ptr != right.m_ptr;
}
#endif