added Python binding for material.h classes pyrit
authorRadek Brich <radek.brich@devl.cz>
Thu, 15 May 2008 00:07:25 +0200
branchpyrit
changeset 96 9eb71e76c7fd
parent 95 ca7d4c665531
child 97 2a853d284a6a
added Python binding for material.h classes added raytracermodule.h header file for declarations updated car.py demo added texture.py demo (based on spheres_glass.py) all remaining 'centre' changed to more common 'center' added some more const's to material.h
README
TODO
demos/SConscript
demos/car.py
demos/demo_PIL.py
demos/render_nff.py
demos/spheres_ao.py
demos/spheres_glass.py
demos/spheres_shadow.py
demos/texture.py
include/material.h
include/pixmap.h
include/raytracermodule.h
src/raytracermodule.cc
--- a/README	Sat May 10 14:29:37 2008 +0200
+++ b/README	Thu May 15 00:07:25 2008 +0200
@@ -8,6 +8,7 @@
 /build    -- output directory for binaries and other generated files
 /ccdemos  -- ray tracer demos in C++
 /demos    -- ray tracer demos in Python
+/docs     -- Doxygen generated documentation
 /include  -- header files
 /models   -- common models for use by demos
 /src      -- ray tracing library source code
@@ -50,7 +51,7 @@
 Threads can be used to render rays paralelly. Arbitrary number
 of threads can be used.
 
-For Windows, get pthreads library here:
+For Windows, get Pthreads library here:
 http://sources.redhat.com/pthreads-win32/
 
 
--- a/TODO	Sat May 10 14:29:37 2008 +0200
+++ b/TODO	Thu May 15 00:07:25 2008 +0200
@@ -4,7 +4,8 @@
 
 Future Plans
 ============
- * Python binding for material.h classes
+ * UV texturing
+ * 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
--- a/demos/SConscript	Sat May 10 14:29:37 2008 +0200
+++ b/demos/SConscript	Thu May 15 00:07:25 2008 +0200
@@ -7,7 +7,7 @@
 	'spheres_ao.py', 'spheres_glass.py', 'spheres_shadow.py',
 	'triangles_monkey.py', 'triangles_sphere.py',
 	'objreader.py', 'plyreader.py', 'lworeader.py',
-	'vector.py', 'render_nff.py', 'demo_PIL.py']
+	'vector.py', 'render_nff.py', 'demo_PIL.py', 'texture.py']
 
 l = []
 for file in files:
--- a/demos/car.py	Sat May 10 14:29:37 2008 +0200
+++ b/demos/car.py	Thu May 15 00:07:25 2008 +0200
@@ -7,12 +7,20 @@
 rt = Raytracer()
 top = KdTree()
 rt.setTop(top)
-cam = Camera(eye=(0.,2.,8.))
+rt.setBgColour((0.2,0.3,0.8))
+cam = Camera(eye=(-5,3,5),lookat=(-1,1.5,0))
 rotx=0.15
 cam.rotate((cos(rotx),-sin(rotx),0.,0.))
 rt.setCamera(cam)
 
-LoadLightwaveLwoFile(rt, "../models/lwo/Nissan300ZX.lwo", scale=0.4, trans=(-0.2,0,0.3))
+LoadLightwaveLwoFile(rt, "../models/lwo/Nissan300ZX.lwo", scale=0.4)
+
+mat = Material(colour=(0.5, 0.5, 0.5))
+ground = Box(L=(-10,-2,-10), H=(10,-1.2,10), material=mat)
+rt.addShape(ground)
+
+wall = Box(L=(-10,-2,-4), H=(10,10,-3), material=mat)
+rt.addShape(wall)
 
 light1 = Light(position=(-5.0, 20.0, 8.0), colour=(0.9, 0.9, 0.9))
 rt.addLight(light1)
@@ -22,6 +30,7 @@
 top.optimize()
 
 sampler = DefaultSampler(800, 600)
+sampler.setOversample(2)
 rt.setSampler(sampler)
 rt.render()
 sampler.getPixmap().writePNG('car.png')
--- a/demos/demo_PIL.py	Sat May 10 14:29:37 2008 +0200
+++ b/demos/demo_PIL.py	Thu May 15 00:07:25 2008 +0200
@@ -20,15 +20,15 @@
 rt.addShape(box)
 
 mat1 = Material(colour=(1.0, 0.0, 0.0))
-bigsphere = Sphere(centre=(3.0, 2.0, -7.0), radius=3.0, material=mat1)
+bigsphere = Sphere(center=(3.0, 2.0, -7.0), radius=3.0, material=mat1)
 rt.addShape(bigsphere)
 
 mat2 = Material(colour=(0.0, 1.0, 0.0))
-smallsphere = Sphere(centre=(-5.5, 1.5, -8.0), radius=2.0, material=mat2)
+smallsphere = Sphere(center=(-5.5, 1.5, -8.0), radius=2.0, material=mat2)
 rt.addShape(smallsphere)
 
 mat3 = Material(colour=(0.0, 0.0, 1.0))
-tinysphere = Sphere(centre=(-1.2, 0.0, -2.0), radius=0.5, material=mat3)
+tinysphere = Sphere(center=(-1.2, 0.0, -2.0), radius=0.5, material=mat3)
 rt.addShape(tinysphere)
 
 top.optimize()
--- a/demos/render_nff.py	Sat May 10 14:29:37 2008 +0200
+++ b/demos/render_nff.py	Thu May 15 00:07:25 2008 +0200
@@ -72,7 +72,7 @@
 	elif ln[0] == 's':	# Sphere
 		center = (float(ln[1]), float(ln[2]), float(ln[3]))
 		radius = float(ln[4])
-		rt.addShape(Sphere(centre=center, radius=radius, material=mat))
+		rt.addShape(Sphere(center=center, radius=radius, material=mat))
 	elif ln[0] == 'p':	# Polygon
 		vertex_count = int(ln[1])
 		vertices = []
--- a/demos/spheres_ao.py	Sat May 10 14:29:37 2008 +0200
+++ b/demos/spheres_ao.py	Thu May 15 00:07:25 2008 +0200
@@ -21,15 +21,15 @@
 rt.addShape(box)
 
 mat1 = Material(colour=(1.0, 0.0, 0.0))
-bigsphere = Sphere(centre=(3.0, 2.0, -7.0), radius=3.0, material=mat1)
+bigsphere = Sphere(center=(3.0, 2.0, -7.0), radius=3.0, material=mat1)
 rt.addShape(bigsphere)
 
 mat2 = Material(colour=(0.0, 1.0, 0.0))
-smallsphere = Sphere(centre=(-5.5, 1.5, -8.0), radius=2.0, material=mat2)
+smallsphere = Sphere(center=(-5.5, 1.5, -8.0), radius=2.0, material=mat2)
 rt.addShape(smallsphere)
 
 mat3 = Material(colour=(0.0, 0.0, 1.0))
