/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * curve generation stuff * */ #include #include #include #include #include #include #include "inferno.h" #include "vecmat.h" #include "gr.h" #include "key.h" #include "editor.h" #include "gameseg.h" #include "console.h" #define ONE_OVER_SQRT2 F1_0 * 0.707106781 #define CURVE_RIGHT 1 #define CURVE_UP 2 segment *OriginalSeg; segment *OriginalMarkedSeg; int OriginalSide; int OriginalMarkedSide; segment *CurveSegs[MAX_SEGMENTS]; int CurveNumSegs; const fix Mh[4][4] = { { 2*F1_0, -2*F1_0, 1*F1_0, 1*F1_0 }, {-3*F1_0, 3*F1_0, -2*F1_0, -1*F1_0 }, { 0*F1_0, 0*F1_0, 1*F1_0, 0*F1_0 }, { 1*F1_0, 0*F1_0, 0*F1_0, 0*F1_0 } }; void generate_banked_curve(fix maxscale, vms_equation coeffs); void create_curve(vms_vector *p1, vms_vector *p4, vms_vector *r1, vms_vector *r4, vms_equation *coeffs) { // Q(t) = (2t^3 - 3t^2 + 1) p1 + (-2t^3 + 3t^2) p4 + (t~3 - 2t^2 + t) r1 + (t^3 - t^2 ) r4 coeffs->n.x3 = fixmul(2*F1_0,p1->x) - fixmul(2*F1_0,p4->x) + r1->x + r4->x; 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); coeffs->n.x1 = r1->x; coeffs->n.x0 = p1->x; coeffs->n.y3 = fixmul(2*F1_0,p1->y) - fixmul(2*F1_0,p4->y) + r1->y + r4->y; 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); coeffs->n.y1 = r1->y; coeffs->n.y0 = p1->y; coeffs->n.z3 = fixmul(2*F1_0,p1->z) - fixmul(2*F1_0,p4->z) + r1->z + r4->z; 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); coeffs->n.z1 = r1->z; coeffs->n.z0 = p1->z; } vms_vector evaluate_curve(vms_equation *coeffs, int degree, fix t) { fix t2, t3; vms_vector coord; if (degree!=3) con_printf(CON_CRITICAL," for Hermite Curves degree must be 3\n"); t2 = fixmul(t,t); t3 = fixmul(t2,t); coord.x = fixmul(coeffs->n.x3,t3) + fixmul(coeffs->n.x2,t2) + fixmul(coeffs->n.x1,t) + coeffs->n.x0; coord.y = fixmul(coeffs->n.y3,t3) + fixmul(coeffs->n.y2,t2) + fixmul(coeffs->n.y1,t) + coeffs->n.y0; coord.z = fixmul(coeffs->n.z3,t3) + fixmul(coeffs->n.z2,t2) + fixmul(coeffs->n.z1,t) + coeffs->n.z0; return coord; } fix curve_dist(vms_equation *coeffs, int degree, fix t0, vms_vector *p0, fix dist) { vms_vector coord; fix t, diff; if (degree!=3) con_printf(CON_CRITICAL," for Hermite Curves degree must be 3\n"); for (t=t0;t<1*F1_0;t+=0.001*F1_0) { coord = evaluate_curve(coeffs, 3, t); diff = dist - vm_vec_dist(&coord, p0); if (diff-ACCURACY)) return t; } return -1*F1_0; } void curve_dir(vms_equation *coeffs, int degree, fix t0, vms_vector *dir) { fix t2; if (degree!=3) con_printf(CON_CRITICAL," for Hermite Curves degree must be 3\n"); t2 = fixmul(t0,t0); dir->x = fixmul(3*F1_0,fixmul(coeffs->n.x3,t2)) + fixmul(2*F1_0,fixmul(coeffs->n.x2,t0)) + coeffs->n.x1; dir->y = fixmul(3*F1_0,fixmul(coeffs->n.y3,t2)) + fixmul(2*F1_0,fixmul(coeffs->n.y2,t0)) + coeffs->n.y1; dir->z = fixmul(3*F1_0,fixmul(coeffs->n.z3,t2)) + fixmul(2*F1_0,fixmul(coeffs->n.z2,t0)) + coeffs->n.z1; vm_vec_normalize( dir ); } void plot_parametric(vms_equation *coeffs, fix min_t, fix max_t, fix del_t) { vms_vector coord, dcoord; fix t, dt; gr_setcolor(15); gr_rect( 75, 40, 325, 290 ); gr_rect( 75, 310, 325, 560 ); gr_rect( 475, 310, 725, 560 ); //gr_pal_fade_in( grd_curscreen->pal ); for (t=min_t;t fixmul( nextdist, 1.5*F1_0 )) { vms_matrix rotmat,rotmat2; vms_vector tdest; if (firstsegflag==1) firstsegflag=0; else extract_forward_vector_from_segment(Cursegp, &tvec); nextdist = vm_vec_mag(&tvec); // nextdist := distance to next point 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) coord = evaluate_curve(&coeffs, 3, t); // coord := point about forward vector magnitude units away from prev_point enddist = vm_vec_dist(&coord, &p4); // enddist := distance from current to end point, vec_dir used as a temporary variable //vm_vec_normalize(vm_vec_sub(&vec_dir, &coord, &prev_point)); vm_vec_normalized_dir(&vec_dir, &coord, &prev_point); if (!med_attach_segment( Cursegp, &New_segment, Curside, AttachSide )) { med_extract_matrix_from_segment( Cursegp,&rotmat ); // rotmat := matrix describing orientation of Cursegp vm_vec_rotate(&tdest,&vec_dir,&rotmat); // tdest := vec_dir in reference frame of Cursegp vec_dir = tdest; vm_vector_2_matrix(&rotmat2,&vec_dir,NULL,NULL); med_rotate_segment( Cursegp, &rotmat2 ); prev_point = coord; Curside = Side_opposite[AttachSide]; CurveSegs[CurveNumSegs]=Cursegp; CurveNumSegs++; } else return 0; } extract_up_vector_from_segment( Cursegp,&tvec ); uangle = vm_vec_delta_ang( &tvec, &r4t, &r4 ); if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; extract_right_vector_from_segment( Cursegp,&tvec ); rangle = vm_vec_delta_ang( &tvec, &r4t, &r4 ); if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; if ((uangle != 0) && (rangle != 0)) { maxscale = CurveNumSegs*F1_0; generate_banked_curve(maxscale, coeffs); } if (CurveNumSegs) { med_form_bridge_segment( Cursegp, Side_opposite[AttachSide], Markedsegp, Markedside ); CurveSegs[CurveNumSegs] = &Segments[ Markedsegp->children[Markedside] ]; CurveNumSegs++; } Cursegp = OriginalSeg; Curside = OriginalSide; med_create_new_segment_from_cursegp(); //warn_if_concave_segments(); if (CurveNumSegs) return 1; else return 0; } void generate_banked_curve(fix maxscale, vms_equation coeffs) { vms_vector vec_dir, tvec, b4r4t; vms_vector coord,prev_point; fix enddist, nextdist; int firstsegflag; fixang rangle, uangle, angle, scaled_ang=0; fix t; if (CurveNumSegs) { extract_up_vector_from_segment( Cursegp,&b4r4t ); uangle = vm_vec_delta_ang( &b4r4t, &r4t, &r4 ); if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; extract_right_vector_from_segment( Cursegp,&b4r4t ); rangle = vm_vec_delta_ang( &b4r4t, &r4t, &r4 ); if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; angle = uangle; if (abs(rangle) < abs(uangle)) angle = rangle; delete_curve(); coord = prev_point = p1; #define MAGIC_NUM 0.707*F1_0 if (maxscale) scaled_ang = fixdiv(angle,fixmul(maxscale,MAGIC_NUM)); t=0; tvec = r1save; firstsegflag = 1; enddist = F1_0; nextdist = 0; while ( enddist > fixmul( nextdist, 1.5*F1_0 )) { vms_matrix rotmat,rotmat2; vms_vector tdest; if (firstsegflag==1) firstsegflag=0; else extract_forward_vector_from_segment(Cursegp, &tvec); nextdist = vm_vec_mag(&tvec); // nextdist := distance to next point 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) coord = evaluate_curve(&coeffs, 3, t); // coord := point about forward vector magnitude units away from prev_point enddist = vm_vec_dist(&coord, &p4); // enddist := distance from current to end point, vec_dir used as a temporary variable //vm_vec_normalize(vm_vec_sub(&vec_dir, &coord, &prev_point)); vm_vec_normalized_dir(&vec_dir, &coord, &prev_point); if (!med_attach_segment( Cursegp, &New_segment, Curside, AttachSide )) { med_extract_matrix_from_segment( Cursegp,&rotmat ); // rotmat := matrix describing orientation of Cursegp vm_vec_rotate(&tdest,&vec_dir,&rotmat); // tdest := vec_dir in reference frame of Cursegp vec_dir = tdest; vm_vec_ang_2_matrix(&rotmat2,&vec_dir,scaled_ang); med_rotate_segment( Cursegp, &rotmat2 ); prev_point = coord; Curside = Side_opposite[AttachSide]; CurveSegs[CurveNumSegs]=Cursegp; CurveNumSegs++; } } } } void delete_curve() { int i; for (i=0; isegnum != -1) med_delete_segment(CurveSegs[i]); } Markedsegp = OriginalMarkedSeg; Markedside = OriginalMarkedSide; Cursegp = OriginalSeg; Curside = OriginalSide; med_create_new_segment_from_cursegp(); CurveNumSegs = 0; //editor_status(""); //warn_if_concave_segments(); } /* void main() { vms_vector p1; vms_vector p4; vms_vector r1; vms_vector r4; vms_equation coeffs; float x, y, z; vms_vector test, test2, tvec; fix t, t0; fix distance, dist; int key; key_init(); printf("Enter p1 (x,y,z): "); scanf("%f %f %f", &x, &y, &z); p1.x = x*F1_0; p1.y = y*F1_0; p1.z = z*F1_0; printf("Enter p4 (x,y,z): "); scanf("%f %f %f", &x, &y, &z); p4.x = x*F1_0; p4.y = y*F1_0; p4.z = z*F1_0; printf("Enter r1 : "); scanf("%f %f %f", &x, &y, &z); r1.x = x*F1_0; r1.y = y*F1_0; r1.z = z*F1_0; printf("Enter r4 : "); scanf("%f %f %f", &x, &y, &z); r4.x = x*F1_0; r4.y = y*F1_0; r4.z = z*F1_0; create_curve( &p1, &p4, &r1, &r4, &coeffs ); printf("\nQ(t) = "); printf("x [%6.3f %6.3f %6.3f %6.3f]\n", f2fl(coeffs.n.x3), f2fl(coeffs.n.x2), f2fl(coeffs.n.x1), f2fl(coeffs.n.x0)); printf(" y [%6.3f %6.3f %6.3f %6.3f]\n", f2fl(coeffs.n.y3), f2fl(coeffs.n.y2), f2fl(coeffs.n.y1), f2fl(coeffs.n.y0)); printf(" z [%6.3f %6.3f %6.3f %6.3f]\n", f2fl(coeffs.n.z3), f2fl(coeffs.n.z2), f2fl(coeffs.n.z1), f2fl(coeffs.n.z0)); printf("\nChecking direction vectors.\n"); for (t=0*F1_0;t<1*F1_0;t+=0.1*F1_0) { curve_dir(&coeffs, 3, t, &test); printf(" t = %.3f dir = <%6.3f, %6.3f, %6.3f >\n", f2fl(t), f2fl(test.x), f2fl(test.y), f2fl(test.z) ); } printf("\nChecking distance function.\n"); printf("Enter a distance: "); scanf("%f", &x); distance = x*F1_0; printf("Enter a (0