add sections about demos to README pyrit
authorRadek Brich <radek.brich@devl.cz>
Mon, 19 May 2008 22:59:04 +0200
branchpyrit
changeset 98 64638385798a
parent 97 2a853d284a6a
child 99 f3abdaa2e8fb
add sections about demos to README update doxygen comments
DEVNOTES
README
TODO
demos/dragon.py
demos/render_nff.py
include/common.h
include/container.h
include/kdtree.h
include/material.h
include/octree.h
include/pixmap.h
include/raytracer.h
include/raytracermodule.h
include/scene.h
include/shapes.h
include/simd.h
models/lwo/Nissan300ZX.txt
src/raytracermodule.cc
--- a/DEVNOTES	Thu May 15 19:15:57 2008 +0200
+++ b/DEVNOTES	Mon May 19 22:59:04 2008 +0200
@@ -1,19 +1,3 @@
-Classes
--------
-
-vector.h -- vector of three scalars, also used for colour
-matrix.h -- matrix class, currently not used
-quaternion.h -- quaternion class for camera rotation
-
-container.h  -- container for shapes, base class for octree and kd-tree
-octree.h -- Octree space subdivision structure for acceleration of ray-shape intersection search
-kdtree.h  -- KdTree space subdivision structure
-
-scene.h -- scene objects: Ray, Light, Camera and shapes
-raytracer.h -- ray tracer class
-common.h -- Float definition (float/double) and some helper functions
-
-
 Container Usage
 ---------------
 (Container|Octree|KdTree) top;
--- a/README	Thu May 15 19:15:57 2008 +0200
+++ b/README	Mon May 19 22:59:04 2008 +0200
@@ -15,8 +15,6 @@
 /tests    -- test programs for classes
 /tools    -- auxiliary programs
 
-Classes organization throughout header files is explained in DEVNOTES.
-
 
 Building
 --------
@@ -37,7 +35,7 @@
 -----------------------
 Not all models are included in distribution. To download the large
 Stanford models, type 'scons download-models', which will download
-end extract the archives to appropriate location.
+and extract the archives to appropriate location.
 
 The download script uses 'tar' and 'wget' utilities.
 
@@ -48,13 +46,79 @@
 
 Pthreads
 --------
-Threads can be used to render rays paralelly. Arbitrary number
+Threads are used to render rays paralelly. Arbitrary number
 of threads can be used.
 
 For Windows, get Pthreads library here:
 http://sources.redhat.com/pthreads-win32/
 
 
