home *** CD-ROM | disk | FTP | other *** search
/ Teach Yourself Game Programming in 21 Days / TYGAMES_R.ISO / source / day_11 / graph11.c next >
Text File  |  1994-08-25  |  10KB  |  391 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. #include "graph11.h"
  21.  
  22. // G L O B A L S /////////////////////////////////////////////////////////////
  23.  
  24.  
  25. void (_interrupt _far *Old_Key_Isr)();  // holds old keyboard interrupt handler
  26.  
  27. int raw_key;  // the global raw keyboard data
  28.  
  29. // the arrow key state table
  30.  
  31. int key_table[NUM_KEYS] = {0,0,0,0,0,0,0,0,0,0};
  32.  
  33.  
  34. void (_interrupt far *Old_Time_Isr)();  // used to hold old interrupt vector
  35.  
  36. // multi-tasking stuff
  37.  
  38. task tasks[MAX_TASKS];             // this is the task list for the system
  39.  
  40. int num_tasks = 0;                 // tracks number of active tasks
  41.  
  42. // F U N C T I O N S //////////////////////////////////////////////////////////
  43.  
  44. void _interrupt _far New_Key_Int()
  45. {
  46.  
  47. // read the key from the hardware and then re-enable the keyboard to
  48. // read another key
  49.  
  50. _asm
  51.    {
  52.    sti                    ; re-enable interrupts
  53.    in al, KEY_BUFFER      ; get the key that was pressed
  54.    xor ah,ah              ; zero out upper 8 bits of AX
  55.    mov raw_key, ax        ; store the key in global variable
  56.    in al, KEY_CONTROL     ; set the control register
  57.    or al, 82h             ; set the proper bits to reset the keyboard flip flop
  58.    out KEY_CONTROL,al     ; send the new data back to the control register
  59.    and al,7fh
  60.    out KEY_CONTROL,al     ; complete the reset
  61.    mov al,20h
  62.    out INT_CONTROL,al     ; re-enable interrupts
  63.                           ; this is not really needed since we are using the
  64.                           ; C _interrupt function type, it does this for us,
  65.                           ; however, it's a good habit to get into and can't
  66.                           ; hurt
  67.  
  68.    } // end inline assembly
  69.  
  70. // now for some C to update the arrow state table
  71.  
  72. // process the key and update the key state table
  73.  
  74. switch(raw_key)
  75.       {
  76.       case MAKE_UP:    // pressing up
  77.            {
  78.            key_table[INDEX_UP]    = 1;
  79.            } break;
  80.  
  81.       case MAKE_DOWN:  // pressing down
  82.            {
  83.            key_table[INDEX_DOWN]  = 1;
  84.            } break;
  85.  
  86.       case MAKE_RIGHT: // pressing right
  87.            {
  88.            key_table[INDEX_RIGHT] = 1;
  89.            } break;
  90.  
  91.       case MAKE_LEFT:  // pressing left
  92.            {
  93.            key_table[INDEX_LEFT]  = 1;
  94.            } break;
  95.  
  96.       case MAKE_ENTER:    // pressing enter
  97.            {
  98.            key_table[INDEX_ENTER]    = 1;
  99.            } break;
  100.  
  101.       case MAKE_TAB :  // pressing tab
  102.            {
  103.            key_table[INDEX_TAB ]  = 1;
  104.            } break;
  105.  
  106.       case MAKE_SPACE : // pressing space
  107.            {
  108.            key_table[INDEX_SPACE ] = 1;
  109.            } break;
  110.  
  111.       case MAKE_CTRL :  // pressing control
  112.            {
  113.            key_table[INDEX_CTRL ]  = 1;
  114.            } break;
  115.  
  116.       case MAKE_ALT  : // pressing alt
  117.            {
  118.            key_table[INDEX_ALT  ] = 1;
  119.            } break;
  120.  
  121.       case MAKE_ESC  :  // pressing escape
  122.            {
  123.            key_table[INDEX_ESC ]  = 1;
  124.            } break;
  125.  
  126.       case BREAK_UP:    // releasing up
  127.            {
  128.            key_table[INDEX_UP]    = 0;
  129.            } break;
  130.  
  131.       case BREAK_DOWN:  // releasing down
  132.            {
  133.            key_table[INDEX_DOWN]  = 0;
  134.            } break;
  135.  
  136.       case BREAK_RIGHT: // releasing right
  137.            {
  138.            key_table[INDEX_RIGHT] = 0;
  139.            } break;
  140.  
  141.       case BREAK_LEFT:  // releasing left
  142.            {
  143.            key_table[INDEX_LEFT]  = 0;
  144.            } break;
  145.  
  146.       case BREAK_ENTER:    // releasing enter
  147.            {
  148.            key_table[INDEX_ENTER]   = 0;
  149.            } break;
  150.  
  151.       case BREAK_TAB :  // releasing tab
  152.            {
  153.            key_table[INDEX_TAB ]  = 0;
  154.            } break;
  155.  
  156.       case BREAK_SPACE : // releasing space
  157.            {
  158.            key_table[INDEX_SPACE ] = 0;
  159.            } break;
  160.  
  161.       case BREAK_CTRL :  // releasing control
  162.            {
  163.            key_table[INDEX_CTRL ]  = 0;
  164.            } break;
  165.  
  166.       case BREAK_ALT  : // releasing alt
  167.            {
  168.            key_table[INDEX_ALT  ] = 0;
  169.            } break;
  170.  
  171.       case BREAK_ESC  :  // releasing escape
  172.            {
  173.            key_table[INDEX_ESC ]  = 0;
  174.            } break;
  175.  
  176.       default: break;
  177.  
  178.       } // end switch
  179.  
  180. // note how we don't chain interrupts, we want total control of the keyboard
  181. // however, if you wanted to chain then you would make a call to the old
  182. // keyboard handler right here.
  183.  
  184.  
  185. } // end New_Key_Int
  186.  
  187. ///////////////////////////////////////////////////////////////////////////////
  188.  
  189. void Install_Keyboard(void)
  190. {
  191.  
  192. Old_Key_Isr = _dos_getvect(KEYBOARD_INT);
  193.  
  194. _dos_setvect(KEYBOARD_INT, New_Key_Int);
  195.  
  196. } // end Install_Keyboard
  197.  
  198. ///////////////////////////////////////////////////////////////////////////////
  199.  
  200. void Delete_Keyboard(void)
  201. {
  202.  
  203. _dos_setvect(KEYBOARD_INT, Old_Key_Isr);
  204.  
  205. } // end Delete_Keyboard
  206.  
  207. ///////////////////////////////////////////////////////////////////////////////
  208.  
  209. void Initialize_Kernal(void)
  210. {
  211.  
  212. // this function will set up the task list and prepare for it to be populated
  213.  
  214. int index; // loop variable
  215.  
  216. for (index=0; index<MAX_TASKS; index++)
  217.     {
  218.     // set id to current location in list
  219.  
  220.     tasks[index].id = index;
  221.  
  222.     // set to inactive
  223.  
  224.     tasks[index].state = TASK_INACTIVE;
  225.  
  226.     // set function pointer to NULL;
  227.  
  228.     tasks[index].task = NULL;
  229.  
  230.     } // end for index
  231.  
  232. } // end Initialize_Kernal
  233.  
  234. ///////////////////////////////////////////////////////////////////////////////
  235.  
  236. void Start_Kernal(void)
  237. {
  238. // install our time keeper ISR while saving old one
  239.  
  240. Old_Time_Isr = _dos_getvect(TIME_KEEPER_INT);
  241.  
  242. _dos_setvect(TIME_KEEPER_INT, Multi_Kernal);
  243.  
  244. } // end Start_Kernal
  245.  
  246. ///////////////////////////////////////////////////////////////////////////////
  247.  
  248. void Stop_Kernal(void)
  249. {
  250.  
  251. // replace old time keeper ISR
  252.  
  253. _dos_setvect(TIME_KEEPER_INT, Old_Time_Isr);
  254.  
  255. } // end Stop_Kernal
  256.  
  257. //////////////////////////////////////////////////////////////////////////////
  258.  
  259. int Add_Task(void (far *function)())
  260. {
  261. // this function will add the task to the task list and return it's id number
  262. // which can be used to delete it.  If the function returns -1 then the
  263. // task list is full and no more tasks can be added
  264.  
  265. int index;
  266.  
  267. for (index=0; index<MAX_TASKS; index++)
  268.     {
  269.     // try and find an inactive task
  270.  
  271.     if (tasks[index].state == TASK_INACTIVE)
  272.        {
  273.        // load new task into this position
  274.  
  275.        tasks[index].state = TASK_ACTIVE;
  276.        tasks[index].id    = index;
  277.        tasks[index].task  = function;  // assign function pointer
  278.  
  279.        // adjust global task monitor
  280.  
  281.        num_tasks++;
  282.  
  283.        // return id to caller
  284.  
  285.        return(tasks[index].id);
  286.  
  287.        } // end if found an inactive task
  288.  
  289.     } // end for index
  290.  
  291. // if we got this far then there are no free spots...bummer
  292.  
  293. return(-1);
  294.  
  295. } // end Add_Task
  296.  
  297. ///////////////////////////////////////////////////////////////////////////////
  298.  
  299. int Delete_Task(int id)
  300. {
  301. // this function will try to delete a task from the task list, if the function
  302. // is successful, it will return 1 else it will return 0.
  303.  
  304. if (tasks[id].state == TASK_ACTIVE)
  305.    {
  306.    // kill task and return success
  307.  
  308.    tasks[id].task   = NULL;
  309.    tasks[id].state  = TASK_INACTIVE;
  310.  
  311.    // decrement number of active tasks
  312.  
  313.    num_tasks--;
  314.  
  315.    return(1);
  316.  
  317.    } // end if task can be deleted
  318. else
  319.    {
  320.    // couldn't delete task
  321.    return(0);
  322.  
  323.    } // end task already dead
  324.  
  325. } // end Delete_Task
  326.  
  327. ///////////////////////////////////////////////////////////////////////////////
  328.  
  329. void _interrupt far Multi_Kernal(void)
  330. {
  331.  
  332. // this function will call all of the task in a round robin manner such that
  333. // only one task will be called per interrupt. note: ther must be at least
  334. // one active task in the task list
  335.  
  336. static int current_task=0;  // current_task to be executed by kernal
  337.  
  338. // test if there are any tasks at all
  339.  
  340. if (num_tasks>0)
  341. {
  342.  
  343. // find an active task
  344.  
  345. while(tasks[current_task].state!=TASK_ACTIVE)
  346.      {
  347.      // move to next task and round robin if at end of task list
  348.  
  349.      if (++current_task>=MAX_TASKS)
  350.         current_task=0;
  351.  
  352.      } // end search for active task
  353.  
  354. // at this point we have an active task so call it
  355.  
  356. tasks[current_task].task(); // weird looking huh!
  357.  
  358. // now we need to move to the next possible task
  359.  
  360. if (++current_task>=MAX_TASKS)
  361.    current_task=0;
  362.  
  363. } // end if there are any tasks
  364.  
  365. // chain to old ISR (play nice with the other children)
  366.  
  367. Old_Time_Isr();
  368.  
  369. } // end Multi_Kernal
  370.  
  371. ///////////////////////////////////////////////////////////////////////////////
  372.  
  373. void Change_Timer(unsigned int new_count)
  374. {
  375.  
  376. // send the control word, mode 2, binary, least/most load sequence
  377.  
  378. _outp(CONTROL_8253, CONTROL_WORD);
  379.  
  380. // now write the least significant byte to the counter register
  381.  
  382. _outp(COUNTER_0,LOW_BYTE(new_count));
  383.  
  384. // and now the the most significant byte
  385.  
  386. _outp(COUNTER_0,HI_BYTE(new_count));
  387.  
  388. } // end Change_Timer
  389.  
  390. ///////////////////////////////////////////////////////////////////////////////
  391.