Subversion Repositories Games.Carmageddon

Rev

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

Rev Author Line No. Line
1 pmbaty 1
#include "skidmark.h"
20 pmbaty 2
#include "brender/brender.h"
1 pmbaty 3
#include "globvars.h"
4
#include "globvrbm.h"
5
#include "harness/trace.h"
6
#include "loading.h"
7
#include "oil.h"
8
#include "piping.h"
9
#include <float.h>
10
#include <math.h>
11
#include <stdlib.h>
12
#include <string.h>
13
 
14
char* gBoring_material_names[2] = { "OILSMEAR.MAT", "ROBSMEAR.MAT" };
15
char* gMaterial_names[2] = { "OILSMEAR.MAT", "GIBSMEAR.MAT" };
16
tSkid gSkids[100];
17
 
18
// IDA: void __usercall StretchMark(tSkid *pMark@<EAX>, br_vector3 *pFrom@<EDX>, br_vector3 *pTo@<EBX>, br_scalar pTexture_start)
19
void StretchMark(tSkid* pMark, br_vector3* pFrom, br_vector3* pTo, br_scalar pTexture_start) {
20
    br_vector3 temp;
21
    br_vector3* rows;
22
    br_scalar len;
23
    br_model* model;
24
    LOG_TRACE("(%p, %p, %p, %f)", pMark, pFrom, pTo, pTexture_start);
25
 
26
    rows = (br_vector3*)&pMark->actor->t.t.mat;
27
    BrVector3Sub(&temp, pTo, pFrom);
28
    len = BrVector3Length(&temp);
29
 
30
    rows[2].v[0] = pMark->normal.v[2] * temp.v[1] - pMark->normal.v[1] * temp.v[2];
31
    rows[2].v[1] = pMark->normal.v[0] * temp.v[2] - pMark->normal.v[2] * temp.v[0];
32
    rows[2].v[2] = pMark->normal.v[1] * temp.v[0] - pMark->normal.v[0] * temp.v[1];
33
 
34
    if (len > BR_SCALAR_EPSILON) {
35
        rows[2].v[0] = 0.05f / len * rows[2].v[0];
36
        rows[2].v[1] = 0.05f / len * rows[2].v[1];
37
        rows[2].v[2] = 0.05f / len * rows[2].v[2];
38
        rows->v[0] = len / len * temp.v[0];
39
        rows->v[1] = len / len * temp.v[1];
40
        rows->v[2] = len / len * temp.v[2];
41
        BrVector3Add(&temp, pTo, pFrom);
42
        BrVector3Scale(&pMark->pos, &temp, 0.5f);
43
        rows[3] = pMark->pos;
44
        model = pMark->actor->model;
45
        model->vertices[1].map.v[0] = pTexture_start / 0.05f;
46
        model->vertices[0].map.v[0] = model->vertices[1].map.v[0];
47
        model->vertices[3].map.v[0] = (pTexture_start + len) / 0.05f;
48
        model->vertices[2].map.v[0] = model->vertices[3].map.v[0];
49
        BrModelUpdate(model, BR_MODU_ALL);
50
    }
51
}
52
 
53
// IDA: br_material* __usercall MaterialFromIndex@<EAX>(int pIndex@<EAX>)
54
br_material* MaterialFromIndex(int pIndex) {
55
    LOG_TRACE("(%d)", pIndex);
56
 
57
    if (pIndex > -2) {
58
        return gCurrent_race.material_modifiers[pIndex].skid_mark_material;
59
    } else {
60
        return gMaterial[-2 - pIndex];
61
    }
62
}
63
 
64
// IDA: void __usercall AdjustSkid(int pSkid_num@<EAX>, br_matrix34 *pMatrix@<EDX>, int pMaterial_index@<EBX>)
65
void AdjustSkid(int pSkid_num, br_matrix34* pMatrix, int pMaterial_index) {
66
    LOG_TRACE("(%d, %p, %d)", pSkid_num, pMatrix, pMaterial_index);
67
 
68
    gSkids[pSkid_num].actor->t.t.mat = *pMatrix;
69
    gSkids[pSkid_num].pos.v[0] = pMatrix->m[3][0];
70
    gSkids[pSkid_num].pos.v[1] = pMatrix->m[3][1];
71
    gSkids[pSkid_num].pos.v[2] = pMatrix->m[3][2];
72
    gSkids[pSkid_num].actor->material = MaterialFromIndex(pMaterial_index);
73
    gSkids[pSkid_num].actor->render_style = BR_RSTYLE_DEFAULT;
74
}
75
 