+Python Demos
+------------
+All demos render images and write the result to PNG file
+named with same base name as the script.
+Scene is constructed using classes imported from pyrit
+Python module.
+
+boxes.py
+        512 cubes with reflections and refractions
+        4x oversampling, two lights, octree
+
+bunny.py
+        glass bunny, ~70k polygons
+        4x oversampling, two lights, kd-tree
+
+car.py
+        low poly car model, LWOB format
+        9x oversampling, two lights, kd-tree
+
+spheres_shadow.py
+        three spheres, sharp shadows
+        4x oversampling, two lights, kd-tree
+
+spheres_ao.py
+        three spheres, ambient occlussion
+
+spheres_glass.py
+        row of glass spheres
+        4x oversampling, three lights, kd-tree
+
+render_nff.py [input.nff] [output.png]
+        renders nff files (http://tog.acm.org/resources/SPD/)
+        reads stdin if no args given
+
+triangles_*.py
+        older examples using OBJ file format
+
+
+C++ Demos
+---------
+Compiled interactive demos. Camera can move freely in the scene.
+
+realtime.exe
+        one hundred spheres with reflections
+
+realtime_bunny.exe
+        bunny model (it loads silently, so be patient)
+
+spheres_shadow.exe
+        "interactive" version of spheres_shadow.py
+
+textures.exe
+        demo of different texture mappings
+
+
+Control keys:
+
+        Up, Down, Left, Right   look around
+        w/s                     forward, backward
+        c                       print camera coordinates
+
+        spheres_shadow demo supports also:
+        r/t, f/g, v/b           move the light (-x/+x, -y/+y, -z/+z)
+        z/x                     change camera focal length (-/+)
+
+
 License
 -------
 This software is published under terms of MIT license.
--- a/TODO	Thu May 15 19:15:57 2008 +0200
+++ b/TODO	Mon May 19 22:59:04 2008 +0200
@@ -8,7 +8,6 @@
  * PlanarMap should allow to choose normal axis
  * Container should implement Shape interface to allow building hierarchies
  * Container should allow local space transformations
- * generalization: Camera "shader" (ray generator), surface shader and maybe light & background shaders
- * put everything into a namespace
  * stochastic oversampling
  * absorbtion of refracted rays in dense materials (can be computed using shape distance and some 'absorbance' constant)
+ * put everything into a namespace
--- a/demos/dragon.py	Thu May 15 19:15:57 2008 +0200
+++ b/demos/dragon.py	Mon May 19 22:59:04 2008 +0200
@@ -25,6 +25,7 @@
 top.optimize()
 
 sampler = DefaultSampler(800, 600)
+sampler.setOversample(1)
 rt.setSampler(sampler)
 rt.render()
 sampler.getPixmap().writePNG('dragon.png')
--- a/demos/render_nff.py	Thu May 15 19:15:57 2008 +0200
+++ b/demos/render_nff.py	Mon May 19 22:59:04 2008 +0200
@@ -1,8 +1,12 @@
 #!/usr/bin/python
 
-# read nff data from standart input and render image to render_nff.png
-# see http://tog.acm.org/resources/SPD/
-# cylinders are not implemented
+# Usage: render_nff.py [scene.nff] [output.png]
+# reads scene from nff file and render it to PNG file
+# if no output file name is given, it makes one from input name
+# reads from stdin by default
+
+# see http://tog.acm.org/resources/SPD/ for nff format description
+# cylinders are currently not implemented
 
 from pyrit import *
 from math import pi
--- a/include/common.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/common.h	Mon May 19 22:59:04 2008 +0200
@@ -59,18 +59,27 @@
 #define NORETURN __attribute__((noreturn))
 #endif
 
-/* verbosity level:
-0: only errors and warnings (E, W)
-1: major status messages (*)
-2: minor status, progress (-)
-3: debug messages (D)
-4: thread debug
-default = 2
-*/
+/**
+ * verbosity level
+ *
+ * - 0: only errors and warnings (E, W)
+ * - 1: major status messages (*)
+ * - 2: minor status, progress (-)
+ * - 3: debug messages (D)
+ * - 4: thread debug
+ *
+ * default is 2
+ */
 extern int pyrit_verbosity;
 
+/**
+ * print status or debugging message
+ * @param[in] vlevel    verbosity level of the message
+ * @see pyrit_verbosity
+ */
 void dbgmsg(const int vlevel, const char *format, ...);
 
+/** template for minimum of three numbers */
 template<typename Type> const Type &min3(const Type &a, const Type &b, const Type &c)
 {
 	if (a <= b)
@@ -89,6 +98,7 @@
 	}
 }
 
+/** template for maximum of three numbers */
 template<typename Type> const Type &max3(const Type &a, const Type &b, const Type &c)
 {
 	if (a >= b)
@@ -107,6 +117,7 @@
 	}
 }
 
