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 | } |