-tinysphere = Sphere(centre=(-1.2, 0.0, -2.0), radius=0.5, material=mat3)
+tinysphere = Sphere(center=(-1.2, 0.0, -2.0), radius=0.5, material=mat3)
 rt.addShape(tinysphere)
 
 top.optimize()
--- a/demos/spheres_glass.py	Sat May 10 14:29:37 2008 +0200
+++ b/demos/spheres_glass.py	Thu May 15 00:07:25 2008 +0200
@@ -23,12 +23,12 @@
 
 mat1 = Material(colour=(1.0, 0.2, 0.1))
 mat1.setReflectivity(0.7)
-bigsphere = Sphere(centre=(12.0, 4.0, 6.0), radius=2.5, material=mat1)
+bigsphere = Sphere(center=(12.0, 4.0, 6.0), radius=2.5, material=mat1)
 rt.addShape(bigsphere)
 
 mat2 = Material(colour=(0.1, 0.4, 0.2))
 mat2.setReflectivity(0.6)
-smallsphere = Sphere(centre=(6.5, 3.5, 8.0), radius=2.0, material=mat2)
+smallsphere = Sphere(center=(6.5, 3.5, 8.0), radius=2.0, material=mat2)
 rt.addShape(smallsphere)
 
 mat3 = Material(colour=(0.9, 0.9, 1.0))
@@ -36,12 +36,13 @@
 mat3.setTransmissivity(0.88)
 mat3.setReflectivity(0.1)
 for i in range(10):
-	sph = Sphere(centre=(5.0+i, 1.5, 4.0), radius=0.5, material=mat3)
+	sph = Sphere(center=(5.0+i, 1.5, 4.0), radius=0.5, material=mat3)
 	rt.addShape(sph)
 
 top.optimize()
 
 sampler = DefaultSampler(800, 600)
+sampler.setOversample(1)
 rt.setSampler(sampler)
 rt.render()
 sampler.getPixmap().writePNG('spheres_glass.png')
--- a/demos/spheres_shadow.py	Sat May 10 14:29:37 2008 +0200
+++ b/demos/spheres_shadow.py	Thu May 15 00:07:25 2008 +0200
@@ -19,15 +19,15 @@
 rt.addShape(box)
 
 mat1 = Material(colour=(1.0, 0.0, 0.0))
-bigsphere = Sphere(centre=(3.0, 2.0, -7.0), radius=3.0, material=mat1)
+bigsphere = Sphere(center=(3.0, 2.0, -7.0), radius=3.0, material=mat1)
 rt.addShape(bigsphere)
 
 mat2 = Material(colour=(0.0, 1.0, 0.0))
-smallsphere = Sphere(centre=(-5.5, 1.5, -8.0), radius=2.0, material=mat2)
+smallsphere = Sphere(center=(-5.5, 1.5, -8.0), radius=2.0, material=mat2)
 rt.addShape(smallsphere)
 
 mat3 = Material(colour=(0.0, 0.0, 1.0))
-tinysphere = Sphere(centre=(-1.2, 0.0, -2.0), radius=0.5, material=mat3)
+tinysphere = Sphere(center=(-1.2, 0.0, -2.0), radius=0.5, material=mat3)
 rt.addShape(tinysphere)
 
 top.optimize()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/demos/texture.py	Thu May 15 00:07:25 2008 +0200
@@ -0,0 +1,49 @@
+#!/usr/bin/python
+
+from pyrit import *
+
+rt = Raytracer()
+top = KdTree()
+rt.setTop(top)
+rt.setCamera(Camera(eye=(10,4,-6),lookat=(10,3.5,0)))
+
+light1 = Light(position=(10.0, 7.0, 3.0), colour=(0.9, 0.3, 0.6))
+rt.addLight(light1)
+
+light2 = Light(position=(8.0, 5.0, 1.0), colour=(0.7, 1.0, 0.3))
+rt.addLight(light2)
+
+light3 = Light(position=(12.0, 8.0, -1.0), colour=(0.8, 0.9, 1.0))
+rt.addLight(light3)
+
+mat0 = Material()
+mat0.setTexture(CloudTexture(5, LinearColourMap((0.0, 0.0, 0.5), (0.5, 1.0, 1.0))))
+mat0.setReflectivity(0.0)
+box = Box(L=(-10.0, 0.0, 50.0), H=(30.0, 1.0, -1.0), material=mat0)
+rt.addShape(box)
+
+mat1 = Material(colour=(1.0, 0.2, 0.1))
+mat1.setReflectivity(0.7)
+bigsphere = Sphere(center=(12.0, 4.0, 6.0), radius=2.5, material=mat1)
+rt.addShape(bigsphere)
+
+mat2 = Material(colour=(0.1, 0.4, 0.2))
+mat2.setReflectivity(0.6)
+smallsphere = Sphere(center=(6.5, 3.5, 8.0), radius=2.0, material=mat2)
+rt.addShape(smallsphere)
+
+mat3 = Material(colour=(0.9, 0.9, 1.0))
+mat3.setPhong(0.2, 1.0, 0.2)
+mat3.setTransmissivity(0.88)
+mat3.setReflectivity(0.1)
+for i in range(10):
+	sph = Sphere(center=(5.0+i, 1.5, 4.0), radius=0.5, material=mat3)
+	rt.addShape(sph)
+
+top.optimize()
+
+sampler = DefaultSampler(800, 600)
+sampler.setOversample(1)
+rt.setSampler(sampler)
+rt.render()
+sampler.getPixmap().writePNG('texture.png')
--- a/include/material.h	Sat May 10 14:29:37 2008 +0200
+++ b/include/material.h	Thu May 15 00:07:25 2008 +0200
@@ -110,7 +110,7 @@
 	TextureMap(const Vector &acenter, const Float &size):
 		center(acenter), invsize(1.0f/size) {};
 	virtual ~TextureMap() {};
