C++ demos: prepare infrastructure, add spheres_shadow.cc pyrit
authorRadek Brich <radek.brich@devl.cz>
Sun, 25 Nov 2007 17:58:29 +0100
branchpyrit
changeset 15 a0a3e334744f
parent 14 fc18ac4833f2
child 16 20bceb605f48
C++ demos: prepare infrastructure, add spheres_shadow.cc rename Ray::a to Ray::o KdNode::shapes changed to pointer and added to union together with *children (to save memory)
.bzrignore
Makefile
TODO
ccdemos/Makefile
ccdemos/image.c
ccdemos/image.h
ccdemos/spheres_shadow.cc
src/common.h
src/kdtree.cc
src/kdtree.h
src/raytracer.cc
src/scene.cc
src/scene.h
--- a/.bzrignore	Sun Nov 25 15:50:01 2007 +0100
+++ b/.bzrignore	Sun Nov 25 17:58:29 2007 +0100
@@ -1,2 +1,4 @@
 demos/*.png
+ccdemos/*.png
 demos/kdtree.obj
+demos/*.ply
--- a/Makefile	Sun Nov 25 15:50:01 2007 +0100
+++ b/Makefile	Sun Nov 25 17:58:29 2007 +0100
@@ -1,4 +1,4 @@
-CCFLAGS=-I./src -Wall -Wno-write-strings -O3 -fno-strict-aliasing -DPTHREADS
+CCFLAGS=-I./src -Wall -Wno-write-strings -g -O3 -fno-strict-aliasing -DPTHREADS
 LDFLAGS=
 
 ifeq ($(OS), Windows_NT)
@@ -46,7 +46,7 @@
 matrix.o: src/matrix.cc src/matrix.h src/vector.h
 noise.o: src/noise.cc src/noise.h
 scene.o: src/scene.cc src/scene.h src/vector.h src/noise.h src/common.h
-kdtree.o: src/kdtree.cc src/kdtree.h
+kdtree.o: src/kdtree.cc src/kdtree.h src/scene.h
 raytracer.o: src/raytracer.cc src/raytracer.h src/scene.h src/vector.h src/noise.h
 
 # python module
--- a/TODO	Sun Nov 25 15:50:01 2007 +0100
+++ b/TODO	Sun Nov 25 17:58:29 2007 +0100
@@ -3,9 +3,6 @@
    - optimize construction: do not use bounding boxes of shapes, instead implement box-shape intersection
  * transforms, camera
  * update Python binding, new classes
- * rename:
-   - Ray.a -> Ray.o or Ray.origin
- * C++ demos
  * more complex demos
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ccdemos/Makefile	Sun Nov 25 17:58:29 2007 +0100
@@ -0,0 +1,22 @@
+CCFLAGS=-g -I../src
+LDFLAGS=-L.. -lpng `python-config --libs`
+objs=image.o ../*.o
+
+all: image.o spheres_shadow
+
+%.o: %.c
+	$(CXX) -c -o $@ $*.c
+
+%.o: %.cc
+	$(CXX) -c -o $@ $*.cc $(CCFLAGS)
+
+%: %.o
+	(cd .. && make)
+	$(CXX) -o $@ $(objs) $*.o $(LDFLAGS)
+
+image.o: image.c
+spheres_shadow.o: spheres_shadow.cc
+spheres_shadow: spheres_shadow.o
+
+clean:
+	rm -f spheres_shadow *.o
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ccdemos/image.c	Sun Nov 25 17:58:29 2007 +0100
@@ -0,0 +1,114 @@
+/* This code is part of RGB Image Library
+   see URL: xxx */
+
+/**************************************************************************
+
+RGB Image Library (rgbimagelib)
+File: image.c
+
+Copyright (c) 2006 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.
+
+**************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <png.h>
+
+#include "image.h"
+
+int new_image(struct image **img, int width, int height, int pixelsize)
+{
+	*img = (struct image *) malloc(sizeof(struct image));
+	(*img)->pixel_size = pixelsize;
+	(*img)->width = width;
+	(*img)->height = height;
+	(*img)->data = (char *) malloc(width * height * pixelsize);
+	return(0);
+}
+
+int destroy_image(struct image **img)
+{
+	free((*img)->data);
+	free(*img);
+	*img = NULL;
+}
+
+/* funkce pro ulozeni obrazku do PNG souboru (vyuziva knihovnu libpng) */
+int save_png(const char *fname, struct image *img)
+{
+	int y; /* pomocna promenna pro pruchod radku obrazu */
+	FILE *f;
+	png_structp png;   /* PNG data */
+	png_infop pnginfo; /* PNG info */
+	char *data;
+
+	if ((f = fopen(fname, "wb")) == NULL)
+		return (0);
+
+	png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+	if (!png) {
+		fclose(f);
+		return (0);
+	}
+
+	pnginfo = png_create_info_struct(png);
+	if (!pnginfo) {
+		fclose(f);
+		png_destroy_write_struct(&png, 0);
+		return (0);
+	}
+
+	if (setjmp(png_jmpbuf(png))) {
+		fclose(f);
+		png_destroy_write_struct(&png, &pnginfo);
+		return (0);
+	}
+
+	/* predat knihovne PNG ukazatel na soubor */
+	png_init_io(png, f);
+
+	/* parametry PNG */
+	png_set_compression_level(png, Z_BEST_COMPRESSION);
+	png_set_IHDR(png, pnginfo, img->width, img->height, 8, PNG_COLOR_TYPE_RGB,
+		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+		PNG_FILTER_TYPE_DEFAULT);
+	png_set_sRGB(png, pnginfo, PNG_sRGB_INTENT_PERCEPTUAL);
+	png_set_sRGB_gAMA_and_cHRM(png, pnginfo, PNG_INFO_sRGB);
+
+	/* zapsat hlavicku */
+	png_write_info(png, pnginfo);
+
+	/* zapsat data */
+	data = img->data;
+	for (y = 0; y < img->height; y++, data += img->width * img->pixel_size)
+		png_write_row(png, (png_byte *) data);
+
+	/* ukoncit soubor a uvolnit pomocne struktury */
+	png_write_end(png, pnginfo);
+	png_destroy_write_struct(&png, 0);
+
+	fclose(f);
+
+	return (1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ccdemos/image.h	Sun Nov 25 17:58:29 2007 +0100
@@ -0,0 +1,20 @@
+#ifndef IMAGE_H
+#define IMAGE_H
+
+#define IMG_GRAYSCALE	1
+#define IMG_RGB		3
+
+/* raw image */
+struct image {
+	int pixel_size;  /* should be 1 for grayscale and 3 for RGB*/
+	int width;
+	int height;
+	char *data;
+};
+
+int new_image(struct image **img, int width, int height, int pixelsize);
+int destroy_image(struct image **img);
+
+int save_png(const char *fname, struct image *img);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ccdemos/spheres_shadow.cc	Sun Nov 25 17:58:29 2007 +0100
@@ -0,0 +1,47 @@
+#include "raytracer.h"
+#include "image.h"
+
+int main()
+{
+	Raytracer rt;
+	Light light1(Vector3(0.0, 5.0, 5.0), Colour(0.7, 0.3, 0.6));
+	rt.addlight(&light1);
+
+	Light light2(Vector3(-2.0, 10.0, 2.0), Colour(0.4, 0.6, 0.3));
+	rt.addlight(&light2);
+
+	Material mat0(Colour(0.7, 0.7, 0.7));
+
+	Box box(Vector3(-20.0, -1.2, -20.0), Vector3(20.0, -1.0, 20.0), &mat0);
+	rt.addshape(&box);
+
+	Material mat1(Colour(1.0, 0.0, 0.0));
+	Sphere bigsphere(Vector3(3.0, 2.0, 7.0), 3.0, &mat1);
+	rt.addshape(&bigsphere);
+
+	Material mat2(Colour(0.0, 1.0, 0.0));
+	Sphere smallsphere(Vector3(-5.5, 1.5, 8.0), 2.0, &mat2);
+	rt.addshape(&smallsphere);
+
+	Material mat3(Colour(0.0, 0.0, 1.0));
+	Sphere tinysphere(Vector3(-1.2, 0.0, 2.0), 0.5, &mat3);
+	rt.addshape(&tinysphere);
+
+	int w = 800;
+	int h = 600;
+	float *fdata = rt.render(w, h);
+
+	struct image *img;
+	new_image(&img, w, h, 3);
+
+	float *fd = fdata;
+	for (char *cd = img->data; cd != img->data + w*h*3; cd++, fd++) {
+		if (*fd > 1.0)
+			*cd = 255;
+		else
+			*cd = (unsigned char)(*fd * 255.0);
+	}
+	free(fdata);
+	save_png("spheres_shadow.png", img);
+	destroy_image(&img);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common.h	Sun Nov 25 17:58:29 2007 +0100
@@ -0,0 +1,9 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <float.h>
+
+#define Eps 1e-6
+#define Inf FLT_MAX
+
+#endif
--- a/src/kdtree.cc	Sun Nov 25 15:50:01 2007 +0100
+++ b/src/kdtree.cc	Sun Nov 25 17:58:29 2007 +0100
@@ -23,10 +23,10 @@
 class SortableShapeList: public vector<SortableShape>
 {
 public:
-	SortableShapeList(ShapeList &shapes, short axis)
+	SortableShapeList(ShapeList *shapes, short axis)
 	{
 		ShapeList::iterator shape;
-		for (shape = shapes.begin(); shape != shapes.end(); shape++)
+		for (shape = shapes->begin(); shape != shapes->end(); shape++)
 			push_back(SortableShape(*shape, axis));
 	};
 };
@@ -89,9 +89,9 @@
 
 void KdNode::subdivide(BBox bbox, int depth)
 {
-	if (depth >= 20 || shapes.size() <= 4)
+	if (depth >= 20 || shapes->size() <= 4)
 	{
-		leaf = true;
+		setLeaf();
 		return;
 	}
 
@@ -173,9 +173,9 @@
 	// choose best split pos
 	const float K = 1.4; // constant, K = cost of traversal / cost of ray-triangle intersection
 	float SAV = 2*(bbox.w()*bbox.h() + bbox.w()*bbox.d() + bbox.h()*bbox.d()); // surface area of node
-	float cost = SAV * (K + shapes.size()); // initial cost = non-split cost
+	float cost = SAV * (K + shapes->size()); // initial cost = non-split cost
 	SplitPos *splitpos = NULL;
-	leaf = true;
+	bool leaf = true;
 	BBox lbb = bbox;
 	BBox rbb = bbox;
 	for (spl = splitlist.begin(); spl != splitlist.end(); spl++)
@@ -196,9 +196,12 @@
 	}
 
 	if (leaf)
+	{
+		setLeaf();
 		return;
+	}
 
-#if 1
+#if 0
 // export kd-tree as .obj for visualization
 // this would be hard to reconstruct later
 	static ofstream F("kdtree.obj");
@@ -289,7 +292,7 @@
 void KdTree::build()
 {
 	root = new KdNode();
-	root->shapes = shapes;
+	root->shapes = &shapes;
 	root->subdivide(bbox, 0);
 	built = true;
 }
@@ -320,14 +323,14 @@
 
 	/* distinguish between internal and external origin */
 	if (a >= 0.0) /* a ray with external origin */
-		enPt->pb = ray.a + ray.dir * a;
+		enPt->pb = ray.o + ray.dir * a;
 	else /* a ray with internal origin */
-		enPt->pb = ray.a;
+		enPt->pb = ray.o;
 
 	/* setup initial exit point in the stack */
 	StackElem *exPt = new StackElem();
 	exPt->t = b;
-	exPt->pb = ray.a + ray.dir * b;
+	exPt->pb = ray.o + ray.dir * b;
 	exPt->node = NULL; /* set termination flag */
 
 	st.push(enPt);
@@ -374,7 +377,7 @@
 			/* case P4 or N4 . . . traverse both children */
 
 			/* signed distance to the splitting plane */
-			t = (splitVal - ray.a.cell[axis]) / ray.dir.cell[axis];
+			t = (splitVal - ray.o.cell[axis]) / ray.dir.cell[axis];
 
 			/* setup the new exit point */
 			st.push(exPt);
@@ -384,8 +387,8 @@
 			exPt->t = t;
 			exPt->node = farchild;
 			exPt->pb[axis] = splitVal;
-			exPt->pb[(axis+1)%3] = ray.a.cell[(axis+1)%3] + t * ray.dir.cell[(axis+1)%3];
-			exPt->pb[(axis+2)%3] = ray.a.cell[(axis+2)%3] + t * ray.dir.cell[(axis+2)%3];
+			exPt->pb[(axis+1)%3] = ray.o.cell[(axis+1)%3] + t * ray.dir.cell[(axis+1)%3];
+			exPt->pb[(axis+2)%3] = ray.o.cell[(axis+2)%3] + t * ray.dir.cell[(axis+2)%3];
 		} /* while */
 
 		/* current node is the leaf . . . empty or full */
@@ -394,7 +397,7 @@
 		Shape *nearest_shape = NULL;
 		float dist = exPt->t;
 		ShapeList::iterator shape;
-		for (shape = node->shapes.begin(); shape != node->shapes.end(); shape++)
+		for (shape = node->shapes->begin(); shape != node->shapes->end(); shape++)
 			if (*shape != origin_shape && (*shape)->intersect(ray, dist)
 			&& dist >= enPt->t)
 				nearest_shape = *shape;
@@ -431,7 +434,7 @@
 	if (node == NULL)
 		node = root;
 	if (node->isLeaf())
-		str << "(leaf: " << node->shapes.size() << " shapes)";
+		str << "(leaf: " << node->shapes->size() << " shapes)";
 	else
 	{
 		str << "(split " << (char)('x'+node->getAxis()) << " at " << node->getSplit() << "; L=";
--- a/src/kdtree.h	Sun Nov 25 15:50:01 2007 +0100
+++ b/src/kdtree.h	Sun Nov 25 17:58:29 2007 +0100
@@ -31,13 +31,14 @@
 class KdNode
 {
 	float split;
-	bool leaf; /* is this node a leaf? */
-	short axis; /* 0,1,2 => x,y,z */
-	KdNode *children;
+	short axis; /* 0,1,2 => x,y,z; 3 => leaf */
 public:
-	ShapeList shapes;
+	union {
+		KdNode *children;
+		ShapeList *shapes;
+	};
 
-	KdNode() : leaf(true), axis(0), shapes() {};
+	KdNode() : axis(3) { shapes = new ShapeList(); };
 
 	void setAxis(short aAxis) { axis = aAxis; };
 	short getAxis() { return axis; };
@@ -45,13 +46,13 @@
 	void setSplit(float aSplit) { split = aSplit; };
 	float getSplit() { return split; };
 
-	void setLeaf(bool aLeaf) { leaf = aLeaf; };
-	bool isLeaf() { return leaf; };
+	void setLeaf() { axis = 3; };
+	bool isLeaf() { return axis == 3; };
 
 	KdNode *getLeftChild() { return children; };
 	KdNode *getRightChild() { return children+1; };
 
-	void addShape(Shape* aShape) { shapes.push_back(aShape); };
+	void addShape(Shape* aShape) { shapes->push_back(aShape); };
 
 	void subdivide(BBox bbox, int depth);
 };
--- a/src/raytracer.cc	Sun Nov 25 15:50:01 2007 +0100
+++ b/src/raytracer.cc	Sun Nov 25 17:58:29 2007 +0100
@@ -99,7 +99,7 @@
 		return bg_colour;
 	} else {
 		Colour acc = Colour();
-		Vector3 P = ray.a + ray.dir * nearest_distance; // point of intersection
+		Vector3 P = ray.o + ray.dir * nearest_distance; // point of intersection
 		Vector3 normal = nearest_shape->normal(P);
 		acc = PhongShader_ambient(*nearest_shape->material, P);
 
@@ -211,17 +211,13 @@
 	RenderrowData *d;
 
 	printf("* building kd-tree\n");
-	//cout << endl;
 	top->optimize();
-	//static_cast<KdTree*>(top)->save(cout);
-	//cout << endl;
 
 	//srand(time(NULL));
 
-	// eye - viewing point
+	/* eye - viewing point */
 	Vector3 eye(0, 0, -5);
 
-	// for each pixel...
 	vy = starty;
 
 #ifdef PTHREADS
@@ -233,6 +229,7 @@
 	int t = 0;
 #endif
 
+	/* for each pixel... */
 	printf("* rendering row   0 (  0%% done)");
 	for (int y = 0; y < h; y++) {
 		d = (RenderrowData*) malloc(sizeof(RenderrowData));
--- a/src/scene.cc	Sun Nov 25 15:50:01 2007 +0100
+++ b/src/scene.cc	Sun Nov 25 17:58:29 2007 +0100
@@ -21,13 +21,13 @@
 	{
 		if (ray.dir.cell[i] == 0) {
 			/* ray is parallel to these planes */
-			if (ray.a.cell[i] < L.cell[i] || ray.a.cell[i] > H.cell[i])
+			if (ray.o.cell[i] < L.cell[i] || ray.o.cell[i] > H.cell[i])
 				return false;
 		} else
 		{
 			/* compute the intersection distance of the planes */
-			t1 = (L.cell[i] - ray.a.cell[i]) / ray.dir.cell[i];
-			t2 = (H.cell[i] - ray.a.cell[i]) / ray.dir.cell[i];
+			t1 = (L.cell[i] - ray.o.cell[i]) / ray.dir.cell[i];
+			t2 = (H.cell[i] - ray.o.cell[i]) / ray.dir.cell[i];
 
 			if (t1 > t2)
 				swap(t1, t2);
@@ -50,7 +50,7 @@
 
 bool Sphere::intersect(const Ray &ray, float &dist)
 {
-	Vector3 V = ((Ray)ray).a - center;
+	Vector3 V = ((Ray)ray).o - center;
 
 	float Vd = - dot(V, ray.dir);
 	float Det = Vd * Vd - (dot(V,V) - sqr_radius);
@@ -81,7 +81,7 @@
 {
 	//allts = new vector<float>();
 
-	Vector3 V = ((Ray)ray).a - center;
+	Vector3 V = ((Ray)ray).o - center;
 	float Vd = - dot(V, ray.dir);
 	float Det = Vd * Vd - (dot(V,V) - sqr_radius);
 
@@ -115,11 +115,7 @@
 {
 	BBox bbox = BBox();
 	bbox.L = center - radius;
-	//bbox.L.y = center.y - radius;
-	//bbox.L.z = center.z - radius;
 	bbox.H = center + radius;
-	//bbox.H.y = center.y + radius;
-	//bbox.H.z = center.z + radius;
 	return bbox;
 }
 
@@ -131,8 +127,8 @@
 
 Vector3 Box::normal(Vector3 &P)
 {
-	Vector3 N(0,1,0);
-	/*for (int i = 0; i < 3; i++)
+	Vector3 N;
+	for (int i = 0; i < 3; i++)
 	{
 		if (P.cell[i] >= L.cell[i]-Eps && P.cell[i] <= L.cell[i]+Eps)
 		//if (P.cell[i] == L.cell[i])
@@ -146,7 +142,7 @@
 			N.cell[i] = +1.0;
 			break;
 		}
-	}*/
+	}
 	return N;
 }
 
@@ -201,7 +197,7 @@
 // see comment for previous method
 bool Triangle::intersect(const Ray &ray, float &dist)
 {
-	Vector3 O = ray.a;
+	Vector3 O = ray.o;
 	Vector3 D = ray.dir;
 
 	const int modulo3[5] = {0,1,2,0,1};
--- a/src/scene.h	Sun Nov 25 15:50:01 2007 +0100
+++ b/src/scene.h	Sun Nov 25 17:58:29 2007 +0100
@@ -19,9 +19,9 @@
 class Ray
 {
 public:
-	Vector3 a, dir;
-	Ray(const Vector3 &aa, const Vector3 &adir):
-		a(aa), dir(adir) {};
+	Vector3 o, dir;
+	Ray(const Vector3 &ao, const Vector3 &adir):
+		o(ao), dir(adir) {};
 };
 
 /* axis-aligned bounding box */