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 "finteray.h"
  2. #include "brender.h"
  3. #include "brucetrk.h"
  4. #include "car.h"
  5. #include "formats.h"
  6. #include "globvars.h"
  7. #include "harness/trace.h"
  8. #include "raycast.h"
  9. #include "world.h"
  10. #include <math.h>
  11. #include <stdlib.h>
  12.  
  13. int gPling_materials = 1;
  14. br_material* gSub_material;
  15. br_material* gReal_material;
  16. int gNfaces;
  17. br_matrix34 gPick_model_to_view__finteray; // suffix added to avoid duplicate symbol
  18. int gTemp_group;
  19. br_model* gNearest_model;
  20. br_model* gSelected_model;
  21. int gNearest_face_group;
  22. int gNearest_face;
  23. br_scalar gNearest_T;
  24. tFace_ref* gPling_face;
  25.  
  26. // IDA: int __cdecl BadDiv(br_scalar a, br_scalar b)
  27. // Suffix added to avoid duplicate symbol
  28. int BadDiv__finteray(br_scalar a, br_scalar b) {
  29.     // LOG_TRACE("(%f, %f)", a, b);
  30.  
  31.     return fabsf(b) < 1.0f && fabsf(a) > fabsf(b) * BR_SCALAR_MAX;
  32. }
  33.  
  34. // IDA: void __usercall DRVector2AccumulateScale(br_vector2 *a@<EAX>, br_vector2 *b@<EDX>, br_scalar s)
  35. // Suffix added to avoid duplicate symbol
  36. void DRVector2AccumulateScale__finteray(br_vector2* a, br_vector2* b, br_scalar s) {
  37.     LOG_TRACE("(%p, %p, %f)", a, b, s);
  38.  
  39.     a->v[0] = b->v[0] * s + a->v[0];
  40.     a->v[1] = b->v[1] * s + a->v[1];
  41. }
  42.  
  43. // 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)
  44. //  Suffix added to avoid duplicate symbol
  45. int PickBoundsTestRay__finteray(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) {
  46.     int i;
  47.     float s;
  48.     float t;
  49.     LOG_TRACE("(%p, %p, %p, %f, %f, %p, %p)", b, rp, rd, t_near, t_far, new_t_near, new_t_far);
  50.  
  51.     for (i = 0; i < 3; i++) {
  52.         if (rd->v[i] >= -0.00000023841858) {
  53.             if (rd->v[i] <= 0.00000023841858) {
  54.                 if (b->max.v[i] < rp->v[i] || rp->v[i] < b->min.v[i]) {
  55.                     return 0;
  56.                 }
  57.             } else {
  58.                 s = (-1.0f / rd->v[i]) * (rp->v[i] - b->max.v[i]);
  59.                 if (s >= BR_SCALAR_MIN) {
  60.                     if (s < t_far) {
  61.                         t_far = (-1.0f / rd->v[i]) * (rp->v[i] - b->max.v[i]);
  62.                     }
  63.                 } else {
  64.                     t_far = BR_SCALAR_MIN;
  65.                 }
  66.                 t = (-1.0f / rd->v[i]) * (rp->v[i] - b->min.v[i]);
  67.                 if (t <= BR_SCALAR_MAX) {
  68.                     if (t > t_near) {
  69.                         t_near = (-1.0f / rd->v[i]) * (rp->v[i] - b->min.v[i]);
  70.                     }
  71.                 } else {
  72.                     t_near = BR_SCALAR_MAX;
  73.                 }
  74.             }
  75.         } else {
  76.             s = (-1.0f / rd->v[i]) * (rp->v[i] - b->max.v[i]);
  77.             if (s <= BR_SCALAR_MAX) {
  78.                 if (s > t_near) {
  79.                     t_near = (-1.0f / rd->v[i]) * (rp->v[i] - b->max.v[i]);
  80.                 }
  81.             } else {
  82.                 t_near = BR_SCALAR_MAX;
  83.             }
  84.             t = (-1.0f / rd->v[i]) * (rp->v[i] - b->min.v[i]);
  85.             if (t >= BR_SCALAR_MIN) {
  86.                 if (t < t_far) {
  87.                     t_far = (-1.0f / rd->v[i]) * (rp->v[i] - b->min.v[i]);
  88.                 }
  89.             } else {
  90.                 t_far = BR_SCALAR_MIN;
  91.             }
  92.         }
  93.     }
  94.     if (t_far < t_near) {
  95.         return 0;
  96.     }
  97.     *new_t_near = t_near;
  98.     *new_t_far = t_far;
  99.     return 1;
  100. }
  101.  
  102. // IDA: int __usercall ActorRayPick2D@<EAX>(br_actor *ap@<EAX>, br_vector3 *pPosition@<EDX>, br_vector3 *pDir@<EBX>, br_model *model@<ECX>, br_material *material, dr_pick2d_cbfn *callback)
  103. int ActorRayPick2D(br_actor* ap, br_vector3* pPosition, br_vector3* pDir, br_model* model, br_material* material, dr_pick2d_cbfn* callback) {
  104.     br_actor* a;
  105.     br_model* this_model;
  106.     br_material* this_material;
  107.     br_scalar t_near;
  108.     br_scalar t_far;
  109.     int r;
  110.     br_matrix34 mat;
  111.     br_matrix34 invmat;
  112.     br_vector3 pos;
  113.     br_vector3 dir;
  114.     void* arg;
  115.     LOG_TRACE("(%p, %p, %p, %p, %p, %p)", ap, pPosition, pDir, model, material, callback);
  116.  
  117.     t_near = 0.0;
  118.     t_far = 1.0;
  119.     r = 0;
  120.     arg = NULL;
  121.     if (ap->model != NULL) {
  122.         this_model = ap->model;
  123.     } else {
  124.         this_model = model;
  125.     }
  126.     if (ap->material != NULL) {
  127.         this_material = ap->material;
  128.     } else {
  129.         this_material = material;
  130.     }
  131.     if (ap->render_style == BR_RSTYLE_NONE) {
  132.         return 0;
  133.     }
  134.     if (ap->identifier != NULL && ap->identifier[0] == '&') {
  135.         BrTransformToMatrix34(&mat, &ap->t);
  136.         BrMatrix34Inverse(&invmat, &mat);
  137.         BrMatrix34ApplyP(&pos, pPosition, &invmat);
  138.         BrMatrix34ApplyV(&dir, pDir, &invmat);
  139.         pPosition = &pos;
  140.         pDir = &dir;
  141.     }
  142.     if (ap->type == BR_ACTOR_MODEL) {
  143.         if (PickBoundsTestRay__finteray(&this_model->bounds, pPosition, pDir, t_near, t_far, &t_near, &t_far)) {
  144.             t_near = 0.0;
  145.             t_far = MIN(1.f, gNearest_T);
  146.             r = callback(ap, this_model, this_material, pPosition, pDir, t_near, t_far, arg);
  147.             if (r) {
  148.                 return r;
  149.             }
  150.         }
  151.         if (r) {
  152.             return r;
  153.         }
  154.     } else if (ap->type >= BR_ACTOR_BOUNDS && ap->type <= BR_ACTOR_BOUNDS_CORRECT) {
  155.         if (PickBoundsTestRay__finteray((br_bounds*)ap->type_data, pPosition, pDir, t_near, t_far, &t_near, &t_far)) {
  156.             for (a = ap->children; a != NULL; a = a->next) {
  157.                 r = ActorRayPick2D(a, pPosition, pDir, this_model, this_material, callback);
  158.                 if (r) {
  159.                     break;
  160.                 }
  161.             }
  162.         }
  163.         return r;
  164.     }
  165.     for (a = ap->children; a != NULL; a = a->next) {
  166.         r = ActorRayPick2D(a, pPosition, pDir, this_model, this_material, callback);
  167.         if (r) {
  168.             break;
  169.         }
  170.     }
  171.     return r;
  172. }
  173.  
  174. // IDA: int __usercall DRSceneRayPick2D@<EAX>(br_actor *world@<EAX>, br_vector3 *pPosition@<EDX>, br_vector3 *pDir@<EBX>, dr_pick2d_cbfn *callback@<ECX>)
  175. int DRSceneRayPick2D(br_actor* world, br_vector3* pPosition, br_vector3* pDir, dr_pick2d_cbfn* callback) {
  176.     LOG_TRACE("(%p, %p, %p, %p)", world, pPosition, pDir, callback);
  177.  
  178.     BrMatrix34Inverse(&gPick_model_to_view__finteray, &world->t.t.mat);
  179.     LOG_WARN_ONCE("Missing material and model pointers to ActorRayPick2D");
  180.     return ActorRayPick2D(world, pPosition, pDir, NULL, NULL, callback);
  181. }
  182.  
  183. // 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)
  184. //  Suffix added to avoid duplicate symbol
  185. int DRModelPick2D__finteray(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) {
  186.     // DR_FACE* fp;
  187.     int f;
  188.     int axis_m;
  189.     int axis_0;
  190.     int axis_1;
  191.     br_scalar t;
  192.     br_scalar n;
  193.     br_scalar d;
  194.     br_vector3 p;
  195.     float u0;
  196.     float u1;
  197.     float u2;
  198.     float v0;
  199.     float v1;
  200.     float v2;
  201.     br_scalar v0i1;
  202.     br_scalar v0i2;
  203.     float alpha;
  204.     float beta;
  205.     float f_d;
  206.     float f_n;
  207.     br_scalar s_alpha;
  208.     br_scalar s_beta;
  209.     br_vector2 map;
  210.     int v;
  211.     int e;
  212.     int r;
  213.     br_material* this_material;
  214.     br_scalar numerator;
  215.     float f_numerator;
  216.     int group;
  217.     LOG_TRACE("(%p, %p, %p, %p, %f, %f, %p, %p)", model, material, ray_pos, ray_dir, t_near, t_far, callback, arg);
  218.  
  219.     struct v11group* grp_ptr;
  220.     br_vector4* eqn;
  221.  
  222.     t_near -= 0.00001f;
  223.     t_far += 0.00001f;
  224.     for (group = 0; group < V11MODEL(model)->ngroups; group++) {
  225.         grp_ptr = &V11MODEL(model)->groups[group];
  226.         for (f = 0; f < V11MODEL(model)->groups[group].nfaces; f++) {
  227.             eqn = &V11MODEL(model)->groups[group].eqn[f];
  228.             if (V11MODEL(model)->groups[group].user) {
  229.                 this_material = V11MODEL(model)->groups[group].user;
  230.             } else {
  231.                 this_material = material;
  232.             }
  233.             d = BrVector3Dot(eqn, ray_dir);
  234.             if (fabs(d) >= 0.00000023841858 && (!this_material || !this_material->identifier || *this_material->identifier != '!' || !gPling_materials)
  235.                 && (!this_material || (this_material->flags & 0x1800) != 0 || d <= 0.0)) {
  236.                 numerator = eqn->v[1] * ray_pos->v[1]
  237.                     + eqn->v[2] * ray_pos->v[2]
  238.                     + eqn->v[0] * ray_pos->v[0]
  239.                     - eqn->v[3];
  240.                 if (!BadDiv__finteray(numerator, d)) {
  241.                     t = -(numerator / d);
  242.                     if (t >= t_near && t <= t_far) {
  243.                         BrVector3Scale(&p, ray_dir, t);
  244.                         BrVector3Accumulate(&p, ray_pos);
  245.                         axis_m = fabsf(eqn->v[0]) < fabsf(eqn->v[1]);
  246.                         if (fabsf(eqn->v[2]) > fabsf(eqn->v[axis_m])) {
  247.                             axis_m = 2;
  248.                         }
  249.                         if (axis_m) {
  250.                             axis_0 = 0;
  251.                             if (axis_m == 1) {
  252.                                 axis_1 = 2;
  253.                             } else {
  254.                                 axis_1 = 1;
  255.                             }
  256.                         } else {
  257.                             axis_0 = 1;
  258.                             axis_1 = 2;
  259.                         }
  260.  
  261.                         v0 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[0]].v[axis_0];
  262.                         u0 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[0]].v[axis_1];
  263.                         v1 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[1]].v[axis_0] - v0;
  264.                         u1 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[1]].v[axis_1] - u0;
  265.                         v2 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[2]].v[axis_0] - v0;
  266.                         u2 = grp_ptr->position[grp_ptr->vertex_numbers[f].v[2]].v[axis_1] - u0;
  267.  
  268.                         v0i1 = p.v[axis_0] - v0;
  269.                         v0i2 = p.v[axis_1] - u0;
  270.                         if (fabs(v1) > 0.0000002384185791015625) {
  271.                             f_n = u2 * v1 - u1 * v2;
  272.                             f_d = v0i2 * v1 - u1 * v0i1;
  273.                             if (fabs(f_n) < fabs(f_d)) {
  274.                                 continue;
  275.                             }
  276.                             if (f_n == 0) {
  277.                                 continue;
  278.                             }
  279.                             beta = f_d / f_n;
  280.                             if (beta < 0.0 || beta > 1.0 || v1 == 0.0) {
  281.                                 continue;
  282.                             }
  283.                             alpha = (v0i1 - beta * v2) / v1;
  284.                         } else {
  285.                             if (fabsf(v2) < fabsf(v0i1)) {
  286.                                 continue;
  287.                             }
  288.                             if (v2 == 0) {
  289.                                 continue;
  290.                             }
  291.  
  292.                             beta = v0i1 / v2;
  293.                             if (beta < 0.0 || beta > 1.0 || u1 == 0.0) {
  294.                                 continue;
  295.                             }
  296.                             alpha = (v0i2 - beta * u2) / u1;
  297.                         }
  298.  
  299.                         if (alpha >= 0.0 && beta + alpha <= 1.0) {
  300.                             s_alpha = alpha;
  301.                             s_beta = beta;
  302.                             BrVector2Scale(&map, &grp_ptr->map[grp_ptr->vertex_numbers[f].v[1]], s_alpha);
  303.                             DRVector2AccumulateScale__finteray(
  304.                                 &map,
  305.                                 &grp_ptr->map[grp_ptr->vertex_numbers[f].v[2]],
  306.                                 s_beta);
  307.                             DRVector2AccumulateScale__finteray(
  308.                                 &map,
  309.                                 &grp_ptr->map[grp_ptr->vertex_numbers[f].v[0]],
  310.                                 1.0 - (s_alpha + s_beta));
  311.                             v = 0;
  312.                             e = 1;
  313.                             if (s_alpha <= s_beta) {
  314.                                 if (0.5 - s_beta / 2.0 > s_alpha) {
  315.                                     e = 0;
  316.                                 }
  317.                                 if (1.0 - s_beta * 2.0 < s_alpha) {
  318.                                     v = 1;
  319.                                 }
  320.                             } else {
  321.                                 if (1.0 - s_beta * 2.0 > s_alpha) {
  322.                                     e = 2;
  323.                                 }
  324.                                 if (0.5 - s_beta / 2.0 < s_alpha) {
  325.                                     v = 2;
  326.                                 }
  327.                             }
  328.                             gTemp_group = group;
  329.                             r = callback(model, this_material, ray_pos, ray_dir, t, f, e, v, &p, &map, arg);
  330.                             if (r) {
  331.                                 return r;
  332.                             }
  333.                         }
  334.                     }
  335.                 }
  336.             }
  337.         }
  338.     }
  339.     return 0;
  340. }
  341.  
  342. // 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)
  343. // Suffix added to avoid duplicate symbol
  344. int FindHighestPolyCallBack__finteray(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) {
  345.     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);
  346.  
  347.     if (pT < (double)gNearest_T) {
  348.         gNearest_T = pT;
  349.         gNearest_model = pModel;
  350.         gNearest_face = pF;
  351.         gNearest_face_group = gTemp_group;
  352.     }
  353.     return 0;
  354. }
  355.  
  356. // 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)
  357. // Suffix added to avoid duplicate symbol
  358. int FindHighestCallBack__finteray(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) {
  359.     LOG_TRACE("(%p, %p, %p, %p, %p, %f, %f, %p)", pActor, pModel, pMaterial, pRay_pos, pRay_dir, pT_near, pT_far, pArg);
  360.  
  361.     if (gProgram_state.current_car.current_car_actor < 0
  362.         || gProgram_state.current_car.car_model_actors[gProgram_state.current_car.current_car_actor].actor != pActor) {
  363.         DRModelPick2D__finteray(pModel, pMaterial, pRay_pos, pRay_dir, pT_near, pT_far, FindHighestPolyCallBack__finteray, pArg);
  364.     }
  365.     return 0;
  366. }
  367.  
  368. // IDA: void __usercall FindFace(br_vector3 *pPosition@<EAX>, br_vector3 *pDir@<EDX>, br_vector3 *nor@<EBX>, br_scalar *t@<ECX>, br_material **material)
  369. void FindFace(br_vector3* pPosition, br_vector3* pDir, br_vector3* nor, br_scalar* t, br_material** material) {
  370.     int group;
  371.     LOG_TRACE("(%p, %p, %p, %p, %p)", pPosition, pDir, nor, t, material);
  372.  
  373.     br_vector4* eqn;
  374.  
  375.     gNearest_T = 100.0f;
  376.     DRSceneRayPick2D(gTrack_actor, pPosition, pDir, FindHighestCallBack__finteray);
  377.     *t = gNearest_T;
  378.     if (*t < 100.0f) {
  379.         group = gNearest_face_group;
  380.         eqn = &V11MODEL(gNearest_model)->groups[group].eqn[gNearest_face];
  381.         nor->v[0] = eqn->v[0];
  382.         nor->v[1] = eqn->v[1];
  383.         nor->v[2] = eqn->v[2];
  384.         *material = V11MODEL(gNearest_model)->groups[group].user;
  385.     }
  386. }
  387.  
  388. // IDA: void __cdecl EnablePlingMaterials()
  389. void EnablePlingMaterials(void) {
  390.     LOG_TRACE("()");
  391.  
  392.     gPling_materials = 1;
  393. }
  394.  
  395. // IDA: void __cdecl DisablePlingMaterials()
  396. void DisablePlingMaterials(void) {
  397.     LOG_TRACE("()");
  398.  
  399.     gPling_materials = 0;
  400. }
  401.  
  402. // IDA: void __usercall CheckSingleFace(tFace_ref *pFace@<EAX>, br_vector3 *ray_pos@<EDX>, br_vector3 *ray_dir@<EBX>, br_vector3 *normal@<ECX>, br_scalar *rt)
  403. void CheckSingleFace(tFace_ref* pFace, br_vector3* ray_pos, br_vector3* ray_dir, br_vector3* normal, br_scalar* rt) {
  404.     br_scalar t;
  405.     br_scalar numerator;
  406.     br_scalar d;
  407.     br_vector3 p;
  408.     br_vector3 tv;
  409.     int axis_m;
  410.     int axis_0;
  411.     int axis_1;
  412.     double u0;
  413.     double u1;
  414.     double u2;
  415.     double v0;
  416.     double v1;
  417.     double v2;
  418.     br_scalar v0i1;
  419.     br_scalar v0i2;
  420.     double alpha;
  421.     double beta;
  422.     double f_d;
  423.     //double f_n; // Pierre-Marie Baty -- unused variable
  424.     //double f_numerator; // Pierre-Marie Baty -- unused variable
  425.     br_material* this_material;
  426.     LOG_TRACE("(%p, %p, %p, %p, %p)", pFace, ray_pos, ray_dir, normal, rt);
  427.  
  428.     this_material = pFace->material;
  429.     *rt = 100.0;
  430.  
  431.     d = pFace->normal.v[1] * ray_dir->v[1] + ray_dir->v[2] * pFace->normal.v[2] + ray_dir->v[0] * pFace->normal.v[0];
  432.     if ((this_material == NULL || (this_material->flags & (BR_MATF_TWO_SIDED | BR_MATF_ALWAYS_VISIBLE)) != 0 || d <= 0.0)
  433.         && (!this_material || !this_material->identifier || *this_material->identifier != '!' || !gPling_materials)
  434.         && fabs(d) >= 0.00000023841858) {
  435.         BrVector3Sub(&p, ray_pos, &pFace->v[0]);
  436.         numerator = BrVector3Dot(&pFace->normal, &p);
  437.         if (!BadDiv__finteray(numerator, d)) {
  438.             if (d > 0.0) {
  439.                 if (-numerator < -0.001 || -numerator > d + 0.003) {
  440.                     return;
  441.                 }
  442.             } else if (numerator < -0.001 || 0.003 - d < numerator) {
  443.                 return;
  444.             }
  445.             t = -(numerator / d);
  446.             if (t > 1.0) {
  447.                 t = 1.0;
  448.             }
  449.             BrVector3Scale(&tv, ray_dir, t);
  450.             BrVector3Accumulate(&tv, ray_pos);
  451.             axis_m = fabs(pFace->normal.v[0]) < fabs(pFace->normal.v[1]);
  452.             if (fabs(pFace->normal.v[2]) > fabs(pFace->normal.v[axis_m])) {
  453.                 axis_m = 2;
  454.             }
  455.             if (axis_m) {
  456.                 axis_0 = 0;
  457.                 if (axis_m == 1) {
  458.                     axis_1 = 2;
  459.                 } else {
  460.                     axis_1 = 1;
  461.                 }
  462.             } else {
  463.                 axis_0 = 1;
  464.                 axis_1 = 2;
  465.             }
  466.             v0i1 = pFace->v[0].v[axis_0];
  467.             v0i2 = pFace->v[0].v[axis_1];
  468.             u0 = pFace->v[1].v[axis_0] - v0i1;
  469.             u1 = pFace->v[1].v[axis_1] - v0i2;
  470.             v0 = pFace->v[2].v[axis_0] - v0i1;
  471.             v1 = pFace->v[2].v[axis_1] - v0i2;
  472.             u2 = tv.v[axis_0] - v0i1;
  473.             v2 = tv.v[axis_1] - v0i2;
  474.             if (fabs(u0) > 0.0000002384185791015625) {
  475.                 f_d = v1 * u0 - u1 * v0;
  476.                 if (f_d == 0) {
  477.                     return;
  478.                 }
  479.                 alpha = (v2 * u0 - u1 * u2) / f_d;
  480.                 beta = (u2 - alpha * v0) / u0;
  481.             } else {
  482.                 alpha = u2 / v0;
  483.                 beta = (v2 - alpha * v1) / u1;
  484.             }
  485.             if (beta >= -0.0001 && alpha >= -0.0001 && alpha + beta <= 1.0001) {
  486.                 *rt = t;
  487.                 *normal = pFace->normal;
  488.                 if (d > 0.0) {
  489.                     BrVector3Negate(normal, normal);
  490.                 }
  491.             }
  492.         }
  493.     }
  494. }
  495.  
  496. // IDA: void __usercall MultiRayCheckSingleFace(int pNum_rays@<EAX>, tFace_ref *pFace@<EDX>, br_vector3 *ray_pos@<EBX>, br_vector3 *ray_dir@<ECX>, br_vector3 *normal, br_scalar *rt)
  497. void MultiRayCheckSingleFace(int pNum_rays, tFace_ref* pFace, br_vector3* ray_pos, br_vector3* ray_dir, br_vector3* normal, br_scalar* rt) {
  498.     int i;
  499.     br_scalar t[4];
  500.     br_scalar numerator;
  501.     br_scalar d;
  502.     br_vector3 p[4];
  503.     br_vector3 tv;
  504.     int axis_m;
  505.     int axis_0;
  506.     int axis_1;
  507.     double u0[4];
  508.     double u1;
  509.     double u2;
  510.     double v0[4];
  511.     double v1;
  512.     double v2;
  513.     br_scalar v0i1;
  514.     br_scalar v0i2;
  515.     double alpha;
  516.     double beta;
  517.     double f_d;
  518.     double f_n;
  519.     double f_numerator;
  520.     br_material* this_material;
  521.     LOG_TRACE("(%d, %p, %p, %p, %p, %p)", pNum_rays, pFace, ray_pos, ray_dir, normal, rt);
  522.  
  523.     this_material = pFace->material;
  524.     d = ray_dir->v[2] * pFace->normal.v[2] + ray_dir->v[1] * pFace->normal.v[1] + ray_dir->v[0] * pFace->normal.v[0];
  525.     for (i = 0; i < pNum_rays; ++i) {
  526.         rt[i] = 100.0;
  527.     }
  528.     if ((!this_material || (this_material->flags & 0x1800) != 0 || d <= 0.0)
  529.         && (!this_material || !this_material->identifier || *this_material->identifier != '!' || !gPling_materials)
  530.         && fabs(d) >= 0.00000023841858) {
  531.         for (i = 0;; ++i) {
  532.             if (i >= pNum_rays) {
  533.                 axis_m = fabs(pFace->normal.v[0]) < fabs(pFace->normal.v[1]);
  534.                 if (fabs(pFace->normal.v[2]) > fabs(pFace->normal.v[axis_m])) {
  535.                     axis_m = 2;
  536.                 }
  537.                 if (axis_m) {
  538.                     axis_0 = 0;
  539.                     if (axis_m == 1) {
  540.                         axis_1 = 2;
  541.                     } else {
  542.                         axis_1 = 1;
  543.                     }
  544.                 } else {
  545.                     axis_0 = 1;
  546.                     axis_1 = 2;
  547.                 }
  548.                 v0i1 = pFace->v[0].v[axis_0];
  549.                 v0i2 = pFace->v[0].v[axis_1];
  550.                 u1 = pFace->v[1].v[axis_0] - v0i1;
  551.                 v1 = pFace->v[1].v[axis_1] - v0i2;
  552.                 u2 = pFace->v[2].v[axis_0] - v0i1;
  553.                 v2 = pFace->v[2].v[axis_1] - v0i2;
  554.                 i = 0;
  555.                 while (1) {
  556.                     if (i >= pNum_rays) {
  557.                         return;
  558.                     }
  559.                     if (t[i] != 100.0) {
  560.                         u0[i] = p[i].v[axis_0] - v0i1;
  561.                         v0[i] = p[i].v[axis_1] - v0i2;
  562.                         if (fabs(u1) <= 0.0000002384185791015625) {
  563.                             alpha = u0[i] / u2;
  564.                             beta = v0[i] - alpha * v2;
  565.                             f_d = beta / v1;
  566.                             goto LABEL_43;
  567.                         }
  568.                         f_numerator = v0[i] * u1 - u0[i] * v1;
  569.                         f_n = v2 * u1 - v1 * u2;
  570.                         if (f_n != 0) {
  571.                             alpha = f_numerator / f_n;
  572.                             beta = u0[i] - alpha * u2;
  573.                             f_d = beta / u1;
  574.                         LABEL_43:
  575.                             if (f_d >= -0.0001 && alpha >= -0.0001 && alpha + f_d <= 1.0001) {
  576.                                 rt[i] = t[i];
  577.                                 *normal = pFace->normal;
  578.                                 if (d > 0.0) {
  579.                                     normal->v[0] = -pFace->normal.v[0];
  580.                                     normal->v[1] = -pFace->normal.v[1];
  581.                                     normal->v[2] = -pFace->normal.v[2];
  582.                                 }
  583.                             }
  584.                         }
  585.                     }
  586.                     ++i;
  587.                     continue;
  588.                 }
  589.             }
  590.             tv.v[0] = ray_pos[i].v[0] - pFace->v[0].v[0];
  591.             tv.v[1] = ray_pos[i].v[1] - pFace->v[0].v[1];
  592.             tv.v[2] = ray_pos[i].v[2] - pFace->v[0].v[2];
  593.             numerator = pFace->normal.v[2] * tv.v[2] + pFace->normal.v[1] * tv.v[1] + pFace->normal.v[0] * tv.v[0];
  594.             if (BadDiv__finteray(numerator, d)) {
  595.                 return;
  596.             }
  597.             if (d > 0.0) {
  598.                 if (-numerator < -0.001 || -numerator > d + 0.003) {
  599.                     t[i] = 100.0;
  600.                     continue;
  601.                 }
  602.             } else if (numerator < -0.001 || 0.003 - d < numerator) {
  603.                 t[i] = 100.0;
  604.                 continue;
  605.             }
  606.             t[i] = -(numerator / d);
  607.             if (t[i] > 1.0) {
  608.                 t[i] = 1.0;
  609.             }
  610.             p[i].v[0] = t[i] * ray_dir->v[0];
  611.             p[i].v[1] = t[i] * ray_dir->v[1];
  612.             p[i].v[2] = t[i] * ray_dir->v[2];
  613.             p[i].v[0] = ray_pos[i].v[0] + p[i].v[0];
  614.             p[i].v[1] = ray_pos[i].v[1] + p[i].v[1];
  615.             p[i].v[2] = ray_pos[i].v[2] + p[i].v[2];
  616.         }
  617.     }
  618. }
  619.  
  620. // IDA: void __usercall GetNewBoundingBox(br_bounds *b2@<EAX>, br_bounds *b1@<EDX>, br_matrix34 *m@<EBX>)
  621. void GetNewBoundingBox(br_bounds* b2, br_bounds* b1, br_matrix34* m) {
  622.     br_vector3 a;
  623.     br_vector3 c[3];
  624.     int j;
  625.     LOG_TRACE("(%p, %p, %p)", b2, b1, m);
  626.  
  627.     BrMatrix34ApplyP(&b2->min, &b1->min, m);
  628.     BrVector3Copy(&b2->max, &b2->min);
  629.     BrVector3Sub(&a, &b1->max, &b1->min);
  630.     for (j = 0; j < 3; j++) {
  631.         BrVector3Scale(&c[j], (br_vector3*)m->m[j], a.v[j]);
  632.     }
  633.     for (j = 0; j < 3; ++j) {
  634.         b2->min.v[j] = (float)(c[2].v[j] < 0.f) * c[2].v[j]
  635.             + (float)(c[1].v[j] < 0.f) * c[1].v[j]
  636.             + (float)(c[0].v[j] < 0.f) * c[0].v[j]
  637.             + b2->min.v[j];
  638.         b2->max.v[j] = (float)(c[0].v[j] > 0.f) * c[0].v[j]
  639.             + (float)(c[2].v[j] > 0.f) * c[2].v[j]
  640.             + (float)(c[1].v[j] > 0.f) * c[1].v[j]
  641.             + b2->max.v[j];
  642.     }
  643. }
  644.  
  645. // IDA: int __usercall FindFacesInBox@<EAX>(tBounds *bnds@<EAX>, tFace_ref *face_list@<EDX>, int max_face@<EBX>)
  646. int FindFacesInBox(tBounds* bnds, tFace_ref* face_list, int max_face) {
  647.     br_vector3 a;
  648.     br_vector3 b;
  649.     br_vector3 c[3];
  650.     int i;
  651.     int j;
  652.     int x;
  653.     int z;
  654.     tU8 cx_min;
  655.     tU8 cx_max;
  656.     tU8 cz_min;
  657.     tU8 cz_max;
  658.     tTrack_spec* track_spec;
  659.     LOG_TRACE("(%p, %p, %d)", bnds, face_list, max_face);
  660.  
  661.     j = 0;
  662.     track_spec = &gProgram_state.track_spec;
  663.     BrVector3Add(&a, &bnds->original_bounds.min, &bnds->original_bounds.max);
  664.     BrVector3Scale(&a, &a, 0.5f);
  665.     BrMatrix34ApplyP(&bnds->box_centre, &a, bnds->mat);
  666.     BrVector3Sub(&b, &bnds->original_bounds.max, &bnds->original_bounds.min);
  667.     bnds->radius = BrVector3Length(&b) / 2.f;
  668.     BrMatrix34ApplyP(&bnds->real_bounds.min, &bnds->original_bounds.min, bnds->mat);
  669.     BrVector3Copy(&bnds->real_bounds.max, &bnds->real_bounds.min);
  670.     for (i = 0; i < 3; ++i) {
  671.         c[i].v[0] = bnds->mat->m[i][0] * b.v[i];
  672.         c[i].v[1] = bnds->mat->m[i][1] * b.v[i];
  673.         c[i].v[2] = bnds->mat->m[i][2] * b.v[i];
  674.     }
  675.     for (i = 0; i < 3; ++i) {
  676.         bnds->real_bounds.min.v[i] += MIN(c[0].v[i], 0.f)
  677.             + MIN(c[1].v[i], 0.f)
  678.             + MIN(c[2].v[i], 0.f);
  679.         bnds->real_bounds.max.v[i] += MAX(c[0].v[i], 0.f)
  680.             + MAX(c[1].v[i], 0.f)
  681.             + MAX(c[2].v[i], 0.f);
  682.     }
  683.     XZToColumnXZ(&cx_min, &cz_min, bnds->real_bounds.min.v[0], bnds->real_bounds.min.v[2], track_spec);
  684.     XZToColumnXZ(&cx_max, &cz_max, bnds->real_bounds.max.v[0], bnds->real_bounds.max.v[2], track_spec);
  685.     if (cx_min != 0) {
  686.         cx_min--;
  687.     }
  688.     if (cz_min != 0) {
  689.         cz_min--;
  690.     }
  691.     if (cx_max + 1 < track_spec->ncolumns_x) {
  692.         cx_max++;
  693.     }
  694.     if (cz_max + 1 < track_spec->ncolumns_z) {
  695.         cz_max++;
  696.     }
  697.     for (x = cx_min; x <= cx_max; x++) {
  698.         for (z = cz_min; z <= cz_max; z++) {
  699.             if (track_spec->columns[z][x] != NULL) {
  700.                 if (track_spec->blends[z][x] != NULL) {
  701.                     track_spec->blends[z][x]->render_style = BR_RSTYLE_FACES;
  702.                 }
  703.                 j = max_face - ActorBoxPick(bnds, track_spec->columns[z][x], model_unk1, material_unk1, &face_list[j], max_face - j, NULL);
  704.                 if (track_spec->blends[z][x] != NULL) {
  705.                     track_spec->blends[z][x]->render_style = BR_RSTYLE_NONE;
  706.                 }
  707.             }
  708.             if (track_spec->lollipops[z][x] != NULL) {
  709.                 j = max_face - ActorBoxPick(bnds, track_spec->lollipops[z][x], model_unk1, material_unk1, &face_list[j], max_face - j, NULL);
  710.             }
  711.         }
  712.     }
  713.     return j;
  714. }
  715.  
  716. // IDA: int __usercall FindFacesInBox2@<EAX>(tBounds *bnds@<EAX>, tFace_ref *face_list@<EDX>, int max_face@<EBX>)
  717. int FindFacesInBox2(tBounds* bnds, tFace_ref* face_list, int max_face) {
  718.     br_vector3 a;
  719.     br_vector3 b;
  720.     br_vector3 c[3];
  721.     int i;
  722.     int j;
  723.     LOG_TRACE("(%p, %p, %d)", bnds, face_list, max_face);
  724.  
  725.     a.v[0] = (bnds->original_bounds.min.v[0] + bnds->original_bounds.max.v[0]) * .5f;
  726.     a.v[1] = (bnds->original_bounds.min.v[1] + bnds->original_bounds.max.v[1]) * .5f;
  727.     a.v[2] = (bnds->original_bounds.min.v[2] + bnds->original_bounds.max.v[2]) * .5f;
  728.     BrMatrix34ApplyP(&bnds->box_centre, &a, bnds->mat);
  729.     BrVector3Sub(&b, &bnds->original_bounds.max, &bnds->original_bounds.min);
  730.     bnds->radius = BrVector3Length(&b) / 2.f;
  731.     BrMatrix34ApplyP(&bnds->real_bounds.min, &bnds->original_bounds.min, bnds->mat);
  732.     BrVector3Copy(&bnds->real_bounds.max, &bnds->real_bounds.min);
  733.     for (i = 0; i < 3; i++) {
  734.         BrVector3Scale(&c[i], (br_vector3*)bnds->mat->m[i], b.v[i]);
  735.     }
  736.     for (i = 0; i < 3; i++) {
  737.       bnds->real_bounds.min.v[i] += MIN(0.f, c[0].v[i]) + MIN(0.f, c[1].v[i]) + MIN(0.f, c[2].v[i]);
  738.       bnds->real_bounds.max.v[i] += MAX(0.f, c[0].v[i]) + MAX(0.f, c[1].v[i]) + MAX(0.f, c[2].v[i]);
  739.   }
  740.   return max_face - ActorBoxPick(bnds, gTrack_actor, model_unk1, material_unk1, face_list, max_face, NULL);
  741. }
  742.  
  743. // IDA: int __usercall ActorBoxPick@<EAX>(tBounds *bnds@<EAX>, br_actor *ap@<EDX>, br_model *model@<EBX>, br_material *material@<ECX>, tFace_ref *face_list, int max_face, br_matrix34 *pMat)
  744. int ActorBoxPick(tBounds* bnds, br_actor* ap, br_model* model, br_material* material, tFace_ref* face_list, int max_face, br_matrix34* pMat) {
  745.     br_model* this_model;
  746.     br_material* this_material;
  747.     int i;
  748.     int n;
  749.     int test_children;
  750.     br_actor* a;
  751.     br_actor* next_a;
  752.     br_matrix34 mat;
  753.     br_matrix34 mat2;
  754.     br_matrix34 invmat;
  755.     br_matrix34 box_to_actor;
  756.     tBounds new_bounds;
  757.     br_bounds br_bnds;
  758.     LOG_TRACE("(%p, %p, %p, %p, %p, %d, %p)", bnds, ap, model, material, face_list, max_face, pMat);
  759.  
  760.     i = 0;
  761.     test_children = 1;
  762.     if (ap->model != NULL) {
  763.         this_model = ap->model;
  764.     } else {
  765.         this_model = model;
  766.     }
  767.     if (ap->material != NULL) {
  768.         this_material = ap->material;
  769.     } else {
  770.         this_material = material;
  771.     }
  772.     if (ap->render_style == BR_RSTYLE_NONE) {
  773.         return max_face;
  774.     }
  775.     if (ap->identifier != NULL && ap->identifier[0] == '&') {
  776.         if (ap->children == NULL) {
  777.             if (ap->type != BR_ACTOR_MODEL) {
  778.                 return max_face;
  779.             }
  780.             if (!BoundsTransformTest(&this_model->bounds, &bnds->real_bounds, &ap->t.t.mat)) {
  781.                 return max_face;
  782.             }
  783.         }
  784.         if (pMat != NULL) {
  785.             BrMatrix34Mul(&mat, &ap->t.t.mat, pMat);
  786.             pMat = &mat;
  787.         } else {
  788.             pMat = &ap->t.t.mat;
  789.         }
  790.         BrMatrix34LPInverse(&invmat, &ap->t.t.mat);
  791.         BrMatrix34Mul(&mat2, bnds->mat, &invmat);
  792.         new_bounds.mat = &mat2;
  793.         BrVector3Copy(&new_bounds.original_bounds.min, &bnds->original_bounds.min);
  794.         BrVector3Copy(&new_bounds.original_bounds.max, &bnds->original_bounds.max);
  795.         BrMatrix34ApplyP(&new_bounds.box_centre, &bnds->box_centre, &invmat);
  796.         new_bounds.radius = bnds->radius;
  797.         GetNewBoundingBox(&new_bounds.real_bounds, &new_bounds.original_bounds, new_bounds.mat);
  798.         if (ap->identifier[1] >= '0' && ap->identifier[1] <= '9') {
  799.             if (!BoundsOverlapTest__finteray(&new_bounds.real_bounds, &this_model->bounds)) {
  800.                 return max_face;
  801.             }
  802.             BrMatrix34LPInverse(&invmat, bnds->mat);
  803.             BrMatrix34Mul(&box_to_actor, &ap->t.t.mat, &invmat);
  804.             GetNewBoundingBox(&br_bnds, &ap->model->bounds, &box_to_actor);
  805.             if (!BoundsOverlapTest__finteray(&br_bnds, &bnds->original_bounds)) {
  806.                 return max_face;
  807.             }
  808.             if (PullActorFromWorld(ap)) {
  809.                 return max_face;
  810.             }
  811.         }
  812.         bnds = &new_bounds;
  813.     }
  814.     if (ap->type == BR_ACTOR_MODEL) {
  815.         if (BoundsOverlapTest__finteray(&bnds->real_bounds, &this_model->bounds)) {
  816.             n = ModelPickBox(ap, bnds, this_model, this_material, &face_list[i], max_face, pMat);
  817.             if (pMat && max_face != n) {
  818.                 StopGroovidelic(ap);
  819.             }
  820.             i += max_face - n;
  821.             max_face = n;
  822.         }
  823.     } else if (ap->type == BR_ACTOR_BOUNDS || ap->type == BR_ACTOR_BOUNDS_CORRECT) {
  824.         test_children = BoundsOverlapTest__finteray(&bnds->real_bounds, (br_bounds*)ap->type_data);
  825.     }
  826.     if (test_children) {
  827.         for (a = ap->children; a != NULL; a = next_a) {
  828.             next_a = a->next;
  829.             n = ActorBoxPick(bnds, a, this_model, this_material, &face_list[i], max_face, pMat);
  830.             i += max_face - n;
  831.             max_face = n;
  832.         }
  833.     }
  834.     return max_face;
  835. }
  836.  
  837. // IDA: int __usercall ModelPickBox@<EAX>(br_actor *actor@<EAX>, tBounds *bnds@<EDX>, br_model *model@<EBX>, br_material *model_material@<ECX>, tFace_ref *face_list, int max_face, br_matrix34 *pMat)
  838. int ModelPickBox(br_actor* actor, tBounds* bnds, br_model* model, br_material* model_material, tFace_ref* face_list, int max_face, br_matrix34* pMat) {
  839.     int f;
  840.     int i;
  841.     int n;
  842.     int group;
  843.     // DR_FACE* fp;
  844.     int v1;
  845.     int v2;
  846.     int v3;
  847.     br_vector3 polygon[12];
  848.     br_vector3 a;
  849.     br_vector3 tv;
  850.     br_scalar t;
  851.     struct v11model* prepared;
  852.     LOG_TRACE("(%p, %p, %p, %p, %p, %d, %p)", actor, bnds, model, model_material, face_list, max_face, pMat);
  853.  
  854.     struct v11group* grp_ptr;
  855.  
  856.     prepared = model->prepared;
  857.     if (max_face <= 0) {
  858.         return 0;
  859.     }
  860.     for (group = 0; prepared->ngroups > group; group++) {
  861.         grp_ptr = &prepared->groups[group];
  862.         for (f = 0; f < prepared->groups[group].nfaces; f++) {
  863.             // fp = &prepared->groups[group].faces[f];
  864.             v1 = grp_ptr->vertex_numbers[f].v[0]; // fp->vertices[0];
  865.             // BrVector3Sub(&a, &prepared->groups[group].vertices[v1].p, &bnds->box_centre);
  866.             BrVector3Sub(&a, &grp_ptr->position[v1], &bnds->box_centre);
  867.             // t = BrVector3Dot((br_vector3*)&fp->eqn, &a);
  868.             t = BrVector3Dot((br_vector3*)&grp_ptr->eqn[f], &a);
  869.             if (fabsf(t) > bnds->radius) {
  870.                 continue;
  871.             }
  872.             // v2 = fp->vertices[1];
  873.             // v3 = fp->vertices[2];
  874.             v2 = grp_ptr->vertex_numbers[f].v[1];
  875.             v3 = grp_ptr->vertex_numbers[f].v[2];
  876.  
  877.             t = bnds->real_bounds.min.v[0];
  878.             if (t > grp_ptr->position[v1].v[0]
  879.                 && t > grp_ptr->position[v2].v[0]
  880.                 && t > grp_ptr->position[v3].v[0]) {
  881.                 continue;
  882.             }
  883.             t = bnds->real_bounds.max.v[0];
  884.             if (t < grp_ptr->position[v1].v[0]
  885.                 && t < grp_ptr->position[v2].v[0]
  886.                 && t < grp_ptr->position[v3].v[0]) {
  887.                 continue;
  888.             }
  889.             t = bnds->real_bounds.min.v[1];
  890.             if (t > grp_ptr->position[v1].v[1]
  891.                 && t > grp_ptr->position[v2].v[1]
  892.                 && t > grp_ptr->position[v3].v[1]) {
  893.                 continue;
  894.             }
  895.             t = bnds->real_bounds.max.v[1];
  896.             if (t < grp_ptr->position[v1].v[1]
  897.                 && t < grp_ptr->position[v2].v[1]
  898.                 && t < grp_ptr->position[v3].v[1]) {
  899.                 continue;
  900.             }
  901.             t = bnds->real_bounds.min.v[2];
  902.             if (t > grp_ptr->position[v1].v[2]
  903.                 && t > grp_ptr->position[v2].v[2]
  904.                 && t > grp_ptr->position[v3].v[2]) {
  905.                 continue;
  906.             }
  907.             t = bnds->real_bounds.max.v[2];
  908.             if (t < grp_ptr->position[v1].v[2]
  909.                 && t < grp_ptr->position[v2].v[2]
  910.                 && t < grp_ptr->position[v3].v[2]) {
  911.                 continue;
  912.             }
  913.             BrVector3Sub(&polygon[1], &grp_ptr->position[v1], (br_vector3*)bnds->mat->m[3]);
  914.             BrVector3Sub(&polygon[2], &grp_ptr->position[v2], (br_vector3*)bnds->mat->m[3]);
  915.             BrVector3Sub(&polygon[3], &grp_ptr->position[v3], (br_vector3*)bnds->mat->m[3]);
  916.             BrMatrix34TApplyV(&polygon[0], &polygon[1], bnds->mat);
  917.             BrMatrix34TApplyV(&polygon[1], &polygon[2], bnds->mat);
  918.             BrMatrix34TApplyV(&polygon[2], &polygon[3], bnds->mat);
  919.             n = 3;
  920.             for (i = 0; i < 3; i++) {
  921.                 ClipToPlaneGE(&polygon[0], &n, i, bnds->original_bounds.min.v[i]);
  922.                 if (n < 3) {
  923.                     break;
  924.                 }
  925.                 ClipToPlaneLE(&polygon[0], &n, i, bnds->original_bounds.max.v[i]);
  926.                 if (n < 3) {
  927.                     break;
  928.                 }
  929.             }
  930.             if (n >= 3) {
  931.                 if (pMat != NULL) {
  932.                     BrMatrix34ApplyP(&face_list->v[0], &grp_ptr->position[v1], pMat);
  933.                     BrMatrix34ApplyP(&face_list->v[1], &grp_ptr->position[v2], pMat);
  934.                     BrMatrix34ApplyP(&face_list->v[2], &grp_ptr->position[v3], pMat);
  935.                     BrVector3Copy(&tv, (br_vector3*)&grp_ptr->eqn[f]);
  936.                     BrMatrix34ApplyV(&face_list->normal, &tv, pMat);
  937.                 } else {
  938.                     BrVector3Copy(&face_list->v[0], &grp_ptr->position[v1]);
  939.                     BrVector3Copy(&face_list->v[1], &grp_ptr->position[v2]);
  940.                     BrVector3Copy(&face_list->v[2], &grp_ptr->position[v3]);
  941.                     BrVector3Copy(&face_list->normal, (br_vector3*)&grp_ptr->eqn[f]);
  942.                 }
  943.                 if (prepared->groups[group].user != NULL) {
  944.                     face_list->material = prepared->groups[group].user;
  945.                 } else {
  946.                     face_list->material = model_material;
  947.                 }
  948.                 face_list->flags = 0;
  949.                 if (face_list->material != NULL && (face_list->material->flags & (BR_MATF_TWO_SIDED | BR_MATF_ALWAYS_VISIBLE)) == 0) {
  950.                     face_list->flags |= (v1 < v2) | (v2 < v3) << 1 | (v3 < v1) << 2;
  951.                 }
  952.                 if (pMat != NULL) {
  953.                     face_list->d = BrVector3LengthSquared(&face_list->v[0]);
  954.                 } else {
  955.                     face_list->d = grp_ptr->eqn[f].v[3];
  956.                 }
  957.                 face_list->map[0] = &grp_ptr->map[v1];
  958.                 face_list->map[1] = &grp_ptr->map[v2];
  959.                 face_list->map[2] = &grp_ptr->map[v3];
  960.                 if (face_list->material != NULL
  961.                     && face_list->material->identifier != NULL
  962.                     && face_list->material->identifier[0] == '!') {
  963.                     gPling_face = face_list;
  964.                 }
  965.                 face_list++;
  966.                 max_face--;
  967.                 if (max_face == 0) {
  968.                     break;
  969.                 }
  970.             }
  971.         }
  972.         if (max_face == 0) {
  973.             break;
  974.         }
  975.     }
  976.     return max_face;
  977. }
  978.  
  979. // IDA: void __usercall ClipToPlaneGE(br_vector3 *p@<EAX>, int *nv@<EDX>, int i@<EBX>, br_scalar limit)
  980. void ClipToPlaneGE(br_vector3* p, int* nv, int i, br_scalar limit) {
  981.     int last_vertex;
  982.     int j;
  983.     int vertex;
  984.     int k;
  985.     br_vector3 p2[12];
  986.     LOG_TRACE("(%p, %p, %d, %f)", p, nv, i, limit);
  987.  
  988.     last_vertex = *nv - 1;
  989.     j = 0;
  990.     for (vertex = 0; *nv > vertex; ++vertex) {
  991.         if ((p[last_vertex].v[i] > limit) != (p[vertex].v[i] > limit)) {
  992.             for (k = 0; k < 3; ++k) {
  993.                 if (i != k) {
  994.                     p2[j].v[k] = (p[vertex].v[k] - p[last_vertex].v[k])
  995.                             * (limit - p[last_vertex].v[i])
  996.                             / (p[vertex].v[i] - p[last_vertex].v[i])
  997.                         + p[last_vertex].v[k];
  998.                 }
  999.             }
  1000.             p2[j++].v[i] = limit;
  1001.         }
  1002.         if (p[vertex].v[i] >= limit) {
  1003.             BrVector3Copy(&p2[j], &p[vertex]);
  1004.             j++;
  1005.         }
  1006.         last_vertex = vertex;
  1007.     }
  1008.     *nv = j;
  1009.     for (k = 0; k < j; k++) {
  1010.         BrVector3Copy(&p[k], &p2[k]);
  1011.     }
  1012. }
  1013.  
  1014. // IDA: void __usercall ClipToPlaneLE(br_vector3 *p@<EAX>, int *nv@<EDX>, int i@<EBX>, br_scalar limit)
  1015. void ClipToPlaneLE(br_vector3* p, int* nv, int i, br_scalar limit) {
  1016.     int last_vertex;
  1017.     int j;
  1018.     int vertex;
  1019.     int k;
  1020.     br_vector3 p2[12];
  1021.     LOG_TRACE("(%p, %p, %d, %f)", p, nv, i, limit);
  1022.  
  1023.     last_vertex = *nv - 1;
  1024.     j = 0;
  1025.     for (vertex = 0; *nv > vertex; ++vertex) {
  1026.         if ((p[vertex].v[i] > limit) != (p[last_vertex].v[i] > limit)) {
  1027.             for (k = 0; k < 3; ++k) {
  1028.                 if (k != i) {
  1029.                     p2[j].v[k] = (p[vertex].v[k] - p[last_vertex].v[k])
  1030.                             * (limit - p[last_vertex].v[i])
  1031.                             / (p[vertex].v[i] - p[last_vertex].v[i])
  1032.                         + p[last_vertex].v[k];
  1033.                 }
  1034.             }
  1035.             p2[j++].v[i] = limit;
  1036.         }
  1037.         if (p[vertex].v[i] <= (double)limit) {
  1038.             BrVector3Copy(&p2[j], &p[vertex]);
  1039.             j++;
  1040.         }
  1041.         last_vertex = vertex;
  1042.     }
  1043.     *nv = j;
  1044.     for (k = 0; k < j; k++) {
  1045.         BrVector3Copy(&p[k], &p2[k]);
  1046.     }
  1047. }
  1048.  
  1049. // IDA: int __usercall BoundsOverlapTest@<EAX>(br_bounds *b1@<EAX>, br_bounds *b2@<EDX>)
  1050. // Suffix added to avoid duplicate symbol
  1051. int BoundsOverlapTest__finteray(br_bounds* b1, br_bounds* b2) {
  1052.     LOG_TRACE("(%p, %p)", b1, b2);
  1053.  
  1054.     return b1->min.v[0] <= b2->max.v[0]
  1055.         && b2->min.v[0] <= b1->max.v[0]
  1056.         && b1->min.v[1] <= b2->max.v[1]
  1057.         && b2->min.v[1] <= b1->max.v[1]
  1058.         && b1->min.v[2] <= b2->max.v[2]
  1059.         && b2->min.v[2] <= b1->max.v[2];
  1060. }
  1061.  
  1062. // IDA: int __usercall BoundsTransformTest@<EAX>(br_bounds *b1@<EAX>, br_bounds *b2@<EDX>, br_matrix34 *M@<EBX>)
  1063. int BoundsTransformTest(br_bounds* b1, br_bounds* b2, br_matrix34* M) {
  1064.     br_scalar val;
  1065.     br_vector3 o;
  1066.     LOG_TRACE("(%p, %p, %p)", b1, b2, M);
  1067.  
  1068.     BrVector3Sub(&o, &b1->max, &b1->min);
  1069.     val = M->m[0][0] * b1->min.v[0] + M->m[1][0] * b1->min.v[1] + M->m[2][0] * b1->min.v[2] + M->m[3][0];
  1070.  
  1071.     if ((M->m[0][0] <= 0.0f ? 0.0f : M->m[0][0] * o.v[0])
  1072.             + (M->m[1][0] <= 0.0f ? 0.0f : M->m[1][0] * o.v[1])
  1073.             + (M->m[2][0] <= 0.0f ? 0.0f : M->m[2][0] * o.v[2])
  1074.             + val
  1075.         < b2->min.v[0]) {
  1076.         return 0;
  1077.     }
  1078.     if ((M->m[0][0] < 0.0f ? M->m[0][0] * o.v[0] : 0.0f)
  1079.             + (M->m[1][0] < 0.0f ? M->m[1][0] * o.v[1] : 0.0f)
  1080.             + (M->m[2][0] < 0.0f ? M->m[2][0] * o.v[2] : 0.0f)
  1081.             + val
  1082.         > b2->max.v[0]) {
  1083.         return 0;
  1084.     }
  1085.  
  1086.     val = M->m[0][2] * b1->min.v[0] + M->m[1][2] * b1->min.v[1] + M->m[2][2] * b1->min.v[2] + M->m[3][2];
  1087.     if ((M->m[0][2] <= 0.0f ? 0.0f : M->m[0][2] * o.v[0])
  1088.             + (M->m[1][2] <= 0.0f ? 0.0f : M->m[1][2] * o.v[1])
  1089.             + (M->m[2][2] <= 0.0f ? 0.0f : M->m[2][2] * o.v[2])
  1090.             + val
  1091.         < b2->min.v[2]) {
  1092.         return 0;
  1093.     }
  1094.     if ((M->m[0][2] < 0.0f ? M->m[0][2] * o.v[0] : 0.0f)
  1095.             + (M->m[1][2] < 0.0f ? M->m[1][2] * o.v[1] : 0.0f)
  1096.             + (M->m[2][2] < 0.0f ? M->m[2][2] * o.v[2] : 0.0f)
  1097.             + val
  1098.         > b2->max.v[2]) {
  1099.         return 0;
  1100.     }
  1101.  
  1102.     val = M->m[0][1] * b1->min.v[0] + M->m[1][1] * b1->min.v[1] + M->m[2][1] * b1->min.v[2] + M->m[3][1];
  1103.     if ((M->m[0][1] <= 0.0f ? 0.0f : M->m[0][1] * o.v[0])
  1104.             + (M->m[1][1] <= 0.0f ? 0.0f : M->m[1][1] * o.v[1])
  1105.             + (M->m[2][1] <= 0.0f ? 0.0f : M->m[2][1] * o.v[2])
  1106.             + val
  1107.         < b2->min.v[1]) {
  1108.         return 0;
  1109.     }
  1110.     if ((M->m[0][1] < 0.0 ? M->m[0][1] * o.v[0] : 0.0)
  1111.             + (M->m[1][1] < 0.0 ? M->m[1][1] * o.v[1] : 0.0)
  1112.             + (M->m[2][1] < 0.0 ? M->m[2][1] * o.v[2] : 0.0)
  1113.             + val
  1114.         > b2->max.v[1]) {
  1115.         return 0;
  1116.     }
  1117.  
  1118.     return 1;
  1119. }
  1120.  
  1121. // IDA: int __usercall LineBoxColl@<EAX>(br_vector3 *o@<EAX>, br_vector3 *p@<EDX>, br_bounds *pB@<EBX>, br_vector3 *pHit_point@<ECX>)
  1122. int LineBoxColl(br_vector3* o, br_vector3* p, br_bounds* pB, br_vector3* pHit_point) {
  1123.     br_vector3 dir;
  1124.     int inside;
  1125.     int quad[3];
  1126.     int i;
  1127.     int which_plane;
  1128.     br_scalar max_t[3];
  1129.     br_scalar cp[3];
  1130.     LOG_TRACE("(%p, %p, %p, %p)", o, p, pB, pHit_point);
  1131.  
  1132.     inside = 1;
  1133.     BrVector3Sub(&dir, p, o);
  1134.     for (i = 0; i < 3; ++i) {
  1135.         if (pB->min.v[i] <= o->v[i]) {
  1136.             if (pB->max.v[i] >= o->v[i]) {
  1137.                 quad[i] = 2;
  1138.             } else {
  1139.                 quad[i] = 0;
  1140.                 max_t[i] = pB->max.v[i];
  1141.                 inside = 0;
  1142.             }
  1143.         } else {
  1144.             quad[i] = 1;
  1145.             max_t[i] = pB->min.v[i];
  1146.             inside = 0;
  1147.         }
  1148.     }
  1149.     if (inside) {
  1150.         BrVector3Copy(pHit_point, o);
  1151.         return 8;
  1152.     } else {
  1153.         for (i = 0; i < 3; ++i) {
  1154.             if (quad[i] == 2 || dir.v[i] == 0.0) {
  1155.                 cp[i] = -1.0;
  1156.             } else {
  1157.                 cp[i] = (max_t[i] - o->v[i]) / dir.v[i];
  1158.             }
  1159.         }
  1160.         which_plane = 0;
  1161.         for (i = 1; i < 3; ++i) {
  1162.             if (cp[which_plane] < cp[i]) {
  1163.                 which_plane = i;
  1164.             }
  1165.         }
  1166.         if (cp[which_plane] >= 0.0 && cp[which_plane] <= 1.0) {
  1167.             for (i = 0; i < 3; ++i) {
  1168.                 if (which_plane == i) {
  1169.                     pHit_point->v[i] = max_t[i];
  1170.                 } else {
  1171.                     pHit_point->v[i] = dir.v[i] * cp[which_plane] + o->v[i];
  1172.                     if (pHit_point->v[i] < pB->min.v[i] || pB->max.v[i] < pHit_point->v[i]) {
  1173.                         return 0;
  1174.                     }
  1175.                 }
  1176.             }
  1177.             return which_plane + 4 * quad[which_plane] + 1;
  1178.         } else {
  1179.             return 0;
  1180.         }
  1181.     }
  1182. }
  1183.  
  1184. // IDA: int __usercall SphereBoxIntersection@<EAX>(br_bounds *pB@<EAX>, br_vector3 *pC@<EDX>, br_scalar pR_squared, br_vector3 *pHit_point)
  1185. int SphereBoxIntersection(br_bounds* pB, br_vector3* pC, br_scalar pR_squared, br_vector3* pHit_point) {
  1186.     int i;
  1187.     br_scalar d;
  1188.     LOG_TRACE("(%p, %p, %f, %p)", pB, pC, pR_squared, pHit_point);
  1189.  
  1190.     d = 0.f;
  1191.     for (i = 0; i < 3; i++) {
  1192.         if (pC->v[i] <= pB->min.v[i]) {
  1193.             pHit_point->v[i] = pB->min.v[i];
  1194.         } else if (pC->v[i] > pB->max.v[i]) {
  1195.             pHit_point->v[i] = pB->max.v[i];
  1196.         } else {
  1197.             pHit_point->v[i] = pC->v[i];
  1198.         }
  1199.         d += (pC->v[i] - pHit_point->v[i]) * (pC->v[i] - pHit_point->v[i]);
  1200.     }
  1201.     return d <= pR_squared;
  1202. }
  1203.  
  1204. // IDA: int __usercall LineBoxCollWithSphere@<EAX>(br_vector3 *o@<EAX>, br_vector3 *p@<EDX>, br_bounds *pB@<EBX>, br_vector3 *pHit_point@<ECX>)
  1205. int LineBoxCollWithSphere(br_vector3* o, br_vector3* p, br_bounds* pB, br_vector3* pHit_point) {
  1206.     int i;
  1207.     int plane;
  1208.     LOG_TRACE("(%p, %p, %p, %p)", o, p, pB, pHit_point);
  1209.  
  1210.     plane = LineBoxColl(o, p, pB, pHit_point);
  1211.  
  1212.     if (plane != 0) {
  1213.         return plane;
  1214.     }
  1215.     if (!SphereBoxIntersection(pB, p, 2.5e-5f, pHit_point)) {
  1216.         return 0;
  1217.     }
  1218.     for (i = 0; i < 3; i++) {
  1219.         if (pB->max.v[i] == pHit_point->v[i] && p->v[i] <= o->v[i]) {
  1220.             return i + 1;
  1221.         }
  1222.         if (pHit_point->v[i] == pB->min.v[i] && p->v[i] >= o->v[i]) {
  1223.             return i + 5;
  1224.         }
  1225.     }
  1226.     return 0;
  1227. }
  1228.  
  1229. // IDA: int __usercall CompVert@<EAX>(int v1@<EAX>, int v2@<EDX>)
  1230. int CompVert(int v1, int v2) {
  1231.     br_vertex* vl;
  1232.     br_vector3 tv;
  1233.     br_vector2 tv2;
  1234.     LOG_TRACE("(%d, %d)", v1, v2);
  1235.  
  1236.     if (v1 == v2) {
  1237.         return 1;
  1238.     }
  1239.     vl = gSelected_model->vertices;
  1240.     BrVector3Sub(&tv, &vl[v1].p, &vl[v2].p);
  1241.     if (BrVector3LengthSquared(&tv) > 1e-5f) {
  1242.         return 0;
  1243.     }
  1244.     BrVector2Sub(&tv2, &vl[v1].map, &vl[v2].map);
  1245.     if (BrVector2LengthSquared(&tv2) > 1e-5f) {
  1246.         return 0;
  1247.     }
  1248.     return 1;
  1249. }
  1250.  
  1251. // IDA: void __usercall SetFacesGroup(int pFace@<EAX>)
  1252. void SetFacesGroup(int pFace) {
  1253.     //int f; // Pierre-Marie Baty -- unused variable
  1254.     //int v; // Pierre-Marie Baty -- unused variable
  1255.     //int i; // Pierre-Marie Baty -- unused variable
  1256.     LOG_TRACE("(%d)", pFace);
  1257.     NOT_IMPLEMENTED();
  1258. }
  1259.  
  1260. // IDA: void __usercall SelectFace(br_vector3 *pDir@<EAX>)
  1261. void SelectFace(br_vector3* pDir) {
  1262.     //tCar_spec* c; // Pierre-Marie Baty -- unused variable
  1263.     //br_vector3 dir; // Pierre-Marie Baty -- unused variable
  1264.     //br_vector3 normal; // Pierre-Marie Baty -- unused variable
  1265.     //br_scalar t; // Pierre-Marie Baty -- unused variable
  1266.     //br_model* old_model; // Pierre-Marie Baty -- unused variable
  1267.     //int i; // Pierre-Marie Baty -- unused variable
  1268.     LOG_TRACE("(%p)", pDir);
  1269.     NOT_IMPLEMENTED();
  1270. }
  1271.  
  1272. // IDA: void __usercall GetTilingLimits(br_vector2 *min@<EAX>, br_vector2 *max@<EDX>)
  1273. void GetTilingLimits(br_vector2* min, br_vector2* max) {
  1274.     int f;
  1275.     int i;
  1276.     int j;
  1277.     br_vertex* verts;
  1278.     br_face* faces;
  1279.     LOG_TRACE("(%p, %p)", min, max);
  1280.  
  1281.     verts = gSelected_model->vertices;
  1282.     faces = gSelected_model->faces;
  1283.     BrVector2Set(min, 32000.f, 32000.f);
  1284.     BrVector2Set(max, -32000.f, -32000.f);
  1285.     for (f = 0; f < gSelected_model->nfaces; f++) {
  1286.         if (faces[f].material == gSub_material) {
  1287.             for (i = 0; i < 3; i++) {
  1288.                 for (j = 0; j < 3; j++) {
  1289.                     if (verts[faces[f].vertices[i]].map.v[j] < min->v[j]) {
  1290.                         min->v[j] = verts[faces[f].vertices[i]].map.v[j];
  1291.                     }
  1292.                     if (verts[faces[f].vertices[i]].map.v[j] > max->v[j]) {
  1293.                         max->v[j] = verts[faces[f].vertices[i]].map.v[j];
  1294.                     }
  1295.                 }
  1296.             }
  1297.         }
  1298.     }
  1299. }
  1300.  
  1301. // IDA: void __usercall Scale(int pD@<EAX>, int factor@<EDX>)
  1302. void Scale(int pD, int factor) {
  1303.     br_vector2 min;
  1304.     br_vector2 max;
  1305.     int f;
  1306.     int v;
  1307.     br_scalar d;
  1308.     br_vertex* verts;
  1309.     br_face* faces;
  1310.     LOG_TRACE("(%d, %d)", pD, factor);
  1311.  
  1312.     if (gSelected_model == NULL) {
  1313.         return;
  1314.     }
  1315.     if (gSelected_model->nfaces != gNfaces) {
  1316.         return;
  1317.     }
  1318.     verts = gSelected_model->vertices;
  1319.     faces = gSelected_model->faces;
  1320.     GetTilingLimits(&min, &max);
  1321.     d = max.v[pD] - min.v[pD];
  1322.     if (d <= 0.f || factor + d <= 0.f) {
  1323.         return;
  1324.     }
  1325.     for (v = 0; v < gSelected_model->nvertices; v++) {
  1326.         for (f = 0; f < gSelected_model->nfaces; f++) {
  1327.             if (faces[f].material == gSub_material
  1328.                     && (faces[f].vertices[0] == v || faces[f].vertices[1] == v || faces[f].vertices[2] == v)) {
  1329.                 verts[v].map.v[pD] = (factor + d) / d * verts[v].map.v[pD];
  1330.                 break;
  1331.             }
  1332.         }
  1333.     }
  1334.     BrModelUpdate(gSelected_model, BR_MODU_ALL);
  1335. }
  1336.  
  1337. // IDA: void __cdecl ScaleUpX()
  1338. void ScaleUpX(void) {
  1339.     LOG_TRACE("()");
  1340.  
  1341.     Scale(0, 1);
  1342. }
  1343.  
  1344. // IDA: void __cdecl ScaleDnX()
  1345. void ScaleDnX(void) {
  1346.     LOG_TRACE("()");
  1347.  
  1348.     Scale(0, -1);
  1349. }
  1350.  
  1351. // IDA: void __cdecl ScaleUpY()
  1352. void ScaleUpY(void) {
  1353.     LOG_TRACE("()");
  1354.  
  1355.     Scale(1, 1);
  1356. }
  1357.  
  1358. // IDA: void __cdecl ScaleDnY()
  1359. void ScaleDnY(void) {
  1360.     LOG_TRACE("()");
  1361.  
  1362.     Scale(1, -1);
  1363. }
  1364.  
  1365. // IDA: void __cdecl SelectFaceForward()
  1366. void SelectFaceForward(void) {
  1367.     br_vector3 dir;
  1368.     LOG_TRACE("()");
  1369.  
  1370.     BrVector3Scale(&dir, (br_vector3*)&gProgram_state.current_car.car_master_actor->t.t.mat.m[2], -2.f);
  1371.     SelectFace(&dir);
  1372. }
  1373.  
  1374. // IDA: void __cdecl SelectFaceDown()
  1375. void SelectFaceDown(void) {
  1376.     br_vector3 dir;
  1377.     LOG_TRACE("()");
  1378.  
  1379.     BrVector3Scale(&dir, (br_vector3*)&gProgram_state.current_car.car_master_actor->t.t.look_up.up, -2.f);
  1380.     SelectFace(&dir);
  1381. }
  1382.