// holy shit
bool raycast_voxels(
cfvec3 origin,
cfvec3 dir,
float max_dist,
cfvec3i hit_pos,
cfvec3i hit_normal,
uint64_t* opaque_mask
) {
cf_vec3_normalize(dir);
cfvec3i voxel = {
(int)floorf(origin[0]),
(int)floorf(origin[1]),
(int)floorf(origin[2])
};
cfvec3i step = {
sign(dir[0]),
sign(dir[1]),
sign(dir[2])
};
cfvec3 t_delta = {
fabsf(dir[0]) < 1e-6 ? 1e30f : fabsf(1.0f / dir[0]),
fabsf(dir[1]) < 1e-6 ? 1e30f : fabsf(1.0f / dir[1]),
fabsf(dir[2]) < 1e-6 ? 1e30f : fabsf(1.0f / dir[2])
};
cfvec3 voxel_boundary;
voxel_boundary[0] = (step[0] > 0 ? (voxel[0] + 1) : voxel[0]);
voxel_boundary[1] = (step[1] > 0 ? (voxel[1] + 1) : voxel[1]);
voxel_boundary[2] = (step[2] > 0 ? (voxel[2] + 1) : voxel[2]);
cfvec3 t_max = {
(dir[0] == 0) ? 1e30f : (voxel_boundary[0] - origin[0]) / dir[0],
(dir[1] == 0) ? 1e30f : (voxel_boundary[1] - origin[1]) / dir[1],
(dir[2] == 0) ? 1e30f : (voxel_boundary[2] - origin[2]) / dir[2]
};
float dist = 0.0f;
for (int i = 0; i < 256; i++) {
// bounds check (your chunk size)
if (voxel[0] < 0 || voxel[1] < 0 || voxel[2] < 0 ||
voxel[0] >= CS_P || voxel[1] >= CS_P || voxel[2] >= CS_P)
return false;
// check voxel
int idx = cf_terrain_get_zxy_index(voxel[0], voxel[1], voxel[2]);
if (opaque_mask[(voxel[1] * CS_P) + voxel[0]] & (1ull << voxel[2])) {
memcpy(hit_pos
, voxel
, sizeof(voxel
)); return true;
}
// step
if (t_max[0] < t_max[1]) {
if (t_max[0] < t_max[2]) {
voxel[0] += step[0];
dist = t_max[0];
t_max[0] += t_delta[0];
memcpy(hit_normal
, (cfvec3i
){ -step
[0], 0, 0 }, sizeof(cfvec3i
)); } else {
voxel[2] += step[2];
dist = t_max[2];
t_max[2] += t_delta[2];
memcpy(hit_normal
, (cfvec3i
){ 0, 0, -step
[2] }, sizeof(cfvec3i
)); }
} else {
if (t_max[1] < t_max[2]) {
voxel[1] += step[1];
dist = t_max[1];
t_max[1] += t_delta[1];
memcpy(hit_normal
, (cfvec3i
){ 0, -step
[1], 0 }, sizeof(cfvec3i
)); } else {
voxel[2] += step[2];
dist = t_max[2];
t_max[2] += t_delta[2];
memcpy(hit_normal
, (cfvec3i
){ 0, 0, -step
[2] }, sizeof(cfvec3i
)); }
}
if (dist > max_dist)
return false;
}
return false;
}