--- /dev/null
+#include <msp/core/application.h>
+#include <msp/core/getopt.h>
+#include <msp/core/inttypes.h>
+#include <msp/geometry/loader.h>
+#include <msp/io/buffered.h>
+#include <msp/io/print.h>
+
+using namespace std;
+using namespace Msp;
+
+class RayTracer: public RegisteredApplication<RayTracer>
+{
+private:
+ Geometry::Shape<double, 3> *shape;
+ unsigned width;
+ unsigned height;
+ string filename;
+ UInt8 *pixels;
+
+public:
+ RayTracer(int, char **);
+ virtual ~RayTracer();
+
+ virtual int main();
+private:
+ void load_shape();
+};
+
+
+RayTracer::RayTracer(int argc, char **argv):
+ shape(0),
+ width(500),
+ height(500),
+ pixels(new UInt8[width*height])
+{
+ GetOpt getopt;
+ getopt.add_option('w', "width", width, GetOpt::REQUIRED_ARG);
+ getopt.add_option('h', "height", height, GetOpt::REQUIRED_ARG);
+ getopt.add_argument("filename", filename, GetOpt::REQUIRED_ARG);
+ getopt(argc, argv);
+}
+
+RayTracer::~RayTracer()
+{
+ delete shape;
+ delete[] pixels;
+}
+
+int RayTracer::main()
+{
+ load_shape();
+
+ for(unsigned y=0; y<height; ++y)
+ {
+ double yf = 1.0-y*2.0/height;
+ for(unsigned x=0; x<width; ++x)
+ {
+ double xf = x*2.0/width-1.0;
+ Geometry::Ray<double, 3> ray(LinAl::Vector<double, 3>(0, 0, 5), LinAl::Vector<double, 3>(xf, yf, -2));
+ Geometry::SurfacePoint<double, 3> points[4];
+ unsigned count = shape->get_intersections(ray, points, 4);
+ UInt8 *pixel = pixels+y*width+x;
+ if(count)
+ *pixel = 255*(0.2+max(dot(points[0].normal, LinAl::Vector<double, 3>(0, 0, 1)), 0.0)*0.8);
+ else
+ *pixel = 0;
+ }
+ }
+
+ IO::Buffered cout_buf(IO::cout);
+ IO::print(cout_buf, "P2\n");
+ IO::print(cout_buf, "%d %d\n", width, height);
+ IO::print(cout_buf, "255\n");
+
+ for(unsigned y=0; y<height; ++y)
+ {
+ for(unsigned x=0; x<width; ++x)
+ IO::print(cout_buf, "%d ", pixels[y*width+x]);
+ IO::print(cout_buf, "\n");
+ }
+
+ return 0;
+}
+
+void RayTracer::load_shape()
+{
+ IO::BufferedFile in(filename);
+ DataFile::Parser parser(in, filename);
+ Geometry::Loader<double, 3> loader;
+ loader.load(parser);
+ shape = loader.get_shape().clone();
+}