1. // holy shit
  2. bool raycast_voxels(
  3. cfvec3 origin,
  4. cfvec3 dir,
  5. float max_dist,
  6. cfvec3i hit_pos,
  7. cfvec3i hit_normal,
  8. uint64_t* opaque_mask
  9. ) {
  10. cf_vec3_normalize(dir);
  11.  
  12. cfvec3i voxel = {
  13. (int)floorf(origin[0]),
  14. (int)floorf(origin[1]),
  15. (int)floorf(origin[2])
  16. };
  17.  
  18. cfvec3i step = {
  19. sign(dir[0]),
  20. sign(dir[1]),
  21. sign(dir[2])
  22. };
  23.  
  24. cfvec3 t_delta = {
  25. fabsf(dir[0]) < 1e-6 ? 1e30f : fabsf(1.0f / dir[0]),
  26. fabsf(dir[1]) < 1e-6 ? 1e30f : fabsf(1.0f / dir[1]),
  27. fabsf(dir[2]) < 1e-6 ? 1e30f : fabsf(1.0f / dir[2])
  28. };
  29.  
  30. cfvec3 voxel_boundary;
  31. voxel_boundary[0] = (step[0] > 0 ? (voxel[0] + 1) : voxel[0]);
  32. voxel_boundary[1] = (step[1] > 0 ? (voxel[1] + 1) : voxel[1]);
  33. voxel_boundary[2] = (step[2] > 0 ? (voxel[2] + 1) : voxel[2]);
  34.  
  35. cfvec3 t_max = {
  36. (dir[0] == 0) ? 1e30f : (voxel_boundary[0] - origin[0]) / dir[0],
  37. (dir[1] == 0) ? 1e30f : (voxel_boundary[1] - origin[1]) / dir[1],
  38. (dir[2] == 0) ? 1e30f : (voxel_boundary[2] - origin[2]) / dir[2]
  39. };
  40.  
  41. float dist = 0.0f;
  42.  
  43. for (int i = 0; i < 256; i++) {
  44. // bounds check (your chunk size)
  45. if (voxel[0] < 0 || voxel[1] < 0 || voxel[2] < 0 ||
  46. voxel[0] >= CS_P || voxel[1] >= CS_P || voxel[2] >= CS_P)
  47. return false;
  48.  
  49. // check voxel
  50. int idx = cf_terrain_get_zxy_index(voxel[0], voxel[1], voxel[2]);
  51.  
  52. if (opaque_mask[(voxel[1] * CS_P) + voxel[0]] & (1ull << voxel[2])) {
  53. memcpy(hit_pos, voxel, sizeof(voxel));
  54. return true;
  55. }
  56.  
  57. // step
  58. if (t_max[0] < t_max[1]) {
  59. if (t_max[0] < t_max[2]) {
  60. voxel[0] += step[0];
  61. dist = t_max[0];
  62. t_max[0] += t_delta[0];
  63. memcpy(hit_normal, (cfvec3i){ -step[0], 0, 0 }, sizeof(cfvec3i));
  64. } else {
  65. voxel[2] += step[2];
  66. dist = t_max[2];
  67. t_max[2] += t_delta[2];
  68. memcpy(hit_normal, (cfvec3i){ 0, 0, -step[2] }, sizeof(cfvec3i));
  69. }
  70. } else {
  71. if (t_max[1] < t_max[2]) {
  72. voxel[1] += step[1];
  73. dist = t_max[1];
  74. t_max[1] += t_delta[1];
  75. memcpy(hit_normal, (cfvec3i){ 0, -step[1], 0 }, sizeof(cfvec3i));
  76. } else {
  77. voxel[2] += step[2];
  78. dist = t_max[2];
  79. t_max[2] += t_delta[2];
  80. memcpy(hit_normal, (cfvec3i){ 0, 0, -step[2] }, sizeof(cfvec3i));
  81. }
  82. }
  83.  
  84. if (dist > max_dist)
  85. return false;
  86. }
  87.  
  88. return false;
  89. }