diff --git a/configure.ac b/configure.ac
index 07494ad..90ac1fa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,5 +32,5 @@ LIBS="$LIBS $SDL_LIBS -lSDL_image"
 
 CXXFLAGS="$CFLAGS"
 
-AC_CONFIG_FILES([Makefile src/Makefile src/sbre/Makefile])
+AC_CONFIG_FILES([Makefile src/Makefile src/sbre/Makefile src/collider/Makefile])
 AC_OUTPUT
diff --git a/src/Makefile.am b/src/Makefile.am
index 6b9094c..bbae6ab 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
 ## Process this file with automake to produce Makefile.in
-SUBDIRS = sbre/
+SUBDIRS = sbre/ collider/
 
 bin_PROGRAMS		= Lephisto3D ModelViewer
 noinst_LIBRARIES = libgui.a
@@ -21,9 +21,9 @@ Lephisto3D_SOURCES	= main.cpp glfreetype.cpp body.cpp space.cpp ship.cpp player.
 											star_system.cpp sector.cpp system_info_view.cpp generic_system_view.cpp date.cpp space_station.cpp \
 											space_station_view.cpp model_body.cpp ship_type.cpp info_view.cpp model_coll_mesh_data.cpp \
 											object_viewer_view.cpp custom_starsystems.cpp serializer.cpp
-Lephisto3D_LDADD = sbre/libsbre.a libgui.a
+Lephisto3D_LDADD = sbre/libsbre.a collider/libcollider.a libgui.a
 
 ModelViewer_SOURCES = sbre_viewer.cpp glfreetype.cpp