-	virtual void map(const Vector &point, Float &u, Float &v) = 0;
+	virtual void map(const Vector &point, Float &u, Float &v) const = 0;
 };
 
 /**
@@ -121,7 +121,7 @@
 public:
 	PlanarMap(const Vector &acenter, const Float &size):
 		TextureMap(acenter, size) {};
-	void map(const Vector &point, Float &u, Float &v)
+	void map(const Vector &point, Float &u, Float &v) const
 	{
 		const Vector p = point - center;
 		u = p.x*invsize;
@@ -137,7 +137,7 @@
 public:
 	CubicMap(const Vector &acenter, const Float &size):
 		TextureMap(acenter, size) {};
-	void map(const Vector &point, Float &u, Float &v)
+	void map(const Vector &point, Float &u, Float &v) const
 	{
 		const Vector p = point - center;
 		if (fabs(p.x) > fabs(p.y))
@@ -191,7 +191,7 @@
 public:
 	CylinderMap(const Vector &acenter, const Float &size):
 		TextureMap(acenter, size) {};
-	void map(const Vector &point, Float &u, Float &v)
+	void map(const Vector &point, Float &u, Float &v) const
 	{
 		const Vector p = point - center;
 		u = ( PI + atan2(p.z, p.x) ) * invsize;
@@ -207,7 +207,7 @@
 public:
 	SphereMap(const Vector &acenter, const Float &size):
 		TextureMap(acenter, size) {};
-	void map(const Vector &point, Float &u, Float &v)
+	void map(const Vector &point, Float &u, Float &v) const
 	{
 		const Vector p = point - center;
 		u = ( PI + atan2(p.z, p.x) ) * invsize;
@@ -221,9 +221,9 @@
 class Texture2D: public Texture
 {
 protected:
-	TextureMap *map;
+	const TextureMap *map;
 public:
-	Texture2D(TextureMap *amap): map(amap) {};
+	Texture2D(const TextureMap *amap): map(amap) {};
 };
 
 /**
@@ -231,9 +231,9 @@
  */
 class ImageTexture: public Texture2D
 {
-	Pixmap *pixmap;
+	const Pixmap *pixmap;
 public:
-	ImageTexture(TextureMap *tmap, Pixmap *image):
+	ImageTexture(const TextureMap *tmap, const Pixmap *image):
 		Texture2D(tmap), pixmap(image) {};
 	Colour evaluate(const Vector &point)
 	{
--- a/include/pixmap.h	Sat May 10 14:29:37 2008 +0200
+++ b/include/pixmap.h	Thu May 15 00:07:25 2008 +0200
@@ -67,7 +67,7 @@
 
 	void setData(Float *afdata, int aw, int ah)
 		{ fdata = afdata; w = aw; h = ah; };
-	Colour get(int x, int y) { return data[y*w + x]; };
+	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; };
 	Float*& getFloatData() { return fdata; };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/raytracermodule.h	Thu May 15 00:07:25 2008 +0200
@@ -0,0 +1,230 @@
+/*
+ * raytracermodule.h: raytracer module for Python
+ *
+ * This file is part of Pyrit Ray Tracer.
+ *
+ * Copyright 2006, 2007, 2008  Radek Brich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef RAYTRACERMODULE_H
+#define RAYTRACERMODULE_H
+
+#include <Python.h>
+#include "raytracer.h"
+#include "octree.h"
+#include "kdtree.h"
+
+
+#define TYPE_OBJECT(name, basicsize, dealloc, flags, doc, methods, members, base, init) \
+{ \
+	PyObject_HEAD_INIT(NULL) \
+	0,                          /* ob_size */ \
+	(name),                     /* tp_name */ \
+	(basicsize),                /* tp_basicsize*/ \
+	0,                          /* tp_itemsize*/ \
+	(dealloc),                  /* tp_dealloc*/ \
+	0,                          /* tp_print*/\
+	0,                          /* tp_getattr*/\
+	0,                          /* tp_setattr*/\
+	0,                          /* tp_compare*/\
+	0,                          /* tp_repr*/\
+	0,                          /* tp_as_number*/\
+	0,                          /* tp_as_sequence*/\
+	0,                          /* tp_as_mapping*/\
+	0,                          /* tp_hash */\
+	0,                          /* tp_call*/\
+	0,                          /* tp_str*/\
+	PyObject_GenericGetAttr,    /* tp_getattro*/\
+	0,                          /* tp_setattro*/\
+	0,                          /* tp_as_buffer*/\
+	(flags),                    /* tp_flags*/\
+	(doc),                      /* tp_doc */\
+	0,                          /* tp_traverse */\
+	0,                          /* tp_clear */\
+	0,                          /* tp_richcompare */\
+	0,                          /* tp_weaklistoffset */\
+	0,                          /* tp_iter */\
+	0,                          /* tp_iternext */\
+	(methods),                  /* tp_methods */\
+	(members),                  /* tp_members */\
+	0,                          /* tp_getset */\
+	(base),                     /* tp_base */\
+	0,                          /* tp_dict */ \
+	0,                          /* tp_descr_get */ \
+	0,                          /* tp_descr_set */ \
+	0,                          /* tp_dictoffset */ \
+	(init),                     /* tp_init */ \
+	0,                          /* tp_alloc */ \
+	0,                          /* tp_new */ \
+	0,                          /* tp_free */ \
+}
+
+/** Light object */
+typedef struct {
+	PyObject_HEAD
+	Light *light;
+} LightObject;
+
+/** Camera object */
+typedef struct {
+	PyObject_HEAD
+	Camera *camera;
+} CameraObject;
+
+/** Pixmap object */
+typedef struct {
+	PyObject_HEAD
+	const Pixmap *pixmap;
+} PixmapObject;
+
+/** abstract TextureMap object */
+typedef struct {
+	PyObject_HEAD
+	TextureMap *texturemap;
+} TextureMapObject;
+
+/** PlanarMap object - inherits TextureMap */
+typedef struct {
+	TextureMapObject texturemap;
+} PlanarMapObject;
+
+/** CubicMap object - inherits TextureMap */
+typedef struct {
+	TextureMapObject texturemap;
+} CubicMapObject;
+
+/** CylinderMap object - inherits TextureMap */
+typedef struct {
+	TextureMapObject texturemap;
+} CylinderMapObject;
+
+/** SphereMap object - inherits TextureMap */
+typedef struct {
+	TextureMapObject texturemap;
+} SphereMapObject;
+
+/** abstract ColourMap object */
+typedef struct {
+	PyObject_HEAD
+	ColourMap *colourmap;
+} ColourMapObject;
+
+/** LinearColourMap object - inherits ColourMap */
+typedef struct {
+	ColourMapObject colourmap;
+} LinearColourMapObject;
+
+/** BoundColourMap object - inherits ColourMap */
+typedef struct {
+	ColourMapObject colourmap;
+	Float *bounds;
+	Colour *colours;
+} BoundColourMapObject;
+
+/** abstract Texture object */
+typedef struct {
+	PyObject_HEAD
+	Texture *texture;
+} TextureObject;
+
+/** ImageTexture object - inherits Texture */
+typedef struct {
+	TextureObject texture;
+} ImageTextureObject;
+
+/** CheckersTexture object - inherits Texture */
+typedef struct {
+	TextureObject texture;
+} CheckersTextureObject;
+
+/** CloudTexture object - inherits Texture */
+typedef struct {
+	TextureObject texture;
+} CloudTextureObject;
+
+/** Material object */
+typedef struct {
+	PyObject_HEAD
+	Material *material;
+} MaterialObject;
+
+/** NormalVertex object */
+typedef struct {
+	PyObject_HEAD
+	NormalVertex *nvertex;
+} NormalVertexObject;
+
+/** abstract Shape object */
+typedef struct {
+	PyObject_HEAD
+	Shape *shape;
+} ShapeObject;
+
+/** Triangle object - inherits Shape */
+typedef struct {
+	ShapeObject shape;
+} TriangleObject;
+
+/** Sphere object - inherits Shape */
+typedef struct {
+	ShapeObject shape;
+} SphereObject;
+
+/** Box object - inherits Shape */
+typedef struct {
+	ShapeObject shape;
+} BoxObject;
+
+/** abstract Sampler object */
+typedef struct {
+	PyObject_HEAD
+	Sampler *sampler;
+} SamplerObject;
+
+/** DefaultSampler object - inherits Sampler */
+typedef struct {
+	SamplerObject sampler;
+} DefaultSamplerObject;
+
+/** Container object */
+typedef struct {
+	PyObject_HEAD
+	Container *container;
+} ContainerObject;
+
+/** Octree object - inherits Container */
+typedef struct {
+	ContainerObject container;
+} OctreeObject;
+
+/** KdTree object - inherits Container */
+typedef struct {
+	ContainerObject container;
+} KdTreeObject;
+
+/** main Raytracer object */
+typedef struct {
+	PyObject_HEAD
+	Raytracer *raytracer;
+	vector<PyObject*> *children;
+} RaytracerObject;
+
+#endif
--- a/src/raytracermodule.cc	Sat May 10 14:29:37 2008 +0200
+++ b/src/raytracermodule.cc	Thu May 15 00:07:25 2008 +0200
@@ -1,5 +1,5 @@
 /*
- * raytracermodule.cc: Python module
+ * raytracermodule.cc: raytracer module for Python
  *
  * This file is part of Pyrit Ray Tracer.
  *
@@ -24,64 +24,13 @@
  * THE SOFTWARE.
  */
 
