Subversion Repositories Games.Carmageddon

Rev

Rev 1 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "raycast.h"
  2. #include "brender.h"
  3. #include "brucetrk.h"
  4. #include "formats.h"
  5. #include "globvars.h"
  6. #include "harness/trace.h"
  7. #include "shortcut.h"
  8. #include <float.h>
  9. #include <math.h>
  10. #include <stdlib.h>
  11.  
  12. br_matrix34 gPick_model_to_view__raycast; // suffix added to avoid duplicate symbol
  13. int gBelow_face_index;
  14. br_scalar gCurrent_y;
  15. int gAbove_face_index;
  16. br_model* gAbove_model;
  17. br_model* gBelow_model;
  18. br_scalar gHighest_y_below;
  19. br_actor* gY_picking_camera;
  20. br_scalar gLowest_y_above;
  21.  
  22. // Added, probably can be replaced with NULL
  23. br_model* model_unk1;
  24. br_material* material_unk1;
  25.  
  26. // IDA: int __usercall DRActorToRoot@<EAX>(br_actor *a@<EAX>, br_actor *world@<EDX>, br_matrix34 *m@<EBX>)
  27. int DRActorToRoot(br_actor* a, br_actor* world, br_matrix34* m) {
  28.     LOG_TRACE("(%p, %p, %p)", a, world, m);
  29.  
  30.     if (world == a) {
  31.         BrMatrix34Identity(m);
  32.         return 1;
  33.     } else {
  34.         BrTransformToMatrix34(m, &a->t);
  35.         for (a = a->parent; a && world != a; a = a->parent) {
  36.             if (a->t.type != BR_TRANSFORM_IDENTITY) {
  37.                 BrMatrix34PostTransform(m, &a->t);
  38.             }
  39.         }
  40.         return world == a;
  41.     }
  42. }
  43.  
  44. // IDA: void __cdecl InitRayCasting()
  45. void InitRayCasting(void) {
  46.     br_camera* camera_ptr;
  47.     LOG_TRACE("()");
  48.  
  49.     gY_picking_camera = BrActorAllocate(BR_ACTOR_CAMERA, NULL);
  50.     camera_ptr = gY_picking_camera->type_data;
  51.     camera_ptr->type = BR_CAMERA_PERSPECTIVE_FOV;
  52.     camera_ptr->field_of_view = BrDegreeToAngle(70.0f);
  53.     camera_ptr->hither_z = 0.001f;
  54.     camera_ptr->yon_z = 1000.0f;
  55.     camera_ptr->aspect = 1.0f;
  56.     gY_picking_camera->t.t.mat.m[0][0] = 1.0;
  57.     gY_picking_camera->t.t.mat.m[0][1] = 0.0;
  58.     gY_picking_camera->t.t.mat.m[0][2] = 0.0;
  59.     gY_picking_camera->t.t.mat.m[1][0] = 0.0;
  60.     gY_picking_camera->t.t.mat.m[1][1] = 0.0;
  61.     gY_picking_camera->t.t.mat.m[1][2] = -1.0;
  62.     gY_picking_camera->t.t.mat.m[2][0] = 0.0;
  63.     gY_picking_camera->t.t.mat.m[2][1] = 1.0;
  64.     gY_picking_camera->t.t.mat.m[2][2] = 0.0;
  65. }
  66.  
  67. // IDA: int __cdecl BadDiv(br_scalar a, br_scalar b)
  68. // Suffix added to avoid duplicate symbol
  69. int BadDiv__raycast(br_scalar a, br_scalar b) {
  70.     // LOG_TRACE("(%f, %f)", a, b);
  71.  
  72.     return fabs(b) < 1.0 && fabs(a) > fabs(b) * BR_SCALAR_MAX;
  73. }
  74.  
  75. // IDA: void __usercall DRVector2AccumulateScale(br_vector2 *a@<EAX>, br_vector2 *b@<EDX>, br_scalar s)
  76. //  Suffix added to avoid duplicate symbol
  77. void DRVector2AccumulateScale__raycast(br_vector2* a, br_vector2* b, br_scalar s) {
  78.     LOG_TRACE("(%p, %p, %f)", a, b, s);
  79.  
  80.     a->v[0] = b->v[0] * s + a->v[0];
  81.     a->v[1] = b->v[1] * s + a->v[1];
  82. }
  83.  
  84. // IDA: int __usercall PickBoundsTestRay@<EAX>(br_bounds *b@<EAX>, br_vector3 *rp@<EDX>, br_vector3 *rd@<EBX>, br_scalar t_near, br_scalar t_far, br_scalar *new_t_near, br_scalar *new_t_far)
  85. // Suffix added to avoid duplicate symbol
  86. int PickBoundsTestRay__raycast(br_bounds* b, br_vector3* rp, br_vector3* rd, br_scalar t_near, br_scalar t_far, br_scalar* new_t_near, br_scalar* new_t_far) {
  87.     int i;
  88.     float s;
  89.     float t;
  90.     LOG_TRACE("(%p, %p, %p, %f, %f, %p, %p)", b, rp, rd, t_near, t_far, new_t_near, new_t_far);
  91.  
  92.     for (i = 0; i < 3; i++) {
  93.         if (rd->v[i] > 0.00000023841858) {
  94.             s = (1.0f / rd->v[i]) * (rp->v[i] - b->max.v[i]);
  95.             if (s > BR_SCALAR_MAX) {
  96.                 t_near = BR_SCALAR_MAX;
  97.             } else if (s > t_near) {
  98.                 t_near = s;
  99.             }
  100.             t = (1.0f / rd->v[i]) * (rp->v[i] - b->min.v[i]);
  101.             if (t < BR_SCALAR_MIN) {
  102.                 t_far = BR_SCALAR_MIN;
  103.             } else if (t < t_far) {
  104.                 t_far = t;
  105.             }
  106.         } else if (rd->v[i] < -0.00000023841858) {
  107.             s = (1.0f / rd->v[i]) * (rp->v[i] - b->max.v[i]);
  108.             if (s < BR_SCALAR_MIN) {
  109.                 t_far = BR_SCALAR_MIN;
  110.             } else if (s < t_far) {
  111.                 t_far = s;
  112.             }
  113.             t = (1.0f / rd->v[i]) * (rp->v[i] - b->min.v[i]);
  114.             if (t > BR_SCALAR_MAX) {
  115.                 t_near = BR_SCALAR_MAX;
  116.             } else if (t > t_near) {
  117.                 t_near = t;
  118.             }
  119.         } else if (rp->v[i] > b->max.v[i] || rp->v[i] < b->min.v[i]) {
  120.             return 0;
  121.         }
  122.     }
  123.     if (t_far < t_near) {
  124.         return 0;
  125.     }
  126.     *new_t_near = t_near;
  127.     *new_t_far = t_far;
  128.     return 1;
  129. }
  130.  
  131. // IDA: int __usercall ActorPick2D@<EAX>(br_actor *ap@<EAX>, br_model *model@<EDX>, br_material *material@<EBX>, dr_pick2d_cbfn *callback@<ECX>, void *arg)
  132. int ActorPick2D(br_actor* ap, br_model* model, br_material* material, dr_pick2d_cbfn* callback, void* arg) {
  133.     br_actor* a;
  134.     br_model* this_model;
  135.     br_material* this_material;
  136.     br_matrix34 m_to_v;
  137.     br_matrix34 v_to_m;
  138.     br_scalar t_near;
  139.     br_scalar t_far;
  140.     int r;
  141.     br_vector3 dir;
  142.     LOG_TRACE("(%p, %p, %p, %p, %p)", ap, model, material, callback, arg);
  143.  
  144.     r = 0;
  145.     if (ap->model != NULL) {
  146.         this_model = ap->model;
  147.     } else {
  148.         this_model = model;
  149.     }
  150.     if (ap->material != NULL) {
  151.         this_material = ap->material;
  152.     } else {
  153.         this_material = material;
  154.     }
  155.     if (ap->render_style == BR_RSTYLE_NONE) {
  156.         return 0;
  157.     }
  158.     m_to_v = gPick_model_to_view__raycast;
  159.  
  160.     BrMatrix34PreTransform(&gPick_model_to_view__raycast, &ap->t);
  161.     if (ap->type == BR_ACTOR_MODEL) {
  162.         BrMatrix34Inverse(&v_to_m, &gPick_model_to_view__raycast);
  163.         if (PickBoundsTestRay__raycast(
  164.                 &this_model->bounds,
  165.                 (br_vector3*)v_to_m.m[3],
  166.                 (br_vector3*)v_to_m.m[2],
  167.                 0.0,
  168.                 BR_SCALAR_MAX,
  169.                 &t_near,
  170.                 &t_far)) {
  171.             dir.v[0] = -v_to_m.m[2][0];
  172.             dir.v[1] = -v_to_m.m[2][1];
  173.             dir.v[2] = -v_to_m.m[2][2];
  174.  
  175.             r = callback(
  176.                 ap,
  177.                 this_model,
  178.                 this_material,
  179.                 (br_vector3*)v_to_m.m[3],
  180.                 &dir,
  181.                 t_near,
  182.                 t_far,
  183.                 arg);
  184.             if (r) {
  185.                 gPick_model_to_view__raycast = m_to_v;
  186.                 return r;
  187.             }
  188.         }
  189.         if (r) {
  190.             gPick_model_to_view__raycast = m_to_v;
  191.             return r;
  192.         }
  193.     } else if (ap->type == BR_ACTOR_BOUNDS || ap->type == BR_ACTOR_BOUNDS_CORRECT) {
  194.         BrMatrix34Inverse(&v_to_m, &gPick_model_to_view__raycast);
  195.         if (PickBoundsTestRay__raycast(
  196.                 (br_bounds*)ap->type_data,
  197.                 (br_vector3*)v_to_m.m[3],
  198.                 (br_vector3*)v_to_m.m[2],
  199.                 0.0,
  200.                 BR_SCALAR_MAX,
  201.                 &t_near,
  202.                 &t_far)) {
  203.             for (a = ap->children; a != NULL; a = a->next) {
  204.                 r = ActorPick2D(a, this_model, this_material, callback, arg);
  205.                 if (r) {
  206.                     break;
  207.                 }
  208.             }
  209.         }
  210.         gPick_model_to_view__raycast = m_to_v;
  211.         return r;
  212.     }
  213.     for (a = ap->children; a != NULL; a = a->next) {
  214.         r = ActorPick2D(a, this_model, this_material, callback, arg);
  215.         if (r) {
  216.             break;
  217.         }
  218.     }
  219.     gPick_model_to_view__raycast = m_to_v;
  220.     return r;
  221. }
  222.  
  223. // IDA: int __usercall DRScenePick2DXY@<EAX>(br_actor *world@<EAX>, br_actor *camera@<EDX>, br_pixelmap *viewport@<EBX>, int pick_x@<ECX>, int pick_y, dr_pick2d_cbfn *callback, void *arg)
  224. int DRScenePick2DXY(br_actor* world, br_actor* camera, br_pixelmap* viewport, int pick_x, int pick_y, dr_pick2d_cbfn* callback, void* arg) {
  225.     br_matrix34 camera_tfm;
  226.     br_scalar scale;
  227.     br_scalar cos_angle;
  228.     br_scalar sin_angle;
  229.     br_camera* camera_data;
  230.     br_angle view_over_2;
  231.     LOG_TRACE("(%p, %p, %p, %d, %d, %p, %p)", world, camera, viewport, pick_x, pick_y, callback, arg);
  232.  
  233.     camera_data = camera->type_data;
  234.     DRActorToRoot(camera, world, &camera_tfm);
  235.     BrMatrix34Inverse(&gPick_model_to_view__raycast, &camera_tfm);
  236.     view_over_2 = camera_data->field_of_view / 2;
  237.     cos_angle = BR_COS(view_over_2);
  238.     sin_angle = BR_SIN(view_over_2);
  239.     scale = cos_angle / sin_angle;
  240.     BrMatrix34PostScale(&gPick_model_to_view__raycast, scale / camera_data->aspect, scale, 1.f);
  241.     BrMatrix34PostShearZ(&gPick_model_to_view__raycast,
  242.         2 * pick_x / (float)viewport->width,
  243.         -2 * pick_y / (float)viewport->height);
  244.     return ActorPick2D(world, model_unk1, material_unk1, callback, arg);
  245. }
  246.  
  247. // IDA: int __usercall DRScenePick2D@<EAX>(br_actor *world@<EAX>, br_actor *camera@<EDX>, dr_pick2d_cbfn *callback@<EBX>, void *arg@<ECX>)
  248. int DRScenePick2D(br_actor* world, br_actor* camera, dr_pick2d_cbfn* callback, void* arg) {
  249.     br_matrix34 camera_tfm;
  250.     br_scalar scale;
  251.     br_camera* camera_data;
  252.     LOG_TRACE("(%p, %p, %p, %p)", world, camera, callback, arg);
  253.  
  254.     camera_data = (br_camera*)camera->type_data;
  255.     DRActorToRoot(camera, world, &camera_tfm);
  256.     BrMatrix34Inverse(&gPick_model_to_view__raycast, &camera_tfm);
  257.     scale = cosf(BrAngleToRadian(camera_data->field_of_view / 2)) / sinf(BrAngleToRadian(camera_data->field_of_view / 2));
  258.  
  259.     BrMatrix34PostScale(&gPick_model_to_view__raycast, scale / camera_data->aspect, scale, 1.0f);
  260.     return ActorPick2D(world, model_unk1, material_unk1, callback, arg);
  261. }
  262.  
  263. // IDA: int __usercall DRModelPick2D@<EAX>(br_model *model@<EAX>, br_material *material@<EDX>, br_vector3 *ray_pos@<EBX>, br_vector3 *ray_dir@<ECX>, br_scalar t_near, br_scalar t_far, dr_modelpick2d_cbfn *callback, void *arg)
  264. // Suffix added to avoid duplicate symbol
  265. int DRModelPick2D__raycast(br_model* model, br_material* material, br_vector3* ray_pos, br_vector3* ray_dir, br_scalar t_near, br_scalar t_far, dr_modelpick2d_cbfn* callback, void* arg) {
  266.     // DR_FACE* fp;
  267.     int f;
  268.     int axis_m;
  269.     int axis_0;
  270.     int axis_1;
  271.     int group;
  272.     br_scalar t;
  273.     //br_scalar n; // Pierre-Marie Baty -- unused variable
  274.     br_scalar d;
  275.     br_vector3 p;
  276.     double u0;
  277.     double u1;
  278.     double u2;
  279.     double v0;
  280.     double v1;
  281.     double v2;
  282.     br_scalar v0i1;
  283.     br_scalar v0i2;
  284.     double alpha;
  285.     double beta;
  286.     double f_d;
  287.     double f_n;
  288.     br_scalar s_alpha;
  289.     br_scalar s_beta;
  290.     br_vector2 map;
  291.     int v;
  292.     int e;
  293.     int r;
  294.     br_material* this_material;
  295.     br_scalar numerator;
  296.     //double f_numerator; // Pierre-Marie Baty -- unused variable
  297.     LOG_TRACE("(%p, %p, %p, %p, %f, %f, %p, %p)", model, material, ray_pos, ray_dir, t_near, t_far, callback, arg);
  298.  
  299.     struct v11group* grp_ptr;
  300.     br_vector4* eqn;
  301.  
  302.     t_near -= 0.001f;
  303.     t_far += 0.001f;
  304.     for (group = 0; group < V11MODEL(model)->ngroups; group++) {
  305.         grp_ptr = &V11MODEL(model)->groups[group];
  306.         for (f = 0; f < V11MODEL(model)->groups[group].nfaces; f++) {
  307.             eqn = &V11MODEL(model)->groups[group].eqn[f];
  308.             if (V11MODEL(model)->groups[group].user != NULL) {
  309.                 this_material = V11MODEL(model)->groups[group].user;
  310.             } else {
  311.                 this_material = material;
  312.             }
  313.             d = BrVector3Dot(eqn, ray_dir);
  314.             if (fabsf(d) >= 0.00000023841858f && ((this_material->flags & (BR_MATF_TWO_SIDED | BR_MATF_ALWAYS_VISIBLE)) != 0 || d <= 0.0)) //
  315.             {
  316.                 numerator = BrVector3Dot(eqn, ray_pos) - eqn->v[3];
  317.                 if (!BadDiv__raycast(numerator, d)) {
  318.                     t = -(numerator / d);
  319.                     if (t >= t_near && t <= t_far) {
  320.                         BrVector3Scale(&p, ray_dir, t);
  321.                         BrVector3Accumulate(&p, ray_pos);
  322.                         axis_m = (fabsf(eqn->v[1]) > fabsf(eqn->v[0])) ? 1 : 0;
  323.                         if (fabsf(eqn->v[2]) > fabsf(eqn->v[axis_m])) {
  324.                             axis_m = 2;
  325.                         }
  326.                         if (axis_m == 0) {
  327.                             axis_0 = 1;
  328.                             axis_1 = 2;
  329.                         } else if (axis_m == 1) {
  330.                             axis_0 = 0;
  331.                             axis_1 = 2;
  332.                         } else if (axis_m == 2) {
  333.                             axis_0 = 0;
  334.                             axis_1 = 1;
  335.                         }
  336.  
  337.                         v0 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[0]].v[axis_0];
  338.                         u0 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[0]].v[axis_1];
  339.  
  340.                         v1 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[1]].v[axis_0] - v0;
  341.                         u1 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[1]].v[axis_1] - u0;
  342.                         v2 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[2]].v[axis_0] - v0;
  343.                         u2 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[2]].v[axis_1] - u0;
  344.  
  345.                         v0i1 = p.v[axis_0] - v0;
  346.                         v0i2 = p.v[axis_1] - u0;
  347.                         if (fabs(v1) > 0.0000002384185791015625) {
  348.                             f_d = v0i2 * v1 - u1 * v0i1;
  349.                             f_n = u2 * v1 - u1 * v2;
  350.                             if (f_n == 0.) {
  351.                                 continue;
  352.                             }
  353.                             beta = f_d / f_n;
  354.                             alpha = (v0i1 - beta * v2) / v1;
  355.                         } else {
  356.                             beta = v0i1 / v2;
  357.                             alpha = (v0i2 - beta * u2) / u1;
  358.                         }
  359.  
  360.                         if (alpha >= 0.0 && beta >= 0.0 && beta + alpha <= 1.0) {
  361.                             s_alpha = alpha;
  362.                             s_beta = beta;
  363.                             BrVector2Scale(&map, &grp_ptr->map[grp_ptr->vertex_numbers[f].v[1]], s_alpha);
  364.                             DRVector2AccumulateScale__raycast(
  365.                                 &map,
  366.                                 &grp_ptr->map[grp_ptr->vertex_numbers[f].v[2]],
  367.                                 s_beta);
  368.                             DRVector2AccumulateScale__raycast(
  369.                                 &map,
  370.                                 &grp_ptr->map[grp_ptr->vertex_numbers[f].v[0]],
  371.                                 1.0f - (s_alpha + s_beta));
  372.                             v = 0;
  373.                             e = 1;
  374.                             if (s_alpha <= s_beta) {
  375.                                 if (0.5f - s_beta / 2.0f > s_alpha) {
  376.                                     e = 0;
  377.                                 }
  378.                                 if (1.0f - s_beta * 2.0f < s_alpha) {
  379.                                     v = 1;
  380.                                 }
  381.                             } else {
  382.                                 if (1.0f - s_beta * 2.0f > s_alpha) {
  383.                                     e = 2;
  384.                                 }
  385.                                 if (0.5f - s_beta / 2.0f < s_alpha) {
  386.                                     v = 2;
  387.                                 }
  388.                             }
  389.                             r = callback(model, this_material, ray_pos, ray_dir, t, f, e, v, &p, &map, arg);
  390.                             if (r != 0) {
  391.                                 return r;
  392.                             }
  393.                         }
  394.                     }
  395.                 }
  396.             }
  397.         }
  398.     }
  399.     return 0;
  400. }
  401.  
  402. // IDA: int __cdecl FindHighestPolyCallBack(br_model *pModel, br_material *pMaterial, br_vector3 *pRay_pos, br_vector3 *pRay_dir, br_scalar pT, int pF, int pE, int pV, br_vector3 *pPoint, br_vector2 *pMap, void *pArg)
  403. //  Suffix added to avoid duplicate symbol
  404. int FindHighestPolyCallBack__raycast(br_model* pModel, br_material* pMaterial, br_vector3* pRay_pos, br_vector3* pRay_dir, br_scalar pT, int pF, int pE, int pV, br_vector3* pPoint, br_vector2* pMap, void* pArg) {
  405.     //br_scalar the_y; // Pierre-Marie Baty -- unused variable
  406.     LOG_TRACE("(%p, %p, %p, %p, %f, %d, %d, %d, %p, %p, %p)", pModel, pMaterial, pRay_pos, pRay_dir, pT, pF, pE, pV, pPoint, pMap, pArg);
  407.  
  408.     if (pPoint->v[1] > gCurrent_y) {
  409.         if (gLowest_y_above > pPoint->v[1]) {
  410.             gLowest_y_above = pPoint->v[1];
  411.             gAbove_face_index = pF;
  412.             gAbove_model = pModel;
  413.         }
  414.     } else if (pPoint->v[1] > gHighest_y_below) {
  415.         gHighest_y_below = pPoint->v[1];
  416.         gBelow_face_index = pF;
  417.         gBelow_model = pModel;
  418.     }
  419.     return 0;
  420. }
  421.  
  422. // IDA: int __cdecl FindHighestCallBack(br_actor *pActor, br_model *pModel, br_material *pMaterial, br_vector3 *pRay_pos, br_vector3 *pRay_dir, br_scalar pT_near, br_scalar pT_far, void *pArg)
  423. //  Suffix added to avoid duplicate symbol
  424. int FindHighestCallBack__raycast(br_actor* pActor, br_model* pModel, br_material* pMaterial, br_vector3* pRay_pos, br_vector3* pRay_dir, br_scalar pT_near, br_scalar pT_far, void* pArg) {
  425.     LOG_TRACE("(%p, %p, %p, %p, %p, %f, %f, %p)", pActor, pModel, pMaterial, pRay_pos, pRay_dir, pT_near, pT_far, pArg);
  426.  
  427.     if (gProgram_state.current_car.current_car_actor < 0
  428.         || gProgram_state.current_car.car_model_actors[gProgram_state.current_car.current_car_actor].actor != pActor) {
  429.         DRModelPick2D__raycast(pModel, pMaterial, pRay_pos, pRay_dir, pT_near, pT_far, FindHighestPolyCallBack__raycast, pArg);
  430.     }
  431.     return 0;
  432. }
  433.  
  434. // IDA: void __usercall FindBestY(br_vector3 *pPosition@<EAX>, br_actor *gWorld@<EDX>, br_scalar pStarting_height, br_scalar *pNearest_y_above, br_scalar *pNearest_y_below, br_model **pNearest_above_model, br_model **pNearest_below_model, int *pNearest_above_face_index, int *pNearest_below_face_index)
  435. void FindBestY(br_vector3* pPosition, br_actor* gWorld, br_scalar pStarting_height, br_scalar* pNearest_y_above, br_scalar* pNearest_y_below, br_model** pNearest_above_model, br_model** pNearest_below_model, int* pNearest_above_face_index, int* pNearest_below_face_index) {
  436.     LOG_TRACE("(%p, %p, %f, %p, %p, %p, %p, %p, %p)", pPosition, gWorld, pStarting_height, pNearest_y_above, pNearest_y_below, pNearest_above_model, pNearest_below_model, pNearest_above_face_index, pNearest_below_face_index);
  437.  
  438.     gLowest_y_above = 30000.0;
  439.     gHighest_y_below = -30000.0;
  440.     gCurrent_y = pPosition->v[1] + 0.000011920929;
  441.     gY_picking_camera->t.t.euler.t = *pPosition;
  442.     gY_picking_camera->t.t.mat.m[3][1] = gY_picking_camera->t.t.mat.m[3][1] + pStarting_height;
  443.     DRScenePick2D(gWorld, gY_picking_camera, FindHighestCallBack__raycast, 0);
  444.     *pNearest_y_above = gLowest_y_above;
  445.     *pNearest_y_below = gHighest_y_below;
  446.     *pNearest_above_model = gAbove_model;
  447.     *pNearest_below_model = gBelow_model;
  448.     *pNearest_above_face_index = gAbove_face_index;
  449.     *pNearest_below_face_index = gBelow_face_index;
  450. }
  451.  
  452. // IDA: int __cdecl FindYVerticallyBelowPolyCallBack(br_model *pModel, br_material *pMaterial, br_vector3 *pRay_pos, br_vector3 *pRay_dir, br_scalar pT, int pF, int pE, int pV, br_vector3 *pPoint, br_vector2 *pMap, void *pArg)
  453. int FindYVerticallyBelowPolyCallBack(br_model* pModel, br_material* pMaterial, br_vector3* pRay_pos, br_vector3* pRay_dir, br_scalar pT, int pF, int pE, int pV, br_vector3* pPoint, br_vector2* pMap, void* pArg) {
  454.     br_scalar the_y;
  455.     LOG_TRACE("(%p, %p, %p, %p, %f, %d, %d, %d, %p, %p, %p)", pModel, pMaterial, pRay_pos, pRay_dir, pT, pF, pE, pV, pPoint, pMap, pArg);
  456.  
  457.     if (pMaterial->identifier == NULL || pMaterial->identifier[0] != '!') {
  458.         the_y = pPoint->v[Y];
  459.         if (the_y > gHighest_y_below) {
  460.             gHighest_y_below = the_y;
  461.         }
  462.     }
  463.     return 0;
  464. }
  465.  
  466. // IDA: int __cdecl FindYVerticallyBelowCallBack(br_actor *pActor, br_model *pModel, br_material *pMaterial, br_vector3 *pRay_pos, br_vector3 *pRay_dir, br_scalar pT_near, br_scalar pT_far, void *pArg)
  467. int FindYVerticallyBelowCallBack(br_actor* pActor, br_model* pModel, br_material* pMaterial, br_vector3* pRay_pos, br_vector3* pRay_dir, br_scalar pT_near, br_scalar pT_far, void* pArg) {
  468.     LOG_TRACE("(%p, %p, %p, %p, %p, %f, %f, %p)", pActor, pModel, pMaterial, pRay_pos, pRay_dir, pT_near, pT_far, pArg);
  469.  
  470.     if (gProgram_state.current_car.current_car_actor < 0
  471.         || gProgram_state.current_car.car_model_actors[gProgram_state.current_car.current_car_actor].actor != pActor) {
  472.         DRModelPick2D__raycast(pModel, pMaterial, pRay_pos, pRay_dir, pT_near, pT_far, (dr_modelpick2d_cbfn*)FindYVerticallyBelowPolyCallBack, pArg);
  473.     }
  474.     return 0;
  475. }
  476.  
  477. // IDA: br_scalar __usercall FindYVerticallyBelow@<ST0>(br_vector3 *pPosition@<EAX>)
  478. br_scalar FindYVerticallyBelow(br_vector3* pPosition) {
  479.     tU8 cx;
  480.     tU8 cz;
  481.     tU8 x;
  482.     tU8 z;
  483.     tTrack_spec* track_spec;
  484.     LOG_TRACE("(%p)", pPosition);
  485.  
  486.     track_spec = &gProgram_state.track_spec;
  487.     XZToColumnXZ(&cx, &cz, pPosition->v[X], pPosition->v[Z], track_spec);
  488.     gHighest_y_below = BR_SCALAR_MIN;
  489.     BrVector3Copy(&gY_picking_camera->t.t.translate.t, pPosition);
  490.     for (x = MAX(cx - 1, 0); x < MIN(cx + 2, track_spec->ncolumns_x); x++) {
  491.         for (z = MAX(cz - 1, 0); z < MIN(cz + 2, track_spec->ncolumns_z); z++) {
  492.             if (track_spec->columns[z][x] != NULL) {
  493.                 if (track_spec->blends[z][x] != NULL) {
  494.                     track_spec->blends[z][x]->render_style = BR_RSTYLE_FACES;
  495.                 }
  496.                 DRScenePick2D(track_spec->columns[z][x], gY_picking_camera, FindYVerticallyBelowCallBack, NULL);
  497.                 if (track_spec->blends[z][x] != NULL) {
  498.                     track_spec->blends[z][x]->render_style = BR_RSTYLE_NONE;
  499.                 }
  500.             }
  501.         }
  502.     }
  503.     return gHighest_y_below;
  504. }
  505.  
  506. // IDA: br_scalar __usercall FindYVerticallyBelow2@<ST0>(br_vector3 *pCast_point@<EAX>)
  507. br_scalar FindYVerticallyBelow2(br_vector3* pCast_point) {
  508.     br_scalar result;
  509.     int number_of_attempts;
  510.     br_vector3 cast_point;
  511.     LOG_TRACE("(%p)", pCast_point);
  512.  
  513.     BrVector3Copy(&cast_point, pCast_point);
  514.     for (number_of_attempts = 0; number_of_attempts <= 10; number_of_attempts++) {
  515.         result = FindYVerticallyBelow(&cast_point);
  516.         cast_point.v[Y] += .2f;
  517.         if (result >= -100.f) {
  518.             return result;
  519.         }
  520.     }
  521.     return result;
  522. }
  523.