/// @description smf_collision_cast_ray_recursive(collisionBuffer, lineStart, lineEnd, regionSize, regionPos)
/// @param collisionBuffer
/// @param lineStart
/// @param lineEnd
/// @param regionSize
/// @param regionPos
var i, j, k, r, t, n, a, b, colBuffer, rayStart, rayEnd, regionSize, halfRegionSize, regionPos, checkPos, intersect, newPos, region, tris, tri, ret;
colBuffer = argument0;
rayStart = argument1;
rayEnd = argument2;
regionSize = argument3;
halfRegionSize = regionSize / 2;
regionPos = argument4;
r = buffer_read(colBuffer, buffer_s32);
//Exit condition
if (!r)
{
buffer_seek(colBuffer, buffer_seek_start, -r);
n = buffer_read(colBuffer, buffer_u16);
for (i = 0; i < n; i ++){tris[i] = buffer_read(colBuffer, buffer_u16);}
for (i = 0; i < n; i ++)
{
//Find intersection with triangle plane
tri = smf_get_triangle(colBuffer, tris[i]);
t = dot_product_3d(tri[9], tri[10], tri[11], rayEnd[0] - rayStart[0], rayEnd[1] - rayStart[1], rayEnd[2] - rayStart[2]);
if (t == 0){continue;}
t = dot_product_3d(tri[9], tri[10], tri[11], tri[0] - rayStart[0], tri[1] - rayStart[1], tri[2] - rayStart[2]) / t;
if ((t <= 0) or (t >= 1)){continue;}
ret[0] = lerp(rayStart[0], rayEnd[0], t);
ret[1] = lerp(rayStart[1], rayEnd[1], t);
ret[2] = lerp(rayStart[2], rayEnd[2], t);
//Check if the intersection is inside the triangle. If not, discard and continue.
a[0] = ret[0] - tri[0]; a[1] = ret[1] - tri[1]; a[2] = ret[2] - tri[2];
b[0] = tri[3] - tri[0]; b[1] = tri[4] - tri[1]; b[2] = tri[5] - tri[2];
if (dot_product_3d(tri[9], tri[10], tri[11], a[2] * b[1] - a[1] * b[2], a[0] * b[2] - a[2] * b[0], a[1] * b[0] - a[0] * b[1]) < 0){continue;}
a[0] = ret[0] - tri[3]; a[1] = ret[1] - tri[4]; a[2] = ret[2] - tri[5];
b[0] = tri[6] - tri[3]; b[1] = tri[7] - tri[4]; b[2] = tri[8] - tri[5];
if (dot_product_3d(tri[9], tri[10], tri[11], a[2] * b[1] - a[1] * b[2], a[0] * b[2] - a[2] * b[0], a[1] * b[0] - a[0] * b[1]) < 0){continue;}
a[0] = ret[0] - tri[6]; a[1] = ret[1] - tri[7]; a[2] = ret[2] - tri[8];
b[0] = tri[0] - tri[6]; b[1] = tri[1] - tri[7]; b[2] = tri[2] - tri[8];
if (dot_product_3d(tri[9], tri[10], tri[11], a[2] * b[1] - a[1] * b[2], a[0] * b[2] - a[2] * b[0], a[1] * b[0] - a[0] * b[1]) < 0){continue;}
//The line intersects the triangle. The ray is shortened by a tiny amount to make sure the returned value is on the correct side of the triangle
t += 1 / dot_product_3d(tri[9], tri[10], tri[11], ret[0] - rayStart[0], ret[1] - rayStart[1], ret[2] - rayStart[2]);
rayEnd[0] = lerp(rayStart[0], rayEnd[0], t);
rayEnd[1] = lerp(rayStart[1], rayEnd[1], t);
rayEnd[2] = lerp(rayStart[2], rayEnd[2], t);
}
return rayEnd;
}
//Find starting region of the line segment
region[0] = (rayStart[0] > regionPos[0] + halfRegionSize);
region[1] = (rayStart[1] > regionPos[1] + halfRegionSize);
region[2] = (rayStart[2] > regionPos[2] + halfRegionSize);
for (i = 0; i < 3; i ++)
{
if (rayEnd[i] == rayStart[i]){continue;}
if ((rayStart[i] < regionPos[i]) or (rayStart[i] > regionPos[i] + regionSize))
{
checkPos = regionPos;
checkPos[i] += region[i] * regionSize;
t = (checkPos[i] - rayStart[i]) / (rayEnd[i] - rayStart[i]);
if ((t <= 0) or (t >= 1)){continue;}
j = (i + 1) mod 3;
k = (i + 2) mod 3;
ret[j] = lerp(rayStart[j], rayEnd[j], t);
ret[k] = lerp(rayStart[k], rayEnd[k], t);
if ((ret[j] < regionPos[j]) or (ret[j] > regionPos[j] + regionSize) or (ret[k] < regionPos[k]) or (ret[k] > regionPos[k] + regionSize)){continue;}
region[j] = (ret[j] > regionPos[j] + halfRegionSize);
region[k] = (ret[k] > regionPos[k] + halfRegionSize);
break;
}
}
//Check for collisions in the starting region of the line segment
buffer_seek(colBuffer, buffer_seek_start, r + region[0] * 4 + region[1] * 8 + region[2] * 16);
newPos[0] = regionPos[0] + halfRegionSize * region[0];
newPos[1] = regionPos[1] + halfRegionSize * region[1];
newPos[2] = regionPos[2] + halfRegionSize * region[2];
rayEnd = smf_collision_cast_ray_recursive(colBuffer, rayStart, rayEnd, halfRegionSize, newPos);
//Check for intersections along the middle axis in all three dimensions
for (i = 0; i < 3; i ++)
{
if (rayEnd[i] == rayStart[i]){continue;}
t = (regionPos[i] + halfRegionSize - rayStart[i]) / (rayEnd[i] - rayStart[i]);
if ((t <= 0) or (t >= 1)){continue;}
j = (i + 1) mod 3;
k = (i + 2) mod 3;
intersect[j] = lerp(rayStart[j], rayEnd[j], t) - regionPos[j];
intersect[k] = lerp(rayStart[k], rayEnd[k], t) - regionPos[k];
if ((intersect[j] < 0) or (intersect[j] > regionSize) or (intersect[k] < 0) or (intersect[k] > regionSize)){continue;}
region[i] = (rayStart[i] < regionPos[i] + halfRegionSize);
region[j] = (intersect[j] >= halfRegionSize);
region[k] = (intersect[k] >= halfRegionSize);
newPos[0] = regionPos[0] + halfRegionSize * region[0];
newPos[1] = regionPos[1] + halfRegionSize * region[1];
newPos[2] = regionPos[2] + halfRegionSize * region[2];
buffer_seek(colBuffer, buffer_seek_start, r + region[0] * 4 + region[1] * 8 + region[2] * 16);
rayEnd = smf_collision_cast_ray_recursive(colBuffer, rayStart, rayEnd, halfRegionSize, newPos);
}
return rayEnd;