rayzor

changeset 13:964f8ea5f095

missed quite a lot of things in my last commit apparently
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 12 Apr 2014 23:37:55 +0300
parents d94a69933a71
children a9a948809c6f
files GNUmakefile Makefile doc/sample.rzr src/camera.cc src/camera.h src/light.h src/object.h src/quat.h src/scene.h src/snode.cc src/snode.h src/vmathmat.h src/vmathray.h
diffstat 13 files changed, 484 insertions(+), 13 deletions(-) [+]
line diff
     1.1 --- a/GNUmakefile	Sat Apr 12 23:28:24 2014 +0300
     1.2 +++ b/GNUmakefile	Sat Apr 12 23:37:55 2014 +0300
     1.3 @@ -1,7 +1,7 @@
     1.4  baseobj = src/main.o src/logger.o src/screen.o src/scrman.o
     1.5  modelobj = src/modeller.o src/min3d.o src/m3drast.o src/lines.o
     1.6  rendobj = src/renderer.o src/vmath.o
     1.7 -scnobj = src/scene.o src/object.o src/xfnode.o
     1.8 +scnobj = src/scene.o src/object.o src/light.o src/camera.o src/snode.o
     1.9  sysobj = src/dosemu/dosemu.o
    1.10  obj = $(baseobj) $(modelobj) $(rendobj) $(scnobj) $(sysobj)
    1.11  dep = $(obj:.o=.d)
     2.1 --- a/Makefile	Sat Apr 12 23:28:24 2014 +0300
     2.2 +++ b/Makefile	Sat Apr 12 23:37:55 2014 +0300
     2.3 @@ -1,7 +1,7 @@
     2.4  baseobj = main.obj logger.obj screen.obj scrman.obj swapbuf.obj
     2.5  modelobj = modeller.obj min3d.obj m3drast.obj lines.obj
     2.6  rendobj = renderer.obj vmath.obj
     2.7 -scnobj = scene.obj object.obj xfnode.obj
     2.8 +scnobj = scene.obj object.obj light.obj camera.obj snode.obj
     2.9  sysobj = gfx.obj vbe.obj dpmi.obj timer.obj mouse.obj keyb.obj
    2.10  obj = $(baseobj) $(modelobj) $(rendobj) $(scnobj) $(sysobj)
    2.11  bin = rayzor.exe
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/doc/sample.rzr	Sat Apr 12 23:37:55 2014 +0300
     3.3 @@ -0,0 +1,61 @@
     3.4 +# vim:set ts=4 sw=4 sts=4 ai:
     3.5 +scene {
     3.6 +	name = "test"
     3.7 +
     3.8 +	material {
     3.9 +		name = "red"
    3.10 +		diffuse = [1, 0, 0]
    3.11 +		specular = [0.8, 0.8, 0.8]
    3.12 +		shininess = 32.0
    3.13 +	}
    3.14 +
    3.15 +	material {
    3.16 +		name = "mirror"
    3.17 +		diffuse = [0.15 0.15 0.15]
    3.18 +		specular = [0.9 0.9 0.9]
    3.19 +		shininess = 60
    3.20 +		reflect = 0.9
    3.21 +	}
    3.22 +
    3.23 +	object {
    3.24 +		name = "sph01"
    3.25 +		type = "sphere"
    3.26 +		material = "red"
    3.27 +
    3.28 +		xform { position = [0, 1, 0] }
    3.29 +	}
    3.30 +
    3.31 +	object {
    3.32 +		name = "box01"
    3.33 +		type = "box"
    3.34 +		material = "mirror"
    3.35 +
    3.36 +		xform { scale = [3, 0.2, 3] }
    3.37 +	}
    3.38 +
    3.39 +	light {
    3.40 +		name = "lt-prim"
    3.41 +		type = "point"
    3.42 +		color = [1, 0.95, 0.85]
    3.43 +
    3.44 +		xform { position = [-10, 10, 10] }
    3.45 +	}
    3.46 +
    3.47 +	light {
    3.48 +		name = "lt-sec"
    3.49 +		type = "point"
    3.50 +		color = [0.3, 0.4, 0.75]
    3.51 +
    3.52 +		xform { position = [20, 10, 6] }
    3.53 +	}
    3.54 +
    3.55 +	camera {
    3.56 +		name = "cam01"
    3.57 +		type = "lookat"
    3.58 +		fov = 50
    3.59 +
    3.60 +		xform { position = [0, 5, 6] }
    3.61 +
    3.62 +		target = [0, 0, 0]
    3.63 +	}
    3.64 +}
     4.1 --- a/src/camera.cc	Sat Apr 12 23:28:24 2014 +0300
     4.2 +++ b/src/camera.cc	Sat Apr 12 23:37:55 2014 +0300
     4.3 @@ -9,12 +9,12 @@
     4.4  
     4.5  void Camera::set_target(const Vector3 &target)
     4.6  {
     4.7 -	this->target->set_position(target);
     4.8 +	this->target.set_position(target);
     4.9  }
    4.10  
    4.11 -const Vector3 &Camera::get_target() const
    4.12 +Vector3 Camera::get_target() const
    4.13  {
    4.14 -	return target->get_position();
    4.15 +	return target.get_position();
    4.16  }
    4.17  
    4.18  void Camera::set_fov(float fov)
    4.19 @@ -30,7 +30,7 @@
    4.20  void Camera::calc_matrix() const
    4.21  {
    4.22  	xform.set_identity();
    4.23 -	xform.lookat(pos, target, Vector3(0, 1, 0));
    4.24 +	xform.lookat(pos, target.get_position(), Vector3(0, 1, 0));
    4.25  	xform_valid = true;
    4.26  }
    4.27  
    4.28 @@ -43,7 +43,7 @@
    4.29  {
    4.30  }
    4.31  
    4.32 -bool Camera::intersect(const Ray &ray, float *dist)
    4.33 +bool Camera::intersect(const Ray &ray, float *dist) const
    4.34  {
    4.35  	return false;
    4.36  }
     5.1 --- a/src/camera.h	Sat Apr 12 23:28:24 2014 +0300
     5.2 +++ b/src/camera.h	Sat Apr 12 23:37:55 2014 +0300
     5.3 @@ -2,7 +2,7 @@
     5.4  #define CAMERA_H_
     5.5  
     5.6  #include "vmath.h"
     5.7 -#include "xfnode.h"
     5.8 +#include "snode.h"
     5.9  
    5.10  class Camera : public SceneNode {
    5.11  private:
    5.12 @@ -16,7 +16,7 @@
    5.13  	Camera();
    5.14  
    5.15  	void set_target(const Vector3 &target);
    5.16 -	const Vector3 &get_target() const;
    5.17 +	Vector3 get_target() const;
    5.18  
    5.19  	void set_fov(float fov);
    5.20  	float get_fov() const;
     6.1 --- a/src/light.h	Sat Apr 12 23:28:24 2014 +0300
     6.2 +++ b/src/light.h	Sat Apr 12 23:37:55 2014 +0300
     6.3 @@ -2,7 +2,7 @@
     6.4  #define LIGHT_H_
     6.5  
     6.6  #include "vmath.h"
     6.7 -#include "xfnode.h"
     6.8 +#include "snode.h"
     6.9  
    6.10  class Light : public SceneNode {
    6.11  private:
     7.1 --- a/src/object.h	Sat Apr 12 23:28:24 2014 +0300
     7.2 +++ b/src/object.h	Sat Apr 12 23:37:55 2014 +0300
     7.3 @@ -2,7 +2,7 @@
     7.4  #define OBJECT_H_
     7.5  
     7.6  #include "vmath.h"
     7.7 -#include "xfnode.h"
     7.8 +#include "snode.h"
     7.9  
    7.10  class Object : public SceneNode {
    7.11  protected:
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/quat.h	Sat Apr 12 23:37:55 2014 +0300
     8.3 @@ -0,0 +1,108 @@
     8.4 +#ifndef QUATERNION_H_
     8.5 +#define	QUATERNION_H_
     8.6 +
     8.7 +class Quat;
     8.8 +
     8.9 +inline Quat operator *(const Quat &a, const Quat &b);
    8.10 +
    8.11 +class Quat{
    8.12 +public:
    8.13 +	float x, y, z, w;
    8.14 +
    8.15 +	Quat() : x(0), y(0), z(0), w(1) {}
    8.16 +	Quat(float xx, float yy, float zz, float ww) : x(xx), y(yy), z(zz), w(ww) {}
    8.17 +
    8.18 +	void set_identity()
    8.19 +	{
    8.20 +		x = y = z = 0.0f;
    8.21 +		w = 1.0f;
    8.22 +	}
    8.23 +
    8.24 +	Quat conjugate() const
    8.25 +	{
    8.26 +		return Quat(-x, -y, -z, w);
    8.27 +	}
    8.28 +
    8.29 +	float length() const
    8.30 +	{
    8.31 +		return (float)sqrt(x * x + y * y + z * z + w * w);
    8.32 +	}
    8.33 +
    8.34 +	float length_sq() const
    8.35 +	{
    8.36 +		return x * x + y * y + z * z + w * w;
    8.37 +	}
    8.38 +
    8.39 +	void normalize()
    8.40 +	{
    8.41 +		float len = length();
    8.42 +		if(len != 0.0) {
    8.43 +			x /= len;
    8.44 +			y /= len;
    8.45 +			z /= len;
    8.46 +			w /= len;
    8.47 +		}
    8.48 +	}
    8.49 +
    8.50 +	Quat inverse() const
    8.51 +	{
    8.52 +		Quat inv = conjugate();
    8.53 +		float len_sq = length_sq();
    8.54 +		if(len_sq != 0.0) {
    8.55 +			inv.x /= len_sq;
    8.56 +			inv.y /= len_sq;
    8.57 +			inv.z /= len_sq;
    8.58 +			inv.w /= len_sq;
    8.59 +		}
    8.60 +		return inv;
    8.61 +	}
    8.62 +
    8.63 +	void set_rotation(float angle, float axis_x, float axis_y, float axis_z)
    8.64 +	{
    8.65 +		float half_angle = angle * 0.5;
    8.66 +		float sin_half = sin(half_angle);
    8.67 +
    8.68 +		w = cos(half_angle);
    8.69 +		x = axis_x * sin_half;
    8.70 +		y = axis_y * sin_half;
    8.71 +		z = axis_z * sin_half;
    8.72 +	}
    8.73 +
    8.74 +	void rotate(float angle, float x, float y, float z)
    8.75 +	{
    8.76 +		Quat q;
    8.77 +		q.set_rotation(angle, x, y, z);
    8.78 +		*this = *this * q;
    8.79 +	}
    8.80 +
    8.81 +	void rotate(const Quat &q)
    8.82 +	{
    8.83 +		*this = q * *this * q.conjugate();
    8.84 +	}
    8.85 +
    8.86 +	Matrix4x4 get_matrix() const
    8.87 +	{
    8.88 +		return Matrix4x4(
    8.89 +			1.0 - 2.0 * y*y - 2.0 * z*z,	2.0 * x * y - 2.0 * w * z,		2.0 * z * x + 2.0 * w * y, 0,
    8.90 +			2.0 * x * y + 2.0 * w * z,		1.0 - 2.0 * x*x - 2.0 * z*z,	2.0 * y * z - 2.0 * w * x, 0,
    8.91 +			2.0 * z * x - 2.0 * w * y,		2.0 * y * z + 2.0 * w * x,		1.0 - 2.0 * x*x - 2.0 * y*y, 0,
    8.92 +			0, 0, 0, 1);
    8.93 +	}
    8.94 +};
    8.95 +
    8.96 +inline Quat operator *(const Quat &a, const Quat &b)
    8.97 +{
    8.98 +	float dot = a.x * b.x + a.y * b.y + a.z * b.z;
    8.99 +	float cross_x = a.y * b.z - a.z * b.y;
   8.100 +	float cross_y = a.z * b.x - a.x * b.z;
   8.101 +	float cross_z = a.x * b.y - a.y * b.x;
   8.102 +
   8.103 +	float w = a.w * b.w - dot;
   8.104 +	float x = a.x * b.w + b.x * a.w + cross_x;
   8.105 +	float y = a.y * b.w + b.y * a.w + cross_y;
   8.106 +	float z = a.z * b.w + b.z * a.w + cross_z;
   8.107 +
   8.108 +	return Quat(x, y, z, w);
   8.109 +}
   8.110 +
   8.111 +#endif	// QUATERNION_H_
     9.1 --- a/src/scene.h	Sat Apr 12 23:28:24 2014 +0300
     9.2 +++ b/src/scene.h	Sat Apr 12 23:37:55 2014 +0300
     9.3 @@ -3,7 +3,7 @@
     9.4  
     9.5  #include <string>
     9.6  #include <vector.h>
     9.7 -#include "xfnode.h"
     9.8 +#include "snode.h"
     9.9  #include "object.h"
    9.10  #include "light.h"
    9.11  #include "camera.h"
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/snode.cc	Sat Apr 12 23:37:55 2014 +0300
    10.3 @@ -0,0 +1,193 @@
    10.4 +#include <string.h>
    10.5 +#include <assert.h>
    10.6 +#include "snode.h"
    10.7 +
    10.8 +
    10.9 +SceneNode::SceneNode()
   10.10 +{
   10.11 +	parent = 0;
   10.12 +	name = 0;
   10.13 +	type = NODE_NULL;
   10.14 +	scale = Vector3(1, 1, 1);
   10.15 +	invalidate();
   10.16 +}
   10.17 +
   10.18 +SceneNode::~SceneNode()
   10.19 +{
   10.20 +	delete [] name;
   10.21 +}
   10.22 +
   10.23 +void SceneNode::set_name(const char *name)
   10.24 +{
   10.25 +	this->name = new char[strlen(name) + 1];
   10.26 +	strcpy(this->name, name);
   10.27 +}
   10.28 +
   10.29 +const char *SceneNode::get_name() const
   10.30 +{
   10.31 +	return name ? name : "<unnamed>";
   10.32 +}
   10.33 +
   10.34 +NodeType SceneNode::get_type() const
   10.35 +{
   10.36 +	return type;
   10.37 +}
   10.38 +
   10.39 +SceneNode *SceneNode::get_parent()
   10.40 +{
   10.41 +	return parent;
   10.42 +}
   10.43 +
   10.44 +const SceneNode *SceneNode::get_parent() const
   10.45 +{
   10.46 +	return parent;
   10.47 +}
   10.48 +
   10.49 +void SceneNode::add_child(SceneNode *child)
   10.50 +{
   10.51 +	children.push_back(child);
   10.52 +	child->parent = this;
   10.53 +	invalidate();
   10.54 +}
   10.55 +
   10.56 +void SceneNode::remove_child(SceneNode *child)
   10.57 +{
   10.58 +	// TODO
   10.59 +	invalidate();
   10.60 +}
   10.61 +
   10.62 +int SceneNode::get_children_count() const
   10.63 +{
   10.64 +	return (int)children.size();
   10.65 +}
   10.66 +
   10.67 +SceneNode *SceneNode::get_child(int idx)
   10.68 +{
   10.69 +	if(idx >= 0 && idx < get_children_count()) {
   10.70 +		return children[idx];
   10.71 +	}
   10.72 +	return 0;
   10.73 +}
   10.74 +
   10.75 +const SceneNode *SceneNode::get_child(int idx) const
   10.76 +{
   10.77 +	if(idx >= 0 && idx < get_children_count()) {
   10.78 +		return children[idx];
   10.79 +	}
   10.80 +	return 0;
   10.81 +}
   10.82 +
   10.83 +
   10.84 +
   10.85 +void SceneNode::set_position(const Vector3 &pos)
   10.86 +{
   10.87 +	this->pos = pos;
   10.88 +	invalidate();
   10.89 +}
   10.90 +
   10.91 +Vector3 SceneNode::get_node_position() const
   10.92 +{
   10.93 +	return pos;
   10.94 +}
   10.95 +
   10.96 +void SceneNode::set_rotation(const Quat &quat)
   10.97 +{
   10.98 +	rot = quat;
   10.99 +	invalidate();
  10.100 +}
  10.101 +
  10.102 +Quat SceneNode::get_node_rotation() const
  10.103 +{
  10.104 +	return rot;
  10.105 +}
  10.106 +
  10.107 +void SceneNode::set_scaling(const Vector3 &scale)
  10.108 +{
  10.109 +	this->scale = scale;
  10.110 +	invalidate();
  10.111 +}
  10.112 +
  10.113 +Vector3 SceneNode::get_node_scaling() const
  10.114 +{
  10.115 +	return scale;
  10.116 +}
  10.117 +
  10.118 +// these take hierarchy into account
  10.119 +Vector3 SceneNode::get_position() const
  10.120 +{
  10.121 +	return transform(get_matrix(), Vector3(0, 0, 0));
  10.122 +}
  10.123 +
  10.124 +Quat SceneNode::get_rotation() const
  10.125 +{
  10.126 +	if(parent) {
  10.127 +		return parent->get_rotation() * rot;
  10.128 +	}
  10.129 +	return rot;
  10.130 +}
  10.131 +
  10.132 +Vector3 SceneNode::get_scaling() const
  10.133 +{
  10.134 +	if(parent) {
  10.135 +		return parent->get_scaling() * scale;
  10.136 +	}
  10.137 +	return scale;
  10.138 +}
  10.139 +
  10.140 +void SceneNode::set_pivot(const Vector3 &pivot)
  10.141 +{
  10.142 +	this->pivot = pivot;
  10.143 +	invalidate();
  10.144 +}
  10.145 +
  10.146 +Vector3 SceneNode::get_pivot() const
  10.147 +{
  10.148 +	return pivot;
  10.149 +}
  10.150 +
  10.151 +const Matrix4x4 &SceneNode::get_matrix() const
  10.152 +{
  10.153 +	calc_matrix();
  10.154 +	return xform;
  10.155 +}
  10.156 +
  10.157 +const Matrix4x4 &SceneNode::get_inv_matrix() const
  10.158 +{
  10.159 +	calc_inv_matrix();
  10.160 +	return inv_xform;
  10.161 +}
  10.162 +
  10.163 +void SceneNode::invalidate() const
  10.164 +{
  10.165 +	xform_valid = inv_xform_valid = false;
  10.166 +}
  10.167 +
  10.168 +// TODO: hierarchy
  10.169 +void SceneNode::calc_matrix() const
  10.170 +{
  10.171 +	xform.set_identity();
  10.172 +	xform.translate(pivot.x, pivot.y, pivot.z);
  10.173 +	xform = xform * rot.get_matrix();
  10.174 +	xform.translate(pos.x, pos.y, pos.z);
  10.175 +	xform.scale(scale.x, scale.y, scale.z);
  10.176 +	xform.translate(-pivot.x, -pivot.y, -pivot.z);
  10.177 +
  10.178 +	xform_valid = true;
  10.179 +}
  10.180 +
  10.181 +void SceneNode::calc_inv_matrix() const
  10.182 +{
  10.183 +	calc_matrix();
  10.184 +
  10.185 +	inv_xform = xform.inverse();
  10.186 +	inv_xform_valid = true;
  10.187 +}
  10.188 +
  10.189 +void SceneNode::draw() const
  10.190 +{
  10.191 +}
  10.192 +
  10.193 +bool SceneNode::intersect(const Ray &ray, float *dist) const
  10.194 +{
  10.195 +	return false;
  10.196 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/snode.h	Sat Apr 12 23:37:55 2014 +0300
    11.3 @@ -0,0 +1,85 @@
    11.4 +#ifndef SCENE_NODE_H_
    11.5 +#define SCENE_NODE_H_
    11.6 +
    11.7 +#include "vector.h"
    11.8 +#include "vmath.h"
    11.9 +#include "quat.h"
   11.10 +#include "vmathmat.h"
   11.11 +#include "vmathray.h"
   11.12 +
   11.13 +enum NodeType {
   11.14 +	NODE_NULL,
   11.15 +	NODE_OBJECT,
   11.16 +	NODE_LIGHT,
   11.17 +	NODE_CAMERA
   11.18 +};
   11.19 +
   11.20 +class SceneNode {
   11.21 +protected:
   11.22 +	char *name;
   11.23 +	NodeType type;
   11.24 +
   11.25 +	Vector3 pos;
   11.26 +	Quat rot;
   11.27 +	Vector3 scale;
   11.28 +	Vector3 pivot;
   11.29 +
   11.30 +	mutable Matrix4x4 xform, inv_xform;
   11.31 +	mutable bool xform_valid, inv_xform_valid;
   11.32 +
   11.33 +	vector<SceneNode*> children;
   11.34 +	SceneNode *parent;
   11.35 +
   11.36 +	SceneNode(const SceneNode &node) {}
   11.37 +	SceneNode &operator =(const SceneNode &node) { return *this; }
   11.38 +
   11.39 +	void invalidate() const;
   11.40 +	virtual void calc_matrix() const;
   11.41 +	virtual void calc_inv_matrix() const;
   11.42 +
   11.43 +public:
   11.44 +	SceneNode();
   11.45 +	virtual ~SceneNode();
   11.46 +
   11.47 +	virtual void set_name(const char *name);
   11.48 +	virtual const char *get_name() const;
   11.49 +
   11.50 +	virtual NodeType get_type() const;
   11.51 +
   11.52 +	virtual SceneNode *get_parent();
   11.53 +	virtual const SceneNode *get_parent() const;
   11.54 +
   11.55 +	// children management
   11.56 +	virtual void add_child(SceneNode *child);
   11.57 +	virtual void remove_child(SceneNode *child);
   11.58 +
   11.59 +	virtual int get_children_count() const;
   11.60 +	virtual SceneNode *get_child(int idx);
   11.61 +	virtual const SceneNode *get_child(int idx) const;
   11.62 +
   11.63 +	virtual void set_position(const Vector3 &pos);
   11.64 +	virtual Vector3 get_node_position() const;
   11.65 +
   11.66 +	virtual void set_rotation(const Quat &quat);
   11.67 +	virtual Quat get_node_rotation() const;
   11.68 +
   11.69 +	virtual void set_scaling(const Vector3 &scale);
   11.70 +	virtual Vector3 get_node_scaling() const;
   11.71 +
   11.72 +	// these take hierarchy into account
   11.73 +	virtual Vector3 get_position() const;
   11.74 +	virtual Quat get_rotation() const;
   11.75 +	virtual Vector3 get_scaling() const;
   11.76 +
   11.77 +	virtual void set_pivot(const Vector3 &pivot);
   11.78 +	virtual Vector3 get_pivot() const;
   11.79 +
   11.80 +	virtual const Matrix4x4 &get_matrix() const;
   11.81 +	virtual const Matrix4x4 &get_inv_matrix() const;
   11.82 +
   11.83 +	virtual void draw() const;
   11.84 +
   11.85 +	virtual bool intersect(const Ray &ray, float *dist = 0) const;
   11.86 +};
   11.87 +
   11.88 +#endif	/* SCENE_NODE_H_ */
    12.1 --- a/src/vmathmat.h	Sat Apr 12 23:28:24 2014 +0300
    12.2 +++ b/src/vmathmat.h	Sat Apr 12 23:37:55 2014 +0300
    12.3 @@ -34,7 +34,7 @@
    12.4  	inline void rotate(float angle, float x, float y, float z);
    12.5  	inline void scale(float x, float y, float z);
    12.6  	inline void perspective(float vfov, float aspect, float znear, float zfar);
    12.7 -	inline void lookat(const Vector3 &pos, const Vector3 &targ, const Vector3 &up);
    12.8 +	void lookat(const Vector3 &pos, const Vector3 &targ, const Vector3 &up);
    12.9  
   12.10  	float *operator [](int idx) { return m[idx]; }
   12.11  	const float *operator [](int idx) const { return m[idx]; }
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/vmathray.h	Sat Apr 12 23:37:55 2014 +0300
    13.3 @@ -0,0 +1,24 @@
    13.4 +#ifndef VMATH_RAY_H_
    13.5 +#define VMATH_RAY_H_
    13.6 +
    13.7 +#include "vmath.h"
    13.8 +#include "vmathmat.h"
    13.9 +
   13.10 +class Ray {
   13.11 +public:
   13.12 +	Vector3 pos, dir;
   13.13 +
   13.14 +	Ray() {}
   13.15 +	Ray(const Vector3 &p, const Vector3 &d) : pos(p), dir(d) {}
   13.16 +};
   13.17 +
   13.18 +inline Ray transform(const Matrix4x4 &m, const Ray &r)
   13.19 +{
   13.20 +	Matrix4x4 rmat = m;
   13.21 +	rmat[0][3] = rmat[1][3] = rmat[2][3] = rmat[3][0] = rmat[3][1] = rmat[3][2] = 0.0;
   13.22 +	rmat[3][3] = 1.0;
   13.23 +
   13.24 +	return Ray(transform(m, r.pos), transform(rmat, r.dir));
   13.25 +}
   13.26 +
   13.27 +#endif	// VMATH_RAY_H_