Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * Portions of this file are copyright Rebirth contributors and licensed as
3
 * described in COPYING.txt.
4
 * Portions of this file are copyright Parallax Software and licensed
5
 * according to the Parallax license below.
6
 * See COPYING.txt for license details.
7
 
8
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
9
SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
10
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
11
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
12
IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
13
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
14
FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
15
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
16
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
17
COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
18
*/
19
 
20
/*
21
 *
22
 * curve generation stuff
23
 *
24
 */
25
 
26
#include <time.h>
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <ctype.h>
31
#include <stdarg.h>
32
#include "inferno.h"
33
#include "vecmat.h"
34
#include "gr.h"
35
#include "key.h"
36
#include "editor.h"
37
#include "editor/esegment.h"
38
#include "gameseg.h"
39
#include "console.h"
40
#define ONE_OVER_SQRT2 F1_0 * 0.707106781
41
#define CURVE_RIGHT 1
42
#define CURVE_UP 2
43
 
44
#include "compiler-range_for.h"
45
#include "partial_range.h"
46
 
47
static imsegptridx_t OriginalSeg = segment_none;
48
static imsegptridx_t OriginalMarkedSeg = segment_none;
49
static int OriginalSide;
50
static int OriginalMarkedSide;
51
static std::array<segment *, MAX_SEGMENTS> CurveSegs;
52
static unsigned CurveNumSegs;
53
 
54
static void generate_banked_curve(fix maxscale, vms_equation coeffs);
55
 
56
static void create_curve(vms_vector &p1, vms_vector &p4, vms_vector &r1, vms_vector &r4, vms_equation &coeffs)
57
{
58
// Q(t) = (2t^3 - 3t^2 + 1) p1 + (-2t^3 + 3t^2) p4 + (t~3 - 2t^2 + t) r1 + (t^3 - t^2 ) r4
59
 
60
    coeffs.n.x3 = fixmul(2*F1_0,p1.x) - fixmul(2*F1_0,p4.x) + r1.x + r4.x;
61
    coeffs.n.x2 = fixmul(-3*F1_0,p1.x) + fixmul(3*F1_0,p4.x) - fixmul(2*F1_0,r1.x) - fixmul(1*F1_0,r4.x);
62
    coeffs.n.x1 = r1.x;
63
    coeffs.n.x0 = p1.x;
64
    coeffs.n.y3 = fixmul(2*F1_0,p1.y) - fixmul(2*F1_0,p4.y) + r1.y + r4.y;
65
    coeffs.n.y2 = fixmul(-3*F1_0,p1.y) + fixmul(3*F1_0,p4.y) - fixmul(2*F1_0,r1.y) - fixmul(1*F1_0,r4.y);
66
    coeffs.n.y1 = r1.y;
67
    coeffs.n.y0 = p1.y;
68
    coeffs.n.z3 = fixmul(2*F1_0,p1.z) - fixmul(2*F1_0,p4.z) + r1.z + r4.z;
69
    coeffs.n.z2 = fixmul(-3*F1_0,p1.z) + fixmul(3*F1_0,p4.z) - fixmul(2*F1_0,r1.z) - fixmul(1*F1_0,r4.z);
70
    coeffs.n.z1 = r1.z;
71
    coeffs.n.z0 = p1.z;
72
 
73
}
74
 
75
vms_vector evaluate_curve(vms_equation *coeffs, int degree, fix t) {
76
    fix t2, t3;
77
    vms_vector coord;
78
 
79
    if (degree != 3)
80
                con_puts(CON_CRITICAL," for Hermite Curves degree must be 3");
81
 
82
    t2 = fixmul(t,t); t3 = fixmul(t2,t);
83
 
84
    coord.x = fixmul(coeffs->n.x3,t3) + fixmul(coeffs->n.x2,t2) + fixmul(coeffs->n.x1,t) + coeffs->n.x0;
85
    coord.y = fixmul(coeffs->n.y3,t3) + fixmul(coeffs->n.y2,t2) + fixmul(coeffs->n.y1,t) + coeffs->n.y0;
86
    coord.z = fixmul(coeffs->n.z3,t3) + fixmul(coeffs->n.z2,t2) + fixmul(coeffs->n.z1,t) + coeffs->n.z0;
87
 
88
    return coord;
89
}
90
 
91
 
92
fix curve_dist(vms_equation *coeffs, int degree, fix t0, const vms_vector &p0, fix dist)
93
{
94
         vms_vector coord;
95
    fix t, diff;
96
 
97
    if (degree != 3)
98
                con_puts(CON_CRITICAL," for Hermite Curves degree must be 3");
99
 
100
    for (t=t0;t<1*F1_0;t+=0.001*F1_0) {
101
        coord = evaluate_curve(coeffs, 3, t);
102
        diff = dist - vm_vec_dist(coord, p0);
103
        if (diff<ACCURACY)   //&&(diff>-ACCURACY))
104
            return t;
105
    }
106
    return -1*F1_0;
107
 
108
}
109
 