+/** trim whitespace from beginning and end of string */
 inline void trim(string& s)
 {
 	const char *ws = " \n";
--- a/include/container.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/container.h	Mon May 19 22:59:04 2008 +0200
@@ -35,7 +35,10 @@
 using namespace std;
 
 /**
- * general container
+ * General container for shapes.
+ *
+ * Does very simple intersection test:
+ * all shapes are tested and the nearest intersection is returned.
  */
 class Container
 {
@@ -47,21 +50,36 @@
 	Container(): bbox(), shapes() {};
 	virtual ~Container() {};
 
+	/** add pointer to shape to the container */
 	virtual void addShape(const Shape* aShape);
 	//void addShapeNoExtend(const Shape* aShape) { shapes.push_back(aShape); };
+
+	/**
+	 * find nearest intersection with shapes in container
+	 * @param[in] origin_shape  this shape should be avoided from the test
+	 * @param[in] ray           the ray
+	 * @param[out] nearest_distance  the nearest allowd distance of intersection;
+	 *                               it is updated when closer intersection is found
+	 * @return intersected shape or NULL if no intersection was found
+	 */
 	virtual const Shape *nearest_intersection(const Shape *origin_shape, const Ray &ray,
 		Float &nearest_distance);
 
-	virtual void optimize() {};
-
-	ShapeList & getShapes() { return shapes; };
-
-	virtual ostream & dump(ostream &st) const;
-
+	/** intersect with whole ray packet */
 #ifndef NO_SIMD
 	virtual void packet_intersection(const Shape* const* origin_shapes, const RayPacket &rays,
 		Float *nearest_distances, const Shape** nearest_shapes);
 #endif
+
+	/** build acceleration structures */
+	virtual void optimize() {};
+
+	/** get reference to the shape list */
+	ShapeList & getShapes() { return shapes; };
+
+	/** write textual representation of the acceleration structure
+	 * and shapes in list to the stream */
+	virtual ostream & dump(ostream &st) const;
 };
 
 #endif
--- a/include/kdtree.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/kdtree.h	Mon May 19 22:59:04 2008 +0200
@@ -55,20 +55,27 @@
 	KdNode() { shapes = new ShapeList(); assert((flags & 3) == 0); setLeaf(); };
 	~KdNode();
 
+	/** mark this node as leaf */
 	void setLeaf() { flags |= 3; };
 	bool isLeaf() const { return (flags & 3) == 3; };
 
+	/** set split axis (this removes leaf flag) */
 	void setAxis(int aAxis) { flags &= ~3; flags |= aAxis; };
 	int getAxis() const { return flags & 3; };
 
+	/** set split position (leaf) */
 	void setSplit(Float aSplit) { split = aSplit; };
 	const Float& getSplit() const { return split; };
 
+	/** set children (non-leaf) */
 	void setChildren(KdNode *node) { children = node; assert((flags & 3) == 0); };
 	KdNode* getLeftChild() const { return (KdNode*)((size_t)children & ~3); };
 	KdNode* getRightChild() const { return (KdNode*)(((size_t)children & ~3) + 16); };
 
+	/** get shape list of the leaf node*/
 	ShapeList* getShapes() const { return (ShapeList*)((size_t)shapes & ~3); };
+
+	/** add shape to shape list */
 	void addShape(const Shape* aShape) { getShapes()->push_back(aShape); };
 };
 
@@ -85,9 +92,14 @@
 	void recursive_build(KdNode *node, const BBox &bbox, int maxdepth);
 	void recursive_load(istream &st, KdNode *node);
 public:
+	/** default constructor, maximum depth is set to 32 */
 	KdTree(): Container(), mempool(64), root(NULL), max_depth(32), built(false) {};
+
+	/** constructor which allows to se maximum tree depth (cannot be changed later) */
 	KdTree(int maxdepth): Container(), mempool(64), root(NULL), max_depth(maxdepth), built(false) {};
 	~KdTree() { if (root) delete root; };
+
+	/** add shape pointer to the container */
 	void addShape(const Shape* aShape) { Container::addShape(aShape); built = false; };
 	const Shape *nearest_intersection(const Shape *origin_shape, const Ray &ray,
 		Float &nearest_distance);
@@ -96,6 +108,8 @@
 		Float *nearest_distances, const Shape **nearest_shapes);
 #endif
 	void optimize() { build(); };
+
+	/** build the tree (alias for 'optimize') */
 	void build();
 	bool isBuilt() const { return built; };
 	KdNode *getRootNode() const { return root; };
--- a/include/material.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/material.h	Mon May 19 22:59:04 2008 +0200
@@ -44,6 +44,8 @@
 {
 public:
 	virtual ~Texture() {};
+
+	/** evaluate texture colour in the point of space */
 	virtual Colour evaluate(const Vector &point) = 0;
 };
 
@@ -54,6 +56,8 @@
 {
 public:
 	virtual ~ColourMap() {};
+
+	/** map float value to colour */
 	virtual Colour map(const Float &val) = 0;
 };
 
@@ -107,9 +111,23 @@
 	Vector center;
 	Float invsize;
 public:
+	/**
+	 * texture map constructor
+	 * @param[in] acenter  central point of texture mapping
+	 * @param[in] size     Size of the texture.
+	 *                     One world space unit is mapped to one texture size
+	 *                     divided by this number.
+	 */
 	TextureMap(const Vector &acenter, const Float &size):
 		center(acenter), invsize(1.0f/size) {};
 	virtual ~TextureMap() {};
+
+	/**
+	 * map 3D space point to 2D u,v coordinates
+	 * @param[in] point  a point in 3D space
+	 * @param[out] u     horizontal texture coordinate
+	 * @param[out] v     vertical texture coordinate
+	 */
 	virtual void map(const Vector &point, Float &u, Float &v) const = 0;
 };
 