76
// IDA: int __usercall FarFromLine2D@<EAX>(br_vector3 *pPt@<EAX>, br_vector3 *pL1@<EDX>, br_vector3 *pL2@<EBX>)
77
int FarFromLine2D(br_vector3* pPt, br_vector3* pL1, br_vector3* pL2) {
78
    br_vector2 line;
79
    br_vector2 to_pt;
80
    br_scalar line_len;
81
    br_scalar cross;
82
    LOG_TRACE("(%p, %p, %p)", pPt, pL1, pL2);
83
 
84
    line.v[0] = pL2->v[0] - pL1->v[0];
85
    line.v[1] = pL2->v[2] - pL1->v[2];
86
    to_pt.v[0] = pPt->v[0] - pL2->v[0];
87
    to_pt.v[1] = pPt->v[2] - pL2->v[2];
88
    cross = -line.v[0] * to_pt.v[1] + to_pt.v[0] * line.v[1];
89
    line_len = sqrtf(line.v[0] * line.v[0] + line.v[1] * line.v[1]);
90
    return fabs(cross) > line_len * 0.050000001;
91
}
92
 
93
// IDA: int __usercall Reflex2D@<EAX>(br_vector3 *pPt@<EAX>, br_vector3 *pL1@<EDX>, br_vector3 *pL2@<EBX>)
94
int Reflex2D(br_vector3* pPt, br_vector3* pL1, br_vector3* pL2) {
95
    br_vector2 line;
96
    br_vector2 to_pt;
97
    LOG_TRACE("(%p, %p, %p)", pPt, pL1, pL2);
98
 
99
    line.v[0] = pL2->v[0] - pL1->v[0];
100
    line.v[1] = pL2->v[2] - pL1->v[2];
101
    to_pt.v[0] = pPt->v[0] - pL2->v[0];
102
    to_pt.v[1] = pPt->v[2] - pL2->v[2];
103
    return to_pt.v[1] * line.v[1] + to_pt.v[0] * line.v[0] < 0.0;
104
}
105
 