110
void plot_parametric(vms_equation *coeffs, fix min_t, fix max_t, fix del_t) {
111
    vms_vector coord, dcoord;
112
    fix t, dt;
113
 
114
        const uint8_t color = 15;
115
        gr_box(*grd_curcanv, 75,  40, 325, 290, color);
116
        gr_box(*grd_curcanv, 75, 310, 325, 560, color);
117
        gr_box(*grd_curcanv,475, 310, 725, 560, color);
118
    //gr_pal_fade_in( grd_curscreen->pal );
119
 
120
    for (t=min_t;t<max_t-del_t;t+=del_t) {
121
        dt = t+del_t;
122
 
123
        coord = evaluate_curve(coeffs, 3, t);
124
        dcoord = evaluate_curve(coeffs, 3, dt);
125
 
126
                gr_line (*grd_curcanv,  75*F1_0 + coord.x, 290*F1_0 - coord.z,  75*F1_0 + dcoord.x, 290*F1_0 - dcoord.z, 9);
127
                gr_line (*grd_curcanv,  75*F1_0 + coord.x, 560*F1_0 - coord.y,  75*F1_0 + dcoord.x, 560*F1_0 - dcoord.y, 10);
128
                gr_line (*grd_curcanv, 475*F1_0 + coord.z, 560*F1_0 - coord.y, 475*F1_0 + dcoord.z, 560*F1_0 - dcoord.y, 12);
129
    }
130
}
131
 
132
static vms_vector p1, p4, r1, r4;
133
static vms_vector r4t, r1save;
134
 
