home *** CD-ROM | disk | FTP | other *** search
/ Teach Yourself Game Programming in 21 Days / TYGAMES_R.ISO / source / day_11 / mtask.c < prev    next >
Text File  |  1994-07-05  |  18KB  |  708 lines

  1.  
  2. // I N C L U D E S ////////////////////////////////////////////////////////////
  3.  
  4. #include <io.h>
  5. #include <conio.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include <fcntl.h>
  11. #include <memory.h>
  12. #include <malloc.h>
  13. #include <math.h>
  14. #include <string.h>
  15.  
  16. #include "graph3.h"  // include graphics our stuff
  17. #include "graph4.h"
  18. #include "graph5.h"
  19. #include "graph6.h"
  20.  
  21. // D E F I N E S //////////////////////////////////////////////////////////////
  22.  
  23. // timer defines
  24.  
  25. #define CONTROL_8253  0x43  // the 8253's control register
  26. #define CONTROL_WORD  0x3C  // the control word to set mode 2,binary least/most
  27. #define COUNTER_0     0x40  // counter 0
  28. #define COUNTER_1     0x41  // counter 1
  29. #define COUNTER_2     0x42  // counter 2
  30.  
  31. #define TIMER_60HZ    0x4DAE // 60 hz
  32. #define TIMER_50HZ    0x5D37 // 50 hz
  33. #define TIMER_40HZ    0x7486 // 40 hz
  34. #define TIMER_30HZ    0x965C // 30 hz
  35. #define TIMER_20HZ    0xE90B // 20 hz
  36. #define TIMER_18HZ    0xFFFF // 18.2 hz (the standard count and the slowest possible)
  37.  
  38. // interrupt table defines
  39.  
  40. #define TIME_KEEPER_INT     0x1C    // the time keeper interrupt
  41.  
  42. // multi-tasking kernal defines
  43.  
  44. #define MAX_TASKS      16  // this should be enough to turn your brains to mush
  45. #define TASK_INACTIVE  0   // this is an inactive task
  46. #define TASK_ACTIVE    1   // this is an active task
  47.  
  48.  
  49. // defines for demo tasks
  50.  
  51. #define NUM_ATOMS 30
  52. #define NUM_STARS 50
  53.  
  54. // M A C R O S ///////////////////////////////////////////////////////////////
  55.  
  56. #define LOW_BYTE(n) (n & 0x00ff)       // extracts the low-byte of a word
  57. #define HI_BYTE(n)  ((n>>8) & 0x00ff)  // extracts the hi-byte of a word
  58.  
  59. // S T U C T U R E S /////////////////////////////////////////////////////////
  60.  
  61. // this is a single task structure
  62.  
  63. typedef struct task_typ
  64.         {
  65.  
  66.         int id;             // the id number for this task
  67.         int state;          // the state of this task
  68.         void (far *task)(); // the function pointer to the task itself
  69.  
  70.         } task, *task_ptr;
  71.  
  72. // structures for demo tasks
  73.  
  74. typedef struct particle_typ
  75.         {
  76.         int x,y;              // position of particle
  77.         int xv,yv;            // velocity of particle
  78.         unsigned char color;  // color of particle
  79.         } particle, *particle_ptr;
  80.  
  81. // P R O T O T Y P E S ///////////////////////////////////////////////////////
  82.  
  83. void Change_Timer(unsigned int new_count);
  84.  
  85. // multi-tasking stuff
  86.  
  87. void Initialize_Kernal(void);
  88.  
  89. void Start_Kernal(void);
  90.  
  91. void Stop_Kernal(void);
  92.  
  93. int Add_Task(void (far *function)());
  94.  
  95. int Delete_Task(int id);
  96.  
  97. void _interrupt far Multi_Kernal(void);
  98.  
  99. // G L O B A L S /////////////////////////////////////////////////////////////
  100.  
  101. void (_interrupt far *Old_Time_Isr)();  // used to hold old interrupt vector
  102.  
  103. // multi-tasking stuff
  104.  
  105. task tasks[MAX_TASKS];             // this is the task list for the system
  106.  
  107. int num_tasks = 0;                 // tracks number of active tasks
  108.  
  109. // globals for demo tasks
  110.  
  111. particle atoms[NUM_ATOMS]; // the balls
  112.  
  113. particle starfield[NUM_STARS]; // the star field
  114.  
  115. int star_id, mirror_id, ball_id; // used to hold id's so that tasks can be
  116.                                  // terminated later
  117.  
  118. // F U N C T I O N S //////////////////////////////////////////////////////////
  119.  
  120. void Initialize_Kernal(void)
  121. {
  122.  
  123. // this function will set up the task list and prepare for it to be populated
  124.  
  125. int index; // loop variable
  126.  
  127. for (index=0; index<MAX_TASKS; index++)
  128.     {
  129.     // set id to current location in list
  130.  
  131.     tasks[index].id = index;
  132.  
  133.     // set to inactive
  134.  
  135.     tasks[index].state = TASK_INACTIVE;
  136.  
  137.     // set function pointer to NULL;
  138.  
  139.     tasks[index].task = NULL;
  140.  
  141.     } // end for index
  142.  
  143. } // end Initialize_Kernal
  144.  
  145. ///////////////////////////////////////////////////////////////////////////////
  146.  
  147. void Start_Kernal(void)
  148. {
  149. // install our time keeper ISR while saving old one
  150.  
  151. Old_Time_Isr = _dos_getvect(TIME_KEEPER_INT);
  152.  
  153. _dos_setvect(TIME_KEEPER_INT, Multi_Kernal);
  154.  
  155. } // end Start_Kernal
  156.  
  157. ///////////////////////////////////////////////////////////////////////////////
  158.  
  159. void Stop_Kernal(void)
  160. {
  161.  
  162. // replace old time keeper ISR
  163.  
  164. _dos_setvect(TIME_KEEPER_INT, Old_Time_Isr);
  165.  
  166. } // end Stop_Kernal
  167.  
  168. //////////////////////////////////////////////////////////////////////////////
  169.  
  170. int Add_Task(void (far *function)())
  171. {
  172. // this function will add the task to the task list and return it's id number
  173. // which can be used to delete it.  If the function returns -1 then the
  174. // task list is full and no more tasks can be added
  175.  
  176. int index;
  177.  
  178. for (index=0; index<MAX_TASKS; index++)
  179.     {
  180.     // try and find an inactive task
  181.  
  182.     if (tasks[index].state == TASK_INACTIVE)
  183.        {
  184.        // load new task into this position
  185.  
  186.        tasks[index].state = TASK_ACTIVE;
  187.        tasks[index].id    = index;
  188.        tasks[index].task  = function;  // assign function pointer
  189.  
  190.        // adjust global task monitor
  191.  
  192.        num_tasks++;
  193.  
  194.        // return id to caller
  195.  
  196.        return(tasks[index].id);
  197.  
  198.        } // end if found an inactive task
  199.  
  200.     } // end for index
  201.  
  202. // if we got this far then there are no free spots...bummer
  203.  
  204. return(-1);
  205.  
  206. } // end Add_Task
  207.  
  208. ///////////////////////////////////////////////////////////////////////////////
  209.  
  210. int Delete_Task(int id)
  211. {
  212. // this function will try to delete a task from the task list, if the function
  213. // is successful, it will return 1 else it will return 0.
  214.  
  215. if (tasks[id].state == TASK_ACTIVE)
  216.    {
  217.    // kill task and return success
  218.  
  219.    tasks[id].task   = NULL;
  220.    tasks[id].state  = TASK_INACTIVE;
  221.  
  222.    // decrement number of active tasks
  223.  
  224.    num_tasks--;
  225.  
  226.    return(1);
  227.  
  228.    } // end if task can be deleted
  229. else
  230.    {
  231.    // couldn't delete task
  232.    return(0);
  233.  
  234.    } // end task already dead
  235.  
  236. } // end Delete_Task
  237.  
  238. ///////////////////////////////////////////////////////////////////////////////
  239.  
  240. void _interrupt far Multi_Kernal(void)
  241. {
  242.  
  243. // this function will call all of the task in a round robin manner such that
  244. // only one task will be called per interrupt. note: ther must be at least
  245. // one active task in the task list
  246.  
  247. static int current_task=0;  // current_task to be executed by kernal
  248.  
  249. // test if there are any tasks at all
  250.  
  251. if (num_tasks>0)
  252. {
  253.  
  254. // find an active task
  255.  
  256. while(tasks[current_task].state!=TASK_ACTIVE)
  257.      {
  258.      // move to next task and round robin if at end of task list
  259.  
  260.      if (++current_task>=MAX_TASKS)
  261.         current_task=0;
  262.  
  263.      } // end search for active task
  264.  
  265. // at this point we have an active task so call it
  266.  
  267. tasks[current_task].task(); // weird looking huh!
  268.  
  269. // now we need to move to the next possible task
  270.  
  271. if (++current_task>=MAX_TASKS)
  272.    current_task=0;
  273.  
  274. } // end if there are any tasks
  275.  
  276. // chain to old ISR (play nice with the other children)
  277.  
  278. Old_Time_Isr();
  279.  
  280. } // end Multi_Kernal
  281.  
  282. ///////////////////////////////////////////////////////////////////////////////
  283.  
  284. void Change_Timer(unsigned int new_count)
  285. {
  286.  
  287. // send the control word, mode 2, binary, least/most load sequence
  288.  
  289. _outp(CONTROL_8253, CONTROL_WORD);
  290.  
  291. // now write the least significant byte to the counter register
  292.  
  293. _outp(COUNTER_0,LOW_BYTE(new_count));
  294.  
  295. // and now the the most significant byte
  296.  
  297. _outp(COUNTER_0,HI_BYTE(new_count));
  298.  
  299. } // end Change_Timer
  300.  
  301.  
  302.  
  303. // D E M O  T A S K S /////////////////////////////////////////////////////////
  304.  
  305. void Rectangle(int xo,int yo,int x1,int y1,unsigned char color)
  306. {
  307.  
  308. // draw a rectangle using the Bline function
  309.  
  310. Bline(xo,yo,x1,yo,color);
  311. Bline(x1,yo,x1,y1,color);
  312. Bline(x1,y1,xo,y1,color);
  313. Bline(xo,y1,xo,yo,color);
  314.  
  315.  
  316. } // end Rectangle
  317.  
  318. ///////////////////////////////////////////////////////////////////////////////
  319.  
  320. void Stars(void)
  321. {
  322. // this function will animate a star field
  323.  
  324. int index; // loop variable
  325.  
  326. static int initialized=0;  // this is the local static state variable
  327.  
  328. if (!initialized)
  329.    {
  330.  
  331.    // initialize all the stars
  332.  
  333.    for (index=0; index<NUM_STARS; index++)
  334.        {
  335.        // initialize each star to a velocity, position and color
  336.  
  337.        starfield[index].x     = 226 + rand()%70;
  338.        starfield[index].y     = 26  + rand()%70;
  339.  
  340.        // decide what star plane the star is in
  341.  
  342.        switch(rand()%3)
  343.              {
  344.              case 0: // plane 1- the farthest star plane
  345.                   {
  346.                   // set velocity and color
  347.  
  348.                   starfield[index].xv = 2;
  349.                   starfield[index].color = 8;
  350.  
  351.                   } break;
  352.  
  353.              case 1: // plane 2-The medium distance star plane
  354.                   {
  355.  
  356.                   starfield[index].xv = 4;
  357.                   starfield[index].color = 7;
  358.  
  359.                   } break;
  360.  
  361.              case 2: // plane 3-The nearest star plane
  362.                   {
  363.  
  364.                   starfield[index].xv = 6;
  365.                   starfield[index].color = 15;
  366.  
  367.                   } break;
  368.  
  369.              } // end switch
  370.  
  371.        } // end for index
  372.  
  373.  
  374.    // draw working window
  375.  
  376.    Rectangle(225,25,225+75,25+75,9);
  377.  
  378.    // set variable to move to next processing state
  379.  
  380.    initialized=1;
  381.  
  382.    } // end if being initialized
  383. else
  384.    { // must be nth time in, so do the usual
  385.  
  386.  
  387.    // process each star
  388.  
  389.    for (index=0; index<NUM_STARS; index++)
  390.        {
  391.        // E R A S E ///////////////////////////////////////////////////////////
  392.  
  393.        Plot_Pixel_Fast(starfield[index].x,starfield[index].y,0);
  394.  
  395.        // M O V E /////////////////////////////////////////////////////////////
  396.  
  397.        if ( (starfield[index].x+=starfield[index].xv)>=225+75 )
  398.           starfield[index].x = 226;
  399.  
  400.        // D R A W /////////////////////////////////////////////////////////////
  401.  
  402.        Plot_Pixel_Fast(starfield[index].x,starfield[index].y,
  403.                        starfield[index].color);
  404.  
  405.        } // end for index
  406.  
  407.    } // end else
  408.  
  409. } // end Stars
  410.  
  411. ///////////////////////////////////////////////////////////////////////////////
  412.  
  413. void Mirror(void)
  414. {
  415. // this function will draw a mirrored pixel image
  416.  
  417. int x,y;
  418.  
  419. unsigned char color;
  420.  
  421. static int initialized=0;  // this is the local static state variable
  422.  
  423. if (!initialized)
  424.    {
  425.  
  426.    // draw working window
  427.  
  428.    Rectangle(125,25,125+75,25+75,9);
  429.  
  430.    // set variable to move to next processing state
  431.  
  432.    initialized=1;
  433.  
  434.    } // end if not intialized
  435. else
  436.    {
  437.  
  438.    // D R A W /////////////////////////////////////////////////////////////////
  439.  
  440.    // draw a mirrored image
  441.  
  442.    x      = rand()%38;
  443.    y      = rand()%38;
  444.    color  = (unsigned char)(rand()%256);
  445.  
  446.    Plot_Pixel_Fast(x+125,y+25,color);
  447.    Plot_Pixel_Fast((75-1)-x+125,y+25,color);
  448.    Plot_Pixel_Fast(x+125,(75-1)-y+25,color);
  449.    Plot_Pixel_Fast((75-1)-x+125,(75-1)-y+25,color);
  450.  
  451.    } // end else
  452.  
  453. } // end Mirror
  454.  
  455. ///////////////////////////////////////////////////////////////////////////////
  456.  
  457. void Balls(void)
  458. {
  459. // this function will bounce a collection of balls around
  460.  
  461. int index; // used for looping
  462.  
  463. static int initialized=0;  // this is the local static state variable
  464.  
  465. if (!initialized)
  466.    {
  467.  
  468.    // initialize all structures
  469.  
  470.    for (index=0; index<NUM_ATOMS; index++)
  471.        {
  472.        // select a random position and trajectory for each atom
  473.        // their background
  474.  
  475.        atoms[index].x     = 26 + rand()%70;
  476.        atoms[index].y     = 26 + rand()%70;
  477.  
  478.        atoms[index].xv    = -2 + rand()%4;
  479.        atoms[index].yv    = -2 + rand()%4;
  480.  
  481.        } // end for index
  482.  
  483.    // draw working window
  484.  
  485.    Rectangle(25,25,25+75,25+75,9);
  486.  
  487.    // set initialized flag so process can switch states
  488.  
  489.    initialized = 1;
  490.  
  491.    } // end if need to initialize
  492. else
  493.    { // do normal processing
  494.  
  495.    // E R A S E /////////////////////////////////////////////////////////////
  496.  
  497.    // loop through the atoms and erase them
  498.  
  499.    for (index=0; index<NUM_ATOMS; index++)
  500.        {
  501.        Plot_Pixel_Fast(atoms[index].x, atoms[index].y, 0);
  502.        } // end for index
  503.  
  504.    // M O V E ////////////////////////////////////////////////////////////////
  505.  
  506.    // loop through the atom array and move each atom also check collsions
  507.    // with the walls of the container
  508.  
  509.    for (index=0; index<NUM_ATOMS; index++)
  510.        {
  511.  
  512.        // move the atoms
  513.  
  514.        atoms[index].x+=atoms[index].xv;
  515.        atoms[index].y+=atoms[index].yv;
  516.  
  517.        // did the atom hit a wall, if so reflect the velocity vector
  518.  
  519.        if (atoms[index].x > 98 || atoms[index].x < 27)
  520.            {
  521.            atoms[index].xv=-atoms[index].xv;
  522.            atoms[index].x+=atoms[index].xv;
  523.            } // end if hit a vertical wall
  524.  
  525.        if (atoms[index].y > 98 || atoms[index].y < 28)
  526.           {
  527.           atoms[index].yv=-atoms[index].yv;
  528.           atoms[index].y+=atoms[index].yv;
  529.           } // end if hit a horizontal wall
  530.  
  531.        } // end for index
  532.  
  533.    // D R A W /////////////////////////////////////////////////////////////////
  534.  
  535.    // loop through the atoms and draw them
  536.  
  537.    for (index=0; index<NUM_ATOMS; index++)
  538.        {
  539.        Plot_Pixel_Fast(atoms[index].x, atoms[index].y, 10);
  540.        } // end for index
  541.  
  542.    } // end else normal processing
  543.  
  544. } // end Balls
  545.  
  546. // M A I N ////////////////////////////////////////////////////////////////////
  547.  
  548. void main(void)
  549. {
  550. int trate=20;           // initial timer rate
  551. int done=0;             // exit flag
  552. char string[80];        // used for printing
  553.  
  554.  
  555. // SECTION 1 //////////////////////////////////////////////////////////////////
  556.  
  557. // set video mode to 320x200 256 color mode
  558.  
  559. Set_Video_Mode(VGA256);
  560.  
  561. // initialize the multi-tasking system
  562.  
  563. Initialize_Kernal();
  564.  
  565. // load in some processes and save their id's
  566.  
  567. star_id   = Add_Task(Stars);
  568.  
  569. ball_id   = Add_Task(Balls);
  570.  
  571. mirror_id = Add_Task(Mirror);
  572.  
  573. // SECTION 2 //////////////////////////////////////////////////////////////////
  574.  
  575. // set timer rate to 20Hz
  576.  
  577. Change_Timer(TIMER_20HZ);
  578.  
  579. // turn on the multi-tasking kernal, each task will be executed every 3
  580. // interrupts since there is a round robin scheduler in place
  581.  
  582. Start_Kernal();
  583.  
  584. // SECTION 3 //////////////////////////////////////////////////////////////////
  585.  
  586. // now do main processing in parallel with other tasks
  587.  
  588. // draw menu
  589.  
  590. Blit_String(10,105,10,   "Multi-Tasking Control Menu",1);
  591. Blit_String(10,110+10,2,"Press (2-6) to Change interrupt rate.",1);
  592. Blit_String(10,110+20,2,"Press 'B' to kill ball task.",1);
  593. Blit_String(10,110+30,2,"Press 'S' to kill stars task.",1);
  594. Blit_String(10,110+40,2,"Press 'M' to kill mirror task.",1);
  595. Blit_String(10,110+50,2,"Press 'Q' to exit.",1);
  596.  
  597. Blit_String(25,10,10,"Balls",0);
  598. Blit_String(125,10,10,"Mirror",0);
  599. Blit_String(225,10,10,"Star Field",0);
  600.  
  601.  
  602. // SECTION 4 //////////////////////////////////////////////////////////////////
  603.  
  604. // main event loop
  605.  
  606. while(!done)
  607.      {
  608.  
  609.      // test if key was hit
  610.  
  611.      if (kbhit())
  612.         {
  613.  
  614.         // get the character and test it
  615.  
  616.         switch(getch())
  617.               {
  618.  
  619.               case '2': // set system timer to 20hz
  620.                       {
  621.  
  622.                       Change_Timer(TIMER_20HZ);
  623.                       trate = 20;
  624.  
  625.                       } break;
  626.  
  627.               case '3': // set system timer to 30hz
  628.                       {
  629.                       Change_Timer(TIMER_30HZ);
  630.                       trate = 30;
  631.  
  632.                       } break;
  633.  
  634.               case '4': // set system timer to 40hz
  635.                       {
  636.                       Change_Timer(TIMER_40HZ);
  637.                       trate = 40;
  638.  
  639.                       } break;
  640.  
  641.               case '5': // set system timer to 50hz
  642.                       {
  643.                       Change_Timer(TIMER_50HZ);
  644.                       trate = 50;
  645.  
  646.                       } break;
  647.  
  648.               case '6': // set system timer to 60hz
  649.                       {
  650.                       Change_Timer(TIMER_60HZ);
  651.                       trate = 60;
  652.  
  653.                       } break;
  654.  
  655. // SECTION 5 //////////////////////////////////////////////////////////////////
  656.  
  657.               case 'b': // kill the ball task
  658.                       {
  659.                       Delete_Task(ball_id);
  660.                       Blit_String(25,10,12,"INACTIVE  ",0);
  661.                       } break;
  662.  
  663.  
  664.               case 's': // kill the star field task
  665.                       {
  666.                       Delete_Task(star_id);
  667.                       Blit_String(225,10,12,"INACTIVE  ",0);
  668.                       } break;
  669.  
  670.  
  671.               case 'm': // kill the mirror task
  672.                       {
  673.                       Delete_Task(mirror_id);
  674.                       Blit_String(125,10,12,"INACTIVE  ",0);
  675.                       } break;
  676.  
  677.               case 'q': done=1; break;
  678.  
  679.               default:break;
  680.  
  681.               } // end switch
  682.  
  683.         } // end if kbhit
  684.  
  685.      // display info
  686.  
  687.      sprintf(string,"System timer at %dHZ  ",trate);
  688.      Blit_String(10,190,15,string,0);
  689.  
  690.      } // end while
  691.  
  692. // SECTION 6 //////////////////////////////////////////////////////////////////
  693.  
  694. // turn off the multi-tasking kernal
  695.  
  696. Stop_Kernal();
  697.  
  698. // reset system timer to 18.2
  699.  
  700. Change_Timer(TIMER_18HZ);
  701.  
  702. // reset the video mode back to text
  703.  
  704. Set_Video_Mode(TEXT_MODE);
  705.  
  706. } // end main
  707.  
  708.