home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Teach Yourself Game Programming in 21 Days
/
TYGAMES_R.ISO
/
source
/
day_11
/
graph11.c
next >
Wrap
Text File
|
1994-08-25
|
10KB
|
391 lines
// I N C L U D E S ////////////////////////////////////////////////////////////
#include <io.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <bios.h>
#include <fcntl.h>
#include <memory.h>
#include <malloc.h>
#include <math.h>
#include <string.h>
#include "graph3.h" // include graphics our stuff
#include "graph4.h"
#include "graph5.h"
#include "graph6.h"
#include "graph11.h"
// G L O B A L S /////////////////////////////////////////////////////////////
void (_interrupt _far *Old_Key_Isr)(); // holds old keyboard interrupt handler
int raw_key; // the global raw keyboard data
// the arrow key state table
int key_table[NUM_KEYS] = {0,0,0,0,0,0,0,0,0,0};
void (_interrupt far *Old_Time_Isr)(); // used to hold old interrupt vector
// multi-tasking stuff
task tasks[MAX_TASKS]; // this is the task list for the system
int num_tasks = 0; // tracks number of active tasks
// F U N C T I O N S //////////////////////////////////////////////////////////
void _interrupt _far New_Key_Int()
{
// read the key from the hardware and then re-enable the keyboard to
// read another key
_asm
{
sti ; re-enable interrupts
in al, KEY_BUFFER ; get the key that was pressed
xor ah,ah ; zero out upper 8 bits of AX
mov raw_key, ax ; store the key in global variable
in al, KEY_CONTROL ; set the control register
or al, 82h ; set the proper bits to reset the keyboard flip flop
out KEY_CONTROL,al ; send the new data back to the control register
and al,7fh
out KEY_CONTROL,al ; complete the reset
mov al,20h
out INT_CONTROL,al ; re-enable interrupts
; this is not really needed since we are using the
; C _interrupt function type, it does this for us,
; however, it's a good habit to get into and can't
; hurt
} // end inline assembly
// now for some C to update the arrow state table
// process the key and update the key state table
switch(raw_key)
{
case MAKE_UP: // pressing up
{
key_table[INDEX_UP] = 1;
} break;
case MAKE_DOWN: // pressing down
{
key_table[INDEX_DOWN] = 1;
} break;
case MAKE_RIGHT: // pressing right
{
key_table[INDEX_RIGHT] = 1;
} break;
case MAKE_LEFT: // pressing left
{
key_table[INDEX_LEFT] = 1;
} break;
case MAKE_ENTER: // pressing enter
{
key_table[INDEX_ENTER] = 1;
} break;
case MAKE_TAB : // pressing tab
{
key_table[INDEX_TAB ] = 1;
} break;
case MAKE_SPACE : // pressing space
{
key_table[INDEX_SPACE ] = 1;
} break;
case MAKE_CTRL : // pressing control
{
key_table[INDEX_CTRL ] = 1;
} break;
case MAKE_ALT : // pressing alt
{
key_table[INDEX_ALT ] = 1;
} break;
case MAKE_ESC : // pressing escape
{
key_table[INDEX_ESC ] = 1;
} break;
case BREAK_UP: // releasing up
{
key_table[INDEX_UP] = 0;
} break;
case BREAK_DOWN: // releasing down
{
key_table[INDEX_DOWN] = 0;
} break;
case BREAK_RIGHT: // releasing right
{
key_table[INDEX_RIGHT] = 0;
} break;
case BREAK_LEFT: // releasing left
{
key_table[INDEX_LEFT] = 0;
} break;
case BREAK_ENTER: // releasing enter
{
key_table[INDEX_ENTER] = 0;
} break;
case BREAK_TAB : // releasing tab
{
key_table[INDEX_TAB ] = 0;
} break;
case BREAK_SPACE : // releasing space
{
key_table[INDEX_SPACE ] = 0;
} break;
case BREAK_CTRL : // releasing control
{
key_table[INDEX_CTRL ] = 0;
} break;
case BREAK_ALT : // releasing alt
{
key_table[INDEX_ALT ] = 0;
} break;
case BREAK_ESC : // releasing escape
{
key_table[INDEX_ESC ] = 0;
} break;
default: break;
} // end switch
// note how we don't chain interrupts, we want total control of the keyboard
// however, if you wanted to chain then you would make a call to the old
// keyboard handler right here.
} // end New_Key_Int
///////////////////////////////////////////////////////////////////////////////
void Install_Keyboard(void)
{
Old_Key_Isr = _dos_getvect(KEYBOARD_INT);
_dos_setvect(KEYBOARD_INT, New_Key_Int);
} // end Install_Keyboard
///////////////////////////////////////////////////////////////////////////////
void Delete_Keyboard(void)
{
_dos_setvect(KEYBOARD_INT, Old_Key_Isr);
} // end Delete_Keyboard
///////////////////////////////////////////////////////////////////////////////
void Initialize_Kernal(void)
{
// this function will set up the task list and prepare for it to be populated
int index; // loop variable
for (index=0; index<MAX_TASKS; index++)
{
// set id to current location in list
tasks[index].id = index;
// set to inactive
tasks[index].state = TASK_INACTIVE;
// set function pointer to NULL;
tasks[index].task = NULL;
} // end for index
} // end Initialize_Kernal
///////////////////////////////////////////////////////////////////////////////
void Start_Kernal(void)
{
// install our time keeper ISR while saving old one
Old_Time_Isr = _dos_getvect(TIME_KEEPER_INT);
_dos_setvect(TIME_KEEPER_INT, Multi_Kernal);
} // end Start_Kernal
///////////////////////////////////////////////////////////////////////////////
void Stop_Kernal(void)
{
// replace old time keeper ISR
_dos_setvect(TIME_KEEPER_INT, Old_Time_Isr);
} // end Stop_Kernal
//////////////////////////////////////////////////////////////////////////////
int Add_Task(void (far *function)())
{
// this function will add the task to the task list and return it's id number
// which can be used to delete it. If the function returns -1 then the
// task list is full and no more tasks can be added
int index;
for (index=0; index<MAX_TASKS; index++)
{
// try and find an inactive task
if (tasks[index].state == TASK_INACTIVE)
{
// load new task into this position
tasks[index].state = TASK_ACTIVE;
tasks[index].id = index;
tasks[index].task = function; // assign function pointer
// adjust global task monitor
num_tasks++;
// return id to caller
return(tasks[index].id);
} // end if found an inactive task
} // end for index
// if we got this far then there are no free spots...bummer
return(-1);
} // end Add_Task
///////////////////////////////////////////////////////////////////////////////
int Delete_Task(int id)
{
// this function will try to delete a task from the task list, if the function
// is successful, it will return 1 else it will return 0.
if (tasks[id].state == TASK_ACTIVE)
{
// kill task and return success
tasks[id].task = NULL;
tasks[id].state = TASK_INACTIVE;
// decrement number of active tasks
num_tasks--;
return(1);
} // end if task can be deleted
else
{
// couldn't delete task
return(0);
} // end task already dead
} // end Delete_Task
///////////////////////////////////////////////////////////////////////////////
void _interrupt far Multi_Kernal(void)
{
// this function will call all of the task in a round robin manner such that
// only one task will be called per interrupt. note: ther must be at least
// one active task in the task list
static int current_task=0; // current_task to be executed by kernal
// test if there are any tasks at all
if (num_tasks>0)
{
// find an active task
while(tasks[current_task].state!=TASK_ACTIVE)
{
// move to next task and round robin if at end of task list
if (++current_task>=MAX_TASKS)
current_task=0;
} // end search for active task
// at this point we have an active task so call it
tasks[current_task].task(); // weird looking huh!
// now we need to move to the next possible task
if (++current_task>=MAX_TASKS)
current_task=0;
} // end if there are any tasks
// chain to old ISR (play nice with the other children)
Old_Time_Isr();
} // end Multi_Kernal
///////////////////////////////////////////////////////////////////////////////
void Change_Timer(unsigned int new_count)
{
// send the control word, mode 2, binary, least/most load sequence
_outp(CONTROL_8253, CONTROL_WORD);
// now write the least significant byte to the counter register
_outp(COUNTER_0,LOW_BYTE(new_count));
// and now the the most significant byte
_outp(COUNTER_0,HI_BYTE(new_count));
} // end Change_Timer
///////////////////////////////////////////////////////////////////////////////