106
// IDA: void __cdecl InitSkids()
107
void InitSkids(void) {
108
    int skid;
109
    int mat;
110
    int sl;
111
    br_model* square;
112
    char* str;
113
#if defined(DETHRACE_FIX_BUGS)
114
    char mat_name[32];
115
#endif
116
    LOG_TRACE("()");
117
 
118
    for (mat = 0; mat < COUNT_OF(gMaterial_names); mat++) {
119
        if (gProgram_state.sausage_eater_mode) {
120
            str = gBoring_material_names[mat];
121
        } else {
122
            str = gMaterial_names[mat];
123
        }
124
        gMaterial[mat] = BrMaterialFind(str);
125
        if (gMaterial[mat] == NULL) {
126
            if (gProgram_state.sausage_eater_mode) {
127
                str = gBoring_material_names[mat];
128
            } else {
129
                str = gMaterial_names[mat];
130
            }
131
 
132
#if defined(DETHRACE_FIX_BUGS)
133
            // Avoid modification of read-only data by strtok.
134
            strcpy(mat_name, str);
135
            str = mat_name;
136
#endif
137
            sl = strlen(strtok(str, "."));
138
            strcpy(str + sl, ".PIX");
139
            BrMapAdd(LoadPixelmap(str));
140
            strcpy(str + sl, ".MAT");
141
            gMaterial[mat] = LoadMaterial(str);
142
            if (gMaterial[mat]) {
143
                BrMaterialAdd(gMaterial[mat]);
144
            } else {
145
                BrFatal("..\\..\\source\\common\\skidmark.c", 207, "Couldn't find %s", gMaterial_names[mat]);
146
            }
147
        }
148
    }
149
 
150
    for (skid = 0; skid < COUNT_OF(gSkids); skid++) {
151
        gSkids[skid].actor = BrActorAllocate(BR_ACTOR_MODEL, NULL);
152
        BrActorAdd(gNon_track_actor, gSkids[skid].actor);
153
        gSkids[skid].actor->t.t.mat.m[1][1] = 0.01f;
154
        gSkids[skid].actor->render_style = BR_RSTYLE_NONE;
155
        square = BrModelAllocate(NULL, 4, 2);
156
        BrVector3Set(&square->vertices[0].p, -0.5f, 1.0f, -0.5f);
157
        BrVector3Set(&square->vertices[1].p, -0.5f, 1.0f, 0.5f);
158
        BrVector3Set(&square->vertices[2].p, 0.5f, 1.0f, 0.5f);
159
        BrVector3Set(&square->vertices[3].p, 0.5f, 1.0f, -0.5f);
160
        BrVector2Set(&square->vertices[0].map, 0.0f, 0.0f);
161
        BrVector2Set(&square->vertices[1].map, 0.0f, 1.0f);
162
        BrVector2Set(&square->vertices[2].map, 1.0f, 1.0f);
163
        BrVector2Set(&square->vertices[3].map, 1.0f, 0.0f);
164
        square->faces[0].vertices[0] = 0;
165
        square->faces[0].vertices[1] = 1;
166
        square->faces[0].vertices[2] = 2;
167
        square->faces[0].smoothing = 1;
168
        square->faces[1].vertices[0] = 0;
169
        square->faces[1].vertices[1] = 2;
170
        square->faces[1].vertices[2] = 3;
171
        square->faces[1].smoothing = 1;
172
        square->flags |= BR_MODF_KEEP_ORIGINAL;
173
        BrModelAdd(square);
174
        gSkids[skid].actor->model = square;
175
    }
176
}
177
 
178
// IDA: void __usercall HideSkid(int pSkid_num@<EAX>)
179
void HideSkid(int pSkid_num) {
180
    LOG_TRACE("(%d)", pSkid_num);
181
 
182
    gSkids[pSkid_num].actor->render_style = BR_RSTYLE_NONE;
183
}
184
 
185
// IDA: void __cdecl HideSkids()
186
void HideSkids(void) {
187
    int skid;
188
    LOG_TRACE("()");
189
 
190
    for (skid = 0; skid < COUNT_OF(gSkids); skid++) {
191
        HideSkid(skid);
192
    }
193
}
194
 
195
// IDA: br_scalar __usercall SkidLen@<ST0>(int pSkid@<EAX>)
196
br_scalar SkidLen(int pSkid) {
197
    LOG_TRACE("(%d)", pSkid);
198
 
199
    return sqrtf(
200
        gSkids[pSkid].actor->t.t.mat.m[0][2] * gSkids[pSkid].actor->t.t.mat.m[0][2]
201
        + gSkids[pSkid].actor->t.t.mat.m[0][1] * gSkids[pSkid].actor->t.t.mat.m[0][1]
202
        + gSkids[pSkid].actor->t.t.mat.m[0][0] * gSkids[pSkid].actor->t.t.mat.m[0][0]);
203
}
204
 