135
int generate_curve(const fix r1scale, const fix r4scale)
136
{
137
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
138
        auto &Vertices = LevelSharedVertexState.get_vertices();
139
    vms_vector vec_dir, tvec;
140
    vms_vector coord,prev_point;
141
    vms_equation coeffs;
142
    fix enddist, nextdist;
143
    int firstsegflag;
144
    fix t, maxscale;
145
    fixang rangle, uangle;
146
 
147
        const vcsegptr_t cursegp = Cursegp;
148
        auto &vcvertptr = Vertices.vcptr;
149
        compute_center_point_on_side(vcvertptr, p1, cursegp, Curside);
150
 
151
    switch( Curside ) {
152
        case WLEFT:
153
            extract_right_vector_from_segment(vcvertptr, cursegp, r1);
154
            vm_vec_scale(r1, -F1_0 );
155
            break;
156
        case WTOP:
157
            extract_up_vector_from_segment(vcvertptr, cursegp, r1);
158
            break;
159
        case WRIGHT:
160
            extract_right_vector_from_segment(vcvertptr, cursegp, r1);
161
            break;
162
        case WBOTTOM:
163
            extract_up_vector_from_segment(vcvertptr, cursegp, r1);
164
            vm_vec_scale(r1, -F1_0 );
165
            break;
166
        case WBACK:
167
            extract_forward_vector_from_segment(vcvertptr, cursegp, r1);
168
            break;
169
        case WFRONT:
170
            extract_forward_vector_from_segment(vcvertptr, cursegp, r1);
171
            vm_vec_scale(r1, -F1_0 );
172
            break;
173
        }            
174
 
175
        const vcsegptr_t markedsegp = Markedsegp;
176
        compute_center_point_on_side(vcvertptr, p4, markedsegp, Markedside);
177
 
178
    switch( Markedside ) {
179
        case WLEFT:
180
            extract_right_vector_from_segment(vcvertptr, markedsegp, r4);
181
            extract_up_vector_from_segment(vcvertptr, markedsegp, r4t);
182
            break;
183
        case WTOP:
184
            extract_up_vector_from_segment(vcvertptr, markedsegp, r4);
185
            vm_vec_scale(r4, -F1_0 );
186
            extract_forward_vector_from_segment(vcvertptr, markedsegp, r4t);
187
            vm_vec_scale(r4t, -F1_0 );
188
            break;
189
        case WRIGHT:
190
            extract_right_vector_from_segment(vcvertptr, markedsegp, r4);
191
            vm_vec_scale(r4, -F1_0 );
192
            extract_up_vector_from_segment(vcvertptr, markedsegp, r4t);
193
            break;
194
        case WBOTTOM:
195
            extract_up_vector_from_segment(vcvertptr, markedsegp, r4);
196
            extract_forward_vector_from_segment(vcvertptr, markedsegp, r4t);
197
            break;
198
        case WBACK:
199
            extract_forward_vector_from_segment(vcvertptr, markedsegp, r4);
200
            vm_vec_scale(r4, -F1_0 );
201
            extract_up_vector_from_segment(vcvertptr, markedsegp, r4t);
202
            break;
203
        case WFRONT:
204
            extract_forward_vector_from_segment(vcvertptr, markedsegp, r4);
205
            extract_up_vector_from_segment(vcvertptr, markedsegp, r4t);
206
            break;
207
        }
208
 
209
    r1save = r1;
210
    tvec = r1;
211
    vm_vec_scale(r1,r1scale);
212
    vm_vec_scale(r4,r4scale);
213
 
214
    create_curve( p1, p4, r1, r4, coeffs );
215
    OriginalSeg = Cursegp;
216
    OriginalMarkedSeg = Markedsegp;
217
    OriginalSide = Curside;
218
    OriginalMarkedSide = Markedside;
219
    CurveNumSegs = 0;
220
    coord = prev_point = p1;
221
 
222
    t=0;
223
    firstsegflag = 1;
224
    enddist = F1_0; nextdist = 0;
225
    while ( enddist > fixmul( nextdist, 1.5*F1_0 )) {
226
            vms_matrix  rotmat;
227
            if (firstsegflag==1)
228
                firstsegflag=0;
229
            else
230
                extract_forward_vector_from_segment(vcvertptr, cursegp, tvec);
231
            nextdist = vm_vec_mag(tvec);                                   // nextdist := distance to next point
232
            t = curve_dist(&coeffs, 3, t, prev_point, nextdist);               // t = argument at which function is forward vector magnitude units away from prev_point (in 3-space, not along curve)
233
            coord = evaluate_curve(&coeffs, 3, t);                                          // coord := point about forward vector magnitude units away from prev_point
234
            enddist = vm_vec_dist(coord, p4);                  // enddist := distance from current to end point, vec_dir used as a temporary variable
235
            //vm_vec_normalize(vm_vec_sub(&vec_dir, &coord, &prev_point));
236
            vm_vec_normalized_dir(vec_dir, coord, prev_point);
237
                        if (!med_attach_segment(Cursegp, vmsegptr(&New_segment), Curside, AttachSide))
238
                {
239
                        med_extract_matrix_from_segment(cursegp, rotmat);                   // rotmat := matrix describing orientation of Cursegp
240
                        const auto tdest = vm_vec_rotate(vec_dir,rotmat);       // tdest := vec_dir in reference frame of Cursegp
241
                        vec_dir = tdest;
242
 
243
            const auto rotmat2 = vm_vector_2_matrix(vec_dir,nullptr,nullptr);
244
 
245
            med_rotate_segment( Cursegp, rotmat2 );
246
                        prev_point = coord;
247
            Curside = Side_opposite[AttachSide];
248
 
249
            CurveSegs[CurveNumSegs]=Cursegp;
250
            CurveNumSegs++;
251
        } else return 0;
252
        }
253
 
254
    extract_up_vector_from_segment(vcvertptr, cursegp, tvec);
255
    uangle = vm_vec_delta_ang( tvec, r4t, r4 );
256
    if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4;
257
    if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4;
258
    if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4;
259
    if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4;
260
    extract_right_vector_from_segment(vcvertptr, cursegp, tvec);
261
    rangle = vm_vec_delta_ang( tvec, r4t, r4 );
262
    if (rangle >= F1_0/8) rangle -= F1_0/4;
263
    if (rangle >= F1_0/8) rangle -= F1_0/4;
264
    if (rangle <= -F1_0/8) rangle += F1_0/4;
265
    if (rangle <= -F1_0/8) rangle += F1_0/4;
266
 
267
    if ((uangle != 0) && (rangle != 0)) {
268
        maxscale = CurveNumSegs*F1_0;
269
        generate_banked_curve(maxscale, coeffs);
270
    }
271
 
272
    if (CurveNumSegs) {
273
        med_form_bridge_segment( Cursegp, Side_opposite[AttachSide], Markedsegp, Markedside );
274
        CurveSegs[CurveNumSegs] = vmsegptr(Markedsegp->children[Markedside]);
275
        CurveNumSegs++;
276
        }
277
 
278
    Cursegp = OriginalSeg;
279
    Curside = OriginalSide;
280
 
281
        med_create_new_segment_from_cursegp();
282
 
283
        //warn_if_concave_segments();
284
 
285
    if (CurveNumSegs) return 1;
286
        else return 0;
287
}
288
 
