Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

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