-#include <Python.h>
+#include "raytracermodule.h"
 
 #include <vector>
-#include "raytracer.h"
-#include "octree.h"
-#include "kdtree.h"
 
-#define TYPE_OBJECT(name, basicsize, dealloc, flags, doc, methods, members, base, init) \
-{ \
-	PyObject_HEAD_INIT(NULL) \
-	0,                          /* ob_size */ \
-	(name),                     /* tp_name */ \
-	(basicsize),                /* tp_basicsize*/ \
-	0,                          /* tp_itemsize*/ \
-	(dealloc),                  /* tp_dealloc*/ \
-	0,                          /* tp_print*/\
-	0,                          /* tp_getattr*/\
-	0,                          /* tp_setattr*/\
-	0,                          /* tp_compare*/\
-	0,                          /* tp_repr*/\
-	0,                          /* tp_as_number*/\
-	0,                          /* tp_as_sequence*/\
-	0,                          /* tp_as_mapping*/\
-	0,                          /* tp_hash */\
-	0,                          /* tp_call*/\
-	0,                          /* tp_str*/\
-	PyObject_GenericGetAttr,    /* tp_getattro*/\
-	0,                          /* tp_setattro*/\
-	0,                          /* tp_as_buffer*/\
-	(flags),                    /* tp_flags*/\
-	(doc),                      /* tp_doc */\
-	0,                          /* tp_traverse */\
-	0,                          /* tp_clear */\
-	0,                          /* tp_richcompare */\
-	0,                          /* tp_weaklistoffset */\
-	0,                          /* tp_iter */\
-	0,                          /* tp_iternext */\
-	(methods),                  /* tp_methods */\
-	(members),                  /* tp_members */\
-	0,                          /* tp_getset */\
-	(base),                     /* tp_base */\
-	0,                          /* tp_dict */ \
-	0,                          /* tp_descr_get */ \
-	0,                          /* tp_descr_set */ \
-	0,                          /* tp_dictoffset */ \
-	(init),                     /* tp_init */ \
-	0,                          /* tp_alloc */ \
-	0,                          /* tp_new */ \
-	0,                          /* tp_free */ \
-}
 
 //=========================== Light Source Object ===========================
 
-typedef struct {
-	PyObject_HEAD
-	Light *light;
-} LightObject;
-
 static PyObject *Light_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static void Light_Destructor(PyObject* self);
 static PyObject *Light_castShadows(PyObject* self, PyObject* args);
@@ -147,11 +96,6 @@
 
 //=========================== Camera Object ===========================
 
-typedef struct {
-	PyObject_HEAD
-	Camera *camera;
-} CameraObject;
-
 static PyObject *Camera_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static void Camera_Destructor(PyObject* self);
 static PyObject *Camera_setEye(PyObject* self, PyObject* args);
@@ -285,12 +229,567 @@
 }
 
 