289
static inline vms_matrix vm_vec_ang_2_matrix (const vms_vector &v, fixang a) __attribute_warn_unused_result;
290
static inline vms_matrix vm_vec_ang_2_matrix (const vms_vector &v, fixang a)
291
{
292
        vms_matrix m;
293
        return vm_vec_ang_2_matrix(m, v, a), m;
294
}
295
 
296
void generate_banked_curve(const fix maxscale, vms_equation coeffs)
297
{
298
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
299
        auto &Vertices = LevelSharedVertexState.get_vertices();
300
    vms_vector vec_dir, tvec, b4r4t;
301
    vms_vector coord,prev_point;
302
    fix enddist, nextdist;
303
    int firstsegflag;
304
    fixang rangle, uangle, angle, scaled_ang=0;
305
    fix t;
306
 
307
    if (CurveNumSegs) {
308
 
309
                const vcsegptr_t cursegp = Cursegp;
310
                auto &vcvertptr = Vertices.vcptr;
311
                extract_up_vector_from_segment(vcvertptr, cursegp, b4r4t);
312
    uangle = vm_vec_delta_ang( b4r4t, r4t, r4 );
313
    if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4;
314
    if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4;
315
    if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4;
316
    if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4;
317
 
318
        extract_right_vector_from_segment(vcvertptr, cursegp, b4r4t);
319
    rangle = vm_vec_delta_ang( b4r4t, r4t, r4 );
320
    if (rangle >= F1_0/8) rangle -= F1_0/4;
321
    if (rangle >= F1_0/8) rangle -= F1_0/4;
322
    if (rangle <= -F1_0/8) rangle += F1_0/4;
323
    if (rangle <= -F1_0/8) rangle += F1_0/4;
324
 
325
    angle = uangle;
326
    if (abs(rangle) < abs(uangle)) angle = rangle;
327
 
328
        delete_curve();
329
 
330
    coord = prev_point = p1;
331
 
332
#define MAGIC_NUM 0.707*F1_0
333
 
334
    if (maxscale)
335
        scaled_ang = fixdiv(angle,fixmul(maxscale,MAGIC_NUM));
336
 
337
    t=0;
338
    tvec = r1save;
339
    firstsegflag = 1;
340
    enddist = F1_0; nextdist = 0;
341
    while ( enddist > fixmul( nextdist, 1.5*F1_0 )) {
342
            vms_matrix  rotmat;
343
            if (firstsegflag==1)
344
                firstsegflag=0;
345
            else
346
                                extract_forward_vector_from_segment(vcvertptr, cursegp, tvec);
347
            nextdist = vm_vec_mag(tvec);                                   // nextdist := distance to next point
348
            t = curve_dist(&coeffs, 3, t, prev_point, nextdist);               // t = argument at which function is forward vector magnitude units away from prev_point (in 3-space, not along curve)
349
            coord = evaluate_curve(&coeffs, 3, t);                                          // coord := point about forward vector magnitude units away from prev_point
350
            enddist = vm_vec_dist(coord, p4);                  // enddist := distance from current to end point, vec_dir used as a temporary variable
351
            //vm_vec_normalize(vm_vec_sub(&vec_dir, &coord, &prev_point));
352
            vm_vec_normalized_dir(vec_dir, coord, prev_point);
353
                        if (!med_attach_segment(Cursegp, vmsegptr(&New_segment), Curside, AttachSide))
354
                        {
355
                                med_extract_matrix_from_segment(cursegp, rotmat);                   // rotmat := matrix describing orientation of Cursegp
356
                        const auto tdest = vm_vec_rotate(vec_dir,rotmat);       // tdest := vec_dir in reference frame of Cursegp
357
                        vec_dir = tdest;
358
            const auto rotmat2 = vm_vec_ang_2_matrix(vec_dir,scaled_ang);
359
 
360
                        med_rotate_segment( Cursegp, rotmat2 );
361
                        prev_point = coord;
362
            Curside = Side_opposite[AttachSide];
363
 
364
            CurveSegs[CurveNumSegs]=Cursegp;
365
            CurveNumSegs++;
366
        }
367
      }
368
    }
369
}
370
 
371
 
372
void delete_curve() {
373
        range_for (auto &i, partial_const_range(CurveSegs, CurveNumSegs))
374
        {
375
        if (i->segnum != segment_none)
376
                        med_delete_segment(vmsegptridx(i));
377
    }
378
    Markedsegp = OriginalMarkedSeg;
379
    Markedside = OriginalMarkedSide;
380
    Cursegp = OriginalSeg;
381
    Curside = OriginalSide;
382
        med_create_new_segment_from_cursegp();
383
    CurveNumSegs = 0;
384
 
385
        //editor_status("");
386
        //warn_if_concave_segments();
387
}