205
// IDA: void __usercall SkidSection(tCar_spec *pCar@<EAX>, int pWheel_num@<EDX>, br_vector3 *pPos@<EBX>, int pMaterial_index@<ECX>)
206
void SkidSection(tCar_spec* pCar, int pWheel_num, br_vector3* pPos, int pMaterial_index) {
207
    static tU16 skid;
208
    br_material* material;
209
    LOG_TRACE("(%p, %d, %p, %d)", pCar, pWheel_num, pPos, pMaterial_index);
210
 
211
    if (BrVector3Dot(&pCar->prev_nor[pWheel_num], &pCar->nor[pWheel_num]) < 0.99699998
212
        || fabs(BrVector3Dot(&pCar->nor[pWheel_num], pPos) - BrVector3Dot(&pCar->prev_skid_pos[pWheel_num], &pCar->nor[pWheel_num])) > 0.0099999998) {
213
        pCar->old_skidding &= ~(1 << pWheel_num);
214
        pCar->old_skid[pWheel_num] = -1;
215
        return;
216
    }
217
 
218
    material = MaterialFromIndex(pMaterial_index);
219
    if (pCar->old_skid[pWheel_num] >= COUNT_OF(gSkids)
220
        || gSkids[pCar->old_skid[pWheel_num]].actor->material != material
221
        || SkidLen(pCar->old_skid[pWheel_num]) > 0.5
222
        || FarFromLine2D(pPos, &pCar->skid_line_start[pWheel_num], &pCar->skid_line_end[pWheel_num])
223
        || Reflex2D(pPos, &pCar->skid_line_start[pWheel_num], &pCar->prev_skid_pos[pWheel_num])) {
224
 
225
        pCar->skid_line_start[pWheel_num] = pCar->prev_skid_pos[pWheel_num];
226
        pCar->skid_line_end[pWheel_num] = *pPos;
227
        gSkids[skid].actor->render_style = BR_RSTYLE_DEFAULT;
228
        gSkids[skid].actor->material = material;
229
        gSkids[skid].normal = pCar->nor[pWheel_num];
230
        StretchMark(&gSkids[skid], &pCar->prev_skid_pos[pWheel_num], pPos, pCar->total_length[pWheel_num]);
231
        PipeSingleSkidAdjustment(skid, &gSkids[skid].actor->t.t.mat, pMaterial_index);
232
        pCar->old_skid[pWheel_num] = skid;
233
        skid = (skid + 1) % COUNT_OF(gSkids);
234
    } else {
235
        StretchMark(&gSkids[pCar->old_skid[pWheel_num]], &pCar->skid_line_start[pWheel_num], pPos, pCar->total_length[pWheel_num]);
236
        PipeSingleSkidAdjustment(pCar->old_skid[pWheel_num], &gSkids[pCar->old_skid[pWheel_num]].actor->t.t.mat, pMaterial_index);
237
    }
238
}
239
 
