Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
5ff83f6734 | |||
6e04286cc2 | |||
f8fc3518dd | |||
8c109a741b | |||
5b734c315d | |||
8170593d56 | |||
e6c943aab4 | |||
5b449506cb | |||
42e2508766 | |||
9f39cddc24 | |||
4c57df0774 | |||
c8658e5e00 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
fart
|
||||
/fart
|
||||
*.bmp
|
||||
*.png
|
||||
/.propane*
|
||||
/.rscons*
|
||||
/build/
|
||||
|
40
Rsconscript
40
Rsconscript
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
54
src/fart/bfile.d
Normal 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
45
src/fart/color.d
Normal 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
18
src/fart/crc32.d
Normal 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
35
src/fart/hton.d
Normal 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
27
src/fart/main.d
Normal 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
158
src/fart/png.d
Normal 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
190
src/fart/vector.d
Normal 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));
|
||||
}
|
130
src/main/BMP.cc
130
src/main/BMP.cc
@ -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;
|
||||
}
|
@ -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();
|
||||
};
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -1,7 +0,0 @@
|
||||
|
||||
#include "PointLight.h"
|
||||
|
||||
PointLight::PointLight()
|
||||
: Light()
|
||||
{
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
111
src/main/Scene.h
111
src/main/Scene.h
@ -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
|
||||
|
345
src/main/fart.cc
345
src/main/fart.cc
@ -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;
|
||||
}
|
@ -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()));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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];
|
||||
|
||||
%%
|
@ -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);
|
||||
}
|
@ -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
22
src/sceneparser.propane
Normal 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;
|
@ -1,9 +0,0 @@
|
||||
|
||||
#include "BoolShape.h"
|
||||
|
||||
void BoolShape::setMaterial(refptr<Material> material)
|
||||
{
|
||||
m_material = material;
|
||||
m_shape1->setMaterial(material);
|
||||
m_shape2->setMaterial(material);
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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"
|
@ -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 */
|
@ -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;
|
||||
}
|
132
src/util/Color.h
132
src/util/Color.h
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user