-ModelViewer_LDADD = sbre/libsbre.a libgui.a
+ModelViewer_LDADD = sbre/libsbre.a collider/libcollider.a libgui.a
 
 
diff --git a/src/collider/Makefile.am b/src/collider/Makefile.am
new file mode 100644
index 0000000..1435d45
--- /dev/null
+++ b/src/collider/Makefile.am
@@ -0,0 +1,5 @@
+noinst_LIBRARIES = libcollider.a
+libcollider_a_SOURCES = geom_tree.cpp
+
+include_HEADERS = geom_tree.h
+
diff --git a/src/collider/geom_tree.cpp b/src/collider/geom_tree.cpp
new file mode 100644
index 0000000..d039c35
--- /dev/null
+++ b/src/collider/geom_tree.cpp
@@ -0,0 +1,417 @@
+/*
+ * Bounding interval hierarchy tree building algorithm.
+ *
+ * These things get used in interactive raytracers. They are nice because:
+ *  n log n builders are easy to write.
+ *  memory requirment is more predictable than kd-trees.
+ *  You don't need a 'mailbox' as objects only appear once in the hierarchy.
+ *  single ray traversal performance is comparable to kd-tree and way faster than bvh.
+ */
+#define MAX_LEAF_PRIMS        2
+#define MAX_DEPTH             20
+#define MAX_SPLITPOS_RETRIES  32
+
+#include <float.h>
+#include <stdio.h>
+#include <assert.h>
+#include <alloca.h>
+#include "../aabb.h"
+#include "geom_tree.h"
+
+#define DEBUG
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+
+class DisplayList;
+
+struct tri_t {
+  int triIdx;
+  tri_t* next;
+  tri_t* GetNext(void) { return next; }
+};
+
+class BIHNode {
+public:
+  BIHNode(void) { m_isleaf = 1; m_axis = 0; m_list = 0; m_left = 0; }
+  void Add(tri_t* tri) {
+    tri->next = GetList();
+    SetList(tri);
+  }
+
+  float FindNiceSplitPos(int splitAxis, int* numPoints, int* numPrims);
+  void Dump(int depth, Aabb& box);
+  void SetAxis(int axis)                { m_axis = axis; }
+  int GetAxis(void) const               { return m_axis; }
+  void SetSplitPos1(float p)            { splitPos1 = p; }
+  void SetSplitPos2(float p)            { splitPos2 = p; }
+  float GetSplitPos1(void)              { return splitPos1; }
+  float GetSplitPos2(void)              { return splitPos2; }
+  void AllocChild(GeomTree* geomTree);
+  void SetLeaf(bool isLeaf)             { m_isleaf = isLeaf; }
+  bool IsLeaf(void)                     { return m_isleaf; }
+  tri_t* GetList(void)                  { return m_list; }
+  BIHNode* GetLeft(void)                { return m_left; }
+  BIHNode* GetRight(void)               { return GetLeft() + 1; }
+  void SetLeft(BIHNode* left)           { m_left = left; }
+  void SetList(tri_t* t)                { m_list = t; }
+
+private:
+  short m_axis;
+  short m_isleaf;
+  union {
+    BIHNode* m_left;
+    tri_t* m_list;
+  };
+  float splitPos1, splitPos2;
+};
+
+void BIHNode::AllocChild(GeomTree* geomTree) {
+  m_left = geomTree->AllocNode();
+  geomTree->AllocNode();
+  /* Right child is implicitly lefet+1. */
+}
+
+BIHNode* GeomTree::AllocNode(void) {
+  assert(m_nodesAllocPos+1 < m_nodesAllocSize);
+  return &m_nodes[m_nodesAllocPos++];
+}
+
+GeomTree::~GeomTree(void) {
+  delete [] m_nodes;
+  delete [] m_triAlloc;
+}
+
+GeomTree::GeomTree(int numTris, float* vertices, int* indices) {
+  m_vertices = vertices;
+  m_indices = indices;
+  m_aabb.min = vector3d(FLT_MAX, FLT_MAX, FLT_MAX);
+  m_aabb.max = vector3d(FLT_MAX, FLT_MAX, FLT_MAX);
+
+  m_triAlloc = new tri_t[numTris];
+  for(int i = 0; i < numTris; i++) {
+    m_aabb.Update(vector3d(vertices[3*i], vertices[3*i+1], vertices[3*i+2]));
+    m_triAlloc[i].triIdx = 3*i;
+    m_triAlloc[i].next = m_triAlloc+i+1;
+  }
+  m_triAlloc[numTris-1].next = 0;
+
+  printf("Building BIHTree of %d triangles\n", numTris);
+  printf("Aabb: %f,%f,%f -> %f,%f,%f\n",
+      m_aabb.min.x,
+      m_aabb.min.y,
+      m_aabb.min.z,
+      m_aabb.max.x,
+      m_aabb.max.y,
+      m_aabb.max.z);
+  m_nodes = new BIHNode[numTris*2];
+  m_nodesAllocSize = numTris*2;
+  m_nodesAllocPos = 0;
+  m_triAllocPos = 0;
+
+  BIHNode* root = AllocNode();
+  root->SetList(m_triAlloc);
+
+  Aabb splitBox = m_aabb;
+  BihTreeGhBuild(root, m_aabb, splitBox, 0, numTris);
+}
+
+void GeomTree::BihTreeGhBuild(BIHNode* a_node, Aabb& a_box, Aabb& a_splitBox, int a_depth, int a_prims) {
+  tri_t** prim_lump = (tri_t**)alloca(sizeof(tri_t*)*a_prims);
+  int num = 0;
+
+  for(tri_t* kdprim = a_node->GetList(); kdprim != NULL; kdprim = kdprim->GetNext()) {
+    prim_lump[num++] = kdprim;
+  }
+
+  /* Simple master split pos picking for the moment. */
+  float splitPos;
+  float splitPos1;
+  float splitPos2;
+
+  a_node->SetLeaf(false);
+  a_node->AllocChild(this);
+  BIHNode* left = a_node->GetLeft();
+  BIHNode* right = a_node->GetRight();
+
+  int s1count, s2count, splitAxis, attempt;
+  attempt = 0;
+
+  for(;;) {
+    splitAxis = 0;
+    vector3d splitBoxSize = a_splitBox.max - a_splitBox.min;
+    if(splitBoxSize.y > splitBoxSize.x) splitAxis = 1;
+    if((splitBoxSize.z > splitBoxSize.y) && (splitBoxSize.z > splitBoxSize.x)) splitAxis = 2;
+
+    /* Split pos in middle of a_splitBox. */
+    splitPos = 0.5f * (a_splitBox.min[splitAxis] + a_splitBox.max[splitAxis]);
+
+    //printf("\n%d: %f ", attemt, splitPos);
+    splitPos1 = a_box.min[splitAxis];
+    splitPos2 = a_box.max[splitAxis];
+
+    s1count = 0, s2count = 0;
+    float fooSum = 0.0f;
+
+    left->SetList(0);
+    right->SetList(0);
+
+    for(int i = 0; i < a_prims; i++) {
+      const int v0 = m_indices[prim_lump[i]->triIdx];
+      const int v1 = m_indices[prim_lump[i]->triIdx+1];
+      const int v2 = m_indices[prim_lump[i]->triIdx+2];
+
+      float p0, p1, p2;
+      float mid;
+
+      p0 = m_vertices[3*v0 + splitAxis];
+      p1 = m_vertices[3*v1 + splitAxis];
+      p2 = m_vertices[3*v2 + splitAxis];
+
+      mid = (p0 + p1 + p2)*0.3333333333333333333f;
+
+      float p_min, p_max;
+
+      p_min = MIN(p0, MIN(p1, p2));
+      p_max = MAX(p0, MAX(p1, p2));
+
+      tri_t* foo = prim_lump[i];
+
+      fooSum += mid;
+
+      if(mid < splitPos) {
+        left->Add(foo);
+        s1count++;
+        if(p_max > splitPos1) splitPos1 = p_max;
+      } else {
+        right->Add(foo);
+        s2count++;
+        if(p_min < splitPos2) splitPos2 = p_min;
+      }
+    }
+    if(s1count == a_prims) {
+      /*
+       * If one side takes up the whole darn parent aabb then
+       * just give up trying to split.
+       */
+      if(splitPos1 >= a_box.max[splitAxis]) {
+        if(attempt < MAX_SPLITPOS_RETRIES) {
+          /* Try splitting at average point. */
+          //printf("YES!!! %d, %f\n", attempt, splitPos);
+          a_splitBox.max = splitPos;
+          attempt++;
+          continue;
+        }
+
+        printf("Warning: Fat node with %d primitives\n", a_prims);
+
+        a_node->SetLeaf(true);
+        a_node->SetList(left->GetList());
+        return;
+      }
+    } else if(s2count == a_prims) {
+      if(splitPos2 <= a_box.min[splitAxis]) {
+        if(attempt < MAX_SPLITPOS_RETRIES) {
+          /* Try splitting at average point. */
+          //printf("YES!!! %d, %f\n", attempt, splitPos);
+          a_splitBox.min[splitAxis] = splitPos;
+          attempt++;
+          continue;
+        }
+        printf("Warning: Fat node with %d primitives\n", a_prims);
+
+        a_node->SetLeaf(true);
+        a_node->SetList(right->GetList());
+        return;
+      }
+    }
+    break;
+  }
+  //printf(prims total %d, left %d, right %d\n", a_prims, s1count, s2count);
+
+  a_node->SetLeaf(false);
+  a_node->SetAxis(splitAxis);
+
+  Aabb b1, b2;
+
+  b1 = a_box;
+  b1.max[splitAxis] = splitPos1;
+  b2 = a_box;
+  b2.min[splitAxis] = splitPos2;
+
+  a_node->SetSplitPos1(splitPos1);
+  a_node->SetSplitPos2(splitPos2);
+
+  if(a_depth > MAX_DEPTH) return;
+
+  if(s1count > MAX_LEAF_PRIMS) {
+    Aabb splitBox = a_splitBox;
+    splitBox.max[splitAxis] = splitPos;
+    BihTreeGhBuild(left, b1, splitBox, a_depth+1, s1count);
+  }
+  else left->SetLeaf(true);
+
+  if(s2count > MAX_LEAF_PRIMS) {
+    Aabb splitBox = a_splitBox;
+    splitBox.min[splitAxis] = splitPos;
+    BihTreeGhBuild(right, b2, splitBox, a_depth+1, s2count);
+  }
+  else right->SetLeaf(true);
+}
+
+#define SIGN_OF(f) (*((unsigned int*)(&f)) >> 31)
+
+void GeomTree::TraceRay(vector3f& start, vector3f& dir, isect_t* isect) {
+  float len = dir.Length();
+  isect->dist = len;
+  isect->triIdx = -1;
+  vector3f normDir = dir*(1.0f/len);
+  TraverseRay(start, normDir, isect);
+}
+
+void GeomTree::TraverseRay(vector3f& a_origin, vector3f& a_dir, isect_t* isect) {
+  float entry_t = 0, exit_t = isect->dist;
+  vector3f rcpD = vector3f(1.0f/a_dir.x, 1.0f/a_dir.y, 1.0f/a_dir.z);
+  int Dneg[3];
+#ifdef DEBUG
+  int num_raytri_tests = 0;
+#endif
+
+  Dneg[0] = (a_dir.x < 0 ? 1 : 0);
+  Dneg[1] = (a_dir.y < 0 ? 1 : 0);
+  Dneg[2] = (a_dir.z < 0 ? 1 : 0);
+
+  for(int i = 0; i < 3; i++) {
+    if(Dneg[i]) {
+      if(a_origin[i] < m_aabb.min[i]) return;
+    }
+    else if(a_origin[i] > m_aabb.max[i]) return;
+  }
+
+  /* Clip ray segment to box. */
+  for(int i = 0; i < 3; i++) {
+    float clip_min = (m_aabb.min[i] - a_origin[i]) * rcpD[i];
+    float clip_max = (m_aabb.max[i] - a_origin[i]) * rcpD[i];
+    if(a_dir[i] > 0.0f) {
+      entry_t = MAX(entry_t, clip_min);
+      exit_t = MIN(exit_t, clip_max);
+    } else {
+      entry_t = MAX(entry_t, clip_max);
+      exit_t = MIN(exit_t, clip_min);
+    }
+    if(entry_t > exit_t) return;
+  }
+
+#if 0
+  /* From final kd-tree version. */
+  /* Init stack. */
+  int entrypoint = 0, exitpoint = 1;
+  /* Init traversal. */
+  KDNode* farchild, *currnode;
+  currnode = obj.m_dlist->sceneTree;
+  m_Stack[entrypoint].t = entry_t;
+  m_Stack[entrypoint].pb = 0 + D * entry_t;
+  m_Stack[exitpoint].t = exit_t;
+  m_Stack[exitpoint].pb = 0 + D * exit_t;
+  m_Stack[exitpoint].node = 0;
+#endif
+
+  /* Init stack. */
+  int stackpos = -1;
+  /* Init traversal. */
+  BIHNode* currnode = &m_nodes[0];
+
+  struct bihstack {
+    BIHNode* node;
+    float entry_t, exit_t;
+  } bihstack[32];
+
+  /* Traverse bih-tree. */
+  while(currnode) {
+    while (!currnode->IsLeaf()) {
+#ifdef DEBUG
+      //m_stats.treeNodeTraversals++;
+#endif
+      const int axis = currnode->GetAxis();
+
+      float d[2];
+      d[0] = (currnode->GetSplitPos1() - a_origin[axis]) * rcpD[axis];
+      d[1] = (currnode->GetSplitPos2() - a_origin[axis]) * rcpD[axis];
+
+      const int dir = Dneg[axis];
+      const int dir1 = 1-Dneg[axis];
+      const float d1 = d[dir];
+      const float d2 = d[dir1];
+
+      if(d1 >= entry_t) {
+        /* Front side. */
+        if(d2 >= exit_t) {
+          /* And not backside. */
+          currnode = currnode->GetLeft()+dir;
+          exit_t = MIN(d1, exit_t);
+          continue;
+        }
+        /* Both. */
+        stackpos++;
+        bihstack[stackpos].node = currnode->GetLeft()+dir1;
+        bihstack[stackpos].entry_t = MAX(d2, entry_t);
+        bihstack[stackpos].exit_t = exit_t;
+
+        currnode = currnode->GetLeft()+dir;
+        exit_t = MIN(d1, exit_t);
+      } else if(d2 < exit_t) {
+        /* Back side only. */
+        currnode = currnode->GetLeft() + dir1;
+        entry_t = MAX(d2, entry_t);
+      } else {
+        goto pop_bstack;
+      }
+    }
+    /* Early termination. */
+    if(isect->dist < entry_t) goto pop_bstack;
+
+    /* Woop, we are a leaf node. */
+    for(tri_t* p = currnode->GetList(); p != NULL; p = p->next) {
+#ifdef DEBUG
+      num_raytri_tests++;
+#endif
+      RayTriIntersect(a_origin, a_dir, p->triIdx, isect);
+    }
+
+pop_bstack:
+    if(stackpos < 0) break;
+
+    currnode = bihstack[stackpos].node;
+    entry_t = bihstack[stackpos].entry_t;
+    exit_t = bihstack[stackpos].exit_t;
+    stackpos--;
+  }
+}
+
+#define EPSILON 0.00001f
+void GeomTree::RayTriIntersect(vector3f& origin, vector3f& dir, int triIdx, isect_t* isect) {
+  vector3f a(&m_vertices[3*m_indices[triIdx]]);
+  vector3f b(&m_vertices[3*m_indices[triIdx+1]]);
+  vector3f c(&m_vertices[3*m_indices[triIdx+2]]);
+
+  vector3f v0_cross, v1_cross, v2_cross;
+  const vector3f n = vector3f::Cross(c-a, b-a);
+
+  v1_cross = vector3f::Cross(b-origin, a-origin);
+  v2_cross = vector3f::Cross(a-origin, c-origin);
+  v0_cross = vector3f::Cross(c-origin, b-origin);
+  float nominator = vector3f::Dot(n, (a-origin));
+
+  const float v0d = vector3f::Dot(v0_cross,dir);
+  const float v1d = vector3f::Dot(v1_cross,dir);
+  const float v2d = vector3f::Dot(v2_cross,dir);
+
+  if(((v0d > 0) && (v1d > 0) && (v2d > 0)) ||
+      ((v0d < 0) && (v1d < 0 && v2d < 0))) {
+    const float dist = nominator / vector3f::Dot(dir, n);
+    if((dist > EPSILON) && (dist < isect->dist)) {
+      isect->dist = dist;
+      isect->triIdx = triIdx;
+    }
+  }
+}
+
diff --git a/src/collider/geom_tree.h b/src/collider/geom_tree.h
new file mode 100644
index 0000000..29e1b01
--- /dev/null
+++ b/src/collider/geom_tree.h
@@ -0,0 +1,38 @@
+#pragma once
+#include "../aabb.h"
+
+class BIHNode;
+class tri_t;
+
+struct isect_t {
+  /* triIdx = -1 if no intersection. */
+  int triIdx;
+  float dist;
+};
+
+class GeomTree {
+public:
+  GeomTree(int numTris, float* vertices, int* indices);
+  ~GeomTree(void);
+  Aabb GetAabb(void) { return m_aabb; }
+  void TraceRay(vector3f& start, vector3f& dir, isect_t* isect);
+
+private:
+  friend class BIHNode;
+  void RayTriIntersect(vector3f& a_origin, vector3f& a_dir, int triIdx, isect_t* isect);
+  void TraverseRay(vector3f& a_origin, vector3f& a_dir, isect_t* isect);
+  BIHNode* AllocNode(void);
+  void BihTreeGhBuild(BIHNode* a_node, Aabb& a_box, Aabb& a_splitBox, int a_depth, int a_prims);
+
+  Aabb m_aabb;
+  BIHNode* m_nodes;
+  int m_nodesAllocPos;
+  int m_nodesAllocSize;
+  tri_t* m_triAlloc;
+  int m_triAllocPos;
+  int m_triAllocSize;
+
+  const float* m_vertices;
+  const int* m_indices;
+};
+
diff --git a/src/sbre_viewer.cpp b/src/sbre_viewer.cpp
index b9b31fb..0627767 100644
--- a/src/sbre_viewer.cpp
+++ b/src/sbre_viewer.cpp
@@ -2,6 +2,7 @@
 #include "sbre/sbre.h"
 #include "glfreetype.h"
 #include "gui.h"
