diff --git a/src/sbre/Makefile.am b/src/sbre/Makefile.am
index 138f1d6..a6697d8 100644
--- a/src/sbre/Makefile.am
+++ b/src/sbre/Makefile.am
@@ -1,6 +1,6 @@
 #  Process this file with automake to produce Makefile.in
 
 noinst_LIBRARIES = libsbre.a
-libsbre_a_SOURCES = brender.cpp models.cpp primfunc.cpp simtriang.cpp transp.cpp jjvector.cpp
+libsbre_a_SOURCES = brender.cpp models.cpp collfunc.cpp primfunc.cpp simtriang.cpp transp.cpp jjvector.cpp
 
 include_HEADERS = fastmath.h sbre.h sbre_int.h sbre_models.h sbre_anim.h jjtypes.h jjvector.h
diff --git a/src/sbre/brender.cpp b/src/sbre/brender.cpp
index e6086cd..8dfaae7 100644
--- a/src/sbre/brender.cpp
+++ b/src/sbre/brender.cpp
@@ -166,6 +166,13 @@ void SetTransState(void) {
   glDisableClientState(GL_NORMAL_ARRAY);
 }
 
+void AllocModelCaches(Model* pModel) {
+  pModel->pNumVtx = (int*)calloc(pModel->numCache, sizeof(int));
+  pModel->pNumIdx = (int*)calloc(pModel->numCache, sizeof(int));
+  pModel->ppVCache = (Vector**)calloc(pModel->numCache, sizeof(Vector*));
+  pModel->ppICache = (uint16**)calloc(pModel->numCache, sizeof(uint16*));
+}
+
 void sbreRenderModel(Vector* pPos, Matrix* pOrient, int model, ObjParams* pParam,
                      float s, Vector* pCompos) {
   Model* pModel = ppModel[model];
@@ -194,13 +201,9 @@ void sbreRenderModel(Vector* pPos, Matrix* pOrient, int model, ObjParams* pParam
   VecInv(&rstate.campos, &rstate.campos);
   if(pCompos) rstate.compos = *pCompos;
   else rstate.compos        = zero_vector;
+  rstate.pCallback = 0;
 
-  if(pModel->numCache && !pModel->ppVCache) {
-    pModel->pNumVtx = (int*)calloc(pModel->numCache, sizeof(int));
-    pModel->pNumIdx = (int*)calloc(pModel->numCache, sizeof(int));
-    pModel->ppVCache = (Vector**)calloc(pModel->numCache, sizeof(Vector*));
-    pModel->ppICache = (uint16**)calloc(pModel->numCache, sizeof(uint16*));
-  }
+  if(pModel->numCache && !pModel->ppVCache)AllocModelCaches(pModel);
 
   SetGeneralState();
   SetOpaqueState();
@@ -234,22 +237,30 @@ void sbreRenderModel(Vector* pPos, Matrix* pOrient, int model, ObjParams* pParam
   glEnable(GL_CULL_FACE);
 }
 
-/* Urgh, needs to recurse too... */
-#if 0
-void sbreRenderModel(Vector* pPos, Matrix* pOrient, int model, ObjParams* pParam,
-                    float s, Vector* pCompos) {
+void sbreGenCollMesh(CollMesh* pCMesh, int model, ObjParams* pParam, float s) {
+  pCMesh->cflag = pCMesh->nv = pCMesh->ni = 0;
+  Vector pos = zero_vector; Matrix orient = identity_matrix;
+  GenCollMeshInternal(&pos, &orient, model, pParam, s, pCMesh);
+}
+
+void GenCollMeshInternal(Vector* pPos, Matrix* pOrient, int model, ObjParams* pParam,
+                          float s, CollMesh* pCMesh) {
   Model* pModel = ppModel[model];
   s *= pModel->scale;
-  float pMV[16];
-  pMV[ 0] = s*pOrient->x1; pMV[1] = s*pOrient->y1; pMV[ 2] = s*pOrient->z1; pMV[ 3] = 0.0f;
-  pMV[ 4] = s*pOrient->x2; pMV[5] = s*pOrient->y2; pMV[ 6] = s*pOrient->z2; pMV[ 7] = 0.0f;
-  pMV[ 8] = s*pOrient->x3; pMV[9] = s*pOrient->y3; pMV[10] = s*pOrient->z3; pMV[11] = 0.0f;
-  pMV[12] = pPos->x; pMV[13] = pPos->y; pMV[14] = pPos->z; pMV[15] = 1.0f;
-  glMatrixMode(GL_MODELVIEW);
-  glLoadMatrixf(pMV);
+  Matrix m = *pOrient;
+  m.x1 *= s; m.x2 *= s; m.x3 *= s;
+  m.y1 *= s; m.y2 *= s; m.y3 *= s;
+  m.z1 *= s; m.z2 *= s; m.z3 *= s;
 
-  Vector* pVtx = (Vector*)alloca(sizeof(Vector)*(pModel->cvStart->cvStart+pModel->numCVtx));
+  Vector* pVtx = (Vector*)alloca(sizeof(Vector)*(pModel->cvStart+pModel->numCVtx));
+  
   ResolveVertices(pModel, pVtx, pParam);
+  for(int i = 6; i < pModel->cvStart+pModel->numCVtx; i++) {
+    Vector tv;
+    MatVecMult(&m, pVtx+i, &tv);
+    VecAdd(&tv, pPos, pVtx+i);
+    if(i == pModel->numPVtx-1) i = pModel->cvStart-1;
+  }
 
   RState rstate;
   rstate.pVtx = pVtx;
@@ -258,40 +269,19 @@ void sbreRenderModel(Vector* pPos, Matrix* pOrient, int model, ObjParams* pParam
   rstate.scale = s;
   rstate.pModel = pModel;
   rstate.pObjParam = pParam;
-  rstate.dn = g_dn;
-  rstate.df = g_df;
   MatTVecMult(pOrient, pPos, &rstate.campos);
   VecInv(&rstate.campos, &rstate.campos);
-  if(pCompos) rstate.compos = *pCompos;
-  else rstate.compos = zero_vector;
-
-  if(pModel->numCache && !pModel->ppVCache) {
-    pModel->pNumVtx = (int*)calloc(pModel->numCache, sizeof(int));
-    pModel->pNumIdx = (int*)calloc(pModel->numCache, sizeof(int));
-    pModel->ppVCache = (Vector**)calloc(pModel->numCache, sizeof(Vector*));
-    pModel->ppICache = (uint16**)calloc(pModel->numCache, sizeof(uint16*));
+  rstate.pCMesh = pCMesh;
+  
+  if(pModel->numCache && !pModel->ppVCache) AllocModelCaches(pModel);
+  
+  uint16* pData = pModel->pLOD[0].pData1;
+  if(pData) while(*pData != PTYPE_END) {
+    pData += pCollFuncTable[*pData & 0xff](pData, pModel, &rstate);
   }
-
-  SetGeneralState();
-  SetOpaqueState();
-
-  float dist = sqrt(VecDot(pPos, pPos));
-  float pixrad = g_sd * pModel->radius*s / dist;
-  int i; for(i = 0; i < 4; i++) {
-    if(pModel->pLOD[i].pixrad >= 1000.0f) break;
-    if(pixrad <= pModel->pLOD[i].pixrad) break;
+  pData = pModel->pLOD[0].pData2;
+  if(pData) while(*pData != PTYPE_END) {
+    pData += pCollFuncTable[*pData & 0xff](pData, pModel, &rstate);
   }
-  uint16* pData = pModel->pLOD[i].pData;
-
-  while(*pData != PTYPE_END) {
-    pData += pPrimFuncTable[*pData & 0xff] (pData, pModel, &rstate);
-  }
-
-  SetTransState();
-  RenderTransparencies(&rstate);
-
-  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-  glEnable(GL_CULL_FACE);
 }
-#endif
 
diff --git a/src/sbre/collfunc.cpp b/src/sbre/collfunc.cpp
new file mode 100644
index 0000000..9c01e2e
--- /dev/null
+++ b/src/sbre/collfunc.cpp
@@ -0,0 +1,215 @@
+#include <malloc.h>
+#include "sbre_int.h"
+#include "sbre.h"   /* For subobject. */
+
+static void ExpandVertices(CollMesh* pCMesh, int n) {
+  if(n < 100) n = 100;
+  pCMesh->maxv += n; n = pCMesh->maxv;
+  pCMesh->pVertex = (float*)realloc(pCMesh->pVertex, n*3*sizeof(float));
+}
+
+static void ExpandIndices(CollMesh* pCMesh, int n) {
+  if(n < 100); n = 100;
+  pCMesh->maxi += n; n = pCMesh->maxi;
+  pCMesh->pIndex = (int*)realloc(pCMesh->pIndex, n*sizeof(int));
+  pCMesh->pFlag  = (int*)realloc(pCMesh->pFlag, sizeof(int) * n/3);
+}
+
+static int CollFuncMatAnim(uint16* pData, Model* pMod, RState* pState) {
+  return 22;
+}
+
+static int CollFuncMatFixed(uint16* pData, Model* pMod, RState* pState) {
+  return 11;
+}
+
+static int CollFuncMatVar(uint16* pData, Model* pMod, RState* pState) {
+  return 2;
+}
+
+static int CollFuncZBias(uint16* pData, Model* pMod, RState* pState) {
+  return 3;
+}
+
+static int CollFuncTriFlat(uint16* pData, Model* pMod, RState* pState) {
+  Vector* pVtx = pState->pVtx;
+  CollMesh* pCMesh = pState->pCMesh;
+  if(pCMesh->maxv - pCMesh->nv < 6) ExpandVertices(pCMesh, 6);
+  if(pCMesh->maxi - pCMesh->ni < 6) ExpandIndices(pCMesh, 6);
+
+  int ni = pCMesh->ni; int nv = pCMesh->nv;
+  Vector* pOut = (Vector*)pCMesh->pVertex;
+  int* pIdx = pCMesh->pIndex;
+  pCMesh->pFlag[ni/3] = pCMesh->cflag;
+
+  for(int i = 0; i < 3; i++) {
+    pOut[nv] = pVtx[pData[i+1]];
+    pIdx[ni++] = nv++;
+  }
+
+  if(pData[0] & RFLAG_XREF) {
+    pCMesh->pFlag[ni/3] = pCMesh->cflag;
+
+    for(int i = 0; i < 3; i++) {
+      Vector* pVec = pVtx + pData[3-i];
+      VecSet(-pVec->x, pVec->y, pVec->z, pOut+nv);
+      pIdx[ni++] = nv++;
+    }
+  }
+  pCMesh->ni = ni; pCMesh->nv = nv;
+  return 4;
+}
+
+static int CollFuncQuadFlat(uint16* pData, Model* pMod, RState* pState) {
+  Vector* pVtx = pState->pVtx;
+  CollMesh* pCMesh = pState->pCMesh;
+  if(pCMesh->maxv - pCMesh->nv <  8) ExpandVertices(pCMesh, 8);
+  if(pCMesh->maxi - pCMesh->ni < 12) ExpandIndices(pCMesh, 12);
+
+  int ni = pCMesh->ni; int nv = pCMesh->nv;
+  Vector* pOut = (Vector*)pCMesh->pVertex;
+  int* pIdx = pCMesh->pIndex;
+  pCMesh->pFlag[ni/3] = pCMesh->pFlag[1+ni/3] = pCMesh->cflag;
+
+  for(int i = 0; i < 4; i++) pOut[nv+i] = pVtx[pData[i+1]];
+  pIdx[ni+0] = nv; pIdx[ni+1] = nv+1; pIdx[ni+2] = nv+2;
+  pIdx[ni+3] = nv; pIdx[ni+4] = nv+2; pIdx[ni+5] = nv+3;
+  ni += 6; nv += 4;
+
+  if(pData[0] & RFLAG_XREF) {
+    pCMesh->pFlag[ni/3] = pCMesh->pFlag[1+ni/3] = pCMesh->cflag;
+
+    for(int i = 0; i < 4; i++) {
+      Vector* pVec = pVtx + pData[i+1];
+      VecSet(-pVec->x, pVec->y, pVec->z, pOut+nv+i);
+    }
+    pIdx[ni+0] = nv; pIdx[ni+1] = nv+2; pIdx[ni+2] = nv + 1;
+    pIdx[ni+3] = nv; pIdx[ni+4] = nv+3; pIdx[ni+5] = nv + 2;
+    ni += 6; nv += 4;
+  }
+  pCMesh->ni = ni; pCMesh->nv = nv;
+  return 5;
+}
+
+static void ArrayCallback(int nv2, int ni2, Vector* pVertex, uint16* pIndex,
+                          uint16 flags, RState* pState) {
+  CollMesh* pCMesh = pState->pCMesh;
+  if(pCMesh->maxv - pCMesh->nv < nv2*2) ExpandVertices(pCMesh, nv2*2);
+  if(pCMesh->maxi - pCMesh->ni < ni2*2) ExpandIndices(pCMesh, ni2*2);
+
+  int ni = pCMesh->ni; int nv = pCMesh->nv;
+  Vector* pOut = (Vector*)pCMesh->pVertex;
+  int* pIdx = pCMesh->pIndex;
+  int* pFlag = pCMesh->pFlag;
+
+  for(int i = 0; i < nv2; i++) pOut[nv+i] = pVertex[i*2];
+  for(int i = 0; i < ni2; i++) pIdx[ni+i] = nv+pIndex[i];
+  for(int i = 0; i < ni2/3; i++) pFlag[ni/3+i] = pCMesh->cflag;
+  ni += ni2; nv += nv2;
+
+  if(flags & RFLAG_XREF) {
+    for(int i = 0; i < nv2; i++) {
+      Vector* pVec = pVertex + i*2;
+      VecSet(-pVec->x, pVec->y, pVec->z, pOut+nv+i);
+    }
+    for(int i = 0; i < ni2; i += 3) {
+      pIdx[ni+i+0] = nv+pIndex[i];
+      pIdx[ni+i+1] = nv+pIndex[i+2];
+      pIdx[ni+i+2] = nv+pIndex[i+1];
+    }
+    for(int i = 0; i < ni2/3; i++) pFlag[ni/3+1] = pCMesh->cflag;
+    ni += ni2; nv+= nv2;
+  }
+  pCMesh->ni = ni; pCMesh->nv = nv;
+}
+
+static int CollFuncCompoundSmooth(uint16* pData, Model* pMod, RState* pState) {
+  pState->pCallback = ArrayCallback;
+  return pPrimFuncTable[*pData & 0xff](pData, pMod, pState);
+}
+
+static int CollFuncCylinder(uint16* pData, Model* pMod, RState* pState) {
+  pState->pCallback = ArrayCallback;
+  return pPrimFuncTable[*pData & 0xff](pData, pMod, pState);
+}
+
+static int CollFuncCircle(uint16* pData, Model* pMod, RState* pState) {
+  pState->pCallback = ArrayCallback;
+  return pPrimFuncTable[*pData & 0xff](pData, pMod, pState);
+}
+
+static int CollFuncTube(uint16* pData, Model* pMod, RState* pState) {
+  pState->pCallback = ArrayCallback;
+  return pPrimFuncTable[*pData & 0xff](pData, pMod, pState);
+}
+
+static int CollFuncExtrusion(uint16* pData, Model* pMod, RState* pState) {
+  pState->pCallback = ArrayCallback;
+  return pPrimFuncTable[*pData & 0xff](pData, pMod, pState);
+}
+
+/*
+uint16 PFUNC_SUBOBJECT
+        uint16 anim
+        uint16 modelnum
+        uint16 offset
+        uint16 norm
+        uint16 zaxis
+        uint16 scale
+*/
+
+static int CollFuncSubObject(uint16* pData, Model* pMod, RState* pState) {
+  /* Return immediately if object is not present. */
+  if(pData[1] != 0x8000 && !pState->pObjParam->pFlag[pData[1]]) return 7;
+
+  /* Build transform matrix, offset. */
+  Vector v1, v2, v3, pos; Matrix m, orient;
+  VecNorm(pState->pVtx+pData[4], &v2);
+  VecNorm(pState->pVtx+pData[5], &v3);
+  VecCross(&v2, &v3, &v1);
+  m.x1 = v1.x; m.x2 = v2.x; m.x3 = v3.x;
+  m.y1 = v1.y; m.y2 = v2.y; m.y3 = v3.y;
+  m.z1 = v1.z; m.z2 = v2.z; m.z3 = v3.z;
+  MatMatMult(&pState->objorient, &m, &orient);
+
+  MatVecMult(&pState->objorient, pState->pVtx+pData[3], &pos);
+  VecAdd(&pos, &pState->objpos, &pos);
+  float scale = pState->scale*pData[6]*0.01f;
+
+  GenCollMeshInternal(&pos, &orient, pData[2], pState->pObjParam, scale, pState->pCMesh);
+  return 7;
+}
+
+static int CollFuncText(uint16* pData, Model* pMod, RState* pState) {
+  return 9;
+}
+
+/*
+uint16 PFUNC_SETCFLAG
+        uint16 flag
+*/
+
+static int CollFuncSetCFlag(uint16* pData, Model* pMod, RState* pState) {
+  pState->pCMesh->cflag = pData[1];
+  return 2;
+}
+
+int (*pCollFuncTable[])(uint16*, Model*, RState*) = {
+  0,    /* End. */
+  CollFuncMatAnim,
+  CollFuncMatFixed,
+  CollFuncMatVar,
+  CollFuncZBias,
+  CollFuncTriFlat,
+  CollFuncQuadFlat,
+  CollFuncCompoundSmooth, /* Just uses steps = 0. */
+  CollFuncCompoundSmooth,
+  CollFuncCircle,
+  CollFuncCylinder,
+  CollFuncTube,
+  CollFuncSubObject,
+  CollFuncText,
+  CollFuncExtrusion,
+  CollFuncSetCFlag,
+};
+
diff --git a/src/sbre/primfunc.cpp b/src/sbre/primfunc.cpp
index c6158a0..b5a029d 100644
--- a/src/sbre/primfunc.cpp
+++ b/src/sbre/primfunc.cpp
@@ -164,7 +164,14 @@ static int PrimFuncQuadFlat(uint16* pData, Model* pMod, RState* pState) {
   return 5;
 }
 
-void RenderArray(int nv, int ni, Vector* pVertex, uint16* pIndex, uint16 flags) {
+static void RenderArray(int nv, int ni, Vector* pVertex, uint16* pIndex,
+                        uint16 flags, RState* pState) {
+
+  if(pState->pCallback) {
+    pState->pCallback(nv, ni, pVertex, pIndex, flags, pState);
+    return;
+  }
+
   glNormalPointer(GL_FLOAT, 2*sizeof(Vector), pVertex+1);
   glVertexPointer(3, GL_FLOAT, 2*sizeof(Vector), pVertex);
   glDrawElements(GL_TRIANGLES, ni, GL_UNSIGNED_SHORT, pIndex);
@@ -180,7 +187,7 @@ void RenderArray(int nv, int ni, Vector* pVertex, uint16* pIndex, uint16 flags)
   }
 }
 
-void CopyArrayToCache(int nv, int ni, Vector* pVertex, uint16* pIndex, int ci, Model* pModel) {
+static void CopyArrayToCache(int nv, int ni, Vector* pVertex, uint16* pIndex, int ci, Model* pModel) {
   pModel->pNumIdx[ci] = ni;
   pModel->pNumVtx[ci] = nv;
   pModel->ppICache[ci] = (uint16 *) malloc (ni*sizeof(uint16));
@@ -210,14 +217,14 @@ uint16 PFUNC_COMPSMOOTH
 /* Tangents should be prescaled. */
 #endif
 
-int PrimFuncCompoundSmooth(uint16* pData, Model* pMod, RState* pState) {
+static int PrimFuncCompoundSmooth(uint16* pData, Model* pMod, RState* pState) {
   Vector *pVtx = pState->pVtx;
   Model *pModel = pState->pModel;
 
   uint16 ci = pData[1];
   if(ci != 0x8000 && pModel->pNumIdx[ci]) {
     RenderArray(pModel->pNumVtx[ci], pModel->pNumIdx[ci],
-      pModel->ppVCache[ci], pModel->ppICache[ci], pData[0]);
+      pModel->ppVCache[ci], pModel->ppICache[ci], pData[0], pState);
     int c; for(c=7; pData[c] != COMP_END; c+=pCompSize[pData[c]]);
     return c+1;
   }
@@ -271,7 +278,7 @@ int PrimFuncCompoundSmooth(uint16* pData, Model* pMod, RState* pState) {
   if((pData[0]&0xff) == PTYPE_COMPFLAT) steps = 0;
   Triangulate(pCPos, pCNorm, steps, &pVertex, &nv, &pIndex, &ni);
 
-  RenderArray(nv, ni, pVertex, pIndex, pData[0]);
+  RenderArray(nv, ni, pVertex, pIndex, pData[0], pState);
   if(ci != 0x8000) CopyArrayToCache(nv, ni, pVertex, pIndex, ci, pModel);
   return c+1;    /* Yeyy for COMP_END */
 }
@@ -293,7 +300,7 @@ static int PrimFuncCylinder(uint16* pData, Model* pMod, RState* pState) {
   uint16 ci = pData[1];
   if(ci != 0x8000 && pModel->pNumIdx[ci]) {
     RenderArray(pModel->pNumVtx[ci], pModel->pNumIdx[ci],
-      pModel->ppVCache[ci], pModel->ppICache[ci], pData[0]);
+      pModel->ppVCache[ci], pModel->ppICache[ci], pData[0], pState);
     return 7;
   }
 
@@ -345,7 +352,7 @@ static int PrimFuncCylinder(uint16* pData, Model* pMod, RState* pState) {
     pIndex[ni++] = i-1+steps*3;
   }
 
-  RenderArray(4*steps, ni, pVertex, pIndex, pData[0]);
+  RenderArray(4*steps, ni, pVertex, pIndex, pData[0], pState);
   if(ci != 0x8000) CopyArrayToCache(4*steps, ni, pVertex, pIndex, ci, pModel);
   return 7;
 }
@@ -367,7 +374,7 @@ static int PrimFuncCircle(uint16* pData, Model* pMod, RState* pState) {
   uint16 ci = pData[1];
   if(ci != 0x8000 && pModel->pNumIdx[ci]) {
     RenderArray (pModel->pNumVtx[ci], pModel->pNumIdx[ci],
-      pModel->ppVCache[ci], pModel->ppICache[ci], pData[0]);
+      pModel->ppVCache[ci], pModel->ppICache[ci], pData[0], pState);
     return 7;
   }
 
@@ -399,7 +406,7 @@ static int PrimFuncCircle(uint16* pData, Model* pMod, RState* pState) {
     pIndex[ni++] = i;
   }
 
-  RenderArray(steps, ni, pVertex, pIndex, pData[0]);
+  RenderArray(steps, ni, pVertex, pIndex, pData[0], pState);
   if(ci != 0x8000) CopyArrayToCache(steps, ni, pVertex, pIndex, ci, pModel);
   return 7;
 }
@@ -422,7 +429,7 @@ static int PrimFuncTube(uint16* pData, Model* pMod, RState* pState) {
   uint16 ci = pData[1];
   if(ci != 0x8000 && pModel->pNumIdx[ci]) {
     RenderArray(pModel->pNumVtx[ci], pModel->pNumIdx[ci],
-      pModel->ppVCache[ci], pModel->ppICache[ci], pData[0]);
+      pModel->ppVCache[ci], pModel->ppICache[ci], pData[0], pState);
     return 8;
   }
 
@@ -490,7 +497,7 @@ steps*7: end, inner, axial
     pIndex[ni++] = i1+steps*7; pIndex[ni++] = i1+steps*5; pIndex[ni++] = i+steps*5;
   }  
 
-  RenderArray(8*steps, ni, pVertex, pIndex, pData[0]);
+  RenderArray(8*steps, ni, pVertex, pIndex, pData[0], pState);
   if(ci != 0x8000) CopyArrayToCache (8*steps, ni, pVertex, pIndex, ci, pModel);
   return 8;
 }
@@ -638,7 +645,7 @@ static int PrimFuncExtrusion (uint16 *pData, Model *pMod, RState *pState)
   {
     glShadeModel (GL_FLAT);
     RenderArray (pModel->pNumVtx[ci], pModel->pNumIdx[ci],
-      pModel->ppVCache[ci], pModel->ppICache[ci], pData[0]);
+      pModel->ppVCache[ci], pModel->ppICache[ci], pData[0], pState);
     glShadeModel (GL_SMOOTH);
     return 8;
   }
@@ -693,12 +700,19 @@ static int PrimFuncExtrusion (uint16 *pData, Model *pMod, RState *pState)
     pIndex[ni++] = i-1+steps*3;
   }
 
-  RenderArray(4*steps, ni, pVertex, pIndex, pData[0]);
+  RenderArray(4*steps, ni, pVertex, pIndex, pData[0], pState);
   if(ci != 0x8000) CopyArrayToCache(4*steps, ni, pVertex, pIndex, ci, pModel);
   return 8;
 }
 
+/*
+uint16 PFUNC_SETCFLAG
+        uint16 flag
+*/
 
+static int PrimFuncSetCFlag(uint16* pData, Model* pMod, RState* pState) {
+  return 2;
+}
 
 /*
 uint16 PFUNC_WINDOWS
@@ -729,6 +743,7 @@ int (*pPrimFuncTable[])(uint16 *, Model *, RState *) = {
   PrimFuncSubObject,
   PrimFuncText,
   PrimFuncExtrusion,
+  PrimFuncSetCFlag,
 };
 
 
diff --git a/src/sbre/sbre.h b/src/sbre/sbre.h
index e33f394..3819ad7 100644
--- a/src/sbre/sbre.h
+++ b/src/sbre/sbre.h
@@ -31,9 +31,20 @@ struct ObjParams {
   char pText[3][256];
 };
 
+struct CollMesh {
+  int nv, ni;
+  float*  pVertex;
+  int*    pIndex;
+  int*    pFlag;
+
+  int maxv, maxi;
+  int cflag;
+};
+
 void sbreSetViewport(int w, int h, float d, float zn, float zf, float dn, float df);
 void sbreSetDirLight(float* pColor, float* pDir);
 void sbreSetWireframe(int val);
 void sbreRenderModel(Vector* pPos, Matrix* pOrient, int model, ObjParams* pParam,
                       float s=1.0f, Vector* pCompos=0);
+void sbreGenCollMesh(CollMesh* pCMesh, int model, ObjParams* pParam, float s = 1.0f);
 
diff --git a/src/sbre/sbre_int.h b/src/sbre/sbre_int.h
index a13ce8a..2541c5c 100644
--- a/src/sbre/sbre_int.h
+++ b/src/sbre/sbre_int.h
@@ -123,10 +123,8 @@ struct RState {
   Vector compos;          /* Object relative center of mass. */
 
   /* Collision output stuff. */
-  int maxCVtx, maxCIdx;
-  int numCVtx, numCIdx;
-  Vector* pCollVtx;
-  int* pCollIdx;
+  CollMesh* pCMesh;
+  void(*pCallback)(int nv, int ni, Vector* pVertex, uint16* pIndex, uint16 flags, RState*);
 };
 
 enum primtype {
@@ -145,6 +143,7 @@ enum primtype {
   PTYPE_SUBOBJECT,
   PTYPE_TEXT,
   PTYPE_EXTRUSION,
+  PTYPE_SETCFLAG,
 };
 
 extern int (*pPrimFuncTable[])(uint16*, Model*, RState*);
@@ -176,4 +175,6 @@ const char pModelString[1][256] = {
 
 void RenderThrusters(RState* pState, int numThrusters, Thruster* pThrusters);
 float ResolveAnim (ObjParams* pObjParam, uint16 type);
+void GenCollMeshInternal(Vector* pPos, Matrix* pOrient, int model, ObjParams* pParam,
+                        float s, CollMesh* pCMesh);
 
diff --git a/src/sbre/sbre_models.h b/src/sbre/sbre_models.h
index ae55afa..dcf471b 100644
--- a/src/sbre/sbre_models.h
+++ b/src/sbre/sbre_models.h
@@ -13,6 +13,7 @@ const int SUB_MAINWHEEL = 3;
 const int SUB_MWUNIT    = 4;
 const int SUB_DISH      = 5;
 
+/* Other subobject indices. */
 const int SUB_WING1     = 30;
 const int SUB_WING2     = 31;