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