home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Homebrewer's Handbook / vr.iso / vroom / vroom1.pas < prev    next >
Pascal/Delphi Source File  |  1996-03-19  |  47KB  |  1,503 lines

  1.  
  2. {------------------------------------------------}
  3. { File_Object_3d method implementations          }
  4. {------------------------------------------------}
  5.  
  6. constructor file_object3d.Init(fname : titletype);
  7. var f : text;
  8.     temp_face : face_ptr;
  9.     temp_vertex : vertex_ptr;
  10.     nv, nf, nfv, vertexno : integer;
  11.     count1, count2, count3 : integer;
  12.     color : byte;
  13.     x1, y1, z1, inten : real;
  14. begin
  15.      object3d.Init;
  16.      assign(f,fname);
  17.      reset(f);
  18.      readln(f,nv);
  19.      if nv<=0 then
  20.      begin
  21.           stop_graphics;
  22.           if nv<=0 then writeln('Fatal file read error - number vertices is negative.')
  23.           else writeln('Fatal file read error - not enough vertices to form a face.');
  24.           halt;
  25.      end;
  26.      read(f,x1);
  27.      read(f,y1);
  28.      readln(f,z1);
  29.      temp_vertex:=add_vertex(x1,y1,z1);
  30.      reference_point.x:=real_to_fixed(x1);
  31.      reference_point.y:=real_to_fixed(y1);
  32.      reference_point.z:=real_to_fixed(z1);
  33.      for count1:=2 to nv do
  34.      begin
  35.           read(f,x1);
  36.           read(f,y1);
  37.           readln(f,z1);
  38.           temp_vertex:=add_vertex(x1,y1,z1);
  39.      end;
  40.      readln(f,nf);
  41.      if nf<>0 then
  42.      begin
  43.           stop_graphics;
  44.           writeln('Fatal file error - file check digit failure.');
  45.           halt;
  46.      end;
  47.      readln(f,nf);
  48.      if nf<=0 then
  49.      begin
  50.           stop_graphics;
  51.           writeln('Fatal file error - no faces in file.');
  52.           halt;
  53.      end;
  54.      for count1:=1 to nf do
  55.      begin
  56.           read(f,color);
  57.           readln(f,inten);
  58.           readln(f,nfv);
  59.           if nfv<0 then
  60.           begin
  61.                stop_graphics;
  62.                if nfv<=0 then writeln('Fatal file read error - number of face vertices is negative.');
  63.                halt;
  64.           end;
  65.           if nfv>0 then
  66.           begin
  67.                new(temp_face);
  68.                if (color<0) or (color>15) then
  69.                begin
  70.                     stop_graphics;
  71.                     writeln('Error! - Face color outside range 0 to 15.');
  72.                halt;
  73.                end;
  74.                temp_face^.colour:=color;
  75.                if (inten<0) or (inten>1) then
  76.                begin
  77.                     stop_graphics;
  78.                     writeln('Error! - Face intensity outside range 0 to 1.');
  79.                     halt;
  80.                end;
  81.                temp_face^.next:=first_face;
  82.                first_face:=temp_face;
  83.                temp_face^.next_order:=first_list_face;
  84.                first_list_face:=temp_face;
  85.                temp_face^.intensity:=real_to_fixed(inten);
  86.                temp_face^.Color:=temp_face^.Colour*16+trunc(temp_face^.intensity/65536*15+0.5);
  87.                temp_face^.sort_z:=0;
  88.                temp_face^.vertex1:=nil;
  89.                for count2:=1 to nfv do
  90.                begin
  91.                     if count2=nfv then readln(f,vertexno) else read(f,vertexno);
  92.                     if (vertexno<1) or (vertexno>nv) then
  93.                     begin
  94.                          stop_graphics;
  95.                          writeln('Fatal file read error - trying to assign non-existant vertex.');
  96.                          halt;
  97.                     end;
  98.                     temp_vertex:=first_vertex;
  99.                     for count3:=1 to (nv-vertexno) do
  100.                        temp_vertex:=temp_vertex^.next;
  101.                     temp_face^.Add_Vertex(temp_vertex);
  102.                end;
  103.           end
  104.           else
  105.           begin
  106.                writeln('File warning - no face vertices! Face ignored.');
  107.           end;
  108.           readln(f,vertexno);
  109.           if vertexno<>0 then
  110.           begin
  111.                stop_graphics;
  112.                writeln('Fatal file error - file check digit failure.');
  113.                halt;
  114.           end;
  115.      end;
  116.      readln(f,vertexno);
  117.      if vertexno<>0 then
  118.      begin
  119.           stop_graphics;
  120.           writeln('Fatal file error - file check digit failure.');
  121.           halt;
  122.      end;
  123.      close(f);
  124.      Build_Normals;
  125. end;
  126.  
  127.  
  128.  
  129. {------------------------------------------------}
  130. { Copy_Object3d method implementations           }
  131. {------------------------------------------------}
  132.  
  133. constructor copy_object3d.Init(source_object : object3d_ptr);
  134. var first_vertex_copy, temp_vertex_copy : vertex_copy_ptr;
  135.     source_vertex, copy_vertex : vertex_ptr;
  136.     source_face, copy_face : face_ptr;
  137.     last_face_vertex, source_face_vertex, copy_face_vertex : face_vertex_ptr;
  138. begin
  139.      if source_object=nil then
  140.      begin
  141.           stop_graphics;
  142.           writeln('Trying to copy a nil object3d');
  143.           halt;
  144.      end;
  145.      object3d.Init;
  146.      lo.x:=source_object^.lo.x;
  147.      lo.y:=source_object^.lo.y;
  148.      lo.z:=source_object^.lo.z;
  149.      hi.x:=source_object^.hi.x;
  150.      hi.y:=source_object^.hi.y;
  151.      hi.z:=source_object^.hi.z;
  152.      reference_point.x:=source_object^.reference_point.x;
  153.      reference_point.y:=source_object^.reference_point.y;
  154.      reference_point.z:=source_object^.reference_point.z;
  155.      first_vertex_copy:=nil;
  156.      source_vertex:=source_object^.first_vertex;
  157.      while source_vertex<>nil do
  158.      begin
  159.           new(copy_vertex);
  160.           copy_vertex^.next:=first_vertex;
  161.           first_vertex:=copy_vertex;
  162.           with copy_vertex^ do
  163.           begin
  164.                screen.x:=source_vertex^.screen.x;
  165.                screen.y:=source_vertex^.screen.y;
  166.                screen.z:=source_vertex^.screen.z;
  167.                world.x:=source_vertex^.world.x;
  168.                world.y:=source_vertex^.world.y;
  169.                world.z:=source_vertex^.world.z;
  170.                clip:=source_vertex^.clip;
  171.           end;
  172.           new(temp_vertex_copy);
  173.           temp_vertex_copy^.next:=first_vertex_copy;
  174.           first_vertex_copy:=temp_vertex_copy;
  175.           temp_vertex_copy^.old_vertex:=source_vertex;
  176.           temp_vertex_copy^.new_vertex:=copy_vertex;
  177.           source_vertex:=source_vertex^.next;
  178.      end;
  179.  
  180.      source_face:=source_object^.first_face;
  181.      while source_face<>nil do
  182.      begin
  183.           new(copy_face);
  184.           copy_face^.next:=first_face;
  185.           first_face:=copy_face;
  186.           copy_face^.next_order:=first_list_face;
  187.           first_list_face:=copy_face;
  188.           copy_face^.intensity:=source_face^.intensity;
  189.           copy_face^.Color:=source_face^.color;
  190.           copy_face^.Colour:=source_face^.colour;
  191.           copy_face^.sort_z:=source_face^.sort_z;
  192.           copy_face^.seen:=source_face^.seen;
  193.           copy_face^.normal.x:=source_face^.normal.x;
  194.           copy_face^.normal.y:=source_face^.normal.y;
  195.           copy_face^.normal.z:=source_face^.normal.z;
  196.           copy_face^.this_fillproc:=source_face^.this_fillproc;
  197.           copy_face^.two_d:=source_face^.two_d;
  198.           copy_face^.vertex1:=nil;
  199.           last_face_vertex:=nil;
  200.           source_face_vertex:=source_face^.vertex1;
  201.           while source_face_vertex<>nil do
  202.           begin
  203.                new(copy_face_vertex);
  204.                copy_face_vertex^.next:=nil;
  205.                if last_face_vertex<>nil then last_face_vertex^.next:=copy_face_vertex
  206.                else copy_face^.vertex1:=copy_face_vertex;
  207.                last_face_vertex:=copy_face_vertex;
  208.                temp_vertex_copy:=first_vertex_copy;
  209.                while (temp_vertex_copy^.next<>nil) and (temp_vertex_copy^.old_vertex<>source_face_vertex^.this_vertex)
  210.                  do temp_vertex_copy:=temp_vertex_copy^.next;
  211.                if temp_vertex_copy<>nil
  212.                  then copy_face_vertex^.this_vertex:=temp_vertex_copy^.new_vertex
  213.                  else copy_face_vertex^.this_vertex:=source_face_vertex^.this_vertex;
  214.                source_face_vertex:=source_face_vertex^.next;
  215.           end;
  216.           source_face:=source_face^.next;
  217.      end;
  218.  
  219.      temp_vertex_copy:=first_vertex_copy;
  220.      while temp_vertex_copy<>nil do
  221.      begin
  222.           first_vertex_copy:=temp_vertex_copy^.next;
  223.           dispose(temp_vertex_copy);
  224.           temp_vertex_copy:=first_vertex_copy;
  225.      end;
  226. end;
  227.  
  228.  
  229. {------------------------------------------------}
  230. { Face method implementations                    }
  231. {------------------------------------------------}
  232.  
  233. constructor Face.Init(var owner : object3d; face_color : byte; inten : real);
  234. begin
  235.      next:=owner.first_face;
  236.      owner.first_face:=@vertex1;
  237.      next_order:=first_list_face;
  238.      first_list_face:=@vertex1;
  239.      if (face_color<0) or (face_color>15) then
  240.      begin
  241.           stop_graphics;
  242.           writeln('Error! - Face color outside range 0 to 15.');
  243.           halt;
  244.      end;
  245.      colour:=face_color;
  246.      if (inten<0) or (inten>1) then
  247.      begin
  248.           stop_graphics;
  249.           writeln('Error! - Face intensity outside range 0 to 1.');
  250.           halt;
  251.      end;
  252.      intensity:=real_to_fixed(inten);
  253.      Color:=Colour*16+trunc(intensity/65536*15+0.5);
  254.  
  255.      vertex1:=nil;
  256.      d:=0;
  257.      normal.x:=0;
  258.      normal.y:=0;
  259.      normal.z:=0;
  260.      sort_z:=0;
  261.      two_d:=false;
  262. end;
  263.  
  264. procedure Face.Add_Vertex(this_vertex : vertex_ptr);
  265. var temp_vertex : face_vertex_ptr;
  266. begin
  267.      if this_vertex=nil then exit;
  268.      new(temp_vertex);
  269.      temp_vertex^.next:=vertex1;
  270.      temp_vertex^.this_vertex:=this_vertex;
  271.      vertex1:=temp_vertex;
  272. end;
  273.  
  274. procedure Face.Build_Normal;
  275. var temp_face_vertex : face_vertex_ptr;
  276.     nx, ny, nz : longint;
  277.     length : longint;
  278.     count : integer;
  279. begin
  280.      two_d:=false;
  281.      nx:=0; ny:=0; nz:=0;
  282.      temp_face_vertex:=vertex1;
  283.      if temp_face_vertex=nil then
  284.      begin
  285.           stop_graphics;
  286.           writeln('Fatal Error ! - Face has no vertices to build normal with.');
  287.           halt;
  288.      end;
  289.      if temp_face_vertex^.next=nil then
  290.      begin
  291.           this_fillproc:=Fill_Face_Point;
  292.           two_d:=true;
  293.      end
  294.      else
  295.      if temp_face_vertex^.next^.next=nil then
  296.      begin
  297.           this_fillproc:=Fill_Face_Line;
  298.           two_d:=true;
  299.      end
  300.      else
  301.      begin
  302.           while temp_face_vertex^.next<>nil do
  303.           begin
  304.                nx:=nx-FixedMul(temp_face_vertex^.this_vertex^.world.y-temp_face_vertex^.next^.this_vertex^.world.y,
  305.                                temp_face_vertex^.this_vertex^.world.z+temp_face_vertex^.next^.this_vertex^.world.z);
  306.                ny:=ny-FixedMul(temp_face_vertex^.this_vertex^.world.z-temp_face_vertex^.next^.this_vertex^.world.z,
  307.                                temp_face_vertex^.this_vertex^.world.x+temp_face_vertex^.next^.this_vertex^.world.x);
  308.                nz:=nz-FixedMul(temp_face_vertex^.this_vertex^.world.x-temp_face_vertex^.next^.this_vertex^.world.x,
  309.                                temp_face_vertex^.this_vertex^.world.y+temp_face_vertex^.next^.this_vertex^.world.y);
  310.                temp_face_vertex:=temp_face_vertex^.next;
  311.           end;
  312.           nx:=nx-FixedMul(temp_face_vertex^.this_vertex^.world.y-vertex1^.this_vertex^.world.y,
  313.                           temp_face_vertex^.this_vertex^.world.z+vertex1^.this_vertex^.world.z);
  314.           ny:=ny-FixedMul(temp_face_vertex^.this_vertex^.world.z-vertex1^.this_vertex^.world.z,
  315.                           temp_face_vertex^.this_vertex^.world.x+vertex1^.this_vertex^.world.x);
  316.           nz:=nz-FixedMul(temp_face_vertex^.this_vertex^.world.x-vertex1^.this_vertex^.world.x,
  317.                           temp_face_vertex^.this_vertex^.world.y+vertex1^.this_vertex^.world.y);
  318.           if (nx=0) and (ny=0) and (nz=0) then
  319.           begin
  320.                two_d:=true;
  321.                this_fillproc:=Fill_Face_Line;
  322.           end
  323.           else
  324.               this_fillproc:=Fill_Face;
  325.      end;
  326.  
  327.      if not(two_d) then
  328.      begin
  329.            length:=real_to_fixed(sqrt(sqr(nx/65536)+sqr(ny/65536)+sqr(nz/65536)));
  330.            normal.x:=FixedDiv(nx,length);
  331.            normal.y:=FixedDiv(ny,length);
  332.            normal.z:=FixedDiv(nz,length);
  333.      end
  334.      else
  335.      begin
  336.           normal.x:=0; normal.y:=0; normal.z:=0;
  337.      end;
  338.      {n.p=D, but I don't need it yet so I've left it}
  339.      Shading;
  340. end;
  341.  
  342. procedure Face.Unit_Normal;
  343. var length : longint;
  344. begin
  345.       if two_d then exit;
  346.       length:=real_to_fixed(sqrt(sqr(normal.x/65536)+sqr(normal.y/65536)+sqr(normal.z/65536)));
  347.       normal.x:=FixedDiv(normal.x,length);
  348.       normal.y:=FixedDiv(normal.y,length);
  349.       normal.z:=FixedDiv(normal.z,length);
  350. end;
  351.  
  352. procedure Face.Shading;
  353. var Intens, CosTheta : longint;
  354. begin
  355.      if not(two_d) then
  356.      begin
  357.           CosTheta:=FixedMul(normal.x,light.x)+FixedMul(normal.y,light.y)+FixedMul(normal.z,light.z);
  358.           if CosTheta<0 then CosTheta:=0;
  359.           Intens:=Ambient_Intensity+FixedMul(Light_Intensity,CosTheta);
  360.           if Intens>65536 then Intens:=65536;
  361.      end
  362.      else
  363.      begin
  364.           Intens:=Ambient_Intensity+Light_Intensity;
  365.           if Intens>65536 then Intens:=65536;
  366.      end;
  367.      Intens:=FixedMul(Intens,intensity);
  368.      Color:=Colour*16+trunc(intens/65536*15+0.5);
  369. end;
  370.  
  371. procedure Face.Fill;
  372. begin
  373.      this_fillproc(@vertex1);
  374. end;
  375.  
  376. destructor Face.Done;
  377. var temp_face : face_ptr;
  378.     temp_face_vertex1, temp_face_vertex2 : face_vertex_ptr;
  379.     temp_obj : object3d_ptr;
  380. begin
  381.      {Remove from sorted face list}
  382.      if first_list_face=@vertex1 then first_list_face:=next_order
  383.      else
  384.      begin
  385.           temp_face:=first_list_face;
  386.           while (temp_face<>nil) and (temp_face^.next_order<>@vertex1) do
  387.                 temp_face:=temp_face^.next_order;
  388.           if temp_face<>nil then temp_face^.next_order:=next_order;
  389.      end;
  390.  
  391.      temp_face_vertex1:=vertex1;
  392.      while temp_face_vertex1<>nil do
  393.      begin
  394.           temp_face_vertex2:=temp_face_vertex1^.next;
  395.           dispose(temp_face_vertex1);
  396.           temp_face_vertex1:=temp_face_vertex2;
  397.      end;
  398. end;
  399.  
  400.  
  401. {------------------------------------------------}
  402. { Timed_Xform method implementations             }
  403. {------------------------------------------------}
  404.  
  405. constructor timed_Xform.Init(this_object : object3d_ptr; start, duration : real);
  406. begin
  407.      this_ob:=this_object;
  408.      t_start:=start;
  409.      t_last:=start;
  410.      if duration=infinity then t_end:=duration else t_end:=t_last+duration;
  411.      next:=first_timed_xform;
  412.      first_timed_xform:=@t_start;
  413. end;
  414.  
  415. procedure timed_Xform.Update;
  416. begin
  417. end;
  418.  
  419. destructor timed_Xform.Done;
  420. var temp : timed_Xform_ptr;
  421. begin
  422.      if first_timed_xform=@t_start then first_timed_xform:=next
  423.      else
  424.      begin
  425.           temp:=first_timed_xform;
  426.           while (temp<>nil) and (temp^.next<>@t_start) do temp:=temp^.next;
  427.           if temp<>nil then temp^.next:=next;
  428.      end;
  429. end;
  430.  
  431.  
  432. constructor timed_rotX.Init(this_object : object3d_ptr ; start, duration, dtheta : real);
  433. begin
  434.      timed_Xform.Init(this_object,start, duration);
  435.      dth:=dtheta;
  436. end;
  437.  
  438. procedure timed_rotX.Update;
  439. var theta : real;
  440. begin
  441.      theta:=round(dth*10*(graphics_time^-t_last))/10;
  442.      if abs(theta)>0 then
  443.      begin
  444.           t_last:=t_last+theta/dth;
  445.           this_ob^.RotateX(theta);
  446.      end;
  447. end;
  448.  
  449. procedure timed_rotY.Update;
  450. var theta : real;
  451. begin
  452.      theta:=round(dth*10*(graphics_time^-t_last))/10;
  453.      if abs(theta)>0 then
  454.      begin
  455.           t_last:=t_last+theta/dth;
  456.           this_ob^.RotateY(theta);
  457.      end;
  458. end;
  459.  
  460. procedure timed_rotZ.Update;
  461. var theta : real;
  462. begin
  463.      theta:=round(dth*10*(graphics_time^-t_last))/10;
  464.      if abs(theta)>0 then
  465.      begin
  466.           t_last:=t_last+theta/dth;
  467.           this_ob^.RotateZ(theta);
  468.      end;
  469. end;
  470.  
  471. constructor timed_rotX_About.Init(this_object : object3d_ptr ; start, duration, dtheta, x1, y1, z1 : real);
  472. begin
  473.      timed_Xform.Init(this_object,start, duration);
  474.      dth:=dtheta;
  475.      X:=x1; Y:=y1; Z:=z1;
  476. end;
  477.  
  478. procedure timed_rotX_About.Update;
  479. var theta : real;
  480. begin
  481.      theta:=round(dth*10*(graphics_time^-t_last))/10;
  482.      if abs(theta)>0 then
  483.      begin
  484.           t_last:=t_last+theta/dth;
  485.           this_ob^.RotateX_About(theta,x,y,z);
  486.      end;
  487. end;
  488.  
  489. procedure timed_rotY_About.Update;
  490. var theta : real;
  491. begin
  492.      theta:=round(dth*10*(graphics_time^-t_last))/10;
  493.      if abs(theta)>0 then
  494.      begin
  495.           t_last:=t_last+theta/dth;
  496.           this_ob^.RotateY_About(theta,x,y,z);
  497.      end;
  498. end;
  499.  
  500. procedure timed_rotZ_About.Update;
  501. var theta : real;
  502. begin
  503.      theta:=round(dth*10*(graphics_time^-t_last))/10;
  504.      if abs(theta)>0 then
  505.      begin
  506.           t_last:=t_last+theta/dth;
  507.           this_ob^.RotateZ_About(theta,x,y,z);
  508.      end;
  509. end;
  510.  
  511. constructor timed_scale.Init(this_object : object3d_ptr ; start, duration, sx1, sy1, sz1 : real);
  512. begin
  513.      stop_graphics;
  514.      writeln('Timed Scale is not implemented yet !!');
  515.      halt;
  516. end;
  517.  
  518. procedure timed_scale.Update;
  519. begin
  520. end;
  521.  
  522. constructor timed_scale_About.Init(this_object : object3d_ptr ; start, duration, sx1, sy1, sz1, x1, y1, z1 : real);
  523. begin
  524.      stop_graphics;
  525.      writeln('Timed Scale About is not implemented yet !!');
  526.      halt;
  527. end;
  528.  
  529. procedure timed_scale_About.Update;
  530. begin
  531. end;
  532.  
  533. constructor timed_translate.Init(this_object : object3d_ptr; start, duration, x1, y1, z1 : real);
  534. begin
  535.      timed_Xform.Init(this_object,start, duration);
  536.      X:=x1; Y:=y1; Z:=z1;
  537. end;
  538.  
  539. procedure timed_translate.Update;
  540. var dt : real;
  541. begin
  542.      dt:=graphics_time^-t_last;
  543.      this_ob^.translate(dt*X,dt*Y,dt*Z);
  544.      t_last:=graphics_time^;
  545. end;
  546.  
  547. {------------------------------------------------}
  548. { General procedures                             }
  549. {------------------------------------------------}
  550.  
  551. procedure Init_System;
  552. var junk : integer;
  553.     r : registers;
  554.     c : char;
  555. begin
  556.      first_object:=nil;
  557.      first_list_face:=nil;
  558.      first_timed_Xform:=nil;
  559.      redraw_all:=true;
  560.      timed_xforms_separately:=false;
  561.      this_keyproc:=NulKeyProc;
  562.      any_textproc:=false;
  563.      cursor2D_mode:=false;
  564.      Set_Default_Cursor2D;
  565.      Cursor_x:=320;
  566.      Cursor_y:=100;
  567.      viewpoint.x:=0;
  568.      viewpoint.y:=0;
  569.      viewpoint.z:=0;
  570.      azimuth:=0;
  571.      colatitude:=0;
  572.      speed:=65536;
  573.      setviewpoint.x:=0;
  574.      setviewpoint.y:=0;
  575.      setviewpoint.z:=0;
  576.      setazimuth:=0;
  577.      setcolatitude:=0;
  578.      setspeed:=65536;
  579.      Set_Window(-20,-15,20,15);
  580.      eye_screen_distance:=int_to_fixed(300);
  581.      hither:=1;
  582.      yon:=10000;
  583.      picture_num:=0;
  584.      r.ax:=$1130;
  585.      r.bh:=$3;
  586.      intr($10,r);
  587.      font_segment:=r.es;
  588.      font_offset:=r.bp;
  589.      assign(output,'OUTPUT.LOG');
  590.      rewrite(output);
  591.      set_background_colour(0,0);
  592.      Start_Graphics;
  593.      Set_Palette;
  594.      Init_CosTable;
  595.      Ambient_Intensity:=65536;
  596.      Light_Intensity:=0;
  597.      Light.x:=0; Light.y:=0; Light.z:=0;
  598.      ReadMouseCounter(junk,junk);
  599.      sort_type:=4;
  600.      write_text_at(7,9, '╔═══════════════════════════╗',5,1,3,1);
  601.      write_text_at(7,10,'║ VROOM VR Graphics Toolbox ║',5,1,3,1);
  602.      write_text_at(7,11,'║',5,1,3,1);
  603.      write_text_at(7+28,11,'║',5,1,3,1);
  604.      write_text_at(8,11,'     by Robin Hollands     ',0,1,3,1);
  605.      write_text_at(7,12,'╚═══════════════════════════╝',5,1,3,1);
  606.      write_text_at(7,15,'   Press a key to continue   ',2,1,0,-1);
  607.      show_page(screen_page_offset);
  608.      c:=ReadKey;
  609.      write_text_at(7,15,'Loading world - please wait...',2,1,0,0);
  610. end;
  611.  
  612. procedure Sort_by_Nearest_Point;
  613. begin
  614.      sort_type:=2;
  615. end;
  616.  
  617. procedure Sort_by_Furthest_Point;
  618. begin
  619.      sort_type:=1;
  620. end;
  621.  
  622. procedure Sort_by_Middle_Point;
  623. begin
  624.      sort_type:=4;
  625. end;
  626.  
  627. procedure Set_Window(wl,wb,wr,wt : real);
  628. var sxr,syr,rxr,ryr : real;
  629. begin
  630.      Sx:=real_to_fixed((Dr-Dl)/(Wr-Wl));
  631.      Sy:=real_to_fixed((Dt-Db)/(Wt-Wb));
  632.      Rx:=real_to_fixed(Dl-Wl*(Dr-Dl)/(Wr-Wl));
  633.      Ry:=real_to_fixed(Db-Wb*(Dt-Db)/(Wt-Wb));
  634. end;
  635.  
  636. procedure Set_World_to_View(x,y,z : longint; azimuth_in, colatitude_in, roll_in : real);
  637. var s1, s2, c1, c2 : longint;
  638.     a,c,r : integer;
  639. begin
  640.      a:=-round(azimuth_in*10);
  641.      c:=-round(colatitude_in*10);
  642.      CosSin(a,c1,s1);
  643.      CosSin(c,c2,s2);
  644.      w2v.data(s1, fixedmul(-c1,s2),  fixedmul(-c1,c2), 0,
  645.                       c1, fixedmul(s1,s2),   fixedmul(s1,c2), 0,
  646.                       0,   c2,     -s2,    0,
  647.                       fixedmul(-x,s1)-fixedmul(y,c1),
  648.                       fixedmul(fixedmul(x,c1),s2)-fixedmul(fixedmul(y,s1),s2)-fixedmul(z,c2),
  649.                       fixedmul(fixedmul(x,c1),c2)-fixedmul(fixedmul(y,s1),c2)+fixedmul(z,s2),
  650.                       65536);
  651.      redraw_all:=true;
  652. end;
  653.  
  654. procedure Set_View(x,y,z, azimuth_in, colatitude_in, roll_in : real);
  655. var r, c : integer;
  656. begin
  657.      x_pos:=x;
  658.      y_pos:=y;
  659.      z_pos:=z;
  660.      viewpoint.x:=real_to_fixed(x);
  661.      viewpoint.y:=real_to_fixed(y);
  662.      viewpoint.z:=real_to_fixed(z);
  663.      azimuth:=azimuth_in;
  664.      colatitude:=colatitude_in;
  665.      Set_World_to_View(viewpoint.x,viewpoint.y,viewpoint.z,azimuth,colatitude,roll);
  666.      main_matrix:=w2v;
  667. end;
  668.  
  669. procedure Redraw_Scene;
  670. var temp_face : face_ptr;
  671. begin
  672.      if screen_page_offset=page0 then screen_page_offset:=page1 else screen_page_offset:=page0;
  673.      if not(timed_xforms_separately) then Apply_Timed_Transforms;
  674.      Transform_World_to_Screen;
  675.      ClGSc;
  676.      Clip_Stuff;
  677.      Sort_Face_List;
  678.  
  679.      temp_face:=first_list_face;
  680.      while temp_face<>nil do
  681.      begin
  682.           if temp_face^.seen then temp_face^.Fill;
  683.           temp_face:=temp_face^.next_order;
  684.      end;
  685.  
  686.      if any_textproc then this_textproc;
  687.      if cursor2D_mode then Draw_Cursor2D(cursor_x div 2, trunc((cursor_y * 1.2)+0.5));
  688.      Show_Page(screen_page_offset);
  689.  
  690.      redraw_all:=false;
  691. end;
  692.  
  693. procedure Transform_World_to_Screen;
  694. var this_ob : object3d_ptr;
  695. begin
  696.      this_ob:=first_object;
  697.      while this_ob<>nil do
  698.      begin
  699.           this_ob^.transform_to_screen;
  700.           this_ob:=this_ob^.next;
  701.      end;
  702. end;
  703.  
  704. procedure Apply_Timed_Transforms;
  705. var temp, temp2 : timed_xform_ptr;
  706.     t_now : real;
  707. begin
  708.      t_now:=graphics_time^;
  709.  
  710.      temp:=first_timed_Xform;
  711.      while temp<>nil do
  712.            if temp^.t_end<t_now then
  713.            begin
  714.                 temp2:=temp;
  715.                 temp:=temp^.next;
  716.                 graphics_time^:=temp2^.t_end;
  717.                 temp2^.Update;
  718.                 graphics_time^:=t_now;
  719.                 if temp2=nil then
  720.                 begin
  721.                      stop_graphics;
  722.                      writeln('Temp2 = nil');
  723.                      halt;
  724.                 end;
  725.                 dispose(temp2,Done);
  726.            end
  727.            else
  728.                temp:=temp^.next;
  729.  
  730.      temp:=first_timed_Xform;
  731.      while temp<>nil do
  732.      begin
  733.            if temp^.t_start<=t_now then
  734.            begin
  735.                 temp^.Update;
  736.               {  temp^.t_last:=t_now;  }{Removed to allow for error correction}
  737.            end;
  738.            temp:=temp^.next;
  739.      end;
  740. end;
  741.  
  742.  
  743. {------------------------------------------------}
  744. { Position and Direction procedures              }
  745. {------------------------------------------------}
  746.  
  747. procedure Store_Settings;
  748. begin
  749.      setviewpoint:=viewpoint;
  750.      setcolatitude:=colatitude;
  751.      setazimuth:=azimuth;
  752.      setspeed:=speed;
  753. end;
  754.  
  755. function KeyBoard_Check : boolean;
  756. var correctkey : boolean;
  757.     ch : char;
  758.     ca,sa,cc,sc : longint;
  759.     s : string[4];
  760. begin
  761.      if not(keypressed) then
  762.      begin
  763.           KeyBoard_Check:=false;
  764.           exit;
  765.      end;
  766.      ch:=ReadKey;
  767.      correctkey:=true;
  768.      case ch of
  769.           '2' : colatitude:=colatitude-5;
  770.           '8' : colatitude:=colatitude+5;
  771.           '6' : azimuth:=azimuth-5;
  772.           '4' : azimuth:=azimuth+5;
  773.           '+' : begin
  774.                      CosSin(round(-colatitude*10),cc,sc);
  775.                      CosSin(round(azimuth*10),ca,sa);
  776.                      viewpoint.x:=viewpoint.x-(FixedMul(speed,FixedMul(cc,ca)));
  777.                      viewpoint.y:=viewpoint.y-(FixedMul(speed,FixedMul(cc,sa)));
  778.                      viewpoint.z:=viewpoint.z-(FixedMul(speed,sc));
  779.                      x_pos:=viewpoint.x/65536;
  780.                      y_pos:=viewpoint.y/65536;
  781.                      z_pos:=viewpoint.z/65536;
  782.                 end;
  783.           '-' : begin
  784.                      CosSin(round(-colatitude*10),cc,sc);
  785.                      CosSin(round(azimuth*10),ca,sa);
  786.                      viewpoint.x:=viewpoint.x+(FixedMul(speed,FixedMul(cc,ca)));
  787.                      viewpoint.y:=viewpoint.y+(FixedMul(speed,FixedMul(cc,sa)));
  788.                      viewpoint.z:=viewpoint.z+(FixedMul(speed,sc));
  789.                      x_pos:=viewpoint.x/65536;
  790.                      y_pos:=viewpoint.y/65536;
  791.                      z_pos:=viewpoint.z/65536;
  792.                 end;
  793.           '*' : speed:=speed shl 2;
  794.           '/' : speed:=speed shr 2;
  795.           's' : begin
  796.                      azimuth:=setazimuth;
  797.                      colatitude:=setcolatitude;
  798.                      speed:=setspeed;
  799.                      viewpoint:=setviewpoint;
  800.                 end;
  801.           'q' : begin
  802.                      Stop_Graphics;
  803.                      writeln('Program terminated normally by user');
  804.                      Halt;
  805.                 end;
  806.           'p' : begin
  807.                      Str(picture_num,s);
  808.                      Send_Screen_to_PCX('pic'+s+'.pcx');
  809.                      inc(picture_num);
  810.                 end;
  811.           'f' : flip_cursor2D_mode;
  812.      else
  813.          correctkey:=this_keyproc(ch);
  814.      end;
  815.      if correctkey then
  816.      begin
  817.           Set_World_to_View(viewpoint.x,viewpoint.y,viewpoint.z,azimuth,colatitude,0);
  818.           main_matrix:=w2v;
  819.      end;
  820.      KeyBoard_Check:=correctkey;
  821. end;
  822.  
  823. function Mouse_Available : boolean;
  824. begin
  825.      if InitMouse=0 then Mouse_Available:=false else Mouse_Available:=true;
  826. end;
  827.  
  828.  
  829. function mouse_check : boolean;
  830. var junk, jx, jy, mouse_x, mouse_y : integer;
  831.     ca,sa,cc,sc, temp_speed : longint;
  832.     change : boolean;
  833. begin
  834.      if cursor2D_mode then mouse_check:=cursor2D_check
  835.      else
  836.      begin
  837.           change:=false;
  838.           ReadMouseCounter(mouse_x, mouse_y);
  839.           if (mouse_x<>0) or (mouse_y<>0) then
  840.           begin
  841.                if mousepress(0,junk,jx,jy)<>3 then
  842.                begin
  843.                     change:=true;
  844.                     azimuth:=azimuth-0.1*mouse_x;
  845.                     colatitude:=colatitude-0.1*mouse_y;
  846.                end
  847.                else
  848.                begin
  849.                     if (mouse_x<>0) then
  850.                     begin
  851.                          temp_speed:=(mouse_x*speed) div 100;
  852.                          change:=true;
  853.                          CosSin(round(azimuth*10),ca,sa);
  854.                          viewpoint.x:=viewpoint.x-(FixedMul(temp_speed,sa));
  855.                          viewpoint.y:=viewpoint.y+(FixedMul(temp_speed,ca));
  856.                          x_pos:=viewpoint.x/65536;
  857.                          y_pos:=viewpoint.y/65536;
  858.                          z_pos:=viewpoint.z/65536;
  859.                     end;
  860.                     if (mouse_y<>0) then
  861.                     begin
  862.                          temp_speed:=(mouse_y*speed) div 100;
  863.                          change:=true;
  864.                          CosSin(round(-(colatitude+90)*10),cc,sc);
  865.                          CosSin(round(azimuth*10),ca,sa);
  866.                          viewpoint.x:=viewpoint.x+(FixedMul(temp_speed,FixedMul(cc,ca)));
  867.                          viewpoint.y:=viewpoint.y+(FixedMul(temp_speed,FixedMul(cc,sa)));
  868.                          viewpoint.z:=viewpoint.z+(FixedMul(temp_speed,sc));
  869.                          x_pos:=viewpoint.x/65536;
  870.                          y_pos:=viewpoint.y/65536;
  871.                          z_pos:=viewpoint.z/65536;
  872.                     end;
  873.                end;
  874.           end;
  875.           if mousepress(0,junk,mouse_x,mouse_y)=1 then
  876.           begin
  877.                change:=true;
  878.                CosSin(round(-colatitude*10),cc,sc);
  879.                CosSin(round(azimuth*10),ca,sa);
  880.                viewpoint.x:=viewpoint.x-(FixedMul(speed,FixedMul(cc,ca)));
  881.                viewpoint.y:=viewpoint.y-(FixedMul(speed,FixedMul(cc,sa)));
  882.                viewpoint.z:=viewpoint.z-(FixedMul(speed,sc));
  883.                x_pos:=viewpoint.x/65536;
  884.                y_pos:=viewpoint.y/65536;
  885.                z_pos:=viewpoint.z/65536;
  886.           end
  887.           else
  888.           if mousepress(0,junk,mouse_x,mouse_y)=2 then
  889.           begin
  890.                change:=true;
  891.                CosSin(round(-colatitude*10),cc,sc);
  892.                CosSin(round(azimuth*10),ca,sa);
  893.                viewpoint.x:=viewpoint.x+(FixedMul(speed,FixedMul(cc,ca)));
  894.                viewpoint.y:=viewpoint.y+(FixedMul(speed,FixedMul(cc,sa)));
  895.                viewpoint.z:=viewpoint.z+(FixedMul(speed,sc));
  896.                x_pos:=viewpoint.x/65536;
  897.                y_pos:=viewpoint.y/65536;
  898.                z_pos:=viewpoint.z/65536;
  899.           end;
  900.           if change then
  901.           begin
  902.                Set_World_to_View(viewpoint.x,viewpoint.y,viewpoint.z,azimuth,colatitude,0);
  903.                main_matrix:=w2v;
  904.           end;
  905.           mouse_check:=change;
  906.      end;
  907.      if mousepress(0,junk,mouse_x,mouse_y)=4 then flip_cursor2D_mode;
  908. end;
  909.  
  910. procedure flip_cursor2D_mode;
  911. begin
  912.      cursor2D_mode:=not(cursor2D_mode);
  913.      if cursor2D_mode then
  914.      begin
  915.           setmouseposition(cursor_x, cursor_y);
  916.      end;
  917.      delay(200);
  918. end;
  919.  
  920. function cursor2D_check : boolean;
  921. var junk, mouse_x, mouse_y, xmin, xmax, ymin, ymax : integer;
  922.     last_z, this_z : longint;
  923.     temp_obj, selected_obj : object3d_ptr;
  924.     temp_face : face_ptr;
  925.     temp_str : string;
  926. begin
  927.      ReadMouseCounter(mouse_x, mouse_y);
  928.      junk:=mouseposition(cursor_x, cursor_y);
  929.      if mousepress(0,junk,mouse_x,mouse_y)=1 then
  930.      begin
  931.           mouse_x:=mouse_x div 2;
  932.           mouse_y:=trunc((mouse_y * 1.2)+0.5);
  933.           selected_obj:=nil;
  934.           temp_obj:=first_object;
  935.           last_z:=$7FFFFFFF;
  936.           while temp_obj<>nil do
  937.           begin
  938.                 if temp_obj^.shown then temp_obj^.Screen_limits(xmin,xmax,ymin,ymax);
  939.                 if temp_obj^.shown and ((xmax>=mouse_x) and (xmin<=mouse_x) and (ymin<=mouse_y) and (ymax>=mouse_y))
  940.                 then
  941.                 begin
  942.                      this_z:=$7FFFFFFF;
  943.                      temp_face:=temp_obj^.first_face;
  944.                      while temp_face<>nil do
  945.                      begin
  946.                           if Cursor_Inside_Face(temp_face,mouse_x,mouse_y) and temp_face^.seen
  947.                           and (temp_face^.long_sort_z<this_z) then this_z:=temp_face^.long_sort_z;
  948.                           temp_face:=temp_face^.next;
  949.                      end;
  950.                      if (selected_obj=nil) or ((selected_obj<>nil) and (this_z<last_z)) then
  951.                      begin
  952.                           selected_obj:=temp_obj;
  953.                           last_z:=this_z;
  954.                      end;
  955.                 end;
  956.                 temp_obj:=temp_obj^.next;
  957.           end;
  958.           if selected_obj<>nil then
  959.           begin
  960.                selected_obj^.select_procedure(selected_obj);
  961.                delay(200);
  962.           end;
  963.      end;
  964. end;
  965.  
  966. function Cursor_Inside_Face(this_face : face_ptr; xpos, ypos : integer) : boolean; external;
  967.  
  968. procedure User_KeyCheck_Proc(new_keyproc : keyproc);
  969. begin
  970.      this_keyproc:=new_keyproc;
  971. end;
  972.  
  973.  
  974. {-----------------------------------------------}
  975. { Shading procedures                            }
  976. {-----------------------------------------------}
  977.  
  978. procedure Set_Ambient_Intensity(inten : real);
  979. begin
  980.      if inten<=0 then Ambient_Intensity:=0
  981.      else if inten>=1 then Ambient_Intensity:=65536
  982.      else Ambient_Intensity:=real_to_fixed(inten);
  983. end;
  984.  
  985. procedure Set_Light(inten, dx, dy, dz : real);
  986. var length : real;
  987. begin
  988.      if inten<=0 then Light_Intensity:=0
  989.      else if inten>=1 then Light_Intensity:=65536
  990.      else Light_Intensity:=real_to_fixed(inten);
  991.      length:=sqrt(sqr(dx)+sqr(dy)+sqr(dz));
  992.      light.x:=real_to_fixed(-dx/length);
  993.      light.y:=real_to_fixed(-dy/length);
  994.      light.z:=real_to_fixed(-dz/length);
  995. end;
  996.  
  997. procedure Set_Background_Colour(color_in : byte; inten : real);
  998. var temp_c, c : byte;
  999. begin
  1000.      if (color_in>=0) and (color_in<=15) and (inten>=0) and (inten<=1) then
  1001.         temp_c:=color_in*16+trunc(inten*15+0.5);
  1002.      background_colour:=0;
  1003.      for c:=1 to 4 do
  1004.      begin
  1005.           background_colour:=background_colour shl 8;
  1006.           background_colour:=background_colour+temp_c;
  1007.      end;
  1008. end;
  1009.  
  1010.  
  1011. {------------------------------------------------}
  1012. { Palette procedures                             }
  1013. {------------------------------------------------}
  1014.  
  1015. type pal_ptr=^mypalette;
  1016.      mypalette=array[0..15,0..15,0..2] of byte;
  1017.  
  1018. procedure Set_Palette;
  1019. var start : pal_ptr;
  1020.     r,g,b : real;
  1021.     c,n,col : integer;
  1022.     reg : registers;
  1023. begin
  1024.      new(start);
  1025.      col:=0;
  1026.      r:=0; g:=0; b:=63/15;
  1027.      for c:=0 to 15 do
  1028.      begin
  1029.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1030.      end;
  1031.      inc(col);
  1032.      r:=0; g:=63/15; b:=0;
  1033.      for c:=0 to 15 do
  1034.      begin
  1035.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1036.      end;
  1037.      inc(col);
  1038.      r:=0; g:=63/15; b:=63/15;
  1039.      for c:=0 to 15 do
  1040.      begin
  1041.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1042.      end;
  1043.      inc(col);
  1044.      r:=63/15; g:=0; b:=0;
  1045.      for c:=0 to 15 do
  1046.      begin
  1047.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1048.      end;
  1049.      inc(col);
  1050.      r:=63/15; g:=0; b:=63/15;
  1051.      for c:=0 to 15 do
  1052.      begin
  1053.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1054.      end;
  1055.      inc(col);
  1056.      r:=63/15; g:=63/15; b:=0;
  1057.      for c:=0 to 15 do
  1058.      begin
  1059.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1060.      end;
  1061.      inc(col);
  1062.      r:=63/15; g:=63/15; b:=63/15;
  1063.      for c:=0 to 15 do
  1064.      begin
  1065.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1066.      end;
  1067.      inc(col);
  1068.      r:=0; g:=63/15; b:=31/15;
  1069.      for c:=0 to 15 do
  1070.      begin
  1071.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1072.      end;
  1073.      inc(col);
  1074.      r:=0; g:=31/15; b:=63/15;
  1075.      for c:=0 to 15 do
  1076.      begin
  1077.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1078.      end;
  1079.      inc(col);
  1080.      r:=31/15; g:=0; b:=63/15;
  1081.      for c:=0 to 15 do
  1082.      begin
  1083.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1084.      end;
  1085.      inc(col);
  1086.      r:=63/15; g:=0; b:=31/15;
  1087.      for c:=0 to 15 do
  1088.      begin
  1089.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1090.      end;
  1091.      inc(col);
  1092.      r:=63/15; g:=31/15; b:=0;
  1093.      for c:=0 to 15 do
  1094.      begin
  1095.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1096.      end;
  1097.      inc(col);
  1098.      r:=31/15; g:=63/15; b:=0;
  1099.      for c:=0 to 15 do
  1100.      begin
  1101.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1102.      end;
  1103.      inc(col);
  1104.      r:=31/15; g:=31/15; b:=63/15;
  1105.      for c:=0 to 15 do
  1106.      begin
  1107.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1108.      end;
  1109.      inc(col);
  1110.      r:=31/15; g:=63/15; b:=31/15;
  1111.      for c:=0 to 15 do
  1112.      begin
  1113.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1114.      end;
  1115.      inc(col);
  1116.      r:=63/15; g:=31/15; b:=31/15;
  1117.      for c:=0 to 15 do
  1118.      begin
  1119.           start^[col,c,0]:=round(r*c); start^[col,c,1]:=round(g*c); start^[col,c,2]:=round(b*c);
  1120.      end;
  1121.      reg.es:=seg(start^);
  1122.      reg.dx:=ofs(start^);
  1123.      reg.bx:=0;
  1124.      reg.cx:=256;
  1125.      reg.ax:=$1012;
  1126.      Intr($10,reg);
  1127.      dispose(start);
  1128. end;
  1129.  
  1130. type one_color_ptr=^one_color;
  1131.      one_color=array[0..15,0..2] of byte;
  1132.  
  1133. procedure New_Color(col_no: byte; r, g, b : real);
  1134. var my_col : one_color_ptr;
  1135.     dr, dg, db : real;
  1136.     c : integer;
  1137.     reg : registers;
  1138. begin
  1139.      if (col_no>15) or (col_no<0) then exit;
  1140.      if (r>1) or (r<0) or (b>1) or (b<0) or (g>1) or (g<0) then exit;
  1141.      new(my_col);
  1142.      dr:=63*r/15; dg:=63*g/15; db:=63*b/15;
  1143.      col_no:=col_no*16;
  1144.      for c:=0 to 15 do
  1145.      begin
  1146.           my_col^[c,0]:=round(c*dr); my_col^[c,1]:=round(c*dg); my_col^[c,2]:=round(c*db);
  1147.      end;
  1148.      reg.es:=seg(my_col^);
  1149.      reg.dx:=ofs(my_col^);
  1150.      reg.bx:=col_no;
  1151.      reg.cx:=16;
  1152.      reg.ax:=$1012;
  1153.      Intr($10,reg);
  1154.      dispose(my_col);
  1155. end;
  1156.  
  1157. procedure Save_Colors(fname : titletype);
  1158. var f : text;
  1159.     c : integer;
  1160.     col : byte;
  1161.     reg : registers;
  1162. begin
  1163.      assign(f,fname);
  1164.      rewrite(f);
  1165.      for c:=0 to 15 do
  1166.      begin
  1167.           col:=c*16+15;
  1168.           reg.bx:=col;
  1169.           reg.ax:=$1015;
  1170.           Intr($10,reg);
  1171.           writeln(f,reg.dh/63,' ',reg.ch/63,' ',reg.cl/63);
  1172.      end;
  1173.      close(f);
  1174. end;
  1175.  
  1176. procedure Load_Colors(fname : titletype);
  1177. var f : text;
  1178.     r,g,b : real;
  1179.     c : integer;
  1180. begin
  1181.      assign(f,fname);
  1182.      reset(f);
  1183.      for c:=0 to 15 do
  1184.      begin
  1185.           readln(f,r,g,b);
  1186.           New_Color(c,r,g,b);
  1187.      end;
  1188.      close(f);
  1189. end;
  1190.  
  1191. procedure Send_Screen_to_PCX(fname : titletype);
  1192. var temp_header : pcx_header;
  1193.     pcxf : file;
  1194.     reg : registers;
  1195.     scan_line : array[0..319] of byte;
  1196.     row, plane, multiple, count, value : integer;
  1197. begin
  1198.      assign(pcxf, fname);
  1199.      rewrite(pcxf,1);
  1200.      with temp_header do
  1201.      begin
  1202.           code:=10;
  1203.           version:=5;
  1204.           mode:=1;
  1205.           bits_p_pixel:=8;
  1206.           x1:=0;
  1207.           x2:=319;
  1208.           y1:=0;
  1209.           y2:=239;
  1210.           Hres:=320;
  1211.           Vres:=240;
  1212.           junk:=0;
  1213.           Nplanes:=1;
  1214.           bytes_p_line:=320;
  1215.           palette_type:=1;
  1216.           for count:=1 to 16 do
  1217.           for multiple:=1 to 3 do palette[count,multiple]:=0;
  1218.           for multiple:=1 to 58 do padding[multiple]:=0;
  1219.           padding[2]:=4;
  1220.           padding[4]:=3;
  1221.      end;
  1222.  
  1223.      BlockWrite(pcxf,temp_header,SizeOf(temp_header));
  1224.  
  1225.      for row:=0 to 239 do
  1226.      begin
  1227.           for plane:=0 to 3 do
  1228.           begin
  1229.                PortW[$03ce]:=(plane shl 8)+$04;
  1230.                for count:=0 to 79 do
  1231.                    scan_line[(count*4)+plane]:=Mem[$a000:(screen_page_offset+row*80+count)];
  1232.           end;
  1233.           multiple:=1;
  1234.           value:=scan_line[0];
  1235.           count:=1;
  1236.           repeat
  1237.                 while ((count<320) and (scan_line[count]=value)) and (multiple<63) do
  1238.                 begin
  1239.                      inc(count);
  1240.                      inc(multiple);
  1241.                 end;
  1242.                 if (multiple=1) and ((value and 192)=0) then BlockWrite(pcxf,value,1)
  1243.                 else
  1244.                 begin
  1245.                      multiple:=multiple or 192;
  1246.                      BlockWrite(pcxf,multiple,1);
  1247.                      BlockWrite(pcxf,value,1);
  1248.                 end;
  1249.                 value:=scan_line[count];
  1250.                 multiple:=1;
  1251.                 inc(count);
  1252.           until count=321;
  1253.      end;
  1254.  
  1255.      value:=$0c;
  1256.      BlockWrite(pcxf,value,1);
  1257.      for count:=0 to 255 do
  1258.      begin
  1259.           reg.bx:=count;
  1260.           reg.ax:=$1015;
  1261.           Intr($10,reg);
  1262.           value:=reg.dh shl 2;
  1263.           BlockWrite(pcxf,value,1);
  1264.           value:=reg.ch shl 2;
  1265.           BlockWrite(pcxf,value,1);
  1266.           value:=reg.cl shl 2;
  1267.           BlockWrite(pcxf,value,1);
  1268.      end;
  1269.      close(pcxf);
  1270. end;
  1271.  
  1272. procedure Fill_Face(this_face : face_ptr); external;
  1273. procedure Fill_Face_Point(this_face : face_ptr); external;
  1274. procedure Fill_Face_Line(this_face : face_ptr); external;
  1275.  
  1276. procedure ClGSc; external;
  1277. procedure Show_Page(page_offset : integer); external;
  1278. procedure Stop_Graphics; external;
  1279. procedure Start_Graphics; external;
  1280. procedure Start_CyberMaxx_Graphics; external;
  1281. procedure Sort_Face_List; external;
  1282. procedure Clip_Stuff; external;
  1283. procedure Text_At(x,y : integer; text : string; colour : byte); external;
  1284. procedure Background_At(x,y : integer; text : string; colour : byte); external;
  1285.  
  1286. procedure Write_Text_At(x,y : integer; text : string; tcolour : byte; tintensity : real; bcolour : byte; bintensity : real);
  1287. begin
  1288.      if (x>39) or (y<0) or (y>29) then exit;
  1289.      if x<0 then
  1290.      begin
  1291.           if (length(text)+x)<0 then exit else
  1292.           begin
  1293.                text:=Copy(text,-x,50);
  1294.                x:=0;
  1295.           end;
  1296.      end;
  1297.      if (bcolour>=0) and (bcolour<=15) and (bintensity>=0) and (bintensity<=1) then
  1298.         Background_At(x,y,text,bcolour*16+trunc(bintensity*15+0.5));
  1299.      if (tcolour>=0) and (tcolour<=15) and (tintensity>=0) and (tintensity<=1) then
  1300.         Text_At(x,y,text,tcolour*16+trunc(tintensity*15+0.5));
  1301. end;
  1302.  
  1303. procedure Set_Text_Proc(temp_textproc : textproc);
  1304. begin
  1305.      any_textproc:=true;
  1306.      this_textproc:=temp_textproc;
  1307. end;
  1308.  
  1309. procedure Set_Default_Cursor2D;
  1310. begin
  1311.      cursor_x_offset:=4;
  1312.      cursor_y_offset:=4;
  1313. {     default_cursor_icon[1]:=11;
  1314.      default_cursor_icon[2]:=$FFC0;
  1315.      default_cursor_icon[3]:=$FF00;
  1316.      default_cursor_icon[4]:=$FE00;
  1317.      default_cursor_icon[5]:=$FC00;
  1318.      default_cursor_icon[6]:=$FC00;
  1319.      default_cursor_icon[7]:=$FE00;
  1320.      default_cursor_icon[8]:=$E700;
  1321.      default_cursor_icon[9]:=$C380;
  1322.      default_cursor_icon[10]:=$81C0;
  1323.      default_cursor_icon[11]:=$80E0;
  1324.      default_cursor_icon[12]:=$0040;
  1325. }    default_cursor_icon[1]:=9;
  1326.      default_cursor_icon[2]:=$0800;
  1327.      default_cursor_icon[3]:=$0800;
  1328.      default_cursor_icon[4]:=$0800;
  1329.      default_cursor_icon[5]:=$0800;
  1330.      default_cursor_icon[6]:=$F780;
  1331.      default_cursor_icon[7]:=$0800;
  1332.      default_cursor_icon[8]:=$0800;
  1333.      default_cursor_icon[9]:=$0800;
  1334.      default_cursor_icon[10]:=$0800;
  1335.      cursor_icon:=@default_cursor_icon;
  1336.      cursor2d_colour(6,1);
  1337. end;
  1338.  
  1339. procedure Cursor2D_Colour(number : byte; intens : real);
  1340. begin
  1341.      if (number>=0) and (number<=15) and (intens>=0) and (intens<=1) then
  1342.         Cursor_colour:=number*16+trunc(intens*15+0.5);
  1343. end;
  1344.  
  1345. procedure Draw_Cursor2D(xpos, ypos : integer); external;
  1346.  
  1347. function Now : real;
  1348. begin
  1349.      Now:=graphics_time^;
  1350. end;
  1351.  
  1352. function NulKeyProc(key : char) : boolean;
  1353. begin
  1354.      NulKeyProc:=false;
  1355. end;
  1356.  
  1357. procedure NulSelectProc(this_object : object3d_ptr);
  1358. begin
  1359. end;
  1360.  
  1361. function Load_Picture(filename : string) : pointer;
  1362. var pcxf : file;
  1363.     size, tw, th : integer;
  1364.     width, height, mybyte, x, y : byte;
  1365.     count : integer;
  1366.     temp : pointer;
  1367.     temp_seg, temp_ofs : word;
  1368.     temp_header : pcx_header;
  1369. begin
  1370.      assign(pcxf,filename);
  1371.      reset(pcxf,1);
  1372.      BlockRead(pcxf,temp_header,sizeof(pcx_header));
  1373.      writeln('PCX Name = ',filename);
  1374.      with temp_header do
  1375.      begin
  1376.           writeln('Code = ',code);
  1377.           writeln('Version = ',version);
  1378.           writeln('Mode = ',mode);
  1379.           writeln('Bits per pixel = ',bits_p_pixel);
  1380.           writeln('Screen coordinates = ',x1,',',y1,' to ',x2,',',y2);
  1381.           writeln('Screen_Res = ',Hres,',',vres);
  1382.           writeln('Planes = ',Nplanes);
  1383.           writeln('Bytes p line = ',bytes_p_line);
  1384.           writeln('Palette_type = ',palette_type);
  1385.           writeln;
  1386.      end;
  1387.      if (temp_header.version<>5) and (temp_header.bits_p_pixel<>8) then
  1388.      begin
  1389.           writeln('Error! - ',filename,' is not a 256 colour PCX file');
  1390.           Load_Picture:=nil;
  1391.           exit;
  1392.      end;
  1393.      width:=temp_header.bytes_p_line;
  1394.      writeln(temp_header.bytes_p_line);
  1395.      writeln('Width = ',width);
  1396.      height:=temp_header.y2-temp_header.y1+1;
  1397.      writeln('Height = ',height);
  1398.      if width>255 then
  1399.      begin
  1400.           writeln('Error! - ',filename,' has a width >255');
  1401.           Load_Picture:=nil;
  1402.           exit;
  1403.      end;
  1404.      if height>255 then
  1405.      begin
  1406.           writeln('Error! - ',filename,' has a height >255');
  1407.           Load_Picture:=nil;
  1408.           exit;
  1409.      end;
  1410.      size:=word(width)*word(height)+2;
  1411.      writeln('Freeing ',size,' bytes');
  1412.      GetMem(temp,size);
  1413.      temp_seg:=Seg(temp^);
  1414.      temp_ofs:=Ofs(temp^);
  1415.      Mem[temp_seg:temp_ofs]:=width;
  1416.      Mem[temp_seg:temp_ofs+1]:=height;
  1417.      size:=word(width)*word(height);
  1418.      temp_ofs:=temp_ofs+2;
  1419.      y:=0;
  1420.      repeat
  1421.            x:=0;
  1422.            repeat
  1423.                  BlockRead(pcxf,mybyte,1);
  1424.                  if (mybyte and 192)=192 then
  1425.                  begin
  1426.                       count:=(mybyte and 63);
  1427.                       BlockRead(pcxf,mybyte,1);
  1428.                       while count>0 do
  1429.                       begin
  1430.                            Mem[temp_seg:temp_ofs]:=mybyte;
  1431.                            inc(temp_ofs);
  1432.                            dec(count);
  1433.                            inc(x);
  1434.                       end;
  1435.                  end
  1436.                  else
  1437.                  begin
  1438.                       Mem[temp_seg:temp_ofs]:=mybyte;
  1439.                       inc(temp_ofs);
  1440.                       inc(x);
  1441.                  end;
  1442.            until x>=(temp_header.bytes_p_line);
  1443.            temp_ofs:=temp_ofs-(x-width);
  1444.            inc(y);
  1445.      until y=height;
  1446.      Load_Picture:=temp;
  1447. end;
  1448.  
  1449.  
  1450. function Number_of_Objects : integer;
  1451. var total : integer;
  1452.     temp_object : object3d_ptr;
  1453. begin
  1454.      total:=0;
  1455.      temp_object:=first_object;
  1456.      while temp_object<>nil do
  1457.      begin
  1458.           inc(total);
  1459.           temp_object:=temp_object^.next;
  1460.      end;
  1461.      Number_of_Objects:=total;
  1462. end;
  1463.  
  1464. function Number_of_Faces : integer;
  1465. var total : integer;
  1466.     temp_object : object3d_ptr;
  1467.     temp_face : face_ptr;
  1468. begin
  1469.      total:=0;
  1470.      temp_object:=first_object;
  1471.      while temp_object<>nil do
  1472.      begin
  1473.           temp_face:=temp_object^.first_face;
  1474.           while temp_face<>nil do
  1475.           begin
  1476.                inc(total);
  1477.                temp_face:=temp_face^.next;
  1478.           end;
  1479.           temp_object:=temp_object^.next;
  1480.      end;
  1481.      Number_of_Faces:=total;
  1482. end;
  1483.  
  1484.  
  1485. function Number_of_Vertices : integer;
  1486. var total : integer;
  1487.     temp_object : object3d_ptr;
  1488.     temp_vertex : vertex_ptr;
  1489. begin
  1490.      total:=0;
  1491.      temp_object:=first_object;
  1492.      while temp_object<>nil do
  1493.      begin
  1494.           temp_vertex:=temp_object^.first_vertex;
  1495.           while temp_vertex<>nil do
  1496.           begin
  1497.                inc(total);
  1498.                temp_vertex:=temp_vertex^.next;
  1499.           end;
  1500.           temp_object:=temp_object^.next;
  1501.      end;
  1502.      Number_of_Vertices:=total;
  1503. end;