Subversion Repositories Games.Carmageddon

Rev

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

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