Subversion Repositories Games.Carmageddon

Rev

Rev 18 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "brucetrk.h"
  2.  
  3. #include "brender/brender.h"
  4. #include "errors.h"
  5. #include "globvars.h"
  6. #include "globvrbm.h"
  7. #include "harness/trace.h"
  8. #include "init.h"
  9. #include "pd/sys.h"
  10. #include "utility.h"
  11. #include "world.h"
  12. #include <math.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15.  
  16. br_actor* gMr_blendy;
  17. int gDefault_blend_pc;
  18.  
  19. // IDA: void __usercall AllocateActorMatrix(tTrack_spec *pTrack_spec@<EAX>, br_actor ****pDst@<EDX>)
  20. void AllocateActorMatrix(tTrack_spec* pTrack_spec, br_actor**** pDst) {
  21.     tU16 z;
  22.     LOG_TRACE("(%p, %p)", pTrack_spec, pDst);
  23.  
  24.     *pDst = BrMemAllocate(sizeof(br_actor***) * pTrack_spec->ncolumns_z, kMem_columns_z);
  25.     for (z = 0; z < pTrack_spec->ncolumns_z; z++) {
  26.         (*pDst)[z] = BrMemAllocate(sizeof(br_actor**) * pTrack_spec->ncolumns_x, kMem_columns_x);
  27.         memset((*pDst)[z], 0, sizeof(br_actor**) * pTrack_spec->ncolumns_x);
  28.     }
  29. }
  30.  
  31. // IDA: void __usercall DisposeActorMatrix(tTrack_spec *pTrack_spec@<EAX>, br_actor ****pVictim@<EDX>, int pRemove_act_mod@<EBX>)
  32. void DisposeActorMatrix(tTrack_spec* pTrack_spec, br_actor**** pVictim, int pRemove_act_mod) {
  33.     tU16 z;
  34.     tU16 x;
  35.     LOG_TRACE("(%p, %p, %d)", pTrack_spec, pVictim, pRemove_act_mod);
  36.  
  37.     if (*pVictim != NULL) {
  38.         for (z = 0; z != pTrack_spec->ncolumns_z; z++) {
  39.             if (pRemove_act_mod != 0) {
  40.                 for (x = 0; x != pTrack_spec->ncolumns_x; x++) {
  41.                     if ((*pVictim)[z][x] != NULL && (*pVictim)[z][x]->model != NULL) {
  42.                         BrModelRemove((*pVictim)[z][x]->model);
  43.                         BrModelFree((*pVictim)[z][x]->model);
  44.                     }
  45.                 }
  46.             }
  47.             BrMemFree((*pVictim)[z]);
  48.         }
  49.         BrMemFree(*pVictim);
  50.     }
  51. }
  52.  
  53. // IDA: void __usercall DisposeColumns(tTrack_spec *pTrack_spec@<EAX>)
  54. void DisposeColumns(tTrack_spec* pTrack_spec) {
  55.     LOG_TRACE("(%p)", pTrack_spec);
  56.  
  57.     DisposeActorMatrix(pTrack_spec, &pTrack_spec->columns, 0);
  58.     DisposeActorMatrix(pTrack_spec, &pTrack_spec->lollipops, 0);
  59.     if (gAusterity_mode == 0) {
  60.         DisposeActorMatrix(pTrack_spec, &pTrack_spec->blends, 1);
  61.     }
  62.     if (pTrack_spec->non_car_list != NULL && (0 < pTrack_spec->ampersand_digits)) {
  63.         BrMemFree(pTrack_spec->non_car_list);
  64.     }
  65. }
  66.  
  67. // IDA: void __usercall XZToColumnXZ(tU8 *pColumn_x@<EAX>, tU8 *pColumn_z@<EDX>, br_scalar pX, br_scalar pZ, tTrack_spec *pTrack_spec)
  68. void XZToColumnXZ(tU8* pColumn_x, tU8* pColumn_z, br_scalar pX, br_scalar pZ, tTrack_spec* pTrack_spec) {
  69.     br_scalar x;
  70.     br_scalar z;
  71.     LOG_TRACE("(%p, %p, %f, %f, %p)", pColumn_x, pColumn_z, pX, pZ, pTrack_spec);
  72.  
  73.     x = (pX - pTrack_spec->origin_x) / pTrack_spec->column_size_x;
  74.     z = (pZ - pTrack_spec->origin_z) / pTrack_spec->column_size_z;
  75.     if (x < 0.0f) {
  76.         x = 0.0f;
  77.     }
  78.     if (x >= pTrack_spec->ncolumns_x) {
  79.         x = pTrack_spec->ncolumns_x - 1.0f;
  80.     }
  81.     if (z < 0.0f) {
  82.         z = 0.0f;
  83.     }
  84.     if (z >= pTrack_spec->ncolumns_z) {
  85.         z = pTrack_spec->ncolumns_z - 1.0f;
  86.     }
  87.     *pColumn_x = (tU8) x; // Pierre-Marie Baty -- added type cast
  88.     *pColumn_z = (tU8) z; // Pierre-Marie Baty -- added type cast
  89. }
  90.  
  91. // IDA: void __usercall StripBlendedFaces(br_actor *pActor@<EAX>, br_model *pModel@<EDX>)
  92. void StripBlendedFaces(br_actor* pActor, br_model* pModel) {
  93.     int i;
  94.     br_face* face;
  95.     int changed_one;
  96.     //char s[256]; // Pierre-Marie Baty -- unused variable
  97.     static tU16 nfaces_allocated;
  98.     LOG_TRACE("(%p, %p)", pActor, pModel);
  99.  
  100.     changed_one = 0;
  101.  
  102.     for (i = 0; i < pModel->nfaces; i++) {
  103.         face = &pModel->faces[i];
  104.         if (face->material != NULL && face->material->identifier != NULL && ((face->material->identifier[0] == '!' && face->material->identifier[1] != '!' && gDefault_blend_pc != 0) || face->material->identifier[1] == '\\')) {
  105.             if (gMr_blendy == NULL) {
  106.                 gMr_blendy = BrActorAllocate(BR_ACTOR_MODEL, NULL);
  107.                 gMr_blendy->render_style = BR_RSTYLE_NONE;
  108.                 gMr_blendy->model = BrModelAllocate(NULL, pModel->nvertices, pModel->nfaces);
  109.                 nfaces_allocated = pModel->nfaces;
  110.                 gMr_blendy->model->nfaces = 0;
  111.                 gMr_blendy->model->flags |= BR_MODF_UPDATEABLE;
  112.                 memcpy(gMr_blendy->model->vertices, pModel->vertices, pModel->nvertices * sizeof(br_vertex));
  113.             }
  114.             if (!AlreadyBlended(face->material)) {
  115.                 if (face->material->identifier[1] == '\\') {
  116.                     if (face->material->identifier[2] == '2') {
  117.                         BlendifyMaterial(face->material, 25);
  118.                     } else if (face->material->identifier[2] == '7') {
  119.                         BlendifyMaterial(face->material, 75);
  120.                     } else {
  121.                         BlendifyMaterial(face->material, 50);
  122.                     }
  123.                 } else {
  124.                     BlendifyMaterial(face->material, gDefault_blend_pc);
  125.                 }
  126.                 BrMaterialUpdate(face->material, BR_MATU_ALL);
  127.             }
  128.             if (nfaces_allocated <= gMr_blendy->model->nfaces) {
  129.                 PDFatalError("Perfectly understandable error by Batwick, thank you very much Bruce.");
  130.             }
  131.             memcpy(&gMr_blendy->model->faces[gMr_blendy->model->nfaces], face, sizeof(br_face));
  132.             gMr_blendy->model->nfaces++;
  133.             if (i < (pModel->nfaces - 1)) {
  134.                 memmove(&pModel->faces[i], &pModel->faces[i + 1], (pModel->nfaces - i - 1) * sizeof(br_face));
  135.             }
  136.             pModel->nfaces--;
  137.             changed_one = 1;
  138.             i--;
  139.         }
  140.     }
  141.     if (changed_one) {
  142.         if (pModel->nfaces != 0) {
  143.             BrModelUpdate(pModel, BR_MODU_ALL);
  144.         } else {
  145.             pActor->model = NULL;
  146.             pActor->type = BR_ACTOR_NONE;
  147.         }
  148.     }
  149. }
  150.  
  151. // IDA: br_uint_32 __cdecl FindNonCarsCB(br_actor *pActor, tTrack_spec *pTrack_spec)
  152. intptr_t FindNonCarsCB(br_actor* pActor, tTrack_spec* pTrack_spec) {
  153.     int i;
  154.     br_scalar r1;
  155.     br_scalar r2;
  156.     br_scalar r3;
  157.     LOG_TRACE("(%p, %p)", pActor, pTrack_spec);
  158.  
  159.     if (pActor->identifier != NULL && pActor->identifier[0] == '&' && pActor->identifier[1] >= '0' && pActor->identifier[1] <= '9') {
  160.         i = (pActor->identifier[4] - '0') * 1000 + (pActor->identifier[5] - '0') * 100 + (pActor->identifier[6] - '0') * 10 + (pActor->identifier[7] - '0');
  161.         if (i < 0 || pTrack_spec->ampersand_digits <= i) {
  162.             return 1;
  163.         }
  164.         r1 = BR_SQR3(pActor->t.t.mat.m[0][0], pActor->t.t.mat.m[0][1], pActor->t.t.mat.m[0][2]);
  165.         r2 = BR_SQR3(pActor->t.t.mat.m[1][0], pActor->t.t.mat.m[1][1], pActor->t.t.mat.m[1][2]);
  166.         r3 = BR_SQR3(pActor->t.t.mat.m[2][0], pActor->t.t.mat.m[2][1], pActor->t.t.mat.m[2][2]);
  167.         if (r1 < .999f || r2 < .999f || r3 < .999f) {
  168.             dr_dprintf("non car was scaled down %s", pActor->identifier);
  169.             pActor->t.t.translate.t.v[0] += 2000.f;
  170.         }
  171.         if (r1 > 1.001f || r2 > 1.001f || r3 > 1.001f) {
  172.             r1 = 1.f / sqrtf(r1);
  173.             r2 = 1.f / sqrtf(r2);
  174.             r3 = 1.f / sqrtf(r3);
  175.             pActor->t.t.mat.m[0][0] *= r1;
  176.             pActor->t.t.mat.m[0][1] *= r1;
  177.             pActor->t.t.mat.m[0][2] *= r1;
  178.             pActor->t.t.mat.m[1][0] *= r2;
  179.             pActor->t.t.mat.m[1][1] *= r2;
  180.             pActor->t.t.mat.m[1][2] *= r2;
  181.             pActor->t.t.mat.m[2][0] *= r3;
  182.             pActor->t.t.mat.m[2][1] *= r3;
  183.             pActor->t.t.mat.m[2][2] *= r3;
  184.             dr_dprintf("non car was scaled up %s", pActor->identifier);
  185.         }
  186.         pTrack_spec->non_car_list[i] = pActor;
  187.         pActor->type_data = NULL;
  188.         return 0;
  189.     } else {
  190.         if (pActor->model != NULL && !gAusterity_mode && pActor->identifier != NULL && pActor->identifier[0] != '&') {
  191.             StripBlendedFaces(pActor, pActor->model);
  192.         }
  193.         return BrActorEnum(pActor, (br_actor_enum_cbfn*)FindNonCarsCB, pTrack_spec);
  194.     }
  195. }
  196.  
  197. // IDA: br_uint_32 __cdecl ProcessModelsCB(br_actor *pActor, tTrack_spec *pTrack_spec)
  198. intptr_t ProcessModelsCB(br_actor* pActor, tTrack_spec* pTrack_spec) {
  199.     unsigned int x;
  200.     unsigned int z;
  201.     int group;
  202.     LOG_TRACE("(%p, %p)", pActor, pTrack_spec);
  203.  
  204.     if (sscanf(pActor->identifier, "%u%u", &x, &z) == 2 && pTrack_spec->ncolumns_x > x && pTrack_spec->ncolumns_z > z) {
  205.         pActor->material = gDefault_track_material;
  206.         pTrack_spec->columns[z][x] = pActor;
  207.         gMr_blendy = NULL;
  208.         if (pActor->model && !gAusterity_mode) {
  209.             StripBlendedFaces(pActor, pActor->model);
  210.         }
  211.         BrActorEnum(pActor, (br_actor_enum_cbfn*)FindNonCarsCB, pTrack_spec);
  212.         if (gMr_blendy) {
  213.             BrActorAdd(pActor, gMr_blendy);
  214.             BrModelAdd(gMr_blendy->model);
  215.             for (group = 0; V11MODEL(gMr_blendy->model)->ngroups > group; ++group) {
  216.                 V11MODEL(gMr_blendy->model)->groups[group].face_colours_material = gMr_blendy->model->faces[*V11MODEL(gMr_blendy->model)->groups[group].face_user].material;
  217.             }
  218.             gMr_blendy->model->flags &= ~BR_MODF_UPDATEABLE;
  219.             DodgyModelUpdate(gMr_blendy->model);
  220.             pTrack_spec->blends[z][x] = gMr_blendy;
  221.         }
  222.     } else if (*pActor->identifier == '%' && sscanf((const char*)pActor->identifier + 1, "%u%u", &x, &z) == 2 && pTrack_spec->ncolumns_x > x && pTrack_spec->ncolumns_z > z) {
  223.         pTrack_spec->lollipops[z][x] = pActor;
  224.     } else {
  225.         BrActorEnum(pActor, (br_actor_enum_cbfn*)ProcessModelsCB, pTrack_spec);
  226.     }
  227.     return 0;
  228. }
  229.  
  230. // IDA: void __usercall ProcessModels(tTrack_spec *pTrack_spec@<EAX>)
  231. void ProcessModels(tTrack_spec* pTrack_spec) {
  232.     LOG_TRACE("(%p)", pTrack_spec);
  233.  
  234.     BrActorEnum(pTrack_spec->the_actor, (br_actor_enum_cbfn*)ProcessModelsCB, pTrack_spec);
  235. }
  236.  
  237. // IDA: void __usercall ExtractColumns(tTrack_spec *pTrack_spec@<EAX>)
  238. void ExtractColumns(tTrack_spec* pTrack_spec) {
  239.     unsigned int x;
  240.     unsigned int z;
  241.     int ad;
  242.     int unsplit;
  243.     //float e; // Pierre-Marie Baty -- unused variable
  244.     br_scalar extra_room;
  245.     br_bounds bounds;
  246.     LOG_TRACE("(%p)", pTrack_spec);
  247.  
  248.     unsplit = 0;
  249.     switch (sscanf(pTrack_spec->the_actor->identifier, "%u%u%f%d", &x, &z, &extra_room, &ad)) {
  250.     case 3:
  251.         BrFailure(
  252.             "Attempt to extract columns from invalid track\n"
  253.             "(It might have been produced by an ancient preproc.\n"
  254.             "This is no longer supported.\n");
  255.         break;
  256.  
  257.     case 4:
  258.         pTrack_spec->ampersand_digits = ad;
  259.         break;
  260.  
  261.     default:
  262.         unsplit = 1;
  263.         x = 1;
  264.         z = 1;
  265.         extra_room = 0.0;
  266.         pTrack_spec->ampersand_digits = 0;
  267.     }
  268.     pTrack_spec->ncolumns_x = x;
  269.     pTrack_spec->ncolumns_z = z;
  270.  
  271.     BrActorToBounds(&bounds, pTrack_spec->the_actor);
  272.     pTrack_spec->column_size_x = (br_scalar) (bounds.max.v[0] - bounds.min.v[0] + extra_room * (br_scalar) 2.0) / (double)pTrack_spec->ncolumns_x; // Pierre-Marie Baty -- added type casts
  273.     pTrack_spec->column_size_z = (br_scalar) (bounds.max.v[2] - bounds.min.v[2] + extra_room * (br_scalar) 2.0) / (double)pTrack_spec->ncolumns_z; // Pierre-Marie Baty -- added type casts
  274.     pTrack_spec->origin_x = bounds.min.v[0] - extra_room;
  275.     pTrack_spec->origin_z = bounds.min.v[2] - extra_room;
  276.     AllocateActorMatrix(pTrack_spec, &pTrack_spec->columns);
  277.     AllocateActorMatrix(pTrack_spec, &pTrack_spec->lollipops);
  278.     AllocateActorMatrix(pTrack_spec, &pTrack_spec->blends);
  279.     if (pTrack_spec->ampersand_digits <= 0) {
  280.         pTrack_spec->non_car_list = NULL;
  281.     } else {
  282.         pTrack_spec->non_car_list = BrMemAllocate(sizeof(br_actor*) * pTrack_spec->ampersand_digits, kMem_non_car_list);
  283.     }
  284.     if (unsplit) {
  285.         **pTrack_spec->columns = pTrack_spec->the_actor;
  286.     } else {
  287.         ProcessModels(pTrack_spec);
  288.     }
  289. }
  290.  
  291. // IDA: void __usercall LollipopizeActor4(br_actor *pActor@<EAX>, br_matrix34 *pRef_to_world@<EDX>, br_actor *pCamera@<EBX>)
  292. void LollipopizeActor4(br_actor* pActor, br_matrix34* pRef_to_world, br_actor* pCamera) {
  293.     LOG_TRACE("(%p, %p, %p)", pActor, pRef_to_world, pCamera);
  294.  
  295.     pActor->t.t.mat.m[1][0] = 0.0;
  296.     pActor->t.t.mat.m[1][1] = 1.0;
  297.     pActor->t.t.mat.m[1][2] = 0.0;
  298.     pActor->t.t.mat.m[2][0] = pRef_to_world->m[2][0];
  299.     pActor->t.t.mat.m[2][1] = pRef_to_world->m[2][1];
  300.     pActor->t.t.mat.m[2][2] = pRef_to_world->m[2][2];
  301.     pActor->t.t.mat.m[0][0] = pActor->t.t.mat.m[1][1] * pActor->t.t.mat.m[2][2]
  302.         - pActor->t.t.mat.m[1][2] * pActor->t.t.mat.m[2][1];
  303.     pActor->t.t.mat.m[0][1] = pActor->t.t.mat.m[1][2] * pActor->t.t.mat.m[2][0]
  304.         - pActor->t.t.mat.m[1][0] * pActor->t.t.mat.m[2][2];
  305.     pActor->t.t.mat.m[0][2] = pActor->t.t.mat.m[2][1] * pActor->t.t.mat.m[1][0]
  306.         - pActor->t.t.mat.m[1][1] * pActor->t.t.mat.m[2][0];
  307. }
  308.  
  309. // IDA: br_uint_32 __cdecl LollipopizeChildren(br_actor *pActor, void *pArg)
  310. intptr_t LollipopizeChildren(br_actor* pActor, void* pArg) {
  311.     tMatrix_and_actor* maa;
  312.     LOG_TRACE("(%p, %p)", pActor, pArg);
  313.  
  314.     maa = pArg;
  315.     LollipopizeActor4(pActor, maa->m, maa->a);
  316.     return 0;
  317. }
  318.  
  319. // IDA: void __usercall DrawColumns(int pDraw_blends@<EAX>, tTrack_spec *pTrack_spec@<EDX>, int pMin_x@<EBX>, int pMax_x@<ECX>, int pMin_z, int pMax_z, br_matrix34 *pCamera_to_world)
  320. void DrawColumns(int pDraw_blends, tTrack_spec* pTrack_spec, int pMin_x, int pMax_x, int pMin_z, int pMax_z, br_matrix34* pCamera_to_world) {
  321.     tU8 column_x;
  322.     tU8 column_z;
  323.     tU8 column_x2;
  324.     tU8 column_z2;
  325.     tMatrix_and_actor maa;
  326.     br_actor* blended_polys;
  327.     LOG_TRACE("(%d, %p, %d, %d, %d, %d, %p)", pDraw_blends, pTrack_spec, pMin_x, pMax_x, pMin_z, pMax_z, pCamera_to_world);
  328.  
  329.     maa.m = pCamera_to_world;
  330.     if (fabs(pCamera_to_world->m[2][2]) >= fabs(pCamera_to_world->m[2][0])) {
  331.         for (column_z = pMin_z; column_z <= pMax_z; ++column_z) {
  332.             for (column_x = pMin_x; column_x <= pMax_x; ++column_x) {
  333.                 if (pCamera_to_world->m[2][0] <= 0.0) {
  334.                     column_x2 = pMin_x + pMax_x - column_x;
  335.                 } else {
  336.                     column_x2 = column_x;
  337.                 }
  338.                 if (pCamera_to_world->m[2][2] <= 0.0) {
  339.                     column_z2 = pMax_z + pMin_z - column_z;
  340.                 } else {
  341.                     column_z2 = column_z;
  342.                 }
  343.                 if (pDraw_blends) {
  344.                     blended_polys = pTrack_spec->blends[column_z2][column_x2];
  345.                     if (blended_polys) {
  346.                         blended_polys->render_style = BR_RSTYLE_FACES;
  347.                         BrZbSceneRenderAdd(blended_polys);
  348.                         blended_polys->render_style = BR_RSTYLE_NONE;
  349.                     }
  350.                 } else {
  351.                     if (pTrack_spec->columns[column_z2][column_x2]) {
  352.                         BrZbSceneRenderAdd(pTrack_spec->columns[column_z2][column_x2]);
  353.                     }
  354.                     if (pTrack_spec->lollipops[column_z2][column_x2]) {
  355.                         maa.a = pTrack_spec->lollipops[column_z2][column_x2];
  356.                         BrActorEnum(pTrack_spec->lollipops[column_z2][column_x2], LollipopizeChildren, &maa);
  357.                         BrZbSceneRenderAdd(pTrack_spec->lollipops[column_z2][column_x2]);
  358.                     }
  359.                 }
  360.             }
  361.         }
  362.     } else {
  363.         for (column_x = pMin_x; column_x <= pMax_x; ++column_x) {
  364.             for (column_z = pMin_z; column_z <= pMax_z; ++column_z) {
  365.                 if (pCamera_to_world->m[2][0] <= 0.0) {
  366.                     column_x2 = pMin_x + pMax_x - column_x;
  367.                 } else {
  368.                     column_x2 = column_x;
  369.                 }
  370.                 if (pCamera_to_world->m[2][2] <= 0.0) {
  371.                     column_z2 = pMax_z + pMin_z - column_z;
  372.                 } else {
  373.                     column_z2 = column_z;
  374.                 }
  375.                 if (pDraw_blends) {
  376.                     blended_polys = pTrack_spec->blends[column_z2][column_x2];
  377.                     if (blended_polys) {
  378.                         blended_polys->render_style = 4;
  379.                         BrZbSceneRenderAdd(blended_polys);
  380.                         blended_polys->render_style = 1;
  381.                     }
  382.                 } else {
  383.                     if (pTrack_spec->columns[column_z2][column_x2]) {
  384.                         BrZbSceneRenderAdd(pTrack_spec->columns[column_z2][column_x2]);
  385.                     }
  386.                     if (pTrack_spec->lollipops[column_z2][column_x2]) {
  387.                         maa.a = pTrack_spec->lollipops[column_z2][column_x2];
  388.                         BrActorEnum(pTrack_spec->lollipops[column_z2][column_x2], LollipopizeChildren, &maa);
  389.                         BrZbSceneRenderAdd(pTrack_spec->lollipops[column_z2][column_x2]);
  390.                     }
  391.                 }
  392.             }
  393.         }
  394.     }
  395. }
  396.  
  397. // IDA: void __usercall RenderTrack(br_actor *pWorld@<EAX>, tTrack_spec *pTrack_spec@<EDX>, br_actor *pCamera@<EBX>, br_matrix34 *pCamera_to_world@<ECX>, int pRender_blends)
  398. void RenderTrack(br_actor* pWorld, tTrack_spec* pTrack_spec, br_actor* pCamera, br_matrix34* pCamera_to_world, int pRender_blends) {
  399.     static tU8 column_x;
  400.     static tU8 column_z;
  401.     static tU8 min_x;
  402.     static tU8 max_x;
  403.     static tU8 min_z;
  404.     static tU8 max_z;
  405.     static br_vector3 edge_before;
  406.     static br_vector3 edge_after;
  407.     static br_camera* camera;
  408.     static br_scalar tan_fov_ish;
  409.     static br_actor* result;
  410.     LOG_TRACE("(%p, %p, %p, %p, %d)", pWorld, pTrack_spec, pCamera, pCamera_to_world, pRender_blends);
  411.  
  412.     if (pTrack_spec->columns != NULL) {
  413.         if (pRender_blends) {
  414.             DrawColumns(1, pTrack_spec, min_x, max_x, min_z, max_z, pCamera_to_world);
  415.         } else {
  416.             camera = (br_camera*)pCamera->type_data;
  417.             XZToColumnXZ(&column_x, &column_z, pCamera_to_world->m[3][0], pCamera_to_world->m[3][2], pTrack_spec);
  418.             min_x = column_x;
  419.             max_x = column_x;
  420.             min_z = column_z;
  421.             max_z = column_z;
  422.             tan_fov_ish = sinf(BrAngleToRadian(camera->field_of_view / 2)) / cosf(BrAngleToRadian(camera->field_of_view / 2));
  423.             edge_after.v[0] = camera->aspect * tan_fov_ish;
  424.             edge_after.v[1] = tan_fov_ish;
  425.             edge_after.v[2] = -1.0;
  426.             edge_before.v[0] = camera->yon_z * gYon_factor * edge_after.v[0];
  427.             edge_before.v[1] = camera->yon_z * gYon_factor * tan_fov_ish;
  428.             edge_before.v[2] = camera->yon_z * gYon_factor * (br_scalar) -1.0; // Pierre-Marie Baty -- added type cast
  429.             BrMatrix34ApplyV(&edge_after, &edge_before, pCamera_to_world);
  430.             XZToColumnXZ(&column_x, &column_z, pCamera_to_world->m[3][0] + edge_after.v[0], pCamera_to_world->m[3][2] + edge_after.v[2], pTrack_spec);
  431.             if (column_x < min_x) {
  432.                 min_x = column_x;
  433.             } else if (column_x > max_x) {
  434.                 max_x = column_x;
  435.             }
  436.             if (column_z < min_z) {
  437.                 min_z = column_z;
  438.             } else if (column_z > max_z) {
  439.                 max_z = column_z;
  440.             }
  441.             edge_before.v[0] = -edge_before.v[0];
  442.             BrMatrix34ApplyV(&edge_after, &edge_before, pCamera_to_world);
  443.             XZToColumnXZ(&column_x, &column_z, pCamera_to_world->m[3][0] + edge_after.v[0], pCamera_to_world->m[3][2] + edge_after.v[2], pTrack_spec);
  444.             if (column_x < min_x) {
  445.                 min_x = column_x;
  446.             } else if (column_x > max_x) {
  447.                 max_x = column_x;
  448.             }
  449.             if (column_z >= min_z) {
  450.                 if (column_z > max_z) {
  451.                     max_z = column_z;
  452.                 }
  453.             } else {
  454.                 min_z = column_z;
  455.             }
  456.             edge_before.v[1] = -edge_before.v[1];
  457.             BrMatrix34ApplyV(&edge_after, &edge_before, pCamera_to_world);
  458.             XZToColumnXZ(&column_x, &column_z, pCamera_to_world->m[3][0] + edge_after.v[0], pCamera_to_world->m[3][2] + edge_after.v[2], pTrack_spec);
  459.             if (column_x < min_x) {
  460.                 min_x = column_x;
  461.             } else if (column_x > max_x) {
  462.                 max_x = column_x;
  463.             }
  464.             if (column_z < min_z) {
  465.                 min_z = column_z;
  466.             } else if (column_z > max_z) {
  467.                 max_z = column_z;
  468.             }
  469.             edge_before.v[0] = -edge_before.v[0];
  470.             BrMatrix34ApplyV(&edge_after, &edge_before, pCamera_to_world);
  471.             XZToColumnXZ(&column_x, &column_z, pCamera_to_world->m[3][0] + edge_after.v[0], pCamera_to_world->m[3][2] + edge_after.v[2], pTrack_spec);
  472.             if (column_x < min_x) {
  473.                 min_x = column_x;
  474.             } else if (column_x > max_x) {
  475.                 max_x = column_x;
  476.             }
  477.             if (column_z < min_z) {
  478.                 min_z = column_z;
  479.             } else if (column_z > max_z) {
  480.                 max_z = column_z;
  481.             }
  482.             if (min_x != 0) {
  483.                 min_x--;
  484.             }
  485.             if (pTrack_spec->ncolumns_x - 1 > max_x) {
  486.                 max_x++;
  487.             }
  488.             if (min_z != 0) {
  489.                 min_z--;
  490.             }
  491.             if (pTrack_spec->ncolumns_z - 1 > max_z) {
  492.                 max_z++;
  493.             }
  494.             DrawColumns(0, pTrack_spec, min_x, max_x, min_z, max_z, pCamera_to_world);
  495.         }
  496.     } else {
  497.         BrZbSceneRenderAdd(pWorld);
  498.     }
  499. }
  500.  
  501. // IDA: br_scalar __cdecl GetYonFactor()
  502. br_scalar GetYonFactor(void) {
  503.  
  504.     return gYon_factor;
  505. }
  506.  
  507. // IDA: void __cdecl SetYonFactor(br_scalar pNew)
  508. void SetYonFactor(br_scalar pNew) {
  509.  
  510.     gYon_factor = pNew;
  511. }
  512.