@@ -309,12 +327,24 @@
 		refract_index = 1.3f;
 	}
 
+	/** set Phong parameters */
 	void setPhong(const Float amb, const Float dif, const Float spec, const Float shin)
 		{ ambient = amb; diffuse = dif; specular = spec; shininess = shin; };
+
+	/** set fraction of light to be reflected */
 	void setReflectivity(const Float refl) { reflectivity = refl; };
+
+	/** set fraction of light to be refracted
+	 * @param[in] trans  the transmissivity amount
+	 * @param[in] rinde  index of refraction
+	 */
 	void setTransmissivity(const Float trans, const Float rindex)
 		{ transmissivity = trans; refract_index = rindex; };
+
+	/** allow triangle smoothing */
 	void setSmooth(int sm) { smooth = sm; };
+
+	/** set the texture */
 	void setTexture(Texture *tex) { texture = tex; };
 };
 
--- a/include/octree.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/octree.h	Mon May 19 22:59:04 2008 +0200
@@ -77,14 +77,23 @@
 	const int max_depth;
 	bool built;
 public:
+	/** default constructor,
+	 * maximum depth of tree is set to 10 */
 	Octree() : Container(), root(NULL), max_depth(10), built(false) {};
+
+	/** constructor
+	 * @param[in] maxdepth	maximum depth of the tree */
 	Octree(int maxdepth) : Container(), root(NULL), max_depth(maxdepth), built(false) {};
 	~Octree() { if (root) delete root; };
 	void addShape(const Shape* aShape) { Container::addShape(aShape); built = false; };
 	const Shape *nearest_intersection(const Shape *origin_shape, const Ray &ray,
 		Float &nearest_distance);
 	void optimize() { build(); };
+
+	/** build the octree
+	 * this is alias of optimize() */
 	void build();
+
 	void save(ostream &str, OctreeNode *node = NULL) {};
 	void load(istream &str, OctreeNode *node = NULL) {};
 };
--- a/include/pixmap.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/pixmap.h	Mon May 19 22:59:04 2008 +0200
@@ -67,11 +67,19 @@
 
 	void setData(Float *afdata, int aw, int ah)
 		{ fdata = afdata; w = aw; h = ah; };
+
+	/** get colour of pixel x,y */
 	const Colour &get(int x, int y) const { return data[y*w + x]; };
 	const int &getWidth() const { return w; };
 	const int &getHeight() const { return h; };
+
+	/** get pixmap data as array of floats */
 	Float*& getFloatData() { return fdata; };
+
+	/** get pixmap data as array of chars */
 	unsigned char *getCharData() const;
+
+	/** write pixmap data to PNG file */
 	int writePNG(const char *fname) const;
 };
 
--- a/include/raytracer.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/raytracer.h	Mon May 19 22:59:04 2008 +0200
@@ -42,26 +42,49 @@
  */
 class Raytracer
 {
-	Container *top;
-	Sampler *sampler;
-	Camera *camera;
-	vector<Light*> lights;
-	Colour bg_colour;
+	Container *top;    /**< container with shapes */
+	Sampler *sampler;  /**< active sampler */
+	Camera *camera;    /**< active camera */
+	vector<Light*> lights; /**< array of lights in the scene */
+	Colour bg_colour;  /**< background colour */
+
+	/* ambient occlussion parameters */
 	Float ao_distance, ao_angle;
 	int ao_samples;
-	int num_threads;
-	int max_depth;
-	bool use_packets;
 
+	int num_threads;  /**< number of threads to use for rendering */
+	int max_depth;    /**< maximum depth of recursion */
+	bool use_packets; /**< allow ray packet tracing */
+
+	/* private helper variables */
 	Sample *sample_queue;
 	int sample_queue_pos, sample_queue_size, sample_queue_count;
 	bool end_of_samples;
 	pthread_mutex_t sample_queue_mutex, sampler_mutex;
 	pthread_cond_t sample_queue_cond, worker_ready_cond;
 
+	/**
+	 * Hammersley spherical point distribution function
+	 * http://www.cse.cuhk.edu.hk/~ttwong/papers/udpoint/udpoints.html
+	 * @param[in] i   sample index
+	 * @param[in] n   number of samples
+	 * @param[in] extent   angle of dispersion
+	 * @param[in] normal   central direction vector
+	 */
 	Vector SphereDistribute(int i, int n, Float extent, const Vector &normal);
+
+	/**
+	 * shader implementing Phong lighting model
+	 * @param[in] P    point of intersection
+	 * @param[in] N    normal in intersect. point
+	 * @param[in] R    direction of reflected ray
+	 * @param[in] V    direction to the viewer
+	 * @return colour of the surface
+	 */
 	Colour PhongShader(const Shape *shape,
 		const Vector &P, const Vector &N, const Vector &V);
+
+	/** light scattering function */
 	void lightScatter(const Ray &ray, const Shape *shape, int depth,
 		const Vector &P, const Vector &normal, bool from_inside, Colour &col);
 
@@ -71,6 +94,7 @@
 	void raytracePacket(RayPacket &rays, Colour *results);
 #endif
 
+	/** main function of the ray tracing worker */
 	NORETURN static void *raytrace_worker(void *d);
 
 public:
@@ -90,21 +114,40 @@
 		pthread_cond_destroy (&worker_ready_cond);
 	}
 