240
// IDA: void __usercall SkidMark(tCar_spec *pCar@<EAX>, int pWheel_num@<EDX>)
241
void SkidMark(tCar_spec* pCar, int pWheel_num) {
242
    br_vector3 pos;
243
    br_vector3 world_pos;
244
    br_vector3 disp;
245
    br_vector3 spesh_to_wheel;
246
    int material_index;
247
    br_scalar dist;
248
    br_scalar dist2;
249
    int on_ground;
250
    //br_material* material; // Pierre-Marie Baty -- unused variable
251
    LOG_TRACE("(%p, %d)", pCar, pWheel_num);
252
 
253
    on_ground = pCar->susp_height[pWheel_num >> 1] > pCar->oldd[pWheel_num];
254
    if (!on_ground) {
255
        pCar->special_start[pWheel_num].v[0] = FLT_MAX;
256
    }
257
    if (pCar->blood_remaining[pWheel_num] != 0 && on_ground) {
258
        pCar->new_skidding |= 1 << pWheel_num;
259
        material_index = -3;
260
    } else if (pCar->oil_remaining[pWheel_num] != 0 && on_ground) {
261
        pCar->new_skidding |= 1 << pWheel_num;
262
        material_index = -2;
263
    } else {
264
        material_index = pCar->material_index[pWheel_num];
265
        if (!gCurrent_race.material_modifiers[material_index].skid_mark_material) {
266
            pCar->old_skidding &= ~(1 << pWheel_num);
267
            return;
268
        }
269
    }
270
 
271
    if (((1 << pWheel_num) & pCar->new_skidding) != 0 || ((1 << pWheel_num) & pCar->old_skidding) != 0) {
272
        if ((pWheel_num & 1) != 0) {
273
            pos.v[0] = pCar->bounds[1].max.v[0] - 0.1725f;
274
        } else {
275
            pos.v[0] = pCar->bounds[1].min.v[0] + 0.1725f;
276
        }
277
        pos.v[1] = pCar->wpos[pWheel_num].v[1] - pCar->oldd[pWheel_num];
278
        pos.v[2] = pCar->wpos[pWheel_num].v[2];
279
        BrMatrix34ApplyP(&world_pos, &pos, &pCar->car_master_actor->t.t.mat);
280
        BrVector3InvScale(&world_pos, &world_pos, WORLD_SCALE);
281
        if (pCar->special_start[pWheel_num].v[0] != FLT_MAX) {
282
 
283
            BrVector3Sub(&spesh_to_wheel, &world_pos, &pCar->special_start[pWheel_num]);
284
            dist = BrVector3Length(&spesh_to_wheel);
285
            if (dist <= BR_SCALAR_EPSILON || (BrVector3Dot(&pCar->direction, &spesh_to_wheel) / dist < 0.70700002)) {
286
                return;
287
            }
288
            world_pos = pCar->special_start[pWheel_num];
289
            pCar->special_start[pWheel_num].v[0] = FLT_MAX;
290
        }
291
        if (((1 << pWheel_num) & pCar->new_skidding) != 0) {
292
            if (((1 << pWheel_num) & pCar->old_skidding) != 0) {
293
                BrVector3Sub(&disp, &world_pos, &pCar->prev_skid_pos[pWheel_num]);
294
                dist2 = BrVector3Length(&disp);
295
                if (dist2 < 0.05f) {
296
                    return;
297
                }
298
                SkidSection(pCar, pWheel_num, &world_pos, material_index);
299
                pCar->total_length[pWheel_num] = pCar->total_length[pWheel_num] + dist2;
300
                pCar->oil_remaining[pWheel_num] = pCar->oil_remaining[pWheel_num] - dist2;
301
                if (pCar->oil_remaining[pWheel_num] < 0.0f) {
302
                    pCar->oil_remaining[pWheel_num] = 0.0f;
303
                }
304
                pCar->blood_remaining[pWheel_num] = pCar->blood_remaining[pWheel_num] - dist2;
305
                if (pCar->blood_remaining[pWheel_num] < 0.0f) {
306
                    pCar->blood_remaining[pWheel_num] = 0.0f;
307
                }
308
            } else {
309
                pCar->old_skidding |= 1 << pWheel_num;
310
                pCar->total_length[pWheel_num] = 0.0f;
311
                pCar->old_skid[pWheel_num] = -1;
312
            }
313
        } else {
314
            pCar->old_skidding &= ~(1 << pWheel_num);
315
        }
316
        pCar->prev_skid_pos[pWheel_num] = world_pos;
317
        pCar->prev_nor[pWheel_num] = pCar->nor[pWheel_num];
318
    }
319
}
320
 
321
// IDA: void __usercall InitCarSkidStuff(tCar_spec *pCar@<EAX>)
322
void InitCarSkidStuff(tCar_spec* pCar) {
323
    int wheel;
324
    LOG_TRACE("(%p)", pCar);
325
 
326
    pCar->old_skidding = 0;
327
    for (wheel = 0; wheel < 4; wheel++) {
328
        pCar->special_start[wheel].v[0] = FLT_MAX;
329
        pCar->blood_remaining[wheel] = 0.0f;
330
        pCar->oil_remaining[wheel] = 0.0f;
331
    }
332
}
333
 
334
// IDA: void __cdecl SkidsPerFrame()
335
void SkidsPerFrame(void) {
336
    int skid;
337
    LOG_TRACE("()");
338
 
339
    for (skid = 0; skid < COUNT_OF(gSkids); skid++) {
340
        if (gSkids[skid].actor->render_style != BR_RSTYLE_NONE) {
341
            EnsureGroundDetailVisible(&gSkids[skid].actor->t.t.translate.t, &gSkids[skid].normal, &gSkids[skid].pos);
342
        }
343
    }
344
}
345
 
346
// IDA: void __cdecl RemoveMaterialsFromSkidmarks()
347
void RemoveMaterialsFromSkidmarks(void) {
348
    //int skid; // Pierre-Marie Baty -- unused variable
349
    LOG_TRACE("()");
350
    NOT_IMPLEMENTED();
351
}