-//=========================== Material Object ===========================
+//=========================== Pixmap Object ===========================
+
+static PyObject* Pixmap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+static PyObject* Pixmap_getWidth(PyObject* self, PyObject* args);
+static PyObject* Pixmap_getHeight(PyObject* self, PyObject* args);
+static PyObject* Pixmap_getCharData(PyObject* self, PyObject* args);
+static PyObject* Pixmap_writePNG(PyObject* self, PyObject* args);
+
+static PyMethodDef PixmapMethods[] = {
+	{"getWidth", (PyCFunction)Pixmap_getWidth, METH_NOARGS, "Get width of pixmap."},
+	{"getHeight", (PyCFunction)Pixmap_getHeight, METH_NOARGS, "Get height of pixmap."},
+	{"getCharData", (PyCFunction)Pixmap_getCharData, METH_NOARGS, "Get raw byte data."},
+	{"writePNG", (PyCFunction)Pixmap_writePNG, METH_VARARGS, "Write pixmap to PNG file."},
+	{NULL, NULL}
+};
+
+static PyTypeObject PixmapType =
+TYPE_OBJECT(
+	"Pixmap",                    /* tp_name */
+	sizeof(PixmapObject),        /* tp_basicsize */
+	0,                           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Pixmap type",               /* tp_doc */
+	PixmapMethods,               /* tp_methods */
+	0,                           /* tp_members */
+	0,                           /* tp_base */
+	0                            /* tp_init */
+);
+
+static PyObject* Pixmap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	int w = 0, h = 0;
+	PixmapObject *v;
+
+	if (!PyArg_ParseTuple(args, "(ii)", &w, &h))
+		return NULL;
+
+	v = PyObject_New(PixmapObject, &PixmapType);
+	v->pixmap = new Pixmap(w, h);
+	return (PyObject*)v;
+}
+
+static PyObject* Pixmap_getWidth(PyObject* self, PyObject* args)
+{
+	return Py_BuildValue("i", ((PixmapObject *)self)->pixmap->getWidth());
+}
+
+static PyObject* Pixmap_getHeight(PyObject* self, PyObject* args)
+{
+	return Py_BuildValue("i", ((PixmapObject *)self)->pixmap->getHeight());
+}
+
+static PyObject *Pixmap_getCharData(PyObject* self, PyObject* args)
+{
+	unsigned char *chardata;
+	int w,h;
+	PyObject *o;
+
+	chardata = ((PixmapObject *)self)->pixmap->getCharData();
+	w = ((PixmapObject *)self)->pixmap->getWidth();
+	h = ((PixmapObject *)self)->pixmap->getHeight();
+	o = Py_BuildValue("s#", chardata, w*h*3);
+	delete[] chardata;
+	return o;
+}
+
+static PyObject *Pixmap_writePNG(PyObject* self, PyObject* args)
+{
+	const char *fname;
+	int res;
+
+	if (!PyArg_ParseTuple(args, "s", &fname))
+		return NULL;
+
+	res = ((PixmapObject *)self)->pixmap->writePNG(fname);
+	return Py_BuildValue("i", res);
+}
+
+
+//=========================== TextureMap Object (abstract) ===========================
+
+static void TextureMap_Destructor(PyObject* self);
+
+static PyMethodDef TextureMapMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject TextureMapType =
+TYPE_OBJECT(
+	"TextureMap",                  /* tp_name */
+	sizeof(TextureMapObject),      /* tp_basicsize */
+	TextureMap_Destructor,         /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"TextureMap type (abstract)",  /* tp_doc */
+	TextureMapMethods,             /* tp_methods */
+	0,                             /* tp_members */
+	0,                             /* tp_base */
+	0                              /* tp_init */
+);
+
+static void TextureMap_Destructor(PyObject* self)
+{
+	delete ((TextureMapObject *)self)->texturemap;
+	self->ob_type->tp_free(self);
+}
+
+
+//=========================== PlanarMap Object ===========================
+
+static PyObject *PlanarMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+
+static PyMethodDef PlanarMapMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject PlanarMapType =
+TYPE_OBJECT(
+	"PlanarMap",                    /* tp_name */
+	sizeof(PlanarMapObject),        /* tp_basicsize */
+	0,                              /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"PlanarMap type",               /* tp_doc */
+	PlanarMapMethods,               /* tp_methods */
+	0,                              /* tp_members */
+	&TextureMapType,                /* tp_base */
+	0                               /* tp_init */
+);
+
+static PyObject* PlanarMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	PlanarMapObject *v;
+	static char *kwdlist[] = {"center", "size", NULL};
+	PyObject *Tcenter = NULL;
+	Vector center;
+	Float size;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!f", kwdlist,
+		&PyTuple_Type, &Tcenter, &size))
+		return NULL;
+
+	if (!PyArg_ParseTuple(Tcenter, "fff", &center.x, &center.y, &center.z))
+		return NULL;
+
+	v = PyObject_New(PlanarMapObject, &PlanarMapType);
+	v->texturemap.texturemap = new PlanarMap(center, size);
+	return (PyObject*)v;
+}
+
+
+//=========================== CubicMap Object ===========================
+
+static PyObject *CubicMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+
+static PyMethodDef CubicMapMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject CubicMapType =
+TYPE_OBJECT(
+	"CubicMap",                    /* tp_name */
+	sizeof(CubicMapObject),        /* tp_basicsize */
+	0,                              /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"CubicMap type",               /* tp_doc */
+	CubicMapMethods,               /* tp_methods */
+	0,                              /* tp_members */
+	&TextureMapType,                /* tp_base */
+	0                               /* tp_init */
+);
+
+static PyObject* CubicMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	CubicMapObject *v;
+	static char *kwdlist[] = {"center", "size", NULL};
+	PyObject *Tcenter = NULL;
+	Vector center;
+	Float size;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!f", kwdlist,
+		&PyTuple_Type, &Tcenter, &size))
+		return NULL;
+
+	if (!PyArg_ParseTuple(Tcenter, "fff", &center.x, &center.y, &center.z))
+		return NULL;
+
+	v = PyObject_New(CubicMapObject, &CubicMapType);
+	v->texturemap.texturemap = new CubicMap(center, size);
+	return (PyObject*)v;
+}
+
+
+//=========================== CylinderMap Object ===========================
+
+static PyObject *CylinderMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+
+static PyMethodDef CylinderMapMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject CylinderMapType =
+TYPE_OBJECT(
+	"CylinderMap",                    /* tp_name */
+	sizeof(CylinderMapObject),        /* tp_basicsize */
+	0,                              /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"CylinderMap type",               /* tp_doc */
+	CylinderMapMethods,               /* tp_methods */
+	0,                              /* tp_members */
+	&TextureMapType,                /* tp_base */
+	0                               /* tp_init */
+);
+
+static PyObject* CylinderMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	CylinderMapObject *v;
+	static char *kwdlist[] = {"center", "size", NULL};
+	PyObject *Tcenter = NULL;
+	Vector center;
+	Float size;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!f", kwdlist,
+		&PyTuple_Type, &Tcenter, &size))
+		return NULL;
+
+	if (!PyArg_ParseTuple(Tcenter, "fff", &center.x, &center.y, &center.z))
+		return NULL;
+
+	v = PyObject_New(CylinderMapObject, &CylinderMapType);
+	v->texturemap.texturemap = new CylinderMap(center, size);
+	return (PyObject*)v;
+}
+
+
+//=========================== SphereMap Object ===========================
+
+static PyObject *SphereMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+
+static PyMethodDef SphereMapMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject SphereMapType =
+TYPE_OBJECT(
+	"SphereMap",                    /* tp_name */
+	sizeof(SphereMapObject),        /* tp_basicsize */
+	0,                              /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"SphereMap type",               /* tp_doc */
+	SphereMapMethods,               /* tp_methods */
+	0,                              /* tp_members */
+	&TextureMapType,                /* tp_base */
+	0                               /* tp_init */
+);
+
+static PyObject* SphereMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	SphereMapObject *v;
+	static char *kwdlist[] = {"center", "size", NULL};
+	PyObject *Tcenter = NULL;
+	Vector center;
+	Float size;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!f", kwdlist,
+		&PyTuple_Type, &Tcenter, &size))
+		return NULL;
+
+	if (!PyArg_ParseTuple(Tcenter, "fff", &center.x, &center.y, &center.z))
+		return NULL;
+
+	v = PyObject_New(SphereMapObject, &SphereMapType);
+	v->texturemap.texturemap = new SphereMap(center, size);
+	return (PyObject*)v;
+}
+
+
+//=========================== ColourMap Object (abstract) ===========================
+
+static void ColourMap_Destructor(PyObject* self);
 