+#include "collider/geom_tree.h"
 
 static SDL_Surface* g_screen;
 static int g_width, g_height;
@@ -11,6 +12,7 @@ static int g_mouseButton[5];
 static int g_model = 0; /* sbre model number. Set with argc. */
 static float g_zbias;
 
+static GLuint mytexture;
 
 static void PollEvents(void) {
   SDL_Event event;
@@ -152,6 +154,78 @@ static void render_coll_mesh(const CollMesh* m) {
   glEnable(GL_LIGHTING);
 }
 
+float foo[512][512];
+float aspectRatio = 1.0;
+float camera_zoom = 1.0;
+static void raytraceCollMesh(vector3f camPos, vector3f camera_up, vector3f camera_forward, GeomTree* geomtree) {
+  memset(foo, 0, sizeof(float)*512*512);
+
+  vector3f toPoint, xMov, yMov;
+
+  vector3f topLeft, topRight, botRight, cross;
+  topLeft = topRight = botRight = camera_forward + camera_zoom;
+  cross = vector3f::Cross (camera_forward, camera_up) * aspectRatio;
+  topLeft = topLeft + camera_up - cross;
+  topRight = topRight + camera_up + cross;
+  botRight = botRight - camera_up + cross;
+
+  xMov = topRight - topLeft;
+  yMov = botRight - topRight;
+  float xstep = 1.0f / 512;
+  float ystep = 1.0f / 512;
+  float xpos, ypos;
+  ypos = 0.0f;
+
+  Uint32 t = SDL_GetTicks();
+  for(int y = 0; y < 512; y++, ypos += ystep) {
+    xpos = 0.0f;
+    for(int x = 0; x < 512; x++, xpos += xstep) {
+      toPoint = topLeft + (xMov * xpos) + (yMov*ypos);
+      toPoint.Normalize();
+      toPoint *= 10000;
+
+      isect_t isect;
+      geomtree->TraceRay(camPos, toPoint, &isect);
+
+      if(isect.triIdx != -1) {
+        foo[x][y] = 10.0/isect.dist;
+      } else {
+        foo[x][y] = 0;
+      }
+    }
+  }
+  printf("%3f million rays/sec\n", (512*512)/(1000.0*(SDL_GetTicks()-t)));
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_LUMINANCE, GL_FLOAT, foo);
+
+  glDisable(GL_DEPTH_TEST);
+  glDisable(GL_LIGHTING);
+  glMatrixMode(GL_PROJECTION);
+  glPushMatrix();
+  glLoadIdentity();
+  glOrtho(0, 1, 0, 1, -1, 1);
+  glMatrixMode(GL_MODELVIEW);
+  glPushMatrix();
+  glLoadIdentity();
+
+  glActiveTextureARB(GL_TEXTURE0_ARB);
+  glEnable(GL_TEXTURE_2D);
+  glDisable(GL_LIGHTING);
+  glBindTexture(GL_TEXTURE_2D, mytexture);
+  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+  glBegin(GL_TRIANGLE_FAN);
+    glTexCoord2i(1,1);
+    glVertex3f(1,1,0);
+    glTexCoord2i(0,1);
+    glVertex3f(0,1,0);
+    glTexCoord2i(0,0);
+    glVertex3f(0,0,0);
+    glTexCoord2i(1,0);
+    glVertex3f(1,0,0);
+  glEnd();
+  glDisable(GL_TEXTURE_2D);
+  printf("done..\n");
+}
+
 void Viewer::MainLoop(void) {
   matrix4x4d rot = matrix4x4d::Identity();
   float distance = 100;
@@ -160,6 +234,10 @@ void Viewer::MainLoop(void) {
   CollMesh* cmesh = (CollMesh*)calloc(1, sizeof(CollMesh));
   sbreGenCollMesh(cmesh, g_model, &params, 1.0f);
 
+  Uint32 t= SDL_GetTicks();
+  GeomTree* geomtree = new GeomTree(cmesh->ni/3, cmesh->pVertex, cmesh->pIndex);
+  printf("Geom tree build in $dms\n", SDL_GetTicks() -t);
+
   for(;;) {
     PollEvents();
 
@@ -186,6 +264,7 @@ void Viewer::MainLoop(void) {
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
     glPushAttrib(GL_ALL_ATTRIB_BITS);
+    if(!g_renderCollMesh) {
     SetSbreParams();
     sbreSetViewport(g_width, g_height, g_width*0.5, 1.0f, 10000.0f, 0.0f, 1.0f);
     sbreSetDirLight(lightCol, lightDir);
@@ -205,6 +284,15 @@ void Viewer::MainLoop(void) {
       //sbreRenderCollMesh(cmesh, &p, &m);
     }
     else sbreRenderModel(&p, &m, g_model, &params);
+
+    } else {
+      vector3d _p = rot * vector3d(0,0,-distance);
+      vector3f camPos(_p.x, _p.y, _p.z);
+      vector3f forward = -vector3f::Normalize(camPos);
+      vector3f up = vector3f::Cross(vector3f(0,1,0), forward);
+      up.Normalize();
+      raytraceCollMesh(camPos, up, forward, geomtree);
+    }
     glPopAttrib();
 
     Gui::Draw();
@@ -213,6 +301,7 @@ void Viewer::MainLoop(void) {
     g_frameTime = (SDL_GetTicks() - lastFoo) * 0.001;
     lastFoo = SDL_GetTicks();
   }
+  delete geomtree;
 }
 
 int main(int argc, char** argv) {
@@ -272,6 +361,13 @@ int main(int argc, char** argv) {
   glEnable(GL_LIGHT0);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
+  glGenTextures(1, &mytexture);
+  glBindTexture(GL_TEXTURE_2D, mytexture);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
   glClearColor(0,0,0,0);
   glViewport(0,0, g_width, g_height);
   GLFTInit();