+	/** start the rendering process */
 	void render();
+
+	/** ray trace one ray */
 	Colour raytrace(Ray &ray, int depth, const Shape *origin_shape);
+
+	/** add shape to container */
 	void addShape(Shape *shape) { top->addShape(shape); };
+
+	/** add light to scene */
 	void addLight(Light *light) { lights.push_back(light); };
+
+	/** set active sampler */
 	void setSampler(Sampler *sampl) { sampler = sampl; };
 	Sampler *&getSampler() { return sampler; };
+
+	/** set active camera */
 	void setCamera(Camera *cam) { camera = cam; };
 	Camera *&getCamera() { return camera; };
+
+	/** set active container */
 	void setTop(Container *atop) { top = atop; };
 	Container *&getTop() { return top; };
 
+	/** set background colour */
 	void setBgColour(const Colour &bg) { bg_colour = bg; };
+
+	/** set maximum depth of recursion */
 	void setMaxDepth(int newdepth) { max_depth = newdepth; };
 
+	/** set ambient occlusion parameters */
 	void ambientOcclusion(int samples, Float distance, Float angle);
+
+	/** set number of threads to use for rendering */
 	void setThreads(int num) { num_threads = num; };
 };
 
--- a/include/raytracermodule.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/raytracermodule.h	Mon May 19 22:59:04 2008 +0200
@@ -1,5 +1,6 @@
-/*
- * raytracermodule.h: raytracer module for Python
+/**
+ * @file  raytracermodule.h
+ * @brief Ray tracer module for Python
  *
  * This file is part of Pyrit Ray Tracer.
  *
--- a/include/scene.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/scene.h	Mon May 19 22:59:04 2008 +0200
@@ -76,7 +76,7 @@
 #endif
 
 /**
- * General camera
+ * Standard ray tracing camera
  */
 class Camera
 {
@@ -84,8 +84,12 @@
 	Float F;
 public:
 	Camera(): eye(0,0,10), p(0,0,-1), u(-1,0,0), v(0,1,0), F(2*tan(PI/8)) {};
+
+	/** Position + p,u,v constructor */
 	Camera(const Vector &C, const Vector &ap, const Vector &au, const Vector &av):
 		eye(C), p(ap), u(au), v(av), F(2*tan(PI/8)) {};
+
+	/** Look-at constructor */
 	Camera(const Vector &from, const Vector &lookat, const Vector &up):
 		eye(from), F(2*tan(PI/8))
 	{
@@ -104,21 +108,37 @@
 	const Vector &getu() const { return u; };
 	const Vector &getv() const { return v; };
 	const Float &getF() const { return F; };
+
 	void setEye(const Vector &aeye) { eye = aeye; };
 	void setp(const Vector &ap) { p = ap; };
 	void setu(const Vector &au) { u = au; };
 	void setv(const Vector &av) { v = av; };
+
+	/** set "screen plane" size
+	 * @param[in] F   height of the screen plane */
 	void setF(const Float &aF) { F = aF; };
+
+	/** set camera's angle of view (in radians) */
 	void setAngle(const Float angle) { F = 2*tan(angle/2); };
+
+	/** rotate camera using a quaternion */
 	void rotate(const Quaternion &q);
+
+	/** translate the camera in its direction
+	 * @param[in] fw	size of forward step
+	 * @param[in] left	size of left step
+	 * @param[in] up	size of up step
+	 */
 	void move(const Float fw, const Float left, const Float up);
 
+	/** make the ray from screen sample according the camera's parameters */
 	const Ray makeRay(const Sample &samp) const
 	{
 		Vector dir = normalize(p - (u*samp.x + v*samp.y)*F);
 		return Ray(eye, dir);
 	};
 
+	/** same as makeRay but for ray packet */
 #ifndef NO_SIMD
 	void makeRayPacket(const Sample *samples, RayPacket &rays) const
 	{
@@ -188,6 +208,8 @@
 		pos(Vector(0,0,0)), colour(Colour(1,1,1)), cast_shadows(true) {};
 	Light(const Vector &position, const Colour &acolour):
 		pos(position), colour(acolour), cast_shadows(true) {};
+
+	/** allow shadows from this light */
 	void castShadows(int cast) { cast_shadows = cast; };
 };
 
@@ -206,7 +228,17 @@
 	Float w() const { return H.x-L.x; };
 	Float h() const { return H.y-L.y; };
 	Float d() const { return H.z-L.z; };
+
+	/**
+	 * intersect ray with the bounding box
+	 * @param[in] ray	the ray
+	 * @param[out] a	distance of first intersection
+	 * @param[out] b	distance of second intersection
+	 * @return true if ray intersects bbox
+	 */
 	bool intersect(const Ray &ray, Float &a, Float &b) const;
+
+	/** same as intersect() but for ray packets */
 #ifndef NO_SIMD
 	mfloat4 intersect_packet(const RayPacket &rays, mfloat4 &a, mfloat4 &b) const;
 #endif
--- a/include/shapes.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/shapes.h	Mon May 19 22:59:04 2008 +0200
@@ -44,7 +44,7 @@
 #endif
 
 /**
- * shape
+ * abstract shape class
  */
 class Shape
 {
@@ -54,9 +54,18 @@
 	Shape() {};
 	virtual ~Shape() {};
 
-	// first intersection point
+	/**
+	 * intersect ray with sphere
+	 * @param[in] ray	the ray
+	 * @param[in] dist	maximum allowed distance of intersection
+	 * @param[out] dist	distance of the intersection if found, unchanged otherwise
+	 * @return true if ray intersects the sphere
+	 */
 	virtual bool intersect(const Ray &ray, Float &dist) const = 0;
 
+	/**
+	 * same as intersect, but for ray packets
+	 */
 #ifndef NO_SIMD
 	virtual mfloat4 intersect_packet(const RayPacket &rays, mfloat4 &dists) const
 	{
@@ -69,17 +78,19 @@
 	};
 #endif
 
-	// all intersections (only for CSG)
+	/** get all intersections -- not needed nor used currently */
 	virtual bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const = 0;
 
-	// intersection with AABB
+	/** test intersection with bounding box */
 	virtual bool intersect_bbox(const BBox &bbox) const = 0;
 
-	// normal at point P
+	/** get surface normal at point P */
 	virtual const Vector normal(const Vector &P) const = 0;
 
+	/** get bounding box of this shape */
 	virtual BBox get_bbox() const = 0;
 
+	/** write textual representation of the shape to stream */
 	virtual ostream & dump(ostream &st) const = 0;
 };
 
@@ -103,17 +114,20 @@
 		center(acenter), radius(aradius),
 		sqr_radius(aradius*aradius), inv_radius(1.0f/aradius)
 		{ material = amaterial; }
+
 	bool intersect(const Ray &ray, Float &dist) const;
+#ifndef NO_SIMD
+	mfloat4 intersect_packet(const RayPacket &rays, mfloat4 &dists) const;
+#endif
 	bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const;
 	bool intersect_bbox(const BBox &bbox) const;
 	const Vector normal(const Vector &P) const { return (P - center) * inv_radius; };
 	BBox get_bbox() const;
+
 	const Vector getCenter() const { return center; };
 	Float getRadius() const { return radius; };
+
 	ostream & dump(ostream &st) const;
-#ifndef NO_SIMD
-	mfloat4 intersect_packet(const RayPacket &rays, mfloat4 &dists) const;
-#endif
 };
 
 /**
@@ -132,16 +146,18 @@
 		material = amaterial;
 	};
 	bool intersect(const Ray &ray, Float &dist) const;
+#ifndef NO_SIMD
+	mfloat4 intersect_packet(const RayPacket &rays, mfloat4 &dists) const;
+#endif
 	bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const { return false; };
 	bool intersect_bbox(const BBox &bbox) const;
 	const Vector normal(const Vector &P) const;
 	BBox get_bbox() const { return BBox(L, H); };
+
 	const Vector getL() const { return L; };
 	const Vector getH() const { return H; };
+
 	ostream & dump(ostream &st) const;
-#ifndef NO_SIMD
-	mfloat4 intersect_packet(const RayPacket &rays, mfloat4 &dists) const;
-#endif
 };
 
 /**
@@ -219,17 +235,21 @@
 	Triangle() {};
 	Triangle(Vertex *aA, Vertex *aB, Vertex *aC, Material *amaterial);
 	bool intersect(const Ray &ray, Float &dist) const;
+#if !defined(NO_SIMD) && defined(TRI_BARI_PRE)
+	mfloat4 intersect_packet(const RayPacket &rays, mfloat4 &dists) const;
+#endif
 	bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const {return false;};
 	bool intersect_bbox(const BBox &bbox) const;
 	const Vector normal(const Vector &P) const { return (material->smooth ? smooth_normal(P) : N); };
+	BBox get_bbox() const;
+
+	/** get real normal of the triangle */
 	const Vector getNormal() const { return N; };
-	BBox get_bbox() const;
+
 	ostream & dump(ostream &st) const;
-#if !defined(NO_SIMD) && defined(TRI_BARI_PRE)
-	mfloat4 intersect_packet(const RayPacket &rays, mfloat4 &dists) const;
-#endif
 };
 