-typedef struct {
-	PyObject_HEAD
-	Material *material;
-} MaterialObject;
+static PyMethodDef ColourMapMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject ColourMapType =
+TYPE_OBJECT(
+	"ColourMap",                  /* tp_name */
+	sizeof(ColourMapObject),      /* tp_basicsize */
+	ColourMap_Destructor,         /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"ColourMap type (abstract)",  /* tp_doc */
+	ColourMapMethods,             /* tp_methods */
+	0,                            /* tp_members */
+	0,                            /* tp_base */
+	0                             /* tp_init */
+);
+
+static void ColourMap_Destructor(PyObject* self)
+{
+	delete ((ColourMapObject *)self)->colourmap;
+	self->ob_type->tp_free(self);
+}
+
+
+//=========================== LinearColourMap Object ===========================
+
+static PyObject *LinearColourMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+
+static PyMethodDef LinearColourMapMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject LinearColourMapType =
+TYPE_OBJECT(
+	"LinearColourMap",                    /* tp_name */
+	sizeof(LinearColourMapObject),        /* tp_basicsize */
+	0,                                    /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"LinearColourMap type",               /* tp_doc */
+	LinearColourMapMethods,               /* tp_methods */
+	0,                                    /* tp_members */
+	&ColourMapType,                       /* tp_base */
+	0                                     /* tp_init */
+);
+
+static PyObject* LinearColourMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	LinearColourMapObject *v;
+	static char *kwdlist[] = {"clow", "chigh", NULL};
+	PyObject *Tclow = NULL;
+	PyObject *Tchigh = NULL;
+	Vector clow, chigh;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!", kwdlist,
+		&PyTuple_Type, &Tclow, &PyTuple_Type, &Tchigh))
+		return NULL;
+
+	if (!PyArg_ParseTuple(Tclow, "fff", &clow.x, &clow.y, &clow.z))
+		return NULL;
+	if (!PyArg_ParseTuple(Tchigh, "fff", &chigh.x, &chigh.y, &chigh.z))
+		return NULL;
+
+	v = PyObject_New(LinearColourMapObject, &LinearColourMapType);
+	v->colourmap.colourmap = new LinearColourMap(clow, chigh);
+	return (PyObject*)v;
+}
+
+
+//=========================== BoundColourMap Object ===========================
+
+static PyObject *BoundColourMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+static void BoundColourMap_Destructor(PyObject* self);
+
+static PyMethodDef BoundColourMapMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject BoundColourMapType =
+TYPE_OBJECT(
+	"BoundColourMap",                    /* tp_name */
+	sizeof(BoundColourMapObject),        /* tp_basicsize */
+	BoundColourMap_Destructor,           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"BoundColourMap type",               /* tp_doc */
+	BoundColourMapMethods,               /* tp_methods */
+	0,                                   /* tp_members */
+	&ColourMapType,                      /* tp_base */
+	0                                    /* tp_init */
+);
+
+static PyObject* BoundColourMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	BoundColourMapObject *v;
+	static char *kwdlist[] = {"bounds", "colours", NULL};
+	PyObject *Tbounds = NULL;
+	PyObject *Tcolours = NULL;
+	PyObject *o;
+	int num;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!", kwdlist,
+		&PyTuple_Type, &Tbounds, &PyTuple_Type, &Tcolours))
+		return NULL;
+
+	/* get lesser of the sizes */
+	num = PyTuple_GET_SIZE(Tbounds);
+	if (num > PyTuple_GET_SIZE(Tcolours))
+		num = PyTuple_GET_SIZE(Tcolours);
+
+	v = PyObject_New(BoundColourMapObject, &BoundColourMapType);
+
+	v->bounds = new Float[num];
+	v->colours = new Colour[num];
+
+	for (int i = 0; i < num; i++)
+	{
+		o = PyTuple_GET_ITEM(Tbounds, i);
+		v->bounds[i] = PyFloat_AsDouble(o);
+		o = PyTuple_GET_ITEM(Tcolours, i);
+		if (!PyArg_ParseTuple(o, "fff", &v->colours[i].r, &v->colours[i].g, &v->colours[i].b))
+			return NULL;
+	}
+
+	v->colourmap.colourmap = new BoundColourMap(v->bounds, v->colours);
+	return (PyObject*)v;
+}
+
+static void BoundColourMap_Destructor(PyObject* self)
+{
+	delete ((BoundColourMapObject *)self)->bounds;
+	delete ((BoundColourMapObject *)self)->colours;
+	self->ob_type->tp_free(self);
+}
+
+
+//=========================== Texture Object (abstract) ===========================
+
+static void Texture_Destructor(PyObject* self);
+
+static PyMethodDef TextureMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject TextureType =
+TYPE_OBJECT(
+	"Texture",                  /* tp_name */
+	sizeof(TextureObject),      /* tp_basicsize */
+	Texture_Destructor,         /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Texture type (abstract)",  /* tp_doc */
+	TextureMethods,             /* tp_methods */
+	0,                          /* tp_members */
+	0,                          /* tp_base */
+	0                           /* tp_init */
+);
+
+static void Texture_Destructor(PyObject* self)
+{
+	delete ((TextureObject *)self)->texture;
+	self->ob_type->tp_free(self);
+}
+
+
+//=========================== ImageTexture Object ===========================
+
+static PyObject *ImageTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+
+static PyMethodDef ImageTextureMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject ImageTextureType =
+TYPE_OBJECT(
+	"ImageTexture",                    /* tp_name */
+	sizeof(ImageTextureObject),        /* tp_basicsize */
+	0,                                 /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"ImageTexture type",               /* tp_doc */
+	ImageTextureMethods,               /* tp_methods */
+	0,                                 /* tp_members */
+	&TextureType,                      /* tp_base */
+	0                                  /* tp_init */
+);
+
+static PyObject* ImageTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	ImageTextureObject *v;
+	static char *kwdlist[] = {"tmap", "image", NULL};
+	TextureMapObject *tmap = NULL;
+	PixmapObject *image = NULL;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!", kwdlist,
+		&TextureMapType, &tmap, &PixmapType, &image))
+		return NULL;
+
+	v = PyObject_New(ImageTextureObject, &ImageTextureType);
+	v->texture.texture = new ImageTexture(tmap->texturemap, image->pixmap);
+	Py_INCREF(tmap);
+	Py_INCREF(image);
+	return (PyObject*)v;
+}
+
+
+//=========================== CheckersTexture Object ===========================
+
+static PyObject *CheckersTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+
+static PyMethodDef CheckersTextureMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject CheckersTextureType =
+TYPE_OBJECT(
+	"CheckersTexture",                    /* tp_name */
+	sizeof(CheckersTextureObject),        /* tp_basicsize */
+	0,                                    /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"CheckersTexture type",               /* tp_doc */
+	CheckersTextureMethods,               /* tp_methods */
+	0,                                    /* tp_members */
+	&TextureType,                         /* tp_base */
+	0                                     /* tp_init */
+);
+
+static PyObject* CheckersTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	CheckersTextureObject *v;
+	static char *kwdlist[] = {"tmap", "cmap", NULL};
+	TextureMapObject *tmap = NULL;
+	ColourMapObject *cmap = NULL;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!", kwdlist,
+		&TextureMapType, &tmap, &ColourMapType, &cmap))
+		return NULL;
+
+	v = PyObject_New(CheckersTextureObject, &CheckersTextureType);
+	v->texture.texture = new CheckersTexture(tmap->texturemap, cmap->colourmap);
+	Py_INCREF(tmap);
+	Py_INCREF(cmap);
+	return (PyObject*)v;
+}
+
+
+//=========================== CloudTexture Object ===========================
+
+static PyObject *CloudTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+
+static PyMethodDef CloudTextureMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject CloudTextureType =
+TYPE_OBJECT(
+	"CloudTexture",                    /* tp_name */
+	sizeof(CloudTextureObject),        /* tp_basicsize */
+	0,                                    /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"CloudTexture type",               /* tp_doc */
+	CloudTextureMethods,               /* tp_methods */
+	0,                                    /* tp_members */
+	&TextureType,                         /* tp_base */
+	0                                     /* tp_init */
+);
+
+static PyObject* CloudTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	CloudTextureObject *v;
+	static char *kwdlist[] = {"detail", "cmap", NULL};
+	Float detail;
+	ColourMapObject *cmap = NULL;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "fO!", kwdlist,
+		&detail, &ColourMapType, &cmap))
+		return NULL;
+
+	v = PyObject_New(CloudTextureObject, &CloudTextureType);
+	v->texture.texture = new CloudTexture(detail, cmap->colourmap);
+	Py_INCREF(cmap);
+	return (PyObject*)v;
+}
+
+
+//=========================== Material Object ===========================
 
 static PyObject *Material_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static void Material_Destructor(PyObject* self);
