bool DynamicsWorld::castRay(
	const btVector3 & origin,
	const btVector3 & direction,
	const btScalar length,
	const btCollisionObject * caster,
	COLLISION_CONTACT & contact) const
{
	btVector3 p = origin + direction * length;
	btVector3 n = -direction;
	btScalar d = length;
	int patch_id = -1;
	const BEZIER * b = 0;
	const TRACKSURFACE * s = TRACKSURFACE::None();
	btCollisionObject * c = 0;

	MyRayResultCallback ray(origin, p, caster);
	rayTest(origin, p, ray);

	// track geometry collision
	bool geometryHit = ray.hasHit();
	if (geometryHit)
	{
		p = ray.m_hitPointWorld;
		n = ray.m_hitNormalWorld;
		d = ray.m_closestHitFraction * length;
		c = ray.m_collisionObject;
		if (c->isStaticObject())
		{
			TRACKSURFACE* tsc = static_cast<TRACKSURFACE*>(c->getUserPointer());
			const std::vector<TRACKSURFACE> & surfaces = track->GetSurfaces();
			if (tsc >= &surfaces[0] && tsc <= &surfaces[surfaces.size()-1])
			{
				s = tsc;
			}
#ifndef EXTBULLET
			else if (c->getCollisionShape()->isCompound())
			{
				TRACKSURFACE* tss = static_cast<TRACKSURFACE*>(ray.m_shape->getUserPointer());
				if (tss >= &surfaces[0] && tss <= &surfaces[surfaces.size()-1])
				{
					s = tss;
				}
			}
#endif
			//std::cerr << "static object without surface" << std::endl;
		}

		// track bezierpatch collision
		if (track)
		{
			MATHVECTOR<float, 3> bezierspace_raystart(origin[1], origin[2], origin[0]);
			MATHVECTOR<float, 3> bezierspace_dir(direction[1], direction[2], direction[0]);
			MATHVECTOR<float, 3> colpoint;
			MATHVECTOR<float, 3> colnormal;
			patch_id = contact.GetPatchId();

			if (track->CastRay(bezierspace_raystart, bezierspace_dir, length,
				patch_id, colpoint, b, colnormal))
			{
				p = btVector3(colpoint[2], colpoint[0], colpoint[1]);
				n = btVector3(colnormal[2], colnormal[0], colnormal[1]);
				d = (colpoint - bezierspace_raystart).Magnitude();
			}
		}

		contact = COLLISION_CONTACT(p, n, d, patch_id, b, s, c);
		return true;
	}

	// should only happen on vehicle rollover
	contact = COLLISION_CONTACT(p, n, d, patch_id, b, s, c);
	return false;
}