+/** template for triangle arrays, currently not used */
 template <class T> class Array
 {
 	T *array;
--- a/include/simd.h	Thu May 15 19:15:57 2008 +0200
+++ b/include/simd.h	Mon May 19 22:59:04 2008 +0200
@@ -72,11 +72,13 @@
 #define mShuffle3 _MM_SHUFFLE(3,3,3,3)
 #define mshuffle _mm_shuffle_ps
 
+/** select values from a and b according to mask (a if mask is 1, b if mask is 0) */
 inline const mfloat4 mselect(const mfloat4& mask, const mfloat4& a, const mfloat4& b)
 {
 	return _mm_or_ps(_mm_and_ps(mask, a), _mm_andnot_ps(mask, b));
 }
 
+/** fast power function */
 inline const mfloat4 mfastpow(const mfloat4& base, const mfloat4& exponent)
 {
     __m128 denom = _mm_mul_ps(exponent, base);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/models/lwo/Nissan300ZX.txt	Mon May 19 22:59:04 2008 +0200
@@ -0,0 +1,2 @@
+This model comes from DMI Car 3D Models collection.
+http://dmi.chez-alice.fr/models1.html
--- a/src/raytracermodule.cc	Thu May 15 19:15:57 2008 +0200
+++ b/src/raytracermodule.cc	Mon May 19 22:59:04 2008 +0200
@@ -914,8 +914,9 @@
 }
 
 
-//=========================== Vertex Object (abstract) ===========================
+//=========================== Vertex Object ===========================
 
+static PyObject *Vertex_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static void Vertex_Destructor(PyObject* self);
 
 static PyMethodDef VertexMethods[] = {
@@ -935,6 +936,32 @@
 	0                            /* tp_init */
 );
 
+static PyObject* Vertex_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	VertexObject *v;
+	static char *kwdlist[] = {"vector", NULL};
+	PyObject *TVer = NULL;
+	Float vx, vy, vz;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O", kwdlist, &TVer))
+		return NULL;
+
+	if (TVer->ob_type == &VertexType)
+	{
+		v = PyObject_New(VertexObject, &VertexType);
+		v->vertex = new Vertex(*((VertexObject*)TVer)->vertex);
+	}
+	else
+	{
+		if (!PyArg_ParseTuple(TVer, "fff", &vx, &vy, &vz))
+			return NULL;
+
+		v = PyObject_New(VertexObject, &VertexType);
+		v->vertex = new Vertex(Vector(vx, vy, vz));
+	}
+	return (PyObject*)v;
+}
+
 static void Vertex_Destructor(PyObject* self)
 {
 	delete ((VertexObject *)self)->vertex;