@@ -298,12 +797,14 @@
 static PyObject *Material_setReflectivity(PyObject* self, PyObject* args);
 static PyObject *Material_setTransmissivity(PyObject* self, PyObject* args);
 static PyObject *Material_setSmooth(PyObject* self, PyObject* args);
+static PyObject *Material_setTexture(PyObject* self, PyObject* args);
 
 static PyMethodDef MaterialMethods[] = {
 	{"setPhong", (PyCFunction)Material_setPhong, METH_VARARGS, "Set ambient, diffuse, specular and shininess Phong model constants."},
 	{"setReflectivity", (PyCFunction)Material_setReflectivity, METH_VARARGS, "Set reflectivity."},
 	{"setTransmissivity", (PyCFunction)Material_setTransmissivity, METH_VARARGS, "Set transmissivity and refraction index."},
 	{"setSmooth", (PyCFunction)Material_setSmooth, METH_VARARGS, "Set triangle smoothing."},
+	{"setTexture", (PyCFunction)Material_setTexture, METH_VARARGS, "Set the texture."},
 	{NULL, NULL}
 };
 
@@ -387,9 +888,9 @@
 
 static PyObject* Material_setSmooth(PyObject* self, PyObject* args)
 {
-	int smooth;
+	int smooth = 1;
 
-	if (!PyArg_ParseTuple(args, "i", &smooth))
+	if (!PyArg_ParseTuple(args, "|i", &smooth))
 		return NULL;
 
 	((MaterialObject *)self)->material->setSmooth(smooth);
@@ -398,14 +899,23 @@
 	return Py_None;
 }
 
+static PyObject* Material_setTexture(PyObject* self, PyObject* args)
+{
+	TextureObject *tex;
+
+	if (!PyArg_ParseTuple(args, "O!", &TextureType, &tex))
+		return NULL;
+
+	((MaterialObject *)self)->material->setTexture(tex->texture);
+
+	Py_INCREF(tex);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
 
 //=========================== NormalVertex Object ===========================
 
-typedef struct {
-	PyObject_HEAD
-	NormalVertex *nvertex;
-} NormalVertexObject;
-
 static PyObject *NormalVertex_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static void NormalVertex_Destructor(PyObject* self);
 static PyObject *NormalVertex_setNormal(PyObject* self, PyObject* args);
@@ -485,11 +995,6 @@
 
 //=========================== Shape Object (abstract) ===========================
 
-typedef struct {
-	PyObject_HEAD
-	Shape *shape;
-} ShapeObject;
-
 static void Shape_Destructor(PyObject* self);
 
 static PyMethodDef ShapeMethods[] = {
@@ -517,10 +1022,6 @@
 
 //=========================== Triangle Object ===========================
 
-typedef struct {
-	ShapeObject shape;
-} TriangleObject;
-
 static PyObject *Triangle_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static PyObject *Triangle_getNormal(PyObject* self, PyObject* args);
 
@@ -575,10 +1076,6 @@
 
 //=========================== Sphere Object ===========================
 
-typedef struct {
-	ShapeObject shape;
-} SphereObject;
-
 static PyObject *Sphere_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 
 static PyMethodDef SphereMethods[] = {
@@ -602,7 +1099,7 @@
 {
 	SphereObject *v;
 	MaterialObject *material;
-	static char *kwdlist[] = {"centre", "radius", "material", NULL};
+	static char *kwdlist[] = {"center", "radius", "material", NULL};
 	PyObject *TCentre = NULL;
 	Float cx, cy, cz, radius;
 
@@ -621,10 +1118,6 @@
 
 //=========================== Box Object ===========================
 
-typedef struct {
-	ShapeObject shape;
-} BoxObject;
-
 static PyObject *Box_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 
 static PyMethodDef BoxMethods[] = {
@@ -669,96 +1162,9 @@
 	return (PyObject*)v;
 }
 
-//=========================== Pixmap Object ===========================
-
-typedef struct {
-	PyObject_HEAD
-	const Pixmap *pixmap;
-} PixmapObject;
-
-static PyObject* Pixmap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
-static PyObject* Pixmap_getWidth(PyObject* self, PyObject* args);
-static PyObject* Pixmap_getHeight(PyObject* self, PyObject* args);
-static PyObject* Pixmap_getCharData(PyObject* self, PyObject* args);
-static PyObject* Pixmap_writePNG(PyObject* self, PyObject* args);
-
-static PyMethodDef PixmapMethods[] = {
-	{"getWidth", (PyCFunction)Pixmap_getWidth, METH_NOARGS, "Get width of pixmap."},
-	{"getHeight", (PyCFunction)Pixmap_getHeight, METH_NOARGS, "Get height of pixmap."},
-	{"getCharData", (PyCFunction)Pixmap_getCharData, METH_NOARGS, "Get raw byte data."},
-	{"writePNG", (PyCFunction)Pixmap_writePNG, METH_VARARGS, "Write pixmap to PNG file."},
-	{NULL, NULL}
-};
-
-static PyTypeObject PixmapType =
-TYPE_OBJECT(
-	"Pixmap",                    /* tp_name */
-	sizeof(PixmapObject),        /* tp_basicsize */
-	0,                           /* tp_dealloc */
-	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
-	"Pixmap type",               /* tp_doc */
-	PixmapMethods,               /* tp_methods */
-	0,                           /* tp_members */
-	0,                           /* tp_base */
-	0                            /* tp_init */
-);
-
-static PyObject* Pixmap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
-{
-	int w = 0, h = 0;
-	PixmapObject *v;
-
-	if (!PyArg_ParseTuple(args, "(ii)", &w, &h))
-		return NULL;
-
-	v = PyObject_New(PixmapObject, &PixmapType);
-	v->pixmap = new Pixmap(w, h);
-	return (PyObject*)v;
-}
-
-static PyObject* Pixmap_getWidth(PyObject* self, PyObject* args)
-{
-	return Py_BuildValue("i", ((PixmapObject *)self)->pixmap->getWidth());
-}
-
-static PyObject* Pixmap_getHeight(PyObject* self, PyObject* args)
-{
-	return Py_BuildValue("i", ((PixmapObject *)self)->pixmap->getHeight());
-}
-
-static PyObject *Pixmap_getCharData(PyObject* self, PyObject* args)
-{
-	unsigned char *chardata;
-	int w,h;
-	PyObject *o;
-
-	chardata = ((PixmapObject *)self)->pixmap->getCharData();
-	w = ((PixmapObject *)self)->pixmap->getWidth();
-	h = ((PixmapObject *)self)->pixmap->getHeight();
-	o = Py_BuildValue("s#", chardata, w*h*3);
-	delete[] chardata;
-	return o;
-}
-
-static PyObject *Pixmap_writePNG(PyObject* self, PyObject* args)
-{
-	const char *fname;
-	int res;
-
-	if (!PyArg_ParseTuple(args, "s", &fname))
-		return NULL;
-
-	res = ((PixmapObject *)self)->pixmap->writePNG(fname);
-	return Py_BuildValue("i", res);
-}
 
 //=========================== Sampler Object (abstract) ===========================
 
-typedef struct {
-	PyObject_HEAD
-	Sampler *sampler;
-} SamplerObject;
-
 static void Sampler_Destructor(PyObject* self);
 static PyObject* Sampler_getPixmap(PyObject* self, PyObject* args);
 
@@ -795,10 +1201,6 @@
 
 //=========================== DefaultSampler Object ===========================
 
-typedef struct {
-	SamplerObject sampler;
-} DefaultSamplerObject;
-
 static PyObject *DefaultSampler_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static PyObject* DefaultSampler_setSubsample(PyObject* self, PyObject* args);
 static PyObject* DefaultSampler_setOversample(PyObject* self, PyObject* args);
@@ -871,11 +1273,6 @@
 
 //=========================== Container Object ===========================
 
-typedef struct {
-	PyObject_HEAD
-	Container *container;
-} ContainerObject;
-
 static PyObject *Container_Constructor(PyObject* self, PyObject* args);
 static void Container_Destructor(PyObject* self);
 static PyObject* Container_optimize(PyObject* self, PyObject* args);
@@ -921,10 +1318,6 @@
 
 //=========================== Octree Object ===========================
 
-typedef struct {
-	ContainerObject container;
-} OctreeObject;
-
 static PyObject* Octree_Constructor(PyObject* self, PyObject* args);
 
 static PyMethodDef OctreeMethods[] = {
@@ -954,10 +1347,6 @@
 
 //=========================== KdTree Object ===========================
 
-typedef struct {
-	ContainerObject container;
-} KdTreeObject;
-
 static PyObject* KdTree_Constructor(PyObject* self, PyObject* args);
 
 static PyMethodDef KdTreeMethods[] = {
@@ -987,12 +1376,6 @@
 
 //=========================== Raytracer Object ===========================
 
-typedef struct {
-	PyObject_HEAD
-	Raytracer *raytracer;
-	vector<PyObject*> *children;
-} RaytracerObject;
-
 static PyObject *Raytracer_Constructor(PyObject* self, PyObject* args);
 static void Raytracer_Destructor(PyObject* self);
 static PyObject *Raytracer_render(PyObject* self, PyObject* args);
@@ -1160,12 +1543,34 @@
 //=========================== Module Methods ===========================
 
 static PyMethodDef ModuleMethods[] = {
-	{"Raytracer", (PyCFunction) Raytracer_Constructor,
-		METH_VARARGS, "Raytracer object constructor."},
 	{"Light", (PyCFunction) Light_Constructor,
 		METH_VARARGS | METH_KEYWORDS, "Light source object constructor."},
 	{"Camera", (PyCFunction) Camera_Constructor,
 		METH_VARARGS | METH_KEYWORDS, "Camera object constructor."},
+	{"Pixmap", (PyCFunction) Pixmap_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "Pixmap object constructor."},
+
+	{"PlanarMap", (PyCFunction) PlanarMap_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "PlanarMap object constructor."},
+	{"CubicMap", (PyCFunction) CubicMap_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "CubicMap object constructor."},
+	{"SphereMap", (PyCFunction) SphereMap_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "SphereMap object constructor."},
+	{"CylinderMap", (PyCFunction) CylinderMap_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "CylinderMap object constructor."},
+
+	{"LinearColourMap", (PyCFunction) LinearColourMap_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "LinearColourMap object constructor."},
+	{"BoundColourMap", (PyCFunction) BoundColourMap_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "BoundColourMap object constructor."},
+
+	{"ImageTexture", (PyCFunction) ImageTexture_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "ImageTexture object constructor."},
+	{"CheckersTexture", (PyCFunction) CheckersTexture_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "CheckersTexture object constructor."},
+	{"CloudTexture", (PyCFunction) CloudTexture_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "CloudTexture object constructor."},
+
 	{"Material", (PyCFunction) Material_Constructor,
 		METH_VARARGS | METH_KEYWORDS, "Material object constructor."},
 	{"NormalVertex", (PyCFunction) NormalVertex_Constructor,
@@ -1176,16 +1581,18 @@
 		METH_VARARGS | METH_KEYWORDS, "Sphere object constructor."},
 	{"Box", (PyCFunction) Box_Constructor,
 		METH_VARARGS | METH_KEYWORDS, "Box object constructor."},
-	{"Pixmap", (PyCFunction) Pixmap_Constructor,
-		METH_VARARGS | METH_KEYWORDS, "Pixmap object constructor."},
 	{"DefaultSampler", (PyCFunction) DefaultSampler_Constructor,
 		METH_VARARGS | METH_KEYWORDS, "DefaultSampler object constructor."},
+
 	{"Container", (PyCFunction) Container_Constructor,
 		METH_NOARGS, "Container object constructor."},
 	{"Octree", (PyCFunction) Octree_Constructor,
 		METH_NOARGS, "Octree object constructor."},
 	{"KdTree", (PyCFunction) KdTree_Constructor,
 		METH_NOARGS, "KdTree object constructor."},
+
+	{"Raytracer", (PyCFunction) Raytracer_Constructor,
+		METH_VARARGS, "Raytracer object constructor."},
 	{NULL, NULL}
 };
 
@@ -1209,6 +1616,18 @@
 	|| PyType_Ready(&ContainerType) < 0
 	|| PyType_Ready(&OctreeType) < 0
 	|| PyType_Ready(&KdTreeType) < 0
+	|| PyType_Ready(&TextureMapType) < 0
+	|| PyType_Ready(&PlanarMapType) < 0
+	|| PyType_Ready(&CubicMapType) < 0
+	|| PyType_Ready(&CylinderMapType) < 0
+	|| PyType_Ready(&SphereMapType) < 0
+	|| PyType_Ready(&ColourMapType) < 0
+	|| PyType_Ready(&LinearColourMapType) < 0
+	|| PyType_Ready(&BoundColourMapType) < 0
+	|| PyType_Ready(&TextureType) < 0
+	|| PyType_Ready(&ImageTextureType) < 0
+	|| PyType_Ready(&CheckersTextureType) < 0
+	|| PyType_Ready(&CloudTextureType) < 0
 	)
 		return;